Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: prefer-template autofix produces syntax error with octal escapes #12085

Merged
merged 1 commit into from Aug 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 1 addition & 10 deletions lib/rules/prefer-template.js
Expand Up @@ -52,16 +52,7 @@ function isOctalEscapeSequence(node) {
return false;
}

const match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-7]{1,3})/u);

if (match) {

// \0 is actually not considered an octal
if (match[2] !== "0" || typeof match[3] !== "undefined") {
return true;
}
}
return false;
return astUtils.hasOctalEscapeSequence(node.raw);
}

/**
Expand Down
16 changes: 16 additions & 0 deletions lib/rules/utils/ast-utils.js
Expand Up @@ -38,6 +38,7 @@ const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "SwitchCase"]);

const DECIMAL_INTEGER_PATTERN = /^(0|[1-9]\d*)$/u;
const OCTAL_ESCAPE_PATTERN = /^(?:[^\\]|\\[^0-7]|\\0(?![0-9]))*\\(?:[1-7]|0[0-9])/u;

/**
* Checks reference if is non initializer and writable.
Expand Down Expand Up @@ -1373,5 +1374,20 @@ module.exports = {
"/*".length +
(match ? match.index + 1 : 0)
);
},

/**
* Determines whether the given raw string contains an octal escape sequence.
*
* "\1", "\2" ... "\7"
* "\00", "\01" ... "\09"
*
* "\0", when not followed by a digit, is not an octal escape sequence.
*
* @param {string} rawString A string in its raw representation.
* @returns {boolean} `true` if the string contains at least one octal escape sequence.
*/
hasOctalEscapeSequence(rawString) {
return OCTAL_ESCAPE_PATTERN.test(rawString);
}
};
10 changes: 10 additions & 0 deletions tests/lib/rules/prefer-template.js
Expand Up @@ -199,6 +199,16 @@ ruleTester.run("prefer-template", rule, {
output: null,
errors
},
{
code: "foo + '\\0\\1'",
output: null,
errors
},
{
code: "foo + '\\08'",
output: null,
errors
},
{
code: "foo + '\\\\033'",
output: "`${foo }\\\\033`",
Expand Down
78 changes: 78 additions & 0 deletions tests/lib/rules/utils/ast-utils.js
Expand Up @@ -1248,4 +1248,82 @@ describe("ast-utils", () => {
assert.strictEqual(astUtils.equalTokens(ast.body[0], ast.body[1], sourceCode), false);
});
});

describe("hasOctalEscapeSequence", () => {

/* eslint-disable quote-props */
const expectedResults = {
"\\1": true,
"\\2": true,
"\\7": true,
"\\00": true,
"\\01": true,
"\\02": true,
"\\07": true,
"\\08": true,
"\\09": true,
"\\10": true,
"\\12": true,
" \\1": true,
"\\1 ": true,
"a\\1": true,
"\\1a": true,
"a\\1a": true,
" \\01": true,
"\\01 ": true,
"a\\01": true,
"\\01a": true,
"a\\01a": true,
"a\\08a": true,
"\\0\\1": true,
"\\0\\01": true,
"\\0\\08": true,
"\\n\\1": true,
"\\n\\01": true,
"\\n\\08": true,
"\\\\\\1": true,
"\\\\\\01": true,
"\\\\\\08": true,

"\\0": false,
"\\8": false,
"\\9": false,
" \\0": false,
"\\0 ": false,
"a\\0": false,
"\\0a": false,
"a\\8a": false,
"\\0\\8": false,
"\\8\\0": false,
"\\80": false,
"\\81": false,
"\\\\": false,
"\\\\0": false,
"\\\\01": false,
"\\\\08": false,
"\\\\1": false,
"\\\\12": false,
"\\\\\\0": false,
"\\\\\\8": false,
"\\0\\\\": false,
"0": false,
"1": false,
"8": false,
"01": false,
"08": false,
"80": false,
"12": false,
"\\a": false,
"\\n": false
};
/* eslint-enable quote-props */

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

assert.strictEqual(astUtils.hasOctalEscapeSequence(ast.body[0].expression.raw), expectedResults[key]);
});
});
});
});