Skip to content

Commit 1720d3f

Browse files
committed
ReactFiberHydrationWarning in react-reconciler: fix special characters
printQuotedStringValue should have been used instead of naive quoted string printing.
1 parent 994765f commit 1720d3f

File tree

2 files changed

+41
-42
lines changed

2 files changed

+41
-42
lines changed

packages/react-dom/src/__tests__/ReactMount-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,7 +1065,7 @@ describe('ReactMount', () => {
10651065
// TODO: Currently, the special characters in the JSX string output are not escaped, the output looks invalid.
10661066
'Warning: Expected server HTML to contain a matching <span> in <div>.\n\n' +
10671067
' <div data-reactroot="">\n' +
1068-
"- {'SSRMismatchTest special characters: '\"\t\n'}\n" +
1068+
"- {'SSRMismatchTest special characters: \\'\"\\t\\n'}\n" +
10691069
'+ <span />\n' +
10701070
' </div>\n\n' +
10711071
' in span (at **)\n' +
@@ -1095,7 +1095,7 @@ describe('ReactMount', () => {
10951095
'Warning: Expected server HTML to contain a matching <span> in <div>.\n\n' +
10961096
` <div data-ssr-mismatch-attribute-with-special-characters={'"'} data-reactroot="">\n` +
10971097
'- <div>SSRMismatchTest text</div>\n' +
1098-
"+ <span>{' — <div>'}</span>\n" +
1098+
"+ <span>{'\\xa0\\u2014 <div>'}</span>\n" +
10991099
' </div>\n\n' +
11001100
' in span (at **)\n' +
11011101
' in div (at **)',

packages/react-reconciler/src/ReactFiberHydrationWarning.js

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,54 @@ function clipStringWithEllipsis(str: string, clipAtLength: number): string {
9292
);
9393
}
9494

95+
function escapeNonPrintableCharacters(str: string, quote: "'" | '"'): string {
96+
return str.replace(/[\s\S]/g, character => {
97+
switch (character) {
98+
case quote:
99+
return '\\' + character;
100+
case '\n':
101+
return '\\n';
102+
case '\t':
103+
return '\\t';
104+
default: {
105+
const charCode = character.charCodeAt(0);
106+
// Do not escape if the character is within the ASCII printable range:
107+
if (charCode >= 0x20 && charCode <= 0x7e) {
108+
return character;
109+
}
110+
const charCodeHex = charCode.toString(16);
111+
const longhand = charCodeHex.length > 2;
112+
return (
113+
'\\' +
114+
(longhand ? 'u' : 'x') +
115+
('0000' + charCodeHex).slice(longhand ? -4 : -2)
116+
);
117+
}
118+
}
119+
});
120+
}
121+
122+
function printQuotedStringValue(str: string, quote: "'" | '"'): string {
123+
return (
124+
quote +
125+
escapeNonPrintableCharacters(
126+
clipStringWithEllipsis(str, PRINT_MAX_STRING_LENGTH),
127+
quote,
128+
) +
129+
quote
130+
);
131+
}
132+
95133
function printValue(value: mixed): string {
96134
try {
97135
if (value === null) {
98136
return 'null';
99137
} else if (value === undefined) {
100138
return 'undefined';
101139
} else if (typeof value === 'string') {
102-
return "'" + clipStringWithEllipsis(value, PRINT_MAX_STRING_LENGTH) + "'";
140+
return printQuotedStringValue(value, "'");
103141
} else if (Array.isArray(value)) {
104142
let ret = '[';
105-
106143
const ic = value.length;
107144
for (let i = 0; i < ic; ++i) {
108145
ret += i > 0 ? ', ' : '';
@@ -145,44 +182,6 @@ function printValue(value: mixed): string {
145182
}
146183
}
147184

148-
function escapeNonPrintableCharacters(str: string, quote: "'" | '"'): string {
149-
return str.replace(/[\s\S]/g, character => {
150-
switch (character) {
151-
case quote:
152-
return '\\' + character;
153-
case '\n':
154-
return '\\n';
155-
case '\t':
156-
return '\\t';
157-
default: {
158-
const charCode = character.charCodeAt(0);
159-
// Do not escape if the character is within the ASCII printable range:
160-
if (charCode >= 0x20 && charCode <= 0x7e) {
161-
return character;
162-
}
163-
const charCodeHex = charCode.toString(16);
164-
const longhand = charCodeHex.length > 2;
165-
return (
166-
'\\' +
167-
(longhand ? 'u' : 'x') +
168-
('0000' + charCodeHex).slice(longhand ? -4 : -2)
169-
);
170-
}
171-
}
172-
});
173-
}
174-
175-
function printQuotedStringValue(str: string, quote: "'" | '"'): string {
176-
return (
177-
quote +
178-
escapeNonPrintableCharacters(
179-
clipStringWithEllipsis(str, PRINT_MAX_STRING_LENGTH),
180-
quote,
181-
) +
182-
quote
183-
);
184-
}
185-
186185
function printCurlyValue(value: mixed): string {
187186
return '{' + printValue(value) + '}';
188187
}

0 commit comments

Comments
 (0)