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

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 (182) hide show
  1. package/README.md +1 -1
  2. package/dist/src/cli/checklist-menu.d.ts +2 -1
  3. package/dist/src/cli/checklist-menu.js +3 -2
  4. package/dist/src/cli/index.js +59 -16
  5. package/dist/src/cli/init-preferences.d.ts +4 -0
  6. package/dist/src/cli/init-preferences.js +35 -0
  7. package/dist/src/cli/init.js +10 -5
  8. package/dist/src/cli/reindex.js +4 -8
  9. package/dist/src/cli/search.d.ts +3 -2
  10. package/dist/src/cli/search.js +71 -66
  11. package/dist/src/cli/ui-build-server.d.ts +12 -0
  12. package/dist/src/cli/ui-build-server.js +26 -0
  13. package/dist/src/cli/ui-build.js +1 -1
  14. package/dist/src/cli/ui.js +1 -1
  15. package/dist/src/format.d.ts +5 -0
  16. package/dist/src/format.js +32 -4
  17. package/dist/src/lattice-model.d.ts +8 -1
  18. package/dist/src/lattice-model.js +4 -1
  19. package/dist/src/lattice.d.ts +2 -2
  20. package/dist/src/lattice.js +17 -34
  21. package/dist/src/markdown-analysis.d.ts +11 -0
  22. package/dist/src/markdown-analysis.js +31 -1
  23. package/dist/src/mcp/server.js +6 -6
  24. package/dist/src/parser-cache.d.ts +1 -1
  25. package/dist/src/parser-cache.js +1 -1
  26. package/dist/src/search/cache.d.ts +3 -0
  27. package/dist/src/search/cache.js +71 -0
  28. package/dist/src/search/chunks.d.ts +23 -0
  29. package/dist/src/search/chunks.js +197 -0
  30. package/dist/src/search/db.d.ts +27 -16
  31. package/dist/src/search/db.js +108 -38
  32. package/dist/src/search/index.d.ts +5 -2
  33. package/dist/src/search/index.js +173 -69
  34. package/dist/src/search/lexical.d.ts +6 -0
  35. package/dist/src/search/lexical.js +36 -0
  36. package/dist/src/search/lock.d.ts +2 -0
  37. package/dist/src/search/lock.js +23 -0
  38. package/dist/src/search/query.d.ts +6 -3
  39. package/dist/src/search/query.js +45 -26
  40. package/dist/src/search/search.d.ts +13 -8
  41. package/dist/src/search/search.js +155 -23
  42. package/dist/src/search/types.d.ts +31 -0
  43. package/dist/src/search/types.js +1 -0
  44. package/dist/src/source-formats.d.ts +1 -1
  45. package/dist/src/source-formats.js +4 -0
  46. package/dist/src/source-parser.js +397 -1
  47. package/dist/src/view/client/assets/GraphView-BWlRdQM4.js +456 -0
  48. package/dist/src/view/client/assets/{MarkdownEditor-B7quqPb8.js → MarkdownEditor-MW-Ck1O0.js} +8 -8
  49. package/dist/src/view/client/assets/_commonjsHelpers-CqkleIqs.js +1 -0
  50. package/dist/src/view/client/assets/abnfDiagram-VCTEODGH-Bn3RshMV.js +1 -0
  51. package/dist/src/view/client/assets/{arc-BnwR8Bu7.js → arc-En9tdFQF.js} +1 -1
  52. package/dist/src/view/client/assets/architectureDiagram-5GKGNRK7-B-9J1VAM.js +36 -0
  53. package/dist/src/view/client/assets/{blockDiagram-I7D4REHJ-DETl8e_H.js → blockDiagram-I7D4REHJ-QlznwalP.js} +2 -2
  54. package/dist/src/view/client/assets/{c4Diagram-7LVT6UL2-DJRAT1Ve.js → c4Diagram-7LVT6UL2-Bp2y8B4_.js} +2 -2
  55. package/dist/src/view/client/assets/channel-uy0fFvcW.js +1 -0
  56. package/dist/src/view/client/assets/{chunk-2Q5K7J3B-C0TmOC1Q.js → chunk-2Q5K7J3B-CnBKL-lm.js} +1 -1
  57. package/dist/src/view/client/assets/{chunk-5VM5RSS4-dfBOrYE6.js → chunk-5VM5RSS4-LLYMi_n6.js} +1 -1
  58. package/dist/src/view/client/assets/{chunk-F27PBJKO-DAnks99K.js → chunk-F27PBJKO-VIeO7VF0.js} +1 -1
  59. package/dist/src/view/client/assets/{chunk-IMKFNOWR-CPjB07if.js → chunk-IMKFNOWR-D5i67DVD.js} +1 -1
  60. package/dist/src/view/client/assets/{chunk-JWPE2WC7-VvU_gZI6.js → chunk-JWPE2WC7-D4qAtoL3.js} +1 -1
  61. package/dist/src/view/client/assets/{chunk-POPQ4Y6H-DDUbVF55.js → chunk-POPQ4Y6H-BMzOyiW_.js} +1 -1
  62. package/dist/src/view/client/assets/{chunk-SVP7TREG-BHROkr6D.js → chunk-SVP7TREG-DWy5nbfp.js} +1 -1
  63. package/dist/src/view/client/assets/{chunk-TICWLB2K-95PzGIOg.js → chunk-TICWLB2K-CVqCANFB.js} +1 -1
  64. package/dist/src/view/client/assets/{chunk-XXDRQBXY-MdmuLhIs.js → chunk-XXDRQBXY-Bp23h6Tf.js} +1 -1
  65. package/dist/src/view/client/assets/classDiagram-ZZMXUADV-DbSEqjA5.js +1 -0
  66. package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-DbSEqjA5.js +1 -0
  67. package/dist/src/view/client/assets/cose-bilkent-JH36ORCC-BCw7fCC2.js +1 -0
  68. package/dist/src/view/client/assets/{cynefin-OW5HDTMX-CeA8IKWo.js → cynefin-OW5HDTMX--lYN4N9m.js} +1 -1
  69. package/dist/src/view/client/assets/cynefinDiagram-5FMLGOSQ-9sK5EV7v.js +62 -0
  70. package/dist/src/view/client/assets/{dagre-GXQ25YYZ-DLQwTa3H.js → dagre-GXQ25YYZ-CoMdEFCq.js} +2 -2
  71. package/dist/src/view/client/assets/{diagram-S7CK7UJ4-kbKdIyXG.js → diagram-S7CK7UJ4-D13dyWdd.js} +2 -2
  72. package/dist/src/view/client/assets/diagram-UQ7AKVKN-PdwLPPPA.js +41 -0
  73. package/dist/src/view/client/assets/{diagram-VSXAHHWV-EXJTU8qq.js → diagram-VSXAHHWV-CtWWa_A7.js} +2 -2
  74. package/dist/src/view/client/assets/diagram-VX7I27RA-BeCYcSU-.js +24 -0
  75. package/dist/src/view/client/assets/diagram-Z3DM3KII-DiWabOBM.js +24 -0
  76. package/dist/src/view/client/assets/ebnfDiagram-PWID7BFC-CZQ3MD_K.js +1 -0
  77. package/dist/src/view/client/assets/{erDiagram-RLTQ6QDP-C925J5A3.js → erDiagram-RLTQ6QDP-B1AhXIrP.js} +2 -2
  78. package/dist/src/view/client/assets/{flowDiagram-HODETNUW-DzoCa-Nq.js → flowDiagram-HODETNUW-Bhr0JM6P.js} +1 -1
  79. package/dist/src/view/client/assets/ganttDiagram-EL5Y4UJY-CbP8iAkg.js +292 -0
  80. package/dist/src/view/client/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  81. package/dist/src/view/client/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  82. package/dist/src/view/client/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  83. package/dist/src/view/client/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  84. package/dist/src/view/client/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
  85. package/dist/src/view/client/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
  86. package/dist/src/view/client/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
  87. package/dist/src/view/client/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  88. package/dist/src/view/client/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
  89. package/dist/src/view/client/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
  90. package/dist/src/view/client/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  91. package/dist/src/view/client/assets/gitGraphDiagram-WWUBYQGX-B9uuGdLF.js +106 -0
  92. package/dist/src/view/client/assets/index-DG0Ez15D.css +1 -0
  93. package/dist/src/view/client/assets/index-nBmbYfun.js +13 -0
  94. package/dist/src/view/client/assets/infoDiagram-27XIBGKW-BrfwQ_Cq.js +2 -0
  95. package/dist/src/view/client/assets/{ishikawaDiagram-5VMMS53U-CW4mto2d.js → ishikawaDiagram-5VMMS53U-CHtJ36re.js} +2 -2
  96. package/dist/src/view/client/assets/{journeyDiagram-3NMN7TZE-8R4eacFW.js → journeyDiagram-3NMN7TZE-BChcgX1s.js} +2 -2
  97. package/dist/src/view/client/assets/{kanban-definition-UXKFOSKX-Cy9ioXEJ.js → kanban-definition-UXKFOSKX-BnwFsKiB.js} +6 -6
  98. package/dist/src/view/client/assets/{layout-C0MFuhth.js → layout-Dnd0pLdb.js} +1 -1
  99. package/dist/src/view/client/assets/{linear-Dv3N4dQR.js → linear-CFhW2ozn.js} +1 -1
  100. package/dist/src/view/client/assets/{maplibre-gl-DnqZgfUS.js → maplibre-gl-CDX6Zuow.js} +1 -1
  101. package/dist/src/view/client/assets/{mermaid.core-bds9A7e2.js → mermaid.core--OP6lXtW.js} +11 -11
  102. package/dist/src/view/client/assets/{mindmap-definition-YA3MSWOX-DjmGW355.js → mindmap-definition-YA3MSWOX-D51y2zbm.js} +2 -2
  103. package/dist/src/view/client/assets/pegDiagram-XKGWAZYB--zyQJDvI.js +1 -0
  104. package/dist/src/view/client/assets/{pieDiagram-E7YTZNPT-CCH2gGR-.js → pieDiagram-E7YTZNPT-Cj8mvpJy.js} +2 -2
  105. package/dist/src/view/client/assets/{quadrantDiagram-AXDQQJYC-CjocPJFz.js → quadrantDiagram-AXDQQJYC-qvhJrnBf.js} +4 -4
  106. package/dist/src/view/client/assets/railroadDiagram-O6MQD6OU-CtWvxpSo.js +1 -0
  107. package/dist/src/view/client/assets/{requirementDiagram-BXWQKSXE-Ct6AoXRr.js → requirementDiagram-BXWQKSXE-CBxen_KG.js} +2 -2
  108. package/dist/src/view/client/assets/{sankeyDiagram-P5KCCOFB-CIpgGN_w.js → sankeyDiagram-P5KCCOFB-B_fUkmfc.js} +2 -2
  109. package/dist/src/view/client/assets/{sequenceDiagram-WJ2MYXX4-DrmLFj6w.js → sequenceDiagram-WJ2MYXX4-Dclv4p68.js} +2 -2
  110. package/dist/src/view/client/assets/sizeCapture-INFHLROL-GfG0sMTZ.js +1 -0
  111. package/dist/src/view/client/assets/stateDiagram-D77RDMKH-YQWPnzxU.js +1 -0
  112. package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-gUj6Hzgl.js +1 -0
  113. package/dist/src/view/client/assets/swimlanes-42K2YHIH-5yiCveVS.js +1 -0
  114. package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-DR7JhrxL.js +8 -0
  115. package/dist/src/view/client/assets/{timeline-definition-24CTP7MA-BExPu6X5.js → timeline-definition-24CTP7MA-BvAbB5Zs.js} +2 -2
  116. package/dist/src/view/client/assets/{vennDiagram-4TSXK5OY-PC1MU3si.js → vennDiagram-4TSXK5OY-guC-r60n.js} +2 -2
  117. package/dist/src/view/client/assets/{wardleyDiagram-VM6X3IG4-DNWqU3fa.js → wardleyDiagram-VM6X3IG4-C0yXcU2x.js} +2 -2
  118. package/dist/src/view/client/assets/{xychartDiagram-S5SC5T6Z-E1uA28_D.js → xychartDiagram-S5SC5T6Z-RPmkPNfK.js} +2 -2
  119. package/dist/src/view/client/index.html +2 -2
  120. package/dist/src/view/document-route.d.ts +2 -0
  121. package/dist/src/view/document-route.js +40 -7
  122. package/dist/src/view/graph.d.ts +2 -2
  123. package/dist/src/view/graph.js +7 -3
  124. package/dist/src/view/highlight.js +207 -203
  125. package/dist/src/view/markdown.js +19 -0
  126. package/dist/src/view/preindexed-search.d.ts +15 -0
  127. package/dist/src/view/preindexed-search.js +25 -0
  128. package/dist/src/view/protocol.d.ts +10 -1
  129. package/dist/src/view/references.js +6 -7
  130. package/dist/src/view/repository.js +10 -2
  131. package/dist/src/view/search-result.d.ts +4 -0
  132. package/dist/src/view/search-result.js +25 -0
  133. package/dist/src/view/search.d.ts +7 -2
  134. package/dist/src/view/search.js +23 -30
  135. package/dist/src/view/server-build.d.ts +21 -0
  136. package/dist/src/view/server-build.js +145 -0
  137. package/dist/src/view/server-deployment.d.ts +32 -0
  138. package/dist/src/view/server-deployment.js +134 -0
  139. package/dist/src/view/server-index-worker.d.ts +6 -0
  140. package/dist/src/view/server-index-worker.js +14 -0
  141. package/dist/src/view/server.js +25 -7
  142. package/dist/src/view/source-target.d.ts +2 -0
  143. package/dist/src/view/source-target.js +24 -0
  144. package/dist/src/view/static-build.d.ts +16 -1
  145. package/dist/src/view/static-build.js +187 -89
  146. package/dist/src/view/static-protocol.d.ts +7 -0
  147. package/dist/src/view/static-protocol.js +5 -0
  148. package/dist/src/view/store.js +17 -7
  149. package/dist/src/view/vercel-build.d.ts +24 -0
  150. package/dist/src/view/vercel-build.js +140 -0
  151. package/dist/src/view/vercel-server-build.d.ts +10 -0
  152. package/dist/src/view/vercel-server-build.js +61 -0
  153. package/dist/vendor/lat.md-server/index.d.ts +1 -1
  154. package/dist/vendor/lat.md-server/index.js +1 -1
  155. package/package.json +20 -5
  156. package/templates/AGENTS.md +1 -1
  157. package/templates/cursor-rules.md +1 -1
  158. package/templates/skill/SKILL.md +1 -1
  159. package/dist/src/view/client/assets/abnfDiagram-VCTEODGH-V7-T6qsl.js +0 -1
  160. package/dist/src/view/client/assets/architectureDiagram-5GKGNRK7-u97vDna9.js +0 -36
  161. package/dist/src/view/client/assets/channel-BwQbnWCN.js +0 -1
  162. package/dist/src/view/client/assets/classDiagram-ZZMXUADV-HvQKkIS-.js +0 -1
  163. package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-HvQKkIS-.js +0 -1
  164. package/dist/src/view/client/assets/cose-bilkent-JH36ORCC-CauUf_rN.js +0 -1
  165. package/dist/src/view/client/assets/cynefinDiagram-5FMLGOSQ-L1rtcT8l.js +0 -62
  166. package/dist/src/view/client/assets/diagram-UQ7AKVKN-kmzp92RC.js +0 -41
  167. package/dist/src/view/client/assets/diagram-VX7I27RA-DAiIyMCG.js +0 -24
  168. package/dist/src/view/client/assets/diagram-Z3DM3KII-G9wz50ZV.js +0 -24
  169. package/dist/src/view/client/assets/ebnfDiagram-PWID7BFC-D2tVRCNA.js +0 -1
  170. package/dist/src/view/client/assets/ganttDiagram-EL5Y4UJY-D2ebbg4p.js +0 -292
  171. package/dist/src/view/client/assets/gitGraphDiagram-WWUBYQGX-B4QratYy.js +0 -106
  172. package/dist/src/view/client/assets/index-D0ajr_Ja.css +0 -1
  173. package/dist/src/view/client/assets/index-KZcnpXJH.js +0 -321
  174. package/dist/src/view/client/assets/infoDiagram-27XIBGKW-DL4mtHkt.js +0 -2
  175. package/dist/src/view/client/assets/pegDiagram-XKGWAZYB-BWsZp0ab.js +0 -1
  176. package/dist/src/view/client/assets/railroadDiagram-O6MQD6OU-BjLeb2KF.js +0 -1
  177. package/dist/src/view/client/assets/sizeCapture-INFHLROL-BdFMe2Lr.js +0 -1
  178. package/dist/src/view/client/assets/stateDiagram-D77RDMKH-Zd9F1goW.js +0 -1
  179. package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-ByIKCftl.js +0 -1
  180. package/dist/src/view/client/assets/swimlanes-42K2YHIH-a7VFwi00.js +0 -1
  181. package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-CzxaUHB-.js +0 -8
  182. /package/dist/src/view/client/assets/{logo-small-RR_KBOAT.svg → logo-RR_KBOAT.svg} +0 -0
@@ -28,12 +28,16 @@ async function ensureParser() {
28
28
  const grammarMap = {
29
29
  '.c': 'tree-sitter-c.wasm',
30
30
  '.dart': 'tree-sitter-dart.wasm',
31
+ '.erb': 'tree-sitter-ruby.wasm',
31
32
  '.go': 'tree-sitter-go.wasm',
32
33
  '.h': 'tree-sitter-c.wasm',
33
34
  '.java': 'tree-sitter-java.wasm',
34
35
  '.js': 'tree-sitter-javascript.wasm',
35
36
  '.jsx': 'tree-sitter-javascript.wasm',
37
+ '.php': 'tree-sitter-php.wasm',
36
38
  '.py': 'tree-sitter-python.wasm',
39
+ '.rake': 'tree-sitter-ruby.wasm',
40
+ '.rb': 'tree-sitter-ruby.wasm',
37
41
  '.rs': 'tree-sitter-rust.wasm',
38
42
  '.ts': 'tree-sitter-typescript.wasm',
39
43
  '.tsx': 'tree-sitter-tsx.wasm',
@@ -246,6 +250,202 @@ function extractPySymbols(tree) {
246
250
  }
247
251
  return symbols;
248
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
+ }
249
449
  function dartDirectChild(node, type) {
250
450
  return node.namedChildren.find((child) => child.type === type) ?? null;
251
451
  }
@@ -554,6 +754,125 @@ function extractJavaSymbols(tree) {
554
754
  collectJavaScope(sourceLines, tree.rootNode, undefined, symbols);
555
755
  return symbols;
556
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
+ }
557
876
  function extractRustSymbols(tree) {
558
877
  const symbols = [];
559
878
  const root = tree.rootNode;
@@ -1096,16 +1415,92 @@ function firstLine(text) {
1096
1415
  const symbolExtractors = {
1097
1416
  '.c': extractCSymbols,
1098
1417
  '.dart': extractDartSymbols,
1418
+ '.erb': extractRubySymbols,
1099
1419
  '.go': extractGoSymbols,
1100
1420
  '.h': extractCSymbols,
1101
1421
  '.java': extractJavaSymbols,
1102
1422
  '.js': extractTsSymbols,
1103
1423
  '.jsx': extractTsSymbols,
1424
+ '.php': extractPhpSymbols,
1104
1425
  '.py': extractPySymbols,
1426
+ '.rake': extractRubySymbols,
1427
+ '.rb': extractRubySymbols,
1105
1428
  '.rs': extractRustSymbols,
1106
1429
  '.ts': extractTsSymbols,
1107
1430
  '.tsx': extractTsSymbols,
1108
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
+ }
1109
1504
  export async function parseSourceSymbols(filePath, content) {
1110
1505
  const ext = sourceFileExtension(filePath);
1111
1506
  if (!ext)
@@ -1113,7 +1508,8 @@ export async function parseSourceSymbols(filePath, content) {
1113
1508
  const lang = await getLanguage(ext);
1114
1509
  const p = await ensureParser();
1115
1510
  p.setLanguage(lang);
1116
- const tree = p.parse(content);
1511
+ const parsedContent = ext === '.erb' && content.includes('<%') ? preprocessErb(content) : content;
1512
+ const tree = p.parse(parsedContent);
1117
1513
  if (!tree)
1118
1514
  return [];
1119
1515
  try {