diff --git a/lib/rules/no-invalid-regexp.js b/lib/rules/no-invalid-regexp.js index 0f1d9c7bedc..81b083536d8 100644 --- a/lib/rules/no-invalid-regexp.js +++ b/lib/rules/no-invalid-regexp.js @@ -59,6 +59,20 @@ module.exports = { } } + /** + * Reports error with the provided message. + * @param {ASTNode} node The node holding the invalid RegExp + * @param {string} message The message to report. + * @returns {void} + */ + function report(node, message) { + context.report({ + node, + messageId: "regexMessage", + data: { message } + }); + } + /** * Check if node is a string * @param {ASTNode} node node to evaluate @@ -108,10 +122,13 @@ module.exports = { /** * Check syntax error in a given flags. - * @param {string} flags The RegExp flags to validate. + * @param {string|null} flags The RegExp flags to validate. * @returns {string|null} The syntax error. */ function validateRegExpFlags(flags) { + if (!flags) { + return null; + } try { validator.validateFlags(flags); return null; @@ -122,34 +139,39 @@ module.exports = { return { "CallExpression, NewExpression"(node) { - if (node.callee.type !== "Identifier" || node.callee.name !== "RegExp" || !isString(node.arguments[0])) { + if (node.callee.type !== "Identifier" || node.callee.name !== "RegExp") { return; } - const pattern = node.arguments[0].value; + let flags = getFlags(node); if (flags && allowedFlags) { flags = flags.replace(allowedFlags, ""); } - const message = - ( - flags && validateRegExpFlags(flags) - ) || - ( + let message = validateRegExpFlags(flags); + + if (message) { + report(node, message); + return; + } + + if (!isString(node.arguments[0])) { + return; + } + + const pattern = node.arguments[0].value; + + message = ( - // If flags are unknown, report the regex only if its pattern is invalid both with and without the "u" flag - flags === null - ? validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false) - : validateRegExpPattern(pattern, flags.includes("u")) - ); + // If flags are unknown, report the regex only if its pattern is invalid both with and without the "u" flag + flags === null + ? validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false) + : validateRegExpPattern(pattern, flags.includes("u")) + ); if (message) { - context.report({ - node, - messageId: "regexMessage", - data: { message } - }); + report(node, message); } } }; diff --git a/tests/lib/rules/no-invalid-regexp.js b/tests/lib/rules/no-invalid-regexp.js index a34752dcda5..047207b5534 100644 --- a/tests/lib/rules/no-invalid-regexp.js +++ b/tests/lib/rules/no-invalid-regexp.js @@ -57,6 +57,12 @@ ruleTester.run("no-invalid-regexp", rule, { options: [{ allowConstructorFlags: ["a"] }] }, + // unknown pattern + "new RegExp(pattern, 'g')", + "new RegExp('.' + '', 'g')", + "new RegExp(pattern, '')", + "new RegExp(pattern)", + // ES2020 "new RegExp('(?<\\\\ud835\\\\udc9c>.)', 'g')", "new RegExp('(?<\\\\u{1d49c}>.)', 'g')", @@ -87,6 +93,14 @@ ruleTester.run("no-invalid-regexp", rule, { code: "new RegExp('.', 'ga')", options: [{ allowConstructorFlags: ["a"] }] }, + { + code: "new RegExp(pattern, 'ga')", + options: [{ allowConstructorFlags: ["a"] }] + }, + { + code: "new RegExp('.' + '', 'ga')", + options: [{ allowConstructorFlags: ["a"] }] + }, { code: "new RegExp('.', 'a')", options: [{ allowConstructorFlags: ["a", "z"] }] @@ -237,6 +251,34 @@ ruleTester.run("no-invalid-regexp", rule, { data: { message: "Invalid regular expression: /\\/: \\ at end of pattern" }, type: "NewExpression" }] + }, + + // https://github.com/eslint/eslint/issues/16573 + { + code: "RegExp(')' + '', 'a');", + errors: [{ + messageId: "regexMessage", + data: { message: "Invalid flags supplied to RegExp constructor 'a'" }, + type: "CallExpression" + }] + }, + { + code: "new RegExp('.' + '', 'az');", + options: [{ allowConstructorFlags: ["z"] }], + errors: [{ + messageId: "regexMessage", + data: { message: "Invalid flags supplied to RegExp constructor 'a'" }, + type: "NewExpression" + }] + }, + { + code: "new RegExp(pattern, 'az');", + options: [{ allowConstructorFlags: ["a"] }], + errors: [{ + messageId: "regexMessage", + data: { message: "Invalid flags supplied to RegExp constructor 'z'" }, + type: "NewExpression" + }] } ] });