123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- "use strict";
- const RegExpValidator = require("@eslint-community/regexpp").RegExpValidator;
- const validator = new RegExpValidator();
- const validFlags = "dgimsuvy";
- const undefined1 = void 0;
- module.exports = {
- meta: {
- type: "problem",
- defaultOptions: [{}],
- docs: {
- description: "Disallow invalid regular expression strings in `RegExp` constructors",
- recommended: true,
- url: "https://eslint.org/docs/latest/rules/no-invalid-regexp"
- },
- schema: [{
- type: "object",
- properties: {
- allowConstructorFlags: {
- type: "array",
- items: {
- type: "string"
- }
- }
- },
- additionalProperties: false
- }],
- messages: {
- regexMessage: "{{message}}."
- }
- },
- create(context) {
- const [{ allowConstructorFlags }] = context.options;
- let allowedFlags = [];
- if (allowConstructorFlags) {
- const temp = allowConstructorFlags.join("").replace(new RegExp(`[${validFlags}]`, "gu"), "");
- if (temp) {
- allowedFlags = [...new Set(temp)];
- }
- }
-
- function report(node, message) {
- context.report({
- node,
- messageId: "regexMessage",
- data: { message }
- });
- }
-
- function isString(node) {
- return node && node.type === "Literal" && typeof node.value === "string";
- }
-
- function getFlags(node) {
- if (node.arguments.length < 2) {
- return "";
- }
- if (isString(node.arguments[1])) {
- return node.arguments[1].value;
- }
- return null;
- }
-
- function validateRegExpPattern(pattern, flags) {
- try {
- validator.validatePattern(pattern, undefined1, undefined1, flags);
- return null;
- } catch (err) {
- return err.message;
- }
- }
-
- function validateRegExpFlags(flags, flagsToCheck, allFlags) {
- const duplicateFlags = [];
- if (typeof flagsToCheck === "string") {
- for (const flag of flagsToCheck) {
- if (allFlags.includes(flag)) {
- duplicateFlags.push(flag);
- }
- }
- }
-
- if (flags && flags.includes("u") && flags.includes("v")) {
- return "Regex 'u' and 'v' flags cannot be used together";
- }
- if (duplicateFlags.length > 0) {
- return `Duplicate flags ('${duplicateFlags.join("")}') supplied to RegExp constructor`;
- }
- if (!flagsToCheck) {
- return null;
- }
- return `Invalid flags supplied to RegExp constructor '${flagsToCheck}'`;
- }
- return {
- "CallExpression, NewExpression"(node) {
- if (node.callee.type !== "Identifier" || node.callee.name !== "RegExp") {
- return;
- }
- const flags = getFlags(node);
- let flagsToCheck = flags;
- const allFlags = allowedFlags.length > 0 ? validFlags.split("").concat(allowedFlags) : validFlags.split("");
- if (flags) {
- allFlags.forEach(flag => {
- flagsToCheck = flagsToCheck.replace(flag, "");
- });
- }
- let message = validateRegExpFlags(flags, flagsToCheck, allFlags);
- if (message) {
- report(node, message);
- return;
- }
- if (!isString(node.arguments[0])) {
- return;
- }
- const pattern = node.arguments[0].value;
- message = (
-
- flags === null
- ? (
- validateRegExpPattern(pattern, { unicode: true, unicodeSets: false }) &&
- validateRegExpPattern(pattern, { unicode: false, unicodeSets: true }) &&
- validateRegExpPattern(pattern, { unicode: false, unicodeSets: false })
- )
- : validateRegExpPattern(pattern, { unicode: flags.includes("u"), unicodeSets: flags.includes("v") })
- );
- if (message) {
- report(node, message);
- }
- }
- };
- }
- };
|