eslint-plugin-ts-data-forge 0.10.5 → 0.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/rules/ast-utils.d.mts +5 -5
  2. package/dist/rules/ast-utils.d.mts.map +1 -1
  3. package/dist/rules/ast-utils.mjs +3 -3
  4. package/dist/rules/ast-utils.mjs.map +1 -1
  5. package/dist/rules/import-binding.d.mts +38 -0
  6. package/dist/rules/import-binding.d.mts.map +1 -0
  7. package/dist/rules/import-binding.mjs +53 -0
  8. package/dist/rules/import-binding.mjs.map +1 -0
  9. package/dist/rules/mutable-result.mjs +37 -37
  10. package/dist/rules/mutable-result.mjs.map +1 -1
  11. package/dist/rules/no-unnecessary-type-guard.d.mts.map +1 -1
  12. package/dist/rules/no-unnecessary-type-guard.mjs +146 -143
  13. package/dist/rules/no-unnecessary-type-guard.mjs.map +1 -1
  14. package/dist/rules/prefer-arr-generate.d.mts.map +1 -1
  15. package/dist/rules/prefer-arr-generate.mjs +129 -131
  16. package/dist/rules/prefer-arr-generate.mjs.map +1 -1
  17. package/dist/rules/prefer-arr-is-bounded-length-array.d.mts.map +1 -1
  18. package/dist/rules/prefer-arr-is-bounded-length-array.mjs +14 -16
  19. package/dist/rules/prefer-arr-is-bounded-length-array.mjs.map +1 -1
  20. package/dist/rules/prefer-arr-is-fixed-length-array.d.mts.map +1 -1
  21. package/dist/rules/prefer-arr-is-fixed-length-array.mjs +15 -17
  22. package/dist/rules/prefer-arr-is-fixed-length-array.mjs.map +1 -1
  23. package/dist/rules/prefer-arr-is-max-length-array.d.mts.map +1 -1
  24. package/dist/rules/prefer-arr-is-max-length-array.mjs +14 -16
  25. package/dist/rules/prefer-arr-is-max-length-array.mjs.map +1 -1
  26. package/dist/rules/prefer-arr-is-min-length-array.d.mts.map +1 -1
  27. package/dist/rules/prefer-arr-is-min-length-array.mjs +14 -16
  28. package/dist/rules/prefer-arr-is-min-length-array.mjs.map +1 -1
  29. package/dist/rules/prefer-arr-is-non-empty.d.mts.map +1 -1
  30. package/dist/rules/prefer-arr-is-non-empty.mjs +14 -16
  31. package/dist/rules/prefer-arr-is-non-empty.mjs.map +1 -1
  32. package/dist/rules/prefer-arr-scan.d.mts.map +1 -1
  33. package/dist/rules/prefer-arr-scan.mjs +9 -18
  34. package/dist/rules/prefer-arr-scan.mjs.map +1 -1
  35. package/dist/rules/prefer-arr-sum.d.mts.map +1 -1
  36. package/dist/rules/prefer-arr-sum.mjs +16 -21
  37. package/dist/rules/prefer-arr-sum.mjs.map +1 -1
  38. package/dist/rules/prefer-arr-uniq.d.mts.map +1 -1
  39. package/dist/rules/prefer-arr-uniq.mjs +38 -43
  40. package/dist/rules/prefer-arr-uniq.mjs.map +1 -1
  41. package/dist/rules/prefer-as-int.d.mts.map +1 -1
  42. package/dist/rules/prefer-as-int.mjs +19 -26
  43. package/dist/rules/prefer-as-int.mjs.map +1 -1
  44. package/dist/rules/prefer-canonical-array-slicing.d.mts.map +1 -1
  45. package/dist/rules/prefer-canonical-array-slicing.mjs +49 -15
  46. package/dist/rules/prefer-canonical-array-slicing.mjs.map +1 -1
  47. package/dist/rules/prefer-canonical-length-cast.mjs +15 -15
  48. package/dist/rules/prefer-canonical-length-cast.mjs.map +1 -1
  49. package/dist/rules/prefer-obj-over-entries-round-trip.d.mts.map +1 -1
  50. package/dist/rules/prefer-obj-over-entries-round-trip.mjs +100 -99
  51. package/dist/rules/prefer-obj-over-entries-round-trip.mjs.map +1 -1
  52. package/dist/rules/prefer-pipe-map-nullable.d.mts.map +1 -1
  53. package/dist/rules/prefer-pipe-map-nullable.mjs +2 -4
  54. package/dist/rules/prefer-pipe-map-nullable.mjs.map +1 -1
  55. package/dist/rules/prefer-range-for-loop.d.mts.map +1 -1
  56. package/dist/rules/prefer-range-for-loop.mjs +18 -24
  57. package/dist/rules/prefer-range-for-loop.mjs.map +1 -1
  58. package/package.json +4 -4
  59. package/src/rules/ast-utils.mts +11 -11
  60. package/src/rules/import-binding.mts +94 -0
  61. package/src/rules/mutable-result.mts +56 -56
  62. package/src/rules/no-unnecessary-type-guard.mts +199 -203
  63. package/src/rules/no-unnecessary-type-guard.test.mts +62 -2
  64. package/src/rules/prefer-arr-generate.mts +184 -194
  65. package/src/rules/prefer-arr-generate.test.mts +262 -134
  66. package/src/rules/prefer-arr-is-bounded-length-array.mts +22 -33
  67. package/src/rules/prefer-arr-is-fixed-length-array.mts +24 -36
  68. package/src/rules/prefer-arr-is-fixed-length-array.test.mts +16 -7
  69. package/src/rules/prefer-arr-is-max-length-array.mts +21 -34
  70. package/src/rules/prefer-arr-is-max-length-array.test.mts +16 -7
  71. package/src/rules/prefer-arr-is-min-length-array.mts +21 -34
  72. package/src/rules/prefer-arr-is-min-length-array.test.mts +16 -7
  73. package/src/rules/prefer-arr-is-non-empty.mts +17 -34
  74. package/src/rules/prefer-arr-is-non-empty.test.mts +110 -0
  75. package/src/rules/prefer-arr-scan.mts +11 -36
  76. package/src/rules/prefer-arr-scan.test.mts +55 -0
  77. package/src/rules/prefer-arr-sum.mts +19 -33
  78. package/src/rules/prefer-arr-uniq.mts +49 -60
  79. package/src/rules/prefer-arr-uniq.test.mts +46 -20
  80. package/src/rules/prefer-as-int.mts +27 -52
  81. package/src/rules/prefer-as-int.test.mts +79 -29
  82. package/src/rules/prefer-canonical-array-slicing.mts +86 -24
  83. package/src/rules/prefer-canonical-array-slicing.test.mts +133 -34
  84. package/src/rules/prefer-canonical-length-cast.mts +18 -18
  85. package/src/rules/prefer-obj-over-entries-round-trip.mts +152 -170
  86. package/src/rules/prefer-obj-over-entries-round-trip.test.mts +48 -6
  87. package/src/rules/prefer-pipe-map-nullable.mts +6 -8
  88. package/src/rules/prefer-range-for-loop.mts +31 -55
@@ -6,11 +6,8 @@ import {
6
6
  type TSESTree,
7
7
  } from '@typescript-eslint/utils';
8
8
  import {
9
- buildNamedImportFix,
10
9
  createGetLayerTypes,
11
10
  getArgumentText,
12
- getImportDeclarations,
13
- getImportedLocalName,
14
11
  negationOf,
15
12
  prefixedNegationOf,
16
13
  skipTypeWrappers,
@@ -19,7 +16,7 @@ import {
19
16
  import { Arr, hasKey, isRecord } from 'ts-data-forge';
20
17
  import type { FixedLengthTuple } from 'ts-type-forge';
21
18
  import * as ts from 'typescript';
22
- import { TS_DATA_FORGE_MODULE } from './constants.mjs';
19
+ import { tsDataForgeValuesAt } from './import-binding.mjs';
23
20
  import { needsMutableResult } from './mutable-result.mjs';
24
21
 
25
22
  type Options = readonly [];
@@ -106,13 +103,6 @@ export const preferArrGenerate: TSESLint.RuleModule<MessageIds, Options> = {
106
103
  create: (context) => {
107
104
  const sourceCode = context.sourceCode;
108
105
 
109
- const program = sourceCode.ast;
110
-
111
- const tsDataForgeImports = getImportDeclarations(
112
- program,
113
- TS_DATA_FORGE_MODULE,
114
- );
115
-
116
106
  const services = sourceCode.parserServices;
117
107
 
118
108
  const tsProgram = services?.program ?? undefined;
@@ -146,9 +136,10 @@ export const preferArrGenerate: TSESLint.RuleModule<MessageIds, Options> = {
146
136
  node: TSESTree.Node,
147
137
  ): ts.Node | undefined => esTreeNodeToTSNodeMap.get(node);
148
138
 
149
- const arrLocalName = getImportedLocalName(tsDataForgeImports, 'Arr');
139
+ // The name the rewrite writes, and, at a node, the edits that bind it.
140
+ const arr = tsDataForgeValuesAt(sourceCode, ['Arr']);
150
141
 
151
- const arrName = arrLocalName ?? 'Arr';
142
+ const arrName = arr.localNames[0] ?? 'Arr';
152
143
 
153
144
  const mut_matches: Match[] = [];
154
145
 
@@ -297,39 +288,38 @@ export const preferArrGenerate: TSESLint.RuleModule<MessageIds, Options> = {
297
288
  mut_matches.push({ node, replacement, autofixable });
298
289
  },
299
290
  'Program:exit': () => {
300
- // The import is added by the first fix only, so that several fixes do
301
- // not insert it at the same position. When the first match is not
302
- // autofixable, the first autofixable one carries it instead.
303
- const firstAutofixable = mut_matches.find((m) => m.autofixable);
304
-
291
+ // Every fix brings `Arr` into scope itself, so that one applied alone
292
+ // (an editor's quick fix) is complete.
305
293
  for (const match of mut_matches) {
306
- const buildFix =
307
- (withImport: boolean): TSESLint.ReportFixFunction =>
308
- (fixer) => [
309
- ...(withImport && arrLocalName === undefined
310
- ? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
311
- 'Arr',
312
- ])
313
- : []),
314
- fixer.replaceText(match.node, match.replacement),
315
- ];
294
+ const binding = arr.at(match.node);
295
+
296
+ const fix: TSESLint.ReportFixFunction | null =
297
+ binding === undefined
298
+ ? null
299
+ : (fixer) => [
300
+ ...binding.edits(fixer),
301
+ fixer.replaceText(match.node, match.replacement),
302
+ ];
316
303
 
317
304
  if (match.autofixable) {
318
305
  context.report({
319
306
  node: match.node,
320
307
  messageId: 'useArrGenerate',
321
- fix: buildFix(match === firstAutofixable),
308
+ fix,
322
309
  });
323
310
  } else {
324
311
  context.report({
325
312
  node: match.node,
326
313
  messageId: 'useArrGenerate',
327
- suggest: [
328
- {
329
- messageId: 'suggestArrGenerate',
330
- fix: buildFix(true),
331
- },
332
- ],
314
+ suggest:
315
+ fix === null
316
+ ? []
317
+ : [
318
+ {
319
+ messageId: 'suggestArrGenerate',
320
+ fix,
321
+ },
322
+ ],
333
323
  });
334
324
  }
335
325
  }
@@ -452,6 +442,63 @@ const getFilterMapShape = (
452
442
  };
453
443
  };
454
444
 
445
+ /** The whitespace at the start of the line that `index` is on. */
446
+ const lineIndentOf = (
447
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
448
+ sourceCode: TSESLint.SourceCode,
449
+ index: number,
450
+ ): string => {
451
+ const { line } = sourceCode.getLocFromIndex(index);
452
+
453
+ const lineText = sourceCode.lines[line - 1] ?? '';
454
+
455
+ return /^\s*/u.exec(lineText)?.[0] ?? '';
456
+ };
457
+
458
+ /**
459
+ * `text`, the source at `range`, with every line after the first shifted from
460
+ * the indentation of the line `range` starts on to `targetIndent`. Left as it
461
+ * is when a template literal or string spans lines inside it, since shifting
462
+ * those lines would change the string.
463
+ */
464
+ const reindent = (
465
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
466
+ sourceCode: TSESLint.SourceCode,
467
+ range: FixedLengthTuple<2, number>,
468
+ targetIndent: string,
469
+ text: string,
470
+ ): string => {
471
+ if (!text.includes('\n')) {
472
+ return text;
473
+ }
474
+
475
+ const spansLines = sourceCode.ast.tokens.some(
476
+ (token) =>
477
+ range[0] <= token.range[0] &&
478
+ token.range[1] <= range[1] &&
479
+ (token.type === AST_TOKEN_TYPES.Template ||
480
+ token.type === AST_TOKEN_TYPES.String) &&
481
+ token.loc.start.line !== token.loc.end.line,
482
+ );
483
+
484
+ if (spansLines) {
485
+ return text;
486
+ }
487
+
488
+ const sourceIndent = lineIndentOf(sourceCode, range[0]);
489
+
490
+ const [first, ...rest] = text.split('\n');
491
+
492
+ return [
493
+ first,
494
+ ...rest.map((line) =>
495
+ line.startsWith(sourceIndent)
496
+ ? `${targetIndent}${line.slice(sourceIndent.length)}`
497
+ : line,
498
+ ),
499
+ ].join('\n');
500
+ };
501
+
455
502
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
456
503
  const buildReplacement = ({
457
504
  sourceCode,
@@ -563,63 +610,6 @@ const losesComments = (
563
610
  );
564
611
  };
565
612
 
566
- /**
567
- * `text`, the source at `range`, with every line after the first shifted from
568
- * the indentation of the line `range` starts on to `targetIndent`. Left as it
569
- * is when a template literal or string spans lines inside it, since shifting
570
- * those lines would change the string.
571
- */
572
- const reindent = (
573
- // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
574
- sourceCode: TSESLint.SourceCode,
575
- range: FixedLengthTuple<2, number>,
576
- targetIndent: string,
577
- text: string,
578
- ): string => {
579
- if (!text.includes('\n')) {
580
- return text;
581
- }
582
-
583
- const spansLines = sourceCode.ast.tokens.some(
584
- (token) =>
585
- range[0] <= token.range[0] &&
586
- token.range[1] <= range[1] &&
587
- (token.type === AST_TOKEN_TYPES.Template ||
588
- token.type === AST_TOKEN_TYPES.String) &&
589
- token.loc.start.line !== token.loc.end.line,
590
- );
591
-
592
- if (spansLines) {
593
- return text;
594
- }
595
-
596
- const sourceIndent = lineIndentOf(sourceCode, range[0]);
597
-
598
- const [first, ...rest] = text.split('\n');
599
-
600
- return [
601
- first,
602
- ...rest.map((line) =>
603
- line.startsWith(sourceIndent)
604
- ? `${targetIndent}${line.slice(sourceIndent.length)}`
605
- : line,
606
- ),
607
- ].join('\n');
608
- };
609
-
610
- /** The whitespace at the start of the line that `index` is on. */
611
- const lineIndentOf = (
612
- // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
613
- sourceCode: TSESLint.SourceCode,
614
- index: number,
615
- ): string => {
616
- const { line } = sourceCode.getLocFromIndex(index);
617
-
618
- const lineText = sourceCode.lines[line - 1] ?? '';
619
-
620
- return /^\s*/u.exec(lineText)?.[0] ?? '';
621
- };
622
-
623
613
  /** Whether `node`, with its type wrappers taken off, is a `….filter(…)` call. */
624
614
  const isFilterCall = (
625
615
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
@@ -642,72 +632,25 @@ const isFilterCall = (
642
632
  };
643
633
 
644
634
  /**
645
- * Whether `node`, a reference or a member access, has a type here narrower
646
- * than its declared one, by a narrowing that a function created here would not
647
- * see. TypeScript keeps the narrowing of a `const`, and of a parameter or `let`
648
- * that is never reassigned, inside a closure; it drops every other one,
649
- * including any narrowing of a property.
635
+ * Whether `type` is an array or tuple, or a union of them, or an intersection
636
+ * with one in it (`readonly T[] & Brand`).
650
637
  */
651
- const isNarrowedHere = (
652
- // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
653
- sourceCode: TSESLint.SourceCode,
638
+ const isArrayOrTupleType = (
654
639
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
655
640
  checker: ts.TypeChecker,
656
641
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
657
- getTsNode: (esNode: TSESTree.Node) => ts.Node | undefined,
658
- // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
659
- node: TSESTree.Node,
660
- isReceiver: boolean,
642
+ type: ts.Type,
661
643
  ): boolean => {
662
- if (
663
- node.type !== AST_NODE_TYPES.Identifier &&
664
- node.type !== AST_NODE_TYPES.MemberExpression
665
- ) {
666
- return false;
667
- }
668
-
669
- // A method about to be called (`xs.flat()`): its type is that of the method,
670
- // which no narrowing of interest changes.
671
- if (
672
- node.parent.type === AST_NODE_TYPES.CallExpression &&
673
- node.parent.callee === node
674
- ) {
675
- return false;
676
- }
677
-
678
- if (node.type === AST_NODE_TYPES.Identifier) {
679
- if (!isReference(node)) {
680
- return false;
681
- }
682
-
683
- const variable = ASTUtils.findVariable(sourceCode.getScope(node), node);
684
-
685
- if (
686
- variable?.references.every(
687
- (reference) => !reference.isWrite() || reference.init === true,
688
- ) === true
689
- ) {
690
- return false;
691
- }
692
- }
693
-
694
- const tsNode = getTsNode(node);
695
-
696
- if (tsNode === undefined) {
697
- return false;
698
- }
699
-
700
- const declaredType = getDeclaredType(checker, tsNode);
701
-
702
- const type = checker.getTypeAtLocation(tsNode);
644
+ const resolved =
645
+ (type.flags & ts.TypeFlags.TypeParameter) !== 0
646
+ ? (checker.getBaseConstraintOfType(type) ?? type)
647
+ : type;
703
648
 
704
- return (
705
- declaredType !== undefined &&
706
- declaredType !== type &&
707
- // The loop only iterates the receiver itself, so a narrowing that leaves
708
- // it an array of the same elements (`Arr.isNonEmpty(xs)`) loses nothing.
709
- !(isReceiver && iteratesTheSame(checker, declaredType, type))
710
- );
649
+ return resolved.isUnion()
650
+ ? resolved.types.every((t) => isArrayOrTupleType(checker, t))
651
+ : resolved.isIntersection()
652
+ ? resolved.types.some((t) => isArrayOrTupleType(checker, t))
653
+ : checker.isArrayType(resolved) || checker.isTupleType(resolved);
711
654
  };
712
655
 
713
656
  /**
@@ -787,6 +730,93 @@ const getDeclaredType = (
787
730
  : checker.getTypeOfSymbolAtLocation(symbol, declaration);
788
731
  };
789
732
 
733
+ /** Whether an identifier reads a binding, rather than naming a property or a key. */
734
+ const isReference = (
735
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
736
+ node: TSESTree.Identifier,
737
+ ): boolean => {
738
+ const { parent } = node;
739
+
740
+ return !(
741
+ (parent.type === AST_NODE_TYPES.MemberExpression &&
742
+ parent.property === node &&
743
+ !parent.computed) ||
744
+ (parent.type === AST_NODE_TYPES.Property &&
745
+ parent.key === node &&
746
+ !parent.computed &&
747
+ !parent.shorthand)
748
+ );
749
+ };
750
+
751
+ /**
752
+ * Whether `node`, a reference or a member access, has a type here narrower
753
+ * than its declared one, by a narrowing that a function created here would not
754
+ * see. TypeScript keeps the narrowing of a `const`, and of a parameter or `let`
755
+ * that is never reassigned, inside a closure; it drops every other one,
756
+ * including any narrowing of a property.
757
+ */
758
+ const isNarrowedHere = (
759
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
760
+ sourceCode: TSESLint.SourceCode,
761
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
762
+ checker: ts.TypeChecker,
763
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
764
+ getTsNode: (esNode: TSESTree.Node) => ts.Node | undefined,
765
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
766
+ node: TSESTree.Node,
767
+ isReceiver: boolean,
768
+ ): boolean => {
769
+ if (
770
+ node.type !== AST_NODE_TYPES.Identifier &&
771
+ node.type !== AST_NODE_TYPES.MemberExpression
772
+ ) {
773
+ return false;
774
+ }
775
+
776
+ // A method about to be called (`xs.flat()`): its type is that of the method,
777
+ // which no narrowing of interest changes.
778
+ if (
779
+ node.parent.type === AST_NODE_TYPES.CallExpression &&
780
+ node.parent.callee === node
781
+ ) {
782
+ return false;
783
+ }
784
+
785
+ if (node.type === AST_NODE_TYPES.Identifier) {
786
+ if (!isReference(node)) {
787
+ return false;
788
+ }
789
+
790
+ const variable = ASTUtils.findVariable(sourceCode.getScope(node), node);
791
+
792
+ if (
793
+ variable?.references.every(
794
+ (reference) => !reference.isWrite() || reference.init === true,
795
+ ) === true
796
+ ) {
797
+ return false;
798
+ }
799
+ }
800
+
801
+ const tsNode = getTsNode(node);
802
+
803
+ if (tsNode === undefined) {
804
+ return false;
805
+ }
806
+
807
+ const declaredType = getDeclaredType(checker, tsNode);
808
+
809
+ const type = checker.getTypeAtLocation(tsNode);
810
+
811
+ return (
812
+ declaredType !== undefined &&
813
+ declaredType !== type &&
814
+ // The loop only iterates the receiver itself, so a narrowing that leaves
815
+ // it an array of the same elements (`Arr.isNonEmpty(xs)`) loses nothing.
816
+ !(isReceiver && iteratesTheSame(checker, declaredType, type))
817
+ );
818
+ };
819
+
790
820
  /**
791
821
  * Whether the binding `identifier` reads is declared inside `container`, as
792
822
  * the parameter of an arrow function in the receiver is: the loop variable
@@ -816,23 +846,8 @@ const isBoundWithin = (
816
846
  );
817
847
  };
818
848
 
819
- /** Whether an identifier reads a binding, rather than naming a property or a key. */
820
- const isReference = (
821
- // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
822
- node: TSESTree.Identifier,
823
- ): boolean => {
824
- const { parent } = node;
825
-
826
- return !(
827
- (parent.type === AST_NODE_TYPES.MemberExpression &&
828
- parent.property === node &&
829
- !parent.computed) ||
830
- (parent.type === AST_NODE_TYPES.Property &&
831
- parent.key === node &&
832
- !parent.computed &&
833
- !parent.shorthand)
834
- );
835
- };
849
+ const isNode = (value: unknown): value is TSESTree.Node =>
850
+ isRecord(value) && hasKey(value, 'type') && typeof value.type === 'string';
836
851
 
837
852
  /**
838
853
  * Whether `node` or a node inside it satisfies `predicate`. A nested
@@ -877,9 +892,6 @@ const someDescendant = (
877
892
  });
878
893
  };
879
894
 
880
- const isNode = (value: unknown): value is TSESTree.Node =>
881
- isRecord(value) && hasKey(value, 'type') && typeof value.type === 'string';
882
-
883
895
  const isReturnStatement = (
884
896
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
885
897
  node: TSESTree.Node,
@@ -894,25 +906,3 @@ const rebindsInGenerator = (
894
906
  node.type === AST_NODE_TYPES.Super ||
895
907
  node.type === AST_NODE_TYPES.MetaProperty ||
896
908
  (node.type === AST_NODE_TYPES.Identifier && node.name === 'arguments');
897
-
898
- /**
899
- * Whether `type` is an array or tuple, or a union of them, or an intersection
900
- * with one in it (`readonly T[] & Brand`).
901
- */
902
- const isArrayOrTupleType = (
903
- // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
904
- checker: ts.TypeChecker,
905
- // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
906
- type: ts.Type,
907
- ): boolean => {
908
- const resolved =
909
- (type.flags & ts.TypeFlags.TypeParameter) !== 0
910
- ? (checker.getBaseConstraintOfType(type) ?? type)
911
- : type;
912
-
913
- return resolved.isUnion()
914
- ? resolved.types.every((t) => isArrayOrTupleType(checker, t))
915
- : resolved.isIntersection()
916
- ? resolved.types.some((t) => isArrayOrTupleType(checker, t))
917
- : checker.isArrayType(resolved) || checker.isTupleType(resolved);
918
- };