summaryrefslogtreecommitdiff
path: root/tools/node_modules/eslint/lib/rules/capitalized-comments.js
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2017-12-22 16:53:42 +0100
committerMichaël Zasso <targos@protonmail.com>2018-01-11 09:48:05 +0100
commit3dc30632755713179f345f4af024bd904c6162d0 (patch)
treef28c4f6dd6dfc5992edf301449d1a371d229755b /tools/node_modules/eslint/lib/rules/capitalized-comments.js
parenta2c7085dd4a8e60d1a47572aca8bb6fcb7a32f88 (diff)
downloadandroid-node-v8-3dc30632755713179f345f4af024bd904c6162d0.tar.gz
android-node-v8-3dc30632755713179f345f4af024bd904c6162d0.tar.bz2
android-node-v8-3dc30632755713179f345f4af024bd904c6162d0.zip
tools: move eslint from tools to tools/node_modules
This is required because we need to add the babel-eslint dependency and it has to be able to resolve "eslint". babel-eslint is required to support future ES features such as async iterators and import.meta. Refs: https://github.com/nodejs/node/pull/17755 PR-URL: https://github.com/nodejs/node/pull/17820 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Diffstat (limited to 'tools/node_modules/eslint/lib/rules/capitalized-comments.js')
-rw-r--r--tools/node_modules/eslint/lib/rules/capitalized-comments.js303
1 files changed, 303 insertions, 0 deletions
diff --git a/tools/node_modules/eslint/lib/rules/capitalized-comments.js b/tools/node_modules/eslint/lib/rules/capitalized-comments.js
new file mode 100644
index 0000000000..1a27608067
--- /dev/null
+++ b/tools/node_modules/eslint/lib/rules/capitalized-comments.js
@@ -0,0 +1,303 @@
+/**
+ * @fileoverview enforce or disallow capitalization of the first letter of a comment
+ * @author Kevin Partington
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const LETTER_PATTERN = require("../util/patterns/letters");
+const astUtils = require("../ast-utils");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const ALWAYS_MESSAGE = "Comments should not begin with a lowercase character",
+ NEVER_MESSAGE = "Comments should not begin with an uppercase character",
+ DEFAULT_IGNORE_PATTERN = astUtils.COMMENTS_IGNORE_PATTERN,
+ WHITESPACE = /\s/g,
+ MAYBE_URL = /^\s*[^:/?#\s]+:\/\/[^?#]/, // TODO: Combine w/ max-len pattern?
+ DEFAULTS = {
+ ignorePattern: null,
+ ignoreInlineComments: false,
+ ignoreConsecutiveComments: false
+ };
+
+/*
+ * 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
+};
+
+/**
+ * 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) {
+ if (!rawOptions) {
+ return Object.assign({}, DEFAULTS);
+ }
+
+ 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})`);
+
+ normalizedOptions[key].ignorePatternRegExp = regExp;
+ }
+ });
+}
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+ meta: {
+ docs: {
+ description: "enforce or disallow capitalization of the first letter of a comment",
+ category: "Stylistic Issues",
+ recommended: false
+ },
+ fixable: "code",
+ schema: [
+ { enum: ["always", "never"] },
+ {
+ oneOf: [
+ SCHEMA_BODY,
+ {
+ type: "object",
+ properties: {
+ line: SCHEMA_BODY,
+ block: SCHEMA_BODY
+ },
+ additionalProperties: false
+ }
+ ]
+ }
+ ]
+ },
+
+ 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(/\*/g, "");
+
+ 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 message = capitalize === "always"
+ ? ALWAYS_MESSAGE
+ : NEVER_MESSAGE;
+
+ context.report({
+ node: null, // Intentionally using loc instead
+ loc: comment.loc,
+ message,
+ 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);
+ }
+ };
+ }
+};