Skip to content

Commit 45eaf42

Browse files
authored
Use single replacer for string escaping (#22335)
1 parent a826c78 commit 45eaf42

5 files changed

+32
-8
lines changed

src/compiler/utilities.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2471,7 +2471,6 @@ namespace ts {
24712471
const singleQuoteEscapedCharsRegExp = /[\\\'\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
24722472
const backtickQuoteEscapedCharsRegExp = /[\\\`\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
24732473
const escapedCharsMap = createMapFromTemplate({
2474-
"\0": "\\0",
24752474
"\t": "\\t",
24762475
"\v": "\\v",
24772476
"\f": "\\f",
@@ -2486,7 +2485,6 @@ namespace ts {
24862485
"\u2029": "\\u2029", // paragraphSeparator
24872486
"\u0085": "\\u0085" // nextLine
24882487
});
2489-
const escapedNullRegExp = /\\0[0-9]/g;
24902488

24912489
/**
24922490
* Based heavily on the abstract 'Quote'/'QuoteJSONString' operation from ECMA-262 (24.3.2.2),
@@ -2498,14 +2496,19 @@ namespace ts {
24982496
quoteChar === CharacterCodes.backtick ? backtickQuoteEscapedCharsRegExp :
24992497
quoteChar === CharacterCodes.singleQuote ? singleQuoteEscapedCharsRegExp :
25002498
doubleQuoteEscapedCharsRegExp;
2501-
return s.replace(escapedCharsRegExp, getReplacement).replace(escapedNullRegExp, nullReplacement);
2499+
return s.replace(escapedCharsRegExp, getReplacement);
25022500
}
25032501

2504-
function nullReplacement(c: string) {
2505-
return "\\x00" + c.charAt(c.length - 1);
2506-
}
2507-
2508-
function getReplacement(c: string) {
2502+
function getReplacement(c: string, offset: number, input: string) {
2503+
if (c.charCodeAt(0) === CharacterCodes.nullCharacter) {
2504+
const lookAhead = input.charCodeAt(offset + c.length);
2505+
if (lookAhead >= CharacterCodes._0 && lookAhead <= CharacterCodes._9) {
2506+
// If the null character is followed by digits, print as a hex escape to prevent the result from parsing as an octal (which is forbidden in strict mode)
2507+
return "\\x00";
2508+
}
2509+
// Otherwise, keep printing a literal \0 for the null character
2510+
return "\\0";
2511+
}
25092512
return escapedCharsMap.get(c) || get16BitUnicodeEscapeSequence(c.charCodeAt(0));
25102513
}
25112514

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//// [nonstrictTemplateWithNotOctalPrintsAsIs.ts]
2+
// https://github.com/Microsoft/TypeScript/issues/21828
3+
const d2 = `\\0041`;
4+
5+
6+
//// [nonstrictTemplateWithNotOctalPrintsAsIs.js]
7+
// https://github.com/Microsoft/TypeScript/issues/21828
8+
var d2 = "\\0041";
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
=== tests/cases/compiler/nonstrictTemplateWithNotOctalPrintsAsIs.ts ===
2+
// https://github.com/Microsoft/TypeScript/issues/21828
3+
const d2 = `\\0041`;
4+
>d2 : Symbol(d2, Decl(nonstrictTemplateWithNotOctalPrintsAsIs.ts, 1, 5))
5+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
=== tests/cases/compiler/nonstrictTemplateWithNotOctalPrintsAsIs.ts ===
2+
// https://github.com/Microsoft/TypeScript/issues/21828
3+
const d2 = `\\0041`;
4+
>d2 : "\\0041"
5+
>`\\0041` : "\\0041"
6+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// https://github.com/Microsoft/TypeScript/issues/21828
2+
const d2 = `\\0041`;

0 commit comments

Comments
 (0)