UNPKG

4.1 kBJavaScriptView Raw
1/**
2 * @fileoverview Validate strings passed to the RegExp constructor
3 * @author Michael Ficarra
4 */
5"use strict";
6
7//------------------------------------------------------------------------------
8// Requirements
9//------------------------------------------------------------------------------
10
11const RegExpValidator = require("regexpp").RegExpValidator;
12const validator = new RegExpValidator({ ecmaVersion: 2018 });
13const validFlags = /[gimuys]/gu;
14const undefined1 = void 0;
15
16//------------------------------------------------------------------------------
17// Rule Definition
18//------------------------------------------------------------------------------
19
20module.exports = {
21 meta: {
22 type: "problem",
23
24 docs: {
25 description: "disallow invalid regular expression strings in `RegExp` constructors",
26 category: "Possible Errors",
27 recommended: true,
28 url: "https://eslint.org/docs/rules/no-invalid-regexp"
29 },
30
31 schema: [{
32 type: "object",
33 properties: {
34 allowConstructorFlags: {
35 type: "array",
36 items: {
37 type: "string"
38 }
39 }
40 },
41 additionalProperties: false
42 }]
43 },
44
45 create(context) {
46
47 const options = context.options[0];
48 let allowedFlags = null;
49
50 if (options && options.allowConstructorFlags) {
51 const temp = options.allowConstructorFlags.join("").replace(validFlags, "");
52
53 if (temp) {
54 allowedFlags = new RegExp(`[${temp}]`, "giu");
55 }
56 }
57
58 /**
59 * Check if node is a string
60 * @param {ASTNode} node node to evaluate
61 * @returns {boolean} True if its a string
62 * @private
63 */
64 function isString(node) {
65 return node && node.type === "Literal" && typeof node.value === "string";
66 }
67
68 /**
69 * Check syntax error in a given pattern.
70 * @param {string} pattern The RegExp pattern to validate.
71 * @param {boolean} uFlag The Unicode flag.
72 * @returns {string|null} The syntax error.
73 */
74 function validateRegExpPattern(pattern, uFlag) {
75 try {
76 validator.validatePattern(pattern, undefined1, undefined1, uFlag);
77 return null;
78 } catch (err) {
79 return err.message;
80 }
81 }
82
83 /**
84 * Check syntax error in a given flags.
85 * @param {string} flags The RegExp flags to validate.
86 * @returns {string|null} The syntax error.
87 */
88 function validateRegExpFlags(flags) {
89 try {
90 validator.validateFlags(flags);
91 return null;
92 } catch (err) {
93 return `Invalid flags supplied to RegExp constructor '${flags}'`;
94 }
95 }
96
97 return {
98 "CallExpression, NewExpression"(node) {
99 if (node.callee.type !== "Identifier" || node.callee.name !== "RegExp" || !isString(node.arguments[0])) {
100 return;
101 }
102 const pattern = node.arguments[0].value;
103 let flags = isString(node.arguments[1]) ? node.arguments[1].value : "";
104
105 if (allowedFlags) {
106 flags = flags.replace(allowedFlags, "");
107 }
108
109 // If flags are unknown, check both are errored or not.
110 const message = validateRegExpFlags(flags) || (
111 flags
112 ? validateRegExpPattern(pattern, flags.indexOf("u") !== -1)
113 : validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false)
114 );
115
116 if (message) {
117 context.report({
118 node,
119 message: "{{message}}.",
120 data: { message }
121 });
122 }
123 }
124 };
125 }
126};