Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update: add more indent options for functions (fixes #6052) #7043

Merged
merged 1 commit into from Sep 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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