eslint-plugin-ts-data-forge 0.10.4 → 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 (93) 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 +5 -5
  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-array.test.mts +87 -5
  67. package/src/rules/prefer-arr-is-bounded-length-array.mts +22 -33
  68. package/src/rules/prefer-arr-is-fixed-length-array.mts +24 -36
  69. package/src/rules/prefer-arr-is-fixed-length-array.test.mts +16 -7
  70. package/src/rules/prefer-arr-is-max-length-array.mts +21 -34
  71. package/src/rules/prefer-arr-is-max-length-array.test.mts +16 -7
  72. package/src/rules/prefer-arr-is-min-length-array.mts +21 -34
  73. package/src/rules/prefer-arr-is-min-length-array.test.mts +16 -7
  74. package/src/rules/prefer-arr-is-non-empty.mts +17 -34
  75. package/src/rules/prefer-arr-is-non-empty.test.mts +110 -0
  76. package/src/rules/prefer-arr-scan.mts +11 -36
  77. package/src/rules/prefer-arr-scan.test.mts +55 -0
  78. package/src/rules/prefer-arr-sum.mts +19 -33
  79. package/src/rules/prefer-arr-uniq.mts +49 -60
  80. package/src/rules/prefer-arr-uniq.test.mts +46 -20
  81. package/src/rules/prefer-as-int.mts +27 -52
  82. package/src/rules/prefer-as-int.test.mts +79 -29
  83. package/src/rules/prefer-canonical-array-slicing.mts +86 -24
  84. package/src/rules/prefer-canonical-array-slicing.test.mts +133 -34
  85. package/src/rules/prefer-canonical-length-cast.mts +18 -18
  86. package/src/rules/prefer-is-non-null-object.test.mts +62 -37
  87. package/src/rules/prefer-is-record-and-has-key.test.mts +32 -17
  88. package/src/rules/prefer-num-safe-parse-float.test.mts +45 -21
  89. package/src/rules/prefer-num-safe-parse-int.test.mts +29 -14
  90. package/src/rules/prefer-obj-over-entries-round-trip.mts +152 -170
  91. package/src/rules/prefer-obj-over-entries-round-trip.test.mts +48 -6
  92. package/src/rules/prefer-pipe-map-nullable.mts +6 -8
  93. package/src/rules/prefer-range-for-loop.mts +31 -55
@@ -202,25 +202,40 @@ describe('prefer-arr-generate', () => {
202
202
  const ys = xs.flatMap((x) => (x === undefined ? [] : [x]));
203
203
  const zs = xs.flatMap((x) => (skip ? [] : [x]));
204
204
  `,
205
- output: dedent`
206
- import { Arr } from 'ts-data-forge';
207
- declare const xs: readonly (number | undefined)[];
208
- declare const skip: boolean;
209
- const ys = Arr.generate(function* () {
210
- for (const x of xs) {
211
- if (x !== undefined) {
212
- yield x;
205
+ output: [
206
+ dedent`
207
+ import { Arr } from 'ts-data-forge';
208
+ declare const xs: readonly (number | undefined)[];
209
+ declare const skip: boolean;
210
+ const ys = Arr.generate(function* () {
211
+ for (const x of xs) {
212
+ if (x !== undefined) {
213
+ yield x;
214
+ }
213
215
  }
214
- }
215
- });
216
- const zs = Arr.generate(function* () {
217
- for (const x of xs) {
218
- if (!skip) {
219
- yield x;
216
+ });
217
+ const zs = xs.flatMap((x) => (skip ? [] : [x]));
218
+ `,
219
+ dedent`
220
+ import { Arr } from 'ts-data-forge';
221
+ declare const xs: readonly (number | undefined)[];
222
+ declare const skip: boolean;
223
+ const ys = Arr.generate(function* () {
224
+ for (const x of xs) {
225
+ if (x !== undefined) {
226
+ yield x;
227
+ }
220
228
  }
221
- }
222
- });
223
- `,
229
+ });
230
+ const zs = Arr.generate(function* () {
231
+ for (const x of xs) {
232
+ if (!skip) {
233
+ yield x;
234
+ }
235
+ }
236
+ });
237
+ `,
238
+ ],
224
239
  errors: [
225
240
  { messageId: 'useArrGenerate' },
226
241
  { messageId: 'useArrGenerate' },
@@ -237,40 +252,58 @@ describe('prefer-arr-generate', () => {
237
252
  const c = xs.flatMap((x) => (n < 0 ? [] : [x]));
238
253
  const d = xs.flatMap((x) => (!ok(x) ? [] : [x]));
239
254
  `,
240
- output: dedent`
241
- import { Arr } from 'ts-data-forge';
242
- declare const xs: readonly (string | undefined)[];
243
- declare const ok: (x: string | undefined) => boolean;
244
- declare const n: number;
245
- const a = Arr.generate(function* () {
246
- for (const x of xs) {
247
- if (x !== undefined && x !== '') {
248
- yield x;
255
+ output: [
256
+ dedent`
257
+ import { Arr } from 'ts-data-forge';
258
+ declare const xs: readonly (string | undefined)[];
259
+ declare const ok: (x: string | undefined) => boolean;
260
+ declare const n: number;
261
+ const a = Arr.generate(function* () {
262
+ for (const x of xs) {
263
+ if (x !== undefined && x !== '') {
264
+ yield x;
265
+ }
249
266
  }
250
- }
251
- });
252
- const b = Arr.generate(function* () {
253
- for (const x of xs) {
254
- if (!ok(x)) {
255
- yield x;
267
+ });
268
+ const b = xs.flatMap((x) => (ok(x) ? [] : [x]));
269
+ const c = xs.flatMap((x) => (n < 0 ? [] : [x]));
270
+ const d = xs.flatMap((x) => (!ok(x) ? [] : [x]));
271
+ `,
272
+ dedent`
273
+ import { Arr } from 'ts-data-forge';
274
+ declare const xs: readonly (string | undefined)[];
275
+ declare const ok: (x: string | undefined) => boolean;
276
+ declare const n: number;
277
+ const a = Arr.generate(function* () {
278
+ for (const x of xs) {
279
+ if (x !== undefined && x !== '') {
280
+ yield x;
281
+ }
256
282
  }
257
- }
258
- });
259
- const c = Arr.generate(function* () {
260
- for (const x of xs) {
261
- if (!(n < 0)) {
262
- yield x;
283
+ });
284
+ const b = Arr.generate(function* () {
285
+ for (const x of xs) {
286
+ if (!ok(x)) {
287
+ yield x;
288
+ }
263
289
  }
264
- }
265
- });
266
- const d = Arr.generate(function* () {
267
- for (const x of xs) {
268
- if (ok(x)) {
269
- yield x;
290
+ });
291
+ const c = Arr.generate(function* () {
292
+ for (const x of xs) {
293
+ if (!(n < 0)) {
294
+ yield x;
295
+ }
270
296
  }
271
- }
272
- });
273
- `,
297
+ });
298
+ const d = Arr.generate(function* () {
299
+ for (const x of xs) {
300
+ if (ok(x)) {
301
+ yield x;
302
+ }
303
+ }
304
+ });
305
+ `,
306
+ ],
274
307
  errors: [
275
308
  { messageId: 'useArrGenerate' },
276
309
  { messageId: 'useArrGenerate' },
@@ -435,6 +468,25 @@ describe('prefer-arr-generate', () => {
435
468
  `,
436
469
  errors: [{ messageId: 'useArrGenerate' }],
437
470
  },
471
+ {
472
+ name: 'no fix when an import type binds Arr',
473
+ code: dedent`
474
+ import type { Arr } from 'ts-data-forge';
475
+ declare const xs: readonly number[];
476
+ const ys = xs.flatMap((x) => (x > 0 ? [x] : []));
477
+ `,
478
+ output: null,
479
+ errors: [{ messageId: 'useArrGenerate' }],
480
+ },
481
+ {
482
+ name: 'no fix where a local binding takes Arr',
483
+ code: dedent`
484
+ declare const xs: readonly number[];
485
+ export const f = (Arr: unknown) => xs.flatMap((x) => (x > 0 ? [x] : []));
486
+ `,
487
+ output: null,
488
+ errors: [{ messageId: 'useArrGenerate' }],
489
+ },
438
490
  {
439
491
  name: 'indents from the line the call starts on, and accepts a mutable array, a tuple or a type parameter',
440
492
  code: dedent`
@@ -446,34 +498,52 @@ describe('prefer-arr-generate', () => {
446
498
  const c = xs.flatMap((x) => (x > 0 ? [x] : []));
447
499
  };
448
500
  `,
449
- output: dedent`
450
- import { Arr } from 'ts-data-forge';
451
- declare const ms: number[];
452
- declare const ts: readonly [number, number];
453
- export const f = <T extends readonly number[]>(xs: T): void => {
454
- const a = Arr.generate(function* () {
455
- for (const x of ms) {
456
- if (x > 0) {
457
- yield x;
501
+ output: [
502
+ dedent`
503
+ import { Arr } from 'ts-data-forge';
504
+ declare const ms: number[];
505
+ declare const ts: readonly [number, number];
506
+ export const f = <T extends readonly number[]>(xs: T): void => {
507
+ const a = Arr.generate(function* () {
508
+ for (const x of ms) {
509
+ if (x > 0) {
510
+ yield x;
511
+ }
458
512
  }
459
- }
460
- });
461
- const b = Arr.generate(function* () {
462
- for (const x of ts) {
463
- if (x > 0) {
464
- yield x;
513
+ });
514
+ const b = ts.flatMap((x) => (x > 0 ? [x] : []));
515
+ const c = xs.flatMap((x) => (x > 0 ? [x] : []));
516
+ };
517
+ `,
518
+ dedent`
519
+ import { Arr } from 'ts-data-forge';
520
+ declare const ms: number[];
521
+ declare const ts: readonly [number, number];
522
+ export const f = <T extends readonly number[]>(xs: T): void => {
523
+ const a = Arr.generate(function* () {
524
+ for (const x of ms) {
525
+ if (x > 0) {
526
+ yield x;
527
+ }
465
528
  }
466
- }
467
- });
468
- const c = Arr.generate(function* () {
469
- for (const x of xs) {
470
- if (x > 0) {
471
- yield x;
529
+ });
530
+ const b = Arr.generate(function* () {
531
+ for (const x of ts) {
532
+ if (x > 0) {
533
+ yield x;
534
+ }
472
535
  }
473
- }
474
- });
475
- };
476
- `,
536
+ });
537
+ const c = Arr.generate(function* () {
538
+ for (const x of xs) {
539
+ if (x > 0) {
540
+ yield x;
541
+ }
542
+ }
543
+ });
544
+ };
545
+ `,
546
+ ],
477
547
  errors: [
478
548
  { messageId: 'useArrGenerate' },
479
549
  { messageId: 'useArrGenerate' },
@@ -691,30 +761,50 @@ describe('prefer-arr-generate', () => {
691
761
  return [...a, ...b];
692
762
  };
693
763
  `,
694
- output: dedent`
695
- import { Arr } from 'ts-data-forge';
696
- declare const c: readonly number[] | undefined;
697
- export const f = (p: readonly number[] | undefined): readonly number[] => {
698
- if (c === undefined || p === undefined) {
699
- return [];
700
- }
701
- const a = Arr.generate(function* () {
702
- for (const x of c) {
703
- if (x > 0) {
704
- yield x;
705
- }
764
+ output: [
765
+ dedent`
766
+ import { Arr } from 'ts-data-forge';
767
+ declare const c: readonly number[] | undefined;
768
+ export const f = (p: readonly number[] | undefined): readonly number[] => {
769
+ if (c === undefined || p === undefined) {
770
+ return [];
706
771
  }
707
- });
708
- const b = Arr.generate(function* () {
709
- for (const x of p) {
710
- if (x > 0) {
711
- yield x;
772
+ const a = Arr.generate(function* () {
773
+ for (const x of c) {
774
+ if (x > 0) {
775
+ yield x;
776
+ }
712
777
  }
778
+ });
779
+ const b = p.flatMap((x) => (x > 0 ? [x] : []));
780
+ return [...a, ...b];
781
+ };
782
+ `,
783
+ dedent`
784
+ import { Arr } from 'ts-data-forge';
785
+ declare const c: readonly number[] | undefined;
786
+ export const f = (p: readonly number[] | undefined): readonly number[] => {
787
+ if (c === undefined || p === undefined) {
788
+ return [];
713
789
  }
714
- });
715
- return [...a, ...b];
716
- };
717
- `,
790
+ const a = Arr.generate(function* () {
791
+ for (const x of c) {
792
+ if (x > 0) {
793
+ yield x;
794
+ }
795
+ }
796
+ });
797
+ const b = Arr.generate(function* () {
798
+ for (const x of p) {
799
+ if (x > 0) {
800
+ yield x;
801
+ }
802
+ }
803
+ });
804
+ return [...a, ...b];
805
+ };
806
+ `,
807
+ ],
718
808
  errors: [
719
809
  { messageId: 'useArrGenerate' },
720
810
  { messageId: 'useArrGenerate' },
@@ -737,34 +827,58 @@ describe('prefer-arr-generate', () => {
737
827
  return [...a, ...b];
738
828
  };
739
829
  `,
740
- output: dedent`
741
- import { Arr } from 'ts-data-forge';
742
- declare const isNonEmpty: <T,>(
743
- xs: readonly T[],
744
- ) => xs is readonly [T, ...T[]];
745
- declare const o: Readonly<{ names: readonly string[] }>;
746
- declare const nested: readonly (readonly string[])[];
747
- export const f = (): readonly string[] => {
748
- if (!isNonEmpty(o.names)) {
749
- return [];
750
- }
751
- const a = Arr.generate(function* () {
752
- for (const x of o.names) {
753
- if (x !== '') {
754
- yield x;
755
- }
830
+ output: [
831
+ dedent`
832
+ import { Arr } from 'ts-data-forge';
833
+ declare const isNonEmpty: <T,>(
834
+ xs: readonly T[],
835
+ ) => xs is readonly [T, ...T[]];
836
+ declare const o: Readonly<{ names: readonly string[] }>;
837
+ declare const nested: readonly (readonly string[])[];
838
+ export const f = (): readonly string[] => {
839
+ if (!isNonEmpty(o.names)) {
840
+ return [];
756
841
  }
757
- });
758
- const b = Arr.generate(function* () {
759
- for (const x of nested.flat()) {
760
- if (x !== '') {
761
- yield x;
842
+ const a = Arr.generate(function* () {
843
+ for (const x of o.names) {
844
+ if (x !== '') {
845
+ yield x;
846
+ }
762
847
  }
848
+ });
849
+ const b = nested.flat().flatMap((x) => (x !== '' ? [x] : []));
850
+ return [...a, ...b];
851
+ };
852
+ `,
853
+ dedent`
854
+ import { Arr } from 'ts-data-forge';
855
+ declare const isNonEmpty: <T,>(
856
+ xs: readonly T[],
857
+ ) => xs is readonly [T, ...T[]];
858
+ declare const o: Readonly<{ names: readonly string[] }>;
859
+ declare const nested: readonly (readonly string[])[];
860
+ export const f = (): readonly string[] => {
861
+ if (!isNonEmpty(o.names)) {
862
+ return [];
763
863
  }
764
- });
765
- return [...a, ...b];
766
- };
767
- `,
864
+ const a = Arr.generate(function* () {
865
+ for (const x of o.names) {
866
+ if (x !== '') {
867
+ yield x;
868
+ }
869
+ }
870
+ });
871
+ const b = Arr.generate(function* () {
872
+ for (const x of nested.flat()) {
873
+ if (x !== '') {
874
+ yield x;
875
+ }
876
+ }
877
+ });
878
+ return [...a, ...b];
879
+ };
880
+ `,
881
+ ],
768
882
  errors: [
769
883
  { messageId: 'useArrGenerate' },
770
884
  { messageId: 'useArrGenerate' },
@@ -867,24 +981,38 @@ describe('prefer-arr-generate through type wrappers', () => {
867
981
  );
868
982
  const b = xs.flatMap!((x) => (x > 0 ? [x] : []));
869
983
  `,
870
- output: dedent`
871
- import { Arr } from 'ts-data-forge';
872
- declare const xs: readonly number[];
873
- const a = Arr.generate(function* () {
874
- for (const x of xs satisfies readonly number[]) {
875
- if (x > 0) {
876
- yield x;
984
+ output: [
985
+ dedent`
986
+ import { Arr } from 'ts-data-forge';
987
+ declare const xs: readonly number[];
988
+ const a = Arr.generate(function* () {
989
+ for (const x of xs satisfies readonly number[]) {
990
+ if (x > 0) {
991
+ yield x;
992
+ }
877
993
  }
878
- }
879
- });
880
- const b = Arr.generate(function* () {
881
- for (const x of xs) {
882
- if (x > 0) {
883
- yield x;
994
+ });
995
+ const b = xs.flatMap!((x) => (x > 0 ? [x] : []));
996
+ `,
997
+ dedent`
998
+ import { Arr } from 'ts-data-forge';
999
+ declare const xs: readonly number[];
1000
+ const a = Arr.generate(function* () {
1001
+ for (const x of xs satisfies readonly number[]) {
1002
+ if (x > 0) {
1003
+ yield x;
1004
+ }
884
1005
  }
885
- }
886
- });
887
- `,
1006
+ });
1007
+ const b = Arr.generate(function* () {
1008
+ for (const x of xs) {
1009
+ if (x > 0) {
1010
+ yield x;
1011
+ }
1012
+ }
1013
+ });
1014
+ `,
1015
+ ],
888
1016
  errors: [
889
1017
  { messageId: 'useArrGenerate' },
890
1018
  { messageId: 'useArrGenerate' },
@@ -72,11 +72,18 @@ ruleTester.run('prefer-arr-is-array', preferArrIsArray, {
72
72
  const result1 = Array.isArray(value1);
73
73
  const result2 = Array.isArray(value2);
74
74
  `,
75
- output: dedent`
76
- import { Arr } from 'ts-data-forge';
77
- const result1 = Arr.isArray(value1);
78
- const result2 = Arr.isArray(value2);
79
- `,
75
+ output: [
76
+ dedent`
77
+ import { Arr } from 'ts-data-forge';
78
+ const result1 = Arr.isArray(value1);
79
+ const result2 = Array.isArray(value2);
80
+ `,
81
+ dedent`
82
+ import { Arr } from 'ts-data-forge';
83
+ const result1 = Arr.isArray(value1);
84
+ const result2 = Arr.isArray(value2);
85
+ `,
86
+ ],
80
87
  errors: [{ messageId: 'useIsArray' }, { messageId: 'useIsArray' }],
81
88
  },
82
89
  ],
@@ -157,3 +164,78 @@ describe('prefer-arr-is-array with parenthesized operands', () => {
157
164
  ],
158
165
  });
159
166
  });
167
+
168
+ describe('prefer-arr-is-array brings Arr into scope', () => {
169
+ ruleTester.run('prefer-arr-is-array', preferArrIsArray, {
170
+ valid: [],
171
+ invalid: [
172
+ {
173
+ name: 'after a leading directive',
174
+ code: dedent`
175
+ 'use client';
176
+ const result = Array.isArray(value);
177
+ `,
178
+ output: dedent`
179
+ 'use client';
180
+ import { Arr } from 'ts-data-forge';
181
+ const result = Arr.isArray(value);
182
+ `,
183
+ errors: [{ messageId: 'useIsArray' }],
184
+ },
185
+ {
186
+ name: 'in the existing named import',
187
+ code: dedent`
188
+ import { Num } from 'ts-data-forge';
189
+ const result = Array.isArray(value);
190
+ `,
191
+ output: dedent`
192
+ import { Num, Arr } from 'ts-data-forge';
193
+ const result = Arr.isArray(value);
194
+ `,
195
+ errors: [{ messageId: 'useIsArray' }],
196
+ },
197
+ {
198
+ name: 'an inline type import becomes a value import',
199
+ code: dedent`
200
+ import { type Arr } from 'ts-data-forge';
201
+ const result = Array.isArray(value);
202
+ `,
203
+ output: dedent`
204
+ import { Arr } from 'ts-data-forge';
205
+ const result = Arr.isArray(value);
206
+ `,
207
+ errors: [{ messageId: 'useIsArray' }],
208
+ },
209
+ {
210
+ name: 'no fix when a type-only declaration imports it',
211
+ code: dedent`
212
+ import type { Arr } from 'ts-data-forge';
213
+ const result = Array.isArray(value);
214
+ `,
215
+ output: null,
216
+ errors: [{ messageId: 'useIsArray' }],
217
+ },
218
+ {
219
+ name: 'the local name of an aliased import',
220
+ code: dedent`
221
+ import { Arr as A } from 'ts-data-forge';
222
+ const result = Array.isArray(value);
223
+ `,
224
+ output: dedent`
225
+ import { Arr as A } from 'ts-data-forge';
226
+ const result = A.isArray(value);
227
+ `,
228
+ errors: [{ messageId: 'useIsArray' }],
229
+ },
230
+ {
231
+ name: 'no fix when something else is named Arr where the call is',
232
+ code: dedent`
233
+ const Arr = 1;
234
+ const result = Array.isArray(value);
235
+ `,
236
+ output: null,
237
+ errors: [{ messageId: 'useIsArray' }],
238
+ },
239
+ ],
240
+ });
241
+ });
@@ -1,16 +1,11 @@
1
1
  import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
2
- import {
3
- buildNamedImportFix,
4
- getArgumentText,
5
- getImportDeclarations,
6
- getNamedImports,
7
- } from 'eslint-rule-forge';
2
+ import { getArgumentText } from 'eslint-rule-forge';
8
3
  import {
9
4
  isArrayOrTupleExpression,
10
5
  isSameArrayText,
11
6
  parseLengthComparison,
12
7
  } from './ast-utils.mjs';
13
- import { TS_DATA_FORGE_MODULE } from './constants.mjs';
8
+ import { tsDataForgeValueAt } from './import-binding.mjs';
14
9
 
15
10
  type Options = readonly [];
16
11
 
@@ -38,13 +33,6 @@ export const preferArrIsBoundedLengthArray: TSESLint.RuleModule<
38
33
  create: (context) => {
39
34
  const sourceCode = context.sourceCode;
40
35
 
41
- const program = sourceCode.ast;
42
-
43
- const tsDataForgeImports = getImportDeclarations(
44
- program,
45
- TS_DATA_FORGE_MODULE,
46
- );
47
-
48
36
  const services = context.sourceCode.parserServices;
49
37
 
50
38
  const mut_nodesToFix: {
@@ -100,14 +88,14 @@ export const preferArrIsBoundedLengthArray: TSESLint.RuleModule<
100
88
  });
101
89
  },
102
90
  'Program:exit': () => {
103
- const namedImports = getNamedImports(tsDataForgeImports);
91
+ const arrAt = tsDataForgeValueAt(sourceCode, 'Arr');
104
92
 
105
- const hasArrImport = namedImports.includes('Arr');
106
-
107
- for (const [
108
- index,
109
- { node, arrayExpression, minExpression, maxExpression },
110
- ] of mut_nodesToFix.entries()) {
93
+ for (const {
94
+ node,
95
+ arrayExpression,
96
+ minExpression,
97
+ maxExpression,
98
+ } of mut_nodesToFix) {
111
99
  const arrayText = getArgumentText(sourceCode, arrayExpression);
112
100
 
113
101
  const minText = sourceCode.getText(minExpression);
@@ -116,6 +104,8 @@ export const preferArrIsBoundedLengthArray: TSESLint.RuleModule<
116
104
 
117
105
  const originalText = sourceCode.getText(node);
118
106
 
107
+ const arr = arrAt(node);
108
+
119
109
  context.report({
120
110
  node,
121
111
  messageId: 'useIsBoundedLengthArray',
@@ -125,18 +115,17 @@ export const preferArrIsBoundedLengthArray: TSESLint.RuleModule<
125
115
  min: minText,
126
116
  max: maxText,
127
117
  },
128
- fix: (fixer) => {
129
- const replacement = `Arr.isBoundedLengthArray(${minText}, ${maxText}, ${arrayText})`;
130
-
131
- const importFixes =
132
- index === 0 && !hasArrImport
133
- ? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
134
- 'Arr',
135
- ])
136
- : [];
137
-
138
- return [...importFixes, fixer.replaceText(node, replacement)];
139
- },
118
+ fix:
119
+ arr === undefined
120
+ ? null
121
+ : (fixer) => {
122
+ const replacement = `${arr.localName}.isBoundedLengthArray(${minText}, ${maxText}, ${arrayText})`;
123
+
124
+ return [
125
+ ...arr.edits(fixer),
126
+ fixer.replaceText(node, replacement),
127
+ ];
128
+ },
140
129
  });
141
130
  }
142
131
  },