@liendev/core 0.19.5

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 (298) hide show
  1. package/README.md +336 -0
  2. package/dist/config/loader.d.ts +12 -0
  3. package/dist/config/loader.d.ts.map +1 -0
  4. package/dist/config/loader.js +46 -0
  5. package/dist/config/loader.js.map +1 -0
  6. package/dist/config/merge.d.ts +20 -0
  7. package/dist/config/merge.d.ts.map +1 -0
  8. package/dist/config/merge.js +71 -0
  9. package/dist/config/merge.js.map +1 -0
  10. package/dist/config/migration-manager.d.ts +46 -0
  11. package/dist/config/migration-manager.d.ts.map +1 -0
  12. package/dist/config/migration-manager.js +119 -0
  13. package/dist/config/migration-manager.js.map +1 -0
  14. package/dist/config/migration.d.ts +20 -0
  15. package/dist/config/migration.d.ts.map +1 -0
  16. package/dist/config/migration.js +155 -0
  17. package/dist/config/migration.js.map +1 -0
  18. package/dist/config/schema.d.ts +101 -0
  19. package/dist/config/schema.d.ts.map +1 -0
  20. package/dist/config/schema.js +58 -0
  21. package/dist/config/schema.js.map +1 -0
  22. package/dist/config/service.d.ts +122 -0
  23. package/dist/config/service.d.ts.map +1 -0
  24. package/dist/config/service.js +477 -0
  25. package/dist/config/service.js.map +1 -0
  26. package/dist/constants.d.ts +20 -0
  27. package/dist/constants.d.ts.map +1 -0
  28. package/dist/constants.js +43 -0
  29. package/dist/constants.js.map +1 -0
  30. package/dist/embeddings/cache.d.ts +45 -0
  31. package/dist/embeddings/cache.d.ts.map +1 -0
  32. package/dist/embeddings/cache.js +109 -0
  33. package/dist/embeddings/cache.js.map +1 -0
  34. package/dist/embeddings/local.d.ts +10 -0
  35. package/dist/embeddings/local.d.ts.map +1 -0
  36. package/dist/embeddings/local.js +63 -0
  37. package/dist/embeddings/local.js.map +1 -0
  38. package/dist/embeddings/types.d.ts +9 -0
  39. package/dist/embeddings/types.d.ts.map +1 -0
  40. package/dist/embeddings/types.js +5 -0
  41. package/dist/embeddings/types.js.map +1 -0
  42. package/dist/errors/codes.d.ts +18 -0
  43. package/dist/errors/codes.d.ts.map +1 -0
  44. package/dist/errors/codes.js +25 -0
  45. package/dist/errors/codes.js.map +1 -0
  46. package/dist/errors/index.d.ts +85 -0
  47. package/dist/errors/index.d.ts.map +1 -0
  48. package/dist/errors/index.js +134 -0
  49. package/dist/errors/index.js.map +1 -0
  50. package/dist/frameworks/detector-service.d.ts +59 -0
  51. package/dist/frameworks/detector-service.d.ts.map +1 -0
  52. package/dist/frameworks/detector-service.js +219 -0
  53. package/dist/frameworks/detector-service.js.map +1 -0
  54. package/dist/frameworks/laravel/config.d.ts +6 -0
  55. package/dist/frameworks/laravel/config.d.ts.map +1 -0
  56. package/dist/frameworks/laravel/config.js +68 -0
  57. package/dist/frameworks/laravel/config.js.map +1 -0
  58. package/dist/frameworks/laravel/detector.d.ts +6 -0
  59. package/dist/frameworks/laravel/detector.d.ts.map +1 -0
  60. package/dist/frameworks/laravel/detector.js +96 -0
  61. package/dist/frameworks/laravel/detector.js.map +1 -0
  62. package/dist/frameworks/nodejs/config.d.ts +6 -0
  63. package/dist/frameworks/nodejs/config.d.ts.map +1 -0
  64. package/dist/frameworks/nodejs/config.js +57 -0
  65. package/dist/frameworks/nodejs/config.js.map +1 -0
  66. package/dist/frameworks/nodejs/detector.d.ts +6 -0
  67. package/dist/frameworks/nodejs/detector.d.ts.map +1 -0
  68. package/dist/frameworks/nodejs/detector.js +77 -0
  69. package/dist/frameworks/nodejs/detector.js.map +1 -0
  70. package/dist/frameworks/php/config.d.ts +6 -0
  71. package/dist/frameworks/php/config.d.ts.map +1 -0
  72. package/dist/frameworks/php/config.js +53 -0
  73. package/dist/frameworks/php/config.js.map +1 -0
  74. package/dist/frameworks/php/detector.d.ts +7 -0
  75. package/dist/frameworks/php/detector.d.ts.map +1 -0
  76. package/dist/frameworks/php/detector.js +101 -0
  77. package/dist/frameworks/php/detector.js.map +1 -0
  78. package/dist/frameworks/registry.d.ts +20 -0
  79. package/dist/frameworks/registry.d.ts.map +1 -0
  80. package/dist/frameworks/registry.js +38 -0
  81. package/dist/frameworks/registry.js.map +1 -0
  82. package/dist/frameworks/shopify/config.d.ts +6 -0
  83. package/dist/frameworks/shopify/config.d.ts.map +1 -0
  84. package/dist/frameworks/shopify/config.js +50 -0
  85. package/dist/frameworks/shopify/config.js.map +1 -0
  86. package/dist/frameworks/shopify/detector.d.ts +6 -0
  87. package/dist/frameworks/shopify/detector.d.ts.map +1 -0
  88. package/dist/frameworks/shopify/detector.js +103 -0
  89. package/dist/frameworks/shopify/detector.js.map +1 -0
  90. package/dist/frameworks/types.d.ts +51 -0
  91. package/dist/frameworks/types.d.ts.map +1 -0
  92. package/dist/frameworks/types.js +21 -0
  93. package/dist/frameworks/types.js.map +1 -0
  94. package/dist/git/tracker.d.ts +56 -0
  95. package/dist/git/tracker.d.ts.map +1 -0
  96. package/dist/git/tracker.js +189 -0
  97. package/dist/git/tracker.js.map +1 -0
  98. package/dist/git/utils.d.ts +60 -0
  99. package/dist/git/utils.d.ts.map +1 -0
  100. package/dist/git/utils.js +152 -0
  101. package/dist/git/utils.js.map +1 -0
  102. package/dist/index.d.ts +77 -0
  103. package/dist/index.d.ts.map +1 -0
  104. package/dist/index.js +95 -0
  105. package/dist/index.js.map +1 -0
  106. package/dist/indexer/ast/chunker.d.ts +28 -0
  107. package/dist/indexer/ast/chunker.d.ts.map +1 -0
  108. package/dist/indexer/ast/chunker.js +268 -0
  109. package/dist/indexer/ast/chunker.js.map +1 -0
  110. package/dist/indexer/ast/complexity/cognitive.d.ts +16 -0
  111. package/dist/indexer/ast/complexity/cognitive.d.ts.map +1 -0
  112. package/dist/indexer/ast/complexity/cognitive.js +106 -0
  113. package/dist/indexer/ast/complexity/cognitive.js.map +1 -0
  114. package/dist/indexer/ast/complexity/cyclomatic.d.ts +12 -0
  115. package/dist/indexer/ast/complexity/cyclomatic.d.ts.map +1 -0
  116. package/dist/indexer/ast/complexity/cyclomatic.js +61 -0
  117. package/dist/indexer/ast/complexity/cyclomatic.js.map +1 -0
  118. package/dist/indexer/ast/complexity/halstead.d.ts +55 -0
  119. package/dist/indexer/ast/complexity/halstead.d.ts.map +1 -0
  120. package/dist/indexer/ast/complexity/halstead.js +290 -0
  121. package/dist/indexer/ast/complexity/halstead.js.map +1 -0
  122. package/dist/indexer/ast/complexity/index.d.ts +13 -0
  123. package/dist/indexer/ast/complexity/index.d.ts.map +1 -0
  124. package/dist/indexer/ast/complexity/index.js +12 -0
  125. package/dist/indexer/ast/complexity/index.js.map +1 -0
  126. package/dist/indexer/ast/parser.d.ts +27 -0
  127. package/dist/indexer/ast/parser.d.ts.map +1 -0
  128. package/dist/indexer/ast/parser.js +103 -0
  129. package/dist/indexer/ast/parser.js.map +1 -0
  130. package/dist/indexer/ast/symbols.d.ts +17 -0
  131. package/dist/indexer/ast/symbols.d.ts.map +1 -0
  132. package/dist/indexer/ast/symbols.js +265 -0
  133. package/dist/indexer/ast/symbols.js.map +1 -0
  134. package/dist/indexer/ast/traversers/index.d.ts +19 -0
  135. package/dist/indexer/ast/traversers/index.d.ts.map +1 -0
  136. package/dist/indexer/ast/traversers/index.js +42 -0
  137. package/dist/indexer/ast/traversers/index.js.map +1 -0
  138. package/dist/indexer/ast/traversers/php.d.ts +21 -0
  139. package/dist/indexer/ast/traversers/php.d.ts.map +1 -0
  140. package/dist/indexer/ast/traversers/php.js +67 -0
  141. package/dist/indexer/ast/traversers/php.js.map +1 -0
  142. package/dist/indexer/ast/traversers/python.d.ts +28 -0
  143. package/dist/indexer/ast/traversers/python.d.ts.map +1 -0
  144. package/dist/indexer/ast/traversers/python.js +67 -0
  145. package/dist/indexer/ast/traversers/python.js.map +1 -0
  146. package/dist/indexer/ast/traversers/types.d.ts +98 -0
  147. package/dist/indexer/ast/traversers/types.d.ts.map +1 -0
  148. package/dist/indexer/ast/traversers/types.js +2 -0
  149. package/dist/indexer/ast/traversers/types.js.map +1 -0
  150. package/dist/indexer/ast/traversers/typescript.d.ts +29 -0
  151. package/dist/indexer/ast/traversers/typescript.d.ts.map +1 -0
  152. package/dist/indexer/ast/traversers/typescript.js +88 -0
  153. package/dist/indexer/ast/traversers/typescript.js.map +1 -0
  154. package/dist/indexer/ast/types.d.ts +59 -0
  155. package/dist/indexer/ast/types.d.ts.map +1 -0
  156. package/dist/indexer/ast/types.js +2 -0
  157. package/dist/indexer/ast/types.js.map +1 -0
  158. package/dist/indexer/change-detector.d.ts +17 -0
  159. package/dist/indexer/change-detector.d.ts.map +1 -0
  160. package/dist/indexer/change-detector.js +207 -0
  161. package/dist/indexer/change-detector.js.map +1 -0
  162. package/dist/indexer/chunk-batch-processor.d.ts +103 -0
  163. package/dist/indexer/chunk-batch-processor.d.ts.map +1 -0
  164. package/dist/indexer/chunk-batch-processor.js +179 -0
  165. package/dist/indexer/chunk-batch-processor.js.map +1 -0
  166. package/dist/indexer/chunker.d.ts +10 -0
  167. package/dist/indexer/chunker.d.ts.map +1 -0
  168. package/dist/indexer/chunker.js +96 -0
  169. package/dist/indexer/chunker.js.map +1 -0
  170. package/dist/indexer/dependency-analyzer.d.ts +60 -0
  171. package/dist/indexer/dependency-analyzer.d.ts.map +1 -0
  172. package/dist/indexer/dependency-analyzer.js +261 -0
  173. package/dist/indexer/dependency-analyzer.js.map +1 -0
  174. package/dist/indexer/incremental.d.ts +47 -0
  175. package/dist/indexer/incremental.d.ts.map +1 -0
  176. package/dist/indexer/incremental.js +284 -0
  177. package/dist/indexer/incremental.js.map +1 -0
  178. package/dist/indexer/index.d.ts +80 -0
  179. package/dist/indexer/index.d.ts.map +1 -0
  180. package/dist/indexer/index.js +364 -0
  181. package/dist/indexer/index.js.map +1 -0
  182. package/dist/indexer/json-template-chunker.d.ts +9 -0
  183. package/dist/indexer/json-template-chunker.d.ts.map +1 -0
  184. package/dist/indexer/json-template-chunker.js +83 -0
  185. package/dist/indexer/json-template-chunker.js.map +1 -0
  186. package/dist/indexer/liquid-chunker.d.ts +13 -0
  187. package/dist/indexer/liquid-chunker.d.ts.map +1 -0
  188. package/dist/indexer/liquid-chunker.js +272 -0
  189. package/dist/indexer/liquid-chunker.js.map +1 -0
  190. package/dist/indexer/manifest.d.ts +122 -0
  191. package/dist/indexer/manifest.d.ts.map +1 -0
  192. package/dist/indexer/manifest.js +262 -0
  193. package/dist/indexer/manifest.js.map +1 -0
  194. package/dist/indexer/progress-tracker.d.ts +35 -0
  195. package/dist/indexer/progress-tracker.d.ts.map +1 -0
  196. package/dist/indexer/progress-tracker.js +33 -0
  197. package/dist/indexer/progress-tracker.js.map +1 -0
  198. package/dist/indexer/scanner.d.ts +16 -0
  199. package/dist/indexer/scanner.d.ts.map +1 -0
  200. package/dist/indexer/scanner.js +159 -0
  201. package/dist/indexer/scanner.js.map +1 -0
  202. package/dist/indexer/symbol-extractor.d.ts +18 -0
  203. package/dist/indexer/symbol-extractor.d.ts.map +1 -0
  204. package/dist/indexer/symbol-extractor.js +351 -0
  205. package/dist/indexer/symbol-extractor.js.map +1 -0
  206. package/dist/indexer/types.d.ts +34 -0
  207. package/dist/indexer/types.d.ts.map +1 -0
  208. package/dist/indexer/types.js +2 -0
  209. package/dist/indexer/types.js.map +1 -0
  210. package/dist/insights/complexity-analyzer.d.ts +82 -0
  211. package/dist/insights/complexity-analyzer.d.ts.map +1 -0
  212. package/dist/insights/complexity-analyzer.js +356 -0
  213. package/dist/insights/complexity-analyzer.js.map +1 -0
  214. package/dist/insights/formatters/index.d.ts +11 -0
  215. package/dist/insights/formatters/index.d.ts.map +1 -0
  216. package/dist/insights/formatters/index.js +20 -0
  217. package/dist/insights/formatters/index.js.map +1 -0
  218. package/dist/insights/formatters/json.d.ts +7 -0
  219. package/dist/insights/formatters/json.d.ts.map +1 -0
  220. package/dist/insights/formatters/json.js +14 -0
  221. package/dist/insights/formatters/json.js.map +1 -0
  222. package/dist/insights/formatters/sarif.d.ts +6 -0
  223. package/dist/insights/formatters/sarif.d.ts.map +1 -0
  224. package/dist/insights/formatters/sarif.js +113 -0
  225. package/dist/insights/formatters/sarif.js.map +1 -0
  226. package/dist/insights/formatters/text.d.ts +6 -0
  227. package/dist/insights/formatters/text.d.ts.map +1 -0
  228. package/dist/insights/formatters/text.js +154 -0
  229. package/dist/insights/formatters/text.js.map +1 -0
  230. package/dist/insights/types.d.ts +73 -0
  231. package/dist/insights/types.d.ts.map +1 -0
  232. package/dist/insights/types.js +9 -0
  233. package/dist/insights/types.js.map +1 -0
  234. package/dist/types/index.d.ts +14 -0
  235. package/dist/types/index.d.ts.map +1 -0
  236. package/dist/types/index.js +8 -0
  237. package/dist/types/index.js.map +1 -0
  238. package/dist/utils/path-matching.d.ts +69 -0
  239. package/dist/utils/path-matching.d.ts.map +1 -0
  240. package/dist/utils/path-matching.js +123 -0
  241. package/dist/utils/path-matching.js.map +1 -0
  242. package/dist/utils/result.d.ts +65 -0
  243. package/dist/utils/result.d.ts.map +1 -0
  244. package/dist/utils/result.js +67 -0
  245. package/dist/utils/result.js.map +1 -0
  246. package/dist/utils/version.d.ts +22 -0
  247. package/dist/utils/version.d.ts.map +1 -0
  248. package/dist/utils/version.js +28 -0
  249. package/dist/utils/version.js.map +1 -0
  250. package/dist/vectordb/batch-insert.d.ts +14 -0
  251. package/dist/vectordb/batch-insert.d.ts.map +1 -0
  252. package/dist/vectordb/batch-insert.js +185 -0
  253. package/dist/vectordb/batch-insert.js.map +1 -0
  254. package/dist/vectordb/boosting/composer.d.ts +51 -0
  255. package/dist/vectordb/boosting/composer.d.ts.map +1 -0
  256. package/dist/vectordb/boosting/composer.js +65 -0
  257. package/dist/vectordb/boosting/composer.js.map +1 -0
  258. package/dist/vectordb/boosting/index.d.ts +22 -0
  259. package/dist/vectordb/boosting/index.d.ts.map +1 -0
  260. package/dist/vectordb/boosting/index.js +22 -0
  261. package/dist/vectordb/boosting/index.js.map +1 -0
  262. package/dist/vectordb/boosting/strategies.d.ts +40 -0
  263. package/dist/vectordb/boosting/strategies.d.ts.map +1 -0
  264. package/dist/vectordb/boosting/strategies.js +174 -0
  265. package/dist/vectordb/boosting/strategies.js.map +1 -0
  266. package/dist/vectordb/boosting/types.d.ts +20 -0
  267. package/dist/vectordb/boosting/types.d.ts.map +1 -0
  268. package/dist/vectordb/boosting/types.js +2 -0
  269. package/dist/vectordb/boosting/types.js.map +1 -0
  270. package/dist/vectordb/intent-classifier.d.ts +99 -0
  271. package/dist/vectordb/intent-classifier.d.ts.map +1 -0
  272. package/dist/vectordb/intent-classifier.js +193 -0
  273. package/dist/vectordb/intent-classifier.js.map +1 -0
  274. package/dist/vectordb/lancedb.d.ts +45 -0
  275. package/dist/vectordb/lancedb.d.ts.map +1 -0
  276. package/dist/vectordb/lancedb.js +203 -0
  277. package/dist/vectordb/lancedb.js.map +1 -0
  278. package/dist/vectordb/maintenance.d.ts +18 -0
  279. package/dist/vectordb/maintenance.d.ts.map +1 -0
  280. package/dist/vectordb/maintenance.js +87 -0
  281. package/dist/vectordb/maintenance.js.map +1 -0
  282. package/dist/vectordb/query.d.ts +34 -0
  283. package/dist/vectordb/query.d.ts.map +1 -0
  284. package/dist/vectordb/query.js +303 -0
  285. package/dist/vectordb/query.js.map +1 -0
  286. package/dist/vectordb/relevance.d.ts +15 -0
  287. package/dist/vectordb/relevance.d.ts.map +1 -0
  288. package/dist/vectordb/relevance.js +19 -0
  289. package/dist/vectordb/relevance.js.map +1 -0
  290. package/dist/vectordb/types.d.ts +29 -0
  291. package/dist/vectordb/types.d.ts.map +1 -0
  292. package/dist/vectordb/types.js +2 -0
  293. package/dist/vectordb/types.js.map +1 -0
  294. package/dist/vectordb/version.d.ts +16 -0
  295. package/dist/vectordb/version.d.ts.map +1 -0
  296. package/dist/vectordb/version.js +40 -0
  297. package/dist/vectordb/version.js.map +1 -0
  298. package/package.json +66 -0
@@ -0,0 +1,268 @@
1
+ import { parseAST, detectLanguage, isASTSupported } from './parser.js';
2
+ import { extractSymbolInfo, extractImports } from './symbols.js';
3
+ import { calculateCognitiveComplexity, calculateHalstead } from './complexity/index.js';
4
+ import { getTraverser } from './traversers/index.js';
5
+ /**
6
+ * Chunk a file using AST-based semantic boundaries
7
+ *
8
+ * Uses Tree-sitter to parse code into an AST and extract semantic chunks
9
+ * (functions, classes, methods) that respect code structure.
10
+ *
11
+ * **Known Limitations:**
12
+ * - Tree-sitter may fail with "Invalid argument" error on very large files (1000+ lines)
13
+ * - When this occurs, Lien automatically falls back to line-based chunking
14
+ * - Configure fallback behavior via `chunking.astFallback` ('line-based' or 'error')
15
+ *
16
+ * @param filepath - Path to the file
17
+ * @param content - File content
18
+ * @param options - Chunking options
19
+ * @returns Array of AST-aware chunks
20
+ * @throws Error if AST parsing fails and astFallback is 'error'
21
+ */
22
+ export function chunkByAST(filepath, content, options = {}) {
23
+ const { minChunkSize = 5 } = options;
24
+ // Check if AST is supported for this file
25
+ const language = detectLanguage(filepath);
26
+ if (!language) {
27
+ throw new Error(`Unsupported language for file: ${filepath}`);
28
+ }
29
+ // Parse the file
30
+ const parseResult = parseAST(content, language);
31
+ // If parsing failed, throw error (caller should fallback to line-based)
32
+ if (!parseResult.tree) {
33
+ throw new Error(`Failed to parse ${filepath}: ${parseResult.error}`);
34
+ }
35
+ const chunks = [];
36
+ const lines = content.split('\n');
37
+ const rootNode = parseResult.tree.rootNode;
38
+ // Get language-specific traverser
39
+ const traverser = getTraverser(language);
40
+ // Extract file-level imports once
41
+ const fileImports = extractImports(rootNode);
42
+ // Find all top-level function and class declarations
43
+ const topLevelNodes = findTopLevelNodes(rootNode, traverser);
44
+ for (const node of topLevelNodes) {
45
+ // For variable declarations, try to find the function inside
46
+ let actualNode = node;
47
+ if (traverser.isDeclarationWithFunction(node)) {
48
+ const declInfo = traverser.findFunctionInDeclaration(node);
49
+ if (declInfo.functionNode) {
50
+ actualNode = declInfo.functionNode;
51
+ }
52
+ }
53
+ // For methods, find the parent container name (e.g., class name)
54
+ const parentClassName = traverser.findParentContainerName(actualNode);
55
+ const symbolInfo = extractSymbolInfo(actualNode, content, parentClassName, language);
56
+ // Extract the code for this node (use original node for full declaration)
57
+ const nodeContent = getNodeContent(node, lines);
58
+ // Create a chunk for this semantic unit
59
+ // Note: Large functions are kept as single chunks (may exceed maxChunkSize)
60
+ // This preserves semantic boundaries - better than splitting mid-function
61
+ chunks.push(createChunk(filepath, node, nodeContent, symbolInfo, fileImports, language));
62
+ }
63
+ // Handle remaining code (imports, exports, top-level statements)
64
+ const coveredRanges = topLevelNodes.map(n => ({
65
+ start: n.startPosition.row,
66
+ end: n.endPosition.row,
67
+ }));
68
+ const uncoveredChunks = extractUncoveredCode(lines, coveredRanges, filepath, minChunkSize, fileImports, language);
69
+ chunks.push(...uncoveredChunks);
70
+ // Sort chunks by line number
71
+ chunks.sort((a, b) => a.metadata.startLine - b.metadata.startLine);
72
+ return chunks;
73
+ }
74
+ /** Check if node is a function-containing declaration at top level */
75
+ function isFunctionDeclaration(node, depth, traverser) {
76
+ if (depth !== 0 || !traverser.isDeclarationWithFunction(node))
77
+ return false;
78
+ return traverser.findFunctionInDeclaration(node).hasFunction;
79
+ }
80
+ /** Check if node is a target type at valid depth */
81
+ function isTargetNode(node, depth, traverser) {
82
+ return depth <= 1 && traverser.targetNodeTypes.includes(node.type);
83
+ }
84
+ /**
85
+ * Find all top-level nodes that should become chunks
86
+ *
87
+ * Uses a language-specific traverser to handle different AST structures.
88
+ * This function is now language-agnostic - all language-specific logic
89
+ * is delegated to the traverser.
90
+ *
91
+ * @param rootNode - Root AST node
92
+ * @param traverser - Language-specific traverser
93
+ * @returns Array of nodes to extract as chunks
94
+ */
95
+ function findTopLevelNodes(rootNode, traverser) {
96
+ const nodes = [];
97
+ function traverse(node, depth) {
98
+ // Capture function declarations and target nodes
99
+ if (isFunctionDeclaration(node, depth, traverser) || isTargetNode(node, depth, traverser)) {
100
+ nodes.push(node);
101
+ return;
102
+ }
103
+ // Handle containers - traverse body at increased depth
104
+ if (traverser.shouldExtractChildren(node)) {
105
+ const body = traverser.getContainerBody(node);
106
+ if (body)
107
+ traverse(body, depth + 1);
108
+ return;
109
+ }
110
+ // Traverse children of traversable nodes
111
+ if (!traverser.shouldTraverseChildren(node))
112
+ return;
113
+ for (let i = 0; i < node.namedChildCount; i++) {
114
+ const child = node.namedChild(i);
115
+ if (child)
116
+ traverse(child, depth);
117
+ }
118
+ }
119
+ traverse(rootNode, 0);
120
+ return nodes;
121
+ }
122
+ /**
123
+ * Extract content for a specific AST node
124
+ */
125
+ function getNodeContent(node, lines) {
126
+ const startLine = node.startPosition.row;
127
+ const endLine = node.endPosition.row;
128
+ return lines.slice(startLine, endLine + 1).join('\n');
129
+ }
130
+ /** Maps symbol types to legacy symbol array keys */
131
+ const SYMBOL_TYPE_TO_ARRAY = {
132
+ function: 'functions',
133
+ method: 'functions',
134
+ class: 'classes',
135
+ interface: 'interfaces',
136
+ };
137
+ /** Symbol types that have meaningful complexity metrics */
138
+ const COMPLEXITY_SYMBOL_TYPES = new Set(['function', 'method']);
139
+ /**
140
+ * Build legacy symbols object for backward compatibility
141
+ */
142
+ function buildLegacySymbols(symbolInfo) {
143
+ const symbols = { functions: [], classes: [], interfaces: [] };
144
+ if (symbolInfo?.name && symbolInfo.type) {
145
+ const arrayKey = SYMBOL_TYPE_TO_ARRAY[symbolInfo.type];
146
+ if (arrayKey)
147
+ symbols[arrayKey].push(symbolInfo.name);
148
+ }
149
+ return symbols;
150
+ }
151
+ /**
152
+ * Determine chunk type from symbol info
153
+ */
154
+ function getChunkType(symbolInfo) {
155
+ if (!symbolInfo)
156
+ return 'block';
157
+ return symbolInfo.type === 'class' ? 'class' : 'function';
158
+ }
159
+ /**
160
+ * Create a chunk from an AST node
161
+ */
162
+ function createChunk(filepath, node, content, symbolInfo, imports, language) {
163
+ const symbols = buildLegacySymbols(symbolInfo);
164
+ const shouldCalcComplexity = symbolInfo?.type && COMPLEXITY_SYMBOL_TYPES.has(symbolInfo.type);
165
+ // Calculate complexity metrics only for functions and methods
166
+ const cognitiveComplexity = shouldCalcComplexity
167
+ ? calculateCognitiveComplexity(node)
168
+ : undefined;
169
+ // Calculate Halstead metrics only for functions and methods
170
+ const halstead = shouldCalcComplexity
171
+ ? calculateHalstead(node, language)
172
+ : undefined;
173
+ return {
174
+ content,
175
+ metadata: {
176
+ file: filepath,
177
+ startLine: node.startPosition.row + 1,
178
+ endLine: node.endPosition.row + 1,
179
+ type: getChunkType(symbolInfo),
180
+ language,
181
+ symbols,
182
+ symbolName: symbolInfo?.name,
183
+ symbolType: symbolInfo?.type,
184
+ parentClass: symbolInfo?.parentClass,
185
+ complexity: symbolInfo?.complexity,
186
+ cognitiveComplexity,
187
+ parameters: symbolInfo?.parameters,
188
+ signature: symbolInfo?.signature,
189
+ imports,
190
+ // Halstead metrics
191
+ halsteadVolume: halstead?.volume,
192
+ halsteadDifficulty: halstead?.difficulty,
193
+ halsteadEffort: halstead?.effort,
194
+ halsteadBugs: halstead?.bugs,
195
+ },
196
+ };
197
+ }
198
+ /**
199
+ * Find gaps between covered ranges (uncovered code)
200
+ */
201
+ function findUncoveredRanges(coveredRanges, totalLines) {
202
+ const uncoveredRanges = [];
203
+ let currentStart = 0;
204
+ // Sort covered ranges
205
+ const sortedRanges = [...coveredRanges].sort((a, b) => a.start - b.start);
206
+ for (const range of sortedRanges) {
207
+ if (currentStart < range.start) {
208
+ // There's a gap before this range
209
+ uncoveredRanges.push({
210
+ start: currentStart,
211
+ end: range.start - 1,
212
+ });
213
+ }
214
+ currentStart = range.end + 1;
215
+ }
216
+ // Handle remaining code after last covered range
217
+ if (currentStart < totalLines) {
218
+ uncoveredRanges.push({
219
+ start: currentStart,
220
+ end: totalLines - 1,
221
+ });
222
+ }
223
+ return uncoveredRanges;
224
+ }
225
+ /**
226
+ * Create a chunk from a line range
227
+ */
228
+ function createChunkFromRange(range, lines, filepath, language, imports) {
229
+ const uncoveredLines = lines.slice(range.start, range.end + 1);
230
+ const content = uncoveredLines.join('\n').trim();
231
+ return {
232
+ content,
233
+ metadata: {
234
+ file: filepath,
235
+ startLine: range.start + 1,
236
+ endLine: range.end + 1,
237
+ type: 'block',
238
+ language,
239
+ // Empty symbols for uncovered code (imports, exports, etc.)
240
+ symbols: { functions: [], classes: [], interfaces: [] },
241
+ imports,
242
+ },
243
+ };
244
+ }
245
+ /**
246
+ * Validate that a chunk meets the minimum size requirements
247
+ */
248
+ function isValidChunk(chunk, minChunkSize) {
249
+ const lineCount = chunk.metadata.endLine - chunk.metadata.startLine + 1;
250
+ return chunk.content.length > 0 && lineCount >= minChunkSize;
251
+ }
252
+ /**
253
+ * Extract code that wasn't covered by function/class chunks
254
+ * (imports, exports, top-level statements)
255
+ */
256
+ function extractUncoveredCode(lines, coveredRanges, filepath, minChunkSize, imports, language) {
257
+ const uncoveredRanges = findUncoveredRanges(coveredRanges, lines.length);
258
+ return uncoveredRanges
259
+ .map(range => createChunkFromRange(range, lines, filepath, language, imports))
260
+ .filter(chunk => isValidChunk(chunk, minChunkSize));
261
+ }
262
+ /**
263
+ * Check if AST chunking should be used for a file
264
+ */
265
+ export function shouldUseAST(filepath) {
266
+ return isASTSupported(filepath);
267
+ }
268
+ //# sourceMappingURL=chunker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunker.js","sourceRoot":"","sources":["../../../src/indexer/ast/chunker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type Parser from 'tree-sitter';
2
+ /**
3
+ * Calculate cognitive complexity of a function
4
+ *
5
+ * Based on SonarSource's Cognitive Complexity specification:
6
+ * - +1 for each break from linear flow (if, for, while, catch, etc.)
7
+ * - +1 for each nesting level when inside a control structure
8
+ * - +1 for each logical operator sequence break (a && b || c)
9
+ *
10
+ * @see https://www.sonarsource.com/docs/CognitiveComplexity.pdf
11
+ *
12
+ * @param node - AST node to analyze (typically a function/method)
13
+ * @returns Cognitive complexity score (minimum 0)
14
+ */
15
+ export declare function calculateCognitiveComplexity(node: Parser.SyntaxNode): number;
16
+ //# sourceMappingURL=cognitive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cognitive.d.ts","sourceRoot":"","sources":["../../../../src/indexer/ast/complexity/cognitive.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AA+FtC;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CA+B5E"}
@@ -0,0 +1,106 @@
1
+ // Node types that increase complexity AND increment nesting for children
2
+ const NESTING_TYPES = new Set([
3
+ 'if_statement', 'for_statement', 'while_statement', 'switch_statement',
4
+ 'catch_clause', 'except_clause', 'do_statement', 'for_in_statement',
5
+ 'for_of_statement', 'foreach_statement', 'match_statement',
6
+ ]);
7
+ // Types that add complexity but DON'T nest (hybrid increments)
8
+ const NON_NESTING_TYPES = new Set([
9
+ 'else_clause', 'elif_clause', 'ternary_expression', 'conditional_expression',
10
+ ]);
11
+ // Lambda types that add complexity when nested
12
+ const LAMBDA_TYPES = new Set(['arrow_function', 'function_expression', 'lambda']);
13
+ /**
14
+ * Check if node is a logical operator and return normalized form
15
+ */
16
+ function getLogicalOperator(node) {
17
+ if (node.type !== 'binary_expression' && node.type !== 'boolean_operator') {
18
+ return null;
19
+ }
20
+ const operator = node.childForFieldName('operator');
21
+ const opText = operator?.text;
22
+ if (opText === '&&' || opText === 'and')
23
+ return '&&';
24
+ if (opText === '||' || opText === 'or')
25
+ return '||';
26
+ return null;
27
+ }
28
+ /**
29
+ * Determine nesting level for a child node based on SonarSource spec.
30
+ */
31
+ function getChildNestingLevel(parent, child, currentLevel) {
32
+ const isCondition = parent.childForFieldName('condition') === child;
33
+ const isElseClause = NON_NESTING_TYPES.has(child.type);
34
+ return (!isCondition && !isElseClause) ? currentLevel + 1 : currentLevel;
35
+ }
36
+ /**
37
+ * Get complexity increment for nested lambda (only adds if already nested)
38
+ */
39
+ function getNestedLambdaIncrement(nodeType, nestingLevel) {
40
+ return (LAMBDA_TYPES.has(nodeType) && nestingLevel > 0) ? 1 : 0;
41
+ }
42
+ /** Traverse logical operator children, passing the operator type */
43
+ function traverseLogicalChildren(n, level, op, ctx) {
44
+ const operator = n.childForFieldName('operator');
45
+ for (let i = 0; i < n.namedChildCount; i++) {
46
+ const child = n.namedChild(i);
47
+ if (child && child !== operator)
48
+ ctx.traverse(child, level, op);
49
+ }
50
+ }
51
+ /** Traverse nesting type children with proper nesting level adjustment */
52
+ function traverseNestingChildren(n, level, ctx) {
53
+ for (let i = 0; i < n.namedChildCount; i++) {
54
+ const child = n.namedChild(i);
55
+ if (child)
56
+ ctx.traverse(child, getChildNestingLevel(n, child, level), null);
57
+ }
58
+ }
59
+ /** Traverse all children at specified level */
60
+ function traverseAllChildren(n, level, ctx) {
61
+ for (let i = 0; i < n.namedChildCount; i++) {
62
+ const child = n.namedChild(i);
63
+ if (child)
64
+ ctx.traverse(child, level, null);
65
+ }
66
+ }
67
+ /**
68
+ * Calculate cognitive complexity of a function
69
+ *
70
+ * Based on SonarSource's Cognitive Complexity specification:
71
+ * - +1 for each break from linear flow (if, for, while, catch, etc.)
72
+ * - +1 for each nesting level when inside a control structure
73
+ * - +1 for each logical operator sequence break (a && b || c)
74
+ *
75
+ * @see https://www.sonarsource.com/docs/CognitiveComplexity.pdf
76
+ *
77
+ * @param node - AST node to analyze (typically a function/method)
78
+ * @returns Cognitive complexity score (minimum 0)
79
+ */
80
+ export function calculateCognitiveComplexity(node) {
81
+ let complexity = 0;
82
+ const ctx = { traverse };
83
+ function traverse(n, nestingLevel, lastLogicalOp) {
84
+ const logicalOp = getLogicalOperator(n);
85
+ if (logicalOp) {
86
+ complexity += (lastLogicalOp !== logicalOp) ? 1 : 0;
87
+ traverseLogicalChildren(n, nestingLevel, logicalOp, ctx);
88
+ return;
89
+ }
90
+ if (NESTING_TYPES.has(n.type)) {
91
+ complexity += 1 + nestingLevel;
92
+ traverseNestingChildren(n, nestingLevel, ctx);
93
+ return;
94
+ }
95
+ if (NON_NESTING_TYPES.has(n.type)) {
96
+ complexity += 1;
97
+ traverseAllChildren(n, nestingLevel + 1, ctx);
98
+ return;
99
+ }
100
+ complexity += getNestedLambdaIncrement(n.type, nestingLevel);
101
+ traverseAllChildren(n, nestingLevel, ctx);
102
+ }
103
+ traverse(node, 0, null);
104
+ return complexity;
105
+ }
106
+ //# sourceMappingURL=cognitive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cognitive.js","sourceRoot":"","sources":["../../../../src/indexer/ast/complexity/cognitive.ts"],"names":[],"mappings":"AAEA,yEAAyE;AACzE,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB;IACtE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,kBAAkB;IACnE,kBAAkB,EAAE,mBAAmB,EAAE,iBAAiB;CAC3D,CAAC,CAAC;AAEH,+DAA+D;AAC/D,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,wBAAwB;CAC7E,CAAC,CAAC;AAEH,+CAA+C;AAC/C,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,gBAAgB,EAAE,qBAAqB,EAAE,QAAQ,CAAC,CAAC,CAAC;AAOlF;;GAEG;AACH,SAAS,kBAAkB,CAAC,IAAuB;IACjD,IAAI,IAAI,CAAC,IAAI,KAAK,mBAAmB,IAAI,IAAI,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;QAC1E,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,QAAQ,EAAE,IAAI,CAAC;IAE9B,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACrD,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACpD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAC3B,MAAyB,EACzB,KAAwB,EACxB,YAAoB;IAEpB,MAAM,WAAW,GAAG,MAAM,CAAC,iBAAiB,CAAC,WAAW,CAAC,KAAK,KAAK,CAAC;IACpE,MAAM,YAAY,GAAG,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvD,OAAO,CAAC,CAAC,WAAW,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;AAC3E,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB,CAAC,QAAgB,EAAE,YAAoB;IACtE,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,oEAAoE;AACpE,SAAS,uBAAuB,CAC9B,CAAoB,EACpB,KAAa,EACb,EAAU,EACV,GAAqB;IAErB,MAAM,QAAQ,GAAG,CAAC,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,KAAK,IAAI,KAAK,KAAK,QAAQ;YAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,SAAS,uBAAuB,CAC9B,CAAoB,EACpB,KAAa,EACb,GAAqB;IAErB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,KAAK;YAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,+CAA+C;AAC/C,SAAS,mBAAmB,CAC1B,CAAoB,EACpB,KAAa,EACb,GAAqB;IAErB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,KAAK;YAAE,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,4BAA4B,CAAC,IAAuB;IAClE,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,GAAG,GAAqB,EAAE,QAAQ,EAAE,CAAC;IAE3C,SAAS,QAAQ,CAAC,CAAoB,EAAE,YAAoB,EAAE,aAA4B;QACxF,MAAM,SAAS,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;QAExC,IAAI,SAAS,EAAE,CAAC;YACd,UAAU,IAAI,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpD,uBAAuB,CAAC,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;YACzD,OAAO;QACT,CAAC;QAED,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,UAAU,IAAI,CAAC,GAAG,YAAY,CAAC;YAC/B,uBAAuB,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC;YAC9C,OAAO;QACT,CAAC;QAED,IAAI,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,UAAU,IAAI,CAAC,CAAC;YAChB,mBAAmB,CAAC,CAAC,EAAE,YAAY,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;YAC9C,OAAO;QACT,CAAC;QAED,UAAU,IAAI,wBAAwB,CAAC,CAAC,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC7D,mBAAmB,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC;IAC5C,CAAC;IAED,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;IACxB,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type Parser from 'tree-sitter';
2
+ /**
3
+ * Calculate cyclomatic complexity of a function
4
+ *
5
+ * Complexity = 1 (base) + number of decision points
6
+ * Decision points: if, while, do...while, for, for...in, for...of, foreach, case, catch, &&, ||, ?:
7
+ *
8
+ * @param node - AST node to analyze (typically a function/method)
9
+ * @returns Cyclomatic complexity score (minimum 1)
10
+ */
11
+ export declare function calculateComplexity(node: Parser.SyntaxNode): number;
12
+ //# sourceMappingURL=cyclomatic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cyclomatic.d.ts","sourceRoot":"","sources":["../../../../src/indexer/ast/complexity/cyclomatic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAgCtC;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAyBnE"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Decision point node types for cyclomatic complexity calculation.
3
+ *
4
+ * These AST node types represent branch points in code flow.
5
+ */
6
+ const DECISION_POINTS = [
7
+ // Common across languages (TypeScript/JavaScript/Python/PHP)
8
+ 'if_statement', // if conditions
9
+ 'while_statement', // while loops
10
+ 'for_statement', // for loops
11
+ 'switch_case', // switch/case statements
12
+ 'catch_clause', // try/catch error handling
13
+ 'ternary_expression', // Ternary operator (a ? b : c)
14
+ 'binary_expression', // For && and || logical operators
15
+ // TypeScript/JavaScript specific
16
+ 'do_statement', // do...while loops
17
+ 'for_in_statement', // for...in loops
18
+ 'for_of_statement', // for...of loops
19
+ // PHP specific
20
+ 'foreach_statement', // PHP foreach loops
21
+ // Python specific
22
+ 'elif_clause', // Python elif (adds decision point)
23
+ // Note: 'else_clause' is NOT a decision point (it's the default path)
24
+ 'except_clause', // Python except (try/except)
25
+ 'conditional_expression', // Python ternary (x if cond else y)
26
+ ];
27
+ /**
28
+ * Calculate cyclomatic complexity of a function
29
+ *
30
+ * Complexity = 1 (base) + number of decision points
31
+ * Decision points: if, while, do...while, for, for...in, for...of, foreach, case, catch, &&, ||, ?:
32
+ *
33
+ * @param node - AST node to analyze (typically a function/method)
34
+ * @returns Cyclomatic complexity score (minimum 1)
35
+ */
36
+ export function calculateComplexity(node) {
37
+ let complexity = 1; // Base complexity
38
+ function traverse(n) {
39
+ if (DECISION_POINTS.includes(n.type)) {
40
+ // For binary expressions, only count && and ||
41
+ if (n.type === 'binary_expression') {
42
+ const operator = n.childForFieldName('operator');
43
+ if (operator && (operator.text === '&&' || operator.text === '||')) {
44
+ complexity++;
45
+ }
46
+ }
47
+ else {
48
+ complexity++;
49
+ }
50
+ }
51
+ // Traverse children
52
+ for (let i = 0; i < n.namedChildCount; i++) {
53
+ const child = n.namedChild(i);
54
+ if (child)
55
+ traverse(child);
56
+ }
57
+ }
58
+ traverse(node);
59
+ return complexity;
60
+ }
61
+ //# sourceMappingURL=cyclomatic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cyclomatic.js","sourceRoot":"","sources":["../../../../src/indexer/ast/complexity/cyclomatic.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,eAAe,GAAG;IACtB,6DAA6D;IAC7D,cAAc,EAAW,gBAAgB;IACzC,iBAAiB,EAAQ,cAAc;IACvC,eAAe,EAAU,YAAY;IACrC,aAAa,EAAY,yBAAyB;IAClD,cAAc,EAAW,2BAA2B;IACpD,oBAAoB,EAAK,+BAA+B;IACxD,mBAAmB,EAAM,kCAAkC;IAE3D,iCAAiC;IACjC,cAAc,EAAW,mBAAmB;IAC5C,kBAAkB,EAAO,iBAAiB;IAC1C,kBAAkB,EAAO,iBAAiB;IAE1C,eAAe;IACf,mBAAmB,EAAM,oBAAoB;IAE7C,kBAAkB;IAClB,aAAa,EAAY,oCAAoC;IAC7D,sEAAsE;IACtE,eAAe,EAAU,6BAA6B;IACtD,wBAAwB,EAAE,oCAAoC;CAC/D,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAuB;IACzD,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,kBAAkB;IAEtC,SAAS,QAAQ,CAAC,CAAoB;QACpC,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YACrC,+CAA+C;YAC/C,IAAI,CAAC,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;gBACnC,MAAM,QAAQ,GAAG,CAAC,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;gBACjD,IAAI,QAAQ,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;oBACnE,UAAU,EAAE,CAAC;gBACf,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,UAAU,EAAE,CAAC;YACf,CAAC;QACH,CAAC;QAED,oBAAoB;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,MAAM,KAAK,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC9B,IAAI,KAAK;gBAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,IAAI,CAAC,CAAC;IACf,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,55 @@
1
+ import type Parser from 'tree-sitter';
2
+ /** Raw Halstead counts from AST */
3
+ export interface HalsteadCounts {
4
+ n1: number;
5
+ n2: number;
6
+ N1: number;
7
+ N2: number;
8
+ operators: Map<string, number>;
9
+ operands: Map<string, number>;
10
+ }
11
+ /** Calculated Halstead metrics */
12
+ export interface HalsteadMetrics {
13
+ vocabulary: number;
14
+ length: number;
15
+ volume: number;
16
+ difficulty: number;
17
+ effort: number;
18
+ time: number;
19
+ bugs: number;
20
+ }
21
+ /**
22
+ * Count operators and operands in an AST node
23
+ *
24
+ * @param node - AST node to analyze (typically a function/method)
25
+ * @param language - Programming language for language-specific handling
26
+ * @returns HalsteadCounts with raw operator/operand counts
27
+ */
28
+ export declare function countHalstead(node: Parser.SyntaxNode, language: string): HalsteadCounts;
29
+ /**
30
+ * Calculate derived Halstead metrics from raw counts
31
+ *
32
+ * Formulas based on Maurice Halstead's "Elements of Software Science" (1977):
33
+ * - Vocabulary (n) = n1 + n2
34
+ * - Length (N) = N1 + N2
35
+ * - Volume (V) = N × log₂(n) - size of implementation
36
+ * - Difficulty (D) = (n1/2) × (N2/n2) - error-proneness
37
+ * - Effort (E) = D × V - mental effort required
38
+ * - Time (T) = E / 18 - seconds to understand (Stroud number)
39
+ * - Bugs (B) = V / 3000 - estimated delivered bugs
40
+ *
41
+ * @param counts - Raw Halstead counts from countHalstead()
42
+ * @returns Calculated HalsteadMetrics
43
+ */
44
+ export declare function calculateHalsteadMetrics(counts: HalsteadCounts): HalsteadMetrics;
45
+ /**
46
+ * Calculate Halstead metrics for an AST node in one call
47
+ *
48
+ * Convenience function that combines countHalstead and calculateHalsteadMetrics.
49
+ *
50
+ * @param node - AST node to analyze
51
+ * @param language - Programming language
52
+ * @returns Calculated HalsteadMetrics
53
+ */
54
+ export declare function calculateHalstead(node: Parser.SyntaxNode, language: string): HalsteadMetrics;
55
+ //# sourceMappingURL=halstead.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"halstead.d.ts","sourceRoot":"","sources":["../../../../src/indexer/ast/complexity/halstead.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,mCAAmC;AACnC,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,kCAAkC;AAClC,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAiOD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAiCvF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAsBhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,CAG5F"}