eslint-plugin-ts-data-forge 0.8.5 → 0.9.0

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 (135) hide show
  1. package/README.md +20 -19
  2. package/dist/plugin.d.mts +2 -0
  3. package/dist/plugin.d.mts.map +1 -1
  4. package/dist/plugin.mjs +1 -0
  5. package/dist/plugin.mjs.map +1 -1
  6. package/dist/rule-types.d.mts +16 -1
  7. package/dist/rule-types.d.mts.map +1 -1
  8. package/dist/rule-types.mjs.map +1 -1
  9. package/dist/rules/ast-utils.d.mts +21 -34
  10. package/dist/rules/ast-utils.d.mts.map +1 -1
  11. package/dist/rules/ast-utils.mjs +53 -58
  12. package/dist/rules/ast-utils.mjs.map +1 -1
  13. package/dist/rules/constants.d.mts +2 -0
  14. package/dist/rules/constants.d.mts.map +1 -1
  15. package/dist/rules/constants.mjs +9 -0
  16. package/dist/rules/constants.mjs.map +1 -1
  17. package/dist/rules/mutable-result.d.mts +10 -0
  18. package/dist/rules/mutable-result.d.mts.map +1 -0
  19. package/dist/rules/mutable-result.mjs +145 -0
  20. package/dist/rules/mutable-result.mjs.map +1 -0
  21. package/dist/rules/no-unnecessary-type-guard.d.mts.map +1 -1
  22. package/dist/rules/no-unnecessary-type-guard.mjs +6 -6
  23. package/dist/rules/no-unnecessary-type-guard.mjs.map +1 -1
  24. package/dist/rules/prefer-arr-generate.d.mts +57 -0
  25. package/dist/rules/prefer-arr-generate.d.mts.map +1 -0
  26. package/dist/rules/prefer-arr-generate.mjs +588 -0
  27. package/dist/rules/prefer-arr-generate.mjs.map +1 -0
  28. package/dist/rules/prefer-arr-is-array.d.mts.map +1 -1
  29. package/dist/rules/prefer-arr-is-array.mjs +7 -5
  30. package/dist/rules/prefer-arr-is-array.mjs.map +1 -1
  31. package/dist/rules/prefer-arr-is-bounded-length-array.d.mts.map +1 -1
  32. package/dist/rules/prefer-arr-is-bounded-length-array.mjs +9 -6
  33. package/dist/rules/prefer-arr-is-bounded-length-array.mjs.map +1 -1
  34. package/dist/rules/prefer-arr-is-fixed-length-array.d.mts.map +1 -1
  35. package/dist/rules/prefer-arr-is-fixed-length-array.mjs +9 -6
  36. package/dist/rules/prefer-arr-is-fixed-length-array.mjs.map +1 -1
  37. package/dist/rules/prefer-arr-is-max-length-array.d.mts.map +1 -1
  38. package/dist/rules/prefer-arr-is-max-length-array.mjs +9 -6
  39. package/dist/rules/prefer-arr-is-max-length-array.mjs.map +1 -1
  40. package/dist/rules/prefer-arr-is-min-length-array.d.mts.map +1 -1
  41. package/dist/rules/prefer-arr-is-min-length-array.mjs +9 -6
  42. package/dist/rules/prefer-arr-is-min-length-array.mjs.map +1 -1
  43. package/dist/rules/prefer-arr-is-non-empty.d.mts.map +1 -1
  44. package/dist/rules/prefer-arr-is-non-empty.mjs +9 -6
  45. package/dist/rules/prefer-arr-is-non-empty.mjs.map +1 -1
  46. package/dist/rules/prefer-arr-scan.d.mts.map +1 -1
  47. package/dist/rules/prefer-arr-scan.mjs +8 -11
  48. package/dist/rules/prefer-arr-scan.mjs.map +1 -1
  49. package/dist/rules/prefer-arr-sum.d.mts.map +1 -1
  50. package/dist/rules/prefer-arr-sum.mjs +8 -6
  51. package/dist/rules/prefer-arr-sum.mjs.map +1 -1
  52. package/dist/rules/prefer-arr-uniq.d.mts.map +1 -1
  53. package/dist/rules/prefer-arr-uniq.mjs +12 -166
  54. package/dist/rules/prefer-arr-uniq.mjs.map +1 -1
  55. package/dist/rules/prefer-as-int.d.mts.map +1 -1
  56. package/dist/rules/prefer-as-int.mjs +6 -8
  57. package/dist/rules/prefer-as-int.mjs.map +1 -1
  58. package/dist/rules/prefer-canonical-array-slicing.d.mts.map +1 -1
  59. package/dist/rules/prefer-canonical-array-slicing.mjs +57 -34
  60. package/dist/rules/prefer-canonical-array-slicing.mjs.map +1 -1
  61. package/dist/rules/prefer-canonical-length-cast.d.mts.map +1 -1
  62. package/dist/rules/prefer-canonical-length-cast.mjs +3 -3
  63. package/dist/rules/prefer-canonical-length-cast.mjs.map +1 -1
  64. package/dist/rules/prefer-canonical-length-guard.d.mts.map +1 -1
  65. package/dist/rules/prefer-canonical-length-guard.mjs +4 -4
  66. package/dist/rules/prefer-canonical-length-guard.mjs.map +1 -1
  67. package/dist/rules/prefer-comparison-over-nullish-guard.d.mts.map +1 -1
  68. package/dist/rules/prefer-comparison-over-nullish-guard.mjs +3 -2
  69. package/dist/rules/prefer-comparison-over-nullish-guard.mjs.map +1 -1
  70. package/dist/rules/prefer-is-non-null-object.d.mts.map +1 -1
  71. package/dist/rules/prefer-is-non-null-object.mjs +113 -43
  72. package/dist/rules/prefer-is-non-null-object.mjs.map +1 -1
  73. package/dist/rules/prefer-is-record-and-has-key.d.mts.map +1 -1
  74. package/dist/rules/prefer-is-record-and-has-key.mjs +105 -48
  75. package/dist/rules/prefer-is-record-and-has-key.mjs.map +1 -1
  76. package/dist/rules/prefer-num-safe-parse-float.d.mts.map +1 -1
  77. package/dist/rules/prefer-num-safe-parse-float.mjs +6 -6
  78. package/dist/rules/prefer-num-safe-parse-float.mjs.map +1 -1
  79. package/dist/rules/prefer-num-safe-parse-int.d.mts.map +1 -1
  80. package/dist/rules/prefer-num-safe-parse-int.mjs +6 -6
  81. package/dist/rules/prefer-num-safe-parse-int.mjs.map +1 -1
  82. package/dist/rules/prefer-obj-over-entries-round-trip.d.mts.map +1 -1
  83. package/dist/rules/prefer-obj-over-entries-round-trip.mjs +9 -12
  84. package/dist/rules/prefer-obj-over-entries-round-trip.mjs.map +1 -1
  85. package/dist/rules/prefer-range-for-loop.d.mts.map +1 -1
  86. package/dist/rules/prefer-range-for-loop.mjs +104 -23
  87. package/dist/rules/prefer-range-for-loop.mjs.map +1 -1
  88. package/dist/rules/rules.d.mts +1 -0
  89. package/dist/rules/rules.d.mts.map +1 -1
  90. package/dist/rules/rules.mjs +2 -0
  91. package/dist/rules/rules.mjs.map +1 -1
  92. package/package.json +11 -10
  93. package/src/plugin.mts +1 -0
  94. package/src/rule-types.mts +17 -1
  95. package/src/rules/ast-utils.mts +73 -80
  96. package/src/rules/constants.mts +12 -0
  97. package/src/rules/mutable-result.mts +204 -0
  98. package/src/rules/no-unnecessary-type-guard.mts +14 -10
  99. package/src/rules/prefer-arr-generate.mts +918 -0
  100. package/src/rules/prefer-arr-generate.test.mts +967 -0
  101. package/src/rules/prefer-arr-is-array.mts +14 -7
  102. package/src/rules/prefer-arr-is-array.test.mts +14 -0
  103. package/src/rules/prefer-arr-is-bounded-length-array.mts +16 -10
  104. package/src/rules/prefer-arr-is-bounded-length-array.test.mts +19 -0
  105. package/src/rules/prefer-arr-is-fixed-length-array.mts +17 -11
  106. package/src/rules/prefer-arr-is-max-length-array.mts +17 -11
  107. package/src/rules/prefer-arr-is-max-length-array.test.mts +8 -0
  108. package/src/rules/prefer-arr-is-min-length-array.mts +17 -11
  109. package/src/rules/prefer-arr-is-min-length-array.test.mts +8 -0
  110. package/src/rules/prefer-arr-is-non-empty.mts +16 -13
  111. package/src/rules/prefer-arr-scan.mts +24 -19
  112. package/src/rules/prefer-arr-sum.mts +18 -14
  113. package/src/rules/prefer-arr-uniq.mts +25 -234
  114. package/src/rules/prefer-as-int.mts +19 -12
  115. package/src/rules/prefer-canonical-array-slicing.mts +79 -52
  116. package/src/rules/prefer-canonical-array-slicing.test.mts +55 -0
  117. package/src/rules/prefer-canonical-length-cast.mts +7 -3
  118. package/src/rules/prefer-canonical-length-guard.mts +9 -4
  119. package/src/rules/prefer-comparison-over-nullish-guard.mts +3 -2
  120. package/src/rules/prefer-comparison-over-nullish-guard.test.mts +16 -0
  121. package/src/rules/prefer-is-non-null-object.mts +171 -64
  122. package/src/rules/prefer-is-non-null-object.test.mts +138 -0
  123. package/src/rules/prefer-is-record-and-has-key.mts +159 -74
  124. package/src/rules/prefer-is-record-and-has-key.test.mts +118 -23
  125. package/src/rules/prefer-num-safe-parse-float.mts +15 -10
  126. package/src/rules/prefer-num-safe-parse-int.mts +15 -13
  127. package/src/rules/prefer-obj-over-entries-round-trip.mts +19 -22
  128. package/src/rules/prefer-range-for-loop.mts +157 -31
  129. package/src/rules/prefer-range-for-loop.test.mts +127 -5
  130. package/src/rules/rules.mts +2 -0
  131. package/dist/rules/import-utils.d.mts +0 -30
  132. package/dist/rules/import-utils.d.mts.map +0 -1
  133. package/dist/rules/import-utils.mjs +0 -98
  134. package/dist/rules/import-utils.mjs.map +0 -1
  135. package/src/rules/import-utils.mts +0 -175
@@ -1,175 +0,0 @@
1
- import {
2
- AST_NODE_TYPES,
3
- type TSESLint,
4
- type TSESTree,
5
- } from '@typescript-eslint/utils';
6
- import type { DeepReadonly } from 'ts-type-forge';
7
- import { isTypeWrapper } from './ast-utils.mjs';
8
- import { TS_DATA_FORGE_MODULE } from './constants.mjs';
9
-
10
- /* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
11
-
12
- export const getTsDataForgeImport = (
13
- program: TSESTree.Program,
14
- ): TSESTree.ImportDeclaration | undefined =>
15
- program.body.find(
16
- (node): node is TSESTree.ImportDeclaration =>
17
- node.type === AST_NODE_TYPES.ImportDeclaration &&
18
- node.source.value === TS_DATA_FORGE_MODULE,
19
- );
20
-
21
- export const getNamedImports = (
22
- node: DeepReadonly<TSESTree.ImportDeclaration> | undefined,
23
- ): readonly string[] => {
24
- if (node === undefined) {
25
- return [];
26
- }
27
-
28
- return node.specifiers.flatMap((specifier) =>
29
- specifier.type === AST_NODE_TYPES.ImportSpecifier
30
- ? (() => {
31
- const importedName =
32
- specifier.imported.type === AST_NODE_TYPES.Identifier
33
- ? specifier.imported.name
34
- : specifier.imported.value;
35
-
36
- return typeof importedName === 'string' ? [importedName] : [];
37
- })()
38
- : [],
39
- );
40
- };
41
-
42
- /**
43
- * Returns the in-scope local name a given canonical export is imported as
44
- * (handling aliases such as `import { isX as y }` → `'y'`), or `undefined` when
45
- * it is not imported. Used so autofixes reference the binding that actually
46
- * exists rather than the canonical name.
47
- */
48
- export const getImportedLocalName = (
49
- node: DeepReadonly<TSESTree.ImportDeclaration> | undefined,
50
- importedName: string,
51
- ): string | undefined =>
52
- node?.specifiers.find(
53
- (specifier) =>
54
- specifier.type === AST_NODE_TYPES.ImportSpecifier &&
55
- (specifier.imported.type === AST_NODE_TYPES.Identifier
56
- ? specifier.imported.name
57
- : specifier.imported.value) === importedName,
58
- )?.local.name;
59
-
60
- type ResolvedCallee = Readonly<{
61
- /** The canonical (imported) ts-data-forge name, regardless of local alias. */
62
- canonicalName: string;
63
- /** The identifier node to rewrite when replacing the callee name. */
64
- propertyNode: TSESTree.Node;
65
- /** Whether the call was made through a namespace import (`tf.isX(...)`). */
66
- isNamespace: boolean;
67
- }>;
68
-
69
- /**
70
- * Builds a resolver that maps a call expression's callee to the canonical
71
- * ts-data-forge function it refers to. Handles named imports (including aliases
72
- * such as `import { isX as y }`) and namespace imports (`import * as tf` →
73
- * `tf.isX(...)`). Returns `undefined` for any callee that does not reference the
74
- * given ts-data-forge import.
75
- */
76
- export const buildCalleeResolver = (
77
- importDecl: TSESTree.ImportDeclaration | undefined,
78
- ): ((
79
- callee: DeepReadonly<TSESTree.Expression>,
80
- ) => ResolvedCallee | undefined) => {
81
- const specifiers = importDecl?.specifiers ?? [];
82
-
83
- const namespaceName = specifiers.find(
84
- (specifier) => specifier.type === AST_NODE_TYPES.ImportNamespaceSpecifier,
85
- )?.local.name;
86
-
87
- const localToCanonical = new Map<string, string>(
88
- specifiers.flatMap((specifier) => {
89
- if (specifier.type !== AST_NODE_TYPES.ImportSpecifier) {
90
- return [];
91
- }
92
-
93
- const importedName =
94
- specifier.imported.type === AST_NODE_TYPES.Identifier
95
- ? specifier.imported.name
96
- : specifier.imported.value;
97
-
98
- return typeof importedName === 'string'
99
- ? [[specifier.local.name, importedName] as const]
100
- : [];
101
- }),
102
- );
103
-
104
- // `(isNull as (u: unknown) => boolean)(x)` and `(tf as typeof tf).isNull(x)`
105
- // still call `isNull`: both the callee and a namespace object are read
106
- // through type wrappers.
107
- const resolve = (
108
- callee: DeepReadonly<TSESTree.Expression>,
109
- ): ResolvedCallee | undefined => {
110
- if (isTypeWrapper(callee)) {
111
- return resolve(callee.expression);
112
- }
113
-
114
- if (callee.type === AST_NODE_TYPES.Identifier) {
115
- const canonicalName = localToCanonical.get(callee.name);
116
-
117
- return canonicalName === undefined
118
- ? undefined
119
- : {
120
- canonicalName,
121
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
122
- propertyNode: callee as TSESTree.Node,
123
- isNamespace: false,
124
- };
125
- }
126
-
127
- if (
128
- namespaceName === undefined ||
129
- callee.type !== AST_NODE_TYPES.MemberExpression ||
130
- callee.computed ||
131
- callee.property.type !== AST_NODE_TYPES.Identifier
132
- ) {
133
- return undefined;
134
- }
135
-
136
- const object = skipReadonlyTypeWrappers(callee.object);
137
-
138
- return object.type === AST_NODE_TYPES.Identifier &&
139
- object.name === namespaceName
140
- ? {
141
- canonicalName: callee.property.name,
142
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
143
- propertyNode: callee.property as TSESTree.Node,
144
- isNamespace: true,
145
- }
146
- : undefined;
147
- };
148
-
149
- return resolve;
150
- };
151
-
152
- const skipReadonlyTypeWrappers = (
153
- node: DeepReadonly<TSESTree.Expression>,
154
- ): DeepReadonly<TSESTree.Expression> =>
155
- isTypeWrapper(node) ? skipReadonlyTypeWrappers(node.expression) : node;
156
-
157
- export const buildImportFixes = (
158
- fixer: TSESLint.RuleFixer,
159
- program: TSESTree.Program,
160
- _tsDataForgeImport: TSESTree.ImportDeclaration | undefined,
161
- requiredNames: readonly string[],
162
- ): readonly TSESLint.RuleFix[] => {
163
- const specifierText = requiredNames.join(', ');
164
-
165
- const importStatement =
166
- `import { ${specifierText} } from '${TS_DATA_FORGE_MODULE}';` as const;
167
-
168
- const newLine = '\n';
169
-
170
- const insertionText = `${importStatement}${newLine}` as const;
171
-
172
- // Always insert at the beginning of the file
173
- // (organize-imports will handle merging/deduplication)
174
- return [fixer.insertTextBefore(program, insertionText)];
175
- };