driftdetect-core 0.1.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 (221) hide show
  1. package/dist/analyzers/ast-analyzer.d.ts +251 -0
  2. package/dist/analyzers/ast-analyzer.d.ts.map +1 -0
  3. package/dist/analyzers/ast-analyzer.js +548 -0
  4. package/dist/analyzers/ast-analyzer.js.map +1 -0
  5. package/dist/analyzers/flow-analyzer.d.ts +241 -0
  6. package/dist/analyzers/flow-analyzer.d.ts.map +1 -0
  7. package/dist/analyzers/flow-analyzer.js +1219 -0
  8. package/dist/analyzers/flow-analyzer.js.map +1 -0
  9. package/dist/analyzers/index.d.ts +18 -0
  10. package/dist/analyzers/index.d.ts.map +1 -0
  11. package/dist/analyzers/index.js +19 -0
  12. package/dist/analyzers/index.js.map +1 -0
  13. package/dist/analyzers/semantic-analyzer.d.ts +252 -0
  14. package/dist/analyzers/semantic-analyzer.d.ts.map +1 -0
  15. package/dist/analyzers/semantic-analyzer.js +1182 -0
  16. package/dist/analyzers/semantic-analyzer.js.map +1 -0
  17. package/dist/analyzers/type-analyzer.d.ts +289 -0
  18. package/dist/analyzers/type-analyzer.d.ts.map +1 -0
  19. package/dist/analyzers/type-analyzer.js +1269 -0
  20. package/dist/analyzers/type-analyzer.js.map +1 -0
  21. package/dist/analyzers/types.d.ts +537 -0
  22. package/dist/analyzers/types.d.ts.map +1 -0
  23. package/dist/analyzers/types.js +11 -0
  24. package/dist/analyzers/types.js.map +1 -0
  25. package/dist/config/config-loader.d.ts +166 -0
  26. package/dist/config/config-loader.d.ts.map +1 -0
  27. package/dist/config/config-loader.js +429 -0
  28. package/dist/config/config-loader.js.map +1 -0
  29. package/dist/config/config-validator.d.ts +204 -0
  30. package/dist/config/config-validator.d.ts.map +1 -0
  31. package/dist/config/config-validator.js +632 -0
  32. package/dist/config/config-validator.js.map +1 -0
  33. package/dist/config/defaults.d.ts +8 -0
  34. package/dist/config/defaults.d.ts.map +1 -0
  35. package/dist/config/defaults.js +26 -0
  36. package/dist/config/defaults.js.map +1 -0
  37. package/dist/config/index.d.ts +10 -0
  38. package/dist/config/index.d.ts.map +1 -0
  39. package/dist/config/index.js +10 -0
  40. package/dist/config/index.js.map +1 -0
  41. package/dist/config/types.d.ts +47 -0
  42. package/dist/config/types.d.ts.map +1 -0
  43. package/dist/config/types.js +7 -0
  44. package/dist/config/types.js.map +1 -0
  45. package/dist/index.d.ts +37 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +39 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/manifest/exporter.d.ts +21 -0
  50. package/dist/manifest/exporter.d.ts.map +1 -0
  51. package/dist/manifest/exporter.js +339 -0
  52. package/dist/manifest/exporter.js.map +1 -0
  53. package/dist/manifest/index.d.ts +14 -0
  54. package/dist/manifest/index.d.ts.map +1 -0
  55. package/dist/manifest/index.js +15 -0
  56. package/dist/manifest/index.js.map +1 -0
  57. package/dist/manifest/manifest-store.d.ts +111 -0
  58. package/dist/manifest/manifest-store.d.ts.map +1 -0
  59. package/dist/manifest/manifest-store.js +418 -0
  60. package/dist/manifest/manifest-store.js.map +1 -0
  61. package/dist/manifest/types.d.ts +238 -0
  62. package/dist/manifest/types.d.ts.map +1 -0
  63. package/dist/manifest/types.js +11 -0
  64. package/dist/manifest/types.js.map +1 -0
  65. package/dist/matcher/confidence-scorer.d.ts +188 -0
  66. package/dist/matcher/confidence-scorer.d.ts.map +1 -0
  67. package/dist/matcher/confidence-scorer.js +302 -0
  68. package/dist/matcher/confidence-scorer.js.map +1 -0
  69. package/dist/matcher/index.d.ts +24 -0
  70. package/dist/matcher/index.d.ts.map +1 -0
  71. package/dist/matcher/index.js +26 -0
  72. package/dist/matcher/index.js.map +1 -0
  73. package/dist/matcher/outlier-detector.d.ts +252 -0
  74. package/dist/matcher/outlier-detector.d.ts.map +1 -0
  75. package/dist/matcher/outlier-detector.js +544 -0
  76. package/dist/matcher/outlier-detector.js.map +1 -0
  77. package/dist/matcher/pattern-matcher.d.ts +169 -0
  78. package/dist/matcher/pattern-matcher.d.ts.map +1 -0
  79. package/dist/matcher/pattern-matcher.js +692 -0
  80. package/dist/matcher/pattern-matcher.js.map +1 -0
  81. package/dist/matcher/types.d.ts +476 -0
  82. package/dist/matcher/types.d.ts.map +1 -0
  83. package/dist/matcher/types.js +36 -0
  84. package/dist/matcher/types.js.map +1 -0
  85. package/dist/parsers/base-parser.d.ts +282 -0
  86. package/dist/parsers/base-parser.d.ts.map +1 -0
  87. package/dist/parsers/base-parser.js +421 -0
  88. package/dist/parsers/base-parser.js.map +1 -0
  89. package/dist/parsers/css-parser.d.ts +225 -0
  90. package/dist/parsers/css-parser.d.ts.map +1 -0
  91. package/dist/parsers/css-parser.js +477 -0
  92. package/dist/parsers/css-parser.js.map +1 -0
  93. package/dist/parsers/index.d.ts +15 -0
  94. package/dist/parsers/index.d.ts.map +1 -0
  95. package/dist/parsers/index.js +15 -0
  96. package/dist/parsers/index.js.map +1 -0
  97. package/dist/parsers/json-parser.d.ts +219 -0
  98. package/dist/parsers/json-parser.d.ts.map +1 -0
  99. package/dist/parsers/json-parser.js +602 -0
  100. package/dist/parsers/json-parser.js.map +1 -0
  101. package/dist/parsers/markdown-parser.d.ts +276 -0
  102. package/dist/parsers/markdown-parser.d.ts.map +1 -0
  103. package/dist/parsers/markdown-parser.js +731 -0
  104. package/dist/parsers/markdown-parser.js.map +1 -0
  105. package/dist/parsers/parser-manager.d.ts +294 -0
  106. package/dist/parsers/parser-manager.d.ts.map +1 -0
  107. package/dist/parsers/parser-manager.js +738 -0
  108. package/dist/parsers/parser-manager.js.map +1 -0
  109. package/dist/parsers/python-parser.d.ts +204 -0
  110. package/dist/parsers/python-parser.d.ts.map +1 -0
  111. package/dist/parsers/python-parser.js +517 -0
  112. package/dist/parsers/python-parser.js.map +1 -0
  113. package/dist/parsers/types.d.ts +43 -0
  114. package/dist/parsers/types.d.ts.map +1 -0
  115. package/dist/parsers/types.js +7 -0
  116. package/dist/parsers/types.js.map +1 -0
  117. package/dist/parsers/typescript-parser.d.ts +264 -0
  118. package/dist/parsers/typescript-parser.d.ts.map +1 -0
  119. package/dist/parsers/typescript-parser.js +658 -0
  120. package/dist/parsers/typescript-parser.js.map +1 -0
  121. package/dist/rules/evaluator.d.ts +305 -0
  122. package/dist/rules/evaluator.d.ts.map +1 -0
  123. package/dist/rules/evaluator.js +579 -0
  124. package/dist/rules/evaluator.js.map +1 -0
  125. package/dist/rules/index.d.ts +13 -0
  126. package/dist/rules/index.d.ts.map +1 -0
  127. package/dist/rules/index.js +13 -0
  128. package/dist/rules/index.js.map +1 -0
  129. package/dist/rules/quick-fix-generator.d.ts +334 -0
  130. package/dist/rules/quick-fix-generator.d.ts.map +1 -0
  131. package/dist/rules/quick-fix-generator.js +1075 -0
  132. package/dist/rules/quick-fix-generator.js.map +1 -0
  133. package/dist/rules/rule-engine.d.ts +241 -0
  134. package/dist/rules/rule-engine.d.ts.map +1 -0
  135. package/dist/rules/rule-engine.js +585 -0
  136. package/dist/rules/rule-engine.js.map +1 -0
  137. package/dist/rules/severity-manager.d.ts +394 -0
  138. package/dist/rules/severity-manager.d.ts.map +1 -0
  139. package/dist/rules/severity-manager.js +619 -0
  140. package/dist/rules/severity-manager.js.map +1 -0
  141. package/dist/rules/types.d.ts +370 -0
  142. package/dist/rules/types.d.ts.map +1 -0
  143. package/dist/rules/types.js +133 -0
  144. package/dist/rules/types.js.map +1 -0
  145. package/dist/rules/variant-manager.d.ts +388 -0
  146. package/dist/rules/variant-manager.d.ts.map +1 -0
  147. package/dist/rules/variant-manager.js +777 -0
  148. package/dist/rules/variant-manager.js.map +1 -0
  149. package/dist/scanner/change-detector.d.ts +164 -0
  150. package/dist/scanner/change-detector.d.ts.map +1 -0
  151. package/dist/scanner/change-detector.js +263 -0
  152. package/dist/scanner/change-detector.js.map +1 -0
  153. package/dist/scanner/dependency-graph.d.ts +270 -0
  154. package/dist/scanner/dependency-graph.d.ts.map +1 -0
  155. package/dist/scanner/dependency-graph.js +436 -0
  156. package/dist/scanner/dependency-graph.js.map +1 -0
  157. package/dist/scanner/file-walker.d.ts +127 -0
  158. package/dist/scanner/file-walker.d.ts.map +1 -0
  159. package/dist/scanner/file-walker.js +526 -0
  160. package/dist/scanner/file-walker.js.map +1 -0
  161. package/dist/scanner/index.d.ts +12 -0
  162. package/dist/scanner/index.d.ts.map +1 -0
  163. package/dist/scanner/index.js +12 -0
  164. package/dist/scanner/index.js.map +1 -0
  165. package/dist/scanner/types.d.ts +218 -0
  166. package/dist/scanner/types.d.ts.map +1 -0
  167. package/dist/scanner/types.js +10 -0
  168. package/dist/scanner/types.js.map +1 -0
  169. package/dist/scanner/worker-pool.d.ts +317 -0
  170. package/dist/scanner/worker-pool.d.ts.map +1 -0
  171. package/dist/scanner/worker-pool.js +571 -0
  172. package/dist/scanner/worker-pool.js.map +1 -0
  173. package/dist/store/cache-manager.d.ts +179 -0
  174. package/dist/store/cache-manager.d.ts.map +1 -0
  175. package/dist/store/cache-manager.js +391 -0
  176. package/dist/store/cache-manager.js.map +1 -0
  177. package/dist/store/history-store.d.ts +314 -0
  178. package/dist/store/history-store.d.ts.map +1 -0
  179. package/dist/store/history-store.js +707 -0
  180. package/dist/store/history-store.js.map +1 -0
  181. package/dist/store/index.d.ts +20 -0
  182. package/dist/store/index.d.ts.map +1 -0
  183. package/dist/store/index.js +26 -0
  184. package/dist/store/index.js.map +1 -0
  185. package/dist/store/lock-file-manager.d.ts +202 -0
  186. package/dist/store/lock-file-manager.d.ts.map +1 -0
  187. package/dist/store/lock-file-manager.js +475 -0
  188. package/dist/store/lock-file-manager.js.map +1 -0
  189. package/dist/store/pattern-store.d.ts +289 -0
  190. package/dist/store/pattern-store.d.ts.map +1 -0
  191. package/dist/store/pattern-store.js +936 -0
  192. package/dist/store/pattern-store.js.map +1 -0
  193. package/dist/store/schema-validator.d.ts +159 -0
  194. package/dist/store/schema-validator.d.ts.map +1 -0
  195. package/dist/store/schema-validator.js +1096 -0
  196. package/dist/store/schema-validator.js.map +1 -0
  197. package/dist/store/types.d.ts +585 -0
  198. package/dist/store/types.d.ts.map +1 -0
  199. package/dist/store/types.js +82 -0
  200. package/dist/store/types.js.map +1 -0
  201. package/dist/types/analysis.d.ts +19 -0
  202. package/dist/types/analysis.d.ts.map +1 -0
  203. package/dist/types/analysis.js +5 -0
  204. package/dist/types/analysis.js.map +1 -0
  205. package/dist/types/common.d.ts +7 -0
  206. package/dist/types/common.d.ts.map +1 -0
  207. package/dist/types/common.js +5 -0
  208. package/dist/types/common.js.map +1 -0
  209. package/dist/types/index.d.ts +12 -0
  210. package/dist/types/index.d.ts.map +1 -0
  211. package/dist/types/index.js +10 -0
  212. package/dist/types/index.js.map +1 -0
  213. package/dist/types/patterns.d.ts +40 -0
  214. package/dist/types/patterns.d.ts.map +1 -0
  215. package/dist/types/patterns.js +7 -0
  216. package/dist/types/patterns.js.map +1 -0
  217. package/dist/types/violations.d.ts +7 -0
  218. package/dist/types/violations.d.ts.map +1 -0
  219. package/dist/types/violations.js +7 -0
  220. package/dist/types/violations.js.map +1 -0
  221. package/package.json +46 -0
@@ -0,0 +1,1269 @@
1
+ /**
2
+ * Type Analyzer - TypeScript type information extraction and analysis
3
+ *
4
+ * Provides type extraction from AST nodes, type relationship analysis,
5
+ * type compatibility checking, and type coverage calculation.
6
+ *
7
+ * @requirements 3.5 - Parser SHALL provide a unified AST query interface across all languages
8
+ */
9
+ /**
10
+ * Primitive type names
11
+ */
12
+ const PRIMITIVE_TYPES = new Set([
13
+ 'string',
14
+ 'number',
15
+ 'boolean',
16
+ 'bigint',
17
+ 'symbol',
18
+ 'null',
19
+ 'undefined',
20
+ 'void',
21
+ 'never',
22
+ 'any',
23
+ 'unknown',
24
+ ]);
25
+ /**
26
+ * TypeScript utility types
27
+ */
28
+ const UTILITY_TYPES = new Set([
29
+ 'Partial',
30
+ 'Required',
31
+ 'Readonly',
32
+ 'Record',
33
+ 'Pick',
34
+ 'Omit',
35
+ 'Exclude',
36
+ 'Extract',
37
+ 'NonNullable',
38
+ 'Parameters',
39
+ 'ConstructorParameters',
40
+ 'ReturnType',
41
+ 'InstanceType',
42
+ 'ThisParameterType',
43
+ 'OmitThisParameter',
44
+ 'ThisType',
45
+ 'Awaited',
46
+ ]);
47
+ /**
48
+ * Type Analyzer class for TypeScript type information extraction and analysis.
49
+ *
50
+ * Provides a unified interface for analyzing type information across
51
+ * TypeScript and JavaScript code.
52
+ *
53
+ * @requirements 3.5 - Unified AST query interface across all languages
54
+ */
55
+ export class TypeAnalyzer {
56
+ /** Cache for resolved types */
57
+ typeCache = new Map();
58
+ /** Type definitions found during analysis */
59
+ typeDefinitions = new Map();
60
+ /**
61
+ * Extract type information from an AST node.
62
+ *
63
+ * @param node - The AST node to extract type from
64
+ * @param options - Extraction options
65
+ * @returns Type information or null if no type found
66
+ */
67
+ extractType(node, options = {}) {
68
+ const { maxDepth = 10 } = options;
69
+ return this.extractTypeFromNode(node, 0, maxDepth);
70
+ }
71
+ /**
72
+ * Analyze all types in an AST.
73
+ *
74
+ * @param ast - The AST to analyze
75
+ * @param options - Analysis options
76
+ * @returns Type analysis result
77
+ */
78
+ analyzeTypes(ast, options = {}) {
79
+ const types = new Map();
80
+ const errors = [];
81
+ // Clear caches for fresh analysis
82
+ this.typeCache.clear();
83
+ this.typeDefinitions.clear();
84
+ // First pass: collect type definitions
85
+ this.collectTypeDefinitions(ast.rootNode);
86
+ // Second pass: analyze all nodes
87
+ this.traverseForTypes(ast.rootNode, types, errors, options);
88
+ // Calculate coverage if requested
89
+ const coverage = options.calculateCoverage
90
+ ? this.calculateCoverageFromTypes(types)
91
+ : 0;
92
+ return { types, errors, coverage };
93
+ }
94
+ /**
95
+ * Check if type1 is a subtype of type2.
96
+ *
97
+ * @param type1 - The potential subtype
98
+ * @param type2 - The potential supertype
99
+ * @returns true if type1 is a subtype of type2
100
+ */
101
+ isSubtypeOf(type1, type2) {
102
+ // Same type is always a subtype of itself
103
+ if (this.areTypesEquivalent(type1, type2)) {
104
+ return true;
105
+ }
106
+ // 'never' is a subtype of everything
107
+ if (type1.kind === 'never') {
108
+ return true;
109
+ }
110
+ // Everything is a subtype of 'unknown'
111
+ if (type2.kind === 'unknown') {
112
+ return true;
113
+ }
114
+ // Everything is a subtype of 'any' (and 'any' is a subtype of everything)
115
+ if (type2.kind === 'any' || type1.kind === 'any') {
116
+ return true;
117
+ }
118
+ // null and undefined are subtypes of nullable types
119
+ if ((type1.kind === 'null' || type1.kind === 'undefined') && type2.isNullable) {
120
+ return true;
121
+ }
122
+ // Union type: type1 is subtype if it's a subtype of any union member
123
+ if (type2.kind === 'union' && type2.unionTypes) {
124
+ return type2.unionTypes.some((t) => this.isSubtypeOf(type1, t));
125
+ }
126
+ // type1 union: all members must be subtypes of type2
127
+ if (type1.kind === 'union' && type1.unionTypes) {
128
+ return type1.unionTypes.every((t) => this.isSubtypeOf(t, type2));
129
+ }
130
+ // Intersection type as supertype: type1 is subtype if it's a subtype of all intersection members
131
+ if (type2.kind === 'intersection' && type2.intersectionTypes) {
132
+ return type2.intersectionTypes.every((t) => this.isSubtypeOf(type1, t));
133
+ }
134
+ // Intersection type as subtype: A & B is a subtype of A and a subtype of B
135
+ if (type1.kind === 'intersection' && type1.intersectionTypes) {
136
+ return type1.intersectionTypes.some((t) => this.isSubtypeOf(t, type2));
137
+ }
138
+ // Array subtyping (covariant)
139
+ if (type1.kind === 'array' && type2.kind === 'array') {
140
+ if (type1.elementType && type2.elementType) {
141
+ return this.isSubtypeOf(type1.elementType, type2.elementType);
142
+ }
143
+ }
144
+ // Object subtyping (structural)
145
+ if (type1.kind === 'object' && type2.kind === 'object') {
146
+ return this.isObjectSubtype(type1, type2);
147
+ }
148
+ // Function subtyping (contravariant in parameters, covariant in return)
149
+ if (type1.kind === 'function' && type2.kind === 'function') {
150
+ return this.isFunctionSubtype(type1, type2);
151
+ }
152
+ // Class/interface inheritance
153
+ if ((type1.kind === 'class' || type1.kind === 'interface') &&
154
+ (type2.kind === 'class' || type2.kind === 'interface')) {
155
+ // Check by name for now (would need full type resolution for accurate check)
156
+ if (type1.name && type2.name && type1.name === type2.name) {
157
+ return true;
158
+ }
159
+ }
160
+ return false;
161
+ }
162
+ /**
163
+ * Check if two types are compatible (assignable).
164
+ *
165
+ * @param type1 - The source type (being assigned)
166
+ * @param type2 - The target type (being assigned to)
167
+ * @returns true if type1 is compatible with type2
168
+ */
169
+ areTypesCompatible(type1, type2) {
170
+ // Subtype relationship implies compatibility
171
+ if (this.isSubtypeOf(type1, type2)) {
172
+ return true;
173
+ }
174
+ // 'any' is compatible with everything
175
+ if (type1.kind === 'any' || type2.kind === 'any') {
176
+ return true;
177
+ }
178
+ // Check for literal type compatibility with primitive
179
+ if (type1.kind === 'literal' && type2.kind === 'primitive') {
180
+ const literalPrimitive = this.getLiteralPrimitiveType(type1);
181
+ return literalPrimitive === type2.name;
182
+ }
183
+ // Optional types are compatible with undefined
184
+ if (type2.isOptional && (type1.kind === 'undefined' || type1.kind === 'void')) {
185
+ return true;
186
+ }
187
+ // Nullable types are compatible with null
188
+ if (type2.isNullable && type1.kind === 'null') {
189
+ return true;
190
+ }
191
+ return false;
192
+ }
193
+ /**
194
+ * Get type coverage information for an AST.
195
+ *
196
+ * @param ast - The AST to analyze
197
+ * @returns Type coverage information
198
+ */
199
+ getTypeCoverage(ast) {
200
+ const locations = this.collectTypeableLocations(ast.rootNode);
201
+ const missingTypeLocations = [];
202
+ let typedLocations = 0;
203
+ let inferredLocations = 0;
204
+ let anyLocations = 0;
205
+ let untypedLocations = 0;
206
+ for (const loc of locations) {
207
+ const typeInfo = this.extractType(loc.node);
208
+ if (!typeInfo) {
209
+ untypedLocations++;
210
+ missingTypeLocations.push(loc.location);
211
+ }
212
+ else if (typeInfo.kind === 'any') {
213
+ anyLocations++;
214
+ }
215
+ else if (loc.isInferred) {
216
+ inferredLocations++;
217
+ }
218
+ else {
219
+ typedLocations++;
220
+ }
221
+ }
222
+ const totalLocations = locations.length;
223
+ const coverage = totalLocations > 0
224
+ ? ((typedLocations + inferredLocations) / totalLocations) * 100
225
+ : 100;
226
+ return {
227
+ totalLocations,
228
+ typedLocations,
229
+ inferredLocations,
230
+ anyLocations,
231
+ untypedLocations,
232
+ coverage,
233
+ missingTypeLocations,
234
+ };
235
+ }
236
+ /**
237
+ * Analyze type relationships in an AST.
238
+ *
239
+ * @param ast - The AST to analyze
240
+ * @returns Array of type relationships found
241
+ */
242
+ analyzeTypeRelationships(ast) {
243
+ const relationships = [];
244
+ // Collect all type definitions first
245
+ this.collectTypeDefinitions(ast.rootNode);
246
+ // Find extends/implements relationships
247
+ this.traverseNode(ast.rootNode, (node) => {
248
+ // Class declarations with extends
249
+ if (node.type === 'class_declaration' || node.type === 'ClassDeclaration') {
250
+ const extendsClause = this.findChildByType(node, 'extends_clause') ||
251
+ this.findChildByType(node, 'heritage_clause');
252
+ if (extendsClause) {
253
+ const className = this.getClassName(node);
254
+ const baseClassName = this.getExtendsName(extendsClause);
255
+ if (className && baseClassName) {
256
+ const classType = this.createNamedType(className, 'class');
257
+ const baseType = this.createNamedType(baseClassName, 'class');
258
+ relationships.push({
259
+ sourceType: classType,
260
+ targetType: baseType,
261
+ kind: 'extends',
262
+ confidence: 1.0,
263
+ });
264
+ relationships.push({
265
+ sourceType: classType,
266
+ targetType: baseType,
267
+ kind: 'subtype',
268
+ confidence: 1.0,
269
+ });
270
+ }
271
+ }
272
+ // Implements clause
273
+ const implementsClause = this.findChildByType(node, 'implements_clause');
274
+ if (implementsClause) {
275
+ const className = this.getClassName(node);
276
+ const interfaceNames = this.getImplementsNames(implementsClause);
277
+ if (className) {
278
+ const classType = this.createNamedType(className, 'class');
279
+ for (const interfaceName of interfaceNames) {
280
+ const interfaceType = this.createNamedType(interfaceName, 'interface');
281
+ relationships.push({
282
+ sourceType: classType,
283
+ targetType: interfaceType,
284
+ kind: 'implements',
285
+ confidence: 1.0,
286
+ });
287
+ }
288
+ }
289
+ }
290
+ }
291
+ // Interface declarations with extends
292
+ if (node.type === 'interface_declaration' || node.type === 'TSInterfaceDeclaration') {
293
+ const extendsClause = this.findChildByType(node, 'extends_clause') ||
294
+ this.findChildByType(node, 'extends_type_clause');
295
+ if (extendsClause) {
296
+ const interfaceName = this.getInterfaceName(node);
297
+ const baseNames = this.getExtendsNames(extendsClause);
298
+ if (interfaceName) {
299
+ const interfaceType = this.createNamedType(interfaceName, 'interface');
300
+ for (const baseName of baseNames) {
301
+ const baseType = this.createNamedType(baseName, 'interface');
302
+ relationships.push({
303
+ sourceType: interfaceType,
304
+ targetType: baseType,
305
+ kind: 'extends',
306
+ confidence: 1.0,
307
+ });
308
+ }
309
+ }
310
+ }
311
+ }
312
+ });
313
+ return relationships;
314
+ }
315
+ /**
316
+ * Check if two types are equivalent.
317
+ *
318
+ * @param type1 - First type
319
+ * @param type2 - Second type
320
+ * @returns true if types are equivalent
321
+ */
322
+ areTypesEquivalent(type1, type2) {
323
+ // Same kind check
324
+ if (type1.kind !== type2.kind) {
325
+ return false;
326
+ }
327
+ // Same name for named types
328
+ if (type1.name !== type2.name) {
329
+ return false;
330
+ }
331
+ // Same text representation
332
+ if (type1.text !== type2.text) {
333
+ return false;
334
+ }
335
+ // Check nullable/optional flags
336
+ if (type1.isNullable !== type2.isNullable || type1.isOptional !== type2.isOptional) {
337
+ return false;
338
+ }
339
+ // Check union types
340
+ if (type1.kind === 'union') {
341
+ if (!type1.unionTypes || !type2.unionTypes) {
342
+ return type1.unionTypes === type2.unionTypes;
343
+ }
344
+ if (type1.unionTypes.length !== type2.unionTypes.length) {
345
+ return false;
346
+ }
347
+ return type1.unionTypes.every((t1, i) => this.areTypesEquivalent(t1, type2.unionTypes[i]));
348
+ }
349
+ // Check intersection types
350
+ if (type1.kind === 'intersection') {
351
+ if (!type1.intersectionTypes || !type2.intersectionTypes) {
352
+ return type1.intersectionTypes === type2.intersectionTypes;
353
+ }
354
+ if (type1.intersectionTypes.length !== type2.intersectionTypes.length) {
355
+ return false;
356
+ }
357
+ return type1.intersectionTypes.every((t1, i) => this.areTypesEquivalent(t1, type2.intersectionTypes[i]));
358
+ }
359
+ // Check array element types
360
+ if (type1.kind === 'array') {
361
+ if (!type1.elementType || !type2.elementType) {
362
+ return type1.elementType === type2.elementType;
363
+ }
364
+ return this.areTypesEquivalent(type1.elementType, type2.elementType);
365
+ }
366
+ // Check function types
367
+ if (type1.kind === 'function') {
368
+ return this.areFunctionTypesEquivalent(type1, type2);
369
+ }
370
+ // Check object types
371
+ if (type1.kind === 'object') {
372
+ return this.areObjectTypesEquivalent(type1, type2);
373
+ }
374
+ return true;
375
+ }
376
+ // ============================================
377
+ // Private Helper Methods
378
+ // ============================================
379
+ /**
380
+ * Extract type from an AST node recursively.
381
+ */
382
+ extractTypeFromNode(node, depth, maxDepth) {
383
+ if (depth > maxDepth) {
384
+ return null;
385
+ }
386
+ // Check cache first - include text in key to differentiate nodes at same position
387
+ const cacheKey = `${node.startPosition.row}:${node.startPosition.column}:${node.type}:${node.text}`;
388
+ if (this.typeCache.has(cacheKey)) {
389
+ return this.typeCache.get(cacheKey);
390
+ }
391
+ const typeInfo = this.extractTypeFromNodeInternal(node, depth, maxDepth);
392
+ if (typeInfo) {
393
+ this.typeCache.set(cacheKey, typeInfo);
394
+ }
395
+ return typeInfo;
396
+ }
397
+ /**
398
+ * Internal type extraction logic.
399
+ */
400
+ extractTypeFromNodeInternal(node, depth, maxDepth) {
401
+ const nodeType = node.type;
402
+ // Type annotation nodes
403
+ if (nodeType === 'type_annotation' || nodeType === 'TSTypeAnnotation') {
404
+ const typeNode = node.children[0];
405
+ if (typeNode) {
406
+ return this.extractTypeFromNode(typeNode, depth + 1, maxDepth);
407
+ }
408
+ }
409
+ // Primitive types
410
+ if (nodeType === 'predefined_type' || nodeType === 'TSStringKeyword' ||
411
+ nodeType === 'TSNumberKeyword' || nodeType === 'TSBooleanKeyword' ||
412
+ nodeType === 'TSAnyKeyword' || nodeType === 'TSVoidKeyword' ||
413
+ nodeType === 'TSNeverKeyword' || nodeType === 'TSUnknownKeyword' ||
414
+ nodeType === 'TSNullKeyword' || nodeType === 'TSUndefinedKeyword') {
415
+ return this.createPrimitiveType(node.text);
416
+ }
417
+ // Type reference (named types)
418
+ if (nodeType === 'type_identifier' || nodeType === 'TSTypeReference' ||
419
+ nodeType === 'generic_type') {
420
+ return this.extractTypeReference(node, depth, maxDepth);
421
+ }
422
+ // Union types
423
+ if (nodeType === 'union_type' || nodeType === 'TSUnionType') {
424
+ return this.extractUnionType(node, depth, maxDepth);
425
+ }
426
+ // Intersection types
427
+ if (nodeType === 'intersection_type' || nodeType === 'TSIntersectionType') {
428
+ return this.extractIntersectionType(node, depth, maxDepth);
429
+ }
430
+ // Array types
431
+ if (nodeType === 'array_type' || nodeType === 'TSArrayType') {
432
+ return this.extractArrayType(node, depth, maxDepth);
433
+ }
434
+ // Tuple types
435
+ if (nodeType === 'tuple_type' || nodeType === 'TSTupleType') {
436
+ return this.extractTupleType(node, depth, maxDepth);
437
+ }
438
+ // Function types
439
+ if (nodeType === 'function_type' || nodeType === 'TSFunctionType') {
440
+ return this.extractFunctionType(node, depth, maxDepth);
441
+ }
442
+ // Object/interface types
443
+ if (nodeType === 'object_type' || nodeType === 'TSTypeLiteral') {
444
+ return this.extractObjectType(node, depth, maxDepth);
445
+ }
446
+ // Literal types
447
+ if (nodeType === 'literal_type' || nodeType === 'TSLiteralType') {
448
+ return this.extractLiteralType(node);
449
+ }
450
+ // Conditional types
451
+ if (nodeType === 'conditional_type' || nodeType === 'TSConditionalType') {
452
+ return this.createTypeInfo('conditional', node.text);
453
+ }
454
+ // Mapped types
455
+ if (nodeType === 'mapped_type' || nodeType === 'TSMappedType') {
456
+ return this.createTypeInfo('mapped', node.text);
457
+ }
458
+ // Indexed access types
459
+ if (nodeType === 'indexed_access_type' || nodeType === 'TSIndexedAccessType') {
460
+ return this.createTypeInfo('indexed', node.text);
461
+ }
462
+ // Type parameters
463
+ if (nodeType === 'type_parameter' || nodeType === 'TSTypeParameter') {
464
+ return this.extractTypeParameter(node);
465
+ }
466
+ // Variable declarations with type annotations
467
+ if (nodeType === 'variable_declarator' || nodeType === 'VariableDeclarator') {
468
+ const typeAnnotation = this.findChildByType(node, 'type_annotation') ||
469
+ this.findChildByType(node, 'TSTypeAnnotation');
470
+ if (typeAnnotation) {
471
+ return this.extractTypeFromNode(typeAnnotation, depth + 1, maxDepth);
472
+ }
473
+ }
474
+ // Function declarations
475
+ if (nodeType === 'function_declaration' || nodeType === 'FunctionDeclaration' ||
476
+ nodeType === 'method_definition' || nodeType === 'MethodDefinition') {
477
+ return this.extractFunctionDeclarationType(node, depth, maxDepth);
478
+ }
479
+ // Parameter declarations
480
+ if (nodeType === 'required_parameter' || nodeType === 'optional_parameter' ||
481
+ nodeType === 'Identifier') {
482
+ const typeAnnotation = this.findChildByType(node, 'type_annotation') ||
483
+ this.findChildByType(node, 'TSTypeAnnotation');
484
+ if (typeAnnotation) {
485
+ return this.extractTypeFromNode(typeAnnotation, depth + 1, maxDepth);
486
+ }
487
+ }
488
+ return null;
489
+ }
490
+ /**
491
+ * Extract type reference (named type).
492
+ */
493
+ extractTypeReference(node, depth, maxDepth) {
494
+ const typeName = this.getTypeName(node);
495
+ const typeArgs = this.extractTypeArguments(node, depth, maxDepth);
496
+ // Check if it's a primitive type
497
+ if (PRIMITIVE_TYPES.has(typeName)) {
498
+ return this.createPrimitiveType(typeName);
499
+ }
500
+ // Check if it's a utility type
501
+ if (UTILITY_TYPES.has(typeName)) {
502
+ const result = {
503
+ kind: 'generic',
504
+ name: typeName,
505
+ text: node.text,
506
+ isNullable: false,
507
+ isOptional: false,
508
+ };
509
+ if (typeArgs.length > 0) {
510
+ result.typeArguments = typeArgs;
511
+ }
512
+ return result;
513
+ }
514
+ // Check if we have a definition for this type
515
+ const definition = this.typeDefinitions.get(typeName);
516
+ if (definition) {
517
+ const result = { ...definition };
518
+ if (typeArgs.length > 0) {
519
+ result.typeArguments = typeArgs;
520
+ }
521
+ return result;
522
+ }
523
+ // Return as a generic named type
524
+ const kind = this.inferTypeKind(typeName);
525
+ const result = {
526
+ kind,
527
+ name: typeName,
528
+ text: node.text,
529
+ isNullable: false,
530
+ isOptional: false,
531
+ };
532
+ if (typeArgs.length > 0) {
533
+ result.typeArguments = typeArgs;
534
+ }
535
+ return result;
536
+ }
537
+ /**
538
+ * Extract union type.
539
+ */
540
+ extractUnionType(node, depth, maxDepth) {
541
+ const unionTypes = [];
542
+ for (const child of node.children) {
543
+ if (child.type !== '|') {
544
+ const childType = this.extractTypeFromNode(child, depth + 1, maxDepth);
545
+ if (childType) {
546
+ unionTypes.push(childType);
547
+ }
548
+ }
549
+ }
550
+ const isNullable = unionTypes.some((t) => t.kind === 'null' || t.kind === 'undefined');
551
+ return {
552
+ kind: 'union',
553
+ text: node.text,
554
+ unionTypes,
555
+ isNullable,
556
+ isOptional: false,
557
+ };
558
+ }
559
+ /**
560
+ * Extract intersection type.
561
+ */
562
+ extractIntersectionType(node, depth, maxDepth) {
563
+ const intersectionTypes = [];
564
+ for (const child of node.children) {
565
+ if (child.type !== '&') {
566
+ const childType = this.extractTypeFromNode(child, depth + 1, maxDepth);
567
+ if (childType) {
568
+ intersectionTypes.push(childType);
569
+ }
570
+ }
571
+ }
572
+ return {
573
+ kind: 'intersection',
574
+ text: node.text,
575
+ intersectionTypes,
576
+ isNullable: false,
577
+ isOptional: false,
578
+ };
579
+ }
580
+ /**
581
+ * Extract array type.
582
+ */
583
+ extractArrayType(node, depth, maxDepth) {
584
+ const elementTypeNode = node.children[0];
585
+ const elementType = elementTypeNode
586
+ ? this.extractTypeFromNode(elementTypeNode, depth + 1, maxDepth)
587
+ : null;
588
+ const result = {
589
+ kind: 'array',
590
+ text: node.text,
591
+ isNullable: false,
592
+ isOptional: false,
593
+ };
594
+ if (elementType) {
595
+ result.elementType = elementType;
596
+ }
597
+ return result;
598
+ }
599
+ /**
600
+ * Extract tuple type.
601
+ */
602
+ extractTupleType(node, depth, maxDepth) {
603
+ const elementTypes = [];
604
+ for (const child of node.children) {
605
+ if (child.type !== '[' && child.type !== ']' && child.type !== ',') {
606
+ const childType = this.extractTypeFromNode(child, depth + 1, maxDepth);
607
+ if (childType) {
608
+ elementTypes.push(childType);
609
+ }
610
+ }
611
+ }
612
+ return {
613
+ kind: 'tuple',
614
+ text: node.text,
615
+ typeArguments: elementTypes,
616
+ isNullable: false,
617
+ isOptional: false,
618
+ };
619
+ }
620
+ /**
621
+ * Extract function type.
622
+ */
623
+ extractFunctionType(node, depth, maxDepth) {
624
+ const parameters = [];
625
+ let returnType = null;
626
+ // Find parameters
627
+ const paramsNode = this.findChildByType(node, 'formal_parameters') ||
628
+ this.findChildByType(node, 'parameters');
629
+ if (paramsNode) {
630
+ for (const param of paramsNode.children) {
631
+ if (param.type === 'required_parameter' || param.type === 'optional_parameter') {
632
+ const paramType = this.extractTypeFromNode(param, depth + 1, maxDepth);
633
+ if (paramType) {
634
+ parameters.push(paramType);
635
+ }
636
+ }
637
+ }
638
+ }
639
+ // Find return type
640
+ const returnTypeNode = this.findChildByType(node, 'type_annotation') ||
641
+ this.findChildByType(node, 'return_type');
642
+ if (returnTypeNode) {
643
+ returnType = this.extractTypeFromNode(returnTypeNode, depth + 1, maxDepth);
644
+ }
645
+ const result = {
646
+ kind: 'function',
647
+ text: node.text,
648
+ isNullable: false,
649
+ isOptional: false,
650
+ };
651
+ if (parameters.length > 0) {
652
+ result.parameters = parameters;
653
+ }
654
+ if (returnType) {
655
+ result.returnType = returnType;
656
+ }
657
+ return result;
658
+ }
659
+ /**
660
+ * Extract object type.
661
+ */
662
+ extractObjectType(node, depth, maxDepth) {
663
+ const properties = [];
664
+ for (const child of node.children) {
665
+ if (child.type === 'property_signature' || child.type === 'TSPropertySignature') {
666
+ const prop = this.extractPropertySignature(child, depth, maxDepth);
667
+ if (prop) {
668
+ properties.push(prop);
669
+ }
670
+ }
671
+ }
672
+ const result = {
673
+ kind: 'object',
674
+ text: node.text,
675
+ isNullable: false,
676
+ isOptional: false,
677
+ };
678
+ if (properties.length > 0) {
679
+ result.properties = properties;
680
+ }
681
+ return result;
682
+ }
683
+ /**
684
+ * Extract property signature.
685
+ */
686
+ extractPropertySignature(node, depth, maxDepth) {
687
+ const nameNode = this.findChildByType(node, 'property_identifier') ||
688
+ this.findChildByType(node, 'Identifier');
689
+ if (!nameNode) {
690
+ return null;
691
+ }
692
+ const typeAnnotation = this.findChildByType(node, 'type_annotation') ||
693
+ this.findChildByType(node, 'TSTypeAnnotation');
694
+ const type = typeAnnotation
695
+ ? this.extractTypeFromNode(typeAnnotation, depth + 1, maxDepth)
696
+ : this.createTypeInfo('any', 'any');
697
+ const isOptional = node.children.some((c) => c.text === '?');
698
+ const isReadonly = node.children.some((c) => c.type === 'readonly' || c.text === 'readonly');
699
+ return {
700
+ name: nameNode.text,
701
+ type: type || this.createTypeInfo('any', 'any'),
702
+ isOptional,
703
+ isReadonly,
704
+ };
705
+ }
706
+ /**
707
+ * Extract literal type.
708
+ */
709
+ extractLiteralType(node) {
710
+ const literalNode = node.children[0];
711
+ const text = literalNode?.text || node.text;
712
+ return {
713
+ kind: 'literal',
714
+ text,
715
+ isNullable: false,
716
+ isOptional: false,
717
+ };
718
+ }
719
+ /**
720
+ * Extract type parameter.
721
+ */
722
+ extractTypeParameter(node) {
723
+ const nameNode = this.findChildByType(node, 'type_identifier') ||
724
+ this.findChildByType(node, 'Identifier');
725
+ const name = nameNode?.text || node.text;
726
+ return {
727
+ kind: 'typeParameter',
728
+ name,
729
+ text: node.text,
730
+ isNullable: false,
731
+ isOptional: false,
732
+ };
733
+ }
734
+ /**
735
+ * Extract function declaration type.
736
+ */
737
+ extractFunctionDeclarationType(node, depth, maxDepth) {
738
+ const parameters = [];
739
+ let returnType = null;
740
+ // Find parameters
741
+ const paramsNode = this.findChildByType(node, 'formal_parameters') ||
742
+ this.findChildByType(node, 'parameters');
743
+ if (paramsNode) {
744
+ for (const param of paramsNode.children) {
745
+ const paramType = this.extractTypeFromNode(param, depth + 1, maxDepth);
746
+ if (paramType) {
747
+ parameters.push(paramType);
748
+ }
749
+ }
750
+ }
751
+ // Find return type annotation
752
+ const returnTypeAnnotation = this.findChildByType(node, 'type_annotation') ||
753
+ this.findChildByType(node, 'return_type');
754
+ if (returnTypeAnnotation) {
755
+ returnType = this.extractTypeFromNode(returnTypeAnnotation, depth + 1, maxDepth);
756
+ }
757
+ const result = {
758
+ kind: 'function',
759
+ text: node.text,
760
+ isNullable: false,
761
+ isOptional: false,
762
+ };
763
+ if (parameters.length > 0) {
764
+ result.parameters = parameters;
765
+ }
766
+ if (returnType) {
767
+ result.returnType = returnType;
768
+ }
769
+ return result;
770
+ }
771
+ /**
772
+ * Extract type arguments from a generic type.
773
+ */
774
+ extractTypeArguments(node, depth, maxDepth) {
775
+ const typeArgs = [];
776
+ const typeArgsNode = this.findChildByType(node, 'type_arguments') ||
777
+ this.findChildByType(node, 'TSTypeParameterInstantiation');
778
+ if (typeArgsNode) {
779
+ for (const child of typeArgsNode.children) {
780
+ if (child.type !== '<' && child.type !== '>' && child.type !== ',') {
781
+ const argType = this.extractTypeFromNode(child, depth + 1, maxDepth);
782
+ if (argType) {
783
+ typeArgs.push(argType);
784
+ }
785
+ }
786
+ }
787
+ }
788
+ return typeArgs;
789
+ }
790
+ /**
791
+ * Collect type definitions from the AST.
792
+ */
793
+ collectTypeDefinitions(node) {
794
+ // Type alias declarations
795
+ if (node.type === 'type_alias_declaration' || node.type === 'TSTypeAliasDeclaration') {
796
+ const nameNode = this.findChildByType(node, 'type_identifier') ||
797
+ this.findChildByType(node, 'Identifier');
798
+ if (nameNode) {
799
+ const typeNode = node.children.find((c) => c.type !== 'type_identifier' && c.type !== 'Identifier' &&
800
+ c.type !== '=' && c.type !== 'type');
801
+ if (typeNode) {
802
+ const typeInfo = this.extractTypeFromNode(typeNode, 0, 10);
803
+ if (typeInfo) {
804
+ this.typeDefinitions.set(nameNode.text, {
805
+ ...typeInfo,
806
+ name: nameNode.text,
807
+ });
808
+ }
809
+ }
810
+ }
811
+ }
812
+ // Interface declarations
813
+ if (node.type === 'interface_declaration' || node.type === 'TSInterfaceDeclaration') {
814
+ const nameNode = this.findChildByType(node, 'type_identifier') ||
815
+ this.findChildByType(node, 'Identifier');
816
+ if (nameNode) {
817
+ this.typeDefinitions.set(nameNode.text, {
818
+ kind: 'interface',
819
+ name: nameNode.text,
820
+ text: node.text,
821
+ isNullable: false,
822
+ isOptional: false,
823
+ });
824
+ }
825
+ }
826
+ // Class declarations
827
+ if (node.type === 'class_declaration' || node.type === 'ClassDeclaration') {
828
+ const nameNode = this.findChildByType(node, 'type_identifier') ||
829
+ this.findChildByType(node, 'Identifier');
830
+ if (nameNode) {
831
+ this.typeDefinitions.set(nameNode.text, {
832
+ kind: 'class',
833
+ name: nameNode.text,
834
+ text: node.text,
835
+ isNullable: false,
836
+ isOptional: false,
837
+ });
838
+ }
839
+ }
840
+ // Enum declarations
841
+ if (node.type === 'enum_declaration' || node.type === 'TSEnumDeclaration') {
842
+ const nameNode = this.findChildByType(node, 'identifier') ||
843
+ this.findChildByType(node, 'Identifier');
844
+ if (nameNode) {
845
+ this.typeDefinitions.set(nameNode.text, {
846
+ kind: 'enum',
847
+ name: nameNode.text,
848
+ text: node.text,
849
+ isNullable: false,
850
+ isOptional: false,
851
+ });
852
+ }
853
+ }
854
+ // Recurse into children
855
+ for (const child of node.children) {
856
+ this.collectTypeDefinitions(child);
857
+ }
858
+ }
859
+ /**
860
+ * Traverse AST for type analysis.
861
+ */
862
+ traverseForTypes(node, types, errors, options) {
863
+ // Extract type from this node if applicable
864
+ const typeInfo = this.extractTypeFromNode(node, 0, 10);
865
+ if (typeInfo) {
866
+ const key = `${node.startPosition.row}:${node.startPosition.column}`;
867
+ types.set(key, typeInfo);
868
+ }
869
+ // Check for type errors
870
+ if (options.deep) {
871
+ this.checkTypeErrors(node, errors);
872
+ }
873
+ // Recurse into children
874
+ for (const child of node.children) {
875
+ this.traverseForTypes(child, types, errors, options);
876
+ }
877
+ }
878
+ /**
879
+ * Check for type errors in a node.
880
+ */
881
+ checkTypeErrors(node, errors) {
882
+ // Check for explicit 'any' usage
883
+ if (node.type === 'predefined_type' && node.text === 'any') {
884
+ errors.push({
885
+ message: "Explicit 'any' type usage",
886
+ location: {
887
+ start: node.startPosition,
888
+ end: node.endPosition,
889
+ },
890
+ });
891
+ }
892
+ // Check for type assertions to 'any'
893
+ if ((node.type === 'as_expression' || node.type === 'TSAsExpression') &&
894
+ node.text.includes(' as any')) {
895
+ errors.push({
896
+ message: "Type assertion to 'any'",
897
+ location: {
898
+ start: node.startPosition,
899
+ end: node.endPosition,
900
+ },
901
+ });
902
+ }
903
+ }
904
+ /**
905
+ * Collect typeable locations from AST.
906
+ */
907
+ collectTypeableLocations(node) {
908
+ const locations = [];
909
+ this.traverseNode(node, (n) => {
910
+ // Variable declarations
911
+ if (n.type === 'variable_declarator' || n.type === 'VariableDeclarator') {
912
+ const hasTypeAnnotation = this.findChildByType(n, 'type_annotation') ||
913
+ this.findChildByType(n, 'TSTypeAnnotation');
914
+ const initializerNode = this.findChildByType(n, 'initializer');
915
+ const hasInitializer = initializerNode !== null || n.children.some((c) => c.type === '=');
916
+ locations.push({
917
+ node: n,
918
+ location: { start: n.startPosition, end: n.endPosition },
919
+ isInferred: !hasTypeAnnotation && hasInitializer,
920
+ });
921
+ }
922
+ // Function parameters
923
+ if (n.type === 'required_parameter' || n.type === 'optional_parameter') {
924
+ const hasTypeAnnotation = this.findChildByType(n, 'type_annotation') ||
925
+ this.findChildByType(n, 'TSTypeAnnotation');
926
+ locations.push({
927
+ node: n,
928
+ location: { start: n.startPosition, end: n.endPosition },
929
+ isInferred: !hasTypeAnnotation,
930
+ });
931
+ }
932
+ // Function return types
933
+ if (n.type === 'function_declaration' || n.type === 'FunctionDeclaration' ||
934
+ n.type === 'arrow_function' || n.type === 'ArrowFunctionExpression') {
935
+ const hasReturnType = this.findChildByType(n, 'type_annotation') ||
936
+ this.findChildByType(n, 'return_type');
937
+ locations.push({
938
+ node: n,
939
+ location: { start: n.startPosition, end: n.endPosition },
940
+ isInferred: !hasReturnType,
941
+ });
942
+ }
943
+ });
944
+ return locations;
945
+ }
946
+ /**
947
+ * Calculate coverage from analyzed types.
948
+ */
949
+ calculateCoverageFromTypes(types) {
950
+ if (types.size === 0) {
951
+ return 100;
952
+ }
953
+ let typedCount = 0;
954
+ let anyCount = 0;
955
+ for (const typeInfo of types.values()) {
956
+ if (typeInfo.kind === 'any') {
957
+ anyCount++;
958
+ }
959
+ else {
960
+ typedCount++;
961
+ }
962
+ }
963
+ return (typedCount / types.size) * 100;
964
+ }
965
+ /**
966
+ * Check if object type1 is a subtype of object type2.
967
+ */
968
+ isObjectSubtype(type1, type2) {
969
+ if (!type2.properties) {
970
+ return true; // Empty object type is supertype of all objects
971
+ }
972
+ if (!type1.properties) {
973
+ return false;
974
+ }
975
+ // All properties in type2 must exist in type1 with compatible types
976
+ for (const prop2 of type2.properties) {
977
+ const prop1 = type1.properties.find((p) => p.name === prop2.name);
978
+ if (!prop1) {
979
+ if (!prop2.isOptional) {
980
+ return false; // Required property missing
981
+ }
982
+ continue;
983
+ }
984
+ if (!this.isSubtypeOf(prop1.type, prop2.type)) {
985
+ return false;
986
+ }
987
+ }
988
+ return true;
989
+ }
990
+ /**
991
+ * Check if function type1 is a subtype of function type2.
992
+ */
993
+ isFunctionSubtype(type1, type2) {
994
+ // Check return type (covariant)
995
+ if (type1.returnType && type2.returnType) {
996
+ if (!this.isSubtypeOf(type1.returnType, type2.returnType)) {
997
+ return false;
998
+ }
999
+ }
1000
+ // Check parameters (contravariant)
1001
+ const params1 = type1.parameters || [];
1002
+ const params2 = type2.parameters || [];
1003
+ // type1 can have fewer required parameters
1004
+ for (let i = 0; i < params2.length; i++) {
1005
+ const param1 = params1[i];
1006
+ const param2 = params2[i];
1007
+ if (!param1) {
1008
+ if (!param2?.isOptional) {
1009
+ return false;
1010
+ }
1011
+ continue;
1012
+ }
1013
+ if (param2 && !this.isSubtypeOf(param2, param1)) {
1014
+ return false; // Contravariant
1015
+ }
1016
+ }
1017
+ return true;
1018
+ }
1019
+ /**
1020
+ * Check if two function types are equivalent.
1021
+ */
1022
+ areFunctionTypesEquivalent(type1, type2) {
1023
+ // Check return types
1024
+ if (type1.returnType && type2.returnType) {
1025
+ if (!this.areTypesEquivalent(type1.returnType, type2.returnType)) {
1026
+ return false;
1027
+ }
1028
+ }
1029
+ else if (type1.returnType !== type2.returnType) {
1030
+ return false;
1031
+ }
1032
+ // Check parameters
1033
+ const params1 = type1.parameters || [];
1034
+ const params2 = type2.parameters || [];
1035
+ if (params1.length !== params2.length) {
1036
+ return false;
1037
+ }
1038
+ for (let i = 0; i < params1.length; i++) {
1039
+ if (!this.areTypesEquivalent(params1[i], params2[i])) {
1040
+ return false;
1041
+ }
1042
+ }
1043
+ return true;
1044
+ }
1045
+ /**
1046
+ * Check if two object types are equivalent.
1047
+ */
1048
+ areObjectTypesEquivalent(type1, type2) {
1049
+ const props1 = type1.properties || [];
1050
+ const props2 = type2.properties || [];
1051
+ if (props1.length !== props2.length) {
1052
+ return false;
1053
+ }
1054
+ for (const prop1 of props1) {
1055
+ const prop2 = props2.find((p) => p.name === prop1.name);
1056
+ if (!prop2) {
1057
+ return false;
1058
+ }
1059
+ if (prop1.isOptional !== prop2.isOptional ||
1060
+ prop1.isReadonly !== prop2.isReadonly) {
1061
+ return false;
1062
+ }
1063
+ if (!this.areTypesEquivalent(prop1.type, prop2.type)) {
1064
+ return false;
1065
+ }
1066
+ }
1067
+ return true;
1068
+ }
1069
+ /**
1070
+ * Get the primitive type for a literal type.
1071
+ */
1072
+ getLiteralPrimitiveType(type) {
1073
+ const text = type.text;
1074
+ if (text.startsWith('"') || text.startsWith("'") || text.startsWith('`')) {
1075
+ return 'string';
1076
+ }
1077
+ if (/^-?\d+(\.\d+)?$/.test(text)) {
1078
+ return 'number';
1079
+ }
1080
+ if (text === 'true' || text === 'false') {
1081
+ return 'boolean';
1082
+ }
1083
+ if (text.endsWith('n')) {
1084
+ return 'bigint';
1085
+ }
1086
+ return 'unknown';
1087
+ }
1088
+ /**
1089
+ * Traverse AST nodes with a callback.
1090
+ */
1091
+ traverseNode(node, callback) {
1092
+ callback(node);
1093
+ for (const child of node.children) {
1094
+ this.traverseNode(child, callback);
1095
+ }
1096
+ }
1097
+ /**
1098
+ * Find a child node by type.
1099
+ */
1100
+ findChildByType(node, type) {
1101
+ for (const child of node.children) {
1102
+ if (child.type === type) {
1103
+ return child;
1104
+ }
1105
+ }
1106
+ return null;
1107
+ }
1108
+ /**
1109
+ * Get type name from a type reference node.
1110
+ */
1111
+ getTypeName(node) {
1112
+ const identifierNode = this.findChildByType(node, 'type_identifier') ||
1113
+ this.findChildByType(node, 'Identifier');
1114
+ if (identifierNode) {
1115
+ return identifierNode.text;
1116
+ }
1117
+ // For simple type identifiers
1118
+ if (node.type === 'type_identifier' || node.type === 'Identifier') {
1119
+ return node.text;
1120
+ }
1121
+ // Extract name from text (remove type arguments)
1122
+ const text = node.text;
1123
+ const angleIndex = text.indexOf('<');
1124
+ return angleIndex > 0 ? text.substring(0, angleIndex) : text;
1125
+ }
1126
+ /**
1127
+ * Infer type kind from name.
1128
+ */
1129
+ inferTypeKind(name) {
1130
+ // Interface naming convention (I prefix)
1131
+ if (name.startsWith('I') && name.length > 1 && name[1] === name[1]?.toUpperCase()) {
1132
+ return 'interface';
1133
+ }
1134
+ // Type naming convention (T prefix for type parameters)
1135
+ if (name.length === 1 && name >= 'A' && name <= 'Z') {
1136
+ return 'typeParameter';
1137
+ }
1138
+ // Default to class for PascalCase names
1139
+ if (name[0] === name[0]?.toUpperCase()) {
1140
+ return 'class';
1141
+ }
1142
+ return 'unknown';
1143
+ }
1144
+ /**
1145
+ * Create a primitive type info.
1146
+ */
1147
+ createPrimitiveType(name) {
1148
+ const kind = this.getPrimitiveKind(name);
1149
+ return {
1150
+ kind,
1151
+ name,
1152
+ text: name,
1153
+ isNullable: name === 'null',
1154
+ isOptional: false,
1155
+ };
1156
+ }
1157
+ /**
1158
+ * Get the TypeKind for a primitive type name.
1159
+ */
1160
+ getPrimitiveKind(name) {
1161
+ switch (name) {
1162
+ case 'null':
1163
+ return 'null';
1164
+ case 'undefined':
1165
+ return 'undefined';
1166
+ case 'void':
1167
+ return 'void';
1168
+ case 'never':
1169
+ return 'never';
1170
+ case 'any':
1171
+ return 'any';
1172
+ case 'unknown':
1173
+ return 'unknown';
1174
+ default:
1175
+ return 'primitive';
1176
+ }
1177
+ }
1178
+ /**
1179
+ * Create a basic type info.
1180
+ */
1181
+ createTypeInfo(kind, text) {
1182
+ return {
1183
+ kind,
1184
+ text,
1185
+ isNullable: false,
1186
+ isOptional: false,
1187
+ };
1188
+ }
1189
+ /**
1190
+ * Create a named type info.
1191
+ */
1192
+ createNamedType(name, kind) {
1193
+ return {
1194
+ kind,
1195
+ name,
1196
+ text: name,
1197
+ isNullable: false,
1198
+ isOptional: false,
1199
+ };
1200
+ }
1201
+ /**
1202
+ * Get class name from a class declaration node.
1203
+ */
1204
+ getClassName(node) {
1205
+ const nameNode = this.findChildByType(node, 'type_identifier') ||
1206
+ this.findChildByType(node, 'Identifier');
1207
+ return nameNode?.text || null;
1208
+ }
1209
+ /**
1210
+ * Get interface name from an interface declaration node.
1211
+ */
1212
+ getInterfaceName(node) {
1213
+ const nameNode = this.findChildByType(node, 'type_identifier') ||
1214
+ this.findChildByType(node, 'Identifier');
1215
+ return nameNode?.text || null;
1216
+ }
1217
+ /**
1218
+ * Get the extended class/interface name from an extends clause.
1219
+ */
1220
+ getExtendsName(node) {
1221
+ const typeNode = this.findChildByType(node, 'type_identifier') ||
1222
+ this.findChildByType(node, 'Identifier') ||
1223
+ this.findChildByType(node, 'generic_type');
1224
+ if (typeNode) {
1225
+ return this.getTypeName(typeNode);
1226
+ }
1227
+ return null;
1228
+ }
1229
+ /**
1230
+ * Get all extended interface names from an extends clause.
1231
+ */
1232
+ getExtendsNames(node) {
1233
+ const names = [];
1234
+ for (const child of node.children) {
1235
+ if (child.type === 'type_identifier' || child.type === 'Identifier' ||
1236
+ child.type === 'generic_type') {
1237
+ const name = this.getTypeName(child);
1238
+ if (name) {
1239
+ names.push(name);
1240
+ }
1241
+ }
1242
+ }
1243
+ return names;
1244
+ }
1245
+ /**
1246
+ * Get implemented interface names from an implements clause.
1247
+ */
1248
+ getImplementsNames(node) {
1249
+ const names = [];
1250
+ for (const child of node.children) {
1251
+ if (child.type === 'type_identifier' || child.type === 'Identifier' ||
1252
+ child.type === 'generic_type') {
1253
+ const name = this.getTypeName(child);
1254
+ if (name) {
1255
+ names.push(name);
1256
+ }
1257
+ }
1258
+ }
1259
+ return names;
1260
+ }
1261
+ /**
1262
+ * Clear internal caches.
1263
+ */
1264
+ clearCache() {
1265
+ this.typeCache.clear();
1266
+ this.typeDefinitions.clear();
1267
+ }
1268
+ }
1269
+ //# sourceMappingURL=type-analyzer.js.map