eslint-plugin-ts-type-forge 0.8.0 → 0.8.1
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/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/plugin.mjs +34 -31
- package/dist/plugin.mjs.map +1 -1
- package/dist/rule-types.mjs +2 -1
- package/dist/rule-types.mjs.map +1 -1
- package/dist/rules/ast-utils.mjs +224 -103
- package/dist/rules/ast-utils.mjs.map +1 -1
- package/dist/rules/constants.mjs +14 -11
- package/dist/rules/constants.mjs.map +1 -1
- package/dist/rules/import-style.mjs +31 -26
- package/dist/rules/import-style.mjs.map +1 -1
- package/dist/rules/import-utils.mjs +49 -29
- 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/no-side-effect-import.mjs +48 -34
- package/dist/rules/no-side-effect-import.mjs.map +1 -1
- package/dist/rules/prefer-canonical-length-constrained-tuple.mjs +93 -73
- package/dist/rules/prefer-canonical-length-constrained-tuple.mjs.map +1 -1
- package/dist/rules/prefer-canonical-mutable-record.mjs +88 -75
- package/dist/rules/prefer-canonical-mutable-record.mjs.map +1 -1
- package/dist/rules/prefer-readonly-or-mutable-record.mjs +41 -45
- package/dist/rules/prefer-readonly-or-mutable-record.mjs.map +1 -1
- package/dist/rules/prefer-strict-or-relaxed-utility-type.mjs +48 -46
- package/dist/rules/prefer-strict-or-relaxed-utility-type.mjs.map +1 -1
- package/dist/rules/rewrite-rule-utils.mjs +31 -28
- package/dist/rules/rewrite-rule-utils.mjs.map +1 -1
- package/dist/rules/rules.mjs +7 -10
- package/dist/rules/rules.mjs.map +1 -1
- package/dist/rules/std-type-rule-utils.mjs +47 -30
- package/dist/rules/std-type-rule-utils.mjs.map +1 -1
- package/dist/types.mjs +2 -2
- package/dist/types.mjs.map +1 -1
- package/package.json +6 -7
|
@@ -1,35 +1,55 @@
|
|
|
1
|
-
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
1
|
+
import { AST_NODE_TYPES, } from '@typescript-eslint/utils';
|
|
2
2
|
import { TS_TYPE_FORGE_MODULE } from './constants.mjs';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
4
|
+
|
|
5
|
+
export const getTsTypeForgeImports = (program) => program.body.filter((node) => node.type === AST_NODE_TYPES.ImportDeclaration &&
|
|
6
|
+
node.source.value === TS_TYPE_FORGE_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
|
+
|
|
27
|
+
export const hasConflictingDeclaration = (program, name) => program.body.some((node) => {
|
|
28
|
+
if (node.type === AST_NODE_TYPES.ImportDeclaration) {
|
|
29
|
+
return (node.source.value !== TS_TYPE_FORGE_MODULE &&
|
|
30
|
+
node.specifiers.some((specifier) => specifier.local.name === name));
|
|
31
|
+
}
|
|
32
|
+
return declaresName(node.type === AST_NODE_TYPES.ExportNamedDeclaration ||
|
|
33
|
+
node.type === AST_NODE_TYPES.ExportDefaultDeclaration
|
|
34
|
+
? node.declaration
|
|
35
|
+
: node, name);
|
|
18
36
|
});
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
export const buildTypeImportFix = (fixer, program, name) => [
|
|
43
|
+
fixer.insertTextBefore(program, `import { type ${name} } from '${TS_TYPE_FORGE_MODULE}';\n`),
|
|
25
44
|
];
|
|
26
45
|
const declaresName = (node, name) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
46
|
+
if (node === null || node === undefined)
|
|
47
|
+
return false;
|
|
48
|
+
if (node.type === AST_NODE_TYPES.TSTypeAliasDeclaration ||
|
|
49
|
+
node.type === AST_NODE_TYPES.TSInterfaceDeclaration ||
|
|
50
|
+
node.type === AST_NODE_TYPES.TSEnumDeclaration) {
|
|
51
|
+
return node.id.name === name;
|
|
52
|
+
}
|
|
53
|
+
return (node.type === AST_NODE_TYPES.ClassDeclaration && node.id?.name === name);
|
|
32
54
|
};
|
|
33
|
-
|
|
34
|
-
export { buildTypeImportFix, getImportedLocalName, getTsTypeForgeImports, hasConflictingDeclaration };
|
|
35
|
-
//# sourceMappingURL=import-utils.mjs.map
|
|
55
|
+
//# 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":"AAAA,OAAO,EACL,cAAc,GAGf,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEvD,uEAAuE;AAEvE,uEAAuE;AACvE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,OAAyB,EACc,EAAE,CACzC,OAAO,CAAC,IAAI,CAAC,MAAM,CACjB,CAAC,IAAI,EAAsC,EAAE,CAC3C,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,iBAAiB;IAC9C,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,oBAAoB,CAC7C,CAAC;AAEJ;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,kBAAyD,EACzD,YAAoB,EACA,EAAE,CACtB,kBAAkB;KACf,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC;KAChD,IAAI,CACH,CAAC,SAAS,EAAE,EAAE,CACZ,SAAS,CAAC,IAAI,KAAK,cAAc,CAAC,eAAe;IACjD,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,UAAU;QACpD,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI;QACzB,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,YAAY,CACjD,EAAE,KAAK,CAAC,IAAI,CAAC;AAElB;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,OAAyB,EACzB,IAAY,EACH,EAAE,CACX,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;IACzB,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,iBAAiB,EAAE,CAAC;QACnD,OAAO,CACL,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,oBAAoB;YAC1C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CACnE,CAAC;IACJ,CAAC;IAED,OAAO,YAAY,CACjB,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,sBAAsB;QACjD,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,wBAAwB;QACrD,CAAC,CAAC,IAAI,CAAC,WAAW;QAClB,CAAC,CAAC,IAAI,EACR,IAAI,CACL,CAAC;AACJ,CAAC,CAAC,CAAC;AAEL;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,KAAyB,EACzB,OAAyB,EACzB,IAAY,EACiB,EAAE,CAC/B;IACE,KAAK,CAAC,gBAAgB,CACpB,OAAO,EACP,iBAAiB,IAAI,YAAY,oBAAoB,MAAM,CAC5D;CACO,CAAC;AAEb,MAAM,YAAY,GAAG,CACnB,IAAsC,EACtC,IAAY,EACH,EAAE;IACX,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAEtD,IACE,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,sBAAsB;QACnD,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,sBAAsB;QACnD,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,iBAAiB,EAC9C,CAAC;QACD,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC;IAC/B,CAAC;IAED,OAAO,CACL,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,gBAAgB,IAAI,IAAI,CAAC,EAAE,EAAE,IAAI,KAAK,IAAI,CACxE,CAAC;AACJ,CAAC,CAAC"}
|
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"}
|
|
@@ -1,41 +1,55 @@
|
|
|
1
1
|
import { Arr } from 'ts-data-forge';
|
|
2
2
|
import { TS_TYPE_FORGE_MODULE } from './constants.mjs';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
export const noSideEffectImport = {
|
|
17
|
+
meta: {
|
|
18
|
+
type: 'problem',
|
|
19
|
+
docs: {
|
|
20
|
+
description: `Remove a side-effect-only \`import '${TS_TYPE_FORGE_MODULE}';\`, which binds no name and has no runtime entry point to resolve to. \`${TS_TYPE_FORGE_MODULE}/global\` is left alone.`,
|
|
21
|
+
},
|
|
22
|
+
fixable: 'code',
|
|
23
|
+
schema: [],
|
|
24
|
+
messages: {
|
|
25
|
+
removeSideEffectImport: `\`import '${TS_TYPE_FORGE_MODULE}';\` binds no name, and \`${TS_TYPE_FORGE_MODULE}\` ships types only — it has no runtime entry point, so the import throws when the module is loaded. Remove it; the ambient globals come from \`${TS_TYPE_FORGE_MODULE}/global\`, not from this.`,
|
|
26
|
+
},
|
|
9
27
|
},
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
fix: (fixer) => removeStatement(fixer, context.sourceCode, node)
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
}),
|
|
28
|
-
defaultOptions: []
|
|
28
|
+
create: (context) => ({
|
|
29
|
+
ImportDeclaration: (node) => {
|
|
30
|
+
if (node.source.value !== TS_TYPE_FORGE_MODULE ||
|
|
31
|
+
!Arr.isEmpty(node.specifiers)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
context.report({
|
|
35
|
+
node,
|
|
36
|
+
messageId: 'removeSideEffectImport',
|
|
37
|
+
fix: (fixer) => removeStatement(fixer, context.sourceCode, node),
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
}),
|
|
41
|
+
defaultOptions: [],
|
|
29
42
|
};
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
30
48
|
const removeStatement = (fixer, sourceCode, node) => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
node.range[1] + (restOfLine?.[0].length ?? 0)
|
|
37
|
-
]);
|
|
49
|
+
const restOfLine = /^[^\S\n]*\n/u.exec(sourceCode.getText().slice(node.range[1]));
|
|
50
|
+
return fixer.removeRange([
|
|
51
|
+
node.range[0],
|
|
52
|
+
node.range[1] + (restOfLine?.[0].length ?? 0),
|
|
53
|
+
]);
|
|
38
54
|
};
|
|
39
|
-
|
|
40
|
-
export { noSideEffectImport };
|
|
41
|
-
//# sourceMappingURL=no-side-effect-import.mjs.map
|
|
55
|
+
//# sourceMappingURL=no-side-effect-import.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-side-effect-import.mjs","sources":["../../src/rules/no-side-effect-import.mts"],"
|
|
1
|
+
{"version":3,"file":"no-side-effect-import.mjs","sourceRoot":"","sources":["../../src/rules/no-side-effect-import.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAMvD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA6C;IAC1E,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,uCAAuC,oBAAoB,6EAA6E,oBAAoB,0BAA0B;SACpM;QACD,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,sBAAsB,EAAE,aAAa,oBAAoB,6BAA6B,oBAAoB,mJAAmJ,oBAAoB,2BAA2B;SAC7S;KACF;IAED,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACpB,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE;YAC1B,IACE,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,oBAAoB;gBAC1C,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAC7B,CAAC;gBACD,OAAO;YACT,CAAC;YAED,OAAO,CAAC,MAAM,CAAC;gBACb,IAAI;gBACJ,SAAS,EAAE,wBAAwB;gBACnC,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC;aACjE,CAAC,CAAC;QACL,CAAC;KACF,CAAC;IACF,cAAc,EAAE,EAAE;CACV,CAAC;AAEX,uEAAuE;AAEvE;;;GAGG;AACH,MAAM,eAAe,GAAG,CACtB,KAAyB,EACzB,UAA+B,EAC/B,IAAmB,EACD,EAAE;IACpB,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CACpC,UAAU,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAC1C,CAAC;IAEF,OAAO,KAAK,CAAC,WAAW,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACb,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;KAC9C,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -1,82 +1,102 @@
|
|
|
1
1
|
import { analyzeUniformTuple } from './ast-utils.mjs';
|
|
2
|
-
import { DEFAULT_MAX_TUPLE_LENGTH,
|
|
3
|
-
import { DEFAULT_IMPORT_STYLE, IMPORT_STYLE_SCHEMA_PROPERTY } from './import-style.mjs';
|
|
2
|
+
import { DEFAULT_MAX_TUPLE_LENGTH, FIXED_LENGTH_TUPLE_TYPE_NAME, MIN_LENGTH_TUPLE_TYPE_NAME, MUTABLE_FIXED_LENGTH_TUPLE_TYPE_NAME, MUTABLE_MIN_LENGTH_TUPLE_TYPE_NAME, MUTABLE_NON_EMPTY_TUPLE_TYPE_NAME, NON_EMPTY_TUPLE_TYPE_NAME, } from './constants.mjs';
|
|
3
|
+
import { DEFAULT_IMPORT_STYLE, IMPORT_STYLE_SCHEMA_PROPERTY, } from './import-style.mjs';
|
|
4
4
|
import { reportTypeRewrites } from './rewrite-rule-utils.mjs';
|
|
5
5
|
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
6
9
|
const MIN_FIXED_LENGTH = 2;
|
|
7
|
-
const preferCanonicalLengthConstrainedTuple = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
10
|
+
export const preferCanonicalLengthConstrainedTuple = {
|
|
11
|
+
meta: {
|
|
12
|
+
type: 'suggestion',
|
|
13
|
+
docs: {
|
|
14
|
+
description: 'Replace uniform tuple spellings such as `[V, ...V[]]` / `[V, V, ...V[]]` / `[V, V, V]` with the canonical ts-type-forge tuple type.',
|
|
15
|
+
},
|
|
16
|
+
fixable: 'code',
|
|
17
|
+
schema: [
|
|
18
|
+
{
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
importStyle: IMPORT_STYLE_SCHEMA_PROPERTY,
|
|
22
|
+
maxLength: {
|
|
23
|
+
type: 'integer',
|
|
24
|
+
minimum: MIN_FIXED_LENGTH,
|
|
25
|
+
description: [
|
|
26
|
+
'Longest tuple the rule rewrites (default',
|
|
27
|
+
`${DEFAULT_MAX_TUPLE_LENGTH}).`,
|
|
28
|
+
'Longer tuples are usually spelled out on purpose, and the named',
|
|
29
|
+
'form stops being more readable.',
|
|
30
|
+
].join(' '),
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
additionalProperties: false,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
messages: {
|
|
37
|
+
useCanonicalTuple: 'Replace `{{original}}` with `{{replacement}}` from ts-type-forge.',
|
|
29
38
|
},
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
},
|
|
40
|
+
create: (context) => {
|
|
41
|
+
const sourceCode = context.sourceCode;
|
|
42
|
+
const options = context.options[0];
|
|
43
|
+
const importStyle = options?.importStyle ?? DEFAULT_IMPORT_STYLE;
|
|
44
|
+
const maxLength = options?.maxLength ?? DEFAULT_MAX_TUPLE_LENGTH;
|
|
45
|
+
const mut_rewrites = [];
|
|
46
|
+
return {
|
|
47
|
+
TSTupleType: (node) => {
|
|
48
|
+
const shape = analyzeUniformTuple(node, sourceCode);
|
|
49
|
+
if (shape === undefined || shape.fixedCount > maxLength)
|
|
50
|
+
return;
|
|
51
|
+
const canonicalName = canonicalNameFor(shape);
|
|
52
|
+
if (canonicalName === undefined)
|
|
53
|
+
return;
|
|
54
|
+
mut_rewrites.push({
|
|
55
|
+
node: shape.node,
|
|
56
|
+
canonicalName,
|
|
57
|
+
typeArgs: shape.fixedCount === 1
|
|
58
|
+
? shape.elementText
|
|
59
|
+
: `${shape.fixedCount}, ${shape.elementText}`,
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
'Program:exit': () => {
|
|
63
|
+
reportTypeRewrites(context, mut_rewrites, 'useCanonicalTuple', importStyle);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
defaultOptions: [
|
|
68
|
+
{ importStyle: DEFAULT_IMPORT_STYLE, maxLength: DEFAULT_MAX_TUPLE_LENGTH },
|
|
32
69
|
],
|
|
33
|
-
messages: {
|
|
34
|
-
useCanonicalTuple: "Replace `{{original}}` with `{{replacement}}` from ts-type-forge."
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
create: (context) => {
|
|
38
|
-
const sourceCode = context.sourceCode;
|
|
39
|
-
const options = context.options[0];
|
|
40
|
-
const importStyle = options?.importStyle ?? DEFAULT_IMPORT_STYLE;
|
|
41
|
-
const maxLength = options?.maxLength ?? DEFAULT_MAX_TUPLE_LENGTH;
|
|
42
|
-
const mut_rewrites = [];
|
|
43
|
-
return {
|
|
44
|
-
TSTupleType: (node) => {
|
|
45
|
-
const shape = analyzeUniformTuple(node, sourceCode);
|
|
46
|
-
if (shape === void 0 || shape.fixedCount > maxLength) return;
|
|
47
|
-
const canonicalName = canonicalNameFor(shape);
|
|
48
|
-
if (canonicalName === void 0) return;
|
|
49
|
-
mut_rewrites.push({
|
|
50
|
-
node: shape.node,
|
|
51
|
-
canonicalName,
|
|
52
|
-
typeArgs: shape.fixedCount === 1 ? shape.elementText : `${shape.fixedCount}, ${shape.elementText}`
|
|
53
|
-
});
|
|
54
|
-
},
|
|
55
|
-
"Program:exit": () => {
|
|
56
|
-
reportTypeRewrites(
|
|
57
|
-
context,
|
|
58
|
-
mut_rewrites,
|
|
59
|
-
"useCanonicalTuple",
|
|
60
|
-
importStyle
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
},
|
|
65
|
-
defaultOptions: [
|
|
66
|
-
{ importStyle: DEFAULT_IMPORT_STYLE, maxLength: DEFAULT_MAX_TUPLE_LENGTH }
|
|
67
|
-
]
|
|
68
70
|
};
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
const canonicalNameFor = (
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
shape) => {
|
|
85
|
+
const { isReadonly, hasRest, fixedCount } = shape;
|
|
86
|
+
if (hasRest) {
|
|
87
|
+
if (fixedCount === 1) {
|
|
88
|
+
return isReadonly
|
|
89
|
+
? NON_EMPTY_TUPLE_TYPE_NAME
|
|
90
|
+
: MUTABLE_NON_EMPTY_TUPLE_TYPE_NAME;
|
|
91
|
+
}
|
|
92
|
+
return isReadonly
|
|
93
|
+
? MIN_LENGTH_TUPLE_TYPE_NAME
|
|
94
|
+
: MUTABLE_MIN_LENGTH_TUPLE_TYPE_NAME;
|
|
74
95
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
96
|
+
if (fixedCount < MIN_FIXED_LENGTH)
|
|
97
|
+
return undefined;
|
|
98
|
+
return isReadonly
|
|
99
|
+
? FIXED_LENGTH_TUPLE_TYPE_NAME
|
|
100
|
+
: MUTABLE_FIXED_LENGTH_TUPLE_TYPE_NAME;
|
|
79
101
|
};
|
|
80
|
-
|
|
81
|
-
export { preferCanonicalLengthConstrainedTuple };
|
|
82
|
-
//# sourceMappingURL=prefer-canonical-length-constrained-tuple.mjs.map
|
|
102
|
+
//# sourceMappingURL=prefer-canonical-length-constrained-tuple.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prefer-canonical-length-constrained-tuple.mjs","sources":["../../src/rules/prefer-canonical-length-constrained-tuple.mts"],"
|
|
1
|
+
{"version":3,"file":"prefer-canonical-length-constrained-tuple.mjs","sourceRoot":"","sources":["../../src/rules/prefer-canonical-length-constrained-tuple.mts"],"names":[],"mappings":"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"}
|
|
@@ -1,83 +1,96 @@
|
|
|
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 { isLocallyBound } from './ast-utils.mjs';
|
|
4
|
-
import { DEFAULT_IMPORT_STYLE, IMPORT_STYLE_SCHEMA_PROPERTY } from './import-style.mjs';
|
|
5
|
-
import { getTsTypeForgeImports,
|
|
4
|
+
import { DEFAULT_IMPORT_STYLE, IMPORT_STYLE_SCHEMA_PROPERTY, } from './import-style.mjs';
|
|
5
|
+
import { getImportedLocalName, getTsTypeForgeImports, } from './import-utils.mjs';
|
|
6
6
|
import { reportTypeRewrites } from './rewrite-rule-utils.mjs';
|
|
7
7
|
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
8
12
|
const WRAPPED_RECORD_NAMES = [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
'Record',
|
|
14
|
+
'ReadonlyRecord',
|
|
15
|
+
'MutableRecord',
|
|
12
16
|
];
|
|
13
|
-
const MUTABLE_TYPE_NAME =
|
|
14
|
-
const MUTABLE_RECORD_TYPE_NAME =
|
|
15
|
-
const preferCanonicalMutableRecord = {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
},
|
|
21
|
-
fixable: "code",
|
|
22
|
-
schema: [
|
|
23
|
-
{
|
|
24
|
-
type: "object",
|
|
25
|
-
properties: {
|
|
26
|
-
importStyle: IMPORT_STYLE_SCHEMA_PROPERTY
|
|
17
|
+
const MUTABLE_TYPE_NAME = 'Mutable';
|
|
18
|
+
const MUTABLE_RECORD_TYPE_NAME = 'MutableRecord';
|
|
19
|
+
export const preferCanonicalMutableRecord = {
|
|
20
|
+
meta: {
|
|
21
|
+
type: 'suggestion',
|
|
22
|
+
docs: {
|
|
23
|
+
description: 'Replace `Mutable<Record<K, V>>` (and `Mutable` applied to `ReadonlyRecord` / `MutableRecord`) with the canonical ts-type-forge `MutableRecord<K, V>`.',
|
|
27
24
|
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const wrapped = node.typeArguments?.params;
|
|
49
|
-
if (wrapped === void 0 || !Arr.isFixedLengthArray(1, wrapped)) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
const record = wrapped[0];
|
|
53
|
-
if (record.type !== AST_NODE_TYPES.TSTypeReference || WRAPPED_RECORD_NAMES.every(
|
|
54
|
-
(name) => !referencesTsTypeForgeType(record, name)
|
|
55
|
-
)) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const recordTypeArgs = record.typeArguments?.params;
|
|
59
|
-
if (recordTypeArgs === void 0 || !Arr.isFixedLengthArray(2, recordTypeArgs)) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
const [K, V] = recordTypeArgs;
|
|
63
|
-
mut_rewrites.push({
|
|
64
|
-
node,
|
|
65
|
-
canonicalName: MUTABLE_RECORD_TYPE_NAME,
|
|
66
|
-
typeArgs: `${sourceCode.getText(K)}, ${sourceCode.getText(V)}`
|
|
67
|
-
});
|
|
68
|
-
},
|
|
69
|
-
"Program:exit": () => {
|
|
70
|
-
reportTypeRewrites(
|
|
71
|
-
context,
|
|
72
|
-
mut_rewrites,
|
|
73
|
-
"useMutableRecord",
|
|
74
|
-
importStyle
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
},
|
|
79
|
-
defaultOptions: [{ importStyle: DEFAULT_IMPORT_STYLE }]
|
|
80
|
-
};
|
|
25
|
+
fixable: 'code',
|
|
26
|
+
schema: [
|
|
27
|
+
{
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
importStyle: IMPORT_STYLE_SCHEMA_PROPERTY,
|
|
31
|
+
},
|
|
32
|
+
additionalProperties: false,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
messages: {
|
|
36
|
+
useMutableRecord: 'Replace `{{original}}` with `{{replacement}}` from ts-type-forge.',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
create: (context) => {
|
|
40
|
+
const importStyle = context.options[0]?.importStyle ?? DEFAULT_IMPORT_STYLE;
|
|
41
|
+
const sourceCode = context.sourceCode;
|
|
42
|
+
const tsTypeForgeImports = getTsTypeForgeImports(sourceCode.ast);
|
|
43
|
+
|
|
44
|
+
|
|
81
45
|
|
|
82
|
-
|
|
83
|
-
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
const referencesTsTypeForgeType = (
|
|
52
|
+
|
|
53
|
+
node, canonicalName) => {
|
|
54
|
+
const typeName = node.typeName;
|
|
55
|
+
|
|
56
|
+
if (typeName.type !== AST_NODE_TYPES.Identifier)
|
|
57
|
+
return false;
|
|
58
|
+
return (typeName.name ===
|
|
59
|
+
getImportedLocalName(tsTypeForgeImports, canonicalName) ||
|
|
60
|
+
(typeName.name === canonicalName &&
|
|
61
|
+
!isLocallyBound(sourceCode, node, canonicalName)));
|
|
62
|
+
};
|
|
63
|
+
const mut_rewrites = [];
|
|
64
|
+
return {
|
|
65
|
+
TSTypeReference: (node) => {
|
|
66
|
+
if (!referencesTsTypeForgeType(node, MUTABLE_TYPE_NAME))
|
|
67
|
+
return;
|
|
68
|
+
const wrapped = node.typeArguments?.params;
|
|
69
|
+
if (wrapped === undefined || !Arr.isFixedLengthArray(1, wrapped)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const record = wrapped[0];
|
|
73
|
+
if (record.type !== AST_NODE_TYPES.TSTypeReference ||
|
|
74
|
+
WRAPPED_RECORD_NAMES.every((name) => !referencesTsTypeForgeType(record, name))) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const recordTypeArgs = record.typeArguments?.params;
|
|
78
|
+
if (recordTypeArgs === undefined ||
|
|
79
|
+
!Arr.isFixedLengthArray(2, recordTypeArgs)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const [K, V] = recordTypeArgs;
|
|
83
|
+
mut_rewrites.push({
|
|
84
|
+
node,
|
|
85
|
+
canonicalName: MUTABLE_RECORD_TYPE_NAME,
|
|
86
|
+
typeArgs: `${sourceCode.getText(K)}, ${sourceCode.getText(V)}`,
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
'Program:exit': () => {
|
|
90
|
+
reportTypeRewrites(context, mut_rewrites, 'useMutableRecord', importStyle);
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
},
|
|
94
|
+
defaultOptions: [{ importStyle: DEFAULT_IMPORT_STYLE }],
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=prefer-canonical-mutable-record.mjs.map
|