Skip to content

Commit

Permalink
Chore: refactor space-before-function-paren rule (#8284)
Browse files Browse the repository at this point in the history
This commit refactors the space-before-function-paren rule to avoid using different variables for each option. This should make the options easier to change in the future. It also updates the rule listeners to use selectors.
  • Loading branch information
not-an-aardvark committed Mar 20, 2017
1 parent ddc6350 commit 9b509ce
Showing 1 changed file with 40 additions and 73 deletions.
113 changes: 40 additions & 73 deletions lib/rules/space-before-function-paren.js
Expand Up @@ -51,31 +51,9 @@ module.exports = {
},

create(context) {

const configuration = context.options[0],
sourceCode = context.getSourceCode();
let requireAnonymousFunctionSpacing = true,
forbidAnonymousFunctionSpacing = false,
requireNamedFunctionSpacing = true,
forbidNamedFunctionSpacing = false,
requireArrowFunctionSpacing = false,
forbidArrowFunctionSpacing = false;

if (typeof configuration === "object") {
requireAnonymousFunctionSpacing = (
!configuration.anonymous || configuration.anonymous === "always");
forbidAnonymousFunctionSpacing = configuration.anonymous === "never";
requireNamedFunctionSpacing = (
!configuration.named || configuration.named === "always");
forbidNamedFunctionSpacing = configuration.named === "never";
requireArrowFunctionSpacing = configuration.asyncArrow === "always";
forbidArrowFunctionSpacing = configuration.asyncArrow === "never";
} else if (configuration === "never") {
requireAnonymousFunctionSpacing = false;
forbidAnonymousFunctionSpacing = true;
requireNamedFunctionSpacing = false;
forbidNamedFunctionSpacing = true;
}
const sourceCode = context.getSourceCode();
const baseConfig = typeof context.options[0] === "string" ? context.options[0] : "always";
const overrideConfig = typeof context.options[0] === "object" ? context.options[0] : {};

/**
* Determines whether a function has a name.
Expand All @@ -100,69 +78,58 @@ module.exports = {
}

/**
* Validates the spacing before function parentheses.
* @param {ASTNode} node The node to be validated.
* @returns {void}
* Gets the config for a given function
* @param {ASTNode} node The function node
* @returns {string} "always", "never", or "ignore"
*/
function validateSpacingBeforeParentheses(node) {
const isArrow = node.type === "ArrowFunctionExpression";
const isNamed = !isArrow && isNamedFunction(node);
const isAnonymousGenerator = node.generator && !isNamed;
const isNormalArrow = isArrow && !node.async;
const isArrowWithoutParens = isArrow && sourceCode.getFirstToken(node, 1).value !== "(";
let forbidSpacing, requireSpacing;

// isAnonymousGenerator → `generator-star-spacing` should warn it. E.g. `function* () {}`
// isNormalArrow → ignore always.
// isArrowWithoutParens → ignore always. E.g. `async a => a`
if (isAnonymousGenerator || isNormalArrow || isArrowWithoutParens) {
return;
}
function getConfigForFunction(node) {
if (node.type === "ArrowFunctionExpression") {

// Always ignore non-async functions and arrow functions without parens, e.g. async foo => bar
if (node.async && astUtils.isOpeningParenToken(sourceCode.getFirstToken(node, { skip: 1 }))) {

if (isArrow) {
forbidSpacing = forbidArrowFunctionSpacing;
requireSpacing = requireArrowFunctionSpacing;
} else if (isNamed) {
forbidSpacing = forbidNamedFunctionSpacing;
requireSpacing = requireNamedFunctionSpacing;
} else {
forbidSpacing = forbidAnonymousFunctionSpacing;
requireSpacing = requireAnonymousFunctionSpacing;
// For backwards compatibility, the base config does not apply to async arrow functions.
return overrideConfig.asyncArrow || "ignore";
}
} else if (isNamedFunction(node)) {
return overrideConfig.named || baseConfig;

// `generator-star-spacing` should warn anonymous generators. E.g. `function* () {}`
} else if (!node.generator) {
return overrideConfig.anonymous || baseConfig;
}

const rightToken = sourceCode.getFirstToken(node, astUtils.isOpeningParenToken);
const leftToken = sourceCode.getTokenBefore(rightToken);
const location = leftToken.loc.end;
return "ignore";
}

return {
":function"(node) {
const functionConfig = getConfigForFunction(node);

if (functionConfig === "ignore") {
return;
}

const rightToken = sourceCode.getFirstToken(node, astUtils.isOpeningParenToken);
const leftToken = sourceCode.getTokenBefore(rightToken);
const hasSpacing = sourceCode.isSpaceBetweenTokens(leftToken, rightToken);

if (sourceCode.isSpaceBetweenTokens(leftToken, rightToken)) {
if (forbidSpacing) {
if (hasSpacing && functionConfig === "never") {
context.report({
node,
loc: location,
loc: leftToken.loc.end,
message: "Unexpected space before function parentheses.",
fix(fixer) {
return fixer.removeRange([leftToken.range[1], rightToken.range[0]]);
}
fix: fixer => fixer.removeRange([leftToken.range[1], rightToken.range[0]])
});
}
} else {
if (requireSpacing) {
} else if (!hasSpacing && functionConfig === "always") {
context.report({
node,
loc: location,
loc: leftToken.loc.end,
message: "Missing space before function parentheses.",
fix(fixer) {
return fixer.insertTextAfter(leftToken, " ");
}
fix: fixer => fixer.insertTextAfter(leftToken, " ")
});
}
}
}

return {
FunctionDeclaration: validateSpacingBeforeParentheses,
FunctionExpression: validateSpacingBeforeParentheses,
ArrowFunctionExpression: validateSpacingBeforeParentheses
};
}
};

0 comments on commit 9b509ce

Please sign in to comment.