diff --git a/rules/prefer-spread.js b/rules/prefer-spread.js index 718e142e88..409d88fc7d 100644 --- a/rules/prefer-spread.js +++ b/rules/prefer-spread.js @@ -1,6 +1,6 @@ 'use strict'; const {isParenthesized, getStaticValue, isCommaToken, hasSideEffect} = require('eslint-utils'); -const {methodCallSelector} = require('./selectors/index.js'); +const {methodCallSelector, not} = require('./selectors/index.js'); const needsSemicolon = require('./utils/needs-semicolon.js'); const {getParenthesizedRange, getParenthesizedText} = require('./utils/parentheses.js'); const shouldAddParenthesesToSpreadElementArgument = require('./utils/should-add-parentheses-to-spread-element-argument.js'); @@ -42,16 +42,12 @@ const arrayFromCallSelector = [ const arrayConcatCallSelector = [ methodCallSelector('concat'), - `:not(${ + not( [ - ...[ - 'Literal', - 'TemplateLiteral', - ].map(type => `[callee.object.type="${type}"]`), - // Most likely it's a static method of a class - '[callee.object.name=/^[A-Z]/]', - ].join(', ') - })`, + 'Literal', + 'TemplateLiteral', + ].map(type => `[callee.object.type="${type}"]`), + ), ].join(''); const arraySliceCallSelector = [ @@ -301,6 +297,20 @@ function fixSlice(node, sourceCode) { }; } +function isClassName(node) { + if (node.type === 'MemberExpression') { + node = node.property; + } + + if (node.type !== 'Identifier') { + return false; + } + + const {name} = node; + + return /^[A-Z]./.test(name) && name.toUpperCase() !== name; +} + const create = context => { const sourceCode = context.getSourceCode(); @@ -313,8 +323,14 @@ const create = context => { }; }, [arrayConcatCallSelector](node) { + const {object} = node.callee; + + if (isClassName(object)) { + return; + } + const scope = context.getScope(); - const staticResult = getStaticValue(node.callee.object, scope); + const staticResult = getStaticValue(object, scope); if (staticResult && !Array.isArray(staticResult.value)) { return; diff --git a/test/prefer-spread.mjs b/test/prefer-spread.mjs index 5857fd8b22..a32e16d0e6 100644 --- a/test/prefer-spread.mjs +++ b/test/prefer-spread.mjs @@ -179,8 +179,7 @@ test.snapshot({ 'const bufA = Buffer.concat([buf1, buf2, buf3], totalLength);', 'Foo.concat(1)', 'FooBar.concat(1)', - 'FOO.concat(1)', - 'A.concat(1)', + 'global.Buffer.concat([])', ], invalid: [ '[1].concat(2)', @@ -266,6 +265,10 @@ test.snapshot({ 'foo.concat(bar, 2, 3, ...baz)', 'notClass.concat(1)', '_A.concat(1)', + // Constants + 'FOO.concat(1)', + 'A.concat(1)', + 'Foo.x.concat(1)', // Semicolon 'if (test) foo.concat(1)', 'if (test) {} else foo.concat(1)', diff --git a/test/snapshots/prefer-spread.mjs.md b/test/snapshots/prefer-spread.mjs.md index 4e88b5d432..206615ed90 100644 --- a/test/snapshots/prefer-spread.mjs.md +++ b/test/snapshots/prefer-spread.mjs.md @@ -1808,6 +1808,54 @@ Generated by [AVA](https://avajs.dev). ` ## Invalid #54 + 1 | FOO.concat(1) + +> Output + + `␊ + 1 | [...FOO, 1]␊ + ` + +> Error 1/1 + + `␊ + > 1 | FOO.concat(1)␊ + | ^^^^^^ Prefer the spread operator over \`Array#concat(…)\`.␊ + ` + +## Invalid #55 + 1 | A.concat(1) + +> Output + + `␊ + 1 | [...A, 1]␊ + ` + +> Error 1/1 + + `␊ + > 1 | A.concat(1)␊ + | ^^^^^^ Prefer the spread operator over \`Array#concat(…)\`.␊ + ` + +## Invalid #56 + 1 | Foo.x.concat(1) + +> Output + + `␊ + 1 | [...Foo.x, 1]␊ + ` + +> Error 1/1 + + `␊ + > 1 | Foo.x.concat(1)␊ + | ^^^^^^ Prefer the spread operator over \`Array#concat(…)\`.␊ + ` + +## Invalid #57 1 | if (test) foo.concat(1) > Output @@ -1823,7 +1871,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^ Prefer the spread operator over \`Array#concat(…)\`.␊ ` -## Invalid #55 +## Invalid #58 1 | if (test) {} else foo.concat(1) > Output @@ -1839,7 +1887,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^ Prefer the spread operator over \`Array#concat(…)\`.␊ ` -## Invalid #56 +## Invalid #59 1 | if (test) {} else foo.concat(1) > Output @@ -1855,7 +1903,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^ Prefer the spread operator over \`Array#concat(…)\`.␊ ` -## Invalid #57 +## Invalid #60 1 | for (;;) foo.concat(1) > Output @@ -1871,7 +1919,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^ Prefer the spread operator over \`Array#concat(…)\`.␊ ` -## Invalid #58 +## Invalid #61 1 | for (a in b) foo.concat(1) > Output @@ -1887,7 +1935,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^ Prefer the spread operator over \`Array#concat(…)\`.␊ ` -## Invalid #59 +## Invalid #62 1 | for (a in b) foo.concat(1) > Output @@ -1903,7 +1951,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^ Prefer the spread operator over \`Array#concat(…)\`.␊ ` -## Invalid #60 +## Invalid #63 1 | for (const a of b) foo.concat(1) > Output @@ -1919,7 +1967,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^ Prefer the spread operator over \`Array#concat(…)\`.␊ ` -## Invalid #61 +## Invalid #64 1 | while (test) foo.concat(1) > Output @@ -1935,7 +1983,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^ Prefer the spread operator over \`Array#concat(…)\`.␊ ` -## Invalid #62 +## Invalid #65 1 | do foo.concat(1); while (test) > Output @@ -1951,7 +1999,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^ Prefer the spread operator over \`Array#concat(…)\`.␊ ` -## Invalid #63 +## Invalid #66 1 | with (foo) foo.concat(1) > Output @@ -1967,7 +2015,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^ Prefer the spread operator over \`Array#concat(…)\`.␊ ` -## Invalid #64 +## Invalid #67 1 | const baz = [2]; 2 | call(foo, ...[bar].concat(baz)); diff --git a/test/snapshots/prefer-spread.mjs.snap b/test/snapshots/prefer-spread.mjs.snap index b1970b8499..101236bedb 100644 Binary files a/test/snapshots/prefer-spread.mjs.snap and b/test/snapshots/prefer-spread.mjs.snap differ