Skip to content

Commit a91332b

Browse files
authored
feat: In no-invalid-regexp validate flags also for non-literal patterns (#16583)
Fixes #16573
1 parent fbcf3ab commit a91332b

2 files changed

Lines changed: 82 additions & 18 deletions

File tree

lib/rules/no-invalid-regexp.js

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,20 @@ module.exports = {
5959
}
6060
}
6161

62+
/**
63+
* Reports error with the provided message.
64+
* @param {ASTNode} node The node holding the invalid RegExp
65+
* @param {string} message The message to report.
66+
* @returns {void}
67+
*/
68+
function report(node, message) {
69+
context.report({
70+
node,
71+
messageId: "regexMessage",
72+
data: { message }
73+
});
74+
}
75+
6276
/**
6377
* Check if node is a string
6478
* @param {ASTNode} node node to evaluate
@@ -108,10 +122,13 @@ module.exports = {
108122

109123
/**
110124
* Check syntax error in a given flags.
111-
* @param {string} flags The RegExp flags to validate.
125+
* @param {string|null} flags The RegExp flags to validate.
112126
* @returns {string|null} The syntax error.
113127
*/
114128
function validateRegExpFlags(flags) {
129+
if (!flags) {
130+
return null;
131+
}
115132
try {
116133
validator.validateFlags(flags);
117134
return null;
@@ -122,34 +139,39 @@ module.exports = {
122139

123140
return {
124141
"CallExpression, NewExpression"(node) {
125-
if (node.callee.type !== "Identifier" || node.callee.name !== "RegExp" || !isString(node.arguments[0])) {
142+
if (node.callee.type !== "Identifier" || node.callee.name !== "RegExp") {
126143
return;
127144
}
128-
const pattern = node.arguments[0].value;
145+
129146
let flags = getFlags(node);
130147

131148
if (flags && allowedFlags) {
132149
flags = flags.replace(allowedFlags, "");
133150
}
134151

135-
const message =
136-
(
137-
flags && validateRegExpFlags(flags)
138-
) ||
139-
(
152+
let message = validateRegExpFlags(flags);
153+
154+
if (message) {
155+
report(node, message);
156+
return;
157+
}
158+
159+
if (!isString(node.arguments[0])) {
160+
return;
161+
}
162+
163+
const pattern = node.arguments[0].value;
164+
165+
message = (
140166

141-
// If flags are unknown, report the regex only if its pattern is invalid both with and without the "u" flag
142-
flags === null
143-
? validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false)
144-
: validateRegExpPattern(pattern, flags.includes("u"))
145-
);
167+
// If flags are unknown, report the regex only if its pattern is invalid both with and without the "u" flag
168+
flags === null
169+
? validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false)
170+
: validateRegExpPattern(pattern, flags.includes("u"))
171+
);
146172

147173
if (message) {
148-
context.report({
149-
node,
150-
messageId: "regexMessage",
151-
data: { message }
152-
});
174+
report(node, message);
153175
}
154176
}
155177
};

tests/lib/rules/no-invalid-regexp.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ ruleTester.run("no-invalid-regexp", rule, {
5757
options: [{ allowConstructorFlags: ["a"] }]
5858
},
5959

60+
// unknown pattern
61+
"new RegExp(pattern, 'g')",
62+
"new RegExp('.' + '', 'g')",
63+
"new RegExp(pattern, '')",
64+
"new RegExp(pattern)",
65+
6066
// ES2020
6167
"new RegExp('(?<\\\\ud835\\\\udc9c>.)', 'g')",
6268
"new RegExp('(?<\\\\u{1d49c}>.)', 'g')",
@@ -87,6 +93,14 @@ ruleTester.run("no-invalid-regexp", rule, {
8793
code: "new RegExp('.', 'ga')",
8894
options: [{ allowConstructorFlags: ["a"] }]
8995
},
96+
{
97+
code: "new RegExp(pattern, 'ga')",
98+
options: [{ allowConstructorFlags: ["a"] }]
99+
},
100+
{
101+
code: "new RegExp('.' + '', 'ga')",
102+
options: [{ allowConstructorFlags: ["a"] }]
103+
},
90104
{
91105
code: "new RegExp('.', 'a')",
92106
options: [{ allowConstructorFlags: ["a", "z"] }]
@@ -237,6 +251,34 @@ ruleTester.run("no-invalid-regexp", rule, {
237251
data: { message: "Invalid regular expression: /\\/: \\ at end of pattern" },
238252
type: "NewExpression"
239253
}]
254+
},
255+
256+
// https://github.com/eslint/eslint/issues/16573
257+
{
258+
code: "RegExp(')' + '', 'a');",
259+
errors: [{
260+
messageId: "regexMessage",
261+
data: { message: "Invalid flags supplied to RegExp constructor 'a'" },
262+
type: "CallExpression"
263+
}]
264+
},
265+
{
266+
code: "new RegExp('.' + '', 'az');",
267+
options: [{ allowConstructorFlags: ["z"] }],
268+
errors: [{
269+
messageId: "regexMessage",
270+
data: { message: "Invalid flags supplied to RegExp constructor 'a'" },
271+
type: "NewExpression"
272+
}]
273+
},
274+
{
275+
code: "new RegExp(pattern, 'az');",
276+
options: [{ allowConstructorFlags: ["a"] }],
277+
errors: [{
278+
messageId: "regexMessage",
279+
data: { message: "Invalid flags supplied to RegExp constructor 'z'" },
280+
type: "NewExpression"
281+
}]
240282
}
241283
]
242284
});

0 commit comments

Comments
 (0)