]> git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/no-control-regex.js
04f3449fb1931e0e140a6734c20ccd8ff0eae967
[pve-eslint.git] / eslint / lib / rules / no-control-regex.js
1 /**
2 * @fileoverview Rule to forbid control characters from regular expressions.
3 * @author Nicholas C. Zakas
4 */
5
6 "use strict";
7
8 const RegExpValidator = require("regexpp").RegExpValidator;
9 const collector = new (class {
10 constructor() {
11 this._source = "";
12 this._controlChars = [];
13 this._validator = new RegExpValidator(this);
14 }
15
16 onPatternEnter() {
17 this._controlChars = [];
18 }
19
20 onCharacter(start, end, cp) {
21 if (cp >= 0x00 &&
22 cp <= 0x1F &&
23 (
24 this._source.codePointAt(start) === cp ||
25 this._source.slice(start, end).startsWith("\\x") ||
26 this._source.slice(start, end).startsWith("\\u")
27 )
28 ) {
29 this._controlChars.push(`\\x${`0${cp.toString(16)}`.slice(-2)}`);
30 }
31 }
32
33 collectControlChars(regexpStr) {
34 try {
35 this._source = regexpStr;
36 this._validator.validatePattern(regexpStr); // Call onCharacter hook
37 } catch {
38
39 // Ignore syntax errors in RegExp.
40 }
41 return this._controlChars;
42 }
43 })();
44
45 //------------------------------------------------------------------------------
46 // Rule Definition
47 //------------------------------------------------------------------------------
48
49 /** @type {import('../shared/types').Rule} */
50 module.exports = {
51 meta: {
52 type: "problem",
53
54 docs: {
55 description: "disallow control characters in regular expressions",
56 recommended: true,
57 url: "https://eslint.org/docs/rules/no-control-regex"
58 },
59
60 schema: [],
61
62 messages: {
63 unexpected: "Unexpected control character(s) in regular expression: {{controlChars}}."
64 }
65 },
66
67 create(context) {
68
69 /**
70 * Get the regex expression
71 * @param {ASTNode} node node to evaluate
72 * @returns {RegExp|null} Regex if found else null
73 * @private
74 */
75 function getRegExpPattern(node) {
76 if (node.regex) {
77 return node.regex.pattern;
78 }
79 if (typeof node.value === "string" &&
80 (node.parent.type === "NewExpression" || node.parent.type === "CallExpression") &&
81 node.parent.callee.type === "Identifier" &&
82 node.parent.callee.name === "RegExp" &&
83 node.parent.arguments[0] === node
84 ) {
85 return node.value;
86 }
87
88 return null;
89 }
90
91 return {
92 Literal(node) {
93 const pattern = getRegExpPattern(node);
94
95 if (pattern) {
96 const controlCharacters = collector.collectControlChars(pattern);
97
98 if (controlCharacters.length > 0) {
99 context.report({
100 node,
101 messageId: "unexpected",
102 data: {
103 controlChars: controlCharacters.join(", ")
104 }
105 });
106 }
107 }
108 }
109 };
110
111 }
112 };