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.
Files changed (35) hide show
  1. package/dist/index.mjs +2 -2
  2. package/dist/index.mjs.map +1 -1
  3. package/dist/plugin.mjs +34 -31
  4. package/dist/plugin.mjs.map +1 -1
  5. package/dist/rule-types.mjs +2 -1
  6. package/dist/rule-types.mjs.map +1 -1
  7. package/dist/rules/ast-utils.mjs +224 -103
  8. package/dist/rules/ast-utils.mjs.map +1 -1
  9. package/dist/rules/constants.mjs +14 -11
  10. package/dist/rules/constants.mjs.map +1 -1
  11. package/dist/rules/import-style.mjs +31 -26
  12. package/dist/rules/import-style.mjs.map +1 -1
  13. package/dist/rules/import-utils.mjs +49 -29
  14. package/dist/rules/import-utils.mjs.map +1 -1
  15. package/dist/rules/index.mjs +2 -2
  16. package/dist/rules/index.mjs.map +1 -1
  17. package/dist/rules/no-side-effect-import.mjs +48 -34
  18. package/dist/rules/no-side-effect-import.mjs.map +1 -1
  19. package/dist/rules/prefer-canonical-length-constrained-tuple.mjs +93 -73
  20. package/dist/rules/prefer-canonical-length-constrained-tuple.mjs.map +1 -1
  21. package/dist/rules/prefer-canonical-mutable-record.mjs +88 -75
  22. package/dist/rules/prefer-canonical-mutable-record.mjs.map +1 -1
  23. package/dist/rules/prefer-readonly-or-mutable-record.mjs +41 -45
  24. package/dist/rules/prefer-readonly-or-mutable-record.mjs.map +1 -1
  25. package/dist/rules/prefer-strict-or-relaxed-utility-type.mjs +48 -46
  26. package/dist/rules/prefer-strict-or-relaxed-utility-type.mjs.map +1 -1
  27. package/dist/rules/rewrite-rule-utils.mjs +31 -28
  28. package/dist/rules/rewrite-rule-utils.mjs.map +1 -1
  29. package/dist/rules/rules.mjs +7 -10
  30. package/dist/rules/rules.mjs.map +1 -1
  31. package/dist/rules/std-type-rule-utils.mjs +47 -30
  32. package/dist/rules/std-type-rule-utils.mjs.map +1 -1
  33. package/dist/types.mjs +2 -2
  34. package/dist/types.mjs.map +1 -1
  35. 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
- const getTsTypeForgeImports = (program) => program.body.filter(
5
- (node) => node.type === AST_NODE_TYPES.ImportDeclaration && node.source.value === TS_TYPE_FORGE_MODULE
6
- );
7
- const getImportedLocalName = (importDeclarations, importedName) => importDeclarations.flatMap((declaration) => declaration.specifiers).find(
8
- (specifier) => specifier.type === AST_NODE_TYPES.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES.Identifier ? specifier.imported.name : specifier.imported.value) === importedName
9
- )?.local.name;
10
- const hasConflictingDeclaration = (program, name) => program.body.some((node) => {
11
- if (node.type === AST_NODE_TYPES.ImportDeclaration) {
12
- return node.source.value !== TS_TYPE_FORGE_MODULE && node.specifiers.some((specifier) => specifier.local.name === name);
13
- }
14
- return declaresName(
15
- node.type === AST_NODE_TYPES.ExportNamedDeclaration || node.type === AST_NODE_TYPES.ExportDefaultDeclaration ? node.declaration : node,
16
- name
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
- const buildTypeImportFix = (fixer, program, name) => [
20
- fixer.insertTextBefore(
21
- program,
22
- `import { type ${name} } from '${TS_TYPE_FORGE_MODULE}';
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
- if (node === null || node === void 0) return false;
28
- if (node.type === AST_NODE_TYPES.TSTypeAliasDeclaration || node.type === AST_NODE_TYPES.TSInterfaceDeclaration || node.type === AST_NODE_TYPES.TSEnumDeclaration) {
29
- return node.id.name === name;
30
- }
31
- return node.type === AST_NODE_TYPES.ClassDeclaration && node.id?.name === name;
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"],"sourcesContent":["import {\n AST_NODE_TYPES,\n type TSESLint,\n type TSESTree,\n} from '@typescript-eslint/utils';\nimport { TS_TYPE_FORGE_MODULE } from './constants.mjs';\n\n/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */\n\n/** Every `import ... from 'ts-type-forge'` declaration in the file. */\nexport const getTsTypeForgeImports = (\n program: TSESTree.Program,\n): readonly TSESTree.ImportDeclaration[] =>\n program.body.filter(\n (node): node is TSESTree.ImportDeclaration =>\n node.type === AST_NODE_TYPES.ImportDeclaration &&\n node.source.value === TS_TYPE_FORGE_MODULE,\n );\n\n/**\n * Returns the in-scope local name a given ts-type-forge export is imported as\n * (handling aliases such as `import type { NonEmptyArray as NEA }` → `'NEA'`),\n * or `undefined` when it is not imported. Used so autofixes reference the\n * binding that actually exists rather than the canonical name.\n */\nexport const getImportedLocalName = (\n importDeclarations: readonly TSESTree.ImportDeclaration[],\n importedName: string,\n): string | undefined =>\n importDeclarations\n .flatMap((declaration) => declaration.specifiers)\n .find(\n (specifier) =>\n specifier.type === AST_NODE_TYPES.ImportSpecifier &&\n (specifier.imported.type === AST_NODE_TYPES.Identifier\n ? specifier.imported.name\n : specifier.imported.value) === importedName,\n )?.local.name;\n\n/**\n * Whether the file already binds `name` to something that is not the\n * ts-type-forge export of the same name — a local type alias / interface /\n * class / enum, or an import from another module. Autofixes that introduce\n * `name` must bail out in that case, because the rewritten type would resolve\n * to the wrong declaration. (ts-type-forge's own sources, which declare\n * `NonEmptyArray` themselves, are the motivating example.)\n */\nexport const hasConflictingDeclaration = (\n program: TSESTree.Program,\n name: string,\n): boolean =>\n program.body.some((node) => {\n if (node.type === AST_NODE_TYPES.ImportDeclaration) {\n return (\n node.source.value !== TS_TYPE_FORGE_MODULE &&\n node.specifiers.some((specifier) => specifier.local.name === name)\n );\n }\n\n return declaresName(\n node.type === AST_NODE_TYPES.ExportNamedDeclaration ||\n node.type === AST_NODE_TYPES.ExportDefaultDeclaration\n ? node.declaration\n : node,\n name,\n );\n });\n\n/**\n * Inserts `import { type <name> } from 'ts-type-forge';` at the top of the\n * file. Placement is deliberately naive: prettier-plugin-organize-imports (or\n * any equivalent) merges and sorts it afterwards.\n */\nexport const buildTypeImportFix = (\n fixer: TSESLint.RuleFixer,\n program: TSESTree.Program,\n name: string,\n): readonly TSESLint.RuleFix[] =>\n [\n fixer.insertTextBefore(\n program,\n `import { type ${name} } from '${TS_TYPE_FORGE_MODULE}';\\n`,\n ),\n ] as const;\n\nconst declaresName = (\n node: TSESTree.Node | null | undefined,\n name: string,\n): boolean => {\n if (node === null || node === undefined) return false;\n\n if (\n node.type === AST_NODE_TYPES.TSTypeAliasDeclaration ||\n node.type === AST_NODE_TYPES.TSInterfaceDeclaration ||\n node.type === AST_NODE_TYPES.TSEnumDeclaration\n ) {\n return node.id.name === name;\n }\n\n return (\n node.type === AST_NODE_TYPES.ClassDeclaration && node.id?.name === name\n );\n};\n"],"names":[],"mappings":";;;AAUO,MAAM,qBAAA,GAAwB,CACnC,OAAA,KAEA,OAAA,CAAQ,IAAA,CAAK,MAAA;AAAA,EACX,CAAC,SACC,IAAA,CAAK,IAAA,KAAS,eAAe,iBAAA,IAC7B,IAAA,CAAK,OAAO,KAAA,KAAU;AAC1B;AAQK,MAAM,oBAAA,GAAuB,CAClC,kBAAA,EACA,YAAA,KAEA,kBAAA,CACG,QAAQ,CAAC,WAAA,KAAgB,WAAA,CAAY,UAAU,CAAA,CAC/C,IAAA;AAAA,EACC,CAAC,SAAA,KACC,SAAA,CAAU,IAAA,KAAS,cAAA,CAAe,oBACjC,SAAA,CAAU,QAAA,CAAS,IAAA,KAAS,cAAA,CAAe,aACxC,SAAA,CAAU,QAAA,CAAS,IAAA,GACnB,SAAA,CAAU,SAAS,KAAA,MAAW;AACtC,CAAA,EAAG,KAAA,CAAM;AAUN,MAAM,yBAAA,GAA4B,CACvC,OAAA,EACA,IAAA,KAEA,QAAQ,IAAA,CAAK,IAAA,CAAK,CAAC,IAAA,KAAS;AAC1B,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,cAAA,CAAe,iBAAA,EAAmB;AAClD,IAAA,OACE,IAAA,CAAK,MAAA,CAAO,KAAA,KAAU,oBAAA,IACtB,IAAA,CAAK,UAAA,CAAW,IAAA,CAAK,CAAC,SAAA,KAAc,SAAA,CAAU,KAAA,CAAM,IAAA,KAAS,IAAI,CAAA;AAAA,EAErE;AAEA,EAAA,OAAO,YAAA;AAAA,IACL,IAAA,CAAK,SAAS,cAAA,CAAe,sBAAA,IAC3B,KAAK,IAAA,KAAS,cAAA,CAAe,wBAAA,GAC3B,IAAA,CAAK,WAAA,GACL,IAAA;AAAA,IACJ;AAAA,GACF;AACF,CAAC;AAOI,MAAM,kBAAA,GAAqB,CAChC,KAAA,EACA,OAAA,EACA,IAAA,KAEA;AAAA,EACE,KAAA,CAAM,gBAAA;AAAA,IACJ,OAAA;AAAA,IACA,CAAA,cAAA,EAAiB,IAAI,CAAA,SAAA,EAAY,oBAAoB,CAAA;AAAA;AAAA;AAEzD;AAEF,MAAM,YAAA,GAAe,CACnB,IAAA,EACA,IAAA,KACY;AACZ,EAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,IAAA,KAAS,MAAA,EAAW,OAAO,KAAA;AAEhD,EAAA,IACE,IAAA,CAAK,IAAA,KAAS,cAAA,CAAe,sBAAA,IAC7B,IAAA,CAAK,IAAA,KAAS,cAAA,CAAe,sBAAA,IAC7B,IAAA,CAAK,IAAA,KAAS,cAAA,CAAe,iBAAA,EAC7B;AACA,IAAA,OAAO,IAAA,CAAK,GAAG,IAAA,KAAS,IAAA;AAAA,EAC1B;AAEA,EAAA,OACE,KAAK,IAAA,KAAS,cAAA,CAAe,gBAAA,IAAoB,IAAA,CAAK,IAAI,IAAA,KAAS,IAAA;AAEvE,CAAA;;"}
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"}
@@ -1,2 +1,2 @@
1
- export { tsTypeForgeRules } from './rules.mjs';
2
- //# sourceMappingURL=index.mjs.map
1
+ export * from './rules.mjs';
2
+ //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
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
- const noSideEffectImport = {
5
- meta: {
6
- type: "problem",
7
- docs: {
8
- 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.`
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
- fixable: "code",
11
- schema: [],
12
- messages: {
13
- removeSideEffectImport: `\`import '${TS_TYPE_FORGE_MODULE}';\` binds no name, and \`${TS_TYPE_FORGE_MODULE}\` ships types only \u2014 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.`
14
- }
15
- },
16
- create: (context) => ({
17
- ImportDeclaration: (node) => {
18
- if (node.source.value !== TS_TYPE_FORGE_MODULE || !Arr.isEmpty(node.specifiers)) {
19
- return;
20
- }
21
- context.report({
22
- node,
23
- messageId: "removeSideEffectImport",
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
- const restOfLine = /^[^\S\n]*\n/u.exec(
32
- sourceCode.getText().slice(node.range[1])
33
- );
34
- return fixer.removeRange([
35
- node.range[0],
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"],"sourcesContent":["import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';\nimport { Arr } from 'ts-data-forge';\nimport { TS_TYPE_FORGE_MODULE } from './constants.mjs';\n\ntype Options = readonly [];\n\ntype MessageIds = 'removeSideEffectImport';\n\n/**\n * `import 'ts-type-forge';` binds nothing, and there is nothing for it to run:\n * the package ships declarations only, and its `exports` map offers no runtime\n * condition at all, so the import fails to resolve the moment the module graph\n * is loaded. TypeScript keeps a side-effect import in the emitted JavaScript —\n * that is the one kind it never elides — so this is a runtime error waiting in\n * a file that type-checks.\n *\n * The ambient globals are a separate entry point, `ts-type-forge/global`,\n * usually brought in through `compilerOptions.types` or a triple-slash\n * reference. This rule matches the bare specifier exactly, so that subpath is\n * left alone.\n */\nexport const noSideEffectImport: TSESLint.RuleModule<MessageIds, Options> = {\n meta: {\n type: 'problem',\n docs: {\n 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.`,\n },\n fixable: 'code',\n schema: [],\n messages: {\n 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.`,\n },\n },\n\n create: (context) => ({\n ImportDeclaration: (node) => {\n if (\n node.source.value !== TS_TYPE_FORGE_MODULE ||\n !Arr.isEmpty(node.specifiers)\n ) {\n return;\n }\n\n context.report({\n node,\n messageId: 'removeSideEffectImport',\n fix: (fixer) => removeStatement(fixer, context.sourceCode, node),\n });\n },\n }),\n defaultOptions: [],\n} as const;\n\n/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */\n\n/**\n * Removes a statement along with the rest of its line, so that deleting it does\n * not leave a blank line where it was.\n */\nconst removeStatement = (\n fixer: TSESLint.RuleFixer,\n sourceCode: TSESLint.SourceCode,\n node: TSESTree.Node,\n): TSESLint.RuleFix => {\n const restOfLine = /^[^\\S\\n]*\\n/u.exec(\n sourceCode.getText().slice(node.range[1]),\n );\n\n return fixer.removeRange([\n node.range[0],\n node.range[1] + (restOfLine?.[0].length ?? 0),\n ]);\n};\n"],"names":[],"mappings":";;;AAqBO,MAAM,kBAAA,GAA+D;AAAA,EAC1E,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,SAAA;AAAA,IACN,IAAA,EAAM;AAAA,MACJ,WAAA,EAAa,CAAA,oCAAA,EAAuC,oBAAoB,CAAA,0EAAA,EAA6E,oBAAoB,CAAA,wBAAA;AAAA,KAC3K;AAAA,IACA,OAAA,EAAS,MAAA;AAAA,IACT,QAAQ,EAAC;AAAA,IACT,QAAA,EAAU;AAAA,MACR,wBAAwB,CAAA,UAAA,EAAa,oBAAoB,CAAA,0BAAA,EAA6B,oBAAoB,wJAAmJ,oBAAoB,CAAA,yBAAA;AAAA;AACnR,GACF;AAAA,EAEA,MAAA,EAAQ,CAAC,OAAA,MAAa;AAAA,IACpB,iBAAA,EAAmB,CAAC,IAAA,KAAS;AAC3B,MAAA,IACE,IAAA,CAAK,OAAO,KAAA,KAAU,oBAAA,IACtB,CAAC,GAAA,CAAI,OAAA,CAAQ,IAAA,CAAK,UAAU,CAAA,EAC5B;AACA,QAAA;AAAA,MACF;AAEA,MAAA,OAAA,CAAQ,MAAA,CAAO;AAAA,QACb,IAAA;AAAA,QACA,SAAA,EAAW,wBAAA;AAAA,QACX,KAAK,CAAC,KAAA,KAAU,gBAAgB,KAAA,EAAO,OAAA,CAAQ,YAAY,IAAI;AAAA,OAChE,CAAA;AAAA,IACH;AAAA,GACF,CAAA;AAAA,EACA,gBAAgB;AAClB;AAQA,MAAM,eAAA,GAAkB,CACtB,KAAA,EACA,UAAA,EACA,IAAA,KACqB;AACrB,EAAA,MAAM,aAAa,cAAA,CAAe,IAAA;AAAA,IAChC,WAAW,OAAA,EAAQ,CAAE,MAAM,IAAA,CAAK,KAAA,CAAM,CAAC,CAAC;AAAA,GAC1C;AAEA,EAAA,OAAO,MAAM,WAAA,CAAY;AAAA,IACvB,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA,IACZ,KAAK,KAAA,CAAM,CAAC,KAAK,UAAA,GAAa,CAAC,EAAE,MAAA,IAAU,CAAA;AAAA,GAC5C,CAAA;AACH,CAAA;;"}
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, 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 } 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
- meta: {
9
- type: "suggestion",
10
- docs: {
11
- description: "Replace uniform tuple spellings such as `[V, ...V[]]` / `[V, V, ...V[]]` / `[V, V, V]` with the canonical ts-type-forge tuple type."
12
- },
13
- fixable: "code",
14
- schema: [
15
- {
16
- type: "object",
17
- properties: {
18
- importStyle: IMPORT_STYLE_SCHEMA_PROPERTY,
19
- maxLength: {
20
- type: "integer",
21
- minimum: MIN_FIXED_LENGTH,
22
- description: [
23
- "Longest tuple the rule rewrites (default",
24
- `${DEFAULT_MAX_TUPLE_LENGTH}).`,
25
- "Longer tuples are usually spelled out on purpose, and the named",
26
- "form stops being more readable."
27
- ].join(" ")
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
- additionalProperties: false
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
- const canonicalNameFor = (shape) => {
70
- const { isReadonly, hasRest, fixedCount } = shape;
71
- if (hasRest) {
72
- if (fixedCount === 1) {
73
- return isReadonly ? NON_EMPTY_TUPLE_TYPE_NAME : MUTABLE_NON_EMPTY_TUPLE_TYPE_NAME;
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
- return isReadonly ? MIN_LENGTH_TUPLE_TYPE_NAME : MUTABLE_MIN_LENGTH_TUPLE_TYPE_NAME;
76
- }
77
- if (fixedCount < MIN_FIXED_LENGTH) return void 0;
78
- return isReadonly ? FIXED_LENGTH_TUPLE_TYPE_NAME : MUTABLE_FIXED_LENGTH_TUPLE_TYPE_NAME;
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"],"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 { reportTypeRewrites, type TypeRewrite } from './rewrite-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: TypeRewrite[] = [];\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 reportTypeRewrites(\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,eAA8B,EAAC;AAErC,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,kBAAA;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;;"}
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, getImportedLocalName } from './import-utils.mjs';
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
- "Record",
10
- "ReadonlyRecord",
11
- "MutableRecord"
13
+ 'Record',
14
+ 'ReadonlyRecord',
15
+ 'MutableRecord',
12
16
  ];
13
- const MUTABLE_TYPE_NAME = "Mutable";
14
- const MUTABLE_RECORD_TYPE_NAME = "MutableRecord";
15
- const preferCanonicalMutableRecord = {
16
- meta: {
17
- type: "suggestion",
18
- docs: {
19
- description: "Replace `Mutable<Record<K, V>>` (and `Mutable` applied to `ReadonlyRecord` / `MutableRecord`) with the canonical ts-type-forge `MutableRecord<K, V>`."
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
- additionalProperties: false
29
- }
30
- ],
31
- messages: {
32
- useMutableRecord: "Replace `{{original}}` with `{{replacement}}` from ts-type-forge."
33
- }
34
- },
35
- create: (context) => {
36
- const importStyle = context.options[0]?.importStyle ?? DEFAULT_IMPORT_STYLE;
37
- const sourceCode = context.sourceCode;
38
- const tsTypeForgeImports = getTsTypeForgeImports(sourceCode.ast);
39
- const referencesTsTypeForgeType = (node, canonicalName) => {
40
- const typeName = node.typeName;
41
- if (typeName.type !== AST_NODE_TYPES.Identifier) return false;
42
- return typeName.name === getImportedLocalName(tsTypeForgeImports, canonicalName) || typeName.name === canonicalName && !isLocallyBound(sourceCode, node, canonicalName);
43
- };
44
- const mut_rewrites = [];
45
- return {
46
- TSTypeReference: (node) => {
47
- if (!referencesTsTypeForgeType(node, MUTABLE_TYPE_NAME)) return;
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
- export { preferCanonicalMutableRecord };
83
- //# sourceMappingURL=prefer-canonical-mutable-record.mjs.map
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