@mionjs/devtools 0.8.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/LICENSE +21 -0
  2. package/build/eslint/cjs/index.cjs +41 -0
  3. package/build/eslint/cjs/index.cjs.map +1 -0
  4. package/build/eslint/cjs/package.json +1 -0
  5. package/build/eslint/cjs/src/eslint/index.cjs +13 -0
  6. package/build/eslint/cjs/src/eslint/index.cjs.map +1 -0
  7. package/build/eslint/cjs/src/eslint/index.d.ts +3 -0
  8. package/build/eslint/cjs/src/eslint/rules/enforce-type-imports.cjs +121 -0
  9. package/build/eslint/cjs/src/eslint/rules/enforce-type-imports.cjs.map +1 -0
  10. package/build/eslint/cjs/src/eslint/rules/enforce-type-imports.d.ts +7 -0
  11. package/build/eslint/cjs/src/eslint/rules/formatTypeNames.cjs +71 -0
  12. package/build/eslint/cjs/src/eslint/rules/formatTypeNames.cjs.map +1 -0
  13. package/build/eslint/cjs/src/eslint/rules/formatTypeNames.d.ts +3 -0
  14. package/build/eslint/cjs/src/eslint/rules/no-mixed-union-properties.cjs +220 -0
  15. package/build/eslint/cjs/src/eslint/rules/no-mixed-union-properties.cjs.map +1 -0
  16. package/build/eslint/cjs/src/eslint/rules/no-mixed-union-properties.d.ts +3 -0
  17. package/build/eslint/cjs/src/eslint/rules/no-type-imports.cjs +251 -0
  18. package/build/eslint/cjs/src/eslint/rules/no-type-imports.cjs.map +1 -0
  19. package/build/eslint/cjs/src/eslint/rules/no-type-imports.d.ts +3 -0
  20. package/build/eslint/cjs/src/eslint/rules/no-typeof-runtype.cjs +72 -0
  21. package/build/eslint/cjs/src/eslint/rules/no-typeof-runtype.cjs.map +1 -0
  22. package/build/eslint/cjs/src/eslint/rules/no-typeof-runtype.d.ts +3 -0
  23. package/build/eslint/cjs/src/eslint/rules/no-unreachable-union-types.cjs +220 -0
  24. package/build/eslint/cjs/src/eslint/rules/no-unreachable-union-types.cjs.map +1 -0
  25. package/build/eslint/cjs/src/eslint/rules/no-unreachable-union-types.d.ts +3 -0
  26. package/build/eslint/cjs/src/eslint/rules/no-vite-client.cjs +71 -0
  27. package/build/eslint/cjs/src/eslint/rules/no-vite-client.cjs.map +1 -0
  28. package/build/eslint/cjs/src/eslint/rules/no-vite-client.d.ts +4 -0
  29. package/build/eslint/cjs/src/eslint/rules/pure-functions.cjs +346 -0
  30. package/build/eslint/cjs/src/eslint/rules/pure-functions.cjs.map +1 -0
  31. package/build/eslint/cjs/src/eslint/rules/pure-functions.d.ts +4 -0
  32. package/build/eslint/cjs/src/eslint/rules/strong-typed-routes.cjs +328 -0
  33. package/build/eslint/cjs/src/eslint/rules/strong-typed-routes.cjs.map +1 -0
  34. package/build/eslint/cjs/src/eslint/rules/strong-typed-routes.d.ts +4 -0
  35. package/build/eslint/cjs/src/eslint/rules/type-formats-imports.cjs +52 -0
  36. package/build/eslint/cjs/src/eslint/rules/type-formats-imports.cjs.map +1 -0
  37. package/build/eslint/cjs/src/eslint/rules/type-formats-imports.d.ts +3 -0
  38. package/build/eslint/cjs/src/pureFns/purityRules.cjs +67 -0
  39. package/build/eslint/cjs/src/pureFns/purityRules.cjs.map +1 -0
  40. package/build/eslint/cjs/src/pureFns/purityRules.d.ts +4 -0
  41. package/build/eslint/esm/index.js +42 -0
  42. package/build/eslint/esm/index.js.map +1 -0
  43. package/build/eslint/esm/src/eslint/index.d.ts +3 -0
  44. package/build/eslint/esm/src/eslint/index.js +14 -0
  45. package/build/eslint/esm/src/eslint/index.js.map +1 -0
  46. package/build/eslint/esm/src/eslint/rules/enforce-type-imports.d.ts +7 -0
  47. package/build/eslint/esm/src/eslint/rules/enforce-type-imports.js +122 -0
  48. package/build/eslint/esm/src/eslint/rules/enforce-type-imports.js.map +1 -0
  49. package/build/eslint/esm/src/eslint/rules/formatTypeNames.d.ts +3 -0
  50. package/build/eslint/esm/src/eslint/rules/formatTypeNames.js +71 -0
  51. package/build/eslint/esm/src/eslint/rules/formatTypeNames.js.map +1 -0
  52. package/build/eslint/esm/src/eslint/rules/no-mixed-union-properties.d.ts +3 -0
  53. package/build/eslint/esm/src/eslint/rules/no-mixed-union-properties.js +221 -0
  54. package/build/eslint/esm/src/eslint/rules/no-mixed-union-properties.js.map +1 -0
  55. package/build/eslint/esm/src/eslint/rules/no-type-imports.d.ts +3 -0
  56. package/build/eslint/esm/src/eslint/rules/no-type-imports.js +252 -0
  57. package/build/eslint/esm/src/eslint/rules/no-type-imports.js.map +1 -0
  58. package/build/eslint/esm/src/eslint/rules/no-typeof-runtype.d.ts +3 -0
  59. package/build/eslint/esm/src/eslint/rules/no-typeof-runtype.js +73 -0
  60. package/build/eslint/esm/src/eslint/rules/no-typeof-runtype.js.map +1 -0
  61. package/build/eslint/esm/src/eslint/rules/no-unreachable-union-types.d.ts +3 -0
  62. package/build/eslint/esm/src/eslint/rules/no-unreachable-union-types.js +221 -0
  63. package/build/eslint/esm/src/eslint/rules/no-unreachable-union-types.js.map +1 -0
  64. package/build/eslint/esm/src/eslint/rules/no-vite-client.d.ts +4 -0
  65. package/build/eslint/esm/src/eslint/rules/no-vite-client.js +72 -0
  66. package/build/eslint/esm/src/eslint/rules/no-vite-client.js.map +1 -0
  67. package/build/eslint/esm/src/eslint/rules/pure-functions.d.ts +4 -0
  68. package/build/eslint/esm/src/eslint/rules/pure-functions.js +347 -0
  69. package/build/eslint/esm/src/eslint/rules/pure-functions.js.map +1 -0
  70. package/build/eslint/esm/src/eslint/rules/strong-typed-routes.d.ts +4 -0
  71. package/build/eslint/esm/src/eslint/rules/strong-typed-routes.js +329 -0
  72. package/build/eslint/esm/src/eslint/rules/strong-typed-routes.js.map +1 -0
  73. package/build/eslint/esm/src/eslint/rules/type-formats-imports.d.ts +3 -0
  74. package/build/eslint/esm/src/eslint/rules/type-formats-imports.js +53 -0
  75. package/build/eslint/esm/src/eslint/rules/type-formats-imports.js.map +1 -0
  76. package/build/eslint/esm/src/pureFns/purityRules.d.ts +4 -0
  77. package/build/eslint/esm/src/pureFns/purityRules.js +67 -0
  78. package/build/eslint/esm/src/pureFns/purityRules.js.map +1 -0
  79. package/build/vite-plugin/cjs/index.cjs +14 -0
  80. package/build/vite-plugin/cjs/index.cjs.map +1 -0
  81. package/build/vite-plugin/cjs/package.json +1 -0
  82. package/build/vite-plugin/cjs/src/pureFns/purityRules.cjs +65 -0
  83. package/build/vite-plugin/cjs/src/pureFns/purityRules.cjs.map +1 -0
  84. package/build/vite-plugin/cjs/src/pureFns/purityRules.d.ts +4 -0
  85. package/build/vite-plugin/cjs/src/vite-plugin/aotCacheGenerator.cjs +235 -0
  86. package/build/vite-plugin/cjs/src/vite-plugin/aotCacheGenerator.cjs.map +1 -0
  87. package/build/vite-plugin/cjs/src/vite-plugin/aotCacheGenerator.d.ts +23 -0
  88. package/build/vite-plugin/cjs/src/vite-plugin/aotDiskCache.cjs +134 -0
  89. package/build/vite-plugin/cjs/src/vite-plugin/aotDiskCache.cjs.map +1 -0
  90. package/build/vite-plugin/cjs/src/vite-plugin/aotDiskCache.d.ts +6 -0
  91. package/build/vite-plugin/cjs/src/vite-plugin/cjsPackageJsonPlugin.cjs +15 -0
  92. package/build/vite-plugin/cjs/src/vite-plugin/cjsPackageJsonPlugin.cjs.map +1 -0
  93. package/build/vite-plugin/cjs/src/vite-plugin/cjsPackageJsonPlugin.d.ts +2 -0
  94. package/build/vite-plugin/cjs/src/vite-plugin/constants.cjs +25 -0
  95. package/build/vite-plugin/cjs/src/vite-plugin/constants.cjs.map +1 -0
  96. package/build/vite-plugin/cjs/src/vite-plugin/constants.d.ts +10 -0
  97. package/build/vite-plugin/cjs/src/vite-plugin/extractPureFn.cjs +628 -0
  98. package/build/vite-plugin/cjs/src/vite-plugin/extractPureFn.cjs.map +1 -0
  99. package/build/vite-plugin/cjs/src/vite-plugin/extractPureFn.d.ts +13 -0
  100. package/build/vite-plugin/cjs/src/vite-plugin/index.cjs +14 -0
  101. package/build/vite-plugin/cjs/src/vite-plugin/index.cjs.map +1 -0
  102. package/build/vite-plugin/cjs/src/vite-plugin/index.d.ts +5 -0
  103. package/build/vite-plugin/cjs/src/vite-plugin/mionVitePlugin.cjs +404 -0
  104. package/build/vite-plugin/cjs/src/vite-plugin/mionVitePlugin.cjs.map +1 -0
  105. package/build/vite-plugin/cjs/src/vite-plugin/mionVitePlugin.d.ts +36 -0
  106. package/build/vite-plugin/cjs/src/vite-plugin/resolveModule.cjs +55 -0
  107. package/build/vite-plugin/cjs/src/vite-plugin/resolveModule.cjs.map +1 -0
  108. package/build/vite-plugin/cjs/src/vite-plugin/resolveModule.d.ts +1 -0
  109. package/build/vite-plugin/cjs/src/vite-plugin/transformers.cjs +165 -0
  110. package/build/vite-plugin/cjs/src/vite-plugin/transformers.cjs.map +1 -0
  111. package/build/vite-plugin/cjs/src/vite-plugin/transformers.d.ts +10 -0
  112. package/build/vite-plugin/cjs/src/vite-plugin/types.cjs +2 -0
  113. package/build/vite-plugin/cjs/src/vite-plugin/types.cjs.map +1 -0
  114. package/build/vite-plugin/cjs/src/vite-plugin/types.d.ts +57 -0
  115. package/build/vite-plugin/cjs/src/vite-plugin/virtual-modules.d.cjs +2 -0
  116. package/build/vite-plugin/cjs/src/vite-plugin/virtual-modules.d.cjs.map +1 -0
  117. package/build/vite-plugin/cjs/src/vite-plugin/virtualModule.cjs +68 -0
  118. package/build/vite-plugin/cjs/src/vite-plugin/virtualModule.cjs.map +1 -0
  119. package/build/vite-plugin/cjs/src/vite-plugin/virtualModule.d.ts +2 -0
  120. package/build/vite-plugin/esm/index.js +14 -0
  121. package/build/vite-plugin/esm/index.js.map +1 -0
  122. package/build/vite-plugin/esm/src/pureFns/purityRules.d.ts +4 -0
  123. package/build/vite-plugin/esm/src/pureFns/purityRules.js +65 -0
  124. package/build/vite-plugin/esm/src/pureFns/purityRules.js.map +1 -0
  125. package/build/vite-plugin/esm/src/vite-plugin/aotCacheGenerator.d.ts +23 -0
  126. package/build/vite-plugin/esm/src/vite-plugin/aotCacheGenerator.js +235 -0
  127. package/build/vite-plugin/esm/src/vite-plugin/aotCacheGenerator.js.map +1 -0
  128. package/build/vite-plugin/esm/src/vite-plugin/aotDiskCache.d.ts +6 -0
  129. package/build/vite-plugin/esm/src/vite-plugin/aotDiskCache.js +133 -0
  130. package/build/vite-plugin/esm/src/vite-plugin/aotDiskCache.js.map +1 -0
  131. package/build/vite-plugin/esm/src/vite-plugin/cjsPackageJsonPlugin.d.ts +2 -0
  132. package/build/vite-plugin/esm/src/vite-plugin/cjsPackageJsonPlugin.js +15 -0
  133. package/build/vite-plugin/esm/src/vite-plugin/cjsPackageJsonPlugin.js.map +1 -0
  134. package/build/vite-plugin/esm/src/vite-plugin/constants.d.ts +10 -0
  135. package/build/vite-plugin/esm/src/vite-plugin/constants.js +25 -0
  136. package/build/vite-plugin/esm/src/vite-plugin/constants.js.map +1 -0
  137. package/build/vite-plugin/esm/src/vite-plugin/extractPureFn.d.ts +13 -0
  138. package/build/vite-plugin/esm/src/vite-plugin/extractPureFn.js +611 -0
  139. package/build/vite-plugin/esm/src/vite-plugin/extractPureFn.js.map +1 -0
  140. package/build/vite-plugin/esm/src/vite-plugin/index.d.ts +5 -0
  141. package/build/vite-plugin/esm/src/vite-plugin/index.js +14 -0
  142. package/build/vite-plugin/esm/src/vite-plugin/index.js.map +1 -0
  143. package/build/vite-plugin/esm/src/vite-plugin/mionVitePlugin.d.ts +36 -0
  144. package/build/vite-plugin/esm/src/vite-plugin/mionVitePlugin.js +387 -0
  145. package/build/vite-plugin/esm/src/vite-plugin/mionVitePlugin.js.map +1 -0
  146. package/build/vite-plugin/esm/src/vite-plugin/resolveModule.d.ts +1 -0
  147. package/build/vite-plugin/esm/src/vite-plugin/resolveModule.js +33 -0
  148. package/build/vite-plugin/esm/src/vite-plugin/resolveModule.js.map +1 -0
  149. package/build/vite-plugin/esm/src/vite-plugin/transformers.d.ts +10 -0
  150. package/build/vite-plugin/esm/src/vite-plugin/transformers.js +148 -0
  151. package/build/vite-plugin/esm/src/vite-plugin/transformers.js.map +1 -0
  152. package/build/vite-plugin/esm/src/vite-plugin/types.d.ts +57 -0
  153. package/build/vite-plugin/esm/src/vite-plugin/types.js +2 -0
  154. package/build/vite-plugin/esm/src/vite-plugin/types.js.map +1 -0
  155. package/build/vite-plugin/esm/src/vite-plugin/virtual-modules.d.js +2 -0
  156. package/build/vite-plugin/esm/src/vite-plugin/virtual-modules.d.js.map +1 -0
  157. package/build/vite-plugin/esm/src/vite-plugin/virtualModule.d.ts +2 -0
  158. package/build/vite-plugin/esm/src/vite-plugin/virtualModule.js +68 -0
  159. package/build/vite-plugin/esm/src/vite-plugin/virtualModule.js.map +1 -0
  160. package/package.json +94 -0
  161. package/src/vite-plugin/virtual-modules.d.ts +48 -0
@@ -0,0 +1,252 @@
1
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
2
+ const ROUTER_FUNCTIONS = ["route", "middleFn", "headersFn"];
3
+ const HANDLER_TYPES = ["Handler", "HeaderHandler"];
4
+ function buildRouterImportCache(program) {
5
+ const routerFunctions = /* @__PURE__ */ new Set();
6
+ const handlerTypes = /* @__PURE__ */ new Set();
7
+ for (const statement of program.body) {
8
+ if (statement.type === AST_NODE_TYPES.ImportDeclaration) {
9
+ const source = statement.source.value;
10
+ if (source === "@mionjs/router" || source === "@mionjs/router/") {
11
+ for (const specifier of statement.specifiers) {
12
+ if (specifier.type === AST_NODE_TYPES.ImportSpecifier && specifier.imported.type === AST_NODE_TYPES.Identifier) {
13
+ const name = specifier.imported.name;
14
+ if (ROUTER_FUNCTIONS.includes(name)) {
15
+ routerFunctions.add(name);
16
+ }
17
+ if (HANDLER_TYPES.includes(name)) {
18
+ handlerTypes.add(name);
19
+ }
20
+ }
21
+ }
22
+ }
23
+ }
24
+ }
25
+ return { routerFunctions, handlerTypes };
26
+ }
27
+ function buildTypeOnlyImportCache(program) {
28
+ const typeOnlyImports = /* @__PURE__ */ new Map();
29
+ for (const statement of program.body) {
30
+ if (statement.type === AST_NODE_TYPES.ImportDeclaration) {
31
+ const isTypeOnlyImport = statement.importKind === "type";
32
+ for (const specifier of statement.specifiers) {
33
+ if (specifier.type === AST_NODE_TYPES.ImportSpecifier) {
34
+ const isTypeOnlySpecifier = specifier.importKind === "type";
35
+ if (isTypeOnlyImport || isTypeOnlySpecifier) {
36
+ const localName = specifier.local.name;
37
+ typeOnlyImports.set(localName, statement);
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
43
+ return { typeOnlyImports };
44
+ }
45
+ function getRouterFunctionName(node, importCache) {
46
+ if (node.callee.type !== AST_NODE_TYPES.Identifier) return null;
47
+ const functionName = node.callee.name;
48
+ if (importCache.routerFunctions.has(functionName)) return functionName;
49
+ return null;
50
+ }
51
+ function extractTypeReferencesWithNodes(typeNode) {
52
+ if (!typeNode) return [];
53
+ const references = [];
54
+ switch (typeNode.type) {
55
+ case AST_NODE_TYPES.TSTypeReference:
56
+ if (typeNode.typeName.type === AST_NODE_TYPES.Identifier) {
57
+ references.push({ typeName: typeNode.typeName.name, node: typeNode });
58
+ }
59
+ if (typeNode.typeArguments) {
60
+ for (const param of typeNode.typeArguments.params) {
61
+ references.push(...extractTypeReferencesWithNodes(param));
62
+ }
63
+ }
64
+ break;
65
+ case AST_NODE_TYPES.TSUnionType:
66
+ case AST_NODE_TYPES.TSIntersectionType:
67
+ for (const member of typeNode.types) {
68
+ references.push(...extractTypeReferencesWithNodes(member));
69
+ }
70
+ break;
71
+ case AST_NODE_TYPES.TSArrayType:
72
+ references.push(...extractTypeReferencesWithNodes(typeNode.elementType));
73
+ break;
74
+ case AST_NODE_TYPES.TSTupleType:
75
+ for (const element of typeNode.elementTypes) {
76
+ references.push(...extractTypeReferencesWithNodes(element));
77
+ }
78
+ break;
79
+ case AST_NODE_TYPES.TSTypeLiteral:
80
+ for (const member of typeNode.members) {
81
+ if (member.type === AST_NODE_TYPES.TSPropertySignature && member.typeAnnotation) {
82
+ references.push(...extractTypeReferencesWithNodes(member.typeAnnotation.typeAnnotation));
83
+ }
84
+ }
85
+ break;
86
+ case AST_NODE_TYPES.TSConditionalType:
87
+ references.push(...extractTypeReferencesWithNodes(typeNode.checkType));
88
+ references.push(...extractTypeReferencesWithNodes(typeNode.extendsType));
89
+ references.push(...extractTypeReferencesWithNodes(typeNode.trueType));
90
+ references.push(...extractTypeReferencesWithNodes(typeNode.falseType));
91
+ break;
92
+ case AST_NODE_TYPES.TSMappedType:
93
+ references.push(...extractTypeReferencesWithNodes(typeNode.typeAnnotation));
94
+ break;
95
+ case AST_NODE_TYPES.TSIndexedAccessType:
96
+ references.push(...extractTypeReferencesWithNodes(typeNode.objectType));
97
+ references.push(...extractTypeReferencesWithNodes(typeNode.indexType));
98
+ break;
99
+ case AST_NODE_TYPES.TSTypeOperator:
100
+ references.push(...extractTypeReferencesWithNodes(typeNode.typeAnnotation));
101
+ break;
102
+ case AST_NODE_TYPES.TSRestType:
103
+ references.push(...extractTypeReferencesWithNodes(typeNode.typeAnnotation));
104
+ break;
105
+ case AST_NODE_TYPES.TSOptionalType:
106
+ references.push(...extractTypeReferencesWithNodes(typeNode.typeAnnotation));
107
+ break;
108
+ case AST_NODE_TYPES.TSFunctionType:
109
+ case AST_NODE_TYPES.TSConstructorType:
110
+ for (const param of typeNode.params) {
111
+ if ("typeAnnotation" in param && param.typeAnnotation) {
112
+ references.push(...extractTypeReferencesWithNodes(param.typeAnnotation.typeAnnotation));
113
+ }
114
+ }
115
+ if (typeNode.returnType) {
116
+ references.push(...extractTypeReferencesWithNodes(typeNode.returnType.typeAnnotation));
117
+ }
118
+ break;
119
+ }
120
+ return references;
121
+ }
122
+ function getParamTypeAnnotation(param) {
123
+ if (param.type === AST_NODE_TYPES.Identifier && param.typeAnnotation) {
124
+ return param.typeAnnotation.typeAnnotation;
125
+ }
126
+ if (param.type === AST_NODE_TYPES.RestElement && param.typeAnnotation) {
127
+ return param.typeAnnotation.typeAnnotation;
128
+ }
129
+ if (param.type === AST_NODE_TYPES.ArrayPattern && param.typeAnnotation) {
130
+ return param.typeAnnotation.typeAnnotation;
131
+ }
132
+ if (param.type === AST_NODE_TYPES.ObjectPattern && param.typeAnnotation) {
133
+ return param.typeAnnotation.typeAnnotation;
134
+ }
135
+ if (param.type === AST_NODE_TYPES.AssignmentPattern) {
136
+ if (param.typeAnnotation) {
137
+ return param.typeAnnotation.typeAnnotation;
138
+ }
139
+ if (param.left.type === AST_NODE_TYPES.Identifier && param.left.typeAnnotation) {
140
+ return param.left.typeAnnotation.typeAnnotation;
141
+ }
142
+ }
143
+ return null;
144
+ }
145
+ function extractParamTypeReferencesWithNodes(params) {
146
+ const references = [];
147
+ for (let i = 1; i < params.length; i++) {
148
+ const param = params[i];
149
+ if (param) {
150
+ const typeAnnotation = getParamTypeAnnotation(param);
151
+ if (typeAnnotation) {
152
+ references.push(...extractTypeReferencesWithNodes(typeAnnotation));
153
+ }
154
+ }
155
+ }
156
+ return references;
157
+ }
158
+ function extractReturnTypeReferencesWithNodes(node) {
159
+ if (node.returnType) {
160
+ return extractTypeReferencesWithNodes(node.returnType.typeAnnotation);
161
+ }
162
+ return [];
163
+ }
164
+ const rule = {
165
+ meta: {
166
+ type: "problem",
167
+ docs: {
168
+ description: "Disallow type-only imports for types used in route/middleFn parameters or return types. Type-only imports are erased at runtime, preventing mion from generating validation and serialization functions."
169
+ },
170
+ messages: {
171
+ noTypeImports: 'Type "{{typeName}}" is imported as type-only but is used in a route/middleFn. Remove the "type" keyword from the import to allow runtime type reflection.'
172
+ },
173
+ schema: []
174
+ },
175
+ defaultOptions: [],
176
+ create(context) {
177
+ let routerImportCache = null;
178
+ let typeOnlyImportCache = null;
179
+ function checkTypeReferencesWithNodes(typeRefs) {
180
+ if (!typeOnlyImportCache) return;
181
+ const reportedTypes = /* @__PURE__ */ new Set();
182
+ for (const { typeName, node } of typeRefs) {
183
+ if (reportedTypes.has(typeName)) continue;
184
+ const importDecl = typeOnlyImportCache.typeOnlyImports.get(typeName);
185
+ if (importDecl) {
186
+ reportedTypes.add(typeName);
187
+ context.report({
188
+ node,
189
+ messageId: "noTypeImports",
190
+ data: { typeName }
191
+ });
192
+ }
193
+ }
194
+ }
195
+ function checkFunctionNode(funcNode) {
196
+ const paramRefs = extractParamTypeReferencesWithNodes(funcNode.params);
197
+ const returnRefs = extractReturnTypeReferencesWithNodes(funcNode);
198
+ const allRefs = [...paramRefs, ...returnRefs];
199
+ checkTypeReferencesWithNodes(allRefs);
200
+ }
201
+ return {
202
+ Program(node) {
203
+ routerImportCache = buildRouterImportCache(node);
204
+ typeOnlyImportCache = buildTypeOnlyImportCache(node);
205
+ },
206
+ CallExpression(node) {
207
+ if (!routerImportCache || !typeOnlyImportCache) return;
208
+ const routerFunctionName = getRouterFunctionName(node, routerImportCache);
209
+ if (!routerFunctionName) return;
210
+ const handler = node.arguments[0];
211
+ if (!handler) return;
212
+ if (handler.type === AST_NODE_TYPES.ArrowFunctionExpression || handler.type === AST_NODE_TYPES.FunctionExpression) {
213
+ checkFunctionNode(handler);
214
+ } else if (handler.type === AST_NODE_TYPES.Identifier) ;
215
+ },
216
+ // Check functions with Handler/HeaderHandler type annotations
217
+ VariableDeclarator(node) {
218
+ if (!routerImportCache || !typeOnlyImportCache) return;
219
+ if (node.id.type === AST_NODE_TYPES.Identifier && node.id.typeAnnotation) {
220
+ const typeAnnotation = node.id.typeAnnotation.typeAnnotation;
221
+ if (typeAnnotation.type === AST_NODE_TYPES.TSTypeReference && typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier && routerImportCache.handlerTypes.has(typeAnnotation.typeName.name)) {
222
+ if (node.init && (node.init.type === AST_NODE_TYPES.ArrowFunctionExpression || node.init.type === AST_NODE_TYPES.FunctionExpression)) {
223
+ checkFunctionNode(node.init);
224
+ }
225
+ }
226
+ }
227
+ if (node.init && node.init.type === AST_NODE_TYPES.TSSatisfiesExpression && node.init.typeAnnotation.type === AST_NODE_TYPES.TSTypeReference && node.init.typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier && routerImportCache.handlerTypes.has(node.init.typeAnnotation.typeName.name)) {
228
+ const expr = node.init.expression;
229
+ if (expr.type === AST_NODE_TYPES.ArrowFunctionExpression || expr.type === AST_NODE_TYPES.FunctionExpression) {
230
+ checkFunctionNode(expr);
231
+ }
232
+ }
233
+ },
234
+ // Check function declarations with JSDoc tags
235
+ FunctionDeclaration(node) {
236
+ if (!routerImportCache || !typeOnlyImportCache) return;
237
+ const sourceCode = context.sourceCode;
238
+ const comments = sourceCode.getCommentsBefore(node);
239
+ for (const comment of comments) {
240
+ if (comment.type === "Block" && (comment.value.includes("@mion:route") || comment.value.includes("@mion:middleFn") || comment.value.includes("@mion:headersFn"))) {
241
+ checkFunctionNode(node);
242
+ break;
243
+ }
244
+ }
245
+ }
246
+ };
247
+ }
248
+ };
249
+ export {
250
+ rule as default
251
+ };
252
+ //# sourceMappingURL=no-type-imports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-type-imports.js","sources":["../../../../../../src/eslint/rules/no-type-imports.ts"],"sourcesContent":["/* ########\n * 2024 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {TSESTree, TSESLint, AST_NODE_TYPES} from '@typescript-eslint/utils';\n\n/** List of router functions that should have strongly typed handlers */\nconst ROUTER_FUNCTIONS = ['route', 'middleFn', 'headersFn'] as const;\n/** List of handler types that can be used with type annotations */\nconst HANDLER_TYPES = ['Handler', 'HeaderHandler'] as const;\n\n/** Cache for imports from @mionjs/router - computed once per file */\ninterface MionRouterImports {\n /** Set of function names imported from @mionjs/router (route, middleFn, headersFn) */\n routerFunctions: Set<string>;\n /** Set of type names imported from @mionjs/router (Handler, HeaderHandler) */\n handlerTypes: Set<string>;\n}\n\n/** Cache for type-only imports - computed once per file */\ninterface TypeOnlyImports {\n /** Map of type name to import declaration node */\n typeOnlyImports: Map<string, TSESTree.ImportDeclaration>;\n}\n\n/** Type reference with its node for precise error reporting */\ninterface TypeRefWithNode {\n typeName: string;\n node: TSESTree.Node;\n}\n\n/** Builds a cache of all imports from @mionjs/router */\nfunction buildRouterImportCache(program: TSESTree.Program): MionRouterImports {\n const routerFunctions = new Set<string>();\n const handlerTypes = new Set<string>();\n\n for (const statement of program.body) {\n if (statement.type === AST_NODE_TYPES.ImportDeclaration) {\n const source = statement.source.value;\n if (source === '@mionjs/router' || source === '@mionjs/router/') {\n for (const specifier of statement.specifiers) {\n if (\n specifier.type === AST_NODE_TYPES.ImportSpecifier &&\n specifier.imported.type === AST_NODE_TYPES.Identifier\n ) {\n const name = specifier.imported.name;\n if (ROUTER_FUNCTIONS.includes(name as (typeof ROUTER_FUNCTIONS)[number])) {\n routerFunctions.add(name);\n }\n if (HANDLER_TYPES.includes(name as (typeof HANDLER_TYPES)[number])) {\n handlerTypes.add(name);\n }\n }\n }\n }\n }\n }\n\n return {routerFunctions, handlerTypes};\n}\n\n/** Builds a cache of all type-only imports */\nfunction buildTypeOnlyImportCache(program: TSESTree.Program): TypeOnlyImports {\n const typeOnlyImports = new Map<string, TSESTree.ImportDeclaration>();\n\n for (const statement of program.body) {\n if (statement.type === AST_NODE_TYPES.ImportDeclaration) {\n // Check if the entire import is type-only: import type { X } from '...'\n const isTypeOnlyImport = statement.importKind === 'type';\n\n for (const specifier of statement.specifiers) {\n if (specifier.type === AST_NODE_TYPES.ImportSpecifier) {\n // Check if individual specifier is type-only: import { type X } from '...'\n const isTypeOnlySpecifier = specifier.importKind === 'type';\n\n if (isTypeOnlyImport || isTypeOnlySpecifier) {\n const localName = specifier.local.name;\n typeOnlyImports.set(localName, statement);\n }\n }\n }\n }\n }\n\n return {typeOnlyImports};\n}\n\n/** Checks if a call expression is calling router functions from @mionjs/router */\nfunction getRouterFunctionName(node: TSESTree.CallExpression, importCache: MionRouterImports): string | null {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) return null;\n const functionName = node.callee.name;\n if (importCache.routerFunctions.has(functionName)) return functionName;\n return null;\n}\n\n/** Extracts all type references with their nodes from a type node recursively */\nfunction extractTypeReferencesWithNodes(typeNode: TSESTree.TypeNode | null | undefined): TypeRefWithNode[] {\n if (!typeNode) return [];\n\n const references: TypeRefWithNode[] = [];\n\n switch (typeNode.type) {\n case AST_NODE_TYPES.TSTypeReference:\n if (typeNode.typeName.type === AST_NODE_TYPES.Identifier) {\n // Report on the type reference node itself (e.g., \"User\" in \": User\")\n references.push({typeName: typeNode.typeName.name, node: typeNode});\n }\n // Also check type arguments (generics)\n if (typeNode.typeArguments) {\n for (const param of typeNode.typeArguments.params) {\n references.push(...extractTypeReferencesWithNodes(param));\n }\n }\n break;\n\n case AST_NODE_TYPES.TSUnionType:\n case AST_NODE_TYPES.TSIntersectionType:\n for (const member of typeNode.types) {\n references.push(...extractTypeReferencesWithNodes(member));\n }\n break;\n\n case AST_NODE_TYPES.TSArrayType:\n references.push(...extractTypeReferencesWithNodes(typeNode.elementType));\n break;\n\n case AST_NODE_TYPES.TSTupleType:\n for (const element of typeNode.elementTypes) {\n references.push(...extractTypeReferencesWithNodes(element));\n }\n break;\n\n case AST_NODE_TYPES.TSTypeLiteral:\n for (const member of typeNode.members) {\n if (member.type === AST_NODE_TYPES.TSPropertySignature && member.typeAnnotation) {\n references.push(...extractTypeReferencesWithNodes(member.typeAnnotation.typeAnnotation));\n }\n }\n break;\n\n case AST_NODE_TYPES.TSConditionalType:\n references.push(...extractTypeReferencesWithNodes(typeNode.checkType));\n references.push(...extractTypeReferencesWithNodes(typeNode.extendsType));\n references.push(...extractTypeReferencesWithNodes(typeNode.trueType));\n references.push(...extractTypeReferencesWithNodes(typeNode.falseType));\n break;\n\n case AST_NODE_TYPES.TSMappedType:\n references.push(...extractTypeReferencesWithNodes(typeNode.typeAnnotation));\n break;\n\n case AST_NODE_TYPES.TSIndexedAccessType:\n references.push(...extractTypeReferencesWithNodes(typeNode.objectType));\n references.push(...extractTypeReferencesWithNodes(typeNode.indexType));\n break;\n\n case AST_NODE_TYPES.TSTypeOperator:\n references.push(...extractTypeReferencesWithNodes(typeNode.typeAnnotation));\n break;\n\n case AST_NODE_TYPES.TSRestType:\n references.push(...extractTypeReferencesWithNodes(typeNode.typeAnnotation));\n break;\n\n case AST_NODE_TYPES.TSOptionalType:\n references.push(...extractTypeReferencesWithNodes(typeNode.typeAnnotation));\n break;\n\n case AST_NODE_TYPES.TSFunctionType:\n case AST_NODE_TYPES.TSConstructorType:\n // Check parameters\n for (const param of typeNode.params) {\n if ('typeAnnotation' in param && param.typeAnnotation) {\n references.push(...extractTypeReferencesWithNodes(param.typeAnnotation.typeAnnotation));\n }\n }\n // Check return type\n if (typeNode.returnType) {\n references.push(...extractTypeReferencesWithNodes(typeNode.returnType.typeAnnotation));\n }\n break;\n }\n\n return references;\n}\n\n/** Gets type annotation from a parameter if it exists */\nfunction getParamTypeAnnotation(param: TSESTree.Parameter): TSESTree.TypeNode | null {\n if (param.type === AST_NODE_TYPES.Identifier && param.typeAnnotation) {\n return param.typeAnnotation.typeAnnotation;\n }\n if (param.type === AST_NODE_TYPES.RestElement && param.typeAnnotation) {\n return param.typeAnnotation.typeAnnotation;\n }\n if (param.type === AST_NODE_TYPES.ArrayPattern && param.typeAnnotation) {\n return param.typeAnnotation.typeAnnotation;\n }\n if (param.type === AST_NODE_TYPES.ObjectPattern && param.typeAnnotation) {\n return param.typeAnnotation.typeAnnotation;\n }\n if (param.type === AST_NODE_TYPES.AssignmentPattern) {\n // Check if there's a type annotation on the pattern itself\n if (param.typeAnnotation) {\n return param.typeAnnotation.typeAnnotation;\n }\n // Check if there's a type annotation on the left side\n if (param.left.type === AST_NODE_TYPES.Identifier && param.left.typeAnnotation) {\n return param.left.typeAnnotation.typeAnnotation;\n }\n }\n return null;\n}\n\n/** Extracts type references with nodes from function parameters (excluding first ctx parameter) */\nfunction extractParamTypeReferencesWithNodes(params: TSESTree.Parameter[]): TypeRefWithNode[] {\n const references: TypeRefWithNode[] = [];\n\n // Skip first parameter (ctx)\n for (let i = 1; i < params.length; i++) {\n const param = params[i];\n if (param) {\n const typeAnnotation = getParamTypeAnnotation(param);\n if (typeAnnotation) {\n references.push(...extractTypeReferencesWithNodes(typeAnnotation));\n }\n }\n }\n\n return references;\n}\n\n/** Extracts type references with nodes from function return type */\nfunction extractReturnTypeReferencesWithNodes(\n node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression | TSESTree.FunctionDeclaration\n): TypeRefWithNode[] {\n if (node.returnType) {\n return extractTypeReferencesWithNodes(node.returnType.typeAnnotation);\n }\n return [];\n}\n\nconst rule: TSESLint.RuleModule<'noTypeImports', []> = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow type-only imports for types used in route/middleFn parameters or return types. Type-only imports are erased at runtime, preventing mion from generating validation and serialization functions.',\n },\n messages: {\n noTypeImports:\n 'Type \"{{typeName}}\" is imported as type-only but is used in a route/middleFn. Remove the \"type\" keyword from the import to allow runtime type reflection.',\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n let routerImportCache: MionRouterImports | null = null;\n let typeOnlyImportCache: TypeOnlyImports | null = null;\n\n /** Reports type-only imports used in handler, highlighting the specific type reference */\n function checkTypeReferencesWithNodes(typeRefs: TypeRefWithNode[]): void {\n if (!typeOnlyImportCache) return;\n\n // Track reported types to avoid duplicates\n const reportedTypes = new Set<string>();\n\n for (const {typeName, node} of typeRefs) {\n // Skip if already reported this type\n if (reportedTypes.has(typeName)) continue;\n\n const importDecl = typeOnlyImportCache.typeOnlyImports.get(typeName);\n if (importDecl) {\n reportedTypes.add(typeName);\n context.report({\n node,\n messageId: 'noTypeImports',\n data: {typeName},\n });\n }\n }\n }\n\n /** Checks a function node for type-only imports */\n function checkFunctionNode(\n funcNode: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression | TSESTree.FunctionDeclaration\n ): void {\n const paramRefs = extractParamTypeReferencesWithNodes(funcNode.params);\n const returnRefs = extractReturnTypeReferencesWithNodes(funcNode);\n const allRefs = [...paramRefs, ...returnRefs];\n\n checkTypeReferencesWithNodes(allRefs);\n }\n\n return {\n Program(node) {\n routerImportCache = buildRouterImportCache(node);\n typeOnlyImportCache = buildTypeOnlyImportCache(node);\n },\n\n CallExpression(node: TSESTree.CallExpression) {\n if (!routerImportCache || !typeOnlyImportCache) return;\n\n const routerFunctionName = getRouterFunctionName(node, routerImportCache);\n if (!routerFunctionName) return;\n\n // Check the first argument (handler function)\n const handler = node.arguments[0];\n if (!handler) return;\n\n if (\n handler.type === AST_NODE_TYPES.ArrowFunctionExpression ||\n handler.type === AST_NODE_TYPES.FunctionExpression\n ) {\n checkFunctionNode(handler);\n } else if (handler.type === AST_NODE_TYPES.Identifier) {\n // Handler is a reference to a function - we need to find the function declaration\n // This is handled by checking function declarations with Handler/HeaderHandler type annotations\n }\n },\n\n // Check functions with Handler/HeaderHandler type annotations\n VariableDeclarator(node: TSESTree.VariableDeclarator) {\n if (!routerImportCache || !typeOnlyImportCache) return;\n\n // Check if the variable has a Handler or HeaderHandler type annotation\n if (node.id.type === AST_NODE_TYPES.Identifier && node.id.typeAnnotation) {\n const typeAnnotation = node.id.typeAnnotation.typeAnnotation;\n if (\n typeAnnotation.type === AST_NODE_TYPES.TSTypeReference &&\n typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier &&\n routerImportCache.handlerTypes.has(typeAnnotation.typeName.name)\n ) {\n // This is a handler with type annotation\n if (\n node.init &&\n (node.init.type === AST_NODE_TYPES.ArrowFunctionExpression ||\n node.init.type === AST_NODE_TYPES.FunctionExpression)\n ) {\n checkFunctionNode(node.init);\n }\n }\n }\n\n // Check for satisfies expressions\n if (\n node.init &&\n node.init.type === AST_NODE_TYPES.TSSatisfiesExpression &&\n node.init.typeAnnotation.type === AST_NODE_TYPES.TSTypeReference &&\n node.init.typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier &&\n routerImportCache.handlerTypes.has(node.init.typeAnnotation.typeName.name)\n ) {\n const expr = node.init.expression;\n if (expr.type === AST_NODE_TYPES.ArrowFunctionExpression || expr.type === AST_NODE_TYPES.FunctionExpression) {\n checkFunctionNode(expr);\n }\n }\n },\n\n // Check function declarations with JSDoc tags\n FunctionDeclaration(node: TSESTree.FunctionDeclaration) {\n if (!routerImportCache || !typeOnlyImportCache) return;\n\n // Check for JSDoc tags\n const sourceCode = context.sourceCode;\n const comments = sourceCode.getCommentsBefore(node);\n\n for (const comment of comments) {\n if (\n comment.type === 'Block' &&\n (comment.value.includes('@mion:route') ||\n comment.value.includes('@mion:middleFn') ||\n comment.value.includes('@mion:headersFn'))\n ) {\n checkFunctionNode(node);\n break;\n }\n }\n },\n };\n },\n};\n\nexport default rule;\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ declare const rule: TSESLint.RuleModule<'noTypeof', []>;
3
+ export default rule;
@@ -0,0 +1,73 @@
1
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
2
+ function containsTypeof(typeNode) {
3
+ if (!typeNode) return false;
4
+ switch (typeNode.type) {
5
+ case AST_NODE_TYPES.TSTypeQuery:
6
+ return true;
7
+ case AST_NODE_TYPES.TSUnionType:
8
+ case AST_NODE_TYPES.TSIntersectionType:
9
+ return typeNode.types.some(containsTypeof);
10
+ case AST_NODE_TYPES.TSTupleType:
11
+ return typeNode.elementTypes.some(containsTypeof);
12
+ default:
13
+ return false;
14
+ }
15
+ }
16
+ function isRunTypeFromMionKit(node, context) {
17
+ const runTypeFunctions = ["runType", "isTypeFn", "typeErrorsFn", "mockTypeFn", "toJavascriptFn"];
18
+ if (node.callee.type !== AST_NODE_TYPES.Identifier || !runTypeFunctions.includes(node.callee.name)) {
19
+ return false;
20
+ }
21
+ const sourceCode = context.sourceCode;
22
+ const program = sourceCode.ast;
23
+ for (const statement of program.body) {
24
+ if (statement.type === AST_NODE_TYPES.ImportDeclaration) {
25
+ const source = statement.source.value;
26
+ if (source === "@mionjs/run-types" || source === "@mionjs/run-types/" || typeof source === "string" && (source.endsWith("/runType") || source.endsWith("/runTypeFunctions"))) {
27
+ for (const specifier of statement.specifiers) {
28
+ if (specifier.type === AST_NODE_TYPES.ImportSpecifier && specifier.imported.type === AST_NODE_TYPES.Identifier && runTypeFunctions.includes(specifier.imported.name)) {
29
+ return true;
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ return false;
36
+ }
37
+ const rule = {
38
+ meta: {
39
+ type: "problem",
40
+ docs: {
41
+ description: "Disallow using `typeof` with run-type functions from @mionjs/run-types"
42
+ },
43
+ messages: {
44
+ noTypeof: "Do not use `typeof` with `{{functionName}}()`. Use explicit type definitions instead."
45
+ },
46
+ schema: []
47
+ // No options
48
+ },
49
+ defaultOptions: [],
50
+ create(context) {
51
+ return {
52
+ CallExpression(node) {
53
+ if (isRunTypeFromMionKit(node, context)) {
54
+ const typeArguments = node.typeArguments || node.typeParameters;
55
+ if (typeArguments?.params.some(containsTypeof)) {
56
+ const functionName = node.callee.name;
57
+ context.report({
58
+ node,
59
+ messageId: "noTypeof",
60
+ data: {
61
+ functionName
62
+ }
63
+ });
64
+ }
65
+ }
66
+ }
67
+ };
68
+ }
69
+ };
70
+ export {
71
+ rule as default
72
+ };
73
+ //# sourceMappingURL=no-typeof-runtype.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-typeof-runtype.js","sources":["../../../../../../src/eslint/rules/no-typeof-runtype.ts"],"sourcesContent":["/* ########\n * 2024 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {TSESTree, TSESLint, AST_NODE_TYPES} from '@typescript-eslint/utils';\n\n/**\n * Recursively checks if a type node contains `typeof`.\n * @param typeNode The type node to check.\n * @returns True if `typeof` is found, otherwise false.\n */\nfunction containsTypeof(typeNode: TSESTree.Node | null): boolean {\n if (!typeNode) return false;\n\n switch (typeNode.type) {\n case AST_NODE_TYPES.TSTypeQuery:\n return true;\n case AST_NODE_TYPES.TSUnionType:\n case AST_NODE_TYPES.TSIntersectionType:\n return typeNode.types.some(containsTypeof);\n case AST_NODE_TYPES.TSTupleType:\n return typeNode.elementTypes.some(containsTypeof);\n default:\n return false;\n }\n}\n\n/**\n * Checks if a call expression is calling runType or related functions from @mionjs/run-types\n * @param node The call expression node\n * @param context The ESLint context\n * @returns True if it's a runType or related function call from @mionjs/run-types\n */\nfunction isRunTypeFromMionKit(node: TSESTree.CallExpression, context: TSESLint.RuleContext<any, any>): boolean {\n // List of functions that should not use typeof\n const runTypeFunctions = ['runType', 'isTypeFn', 'typeErrorsFn', 'mockTypeFn', 'toJavascriptFn'];\n\n // Check if the callee is an identifier with one of the runType function names\n if (node.callee.type !== AST_NODE_TYPES.Identifier || !runTypeFunctions.includes(node.callee.name)) {\n return false;\n }\n\n // Get the source code to check imports\n const sourceCode = context.sourceCode;\n const program = sourceCode.ast;\n\n // Look for import statements that import runType or related functions from @mionjs/run-types or relative paths\n for (const statement of program.body) {\n if (statement.type === AST_NODE_TYPES.ImportDeclaration) {\n const source = statement.source.value;\n // Check for @mionjs/run-types package or relative imports that end with runType or runTypeFunctions\n if (\n source === '@mionjs/run-types' ||\n source === '@mionjs/run-types/' ||\n (typeof source === 'string' && (source.endsWith('/runType') || source.endsWith('/runTypeFunctions')))\n ) {\n // Check if any of the runType functions are imported\n for (const specifier of statement.specifiers) {\n if (\n specifier.type === AST_NODE_TYPES.ImportSpecifier &&\n specifier.imported.type === AST_NODE_TYPES.Identifier &&\n runTypeFunctions.includes(specifier.imported.name)\n ) {\n return true;\n }\n }\n }\n }\n }\n\n return false;\n}\n\nconst rule: TSESLint.RuleModule<'noTypeof', []> = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Disallow using `typeof` with run-type functions from @mionjs/run-types',\n },\n messages: {\n noTypeof: 'Do not use `typeof` with `{{functionName}}()`. Use explicit type definitions instead.',\n },\n schema: [], // No options\n },\n defaultOptions: [],\n create(context) {\n return {\n CallExpression(node: TSESTree.CallExpression) {\n // Ensure the function being called is a run-type function from @mionjs/run-types\n if (isRunTypeFromMionKit(node, context)) {\n // Check if type arguments contain typeof\n const typeArguments = (node as any).typeArguments || (node as any).typeParameters;\n if (typeArguments?.params.some(containsTypeof)) {\n const functionName = (node.callee as TSESTree.Identifier).name;\n context.report({\n node,\n messageId: 'noTypeof',\n data: {\n functionName,\n },\n });\n }\n }\n },\n };\n },\n};\n\nexport default rule;\n"],"names":[],"mappings":";AAcA,SAAS,eAAe,UAAyC;AAC7D,MAAI,CAAC,SAAU,QAAO;AAEtB,UAAQ,SAAS,MAAA;AAAA,IACb,KAAK,eAAe;AAChB,aAAO;AAAA,IACX,KAAK,eAAe;AAAA,IACpB,KAAK,eAAe;AAChB,aAAO,SAAS,MAAM,KAAK,cAAc;AAAA,IAC7C,KAAK,eAAe;AAChB,aAAO,SAAS,aAAa,KAAK,cAAc;AAAA,IACpD;AACI,aAAO;AAAA,EAAA;AAEnB;AAQA,SAAS,qBAAqB,MAA+B,SAAkD;AAE3G,QAAM,mBAAmB,CAAC,WAAW,YAAY,gBAAgB,cAAc,gBAAgB;AAG/F,MAAI,KAAK,OAAO,SAAS,eAAe,cAAc,CAAC,iBAAiB,SAAS,KAAK,OAAO,IAAI,GAAG;AAChG,WAAO;AAAA,EACX;AAGA,QAAM,aAAa,QAAQ;AAC3B,QAAM,UAAU,WAAW;AAG3B,aAAW,aAAa,QAAQ,MAAM;AAClC,QAAI,UAAU,SAAS,eAAe,mBAAmB;AACrD,YAAM,SAAS,UAAU,OAAO;AAEhC,UACI,WAAW,uBACX,WAAW,wBACV,OAAO,WAAW,aAAa,OAAO,SAAS,UAAU,KAAK,OAAO,SAAS,mBAAmB,IACpG;AAEE,mBAAW,aAAa,UAAU,YAAY;AAC1C,cACI,UAAU,SAAS,eAAe,mBAClC,UAAU,SAAS,SAAS,eAAe,cAC3C,iBAAiB,SAAS,UAAU,SAAS,IAAI,GACnD;AACE,mBAAO;AAAA,UACX;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO;AACX;AAEA,MAAM,OAA4C;AAAA,EAC9C,MAAM;AAAA,IACF,MAAM;AAAA,IACN,MAAM;AAAA,MACF,aAAa;AAAA,IAAA;AAAA,IAEjB,UAAU;AAAA,MACN,UAAU;AAAA,IAAA;AAAA,IAEd,QAAQ,CAAA;AAAA;AAAA,EAAC;AAAA,EAEb,gBAAgB,CAAA;AAAA,EAChB,OAAO,SAAS;AACZ,WAAO;AAAA,MACH,eAAe,MAA+B;AAE1C,YAAI,qBAAqB,MAAM,OAAO,GAAG;AAErC,gBAAM,gBAAiB,KAAa,iBAAkB,KAAa;AACnE,cAAI,eAAe,OAAO,KAAK,cAAc,GAAG;AAC5C,kBAAM,eAAgB,KAAK,OAA+B;AAC1D,oBAAQ,OAAO;AAAA,cACX;AAAA,cACA,WAAW;AAAA,cACX,MAAM;AAAA,gBACF;AAAA,cAAA;AAAA,YACJ,CACH;AAAA,UACL;AAAA,QACJ;AAAA,MACJ;AAAA,IAAA;AAAA,EAER;AACJ;"}
@@ -0,0 +1,3 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ declare const rule: TSESLint.RuleModule<'unreachableUnionType', []>;
3
+ export default rule;
@@ -0,0 +1,221 @@
1
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
2
+ function getObjectTypeProperties(node) {
3
+ if (node.type === AST_NODE_TYPES.TSTypeLiteral) {
4
+ const props = [];
5
+ for (const member of node.members) {
6
+ if (member.type === AST_NODE_TYPES.TSPropertySignature && member.key.type === AST_NODE_TYPES.Identifier) {
7
+ props.push({ name: member.key.name, isOptional: !!member.optional });
8
+ }
9
+ }
10
+ return props;
11
+ }
12
+ return null;
13
+ }
14
+ function isSupersetOf(typeAProps, typeBProps) {
15
+ const typeARequired = typeAProps.filter((p) => !p.isOptional);
16
+ const typeBRequired = typeBProps.filter((p) => !p.isOptional);
17
+ if (typeARequired.length < typeBRequired.length) return false;
18
+ const isMoreSpecific = typeAProps.length > typeBProps.length || typeAProps.length === typeBProps.length && typeARequired.length > typeBRequired.length;
19
+ if (!isMoreSpecific) return false;
20
+ for (const propB of typeBProps) {
21
+ const propA = typeAProps.find((p) => p.name === propB.name);
22
+ if (!propA) return false;
23
+ }
24
+ return true;
25
+ }
26
+ function findUnreachableTypes(unionNode) {
27
+ const issues = [];
28
+ const typesWithProps = [];
29
+ for (const typeNode of unionNode.types) {
30
+ const props = getObjectTypeProperties(typeNode);
31
+ if (props && props.length > 0) {
32
+ typesWithProps.push({ node: typeNode, props });
33
+ }
34
+ }
35
+ for (let i = 0; i < typesWithProps.length; i++) {
36
+ for (let j = i + 1; j < typesWithProps.length; j++) {
37
+ const typeA = typesWithProps[i];
38
+ const typeB = typesWithProps[j];
39
+ if (isSupersetOf(typeB.props, typeA.props)) {
40
+ issues.push({ unreachable: typeB.node, blocker: typeA.node });
41
+ }
42
+ }
43
+ }
44
+ return issues;
45
+ }
46
+ function getTypeDescription(node) {
47
+ if (node.type === AST_NODE_TYPES.TSTypeLiteral) {
48
+ const props = getObjectTypeProperties(node);
49
+ if (props) {
50
+ return `{${props.map((p) => p.isOptional ? `${p.name}?` : p.name).join(", ")}}`;
51
+ }
52
+ }
53
+ return "object type";
54
+ }
55
+ function getRouterFunctionName(func, context) {
56
+ const parent = func.parent;
57
+ if (parent?.type === AST_NODE_TYPES.CallExpression) {
58
+ if (parent.callee.type === AST_NODE_TYPES.Identifier) {
59
+ const functionName = parent.callee.name;
60
+ if (["route", "middleFn", "headersFn"].includes(functionName) && isImportedFromMionRouter(functionName, context)) {
61
+ return functionName;
62
+ }
63
+ }
64
+ }
65
+ return null;
66
+ }
67
+ function isInCheckableParameter(node, func, routerFunctionName) {
68
+ let current = node.parent;
69
+ while (current && current !== func) {
70
+ if (current.type === AST_NODE_TYPES.Identifier || current.type === AST_NODE_TYPES.ArrayPattern || current.type === AST_NODE_TYPES.ObjectPattern) {
71
+ const paramIndex = func.params.indexOf(current);
72
+ if (paramIndex !== -1) {
73
+ if ((routerFunctionName === "route" || routerFunctionName === "middleFn") && paramIndex >= 1) {
74
+ return true;
75
+ }
76
+ if (routerFunctionName === "headersFn" && paramIndex >= 2) {
77
+ return true;
78
+ }
79
+ return false;
80
+ }
81
+ }
82
+ current = current.parent;
83
+ }
84
+ return false;
85
+ }
86
+ function isRouterUnionType(node, context) {
87
+ let current = node.parent;
88
+ while (current) {
89
+ if (current.type === AST_NODE_TYPES.ArrowFunctionExpression || current.type === AST_NODE_TYPES.FunctionExpression || current.type === AST_NODE_TYPES.FunctionDeclaration) {
90
+ const routerFunctionName = getRouterFunctionName(current, context);
91
+ if (routerFunctionName) {
92
+ if (current.returnType?.typeAnnotation === node || isDescendantOf(node, current.returnType?.typeAnnotation)) {
93
+ return true;
94
+ }
95
+ if (isInCheckableParameter(node, current, routerFunctionName)) {
96
+ return true;
97
+ }
98
+ }
99
+ }
100
+ if (current.type === AST_NODE_TYPES.TSTypeAnnotation) {
101
+ const typeAnnotationParent = current.parent;
102
+ if (typeAnnotationParent?.type === AST_NODE_TYPES.Identifier) {
103
+ const declarator = typeAnnotationParent.parent;
104
+ if (declarator?.type === AST_NODE_TYPES.VariableDeclarator) {
105
+ if (current.typeAnnotation.type === AST_NODE_TYPES.TSTypeReference) {
106
+ const typeName = current.typeAnnotation.typeName;
107
+ if (typeName.type === AST_NODE_TYPES.Identifier) {
108
+ if ((typeName.name === "Handler" || typeName.name === "HeaderHandler") && isImportedFromMionRouter(typeName.name, context)) {
109
+ return true;
110
+ }
111
+ }
112
+ }
113
+ }
114
+ }
115
+ }
116
+ current = current.parent;
117
+ }
118
+ return false;
119
+ }
120
+ function isDescendantOf(node, ancestor) {
121
+ if (!node || !ancestor) return false;
122
+ let current = node;
123
+ while (current) {
124
+ if (current === ancestor) return true;
125
+ current = current.parent;
126
+ }
127
+ return false;
128
+ }
129
+ function isImportedFromMionRouter(name, context) {
130
+ const sourceCode = context.sourceCode;
131
+ const program = sourceCode.ast;
132
+ for (const statement of program.body) {
133
+ if (statement.type === AST_NODE_TYPES.ImportDeclaration) {
134
+ const source = statement.source.value;
135
+ if (source === "@mionjs/router" || source === "@mionjs/router/") {
136
+ for (const specifier of statement.specifiers) {
137
+ if (specifier.type === AST_NODE_TYPES.ImportSpecifier && specifier.imported.type === AST_NODE_TYPES.Identifier && specifier.imported.name === name) {
138
+ return true;
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ return false;
145
+ }
146
+ function resolveTypeReference(node, context) {
147
+ if (node.type !== AST_NODE_TYPES.TSTypeReference) {
148
+ return null;
149
+ }
150
+ if (node.typeName.type !== AST_NODE_TYPES.Identifier) {
151
+ return null;
152
+ }
153
+ const typeName = node.typeName.name;
154
+ const sourceCode = context.sourceCode;
155
+ const program = sourceCode.ast;
156
+ for (const statement of program.body) {
157
+ if (statement.type === AST_NODE_TYPES.TSTypeAliasDeclaration) {
158
+ if (statement.id.name === typeName && statement.typeAnnotation.type === AST_NODE_TYPES.TSUnionType) {
159
+ return statement.typeAnnotation;
160
+ }
161
+ }
162
+ }
163
+ return null;
164
+ }
165
+ const rule = {
166
+ meta: {
167
+ type: "problem",
168
+ docs: {
169
+ description: "Detect union types where one interface is unreachable at runtime when using isType function because a subset type comes before it"
170
+ },
171
+ messages: {
172
+ unreachableUnionType: "Union type {{unreachableType}} is unreachable at runtime when doing type checking because {{blockerType}} will always match first. To fix this move the more specific type {{unreachableType}} first within the union, ie: {{unreachableType}} | {{blockerType}} "
173
+ },
174
+ schema: []
175
+ },
176
+ defaultOptions: [],
177
+ create(context) {
178
+ return {
179
+ TSUnionType(node) {
180
+ if (!isRouterUnionType(node, context)) {
181
+ return;
182
+ }
183
+ const issues = findUnreachableTypes(node);
184
+ for (const issue of issues) {
185
+ context.report({
186
+ node,
187
+ messageId: "unreachableUnionType",
188
+ data: {
189
+ unreachableType: getTypeDescription(issue.unreachable),
190
+ blockerType: getTypeDescription(issue.blocker)
191
+ }
192
+ });
193
+ }
194
+ },
195
+ TSTypeReference(node) {
196
+ const unionType = resolveTypeReference(node, context);
197
+ if (!unionType) {
198
+ return;
199
+ }
200
+ if (!isRouterUnionType(node, context)) {
201
+ return;
202
+ }
203
+ const issues = findUnreachableTypes(unionType);
204
+ for (const issue of issues) {
205
+ context.report({
206
+ node,
207
+ messageId: "unreachableUnionType",
208
+ data: {
209
+ unreachableType: getTypeDescription(issue.unreachable),
210
+ blockerType: getTypeDescription(issue.blocker)
211
+ }
212
+ });
213
+ }
214
+ }
215
+ };
216
+ }
217
+ };
218
+ export {
219
+ rule as default
220
+ };
221
+ //# sourceMappingURL=no-unreachable-union-types.js.map