Skip to content

Commit

Permalink
Update: "off" options for "space-before-blocks" (refs #10906) (#10907)
Browse files Browse the repository at this point in the history
* Update: "off" options for "space-before-blocks" (refs #10906)

See #10906

Where "always" enforces space and "never" enforces no-space, "off" does not enforce any space preference.

It may be useful to add a similar "off" option to other enums only allowing "always" and "never", too, but that is outside the scope of this PR.
  • Loading branch information
pineapplemachine authored and nzakas committed Nov 9, 2018
1 parent 57f357e commit ae2b61d
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 36 deletions.
2 changes: 1 addition & 1 deletion docs/rules/space-before-blocks.md
Expand Up @@ -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" }` )

Expand Down
79 changes: 44 additions & 35 deletions lib/rules/space-before-blocks.js
Expand Up @@ -34,13 +34,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
Expand All @@ -53,18 +53,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;
}

/**
Expand All @@ -90,35 +99,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]]);
}
});
}
}
}
Expand Down
130 changes: 130 additions & 0 deletions tests/lib/rules/space-before-blocks.js
Expand Up @@ -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.",
Expand Down Expand Up @@ -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 } },
Expand Down Expand Up @@ -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: { ecmaVersion: 6 },
errors: [expectedNoSpacingError]
},
{
code: "class test { constructor() {} }",
output: "class test{ constructor() {} }",
options: classesNeverOthersOffArgs,
parserOptions: { ecmaVersion: 6 },
errors: [expectedNoSpacingError]
}
]
});

0 comments on commit ae2b61d

Please sign in to comment.