Skip to content

Commit f20b9e9

Browse files
Fix: Relax no-useless-escape's handling of ']' in regexes (fixes #7789) (#7793)
']' is only allowed to be unescaped in regular expressions when the engine implements Annex B, a legacy part of the ECMA262 spec which is only normative for browsers. In engines that do not implement Annex B, regular expressions like /]/ are a syntax error. Since ESLint can't tell what engine the code will run on, it shouldn't consider escaping ] to be "useless" since it's only useless on engines that implement Annex B, and only in regular expressions that don't contain the unicode flag. (For example, the regular expression /]/u is a syntax error even on engines that implement Annex B.)
1 parent 3004c1e commit f20b9e9

2 files changed

Lines changed: 11 additions & 16 deletions

File tree

lib/rules/no-useless-escape.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ function union(setA, setB) {
2525
}
2626

2727
const VALID_STRING_ESCAPES = new Set("\\nrvtbfux\n\r\u2028\u2029");
28-
const REGEX_GENERAL_ESCAPES = new Set("\\bcdDfnrsStvwWxu0123456789");
29-
const REGEX_CHARCLASS_ESCAPES = union(REGEX_GENERAL_ESCAPES, new Set("]"));
28+
const REGEX_GENERAL_ESCAPES = new Set("\\bcdDfnrsStvwWxu0123456789]");
3029
const REGEX_NON_CHARCLASS_ESCAPES = union(REGEX_GENERAL_ESCAPES, new Set("^/.$*+?[{}|()B"));
3130

3231
/**
@@ -194,7 +193,7 @@ module.exports = {
194193
.filter(charInfo => charInfo.escaped)
195194

196195
// Filter out characters that are valid to escape, based on their position in the regular expression.
197-
.filter(charInfo => !(charInfo.inCharClass ? REGEX_CHARCLASS_ESCAPES : REGEX_NON_CHARCLASS_ESCAPES).has(charInfo.text))
196+
.filter(charInfo => !(charInfo.inCharClass ? REGEX_GENERAL_ESCAPES : REGEX_NON_CHARCLASS_ESCAPES).has(charInfo.text))
198197

199198
// Report all the remaining characters.
200199
.forEach(charInfo => report(node, charInfo.index, charInfo.text));

tests/lib/rules/no-useless-escape.js

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,15 @@ ruleTester.run("no-useless-escape", rule, {
105105
"var foo = /[\\0]/", // null character in character class
106106

107107
"var foo = 'foo \\\u2028 bar'",
108-
"var foo = 'foo \\\u2029 bar'"
108+
"var foo = 'foo \\\u2029 bar'",
109+
110+
// https://github.com/eslint/eslint/issues/7789
111+
String.raw`/]/`,
112+
String.raw`/\]/`,
113+
{ code: String.raw`/\]/u`, parserOptions: { ecmaVersion: 6 } },
114+
String.raw`var foo = /foo\]/`,
115+
String.raw`var foo = /[[]\]/`, // A character class containing '[', followed by a ']' character
116+
String.raw`var foo = /\[foo\.bar\]/`
109117
],
110118

111119
invalid: [
@@ -237,18 +245,6 @@ ruleTester.run("no-useless-escape", rule, {
237245
code: String.raw`var foo = /[\[]/`,
238246
errors: [{ line: 1, column: 13, message: "Unnecessary escape character: \\[.", type: "Literal" }]
239247
},
240-
{
241-
code: String.raw`var foo = /foo\]/`,
242-
errors: [{ line: 1, column: 15, message: "Unnecessary escape character: \\].", type: "Literal" }]
243-
},
244-
{
245-
code: String.raw`var foo = /[[]\]/`, // A character class containing '[', followed by a ']' character
246-
errors: [{ line: 1, column: 15, message: "Unnecessary escape character: \\].", type: "Literal" }]
247-
},
248-
{
249-
code: String.raw`var foo = /\[foo\.bar\]/`, // Matches the literal string '[foo.bar]'
250-
errors: [{ line: 1, column: 22, message: "Unnecessary escape character: \\].", type: "Literal" }]
251-
},
252248
{
253249
code: String.raw`var foo = /[\/]/`, // A character class containing '/'
254250
errors: [{ line: 1, column: 13, message: "Unnecessary escape character: \\/.", type: "Literal" }]

0 commit comments

Comments
 (0)