Skip to content
Permalink
Browse files

New: gen-star rule (refs eslint#1617)

  • Loading branch information...
Jamund Ferguson
Jamund Ferguson committed Jan 11, 2015
1 parent 06eb843 commit 1fd91532f614336817c7c5d98ac4d86a9bc3bead
Showing with 357 additions and 0 deletions.
  1. +1 −0 conf/eslint.json
  2. +1 −0 docs/rules/README.md
  3. +92 −0 docs/rules/generator-star.md
  4. +63 −0 lib/rules/generator-star.js
  5. +200 −0 tests/lib/rules/generator-star.js
@@ -116,6 +116,7 @@
"eqeqeq": 2,
"func-names": 0,
"func-style": [0, "declaration"],
"generator-star": 0,
"global-strict": [2, "never"],
"guard-for-in": 0,
"handle-callback-err": 0,
@@ -172,6 +172,7 @@ These rules are purely matters of style and are quite subjective.
These rules are only relevant to ES6 environments and are off by default.

* [no-var](no-var.md) - require `let` or `const` instead of `var` (off by default)
* [generator-star](generator-star.md) - enforce the position of the `*` in generator functions (off by default)

## Legacy

@@ -0,0 +1,92 @@
# Enforce the position of the * in generators (generator-star)

Generators are a new type of function in ECMAScript 6 that can return multiple values over time.
These special functions are indicated by placing an `*` after the`function` keyword.

Here's an example of a generator function:

```js
function* generator() {
yield "44";
yield "55";
}
```

This is also valid:

```js
function *generator() {
yield "44";
yield "55";
}
```

This is valid as well:

```js
function * generator() {
yield "44";
yield "55";
}
```

To keep a sense of consistency when using generators this rule enforces a single position for the `*`.

## Rule Details

This rule enforces that the `*` is either placed next to the `function` keyword or the name of the function. The single
option for this rule is a string specifying the placement of the asterick. For this option you may pass either
`"start"` or `"end"`. The default is `"end"`.

You can set the style in configuration like this:

```json
"generator-star": [2, "start"]
```

When using `"start"` this syntax will be enforced:

```js
function* generator() {
}
```

When using `"end"` this syntax will be enforced:

```js
function *generator() {
}
```

When using the expression syntax `"start"` will be enforced here:

```js
var generator = function* () {
}
```

When using the expression syntax `"end"` will be enforced here:

```js
var generator = function *() {
}
```
When using the expression syntax this is valid for both `"start"` and `"end"`:

```js
var generator = function*() {
}
```

If you intend to use this rule, you must set the `{ "generators": true }` flag in the `ecmaFeatures` configuration
object to give ESLint the ability to understand generators.

Also note, that shortened object literal syntax for generators is not affected by this rule.

## When Not To Use It

If your project will not be using generators you do not need this rule.

## Further Reading

* [Understanding ES6: Generators](https://leanpub.com/understandinges6/read/#leanpub-auto-generators)
@@ -0,0 +1,63 @@
/**
* @fileoverview Rule to check for the position of the * in your generator functions
* @author Jamund Ferguson
* @copyright 2014 Jamund Ferguson. All rights reserved.
*/

"use strict";

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

module.exports = function(context) {

var position = context.options[0] || "end";

/**
* Check the position of the start compared to the expected position.
* @param {Object} node - the entire function node
* @param {Object} starToken - the star token
* @returns {void}
*/
function checkStarPosition(node, starToken) {

if (!node.generator) {
return;
}

// check for function *name() {}
if (position === "end") {

// * starts where the next identifier begins
if (starToken.range[1] !== context.getTokenAfter(starToken).range[0]) {
context.report(node, "Expected a space before *.");
}
}

// check for function* name() {}
if (position === "start") {

// * ends where the previous identifier ends
if (starToken.range[0] !== context.getTokenBefore(starToken).range[1]) {
context.report(node, "Expected no space before *.");
}
}
}

return {

"FunctionDeclaration": function (node) {
var starToken = context.getTokenBefore(node.id);
checkStarPosition(node, starToken);
},

"FunctionExpression": function (node) {

// count back an extra token if you have a named anonymous function
var starToken = context.getTokenBefore(node.body, node.id ? 3 : 2);
checkStarPosition(node, starToken);
}
};

};
@@ -0,0 +1,200 @@
/**
* @fileoverview Tests for generator-star rule.
* @author Jamund Ferguson
* @copyright 2014 Jamund Ferguson. All rights reserved.
*/

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

var eslint = require("../../../lib/eslint"),
ESLintTester = require("eslint-tester");

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

var eslintTester = new ESLintTester(eslint);
eslintTester.addRuleTest("lib/rules/generator-star", {
valid: [
{
code: "function *foo(){}",
ecmaFeatures: { "generators": true }
},
{
code: "function* foo(){}",
args: [1, "start"],
ecmaFeatures: { "generators": true }
},
{
code: "function *foo(){}",
args: [1, "end"],
ecmaFeatures: { "generators": true }
},
{
code: "var foo = function* foo(){}",
args: [1, "start"],
ecmaFeatures: { "generators": true }
},
{
code: "var foo = function *(){}",
args: [1, "end"],
ecmaFeatures: { "generators": true }
},
{
code: "var foo = function* foo(){}",
args: [1, "start"],
ecmaFeatures: { "generators": true }
},
{
code: "var foo = function *foo(){}",
args: [1, "end"],
ecmaFeatures: { "generators": true }
},
{
code: "var foo = function* foo(){}",
args: [1, "start"],
ecmaFeatures: { "generators": true }
},
{
code: "var foo = function *foo(){}",
args: [1, "end"],
ecmaFeatures: { "generators": true }
},
{
code: "var x = { *foo(){} }",
args: [1, "start"],
ecmaFeatures: { "generators": true, "objectLiteralShorthandMethods": true }
},
{
code: "var x = { *foo(){} }",
args: [1, "end"],
ecmaFeatures: { "generators": true, "objectLiteralShorthandMethods": true }
},
{
code: "var foo = function*(){}",
args: [1, "start"],
ecmaFeatures: { "generators": true }
},
{
code: "var foo = function*(){}",
args: [1, "end"],
ecmaFeatures: { "generators": true }
}
],

invalid: [
{
code: "function * foo(){}",
args: [1, "start"],
ecmaFeatures: {"generators": true},
errors: [
{
message: "Expected no space before *.",
type: "FunctionDeclaration"
}
]
},
{
code: "function * foo(){}",
args: [1, "end"],
ecmaFeatures: {"generators": true},
errors: [
{
message: "Expected a space before *.",
type: "FunctionDeclaration"
}
]
},
{
code: "function *foo(){}",
ecmaFeatures: {"generators": true},
args: [1, "start"],
errors: [
{
message: "Expected no space before *.",
type: "FunctionDeclaration"
}
]
},
{
code: "var foo = function* (){}",
args: [1, "end"],
ecmaFeatures: { "generators": true },
errors: [
{
message: "Expected a space before *.",
type: "FunctionExpression"
}
]
},
{
code: "var foo = function * (){}",
args: [1, "start"],
ecmaFeatures: { "generators": true },
errors: [
{
message: "Expected no space before *.",
type: "FunctionExpression"
}
]
},
{
code: "var foo = function * (){}",
args: [1, "end"],
ecmaFeatures: { "generators": true },
errors: [
{
message: "Expected a space before *.",
type: "FunctionExpression"
}
]
},
{
code: "var foo = function* foo(){}",
args: [1, "end"],
ecmaFeatures: { "generators": true },
errors: [
{
message: "Expected a space before *.",
type: "FunctionExpression"
}
]
},
{
code: "var foo = function *foo(){}",
args: [1, "start"],
ecmaFeatures: { "generators": true },
errors: [
{
message: "Expected no space before *.",
type: "FunctionExpression"
}
]
},
{
code: "var foo = function * foo(){}",
args: [1, "end"],
ecmaFeatures: { "generators": true },
errors: [
{
message: "Expected a space before *.",
type: "FunctionExpression"
}
]
},
{
code: "var foo = function * foo(){}",
args: [1, "start"],
ecmaFeatures: { "generators": true },
errors: [
{
message: "Expected no space before *.",
type: "FunctionExpression"
}
]
}

]
});

0 comments on commit 1fd9153

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