From de2865911a570a062dd1d832dca68079934b9ebe Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Mon, 7 Nov 2022 17:08:18 +0800 Subject: [PATCH 01/12] Basic --- configs/recommended.js | 1 + docs/rules/prefer-set-size.md | 16 +++++ rules/prefer-set-size.js | 87 ++++++++++++++++++++++++ test/prefer-set-size.mjs | 25 +++++++ test/snapshots/prefer-set-size.mjs.md | 21 ++++++ test/snapshots/prefer-set-size.mjs.snap | Bin 0 -> 175 bytes 6 files changed, 150 insertions(+) create mode 100644 docs/rules/prefer-set-size.md create mode 100644 rules/prefer-set-size.js create mode 100644 test/prefer-set-size.mjs create mode 100644 test/snapshots/prefer-set-size.mjs.md create mode 100644 test/snapshots/prefer-set-size.mjs.snap diff --git a/configs/recommended.js b/configs/recommended.js index 2e7ffd8713..a1d26d031a 100644 --- a/configs/recommended.js +++ b/configs/recommended.js @@ -101,6 +101,7 @@ module.exports = { 'unicorn/prefer-reflect-apply': 'error', 'unicorn/prefer-regexp-test': 'error', 'unicorn/prefer-set-has': 'error', + 'unicorn/prefer-set-size': 'error', 'unicorn/prefer-spread': 'error', // TODO: Enable this by default when targeting Node.js 16. 'unicorn/prefer-string-replace-all': 'off', diff --git a/docs/rules/prefer-set-size.md b/docs/rules/prefer-set-size.md new file mode 100644 index 0000000000..70070de78b --- /dev/null +++ b/docs/rules/prefer-set-size.md @@ -0,0 +1,16 @@ + + + + + +## Fail + +```js +const foo = 'unicorn'; +``` + +## Pass + +```js +const foo = '🦄'; +``` diff --git a/rules/prefer-set-size.js b/rules/prefer-set-size.js new file mode 100644 index 0000000000..85a278cb5f --- /dev/null +++ b/rules/prefer-set-size.js @@ -0,0 +1,87 @@ +'use strict'; +const { + memberExpressionSelector, + newExpressionSelector, +} = require('./selectors/index.js'); +const {} = require('./fix/index.js'); +const { findVariable } = require('eslint-utils'); + +const MESSAGE_ID = 'prefer-set-size'; +const messages = { + [MESSAGE_ID]: 'Prefer use `Set#size`.' +} + +const lengthAccessSelector = [ + memberExpressionSelector('length'), + '[object.type="ArrayExpression"]', + '[object.elements.length=1]', + '[object.elements.0.type="SpreadElement"]', +].join(''); + +const isNewSet = node => + node.type === 'NewExpression' + && node.callee.type === 'Identifier' + && node.callee.name === 'Set'; + +function isSet(node, scope) { + if (isNewSet(node)) { + return true; + } + + + if (node.type !== 'Identifier') { + return false; + } + + const variable = findVariable(scope, maybeSet); +} + + +// `[...set].length` -> `set.size` +function fix(sourceCode, lengthAccessNodes) { + const { + object: arrayExpression, + property + } = lengthAccessNodes; + const set = arrayExpression.elements[0].argument; + + /** @param {import('eslint').Rule.RuleFixer} fixer */ + return function * (fixer) { + yield fixer.replaceText(property, 'size'); + yield fixer.replaceText(arrayExpression, sourceCode.getText(set)); + } +} + +/** @param {import('eslint').Rule.RuleContext} context */ +const create = context => { + const sourceCode = context.getSourceCode(); + + return { + [lengthAccessSelector](node) { + const maybeSet = node.object.elements[0].argument; + if (!isSet(maybeSet, context.getScope())) { + return; + } + + return { + node: node.property, + messageId: MESSAGE_ID, + fix: fix(sourceCode, node), + } + } + }; +}; + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + create, + meta: { + type: 'suggestion', + docs: { + description: 'Prefer use `Set#size` instead of `Array#length`.', + }, + fixable: 'code', + + messages, + }, +}; diff --git a/test/prefer-set-size.mjs b/test/prefer-set-size.mjs new file mode 100644 index 0000000000..5cf306d58a --- /dev/null +++ b/test/prefer-set-size.mjs @@ -0,0 +1,25 @@ +import outdent from 'outdent'; +import {getTester} from './utils/test.mjs'; + +const {test} = getTester(import.meta); + +test.snapshot({ + valid: [ + // 'new Set(foo).size', + // 'for (const foo of bar) console.log([...foo].length)', + // '[...new Set(array), foo].length', + // '[foo, ...new Set(array), ].length', + // '[...new Set(array)].notLength', + // '[...new Set(array)].length()', + // '[...new Set(array)]?.length', + // '[...new Set(array)][length]', + // '[...new Set(array)]["length"]', + ], + invalid: [ + '[...new Set(array)].length', + // outdent` + // const foo = new Set([]); + // console.log([...foo].length); + // `, + ], +}); diff --git a/test/snapshots/prefer-set-size.mjs.md b/test/snapshots/prefer-set-size.mjs.md new file mode 100644 index 0000000000..bb34915d88 --- /dev/null +++ b/test/snapshots/prefer-set-size.mjs.md @@ -0,0 +1,21 @@ +# Snapshot report for `test/prefer-set-size.mjs` + +The actual snapshot is saved in `prefer-set-size.mjs.snap`. + +Generated by [AVA](https://avajs.dev). + +## Invalid #1 + 1 | [...new Set(array)].length + +> Output + + `␊ + 1 | new Set(array).size␊ + ` + +> Error 1/1 + + `␊ + > 1 | [...new Set(array)].length␊ + | ^^^^^^ Prefer use \`Set#size\`.␊ + ` diff --git a/test/snapshots/prefer-set-size.mjs.snap b/test/snapshots/prefer-set-size.mjs.snap new file mode 100644 index 0000000000000000000000000000000000000000..b89b3f66ca9b3cca6036711527618e838404f293 GIT binary patch literal 175 zcmV;g08sxyRzVFmP900Np&JQ0YQ8Q8&MjI0cTjM7{R3Wf?b3VEsJ z3c;x*8i_?kiItjq#hF#9Tqp{oxa`0RqxJOkP!-4O<)r4Nmt+7 Date: Mon, 7 Nov 2022 17:18:26 +0800 Subject: [PATCH 02/12] Variable --- rules/prefer-set-size.js | 19 +++++++++++++++++-- test/prefer-set-size.mjs | 8 ++++---- test/snapshots/prefer-set-size.mjs.md | 19 +++++++++++++++++++ test/snapshots/prefer-set-size.mjs.snap | Bin 175 -> 263 bytes 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/rules/prefer-set-size.js b/rules/prefer-set-size.js index 85a278cb5f..ba33f3d66a 100644 --- a/rules/prefer-set-size.js +++ b/rules/prefer-set-size.js @@ -19,7 +19,7 @@ const lengthAccessSelector = [ ].join(''); const isNewSet = node => - node.type === 'NewExpression' + node?.type === 'NewExpression' && node.callee.type === 'Identifier' && node.callee.name === 'Set'; @@ -33,7 +33,22 @@ function isSet(node, scope) { return false; } - const variable = findVariable(scope, maybeSet); + const variable = findVariable(scope, node); + + if (!variable || variable.defs.length !== 1) { + return false; + } + + const [definition] = variable.defs; + + if (definition.type !== 'Variable' || definition.kind !== 'const') { + return false; + } + + const declarator = definition.node; + return declarator.type === 'VariableDeclarator' + && declarator.id.type === 'Identifier' + && isNewSet(definition.node.init) } diff --git a/test/prefer-set-size.mjs b/test/prefer-set-size.mjs index 5cf306d58a..fab46823d5 100644 --- a/test/prefer-set-size.mjs +++ b/test/prefer-set-size.mjs @@ -17,9 +17,9 @@ test.snapshot({ ], invalid: [ '[...new Set(array)].length', - // outdent` - // const foo = new Set([]); - // console.log([...foo].length); - // `, + outdent` + const foo = new Set([]); + console.log([...foo].length); + `, ], }); diff --git a/test/snapshots/prefer-set-size.mjs.md b/test/snapshots/prefer-set-size.mjs.md index bb34915d88..298a7d362e 100644 --- a/test/snapshots/prefer-set-size.mjs.md +++ b/test/snapshots/prefer-set-size.mjs.md @@ -19,3 +19,22 @@ Generated by [AVA](https://avajs.dev). > 1 | [...new Set(array)].length␊ | ^^^^^^ Prefer use \`Set#size\`.␊ ` + +## Invalid #2 + 1 | const foo = new Set([]); + 2 | console.log([...foo].length); + +> Output + + `␊ + 1 | const foo = new Set([]);␊ + 2 | console.log(foo.size);␊ + ` + +> Error 1/1 + + `␊ + 1 | const foo = new Set([]);␊ + > 2 | console.log([...foo].length);␊ + | ^^^^^^ Prefer use \`Set#size\`.␊ + ` diff --git a/test/snapshots/prefer-set-size.mjs.snap b/test/snapshots/prefer-set-size.mjs.snap index b89b3f66ca9b3cca6036711527618e838404f293..8183f2ea3c6ba55df9e78847c7510a61b128a50b 100644 GIT binary patch literal 263 zcmV+i0r>twRzVasfLqa5cOQ!g00000000B? zVqjokV)$^J?L*)J&24LP*u(`Knw6LsK)@S{uL1GTg2#uiPc_cmwP5}4QcGtSCa~y# zC{AZ&U|?oo2kT;FWe{YvDLIJw2epSiPLoy!4U`uyqPRHCRC$7$^i3 zrKY78DU=qcDkK1nRt7mGK@Zg_(omEZDu%fUkBjg- N2mn;7>mRWJ008f6ZM*;g literal 175 zcmV;g08sxyRzVFmP900Np&JQ0YQ8Q8&MjI0cTjM7{R3Wf?b3VEsJ z3c;x*8i_?kiItjq#hF#9Tqp{oxa`0RqxJOkP!-4O<)r4Nmt+7 Date: Mon, 7 Nov 2022 17:19:36 +0800 Subject: [PATCH 03/12] Valid tests --- test/prefer-set-size.mjs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/test/prefer-set-size.mjs b/test/prefer-set-size.mjs index fab46823d5..16bce6e40c 100644 --- a/test/prefer-set-size.mjs +++ b/test/prefer-set-size.mjs @@ -5,15 +5,16 @@ const {test} = getTester(import.meta); test.snapshot({ valid: [ - // 'new Set(foo).size', - // 'for (const foo of bar) console.log([...foo].length)', - // '[...new Set(array), foo].length', - // '[foo, ...new Set(array), ].length', - // '[...new Set(array)].notLength', - // '[...new Set(array)].length()', - // '[...new Set(array)]?.length', - // '[...new Set(array)][length]', - // '[...new Set(array)]["length"]', + 'new Set(foo).size', + 'for (const foo of bar) console.log([...foo].length)', + '[...new Set(array), foo].length', + '[foo, ...new Set(array), ].length', + '[...new Set(array)].notLength', + '[...new Set(array)]?.length', + '[...new Set(array)][length]', + '[...new Set(array)]["length"]', + '[...new NotSet(array)].length', + '[...Set(array)].length', ], invalid: [ '[...new Set(array)].length', From e0862b35033a72a23ef8fb7a1ecaa564e5d5748a Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Mon, 7 Nov 2022 17:21:04 +0800 Subject: [PATCH 04/12] More valid test --- test/prefer-set-size.mjs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/prefer-set-size.mjs b/test/prefer-set-size.mjs index 16bce6e40c..5afd7a0e7e 100644 --- a/test/prefer-set-size.mjs +++ b/test/prefer-set-size.mjs @@ -15,6 +15,9 @@ test.snapshot({ '[...new Set(array)]["length"]', '[...new NotSet(array)].length', '[...Set(array)].length', + 'const foo = new NotSet([]);[...foo].length;', + 'const {foo} = new Set([]);[...foo].length;', + 'const [foo] = new Set([]);[...foo].length;', ], invalid: [ '[...new Set(array)].length', From ab8c75942be5d8fd4d0aba6043b80f39a06f5760 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Mon, 7 Nov 2022 17:26:24 +0800 Subject: [PATCH 05/12] Edge case --- rules/prefer-set-size.js | 3 ++- test/prefer-set-size.mjs | 5 +++++ test/snapshots/prefer-set-size.mjs.md | 22 ++++++++++++++++++++++ test/snapshots/prefer-set-size.mjs.snap | Bin 263 -> 368 bytes 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/rules/prefer-set-size.js b/rules/prefer-set-size.js index ba33f3d66a..b9a6444edb 100644 --- a/rules/prefer-set-size.js +++ b/rules/prefer-set-size.js @@ -3,7 +3,7 @@ const { memberExpressionSelector, newExpressionSelector, } = require('./selectors/index.js'); -const {} = require('./fix/index.js'); +const { fixSpaceAroundKeyword } = require('./fix/index.js'); const { findVariable } = require('eslint-utils'); const MESSAGE_ID = 'prefer-set-size'; @@ -64,6 +64,7 @@ function fix(sourceCode, lengthAccessNodes) { return function * (fixer) { yield fixer.replaceText(property, 'size'); yield fixer.replaceText(arrayExpression, sourceCode.getText(set)); + yield * fixSpaceAroundKeyword(fixer, lengthAccessNodes, sourceCode) } } diff --git a/test/prefer-set-size.mjs b/test/prefer-set-size.mjs index 5afd7a0e7e..adbdbb5ad4 100644 --- a/test/prefer-set-size.mjs +++ b/test/prefer-set-size.mjs @@ -25,5 +25,10 @@ test.snapshot({ const foo = new Set([]); console.log([...foo].length); `, + outdent` + function isUnique(array) { + return[...new Set(array)].length === array.length + } + `, ], }); diff --git a/test/snapshots/prefer-set-size.mjs.md b/test/snapshots/prefer-set-size.mjs.md index 298a7d362e..b2ab835c61 100644 --- a/test/snapshots/prefer-set-size.mjs.md +++ b/test/snapshots/prefer-set-size.mjs.md @@ -38,3 +38,25 @@ Generated by [AVA](https://avajs.dev). > 2 | console.log([...foo].length);␊ | ^^^^^^ Prefer use \`Set#size\`.␊ ` + +## Invalid #3 + 1 | function isUnique(array) { + 2 | return[...new Set(array)].length === array.length + 3 | } + +> Output + + `␊ + 1 | function isUnique(array) {␊ + 2 | return new Set(array).size === array.length␊ + 3 | }␊ + ` + +> Error 1/1 + + `␊ + 1 | function isUnique(array) {␊ + > 2 | return[...new Set(array)].length === array.length␊ + | ^^^^^^ Prefer use \`Set#size\`.␊ + 3 | }␊ + ` diff --git a/test/snapshots/prefer-set-size.mjs.snap b/test/snapshots/prefer-set-size.mjs.snap index 8183f2ea3c6ba55df9e78847c7510a61b128a50b..cf4d0a4bb632a7c89136dcac7586e27096c6e180 100644 GIT binary patch literal 368 zcmV-$0gwJcRzVriAC9wq2t1&#A6 zwN(J~^>R}4(n~UcT8x2OYPpcDVp_yN*e*L{yQ1~<^iZvfg<62kMg@>Y1)Lxb3={&2 zQqxk46iSOz6%v5vDudjgpoi7LjJ8nsCgtwRzVasfLqa5cOQ!g00000000B? zVqjokV)$^J?L*)J&24LP*u(`Knw6LsK)@S{uL1GTg2#uiPc_cmwP5}4QcGtSCa~y# zC{AZ&U|?oo2kT;FWe{YvDLIJw2epSiPLoy!4U`uyqPRHCRC$7$^i3 zrKY78DU=qcDkK1nRt7mGK@Zg_(omEZDu%fUkBjg- N2mn;7>mRWJ008f6ZM*;g From bcf7dafd8a14c865f9a6aef590fe5f00112373fa Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Mon, 7 Nov 2022 17:34:47 +0800 Subject: [PATCH 06/12] Keep comments --- rules/prefer-set-size.js | 5 +- test/prefer-set-size.mjs | 10 +++ test/snapshots/prefer-set-size.mjs.md | 93 ++++++++++++++++++++++++ test/snapshots/prefer-set-size.mjs.snap | Bin 368 -> 640 bytes 4 files changed, 107 insertions(+), 1 deletion(-) diff --git a/rules/prefer-set-size.js b/rules/prefer-set-size.js index b9a6444edb..97b745c222 100644 --- a/rules/prefer-set-size.js +++ b/rules/prefer-set-size.js @@ -60,6 +60,10 @@ function fix(sourceCode, lengthAccessNodes) { } = lengthAccessNodes; const set = arrayExpression.elements[0].argument; + if (sourceCode.getCommentsInside(arrayExpression).length > sourceCode.getCommentsInside(set).length) { + return; + } + /** @param {import('eslint').Rule.RuleFixer} fixer */ return function * (fixer) { yield fixer.replaceText(property, 'size'); @@ -97,7 +101,6 @@ module.exports = { description: 'Prefer use `Set#size` instead of `Array#length`.', }, fixable: 'code', - messages, }, }; diff --git a/test/prefer-set-size.mjs b/test/prefer-set-size.mjs index adbdbb5ad4..3d2f7e3e98 100644 --- a/test/prefer-set-size.mjs +++ b/test/prefer-set-size.mjs @@ -16,6 +16,7 @@ test.snapshot({ '[...new NotSet(array)].length', '[...Set(array)].length', 'const foo = new NotSet([]);[...foo].length;', + 'let foo = new Set([]);[...foo].length;', 'const {foo} = new Set([]);[...foo].length;', 'const [foo] = new Set([]);[...foo].length;', ], @@ -30,5 +31,14 @@ test.snapshot({ return[...new Set(array)].length === array.length } `, + '[...new Set(array),].length', + '[...(( new Set(array) ))].length', + '(( [...new Set(array)] )).length', + outdent` + foo + ;[...new Set(array)].length + `, + '[/* comment */...new Set(array)].length', + '[...new /* comment */ Set(array)].length', ], }); diff --git a/test/snapshots/prefer-set-size.mjs.md b/test/snapshots/prefer-set-size.mjs.md index b2ab835c61..bccbbc7820 100644 --- a/test/snapshots/prefer-set-size.mjs.md +++ b/test/snapshots/prefer-set-size.mjs.md @@ -60,3 +60,96 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^ Prefer use \`Set#size\`.␊ 3 | }␊ ` + +## Invalid #4 + 1 | [...new Set(array),].length + +> Output + + `␊ + 1 | new Set(array).size␊ + ` + +> Error 1/1 + + `␊ + > 1 | [...new Set(array),].length␊ + | ^^^^^^ Prefer use \`Set#size\`.␊ + ` + +## Invalid #5 + 1 | [...(( new Set(array) ))].length + +> Output + + `␊ + 1 | new Set(array).size␊ + ` + +> Error 1/1 + + `␊ + > 1 | [...(( new Set(array) ))].length␊ + | ^^^^^^ Prefer use \`Set#size\`.␊ + ` + +## Invalid #6 + 1 | (( [...new Set(array)] )).length + +> Output + + `␊ + 1 | (( new Set(array) )).size␊ + ` + +> Error 1/1 + + `␊ + > 1 | (( [...new Set(array)] )).length␊ + | ^^^^^^ Prefer use \`Set#size\`.␊ + ` + +## Invalid #7 + 1 | foo + 2 | ;[...new Set(array)].length + +> Output + + `␊ + 1 | foo␊ + 2 | ;new Set(array).size␊ + ` + +> Error 1/1 + + `␊ + 1 | foo␊ + > 2 | ;[...new Set(array)].length␊ + | ^^^^^^ Prefer use \`Set#size\`.␊ + ` + +## Invalid #8 + 1 | [/* comment */...new Set(array)].length + +> Error 1/1 + + `␊ + > 1 | [/* comment */...new Set(array)].length␊ + | ^^^^^^ Prefer use \`Set#size\`.␊ + ` + +## Invalid #9 + 1 | [...new /* comment */ Set(array)].length + +> Output + + `␊ + 1 | new /* comment */ Set(array).size␊ + ` + +> Error 1/1 + + `␊ + > 1 | [...new /* comment */ Set(array)].length␊ + | ^^^^^^ Prefer use \`Set#size\`.␊ + ` diff --git a/test/snapshots/prefer-set-size.mjs.snap b/test/snapshots/prefer-set-size.mjs.snap index cf4d0a4bb632a7c89136dcac7586e27096c6e180..07b840cea5b9698704e162f46a5f675c08817a46 100644 GIT binary patch literal 640 zcmV-`0)PEMRzVrUPfi}_%A%#FeAZP+&^-rA}826vN$mx2helEN0KPIr~PAIko zDm2Q}VXbu!V0Afqso_}?2-fr8Dw|&ma5q`!57WHO=;6FgT zlkM}_1tuvUB+%Ckc7Dj@z@ z@c8icsm7VR7OekWYU%941Qxvv#nx;L49pDd;ILt2We{X6;j&XORH#vi*4I)<&d<$F z%_~vR($~||%S$a+2u>~0NGvK!tkjIv%Sp{kFUjCi0D>9?f*=kI6atD;(^88RN{dq! z5`cy&7iU(bCg^dYxIhzVCddUK3sD?_WW63pBdWGCn8TrN#if;0my_ajMX1v?G!#&S zOFcSfp1_tSiOvhOa9j*phD9jWp>lZH zLY2LJ#xs2`F5 literal 368 zcmV-$0gwJcRzVriAC9wq2t1&#A6 zwN(J~^>R}4(n~UcT8x2OYPpcDVp_yN*e*L{yQ1~<^iZvfg<62kMg@>Y1)Lxb3={&2 zQqxk46iSOz6%v5vDudjgpoi7LjJ8nsCg Date: Mon, 7 Nov 2022 17:42:29 +0800 Subject: [PATCH 07/12] Docs --- docs/rules/prefer-set-size.md | 10 +++++++--- rules/prefer-set-size.js | 11 ++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/rules/prefer-set-size.md b/docs/rules/prefer-set-size.md index 70070de78b..d1174e28ca 100644 --- a/docs/rules/prefer-set-size.md +++ b/docs/rules/prefer-set-size.md @@ -1,16 +1,20 @@ - +Prefer use `Set#size` directly instead of convert it to an array, and use `.length` of the array. ## Fail ```js -const foo = 'unicorn'; +function isUnique(array) { + return [...new Set(array)].length === array.length; +} ``` ## Pass ```js -const foo = '🦄'; +function isUnique(array) { + return new Set(array).size === array.length; +} ``` diff --git a/rules/prefer-set-size.js b/rules/prefer-set-size.js index 97b745c222..7d4a5a6010 100644 --- a/rules/prefer-set-size.js +++ b/rules/prefer-set-size.js @@ -1,14 +1,11 @@ 'use strict'; -const { - memberExpressionSelector, - newExpressionSelector, -} = require('./selectors/index.js'); -const { fixSpaceAroundKeyword } = require('./fix/index.js'); const { findVariable } = require('eslint-utils'); +const {memberExpressionSelector} = require('./selectors/index.js'); +const { fixSpaceAroundKeyword } = require('./fix/index.js'); const MESSAGE_ID = 'prefer-set-size'; const messages = { - [MESSAGE_ID]: 'Prefer use `Set#size`.' + [MESSAGE_ID]: 'Prefer use `Set#size` instead of `Array#length`.' } const lengthAccessSelector = [ @@ -98,7 +95,7 @@ module.exports = { meta: { type: 'suggestion', docs: { - description: 'Prefer use `Set#size` instead of `Array#length`.', + description: 'Prefer use `Set#size` instead of convert it to Array first.', }, fixable: 'code', messages, From 0be530b8c193331bd00fc5d447f7be51c7449b2f Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Mon, 7 Nov 2022 18:53:14 +0800 Subject: [PATCH 08/12] Linting --- docs/rules/prefer-set-size.md | 6 ++++++ readme.md | 1 + rules/prefer-set-size.js | 22 ++++++++++------------ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/docs/rules/prefer-set-size.md b/docs/rules/prefer-set-size.md index d1174e28ca..00f082fd92 100644 --- a/docs/rules/prefer-set-size.md +++ b/docs/rules/prefer-set-size.md @@ -1,3 +1,9 @@ +# Prefer use `Set#size` instead of convert it to Array first + +✅ This rule is enabled in the `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs). + +🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). + diff --git a/readme.md b/readme.md index faa635af74..acef8d442d 100644 --- a/readme.md +++ b/readme.md @@ -139,6 +139,7 @@ Use a [preset config](#preset-configs) or configure each rules in `package.json` | [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | ✅ | 🔧 | | | [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ | 🔧 | | | [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | +| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer use `Set#size` instead of convert it to Array first. | ✅ | 🔧 | | | [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#slice()` and `String#split('')`. | ✅ | 🔧 | 💡 | | [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | | 🔧 | | | [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | | diff --git a/rules/prefer-set-size.js b/rules/prefer-set-size.js index 7d4a5a6010..214321f210 100644 --- a/rules/prefer-set-size.js +++ b/rules/prefer-set-size.js @@ -1,12 +1,12 @@ 'use strict'; -const { findVariable } = require('eslint-utils'); +const {findVariable} = require('eslint-utils'); const {memberExpressionSelector} = require('./selectors/index.js'); -const { fixSpaceAroundKeyword } = require('./fix/index.js'); +const {fixSpaceAroundKeyword} = require('./fix/index.js'); const MESSAGE_ID = 'prefer-set-size'; const messages = { - [MESSAGE_ID]: 'Prefer use `Set#size` instead of `Array#length`.' -} + [MESSAGE_ID]: 'Prefer use `Set#size` instead of `Array#length`.', +}; const lengthAccessSelector = [ memberExpressionSelector('length'), @@ -25,7 +25,6 @@ function isSet(node, scope) { return true; } - if (node.type !== 'Identifier') { return false; } @@ -45,15 +44,14 @@ function isSet(node, scope) { const declarator = definition.node; return declarator.type === 'VariableDeclarator' && declarator.id.type === 'Identifier' - && isNewSet(definition.node.init) + && isNewSet(definition.node.init); } - // `[...set].length` -> `set.size` function fix(sourceCode, lengthAccessNodes) { const { object: arrayExpression, - property + property, } = lengthAccessNodes; const set = arrayExpression.elements[0].argument; @@ -65,8 +63,8 @@ function fix(sourceCode, lengthAccessNodes) { return function * (fixer) { yield fixer.replaceText(property, 'size'); yield fixer.replaceText(arrayExpression, sourceCode.getText(set)); - yield * fixSpaceAroundKeyword(fixer, lengthAccessNodes, sourceCode) - } + yield * fixSpaceAroundKeyword(fixer, lengthAccessNodes, sourceCode); + }; } /** @param {import('eslint').Rule.RuleContext} context */ @@ -84,8 +82,8 @@ const create = context => { node: node.property, messageId: MESSAGE_ID, fix: fix(sourceCode, node), - } - } + }; + }, }; }; From f99a2031b7e84ea0c722cbbdeca7c7195774a834 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Mon, 7 Nov 2022 19:04:53 +0800 Subject: [PATCH 09/12] Fix snapshots --- test/snapshots/prefer-set-size.mjs.md | 18 +++++++++--------- test/snapshots/prefer-set-size.mjs.snap | Bin 640 -> 668 bytes 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/snapshots/prefer-set-size.mjs.md b/test/snapshots/prefer-set-size.mjs.md index bccbbc7820..72b1c65d28 100644 --- a/test/snapshots/prefer-set-size.mjs.md +++ b/test/snapshots/prefer-set-size.mjs.md @@ -17,7 +17,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | [...new Set(array)].length␊ - | ^^^^^^ Prefer use \`Set#size\`.␊ + | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #2 @@ -36,7 +36,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | const foo = new Set([]);␊ > 2 | console.log([...foo].length);␊ - | ^^^^^^ Prefer use \`Set#size\`.␊ + | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #3 @@ -57,7 +57,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | function isUnique(array) {␊ > 2 | return[...new Set(array)].length === array.length␊ - | ^^^^^^ Prefer use \`Set#size\`.␊ + | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ 3 | }␊ ` @@ -74,7 +74,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | [...new Set(array),].length␊ - | ^^^^^^ Prefer use \`Set#size\`.␊ + | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #5 @@ -90,7 +90,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | [...(( new Set(array) ))].length␊ - | ^^^^^^ Prefer use \`Set#size\`.␊ + | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #6 @@ -106,7 +106,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | (( [...new Set(array)] )).length␊ - | ^^^^^^ Prefer use \`Set#size\`.␊ + | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #7 @@ -125,7 +125,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | foo␊ > 2 | ;[...new Set(array)].length␊ - | ^^^^^^ Prefer use \`Set#size\`.␊ + | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #8 @@ -135,7 +135,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | [/* comment */...new Set(array)].length␊ - | ^^^^^^ Prefer use \`Set#size\`.␊ + | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #9 @@ -151,5 +151,5 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | [...new /* comment */ Set(array)].length␊ - | ^^^^^^ Prefer use \`Set#size\`.␊ + | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ ` diff --git a/test/snapshots/prefer-set-size.mjs.snap b/test/snapshots/prefer-set-size.mjs.snap index 07b840cea5b9698704e162f46a5f675c08817a46..210745af4bb9c1ca998247142547ea9745730883 100644 GIT binary patch delta 645 zcmV;00($*`1)K#UK~_N^Q*L2!b7*gLAa*he0svWMVk?loVk2+{+QOAX2zQYpB!8F- z#Oj|qH!$u$d6CogQ2ktX*?&x6(JN3~3{+^8mD%BKCo)5A9^cv~#;E5^V9`ZTY{Xn!yiKLTML$*c1?%_9ZwE&b9t$)%nNEXvIa!Tmt| z;W*oezyq4w*5t5>3pg|@F@Z&IL2&~c1H;dP$A_;^HO}0%VEyk>OJ^4*u;@xC)@Em5 zU}j(khYceugCJ8M1DBnGp+b#9w7!-?a(-@ZYF>$gmcE{zUS4XsLU3w{Mt@>aQDUWL ztX@uPUV2FemjV#fC=dj3V4x6Cl$w@Wq)=L%s*nIQOu0C-Dm6hNGq1QLH8DjYKTRRQ z5oEkF#P9??E@a0sY65KoxeeqL6z3s1Ob=uviZ-SRa6du4flDu`o}!Mg6rsM-&`>}P zV+BoYzG;B@2BRacEvB3>FPGZJz)BKu)W~xMu?(%$Kq%Is zTOiv)9h;mF)BuWj1zWhoqhmF#p@|11ou8Acmy@5a0aOI`3{Vm!8m2Q4GRqFbERffM f3Sr&_+c!8;6=Mm`*dZcv$aN|Jr@9WbTL=IE&Y~EC delta 617 zcmV-v0+#)p1%L%2K~_N^Q*L2!b7*gLAa*he0szGeV^w1K5izkC7U<92`#6yzB!6fE zV)aj*8yNSWyvXT#sD3WH>^~;3=uRlM1u8Vk%IxsA6Pcklk8f=gW7KmduxJhxKLBD& z-JXASZr*O&j<$zc;0aA;Oy0*lJCLhvde{#o$&@b#(2nY$LO|6OY7?7{>Vy$r?HYzz#{ z4D8^rVPs_xWGvybQ!rGhQHa*pQb^9v%}vcKQP9%Y)6>gKEmsImEzw9UDt}6>)Qr{3 zNzF?y$>34|f*J*aAPx)^0*X@8Qi~Kyi&GU6fQBg-XI7;q=y9RAKoe*t$ORw^Q5=C} zy&gy-scSfp1_tSiOvhOa9j*phD9jWp>lZHLYPXzkqwg0 z&q>wG$xqh+DgrwhD2ZZJEg_@qFpL8E52z64C$M#NO$AXn1Dc3%#_u2i8_h>`YX<-T DOFtHH From 4cd7578e12360a9f20d9e9adfcf75f14fcee5dd3 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Mon, 7 Nov 2022 19:53:06 +0800 Subject: [PATCH 10/12] Imporve coverage --- test/prefer-set-size.mjs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/prefer-set-size.mjs b/test/prefer-set-size.mjs index 3d2f7e3e98..c533cad911 100644 --- a/test/prefer-set-size.mjs +++ b/test/prefer-set-size.mjs @@ -19,6 +19,8 @@ test.snapshot({ 'let foo = new Set([]);[...foo].length;', 'const {foo} = new Set([]);[...foo].length;', 'const [foo] = new Set([]);[...foo].length;', + '[...foo].length', + 'var foo = new Set(); var foo = new Set(); [...foo].length', ], invalid: [ '[...new Set(array)].length', From 0a292a4855844ebfab08cda64d48ba1ea92a7390 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Tue, 15 Nov 2022 18:40:24 +0800 Subject: [PATCH 11/12] Apply suggestions from code review Co-authored-by: Sindre Sorhus --- docs/rules/prefer-set-size.md | 4 ++-- rules/prefer-set-size.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/rules/prefer-set-size.md b/docs/rules/prefer-set-size.md index 00f082fd92..7ddc30c1d1 100644 --- a/docs/rules/prefer-set-size.md +++ b/docs/rules/prefer-set-size.md @@ -1,4 +1,4 @@ -# Prefer use `Set#size` instead of convert it to Array first +# Prefer using `Set#size` instead of `Array#length` ✅ This rule is enabled in the `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs). @@ -7,7 +7,7 @@ -Prefer use `Set#size` directly instead of convert it to an array, and use `.length` of the array. +Prefer using `Set#size` directly instead of first converting it to an array and then using its `.length` property. ## Fail diff --git a/rules/prefer-set-size.js b/rules/prefer-set-size.js index 214321f210..1af2c9df63 100644 --- a/rules/prefer-set-size.js +++ b/rules/prefer-set-size.js @@ -5,7 +5,7 @@ const {fixSpaceAroundKeyword} = require('./fix/index.js'); const MESSAGE_ID = 'prefer-set-size'; const messages = { - [MESSAGE_ID]: 'Prefer use `Set#size` instead of `Array#length`.', + [MESSAGE_ID]: 'Prefer using `Set#size` instead of `Array#length`.', }; const lengthAccessSelector = [ From f2b92db3c84484fce8f98feb9f88c049e9aa4938 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Tue, 15 Nov 2022 18:57:05 +0800 Subject: [PATCH 12/12] Fix --- readme.md | 2 +- rules/prefer-set-size.js | 2 +- test/snapshots/prefer-set-size.mjs.md | 18 +++++++++--------- test/snapshots/prefer-set-size.mjs.snap | Bin 668 -> 672 bytes 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/readme.md b/readme.md index acef8d442d..fd32d71970 100644 --- a/readme.md +++ b/readme.md @@ -139,7 +139,7 @@ Use a [preset config](#preset-configs) or configure each rules in `package.json` | [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | ✅ | 🔧 | | | [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ | 🔧 | | | [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 | -| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer use `Set#size` instead of convert it to Array first. | ✅ | 🔧 | | +| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ | 🔧 | | | [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#slice()` and `String#split('')`. | ✅ | 🔧 | 💡 | | [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | | 🔧 | | | [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | | diff --git a/rules/prefer-set-size.js b/rules/prefer-set-size.js index 1af2c9df63..c7b7eaf6ec 100644 --- a/rules/prefer-set-size.js +++ b/rules/prefer-set-size.js @@ -93,7 +93,7 @@ module.exports = { meta: { type: 'suggestion', docs: { - description: 'Prefer use `Set#size` instead of convert it to Array first.', + description: 'Prefer using `Set#size` instead of `Array#length`.', }, fixable: 'code', messages, diff --git a/test/snapshots/prefer-set-size.mjs.md b/test/snapshots/prefer-set-size.mjs.md index 72b1c65d28..99ee5ca8b5 100644 --- a/test/snapshots/prefer-set-size.mjs.md +++ b/test/snapshots/prefer-set-size.mjs.md @@ -17,7 +17,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | [...new Set(array)].length␊ - | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ + | ^^^^^^ Prefer using \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #2 @@ -36,7 +36,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | const foo = new Set([]);␊ > 2 | console.log([...foo].length);␊ - | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ + | ^^^^^^ Prefer using \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #3 @@ -57,7 +57,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | function isUnique(array) {␊ > 2 | return[...new Set(array)].length === array.length␊ - | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ + | ^^^^^^ Prefer using \`Set#size\` instead of \`Array#length\`.␊ 3 | }␊ ` @@ -74,7 +74,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | [...new Set(array),].length␊ - | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ + | ^^^^^^ Prefer using \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #5 @@ -90,7 +90,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | [...(( new Set(array) ))].length␊ - | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ + | ^^^^^^ Prefer using \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #6 @@ -106,7 +106,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | (( [...new Set(array)] )).length␊ - | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ + | ^^^^^^ Prefer using \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #7 @@ -125,7 +125,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | foo␊ > 2 | ;[...new Set(array)].length␊ - | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ + | ^^^^^^ Prefer using \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #8 @@ -135,7 +135,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | [/* comment */...new Set(array)].length␊ - | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ + | ^^^^^^ Prefer using \`Set#size\` instead of \`Array#length\`.␊ ` ## Invalid #9 @@ -151,5 +151,5 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | [...new /* comment */ Set(array)].length␊ - | ^^^^^^ Prefer use \`Set#size\` instead of \`Array#length\`.␊ + | ^^^^^^ Prefer using \`Set#size\` instead of \`Array#length\`.␊ ` diff --git a/test/snapshots/prefer-set-size.mjs.snap b/test/snapshots/prefer-set-size.mjs.snap index 210745af4bb9c1ca998247142547ea9745730883..66a1fea33ec5c76bc56c2eb6f1a2d572c911245a 100644 GIT binary patch delta 611 zcmV-p0-XJv1)v2YK~_N^Q*L2!b7*gLAa*he0suTIdMdwl=Iq$)@aS~rXiSkJB^nRJ z>Yq9{Fz!Ejk<;~1{akk0e@tM}YfxMckzo}$Wl(I+#K2&w+w-r^&D(9;@wU%dIl|AF zz@m$wIG>q;VJF+?vkOd8KFIAcciN_T*@Ou!x)_R0k**hiEEK;3;zv4?SLbn>M+)3q z`lWM{OFa`V7=9K!K74(uaptZC z>wlM8I=e7|MR!86Ejt4PGXpy~Y#3P?1eqovsD%2=M>uV__=jZ08=9MUD>Fep~ z<)xM@1gDmNXe1UDC01(2>gA;7rI%!IDF8u@0znW51_}X1scET23Z=!FdFcuXK;x8) zGpkY)6f*OQOHvb46!Oy)5*$GmC_{`-(BndO9-}7EK9K7`jzMuClGF4+MxtnAngsV1 z)FZg`lIksL`AZS%FAWU^)NoeN#O9wSn16ukqcP)u2Be8de^AN&u~7G?mF6XvWaj57 zWEO|!WfqpE!n{!pRA2;Dz*&@9Qd*RU=1Z^_6>M#76~KIi-p0034G5*Ppg delta 607 zcmV-l0-*h%1)K#UK~_N^Q*L2!b7*gLAa*he0svWMVk?loVk2+{+QOAX2zQYpB^nFF z>Yq9{Fz!Ejk<;~1{akk0e@tM}D^Oevkzo}$MNn+W#K2&w+w-r^&D(9;@wU%dIl|AF zz@l@YIGve+VJF+?vkOd8KFIAcciN_T*@Ou!Iva|$k**hiFcd!mVI9e<^Ek~T1@0~V z(mBbco(U|<%?iQ&K>Xo2+lRmdn%maou!##eG%GQIMQ=fI0~-Uw&w|H?uTM43+_hl+ z?@~)=7bdXiN+{N5XJBAvU zK_N4*xFj_(MIk>;A;A%3yfVb_1U)Wf$1!RGZ3DRtDktfcXZfJ{mJ#K$?hu^aWL19}9JTT4`Q#NoIbYLS}Jj zUS?rwD$EnrKm|rX1)N2xC8b4qXnq8HP{G#LRsqaMINcbir54radl(4YWru7Rmf(R} zfXzlwU~y7Ew6J-FQ4Qvk{CsHeSYrtnjEF~Qg80)Kw-52fK2;)K8YwdpayKITVN2vh zXFIxDx|^{Kt<*p$)}dP<+d>_ioDb9hig*QExWl7kHLanE2PB=Jld6}KpRNH^1ojM2 t5+xd@GY~S%4#O;v*MSOQ-UZt?I8qg33C`FdB67%eDgdXt4zybc004I{1j_&b