eslint-plugin-ts-data-forge 0.8.5 → 0.8.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 (97) hide show
  1. package/dist/rules/ast-utils.d.mts +0 -32
  2. package/dist/rules/ast-utils.d.mts.map +1 -1
  3. package/dist/rules/ast-utils.mjs +4 -56
  4. package/dist/rules/ast-utils.mjs.map +1 -1
  5. package/dist/rules/no-unnecessary-type-guard.d.mts.map +1 -1
  6. package/dist/rules/no-unnecessary-type-guard.mjs +6 -6
  7. package/dist/rules/no-unnecessary-type-guard.mjs.map +1 -1
  8. package/dist/rules/prefer-arr-is-array.d.mts.map +1 -1
  9. package/dist/rules/prefer-arr-is-array.mjs +7 -5
  10. package/dist/rules/prefer-arr-is-array.mjs.map +1 -1
  11. package/dist/rules/prefer-arr-is-bounded-length-array.d.mts.map +1 -1
  12. package/dist/rules/prefer-arr-is-bounded-length-array.mjs +9 -6
  13. package/dist/rules/prefer-arr-is-bounded-length-array.mjs.map +1 -1
  14. package/dist/rules/prefer-arr-is-fixed-length-array.d.mts.map +1 -1
  15. package/dist/rules/prefer-arr-is-fixed-length-array.mjs +9 -6
  16. package/dist/rules/prefer-arr-is-fixed-length-array.mjs.map +1 -1
  17. package/dist/rules/prefer-arr-is-max-length-array.d.mts.map +1 -1
  18. package/dist/rules/prefer-arr-is-max-length-array.mjs +9 -6
  19. package/dist/rules/prefer-arr-is-max-length-array.mjs.map +1 -1
  20. package/dist/rules/prefer-arr-is-min-length-array.d.mts.map +1 -1
  21. package/dist/rules/prefer-arr-is-min-length-array.mjs +9 -6
  22. package/dist/rules/prefer-arr-is-min-length-array.mjs.map +1 -1
  23. package/dist/rules/prefer-arr-is-non-empty.d.mts.map +1 -1
  24. package/dist/rules/prefer-arr-is-non-empty.mjs +9 -6
  25. package/dist/rules/prefer-arr-is-non-empty.mjs.map +1 -1
  26. package/dist/rules/prefer-arr-scan.d.mts.map +1 -1
  27. package/dist/rules/prefer-arr-scan.mjs +8 -11
  28. package/dist/rules/prefer-arr-scan.mjs.map +1 -1
  29. package/dist/rules/prefer-arr-sum.d.mts.map +1 -1
  30. package/dist/rules/prefer-arr-sum.mjs +8 -6
  31. package/dist/rules/prefer-arr-sum.mjs.map +1 -1
  32. package/dist/rules/prefer-arr-uniq.d.mts.map +1 -1
  33. package/dist/rules/prefer-arr-uniq.mjs +11 -18
  34. package/dist/rules/prefer-arr-uniq.mjs.map +1 -1
  35. package/dist/rules/prefer-as-int.d.mts.map +1 -1
  36. package/dist/rules/prefer-as-int.mjs +6 -8
  37. package/dist/rules/prefer-as-int.mjs.map +1 -1
  38. package/dist/rules/prefer-canonical-array-slicing.d.mts.map +1 -1
  39. package/dist/rules/prefer-canonical-array-slicing.mjs +10 -6
  40. package/dist/rules/prefer-canonical-array-slicing.mjs.map +1 -1
  41. package/dist/rules/prefer-canonical-length-cast.d.mts.map +1 -1
  42. package/dist/rules/prefer-canonical-length-cast.mjs +3 -3
  43. package/dist/rules/prefer-canonical-length-cast.mjs.map +1 -1
  44. package/dist/rules/prefer-canonical-length-guard.d.mts.map +1 -1
  45. package/dist/rules/prefer-canonical-length-guard.mjs +4 -4
  46. package/dist/rules/prefer-canonical-length-guard.mjs.map +1 -1
  47. package/dist/rules/prefer-comparison-over-nullish-guard.d.mts.map +1 -1
  48. package/dist/rules/prefer-comparison-over-nullish-guard.mjs +3 -2
  49. package/dist/rules/prefer-comparison-over-nullish-guard.mjs.map +1 -1
  50. package/dist/rules/prefer-is-non-null-object.d.mts.map +1 -1
  51. package/dist/rules/prefer-is-non-null-object.mjs +5 -5
  52. package/dist/rules/prefer-is-non-null-object.mjs.map +1 -1
  53. package/dist/rules/prefer-is-record-and-has-key.d.mts.map +1 -1
  54. package/dist/rules/prefer-is-record-and-has-key.mjs +5 -5
  55. package/dist/rules/prefer-is-record-and-has-key.mjs.map +1 -1
  56. package/dist/rules/prefer-num-safe-parse-float.d.mts.map +1 -1
  57. package/dist/rules/prefer-num-safe-parse-float.mjs +6 -6
  58. package/dist/rules/prefer-num-safe-parse-float.mjs.map +1 -1
  59. package/dist/rules/prefer-num-safe-parse-int.d.mts.map +1 -1
  60. package/dist/rules/prefer-num-safe-parse-int.mjs +6 -6
  61. package/dist/rules/prefer-num-safe-parse-int.mjs.map +1 -1
  62. package/dist/rules/prefer-obj-over-entries-round-trip.d.mts.map +1 -1
  63. package/dist/rules/prefer-obj-over-entries-round-trip.mjs +9 -12
  64. package/dist/rules/prefer-obj-over-entries-round-trip.mjs.map +1 -1
  65. package/dist/rules/prefer-range-for-loop.d.mts.map +1 -1
  66. package/dist/rules/prefer-range-for-loop.mjs +8 -8
  67. package/dist/rules/prefer-range-for-loop.mjs.map +1 -1
  68. package/package.json +5 -4
  69. package/src/rules/ast-utils.mts +8 -82
  70. package/src/rules/no-unnecessary-type-guard.mts +14 -10
  71. package/src/rules/prefer-arr-is-array.mts +14 -7
  72. package/src/rules/prefer-arr-is-array.test.mts +14 -0
  73. package/src/rules/prefer-arr-is-bounded-length-array.mts +16 -10
  74. package/src/rules/prefer-arr-is-fixed-length-array.mts +17 -11
  75. package/src/rules/prefer-arr-is-max-length-array.mts +17 -11
  76. package/src/rules/prefer-arr-is-min-length-array.mts +17 -11
  77. package/src/rules/prefer-arr-is-non-empty.mts +16 -13
  78. package/src/rules/prefer-arr-scan.mts +24 -19
  79. package/src/rules/prefer-arr-sum.mts +18 -14
  80. package/src/rules/prefer-arr-uniq.mts +24 -28
  81. package/src/rules/prefer-as-int.mts +19 -12
  82. package/src/rules/prefer-canonical-array-slicing.mts +22 -12
  83. package/src/rules/prefer-canonical-length-cast.mts +7 -3
  84. package/src/rules/prefer-canonical-length-guard.mts +9 -4
  85. package/src/rules/prefer-comparison-over-nullish-guard.mts +3 -2
  86. package/src/rules/prefer-comparison-over-nullish-guard.test.mts +16 -0
  87. package/src/rules/prefer-is-non-null-object.mts +11 -7
  88. package/src/rules/prefer-is-record-and-has-key.mts +14 -10
  89. package/src/rules/prefer-num-safe-parse-float.mts +15 -10
  90. package/src/rules/prefer-num-safe-parse-int.mts +15 -13
  91. package/src/rules/prefer-obj-over-entries-round-trip.mts +19 -22
  92. package/src/rules/prefer-range-for-loop.mts +16 -11
  93. package/dist/rules/import-utils.d.mts +0 -30
  94. package/dist/rules/import-utils.d.mts.map +0 -1
  95. package/dist/rules/import-utils.mjs +0 -98
  96. package/dist/rules/import-utils.mjs.map +0 -1
  97. package/src/rules/import-utils.mts +0 -175
@@ -3,17 +3,16 @@ import {
3
3
  type TSESLint,
4
4
  type TSESTree,
5
5
  } from '@typescript-eslint/utils';
6
- import * as ts from 'typescript';
7
6
  import {
7
+ buildNamedImportFix,
8
+ getArgumentText,
9
+ getImportDeclarations,
10
+ getNamedImports,
8
11
  skipTypeWrappers,
9
- toArgumentText,
10
12
  typeWrapperLayers,
11
- } from './ast-utils.mjs';
12
- import {
13
- buildImportFixes,
14
- getNamedImports,
15
- getTsDataForgeImport,
16
- } from './import-utils.mjs';
13
+ } from 'eslint-rule-forge';
14
+ import * as ts from 'typescript';
15
+ import { TS_DATA_FORGE_MODULE } from './constants.mjs';
17
16
 
18
17
  type Options = readonly [];
19
18
 
@@ -63,7 +62,10 @@ export const preferNumSafeParseInt: TSESLint.RuleModule<MessageIds, Options> = {
63
62
 
64
63
  const program = sourceCode.ast;
65
64
 
66
- const tsDataForgeImport = getTsDataForgeImport(program);
65
+ const tsDataForgeImports = getImportDeclarations(
66
+ program,
67
+ TS_DATA_FORGE_MODULE,
68
+ );
67
69
 
68
70
  const services = context.sourceCode.parserServices;
69
71
 
@@ -147,7 +149,7 @@ export const preferNumSafeParseInt: TSESLint.RuleModule<MessageIds, Options> = {
147
149
  mut_nodesToFix.push({ node, argExpression: firstArg });
148
150
  },
149
151
  'Program:exit': () => {
150
- const namedImports = getNamedImports(tsDataForgeImport);
152
+ const namedImports = getNamedImports(tsDataForgeImports);
151
153
 
152
154
  const missingImports = (['Num', 'Result'] as const).filter(
153
155
  (name) => !namedImports.includes(name),
@@ -157,7 +159,7 @@ export const preferNumSafeParseInt: TSESLint.RuleModule<MessageIds, Options> = {
157
159
  index,
158
160
  { node, argExpression },
159
161
  ] of mut_nodesToFix.entries()) {
160
- const argText = toArgumentText(argExpression, sourceCode);
162
+ const argText = getArgumentText(sourceCode, argExpression);
161
163
 
162
164
  const originalText = sourceCode.getText(node);
163
165
 
@@ -173,10 +175,10 @@ export const preferNumSafeParseInt: TSESLint.RuleModule<MessageIds, Options> = {
173
175
 
174
176
  const importFixes =
175
177
  index === 0 && missingImports.length > 0
176
- ? buildImportFixes(
178
+ ? buildNamedImportFix(
177
179
  fixer,
178
180
  program,
179
- tsDataForgeImport,
181
+ TS_DATA_FORGE_MODULE,
180
182
  missingImports,
181
183
  )
182
184
  : [];
@@ -3,14 +3,16 @@ import {
3
3
  type TSESLint,
4
4
  type TSESTree,
5
5
  } from '@typescript-eslint/utils';
6
- import { Arr } from 'ts-data-forge';
7
- import type { ReadonlyRecord } from 'ts-type-forge';
8
6
  import {
9
- buildImportFixes,
7
+ buildNamedImportFix,
8
+ getArgumentText,
9
+ getImportDeclarations,
10
10
  getImportedLocalName,
11
11
  getNamedImports,
12
- getTsDataForgeImport,
13
- } from './import-utils.mjs';
12
+ } from 'eslint-rule-forge';
13
+ import { Arr } from 'ts-data-forge';
14
+ import type { ReadonlyRecord } from 'ts-type-forge';
15
+ import { TS_DATA_FORGE_MODULE } from './constants.mjs';
14
16
 
15
17
  /* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
16
18
 
@@ -91,7 +93,10 @@ export const preferObjOverEntriesRoundTrip: TSESLint.RuleModule<
91
93
 
92
94
  const program = sourceCode.ast;
93
95
 
94
- const tsDataForgeImport = getTsDataForgeImport(program);
96
+ const tsDataForgeImports = getImportDeclarations(
97
+ program,
98
+ TS_DATA_FORGE_MODULE,
99
+ );
95
100
 
96
101
  const mut_roundTrips: {
97
102
  node: TSESTree.CallExpression;
@@ -146,7 +151,7 @@ export const preferObjOverEntriesRoundTrip: TSESLint.RuleModule<
146
151
  body.test,
147
152
  );
148
153
 
149
- const someText = `${optionalName}.some(${argumentText(sourceCode.getText(body.kept), body.kept)})`;
154
+ const someText = `${optionalName}.some(${getArgumentText(sourceCode, body.kept)})`;
150
155
 
151
156
  const noneText = `${optionalName}.none`;
152
157
 
@@ -167,12 +172,13 @@ export const preferObjOverEntriesRoundTrip: TSESLint.RuleModule<
167
172
  },
168
173
 
169
174
  'Program:exit': () => {
170
- const namedImports = getNamedImports(tsDataForgeImport);
175
+ const namedImports = getNamedImports(tsDataForgeImports);
171
176
 
172
- const objName = getImportedLocalName(tsDataForgeImport, 'Obj') ?? 'Obj';
177
+ const objName =
178
+ getImportedLocalName(tsDataForgeImports, 'Obj') ?? 'Obj';
173
179
 
174
180
  const optionalName =
175
- getImportedLocalName(tsDataForgeImport, 'Optional') ?? 'Optional';
181
+ getImportedLocalName(tsDataForgeImports, 'Optional') ?? 'Optional';
176
182
 
177
183
  const needsOptional = mut_roundTrips.some(
178
184
  ({ roundTrip }) => roundTrip.body.kind === 'optional',
@@ -191,19 +197,16 @@ export const preferObjOverEntriesRoundTrip: TSESLint.RuleModule<
191
197
  node,
192
198
  messageId: MESSAGE_ID_OF[roundTrip.method],
193
199
  fix: (fixer) => {
194
- const recordText = argumentText(
195
- sourceCode.getText(roundTrip.record),
196
- roundTrip.record,
197
- );
200
+ const recordText = getArgumentText(sourceCode, roundTrip.record);
198
201
 
199
202
  const replacement = `${objName}.${roundTrip.method}(${recordText}, ${buildParams(roundTrip)} => ${buildCallbackBody(roundTrip, optionalName)})`;
200
203
 
201
204
  const importFixes =
202
205
  index === 0 && missingImports.length > 0
203
- ? buildImportFixes(
206
+ ? buildNamedImportFix(
204
207
  fixer,
205
208
  program,
206
- tsDataForgeImport,
209
+ TS_DATA_FORGE_MODULE,
207
210
  missingImports,
208
211
  )
209
212
  : [];
@@ -551,12 +554,6 @@ const conditionalTestText = (
551
554
  ): string =>
552
555
  NEEDS_PARENS_AS_TEST.has(node.type) ? (`(${text})` as const) : text;
553
556
 
554
- /** A comma expression would read as another argument without parentheses. */
555
- const argumentText = (text: string, node: TSESTree.Expression): string =>
556
- node.type === AST_NODE_TYPES.SequenceExpression
557
- ? (`(${text})` as const)
558
- : text;
559
-
560
557
  /**
561
558
  * A concise arrow body cannot start with `{`, nor hold a bare comma. The text
562
559
  * is what decides the first case rather than the node type, because an object
@@ -3,13 +3,15 @@ import {
3
3
  type TSESLint,
4
4
  type TSESTree,
5
5
  } from '@typescript-eslint/utils';
6
- import { Arr } from 'ts-data-forge';
7
- import { skipTypeWrappers, toArgumentText } from './ast-utils.mjs';
8
6
  import {
9
- buildImportFixes,
7
+ buildNamedImportFix,
8
+ getArgumentText,
9
+ getImportDeclarations,
10
10
  getNamedImports,
11
- getTsDataForgeImport,
12
- } from './import-utils.mjs';
11
+ skipTypeWrappers,
12
+ } from 'eslint-rule-forge';
13
+ import { Arr } from 'ts-data-forge';
14
+ import { TS_DATA_FORGE_MODULE } from './constants.mjs';
13
15
 
14
16
  type Options = readonly [];
15
17
 
@@ -35,7 +37,10 @@ export const preferRangeForLoop: TSESLint.RuleModule<MessageIds, Options> = {
35
37
 
36
38
  const program = sourceCode.ast;
37
39
 
38
- const tsDataForgeImport = getTsDataForgeImport(program);
40
+ const tsDataForgeImports = getImportDeclarations(
41
+ program,
42
+ TS_DATA_FORGE_MODULE,
43
+ );
39
44
 
40
45
  const mut_nodesToFix: {
41
46
  node: TSESTree.ForStatement;
@@ -128,15 +133,15 @@ export const preferRangeForLoop: TSESLint.RuleModule<MessageIds, Options> = {
128
133
  }
129
134
  } else {
130
135
  // Variable step like i += step
131
- mut_step = toArgumentText(node.update.right, sourceCode);
136
+ mut_step = getArgumentText(sourceCode, node.update.right);
132
137
  }
133
138
  } else {
134
139
  return;
135
140
  }
136
141
 
137
- const beginText = toArgumentText(beginExpr, sourceCode);
142
+ const beginText = getArgumentText(sourceCode, beginExpr);
138
143
 
139
- const endText = toArgumentText(endExpr, sourceCode);
144
+ const endText = getArgumentText(sourceCode, endExpr);
140
145
 
141
146
  mut_nodesToFix.push({
142
147
  node,
@@ -147,7 +152,7 @@ export const preferRangeForLoop: TSESLint.RuleModule<MessageIds, Options> = {
147
152
  });
148
153
  },
149
154
  'Program:exit': () => {
150
- const namedImports = getNamedImports(tsDataForgeImport);
155
+ const namedImports = getNamedImports(tsDataForgeImports);
151
156
 
152
157
  const hasRangeImport = namedImports.includes('range');
153
158
 
@@ -175,7 +180,7 @@ export const preferRangeForLoop: TSESLint.RuleModule<MessageIds, Options> = {
175
180
 
176
181
  const importFixes =
177
182
  index === 0 && !hasRangeImport
178
- ? buildImportFixes(fixer, program, tsDataForgeImport, [
183
+ ? buildNamedImportFix(fixer, program, TS_DATA_FORGE_MODULE, [
179
184
  'range',
180
185
  ])
181
186
  : [];
@@ -1,30 +0,0 @@
1
- import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
2
- import type { DeepReadonly } from 'ts-type-forge';
3
- export declare const getTsDataForgeImport: (program: TSESTree.Program) => TSESTree.ImportDeclaration | undefined;
4
- export declare const getNamedImports: (node: DeepReadonly<TSESTree.ImportDeclaration> | undefined) => readonly string[];
5
- /**
6
- * Returns the in-scope local name a given canonical export is imported as
7
- * (handling aliases such as `import { isX as y }` → `'y'`), or `undefined` when
8
- * it is not imported. Used so autofixes reference the binding that actually
9
- * exists rather than the canonical name.
10
- */
11
- export declare const getImportedLocalName: (node: DeepReadonly<TSESTree.ImportDeclaration> | undefined, importedName: string) => string | undefined;
12
- type ResolvedCallee = Readonly<{
13
- /** The canonical (imported) ts-data-forge name, regardless of local alias. */
14
- canonicalName: string;
15
- /** The identifier node to rewrite when replacing the callee name. */
16
- propertyNode: TSESTree.Node;
17
- /** Whether the call was made through a namespace import (`tf.isX(...)`). */
18
- isNamespace: boolean;
19
- }>;
20
- /**
21
- * Builds a resolver that maps a call expression's callee to the canonical
22
- * ts-data-forge function it refers to. Handles named imports (including aliases
23
- * such as `import { isX as y }`) and namespace imports (`import * as tf` →
24
- * `tf.isX(...)`). Returns `undefined` for any callee that does not reference the
25
- * given ts-data-forge import.
26
- */
27
- export declare const buildCalleeResolver: (importDecl: TSESTree.ImportDeclaration | undefined) => ((callee: DeepReadonly<TSESTree.Expression>) => ResolvedCallee | undefined);
28
- export declare const buildImportFixes: (fixer: TSESLint.RuleFixer, program: TSESTree.Program, _tsDataForgeImport: TSESTree.ImportDeclaration | undefined, requiredNames: readonly string[]) => readonly TSESLint.RuleFix[];
29
- export {};
30
- //# sourceMappingURL=import-utils.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"import-utils.d.mts","sourceRoot":"","sources":["../../src/rules/import-utils.mts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,QAAQ,EACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAMlD,eAAO,MAAM,oBAAoB,YACtB,QAAQ,CAAC,OAAO,KACxB,QAAQ,CAAC,iBAAiB,GAAG,SAK7B,CAAC;AAEJ,eAAO,MAAM,eAAe,SACpB,YAAY,CAAC,QAAQ,CAAC,iBAAiB,CAAC,GAAG,SAAS,KACzD,SAAS,MAAM,EAiBjB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,SACzB,YAAY,CAAC,QAAQ,CAAC,iBAAiB,CAAC,GAAG,SAAS,gBAC5C,MAAM,KACnB,MAAM,GAAG,SAOG,CAAC;AAEhB,KAAK,cAAc,GAAG,QAAQ,CAAC;IAC7B,8EAA8E;IAC9E,aAAa,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC;IAC5B,4EAA4E;IAC5E,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,eAClB,QAAQ,CAAC,iBAAiB,GAAG,SAAS,KACjD,CAAC,CACF,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,KACtC,cAAc,GAAG,SAAS,CAsE9B,CAAC;AAOF,eAAO,MAAM,gBAAgB,UACpB,QAAQ,CAAC,SAAS,WAChB,QAAQ,CAAC,OAAO,sBACL,QAAQ,CAAC,iBAAiB,GAAG,SAAS,iBAC3C,SAAS,MAAM,EAAE,KAC/B,SAAS,QAAQ,CAAC,OAAO,EAa3B,CAAC"}
@@ -1,98 +0,0 @@
1
- import { AST_NODE_TYPES, } from '@typescript-eslint/utils';
2
- import { isTypeWrapper } from './ast-utils.mjs';
3
- import { TS_DATA_FORGE_MODULE } from './constants.mjs';
4
-
5
- export const getTsDataForgeImport = (program) => program.body.find((node) => node.type === AST_NODE_TYPES.ImportDeclaration &&
6
- node.source.value === TS_DATA_FORGE_MODULE);
7
- export const getNamedImports = (node) => {
8
- if (node === undefined) {
9
- return [];
10
- }
11
- return node.specifiers.flatMap((specifier) => specifier.type === AST_NODE_TYPES.ImportSpecifier
12
- ? (() => {
13
- const importedName = specifier.imported.type === AST_NODE_TYPES.Identifier
14
- ? specifier.imported.name
15
- : specifier.imported.value;
16
- return typeof importedName === 'string' ? [importedName] : [];
17
- })()
18
- : []);
19
- };
20
-
21
-
22
-
23
-
24
-
25
-
26
- export const getImportedLocalName = (node, importedName) => node?.specifiers.find((specifier) => specifier.type === AST_NODE_TYPES.ImportSpecifier &&
27
- (specifier.imported.type === AST_NODE_TYPES.Identifier
28
- ? specifier.imported.name
29
- : specifier.imported.value) === importedName)?.local.name;
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
- export const buildCalleeResolver = (importDecl) => {
38
- const specifiers = importDecl?.specifiers ?? [];
39
- const namespaceName = specifiers.find((specifier) => specifier.type === AST_NODE_TYPES.ImportNamespaceSpecifier)?.local.name;
40
- const localToCanonical = new Map(specifiers.flatMap((specifier) => {
41
- if (specifier.type !== AST_NODE_TYPES.ImportSpecifier) {
42
- return [];
43
- }
44
- const importedName = specifier.imported.type === AST_NODE_TYPES.Identifier
45
- ? specifier.imported.name
46
- : specifier.imported.value;
47
- return typeof importedName === 'string'
48
- ? [[specifier.local.name, importedName]]
49
- : [];
50
- }));
51
-
52
-
53
-
54
- const resolve = (callee) => {
55
- if (isTypeWrapper(callee)) {
56
- return resolve(callee.expression);
57
- }
58
- if (callee.type === AST_NODE_TYPES.Identifier) {
59
- const canonicalName = localToCanonical.get(callee.name);
60
- return canonicalName === undefined
61
- ? undefined
62
- : {
63
- canonicalName,
64
-
65
- propertyNode: callee,
66
- isNamespace: false,
67
- };
68
- }
69
- if (namespaceName === undefined ||
70
- callee.type !== AST_NODE_TYPES.MemberExpression ||
71
- callee.computed ||
72
- callee.property.type !== AST_NODE_TYPES.Identifier) {
73
- return undefined;
74
- }
75
- const object = skipReadonlyTypeWrappers(callee.object);
76
- return object.type === AST_NODE_TYPES.Identifier &&
77
- object.name === namespaceName
78
- ? {
79
- canonicalName: callee.property.name,
80
-
81
- propertyNode: callee.property,
82
- isNamespace: true,
83
- }
84
- : undefined;
85
- };
86
- return resolve;
87
- };
88
- const skipReadonlyTypeWrappers = (node) => isTypeWrapper(node) ? skipReadonlyTypeWrappers(node.expression) : node;
89
- export const buildImportFixes = (fixer, program, _tsDataForgeImport, requiredNames) => {
90
- const specifierText = requiredNames.join(', ');
91
- const importStatement = `import { ${specifierText} } from '${TS_DATA_FORGE_MODULE}';`;
92
- const newLine = '\n';
93
- const insertionText = `${importStatement}${newLine}`;
94
-
95
-
96
- return [fixer.insertTextBefore(program, insertionText)];
97
- };
98
- //# sourceMappingURL=import-utils.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"import-utils.mjs","sourceRoot":"","sources":["../../src/rules/import-utils.mts"],"names":[],"mappings":"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"}
@@ -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
- };