Skip to content

Commit

Permalink
New: padding-line-between-statements rule (fixes #7356) (#8099)
Browse files Browse the repository at this point in the history
* New: newline-between-statements (fixes #7356)

* Chore: refactor with AST selectors

* Fix: add more tests.

- The kind `directive`  matches to only directive prologue.
- The kind `expression` does not match to directive prologue.
- The kinds `block-like` and `multiline-block-like` match to do-while
statements.
- The kinds `block-like` and `multiline-block-like` do not match to
classes.

* Update: change options' form.

- It was the array of arrays, but it becomes the array of objects.

* Update: rename

* Update: deprecate 3 rules as replaced by this

* use astUtils.STATEMENT_LIST_PARENTS instead of local RegExp.

* avoid catastrophic backtracking

* improve IIFE check for unary expressions

* fix a bug about semicolon-less style and empty statements

* unwrap the array of options

* use constants for error messages.

* update document

* fix plural

* fix blankline → blankLine
  • Loading branch information
mysticatea authored and not-an-aardvark committed May 15, 2017
1 parent 0ef09ea commit a93a2f9
Show file tree
Hide file tree
Showing 13 changed files with 5,293 additions and 6 deletions.
1 change: 1 addition & 0 deletions conf/eslint-recommended.js
Expand Up @@ -221,6 +221,7 @@ module.exports = {
"operator-assignment": "off",
"operator-linebreak": "off",
"padded-blocks": "off",
"padding-line-between-statements": "off",
"prefer-arrow-callback": "off",
"prefer-const": "off",
"prefer-destructuring": "off",
Expand Down
2 changes: 2 additions & 0 deletions docs/rules/lines-around-directive.md
@@ -1,5 +1,7 @@
# require or disallow newlines around directives (lines-around-directive)

This rule was **deprecated** in ESLint v4.0.0 and replaced by the [padding-line-between-statements](padding-line-between-statements.md) rule.

Directives are used in JavaScript to indicate to the execution environment that a script would like to opt into a feature such as `"strict mode"`. Directives are grouped together in a [directive prologue](http://www.ecma-international.org/ecma-262/7.0/#directive-prologue) at the top of either a file or function block and are applied to the scope in which they occur.

```js
Expand Down
2 changes: 2 additions & 0 deletions docs/rules/newline-after-var.md
@@ -1,5 +1,7 @@
# require or disallow an empty line after variable declarations (newline-after-var)

This rule was **deprecated** in ESLint v4.0.0 and replaced by the [padding-line-between-statements](padding-line-between-statements.md) rule.

As of today there is no consistency in separating variable declarations from the rest of the code. Some developers leave an empty line between var statements and the rest of the code like:

```js
Expand Down
2 changes: 2 additions & 0 deletions docs/rules/newline-before-return.md
@@ -1,5 +1,7 @@
# require an empty line before `return` statements (newline-before-return)

This rule was **deprecated** in ESLint v4.0.0 and replaced by the [padding-line-between-statements](padding-line-between-statements.md) rule.

There is no hard and fast rule about whether empty lines should precede `return` statements in JavaScript. However, clearly delineating where a function is returning can greatly increase the readability and clarity of the code. For example:

```js
Expand Down
235 changes: 235 additions & 0 deletions docs/rules/padding-line-between-statements.md
@@ -0,0 +1,235 @@
# Require or disallow padding lines between statements (padding-line-between-statements)

This rule requires or disallows blank lines between the given 2 kinds of statements.
Properly blank lines help developers to understand the code.

For example, the following configuration requires a blank line between a variable declaration and a `return` statement.

```js
/*eslint padding-line-between-statements: [
"error",
{ blankLine: "always", prev: "var", next: "return" }
]*/

function foo() {
var a = 1;

return a;
}
```

## Rule Details

This rule does nothing if no configuration.

A configuration is an object which has 3 properties; `blankLine`, `prev` and `next`. For example, `{ blankLine: "always", prev: "var", next: "return" }` is meaning "it requires one or more blank lines between a variable declaration and a `return` statement."
You can supply any number of configurations. If an statement pair matches multiple configurations, the last matched configuration will be used.

```json
{
"padding-line-between-statements": [
"error",
{ "blankLine": LINEBREAK_TYPE, "prev": STATEMENT_TYPE, "next": STATEMENT_TYPE },
{ "blankLine": LINEBREAK_TYPE, "prev": STATEMENT_TYPE, "next": STATEMENT_TYPE },
{ "blankLine": LINEBREAK_TYPE, "prev": STATEMENT_TYPE, "next": STATEMENT_TYPE },
{ "blankLine": LINEBREAK_TYPE, "prev": STATEMENT_TYPE, "next": STATEMENT_TYPE },
...
]
}
```

- `LINEBREAK_TYPE` is one of the following.
- `"any"` just ignores the statement pair.
- `"never"` disallows blank lines.
- `"always"` requires one or more blank lines. Note it does not count lines that comments exist as blank lines.

- `STATEMENT_TYPE` is one of the following, or an array of the following.
- `"*"` is wildcard. This matches any statements.
- `"block"` is lonely blocks.
- `"block-like"` is block like statements. This matches statements that the last token is the closing brace of blocks; e.g. `{ }`, `if (a) { }`, and `while (a) { }`.
- `"break"` is `break` statements.
- `"case"` is `case` labels.
- `"cjs-export"` is `export` statements of CommonJS; e.g. `module.exports = 0`, `module.exports.foo = 1`, and `exports.foo = 2`. This is the special cases of assignment.
- `"cjs-import"` is `import` statements of CommonJS; e.g. `const foo = require("foo")`. This is the special cases of variable declarations.
- `"class"` is `class` declarations.
- `"const"` is `const` variable declarations.
- `"continue"` is `continue` statements.
- `"debugger"` is `debugger` statements.
- `"default"` is `default` labels.
- `"directive"` is directive prologues. This matches directives; e.g. `"use strict"`.
- `"do"` is `do-while` statements. This matches all statements that the first token is `do` keyword.
- `"empty"` is empty statements.
- `"export"` is `export` declarations.
- `"expression"` is expression statements.
- `"for"` is `for` loop families. This matches all statements that the first token is `for` keyword.
- `"function"` is function declarations.
- `"if"` is `if` statements.
- `"import"` is `import` declarations.
- `"let"` is `let` variable declarations.
- `"multiline-block-like"` is block like statements. This is the same as `block-like` type, but only the block is multiline.
- `"return"` is `return` statements.
- `"switch"` is `switch` statements.
- `"throw"` is `throw` statements.
- `"try"` is `try` statements.
- `"var"` is `var` variable declarations.
- `"while"` is `while` loop statements.
- `"with"` is `with` statements.

## Examples

This configuration would require blank lines before all `return` statements, like the [newline-before-return] rule.

Examples of **incorrect** code for the `[{ blankLine: "always", prev: "*", next: "return" }]` configuration:

```js
/*eslint padding-line-between-statements: [
"error",
{ blankLine: "always", prev: "*", next: "return" }
]*/

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

Examples of **correct** code for the `[{ blankLine: "always", prev: "*", next: "return" }]` configuration:

```js
/*eslint padding-line-between-statements: [
"error",
{ blankLine: "always", prev: "*", next: "return" }
]*/

function foo() {
bar();

return;
}

function foo() {
return;
}
```

----

This configuration would require blank lines after every sequence of variable declarations, like the [newline-after-var] rule.

Examples of **incorrect** code for the `[{ blankLine: "always", prev: ["const", "let", "var"], next: "*"}, { blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"]}]` configuration:

```js
/*eslint padding-line-between-statements: [
"error",
{ blankLine: "always", prev: ["const", "let", "var"], next: "*"},
{ blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"]}
]*/

function foo() {
var a = 0;
bar();
}

function foo() {
let a = 0;
bar();
}

function foo() {
const a = 0;
bar();
}
```

Examples of **correct** code for the `[{ blankLine: "always", prev: ["const", "let", "var"], next: "*"}, { blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"]}]` configuration:

```js
/*eslint padding-line-between-statements: [
"error",
{ blankLine: "always", prev: ["const", "let", "var"], next: "*"},
{ blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"]}
]*/

function foo() {
var a = 0;
var b = 0;

bar();
}

function foo() {
let a = 0;
const b = 0;

bar();
}

function foo() {
const a = 0;
const b = 0;

bar();
}
```

----

This configuration would require blank lines after all directive prologues, like the [lines-around-directive] rule.

Examples of **incorrect** code for the `[{ blankLine: "always", prev: "directive", next: "*" }, { blankLine: "any", prev: "directive", next: "directive" }]` configuration:

```js
/*eslint padding-line-between-statements: [
"error",
{ blankLine: "always", prev: "directive", next: "*" },
{ blankLine: "any", prev: "directive", next: "directive" }
]*/

"use strict";
foo();
```

Examples of **correct** code for the `[{ blankLine: "always", prev: "directive", next: "*" }, { blankLine: "any", prev: "directive", next: "directive" }]` configuration:

```js
/*eslint padding-line-between-statements: [
"error",
{ blankLine: "always", prev: "directive", next: "*" },
{ blankLine: "any", prev: "directive", next: "directive" }
]*/

"use strict";
"use asm";

foo();
```

## Compatibility

- **JSCS:** [requirePaddingNewLineAfterVariableDeclaration]
- **JSCS:** [requirePaddingNewLinesAfterBlocks]
- **JSCS:** [disallowPaddingNewLinesAfterBlocks]
- **JSCS:** [requirePaddingNewLinesAfterUseStrict]
- **JSCS:** [disallowPaddingNewLinesAfterUseStrict]
- **JSCS:** [requirePaddingNewLinesBeforeExport]
- **JSCS:** [disallowPaddingNewLinesBeforeExport]
- **JSCS:** [requirePaddingNewlinesBeforeKeywords]
- **JSCS:** [disallowPaddingNewlinesBeforeKeywords]

## When Not To Use It

If you don't want to notify warnings about linebreaks, then it's safe to disable this rule.


[lines-around-directive]: http://eslint.org/docs/rules/lines-around-directive
[newline-after-var]: http://eslint.org/docs/rules/newline-after-var
[newline-before-return]: http://eslint.org/docs/rules/newline-before-return
[requirePaddingNewLineAfterVariableDeclaration]: http://jscs.info/rule/requirePaddingNewLineAfterVariableDeclaration
[requirePaddingNewLinesAfterBlocks]: http://jscs.info/rule/requirePaddingNewLinesAfterBlocks
[disallowPaddingNewLinesAfterBlocks]: http://jscs.info/rule/disallowPaddingNewLinesAfterBlocks
[requirePaddingNewLinesAfterUseStrict]: http://jscs.info/rule/requirePaddingNewLinesAfterUseStrict
[disallowPaddingNewLinesAfterUseStrict]: http://jscs.info/rule/disallowPaddingNewLinesAfterUseStrict
[requirePaddingNewLinesBeforeExport]: http://jscs.info/rule/requirePaddingNewLinesBeforeExport
[disallowPaddingNewLinesBeforeExport]: http://jscs.info/rule/disallowPaddingNewLinesBeforeExport
[requirePaddingNewlinesBeforeKeywords]: http://jscs.info/rule/requirePaddingNewlinesBeforeKeywords
[disallowPaddingNewlinesBeforeKeywords]: http://jscs.info/rule/disallowPaddingNewlinesBeforeKeywords
7 changes: 5 additions & 2 deletions lib/rules/lines-around-directive.js
@@ -1,6 +1,7 @@
/**
* @fileoverview Require or disallow newlines around directives.
* @author Kai Cataldo
* @deprecated
*/

"use strict";
Expand All @@ -16,7 +17,8 @@ module.exports = {
docs: {
description: "require or disallow newlines around directives",
category: "Stylistic Issues",
recommended: false
recommended: false,
replacedBy: ["padding-line-between-statements"]
},
schema: [{
oneOf: [
Expand All @@ -38,7 +40,8 @@ module.exports = {
}
]
}],
fixable: "whitespace"
fixable: "whitespace",
deprecated: true
},

create(context) {
Expand Down
8 changes: 6 additions & 2 deletions lib/rules/newline-after-var.js
@@ -1,6 +1,7 @@
/**
* @fileoverview Rule to check empty newline after "var" statement
* @author Gopal Venkatesan
* @deprecated
*/

"use strict";
Expand All @@ -20,7 +21,8 @@ module.exports = {
docs: {
description: "require or disallow an empty line after variable declarations",
category: "Stylistic Issues",
recommended: false
recommended: false,
replacedBy: ["padding-line-between-statements"]
},

schema: [
Expand All @@ -29,7 +31,9 @@ module.exports = {
}
],

fixable: "whitespace"
fixable: "whitespace",

deprecated: true
},

create(context) {
Expand Down
7 changes: 5 additions & 2 deletions lib/rules/newline-before-return.js
@@ -1,6 +1,7 @@
/**
* @fileoverview Rule to require newlines before `return` statement
* @author Kai Cataldo
* @deprecated
*/
"use strict";

Expand All @@ -13,10 +14,12 @@ module.exports = {
docs: {
description: "require an empty line before `return` statements",
category: "Stylistic Issues",
recommended: false
recommended: false,
replacedBy: ["padding-line-between-statements"]
},
fixable: "whitespace",
schema: []
schema: [],
deprecated: true
},

create(context) {
Expand Down

0 comments on commit a93a2f9

Please sign in to comment.