1 | /**
|
2 | * @fileoverview Look for useless escapes in strings and regexes
|
3 | * @author Onur Temizkan
|
4 | */
|
5 |
|
6 | ;
|
7 |
|
8 | //------------------------------------------------------------------------------
|
9 | // Rule Definition
|
10 | //------------------------------------------------------------------------------
|
11 |
|
12 | const VALID_STRING_ESCAPES = [
|
13 | "\\",
|
14 | "n",
|
15 | "r",
|
16 | "v",
|
17 | "t",
|
18 | "b",
|
19 | "f",
|
20 | "u",
|
21 | "x",
|
22 | "\n",
|
23 | "\r"
|
24 | ];
|
25 |
|
26 | const VALID_REGEX_ESCAPES = [
|
27 | "\\",
|
28 | ".",
|
29 | "-",
|
30 | "^",
|
31 | "$",
|
32 | "*",
|
33 | "+",
|
34 | "?",
|
35 | "{",
|
36 | "}",
|
37 | "[",
|
38 | "]",
|
39 | "|",
|
40 | "(",
|
41 | ")",
|
42 | "b",
|
43 | "B",
|
44 | "c",
|
45 | "d",
|
46 | "D",
|
47 | "f",
|
48 | "n",
|
49 | "r",
|
50 | "s",
|
51 | "S",
|
52 | "t",
|
53 | "v",
|
54 | "w",
|
55 | "W",
|
56 | "x",
|
57 | "u"
|
58 | ];
|
59 |
|
60 | module.exports = {
|
61 | meta: {
|
62 | docs: {
|
63 | description: "disallow unnecessary escape characters",
|
64 | category: "Best Practices",
|
65 | recommended: false
|
66 | },
|
67 |
|
68 | schema: []
|
69 | },
|
70 |
|
71 | create(context) {
|
72 |
|
73 | /**
|
74 | * Checks if the escape character in given slice is unnecessary.
|
75 | *
|
76 | * @private
|
77 | * @param {string[]} escapes - list of valid escapes
|
78 | * @param {ASTNode} node - node to validate.
|
79 | * @param {string} elm - string slice to validate.
|
80 | * @returns {void}
|
81 | */
|
82 | function validate(escapes, node, elm) {
|
83 | const escapeNotFound = escapes.indexOf(elm[0][1]) === -1;
|
84 | const isQuoteEscape = elm[0][1] === node.raw[0];
|
85 |
|
86 | if (escapeNotFound && !isQuoteEscape) {
|
87 | context.report({
|
88 | node,
|
89 | loc: {
|
90 | line: node.loc.start.line,
|
91 | column: node.loc.start.column + elm.index
|
92 | },
|
93 | message: "Unnecessary escape character: {{character}}.",
|
94 | data: {
|
95 | character: elm[0]
|
96 | }
|
97 | });
|
98 | }
|
99 | }
|
100 |
|
101 | /**
|
102 | * Checks if a node has an escape.
|
103 | *
|
104 | * @param {ASTNode} node - node to check.
|
105 | * @returns {void}
|
106 | */
|
107 | function check(node) {
|
108 | let nodeEscapes, match;
|
109 | const pattern = /\\[^\d]/g;
|
110 |
|
111 | if (typeof node.value === "string") {
|
112 |
|
113 | // JSXAttribute doesn't have any escape sequence: https://facebook.github.io/jsx/
|
114 | if (node.parent.type === "JSXAttribute") {
|
115 | return;
|
116 | }
|
117 |
|
118 | nodeEscapes = VALID_STRING_ESCAPES;
|
119 | } else if (node.regex) {
|
120 | nodeEscapes = VALID_REGEX_ESCAPES;
|
121 | } else {
|
122 | return;
|
123 | }
|
124 |
|
125 | while ((match = pattern.exec(node.raw))) {
|
126 | validate(nodeEscapes, node, match);
|
127 | }
|
128 | }
|
129 | return {
|
130 | Literal: check
|
131 | };
|
132 | }
|
133 | };
|