Skip to content

Commit

Permalink
Update: support single argument on newline with function-paren-newline (
Browse files Browse the repository at this point in the history
  • Loading branch information
gwer authored and not-an-aardvark committed Apr 2, 2019
1 parent fd1c91b commit 2f8ae13
Show file tree
Hide file tree
Showing 3 changed files with 450 additions and 5 deletions.
51 changes: 51 additions & 0 deletions docs/rules/function-paren-newline.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This rule has a single option, which can either be a string or an object.
* `"always"` requires line breaks inside all function parentheses.
* `"never"` disallows line breaks inside all function parentheses.
* `"multiline"` (default) requires linebreaks inside function parentheses if any of the parameters/arguments have a line break between them. Otherwise, it disallows linebreaks.
* `"multiline-arguments"` works like `multiline` but allows linebreaks inside function parentheses if there is only one parameter/argument.
* `"consistent"` requires consistent usage of linebreaks for each pair of parentheses. It reports an error if one parenthesis in the pair has a linebreak inside it and the other parenthesis does not.
* `{ "minItems": value }` requires linebreaks inside function parentheses if the number of parameters/arguments is at least `value`. Otherwise, it disallows linebreaks.

Expand Down Expand Up @@ -225,6 +226,56 @@ foo(
);
```

Examples of **incorrect** code for this rule with the `"multiline-arguments"` option:

```js
/* eslint function-paren-newline: ["error", "multiline-arguments"] */

function foo(bar,
baz
) {}

var foo = function(bar,
baz
) {};

var foo = (
bar,
baz) => {};

foo(
bar,
baz);

foo(
bar, qux,
baz
);
```

Examples of **correct** code for this rule with the consistent `"multiline-arguments"` option:

```js
/* eslint function-paren-newline: ["error", "multiline-arguments"] */

function foo(
bar,
baz
) {}

var foo = function(bar, baz) {};

var foo = (
bar
) => {};

foo(
function() {
return baz;
}
);
```

Examples of **incorrect** code for this rule with the `{ "minItems": 3 }` option:

```js
Expand Down
42 changes: 39 additions & 3 deletions lib/rules/function-paren-newline.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ module.exports = {
{
oneOf: [
{
enum: ["always", "never", "consistent", "multiline"]
enum: ["always", "never", "consistent", "multiline", "multiline-arguments"]
},
{
type: "object",
Expand All @@ -50,6 +50,7 @@ module.exports = {
messages: {
expectedBefore: "Expected newline before ')'.",
expectedAfter: "Expected newline after '('.",
expectedBetween: "Expected newline between arguments/params.",
unexpectedBefore: "Unexpected newline before '('.",
unexpectedAfter: "Unexpected newline after ')'."
}
Expand All @@ -59,6 +60,7 @@ module.exports = {
const sourceCode = context.getSourceCode();
const rawOption = context.options[0] || "multiline";
const multilineOption = rawOption === "multiline";
const multilineArgumentsOption = rawOption === "multiline-arguments";
const consistentOption = rawOption === "consistent";
let minItems;

Expand All @@ -83,7 +85,10 @@ module.exports = {
* @returns {boolean} `true` if there should be newlines inside the function parens
*/
function shouldHaveNewlines(elements, hasLeftNewline) {
if (multilineOption) {
if (multilineArgumentsOption && elements.length === 1) {
return hasLeftNewline;
}
if (multilineOption || multilineArgumentsOption) {
return elements.some((element, index) => index !== elements.length - 1 && element.loc.end.line !== elements[index + 1].loc.start.line);
}
if (consistentOption) {
Expand All @@ -93,7 +98,7 @@ module.exports = {
}

/**
* Validates a list of arguments or parameters
* Validates parens
* @param {Object} parens An object with keys `leftParen` for the left paren token, and `rightParen` for the right paren token
* @param {ASTNode[]} elements The arguments or parameters in the list
* @returns {void}
Expand Down Expand Up @@ -148,6 +153,33 @@ module.exports = {
}
}

/**
* Validates a list of arguments or parameters
* @param {Object} parens An object with keys `leftParen` for the left paren token, and `rightParen` for the right paren token
* @param {ASTNode[]} elements The arguments or parameters in the list
* @returns {void}
*/
function validateArguments(parens, elements) {
const leftParen = parens.leftParen;
const tokenAfterLeftParen = sourceCode.getTokenAfter(leftParen);
const hasLeftNewline = !astUtils.isTokenOnSameLine(leftParen, tokenAfterLeftParen);
const needsNewlines = shouldHaveNewlines(elements, hasLeftNewline);

for (let i = 0; i <= elements.length - 2; i++) {
const currentElement = elements[i];
const nextElement = elements[i + 1];
const hasNewLine = currentElement.loc.end.line !== nextElement.loc.start.line;

if (!hasNewLine && needsNewlines) {
context.report({
node: currentElement,
messageId: "expectedBetween",
fix: fixer => fixer.insertTextBefore(nextElement, "\n")
});
}
}
}

/**
* Gets the left paren and right paren tokens of a node.
* @param {ASTNode} node The node with parens
Expand Down Expand Up @@ -215,6 +247,10 @@ module.exports = {

if (parens) {
validateParens(parens, astUtils.isFunction(node) ? node.params : node.arguments);

if (multilineArgumentsOption) {
validateArguments(parens, astUtils.isFunction(node) ? node.params : node.arguments);
}
}
}

Expand Down

0 comments on commit 2f8ae13

Please sign in to comment.