.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / no-nonoctal-decimal-escape.js
1 /**
2  * @fileoverview Rule to disallow `\8` and `\9` escape sequences in string literals.
3  * @author Milos Djermanovic
4  */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Helpers
10 //------------------------------------------------------------------------------
11
12 const QUICK_TEST_REGEX = /\\[89]/u;
13
14 /**
15  * Returns unicode escape sequence that represents the given character.
16  * @param {string} character A single code unit.
17  * @returns {string} "\uXXXX" sequence.
18  */
19 function getUnicodeEscape(character) {
20     return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
21 }
22
23 //------------------------------------------------------------------------------
24 // Rule Definition
25 //------------------------------------------------------------------------------
26
27 module.exports = {
28     meta: {
29         type: "suggestion",
30
31         docs: {
32             description: "disallow `\\8` and `\\9` escape sequences in string literals",
33             category: "Best Practices",
34             recommended: false,
35             url: "https://eslint.org/docs/rules/no-nonoctal-decimal-escape",
36             suggestion: true
37         },
38
39         schema: [],
40
41         messages: {
42             decimalEscape: "Don't use '{{decimalEscape}}' escape sequence.",
43
44             // suggestions
45             refactor: "Replace '{{original}}' with '{{replacement}}'. This maintains the current functionality.",
46             escapeBackslash: "Replace '{{original}}' with '{{replacement}}' to include the actual backslash character."
47         }
48     },
49
50     create(context) {
51         const sourceCode = context.getSourceCode();
52
53         /**
54          * Creates a new Suggestion object.
55          * @param {string} messageId "refactor" or "escapeBackslash".
56          * @param {int[]} range The range to replace.
57          * @param {string} replacement New text for the range.
58          * @returns {Object} Suggestion
59          */
60         function createSuggestion(messageId, range, replacement) {
61             return {
62                 messageId,
63                 data: {
64                     original: sourceCode.getText().slice(...range),
65                     replacement
66                 },
67                 fix(fixer) {
68                     return fixer.replaceTextRange(range, replacement);
69                 }
70             };
71         }
72
73         return {
74             Literal(node) {
75                 if (typeof node.value !== "string") {
76                     return;
77                 }
78
79                 if (!QUICK_TEST_REGEX.test(node.raw)) {
80                     return;
81                 }
82
83                 const regex = /(?:[^\\]|(?<previousEscape>\\.))*?(?<decimalEscape>\\[89])/suy;
84                 let match;
85
86                 while ((match = regex.exec(node.raw))) {
87                     const { previousEscape, decimalEscape } = match.groups;
88                     const decimalEscapeRangeEnd = node.range[0] + match.index + match[0].length;
89                     const decimalEscapeRangeStart = decimalEscapeRangeEnd - decimalEscape.length;
90                     const decimalEscapeRange = [decimalEscapeRangeStart, decimalEscapeRangeEnd];
91                     const suggest = [];
92
93                     // When `regex` is matched, `previousEscape` can only capture characters adjacent to `decimalEscape`
94                     if (previousEscape === "\\0") {
95
96                         /*
97                          * Now we have a NULL escape "\0" immediately followed by a decimal escape, e.g.: "\0\8".
98                          * Fixing this to "\08" would turn "\0" into a legacy octal escape. To avoid producing
99                          * an octal escape while fixing a decimal escape, we provide different suggestions.
100                          */
101                         suggest.push(
102                             createSuggestion( // "\0\8" -> "\u00008"
103                                 "refactor",
104                                 [decimalEscapeRangeStart - previousEscape.length, decimalEscapeRangeEnd],
105                                 `${getUnicodeEscape("\0")}${decimalEscape[1]}`
106                             ),
107                             createSuggestion( // "\8" -> "\u0038"
108                                 "refactor",
109                                 decimalEscapeRange,
110                                 getUnicodeEscape(decimalEscape[1])
111                             )
112                         );
113                     } else {
114                         suggest.push(
115                             createSuggestion( // "\8" -> "8"
116                                 "refactor",
117                                 decimalEscapeRange,
118                                 decimalEscape[1]
119                             )
120                         );
121                     }
122
123                     suggest.push(
124                         createSuggestion( // "\8" -> "\\8"
125                             "escapeBackslash",
126                             decimalEscapeRange,
127                             `\\${decimalEscape}`
128                         )
129                     );
130
131                     context.report({
132                         node,
133                         loc: {
134                             start: sourceCode.getLocFromIndex(decimalEscapeRangeStart),
135                             end: sourceCode.getLocFromIndex(decimalEscapeRangeEnd)
136                         },
137                         messageId: "decimalEscape",
138                         data: {
139                             decimalEscape
140                         },
141                         suggest
142                     });
143                 }
144             }
145         };
146     }
147 };