-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathno-invalid-regexp.ts
89 lines (80 loc) · 2.96 KB
/
no-invalid-regexp.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import type { RegExpContextForInvalid, RegExpContextForUnknown } from "../utils"
import { createRule, defineRegexpVisitor } from "../utils"
/** Returns the position of the error */
function getErrorIndex(error: SyntaxError): number | null {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- x
const index = (error as any).index
if (typeof index === "number") {
return index
}
return null
}
export default createRule("no-invalid-regexp", {
meta: {
docs: {
description:
"disallow invalid regular expression strings in `RegExp` constructors",
category: "Possible Errors",
recommended: true,
},
schema: [],
messages: {
error: "{{message}}",
duplicateFlag: "Duplicate {{flag}} flag.",
uvFlag: "Regex 'u' and 'v' flags cannot be used together.",
},
type: "problem",
},
create(context) {
function visitInvalid(regexpContext: RegExpContextForInvalid): void {
const { node, error, patternSource } = regexpContext
let loc = undefined
const index = getErrorIndex(error)
if (
index !== null &&
index >= 0 &&
index <= patternSource.value.length
) {
// The error index regexpp reports is a little weird.
// It's either spot on or one character to the right.
// Since we can't know which index is correct, we will report
// both positions.
loc = patternSource.getAstLocation({
start: Math.max(index - 1, 0),
end: Math.min(index + 1, patternSource.value.length),
})
}
context.report({
node,
loc: loc ?? undefined,
messageId: "error",
data: { message: error.message },
})
}
/** Checks for the combination of `u` and `v` flags */
function visitUnknown(regexpContext: RegExpContextForUnknown): void {
const { node, flags, flagsString, getFlagsLocation } = regexpContext
const flagSet = new Set<string>()
for (const flag of flagsString ?? "") {
if (flagSet.has(flag)) {
context.report({
node,
loc: getFlagsLocation(),
messageId: "duplicateFlag",
data: { flag },
})
return
}
flagSet.add(flag)
}
if (flags.unicode && flags.unicodeSets) {
context.report({
node,
loc: getFlagsLocation(),
messageId: "uvFlag",
})
}
}
return defineRegexpVisitor(context, { visitInvalid, visitUnknown })
},
})