@plebeiantech/lat.md 0.12.3-fork.17 → 0.12.3-fork.20

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 (244) hide show
  1. package/README.md +1 -1
  2. package/dist/src/cli/agent-invocation.d.ts +6 -0
  3. package/dist/src/cli/agent-invocation.js +23 -0
  4. package/dist/src/cli/fork-instructions.js +1 -1
  5. package/dist/src/cli/fork-scaffold.js +2 -2
  6. package/dist/src/cli/graph.d.ts +1 -1
  7. package/dist/src/cli/hook.js +11 -11
  8. package/dist/src/cli/index.js +41 -59
  9. package/dist/src/cli/init-preferences.js +5 -4
  10. package/dist/src/cli/init.d.ts +1 -1
  11. package/dist/src/cli/init.js +54 -45
  12. package/dist/src/cli/reindex.d.ts +1 -1
  13. package/dist/src/cli/reindex.js +2 -2
  14. package/dist/src/cli/search.d.ts +4 -4
  15. package/dist/src/cli/search.js +41 -28
  16. package/dist/src/cli/ui-build-server.d.ts +1 -1
  17. package/dist/src/cli/ui-build.d.ts +1 -1
  18. package/dist/src/cli/ui.d.ts +1 -1
  19. package/dist/src/fork/antigravity-hook.js +6 -6
  20. package/dist/src/fork/antigravity-init.d.ts +2 -2
  21. package/dist/src/fork/antigravity-init.js +2 -2
  22. package/dist/src/graph-export.js +7 -7
  23. package/dist/src/knowledge/index.js +2 -2
  24. package/dist/src/mcp/server.js +8 -8
  25. package/dist/src/search/cache.d.ts +1 -1
  26. package/dist/src/search/cache.js +40 -7
  27. package/dist/src/search/chunks.d.ts +2 -2
  28. package/dist/src/search/db.d.ts +5 -4
  29. package/dist/src/search/db.js +36 -40
  30. package/dist/src/search/embedder.js +1 -1
  31. package/dist/src/search/index.d.ts +1 -1
  32. package/dist/src/search/index.js +2 -2
  33. package/dist/src/search/lock.d.ts +4 -1
  34. package/dist/src/search/lock.js +30 -8
  35. package/dist/src/search/query.d.ts +5 -2
  36. package/dist/src/search/query.js +55 -38
  37. package/dist/src/search/search.d.ts +3 -1
  38. package/dist/src/search/search.js +21 -12
  39. package/dist/src/search/types.d.ts +2 -18
  40. package/dist/src/view/client/assets/{GraphView-BWlRdQM4.js → GraphView-Dij8mAA_.js} +1 -1
  41. package/dist/src/view/client/assets/{MarkdownEditor-MW-Ck1O0.js → MarkdownEditor-88Wbt0M1.js} +1 -1
  42. package/dist/src/view/client/assets/{abnfDiagram-VCTEODGH-Bn3RshMV.js → abnfDiagram-VCTEODGH-y0DlYa8E.js} +1 -1
  43. package/dist/src/view/client/assets/{arc-En9tdFQF.js → arc-FlMu8dnO.js} +1 -1
  44. package/dist/src/view/client/assets/{architectureDiagram-5GKGNRK7-B-9J1VAM.js → architectureDiagram-5GKGNRK7-DA_uWZW1.js} +1 -1
  45. package/dist/src/view/client/assets/{blockDiagram-I7D4REHJ-QlznwalP.js → blockDiagram-I7D4REHJ-BHQ5LU85.js} +1 -1
  46. package/dist/src/view/client/assets/{c4Diagram-7LVT6UL2-Bp2y8B4_.js → c4Diagram-7LVT6UL2-BRucKCt2.js} +1 -1
  47. package/dist/src/view/client/assets/channel-BgDNA_Ay.js +1 -0
  48. package/dist/src/view/client/assets/{chunk-2Q5K7J3B-CnBKL-lm.js → chunk-2Q5K7J3B-BJPcFivt.js} +1 -1
  49. package/dist/src/view/client/assets/{chunk-5VM5RSS4-LLYMi_n6.js → chunk-5VM5RSS4-v2q99bGz.js} +1 -1
  50. package/dist/src/view/client/assets/{chunk-F27PBJKO-VIeO7VF0.js → chunk-F27PBJKO-CcHOuJCs.js} +1 -1
  51. package/dist/src/view/client/assets/{chunk-IMKFNOWR-D5i67DVD.js → chunk-IMKFNOWR-DNxYuJNq.js} +1 -1
  52. package/dist/src/view/client/assets/{chunk-JWPE2WC7-D4qAtoL3.js → chunk-JWPE2WC7-C0eHKvLW.js} +1 -1
  53. package/dist/src/view/client/assets/{chunk-POPQ4Y6H-BMzOyiW_.js → chunk-POPQ4Y6H-57CWp2Ve.js} +1 -1
  54. package/dist/src/view/client/assets/{chunk-SVP7TREG-DWy5nbfp.js → chunk-SVP7TREG-BqcoxIJw.js} +1 -1
  55. package/dist/src/view/client/assets/{chunk-TICWLB2K-CVqCANFB.js → chunk-TICWLB2K-DRUJR5zH.js} +1 -1
  56. package/dist/src/view/client/assets/{chunk-XXDRQBXY-Bp23h6Tf.js → chunk-XXDRQBXY-Dez0oRoM.js} +1 -1
  57. package/dist/src/view/client/assets/classDiagram-ZZMXUADV-CFZ_Sgh5.js +1 -0
  58. package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-CFZ_Sgh5.js +1 -0
  59. package/dist/src/view/client/assets/{cose-bilkent-JH36ORCC-BCw7fCC2.js → cose-bilkent-JH36ORCC-BHtud6Hg.js} +1 -1
  60. package/dist/src/view/client/assets/{cynefin-OW5HDTMX--lYN4N9m.js → cynefin-OW5HDTMX-BjBW8VGk.js} +1 -1
  61. package/dist/src/view/client/assets/{cynefinDiagram-5FMLGOSQ-9sK5EV7v.js → cynefinDiagram-5FMLGOSQ-DwGuD7oF.js} +1 -1
  62. package/dist/src/view/client/assets/{dagre-GXQ25YYZ-CoMdEFCq.js → dagre-GXQ25YYZ-C5zSlGK9.js} +1 -1
  63. package/dist/src/view/client/assets/{diagram-S7CK7UJ4-D13dyWdd.js → diagram-S7CK7UJ4-C_NhA3bj.js} +1 -1
  64. package/dist/src/view/client/assets/{diagram-UQ7AKVKN-PdwLPPPA.js → diagram-UQ7AKVKN-az7QPYNb.js} +1 -1
  65. package/dist/src/view/client/assets/{diagram-VSXAHHWV-CtWWa_A7.js → diagram-VSXAHHWV-BRvDuM8_.js} +1 -1
  66. package/dist/src/view/client/assets/{diagram-VX7I27RA-BeCYcSU-.js → diagram-VX7I27RA-BWLgF6S-.js} +1 -1
  67. package/dist/src/view/client/assets/{diagram-Z3DM3KII-DiWabOBM.js → diagram-Z3DM3KII-DV3d6mL5.js} +1 -1
  68. package/dist/src/view/client/assets/{ebnfDiagram-PWID7BFC-CZQ3MD_K.js → ebnfDiagram-PWID7BFC-yUXrEAvK.js} +1 -1
  69. package/dist/src/view/client/assets/{erDiagram-RLTQ6QDP-B1AhXIrP.js → erDiagram-RLTQ6QDP-D35FN1Pt.js} +1 -1
  70. package/dist/src/view/client/assets/{flowDiagram-HODETNUW-Bhr0JM6P.js → flowDiagram-HODETNUW-BciZqsjT.js} +1 -1
  71. package/dist/src/view/client/assets/{ganttDiagram-EL5Y4UJY-CbP8iAkg.js → ganttDiagram-EL5Y4UJY-BysPGgXS.js} +1 -1
  72. package/dist/src/view/client/assets/{gitGraphDiagram-WWUBYQGX-B9uuGdLF.js → gitGraphDiagram-WWUBYQGX-C3DdJ5xG.js} +1 -1
  73. package/dist/src/view/client/assets/index-CJokoRSp.js +13 -0
  74. package/dist/src/view/client/assets/{infoDiagram-27XIBGKW-BrfwQ_Cq.js → infoDiagram-27XIBGKW-D3HZrDRb.js} +1 -1
  75. package/dist/src/view/client/assets/{ishikawaDiagram-5VMMS53U-CHtJ36re.js → ishikawaDiagram-5VMMS53U-BXyVIXTU.js} +1 -1
  76. package/dist/src/view/client/assets/{journeyDiagram-3NMN7TZE-BChcgX1s.js → journeyDiagram-3NMN7TZE-D4-1NxVU.js} +1 -1
  77. package/dist/src/view/client/assets/{kanban-definition-UXKFOSKX-BnwFsKiB.js → kanban-definition-UXKFOSKX-4Gu_5yBA.js} +1 -1
  78. package/dist/src/view/client/assets/{layout-Dnd0pLdb.js → layout-Jf1K3TMM.js} +1 -1
  79. package/dist/src/view/client/assets/{linear-CFhW2ozn.js → linear-DWfwzUT_.js} +1 -1
  80. package/dist/src/view/client/assets/{mermaid.core--OP6lXtW.js → mermaid.core-DMx_DAl8.js} +5 -5
  81. package/dist/src/view/client/assets/{mindmap-definition-YA3MSWOX-D51y2zbm.js → mindmap-definition-YA3MSWOX-8pxY_RWi.js} +1 -1
  82. package/dist/src/view/client/assets/{pegDiagram-XKGWAZYB--zyQJDvI.js → pegDiagram-XKGWAZYB-DNAw_O5t.js} +1 -1
  83. package/dist/src/view/client/assets/{pieDiagram-E7YTZNPT-Cj8mvpJy.js → pieDiagram-E7YTZNPT-uuvRCDkC.js} +1 -1
  84. package/dist/src/view/client/assets/{quadrantDiagram-AXDQQJYC-qvhJrnBf.js → quadrantDiagram-AXDQQJYC-BER2O4Aq.js} +1 -1
  85. package/dist/src/view/client/assets/{railroadDiagram-O6MQD6OU-CtWvxpSo.js → railroadDiagram-O6MQD6OU-CxEsJ_0n.js} +1 -1
  86. package/dist/src/view/client/assets/{requirementDiagram-BXWQKSXE-CBxen_KG.js → requirementDiagram-BXWQKSXE-yS9rspca.js} +1 -1
  87. package/dist/src/view/client/assets/{sankeyDiagram-P5KCCOFB-B_fUkmfc.js → sankeyDiagram-P5KCCOFB-Bqt70a2j.js} +1 -1
  88. package/dist/src/view/client/assets/{sequenceDiagram-WJ2MYXX4-Dclv4p68.js → sequenceDiagram-WJ2MYXX4-BvOOEJNr.js} +1 -1
  89. package/dist/src/view/client/assets/{sizeCapture-INFHLROL-GfG0sMTZ.js → sizeCapture-INFHLROL-CvO_Pjjo.js} +1 -1
  90. package/dist/src/view/client/assets/{stateDiagram-D77RDMKH-YQWPnzxU.js → stateDiagram-D77RDMKH-KLmVOZkq.js} +1 -1
  91. package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-KCS8Mdzu.js +1 -0
  92. package/dist/src/view/client/assets/{swimlanes-42K2YHIH-5yiCveVS.js → swimlanes-42K2YHIH-DC1r4_sq.js} +1 -1
  93. package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-B2TcAwis.js +8 -0
  94. package/dist/src/view/client/assets/{timeline-definition-24CTP7MA-BvAbB5Zs.js → timeline-definition-24CTP7MA-ChXLOuBL.js} +1 -1
  95. package/dist/src/view/client/assets/{vennDiagram-4TSXK5OY-guC-r60n.js → vennDiagram-4TSXK5OY-D9_h25-Y.js} +1 -1
  96. package/dist/src/view/client/assets/{wardleyDiagram-VM6X3IG4-C0yXcU2x.js → wardleyDiagram-VM6X3IG4-CsQJGGW0.js} +1 -1
  97. package/dist/src/view/client/assets/{xychartDiagram-S5SC5T6Z-RPmkPNfK.js → xychartDiagram-S5SC5T6Z-DGMuPMlm.js} +1 -1
  98. package/dist/src/view/client/index.html +1 -1
  99. package/dist/src/view/diagnostics.d.ts +2 -2
  100. package/dist/src/view/diagnostics.js +5 -5
  101. package/dist/src/view/external-document-tree.js +1 -1
  102. package/dist/src/view/git-diff.js +1 -1
  103. package/dist/src/view/git.js +1 -1
  104. package/dist/src/view/graph.d.ts +2 -2
  105. package/dist/src/view/graph.js +2 -2
  106. package/dist/src/view/markdown.js +1 -1
  107. package/dist/src/view/preindexed-search.d.ts +1 -1
  108. package/dist/src/view/protocol.d.ts +2 -18
  109. package/dist/src/view/publication.d.ts +2 -0
  110. package/dist/src/view/publication.js +78 -0
  111. package/dist/src/view/references.d.ts +3 -3
  112. package/dist/src/view/references.js +3 -3
  113. package/dist/src/view/repository.d.ts +6 -6
  114. package/dist/src/view/repository.js +28 -14
  115. package/dist/src/view/request-security.d.ts +5 -0
  116. package/dist/src/view/request-security.js +46 -0
  117. package/dist/src/view/search-result.d.ts +1 -1
  118. package/dist/src/view/search-result.js +1 -1
  119. package/dist/src/view/search.d.ts +1 -1
  120. package/dist/src/view/server-build.d.ts +2 -2
  121. package/dist/src/view/server-build.js +2 -2
  122. package/dist/src/view/server-deployment.d.ts +1 -2
  123. package/dist/src/view/server-deployment.js +6 -46
  124. package/dist/src/view/server-index-worker.d.ts +1 -1
  125. package/dist/src/view/server.d.ts +1 -1
  126. package/dist/src/view/server.js +13 -3
  127. package/dist/src/view/source-target.js +2 -2
  128. package/dist/src/view/static-build.d.ts +1 -1
  129. package/dist/src/view/static-build.js +49 -17
  130. package/dist/src/view/store.d.ts +4 -2
  131. package/dist/src/view/store.js +31 -19
  132. package/dist/src/view/table-of-contents.d.ts +1 -1
  133. package/dist/src/view/table-of-contents.js +1 -1
  134. package/dist/src/view/vercel-server-build.d.ts +1 -1
  135. package/package.json +19 -29
  136. package/templates/AGENTS.md +2 -2
  137. package/templates/cursor-rules.md +2 -2
  138. package/templates/opencode-plugin.ts +9 -9
  139. package/templates/pi-extension.ts +11 -11
  140. package/templates/skill/SKILL.md +2 -1
  141. package/dist/src/cli/check-context.d.ts +0 -56
  142. package/dist/src/cli/check-context.js +0 -215
  143. package/dist/src/cli/check-coverage.d.ts +0 -2
  144. package/dist/src/cli/check-coverage.js +0 -75
  145. package/dist/src/cli/check-frontmatter.d.ts +0 -12
  146. package/dist/src/cli/check-frontmatter.js +0 -44
  147. package/dist/src/cli/check-mode.d.ts +0 -21
  148. package/dist/src/cli/check-mode.js +0 -394
  149. package/dist/src/cli/check-status.d.ts +0 -74
  150. package/dist/src/cli/check-status.js +0 -217
  151. package/dist/src/cli/check.d.ts +0 -52
  152. package/dist/src/cli/check.js +0 -834
  153. package/dist/src/cli/context.d.ts +0 -11
  154. package/dist/src/cli/context.js +0 -58
  155. package/dist/src/cli/expand.d.ts +0 -7
  156. package/dist/src/cli/expand.js +0 -141
  157. package/dist/src/cli/external.d.ts +0 -11
  158. package/dist/src/cli/external.js +0 -185
  159. package/dist/src/cli/gen-index.d.ts +0 -45
  160. package/dist/src/cli/gen-index.js +0 -235
  161. package/dist/src/cli/link-scheme.d.ts +0 -54
  162. package/dist/src/cli/link-scheme.js +0 -101
  163. package/dist/src/cli/locate.d.ts +0 -2
  164. package/dist/src/cli/locate.js +0 -18
  165. package/dist/src/cli/refs.d.ts +0 -23
  166. package/dist/src/cli/refs.js +0 -274
  167. package/dist/src/cli/section.d.ts +0 -45
  168. package/dist/src/cli/section.js +0 -328
  169. package/dist/src/cli/select-menu.d.ts +0 -13
  170. package/dist/src/cli/select-menu.js +0 -100
  171. package/dist/src/code-refs.d.ts +0 -29
  172. package/dist/src/code-refs.js +0 -479
  173. package/dist/src/config.d.ts +0 -29
  174. package/dist/src/config.js +0 -83
  175. package/dist/src/context.d.ts +0 -26
  176. package/dist/src/context.js +0 -11
  177. package/dist/src/document-formats.d.ts +0 -7
  178. package/dist/src/document-formats.js +0 -39
  179. package/dist/src/extensions/alert-marker.d.ts +0 -25
  180. package/dist/src/extensions/alert-marker.js +0 -55
  181. package/dist/src/extensions/wiki-link/from-markdown.d.ts +0 -5
  182. package/dist/src/extensions/wiki-link/from-markdown.js +0 -34
  183. package/dist/src/extensions/wiki-link/index.d.ts +0 -4
  184. package/dist/src/extensions/wiki-link/index.js +0 -3
  185. package/dist/src/extensions/wiki-link/syntax.d.ts +0 -14
  186. package/dist/src/extensions/wiki-link/syntax.js +0 -121
  187. package/dist/src/extensions/wiki-link/to-markdown.d.ts +0 -5
  188. package/dist/src/extensions/wiki-link/to-markdown.js +0 -28
  189. package/dist/src/extensions/wiki-link/types.d.ts +0 -34
  190. package/dist/src/extensions/wiki-link/types.js +0 -1
  191. package/dist/src/external-documents.d.ts +0 -56
  192. package/dist/src/external-documents.js +0 -404
  193. package/dist/src/external-sources.d.ts +0 -136
  194. package/dist/src/external-sources.js +0 -1098
  195. package/dist/src/fork/frontmatter-fields.d.ts +0 -36
  196. package/dist/src/fork/frontmatter-fields.js +0 -23
  197. package/dist/src/format.d.ts +0 -16
  198. package/dist/src/format.js +0 -76
  199. package/dist/src/init-version.d.ts +0 -10
  200. package/dist/src/init-version.js +0 -49
  201. package/dist/src/lattice-model.d.ts +0 -84
  202. package/dist/src/lattice-model.js +0 -467
  203. package/dist/src/lattice.d.ts +0 -14
  204. package/dist/src/lattice.js +0 -353
  205. package/dist/src/markdown-analysis-cache.d.ts +0 -20
  206. package/dist/src/markdown-analysis-cache.js +0 -139
  207. package/dist/src/markdown-analysis-worker.d.ts +0 -16
  208. package/dist/src/markdown-analysis-worker.js +0 -33
  209. package/dist/src/markdown-analysis.d.ts +0 -61
  210. package/dist/src/markdown-analysis.js +0 -169
  211. package/dist/src/markdown-analyzer-loader.d.ts +0 -4
  212. package/dist/src/markdown-analyzer-loader.js +0 -13
  213. package/dist/src/markdown-validation.d.ts +0 -25
  214. package/dist/src/markdown-validation.js +0 -104
  215. package/dist/src/parser-cache.d.ts +0 -17
  216. package/dist/src/parser-cache.js +0 -65
  217. package/dist/src/parser-import.d.ts +0 -8
  218. package/dist/src/parser-import.js +0 -1
  219. package/dist/src/parser.d.ts +0 -3
  220. package/dist/src/parser.js +0 -93
  221. package/dist/src/path.d.ts +0 -2
  222. package/dist/src/path.js +0 -4
  223. package/dist/src/profiler.d.ts +0 -16
  224. package/dist/src/profiler.js +0 -81
  225. package/dist/src/project-analysis.d.ts +0 -59
  226. package/dist/src/project-analysis.js +0 -233
  227. package/dist/src/project-discovery.d.ts +0 -6
  228. package/dist/src/project-discovery.js +0 -30
  229. package/dist/src/repository-path.d.ts +0 -11
  230. package/dist/src/repository-path.js +0 -52
  231. package/dist/src/source-formats.d.ts +0 -7
  232. package/dist/src/source-formats.js +0 -30
  233. package/dist/src/source-parser.d.ts +0 -67
  234. package/dist/src/source-parser.js +0 -1749
  235. package/dist/src/untrusted.d.ts +0 -18
  236. package/dist/src/untrusted.js +0 -93
  237. package/dist/src/view/client/assets/channel-uy0fFvcW.js +0 -1
  238. package/dist/src/view/client/assets/classDiagram-ZZMXUADV-DbSEqjA5.js +0 -1
  239. package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-DbSEqjA5.js +0 -1
  240. package/dist/src/view/client/assets/index-nBmbYfun.js +0 -13
  241. package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-gUj6Hzgl.js +0 -1
  242. package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-DR7JhrxL.js +0 -8
  243. package/dist/src/walk.d.ts +0 -20
  244. package/dist/src/walk.js +0 -121
@@ -1,1749 +0,0 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { dirname, join } from 'node:path';
3
- import { createRequire } from 'node:module';
4
- import { performance } from 'node:perf_hooks';
5
- import { PARSER_CACHE_VERSION, hashParserContent, parsedCachePath, parserCacheIdentity, readParsedCache, writeParsedCache, } from './parser-cache.js';
6
- import { Parser, Language, } from 'web-tree-sitter';
7
- import { sourceFileExtension, } from './source-formats.js';
8
- // Lazy singleton for the parser
9
- let parserReady = null;
10
- let parserInstance = null;
11
- const languages = new Map();
12
- function wasmDir() {
13
- const require = createRequire(import.meta.url);
14
- const pkgPath = require.resolve('@repomix/tree-sitter-wasms/package.json');
15
- return join(dirname(pkgPath), 'out');
16
- }
17
- async function ensureParser() {
18
- if (!parserReady) {
19
- parserReady = Parser.init();
20
- }
21
- await parserReady;
22
- if (!parserInstance) {
23
- parserInstance = new Parser();
24
- }
25
- return parserInstance;
26
- }
27
- /** Every supported source extension must declare a tree-sitter grammar. */
28
- const grammarMap = {
29
- '.c': 'tree-sitter-c.wasm',
30
- '.dart': 'tree-sitter-dart.wasm',
31
- '.erb': 'tree-sitter-ruby.wasm',
32
- '.go': 'tree-sitter-go.wasm',
33
- '.h': 'tree-sitter-c.wasm',
34
- '.java': 'tree-sitter-java.wasm',
35
- '.js': 'tree-sitter-javascript.wasm',
36
- '.jsx': 'tree-sitter-javascript.wasm',
37
- '.php': 'tree-sitter-php.wasm',
38
- '.py': 'tree-sitter-python.wasm',
39
- '.rake': 'tree-sitter-ruby.wasm',
40
- '.rb': 'tree-sitter-ruby.wasm',
41
- '.rs': 'tree-sitter-rust.wasm',
42
- '.ts': 'tree-sitter-typescript.wasm',
43
- '.tsx': 'tree-sitter-tsx.wasm',
44
- };
45
- async function getLanguage(ext) {
46
- const wasmFile = grammarMap[ext];
47
- // Ensure WASM runtime is initialized before loading languages
48
- await ensureParser();
49
- if (!languages.has(wasmFile)) {
50
- const wasmPath = join(wasmDir(), wasmFile);
51
- const lang = await Language.load(wasmPath);
52
- languages.set(wasmFile, lang);
53
- }
54
- return languages.get(wasmFile);
55
- }
56
- function extractName(node) {
57
- const nameNode = node.childForFieldName('name');
58
- return nameNode ? nameNode.text : null;
59
- }
60
- function extractTsSymbols(tree) {
61
- const symbols = [];
62
- const root = tree.rootNode;
63
- for (let i = 0; i < root.childCount; i++) {
64
- let node = root.child(i);
65
- // Unwrap export_statement to get the inner declaration
66
- const isExport = node.type === 'export_statement';
67
- if (isExport) {
68
- const inner = node.namedChildren.find((c) => c.type === 'function_declaration' ||
69
- c.type === 'class_declaration' ||
70
- c.type === 'lexical_declaration' ||
71
- c.type === 'type_alias_declaration' ||
72
- c.type === 'interface_declaration' ||
73
- c.type === 'abstract_class_declaration');
74
- if (inner)
75
- node = inner;
76
- }
77
- const startLine = node.startPosition.row + 1;
78
- const endLine = node.endPosition.row + 1;
79
- if (node.type === 'function_declaration' ||
80
- node.type === 'generator_function_declaration') {
81
- const name = extractName(node);
82
- if (name) {
83
- symbols.push({
84
- name,
85
- kind: 'function',
86
- startLine,
87
- endLine,
88
- signature: firstLine(node.text),
89
- });
90
- }
91
- }
92
- else if (node.type === 'class_declaration' ||
93
- node.type === 'abstract_class_declaration') {
94
- const name = extractName(node);
95
- if (name) {
96
- symbols.push({
97
- name,
98
- kind: 'class',
99
- startLine,
100
- endLine,
101
- signature: firstLine(node.text),
102
- });
103
- // Extract methods
104
- const body = node.childForFieldName('body');
105
- if (body) {
106
- extractClassMethods(body, name, symbols);
107
- }
108
- }
109
- }
110
- else if (node.type === 'lexical_declaration') {
111
- // const/let declarations
112
- for (const decl of node.namedChildren) {
113
- if (decl.type === 'variable_declarator') {
114
- const name = extractName(decl);
115
- if (name) {
116
- symbols.push({
117
- name,
118
- kind: 'const',
119
- startLine,
120
- endLine,
121
- signature: firstLine(node.text),
122
- });
123
- }
124
- }
125
- }
126
- }
127
- else if (node.type === 'type_alias_declaration') {
128
- const name = extractName(node);
129
- if (name) {
130
- symbols.push({
131
- name,
132
- kind: 'type',
133
- startLine,
134
- endLine,
135
- signature: firstLine(node.text),
136
- });
137
- }
138
- }
139
- else if (node.type === 'interface_declaration') {
140
- const name = extractName(node);
141
- if (name) {
142
- symbols.push({
143
- name,
144
- kind: 'interface',
145
- startLine,
146
- endLine,
147
- signature: firstLine(node.text),
148
- });
149
- }
150
- }
151
- }
152
- return symbols;
153
- }
154
- function extractClassMethods(body, className, symbols) {
155
- for (let i = 0; i < body.namedChildCount; i++) {
156
- const member = body.namedChild(i);
157
- if (member.type === 'method_definition' ||
158
- member.type === 'public_field_definition') {
159
- const name = extractName(member);
160
- if (name) {
161
- symbols.push({
162
- name,
163
- kind: 'method',
164
- parent: className,
165
- startLine: member.startPosition.row + 1,
166
- endLine: member.endPosition.row + 1,
167
- signature: firstLine(member.text),
168
- });
169
- }
170
- }
171
- }
172
- }
173
- function extractPySymbols(tree) {
174
- const symbols = [];
175
- const root = tree.rootNode;
176
- for (let i = 0; i < root.childCount; i++) {
177
- const node = root.child(i);
178
- const startLine = node.startPosition.row + 1;
179
- const endLine = node.endPosition.row + 1;
180
- // Unwrap decorated_definition to get the inner function/class
181
- const inner = node.type === 'decorated_definition'
182
- ? node.childForFieldName('definition')
183
- : node;
184
- if (!inner)
185
- continue;
186
- if (inner.type === 'function_definition') {
187
- const name = extractName(inner);
188
- if (name) {
189
- symbols.push({
190
- name,
191
- kind: 'function',
192
- startLine,
193
- endLine,
194
- signature: firstLine(inner.text),
195
- });
196
- }
197
- }
198
- else if (inner.type === 'class_definition') {
199
- const name = extractName(inner);
200
- if (name) {
201
- symbols.push({
202
- name,
203
- kind: 'class',
204
- startLine,
205
- endLine,
206
- signature: firstLine(inner.text),
207
- });
208
- // Extract methods
209
- const body = inner.childForFieldName('body');
210
- if (body) {
211
- for (let j = 0; j < body.namedChildCount; j++) {
212
- let member = body.namedChild(j);
213
- // Unwrap decorated methods
214
- if (member.type === 'decorated_definition') {
215
- member = member.childForFieldName('definition') ?? member;
216
- }
217
- if (member.type === 'function_definition') {
218
- const methodName = extractName(member);
219
- if (methodName) {
220
- symbols.push({
221
- name: methodName,
222
- kind: 'method',
223
- parent: name,
224
- startLine: member.startPosition.row + 1,
225
- endLine: member.endPosition.row + 1,
226
- signature: firstLine(member.text),
227
- });
228
- }
229
- }
230
- }
231
- }
232
- }
233
- }
234
- else if (inner.type === 'expression_statement' &&
235
- inner.namedChildCount === 1 &&
236
- inner.namedChild(0).type === 'assignment') {
237
- // Top-level assignment: FOO = ...
238
- const assign = inner.namedChild(0);
239
- const left = assign.childForFieldName('left');
240
- if (left && left.type === 'identifier') {
241
- symbols.push({
242
- name: left.text,
243
- kind: 'variable',
244
- startLine,
245
- endLine,
246
- signature: firstLine(node.text),
247
- });
248
- }
249
- }
250
- }
251
- return symbols;
252
- }
253
- function collectRubyScope(scope, parent, symbols) {
254
- for (const node of scope.namedChildren) {
255
- const startLine = node.startPosition.row + 1;
256
- const endLine = node.endPosition.row + 1;
257
- const signature = firstLine(node.text);
258
- if (node.type === 'class' || node.type === 'module') {
259
- const nameNode = node.childForFieldName('name');
260
- if (nameNode) {
261
- let childPart;
262
- let parentPart;
263
- if (nameNode.type === 'scope_resolution' &&
264
- nameNode.namedChildren.length === 2) {
265
- parentPart = nameNode.namedChildren[0].text;
266
- childPart = nameNode.namedChildren[1].text;
267
- symbols.push({
268
- name: childPart,
269
- kind: 'class',
270
- startLine,
271
- endLine,
272
- signature,
273
- });
274
- symbols.push({
275
- name: childPart,
276
- kind: 'class',
277
- parent: parentPart,
278
- startLine,
279
- endLine,
280
- signature,
281
- });
282
- }
283
- else {
284
- childPart = nameNode.text;
285
- symbols.push({
286
- name: childPart,
287
- kind: 'class',
288
- startLine,
289
- endLine,
290
- signature,
291
- });
292
- if (parent) {
293
- symbols.push({
294
- name: childPart,
295
- kind: 'class',
296
- parent,
297
- startLine,
298
- endLine,
299
- signature,
300
- });
301
- }
302
- }
303
- const body = node.childForFieldName('body');
304
- if (body) {
305
- collectRubyScope(body, childPart, symbols);
306
- }
307
- }
308
- }
309
- else if (node.type === 'method' || node.type === 'singleton_method') {
310
- const name = extractName(node);
311
- if (name) {
312
- symbols.push({
313
- name,
314
- kind: parent ? 'method' : 'function',
315
- ...(parent ? { parent } : {}),
316
- startLine,
317
- endLine,
318
- signature,
319
- });
320
- }
321
- }
322
- else if (node.type === 'assignment') {
323
- const left = node.childForFieldName('left');
324
- if (left) {
325
- if (left.type === 'scope_resolution' &&
326
- left.namedChildren.length === 2) {
327
- const parentPart = left.namedChildren[0].text;
328
- const childPart = left.namedChildren[1].text;
329
- symbols.push({
330
- name: childPart,
331
- kind: 'const',
332
- startLine,
333
- endLine,
334
- signature,
335
- });
336
- symbols.push({
337
- name: childPart,
338
- kind: 'const',
339
- parent: parentPart,
340
- startLine,
341
- endLine,
342
- signature,
343
- });
344
- }
345
- else if (left.type === 'constant' ||
346
- (left.type === 'identifier' && /^[A-Z]/.test(left.text))) {
347
- const name = left.text;
348
- symbols.push({
349
- name,
350
- kind: 'const',
351
- startLine,
352
- endLine,
353
- signature,
354
- });
355
- if (parent) {
356
- symbols.push({
357
- name,
358
- kind: 'const',
359
- parent,
360
- startLine,
361
- endLine,
362
- signature,
363
- });
364
- }
365
- }
366
- }
367
- }
368
- else if (node.type === 'call') {
369
- const methodNode = node.childForFieldName('method');
370
- const methodName = methodNode?.text;
371
- if (methodName === 'task' ||
372
- methodName === 'multitask' ||
373
- methodName === 'file') {
374
- const name = extractRubyRakeName(node);
375
- if (name) {
376
- symbols.push({
377
- name,
378
- kind: parent ? 'method' : 'function',
379
- ...(parent ? { parent } : {}),
380
- startLine,
381
- endLine,
382
- signature,
383
- });
384
- }
385
- }
386
- else if (methodName === 'namespace') {
387
- const name = extractRubyRakeName(node);
388
- if (name) {
389
- symbols.push({
390
- name,
391
- kind: 'class',
392
- startLine,
393
- endLine,
394
- signature,
395
- });
396
- if (parent) {
397
- symbols.push({
398
- name,
399
- kind: 'class',
400
- parent,
401
- startLine,
402
- endLine,
403
- signature,
404
- });
405
- }
406
- const block = node.childForFieldName('block') ??
407
- node.namedChildren.find((n) => n.type === 'do_block' || n.type === 'block');
408
- if (block) {
409
- const body = block.childForFieldName('body') ??
410
- block.namedChildren.find((n) => n.type === 'body_statement' || n.type === 'block_body') ??
411
- block;
412
- collectRubyScope(body, name, symbols);
413
- }
414
- }
415
- }
416
- }
417
- }
418
- }
419
- function extractRubyRakeName(node) {
420
- const args = node.childForFieldName('arguments');
421
- if (!args || args.namedChildren.length === 0)
422
- return null;
423
- let first = args.namedChildren[0];
424
- if (first.type === 'pair') {
425
- first = first.childForFieldName('key') ?? first.namedChildren[0];
426
- }
427
- if (!first)
428
- return null;
429
- if (first.type === 'simple_symbol') {
430
- return first.text.replace(/^:/, '');
431
- }
432
- if (first.type === 'hash_key_symbol') {
433
- return first.text.replace(/:$/, '');
434
- }
435
- if (first.type === 'string') {
436
- const content = first.namedChildren.find((c) => c.type === 'string_content');
437
- return content ? content.text : first.text.replace(/^['"]|['"]$/g, '');
438
- }
439
- if (first.type === 'identifier') {
440
- return first.text;
441
- }
442
- return null;
443
- }
444
- function extractRubySymbols(tree) {
445
- const symbols = [];
446
- collectRubyScope(tree.rootNode, undefined, symbols);
447
- return symbols;
448
- }
449
- function dartDirectChild(node, type) {
450
- return node.namedChildren.find((child) => child.type === type) ?? null;
451
- }
452
- function dartDefinitionName(node) {
453
- const fieldName = extractName(node);
454
- if (fieldName)
455
- return fieldName;
456
- if (node.type === 'class_definition') {
457
- const alias = dartDirectChild(node, 'mixin_application_class');
458
- return alias ? (dartDirectChild(alias, 'identifier')?.text ?? null) : null;
459
- }
460
- if (node.type === 'type_alias') {
461
- return dartDirectChild(node, 'type_identifier')?.text ?? null;
462
- }
463
- return dartDirectChild(node, 'identifier')?.text ?? null;
464
- }
465
- function dartCallableNode(node) {
466
- if (node.type !== 'method_signature' && node.type !== 'declaration') {
467
- return node;
468
- }
469
- return (node.namedChildren.find((child) => [
470
- 'constructor_signature',
471
- 'factory_constructor_signature',
472
- 'function_signature',
473
- 'getter_signature',
474
- 'operator_signature',
475
- 'redirecting_factory_constructor_signature',
476
- 'setter_signature',
477
- ].includes(child.type)) ?? null);
478
- }
479
- function dartCallableName(node, parent) {
480
- const callable = dartCallableNode(node);
481
- if (!callable)
482
- return null;
483
- if (callable.type === 'operator_signature') {
484
- const operator = callable.namedChildren.find((child) => child.type.endsWith('_operator'));
485
- return operator ? `operator ${operator.text}` : null;
486
- }
487
- if (callable.type === 'constructor_signature' ||
488
- callable.type === 'factory_constructor_signature' ||
489
- callable.type === 'redirecting_factory_constructor_signature') {
490
- const names = callable.namedChildren
491
- .filter((child) => child.type === 'identifier')
492
- .map((child) => child.text);
493
- if (names.length === 0)
494
- return null;
495
- if (names.length === 1)
496
- return names[0];
497
- return names[0] === parent ? names[1] : names.at(-1);
498
- }
499
- return extractName(callable);
500
- }
501
- function dartAnnotatedStart(siblings, index) {
502
- let start = siblings[index];
503
- for (let i = index - 1; i >= 0 && siblings[i].type === 'annotation'; i--) {
504
- start = siblings[i];
505
- }
506
- return start;
507
- }
508
- function dartDefinitionEnd(siblings, index) {
509
- return siblings[index + 1]?.type === 'function_body'
510
- ? siblings[index + 1]
511
- : siblings[index];
512
- }
513
- function dartSignature(sourceLines, node) {
514
- return sourceLines[node.startPosition.row]?.trim() ?? '';
515
- }
516
- function pushDartSymbol(sourceLines, symbols, name, kind, node, options = {}) {
517
- symbols.push({
518
- name,
519
- kind,
520
- ...(options.parent ? { parent: options.parent } : {}),
521
- startLine: (options.start ?? node).startPosition.row + 1,
522
- endLine: (options.end ?? node).endPosition.row + 1,
523
- signature: dartSignature(sourceLines, node),
524
- });
525
- }
526
- function dartVariableKind(siblings, index, container) {
527
- if (container?.namedChildren.some((child) => child.type === 'const_builtin')) {
528
- return 'const';
529
- }
530
- const row = siblings[index].startPosition.row;
531
- for (let i = index - 1; i >= 0 && siblings[i].endPosition.row === row; i--) {
532
- if (siblings[i].type === 'const_builtin')
533
- return 'const';
534
- }
535
- return 'variable';
536
- }
537
- function extractDartVariables(sourceLines, symbols, node, kind, parent) {
538
- const lists = node.type === 'initialized_identifier_list' ||
539
- node.type === 'static_final_declaration_list'
540
- ? [node]
541
- : node.namedChildren.filter((child) => child.type === 'initialized_identifier_list' ||
542
- child.type === 'static_final_declaration_list');
543
- for (const list of lists) {
544
- for (const declaration of list.namedChildren) {
545
- if (declaration.type !== 'initialized_identifier' &&
546
- declaration.type !== 'static_final_declaration') {
547
- continue;
548
- }
549
- const name = dartDirectChild(declaration, 'identifier')?.text;
550
- if (name) {
551
- pushDartSymbol(sourceLines, symbols, name, kind, node, { parent });
552
- }
553
- }
554
- }
555
- }
556
- function extractDartMembers(sourceLines, body, parent, symbols) {
557
- const children = body.namedChildren;
558
- for (let i = 0; i < children.length; i++) {
559
- const node = children[i];
560
- if (node.type === 'method_signature') {
561
- const name = dartCallableName(node, parent);
562
- if (name) {
563
- pushDartSymbol(sourceLines, symbols, name, 'method', node, {
564
- parent,
565
- start: dartAnnotatedStart(children, i),
566
- end: dartDefinitionEnd(children, i),
567
- });
568
- }
569
- }
570
- else if (node.type === 'declaration') {
571
- const name = dartCallableName(node, parent);
572
- if (name) {
573
- pushDartSymbol(sourceLines, symbols, name, 'method', node, { parent });
574
- }
575
- extractDartVariables(sourceLines, symbols, node, dartVariableKind(children, i, node), parent);
576
- }
577
- else if (node.type === 'enum_constant') {
578
- const name = extractName(node);
579
- if (name) {
580
- pushDartSymbol(sourceLines, symbols, name, 'const', node, { parent });
581
- }
582
- }
583
- }
584
- }
585
- function extractDartSymbols(tree) {
586
- const symbols = [];
587
- const children = tree.rootNode.namedChildren;
588
- const sourceLines = tree.rootNode.text.split('\n');
589
- for (let i = 0; i < children.length; i++) {
590
- const node = children[i];
591
- const start = dartAnnotatedStart(children, i);
592
- if (node.type === 'function_signature' ||
593
- node.type === 'getter_signature' ||
594
- node.type === 'setter_signature') {
595
- const name = dartCallableName(node);
596
- if (name) {
597
- pushDartSymbol(sourceLines, symbols, name, 'function', node, {
598
- start,
599
- end: dartDefinitionEnd(children, i),
600
- });
601
- }
602
- }
603
- else if (node.type === 'class_definition') {
604
- const name = dartDefinitionName(node);
605
- if (!name)
606
- continue;
607
- pushDartSymbol(sourceLines, symbols, name, 'class', node, { start });
608
- const body = node.childForFieldName('body');
609
- if (body)
610
- extractDartMembers(sourceLines, body, name, symbols);
611
- }
612
- else if (node.type === 'mixin_declaration') {
613
- const name = dartDefinitionName(node);
614
- if (!name)
615
- continue;
616
- pushDartSymbol(sourceLines, symbols, name, 'interface', node, { start });
617
- const body = dartDirectChild(node, 'class_body');
618
- if (body)
619
- extractDartMembers(sourceLines, body, name, symbols);
620
- }
621
- else if (node.type === 'extension_declaration') {
622
- const name = extractName(node);
623
- if (!name)
624
- continue;
625
- pushDartSymbol(sourceLines, symbols, name, 'class', node, { start });
626
- const body = node.childForFieldName('body');
627
- if (body)
628
- extractDartMembers(sourceLines, body, name, symbols);
629
- }
630
- else if (node.type === 'enum_declaration') {
631
- const name = extractName(node);
632
- if (!name)
633
- continue;
634
- pushDartSymbol(sourceLines, symbols, name, 'class', node, { start });
635
- const body = node.childForFieldName('body');
636
- if (body)
637
- extractDartMembers(sourceLines, body, name, symbols);
638
- }
639
- else if (node.type === 'extension_type_declaration') {
640
- const name = extractName(node);
641
- if (!name)
642
- continue;
643
- pushDartSymbol(sourceLines, symbols, name, 'type', node, { start });
644
- const representation = node.childForFieldName('representation');
645
- const representationName = representation?.childForFieldName('name');
646
- if (representation && representationName) {
647
- pushDartSymbol(sourceLines, symbols, representationName.text, 'variable', representation, { parent: name });
648
- }
649
- const body = node.childForFieldName('body');
650
- if (body)
651
- extractDartMembers(sourceLines, body, name, symbols);
652
- }
653
- else if (node.type === 'type_alias') {
654
- const name = dartDefinitionName(node);
655
- if (name) {
656
- pushDartSymbol(sourceLines, symbols, name, 'type', node, { start });
657
- }
658
- }
659
- else if (node.type === 'initialized_identifier_list' ||
660
- node.type === 'static_final_declaration_list') {
661
- extractDartVariables(sourceLines, symbols, node, dartVariableKind(children, i));
662
- }
663
- }
664
- return symbols;
665
- }
666
- const javaTypeKinds = {
667
- annotation_type_declaration: 'interface',
668
- class_declaration: 'class',
669
- enum_declaration: 'class',
670
- interface_declaration: 'interface',
671
- record_declaration: 'class',
672
- };
673
- function javaSignature(sourceLines, node) {
674
- const declarator = node.namedChildren.find((child) => child.type === 'variable_declarator');
675
- const name = node.childForFieldName('name') ?? declarator?.childForFieldName('name');
676
- return sourceLines[(name ?? node).startPosition.row]?.trim() ?? '';
677
- }
678
- function pushJavaSymbol(sourceLines, symbols, name, kind, node, parent) {
679
- const symbol = {
680
- name,
681
- kind,
682
- ...(parent ? { parent } : {}),
683
- startLine: node.startPosition.row + 1,
684
- endLine: node.endPosition.row + 1,
685
- signature: javaSignature(sourceLines, node),
686
- };
687
- symbols.push(symbol);
688
- return symbol;
689
- }
690
- function extractJavaVariables(sourceLines, symbols, node, parent) {
691
- const kind = node.type === 'constant_declaration' ? 'const' : 'variable';
692
- for (const declarator of node.namedChildren) {
693
- if (declarator.type !== 'variable_declarator')
694
- continue;
695
- const name = extractName(declarator);
696
- if (name) {
697
- pushJavaSymbol(sourceLines, symbols, name, kind, node, parent);
698
- }
699
- }
700
- }
701
- function collectJavaScope(sourceLines, scope, parent, symbols) {
702
- for (const node of scope.namedChildren) {
703
- const typeKind = javaTypeKinds[node.type];
704
- if (typeKind) {
705
- const name = extractName(node);
706
- if (!name)
707
- continue;
708
- const symbol = pushJavaSymbol(sourceLines, symbols, name, typeKind, node);
709
- if (parent)
710
- symbols.push({ ...symbol, parent });
711
- if (node.type === 'record_declaration') {
712
- const parameters = node.childForFieldName('parameters');
713
- for (const parameter of parameters?.namedChildren ?? []) {
714
- const component = extractName(parameter);
715
- if (component) {
716
- pushJavaSymbol(sourceLines, symbols, component, 'variable', parameter, name);
717
- }
718
- }
719
- }
720
- const body = node.childForFieldName('body');
721
- if (body)
722
- collectJavaScope(sourceLines, body, name, symbols);
723
- continue;
724
- }
725
- if (!parent)
726
- continue;
727
- if (node.type === 'method_declaration' ||
728
- node.type === 'constructor_declaration' ||
729
- node.type === 'compact_constructor_declaration' ||
730
- node.type === 'annotation_type_element_declaration') {
731
- const name = extractName(node);
732
- if (name) {
733
- pushJavaSymbol(sourceLines, symbols, name, 'method', node, parent);
734
- }
735
- }
736
- else if (node.type === 'field_declaration' ||
737
- node.type === 'constant_declaration') {
738
- extractJavaVariables(sourceLines, symbols, node, parent);
739
- }
740
- else if (node.type === 'enum_constant') {
741
- const name = extractName(node);
742
- if (name) {
743
- pushJavaSymbol(sourceLines, symbols, name, 'const', node, parent);
744
- }
745
- }
746
- else if (node.type === 'enum_body_declarations') {
747
- collectJavaScope(sourceLines, node, parent, symbols);
748
- }
749
- }
750
- }
751
- function extractJavaSymbols(tree) {
752
- const symbols = [];
753
- const sourceLines = tree.rootNode.text.split('\n');
754
- collectJavaScope(sourceLines, tree.rootNode, undefined, symbols);
755
- return symbols;
756
- }
757
- function phpSignature(sourceLines, node) {
758
- const declaration = node.namedChildren.find((child) => child.type !== 'attribute_list');
759
- return sourceLines[(declaration ?? node).startPosition.row]?.trim() ?? '';
760
- }
761
- function phpName(node) {
762
- const nameNode = node.childForFieldName('name');
763
- if (nameNode?.type === 'by_ref') {
764
- return (nameNode.namedChildren
765
- .find((child) => child.type === 'variable_name')
766
- ?.text.replace(/^\$/, '') ?? null);
767
- }
768
- const name = extractName(node) ??
769
- node.namedChildren.find((child) => child.type === 'name')?.text ??
770
- null;
771
- return name?.replace(/^\$/, '') ?? null;
772
- }
773
- function pushPhpSymbol(sourceLines, symbols, node, name, kind, parent) {
774
- symbols.push({
775
- name,
776
- kind,
777
- ...(parent ? { parent } : {}),
778
- startLine: node.startPosition.row + 1,
779
- endLine: node.endPosition.row + 1,
780
- signature: phpSignature(sourceLines, node),
781
- });
782
- }
783
- function extractPhpVariables(sourceLines, symbols, node, parent) {
784
- const kind = node.type === 'const_declaration' ? 'const' : 'variable';
785
- for (const child of node.namedChildren) {
786
- if (child.type !== 'const_element' && child.type !== 'property_element') {
787
- continue;
788
- }
789
- const name = phpName(child);
790
- if (name)
791
- pushPhpSymbol(sourceLines, symbols, node, name, kind, parent);
792
- }
793
- }
794
- const phpTypeKinds = {
795
- class_declaration: 'class',
796
- interface_declaration: 'interface',
797
- trait_declaration: 'interface',
798
- enum_declaration: 'class',
799
- };
800
- // Recurse through declaration containers, not arbitrary expressions: anonymous
801
- // classes and closures must not leak their members into the enclosing scope.
802
- const phpScopeContainers = new Set([
803
- 'namespace_definition',
804
- 'compound_statement',
805
- 'declaration_list',
806
- 'enum_declaration_list',
807
- 'if_statement',
808
- 'else_if_clause',
809
- 'else_clause',
810
- 'switch_statement',
811
- 'switch_block',
812
- 'case_statement',
813
- 'default_statement',
814
- 'while_statement',
815
- 'do_statement',
816
- 'for_statement',
817
- 'foreach_statement',
818
- 'try_statement',
819
- 'catch_clause',
820
- 'finally_clause',
821
- 'declare_statement',
822
- ]);
823
- function collectPhpScope(sourceLines, scope, symbols, parent) {
824
- for (const node of scope.namedChildren) {
825
- const typeKind = phpTypeKinds[node.type];
826
- if (typeKind) {
827
- const name = phpName(node);
828
- if (!name)
829
- continue;
830
- pushPhpSymbol(sourceLines, symbols, node, name, typeKind);
831
- const body = node.childForFieldName('body');
832
- if (body)
833
- collectPhpScope(sourceLines, body, symbols, name);
834
- continue;
835
- }
836
- if (node.type === 'function_definition' && !parent) {
837
- const name = phpName(node);
838
- if (name)
839
- pushPhpSymbol(sourceLines, symbols, node, name, 'function');
840
- }
841
- else if (node.type === 'method_declaration' && parent) {
842
- const name = phpName(node);
843
- if (name)
844
- pushPhpSymbol(sourceLines, symbols, node, name, 'method', parent);
845
- if (name?.toLowerCase() === '__construct') {
846
- const parameters = node.childForFieldName('parameters');
847
- for (const parameter of parameters?.namedChildren ?? []) {
848
- if (parameter.type !== 'property_promotion_parameter')
849
- continue;
850
- const propertyName = phpName(parameter);
851
- if (!propertyName)
852
- continue;
853
- pushPhpSymbol(sourceLines, symbols, parameter, propertyName, 'variable', parent);
854
- }
855
- }
856
- }
857
- else if (node.type === 'const_declaration' ||
858
- node.type === 'property_declaration') {
859
- extractPhpVariables(sourceLines, symbols, node, parent);
860
- }
861
- else if (node.type === 'enum_case' && parent) {
862
- const name = phpName(node);
863
- if (name)
864
- pushPhpSymbol(sourceLines, symbols, node, name, 'const', parent);
865
- }
866
- else if (phpScopeContainers.has(node.type)) {
867
- collectPhpScope(sourceLines, node, symbols, parent);
868
- }
869
- }
870
- }
871
- function extractPhpSymbols(tree) {
872
- const symbols = [];
873
- collectPhpScope(tree.rootNode.text.split('\n'), tree.rootNode, symbols);
874
- return symbols;
875
- }
876
- function extractRustSymbols(tree) {
877
- const symbols = [];
878
- const root = tree.rootNode;
879
- for (let i = 0; i < root.childCount; i++) {
880
- const node = root.child(i);
881
- const startLine = node.startPosition.row + 1;
882
- const endLine = node.endPosition.row + 1;
883
- if (node.type === 'function_item') {
884
- const name = extractName(node);
885
- if (name) {
886
- symbols.push({
887
- name,
888
- kind: 'function',
889
- startLine,
890
- endLine,
891
- signature: firstLine(node.text),
892
- });
893
- }
894
- }
895
- else if (node.type === 'struct_item') {
896
- const name = extractName(node);
897
- if (name) {
898
- symbols.push({
899
- name,
900
- kind: 'class',
901
- startLine,
902
- endLine,
903
- signature: firstLine(node.text),
904
- });
905
- }
906
- }
907
- else if (node.type === 'enum_item') {
908
- const name = extractName(node);
909
- if (name) {
910
- symbols.push({
911
- name,
912
- kind: 'class',
913
- startLine,
914
- endLine,
915
- signature: firstLine(node.text),
916
- });
917
- }
918
- }
919
- else if (node.type === 'trait_item') {
920
- const name = extractName(node);
921
- if (name) {
922
- symbols.push({
923
- name,
924
- kind: 'interface',
925
- startLine,
926
- endLine,
927
- signature: firstLine(node.text),
928
- });
929
- }
930
- }
931
- else if (node.type === 'impl_item') {
932
- // impl Type { ... } or impl Trait for Type { ... }
933
- const typeName = node.childForFieldName('type')?.text;
934
- if (!typeName)
935
- continue;
936
- const body = node.childForFieldName('body');
937
- if (!body)
938
- continue;
939
- for (let j = 0; j < body.namedChildCount; j++) {
940
- const member = body.namedChild(j);
941
- if (member.type === 'function_item') {
942
- const name = extractName(member);
943
- if (name) {
944
- symbols.push({
945
- name,
946
- kind: 'method',
947
- parent: typeName,
948
- startLine: member.startPosition.row + 1,
949
- endLine: member.endPosition.row + 1,
950
- signature: firstLine(member.text),
951
- });
952
- }
953
- }
954
- }
955
- }
956
- else if (node.type === 'const_item') {
957
- const name = extractName(node);
958
- if (name) {
959
- symbols.push({
960
- name,
961
- kind: 'const',
962
- startLine,
963
- endLine,
964
- signature: firstLine(node.text),
965
- });
966
- }
967
- }
968
- else if (node.type === 'static_item') {
969
- const name = extractName(node);
970
- if (name) {
971
- symbols.push({
972
- name,
973
- kind: 'variable',
974
- startLine,
975
- endLine,
976
- signature: firstLine(node.text),
977
- });
978
- }
979
- }
980
- else if (node.type === 'type_item') {
981
- const name = extractName(node);
982
- if (name) {
983
- symbols.push({
984
- name,
985
- kind: 'type',
986
- startLine,
987
- endLine,
988
- signature: firstLine(node.text),
989
- });
990
- }
991
- }
992
- }
993
- return symbols;
994
- }
995
- /**
996
- * Extract the receiver type name from a Go method declaration's receiver node.
997
- * Handles both value receivers (Greeter) and pointer receivers (*Greeter).
998
- */
999
- function goReceiverType(receiverNode) {
1000
- const param = receiverNode.namedChild(0);
1001
- if (!param)
1002
- return null;
1003
- const typeNode = param.childForFieldName('type');
1004
- if (!typeNode)
1005
- return null;
1006
- // pointer_type -> child is the actual type name
1007
- if (typeNode.type === 'pointer_type') {
1008
- return typeNode.namedChild(0)?.text ?? null;
1009
- }
1010
- return typeNode.text;
1011
- }
1012
- function extractGoSymbols(tree) {
1013
- const symbols = [];
1014
- const root = tree.rootNode;
1015
- for (let i = 0; i < root.childCount; i++) {
1016
- const node = root.child(i);
1017
- const startLine = node.startPosition.row + 1;
1018
- const endLine = node.endPosition.row + 1;
1019
- if (node.type === 'function_declaration') {
1020
- const name = extractName(node);
1021
- if (name) {
1022
- symbols.push({
1023
- name,
1024
- kind: 'function',
1025
- startLine,
1026
- endLine,
1027
- signature: firstLine(node.text),
1028
- });
1029
- }
1030
- }
1031
- else if (node.type === 'method_declaration') {
1032
- const name = extractName(node);
1033
- const receiver = node.childForFieldName('receiver');
1034
- const typeName = receiver ? goReceiverType(receiver) : null;
1035
- if (name && typeName) {
1036
- symbols.push({
1037
- name,
1038
- kind: 'method',
1039
- parent: typeName,
1040
- startLine,
1041
- endLine,
1042
- signature: firstLine(node.text),
1043
- });
1044
- }
1045
- }
1046
- else if (node.type === 'type_declaration') {
1047
- for (let j = 0; j < node.namedChildCount; j++) {
1048
- const spec = node.namedChild(j);
1049
- if (spec.type !== 'type_spec')
1050
- continue;
1051
- const name = spec.childForFieldName('name')?.text;
1052
- if (!name)
1053
- continue;
1054
- const typeNode = spec.childForFieldName('type');
1055
- const kind = typeNode?.type === 'interface_type' ? 'interface' : 'class';
1056
- symbols.push({
1057
- name,
1058
- kind,
1059
- startLine: spec.startPosition.row + 1,
1060
- endLine: spec.endPosition.row + 1,
1061
- signature: firstLine(node.text),
1062
- });
1063
- }
1064
- }
1065
- else if (node.type === 'const_declaration') {
1066
- for (let j = 0; j < node.namedChildCount; j++) {
1067
- const spec = node.namedChild(j);
1068
- if (spec.type !== 'const_spec')
1069
- continue;
1070
- const name = spec.childForFieldName('name')?.text;
1071
- if (name) {
1072
- symbols.push({
1073
- name,
1074
- kind: 'const',
1075
- startLine: spec.startPosition.row + 1,
1076
- endLine: spec.endPosition.row + 1,
1077
- signature: firstLine(node.text),
1078
- });
1079
- }
1080
- }
1081
- }
1082
- else if (node.type === 'var_declaration') {
1083
- for (let j = 0; j < node.namedChildCount; j++) {
1084
- const spec = node.namedChild(j);
1085
- if (spec.type !== 'var_spec')
1086
- continue;
1087
- const name = spec.childForFieldName('name')?.text;
1088
- if (name) {
1089
- symbols.push({
1090
- name,
1091
- kind: 'variable',
1092
- startLine: spec.startPosition.row + 1,
1093
- endLine: spec.endPosition.row + 1,
1094
- signature: firstLine(node.text),
1095
- });
1096
- }
1097
- }
1098
- }
1099
- }
1100
- return symbols;
1101
- }
1102
- /**
1103
- * Extract the declarator name from a C function_declarator node.
1104
- * Handles plain identifiers and pointer declarators (*name).
1105
- */
1106
- function cFuncName(declarator) {
1107
- // Unwrap pointer_declarator layers (for functions returning pointers,
1108
- // e.g. `JSRuntime *JS_NewRuntime(void)` → pointer_declarator > function_declarator)
1109
- let node = declarator;
1110
- while (node.type === 'pointer_declarator') {
1111
- const child = node.childForFieldName('declarator');
1112
- if (!child)
1113
- return null;
1114
- node = child;
1115
- }
1116
- if (node.type === 'function_declarator') {
1117
- const inner = node.childForFieldName('declarator');
1118
- if (!inner)
1119
- return null;
1120
- if (inner.type === 'identifier')
1121
- return inner.text;
1122
- if (inner.type === 'pointer_declarator') {
1123
- // *name — dig through pointer layers
1124
- let cur = inner;
1125
- while (cur.type === 'pointer_declarator') {
1126
- const child = cur.childForFieldName('declarator');
1127
- if (!child)
1128
- return null;
1129
- cur = child;
1130
- }
1131
- return cur.type === 'identifier' ? cur.text : null;
1132
- }
1133
- }
1134
- return null;
1135
- }
1136
- /**
1137
- * Extract the variable name from a C init_declarator or plain declarator.
1138
- * Handles pointers like `*DEFAULT_NAME = "World"`.
1139
- */
1140
- function cVarName(declarator) {
1141
- let node = declarator;
1142
- // Unwrap init_declarator to get the declarator part
1143
- if (node.type === 'init_declarator') {
1144
- const inner = node.childForFieldName('declarator');
1145
- if (!inner)
1146
- return null;
1147
- node = inner;
1148
- }
1149
- // Unwrap array_declarator (e.g. `char js_version[]`)
1150
- if (node.type === 'array_declarator') {
1151
- const inner = node.childForFieldName('declarator');
1152
- if (!inner)
1153
- return null;
1154
- node = inner;
1155
- }
1156
- if (node.type === 'identifier')
1157
- return node.text;
1158
- if (node.type === 'pointer_declarator') {
1159
- let cur = node;
1160
- while (cur.type === 'pointer_declarator') {
1161
- const child = cur.childForFieldName('declarator');
1162
- if (!child)
1163
- return null;
1164
- cur = child;
1165
- }
1166
- return cur.type === 'identifier' ? cur.text : null;
1167
- }
1168
- return null;
1169
- }
1170
- function extractCSymbols(tree) {
1171
- const symbols = [];
1172
- collectCNodes(tree.rootNode, symbols);
1173
- return symbols;
1174
- }
1175
- /**
1176
- * Walk C AST nodes, collecting symbols. Recurses into preprocessor
1177
- * conditional blocks (ifdef/ifndef/if), linkage specifications
1178
- * (extern "C" { ... }), and declaration lists so that include guards
1179
- * and conditional compilation don't hide declarations.
1180
- *
1181
- * For #if/#ifdef/#ifndef, only the "then" branch is traversed —
1182
- * preproc_else and preproc_elif children are skipped.
1183
- */
1184
- function collectCNodes(parent, symbols) {
1185
- for (let i = 0; i < parent.childCount; i++) {
1186
- const node = parent.child(i);
1187
- const startLine = node.startPosition.row + 1;
1188
- const endLine = node.endPosition.row + 1;
1189
- if (node.type === 'function_definition') {
1190
- const declarator = node.childForFieldName('declarator');
1191
- const name = declarator ? cFuncName(declarator) : null;
1192
- if (name) {
1193
- symbols.push({
1194
- name,
1195
- kind: 'function',
1196
- startLine,
1197
- endLine,
1198
- signature: firstLine(node.text),
1199
- });
1200
- }
1201
- }
1202
- else if (node.type === 'struct_specifier') {
1203
- const name = extractName(node);
1204
- if (name) {
1205
- symbols.push({
1206
- name,
1207
- kind: 'class',
1208
- startLine,
1209
- endLine,
1210
- signature: firstLine(node.text),
1211
- });
1212
- collectCStructFields(node, name, symbols);
1213
- }
1214
- }
1215
- else if (node.type === 'enum_specifier') {
1216
- const name = extractName(node);
1217
- if (name) {
1218
- symbols.push({
1219
- name,
1220
- kind: 'class',
1221
- startLine,
1222
- endLine,
1223
- signature: firstLine(node.text),
1224
- });
1225
- }
1226
- collectCEnumMembers(node, symbols, name ?? undefined);
1227
- }
1228
- else if (node.type === 'type_definition') {
1229
- let declarator = node.childForFieldName('declarator');
1230
- // Unwrap pointer_declarator for pointer typedefs
1231
- // e.g. `typedef struct __JSValue *JSValue;`
1232
- while (declarator?.type === 'pointer_declarator') {
1233
- declarator = declarator.childForFieldName('declarator') ?? null;
1234
- }
1235
- const name = declarator?.type === 'type_identifier' ? declarator.text : null;
1236
- if (name) {
1237
- symbols.push({
1238
- name,
1239
- kind: 'type',
1240
- startLine,
1241
- endLine,
1242
- signature: firstLine(node.text),
1243
- });
1244
- }
1245
- for (const child of node.namedChildren) {
1246
- if (child.type === 'enum_specifier') {
1247
- collectCEnumMembers(child, symbols, name ?? extractName(child) ?? undefined);
1248
- }
1249
- else if (child.type === 'struct_specifier' && name) {
1250
- collectCStructFields(child, name, symbols);
1251
- }
1252
- }
1253
- }
1254
- else if (node.type === 'declaration') {
1255
- const declarator = node.childForFieldName('declarator');
1256
- // Try as function declaration first (e.g. `void greet(const char *name);`
1257
- // in headers), then fall back to variable.
1258
- const funcName = declarator ? cFuncName(declarator) : null;
1259
- if (funcName) {
1260
- symbols.push({
1261
- name: funcName,
1262
- kind: 'function',
1263
- startLine,
1264
- endLine,
1265
- signature: firstLine(node.text),
1266
- });
1267
- }
1268
- else {
1269
- const name = declarator ? cVarName(declarator) : null;
1270
- if (name) {
1271
- symbols.push({
1272
- name,
1273
- kind: 'variable',
1274
- startLine,
1275
- endLine,
1276
- signature: firstLine(node.text),
1277
- });
1278
- }
1279
- }
1280
- }
1281
- else if (node.type === 'preproc_def' ||
1282
- node.type === 'preproc_function_def') {
1283
- const name = extractName(node);
1284
- if (name) {
1285
- symbols.push({
1286
- name,
1287
- kind: 'const',
1288
- startLine,
1289
- endLine,
1290
- signature: firstLine(node.text),
1291
- });
1292
- }
1293
- }
1294
- else if (node.type === 'preproc_ifdef' ||
1295
- node.type === 'preproc_ifndef' ||
1296
- node.type === 'preproc_if') {
1297
- // Recurse into conditional blocks (then-branch only).
1298
- // preproc_else / preproc_elif children are skipped.
1299
- collectCNodes(node, symbols);
1300
- }
1301
- else if (node.type === 'linkage_specification' ||
1302
- node.type === 'declaration_list') {
1303
- // extern "C" { ... } wraps declarations in linkage_specification
1304
- // containing a declaration_list — recurse through both.
1305
- collectCNodes(node, symbols);
1306
- }
1307
- else if (node.type === 'preproc_else' || node.type === 'preproc_elif') {
1308
- // Skip else/elif branches of preprocessor conditionals.
1309
- }
1310
- }
1311
- }
1312
- function collectCEnumMembers(enumSpecifier, symbols, enumName) {
1313
- for (const child of enumSpecifier.namedChildren) {
1314
- if (child.type !== 'enumerator_list')
1315
- continue;
1316
- for (const enumerator of child.namedChildren) {
1317
- if (enumerator.type !== 'enumerator')
1318
- continue;
1319
- const name = extractName(enumerator);
1320
- if (!name)
1321
- continue;
1322
- const sym = {
1323
- name,
1324
- kind: 'const',
1325
- startLine: enumerator.startPosition.row + 1,
1326
- endLine: enumerator.endPosition.row + 1,
1327
- signature: firstLine(enumerator.text),
1328
- };
1329
- // Emit without parent (standalone lookup like #GREEN)
1330
- symbols.push(sym);
1331
- // Also emit with parent so #Color#GREEN works
1332
- if (enumName) {
1333
- symbols.push({ ...sym, parent: enumName });
1334
- }
1335
- }
1336
- }
1337
- }
1338
- /**
1339
- * Extract struct field/member names from a struct_specifier and emit
1340
- * them as symbols with `parent` set to the struct name.
1341
- * Handles plain identifiers, pointers, arrays, bitfields, and
1342
- * anonymous union/struct members (recurses into them).
1343
- */
1344
- function collectCStructFields(structNode, structName, symbols) {
1345
- for (const child of structNode.namedChildren) {
1346
- if (child.type !== 'field_declaration_list')
1347
- continue;
1348
- collectFieldsFromList(child, structName, symbols);
1349
- }
1350
- }
1351
- function collectFieldsFromList(fieldList, structName, symbols) {
1352
- for (const field of fieldList.namedChildren) {
1353
- if (field.type !== 'field_declaration')
1354
- continue;
1355
- const declarator = field.childForFieldName('declarator');
1356
- if (declarator) {
1357
- const name = cFieldName(declarator);
1358
- if (!name)
1359
- continue;
1360
- symbols.push({
1361
- name,
1362
- kind: 'variable',
1363
- parent: structName,
1364
- startLine: field.startPosition.row + 1,
1365
- endLine: field.endPosition.row + 1,
1366
- signature: firstLine(field.text),
1367
- });
1368
- }
1369
- else {
1370
- // Anonymous union/struct member — recurse into its field list
1371
- for (const inner of field.namedChildren) {
1372
- if ((inner.type === 'union_specifier' ||
1373
- inner.type === 'struct_specifier') &&
1374
- !extractName(inner)) {
1375
- for (const sub of inner.namedChildren) {
1376
- if (sub.type === 'field_declaration_list') {
1377
- collectFieldsFromList(sub, structName, symbols);
1378
- }
1379
- }
1380
- }
1381
- }
1382
- }
1383
- }
1384
- }
1385
- /**
1386
- * Extract the field name from a C struct field declarator.
1387
- * Handles field_identifier, pointer_declarator, array_declarator,
1388
- * and bitfield_clause (e.g. `uint8_t extensible : 1`).
1389
- */
1390
- function cFieldName(declarator) {
1391
- let node = declarator;
1392
- // Unwrap pointer_declarator layers (e.g. `JSShape *shape`)
1393
- while (node.type === 'pointer_declarator') {
1394
- const child = node.childForFieldName('declarator');
1395
- if (!child)
1396
- return null;
1397
- node = child;
1398
- }
1399
- // Unwrap array_declarator (e.g. `char name[32]`)
1400
- if (node.type === 'array_declarator') {
1401
- const inner = node.childForFieldName('declarator');
1402
- if (!inner)
1403
- return null;
1404
- node = inner;
1405
- }
1406
- if (node.type === 'field_identifier')
1407
- return node.text;
1408
- return null;
1409
- }
1410
- function firstLine(text) {
1411
- const nl = text.indexOf('\n');
1412
- return nl === -1 ? text : text.slice(0, nl);
1413
- }
1414
- /** Every supported source extension must declare a symbol extractor. */
1415
- const symbolExtractors = {
1416
- '.c': extractCSymbols,
1417
- '.dart': extractDartSymbols,
1418
- '.erb': extractRubySymbols,
1419
- '.go': extractGoSymbols,
1420
- '.h': extractCSymbols,
1421
- '.java': extractJavaSymbols,
1422
- '.js': extractTsSymbols,
1423
- '.jsx': extractTsSymbols,
1424
- '.php': extractPhpSymbols,
1425
- '.py': extractPySymbols,
1426
- '.rake': extractRubySymbols,
1427
- '.rb': extractRubySymbols,
1428
- '.rs': extractRustSymbols,
1429
- '.ts': extractTsSymbols,
1430
- '.tsx': extractTsSymbols,
1431
- };
1432
- function preprocessErb(content) {
1433
- let result = '';
1434
- let inRuby = false;
1435
- let inComment = false;
1436
- let i = 0;
1437
- while (i < content.length) {
1438
- if (!inRuby && !inComment) {
1439
- if (content.startsWith('<%%', i)) {
1440
- result += ' ';
1441
- i += 3;
1442
- }
1443
- else if (content.startsWith('<%#', i)) {
1444
- inComment = true;
1445
- result += ' ';
1446
- i += 3;
1447
- }
1448
- else if (content.startsWith('<%', i)) {
1449
- inRuby = true;
1450
- let tagLen = 2;
1451
- while (i + tagLen < content.length &&
1452
- ['=', '-', '~'].includes(content[i + tagLen])) {
1453
- tagLen++;
1454
- }
1455
- result += ' '.repeat(tagLen);
1456
- i += tagLen;
1457
- }
1458
- else {
1459
- const ch = content[i];
1460
- result += ch === '\n' ? '\n' : ' ';
1461
- i++;
1462
- }
1463
- }
1464
- else if (inComment) {
1465
- if (content.startsWith('%>', i)) {
1466
- inComment = false;
1467
- result += ' ';
1468
- i += 2;
1469
- }
1470
- else if (content.startsWith('-%>', i) || content.startsWith('~%>', i)) {
1471
- inComment = false;
1472
- result += ' ';
1473
- i += 3;
1474
- }
1475
- else {
1476
- const ch = content[i];
1477
- result += ch === '\n' ? '\n' : ' ';
1478
- i++;
1479
- }
1480
- }
1481
- else {
1482
- if (content.startsWith('%%>', i)) {
1483
- result += ' ';
1484
- i += 3;
1485
- }
1486
- else if (content.startsWith('%>', i)) {
1487
- inRuby = false;
1488
- result += ' ';
1489
- i += 2;
1490
- }
1491
- else if (content.startsWith('-%>', i) || content.startsWith('~%>', i)) {
1492
- inRuby = false;
1493
- result += ' ';
1494
- i += 3;
1495
- }
1496
- else {
1497
- result += content[i];
1498
- i++;
1499
- }
1500
- }
1501
- }
1502
- return result;
1503
- }
1504
- export async function parseSourceSymbols(filePath, content) {
1505
- const ext = sourceFileExtension(filePath);
1506
- if (!ext)
1507
- return [];
1508
- const lang = await getLanguage(ext);
1509
- const p = await ensureParser();
1510
- p.setLanguage(lang);
1511
- const parsedContent = ext === '.erb' && content.includes('<%') ? preprocessErb(content) : content;
1512
- const tree = p.parse(parsedContent);
1513
- if (!tree)
1514
- return [];
1515
- try {
1516
- return symbolExtractors[ext](tree);
1517
- }
1518
- finally {
1519
- tree.delete();
1520
- }
1521
- }
1522
- function isRecord(value) {
1523
- return typeof value === 'object' && value !== null && !Array.isArray(value);
1524
- }
1525
- const sourceSymbolKinds = new Set([
1526
- 'function',
1527
- 'class',
1528
- 'const',
1529
- 'type',
1530
- 'interface',
1531
- 'method',
1532
- 'variable',
1533
- ]);
1534
- function isSourceSymbol(value) {
1535
- if (!isRecord(value))
1536
- return false;
1537
- return (typeof value.name === 'string' &&
1538
- typeof value.kind === 'string' &&
1539
- sourceSymbolKinds.has(value.kind) &&
1540
- (value.parent === undefined || typeof value.parent === 'string') &&
1541
- Number.isInteger(value.startLine) &&
1542
- value.startLine > 0 &&
1543
- Number.isInteger(value.endLine) &&
1544
- value.endLine >= value.startLine &&
1545
- typeof value.signature === 'string');
1546
- }
1547
- function cachedSourceAnalysis(entry, contentHash, identity, timings) {
1548
- if (!entry ||
1549
- entry.version !== PARSER_CACHE_VERSION ||
1550
- entry.contentHash !== contentHash ||
1551
- !isRecord(entry.value) ||
1552
- entry.value.path !== identity ||
1553
- !Array.isArray(entry.value.symbols) ||
1554
- !entry.value.symbols.every(isSourceSymbol)) {
1555
- return null;
1556
- }
1557
- return {
1558
- path: identity,
1559
- symbols: entry.value.symbols,
1560
- timings: {
1561
- ...timings,
1562
- cacheStatus: 'hit',
1563
- cacheWriteMs: 0,
1564
- parseMs: 0,
1565
- },
1566
- };
1567
- }
1568
- /** Request-scoped owner for in-flight and completed source parser work. */
1569
- export class SourceParserRuntime {
1570
- analyses = new Map();
1571
- symbols = new Map();
1572
- clear() {
1573
- this.analyses.clear();
1574
- this.symbols.clear();
1575
- }
1576
- }
1577
- const defaultSourceParserRuntime = new SourceParserRuntime();
1578
- /** Return the parser cache path for one project source file. */
1579
- export function sourceAnalysisCachePath(latDir, projectRoot, absolutePath) {
1580
- return parsedCachePath(latDir, parserCacheIdentity(absolutePath, projectRoot));
1581
- }
1582
- /** Analyze source content through the shared versioned persistent cache. */
1583
- export async function analyzeSourceSymbols(filePath, content, latDir, options = {}) {
1584
- const identity = (options.identity ?? filePath)
1585
- .replaceAll('\\', '/')
1586
- .normalize('NFC');
1587
- const hashStarted = performance.now();
1588
- const contentHash = hashParserContent(content);
1589
- const hashMs = performance.now() - hashStarted;
1590
- const cache = options.cache !== false;
1591
- const cachePath = parsedCachePath(latDir, identity);
1592
- const promiseKey = `${cache ? 'cache' : 'direct'}\0${cachePath}\0${contentHash}`;
1593
- const runtime = options.runtime ?? defaultSourceParserRuntime;
1594
- let analysis = runtime.analyses.get(promiseKey);
1595
- if (!analysis) {
1596
- analysis = (async () => {
1597
- const cacheStarted = performance.now();
1598
- const entry = cache ? await readParsedCache(cachePath) : null;
1599
- const cacheReadMs = cache ? performance.now() - cacheStarted : 0;
1600
- const timings = {
1601
- readMs: options.readMs ?? 0,
1602
- hashMs,
1603
- cacheReadMs,
1604
- cacheStatus: cache ? 'miss' : 'disabled',
1605
- };
1606
- const cached = cache
1607
- ? cachedSourceAnalysis(entry, contentHash, identity, timings)
1608
- : null;
1609
- if (cached)
1610
- return cached;
1611
- const parseStarted = performance.now();
1612
- const symbols = await parseSourceSymbols(filePath, content);
1613
- const result = {
1614
- path: identity,
1615
- symbols,
1616
- timings: {
1617
- ...timings,
1618
- cacheWriteMs: 0,
1619
- parseMs: performance.now() - parseStarted,
1620
- },
1621
- };
1622
- if (!cache)
1623
- return result;
1624
- const writeStarted = performance.now();
1625
- try {
1626
- await writeParsedCache(cachePath, contentHash, result);
1627
- }
1628
- catch {
1629
- // The cache is a disposable optimization; parsing must work read-only.
1630
- }
1631
- result.timings.cacheWriteMs = performance.now() - writeStarted;
1632
- return result;
1633
- })();
1634
- runtime.analyses.set(promiseKey, analysis);
1635
- }
1636
- return analysis;
1637
- }
1638
- /** Clear the symbol cache. Call between top-level operations. */
1639
- export function clearSymbolCache() {
1640
- defaultSourceParserRuntime.clear();
1641
- }
1642
- /**
1643
- * Check whether a source file path (relative to projectRoot) has a given symbol.
1644
- * Used by lat check to validate source code wiki links lazily.
1645
- */
1646
- export async function resolveSourceSymbol(filePath, symbolPath, projectRoot, options = {}) {
1647
- const absPath = join(projectRoot, filePath);
1648
- const latDir = options.latDir ?? join(projectRoot, 'lat.md');
1649
- const cacheKey = `${latDir}\0${absPath}`;
1650
- const runtime = options.runtime ?? defaultSourceParserRuntime;
1651
- let cachedPromise = runtime.symbols.get(cacheKey);
1652
- const created = !cachedPromise;
1653
- if (!cachedPromise) {
1654
- cachedPromise = (async () => {
1655
- const readStarted = performance.now();
1656
- let content;
1657
- try {
1658
- content = await readFile(absPath, 'utf-8');
1659
- }
1660
- catch {
1661
- return { symbols: [] };
1662
- }
1663
- const readMs = performance.now() - readStarted;
1664
- try {
1665
- const analysis = await analyzeSourceSymbols(filePath, content, latDir, {
1666
- cache: options.cache,
1667
- identity: parserCacheIdentity(absPath, projectRoot),
1668
- readMs,
1669
- runtime,
1670
- });
1671
- return { symbols: analysis.symbols, analysis };
1672
- }
1673
- catch (err) {
1674
- return {
1675
- symbols: [],
1676
- error: `failed to parse "${filePath}": ${err instanceof Error ? err.message : String(err)}`,
1677
- };
1678
- }
1679
- })();
1680
- runtime.symbols.set(cacheKey, cachedPromise);
1681
- }
1682
- const cached = await cachedPromise;
1683
- if (created && cached.analysis)
1684
- options.onFileAnalyzed?.(cached.analysis);
1685
- if (cached.error) {
1686
- return { found: false, symbols: cached.symbols, error: cached.error };
1687
- }
1688
- const { symbols } = cached;
1689
- const parts = symbolPath.split('#');
1690
- if (parts.length === 1) {
1691
- // Simple symbol: getConfigDir
1692
- const found = symbols.some((s) => s.name === parts[0] && !s.parent);
1693
- return { found, symbols };
1694
- }
1695
- if (parts.length === 2) {
1696
- // Nested symbol: MyClass#myMethod
1697
- const found = symbols.some((s) => s.name === parts[1] && s.parent === parts[0]);
1698
- return { found, symbols };
1699
- }
1700
- return { found: false, symbols };
1701
- }
1702
- /**
1703
- * Convert source symbols to Section objects for uniform handling.
1704
- */
1705
- export function sourceSymbolsToSections(symbols, filePath) {
1706
- const sections = [];
1707
- const classMap = new Map();
1708
- const parentNames = new Set(symbols.flatMap((symbol) => (symbol.parent ? [symbol.parent] : [])));
1709
- for (const sym of symbols) {
1710
- if (sym.parent)
1711
- continue; // Handle methods after their class
1712
- const section = {
1713
- id: `${filePath}#${sym.name}`,
1714
- heading: sym.name,
1715
- depth: 1,
1716
- file: filePath,
1717
- filePath,
1718
- children: [],
1719
- startLine: sym.startLine,
1720
- endLine: sym.endLine,
1721
- firstParagraph: sym.signature,
1722
- };
1723
- sections.push(section);
1724
- if (parentNames.has(sym.name)) {
1725
- classMap.set(sym.name, section);
1726
- }
1727
- }
1728
- // Add methods as children
1729
- for (const sym of symbols) {
1730
- if (!sym.parent)
1731
- continue;
1732
- const parentSection = classMap.get(sym.parent);
1733
- if (!parentSection)
1734
- continue;
1735
- const section = {
1736
- id: `${filePath}#${sym.parent}#${sym.name}`,
1737
- heading: sym.name,
1738
- depth: 2,
1739
- file: filePath,
1740
- filePath,
1741
- children: [],
1742
- startLine: sym.startLine,
1743
- endLine: sym.endLine,
1744
- firstParagraph: sym.signature,
1745
- };
1746
- parentSection.children.push(section);
1747
- }
1748
- return sections;
1749
- }