Skip to content

Commit

Permalink
Update: add more indent options for functions (fixes eslint#6052)
Browse files Browse the repository at this point in the history
  • Loading branch information
not-an-aardvark committed Sep 2, 2016
1 parent 4126f12 commit 16b3182
Show file tree
Hide file tree
Showing 3 changed files with 432 additions and 2 deletions.
102 changes: 102 additions & 0 deletions docs/rules/indent.md
Expand Up @@ -74,6 +74,12 @@ This rule has an object option:
* `"VariableDeclarator"` (default: 1) enforces indentation level for `var` declarators; can also take an object to define separate rules for `var`, `let` and `const` declarations.
* `"outerIIFEBody"` (default: 1) enforces indentation level for file-level IIFEs.
* `"MemberExpression"` (off by default) enforces indentation level for multi-line property chains (except in variable declarations and assignments)
* `"FunctionDeclaration"` takes an object to define rules for function declarations.
* `parameters` (off by default) enforces indentation level for parameters in a function declaration. This can either be a number indicating indentation level, or the string `"first"` indicating that all parameters of the declaration must be aligned with the first parameter.
* `body` (default: 1) enforces indentation level for the body of a function declaration.
* `"FunctionExpression"` takes an object to define rules for function expressions.
* `parameters` (off by default) enforces indentation level for parameters in a function expression. This can either be a number indicating indentation level, or the string `"first"` indicating that all parameters of the expression must be aligned with the first parameter.
* `body` (default: 1) enforces indentation level for the body of a function expression.

Level of indentation denotes the multiple of the indent specified. Example:

Expand Down Expand Up @@ -281,6 +287,102 @@ var bip = aardvark.badger
.coyote;
```

### FunctionDeclaration

Examples of **incorrect** code for this rule with the `2, { "FunctionDeclaration": {"body": 1, "parameters": 2} }` option:

```js
/*eslint indent: ["error", 2, { "FunctionDeclaration": {"body": 1, "parameters": 2} }]*/

function foo(bar,
baz,
qux) {
qux();
}
```

Examples of **correct** code for this rule with the `2, { "FunctionDeclaration": {"body": 1, "parameters": 2} }` option:

```js
/*eslint indent: ["error", 2, { "FunctionDeclaration": {"body": 1, "parameters": 2} }]*/

function foo(bar,
baz,
qux) {
qux();
}
```

Examples of **incorrect** code for this rule with the `2, { "FunctionDeclaration": {"parameters": "first"} }` option:

```js
/*eslint indent: ["error", 2, {"FunctionDeclaration": {"parameters": "first"}}]*/

function foo(bar, baz,
qux, boop) {
qux();
}
```

Examples of **correct** code for this rule with the `2, { "FunctionDeclaration": {"parameters": "first"} }` option:

```js
/*eslint indent: ["error", 2, {"FunctionDeclaration": {"parameters": "first"}}]*/

function foo(bar, baz,
qux, boop) {
qux();
}
```

### FunctionExpression

Examples of **incorrect** code for this rule with the `2, { "FunctionExpression": {"body": 1, "parameters": 2} }` option:

```js
/*eslint indent: ["error", 2, { "FunctionExpression": {"body": 1, "parameters": 2} }]*/

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

Examples of **correct** code for this rule with the `2, { "FunctionExpression": {"body": 1, "parameters": 2} }` option:

```js
/*eslint indent: ["error", 2, { "FunctionExpression": {"body": 1, "parameters": 2} }]*/

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

Examples of **incorrect** code for this rule with the `2, { "FunctionExpression": {"parameters": "first"} }` option:

```js
/*eslint indent: ["error", 2, {"FunctionExpression": {"parameters": "first"}}]*/

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

Examples of **correct** code for this rule with the `2, { "FunctionExpression": {"parameters": "first"} }` option:

```js
/*eslint indent: ["error", 2, {"FunctionExpression": {"parameters": "first"}}]*/

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

## Compatibility

* **JSHint**: `indent`
Expand Down
88 changes: 86 additions & 2 deletions lib/rules/indent.js
Expand Up @@ -73,6 +73,46 @@ module.exports = {
MemberExpression: {
type: "integer",
minimum: 0
},
FunctionDeclaration: {
type: "object",
properties: {
parameters: {
oneOf: [
{
type: "integer",
minimum: 0
},
{
enum: ["first"]
}
]
},
body: {
type: "integer",
minimum: 0
}
}
},
FunctionExpression: {
type: "object",
properties: {
parameters: {
oneOf: [
{
type: "integer",
minimum: 0
},
{
enum: ["first"]
}
]
},
body: {
type: "integer",
minimum: 0
}
}
}
},
additionalProperties: false
Expand All @@ -84,6 +124,8 @@ module.exports = {

const MESSAGE = "Expected indentation of {{needed}} {{type}} {{characters}} but found {{gotten}}.";
const DEFAULT_VARIABLE_INDENT = 1;
const DEFAULT_PARAMETER_INDENT = null; // For backwards compatibility, don't check parameter indentation unless specified in the config
const DEFAULT_FUNCTION_BODY_INDENT = 1;

let indentType = "space";
let indentSize = 4;
Expand All @@ -94,7 +136,15 @@ module.exports = {
let: DEFAULT_VARIABLE_INDENT,
const: DEFAULT_VARIABLE_INDENT
},
outerIIFEBody: null
outerIIFEBody: null,
FunctionDeclaration: {
parameters: DEFAULT_PARAMETER_INDENT,
body: DEFAULT_FUNCTION_BODY_INDENT
},
FunctionExpression: {
parameters: DEFAULT_PARAMETER_INDENT,
body: DEFAULT_FUNCTION_BODY_INDENT
}
};

const sourceCode = context.getSourceCode();
Expand Down Expand Up @@ -131,6 +181,14 @@ module.exports = {
if (typeof opts.MemberExpression === "number") {
options.MemberExpression = opts.MemberExpression;
}

if (typeof opts.FunctionDeclaration === "object") {
Object.assign(options.FunctionDeclaration, opts.FunctionDeclaration);
}

if (typeof opts.FunctionExpression === "object") {
Object.assign(options.FunctionExpression, opts.FunctionExpression);
}
}
}

Expand Down Expand Up @@ -492,11 +550,15 @@ module.exports = {
}

// function body indent should be indent + indent size, unless this
// is the outer IIFE and that option is enabled.
// is a FunctionDeclaration, FunctionExpression, or outer IIFE and the corresponding options are enabled.
let functionOffset = indentSize;

if (options.outerIIFEBody !== null && isOuterIIFE(calleeNode)) {
functionOffset = options.outerIIFEBody * indentSize;
} else if (calleeNode.type === "FunctionExpression") {
functionOffset = options.FunctionExpression.body * indentSize;
} else if (calleeNode.type === "FunctionDeclaration") {
functionOffset = options.FunctionDeclaration.body * indentSize;
}
indent += functionOffset;

Expand Down Expand Up @@ -884,6 +946,28 @@ module.exports = {
const caseIndent = expectedCaseIndent(node);

checkNodesIndent(node.consequent, caseIndent + indentSize);
},

FunctionDeclaration(node) {
if (isSingleLineNode(node)) {
return;
}
if (options.FunctionDeclaration.parameters === "first" && node.params.length) {
checkNodesIndent(node.params.slice(1), node.params[0].loc.start.column);
} else if (options.FunctionDeclaration.parameters !== null) {
checkNodesIndent(node.params, indentSize * options.FunctionDeclaration.parameters);
}
},

FunctionExpression(node) {
if (isSingleLineNode(node)) {
return;
}
if (options.FunctionExpression.parameters === "first" && node.params.length) {
checkNodesIndent(node.params.slice(1), node.params[0].loc.start.column);
} else if (options.FunctionExpression.parameters !== null) {
checkNodesIndent(node.params, indentSize * options.FunctionExpression.parameters);
}
}
};

Expand Down

0 comments on commit 16b3182

Please sign in to comment.