eslint-plugin-ts-fortress 1.1.0 → 1.2.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 +83 -4
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/plugin.d.mts +5 -0
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin.mjs +32 -28
- package/dist/plugin.mjs.map +1 -1
- package/dist/rule-types.d.mts +43 -0
- package/dist/rule-types.d.mts.map +1 -1
- package/dist/rule-types.mjs +2 -1
- package/dist/rule-types.mjs.map +1 -1
- package/dist/rules/constants.mjs +17 -12
- package/dist/rules/constants.mjs.map +1 -1
- package/dist/rules/import-utils.mjs +96 -52
- package/dist/rules/import-utils.mjs.map +1 -1
- package/dist/rules/index.mjs +2 -2
- package/dist/rules/index.mjs.map +1 -1
- package/dist/rules/prefer-canonical-length-constrained-type.mjs +226 -157
- package/dist/rules/prefer-canonical-length-constrained-type.mjs.map +1 -1
- package/dist/rules/prefer-namespace-import.mjs +201 -149
- package/dist/rules/prefer-namespace-import.mjs.map +1 -1
- package/dist/rules/prefer-schema-over-guard-chain.d.mts +56 -0
- package/dist/rules/prefer-schema-over-guard-chain.d.mts.map +1 -0
- package/dist/rules/prefer-schema-over-guard-chain.mjs +212 -0
- package/dist/rules/prefer-schema-over-guard-chain.mjs.map +1 -0
- package/dist/rules/rules.d.mts +4 -0
- package/dist/rules/rules.d.mts.map +1 -1
- package/dist/rules/rules.mjs +6 -7
- package/dist/rules/rules.mjs.map +1 -1
- package/dist/types.mjs +2 -2
- package/dist/types.mjs.map +1 -1
- package/package.json +6 -7
- package/src/plugin.mts +1 -0
- package/src/rule-types.mts +50 -0
- package/src/rules/prefer-schema-over-guard-chain.mts +257 -0
- package/src/rules/prefer-schema-over-guard-chain.test.mts +143 -0
- package/src/rules/rules.mts +2 -0
package/README.md
CHANGED
|
@@ -67,10 +67,11 @@ export default [
|
|
|
67
67
|
|
|
68
68
|
## Rules
|
|
69
69
|
|
|
70
|
-
| Rule | Description
|
|
71
|
-
| :----------------------------------------- |
|
|
72
|
-
| `prefer-canonical-length-constrained-type` | Normalize a length-constrained array combinator with degenerate bounds to its canonical form.
|
|
73
|
-
| `prefer-namespace-import` | Require `ts-fortress` to be imported as a namespace rather than by name.
|
|
70
|
+
| Rule | Description |
|
|
71
|
+
| :----------------------------------------- | :--------------------------------------------------------------------------------------------- |
|
|
72
|
+
| `prefer-canonical-length-constrained-type` | Normalize a length-constrained array combinator with degenerate bounds to its canonical form. |
|
|
73
|
+
| `prefer-namespace-import` | Require `ts-fortress` to be imported as a namespace rather than by name. |
|
|
74
|
+
| `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. |
|
|
74
75
|
|
|
75
76
|
### `prefer-canonical-length-constrained-type`
|
|
76
77
|
|
|
@@ -216,6 +217,84 @@ completed safely:
|
|
|
216
217
|
- the file has two namespace imports of `ts-fortress`, or one declaration that
|
|
217
218
|
mixes a namespace specifier with a named or default one.
|
|
218
219
|
|
|
220
|
+
### `prefer-schema-over-guard-chain`
|
|
221
|
+
|
|
222
|
+
A long chain of hand-written type guards is a shape declaration that cannot be
|
|
223
|
+
read as one:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
// ❌
|
|
227
|
+
const isProject = (value: unknown): value is Project =>
|
|
228
|
+
isRecord(value) &&
|
|
229
|
+
hasKey(value, 'name') &&
|
|
230
|
+
isString(value.name) &&
|
|
231
|
+
hasKey(value, 'path') &&
|
|
232
|
+
isString(value.path);
|
|
233
|
+
|
|
234
|
+
// ✅
|
|
235
|
+
const PROJECT = t.record({ name: t.string(), path: t.string() });
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The length is the least of it. What the chain cannot do is say what was wrong:
|
|
239
|
+
it returns `false`, so the caller filtering on it drops the value silently, with
|
|
240
|
+
nothing left of which field was missing or what type it turned out to be. The
|
|
241
|
+
shape is declared and checked in the same breath, so it cannot be named, reused,
|
|
242
|
+
or read on its own. `validate` returns structured `ValidationError`s, ready for
|
|
243
|
+
`validationErrorsToMessages`.
|
|
244
|
+
|
|
245
|
+
The rule reports; there is no fix. Writing the schema is the work, and it is not
|
|
246
|
+
mechanical — the chain says what the value must _have_, never what it _is_, so
|
|
247
|
+
an optional member, a union, and a member that is simply never checked are
|
|
248
|
+
indistinguishable from the guards alone.
|
|
249
|
+
|
|
250
|
+
#### What is counted
|
|
251
|
+
|
|
252
|
+
Guards within one `&&` chain, or one `||` chain of negated guards — the
|
|
253
|
+
early-return spelling of the same check — grouped by the identifier their first
|
|
254
|
+
argument is rooted at, so `hasKey(a, 'b')` and `isString(a.b)` count together
|
|
255
|
+
while guards on two different values do not add up.
|
|
256
|
+
|
|
257
|
+
A whole function body is deliberately not the unit. The same value checked once
|
|
258
|
+
per field across a `fill`-style function is a series of defaults rather than a
|
|
259
|
+
shape check, and measuring both units over one repository showed those to be
|
|
260
|
+
almost all of what a function-scoped count reports.
|
|
261
|
+
|
|
262
|
+
#### Options
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
'ts-fortress/prefer-schema-over-guard-chain': ['error', { threshold: 4 }],
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
- `threshold` (default `5`) — how many guards on one value a single chain may
|
|
269
|
+
contain before it is reported.
|
|
270
|
+
- `guards` (default: the `ts-data-forge` narrowing helpers — `hasKey`,
|
|
271
|
+
`isRecord`, `isString`, `isNumber`, `isBoolean`, `isBigint`, `isSymbol`,
|
|
272
|
+
`isArray`, `isNonEmpty`, `isNonNullish`, `isNotNull`, `isNotUndefined`,
|
|
273
|
+
`isPrimitive`) — the names to count, replacing the default list. A member call
|
|
274
|
+
is matched on its property name, so `Arr.isArray` is named `isArray`.
|
|
275
|
+
|
|
276
|
+
The default threshold comes from a distribution rather than from taste. Counted
|
|
277
|
+
over the 3420 files of the repository this rule was written in, as they stood
|
|
278
|
+
before it was applied to them:
|
|
279
|
+
|
|
280
|
+
| guards | chains |
|
|
281
|
+
| -----: | -----: |
|
|
282
|
+
| 1 | 103 |
|
|
283
|
+
| 2 | 41 |
|
|
284
|
+
| 3 | 17 |
|
|
285
|
+
| 4 | 1 |
|
|
286
|
+
| 5 | 1 |
|
|
287
|
+
| 6+ | 0 |
|
|
288
|
+
|
|
289
|
+
One and two are ordinary narrowing and reporting them would be noise; three is
|
|
290
|
+
still common enough to be a style rather than a smell. Four and five have one
|
|
291
|
+
chain each, and they differ in exactly the way the threshold has to: the chain
|
|
292
|
+
of four narrows a value that is already typed, which is the case this rule is
|
|
293
|
+
least interested in, while the chain of five narrows the result of a
|
|
294
|
+
`JSON.parse` — the case it exists for. So the default sits between them, at the
|
|
295
|
+
length of the chain that prompted the rule. That chain of five is the one site
|
|
296
|
+
the rule reported when it was turned on, and it has since been rewritten.
|
|
297
|
+
|
|
219
298
|
## License
|
|
220
299
|
|
|
221
300
|
[Apache-2.0](https://github.com/noshiro-pf/mono/blob/main/libs/eslint-plugin-ts-fortress/LICENSE)
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { eslintPluginTsFortress } from './plugin.mjs';
|
|
2
|
-
export { tsFortressRules } from './rules/
|
|
3
|
-
//# sourceMappingURL=index.mjs.map
|
|
2
|
+
export { tsFortressRules } from './rules/index.mjs';
|
|
3
|
+
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAKtD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/plugin.d.mts
CHANGED
|
@@ -8,6 +8,10 @@ export declare const eslintPluginTsFortress: {
|
|
|
8
8
|
readonly 'prefer-namespace-import': import("@typescript-eslint/utils/ts-eslint").RuleModule<"removeSideEffectImport" | "useNamespaceImport", readonly [(Readonly<{
|
|
9
9
|
namespaceName?: string;
|
|
10
10
|
}> | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
11
|
+
readonly 'prefer-schema-over-guard-chain': import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferSchema", readonly [(Readonly<{
|
|
12
|
+
threshold?: number;
|
|
13
|
+
guards?: readonly string[];
|
|
14
|
+
}> | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
11
15
|
};
|
|
12
16
|
readonly configs: {
|
|
13
17
|
/** Enables every rule of this plugin at `error`. */
|
|
@@ -19,6 +23,7 @@ export declare const eslintPluginTsFortress: {
|
|
|
19
23
|
readonly rules: {
|
|
20
24
|
readonly 'ts-fortress/prefer-canonical-length-constrained-type': 'error';
|
|
21
25
|
readonly 'ts-fortress/prefer-namespace-import': 'error';
|
|
26
|
+
readonly 'ts-fortress/prefer-schema-over-guard-chain': 'error';
|
|
22
27
|
};
|
|
23
28
|
};
|
|
24
29
|
};
|
package/dist/plugin.d.mts.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/plugin.mjs
CHANGED
|
@@ -1,34 +1,38 @@
|
|
|
1
|
-
import { tsFortressRules } from './rules/
|
|
1
|
+
import { tsFortressRules } from './rules/index.mjs';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
2
7
|
|
|
3
8
|
const recommendedRules = {
|
|
4
|
-
|
|
5
|
-
|
|
9
|
+
'ts-fortress/prefer-canonical-length-constrained-type': 'error',
|
|
10
|
+
'ts-fortress/prefer-namespace-import': 'error',
|
|
11
|
+
'ts-fortress/prefer-schema-over-guard-chain': 'error',
|
|
6
12
|
};
|
|
7
13
|
const recommendedConfig = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
};
|
|
22
|
-
const eslintPluginTsFortress = {
|
|
23
|
-
meta: {
|
|
24
|
-
name: "eslint-plugin-ts-fortress"
|
|
25
|
-
},
|
|
26
|
-
rules: tsFortressRules,
|
|
27
|
-
configs: {
|
|
28
|
-
/** Enables every rule of this plugin at `error`. */
|
|
29
|
-
recommended: recommendedConfig
|
|
30
|
-
}
|
|
14
|
+
name: 'ts-fortress/recommended',
|
|
15
|
+
plugins: {
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
get 'ts-fortress'() {
|
|
23
|
+
return eslintPluginTsFortress;
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
rules: recommendedRules,
|
|
31
27
|
};
|
|
28
|
+
export const eslintPluginTsFortress = {
|
|
29
|
+
meta: {
|
|
30
|
+
name: 'eslint-plugin-ts-fortress',
|
|
31
|
+
},
|
|
32
|
+
rules: tsFortressRules,
|
|
33
|
+
configs: {
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
recommended: recommendedConfig,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=plugin.mjs.map
|
package/dist/plugin.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.mjs","
|
|
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"}
|
package/dist/rule-types.d.mts
CHANGED
|
@@ -57,12 +57,55 @@ declare namespace PreferNamespaceImport {
|
|
|
57
57
|
type Options = NonNullable<RuleOptionsOf<'prefer-namespace-import'>[0]>;
|
|
58
58
|
type RuleEntry = 'off' | Linter.Severity | SpreadOptionsIfIsArray<readonly [Linter.StringSeverity, Options]>;
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* @description Report a chain of hand-written type guards narrowing one value, once it is long enough to be a schema, and point at `ts-fortress`
|
|
62
|
+
*
|
|
63
|
+
* ```md
|
|
64
|
+
* | key | value |
|
|
65
|
+
* | :--------- | :--------- |
|
|
66
|
+
* | type | suggestion |
|
|
67
|
+
* | deprecated | false |
|
|
68
|
+
* | fixable | false |
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
declare namespace PreferSchemaOverGuardChain {
|
|
72
|
+
/**
|
|
73
|
+
* ### schema
|
|
74
|
+
*
|
|
75
|
+
* ```json
|
|
76
|
+
* [
|
|
77
|
+
* {
|
|
78
|
+
* "type": "object",
|
|
79
|
+
* "properties": {
|
|
80
|
+
* "threshold": {
|
|
81
|
+
* "type": "integer",
|
|
82
|
+
* "minimum": 2,
|
|
83
|
+
* "description": "How many guards on one value a single chain may contain before it is reported. Defaults to 5."
|
|
84
|
+
* },
|
|
85
|
+
* "guards": {
|
|
86
|
+
* "type": "array",
|
|
87
|
+
* "items": {
|
|
88
|
+
* "type": "string"
|
|
89
|
+
* },
|
|
90
|
+
* "description": "Names of the guard functions to count, replacing the default list. A member call is matched on its property name, so `Arr.isArray` is named `isArray`."
|
|
91
|
+
* }
|
|
92
|
+
* },
|
|
93
|
+
* "additionalProperties": false
|
|
94
|
+
* }
|
|
95
|
+
* ]
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
type Options = NonNullable<RuleOptionsOf<'prefer-schema-over-guard-chain'>[0]>;
|
|
99
|
+
type RuleEntry = 'off' | Linter.Severity | SpreadOptionsIfIsArray<readonly [Linter.StringSeverity, Options]>;
|
|
100
|
+
}
|
|
60
101
|
export type EslintTsFortressRules = Readonly<{
|
|
61
102
|
'ts-fortress/prefer-canonical-length-constrained-type': PreferCanonicalLengthConstrainedType.RuleEntry;
|
|
62
103
|
'ts-fortress/prefer-namespace-import': PreferNamespaceImport.RuleEntry;
|
|
104
|
+
'ts-fortress/prefer-schema-over-guard-chain': PreferSchemaOverGuardChain.RuleEntry;
|
|
63
105
|
}>;
|
|
64
106
|
export type EslintTsFortressRulesOption = Readonly<{
|
|
65
107
|
'ts-fortress/prefer-namespace-import': PreferNamespaceImport.Options;
|
|
108
|
+
'ts-fortress/prefer-schema-over-guard-chain': PreferSchemaOverGuardChain.Options;
|
|
66
109
|
}>;
|
|
67
110
|
type AssertTrue<B extends true> = B;
|
|
68
111
|
export type RuleNamesAreInSync = AssertTrue<TypeEq<keyof EslintTsFortressRules, `ts-fortress/${keyof typeof tsFortressRules}`>>;
|
|
@@ -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,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,sDAAsD,EAAE,oCAAoC,CAAC,SAAS,CAAC;IACvG,qCAAqC,EAAE,qBAAqB,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,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"}
|
package/dist/rule-types.mjs
CHANGED
package/dist/rule-types.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-types.mjs","
|
|
1
|
+
{"version":3,"file":"rule-types.mjs","sourceRoot":"","sources":["../src/rule-types.mts"],"names":[],"mappings":"AAAA,oBAAoB"}
|
package/dist/rules/constants.mjs
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
const TS_FORTRESS_MODULE =
|
|
2
|
-
const ARRAY_FN =
|
|
3
|
-
const BOUNDED_LENGTH_TUPLE_FN =
|
|
4
|
-
const FIXED_LENGTH_TUPLE_FN =
|
|
5
|
-
const MAX_LENGTH_TUPLE_FN =
|
|
6
|
-
const MIN_LENGTH_ARRAY_FN =
|
|
7
|
-
const MIN_LENGTH_TUPLE_FN =
|
|
8
|
-
const NON_EMPTY_ARRAY_FN =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
export const TS_FORTRESS_MODULE = 'ts-fortress';
|
|
2
|
+
export const ARRAY_FN = 'array';
|
|
3
|
+
export const BOUNDED_LENGTH_TUPLE_FN = 'boundedLengthTuple';
|
|
4
|
+
export const FIXED_LENGTH_TUPLE_FN = 'fixedLengthTuple';
|
|
5
|
+
export const MAX_LENGTH_TUPLE_FN = 'maxLengthTuple';
|
|
6
|
+
export const MIN_LENGTH_ARRAY_FN = 'minLengthArray';
|
|
7
|
+
export const MIN_LENGTH_TUPLE_FN = 'minLengthTuple';
|
|
8
|
+
export const NON_EMPTY_ARRAY_FN = 'nonEmptyArray';
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
export const STRUCTURAL_PREFIX_CAP = 10;
|
|
17
|
+
//# sourceMappingURL=constants.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.mjs","sources":["../../src/rules/constants.mts"],"
|
|
1
|
+
{"version":3,"file":"constants.mjs","sourceRoot":"","sources":["../../src/rules/constants.mts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,aAAa,CAAC;AAEhD,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAO,CAAC;AAEhC,MAAM,CAAC,MAAM,uBAAuB,GAAG,oBAAoB,CAAC;AAE5D,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AAExD,MAAM,CAAC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AAEpD,MAAM,CAAC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AAEpD,MAAM,CAAC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AAEpD,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC"}
|
|
@@ -1,58 +1,102 @@
|
|
|
1
|
-
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
1
|
+
import { AST_NODE_TYPES, } from '@typescript-eslint/utils';
|
|
2
2
|
import { Arr } from 'ts-data-forge';
|
|
3
3
|
import { TS_FORTRESS_MODULE } from './constants.mjs';
|
|
4
4
|
|
|
5
|
-
const getTsFortressImports = (program) => program.body.filter(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
5
|
+
export const getTsFortressImports = (program) => program.body.filter((node) => node.type === AST_NODE_TYPES.ImportDeclaration &&
|
|
6
|
+
node.source.value === TS_FORTRESS_MODULE);
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export const getImportedLocalName = (importDeclarations, importedName) => importDeclarations
|
|
14
|
+
.flatMap((declaration) => declaration.specifiers)
|
|
15
|
+
.find((specifier) => specifier.type === AST_NODE_TYPES.ImportSpecifier &&
|
|
16
|
+
(specifier.imported.type === AST_NODE_TYPES.Identifier
|
|
17
|
+
? specifier.imported.name
|
|
18
|
+
: specifier.imported.value) === importedName)?.local.name;
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
export const buildCalleeResolver = (importDeclarations) => {
|
|
27
|
+
const specifiers = importDeclarations.flatMap((declaration) => declaration.specifiers);
|
|
28
|
+
const namespaceNames = new Set(specifiers
|
|
29
|
+
.filter((specifier) => specifier.type === AST_NODE_TYPES.ImportNamespaceSpecifier)
|
|
30
|
+
.map((specifier) => specifier.local.name));
|
|
31
|
+
const localToCanonical = new Map(specifiers.flatMap((specifier) => {
|
|
32
|
+
if (specifier.type !== AST_NODE_TYPES.ImportSpecifier)
|
|
33
|
+
return [];
|
|
34
|
+
const importedName = specifier.imported.type === AST_NODE_TYPES.Identifier
|
|
35
|
+
? specifier.imported.name
|
|
36
|
+
: specifier.imported.value;
|
|
37
|
+
return typeof importedName === 'string'
|
|
38
|
+
? [[specifier.local.name, importedName]]
|
|
39
|
+
: [];
|
|
40
|
+
}));
|
|
41
|
+
return (callee) => {
|
|
42
|
+
if (callee.type === AST_NODE_TYPES.Identifier) {
|
|
43
|
+
const canonicalName = localToCanonical.get(callee.name);
|
|
44
|
+
return canonicalName === undefined
|
|
45
|
+
? undefined
|
|
46
|
+
: { canonicalName, propertyNode: callee, isNamespace: false };
|
|
47
|
+
}
|
|
48
|
+
return callee.type === AST_NODE_TYPES.MemberExpression &&
|
|
49
|
+
!callee.computed &&
|
|
50
|
+
callee.object.type === AST_NODE_TYPES.Identifier &&
|
|
51
|
+
namespaceNames.has(callee.object.name) &&
|
|
52
|
+
callee.property.type === AST_NODE_TYPES.Identifier
|
|
53
|
+
? {
|
|
54
|
+
canonicalName: callee.property.name,
|
|
55
|
+
propertyNode: callee.property,
|
|
56
|
+
isNamespace: true,
|
|
57
|
+
}
|
|
58
|
+
: undefined;
|
|
59
|
+
};
|
|
38
60
|
};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
export const hasForeignBinding = (sourceCode, node, name) => {
|
|
71
|
+
for (let mut_scope = sourceCode.getScope(node); mut_scope !== null; mut_scope = mut_scope.upper) {
|
|
72
|
+
const variable = mut_scope.set.get(name);
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
if (variable !== undefined) {
|
|
76
|
+
return variable.defs.some((def) => !isTsFortressImportDef(def.node));
|
|
77
|
+
}
|
|
44
78
|
}
|
|
45
|
-
|
|
46
|
-
return false;
|
|
79
|
+
return false;
|
|
47
80
|
};
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
export
|
|
58
|
-
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
export const buildImportsFix = (fixer, program, names) => Arr.isEmpty(names)
|
|
91
|
+
? []
|
|
92
|
+
: [
|
|
93
|
+
fixer.insertTextBefore(program, names
|
|
94
|
+
.map((name) => `import { ${name} } from '${TS_FORTRESS_MODULE}';\n`)
|
|
95
|
+
.join('')),
|
|
96
|
+
];
|
|
97
|
+
const isTsFortressImportDef = (node) => (node.type === AST_NODE_TYPES.ImportSpecifier ||
|
|
98
|
+
node.type === AST_NODE_TYPES.ImportDefaultSpecifier ||
|
|
99
|
+
node.type === AST_NODE_TYPES.ImportNamespaceSpecifier) &&
|
|
100
|
+
node.parent.type === AST_NODE_TYPES.ImportDeclaration &&
|
|
101
|
+
node.parent.source.value === TS_FORTRESS_MODULE;
|
|
102
|
+
//# sourceMappingURL=import-utils.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-utils.mjs","sources":["../../src/rules/import-utils.mts"],"
|
|
1
|
+
{"version":3,"file":"import-utils.mjs","sourceRoot":"","sources":["../../src/rules/import-utils.mts"],"names":[],"mappings":"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"}
|
package/dist/rules/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
//# sourceMappingURL=index.mjs.map
|
|
1
|
+
export * from './rules.mjs';
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
package/dist/rules/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/rules/index.mts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
|