.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / no-nonoctal-decimal-escape.js
diff --git a/.config/coc/extensions/node_modules/coc-prettier/node_modules/eslint/lib/rules/no-nonoctal-decimal-escape.js b/.config/coc/extensions/node_modules/coc-prettier/node_modules/eslint/lib/rules/no-nonoctal-decimal-escape.js
new file mode 100644 (file)
index 0000000..a4b46d9
--- /dev/null
@@ -0,0 +1,147 @@
+/**
+ * @fileoverview Rule to disallow `\8` and `\9` escape sequences in string literals.
+ * @author Milos Djermanovic
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const QUICK_TEST_REGEX = /\\[89]/u;
+
+/**
+ * Returns unicode escape sequence that represents the given character.
+ * @param {string} character A single code unit.
+ * @returns {string} "\uXXXX" sequence.
+ */
+function getUnicodeEscape(character) {
+    return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
+}
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+    meta: {
+        type: "suggestion",
+
+        docs: {
+            description: "disallow `\\8` and `\\9` escape sequences in string literals",
+            category: "Best Practices",
+            recommended: false,
+            url: "https://eslint.org/docs/rules/no-nonoctal-decimal-escape",
+            suggestion: true
+        },
+
+        schema: [],
+
+        messages: {
+            decimalEscape: "Don't use '{{decimalEscape}}' escape sequence.",
+
+            // suggestions
+            refactor: "Replace '{{original}}' with '{{replacement}}'. This maintains the current functionality.",
+            escapeBackslash: "Replace '{{original}}' with '{{replacement}}' to include the actual backslash character."
+        }
+    },
+
+    create(context) {
+        const sourceCode = context.getSourceCode();
+
+        /**
+         * Creates a new Suggestion object.
+         * @param {string} messageId "refactor" or "escapeBackslash".
+         * @param {int[]} range The range to replace.
+         * @param {string} replacement New text for the range.
+         * @returns {Object} Suggestion
+         */
+        function createSuggestion(messageId, range, replacement) {
+            return {
+                messageId,
+                data: {
+                    original: sourceCode.getText().slice(...range),
+                    replacement
+                },
+                fix(fixer) {
+                    return fixer.replaceTextRange(range, replacement);
+                }
+            };
+        }
+
+        return {
+            Literal(node) {
+                if (typeof node.value !== "string") {
+                    return;
+                }
+
+                if (!QUICK_TEST_REGEX.test(node.raw)) {
+                    return;
+                }
+
+                const regex = /(?:[^\\]|(?<previousEscape>\\.))*?(?<decimalEscape>\\[89])/suy;
+                let match;
+
+                while ((match = regex.exec(node.raw))) {
+                    const { previousEscape, decimalEscape } = match.groups;
+                    const decimalEscapeRangeEnd = node.range[0] + match.index + match[0].length;
+                    const decimalEscapeRangeStart = decimalEscapeRangeEnd - decimalEscape.length;
+                    const decimalEscapeRange = [decimalEscapeRangeStart, decimalEscapeRangeEnd];
+                    const suggest = [];
+
+                    // When `regex` is matched, `previousEscape` can only capture characters adjacent to `decimalEscape`
+                    if (previousEscape === "\\0") {
+
+                        /*
+                         * Now we have a NULL escape "\0" immediately followed by a decimal escape, e.g.: "\0\8".
+                         * Fixing this to "\08" would turn "\0" into a legacy octal escape. To avoid producing
+                         * an octal escape while fixing a decimal escape, we provide different suggestions.
+                         */
+                        suggest.push(
+                            createSuggestion( // "\0\8" -> "\u00008"
+                                "refactor",
+                                [decimalEscapeRangeStart - previousEscape.length, decimalEscapeRangeEnd],
+                                `${getUnicodeEscape("\0")}${decimalEscape[1]}`
+                            ),
+                            createSuggestion( // "\8" -> "\u0038"
+                                "refactor",
+                                decimalEscapeRange,
+                                getUnicodeEscape(decimalEscape[1])
+                            )
+                        );
+                    } else {
+                        suggest.push(
+                            createSuggestion( // "\8" -> "8"
+                                "refactor",
+                                decimalEscapeRange,
+                                decimalEscape[1]
+                            )
+                        );
+                    }
+
+                    suggest.push(
+                        createSuggestion( // "\8" -> "\\8"
+                            "escapeBackslash",
+                            decimalEscapeRange,
+                            `\\${decimalEscape}`
+                        )
+                    );
+
+                    context.report({
+                        node,
+                        loc: {
+                            start: sourceCode.getLocFromIndex(decimalEscapeRangeStart),
+                            end: sourceCode.getLocFromIndex(decimalEscapeRangeEnd)
+                        },
+                        messageId: "decimalEscape",
+                        data: {
+                            decimalEscape
+                        },
+                        suggest
+                    });
+                }
+            }
+        };
+    }
+};