--- /dev/null
+/**
+ * @fileoverview Validate strings passed to the RegExp constructor
+ * @author Michael Ficarra
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const RegExpValidator = require("regexpp").RegExpValidator;
+const validator = new RegExpValidator({ ecmaVersion: 2018 });
+const validFlags = /[gimuys]/gu;
+const undefined1 = void 0;
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+ meta: {
+ type: "problem",
+
+ docs: {
+ description: "disallow invalid regular expression strings in `RegExp` constructors",
+ category: "Possible Errors",
+ recommended: true,
+ url: "https://eslint.org/docs/rules/no-invalid-regexp"
+ },
+
+ schema: [{
+ type: "object",
+ properties: {
+ allowConstructorFlags: {
+ type: "array",
+ items: {
+ type: "string"
+ }
+ }
+ },
+ additionalProperties: false
+ }]
+ },
+
+ create(context) {
+
+ const options = context.options[0];
+ let allowedFlags = null;
+
+ if (options && options.allowConstructorFlags) {
+ const temp = options.allowConstructorFlags.join("").replace(validFlags, "");
+
+ if (temp) {
+ allowedFlags = new RegExp(`[${temp}]`, "giu");
+ }
+ }
+
+ /**
+ * Check if node is a string
+ * @param {ASTNode} node node to evaluate
+ * @returns {boolean} True if its a string
+ * @private
+ */
+ function isString(node) {
+ return node && node.type === "Literal" && typeof node.value === "string";
+ }
+
+ /**
+ * Check syntax error in a given pattern.
+ * @param {string} pattern The RegExp pattern to validate.
+ * @param {boolean} uFlag The Unicode flag.
+ * @returns {string|null} The syntax error.
+ */
+ function validateRegExpPattern(pattern, uFlag) {
+ try {
+ validator.validatePattern(pattern, undefined1, undefined1, uFlag);
+ return null;
+ } catch (err) {
+ return err.message;
+ }
+ }
+
+ /**
+ * Check syntax error in a given flags.
+ * @param {string} flags The RegExp flags to validate.
+ * @returns {string|null} The syntax error.
+ */
+ function validateRegExpFlags(flags) {
+ try {
+ validator.validateFlags(flags);
+ return null;
+ } catch (err) {
+ return `Invalid flags supplied to RegExp constructor '${flags}'`;
+ }
+ }
+
+ return {
+ "CallExpression, NewExpression"(node) {
+ if (node.callee.type !== "Identifier" || node.callee.name !== "RegExp" || !isString(node.arguments[0])) {
+ return;
+ }
+ const pattern = node.arguments[0].value;
+ let flags = isString(node.arguments[1]) ? node.arguments[1].value : "";
+
+ if (allowedFlags) {
+ flags = flags.replace(allowedFlags, "");
+ }
+
+ // If flags are unknown, check both are errored or not.
+ const message = validateRegExpFlags(flags) || (
+ flags
+ ? validateRegExpPattern(pattern, flags.indexOf("u") !== -1)
+ : validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false)
+ );
+
+ if (message) {
+ context.report({
+ node,
+ message: "{{message}}.",
+ data: { message }
+ });
+ }
+ }
+ };
+ }
+};