123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- /**
- * @fileoverview A rule to ensure whitespace before blocks.
- * @author Mathias Schreck <https://github.com/lo1tuma>
- */
- "use strict";
- const astUtils = require("./utils/ast-utils");
- //------------------------------------------------------------------------------
- // Rule Definition
- //------------------------------------------------------------------------------
- module.exports = {
- meta: {
- type: "layout",
- docs: {
- description: "enforce consistent spacing before blocks",
- category: "Stylistic Issues",
- recommended: false,
- url: "https://eslint.org/docs/rules/space-before-blocks"
- },
- fixable: "whitespace",
- schema: [
- {
- oneOf: [
- {
- enum: ["always", "never"]
- },
- {
- type: "object",
- properties: {
- keywords: {
- enum: ["always", "never", "off"]
- },
- functions: {
- enum: ["always", "never", "off"]
- },
- classes: {
- enum: ["always", "never", "off"]
- }
- },
- additionalProperties: false
- }
- ]
- }
- ],
- messages: {
- unexpectedSpace: "Unexpected space before opening brace.",
- missingSpace: "Missing space before opening brace."
- }
- },
- create(context) {
- const config = context.options[0],
- sourceCode = context.getSourceCode();
- let alwaysFunctions = true,
- alwaysKeywords = true,
- alwaysClasses = true,
- neverFunctions = false,
- neverKeywords = false,
- neverClasses = false;
- if (typeof config === "object") {
- alwaysFunctions = config.functions === "always";
- alwaysKeywords = config.keywords === "always";
- alwaysClasses = config.classes === "always";
- neverFunctions = config.functions === "never";
- neverKeywords = config.keywords === "never";
- neverClasses = config.classes === "never";
- } else if (config === "never") {
- alwaysFunctions = false;
- alwaysKeywords = false;
- alwaysClasses = false;
- neverFunctions = true;
- neverKeywords = true;
- neverClasses = true;
- }
- /**
- * Checks whether or not a given token is an arrow operator (=>) or a keyword
- * in order to avoid to conflict with `arrow-spacing` and `keyword-spacing`.
- * @param {Token} token A token to check.
- * @returns {boolean} `true` if the token is an arrow operator.
- */
- function isConflicted(token) {
- return (token.type === "Punctuator" && token.value === "=>") || token.type === "Keyword";
- }
- /**
- * Checks the given BlockStatement node has a preceding space if it doesn’t start on a new line.
- * @param {ASTNode|Token} node The AST node of a BlockStatement.
- * @returns {void} undefined.
- */
- function checkPrecedingSpace(node) {
- const precedingToken = sourceCode.getTokenBefore(node);
- if (precedingToken && !isConflicted(precedingToken) && astUtils.isTokenOnSameLine(precedingToken, node)) {
- const hasSpace = sourceCode.isSpaceBetweenTokens(precedingToken, node);
- const parent = context.getAncestors().pop();
- let requireSpace;
- let requireNoSpace;
- if (parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration") {
- requireSpace = alwaysFunctions;
- requireNoSpace = neverFunctions;
- } else if (node.type === "ClassBody") {
- requireSpace = alwaysClasses;
- requireNoSpace = neverClasses;
- } else {
- requireSpace = alwaysKeywords;
- requireNoSpace = neverKeywords;
- }
- if (requireSpace && !hasSpace) {
- context.report({
- node,
- messageId: "missingSpace",
- fix(fixer) {
- return fixer.insertTextBefore(node, " ");
- }
- });
- } else if (requireNoSpace && hasSpace) {
- context.report({
- node,
- messageId: "unexpectedSpace",
- fix(fixer) {
- return fixer.removeRange([precedingToken.range[1], node.range[0]]);
- }
- });
- }
- }
- }
- /**
- * Checks if the CaseBlock of an given SwitchStatement node has a preceding space.
- * @param {ASTNode} node The node of a SwitchStatement.
- * @returns {void} undefined.
- */
- function checkSpaceBeforeCaseBlock(node) {
- const cases = node.cases;
- let openingBrace;
- if (cases.length > 0) {
- openingBrace = sourceCode.getTokenBefore(cases[0]);
- } else {
- openingBrace = sourceCode.getLastToken(node, 1);
- }
- checkPrecedingSpace(openingBrace);
- }
- return {
- BlockStatement: checkPrecedingSpace,
- ClassBody: checkPrecedingSpace,
- SwitchStatement: checkSpaceBeforeCaseBlock
- };
- }
- };
|