Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 256f656

Browse files
authored
Fix: autofix shouldn't produce template literals with \8 or \9 (#13737)
* Fix: autofix shouldn't produce template literals with `\8` or `\9` * Rename functions
1 parent b165aa5 commit 256f656

File tree

6 files changed

+66
-42
lines changed

6 files changed

+66
-42
lines changed

lib/rules/prefer-template.js

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,33 +39,25 @@ function getTopConcatBinaryExpression(node) {
3939
}
4040

4141
/**
42-
* Determines whether a given node is a octal escape sequence
42+
* Checks whether or not a node contains a string literal with an octal or non-octal decimal escape sequence
4343
* @param {ASTNode} node A node to check
44-
* @returns {boolean} `true` if the node is an octal escape sequence
44+
* @returns {boolean} `true` if at least one string literal within the node contains
45+
* an octal or non-octal decimal escape sequence
4546
*/
46-
function isOctalEscapeSequence(node) {
47-
48-
// No need to check TemplateLiterals – would throw error with octal escape
49-
const isStringLiteral = node.type === "Literal" && typeof node.value === "string";
50-
51-
if (!isStringLiteral) {
52-
return false;
47+
function hasOctalOrNonOctalDecimalEscapeSequence(node) {
48+
if (isConcatenation(node)) {
49+
return (
50+
hasOctalOrNonOctalDecimalEscapeSequence(node.left) ||
51+
hasOctalOrNonOctalDecimalEscapeSequence(node.right)
52+
);
5353
}
5454

55-
return astUtils.hasOctalEscapeSequence(node.raw);
56-
}
57-
58-
/**
59-
* Checks whether or not a node contains a octal escape sequence
60-
* @param {ASTNode} node A node to check
61-
* @returns {boolean} `true` if the node contains an octal escape sequence
62-
*/
63-
function hasOctalEscapeSequence(node) {
64-
if (isConcatenation(node)) {
65-
return hasOctalEscapeSequence(node.left) || hasOctalEscapeSequence(node.right);
55+
// No need to check TemplateLiterals – would throw parsing error
56+
if (node.type === "Literal" && typeof node.value === "string") {
57+
return astUtils.hasOctalOrNonOctalDecimalEscapeSequence(node.raw);
6658
}
6759

68-
return isOctalEscapeSequence(node);
60+
return false;
6961
}
7062

7163
/**
@@ -237,7 +229,7 @@ module.exports = {
237229
function fixNonStringBinaryExpression(fixer, node) {
238230
const topBinaryExpr = getTopConcatBinaryExpression(node.parent);
239231

240-
if (hasOctalEscapeSequence(topBinaryExpr)) {
232+
if (hasOctalOrNonOctalDecimalEscapeSequence(topBinaryExpr)) {
241233
return null;
242234
}
243235

lib/rules/quotes.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,12 @@ module.exports = {
282282
description: settings.description
283283
},
284284
fix(fixer) {
285-
if (quoteOption === "backtick" && astUtils.hasOctalEscapeSequence(rawVal)) {
285+
if (quoteOption === "backtick" && astUtils.hasOctalOrNonOctalDecimalEscapeSequence(rawVal)) {
286286

287-
// An octal escape sequence in a template literal would produce syntax error, even in non-strict mode.
287+
/*
288+
* An octal or non-octal decimal escape sequence in a template literal would
289+
* produce syntax error, even in non-strict mode.
290+
*/
288291
return null;
289292
}
290293

lib/rules/utils/ast-utils.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
3838
const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "SwitchCase"]);
3939

4040
const DECIMAL_INTEGER_PATTERN = /^(?:0|0[0-7]*[89]\d*|[1-9](?:_?\d)*)$/u;
41-
const OCTAL_ESCAPE_PATTERN = /^(?:[^\\]|\\[^0-7]|\\0(?![0-9]))*\\(?:[1-7]|0[0-9])/u;
41+
42+
// Tests the presence of at least one LegacyOctalEscapeSequence or NonOctalDecimalEscapeSequence in a raw string
43+
const OCTAL_OR_NON_OCTAL_DECIMAL_ESCAPE_PATTERN = /^(?:[^\\]|\\.)*\\(?:[1-9]|0[0-9])/su;
4244

4345
const LOGICAL_ASSIGNMENT_OPERATORS = new Set(["&&=", "||=", "??="]);
4446

@@ -1777,17 +1779,19 @@ module.exports = {
17771779
},
17781780

17791781
/**
1780-
* Determines whether the given raw string contains an octal escape sequence.
1782+
* Determines whether the given raw string contains an octal escape sequence
1783+
* or a non-octal decimal escape sequence ("\8", "\9").
17811784
*
1782-
* "\1", "\2" ... "\7"
1783-
* "\00", "\01" ... "\09"
1785+
* "\1", "\2" ... "\7", "\8", "\9"
1786+
* "\00", "\01" ... "\07", "\08", "\09"
17841787
*
17851788
* "\0", when not followed by a digit, is not an octal escape sequence.
17861789
* @param {string} rawString A string in its raw representation.
1787-
* @returns {boolean} `true` if the string contains at least one octal escape sequence.
1790+
* @returns {boolean} `true` if the string contains at least one octal escape sequence
1791+
* or at least one non-octal decimal escape sequence.
17881792
*/
1789-
hasOctalEscapeSequence(rawString) {
1790-
return OCTAL_ESCAPE_PATTERN.test(rawString);
1793+
hasOctalOrNonOctalDecimalEscapeSequence(rawString) {
1794+
return OCTAL_OR_NON_OCTAL_DECIMAL_ESCAPE_PATTERN.test(rawString);
17911795
},
17921796

17931797
isLogicalExpression,

tests/lib/rules/prefer-template.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ ruleTester.run("prefer-template", rule, {
194194
output: null,
195195
errors
196196
},
197+
{
198+
code: "foo + 'does not autofix non-octal decimal escape sequence' + '\\8'",
199+
output: null,
200+
errors
201+
},
197202
{
198203
code: "foo + '\\n other text \\033'",
199204
output: null,

tests/lib/rules/quotes.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,19 @@ ruleTester.run("quotes", rule, {
614614
type: "Literal"
615615
}
616616
]
617+
},
618+
{
619+
code: "var nonOctalDecimalEscape = '\\8'",
620+
output: null,
621+
options: ["backtick"],
622+
parserOptions: { ecmaVersion: 6 },
623+
errors: [
624+
{
625+
messageId: "wrongQuotes",
626+
data: { description: "backtick" },
627+
type: "Literal"
628+
}
629+
]
617630
}
618631
]
619632
});

tests/lib/rules/utils/ast-utils.js

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,7 +1648,7 @@ describe("ast-utils", () => {
16481648
});
16491649
});
16501650

1651-
describe("hasOctalEscapeSequence", () => {
1651+
describe("hasOctalOrNonOctalDecimalEscapeSequence", () => {
16521652

16531653
/* eslint-disable quote-props */
16541654
const expectedResults = {
@@ -1683,27 +1683,31 @@ describe("ast-utils", () => {
16831683
"\\\\\\1": true,
16841684
"\\\\\\01": true,
16851685
"\\\\\\08": true,
1686+
"\\8": true,
1687+
"\\9": true,
1688+
"a\\8a": true,
1689+
"\\0\\8": true,
1690+
"\\8\\0": true,
1691+
"\\80": true,
1692+
"\\81": true,
1693+
"\\\\\\8": true,
1694+
"\\\n\\1": true,
1695+
"foo\\\nbar\\2baz": true,
1696+
"\\\n\\8": true,
1697+
"foo\\\nbar\\9baz": true,
16861698

16871699
"\\0": false,
1688-
"\\8": false,
1689-
"\\9": false,
16901700
" \\0": false,
16911701
"\\0 ": false,
16921702
"a\\0": false,
16931703
"\\0a": false,
1694-
"a\\8a": false,
1695-
"\\0\\8": false,
1696-
"\\8\\0": false,
1697-
"\\80": false,
1698-
"\\81": false,
16991704
"\\\\": false,
17001705
"\\\\0": false,
17011706
"\\\\01": false,
17021707
"\\\\08": false,
17031708
"\\\\1": false,
17041709
"\\\\12": false,
17051710
"\\\\\\0": false,
1706-
"\\\\\\8": false,
17071711
"\\0\\\\": false,
17081712
"0": false,
17091713
"1": false,
@@ -1713,15 +1717,18 @@ describe("ast-utils", () => {
17131717
"80": false,
17141718
"12": false,
17151719
"\\a": false,
1716-
"\\n": false
1720+
"\\n": false,
1721+
"\\\n": false,
1722+
"foo\\\nbar": false,
1723+
"128\\\n349": false
17171724
};
17181725
/* eslint-enable quote-props */
17191726

17201727
Object.keys(expectedResults).forEach(key => {
17211728
it(`should return ${expectedResults[key]} for ${key}`, () => {
17221729
const ast = espree.parse(`"${key}"`);
17231730

1724-
assert.strictEqual(astUtils.hasOctalEscapeSequence(ast.body[0].expression.raw), expectedResults[key]);
1731+
assert.strictEqual(astUtils.hasOctalOrNonOctalDecimalEscapeSequence(ast.body[0].expression.raw), expectedResults[key]);
17251732
});
17261733
});
17271734
});

0 commit comments

Comments
 (0)