/
prefer-regex-literals.js
109 lines (93 loc) · 3.62 KB
/
prefer-regex-literals.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/**
* @fileoverview Rule to disallow use of the `RegExp` constructor in favor of regular expression literals
* @author Milos Djermanovic
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
const { CALL, CONSTRUCT, ReferenceTracker } = require("eslint-utils");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/**
* Determines whether the given node is a string literal.
* @param {ASTNode} node Node to check.
* @returns {boolean} True if the node is a string literal.
*/
function isStringLiteral(node) {
return node.type === "Literal" && typeof node.value === "string";
}
/**
* Determines whether the given node is a template literal without expressions.
* @param {ASTNode} node Node to check.
* @returns {boolean} True if the node is a template literal without expressions.
*/
function isStaticTemplateLiteral(node) {
return node.type === "TemplateLiteral" && node.expressions.length === 0;
}
/**
* Determines whether the given node is a String.raw`` tagged template expression
* with a static template literal.
* @param {ASTNode} node Node to check.
* @returns {boolean} True if the node is String.raw`` with a static template.
*/
function isStringRawTaggedStaticTemplateLiteral(node) {
return node.type === "TaggedTemplateExpression" &&
node.tag.type === "MemberExpression" &&
node.tag.object.type === "Identifier" && node.tag.object.name === "String" &&
astUtils.getStaticPropertyName(node.tag) === "raw" &&
isStaticTemplateLiteral(node.quasi);
}
/**
* Determines whether the given node is considered to be a static string by the logic of this rule.
* @param {ASTNode} node Node to check.
* @returns {boolean} True if the node is a static string.
*/
function isStaticString(node) {
return isStringLiteral(node) ||
isStaticTemplateLiteral(node) ||
isStringRawTaggedStaticTemplateLiteral(node);
}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "disallow use of the `RegExp` constructor in favor of regular expression literals",
category: "Best Practices",
recommended: false,
url: "https://eslint.org/docs/rules/prefer-regex-literals"
},
schema: [],
messages: {
unexpectedRegExp: "Use a regular expression literal instead of the 'RegExp' constructor."
}
},
create(context) {
return {
Program() {
const scope = context.getScope();
const tracker = new ReferenceTracker(scope);
const traceMap = {
RegExp: {
[CALL]: true,
[CONSTRUCT]: true
}
};
for (const { node } of tracker.iterateGlobalReferences(traceMap)) {
const args = node.arguments;
if (
(args.length === 1 || args.length === 2) &&
args.every(isStaticString)
) {
context.report({ node, messageId: "unexpectedRegExp" });
}
}
}
};
}
};