Skip to content
Permalink
Browse files

New: `one-var-declaration-per-line` rule (fixes #1622)

  • Loading branch information...
alberto committed Jan 20, 2016
1 parent ebe62f1 commit 79e8a0b608ac3be1fab011eb9ee20642f3551853
@@ -167,6 +167,7 @@
"object-curly-spacing": 0,
"object-shorthand": 0,
"one-var": 0,
"one-var-declaration-per-line": 0,
"operator-assignment": 0,
"operator-linebreak": 0,
"padded-blocks": 0,
@@ -192,6 +192,7 @@ These rules are purely matters of style and are quite subjective.
* [no-unneeded-ternary](no-unneeded-ternary.md) - disallow the use of ternary operators when a simpler alternative exists
* [object-curly-spacing](object-curly-spacing.md) - require or disallow padding inside curly braces (fixable)
* [one-var](one-var.md) - require or disallow one variable declaration per function
* [one-var-declaration-per-line](one-var-declaration-per-line.md) - require or disallow an newline around variable declarations
* [operator-assignment](operator-assignment.md) - require assignment operator shorthand where possible or prohibit it entirely
* [operator-linebreak](operator-linebreak.md) - enforce operators to be placed before or after line breaks
* [padded-blocks](padded-blocks.md) - enforce padding within blocks
@@ -0,0 +1,85 @@
# Require or disallow an newline around variable declarations (one-var-declaration-per-line)

Some developers declare multiple var statements on the same line:

```js
var foo, bar, baz = 0;
```

Others prefer to declare one var per line.

```js
var foo,
bar,
baz = 0;
```

This rule enforces a consistent style across the entire project.

## Rule Details

This rule enforces a consistent coding style where newlines are required or disallowed after each var declaration or just when there is a variable initialization. It ignores var declarations inside for loop conditionals.

### Options

This rule takes one option, a string, which can be:

* `"always"` enforces a newline around each variable declaration (default)
* `"initializations"` enforces a newline around a variable initialization

The following patterns are considered problems when set to `"always"`:

```js
/*eslint one-var-declaration-per-line: [2, "always"]*/
/*eslint-env es6*/
var a, b; /*error Expected variable declaration to be on a new line. */
let a, b = 0; /*error Expected variable declaration to be on a new line. */
const a = 0, b = 0; /*error Expected variable declaration to be on a new line. */
```

The following patterns are not considered problems when set to `"always"`:

```js
/*eslint one-var-declaration-per-line: [2, "always"]*/
/*eslint-env es6*/
var a,
b;
let a,
b = 0;
```

The following patterns are considered problems when set to `"initializations"`:

```js
/*eslint one-var-declaration-per-line: [2, "initializations"]*/
/*eslint-env es6*/
var a, b, c = 0; /*error Expected variable declaration to be on a new line. */
let a,
b = 0, c; /*error Expected variable declaration to be on a new line. */
```

The following patterns are not considered problems when set to `"initializations"`:

```js
/*eslint one-var-declaration-per-line: [2, "initializations"]*/
/*eslint-env es6*/
var a, b;
let a,
b;
let a,
b = 0;
```

## Related Rules

* [one-var](one-var.md)
@@ -0,0 +1,74 @@
/**
* @fileoverview Rule to check multiple var declarations per line
* @author Alberto Rodríguez
* @copyright 2016 Alberto Rodríguez. All rights reserved.
* See LICENSE file in root directory for full license.
*/
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function(context) {

var ERROR_MESSAGE = "Expected variable declaration to be on a new line.";
var always = context.options[0] === "always";

//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------


/**
* Determine if provided keyword is a variant of for specifiers
* @private
* @param {string} keyword - keyword to test
* @returns {boolean} True if `keyword` is a variant of for specifier
*/
function isForTypeSpecifier(keyword) {
return keyword === "ForStatement" || keyword === "ForInStatement" || keyword === "ForOfStatement";
}

/**
* Checks newlines around variable declarations.
* @private
* @param {ASTNode} node - `VariableDeclaration` node to test
* @returns {void}
*/
function checkForNewLine(node) {
if (isForTypeSpecifier(node.parent.type)) {
return;
}

var declarations = node.declarations;
var prev;
declarations.forEach(function(current) {
if (prev && prev.loc.end.line === current.loc.start.line) {
if (always || prev.init || current.init) {
context.report({
node: node,
message: ERROR_MESSAGE,
loc: current.loc.start
});
}
}
prev = current;
});
}

//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------

return {
"VariableDeclaration": checkForNewLine
};

};

module.exports.schema = [
{
"enum": ["always", "initializations"]
}
];
@@ -0,0 +1,91 @@
/**
* @fileoverview Tests for one-var-declaration-per-line rule.
* @author Alberto Rodríguez
* @copyright 2016 Alberto Rodríguez. All rights reserved.
* See LICENSE file in root directory for full license.
*/

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

var rule = require("../../../lib/rules/one-var-declaration-per-line"),
RuleTester = require("../../../lib/testers/rule-tester");

//------------------------------------------------------------------------------
// Fixtures
//------------------------------------------------------------------------------

/**
* Returns an error object at the specified line and column
* @private
* @param {int} line - line number
* @param {int} column - column number
* @returns {Oject} Error object
*/
function errorAt(line, column) {
return {
message: "Expected variable declaration to be on a new line.",
type: "VariableDeclaration",
line: line,
column: column
};
}


//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

var ruleTester = new RuleTester();

ruleTester.run("one-var-declaration-per-line", rule, {
valid: [
{code: "var a, b, c,\nd = 0;", options: ["initializations"]},
{code: "var a, b, c,\n\nd = 0;", options: ["initializations"]},
{code: "var a, b,\nc=0\nd = 0;", options: ["initializations"]},
{code: "let a, b;", options: ["initializations"], parserOptions: { ecmaVersion: 6 } },
{code: "var a = 0; var b = 0;", options: ["initializations"]},
{code: "var a, b,\nc=0\nd = 0;"},

{code: "var a,\nb,\nc,\nd = 0;", options: ["always"]},
{code: "var a = 0,\nb;", options: ["always"]},
{code: "var a = 0,\n\nb;", options: ["always"]},

{code: "var a; var b;", options: ["always"]},
{code: "for(var a = 0, b = 0;;){}", options: ["always"]},
{code: "for(let a = 0, b = 0;;){}", options: ["always"], parserOptions: { ecmaVersion: 6 } },
{code: "for(const a = 0, b = 0;;){}", options: ["always"], parserOptions: { ecmaVersion: 6 } },
{code: "for(var a in obj){}", options: ["always"]},
{code: "for(let a in obj){}", options: ["always"], parserOptions: { ecmaVersion: 6 } },
{code: "for(const a in obj){}", options: ["always"], parserOptions: { ecmaVersion: 6 } },
{code: "for(var a of arr){}", options: ["always"], parserOptions: { ecmaVersion: 6 } },
{code: "for(let a of arr){}", options: ["always"], parserOptions: { ecmaVersion: 6 } },
{code: "for(const a of arr){}", options: ["always"], parserOptions: { ecmaVersion: 6 } },

{code: "export let a, b;", options: ["initializations"], parserOptions: { sourceType: "module" } },
{code: "export let a,\n b = 0;", options: ["initializations"], parserOptions: { sourceType: "module" } }
],

invalid: [
{code: "var a, b;", options: ["always"], errors: [errorAt(1, 8)]},
{code: "let a, b;", options: ["always"], errors: [errorAt(1, 8)], parserOptions: { ecmaVersion: 6 } },
{code: "var a, b = 0;", options: ["always"], errors: [errorAt(1, 8)]},
{code: "var a = {\n foo: bar\n}, b;", options: ["always"], errors: [errorAt(3, 4)]},
{code: "var a\n=0, b;", options: ["always"], errors: [errorAt(2, 5)]},
{code: "let a, b = 0;", options: ["always"], errors: [errorAt(1, 8)], parserOptions: { ecmaVersion: 6 } },
{code: "const a = 0, b = 0;", options: ["always"], errors: [errorAt(1, 14)], parserOptions: { ecmaVersion: 6 } },

{code: "var a, b, c = 0;", options: ["initializations"], errors: [errorAt(1, 11)] },
{code: "var a, b,\nc = 0, d;", options: ["initializations"], errors: [errorAt(2, 8)] },
{code: "var a, b,\nc = 0, d = 0;", options: ["initializations"], errors: [errorAt(2, 8)] },
{code: "var a\n=0, b = 0;", options: ["initializations"], errors: [errorAt(2, 5)] },
{code: "var a = {\n foo: bar\n}, b;", options: ["initializations"], errors: [errorAt(3, 4)] },

{code: "for(var a = 0, b = 0;;){\nvar c,d;}", options: ["always"], errors: [errorAt(2, 7)] },
{code: "export let a, b;", options: ["always"], errors: [errorAt(1, 15)], parserOptions: { sourceType: "module" } },
{code: "export let a, b = 0;", options: ["initializations"], errors: [errorAt(1, 15)], parserOptions: { sourceType: "module" } }
]
});

0 comments on commit 79e8a0b

Please sign in to comment.
You can’t perform that action at this time.