2 * @fileoverview Rule to forbid control charactes from regular expressions.
3 * @author Nicholas C. Zakas
8 const RegExpValidator = require("regexpp").RegExpValidator;
9 const collector = new (class {
11 this.ecmaVersion = 2018;
13 this._controlChars = [];
14 this._validator = new RegExpValidator(this);
18 this._controlChars = [];
21 onCharacter(start, end, cp) {
25 this._source.codePointAt(start) === cp ||
26 this._source.slice(start, end).startsWith("\\x") ||
27 this._source.slice(start, end).startsWith("\\u")
30 this._controlChars.push(`\\x${`0${cp.toString(16)}`.slice(-2)}`);
34 collectControlChars(regexpStr) {
36 this._source = regexpStr;
37 this._validator.validatePattern(regexpStr); // Call onCharacter hook
40 // Ignore syntax errors in RegExp.
42 return this._controlChars;
46 //------------------------------------------------------------------------------
48 //------------------------------------------------------------------------------
55 description: "disallow control characters in regular expressions",
56 category: "Possible Errors",
58 url: "https://eslint.org/docs/rules/no-control-regex"
64 unexpected: "Unexpected control character(s) in regular expression: {{controlChars}}."
71 * Get the regex expression
72 * @param {ASTNode} node node to evaluate
73 * @returns {RegExp|null} Regex if found else null
76 function getRegExpPattern(node) {
78 return node.regex.pattern;
80 if (typeof node.value === "string" &&
81 (node.parent.type === "NewExpression" || node.parent.type === "CallExpression") &&
82 node.parent.callee.type === "Identifier" &&
83 node.parent.callee.name === "RegExp" &&
84 node.parent.arguments[0] === node
94 const pattern = getRegExpPattern(node);
97 const controlCharacters = collector.collectControlChars(pattern);
99 if (controlCharacters.length > 0) {
102 messageId: "unexpected",
104 controlChars: controlCharacters.join(", ")