diff --git a/docs/rules/space-before-blocks.md b/docs/rules/space-before-blocks.md index 60f0717b3e1e..ab4c2a2b4003 100644 --- a/docs/rules/space-before-blocks.md +++ b/docs/rules/space-before-blocks.md @@ -17,7 +17,7 @@ This rule will enforce consistency of spacing before blocks. It is only applied This rule takes one argument. If it is `"always"` then blocks must always have at least one preceding space. If `"never"` then all blocks should never have any preceding space. If different spacing is desired for function blocks, keyword blocks and classes, an optional configuration object can be passed as the rule argument to -configure the cases separately. +configure the cases separately. If any value in the configuration object is `"off"`, then neither style will be enforced for blocks of that kind. ( e.g. `{ "functions": "never", "keywords": "always", "classes": "always" }` ) diff --git a/lib/rules/space-before-blocks.js b/lib/rules/space-before-blocks.js index 4f22ae6b6538..9034c61db8b6 100644 --- a/lib/rules/space-before-blocks.js +++ b/lib/rules/space-before-blocks.js @@ -32,13 +32,13 @@ module.exports = { type: "object", properties: { keywords: { - enum: ["always", "never"] + enum: ["always", "never", "off"] }, functions: { - enum: ["always", "never"] + enum: ["always", "never", "off"] }, classes: { - enum: ["always", "never"] + enum: ["always", "never", "off"] } }, additionalProperties: false @@ -51,18 +51,27 @@ module.exports = { create(context) { const config = context.options[0], sourceCode = context.getSourceCode(); - let checkFunctions = true, - checkKeywords = true, - checkClasses = true; + let alwaysFunctions = true, + alwaysKeywords = true, + alwaysClasses = true, + neverFunctions = false, + neverKeywords = false, + neverClasses = false; if (typeof config === "object") { - checkFunctions = config.functions !== "never"; - checkKeywords = config.keywords !== "never"; - checkClasses = config.classes !== "never"; + 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") { - checkFunctions = false; - checkKeywords = false; - checkClasses = false; + alwaysFunctions = false; + alwaysKeywords = false; + alwaysClasses = false; + neverFunctions = true; + neverKeywords = true; + neverClasses = true; } /** @@ -88,35 +97,35 @@ module.exports = { const hasSpace = sourceCode.isSpaceBetweenTokens(precedingToken, node); const parent = context.getAncestors().pop(); let requireSpace; + let requireNoSpace; if (parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration") { - requireSpace = checkFunctions; + requireSpace = alwaysFunctions; + requireNoSpace = neverFunctions; } else if (node.type === "ClassBody") { - requireSpace = checkClasses; + requireSpace = alwaysClasses; + requireNoSpace = neverClasses; } else { - requireSpace = checkKeywords; + requireSpace = alwaysKeywords; + requireNoSpace = neverKeywords; } - if (requireSpace) { - if (!hasSpace) { - context.report({ - node, - message: "Missing space before opening brace.", - fix(fixer) { - return fixer.insertTextBefore(node, " "); - } - }); - } - } else { - if (hasSpace) { - context.report({ - node, - message: "Unexpected space before opening brace.", - fix(fixer) { - return fixer.removeRange([precedingToken.range[1], node.range[0]]); - } - }); - } + if (requireSpace && !hasSpace) { + context.report({ + node, + message: "Missing space before opening brace.", + fix(fixer) { + return fixer.insertTextBefore(node, " "); + } + }); + } else if (requireNoSpace && hasSpace) { + context.report({ + node, + message: "Unexpected space before opening brace.", + fix(fixer) { + return fixer.removeRange([precedingToken.range[1], node.range[0]]); + } + }); } } } diff --git a/tests/lib/rules/space-before-blocks.js b/tests/lib/rules/space-before-blocks.js index e0ccb67ad0dd..330ee60d4bda 100644 --- a/tests/lib/rules/space-before-blocks.js +++ b/tests/lib/rules/space-before-blocks.js @@ -21,6 +21,12 @@ const ruleTester = new RuleTester(), functionsOnlyArgs = [{ functions: "always", keywords: "never", classes: "never" }], keywordOnlyArgs = [{ functions: "never", keywords: "always", classes: "never" }], classesOnlyArgs = [{ functions: "never", keywords: "never", classes: "always" }], + functionsAlwaysOthersOffArgs = [{ functions: "always", keywords: "off", classes: "off" }], + keywordAlwaysOthersOffArgs = [{ functions: "off", keywords: "always", classes: "off" }], + classesAlwaysOthersOffArgs = [{ functions: "off", keywords: "off", classes: "always" }], + functionsNeverOthersOffArgs = [{ functions: "never", keywords: "off", classes: "off" }], + keywordNeverOthersOffArgs = [{ functions: "off", keywords: "never", classes: "off" }], + classesNeverOthersOffArgs = [{ functions: "off", keywords: "off", classes: "never" }], expectedSpacingErrorMessage = "Missing space before opening brace.", expectedSpacingError = { message: expectedSpacingErrorMessage }, expectedNoSpacingErrorMessage = "Unexpected space before opening brace.", @@ -131,6 +137,54 @@ ruleTester.run("space-before-blocks", rule, { code: "class test {}", parserOptions: { ecmaVersion: 6 } }, + { code: "function a(){if(b) {}}", options: keywordAlwaysOthersOffArgs }, + { code: "function a() {if(b) {}}", options: keywordAlwaysOthersOffArgs }, + { code: "function a() {if(b){}}", options: functionsAlwaysOthersOffArgs }, + { code: "function a() {if(b) {}}", options: functionsAlwaysOthersOffArgs }, + { + code: "class test { constructor(){if(a){}} }", + options: classesAlwaysOthersOffArgs, + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class test { constructor() {if(a){}} }", + options: classesAlwaysOthersOffArgs, + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class test { constructor(){if(a) {}} }", + options: classesAlwaysOthersOffArgs, + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class test { constructor() {if(a) {}} }", + options: classesAlwaysOthersOffArgs, + parserOptions: { ecmaVersion: 6 } + }, + { code: "function a(){if(b){}}", options: keywordNeverOthersOffArgs }, + { code: "function a() {if(b){}}", options: keywordNeverOthersOffArgs }, + { code: "function a(){if(b){}}", options: functionsNeverOthersOffArgs }, + { code: "function a(){if(b) {}}", options: functionsNeverOthersOffArgs }, + { + code: "class test{ constructor(){if(a){}} }", + options: classesNeverOthersOffArgs, + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class test{ constructor() {if(a){}} }", + options: classesNeverOthersOffArgs, + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class test{ constructor(){if(a) {}} }", + options: classesNeverOthersOffArgs, + parserOptions: { ecmaVersion: 6 } + }, + { + code: "class test{ constructor() {if(a) {}} }", + options: classesNeverOthersOffArgs, + parserOptions: { ecmaVersion: 6 } + }, // https://github.com/eslint/eslint/issues/3769 { code: "()=>{};", options: ["always"], parserOptions: { ecmaVersion: 6 } }, @@ -427,6 +481,82 @@ ruleTester.run("space-before-blocks", rule, { options: neverArgs, parserOptions: { ecmaVersion: 6 }, errors: [expectedNoSpacingError] + }, + { + code: "if(a){ function a(){} }", + output: "if(a){ function a() {} }", + options: functionsAlwaysOthersOffArgs, + errors: [expectedSpacingError] + }, + { + code: "if(a) { function a(){} }", + output: "if(a) { function a() {} }", + options: functionsAlwaysOthersOffArgs, + errors: [expectedSpacingError] + }, + { + code: "if(a){ function a(){} }", + output: "if(a) { function a(){} }", + options: keywordAlwaysOthersOffArgs, + errors: [expectedSpacingError] + }, + { + code: "if(a){ function a() {} }", + output: "if(a) { function a() {} }", + options: keywordAlwaysOthersOffArgs, + errors: [expectedSpacingError] + }, + { + code: "class test{ constructor(){} }", + output: "class test { constructor(){} }", + options: classesAlwaysOthersOffArgs, + parserOptions: { ecmaVersion: 6 }, + errors: [expectedSpacingError] + }, + { + code: "class test{ constructor() {} }", + output: "class test { constructor() {} }", + options: classesAlwaysOthersOffArgs, + parserOptions: { ecmaVersion: 6 }, + errors: [expectedSpacingError] + }, + { + code: "if(a){ function a() {} }", + output: "if(a){ function a(){} }", + options: functionsNeverOthersOffArgs, + errors: [expectedNoSpacingError] + }, + { + code: "if(a) { function a() {} }", + output: "if(a) { function a(){} }", + options: functionsNeverOthersOffArgs, + errors: [expectedNoSpacingError] + }, + { + code: "if(a) { function a(){} }", + output: "if(a){ function a(){} }", + options: keywordNeverOthersOffArgs, + errors: [expectedNoSpacingError] + }, + { + code: "if(a) { function a() {} }", + output: "if(a){ function a() {} }", + options: keywordNeverOthersOffArgs, + errors: [expectedNoSpacingError] + }, + { + code: "class test { constructor(){} }", + output: "class test{ constructor(){} }", + options: classesNeverOthersOffArgs, + parserOptions: { ecmaNoVersion: 6 }, + errors: [expectedSpacingError] + }, + { + code: "class test { constructor() {} }", + output: "class test{ constructor() {} }", + options: classesNeverOthersOffArgs, + parserOptions: { ecmaNoVersion: 6 }, + errors: [expectedSpacingError] } ] });