eslint-plugin-ts-type-forge 0.5.0 → 0.6.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.
- package/README.md +80 -13
- package/dist/plugin.d.mts +8 -0
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin.mjs +3 -1
- package/dist/plugin.mjs.map +1 -1
- package/dist/rule-types.d.mts +78 -0
- package/dist/rule-types.d.mts.map +1 -1
- package/dist/rules/import-style.d.mts +21 -0
- package/dist/rules/import-style.d.mts.map +1 -0
- package/dist/rules/import-style.mjs +29 -0
- package/dist/rules/import-style.mjs.map +1 -0
- package/dist/rules/prefer-canonical-length-constrained-tuple.d.mts.map +1 -1
- package/dist/rules/prefer-canonical-length-constrained-tuple.mjs +2 -1
- package/dist/rules/prefer-canonical-length-constrained-tuple.mjs.map +1 -1
- package/dist/rules/prefer-readonly-or-mutable-record.d.mts +10 -0
- package/dist/rules/prefer-readonly-or-mutable-record.d.mts.map +1 -0
- package/dist/rules/prefer-readonly-or-mutable-record.mjs +49 -0
- package/dist/rules/prefer-readonly-or-mutable-record.mjs.map +1 -0
- package/dist/rules/prefer-strict-or-relaxed-utility-type.d.mts +10 -0
- package/dist/rules/prefer-strict-or-relaxed-utility-type.d.mts.map +1 -0
- package/dist/rules/prefer-strict-or-relaxed-utility-type.mjs +49 -0
- package/dist/rules/prefer-strict-or-relaxed-utility-type.mjs.map +1 -0
- package/dist/rules/rules.d.mts +6 -0
- package/dist/rules/rules.d.mts.map +1 -1
- package/dist/rules/rules.mjs +5 -1
- package/dist/rules/rules.mjs.map +1 -1
- package/dist/rules/std-type-rule-utils.d.mts +22 -0
- package/dist/rules/std-type-rule-utils.d.mts.map +1 -0
- package/dist/rules/std-type-rule-utils.mjs +40 -0
- package/dist/rules/std-type-rule-utils.mjs.map +1 -0
- package/dist/rules/tuple-rule-utils.d.mts +1 -19
- package/dist/rules/tuple-rule-utils.d.mts.map +1 -1
- package/dist/rules/tuple-rule-utils.mjs +3 -26
- package/dist/rules/tuple-rule-utils.mjs.map +1 -1
- package/package.json +2 -2
- package/src/plugin.mts +2 -0
- package/src/rule-types.mts +92 -0
- package/src/rules/import-style.mts +60 -0
- package/src/rules/prefer-canonical-length-constrained-tuple.mts +2 -3
- package/src/rules/prefer-readonly-or-mutable-record.mts +74 -0
- package/src/rules/prefer-readonly-or-mutable-record.test.mts +160 -0
- package/src/rules/prefer-strict-or-relaxed-utility-type.mts +80 -0
- package/src/rules/prefer-strict-or-relaxed-utility-type.test.mts +279 -0
- package/src/rules/rules.mts +4 -0
- package/src/rules/std-type-rule-utils.mts +103 -0
- package/src/rules/tuple-rule-utils.mts +2 -58
package/README.md
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
ESLint rules that steer TypeScript **type declarations** toward
|
|
4
4
|
[`ts-type-forge`](https://www.npmjs.com/package/ts-type-forge) idioms — replacing
|
|
5
5
|
hand-rolled uniform tuple spellings with the library's named length-constrained
|
|
6
|
-
tuple types
|
|
6
|
+
tuple types, and the standard library's under-specified `Exclude` / `Extract` /
|
|
7
|
+
`Omit` / `Pick` / `Record` with counterparts that state what was left implicit.
|
|
8
|
+
Every rewrite is **type-preserving**.
|
|
7
9
|
|
|
8
10
|
## Installation
|
|
9
11
|
|
|
@@ -70,9 +72,13 @@ export default [
|
|
|
70
72
|
|
|
71
73
|
## Rules
|
|
72
74
|
|
|
73
|
-
| Rule | Description
|
|
74
|
-
| :------------------------------------------ |
|
|
75
|
-
| `prefer-canonical-length-constrained-tuple` | Replace hand-rolled uniform tuple spellings with the canonical ts-type-forge tuple type.
|
|
75
|
+
| Rule | Fix | Description |
|
|
76
|
+
| :------------------------------------------ | :--------- | :---------------------------------------------------------------------------------------- |
|
|
77
|
+
| `prefer-canonical-length-constrained-tuple` | autofix | Replace hand-rolled uniform tuple spellings with the canonical ts-type-forge tuple type. |
|
|
78
|
+
| `prefer-strict-or-relaxed-utility-type` | suggestion | Replace `Exclude` / `Extract` / `Omit` / `Pick` with the `Strict*` or `Relaxed*` variant. |
|
|
79
|
+
| `prefer-readonly-or-mutable-record` | suggestion | Replace `Record` with `ReadonlyRecord` or `MutableRecord`. |
|
|
80
|
+
|
|
81
|
+
### `prefer-canonical-length-constrained-tuple`
|
|
76
82
|
|
|
77
83
|
It covers the whole uniform-tuple family:
|
|
78
84
|
|
|
@@ -112,7 +118,7 @@ type AtLeastTwo = MutableMinLengthTuple<2, string>;
|
|
|
112
118
|
Single-element tuples without a rest (`readonly [V]`) are left alone — they read
|
|
113
119
|
better as-is than `FixedLengthTuple<1, V>`.
|
|
114
120
|
|
|
115
|
-
|
|
121
|
+
#### The rule deliberately leaves alone
|
|
116
122
|
|
|
117
123
|
- heterogeneous tuples (`readonly [string, number]`);
|
|
118
124
|
- labelled members (`readonly [head: V, ...tail: V[]]`), because rewriting them
|
|
@@ -121,21 +127,82 @@ better as-is than `FixedLengthTuple<1, V>`.
|
|
|
121
127
|
- files that already bind the target name to something else (a local alias, or
|
|
122
128
|
an import from another module).
|
|
123
129
|
|
|
130
|
+
### `prefer-strict-or-relaxed-utility-type`
|
|
131
|
+
|
|
132
|
+
`Exclude<T, U>`, `Extract<T, U>`, `Omit<T, K>` and `Pick<T, K>` do not constrain
|
|
133
|
+
their second argument, so a member or key that is not part of `T` is silently
|
|
134
|
+
accepted — typically producing an empty result instead of the compile error that
|
|
135
|
+
would have pointed at the leftover of a rename.
|
|
136
|
+
|
|
137
|
+
ts-type-forge splits each one in two, and this rule makes the choice explicit:
|
|
138
|
+
|
|
139
|
+
| built-in | checks the second argument | keeps the built-in behavior |
|
|
140
|
+
| :-------------- | :------------------------- | :-------------------------- |
|
|
141
|
+
| `Exclude<T, U>` | `StrictExclude<T, U>` | `RelaxedExclude<T, U>` |
|
|
142
|
+
| `Extract<T, U>` | `StrictExtract<T, U>` | `RelaxedExtract<T, U>` |
|
|
143
|
+
| `Omit<T, K>` | `StrictOmit<T, K>` | `RelaxedOmit<T, K>` |
|
|
144
|
+
| `Pick<T, K>` | `StrictPick<T, K>` | `RelaxedPick<T, K>` |
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
// ❌
|
|
148
|
+
type Remaining = Exclude<'a' | 'b' | 'c', 'a'>;
|
|
149
|
+
type PublicInfo = Omit<Person, 'email'>;
|
|
150
|
+
|
|
151
|
+
// ✅ — the key is checked against the union / `keyof T`
|
|
152
|
+
type Remaining = StrictExclude<'a' | 'b' | 'c', 'a'>;
|
|
153
|
+
type PublicInfo = StrictOmit<Person, 'email'>;
|
|
154
|
+
|
|
155
|
+
// ✅ — deliberately unchecked (the subtrahend need not be part of `T`)
|
|
156
|
+
type NonStrings = RelaxedExclude<string | number | boolean, string>;
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Reach for `Relaxed*` when the second argument genuinely need not be part of the
|
|
160
|
+
first — a key set computed from a still deferred type parameter, or a subtraction
|
|
161
|
+
whose subtrahend is only partly present.
|
|
162
|
+
|
|
163
|
+
### `prefer-readonly-or-mutable-record`
|
|
164
|
+
|
|
165
|
+
`Record<K, V>` says nothing about whether the properties may be reassigned, so
|
|
166
|
+
the mutability of every record spelled with it is decided by whoever reads it.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
// ❌
|
|
170
|
+
type Config = Record<string, string | number>;
|
|
171
|
+
|
|
172
|
+
// ✅
|
|
173
|
+
type Config = ReadonlyRecord<string, string | number>;
|
|
174
|
+
type Counters = MutableRecord<string, number>;
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Both rules deliberately leave alone
|
|
178
|
+
|
|
179
|
+
- qualified names (`Utils.Pick<…>`) — they never denote the standard-library
|
|
180
|
+
type;
|
|
181
|
+
- files that declare or import their own `Pick` / `Record` / …, for the same
|
|
182
|
+
reason;
|
|
183
|
+
- the choice itself: replacing `Exclude` with `StrictExclude` can turn working
|
|
184
|
+
code into a compile error, and `Record` maps onto two different types, so
|
|
185
|
+
these rules report **suggestions** rather than an autofix. Editors offer both
|
|
186
|
+
replacements; `--fix` changes nothing.
|
|
187
|
+
|
|
124
188
|
## Options
|
|
125
189
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
|
190
|
+
`importStyle` is accepted by every rule; `maxLength` only by
|
|
191
|
+
`prefer-canonical-length-constrained-tuple`.
|
|
192
|
+
|
|
193
|
+
| Option | Type | Default | Description |
|
|
194
|
+
| :------------ | :-------------------- | :-------- | :------------------------------------------------------------------ |
|
|
195
|
+
| `importStyle` | `'global' \| 'named'` | `'named'` | How the ts-type-forge type is brought into scope. |
|
|
196
|
+
| `maxLength` | `integer` | `10` | Longest tuple `prefer-canonical-length-constrained-tuple` rewrites. |
|
|
130
197
|
|
|
131
198
|
- `'global'` — the ambient globals of `ts-type-forge/global` are in use
|
|
132
|
-
(`/// <reference types="ts-type-forge/global" />`), so the
|
|
133
|
-
|
|
134
|
-
- `'named'` — the
|
|
199
|
+
(`/// <reference types="ts-type-forge/global" />`), so the fix only rewrites
|
|
200
|
+
the type and never touches imports.
|
|
201
|
+
- `'named'` — the fix additionally inserts
|
|
135
202
|
`import { type … } from 'ts-type-forge';` when the name is not imported yet.
|
|
136
203
|
|
|
137
204
|
Either way, if the file already imports the target type from `ts-type-forge`
|
|
138
|
-
(possibly under an alias), the
|
|
205
|
+
(possibly under an alias), the fix reuses that binding.
|
|
139
206
|
|
|
140
207
|
```ts
|
|
141
208
|
{
|
package/dist/plugin.d.mts
CHANGED
|
@@ -8,6 +8,12 @@ export declare const eslintPluginTsTypeForge: {
|
|
|
8
8
|
importStyle?: 'global' | 'named';
|
|
9
9
|
maxLength?: number;
|
|
10
10
|
}> | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
11
|
+
readonly 'prefer-readonly-or-mutable-record': import("@typescript-eslint/utils/ts-eslint").RuleModule<"replaceWith" | "useReadonlyOrMutableRecord", readonly [(Readonly<{
|
|
12
|
+
importStyle?: 'global' | 'named';
|
|
13
|
+
}> | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
14
|
+
readonly 'prefer-strict-or-relaxed-utility-type': import("@typescript-eslint/utils/ts-eslint").RuleModule<"replaceWith" | "useStrictOrRelaxed", readonly [(Readonly<{
|
|
15
|
+
importStyle?: 'global' | 'named';
|
|
16
|
+
}> | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
11
17
|
};
|
|
12
18
|
readonly configs: {
|
|
13
19
|
/** Enables every rule of this plugin at `error`. */
|
|
@@ -18,6 +24,8 @@ export declare const eslintPluginTsTypeForge: {
|
|
|
18
24
|
};
|
|
19
25
|
readonly rules: {
|
|
20
26
|
readonly 'ts-type-forge/prefer-canonical-length-constrained-tuple': 'error';
|
|
27
|
+
readonly 'ts-type-forge/prefer-readonly-or-mutable-record': 'error';
|
|
28
|
+
readonly 'ts-type-forge/prefer-strict-or-relaxed-utility-type': 'error';
|
|
21
29
|
};
|
|
22
30
|
};
|
|
23
31
|
};
|
package/dist/plugin.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.mts","sourceRoot":"","sources":["../src/plugin.mts"],"names":[],"mappings":"AACA,OAAO,EAAyB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin.d.mts","sourceRoot":"","sources":["../src/plugin.mts"],"names":[],"mappings":"AACA,OAAO,EAAyB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAgCvE,eAAO,MAAM,uBAAuB;;iBAEhC,IAAI,EAAE,6BAA6B;;;;;;;;;;;;;;;QAInC,oDAAoD;iBACpD,WAAW;2BAtBP,2BAA2B;;yBAQ3B,eAAe,EAAI,YAAY;;;oFAhBsB,OAAO;4EACf,OAAO;gFACH,OAAO;;;;CA8B/B,CAAC"}
|
package/dist/plugin.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { tsTypeForgeRules } from './rules/rules.mjs';
|
|
2
2
|
|
|
3
3
|
const recommendedRules = {
|
|
4
|
-
"ts-type-forge/prefer-canonical-length-constrained-tuple": "error"
|
|
4
|
+
"ts-type-forge/prefer-canonical-length-constrained-tuple": "error",
|
|
5
|
+
"ts-type-forge/prefer-readonly-or-mutable-record": "error",
|
|
6
|
+
"ts-type-forge/prefer-strict-or-relaxed-utility-type": "error"
|
|
5
7
|
};
|
|
6
8
|
const recommendedConfig = {
|
|
7
9
|
name: "ts-type-forge/recommended",
|
package/dist/plugin.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.mjs","sources":["../src/plugin.mts"],"sourcesContent":["import { tsTypeForgeRules } from './rules/index.mjs';\nimport { type ESLintFlatConfig, type ESLintPlugin } from './types.mjs';\n\n/**\n * Every rule this plugin ships, at `error`.\n *\n * The `satisfies` clause below is keyed off {@link tsTypeForgeRules}, so adding\n * a rule without listing it here fails to type-check.\n */\nconst recommendedRules = {\n 'ts-type-forge/prefer-canonical-length-constrained-tuple': 'error',\n} as const satisfies Readonly<\n Record<`ts-type-forge/${keyof typeof tsTypeForgeRules}`, 'error'>\n>;\n\nconst recommendedConfig = {\n name: 'ts-type-forge/recommended',\n plugins: {\n // Resolved lazily so that this config registers the *same* object that\n // `eslintPluginTsTypeForge` refers to. ESLint rejects a plugin name that\n // maps to two different objects with `Cannot redefine plugin`, which is\n // what a user combining this preset with their own\n // `plugins: { 'ts-type-forge': eslintPluginTsTypeForge }` entry would hit\n // if the preset embedded a separate copy of the plugin.\n get 'ts-type-forge'(): ESLintPlugin {\n return eslintPluginTsTypeForge;\n },\n },\n rules: recommendedRules,\n} as const satisfies ESLintFlatConfig;\n\nexport const eslintPluginTsTypeForge = {\n meta: {\n name: 'eslint-plugin-ts-type-forge',\n },\n rules: tsTypeForgeRules,\n configs: {\n /** Enables every rule of this plugin at `error`. */\n recommended: recommendedConfig,\n },\n} as const satisfies ESLintPlugin;\n"],"names":[],"mappings":";;AASA,MAAM,gBAAA,GAAmB;AAAA,EACvB,yDAAA,EAA2D;
|
|
1
|
+
{"version":3,"file":"plugin.mjs","sources":["../src/plugin.mts"],"sourcesContent":["import { tsTypeForgeRules } from './rules/index.mjs';\nimport { type ESLintFlatConfig, type ESLintPlugin } from './types.mjs';\n\n/**\n * Every rule this plugin ships, at `error`.\n *\n * The `satisfies` clause below is keyed off {@link tsTypeForgeRules}, so adding\n * a rule without listing it here fails to type-check.\n */\nconst recommendedRules = {\n 'ts-type-forge/prefer-canonical-length-constrained-tuple': 'error',\n 'ts-type-forge/prefer-readonly-or-mutable-record': 'error',\n 'ts-type-forge/prefer-strict-or-relaxed-utility-type': 'error',\n} as const satisfies Readonly<\n Record<`ts-type-forge/${keyof typeof tsTypeForgeRules}`, 'error'>\n>;\n\nconst recommendedConfig = {\n name: 'ts-type-forge/recommended',\n plugins: {\n // Resolved lazily so that this config registers the *same* object that\n // `eslintPluginTsTypeForge` refers to. ESLint rejects a plugin name that\n // maps to two different objects with `Cannot redefine plugin`, which is\n // what a user combining this preset with their own\n // `plugins: { 'ts-type-forge': eslintPluginTsTypeForge }` entry would hit\n // if the preset embedded a separate copy of the plugin.\n get 'ts-type-forge'(): ESLintPlugin {\n return eslintPluginTsTypeForge;\n },\n },\n rules: recommendedRules,\n} as const satisfies ESLintFlatConfig;\n\nexport const eslintPluginTsTypeForge = {\n meta: {\n name: 'eslint-plugin-ts-type-forge',\n },\n rules: tsTypeForgeRules,\n configs: {\n /** Enables every rule of this plugin at `error`. */\n recommended: recommendedConfig,\n },\n} as const satisfies ESLintPlugin;\n"],"names":[],"mappings":";;AASA,MAAM,gBAAA,GAAmB;AAAA,EACvB,yDAAA,EAA2D,OAAA;AAAA,EAC3D,iDAAA,EAAmD,OAAA;AAAA,EACnD,qDAAA,EAAuD;AACzD,CAAA;AAIA,MAAM,iBAAA,GAAoB;AAAA,EACxB,IAAA,EAAM,2BAAA;AAAA,EACN,OAAA,EAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOP,IAAI,eAAA,GAAgC;AAClC,MAAA,OAAO,uBAAA;AAAA,IACT;AAAA,GACF;AAAA,EACA,KAAA,EAAO;AACT,CAAA;AAEO,MAAM,uBAAA,GAA0B;AAAA,EACrC,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM;AAAA,GACR;AAAA,EACA,KAAA,EAAO,gBAAA;AAAA,EACP,OAAA,EAAS;AAAA;AAAA,IAEP,WAAA,EAAa;AAAA;AAEjB;;;;"}
|
package/dist/rule-types.d.mts
CHANGED
|
@@ -51,11 +51,89 @@ declare namespace PreferCanonicalLengthConstrainedTuple {
|
|
|
51
51
|
type Options = NonNullable<RuleOptionsOf<'prefer-canonical-length-constrained-tuple'>[0]>;
|
|
52
52
|
type RuleEntry = 'off' | Linter.Severity | SpreadOptionsIfIsArray<readonly [Linter.StringSeverity, Options]>;
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* @description Replace the built-in `Record` with the ts-type-forge `ReadonlyRecord` or `MutableRecord`, so that the mutability of the record is stated rather than implied.
|
|
56
|
+
*
|
|
57
|
+
* ```md
|
|
58
|
+
* | key | value |
|
|
59
|
+
* | :--------- | :--------- |
|
|
60
|
+
* | type | suggestion |
|
|
61
|
+
* | deprecated | false |
|
|
62
|
+
* | fixable | false |
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
declare namespace PreferReadonlyOrMutableRecord {
|
|
66
|
+
/**
|
|
67
|
+
* ### schema
|
|
68
|
+
*
|
|
69
|
+
* ```json
|
|
70
|
+
* [
|
|
71
|
+
* {
|
|
72
|
+
* "type": "object",
|
|
73
|
+
* "properties": {
|
|
74
|
+
* "importStyle": {
|
|
75
|
+
* "type": "string",
|
|
76
|
+
* "enum": [
|
|
77
|
+
* "global",
|
|
78
|
+
* "named"
|
|
79
|
+
* ],
|
|
80
|
+
* "description": "How the ts-type-forge type is brought into scope. 'named' (default) makes the autofix add the corresponding `import { type … } from 'ts-type-forge';` when the name is not imported yet; 'global' assumes the ambient globals of `ts-type-forge/global` and never touches imports."
|
|
81
|
+
* }
|
|
82
|
+
* },
|
|
83
|
+
* "additionalProperties": false
|
|
84
|
+
* }
|
|
85
|
+
* ]
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
type Options = NonNullable<RuleOptionsOf<'prefer-readonly-or-mutable-record'>[0]>;
|
|
89
|
+
type RuleEntry = 'off' | Linter.Severity | SpreadOptionsIfIsArray<readonly [Linter.StringSeverity, Options]>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* @description Replace the built-in `Exclude` / `Extract` / `Omit` / `Pick` with the ts-type-forge `Strict*` or `Relaxed*` counterpart, so that the unchecked second argument becomes an explicit choice.
|
|
93
|
+
*
|
|
94
|
+
* ```md
|
|
95
|
+
* | key | value |
|
|
96
|
+
* | :--------- | :--------- |
|
|
97
|
+
* | type | suggestion |
|
|
98
|
+
* | deprecated | false |
|
|
99
|
+
* | fixable | false |
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
declare namespace PreferStrictOrRelaxedUtilityType {
|
|
103
|
+
/**
|
|
104
|
+
* ### schema
|
|
105
|
+
*
|
|
106
|
+
* ```json
|
|
107
|
+
* [
|
|
108
|
+
* {
|
|
109
|
+
* "type": "object",
|
|
110
|
+
* "properties": {
|
|
111
|
+
* "importStyle": {
|
|
112
|
+
* "type": "string",
|
|
113
|
+
* "enum": [
|
|
114
|
+
* "global",
|
|
115
|
+
* "named"
|
|
116
|
+
* ],
|
|
117
|
+
* "description": "How the ts-type-forge type is brought into scope. 'named' (default) makes the autofix add the corresponding `import { type … } from 'ts-type-forge';` when the name is not imported yet; 'global' assumes the ambient globals of `ts-type-forge/global` and never touches imports."
|
|
118
|
+
* }
|
|
119
|
+
* },
|
|
120
|
+
* "additionalProperties": false
|
|
121
|
+
* }
|
|
122
|
+
* ]
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
type Options = NonNullable<RuleOptionsOf<'prefer-strict-or-relaxed-utility-type'>[0]>;
|
|
126
|
+
type RuleEntry = 'off' | Linter.Severity | SpreadOptionsIfIsArray<readonly [Linter.StringSeverity, Options]>;
|
|
127
|
+
}
|
|
54
128
|
export type EslintTsTypeForgeRules = Readonly<{
|
|
55
129
|
'ts-type-forge/prefer-canonical-length-constrained-tuple': PreferCanonicalLengthConstrainedTuple.RuleEntry;
|
|
130
|
+
'ts-type-forge/prefer-readonly-or-mutable-record': PreferReadonlyOrMutableRecord.RuleEntry;
|
|
131
|
+
'ts-type-forge/prefer-strict-or-relaxed-utility-type': PreferStrictOrRelaxedUtilityType.RuleEntry;
|
|
56
132
|
}>;
|
|
57
133
|
export type EslintTsTypeForgeRulesOption = Readonly<{
|
|
58
134
|
'ts-type-forge/prefer-canonical-length-constrained-tuple': PreferCanonicalLengthConstrainedTuple.Options;
|
|
135
|
+
'ts-type-forge/prefer-readonly-or-mutable-record': PreferReadonlyOrMutableRecord.Options;
|
|
136
|
+
'ts-type-forge/prefer-strict-or-relaxed-utility-type': PreferStrictOrRelaxedUtilityType.Options;
|
|
59
137
|
}>;
|
|
60
138
|
type AssertTrue<B extends true> = B;
|
|
61
139
|
export type RuleNamesAreInSync = AssertTrue<TypeEq<keyof EslintTsTypeForgeRules, `ts-type-forge/${keyof typeof tsTypeForgeRules}`>>;
|
|
@@ -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,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,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,gBAAgB,IAC3D,CAAC,OAAO,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS,QAAQ,CAAC,UAAU,CACzD,MAAM,WAAW,SAAS,MAAM,EAChC,MAAM,OAAO,SAAS,SAAS,OAAO,EAAE,CACzC,GACG,OAAO,GACP,KAAK,CAAC;AAEZ;;;;;;;;;;GAUG;AACH,kBAAU,qCAAqC,CAAC;IAC9C;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,KAAY,OAAO,GAAG,WAAW,CAC/B,aAAa,CAAC,2CAA2C,CAAC,CAAC,CAAC,CAAC,CAC9D,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,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,yDAAyD,EAAE,qCAAqC,CAAC,SAAS,CAAC;
|
|
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,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,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,gBAAgB,IAC3D,CAAC,OAAO,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS,QAAQ,CAAC,UAAU,CACzD,MAAM,WAAW,SAAS,MAAM,EAChC,MAAM,OAAO,SAAS,SAAS,OAAO,EAAE,CACzC,GACG,OAAO,GACP,KAAK,CAAC;AAEZ;;;;;;;;;;GAUG;AACH,kBAAU,qCAAqC,CAAC;IAC9C;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,KAAY,OAAO,GAAG,WAAW,CAC/B,aAAa,CAAC,2CAA2C,CAAC,CAAC,CAAC,CAAC,CAC9D,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,6BAA6B,CAAC;IACtC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAY,OAAO,GAAG,WAAW,CAC/B,aAAa,CAAC,mCAAmC,CAAC,CAAC,CAAC,CAAC,CACtD,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,gCAAgC,CAAC;IACzC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAY,OAAO,GAAG,WAAW,CAC/B,aAAa,CAAC,uCAAuC,CAAC,CAAC,CAAC,CAAC,CAC1D,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,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,yDAAyD,EAAE,qCAAqC,CAAC,SAAS,CAAC;IAC3G,iDAAiD,EAAE,6BAA6B,CAAC,SAAS,CAAC;IAC3F,qDAAqD,EAAE,gCAAgC,CAAC,SAAS,CAAC;CACnG,CAAC,CAAC;AAEH,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC;IAClD,yDAAyD,EAAE,qCAAqC,CAAC,OAAO,CAAC;IACzG,iDAAiD,EAAE,6BAA6B,CAAC,OAAO,CAAC;IACzF,qDAAqD,EAAE,gCAAgC,CAAC,OAAO,CAAC;CACjG,CAAC,CAAC;AAIH,KAAK,UAAU,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;AAEpC,MAAM,MAAM,kBAAkB,GAAG,UAAU,CACzC,MAAM,CACJ,MAAM,sBAAsB,EAC5B,iBAAiB,MAAM,OAAO,gBAAgB,EAAE,CACjD,CACF,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
/** `JSONSchema4`, reached through the public rule-module types. */
|
|
3
|
+
type JsonSchema = Exclude<TSESLint.RuleModule<string, readonly unknown[]>['meta']['schema'], readonly unknown[]>;
|
|
4
|
+
export type ImportStyle = 'global' | 'named';
|
|
5
|
+
export declare const DEFAULT_IMPORT_STYLE: ImportStyle;
|
|
6
|
+
export declare const IMPORT_STYLE_SCHEMA_PROPERTY: JsonSchema;
|
|
7
|
+
/**
|
|
8
|
+
* Resolves how a ts-type-forge type name should be written in this file, and
|
|
9
|
+
* whether the fix has to add an import for it.
|
|
10
|
+
*
|
|
11
|
+
* Returns `undefined` when the name is already bound to something else (a local
|
|
12
|
+
* alias, or an import from another module) — rewriting to it would then silently
|
|
13
|
+
* resolve to the wrong declaration, which is exactly what happens inside
|
|
14
|
+
* ts-type-forge's own sources.
|
|
15
|
+
*/
|
|
16
|
+
export declare const resolveTypeName: (program: TSESTree.Program, canonicalName: string, importStyle: ImportStyle) => Readonly<{
|
|
17
|
+
localName: string;
|
|
18
|
+
needsImport: boolean;
|
|
19
|
+
}> | undefined;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=import-style.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-style.d.mts","sourceRoot":"","sources":["../../src/rules/import-style.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAUxE,mEAAmE;AACnE,KAAK,UAAU,GAAG,OAAO,CACvB,QAAQ,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EACjE,SAAS,OAAO,EAAE,CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7C,eAAO,MAAM,oBAAoB,EAAE,WAAqB,CAAC;AAEzD,eAAO,MAAM,4BAA4B,EAAE,UAW1C,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,YACjB,QAAQ,CAAC,OAAO,iBACV,MAAM,eACR,WAAW,KACvB,QAAQ,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC,GAAG,SAa1D,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { TS_TYPE_FORGE_MODULE } from './constants.mjs';
|
|
2
|
+
import { getImportedLocalName, getTsTypeForgeImports, hasConflictingDeclaration } from './import-utils.mjs';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_IMPORT_STYLE = "named";
|
|
5
|
+
const IMPORT_STYLE_SCHEMA_PROPERTY = {
|
|
6
|
+
type: "string",
|
|
7
|
+
enum: ["global", "named"],
|
|
8
|
+
description: [
|
|
9
|
+
"How the ts-type-forge type is brought into scope.",
|
|
10
|
+
"'named' (default) makes the autofix add the corresponding",
|
|
11
|
+
`\`import { type \u2026 } from '${TS_TYPE_FORGE_MODULE}';\``,
|
|
12
|
+
"when the name is not imported yet; 'global' assumes the",
|
|
13
|
+
"ambient globals of `ts-type-forge/global` and never touches",
|
|
14
|
+
"imports."
|
|
15
|
+
].join(" ")
|
|
16
|
+
};
|
|
17
|
+
const resolveTypeName = (program, canonicalName, importStyle) => {
|
|
18
|
+
const importedLocalName = getImportedLocalName(
|
|
19
|
+
getTsTypeForgeImports(program),
|
|
20
|
+
canonicalName
|
|
21
|
+
);
|
|
22
|
+
if (importedLocalName !== void 0) {
|
|
23
|
+
return { localName: importedLocalName, needsImport: false };
|
|
24
|
+
}
|
|
25
|
+
return hasConflictingDeclaration(program, canonicalName) ? void 0 : { localName: canonicalName, needsImport: importStyle === "named" };
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export { DEFAULT_IMPORT_STYLE, IMPORT_STYLE_SCHEMA_PROPERTY, resolveTypeName };
|
|
29
|
+
//# sourceMappingURL=import-style.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-style.mjs","sources":["../../src/rules/import-style.mts"],"sourcesContent":["import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';\nimport { TS_TYPE_FORGE_MODULE } from './constants.mjs';\nimport {\n getImportedLocalName,\n getTsTypeForgeImports,\n hasConflictingDeclaration,\n} from './import-utils.mjs';\n\n/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */\n\n/** `JSONSchema4`, reached through the public rule-module types. */\ntype JsonSchema = Exclude<\n TSESLint.RuleModule<string, readonly unknown[]>['meta']['schema'],\n readonly unknown[]\n>;\n\nexport type ImportStyle = 'global' | 'named';\n\nexport const DEFAULT_IMPORT_STYLE: ImportStyle = 'named';\n\nexport const IMPORT_STYLE_SCHEMA_PROPERTY: JsonSchema = {\n type: 'string',\n enum: ['global', 'named'],\n description: [\n 'How the ts-type-forge type is brought into scope.',\n \"'named' (default) makes the autofix add the corresponding\",\n `\\`import { type … } from '${TS_TYPE_FORGE_MODULE}';\\``,\n \"when the name is not imported yet; 'global' assumes the\",\n 'ambient globals of `ts-type-forge/global` and never touches',\n 'imports.',\n ].join(' '),\n};\n\n/**\n * Resolves how a ts-type-forge type name should be written in this file, and\n * whether the fix has to add an import for it.\n *\n * Returns `undefined` when the name is already bound to something else (a local\n * alias, or an import from another module) — rewriting to it would then silently\n * resolve to the wrong declaration, which is exactly what happens inside\n * ts-type-forge's own sources.\n */\nexport const resolveTypeName = (\n program: TSESTree.Program,\n canonicalName: string,\n importStyle: ImportStyle,\n): Readonly<{ localName: string; needsImport: boolean }> | undefined => {\n const importedLocalName = getImportedLocalName(\n getTsTypeForgeImports(program),\n canonicalName,\n );\n\n if (importedLocalName !== undefined) {\n return { localName: importedLocalName, needsImport: false };\n }\n\n return hasConflictingDeclaration(program, canonicalName)\n ? undefined\n : { localName: canonicalName, needsImport: importStyle === 'named' };\n};\n"],"names":[],"mappings":";;;AAkBO,MAAM,oBAAA,GAAoC;AAE1C,MAAM,4BAAA,GAA2C;AAAA,EACtD,IAAA,EAAM,QAAA;AAAA,EACN,IAAA,EAAM,CAAC,QAAA,EAAU,OAAO,CAAA;AAAA,EACxB,WAAA,EAAa;AAAA,IACX,mDAAA;AAAA,IACA,2DAAA;AAAA,IACA,kCAA6B,oBAAoB,CAAA,IAAA,CAAA;AAAA,IACjD,yDAAA;AAAA,IACA,6DAAA;AAAA,IACA;AAAA,GACF,CAAE,KAAK,GAAG;AACZ;AAWO,MAAM,eAAA,GAAkB,CAC7B,OAAA,EACA,aAAA,EACA,WAAA,KACsE;AACtE,EAAA,MAAM,iBAAA,GAAoB,oBAAA;AAAA,IACxB,sBAAsB,OAAO,CAAA;AAAA,IAC7B;AAAA,GACF;AAEA,EAAA,IAAI,sBAAsB,MAAA,EAAW;AACnC,IAAA,OAAO,EAAE,SAAA,EAAW,iBAAA,EAAmB,WAAA,EAAa,KAAA,EAAM;AAAA,EAC5D;AAEA,EAAA,OAAO,yBAAA,CAA0B,OAAA,EAAS,aAAa,CAAA,GACnD,MAAA,GACA,EAAE,SAAA,EAAW,aAAA,EAAe,WAAA,EAAa,WAAA,KAAgB,OAAA,EAAQ;AACvE;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefer-canonical-length-constrained-tuple.d.mts","sourceRoot":"","sources":["../../src/rules/prefer-canonical-length-constrained-tuple.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"prefer-canonical-length-constrained-tuple.d.mts","sourceRoot":"","sources":["../../src/rules/prefer-canonical-length-constrained-tuple.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAiBzD,KAAK,OAAO,GAAG,SAAS;IACtB,QAAQ,CAAC;QACP,WAAW,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;QACjC,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ,CAAC;AAEF,KAAK,UAAU,GAAG,mBAAmB,CAAC;AAQtC,eAAO,MAAM,qCAAqC,EAAE,QAAQ,CAAC,UAAU,CACrE,UAAU,EACV,OAAO,CA6EC,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { analyzeUniformTuple } from './ast-utils.mjs';
|
|
2
2
|
import { DEFAULT_MAX_TUPLE_LENGTH, NON_EMPTY_TUPLE_TYPE_NAME, MUTABLE_NON_EMPTY_TUPLE_TYPE_NAME, MIN_LENGTH_TUPLE_TYPE_NAME, MUTABLE_MIN_LENGTH_TUPLE_TYPE_NAME, FIXED_LENGTH_TUPLE_TYPE_NAME, MUTABLE_FIXED_LENGTH_TUPLE_TYPE_NAME } from './constants.mjs';
|
|
3
|
-
import { DEFAULT_IMPORT_STYLE, IMPORT_STYLE_SCHEMA_PROPERTY
|
|
3
|
+
import { DEFAULT_IMPORT_STYLE, IMPORT_STYLE_SCHEMA_PROPERTY } from './import-style.mjs';
|
|
4
|
+
import { reportTupleRewrites } from './tuple-rule-utils.mjs';
|
|
4
5
|
|
|
5
6
|
const MIN_FIXED_LENGTH = 2;
|
|
6
7
|
const preferCanonicalLengthConstrainedTuple = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefer-canonical-length-constrained-tuple.mjs","sources":["../../src/rules/prefer-canonical-length-constrained-tuple.mts"],"sourcesContent":["import { type TSESLint } from '@typescript-eslint/utils';\nimport { analyzeUniformTuple, type UniformTupleShape } from './ast-utils.mjs';\nimport {\n DEFAULT_MAX_TUPLE_LENGTH,\n FIXED_LENGTH_TUPLE_TYPE_NAME,\n MIN_LENGTH_TUPLE_TYPE_NAME,\n MUTABLE_FIXED_LENGTH_TUPLE_TYPE_NAME,\n MUTABLE_MIN_LENGTH_TUPLE_TYPE_NAME,\n MUTABLE_NON_EMPTY_TUPLE_TYPE_NAME,\n NON_EMPTY_TUPLE_TYPE_NAME,\n} from './constants.mjs';\nimport {\n DEFAULT_IMPORT_STYLE,\n IMPORT_STYLE_SCHEMA_PROPERTY,\n
|
|
1
|
+
{"version":3,"file":"prefer-canonical-length-constrained-tuple.mjs","sources":["../../src/rules/prefer-canonical-length-constrained-tuple.mts"],"sourcesContent":["import { type TSESLint } from '@typescript-eslint/utils';\nimport { analyzeUniformTuple, type UniformTupleShape } from './ast-utils.mjs';\nimport {\n DEFAULT_MAX_TUPLE_LENGTH,\n FIXED_LENGTH_TUPLE_TYPE_NAME,\n MIN_LENGTH_TUPLE_TYPE_NAME,\n MUTABLE_FIXED_LENGTH_TUPLE_TYPE_NAME,\n MUTABLE_MIN_LENGTH_TUPLE_TYPE_NAME,\n MUTABLE_NON_EMPTY_TUPLE_TYPE_NAME,\n NON_EMPTY_TUPLE_TYPE_NAME,\n} from './constants.mjs';\nimport {\n DEFAULT_IMPORT_STYLE,\n IMPORT_STYLE_SCHEMA_PROPERTY,\n} from './import-style.mjs';\nimport { reportTupleRewrites, type TupleRewrite } from './tuple-rule-utils.mjs';\n\ntype Options = readonly [\n Readonly<{\n importStyle?: 'global' | 'named';\n maxLength?: number;\n }>?,\n];\n\ntype MessageIds = 'useCanonicalTuple';\n\n/**\n * A single fixed element without a rest (`[V]`) is left alone: it reads better\n * than `FixedLengthTuple<1, V>`.\n */\nconst MIN_FIXED_LENGTH = 2;\n\nexport const preferCanonicalLengthConstrainedTuple: TSESLint.RuleModule<\n MessageIds,\n Options\n> = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Replace uniform tuple spellings such as `[V, ...V[]]` / `[V, V, ...V[]]` / `[V, V, V]` with the canonical ts-type-forge tuple type.',\n },\n fixable: 'code',\n schema: [\n {\n type: 'object',\n properties: {\n importStyle: IMPORT_STYLE_SCHEMA_PROPERTY,\n maxLength: {\n type: 'integer',\n minimum: MIN_FIXED_LENGTH,\n description: [\n 'Longest tuple the rule rewrites (default',\n `${DEFAULT_MAX_TUPLE_LENGTH}).`,\n 'Longer tuples are usually spelled out on purpose, and the named',\n 'form stops being more readable.',\n ].join(' '),\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n useCanonicalTuple:\n 'Replace `{{original}}` with `{{replacement}}` from ts-type-forge.',\n },\n },\n\n create: (context) => {\n const sourceCode = context.sourceCode;\n\n const options = context.options[0];\n\n const importStyle = options?.importStyle ?? DEFAULT_IMPORT_STYLE;\n\n const maxLength = options?.maxLength ?? DEFAULT_MAX_TUPLE_LENGTH;\n\n const mut_rewrites: TupleRewrite[] = [];\n\n return {\n TSTupleType: (node) => {\n const shape = analyzeUniformTuple(node, sourceCode);\n\n if (shape === undefined || shape.fixedCount > maxLength) return;\n\n const canonicalName = canonicalNameFor(shape);\n\n if (canonicalName === undefined) return;\n\n mut_rewrites.push({\n node: shape.node,\n canonicalName,\n typeArgs:\n shape.fixedCount === 1\n ? shape.elementText\n : `${shape.fixedCount}, ${shape.elementText}`,\n });\n },\n 'Program:exit': () => {\n reportTupleRewrites(\n context,\n mut_rewrites,\n 'useCanonicalTuple',\n importStyle,\n );\n },\n };\n },\n defaultOptions: [\n { importStyle: DEFAULT_IMPORT_STYLE, maxLength: DEFAULT_MAX_TUPLE_LENGTH },\n ],\n} as const;\n\n/**\n * The ts-type-forge type a given tuple shape spells out, or `undefined` when the\n * shape is deliberately left alone.\n *\n * | shape | readonly | mutable |\n * | :-------------------- | :------------------ | :------------------------- |\n * | `[V, ...V[]]` | `NonEmptyTuple` | `MutableNonEmptyTuple` |\n * | `[V, …×N, ...V[]]` | `MinLengthTuple` | `MutableMinLengthTuple` |\n * | `[V, …×N]` (N >= 2) | `FixedLengthTuple` | `MutableFixedLengthTuple` |\n */\nconst canonicalNameFor = (\n // `UniformTupleShape` carries a `TSESTree.Node`, which is not deeply readonly.\n // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types\n shape: UniformTupleShape,\n): string | undefined => {\n const { isReadonly, hasRest, fixedCount } = shape;\n\n if (hasRest) {\n if (fixedCount === 1) {\n return isReadonly\n ? NON_EMPTY_TUPLE_TYPE_NAME\n : MUTABLE_NON_EMPTY_TUPLE_TYPE_NAME;\n }\n\n return isReadonly\n ? MIN_LENGTH_TUPLE_TYPE_NAME\n : MUTABLE_MIN_LENGTH_TUPLE_TYPE_NAME;\n }\n\n if (fixedCount < MIN_FIXED_LENGTH) return undefined;\n\n return isReadonly\n ? FIXED_LENGTH_TUPLE_TYPE_NAME\n : MUTABLE_FIXED_LENGTH_TUPLE_TYPE_NAME;\n};\n"],"names":[],"mappings":";;;;;AA8BA,MAAM,gBAAA,GAAmB,CAAA;AAElB,MAAM,qCAAA,GAGT;AAAA,EACF,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,YAAA;AAAA,IACN,IAAA,EAAM;AAAA,MACJ,WAAA,EACE;AAAA,KACJ;AAAA,IACA,OAAA,EAAS,MAAA;AAAA,IACT,MAAA,EAAQ;AAAA,MACN;AAAA,QACE,IAAA,EAAM,QAAA;AAAA,QACN,UAAA,EAAY;AAAA,UACV,WAAA,EAAa,4BAAA;AAAA,UACb,SAAA,EAAW;AAAA,YACT,IAAA,EAAM,SAAA;AAAA,YACN,OAAA,EAAS,gBAAA;AAAA,YACT,WAAA,EAAa;AAAA,cACX,0CAAA;AAAA,cACA,GAAG,wBAAwB,CAAA,EAAA,CAAA;AAAA,cAC3B,iEAAA;AAAA,cACA;AAAA,aACF,CAAE,KAAK,GAAG;AAAA;AACZ,SACF;AAAA,QACA,oBAAA,EAAsB;AAAA;AACxB,KACF;AAAA,IACA,QAAA,EAAU;AAAA,MACR,iBAAA,EACE;AAAA;AACJ,GACF;AAAA,EAEA,MAAA,EAAQ,CAAC,OAAA,KAAY;AACnB,IAAA,MAAM,aAAa,OAAA,CAAQ,UAAA;AAE3B,IAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,CAAQ,CAAC,CAAA;AAEjC,IAAA,MAAM,WAAA,GAAc,SAAS,WAAA,IAAe,oBAAA;AAE5C,IAAA,MAAM,SAAA,GAAY,SAAS,SAAA,IAAa,wBAAA;AAExC,IAAA,MAAM,eAA+B,EAAC;AAEtC,IAAA,OAAO;AAAA,MACL,WAAA,EAAa,CAAC,IAAA,KAAS;AACrB,QAAA,MAAM,KAAA,GAAQ,mBAAA,CAAoB,IAAA,EAAM,UAAU,CAAA;AAElD,QAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,CAAM,UAAA,GAAa,SAAA,EAAW;AAEzD,QAAA,MAAM,aAAA,GAAgB,iBAAiB,KAAK,CAAA;AAE5C,QAAA,IAAI,kBAAkB,MAAA,EAAW;AAEjC,QAAA,YAAA,CAAa,IAAA,CAAK;AAAA,UAChB,MAAM,KAAA,CAAM,IAAA;AAAA,UACZ,aAAA;AAAA,UACA,QAAA,EACE,KAAA,CAAM,UAAA,KAAe,CAAA,GACjB,KAAA,CAAM,WAAA,GACN,CAAA,EAAG,KAAA,CAAM,UAAU,CAAA,EAAA,EAAK,KAAA,CAAM,WAAW,CAAA;AAAA,SAChD,CAAA;AAAA,MACH,CAAA;AAAA,MACA,gBAAgB,MAAM;AACpB,QAAA,mBAAA;AAAA,UACE,OAAA;AAAA,UACA,YAAA;AAAA,UACA,mBAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAAA,KACF;AAAA,EACF,CAAA;AAAA,EACA,cAAA,EAAgB;AAAA,IACd,EAAE,WAAA,EAAa,oBAAA,EAAsB,SAAA,EAAW,wBAAA;AAAyB;AAE7E;AAYA,MAAM,gBAAA,GAAmB,CAGvB,KAAA,KACuB;AACvB,EAAA,MAAM,EAAE,UAAA,EAAY,OAAA,EAAS,UAAA,EAAW,GAAI,KAAA;AAE5C,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,IAAI,eAAe,CAAA,EAAG;AACpB,MAAA,OAAO,aACH,yBAAA,GACA,iCAAA;AAAA,IACN;AAEA,IAAA,OAAO,aACH,0BAAA,GACA,kCAAA;AAAA,EACN;AAEA,EAAA,IAAI,UAAA,GAAa,kBAAkB,OAAO,MAAA;AAE1C,EAAA,OAAO,aACH,4BAAA,GACA,oCAAA;AACN,CAAA;;;;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
type Options = readonly [
|
|
3
|
+
Readonly<{
|
|
4
|
+
importStyle?: 'global' | 'named';
|
|
5
|
+
}>?
|
|
6
|
+
];
|
|
7
|
+
type MessageIds = 'useReadonlyOrMutableRecord' | 'replaceWith';
|
|
8
|
+
export declare const preferReadonlyOrMutableRecord: TSESLint.RuleModule<MessageIds, Options>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=prefer-readonly-or-mutable-record.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefer-readonly-or-mutable-record.d.mts","sourceRoot":"","sources":["../../src/rules/prefer-readonly-or-mutable-record.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAUzD,KAAK,OAAO,GAAG,SAAS;IACtB,QAAQ,CAAC;QACP,WAAW,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;KAClC,CAAC,CAAC;CACJ,CAAC;AAEF,KAAK,UAAU,GAAG,4BAA4B,GAAG,aAAa,CAAC;AAW/D,eAAO,MAAM,6BAA6B,EAAE,QAAQ,CAAC,UAAU,CAC7D,UAAU,EACV,OAAO,CA4CC,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { DEFAULT_IMPORT_STYLE, IMPORT_STYLE_SCHEMA_PROPERTY } from './import-style.mjs';
|
|
2
|
+
import { reportStdTypeReference } from './std-type-rule-utils.mjs';
|
|
3
|
+
|
|
4
|
+
const ALTERNATIVES = /* @__PURE__ */ new Map([
|
|
5
|
+
["Record", ["ReadonlyRecord", "MutableRecord"]]
|
|
6
|
+
]);
|
|
7
|
+
const preferReadonlyOrMutableRecord = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "suggestion",
|
|
10
|
+
docs: {
|
|
11
|
+
description: "Replace the built-in `Record` with the ts-type-forge `ReadonlyRecord` or `MutableRecord`, so that the mutability of the record is stated rather than implied."
|
|
12
|
+
},
|
|
13
|
+
hasSuggestions: true,
|
|
14
|
+
schema: [
|
|
15
|
+
{
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
importStyle: IMPORT_STYLE_SCHEMA_PROPERTY
|
|
19
|
+
},
|
|
20
|
+
additionalProperties: false
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
messages: {
|
|
24
|
+
useReadonlyOrMutableRecord: "Use {{alternatives}} from ts-type-forge instead of the built-in `{{name}}`.",
|
|
25
|
+
replaceWith: "Replace `{{name}}` with `{{replacement}}`."
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
create: (context) => {
|
|
29
|
+
const importStyle = context.options[0]?.importStyle ?? DEFAULT_IMPORT_STYLE;
|
|
30
|
+
return {
|
|
31
|
+
TSTypeReference: (node) => {
|
|
32
|
+
reportStdTypeReference(
|
|
33
|
+
context,
|
|
34
|
+
node,
|
|
35
|
+
ALTERNATIVES,
|
|
36
|
+
{
|
|
37
|
+
report: "useReadonlyOrMutableRecord",
|
|
38
|
+
suggestion: "replaceWith"
|
|
39
|
+
},
|
|
40
|
+
importStyle
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
defaultOptions: [{ importStyle: DEFAULT_IMPORT_STYLE }]
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export { preferReadonlyOrMutableRecord };
|
|
49
|
+
//# sourceMappingURL=prefer-readonly-or-mutable-record.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefer-readonly-or-mutable-record.mjs","sources":["../../src/rules/prefer-readonly-or-mutable-record.mts"],"sourcesContent":["import { type TSESLint } from '@typescript-eslint/utils';\nimport {\n DEFAULT_IMPORT_STYLE,\n IMPORT_STYLE_SCHEMA_PROPERTY,\n} from './import-style.mjs';\nimport {\n reportStdTypeReference,\n type StdTypeAlternatives,\n} from './std-type-rule-utils.mjs';\n\ntype Options = readonly [\n Readonly<{\n importStyle?: 'global' | 'named';\n }>?,\n];\n\ntype MessageIds = 'useReadonlyOrMutableRecord' | 'replaceWith';\n\n/**\n * `Record` says nothing about whether the properties may be reassigned, so the\n * mutability of every record type spelled with it is decided by whoever reads\n * it. The ts-type-forge pair spells it out.\n */\nconst ALTERNATIVES: StdTypeAlternatives = new Map([\n ['Record', ['ReadonlyRecord', 'MutableRecord']],\n]);\n\nexport const preferReadonlyOrMutableRecord: TSESLint.RuleModule<\n MessageIds,\n Options\n> = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Replace the built-in `Record` with the ts-type-forge `ReadonlyRecord` or `MutableRecord`, so that the mutability of the record is stated rather than implied.',\n },\n hasSuggestions: true,\n schema: [\n {\n type: 'object',\n properties: {\n importStyle: IMPORT_STYLE_SCHEMA_PROPERTY,\n },\n additionalProperties: false,\n },\n ],\n messages: {\n useReadonlyOrMutableRecord:\n 'Use {{alternatives}} from ts-type-forge instead of the built-in `{{name}}`.',\n replaceWith: 'Replace `{{name}}` with `{{replacement}}`.',\n },\n },\n\n create: (context) => {\n const importStyle = context.options[0]?.importStyle ?? DEFAULT_IMPORT_STYLE;\n\n return {\n TSTypeReference: (node) => {\n reportStdTypeReference(\n context,\n node,\n ALTERNATIVES,\n {\n report: 'useReadonlyOrMutableRecord',\n suggestion: 'replaceWith',\n },\n importStyle,\n );\n },\n };\n },\n defaultOptions: [{ importStyle: DEFAULT_IMPORT_STYLE }],\n} as const;\n"],"names":[],"mappings":";;;AAuBA,MAAM,YAAA,uBAAwC,GAAA,CAAI;AAAA,EAChD,CAAC,QAAA,EAAU,CAAC,gBAAA,EAAkB,eAAe,CAAC;AAChD,CAAC,CAAA;AAEM,MAAM,6BAAA,GAGT;AAAA,EACF,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,YAAA;AAAA,IACN,IAAA,EAAM;AAAA,MACJ,WAAA,EACE;AAAA,KACJ;AAAA,IACA,cAAA,EAAgB,IAAA;AAAA,IAChB,MAAA,EAAQ;AAAA,MACN;AAAA,QACE,IAAA,EAAM,QAAA;AAAA,QACN,UAAA,EAAY;AAAA,UACV,WAAA,EAAa;AAAA,SACf;AAAA,QACA,oBAAA,EAAsB;AAAA;AACxB,KACF;AAAA,IACA,QAAA,EAAU;AAAA,MACR,0BAAA,EACE,6EAAA;AAAA,MACF,WAAA,EAAa;AAAA;AACf,GACF;AAAA,EAEA,MAAA,EAAQ,CAAC,OAAA,KAAY;AACnB,IAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,OAAA,CAAQ,CAAC,GAAG,WAAA,IAAe,oBAAA;AAEvD,IAAA,OAAO;AAAA,MACL,eAAA,EAAiB,CAAC,IAAA,KAAS;AACzB,QAAA,sBAAA;AAAA,UACE,OAAA;AAAA,UACA,IAAA;AAAA,UACA,YAAA;AAAA,UACA;AAAA,YACE,MAAA,EAAQ,4BAAA;AAAA,YACR,UAAA,EAAY;AAAA,WACd;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAAA,KACF;AAAA,EACF,CAAA;AAAA,EACA,cAAA,EAAgB,CAAC,EAAE,WAAA,EAAa,sBAAsB;AACxD;;;;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
type Options = readonly [
|
|
3
|
+
Readonly<{
|
|
4
|
+
importStyle?: 'global' | 'named';
|
|
5
|
+
}>?
|
|
6
|
+
];
|
|
7
|
+
type MessageIds = 'useStrictOrRelaxed' | 'replaceWith';
|
|
8
|
+
export declare const preferStrictOrRelaxedUtilityType: TSESLint.RuleModule<MessageIds, Options>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=prefer-strict-or-relaxed-utility-type.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefer-strict-or-relaxed-utility-type.d.mts","sourceRoot":"","sources":["../../src/rules/prefer-strict-or-relaxed-utility-type.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAUzD,KAAK,OAAO,GAAG,SAAS;IACtB,QAAQ,CAAC;QACP,WAAW,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;KAClC,CAAC,CAAC;CACJ,CAAC;AAEF,KAAK,UAAU,GAAG,oBAAoB,GAAG,aAAa,CAAC;AAoBvD,eAAO,MAAM,gCAAgC,EAAE,QAAQ,CAAC,UAAU,CAChE,UAAU,EACV,OAAO,CAyCC,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { DEFAULT_IMPORT_STYLE, IMPORT_STYLE_SCHEMA_PROPERTY } from './import-style.mjs';
|
|
2
|
+
import { reportStdTypeReference } from './std-type-rule-utils.mjs';
|
|
3
|
+
|
|
4
|
+
const ALTERNATIVES = /* @__PURE__ */ new Map([
|
|
5
|
+
["Exclude", ["StrictExclude", "RelaxedExclude"]],
|
|
6
|
+
["Extract", ["StrictExtract", "RelaxedExtract"]],
|
|
7
|
+
["Omit", ["StrictOmit", "RelaxedOmit"]],
|
|
8
|
+
["Pick", ["StrictPick", "RelaxedPick"]]
|
|
9
|
+
]);
|
|
10
|
+
const preferStrictOrRelaxedUtilityType = {
|
|
11
|
+
meta: {
|
|
12
|
+
type: "suggestion",
|
|
13
|
+
docs: {
|
|
14
|
+
description: "Replace the built-in `Exclude` / `Extract` / `Omit` / `Pick` with the ts-type-forge `Strict*` or `Relaxed*` counterpart, so that the unchecked second argument becomes an explicit choice."
|
|
15
|
+
},
|
|
16
|
+
hasSuggestions: true,
|
|
17
|
+
schema: [
|
|
18
|
+
{
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
importStyle: IMPORT_STYLE_SCHEMA_PROPERTY
|
|
22
|
+
},
|
|
23
|
+
additionalProperties: false
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
messages: {
|
|
27
|
+
useStrictOrRelaxed: "Use {{alternatives}} from ts-type-forge instead of the built-in `{{name}}`.",
|
|
28
|
+
replaceWith: "Replace `{{name}}` with `{{replacement}}`."
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
create: (context) => {
|
|
32
|
+
const importStyle = context.options[0]?.importStyle ?? DEFAULT_IMPORT_STYLE;
|
|
33
|
+
return {
|
|
34
|
+
TSTypeReference: (node) => {
|
|
35
|
+
reportStdTypeReference(
|
|
36
|
+
context,
|
|
37
|
+
node,
|
|
38
|
+
ALTERNATIVES,
|
|
39
|
+
{ report: "useStrictOrRelaxed", suggestion: "replaceWith" },
|
|
40
|
+
importStyle
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
defaultOptions: [{ importStyle: DEFAULT_IMPORT_STYLE }]
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export { preferStrictOrRelaxedUtilityType };
|
|
49
|
+
//# sourceMappingURL=prefer-strict-or-relaxed-utility-type.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefer-strict-or-relaxed-utility-type.mjs","sources":["../../src/rules/prefer-strict-or-relaxed-utility-type.mts"],"sourcesContent":["import { type TSESLint } from '@typescript-eslint/utils';\nimport {\n DEFAULT_IMPORT_STYLE,\n IMPORT_STYLE_SCHEMA_PROPERTY,\n} from './import-style.mjs';\nimport {\n reportStdTypeReference,\n type StdTypeAlternatives,\n} from './std-type-rule-utils.mjs';\n\ntype Options = readonly [\n Readonly<{\n importStyle?: 'global' | 'named';\n }>?,\n];\n\ntype MessageIds = 'useStrictOrRelaxed' | 'replaceWith';\n\n/**\n * The standard-library types whose second argument is unchecked, and the\n * ts-type-forge pair that makes the choice explicit.\n *\n * `Strict*` constrains the second argument (`U extends T` / `K extends keyof T`),\n * so a key that does not exist — typically a leftover after a rename — is a\n * compile error instead of a silently empty result. `Relaxed*` keeps the\n * standard-library behavior for the cases that genuinely need it (a subtrahend\n * that is not provably part of the union, a key set computed from a still\n * deferred type parameter).\n */\nconst ALTERNATIVES: StdTypeAlternatives = new Map([\n ['Exclude', ['StrictExclude', 'RelaxedExclude']],\n ['Extract', ['StrictExtract', 'RelaxedExtract']],\n ['Omit', ['StrictOmit', 'RelaxedOmit']],\n ['Pick', ['StrictPick', 'RelaxedPick']],\n]);\n\nexport const preferStrictOrRelaxedUtilityType: TSESLint.RuleModule<\n MessageIds,\n Options\n> = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Replace the built-in `Exclude` / `Extract` / `Omit` / `Pick` with the ts-type-forge `Strict*` or `Relaxed*` counterpart, so that the unchecked second argument becomes an explicit choice.',\n },\n hasSuggestions: true,\n schema: [\n {\n type: 'object',\n properties: {\n importStyle: IMPORT_STYLE_SCHEMA_PROPERTY,\n },\n additionalProperties: false,\n },\n ],\n messages: {\n useStrictOrRelaxed:\n 'Use {{alternatives}} from ts-type-forge instead of the built-in `{{name}}`.',\n replaceWith: 'Replace `{{name}}` with `{{replacement}}`.',\n },\n },\n\n create: (context) => {\n const importStyle = context.options[0]?.importStyle ?? DEFAULT_IMPORT_STYLE;\n\n return {\n TSTypeReference: (node) => {\n reportStdTypeReference(\n context,\n node,\n ALTERNATIVES,\n { report: 'useStrictOrRelaxed', suggestion: 'replaceWith' },\n importStyle,\n );\n },\n };\n },\n defaultOptions: [{ importStyle: DEFAULT_IMPORT_STYLE }],\n} as const;\n"],"names":[],"mappings":";;;AA6BA,MAAM,YAAA,uBAAwC,GAAA,CAAI;AAAA,EAChD,CAAC,SAAA,EAAW,CAAC,eAAA,EAAiB,gBAAgB,CAAC,CAAA;AAAA,EAC/C,CAAC,SAAA,EAAW,CAAC,eAAA,EAAiB,gBAAgB,CAAC,CAAA;AAAA,EAC/C,CAAC,MAAA,EAAQ,CAAC,YAAA,EAAc,aAAa,CAAC,CAAA;AAAA,EACtC,CAAC,MAAA,EAAQ,CAAC,YAAA,EAAc,aAAa,CAAC;AACxC,CAAC,CAAA;AAEM,MAAM,gCAAA,GAGT;AAAA,EACF,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,YAAA;AAAA,IACN,IAAA,EAAM;AAAA,MACJ,WAAA,EACE;AAAA,KACJ;AAAA,IACA,cAAA,EAAgB,IAAA;AAAA,IAChB,MAAA,EAAQ;AAAA,MACN;AAAA,QACE,IAAA,EAAM,QAAA;AAAA,QACN,UAAA,EAAY;AAAA,UACV,WAAA,EAAa;AAAA,SACf;AAAA,QACA,oBAAA,EAAsB;AAAA;AACxB,KACF;AAAA,IACA,QAAA,EAAU;AAAA,MACR,kBAAA,EACE,6EAAA;AAAA,MACF,WAAA,EAAa;AAAA;AACf,GACF;AAAA,EAEA,MAAA,EAAQ,CAAC,OAAA,KAAY;AACnB,IAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,OAAA,CAAQ,CAAC,GAAG,WAAA,IAAe,oBAAA;AAEvD,IAAA,OAAO;AAAA,MACL,eAAA,EAAiB,CAAC,IAAA,KAAS;AACzB,QAAA,sBAAA;AAAA,UACE,OAAA;AAAA,UACA,IAAA;AAAA,UACA,YAAA;AAAA,UACA,EAAE,MAAA,EAAQ,oBAAA,EAAsB,UAAA,EAAY,aAAA,EAAc;AAAA,UAC1D;AAAA,SACF;AAAA,MACF;AAAA,KACF;AAAA,EACF,CAAA;AAAA,EACA,cAAA,EAAgB,CAAC,EAAE,WAAA,EAAa,sBAAsB;AACxD;;;;"}
|
package/dist/rules/rules.d.mts
CHANGED
|
@@ -3,5 +3,11 @@ export declare const tsTypeForgeRules: {
|
|
|
3
3
|
importStyle?: 'global' | 'named';
|
|
4
4
|
maxLength?: number;
|
|
5
5
|
}> | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
6
|
+
readonly 'prefer-readonly-or-mutable-record': import("@typescript-eslint/utils/ts-eslint").RuleModule<"replaceWith" | "useReadonlyOrMutableRecord", readonly [(Readonly<{
|
|
7
|
+
importStyle?: 'global' | 'named';
|
|
8
|
+
}> | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
9
|
+
readonly 'prefer-strict-or-relaxed-utility-type': import("@typescript-eslint/utils/ts-eslint").RuleModule<"replaceWith" | "useStrictOrRelaxed", readonly [(Readonly<{
|
|
10
|
+
importStyle?: 'global' | 'named';
|
|
11
|
+
}> | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
6
12
|
};
|
|
7
13
|
//# sourceMappingURL=rules.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.mts","sourceRoot":"","sources":["../../src/rules/rules.mts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rules.d.mts","sourceRoot":"","sources":["../../src/rules/rules.mts"],"names":[],"mappings":"AAKA,eAAO,MAAM,gBAAgB;;;;;;;;;;;CAKa,CAAC"}
|
package/dist/rules/rules.mjs
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { preferCanonicalLengthConstrainedTuple } from './prefer-canonical-length-constrained-tuple.mjs';
|
|
2
|
+
import { preferReadonlyOrMutableRecord } from './prefer-readonly-or-mutable-record.mjs';
|
|
3
|
+
import { preferStrictOrRelaxedUtilityType } from './prefer-strict-or-relaxed-utility-type.mjs';
|
|
2
4
|
|
|
3
5
|
const tsTypeForgeRules = {
|
|
4
|
-
"prefer-canonical-length-constrained-tuple": preferCanonicalLengthConstrainedTuple
|
|
6
|
+
"prefer-canonical-length-constrained-tuple": preferCanonicalLengthConstrainedTuple,
|
|
7
|
+
"prefer-readonly-or-mutable-record": preferReadonlyOrMutableRecord,
|
|
8
|
+
"prefer-strict-or-relaxed-utility-type": preferStrictOrRelaxedUtilityType
|
|
5
9
|
};
|
|
6
10
|
|
|
7
11
|
export { tsTypeForgeRules };
|
package/dist/rules/rules.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.mjs","sources":["../../src/rules/rules.mts"],"sourcesContent":["import { type ESLintPlugin } from '../types.mjs';\nimport { preferCanonicalLengthConstrainedTuple } from './prefer-canonical-length-constrained-tuple.mjs';\n\nexport const tsTypeForgeRules = {\n 'prefer-canonical-length-constrained-tuple':\n preferCanonicalLengthConstrainedTuple,\n} as const satisfies ESLintPlugin['rules'];\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rules.mjs","sources":["../../src/rules/rules.mts"],"sourcesContent":["import { type ESLintPlugin } from '../types.mjs';\nimport { preferCanonicalLengthConstrainedTuple } from './prefer-canonical-length-constrained-tuple.mjs';\nimport { preferReadonlyOrMutableRecord } from './prefer-readonly-or-mutable-record.mjs';\nimport { preferStrictOrRelaxedUtilityType } from './prefer-strict-or-relaxed-utility-type.mjs';\n\nexport const tsTypeForgeRules = {\n 'prefer-canonical-length-constrained-tuple':\n preferCanonicalLengthConstrainedTuple,\n 'prefer-readonly-or-mutable-record': preferReadonlyOrMutableRecord,\n 'prefer-strict-or-relaxed-utility-type': preferStrictOrRelaxedUtilityType,\n} as const satisfies ESLintPlugin['rules'];\n"],"names":[],"mappings":";;;;AAKO,MAAM,gBAAA,GAAmB;AAAA,EAC9B,2CAAA,EACE,qCAAA;AAAA,EACF,mCAAA,EAAqC,6BAAA;AAAA,EACrC,uCAAA,EAAyC;AAC3C;;;;"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
import { type ImportStyle } from './import-style.mjs';
|
|
3
|
+
/**
|
|
4
|
+
* The ts-type-forge replacements offered for one standard-library type, in the
|
|
5
|
+
* order they are suggested.
|
|
6
|
+
*/
|
|
7
|
+
export type StdTypeAlternatives = ReadonlyMap<string, readonly string[]>;
|
|
8
|
+
/**
|
|
9
|
+
* Reports a reference to a banned standard-library type and offers one
|
|
10
|
+
* suggestion per ts-type-forge alternative.
|
|
11
|
+
*
|
|
12
|
+
* Choosing between the alternatives is a semantic decision — `StrictExclude`
|
|
13
|
+
* additionally checks that the subtrahend is part of the union, `ReadonlyRecord`
|
|
14
|
+
* and `MutableRecord` describe different types — so this is deliberately *not*
|
|
15
|
+
* an autofix. Each suggestion carries its own import fix, which is safe because
|
|
16
|
+
* ESLint applies suggestions one at a time.
|
|
17
|
+
*/
|
|
18
|
+
export declare const reportStdTypeReference: <MessageIds extends string>(context: TSESLint.RuleContext<MessageIds, readonly unknown[]>, node: TSESTree.TSTypeReference, alternatives: StdTypeAlternatives, messageIds: Readonly<{
|
|
19
|
+
report: MessageIds;
|
|
20
|
+
suggestion: MessageIds;
|
|
21
|
+
}>, importStyle: ImportStyle) => void;
|
|
22
|
+
//# sourceMappingURL=std-type-rule-utils.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"std-type-rule-utils.d.mts","sourceRoot":"","sources":["../../src/rules/std-type-rule-utils.mts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,QAAQ,EACd,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKvE;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;AAEzE;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,GAAI,UAAU,SAAS,MAAM,WACrD,QAAQ,CAAC,WAAW,CAAC,UAAU,EAAE,SAAS,OAAO,EAAE,CAAC,QACvD,QAAQ,CAAC,eAAe,gBAChB,mBAAmB,cACrB,QAAQ,CAAC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,CAAC,eACvD,WAAW,KACvB,IA4CF,CAAC"}
|