eslint-plugin-ts-fortress 1.2.4 → 1.3.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 (50) hide show
  1. package/README.md +102 -4
  2. package/dist/plugin.d.mts +5 -1
  3. package/dist/plugin.d.mts.map +1 -1
  4. package/dist/plugin.mjs +2 -0
  5. package/dist/plugin.mjs.map +1 -1
  6. package/dist/rule-types.d.mts +43 -4
  7. package/dist/rule-types.d.mts.map +1 -1
  8. package/dist/rules/ast-utils.d.mts +15 -0
  9. package/dist/rules/ast-utils.d.mts.map +1 -0
  10. package/dist/rules/ast-utils.mjs +24 -0
  11. package/dist/rules/ast-utils.mjs.map +1 -0
  12. package/dist/rules/export-usage.d.mts +19 -0
  13. package/dist/rules/export-usage.d.mts.map +1 -0
  14. package/dist/rules/export-usage.mjs +252 -0
  15. package/dist/rules/export-usage.mjs.map +1 -0
  16. package/dist/rules/no-type-only-codec.d.mts +25 -0
  17. package/dist/rules/no-type-only-codec.d.mts.map +1 -0
  18. package/dist/rules/no-type-only-codec.mjs +270 -0
  19. package/dist/rules/no-type-only-codec.mjs.map +1 -0
  20. package/dist/rules/package-entry-points.d.mts +22 -0
  21. package/dist/rules/package-entry-points.d.mts.map +1 -0
  22. package/dist/rules/package-entry-points.mjs +195 -0
  23. package/dist/rules/package-entry-points.mjs.map +1 -0
  24. package/dist/rules/prefer-canonical-length-constrained-type.d.mts.map +1 -1
  25. package/dist/rules/prefer-canonical-length-constrained-type.mjs +44 -14
  26. package/dist/rules/prefer-canonical-length-constrained-type.mjs.map +1 -1
  27. package/dist/rules/prefer-schema-over-guard-chain.d.mts.map +1 -1
  28. package/dist/rules/prefer-schema-over-guard-chain.mjs +36 -21
  29. package/dist/rules/prefer-schema-over-guard-chain.mjs.map +1 -1
  30. package/dist/rules/rules.d.mts +3 -0
  31. package/dist/rules/rules.d.mts.map +1 -1
  32. package/dist/rules/rules.mjs +2 -0
  33. package/dist/rules/rules.mjs.map +1 -1
  34. package/dist/types.d.mts +2 -2
  35. package/dist/types.d.mts.map +1 -1
  36. package/package.json +3 -3
  37. package/src/plugin.mts +6 -4
  38. package/src/plugin.test.mts +0 -13
  39. package/src/rule-types.mts +48 -4
  40. package/src/rules/ast-utils.mts +35 -0
  41. package/src/rules/export-usage.mts +403 -0
  42. package/src/rules/no-type-only-codec.mts +398 -0
  43. package/src/rules/no-type-only-codec.test.mts +799 -0
  44. package/src/rules/package-entry-points.mts +294 -0
  45. package/src/rules/prefer-canonical-length-constrained-type.mts +65 -17
  46. package/src/rules/prefer-canonical-length-constrained-type.test.mts +145 -0
  47. package/src/rules/prefer-schema-over-guard-chain.mts +46 -29
  48. package/src/rules/prefer-schema-over-guard-chain.test.mts +82 -0
  49. package/src/rules/rules.mts +3 -1
  50. package/src/types.mts +2 -2
package/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  ESLint rules that steer schema definitions toward
4
4
  [`ts-fortress`](https://www.npmjs.com/package/ts-fortress) idioms. Every rule except
5
- `prefer-schema-over-guard-chain` (which only reports) is auto-fixable, and every
6
- rewrite is **type-preserving**.
5
+ `prefer-schema-over-guard-chain` and `no-type-only-codec` (which only report) is
6
+ auto-fixable, and every rewrite is **type-preserving**.
7
7
 
8
8
  ## Installation
9
9
 
@@ -11,8 +11,10 @@ rewrite is **type-preserving**.
11
11
  npm install --save-dev eslint-plugin-ts-fortress
12
12
  ```
13
13
 
14
- Requires ESLint 9+ (flat config) and TypeScript. No rule is type-aware, so a
15
- configured TypeScript project is not required.
14
+ Requires ESLint 9+ (flat config) and TypeScript. A configured TypeScript project
15
+ is not required: only `no-type-only-codec` reads type information, and without it
16
+ the rule checks less rather than failing (see
17
+ [Type information](#type-information)).
16
18
 
17
19
  ## Usage (flat config)
18
20
 
@@ -73,6 +75,7 @@ export default [
73
75
  | `prefer-canonical-length-constrained-type` | Normalize a length-constrained array combinator with degenerate bounds to its canonical form. |
74
76
  | `prefer-namespace-import` | Require `ts-fortress` to be imported as a namespace rather than by name. |
75
77
  | `prefer-schema-over-guard-chain` | Report a hand-written chain of type guards on one value once it is long enough to be a schema. |
78
+ | `no-type-only-codec` | Report a codec whose value nothing reads, only the type `TypeOf` derives from it. |
76
79
 
77
80
  ### `prefer-canonical-length-constrained-type`
78
81
 
@@ -296,6 +299,101 @@ least interested in, while the chain of five narrows the result of a
296
299
  length of the chain that prompted the rule. That chain of five is the one site
297
300
  the rule reported when it was turned on, and it has since been rewritten.
298
301
 
302
+ ### `no-type-only-codec`
303
+
304
+ A codec exists to check values at runtime. One whose value nothing reads — it is
305
+ there only so that `t.TypeOf` can derive a type from it — is a type written the
306
+ long way round: it costs a runtime object, keeps `ts-fortress` in the bundle of
307
+ whatever imports it, and reads as if something validated with it.
308
+
309
+ ```ts
310
+ // ❌ — every import of `User` elsewhere is `import type`
311
+ export const User = t.record({ name: t.string() });
312
+
313
+ export type User = t.TypeOf<typeof User>;
314
+
315
+ // ✅
316
+ export type User = Readonly<{ name: string }>;
317
+ ```
318
+
319
+ The rule looks at a top-level `const X` paired with a top-level
320
+ `type Y = t.TypeOf<typeof X>` — `Y` is usually `X` itself, or `X` is named
321
+ `yTypeDef` — and reports `X` when none of these reads its value:
322
+
323
+ - **its own file**: any reference outside a type. `typeof X` in another type
324
+ does not count; `t.array(X)` in another codec does.
325
+ - **the other files of the TypeScript project**: an import that is not
326
+ `import type` / `import { type X }`, whatever the importer then does with it;
327
+ a namespace import read as `ns.X` or `ns['X']` outside a type, or used whole
328
+ (`f(ns)`, `ns[key]`); a dynamic `import()`. Re-exports are followed, so a
329
+ barrel is transparent.
330
+ - **an entry point** — a file the package publishes (see
331
+ [Entry points](#entry-points)) — that re-exports it as a value, directly or
332
+ through any chain of `export { … } from` / `export * from`.
333
+
334
+ The rule reports; there is no fix, since writing the type out is not
335
+ mechanical.
336
+
337
+ #### Type information
338
+
339
+ Whether another file reads an exported codec is a question about the whole
340
+ TypeScript project, so the rule answers it from the program a file is linted
341
+ with. Turn type information on for it to check exported codecs at all:
342
+
343
+ ```ts
344
+ // eslint.config.mts
345
+ import { eslintPluginTsFortress } from 'eslint-plugin-ts-fortress';
346
+
347
+ export default [
348
+ eslintPluginTsFortress.configs.recommended,
349
+ {
350
+ languageOptions: {
351
+ parserOptions: {
352
+ projectService: true,
353
+ tsconfigRootDir: import.meta.dirname,
354
+ },
355
+ },
356
+ },
357
+ ];
358
+ ```
359
+
360
+ Without it, a codec that is not exported is still checked — that needs nothing
361
+ but its own file — and an exported one is left alone.
362
+
363
+ The rule sees the files of that program and nothing else. An importer counts
364
+ only if the `tsconfig.json` linting the codec's file includes it, so tests under
365
+ a separate project import nothing as far as the rule can tell, and another
366
+ package that imports the codec reaches it through an entry point.
367
+
368
+ #### Entry points
369
+
370
+ A codec the package publishes is public API, whoever uses it. The entry points
371
+ are read from the `package.json` nearest to the file — `exports`, every subpath
372
+ and condition of it, and the legacy `main`, `module`, `types` and `typings`
373
+ fields — and traced back to source: a target that is a file of the project is
374
+ taken as it is, and an output such as `./dist/index.mjs` becomes the source it
375
+ was built from, `src/index.mts` (the project's `outDir` and `rootDir` are used
376
+ when set; otherwise a leading `dist`, `lib`, `build`, `out`, `esm` or `cjs`
377
+ directory becomes `src`). The conditions of one subpath describe one module, so
378
+ a subpath counts as traced when any of its targets is, and a `types` file a
379
+ build writes on its own does not need a source. A package that publishes nothing
380
+ — an application — has no entry points.
381
+
382
+ When some subpath cannot be traced back to a file of the project, what the
383
+ package publishes is not known, and the rule leaves its exported codecs alone
384
+ rather than report public API. Name the entry points yourself for such a layout:
385
+
386
+ ```ts
387
+ 'ts-fortress/no-type-only-codec': [
388
+ 'error',
389
+ { entryPoints: [path.resolve(import.meta.dirname, 'src/public-api.mts')] },
390
+ ],
391
+ ```
392
+
393
+ - `entryPoints` (default: read from `package.json`) — the files whose exports
394
+ are public API, replacing what `package.json` says. Relative paths resolve
395
+ against the directory ESLint runs in, so pass absolute ones, as above.
396
+
299
397
  ## License
300
398
 
301
399
  [Apache-2.0](https://github.com/noshiro-pf/mono/blob/main/libs/eslint-plugin-ts-fortress/LICENSE)
package/dist/plugin.d.mts CHANGED
@@ -1,9 +1,12 @@
1
- import { type ESLintPlugin } from './types.mjs';
1
+ import type { ESLintPlugin } from './types.mjs';
2
2
  export declare const eslintPluginTsFortress: {
3
3
  readonly meta: {
4
4
  readonly name: 'eslint-plugin-ts-fortress';
5
5
  };
6
6
  readonly rules: {
7
+ readonly 'no-type-only-codec': import("@typescript-eslint/utils/ts-eslint").RuleModule<"typeOnlyCodec", readonly [(Readonly<{
8
+ entryPoints?: readonly string[];
9
+ }> | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
7
10
  readonly 'prefer-canonical-length-constrained-type': import("@typescript-eslint/utils/ts-eslint").RuleModule<"useCanonicalType", readonly [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
8
11
  readonly 'prefer-namespace-import': import("@typescript-eslint/utils/ts-eslint").RuleModule<"removeSideEffectImport" | "useNamespaceImport", readonly [(Readonly<{
9
12
  namespaceName?: string;
@@ -21,6 +24,7 @@ export declare const eslintPluginTsFortress: {
21
24
  readonly 'ts-fortress': ESLintPlugin;
22
25
  };
23
26
  readonly rules: {
27
+ readonly 'ts-fortress/no-type-only-codec': 'error';
24
28
  readonly 'ts-fortress/prefer-canonical-length-constrained-type': 'error';
25
29
  readonly 'ts-fortress/prefer-namespace-import': 'error';
26
30
  readonly 'ts-fortress/prefer-schema-over-guard-chain': 'error';
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.mts","sourceRoot":"","sources":["../src/plugin.mts"],"names":[],"mappings":"AAEA,OAAO,EAAyB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAiCvE,eAAO,MAAM,sBAAsB;;iBAE/B,IAAI,EAAE,2BAA2B;;;;;;;;;;;;;QAIjC,oDAAoD;iBACpD,WAAW;2BAtBP,yBAAyB;;yBAQzB,aAAa,EAAI,YAAY;;;iFAjBqB,OAAO;gEACxB,OAAO;uEACA,OAAO;;;;CA+BtB,CAAC"}
1
+ {"version":3,"file":"plugin.d.mts","sourceRoot":"","sources":["../src/plugin.mts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,aAAa,CAAC;AAmClE,eAAO,MAAM,sBAAsB;;iBAE/B,IAAI,EAAE,2BAA2B;;;;;;;;;;;;;;;;QAIjC,oDAAoD;iBACpD,WAAW;2BAtBP,yBAAyB;;yBAQzB,aAAa,EAAI,YAAY;;;2DAlBD,OAAO;iFACe,OAAO;gEACxB,OAAO;uEACA,OAAO;;;;CA+BtB,CAAC"}
package/dist/plugin.mjs CHANGED
@@ -5,7 +5,9 @@ import { tsFortressRules } from './rules/index.mjs';
5
5
 
6
6
 
7
7
 
8
+
8
9
  const recommendedRules = {
10
+ 'ts-fortress/no-type-only-codec': 'error',
9
11
  'ts-fortress/prefer-canonical-length-constrained-type': 'error',
10
12
  'ts-fortress/prefer-namespace-import': 'error',
11
13
  'ts-fortress/prefer-schema-over-guard-chain': 'error',
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.mjs","sourceRoot":"","sources":["../src/plugin.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG;IACvB,sDAAsD,EAAE,OAAO;IAC/D,qCAAqC,EAAE,OAAO;IAC9C,4CAA4C,EAAE,OAAO;CAItD,CAAC;AAEF,MAAM,iBAAiB,GAAG;IACxB,IAAI,EAAE,yBAAyB;IAC/B,OAAO,EAAE;QACP,uEAAuE;QACvE,wEAAwE;QACxE,wEAAwE;QACxE,mDAAmD;QACnD,0EAA0E;QAC1E,qDAAqD;QACrD,IAAI,aAAa;YACf,OAAO,sBAAsB,CAAC;QAChC,CAAC;KACF;IACD,KAAK,EAAE,gBAAgB;CACY,CAAC;AAEtC,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,IAAI,EAAE;QACJ,IAAI,EAAE,2BAA2B;KAClC;IACD,KAAK,EAAE,eAAe;IACtB,OAAO,EAAE;QACP,oDAAoD;QACpD,WAAW,EAAE,iBAAiB;KAC/B;CAC8B,CAAC"}
1
+ {"version":3,"file":"plugin.mjs","sourceRoot":"","sources":["../src/plugin.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD;;;;;;GAMG;AACH,MAAM,gBAAgB,GAAG;IACvB,gCAAgC,EAAE,OAAO;IACzC,sDAAsD,EAAE,OAAO;IAC/D,qCAAqC,EAAE,OAAO;IAC9C,4CAA4C,EAAE,OAAO;CAItD,CAAC;AAEF,MAAM,iBAAiB,GAAG;IACxB,IAAI,EAAE,yBAAyB;IAC/B,OAAO,EAAE;QACP,uEAAuE;QACvE,wEAAwE;QACxE,wEAAwE;QACxE,mDAAmD;QACnD,0EAA0E;QAC1E,qDAAqD;QACrD,IAAI,aAAa;YACf,OAAO,sBAAsB,CAAC;QAChC,CAAC;KACF;IACD,KAAK,EAAE,gBAAgB;CACY,CAAC;AAEtC,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,IAAI,EAAE;QACJ,IAAI,EAAE,2BAA2B;KAClC;IACD,KAAK,EAAE,eAAe;IACtB,OAAO,EAAE;QACP,oDAAoD;QACpD,WAAW,EAAE,iBAAiB;KAC/B;CAC8B,CAAC"}
@@ -1,7 +1,7 @@
1
- import { type TSESLint } from '@typescript-eslint/utils';
2
- import { type Linter } from 'eslint';
3
- import { type TypeEq } from 'ts-type-forge';
4
- import { type tsFortressRules } from './rules/index.mjs';
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
+ import type { Linter } from 'eslint';
3
+ import type { TypeEq } from 'ts-type-forge';
4
+ import type { tsFortressRules } from './rules/index.mjs';
5
5
  type SpreadOptionsIfIsArray<T extends readonly [Linter.StringSeverity, unknown]> = T[1] extends readonly unknown[] ? readonly [Linter.StringSeverity, ...T[1]] : T;
6
6
  /**
7
7
  * Extracts the options tuple type of a rule from its TypeScript
@@ -9,6 +9,43 @@ type SpreadOptionsIfIsArray<T extends readonly [Linter.StringSeverity, unknown]>
9
9
  * without converting `meta.schema` (JSON Schema) back into TypeScript types.
10
10
  */
11
11
  type RuleOptionsOf<Name extends keyof typeof tsFortressRules> = (typeof tsFortressRules)[Name] extends TSESLint.RuleModule<infer _MessageIds extends string, infer Options extends readonly unknown[]> ? Options : never;
12
+ /**
13
+ * @description Report a ts-fortress codec `X` paired with `type Y = t.TypeOf<typeof X>` whose value nothing reads, so that `Y` is declared as a plain type instead.
14
+ *
15
+ * ```md
16
+ * | key | value |
17
+ * | :--------- | :--------- |
18
+ * | type | suggestion |
19
+ * | deprecated | false |
20
+ * | fixable | false |
21
+ * ```
22
+ */
23
+ declare namespace NoTypeOnlyCodec {
24
+ /**
25
+ * ### schema
26
+ *
27
+ * ```json
28
+ * [
29
+ * {
30
+ * "type": "object",
31
+ * "properties": {
32
+ * "entryPoints": {
33
+ * "type": "array",
34
+ * "items": {
35
+ * "type": "string"
36
+ * },
37
+ * "uniqueItems": true,
38
+ * "description": "Files whose exports are public API. A codec they export, directly or through re-exports, is never reported. Replaces the entry points read from the nearest package.json, for a layout they cannot be traced back to source from. Relative paths are resolved against the working directory ESLint runs in; pass absolute paths to make the config independent of it."
39
+ * }
40
+ * },
41
+ * "additionalProperties": false
42
+ * }
43
+ * ]
44
+ * ```
45
+ */
46
+ type Options = NonNullable<RuleOptionsOf<'no-type-only-codec'>[0]>;
47
+ type RuleEntry = 'off' | Linter.Severity | SpreadOptionsIfIsArray<readonly [Linter.StringSeverity, Options]>;
48
+ }
12
49
  /**
13
50
  * @description Normalize a length-constrained ts-fortress array combinator whose bounds are degenerate (e.g. `minLengthArray(1, x)`, `boundedLengthTuple(n, n, x)`) to the combinator that names that constraint directly.
14
51
  *
@@ -99,11 +136,13 @@ declare namespace PreferSchemaOverGuardChain {
99
136
  type RuleEntry = 'off' | Linter.Severity | SpreadOptionsIfIsArray<readonly [Linter.StringSeverity, Options]>;
100
137
  }
101
138
  export type EslintTsFortressRules = Readonly<{
139
+ 'ts-fortress/no-type-only-codec': NoTypeOnlyCodec.RuleEntry;
102
140
  'ts-fortress/prefer-canonical-length-constrained-type': PreferCanonicalLengthConstrainedType.RuleEntry;
103
141
  'ts-fortress/prefer-namespace-import': PreferNamespaceImport.RuleEntry;
104
142
  'ts-fortress/prefer-schema-over-guard-chain': PreferSchemaOverGuardChain.RuleEntry;
105
143
  }>;
106
144
  export type EslintTsFortressRulesOption = Readonly<{
145
+ 'ts-fortress/no-type-only-codec': NoTypeOnlyCodec.Options;
107
146
  'ts-fortress/prefer-namespace-import': PreferNamespaceImport.Options;
108
147
  'ts-fortress/prefer-schema-over-guard-chain': PreferSchemaOverGuardChain.Options;
109
148
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"rule-types.d.mts","sourceRoot":"","sources":["../src/rule-types.mts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,KAAK,sBAAsB,CACzB,CAAC,SAAS,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,IACjD,CAAC,CAAC,CAAC,CAAC,SAAS,SAAS,OAAO,EAAE,GAC/B,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GACzC,CAAC,CAAC;AAEN;;;;GAIG;AACH,KAAK,aAAa,CAAC,IAAI,SAAS,MAAM,OAAO,eAAe,IAC1D,CAAC,OAAO,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS,QAAQ,CAAC,UAAU,CACxD,MAAM,WAAW,SAAS,MAAM,EAChC,MAAM,OAAO,SAAS,SAAS,OAAO,EAAE,CACzC,GACG,OAAO,GACP,KAAK,CAAC;AAEZ;;;;;;;;;;GAUG;AACH,kBAAU,oCAAoC,CAAC;IAC7C,KAAY,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC;CAC/C;AAED;;;;;;;;;;GAUG;AACH,kBAAU,qBAAqB,CAAC;IAC9B;;;;;;;;;;;;;;;;;;OAkBG;IACH,KAAY,OAAO,GAAG,WAAW,CAC/B,aAAa,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAC5C,CAAC;IAEF,KAAY,SAAS,GACjB,KAAK,GACL,MAAM,CAAC,QAAQ,GACf,sBAAsB,CAAC,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;CACvE;AAED;;;;;;;;;;GAUG;AACH,kBAAU,0BAA0B,CAAC;IACnC;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,KAAY,OAAO,GAAG,WAAW,CAC/B,aAAa,CAAC,gCAAgC,CAAC,CAAC,CAAC,CAAC,CACnD,CAAC;IAEF,KAAY,SAAS,GACjB,KAAK,GACL,MAAM,CAAC,QAAQ,GACf,sBAAsB,CAAC,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;CACvE;AAED,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,sDAAsD,EAAE,oCAAoC,CAAC,SAAS,CAAC;IACvG,qCAAqC,EAAE,qBAAqB,CAAC,SAAS,CAAC;IACvE,4CAA4C,EAAE,0BAA0B,CAAC,SAAS,CAAC;CACpF,CAAC,CAAC;AAEH,MAAM,MAAM,2BAA2B,GAAG,QAAQ,CAAC;IACjD,qCAAqC,EAAE,qBAAqB,CAAC,OAAO,CAAC;IACrE,4CAA4C,EAAE,0BAA0B,CAAC,OAAO,CAAC;CAClF,CAAC,CAAC;AAIH,KAAK,UAAU,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;AAEpC,MAAM,MAAM,kBAAkB,GAAG,UAAU,CACzC,MAAM,CACJ,MAAM,qBAAqB,EAC3B,eAAe,MAAM,OAAO,eAAe,EAAE,CAC9C,CACF,CAAC"}
1
+ {"version":3,"file":"rule-types.d.mts","sourceRoot":"","sources":["../src/rule-types.mts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { type TSESTree } from '@typescript-eslint/utils';
2
+ /**
3
+ * `node` with every `as`, `satisfies`, `!` and `<T>` around it taken off: the
4
+ * expression whose value it is. Judge syntax on what this returns, so that a
5
+ * wrapper does not hide a pattern (`isString((x as R).a)`), and keep the
6
+ * original node for fix text. See `docs/writing-lint-rules.md` at the
7
+ * repository root.
8
+ *
9
+ * A copy of the helper in `eslint-config-typed`, which this package, published
10
+ * on its own, cannot import.
11
+ */
12
+ export declare const skipTypeWrappers: (node: TSESTree.Node) => TSESTree.Node;
13
+ export declare const isTypeWrapper: (node: TSESTree.Node) => node is TypeWrapper;
14
+ export type TypeWrapper = TSESTree.TSAsExpression | TSESTree.TSNonNullExpression | TSESTree.TSSatisfiesExpression | TSESTree.TSTypeAssertion;
15
+ //# sourceMappingURL=ast-utils.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-utils.d.mts","sourceRoot":"","sources":["../../src/rules/ast-utils.mts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEzE;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,SAErB,QAAQ,CAAC,IAAI,KAClB,QAAQ,CAAC,IACoD,CAAC;AAEjE,eAAO,MAAM,aAAa,SAElB,QAAQ,CAAC,IAAI,KAClB,IAAI,IAAI,WAA2C,CAAC;AAEvD,MAAM,MAAM,WAAW,GACnB,QAAQ,CAAC,cAAc,GACvB,QAAQ,CAAC,mBAAmB,GAC5B,QAAQ,CAAC,qBAAqB,GAC9B,QAAQ,CAAC,eAAe,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+ export const skipTypeWrappers = (
13
+
14
+ node) => isTypeWrapper(node) ? skipTypeWrappers(node.expression) : node;
15
+ export const isTypeWrapper = (
16
+
17
+ node) => TYPE_WRAPPERS.has(node.type);
18
+ const TYPE_WRAPPERS = new Set([
19
+ AST_NODE_TYPES.TSAsExpression,
20
+ AST_NODE_TYPES.TSNonNullExpression,
21
+ AST_NODE_TYPES.TSSatisfiesExpression,
22
+ AST_NODE_TYPES.TSTypeAssertion,
23
+ ]);
24
+ //# sourceMappingURL=ast-utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-utils.mjs","sourceRoot":"","sources":["../../src/rules/ast-utils.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAiB,MAAM,0BAA0B,CAAC;AAEzE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;AAC9B,8EAA8E;AAC9E,IAAmB,EACJ,EAAE,CACjB,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAEjE,MAAM,CAAC,MAAM,aAAa,GAAG;AAC3B,8EAA8E;AAC9E,IAAmB,EACE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAQvD,MAAM,aAAa,GAAgC,IAAI,GAAG,CAAC;IACzD,cAAc,CAAC,cAAc;IAC7B,cAAc,CAAC,mBAAmB;IAClC,cAAc,CAAC,qBAAqB;IACpC,cAAc,CAAC,eAAe;CAC/B,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ import * as ts from 'typescript';
2
+ /**
3
+ * Whether the value `fileName` exports as `exportName` may be read at runtime
4
+ * by a file of `program`, or is public API because one of `entryPoints`
5
+ * re-exports it.
6
+ *
7
+ * Answered from the import and export declarations of every file in the
8
+ * program, nothing more, and it errs towards "used" wherever they do not
9
+ * decide it: a non-type import counts as a value use whatever the importer does
10
+ * with it, and a namespace or a module that leaves the file whole (a dynamic
11
+ * `import()`, `export { ns }`, `f(ns)`) uses every export. A type-only import or
12
+ * re-export is never a use. A re-export is followed to what imports the
13
+ * re-exporting file, so a barrel is transparent.
14
+ *
15
+ * Files outside `program` are not seen at all, so an importer only counts when
16
+ * the TypeScript project that lints `fileName` includes it.
17
+ */
18
+ export declare const isExportedValueUsed: (program: ts.Program, fileName: string, exportName: string, entryPoints: ReadonlySet<string>) => boolean;
19
+ //# sourceMappingURL=export-usage.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export-usage.d.mts","sourceRoot":"","sources":["../../src/rules/export-usage.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,mBAAmB,YACrB,EAAE,CAAC,OAAO,YACT,MAAM,cACJ,MAAM,eACL,WAAW,CAAC,MAAM,CAAC,KAC/B,OACyE,CAAC"}
@@ -0,0 +1,252 @@
1
+ import * as ts from 'typescript';
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+ export const isExportedValueUsed = (program, fileName, exportName, entryPoints) => isUsed(importEdges(program), entryPoints, fileName, exportName, new Set());
19
+
20
+
21
+
22
+
23
+
24
+ const importEdgesCache = new WeakMap();
25
+
26
+
27
+
28
+
29
+ const namespaceMembersCache = new WeakMap();
30
+
31
+ const DYNAMIC_IMPORT_PATTERN = /\b(?:import|require)\s*\(/u;
32
+
33
+ const isUsed = (edges, entryPoints, fileName, exportName, mut_visited) => {
34
+ if (entryPoints.has(fileName)) {
35
+ return true;
36
+ }
37
+ const key = `${fileName}\0${exportName}`;
38
+
39
+ if (mut_visited.has(key)) {
40
+ return false;
41
+ }
42
+ mut_visited.add(key);
43
+ const follow = (importer, name) => isUsed(edges, entryPoints, importer, name, mut_visited);
44
+ return (edges.get(fileName) ?? []).some((edge) => {
45
+ switch (edge.kind) {
46
+ case 'everything':
47
+ return true;
48
+ case 'named':
49
+ return edge.name === exportName;
50
+ case 'namespace': {
51
+ const members = namespaceMembers(edge);
52
+ return members === 'all' || members.has(exportName);
53
+ }
54
+ case 're-export':
55
+ return edge.name === exportName && follow(edge.importer, edge.as);
56
+ case 're-export-all':
57
+
58
+ return exportName !== 'default' && follow(edge.importer, exportName);
59
+ case 're-export-namespace':
60
+ return follow(edge.importer, edge.as);
61
+ }
62
+ });
63
+ };
64
+
65
+ const importEdges = (program) => {
66
+ const cached = importEdgesCache.get(program);
67
+ if (cached !== undefined) {
68
+ return cached;
69
+ }
70
+ const checker = program.getTypeChecker();
71
+ const mut_edges = new Map();
72
+ const add = (moduleSpecifier, ...edges) => {
73
+ const target = resolveModule(checker, moduleSpecifier);
74
+ if (target === undefined) {
75
+ return;
76
+ }
77
+ const mut_existing = mut_edges.get(target);
78
+ if (mut_existing === undefined) {
79
+ mut_edges.set(target, Array.from(edges));
80
+ }
81
+ else {
82
+ mut_existing.push(...edges);
83
+ }
84
+ };
85
+ for (const sourceFile of program.getSourceFiles()) {
86
+ if (sourceFile.isDeclarationFile ||
87
+ program.isSourceFileFromExternalLibrary(sourceFile) ||
88
+ program.isSourceFileDefaultLibrary(sourceFile)) {
89
+ continue;
90
+ }
91
+ for (const statement of sourceFile.statements) {
92
+ collectStatementEdges(sourceFile, statement, add);
93
+ }
94
+
95
+
96
+ if (DYNAMIC_IMPORT_PATTERN.test(sourceFile.text)) {
97
+ collectDynamicImportEdges(sourceFile, add);
98
+ }
99
+ }
100
+ importEdgesCache.set(program, mut_edges);
101
+ return mut_edges;
102
+ };
103
+ const collectStatementEdges = (sourceFile, statement, add) => {
104
+ if (ts.isImportDeclaration(statement)) {
105
+ const clause = statement.importClause;
106
+
107
+
108
+ if (clause === undefined || ts.isTypeOnlyImportDeclaration(clause)) {
109
+ return;
110
+ }
111
+ const bindings = clause.namedBindings;
112
+ add(statement.moduleSpecifier, ...(clause.name === undefined
113
+ ? []
114
+ : [{ kind: 'named', name: 'default' }]), ...(bindings === undefined
115
+ ? []
116
+ : ts.isNamespaceImport(bindings)
117
+ ? [
118
+ {
119
+ kind: 'namespace',
120
+ importer: sourceFile,
121
+ localName: bindings.name.text,
122
+ },
123
+ ]
124
+ : bindings.elements
125
+ .filter((element) => !element.isTypeOnly)
126
+ .map((element) => ({
127
+ kind: 'named',
128
+ name: (element.propertyName ?? element.name).text,
129
+ }))));
130
+ return;
131
+ }
132
+ if (ts.isExportDeclaration(statement)) {
133
+ if (statement.moduleSpecifier === undefined || statement.isTypeOnly) {
134
+ return;
135
+ }
136
+ const exportClause = statement.exportClause;
137
+ const importer = sourceFile.fileName;
138
+ add(statement.moduleSpecifier, ...(exportClause === undefined
139
+ ? [{ kind: 're-export-all', importer }]
140
+ : ts.isNamespaceExport(exportClause)
141
+ ? [
142
+ {
143
+ kind: 're-export-namespace',
144
+ importer,
145
+ as: exportClause.name.text,
146
+ },
147
+ ]
148
+ : exportClause.elements
149
+ .filter((element) => !element.isTypeOnly)
150
+ .map((element) => ({
151
+ kind: 're-export',
152
+ importer,
153
+ name: (element.propertyName ?? element.name).text,
154
+ as: element.name.text,
155
+ }))));
156
+ return;
157
+ }
158
+ if (ts.isImportEqualsDeclaration(statement) &&
159
+ !statement.isTypeOnly &&
160
+ ts.isExternalModuleReference(statement.moduleReference)) {
161
+ add(statement.moduleReference.expression, { kind: 'everything' });
162
+ }
163
+ };
164
+
165
+
166
+
167
+
168
+
169
+ const collectDynamicImportEdges = (sourceFile, add) => {
170
+ const visit = (node) => {
171
+ if (ts.isCallExpression(node) &&
172
+ (node.expression.kind === ts.SyntaxKind.ImportKeyword ||
173
+ (ts.isIdentifier(node.expression) &&
174
+ node.expression.text === 'require'))) {
175
+ const [argument] = node.arguments;
176
+ if (argument !== undefined && ts.isStringLiteralLike(argument)) {
177
+ add(argument, { kind: 'everything' });
178
+ }
179
+ }
180
+ ts.forEachChild(node, visit);
181
+ };
182
+ visit(sourceFile);
183
+ };
184
+
185
+
186
+
187
+
188
+
189
+ const resolveModule = (checker, moduleSpecifier) => checker
190
+ .getSymbolAtLocation(moduleSpecifier)
191
+ ?.declarations?.find(ts.isSourceFile)?.fileName;
192
+ const namespaceMembers = (edge) => {
193
+ const cached = namespaceMembersCache.get(edge);
194
+ if (cached !== undefined) {
195
+ return cached;
196
+ }
197
+ const result = collectNamespaceMembers(edge.importer, edge.localName);
198
+ namespaceMembersCache.set(edge, result);
199
+ return result;
200
+ };
201
+
202
+
203
+
204
+
205
+
206
+
207
+
208
+ const collectNamespaceMembers = (sourceFile, localName) => {
209
+ const mut_names = new Set();
210
+ const isNamespace = (node) => ts.isIdentifier(node) && node.text === localName;
211
+
212
+ const visit = (node) => {
213
+ if (ts.isImportDeclaration(node) ||
214
+
215
+
216
+
217
+ (ts.isTypeNode(node) && !ts.isExpressionWithTypeArguments(node))) {
218
+ return undefined;
219
+ }
220
+ if (ts.isPropertyAccessExpression(node) && isNamespace(node.expression)) {
221
+ mut_names.add(node.name.text);
222
+ return undefined;
223
+ }
224
+ if (ts.isElementAccessExpression(node) && isNamespace(node.expression)) {
225
+ if (!ts.isStringLiteralLike(node.argumentExpression)) {
226
+ return true;
227
+ }
228
+ mut_names.add(node.argumentExpression.text);
229
+ return undefined;
230
+ }
231
+ return ((isNamespace(node) && !isPropertyName(node)) ||
232
+ ts.forEachChild(node, visit));
233
+ };
234
+ return visit(sourceFile) === true ? 'all' : mut_names;
235
+ };
236
+
237
+
238
+
239
+
240
+ const isPropertyName = (node) => {
241
+ const parent = node.parent;
242
+ return (((ts.isPropertyAccessExpression(parent) ||
243
+ ts.isPropertyAssignment(parent) ||
244
+ ts.isPropertyDeclaration(parent) ||
245
+ ts.isMethodDeclaration(parent) ||
246
+ ts.isGetAccessorDeclaration(parent) ||
247
+ ts.isSetAccessorDeclaration(parent) ||
248
+ ts.isEnumMember(parent)) &&
249
+ parent.name === node) ||
250
+ (ts.isBindingElement(parent) && parent.propertyName === node));
251
+ };
252
+ //# sourceMappingURL=export-usage.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export-usage.mjs","sourceRoot":"","sources":["../../src/rules/export-usage.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,OAAmB,EACnB,QAAgB,EAChB,UAAkB,EAClB,WAAgC,EACvB,EAAE,CACX,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;AAsB7E;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,IAAI,OAAO,EAGjC,CAAC;AAEJ;;;GAGG;AACH,MAAM,qBAAqB,GAAG,IAAI,OAAO,EAGtC,CAAC;AAEJ,+EAA+E;AAC/E,MAAM,sBAAsB,GAAG,4BAA4B,CAAC;AAE5D,uEAAuE;AAEvE,MAAM,MAAM,GAAG,CACb,KAAiD,EACjD,WAAgC,EAChC,QAAgB,EAChB,UAAkB,EAClB,WAAwB,EACf,EAAE;IACX,IAAI,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,GAAG,GAAG,GAAG,QAAQ,KAAK,UAAU,EAAW,CAAC;IAElD,0EAA0E;IAC1E,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAErB,MAAM,MAAM,GAAG,CAAC,QAAgB,EAAE,IAAY,EAAW,EAAE,CACzD,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;IAE1D,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QAC/C,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,KAAK,YAAY;gBACf,OAAO,IAAI,CAAC;YAEd,KAAK,OAAO;gBACV,OAAO,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC;YAElC,KAAK,WAAW,EAAE,CAAC;gBACjB,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;gBAEvC,OAAO,OAAO,KAAK,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACtD,CAAC;YAED,KAAK,WAAW;gBACd,OAAO,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;YAEpE,KAAK,eAAe;gBAClB,sDAAsD;gBACtD,OAAO,UAAU,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YAEvE,KAAK,qBAAqB;gBACxB,OAAO,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,kEAAkE;AAClE,MAAM,WAAW,GAAG,CAClB,OAAmB,EACyB,EAAE;IAC9C,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAE7C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAEzC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAwB,CAAC;IAElD,MAAM,GAAG,GAAG,CACV,eAA8B,EAC9B,GAAG,KAA4B,EACzB,EAAE;QACR,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QAEvD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAE3C,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC/B,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,YAAY,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC;IAEF,KAAK,MAAM,UAAU,IAAI,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;QAClD,IACE,UAAU,CAAC,iBAAiB;YAC5B,OAAO,CAAC,+BAA+B,CAAC,UAAU,CAAC;YACnD,OAAO,CAAC,0BAA0B,CAAC,UAAU,CAAC,EAC9C,CAAC;YACD,SAAS;QACX,CAAC;QAED,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,UAAU,EAAE,CAAC;YAC9C,qBAAqB,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;QACpD,CAAC;QAED,uEAAuE;QACvE,+CAA+C;QAC/C,IAAI,sBAAsB,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACjD,yBAAyB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,gBAAgB,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAEzC,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAC5B,UAAyB,EACzB,SAAuB,EACvB,GAGS,EACH,EAAE;IACR,IAAI,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,SAAS,CAAC,YAAY,CAAC;QAEtC,0EAA0E;QAC1E,cAAc;QACd,IAAI,MAAM,KAAK,SAAS,IAAI,EAAE,CAAC,2BAA2B,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,CAAC;QAEtC,GAAG,CACD,SAAS,CAAC,eAAe,EACzB,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS;YAC3B,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAW,CAAC,CAAC,EAClD,GAAG,CAAC,QAAQ,KAAK,SAAS;YACxB,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC;gBAC9B,CAAC,CAAC;oBACE;wBACE,IAAI,EAAE,WAAW;wBACjB,QAAQ,EAAE,UAAU;wBACpB,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI;qBACrB;iBACX;gBACH,CAAC,CAAC,QAAQ,CAAC,QAAQ;qBACd,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;qBACxC,GAAG,CACF,CAAC,OAAO,EAAE,EAAE,CACV,CAAC;oBACC,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,CAAC,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI;iBAClD,CAAU,CACd,CAAC,CACX,CAAC;QAEF,OAAO;IACT,CAAC;IAED,IAAI,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC;QACtC,IAAI,SAAS,CAAC,eAAe,KAAK,SAAS,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;YACpE,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,SAAS,CAAC,YAAY,CAAC;QAE5C,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC;QAErC,GAAG,CACD,SAAS,CAAC,eAAe,EACzB,GAAG,CAAC,YAAY,KAAK,SAAS;YAC5B,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAW,CAAC;YAChD,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,YAAY,CAAC;gBAClC,CAAC,CAAC;oBACE;wBACE,IAAI,EAAE,qBAAqB;wBAC3B,QAAQ;wBACR,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI;qBAClB;iBACX;gBACH,CAAC,CAAC,YAAY,CAAC,QAAQ;qBAClB,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;qBACxC,GAAG,CACF,CAAC,OAAO,EAAE,EAAE,CACV,CAAC;oBACC,IAAI,EAAE,WAAW;oBACjB,QAAQ;oBACR,IAAI,EAAE,CAAC,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI;oBACjD,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI;iBACtB,CAAU,CACd,CAAC,CACX,CAAC;QAEF,OAAO;IACT,CAAC;IAED,IACE,EAAE,CAAC,yBAAyB,CAAC,SAAS,CAAC;QACvC,CAAC,SAAS,CAAC,UAAU;QACrB,EAAE,CAAC,yBAAyB,CAAC,SAAS,CAAC,eAAe,CAAC,EACvD,CAAC;QACD,GAAG,CAAC,SAAS,CAAC,eAAe,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;IACpE,CAAC;AACH,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,yBAAyB,GAAG,CAChC,UAAyB,EACzB,GAGS,EACH,EAAE;IACR,MAAM,KAAK,GAAG,CAAC,IAAa,EAAQ,EAAE;QACpC,IACE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;YACzB,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,aAAa;gBACnD,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC;oBAC/B,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,EACxC,CAAC;YACD,MAAM,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;YAElC,IAAI,QAAQ,KAAK,SAAS,IAAI,EAAE,CAAC,mBAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC/D,GAAG,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QAED,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC,CAAC;IAEF,KAAK,CAAC,UAAU,CAAC,CAAC;AACpB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,aAAa,GAAG,CACpB,OAAuB,EACvB,eAA8B,EACV,EAAE,CACtB,OAAO;KACJ,mBAAmB,CAAC,eAAe,CAAC;IACrC,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC;AAEpD,MAAM,gBAAgB,GAAG,CAAC,IAAyB,EAAoB,EAAE;IACvE,MAAM,MAAM,GAAG,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAE/C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,MAAM,GAAG,uBAAuB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAEtE,qBAAqB,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAExC,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,uBAAuB,GAAG,CAC9B,UAAyB,EACzB,SAAiB,EACC,EAAE;IACpB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IAEpC,MAAM,WAAW,GAAG,CAAC,IAAa,EAAyB,EAAE,CAC3D,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC;IAEnD,kEAAkE;IAClE,MAAM,KAAK,GAAG,CAAC,IAAa,EAAuB,EAAE;QACnD,IACE,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC;YAC5B,yEAAyE;YACzE,kEAAkE;YAClE,gCAAgC;YAChC,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,6BAA6B,CAAC,IAAI,CAAC,CAAC,EAChE,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YACxE,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAE9B,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YACvE,IAAI,CAAC,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBACrD,OAAO,IAAI,CAAC;YACd,CAAC;YAED,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAE5C,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,CACL,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YAC5C,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAC7B,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,KAAK,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACxD,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,cAAc,GAAG,CAAC,IAAmB,EAAW,EAAE;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAE3B,OAAO,CACL,CAAC,CAAC,EAAE,CAAC,0BAA0B,CAAC,MAAM,CAAC;QACrC,EAAE,CAAC,oBAAoB,CAAC,MAAM,CAAC;QAC/B,EAAE,CAAC,qBAAqB,CAAC,MAAM,CAAC;QAChC,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC;QAC9B,EAAE,CAAC,wBAAwB,CAAC,MAAM,CAAC;QACnC,EAAE,CAAC,wBAAwB,CAAC,MAAM,CAAC;QACnC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACxB,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC;QACvB,CAAC,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,YAAY,KAAK,IAAI,CAAC,CAC9D,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { type TSESLint } from '@typescript-eslint/utils';
2
+ type Options = readonly [
3
+ Readonly<{
4
+ entryPoints?: readonly string[];
5
+ }>?
6
+ ];
7
+ type MessageIds = 'typeOnlyCodec';
8
+ /**
9
+ * A codec exists to check values at runtime. One declared next to
10
+ * `type Y = t.TypeOf<typeof X>` and never read as a value is a type written the
11
+ * long way round: it costs a runtime object and a bundle import, and it reads
12
+ * as if something validated with it. This rule reports such a codec, so that
13
+ * `Y` becomes a plain type alias.
14
+ *
15
+ * "Never read as a value" means: no value reference in its own file outside
16
+ * `typeof`, every import of it elsewhere `import type`, and no entry point
17
+ * re-exporting it. The entry points are what the nearest `package.json`
18
+ * publishes, traced back to source, unless the `entryPoints` option names them.
19
+ * The cross-file part reads the importers from the TypeScript program; without
20
+ * type information, or when the published entry points cannot all be traced
21
+ * back to source, an exported codec is left alone.
22
+ */
23
+ export declare const noTypeOnlyCodec: TSESLint.RuleModule<MessageIds, Options>;
24
+ export {};
25
+ //# sourceMappingURL=no-type-only-codec.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-type-only-codec.d.mts","sourceRoot":"","sources":["../../src/rules/no-type-only-codec.mts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,0BAA0B,CAAC;AAQlC,KAAK,OAAO,GAAG,SAAS;IACtB,QAAQ,CAAC;QACP,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;KACjC,CAAC,CAAC;CACJ,CAAC;AAEF,KAAK,UAAU,GAAG,eAAe,CAAC;AAKlC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,UAAU,CAAC,UAAU,EAAE,OAAO,CA2F3D,CAAC"}