Skip to content

Commit b04d707

Browse files
authored
Refactor defineRegexpVisitor (#150)
1 parent bbddc6e commit b04d707

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+667
-918
lines changed

.eslintrc.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@ module.exports = {
2727
"no-shadow": "off", // ts bug?
2828
"@typescript-eslint/no-shadow": "error",
2929

30+
// Rules for implementing this plugin.
31+
"no-restricted-imports": [
32+
"error",
33+
{
34+
paths: [
35+
{
36+
name: "regexp-ast-analysis",
37+
importNames: ["toCharSet"],
38+
message:
39+
"Please use toCharSet from RegExpContext instead.",
40+
},
41+
],
42+
},
43+
],
44+
3045
// https://github.com/ota-meshi/eslint-plugin-regexp/pull/49
3146
"no-empty-character-class": "error",
3247
"regexp/negation": "error",

lib/rules/confusing-quantifier.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import type { Expression } from "estree"
21
import type { RegExpVisitor } from "regexpp/visitor"
2+
import type { RegExpContext } from "../utils"
33
import {
44
createRule,
55
defineRegexpVisitor,
66
getQuantifierOffsets,
7-
getRegexpLocation,
87
quantToString,
98
} from "../utils"
109
import { isPotentiallyEmpty } from "regexp-ast-analysis"
@@ -26,22 +25,20 @@ export default createRule("confusing-quantifier", {
2625
type: "problem",
2726
},
2827
create(context) {
29-
const sourceCode = context.getSourceCode()
30-
3128
/**
3229
* Create visitor
33-
* @param node
3430
*/
35-
function createVisitor(node: Expression): RegExpVisitor.Handlers {
31+
function createVisitor({
32+
node,
33+
getRegexpLocation,
34+
}: RegExpContext): RegExpVisitor.Handlers {
3635
return {
3736
onQuantifierEnter(qNode) {
3837
if (qNode.min > 0 && isPotentiallyEmpty(qNode.element)) {
3938
const proposal = quantToString({ ...qNode, min: 0 })
4039
context.report({
4140
node,
4241
loc: getRegexpLocation(
43-
sourceCode,
44-
node,
4542
qNode,
4643
getQuantifierOffsets(qNode),
4744
),

lib/rules/letter-case.ts

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import type { Expression } from "estree"
21
import type { RegExpVisitor } from "regexpp/visitor"
32
import type { Character, CharacterClassRange } from "regexpp/ast"
3+
import type { RegExpContext } from "../utils"
44
import {
55
createRule,
66
defineRegexpVisitor,
7-
fixReplaceNode,
8-
getRegexpLocation,
97
isLetter,
108
isLowercaseLetter,
119
isUppercaseLetter,
@@ -87,34 +85,33 @@ export default createRule("letter-case", {
8785
},
8886
create(context) {
8987
const options = parseOptions(context.options[0])
90-
const sourceCode = context.getSourceCode()
9188

9289
/**
9390
* Report
9491
*/
9592
function report(
96-
node: Expression,
93+
{ node, getRegexpLocation, fixReplaceNode }: RegExpContext,
9794
reportNode: CharacterClassRange | Character,
9895
letterCase: "lowercase" | "uppercase",
9996
convertText: (converter: (s: string) => string) => string,
10097
) {
10198
context.report({
10299
node,
103-
loc: getRegexpLocation(sourceCode, node, reportNode),
100+
loc: getRegexpLocation(reportNode),
104101
messageId: "unexpected",
105102
data: {
106103
char: reportNode.raw,
107104
case: letterCase,
108105
},
109-
fix: fixReplaceNode(sourceCode, node, reportNode, () =>
106+
fix: fixReplaceNode(reportNode, () =>
110107
convertText(CONVERTER[letterCase]),
111108
),
112109
})
113110
}
114111

115112
/** Verify for Character in case insensitive */
116113
function verifyCharacterInCaseInsensitive(
117-
node: Expression,
114+
regexpContext: RegExpContext,
118115
cNode: Character,
119116
) {
120117
if (
@@ -130,14 +127,14 @@ export default createRule("letter-case", {
130127
return
131128
}
132129

133-
report(node, cNode, options.caseInsensitive, (converter) =>
130+
report(regexpContext, cNode, options.caseInsensitive, (converter) =>
134131
converter(String.fromCodePoint(cNode.value)),
135132
)
136133
}
137134

138135
/** Verify for CharacterClassRange in case insensitive */
139136
function verifyCharacterClassRangeInCaseInsensitive(
140-
node: Expression,
137+
regexpContext: RegExpContext,
141138
ccrNode: CharacterClassRange,
142139
) {
143140
if (options.caseInsensitive === "ignore") {
@@ -156,7 +153,7 @@ export default createRule("letter-case", {
156153
return
157154
}
158155
report(
159-
node,
156+
regexpContext,
160157
ccrNode,
161158
options.caseInsensitive,
162159
(converter) =>
@@ -168,7 +165,7 @@ export default createRule("letter-case", {
168165

169166
/** Verify for Character in unicode escape */
170167
function verifyCharacterInUnicodeEscape(
171-
node: Expression,
168+
regexpContext: RegExpContext,
172169
cNode: Character,
173170
) {
174171
if (options.unicodeEscape === "ignore") {
@@ -179,7 +176,7 @@ export default createRule("letter-case", {
179176
return
180177
}
181178
report(
182-
node,
179+
regexpContext,
183180
cNode,
184181
options.unicodeEscape,
185182
(converter) => `${parts[1]}${converter(parts[2])}${parts[3]}`,
@@ -188,7 +185,7 @@ export default createRule("letter-case", {
188185

189186
/** Verify for Character in hexadecimal escape */
190187
function verifyCharacterInHexadecimalEscape(
191-
node: Expression,
188+
regexpContext: RegExpContext,
192189
cNode: Character,
193190
) {
194191
if (options.hexadecimalEscape === "ignore") {
@@ -199,15 +196,18 @@ export default createRule("letter-case", {
199196
return
200197
}
201198
report(
202-
node,
199+
regexpContext,
203200
cNode,
204201
options.hexadecimalEscape,
205202
(converter) => `\\x${converter(parts[1])}`,
206203
)
207204
}
208205

209206
/** Verify for Character in control escape */
210-
function verifyCharacterInControl(node: Expression, cNode: Character) {
207+
function verifyCharacterInControl(
208+
regexpContext: RegExpContext,
209+
cNode: Character,
210+
) {
211211
if (options.controlEscape === "ignore") {
212212
return
213213
}
@@ -216,7 +216,7 @@ export default createRule("letter-case", {
216216
return
217217
}
218218
report(
219-
node,
219+
regexpContext,
220220
cNode,
221221
options.controlEscape,
222222
(converter) => `\\c${converter(parts[1])}`,
@@ -225,33 +225,31 @@ export default createRule("letter-case", {
225225

226226
/**
227227
* Create visitor
228-
* @param node
229228
*/
230229
function createVisitor(
231-
node: Expression,
232-
_pattern: string,
233-
flags: string,
230+
regexpContext: RegExpContext,
234231
): RegExpVisitor.Handlers {
232+
const { flags } = regexpContext
235233
return {
236234
onCharacterEnter(cNode) {
237-
if (flags.includes("i")) {
238-
verifyCharacterInCaseInsensitive(node, cNode)
235+
if (flags.ignoreCase) {
236+
verifyCharacterInCaseInsensitive(regexpContext, cNode)
239237
}
240238
if (cNode.raw.startsWith("\\u")) {
241-
verifyCharacterInUnicodeEscape(node, cNode)
239+
verifyCharacterInUnicodeEscape(regexpContext, cNode)
242240
}
243241
if (/^\\x.+$/u.test(cNode.raw)) {
244-
verifyCharacterInHexadecimalEscape(node, cNode)
242+
verifyCharacterInHexadecimalEscape(regexpContext, cNode)
245243
}
246244
if (/^\\c[A-Za-z]$/u.test(cNode.raw)) {
247-
verifyCharacterInControl(node, cNode)
245+
verifyCharacterInControl(regexpContext, cNode)
248246
}
249247
},
250-
...(flags.includes("i")
248+
...(flags.ignoreCase
251249
? {
252250
onCharacterClassRangeEnter(ccrNode) {
253251
verifyCharacterClassRangeInCaseInsensitive(
254-
node,
252+
regexpContext,
255253
ccrNode,
256254
)
257255
},

lib/rules/match-any.ts

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,8 @@
1-
import type { Expression } from "estree"
21
import type { RegExpVisitor } from "regexpp/visitor"
32
import type { Rule } from "eslint"
43
import type { CharacterClass, Node as RegExpNode } from "regexpp/ast"
5-
import {
6-
createRule,
7-
defineRegexpVisitor,
8-
getRegexpLocation,
9-
getRegexpRange,
10-
fixerApplyEscape,
11-
parseFlags,
12-
isRegexpLiteral,
13-
} from "../utils"
14-
import type { ReadonlyFlags } from "regexp-ast-analysis"
4+
import type { RegExpContext } from "../utils"
5+
import { createRule, defineRegexpVisitor, isRegexpLiteral } from "../utils"
156
import { matchesAllCharacters } from "regexp-ast-analysis"
167

178
const OPTION_SS1 = "[\\s\\S]" as const
@@ -74,9 +65,8 @@ export default createRule("match-any", {
7465
*/
7566
function* fix(
7667
fixer: Rule.RuleFixer,
77-
node: Expression,
68+
{ node, flags, getRegexpRange, fixerApplyEscape }: RegExpContext,
7869
regexpNode: RegExpNode,
79-
flags: ReadonlyFlags,
8070
) {
8171
if (!preference) {
8272
return
@@ -91,7 +81,7 @@ export default createRule("match-any", {
9181
return
9282
}
9383
}
94-
const range = getRegexpRange(sourceCode, node, regexpNode)
84+
const range = getRegexpRange(regexpNode)
9585
if (range == null) {
9686
return
9787
}
@@ -103,16 +93,13 @@ export default createRule("match-any", {
10393
) {
10494
yield fixer.replaceTextRange(
10595
[range[0] + 1, range[1] - 1],
106-
fixerApplyEscape(preference.slice(1, -1), node),
96+
fixerApplyEscape(preference.slice(1, -1)),
10797
)
10898
return
10999
}
110100

111101
const replacement = preference === OPTION_DOTALL ? "." : preference
112-
yield fixer.replaceTextRange(
113-
range,
114-
fixerApplyEscape(replacement, node),
115-
)
102+
yield fixer.replaceTextRange(range, fixerApplyEscape(replacement))
116103

117104
if (preference === OPTION_DOTALL) {
118105
// Autofix to dotAll depends on the flag.
@@ -129,14 +116,11 @@ export default createRule("match-any", {
129116

130117
/**
131118
* Create visitor
132-
* @param node
133119
*/
134120
function createVisitor(
135-
node: Expression,
136-
_pattern: string,
137-
flagsStr: string,
121+
regexpContext: RegExpContext,
138122
): RegExpVisitor.Handlers {
139-
const flags = parseFlags(flagsStr)
123+
const { node, flags, getRegexpLocation } = regexpContext
140124

141125
return {
142126
onCharacterSetEnter(csNode) {
@@ -147,13 +131,13 @@ export default createRule("match-any", {
147131
) {
148132
context.report({
149133
node,
150-
loc: getRegexpLocation(sourceCode, node, csNode),
134+
loc: getRegexpLocation(csNode),
151135
messageId: "unexpected",
152136
data: {
153137
expr: ".",
154138
},
155139
fix(fixer) {
156-
return fix(fixer, node, csNode, flags)
140+
return fix(fixer, regexpContext, csNode)
157141
},
158142
})
159143
}
@@ -165,13 +149,13 @@ export default createRule("match-any", {
165149
) {
166150
context.report({
167151
node,
168-
loc: getRegexpLocation(sourceCode, node, ccNode),
152+
loc: getRegexpLocation(ccNode),
169153
messageId: "unexpected",
170154
data: {
171155
expr: ccNode.raw,
172156
},
173157
fix(fixer) {
174-
return fix(fixer, node, ccNode, flags)
158+
return fix(fixer, regexpContext, ccNode)
175159
},
176160
})
177161
}

0 commit comments

Comments
 (0)