@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.
- package/README.md +1 -1
- package/dist/src/cli/agent-invocation.d.ts +6 -0
- package/dist/src/cli/agent-invocation.js +23 -0
- package/dist/src/cli/fork-instructions.js +1 -1
- package/dist/src/cli/fork-scaffold.js +2 -2
- package/dist/src/cli/graph.d.ts +1 -1
- package/dist/src/cli/hook.js +11 -11
- package/dist/src/cli/index.js +41 -59
- package/dist/src/cli/init-preferences.js +5 -4
- package/dist/src/cli/init.d.ts +1 -1
- package/dist/src/cli/init.js +54 -45
- package/dist/src/cli/reindex.d.ts +1 -1
- package/dist/src/cli/reindex.js +2 -2
- package/dist/src/cli/search.d.ts +4 -4
- package/dist/src/cli/search.js +41 -28
- package/dist/src/cli/ui-build-server.d.ts +1 -1
- package/dist/src/cli/ui-build.d.ts +1 -1
- package/dist/src/cli/ui.d.ts +1 -1
- package/dist/src/fork/antigravity-hook.js +6 -6
- package/dist/src/fork/antigravity-init.d.ts +2 -2
- package/dist/src/fork/antigravity-init.js +2 -2
- package/dist/src/graph-export.js +7 -7
- package/dist/src/knowledge/index.js +2 -2
- package/dist/src/mcp/server.js +8 -8
- package/dist/src/search/cache.d.ts +1 -1
- package/dist/src/search/cache.js +40 -7
- package/dist/src/search/chunks.d.ts +2 -2
- package/dist/src/search/db.d.ts +5 -4
- package/dist/src/search/db.js +36 -40
- package/dist/src/search/embedder.js +1 -1
- package/dist/src/search/index.d.ts +1 -1
- package/dist/src/search/index.js +2 -2
- package/dist/src/search/lock.d.ts +4 -1
- package/dist/src/search/lock.js +30 -8
- package/dist/src/search/query.d.ts +5 -2
- package/dist/src/search/query.js +55 -38
- package/dist/src/search/search.d.ts +3 -1
- package/dist/src/search/search.js +21 -12
- package/dist/src/search/types.d.ts +2 -18
- package/dist/src/view/client/assets/{GraphView-BWlRdQM4.js → GraphView-Dij8mAA_.js} +1 -1
- package/dist/src/view/client/assets/{MarkdownEditor-MW-Ck1O0.js → MarkdownEditor-88Wbt0M1.js} +1 -1
- package/dist/src/view/client/assets/{abnfDiagram-VCTEODGH-Bn3RshMV.js → abnfDiagram-VCTEODGH-y0DlYa8E.js} +1 -1
- package/dist/src/view/client/assets/{arc-En9tdFQF.js → arc-FlMu8dnO.js} +1 -1
- package/dist/src/view/client/assets/{architectureDiagram-5GKGNRK7-B-9J1VAM.js → architectureDiagram-5GKGNRK7-DA_uWZW1.js} +1 -1
- package/dist/src/view/client/assets/{blockDiagram-I7D4REHJ-QlznwalP.js → blockDiagram-I7D4REHJ-BHQ5LU85.js} +1 -1
- package/dist/src/view/client/assets/{c4Diagram-7LVT6UL2-Bp2y8B4_.js → c4Diagram-7LVT6UL2-BRucKCt2.js} +1 -1
- package/dist/src/view/client/assets/channel-BgDNA_Ay.js +1 -0
- package/dist/src/view/client/assets/{chunk-2Q5K7J3B-CnBKL-lm.js → chunk-2Q5K7J3B-BJPcFivt.js} +1 -1
- package/dist/src/view/client/assets/{chunk-5VM5RSS4-LLYMi_n6.js → chunk-5VM5RSS4-v2q99bGz.js} +1 -1
- package/dist/src/view/client/assets/{chunk-F27PBJKO-VIeO7VF0.js → chunk-F27PBJKO-CcHOuJCs.js} +1 -1
- package/dist/src/view/client/assets/{chunk-IMKFNOWR-D5i67DVD.js → chunk-IMKFNOWR-DNxYuJNq.js} +1 -1
- package/dist/src/view/client/assets/{chunk-JWPE2WC7-D4qAtoL3.js → chunk-JWPE2WC7-C0eHKvLW.js} +1 -1
- package/dist/src/view/client/assets/{chunk-POPQ4Y6H-BMzOyiW_.js → chunk-POPQ4Y6H-57CWp2Ve.js} +1 -1
- package/dist/src/view/client/assets/{chunk-SVP7TREG-DWy5nbfp.js → chunk-SVP7TREG-BqcoxIJw.js} +1 -1
- package/dist/src/view/client/assets/{chunk-TICWLB2K-CVqCANFB.js → chunk-TICWLB2K-DRUJR5zH.js} +1 -1
- package/dist/src/view/client/assets/{chunk-XXDRQBXY-Bp23h6Tf.js → chunk-XXDRQBXY-Dez0oRoM.js} +1 -1
- package/dist/src/view/client/assets/classDiagram-ZZMXUADV-CFZ_Sgh5.js +1 -0
- package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-CFZ_Sgh5.js +1 -0
- package/dist/src/view/client/assets/{cose-bilkent-JH36ORCC-BCw7fCC2.js → cose-bilkent-JH36ORCC-BHtud6Hg.js} +1 -1
- package/dist/src/view/client/assets/{cynefin-OW5HDTMX--lYN4N9m.js → cynefin-OW5HDTMX-BjBW8VGk.js} +1 -1
- package/dist/src/view/client/assets/{cynefinDiagram-5FMLGOSQ-9sK5EV7v.js → cynefinDiagram-5FMLGOSQ-DwGuD7oF.js} +1 -1
- package/dist/src/view/client/assets/{dagre-GXQ25YYZ-CoMdEFCq.js → dagre-GXQ25YYZ-C5zSlGK9.js} +1 -1
- package/dist/src/view/client/assets/{diagram-S7CK7UJ4-D13dyWdd.js → diagram-S7CK7UJ4-C_NhA3bj.js} +1 -1
- package/dist/src/view/client/assets/{diagram-UQ7AKVKN-PdwLPPPA.js → diagram-UQ7AKVKN-az7QPYNb.js} +1 -1
- package/dist/src/view/client/assets/{diagram-VSXAHHWV-CtWWa_A7.js → diagram-VSXAHHWV-BRvDuM8_.js} +1 -1
- package/dist/src/view/client/assets/{diagram-VX7I27RA-BeCYcSU-.js → diagram-VX7I27RA-BWLgF6S-.js} +1 -1
- package/dist/src/view/client/assets/{diagram-Z3DM3KII-DiWabOBM.js → diagram-Z3DM3KII-DV3d6mL5.js} +1 -1
- package/dist/src/view/client/assets/{ebnfDiagram-PWID7BFC-CZQ3MD_K.js → ebnfDiagram-PWID7BFC-yUXrEAvK.js} +1 -1
- package/dist/src/view/client/assets/{erDiagram-RLTQ6QDP-B1AhXIrP.js → erDiagram-RLTQ6QDP-D35FN1Pt.js} +1 -1
- package/dist/src/view/client/assets/{flowDiagram-HODETNUW-Bhr0JM6P.js → flowDiagram-HODETNUW-BciZqsjT.js} +1 -1
- package/dist/src/view/client/assets/{ganttDiagram-EL5Y4UJY-CbP8iAkg.js → ganttDiagram-EL5Y4UJY-BysPGgXS.js} +1 -1
- package/dist/src/view/client/assets/{gitGraphDiagram-WWUBYQGX-B9uuGdLF.js → gitGraphDiagram-WWUBYQGX-C3DdJ5xG.js} +1 -1
- package/dist/src/view/client/assets/index-CJokoRSp.js +13 -0
- package/dist/src/view/client/assets/{infoDiagram-27XIBGKW-BrfwQ_Cq.js → infoDiagram-27XIBGKW-D3HZrDRb.js} +1 -1
- package/dist/src/view/client/assets/{ishikawaDiagram-5VMMS53U-CHtJ36re.js → ishikawaDiagram-5VMMS53U-BXyVIXTU.js} +1 -1
- package/dist/src/view/client/assets/{journeyDiagram-3NMN7TZE-BChcgX1s.js → journeyDiagram-3NMN7TZE-D4-1NxVU.js} +1 -1
- package/dist/src/view/client/assets/{kanban-definition-UXKFOSKX-BnwFsKiB.js → kanban-definition-UXKFOSKX-4Gu_5yBA.js} +1 -1
- package/dist/src/view/client/assets/{layout-Dnd0pLdb.js → layout-Jf1K3TMM.js} +1 -1
- package/dist/src/view/client/assets/{linear-CFhW2ozn.js → linear-DWfwzUT_.js} +1 -1
- package/dist/src/view/client/assets/{mermaid.core--OP6lXtW.js → mermaid.core-DMx_DAl8.js} +5 -5
- package/dist/src/view/client/assets/{mindmap-definition-YA3MSWOX-D51y2zbm.js → mindmap-definition-YA3MSWOX-8pxY_RWi.js} +1 -1
- package/dist/src/view/client/assets/{pegDiagram-XKGWAZYB--zyQJDvI.js → pegDiagram-XKGWAZYB-DNAw_O5t.js} +1 -1
- package/dist/src/view/client/assets/{pieDiagram-E7YTZNPT-Cj8mvpJy.js → pieDiagram-E7YTZNPT-uuvRCDkC.js} +1 -1
- package/dist/src/view/client/assets/{quadrantDiagram-AXDQQJYC-qvhJrnBf.js → quadrantDiagram-AXDQQJYC-BER2O4Aq.js} +1 -1
- package/dist/src/view/client/assets/{railroadDiagram-O6MQD6OU-CtWvxpSo.js → railroadDiagram-O6MQD6OU-CxEsJ_0n.js} +1 -1
- package/dist/src/view/client/assets/{requirementDiagram-BXWQKSXE-CBxen_KG.js → requirementDiagram-BXWQKSXE-yS9rspca.js} +1 -1
- package/dist/src/view/client/assets/{sankeyDiagram-P5KCCOFB-B_fUkmfc.js → sankeyDiagram-P5KCCOFB-Bqt70a2j.js} +1 -1
- package/dist/src/view/client/assets/{sequenceDiagram-WJ2MYXX4-Dclv4p68.js → sequenceDiagram-WJ2MYXX4-BvOOEJNr.js} +1 -1
- package/dist/src/view/client/assets/{sizeCapture-INFHLROL-GfG0sMTZ.js → sizeCapture-INFHLROL-CvO_Pjjo.js} +1 -1
- package/dist/src/view/client/assets/{stateDiagram-D77RDMKH-YQWPnzxU.js → stateDiagram-D77RDMKH-KLmVOZkq.js} +1 -1
- package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-KCS8Mdzu.js +1 -0
- package/dist/src/view/client/assets/{swimlanes-42K2YHIH-5yiCveVS.js → swimlanes-42K2YHIH-DC1r4_sq.js} +1 -1
- package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-B2TcAwis.js +8 -0
- package/dist/src/view/client/assets/{timeline-definition-24CTP7MA-BvAbB5Zs.js → timeline-definition-24CTP7MA-ChXLOuBL.js} +1 -1
- package/dist/src/view/client/assets/{vennDiagram-4TSXK5OY-guC-r60n.js → vennDiagram-4TSXK5OY-D9_h25-Y.js} +1 -1
- package/dist/src/view/client/assets/{wardleyDiagram-VM6X3IG4-C0yXcU2x.js → wardleyDiagram-VM6X3IG4-CsQJGGW0.js} +1 -1
- package/dist/src/view/client/assets/{xychartDiagram-S5SC5T6Z-RPmkPNfK.js → xychartDiagram-S5SC5T6Z-DGMuPMlm.js} +1 -1
- package/dist/src/view/client/index.html +1 -1
- package/dist/src/view/diagnostics.d.ts +2 -2
- package/dist/src/view/diagnostics.js +5 -5
- package/dist/src/view/external-document-tree.js +1 -1
- package/dist/src/view/git-diff.js +1 -1
- package/dist/src/view/git.js +1 -1
- package/dist/src/view/graph.d.ts +2 -2
- package/dist/src/view/graph.js +2 -2
- package/dist/src/view/markdown.js +1 -1
- package/dist/src/view/preindexed-search.d.ts +1 -1
- package/dist/src/view/protocol.d.ts +2 -18
- package/dist/src/view/publication.d.ts +2 -0
- package/dist/src/view/publication.js +78 -0
- package/dist/src/view/references.d.ts +3 -3
- package/dist/src/view/references.js +3 -3
- package/dist/src/view/repository.d.ts +6 -6
- package/dist/src/view/repository.js +28 -14
- package/dist/src/view/request-security.d.ts +5 -0
- package/dist/src/view/request-security.js +46 -0
- package/dist/src/view/search-result.d.ts +1 -1
- package/dist/src/view/search-result.js +1 -1
- package/dist/src/view/search.d.ts +1 -1
- package/dist/src/view/server-build.d.ts +2 -2
- package/dist/src/view/server-build.js +2 -2
- package/dist/src/view/server-deployment.d.ts +1 -2
- package/dist/src/view/server-deployment.js +6 -46
- package/dist/src/view/server-index-worker.d.ts +1 -1
- package/dist/src/view/server.d.ts +1 -1
- package/dist/src/view/server.js +13 -3
- package/dist/src/view/source-target.js +2 -2
- package/dist/src/view/static-build.d.ts +1 -1
- package/dist/src/view/static-build.js +49 -17
- package/dist/src/view/store.d.ts +4 -2
- package/dist/src/view/store.js +31 -19
- package/dist/src/view/table-of-contents.d.ts +1 -1
- package/dist/src/view/table-of-contents.js +1 -1
- package/dist/src/view/vercel-server-build.d.ts +1 -1
- package/package.json +19 -29
- package/templates/AGENTS.md +2 -2
- package/templates/cursor-rules.md +2 -2
- package/templates/opencode-plugin.ts +9 -9
- package/templates/pi-extension.ts +11 -11
- package/templates/skill/SKILL.md +2 -1
- package/dist/src/cli/check-context.d.ts +0 -56
- package/dist/src/cli/check-context.js +0 -215
- package/dist/src/cli/check-coverage.d.ts +0 -2
- package/dist/src/cli/check-coverage.js +0 -75
- package/dist/src/cli/check-frontmatter.d.ts +0 -12
- package/dist/src/cli/check-frontmatter.js +0 -44
- package/dist/src/cli/check-mode.d.ts +0 -21
- package/dist/src/cli/check-mode.js +0 -394
- package/dist/src/cli/check-status.d.ts +0 -74
- package/dist/src/cli/check-status.js +0 -217
- package/dist/src/cli/check.d.ts +0 -52
- package/dist/src/cli/check.js +0 -834
- package/dist/src/cli/context.d.ts +0 -11
- package/dist/src/cli/context.js +0 -58
- package/dist/src/cli/expand.d.ts +0 -7
- package/dist/src/cli/expand.js +0 -141
- package/dist/src/cli/external.d.ts +0 -11
- package/dist/src/cli/external.js +0 -185
- package/dist/src/cli/gen-index.d.ts +0 -45
- package/dist/src/cli/gen-index.js +0 -235
- package/dist/src/cli/link-scheme.d.ts +0 -54
- package/dist/src/cli/link-scheme.js +0 -101
- package/dist/src/cli/locate.d.ts +0 -2
- package/dist/src/cli/locate.js +0 -18
- package/dist/src/cli/refs.d.ts +0 -23
- package/dist/src/cli/refs.js +0 -274
- package/dist/src/cli/section.d.ts +0 -45
- package/dist/src/cli/section.js +0 -328
- package/dist/src/cli/select-menu.d.ts +0 -13
- package/dist/src/cli/select-menu.js +0 -100
- package/dist/src/code-refs.d.ts +0 -29
- package/dist/src/code-refs.js +0 -479
- package/dist/src/config.d.ts +0 -29
- package/dist/src/config.js +0 -83
- package/dist/src/context.d.ts +0 -26
- package/dist/src/context.js +0 -11
- package/dist/src/document-formats.d.ts +0 -7
- package/dist/src/document-formats.js +0 -39
- package/dist/src/extensions/alert-marker.d.ts +0 -25
- package/dist/src/extensions/alert-marker.js +0 -55
- package/dist/src/extensions/wiki-link/from-markdown.d.ts +0 -5
- package/dist/src/extensions/wiki-link/from-markdown.js +0 -34
- package/dist/src/extensions/wiki-link/index.d.ts +0 -4
- package/dist/src/extensions/wiki-link/index.js +0 -3
- package/dist/src/extensions/wiki-link/syntax.d.ts +0 -14
- package/dist/src/extensions/wiki-link/syntax.js +0 -121
- package/dist/src/extensions/wiki-link/to-markdown.d.ts +0 -5
- package/dist/src/extensions/wiki-link/to-markdown.js +0 -28
- package/dist/src/extensions/wiki-link/types.d.ts +0 -34
- package/dist/src/extensions/wiki-link/types.js +0 -1
- package/dist/src/external-documents.d.ts +0 -56
- package/dist/src/external-documents.js +0 -404
- package/dist/src/external-sources.d.ts +0 -136
- package/dist/src/external-sources.js +0 -1098
- package/dist/src/fork/frontmatter-fields.d.ts +0 -36
- package/dist/src/fork/frontmatter-fields.js +0 -23
- package/dist/src/format.d.ts +0 -16
- package/dist/src/format.js +0 -76
- package/dist/src/init-version.d.ts +0 -10
- package/dist/src/init-version.js +0 -49
- package/dist/src/lattice-model.d.ts +0 -84
- package/dist/src/lattice-model.js +0 -467
- package/dist/src/lattice.d.ts +0 -14
- package/dist/src/lattice.js +0 -353
- package/dist/src/markdown-analysis-cache.d.ts +0 -20
- package/dist/src/markdown-analysis-cache.js +0 -139
- package/dist/src/markdown-analysis-worker.d.ts +0 -16
- package/dist/src/markdown-analysis-worker.js +0 -33
- package/dist/src/markdown-analysis.d.ts +0 -61
- package/dist/src/markdown-analysis.js +0 -169
- package/dist/src/markdown-analyzer-loader.d.ts +0 -4
- package/dist/src/markdown-analyzer-loader.js +0 -13
- package/dist/src/markdown-validation.d.ts +0 -25
- package/dist/src/markdown-validation.js +0 -104
- package/dist/src/parser-cache.d.ts +0 -17
- package/dist/src/parser-cache.js +0 -65
- package/dist/src/parser-import.d.ts +0 -8
- package/dist/src/parser-import.js +0 -1
- package/dist/src/parser.d.ts +0 -3
- package/dist/src/parser.js +0 -93
- package/dist/src/path.d.ts +0 -2
- package/dist/src/path.js +0 -4
- package/dist/src/profiler.d.ts +0 -16
- package/dist/src/profiler.js +0 -81
- package/dist/src/project-analysis.d.ts +0 -59
- package/dist/src/project-analysis.js +0 -233
- package/dist/src/project-discovery.d.ts +0 -6
- package/dist/src/project-discovery.js +0 -30
- package/dist/src/repository-path.d.ts +0 -11
- package/dist/src/repository-path.js +0 -52
- package/dist/src/source-formats.d.ts +0 -7
- package/dist/src/source-formats.js +0 -30
- package/dist/src/source-parser.d.ts +0 -67
- package/dist/src/source-parser.js +0 -1749
- package/dist/src/untrusted.d.ts +0 -18
- package/dist/src/untrusted.js +0 -93
- package/dist/src/view/client/assets/channel-uy0fFvcW.js +0 -1
- package/dist/src/view/client/assets/classDiagram-ZZMXUADV-DbSEqjA5.js +0 -1
- package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-DbSEqjA5.js +0 -1
- package/dist/src/view/client/assets/index-nBmbYfun.js +0 -13
- package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-gUj6Hzgl.js +0 -1
- package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-DR7JhrxL.js +0 -8
- package/dist/src/walk.d.ts +0 -20
- 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
|
-
}
|