]> git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/no-invalid-regexp.js
import and build new upstream release 7.2.0
[pve-eslint.git] / eslint / lib / rules / no-invalid-regexp.js
1 /**
2 * @fileoverview Validate strings passed to the RegExp constructor
3 * @author Michael Ficarra
4 */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Requirements
9 //------------------------------------------------------------------------------
10
11 const RegExpValidator = require("regexpp").RegExpValidator;
12 const validator = new RegExpValidator({ ecmaVersion: 2018 });
13 const validFlags = /[gimuys]/gu;
14 const undefined1 = void 0;
15
16 //------------------------------------------------------------------------------
17 // Rule Definition
18 //------------------------------------------------------------------------------
19
20 module.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 messages: {
45 regexMessage: "{{message}}."
46 }
47 },
48
49 create(context) {
50
51 const options = context.options[0];
52 let allowedFlags = null;
53
54 if (options && options.allowConstructorFlags) {
55 const temp = options.allowConstructorFlags.join("").replace(validFlags, "");
56
57 if (temp) {
58 allowedFlags = new RegExp(`[${temp}]`, "giu");
59 }
60 }
61
62 /**
63 * Check if node is a string
64 * @param {ASTNode} node node to evaluate
65 * @returns {boolean} True if its a string
66 * @private
67 */
68 function isString(node) {
69 return node && node.type === "Literal" && typeof node.value === "string";
70 }
71
72 /**
73 * Check syntax error in a given pattern.
74 * @param {string} pattern The RegExp pattern to validate.
75 * @param {boolean} uFlag The Unicode flag.
76 * @returns {string|null} The syntax error.
77 */
78 function validateRegExpPattern(pattern, uFlag) {
79 try {
80 validator.validatePattern(pattern, undefined1, undefined1, uFlag);
81 return null;
82 } catch (err) {
83 return err.message;
84 }
85 }
86
87 /**
88 * Check syntax error in a given flags.
89 * @param {string} flags The RegExp flags to validate.
90 * @returns {string|null} The syntax error.
91 */
92 function validateRegExpFlags(flags) {
93 try {
94 validator.validateFlags(flags);
95 return null;
96 } catch {
97 return `Invalid flags supplied to RegExp constructor '${flags}'`;
98 }
99 }
100
101 return {
102 "CallExpression, NewExpression"(node) {
103 if (node.callee.type !== "Identifier" || node.callee.name !== "RegExp" || !isString(node.arguments[0])) {
104 return;
105 }
106 const pattern = node.arguments[0].value;
107 let flags = isString(node.arguments[1]) ? node.arguments[1].value : "";
108
109 if (allowedFlags) {
110 flags = flags.replace(allowedFlags, "");
111 }
112
113 // If flags are unknown, check both are errored or not.
114 const message = validateRegExpFlags(flags) || (
115 flags
116 ? validateRegExpPattern(pattern, flags.indexOf("u") !== -1)
117 : validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false)
118 );
119
120 if (message) {
121 context.report({
122 node,
123 messageId: "regexMessage",
124 data: { message }
125 });
126 }
127 }
128 };
129 }
130 };