From 81fcfef11c2f6162a2fe139e11f2ff9403166e8a Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 May 2020 16:06:28 +0800 Subject: [PATCH] Add destructuring --- docs/rules/prefer-array-find.md | 4 ++ rules/prefer-array-find.js | 27 +++++++++- test/prefer-array-find.js | 89 ++++++++++++++++++++++++++++++++- 3 files changed, 118 insertions(+), 2 deletions(-) diff --git a/docs/rules/prefer-array-find.md b/docs/rules/prefer-array-find.md index eab2afbb72..05b879dd23 100644 --- a/docs/rules/prefer-array-find.md +++ b/docs/rules/prefer-array-find.md @@ -14,6 +14,10 @@ const item = array.filter(x => x === '🦄')[0]; const item = array.filter(x => x === '🦄').shift(); ``` +```js +const [item] = array.filter(x => x === '🦄'); +``` + ## Pass ```js diff --git a/rules/prefer-array-find.js b/rules/prefer-array-find.js index 4988223fd9..08bbc0caaf 100644 --- a/rules/prefer-array-find.js +++ b/rules/prefer-array-find.js @@ -4,6 +4,7 @@ const methodSelector = require('./utils/method-selector'); const MESSAGE_ID_ZERO_INDEX = 'prefer-array-find-over-filter-zero-index'; const MESSAGE_ID_SHIFT = 'prefer-array-find-over-filter-shift'; +const MESSAGE_ID_DESTRUCTURING = 'prefer-array-find-over-filter-destructuring'; const zeroIndexSelector = [ 'MemberExpression', @@ -31,6 +32,19 @@ const shiftSelector = [ }) ].join(''); +const destructuringSelector = [ + 'VariableDeclarator', + '[id.type="ArrayPattern"]', + '[id.elements.length=1]', + '[id.elements.0.type="Identifier"]', + methodSelector({ + name: 'filter', + min: 1, + max: 2, + property: 'init' + }) +].join(''); + const create = context => { return { [zeroIndexSelector](node) { @@ -52,6 +66,16 @@ const create = context => { fixer.removeRange([node.callee.object.range[1], node.range[1]]) ] }); + }, + [destructuringSelector](node) { + context.report({ + node, + messageId: MESSAGE_ID_DECONSTRUCTING, + fix: fixer => [ + fixer.replaceText(node.init.callee.property, 'find'), + fixer.replaceText(node.id, context.getSourceCode().getText(node.id.elements[0])) + ] + }); } }; }; @@ -66,7 +90,8 @@ module.exports = { fixable: 'code', messages: { [MESSAGE_ID_ZERO_INDEX]: 'Prefer `.find(…)` over `.filter(…)[0]`.', - [MESSAGE_ID_SHIFT]: 'Prefer `.find(…)` over `.filter(…).shift()`.' + [MESSAGE_ID_SHIFT]: 'Prefer `.find(…)` over `.filter(…).shift()`.', + [MESSAGE_ID_DESTRUCTURING]: 'Prefer `.find(…)` over destructuring `.filter(…)`.' } } }; diff --git a/test/prefer-array-find.js b/test/prefer-array-find.js index e216b14dc8..8e716b0333 100644 --- a/test/prefer-array-find.js +++ b/test/prefer-array-find.js @@ -5,6 +5,7 @@ import rule from '../rules/prefer-array-find'; const MESSAGE_ID_ZERO_INDEX = 'prefer-array-find-over-filter-zero-index'; const MESSAGE_ID_SHIFT = 'prefer-array-find-over-filter-shift'; +const MESSAGE_ID_DESTRUCTURING = 'prefer-array-find-over-filter-destructuring'; const ruleTester = avaRuleTester(test, { parserOptions: { @@ -39,29 +40,50 @@ ruleTester.run('prefer-array-find', rule, { 'array.filter(foo).shift(extraArgument)', 'array.filter(foo).shift(...[])', + // Test `const [item] = ` + // Not `VariableDeclarator` + '[foo] = array.filter(bar)', + // Not `ArrayPattern` + 'const foo = array.filter(bar)', + 'const {0: foo} = array.filter(bar)', + // `elements` + 'const [] = array.filter(bar)', + 'const [foo, another] = array.filter(bar)', + 'const [, foo] = array.filter(bar)', + 'const [foo = bar] = array.filter(baz)', + 'const [{foo}] = array.filter(bar)', + // Test `.filter()` // Not `CallExpression` 'array.filter[0]', 'array.filter.shift()', + 'const [foo] = array.filter', // Not `MemberExpression` 'filter(foo)[0]', 'filter(foo).shift()', + 'const [foo] = filter(foo)', // `callee.property` is not a `Identifier` 'array["filter"](foo)[0]', 'array["filter"](foo).shift()', + 'const [foo] = array["filter"](bar)', // Computed 'array[filter](foo)[0]', 'array[filter](foo).shift()', + 'const [foo] = array[filter](bar)', // Not `filter` 'array.notFilter(foo)[0]', 'array.notFilter(foo).shift()', + 'const [foo] = array.notFilter(bar)', // More or less argument(s) 'array.filter()[0]', 'array.filter(foo, thisArgument, extraArgument)[0]', 'array.filter(...foo)[0]', 'array.filter().shift()', 'array.filter(foo, thisArgument, extraArgument).shift()', - 'array.filter(...foo).shift()' + 'array.filter(...foo).shift()', + 'const [foo] = array.filter()', + 'const [foo] = array.filter(foo, thisArgument, extraArgument)', + 'const [foo] = array.filter(...foo)' ], invalid: [ { @@ -74,6 +96,36 @@ ruleTester.run('prefer-array-find', rule, { output: 'array.find(foo)', errors: [{messageId: MESSAGE_ID_SHIFT}] }, + { + code: 'const [foo] = array.filter(bar)', + output: 'const foo = array.find(bar)', + errors: [{messageId: MESSAGE_ID_DESTRUCTURING}] + }, + { + code: 'const [foo, ] = array.filter(bar)', + output: 'const foo = array.find(bar)', + errors: [{messageId: MESSAGE_ID_DESTRUCTURING}] + }, + { + code: 'var [foo, ] = array.filter(bar)', + output: 'var foo = array.find(bar)', + errors: [{messageId: MESSAGE_ID_DESTRUCTURING}] + }, + { + code: 'let [foo, ] = array.filter(bar)', + output: 'let foo = array.find(bar)', + errors: [{messageId: MESSAGE_ID_DESTRUCTURING}] + }, + { + code: 'let a = 1, [foo, ] = array.filter(bar)', + output: 'let a = 1, foo = array.find(bar)', + errors: [{messageId: MESSAGE_ID_DESTRUCTURING}] + }, + { + code: 'for (let [i] = array.filter(bar); i< 10; i++) {}', + output: 'for (let i = array.find(bar); i< 10; i++) {}', + errors: [{messageId: MESSAGE_ID_DESTRUCTURING}] + }, { code: 'array.filter(foo, thisArgument)[0]', output: 'array.find(foo, thisArgument)', @@ -84,6 +136,11 @@ ruleTester.run('prefer-array-find', rule, { output: 'array.find(foo, thisArgument)', errors: [{messageId: MESSAGE_ID_SHIFT}] }, + { + code: 'const [foo] = array.filter(bar, thisArgument)', + output: 'const foo = array.find(bar, thisArgument)', + errors: [{messageId: MESSAGE_ID_DESTRUCTURING}] + }, { code: outdent` const item = array @@ -108,6 +165,36 @@ ruleTester.run('prefer-array-find', rule, { ; `, errors: [{messageId: MESSAGE_ID_SHIFT}] + }, + { + code: outdent` + const [ + // comment 1 + item + ] + // comment 2 + = array + // comment 3 + .filter( + // comment 4 + x => x === '🦄' + ) + // comment 5 + ; + `, + output: outdent` + const item + // comment 2 + = array + // comment 3 + .find( + // comment 4 + x => x === '🦄' + ) + // comment 5 + ; + `, + errors: [{messageId: MESSAGE_ID_DESTRUCTURING}] } ] });