Skip to content

Commit

Permalink
New: Add allowImplicit option to array-callback-return (fixes #8539) (#…
Browse files Browse the repository at this point in the history
…9344)

* New: Add allowImplicit option to array-callback-return (fixes #8539)

* Chore: add tests

* Update array-callback-return.md

* chore: rename options

* Update array-callback-return.js

* Update array-callback-return.js

* Update array-callback-return.js

* Improve allowImplicit option description

* Test explicit return when "allowImplicit": true
  • Loading branch information
jamescdavis authored and kaicataldo committed Dec 21, 2017
1 parent e9d5dfd commit ae51eb2
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 3 deletions.
15 changes: 15 additions & 0 deletions docs/rules/array-callback-return.md
Expand Up @@ -72,6 +72,21 @@ var foo = Array.from(nodes, function(node) {
var bar = foo.map(node => node.getAttribute("id"));
```

## Options

This rule has an object option:

* `"allowImplicit": false` (default) When set to true, allows implicitly returning `undefined` with a `return` statement containing no expression.

Examples of **correct** code for the `{ "allowImplicit": true }` option:

```js
/*eslint array-callback-return: ["error", { allowImplicit: true }]*/
var undefAllTheThings = myArray.map(function(item) {
return;
});
```

## Known Limitations

This rule checks callback functions of methods with the given names, *even if* the object which has the method is *not* an array.
Expand Down
18 changes: 16 additions & 2 deletions lib/rules/array-callback-return.js
Expand Up @@ -145,10 +145,23 @@ module.exports = {
recommended: false
},

schema: []
schema: [
{
type: "object",
properties: {
allowImplicit: {
type: "boolean"
}
},
additionalProperties: false
}
]
},

create(context) {

const options = context.options[0] || { allowImplicit: false };

let funcInfo = {
upper: null,
codePath: null,
Expand Down Expand Up @@ -212,7 +225,8 @@ module.exports = {
if (funcInfo.shouldCheck) {
funcInfo.hasReturn = true;

if (!node.argument) {
// if allowImplicit: false, should also check node.argument
if (!options.allowImplicit && !node.argument) {
context.report({
node,
message: "{{name}} expected a return value.",
Expand Down
39 changes: 38 additions & 1 deletion tests/lib/rules/array-callback-return.js
Expand Up @@ -14,11 +14,24 @@ const rule = require("../../../lib/rules/array-callback-return"),

const ruleTester = new RuleTester();

const allowImplicitOptions = [{ allowImplicit: true }];

ruleTester.run("array-callback-return", rule, {
valid: [

// options: { allowImplicit: false }
"Array.from(x, function() { return true; })",
"Int32Array.from(x, function() { return true; })",
{ code: "Array.from(x, function() { return true; })", options: [{ allowImplicit: false }] },
{ code: "Int32Array.from(x, function() { return true; })", options: [{ allowImplicit: false }] },

// options: { allowImplicit: true }
{ code: "Array.from(x, function() { return; })", options: allowImplicitOptions },
{ code: "Int32Array.from(x, function() { return; })", options: allowImplicitOptions },

"Arrow.from(x, function() {})",

// options: { allowImplicit: false }
"foo.every(function() { return true; })",
"foo.filter(function() { return true; })",
"foo.find(function() { return true; })",
Expand All @@ -28,17 +41,39 @@ ruleTester.run("array-callback-return", rule, {
"foo.reduceRight(function() { return true; })",
"foo.some(function() { return true; })",
"foo.sort(function() { return 0; })",

// options: { allowImplicit: true }
{ code: "foo.every(function() { return; })", options: allowImplicitOptions },
{ code: "foo.filter(function() { return; })", options: allowImplicitOptions },
{ code: "foo.find(function() { return; })", options: allowImplicitOptions },
{ code: "foo.findIndex(function() { return; })", options: allowImplicitOptions },
{ code: "foo.map(function() { return; })", options: allowImplicitOptions },
{ code: "foo.reduce(function() { return; })", options: allowImplicitOptions },
{ code: "foo.reduceRight(function() { return; })", options: allowImplicitOptions },
{ code: "foo.some(function() { return; })", options: allowImplicitOptions },
{ code: "foo.sort(function() { return; })", options: allowImplicitOptions },

"foo.abc(function() {})",
"every(function() {})",
"foo[every](function() {})",
"var every = function() {}",
{ code: "foo[`${every}`](function() {})", parserOptions: { ecmaVersion: 6 } },
{ code: "foo.every(() => true)", parserOptions: { ecmaVersion: 6 } },

// options: { allowImplicit: false }
{ code: "foo.every(() => { return true; })", parserOptions: { ecmaVersion: 6 } },
"foo.every(function() { if (a) return true; else return false; })",
"foo.every(function() { switch (a) { case 0: bar(); default: return true; } })",
"foo.every(function() { try { bar(); return true; } catch (err) { return false; } })",
"foo.every(function() { try { bar(); } finally { return true; } })",

// options: { allowImplicit: true }
{ code: "foo.every(() => { return; })", options: allowImplicitOptions, parserOptions: { ecmaVersion: 6 } },
{ code: "foo.every(function() { if (a) return; else return a; })", options: allowImplicitOptions },
{ code: "foo.every(function() { switch (a) { case 0: bar(); default: return; } })", options: allowImplicitOptions },
{ code: "foo.every(function() { try { bar(); return; } catch (err) { return; } })", options: allowImplicitOptions },
{ code: "foo.every(function() { try { bar(); } finally { return; } })", options: allowImplicitOptions },

"foo.every(function(){}())",
"foo.every(function(){ return function() { return true; }; }())",
"foo.every(function(){ return function() { return; }; })",
Expand Down Expand Up @@ -93,6 +128,8 @@ ruleTester.run("array-callback-return", rule, {
{ code: "foo.every(a ? function() {} : function() {})", errors: ["Expected to return a value in function.", "Expected to return a value in function."] },
{ code: "foo.every(a ? function foo() {} : function bar() {})", errors: ["Expected to return a value in function 'foo'.", "Expected to return a value in function 'bar'."] },
{ code: "foo.every(function(){ return function() {}; }())", errors: [{ message: "Expected to return a value in function.", column: 30 }] },
{ code: "foo.every(function(){ return function foo() {}; }())", errors: [{ message: "Expected to return a value in function 'foo'.", column: 39 }] }
{ code: "foo.every(function(){ return function foo() {}; }())", errors: [{ message: "Expected to return a value in function 'foo'.", column: 39 }] },
{ code: "foo.every(() => {})", options: [{ allowImplicit: false }], parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Expected to return a value in arrow function." }] },
{ code: "foo.every(() => {})", options: [{ allowImplicit: true }], parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Expected to return a value in arrow function." }] }
]
});

0 comments on commit ae51eb2

Please sign in to comment.