UNPKG

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