Skip to content

Commit 8382ea2

Browse files
authored
fix: autofix for incorrect no-escaping in regexp/no-useless-string-literal (#645)
1 parent 184831f commit 8382ea2

File tree

3 files changed

+42
-9
lines changed

3 files changed

+42
-9
lines changed

.changeset/quick-ties-bake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-regexp": patch
3+
---
4+
5+
fix: autofix for incorrect no-escaping in `regexp/no-useless-string-literal`

lib/rules/no-useless-string-literal.ts

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ export default createRule("no-useless-string-literal", {
4343
.join("|")
4444
if (!alternativesText.length) {
4545
const escape =
46-
isNeedEscapedInCharacterClass(
46+
isNeedEscapeForAdjacentPreviousCharacter(
47+
csdNode,
48+
saNode,
49+
) ||
50+
isNeedEscapeForAdjacentNextCharacter(
4751
csdNode,
4852
saNode,
4953
)
@@ -60,12 +64,13 @@ export default createRule("no-useless-string-literal", {
6064
saNode.raw === "^" ? "\\" : ""
6165
return String.raw`[${escape}${saNode.raw}\q{${alternativesText}}]`
6266
}
63-
const escape = isNeedEscapedInCharacterClass(
64-
csdNode,
65-
saNode,
66-
)
67-
? "\\"
68-
: ""
67+
const escape =
68+
isNeedEscapeForAdjacentPreviousCharacter(
69+
csdNode,
70+
saNode,
71+
)
72+
? "\\"
73+
: ""
6974
return String.raw`${escape}${saNode.raw}\q{${alternativesText}}`
7075
}),
7176
})
@@ -74,9 +79,10 @@ export default createRule("no-useless-string-literal", {
7479
}
7580

7681
/**
77-
* Checks whether an escape is required if the given character when placed before a \q{...}
82+
* Checks whether the given character requires escaping
83+
* when adjacent to the previous character.
7884
*/
79-
function isNeedEscapedInCharacterClass(
85+
function isNeedEscapeForAdjacentPreviousCharacter(
8086
disjunction: ClassStringDisjunction,
8187
character: StringAlternative,
8288
) {
@@ -97,6 +103,23 @@ export default createRule("no-useless-string-literal", {
97103
disjunction.parent.start === disjunction.start - 1
98104
)
99105
}
106+
107+
/**
108+
* Checks whether the given character requires escaping
109+
* when adjacent to the next character.
110+
*/
111+
function isNeedEscapeForAdjacentNextCharacter(
112+
disjunction: ClassStringDisjunction,
113+
character: StringAlternative,
114+
) {
115+
const char = character.raw
116+
// Avoid [\q{&}&&A] => [&&&A]
117+
return (
118+
RESERVED_DOUBLE_PUNCTUATOR_CHARS.has(char) &&
119+
// The next character is the same
120+
pattern[disjunction.end] === char
121+
)
122+
}
100123
}
101124

102125
return defineRegexpVisitor(context, {

tests/lib/rules/no-useless-string-literal.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ tester.run("no-useless-string-literal", rule as any, {
7979
output: String.raw`/[A&&\&]/v`,
8080
errors: ["Unexpected string disjunction of single character."],
8181
},
82+
{
83+
code: String.raw`/[\q{&}&&A]/v`,
84+
output: String.raw`/[\&&&A]/v`,
85+
errors: ["Unexpected string disjunction of single character."],
86+
},
8287
{
8388
code: String.raw`/[A&&\q{^|ab}]/v`,
8489
output: String.raw`/[A&&[\^\q{ab}]]/v`,

0 commit comments

Comments
 (0)