Actualizacion maquina principal
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / capitalized-comments.js
diff --git a/.config/coc/extensions/node_modules/coc-prettier/node_modules/eslint/lib/rules/capitalized-comments.js b/.config/coc/extensions/node_modules/coc-prettier/node_modules/eslint/lib/rules/capitalized-comments.js
new file mode 100644 (file)
index 0000000..d7524b8
--- /dev/null
@@ -0,0 +1,300 @@
+/**
+ * @fileoverview enforce or disallow capitalization of the first letter of a comment
+ * @author Kevin Partington
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const LETTER_PATTERN = require("./utils/patterns/letters");
+const astUtils = require("./utils/ast-utils");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const DEFAULT_IGNORE_PATTERN = astUtils.COMMENTS_IGNORE_PATTERN,
+    WHITESPACE = /\s/gu,
+    MAYBE_URL = /^\s*[^:/?#\s]+:\/\/[^?#]/u; // TODO: Combine w/ max-len pattern?
+
+/*
+ * Base schema body for defining the basic capitalization rule, ignorePattern,
+ * and ignoreInlineComments values.
+ * This can be used in a few different ways in the actual schema.
+ */
+const SCHEMA_BODY = {
+    type: "object",
+    properties: {
+        ignorePattern: {
+            type: "string"
+        },
+        ignoreInlineComments: {
+            type: "boolean"
+        },
+        ignoreConsecutiveComments: {
+            type: "boolean"
+        }
+    },
+    additionalProperties: false
+};
+const DEFAULTS = {
+    ignorePattern: "",
+    ignoreInlineComments: false,
+    ignoreConsecutiveComments: false
+};
+
+/**
+ * Get normalized options for either block or line comments from the given
+ * user-provided options.
+ * - If the user-provided options is just a string, returns a normalized
+ *   set of options using default values for all other options.
+ * - If the user-provided options is an object, then a normalized option
+ *   set is returned. Options specified in overrides will take priority
+ *   over options specified in the main options object, which will in
+ *   turn take priority over the rule's defaults.
+ * @param {Object|string} rawOptions The user-provided options.
+ * @param {string} which Either "line" or "block".
+ * @returns {Object} The normalized options.
+ */
+function getNormalizedOptions(rawOptions, which) {
+    return Object.assign({}, DEFAULTS, rawOptions[which] || rawOptions);
+}
+
+/**
+ * Get normalized options for block and line comments.
+ * @param {Object|string} rawOptions The user-provided options.
+ * @returns {Object} An object with "Line" and "Block" keys and corresponding
+ * normalized options objects.
+ */
+function getAllNormalizedOptions(rawOptions = {}) {
+    return {
+        Line: getNormalizedOptions(rawOptions, "line"),
+        Block: getNormalizedOptions(rawOptions, "block")
+    };
+}
+
+/**
+ * Creates a regular expression for each ignorePattern defined in the rule
+ * options.
+ *
+ * This is done in order to avoid invoking the RegExp constructor repeatedly.
+ * @param {Object} normalizedOptions The normalized rule options.
+ * @returns {void}
+ */
+function createRegExpForIgnorePatterns(normalizedOptions) {
+    Object.keys(normalizedOptions).forEach(key => {
+        const ignorePatternStr = normalizedOptions[key].ignorePattern;
+
+        if (ignorePatternStr) {
+            const regExp = RegExp(`^\\s*(?:${ignorePatternStr})`, "u");
+
+            normalizedOptions[key].ignorePatternRegExp = regExp;
+        }
+    });
+}
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+    meta: {
+        type: "suggestion",
+
+        docs: {
+            description: "enforce or disallow capitalization of the first letter of a comment",
+            category: "Stylistic Issues",
+            recommended: false,
+            url: "https://eslint.org/docs/rules/capitalized-comments"
+        },
+
+        fixable: "code",
+
+        schema: [
+            { enum: ["always", "never"] },
+            {
+                oneOf: [
+                    SCHEMA_BODY,
+                    {
+                        type: "object",
+                        properties: {
+                            line: SCHEMA_BODY,
+                            block: SCHEMA_BODY
+                        },
+                        additionalProperties: false
+                    }
+                ]
+            }
+        ],
+
+        messages: {
+            unexpectedLowercaseComment: "Comments should not begin with a lowercase character.",
+            unexpectedUppercaseComment: "Comments should not begin with an uppercase character."
+        }
+    },
+
+    create(context) {
+
+        const capitalize = context.options[0] || "always",
+            normalizedOptions = getAllNormalizedOptions(context.options[1]),
+            sourceCode = context.getSourceCode();
+
+        createRegExpForIgnorePatterns(normalizedOptions);
+
+        //----------------------------------------------------------------------
+        // Helpers
+        //----------------------------------------------------------------------
+
+        /**
+         * Checks whether a comment is an inline comment.
+         *
+         * For the purpose of this rule, a comment is inline if:
+         * 1. The comment is preceded by a token on the same line; and
+         * 2. The command is followed by a token on the same line.
+         *
+         * Note that the comment itself need not be single-line!
+         *
+         * Also, it follows from this definition that only block comments can
+         * be considered as possibly inline. This is because line comments
+         * would consume any following tokens on the same line as the comment.
+         * @param {ASTNode} comment The comment node to check.
+         * @returns {boolean} True if the comment is an inline comment, false
+         * otherwise.
+         */
+        function isInlineComment(comment) {
+            const previousToken = sourceCode.getTokenBefore(comment, { includeComments: true }),
+                nextToken = sourceCode.getTokenAfter(comment, { includeComments: true });
+
+            return Boolean(
+                previousToken &&
+                nextToken &&
+                comment.loc.start.line === previousToken.loc.end.line &&
+                comment.loc.end.line === nextToken.loc.start.line
+            );
+        }
+
+        /**
+         * Determine if a comment follows another comment.
+         * @param {ASTNode} comment The comment to check.
+         * @returns {boolean} True if the comment follows a valid comment.
+         */
+        function isConsecutiveComment(comment) {
+            const previousTokenOrComment = sourceCode.getTokenBefore(comment, { includeComments: true });
+
+            return Boolean(
+                previousTokenOrComment &&
+                ["Block", "Line"].indexOf(previousTokenOrComment.type) !== -1
+            );
+        }
+
+        /**
+         * Check a comment to determine if it is valid for this rule.
+         * @param {ASTNode} comment The comment node to process.
+         * @param {Object} options The options for checking this comment.
+         * @returns {boolean} True if the comment is valid, false otherwise.
+         */
+        function isCommentValid(comment, options) {
+
+            // 1. Check for default ignore pattern.
+            if (DEFAULT_IGNORE_PATTERN.test(comment.value)) {
+                return true;
+            }
+
+            // 2. Check for custom ignore pattern.
+            const commentWithoutAsterisks = comment.value
+                .replace(/\*/gu, "");
+
+            if (options.ignorePatternRegExp && options.ignorePatternRegExp.test(commentWithoutAsterisks)) {
+                return true;
+            }
+
+            // 3. Check for inline comments.
+            if (options.ignoreInlineComments && isInlineComment(comment)) {
+                return true;
+            }
+
+            // 4. Is this a consecutive comment (and are we tolerating those)?
+            if (options.ignoreConsecutiveComments && isConsecutiveComment(comment)) {
+                return true;
+            }
+
+            // 5. Does the comment start with a possible URL?
+            if (MAYBE_URL.test(commentWithoutAsterisks)) {
+                return true;
+            }
+
+            // 6. Is the initial word character a letter?
+            const commentWordCharsOnly = commentWithoutAsterisks
+                .replace(WHITESPACE, "");
+
+            if (commentWordCharsOnly.length === 0) {
+                return true;
+            }
+
+            const firstWordChar = commentWordCharsOnly[0];
+
+            if (!LETTER_PATTERN.test(firstWordChar)) {
+                return true;
+            }
+
+            // 7. Check the case of the initial word character.
+            const isUppercase = firstWordChar !== firstWordChar.toLocaleLowerCase(),
+                isLowercase = firstWordChar !== firstWordChar.toLocaleUpperCase();
+
+            if (capitalize === "always" && isLowercase) {
+                return false;
+            }
+            if (capitalize === "never" && isUppercase) {
+                return false;
+            }
+
+            return true;
+        }
+
+        /**
+         * Process a comment to determine if it needs to be reported.
+         * @param {ASTNode} comment The comment node to process.
+         * @returns {void}
+         */
+        function processComment(comment) {
+            const options = normalizedOptions[comment.type],
+                commentValid = isCommentValid(comment, options);
+
+            if (!commentValid) {
+                const messageId = capitalize === "always"
+                    ? "unexpectedLowercaseComment"
+                    : "unexpectedUppercaseComment";
+
+                context.report({
+                    node: null, // Intentionally using loc instead
+                    loc: comment.loc,
+                    messageId,
+                    fix(fixer) {
+                        const match = comment.value.match(LETTER_PATTERN);
+
+                        return fixer.replaceTextRange(
+
+                            // Offset match.index by 2 to account for the first 2 characters that start the comment (// or /*)
+                            [comment.range[0] + match.index + 2, comment.range[0] + match.index + 3],
+                            capitalize === "always" ? match[0].toLocaleUpperCase() : match[0].toLocaleLowerCase()
+                        );
+                    }
+                });
+            }
+        }
+
+        //----------------------------------------------------------------------
+        // Public
+        //----------------------------------------------------------------------
+
+        return {
+            Program() {
+                const comments = sourceCode.getAllComments();
+
+                comments.filter(token => token.type !== "Shebang").forEach(processComment);
+            }
+        };
+    }
+};