Skip to content

Commit 42a558f

Browse files
authored
prefer-spread: Fix: Skip TypedArray and ArrayBuffer constructor calls (#2871)
1 parent cbb2377 commit 42a558f

File tree

4 files changed

+53
-25
lines changed

4 files changed

+53
-25
lines changed

rules/prefer-spread.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
} from './utils/index.js';
1010
import {removeMethodCall} from './fix/index.js';
1111
import {isLiteral, isMethodCall} from './ast/index.js';
12+
import typedArrayTypes from './shared/typed-array.js';
1213

1314
const ERROR_ARRAY_FROM = 'array-from';
1415
const ERROR_ARRAY_CONCAT = 'array-concat';
@@ -41,6 +42,29 @@ const ignoredSliceCallee = [
4142
'this',
4243
];
4344

45+
// TypedArray and ArrayBuffer constructors - these have .slice() but spreading them
46+
// either doesn't work (ArrayBuffer has no iterator) or changes the type (TypedArray.slice()
47+
// returns the same typed array, but spreading converts to number[])
48+
const typedArrayConstructors = new Set([
49+
...typedArrayTypes,
50+
'ArrayBuffer',
51+
'SharedArrayBuffer',
52+
]);
53+
54+
/**
55+
Check if node is a TypedArray/ArrayBuffer construction (new Uint8Array(...)).
56+
57+
@param {import('estree').Node} node
58+
@returns {boolean}
59+
*/
60+
function isTypedArrayConstruction(node) {
61+
return (
62+
node.type === 'NewExpression'
63+
&& node.callee.type === 'Identifier'
64+
&& typedArrayConstructors.has(node.callee.name)
65+
);
66+
}
67+
4468
const isArrayLiteral = node => node.type === 'ArrayExpression';
4569
const isArrayLiteralHasTrailingComma = (node, sourceCode) => {
4670
if (node.elements.length === 0) {
@@ -416,6 +440,12 @@ const create = context => {
416440
return;
417441
}
418442

443+
// Skip TypedArray/ArrayBuffer constructions - spreading them either fails
444+
// (ArrayBuffer has no iterator) or changes the type (TypedArray -> number[])
445+
if (isTypedArrayConstruction(node.callee.object)) {
446+
return;
447+
}
448+
419449
const [firstArgument] = node.arguments;
420450
if (firstArgument && !isLiteral(firstArgument, 0)) {
421451
return;

test/prefer-spread.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,24 @@ test.snapshot({
314314
'file.slice()',
315315
'class A {foo() {this.slice()}}',
316316
'scopeManager?.scopes.slice()',
317+
// TypedArray/ArrayBuffer constructors - spreading doesn't work or changes type
318+
'new ArrayBuffer(10).slice()',
319+
'new ArrayBuffer(10).slice(0)',
320+
'new SharedArrayBuffer(10).slice()',
321+
'new SharedArrayBuffer(10).slice(0)',
322+
'new Int8Array([1, 2, 3]).slice()',
323+
'new Int8Array([1, 2, 3]).slice(0)',
324+
'new Uint8Array([10, 20, 30, 40, 50]).slice()',
325+
'new Uint8Array([10, 20, 30, 40, 50]).slice(0)',
326+
'new Uint8ClampedArray([1, 2, 3]).slice()',
327+
'new Int16Array([1, 2, 3]).slice()',
328+
'new Uint16Array([1, 2, 3]).slice()',
329+
'new Int32Array([1, 2, 3]).slice()',
330+
'new Uint32Array([1, 2, 3]).slice()',
331+
'new Float32Array([1, 2, 3]).slice()',
332+
'new Float64Array([1, 2, 3]).slice()',
333+
'new BigInt64Array([1n, 2n, 3n]).slice()',
334+
'new BigUint64Array([1n, 2n, 3n]).slice()',
317335
],
318336
invalid: [
319337
'array.slice()',
@@ -328,9 +346,8 @@ test.snapshot({
328346
bar()
329347
foo.slice()
330348
`,
331-
// `{String,TypedArray}#slice` are wrongly detected
349+
// `String#slice` is wrongly detected (strings are iterable but spreading produces array, not string)
332350
'"".slice()',
333-
'new Uint8Array([10, 20, 30, 40, 50]).slice()',
334351
'array.slice(0)',
335352
'array.slice(0b0)',
336353
'array.slice(0.00)',

test/snapshots/prefer-spread.js.md

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2322,26 +2322,7 @@ Generated by [AVA](https://avajs.dev).
23222322
1 | [...""]␊
23232323
`
23242324

2325-
## invalid(10): new Uint8Array([10, 20, 30, 40, 50]).slice()
2326-
2327-
> Input
2328-
2329-
`␊
2330-
1 | new Uint8Array([10, 20, 30, 40, 50]).slice()␊
2331-
`
2332-
2333-
> Error 1/1
2334-
2335-
`␊
2336-
Message:␊
2337-
> 1 | new Uint8Array([10, 20, 30, 40, 50]).slice()␊
2338-
| ^^^^^ Prefer the spread operator over \`Array#slice()\`.␊
2339-
2340-
Output:␊
2341-
1 | [...new Uint8Array([10, 20, 30, 40, 50])]␊
2342-
`
2343-
2344-
## invalid(11): array.slice(0)
2325+
## invalid(10): array.slice(0)
23452326

23462327
> Input
23472328
@@ -2360,7 +2341,7 @@ Generated by [AVA](https://avajs.dev).
23602341
1 | [...array]␊
23612342
`
23622343

2363-
## invalid(12): array.slice(0b0)
2344+
## invalid(11): array.slice(0b0)
23642345

23652346
> Input
23662347
@@ -2379,7 +2360,7 @@ Generated by [AVA](https://avajs.dev).
23792360
1 | [...array]␊
23802361
`
23812362

2382-
## invalid(13): array.slice(0.00)
2363+
## invalid(12): array.slice(0.00)
23832364

23842365
> Input
23852366
@@ -2398,7 +2379,7 @@ Generated by [AVA](https://avajs.dev).
23982379
1 | [...array]␊
23992380
`
24002381

2401-
## invalid(14): array.slice(0.00, )
2382+
## invalid(13): array.slice(0.00, )
24022383

24032384
> Input
24042385
-29 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)