summaryrefslogtreecommitdiff
path: root/tools/node_modules/eslint/lib/rules/keyword-spacing.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/node_modules/eslint/lib/rules/keyword-spacing.js')
-rw-r--r--tools/node_modules/eslint/lib/rules/keyword-spacing.js584
1 files changed, 584 insertions, 0 deletions
diff --git a/tools/node_modules/eslint/lib/rules/keyword-spacing.js b/tools/node_modules/eslint/lib/rules/keyword-spacing.js
new file mode 100644
index 0000000000..218cfd02be
--- /dev/null
+++ b/tools/node_modules/eslint/lib/rules/keyword-spacing.js
@@ -0,0 +1,584 @@
+/**
+ * @fileoverview Rule to enforce spacing before and after keywords.
+ * @author Toru Nagashima
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const astUtils = require("../ast-utils"),
+ keywords = require("../util/keywords");
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+const PREV_TOKEN = /^[)\]}>]$/;
+const NEXT_TOKEN = /^(?:[([{<~!]|\+\+?|--?)$/;
+const PREV_TOKEN_M = /^[)\]}>*]$/;
+const NEXT_TOKEN_M = /^[{*]$/;
+const TEMPLATE_OPEN_PAREN = /\$\{$/;
+const TEMPLATE_CLOSE_PAREN = /^\}/;
+const CHECK_TYPE = /^(?:JSXElement|RegularExpression|String|Template)$/;
+const KEYS = keywords.concat(["as", "async", "await", "from", "get", "let", "of", "set", "yield"]);
+
+// check duplications.
+(function() {
+ KEYS.sort();
+ for (let i = 1; i < KEYS.length; ++i) {
+ if (KEYS[i] === KEYS[i - 1]) {
+ throw new Error(`Duplication was found in the keyword list: ${KEYS[i]}`);
+ }
+ }
+}());
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+/**
+ * Checks whether or not a given token is a "Template" token ends with "${".
+ *
+ * @param {Token} token - A token to check.
+ * @returns {boolean} `true` if the token is a "Template" token ends with "${".
+ */
+function isOpenParenOfTemplate(token) {
+ return token.type === "Template" && TEMPLATE_OPEN_PAREN.test(token.value);
+}
+
+/**
+ * Checks whether or not a given token is a "Template" token starts with "}".
+ *
+ * @param {Token} token - A token to check.
+ * @returns {boolean} `true` if the token is a "Template" token starts with "}".
+ */
+function isCloseParenOfTemplate(token) {
+ return token.type === "Template" && TEMPLATE_CLOSE_PAREN.test(token.value);
+}
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+ meta: {
+ docs: {
+ description: "enforce consistent spacing before and after keywords",
+ category: "Stylistic Issues",
+ recommended: false
+ },
+
+ fixable: "whitespace",
+
+ schema: [
+ {
+ type: "object",
+ properties: {
+ before: { type: "boolean" },
+ after: { type: "boolean" },
+ overrides: {
+ type: "object",
+ properties: KEYS.reduce((retv, key) => {
+ retv[key] = {
+ type: "object",
+ properties: {
+ before: { type: "boolean" },
+ after: { type: "boolean" }
+ },
+ additionalProperties: false
+ };
+ return retv;
+ }, {}),
+ additionalProperties: false
+ }
+ },
+ additionalProperties: false
+ }
+ ]
+ },
+
+ create(context) {
+ const sourceCode = context.getSourceCode();
+
+ /**
+ * Reports a given token if there are not space(s) before the token.
+ *
+ * @param {Token} token - A token to report.
+ * @param {RegExp|undefined} pattern - Optional. A pattern of the previous
+ * token to check.
+ * @returns {void}
+ */
+ function expectSpaceBefore(token, pattern) {
+ pattern = pattern || PREV_TOKEN;
+
+ const prevToken = sourceCode.getTokenBefore(token);
+
+ if (prevToken &&
+ (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) &&
+ !isOpenParenOfTemplate(prevToken) &&
+ astUtils.isTokenOnSameLine(prevToken, token) &&
+ !sourceCode.isSpaceBetweenTokens(prevToken, token)
+ ) {
+ context.report({
+ loc: token.loc.start,
+ message: "Expected space(s) before \"{{value}}\".",
+ data: token,
+ fix(fixer) {
+ return fixer.insertTextBefore(token, " ");
+ }
+ });
+ }
+ }
+
+ /**
+ * Reports a given token if there are space(s) before the token.
+ *
+ * @param {Token} token - A token to report.
+ * @param {RegExp|undefined} pattern - Optional. A pattern of the previous
+ * token to check.
+ * @returns {void}
+ */
+ function unexpectSpaceBefore(token, pattern) {
+ pattern = pattern || PREV_TOKEN;
+
+ const prevToken = sourceCode.getTokenBefore(token);
+
+ if (prevToken &&
+ (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) &&
+ !isOpenParenOfTemplate(prevToken) &&
+ astUtils.isTokenOnSameLine(prevToken, token) &&
+ sourceCode.isSpaceBetweenTokens(prevToken, token)
+ ) {
+ context.report({
+ loc: token.loc.start,
+ message: "Unexpected space(s) before \"{{value}}\".",
+ data: token,
+ fix(fixer) {
+ return fixer.removeRange([prevToken.range[1], token.range[0]]);
+ }
+ });
+ }
+ }
+
+ /**
+ * Reports a given token if there are not space(s) after the token.
+ *
+ * @param {Token} token - A token to report.
+ * @param {RegExp|undefined} pattern - Optional. A pattern of the next
+ * token to check.
+ * @returns {void}
+ */
+ function expectSpaceAfter(token, pattern) {
+ pattern = pattern || NEXT_TOKEN;
+
+ const nextToken = sourceCode.getTokenAfter(token);
+
+ if (nextToken &&
+ (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) &&
+ !isCloseParenOfTemplate(nextToken) &&
+ astUtils.isTokenOnSameLine(token, nextToken) &&
+ !sourceCode.isSpaceBetweenTokens(token, nextToken)
+ ) {
+ context.report({
+ loc: token.loc.start,
+ message: "Expected space(s) after \"{{value}}\".",
+ data: token,
+ fix(fixer) {
+ return fixer.insertTextAfter(token, " ");
+ }
+ });
+ }
+ }
+
+ /**
+ * Reports a given token if there are space(s) after the token.
+ *
+ * @param {Token} token - A token to report.
+ * @param {RegExp|undefined} pattern - Optional. A pattern of the next
+ * token to check.
+ * @returns {void}
+ */
+ function unexpectSpaceAfter(token, pattern) {
+ pattern = pattern || NEXT_TOKEN;
+
+ const nextToken = sourceCode.getTokenAfter(token);
+
+ if (nextToken &&
+ (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) &&
+ !isCloseParenOfTemplate(nextToken) &&
+ astUtils.isTokenOnSameLine(token, nextToken) &&
+ sourceCode.isSpaceBetweenTokens(token, nextToken)
+ ) {
+ context.report({
+ loc: token.loc.start,
+ message: "Unexpected space(s) after \"{{value}}\".",
+ data: token,
+ fix(fixer) {
+ return fixer.removeRange([token.range[1], nextToken.range[0]]);
+ }
+ });
+ }
+ }
+
+ /**
+ * Parses the option object and determines check methods for each keyword.
+ *
+ * @param {Object|undefined} options - The option object to parse.
+ * @returns {Object} - Normalized option object.
+ * Keys are keywords (there are for every keyword).
+ * Values are instances of `{"before": function, "after": function}`.
+ */
+ function parseOptions(options) {
+ const before = !options || options.before !== false;
+ const after = !options || options.after !== false;
+ const defaultValue = {
+ before: before ? expectSpaceBefore : unexpectSpaceBefore,
+ after: after ? expectSpaceAfter : unexpectSpaceAfter
+ };
+ const overrides = (options && options.overrides) || {};
+ const retv = Object.create(null);
+
+ for (let i = 0; i < KEYS.length; ++i) {
+ const key = KEYS[i];
+ const override = overrides[key];
+
+ if (override) {
+ const thisBefore = ("before" in override) ? override.before : before;
+ const thisAfter = ("after" in override) ? override.after : after;
+
+ retv[key] = {
+ before: thisBefore ? expectSpaceBefore : unexpectSpaceBefore,
+ after: thisAfter ? expectSpaceAfter : unexpectSpaceAfter
+ };
+ } else {
+ retv[key] = defaultValue;
+ }
+ }
+
+ return retv;
+ }
+
+ const checkMethodMap = parseOptions(context.options[0]);
+
+ /**
+ * Reports a given token if usage of spacing followed by the token is
+ * invalid.
+ *
+ * @param {Token} token - A token to report.
+ * @param {RegExp|undefined} pattern - Optional. A pattern of the previous
+ * token to check.
+ * @returns {void}
+ */
+ function checkSpacingBefore(token, pattern) {
+ checkMethodMap[token.value].before(token, pattern);
+ }
+
+ /**
+ * Reports a given token if usage of spacing preceded by the token is
+ * invalid.
+ *
+ * @param {Token} token - A token to report.
+ * @param {RegExp|undefined} pattern - Optional. A pattern of the next
+ * token to check.
+ * @returns {void}
+ */
+ function checkSpacingAfter(token, pattern) {
+ checkMethodMap[token.value].after(token, pattern);
+ }
+
+ /**
+ * Reports a given token if usage of spacing around the token is invalid.
+ *
+ * @param {Token} token - A token to report.
+ * @returns {void}
+ */
+ function checkSpacingAround(token) {
+ checkSpacingBefore(token);
+ checkSpacingAfter(token);
+ }
+
+ /**
+ * Reports the first token of a given node if the first token is a keyword
+ * and usage of spacing around the token is invalid.
+ *
+ * @param {ASTNode|null} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingAroundFirstToken(node) {
+ const firstToken = node && sourceCode.getFirstToken(node);
+
+ if (firstToken && firstToken.type === "Keyword") {
+ checkSpacingAround(firstToken);
+ }
+ }
+
+ /**
+ * Reports the first token of a given node if the first token is a keyword
+ * and usage of spacing followed by the token is invalid.
+ *
+ * This is used for unary operators (e.g. `typeof`), `function`, and `super`.
+ * Other rules are handling usage of spacing preceded by those keywords.
+ *
+ * @param {ASTNode|null} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingBeforeFirstToken(node) {
+ const firstToken = node && sourceCode.getFirstToken(node);
+
+ if (firstToken && firstToken.type === "Keyword") {
+ checkSpacingBefore(firstToken);
+ }
+ }
+
+ /**
+ * Reports the previous token of a given node if the token is a keyword and
+ * usage of spacing around the token is invalid.
+ *
+ * @param {ASTNode|null} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingAroundTokenBefore(node) {
+ if (node) {
+ const token = sourceCode.getTokenBefore(node, astUtils.isKeywordToken);
+
+ checkSpacingAround(token);
+ }
+ }
+
+ /**
+ * Reports `async` or `function` keywords of a given node if usage of
+ * spacing around those keywords is invalid.
+ *
+ * @param {ASTNode} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingForFunction(node) {
+ const firstToken = node && sourceCode.getFirstToken(node);
+
+ if (firstToken &&
+ ((firstToken.type === "Keyword" && firstToken.value === "function") ||
+ firstToken.value === "async")
+ ) {
+ checkSpacingBefore(firstToken);
+ }
+ }
+
+ /**
+ * Reports `class` and `extends` keywords of a given node if usage of
+ * spacing around those keywords is invalid.
+ *
+ * @param {ASTNode} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingForClass(node) {
+ checkSpacingAroundFirstToken(node);
+ checkSpacingAroundTokenBefore(node.superClass);
+ }
+
+ /**
+ * Reports `if` and `else` keywords of a given node if usage of spacing
+ * around those keywords is invalid.
+ *
+ * @param {ASTNode} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingForIfStatement(node) {
+ checkSpacingAroundFirstToken(node);
+ checkSpacingAroundTokenBefore(node.alternate);
+ }
+
+ /**
+ * Reports `try`, `catch`, and `finally` keywords of a given node if usage
+ * of spacing around those keywords is invalid.
+ *
+ * @param {ASTNode} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingForTryStatement(node) {
+ checkSpacingAroundFirstToken(node);
+ checkSpacingAroundFirstToken(node.handler);
+ checkSpacingAroundTokenBefore(node.finalizer);
+ }
+
+ /**
+ * Reports `do` and `while` keywords of a given node if usage of spacing
+ * around those keywords is invalid.
+ *
+ * @param {ASTNode} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingForDoWhileStatement(node) {
+ checkSpacingAroundFirstToken(node);
+ checkSpacingAroundTokenBefore(node.test);
+ }
+
+ /**
+ * Reports `for` and `in` keywords of a given node if usage of spacing
+ * around those keywords is invalid.
+ *
+ * @param {ASTNode} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingForForInStatement(node) {
+ checkSpacingAroundFirstToken(node);
+ checkSpacingAroundTokenBefore(node.right);
+ }
+
+ /**
+ * Reports `for` and `of` keywords of a given node if usage of spacing
+ * around those keywords is invalid.
+ *
+ * @param {ASTNode} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingForForOfStatement(node) {
+ checkSpacingAroundFirstToken(node);
+ checkSpacingAround(sourceCode.getTokenBefore(node.right, astUtils.isNotOpeningParenToken));
+ }
+
+ /**
+ * Reports `import`, `export`, `as`, and `from` keywords of a given node if
+ * usage of spacing around those keywords is invalid.
+ *
+ * This rule handles the `*` token in module declarations.
+ *
+ * import*as A from "./a"; /*error Expected space(s) after "import".
+ * error Expected space(s) before "as".
+ *
+ * @param {ASTNode} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingForModuleDeclaration(node) {
+ const firstToken = sourceCode.getFirstToken(node);
+
+ checkSpacingBefore(firstToken, PREV_TOKEN_M);
+ checkSpacingAfter(firstToken, NEXT_TOKEN_M);
+
+ if (node.source) {
+ const fromToken = sourceCode.getTokenBefore(node.source);
+
+ checkSpacingBefore(fromToken, PREV_TOKEN_M);
+ checkSpacingAfter(fromToken, NEXT_TOKEN_M);
+ }
+ }
+
+ /**
+ * Reports `as` keyword of a given node if usage of spacing around this
+ * keyword is invalid.
+ *
+ * @param {ASTNode} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingForImportNamespaceSpecifier(node) {
+ const asToken = sourceCode.getFirstToken(node, 1);
+
+ checkSpacingBefore(asToken, PREV_TOKEN_M);
+ }
+
+ /**
+ * Reports `static`, `get`, and `set` keywords of a given node if usage of
+ * spacing around those keywords is invalid.
+ *
+ * @param {ASTNode} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingForProperty(node) {
+ if (node.static) {
+ checkSpacingAroundFirstToken(node);
+ }
+ if (node.kind === "get" ||
+ node.kind === "set" ||
+ (
+ (node.method || node.type === "MethodDefinition") &&
+ node.value.async
+ )
+ ) {
+ const token = sourceCode.getTokenBefore(
+ node.key,
+ tok => {
+ switch (tok.value) {
+ case "get":
+ case "set":
+ case "async":
+ return true;
+ default:
+ return false;
+ }
+ }
+ );
+
+ if (!token) {
+ throw new Error("Failed to find token get, set, or async beside method name");
+ }
+
+
+ checkSpacingAround(token);
+ }
+ }
+
+ /**
+ * Reports `await` keyword of a given node if usage of spacing before
+ * this keyword is invalid.
+ *
+ * @param {ASTNode} node - A node to report.
+ * @returns {void}
+ */
+ function checkSpacingForAwaitExpression(node) {
+ checkSpacingBefore(sourceCode.getFirstToken(node));
+ }
+
+ return {
+
+ // Statements
+ DebuggerStatement: checkSpacingAroundFirstToken,
+ WithStatement: checkSpacingAroundFirstToken,
+
+ // Statements - Control flow
+ BreakStatement: checkSpacingAroundFirstToken,
+ ContinueStatement: checkSpacingAroundFirstToken,
+ ReturnStatement: checkSpacingAroundFirstToken,
+ ThrowStatement: checkSpacingAroundFirstToken,
+ TryStatement: checkSpacingForTryStatement,
+
+ // Statements - Choice
+ IfStatement: checkSpacingForIfStatement,
+ SwitchStatement: checkSpacingAroundFirstToken,
+ SwitchCase: checkSpacingAroundFirstToken,
+
+ // Statements - Loops
+ DoWhileStatement: checkSpacingForDoWhileStatement,
+ ForInStatement: checkSpacingForForInStatement,
+ ForOfStatement: checkSpacingForForOfStatement,
+ ForStatement: checkSpacingAroundFirstToken,
+ WhileStatement: checkSpacingAroundFirstToken,
+
+ // Statements - Declarations
+ ClassDeclaration: checkSpacingForClass,
+ ExportNamedDeclaration: checkSpacingForModuleDeclaration,
+ ExportDefaultDeclaration: checkSpacingAroundFirstToken,
+ ExportAllDeclaration: checkSpacingForModuleDeclaration,
+ FunctionDeclaration: checkSpacingForFunction,
+ ImportDeclaration: checkSpacingForModuleDeclaration,
+ VariableDeclaration: checkSpacingAroundFirstToken,
+
+ // Expressions
+ ArrowFunctionExpression: checkSpacingForFunction,
+ AwaitExpression: checkSpacingForAwaitExpression,
+ ClassExpression: checkSpacingForClass,
+ FunctionExpression: checkSpacingForFunction,
+ NewExpression: checkSpacingBeforeFirstToken,
+ Super: checkSpacingBeforeFirstToken,
+ ThisExpression: checkSpacingBeforeFirstToken,
+ UnaryExpression: checkSpacingBeforeFirstToken,
+ YieldExpression: checkSpacingBeforeFirstToken,
+
+ // Others
+ ImportNamespaceSpecifier: checkSpacingForImportNamespaceSpecifier,
+ MethodDefinition: checkSpacingForProperty,
+ Property: checkSpacingForProperty
+ };
+ }
+};