gitnexus 1.6.5-rc.2 → 1.6.5-rc.21
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/_shared/scope-resolution/method-dispatch-index.d.ts +26 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/method-dispatch-index.js +22 -3
- package/dist/_shared/scope-resolution/method-dispatch-index.js.map +1 -1
- package/dist/_shared/scope-resolution/registries/lookup-core.js +18 -1
- package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -1
- package/dist/cli/ai-context.d.ts +1 -0
- package/dist/cli/ai-context.js +30 -12
- package/dist/cli/analyze.d.ts +18 -0
- package/dist/cli/analyze.js +33 -4
- package/dist/cli/augment.d.ts +1 -1
- package/dist/cli/augment.js +1 -1
- package/dist/cli/index.js +6 -1
- package/dist/cli/setup.js +6 -0
- package/dist/core/augmentation/engine.d.ts +2 -2
- package/dist/core/augmentation/engine.js +26 -6
- package/dist/core/embeddings/ast-utils.js +2 -1
- package/dist/core/embeddings/http-client.js +22 -6
- package/dist/core/group/extractors/grpc-extractor.js +2 -1
- package/dist/core/group/extractors/http-patterns/python.js +175 -0
- package/dist/core/group/extractors/http-route-extractor.js +2 -1
- package/dist/core/group/extractors/include-extractor.js +2 -1
- package/dist/core/group/extractors/thrift-extractor.js +2 -1
- package/dist/core/group/extractors/tree-sitter-scanner.js +2 -1
- package/dist/core/incremental/shadow-candidates.d.ts +44 -0
- package/dist/core/incremental/shadow-candidates.js +74 -0
- package/dist/core/incremental/subgraph-extract.d.ts +64 -0
- package/dist/core/incremental/subgraph-extract.js +111 -0
- package/dist/core/ingestion/call-processor.js +166 -47
- package/dist/core/ingestion/community-processor.js +18 -0
- package/dist/core/ingestion/heritage-processor.js +3 -2
- package/dist/core/ingestion/import-processor.js +2 -1
- package/dist/core/ingestion/import-resolvers/standard.d.ts +5 -0
- package/dist/core/ingestion/import-resolvers/standard.js +27 -1
- package/dist/core/ingestion/import-resolvers/utils.js +4 -0
- package/dist/core/ingestion/languages/c/arity-metadata.d.ts +14 -0
- package/dist/core/ingestion/languages/c/arity-metadata.js +94 -0
- package/dist/core/ingestion/languages/c/arity.d.ts +6 -0
- package/dist/core/ingestion/languages/c/arity.js +18 -0
- package/dist/core/ingestion/languages/c/captures.d.ts +2 -0
- package/dist/core/ingestion/languages/c/captures.js +105 -0
- package/dist/core/ingestion/languages/c/header-scan.d.ts +7 -0
- package/dist/core/ingestion/languages/c/header-scan.js +55 -0
- package/dist/core/ingestion/languages/c/import-decomposer.d.ts +8 -0
- package/dist/core/ingestion/languages/c/import-decomposer.js +50 -0
- package/dist/core/ingestion/languages/c/import-target.d.ts +14 -0
- package/dist/core/ingestion/languages/c/import-target.js +57 -0
- package/dist/core/ingestion/languages/c/index.d.ts +11 -0
- package/dist/core/ingestion/languages/c/index.js +11 -0
- package/dist/core/ingestion/languages/c/interpret.d.ts +14 -0
- package/dist/core/ingestion/languages/c/interpret.js +48 -0
- package/dist/core/ingestion/languages/c/merge-bindings.d.ts +7 -0
- package/dist/core/ingestion/languages/c/merge-bindings.js +23 -0
- package/dist/core/ingestion/languages/c/query.d.ts +3 -0
- package/dist/core/ingestion/languages/c/query.js +161 -0
- package/dist/core/ingestion/languages/c/scope-resolver.d.ts +13 -0
- package/dist/core/ingestion/languages/c/scope-resolver.js +60 -0
- package/dist/core/ingestion/languages/c/simple-hooks.d.ts +14 -0
- package/dist/core/ingestion/languages/c/simple-hooks.js +19 -0
- package/dist/core/ingestion/languages/c/static-linkage.d.ts +13 -0
- package/dist/core/ingestion/languages/c/static-linkage.js +57 -0
- package/dist/core/ingestion/languages/c-cpp.js +10 -0
- package/dist/core/ingestion/languages/csharp/captures.js +2 -1
- package/dist/core/ingestion/languages/csharp/namespace-siblings.js +3 -2
- package/dist/core/ingestion/languages/go/captures.js +2 -1
- package/dist/core/ingestion/languages/go/range-binding.js +2 -1
- package/dist/core/ingestion/languages/java/arity-metadata.d.ts +18 -0
- package/dist/core/ingestion/languages/java/arity-metadata.js +40 -0
- package/dist/core/ingestion/languages/java/arity.d.ts +10 -0
- package/dist/core/ingestion/languages/java/arity.js +24 -0
- package/dist/core/ingestion/languages/java/cache-stats.d.ts +15 -0
- package/dist/core/ingestion/languages/java/cache-stats.js +26 -0
- package/dist/core/ingestion/languages/java/captures.d.ts +17 -0
- package/dist/core/ingestion/languages/java/captures.js +187 -0
- package/dist/core/ingestion/languages/java/import-decomposer.d.ts +18 -0
- package/dist/core/ingestion/languages/java/import-decomposer.js +85 -0
- package/dist/core/ingestion/languages/java/import-target.d.ts +17 -0
- package/dist/core/ingestion/languages/java/import-target.js +100 -0
- package/dist/core/ingestion/languages/java/index.d.ts +29 -0
- package/dist/core/ingestion/languages/java/index.js +29 -0
- package/dist/core/ingestion/languages/java/interpret.d.ts +13 -0
- package/dist/core/ingestion/languages/java/interpret.js +131 -0
- package/dist/core/ingestion/languages/java/merge-bindings.d.ts +12 -0
- package/dist/core/ingestion/languages/java/merge-bindings.js +40 -0
- package/dist/core/ingestion/languages/java/query.d.ts +30 -0
- package/dist/core/ingestion/languages/java/query.js +192 -0
- package/dist/core/ingestion/languages/java/receiver-binding.d.ts +11 -0
- package/dist/core/ingestion/languages/java/receiver-binding.js +95 -0
- package/dist/core/ingestion/languages/java/scope-resolver.d.ts +50 -0
- package/dist/core/ingestion/languages/java/scope-resolver.js +74 -0
- package/dist/core/ingestion/languages/java/simple-hooks.d.ts +13 -0
- package/dist/core/ingestion/languages/java/simple-hooks.js +34 -0
- package/dist/core/ingestion/languages/java.js +11 -0
- package/dist/core/ingestion/languages/php/arity-metadata.d.ts +28 -0
- package/dist/core/ingestion/languages/php/arity-metadata.js +63 -0
- package/dist/core/ingestion/languages/php/arity.d.ts +25 -0
- package/dist/core/ingestion/languages/php/arity.js +40 -0
- package/dist/core/ingestion/languages/php/cache-stats.d.ts +15 -0
- package/dist/core/ingestion/languages/php/cache-stats.js +26 -0
- package/dist/core/ingestion/languages/php/captures.d.ts +34 -0
- package/dist/core/ingestion/languages/php/captures.js +739 -0
- package/dist/core/ingestion/languages/php/import-decomposer.d.ts +28 -0
- package/dist/core/ingestion/languages/php/import-decomposer.js +265 -0
- package/dist/core/ingestion/languages/php/import-target.d.ts +47 -0
- package/dist/core/ingestion/languages/php/import-target.js +100 -0
- package/dist/core/ingestion/languages/php/index.d.ts +68 -0
- package/dist/core/ingestion/languages/php/index.js +72 -0
- package/dist/core/ingestion/languages/php/interpret.d.ts +36 -0
- package/dist/core/ingestion/languages/php/interpret.js +241 -0
- package/dist/core/ingestion/languages/php/merge-bindings.d.ts +19 -0
- package/dist/core/ingestion/languages/php/merge-bindings.js +47 -0
- package/dist/core/ingestion/languages/php/namespace-siblings.d.ts +51 -0
- package/dist/core/ingestion/languages/php/namespace-siblings.js +288 -0
- package/dist/core/ingestion/languages/php/query.d.ts +32 -0
- package/dist/core/ingestion/languages/php/query.js +326 -0
- package/dist/core/ingestion/languages/php/receiver-binding.d.ts +36 -0
- package/dist/core/ingestion/languages/php/receiver-binding.js +128 -0
- package/dist/core/ingestion/languages/php/scope-resolver.d.ts +23 -0
- package/dist/core/ingestion/languages/php/scope-resolver.js +358 -0
- package/dist/core/ingestion/languages/php/simple-hooks.d.ts +42 -0
- package/dist/core/ingestion/languages/php/simple-hooks.js +111 -0
- package/dist/core/ingestion/languages/php.d.ts +0 -7
- package/dist/core/ingestion/languages/php.js +15 -0
- package/dist/core/ingestion/languages/python/captures.js +2 -1
- package/dist/core/ingestion/languages/typescript/captures.js +2 -1
- package/dist/core/ingestion/parsing-processor.d.ts +22 -2
- package/dist/core/ingestion/parsing-processor.js +85 -50
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +5 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +119 -11
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +14 -0
- package/dist/core/ingestion/pipeline.d.ts +13 -0
- package/dist/core/ingestion/registry-primary-flag.js +2 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +65 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.d.ts +1 -1
- package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.js +12 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +5 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +25 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +79 -7
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +7 -3
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +24 -4
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +21 -2
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +13 -1
- package/dist/core/ingestion/scope-resolution/pipeline/registry.js +6 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +17 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +31 -7
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
- package/dist/core/ingestion/tree-sitter-queries.js +10 -0
- package/dist/core/ingestion/workers/parse-worker.js +2 -1
- package/dist/core/lbug/lbug-adapter.d.ts +26 -0
- package/dist/core/lbug/lbug-adapter.js +174 -40
- package/dist/core/lbug/pool-adapter.js +19 -2
- package/dist/core/run-analyze.d.ts +2 -0
- package/dist/core/run-analyze.js +323 -29
- package/dist/core/tree-sitter/safe-parse.d.ts +6 -0
- package/dist/core/tree-sitter/safe-parse.js +32 -0
- package/dist/server/git-clone.js +10 -13
- package/dist/storage/file-hash.d.ts +47 -0
- package/dist/storage/file-hash.js +86 -0
- package/dist/storage/git.d.ts +17 -6
- package/dist/storage/git.js +46 -12
- package/dist/storage/parse-cache.d.ts +67 -0
- package/dist/storage/parse-cache.js +182 -0
- package/dist/storage/repo-manager.d.ts +41 -1
- package/dist/storage/repo-manager.js +17 -2
- package/hooks/claude/gitnexus-hook.cjs +8 -1
- package/hooks/claude/hook-lock.cjs +119 -0
- package/package.json +1 -1
- package/web/assets/{agent-BpHQleHE.js → agent-BG6RCOzz.js} +1 -1
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-F-tujre-.js +1 -0
- package/web/assets/architectureDiagram-UL44E2DR-2GL7nOvO.js +36 -0
- package/web/assets/blockDiagram-7IZFK4PR-5AjX0pPU.js +132 -0
- package/web/assets/{c4Diagram-DFAF54RM-DeJV1rCn.js → c4Diagram-Y2BXMSZH-hLOeq7xC.js} +2 -2
- package/web/assets/chunk-2T2R6R2M-B_pq_2nf.js +4 -0
- package/web/assets/chunk-2UTLFMKG-CpoohCFN.js +1 -0
- package/web/assets/{chunk-7RZVMHOQ-BdIU-RGO.js → chunk-3SSMPTDK-CfqpR3Nr.js} +1 -1
- package/web/assets/chunk-4R4BOZG6-D3gm7tYj.js +159 -0
- package/web/assets/chunk-6764PJDD-WcI965eO.js +1 -0
- package/web/assets/chunk-AQ6EADP3-BpMj3rQl.js +1 -0
- package/web/assets/{chunk-KSICW3F5-C2tZmXwv.js → chunk-AZZRMDJM-DSoCJlUA.js} +1 -1
- package/web/assets/chunk-C62D2QBJ-CvFF2PnB.js +1 -0
- package/web/assets/chunk-CEXFNPSA-DdNtJtrF.js +1 -0
- package/web/assets/chunk-J5EP6P6S-DtcVaAJI.js +1 -0
- package/web/assets/{chunk-AEOMTBSW-D7qjBMHW.js → chunk-JQRUD6KW-DElaNjc0.js} +1 -1
- package/web/assets/chunk-KGYTTC2M-D0K5or7e.js +1 -0
- package/web/assets/chunk-KRXBNO2N-DpR8iDt8.js +1 -0
- package/web/assets/chunk-LCXTWHL2-DdMObOEk.js +231 -0
- package/web/assets/chunk-LII3EMHJ-I78zXtzi.js +1 -0
- package/web/assets/chunk-RERM46MO-Betu1cSy.js +1 -0
- package/web/assets/chunk-RG4AUYOV-BUCJ2JP5.js +206 -0
- package/web/assets/chunk-RKZBBQEN-Cutpza0t.js +1 -0
- package/web/assets/chunk-RLI5ZMPA-BFUxCvX2.js +1 -0
- package/web/assets/chunk-T5OCTHI4-DKwlkuvB.js +1 -0
- package/web/assets/chunk-UP6H54XL-0YWa0NDg.js +1 -0
- package/web/assets/chunk-UXSXWOXI-CSz0OXpz.js +1 -0
- package/web/assets/chunk-W44A43WB-AOmgoT-X.js +1 -0
- package/web/assets/{chunk-RWUO3TPN-DTWzAhQ1.js → chunk-ZXARS5L4-DIzgxjMw.js} +1 -1
- package/web/assets/classDiagram-KGZ6W3CR-BT-rn7LF.js +1 -0
- package/web/assets/classDiagram-v2-72OJOZXJ-uR3nDadY.js +1 -0
- package/web/assets/{cose-bilkent-PNC4W37J-DdZq7Qz_.js → cose-bilkent-UX7MHV2Q-DCSCD1TK.js} +1 -1
- package/web/assets/dagre-ND4H6XIP-CsciHSij.js +4 -0
- package/web/assets/diagram-3NCE3AQN-BKUT5Rpc.js +43 -0
- package/web/assets/diagram-GF46GFSD-Dxb4hZSo.js +24 -0
- package/web/assets/diagram-HNR7UZ2L-D3qus9Cn.js +3 -0
- package/web/assets/diagram-QXG6HAR7-r9BMLGGP.js +24 -0
- package/web/assets/diagram-WEQXMOUZ-BGXqs7-m.js +10 -0
- package/web/assets/{erDiagram-GCSMX5X6-DfdN6iqF.js → erDiagram-L5TCEMPS-LgSWVrkZ.js} +2 -2
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-By7r3bla.js +1 -0
- package/web/assets/flowDiagram-H6V6AXG4-Bj_vV5ky.js +162 -0
- package/web/assets/ganttDiagram-JCBTUEKG-B1eVITSh.js +292 -0
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-ClEP6RdE.js +1 -0
- package/web/assets/gitGraphDiagram-S2ZK5IYY-BP0R-_FD.js +106 -0
- package/web/assets/{index-3NUCUW2s.js → index-oL-ZNYwb.js} +80 -81
- package/web/assets/info-J43DQDTF-KCYPFFUO-bBJRjmP5.js +1 -0
- package/web/assets/infoDiagram-3YFTVSEB-Dmj4OEO3.js +2 -0
- package/web/assets/{ishikawaDiagram-YMYX4NHK-BF8AtDaj.js → ishikawaDiagram-BNXS4ZKH-B3NgQ4lJ.js} +2 -2
- package/web/assets/{journeyDiagram-SO5T7YLQ-BW8oKa3N.js → journeyDiagram-M6C3CM3L-DALmL4_N.js} +3 -3
- package/web/assets/{kanban-definition-LJHFXRCJ-DzbOsR-2.js → kanban-definition-75IXJCU3-AvVbHpnN.js} +4 -4
- package/web/assets/{katex-GD7MH7QM-CJiOjBBJ.js → katex-K3KEBU37-CqF6_ZN-.js} +1 -1
- package/web/assets/{mindmap-definition-2EUWGEK5-BIXGQALq.js → mindmap-definition-2TDM6QVE-B5c9VOzs.js} +28 -28
- package/web/assets/packet-YPE3B663-LP52Z2RK-1ZCldnu3.js +1 -0
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-EhjHC5EE.js +1 -0
- package/web/assets/pieDiagram-CU6KROY3-Po2HSSR4.js +30 -0
- package/web/assets/quadrantDiagram-VICAPDV7-C47UxSZD.js +7 -0
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-CvXjgxlW.js +1 -0
- package/web/assets/{requirementDiagram-M5DCFWZL-CzUUrhQD.js → requirementDiagram-JXO7QTGE-CpECN_Hq.js} +6 -6
- package/web/assets/sankeyDiagram-URQDO5SZ-B3b7cLrS.js +40 -0
- package/web/assets/sequenceDiagram-VS2MUI6T-CRJ95oVP.js +162 -0
- package/web/assets/stateDiagram-7D4R322I-C7U9b3ks.js +1 -0
- package/web/assets/stateDiagram-v2-36443NZ5-BQajbtov.js +1 -0
- package/web/assets/{timeline-definition-5SPVSISX-DkMiGj4Z.js → timeline-definition-O6YCAMPW-rtbk6BBo.js} +4 -4
- package/web/assets/treeView-BLDUP644-QA4HXRO3-R2o5gwfP.js +1 -0
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-Cesmac_u.js +1 -0
- package/web/assets/{vennDiagram-IE5QUKF5-BCxMmf9q.js → vennDiagram-MWXL3ELB-W8Yoaayh.js} +3 -3
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-B9HYoRgA.js +1 -0
- package/web/assets/wardleyDiagram-CUQ6CDDI-DIZw5Abj.js +78 -0
- package/web/assets/{xychartDiagram-ZHJ5623Y-DZ7fP1_3.js → xychartDiagram-N2JHSOCM-DGRtrj4P.js} +3 -3
- package/web/index.html +2 -2
- package/web/assets/architecture-YZFGNWBL-S5CXDPWN-BUzkWgDl.js +0 -1
- package/web/assets/architectureDiagram-EMZXCZ2Q-CXbzok1G.js +0 -36
- package/web/assets/blockDiagram-IGV67L2C-DA1QJ4ZB.js +0 -132
- package/web/assets/chunk-3GS5O3IE-B8hpnia8.js +0 -231
- package/web/assets/chunk-3YCYZ6SJ-B-BVu21C.js +0 -1
- package/web/assets/chunk-6NTNNK5N-DW-jYSDr.js +0 -1
- package/web/assets/chunk-A34GCYZU-BbZl-IKy.js +0 -1
- package/web/assets/chunk-DJ7UZH7F-B5tMfF87.js +0 -1
- package/web/assets/chunk-DKKBVRCY-Djm-6K_e.js +0 -4
- package/web/assets/chunk-DU5LTGQ6-QPoynYcp.js +0 -1
- package/web/assets/chunk-FXACKDTF-jieSmbe2.js +0 -159
- package/web/assets/chunk-H3VCZNTA-8EMHZ3SV.js +0 -1
- package/web/assets/chunk-HN6EAY2L-CgE_agsD.js +0 -1
- package/web/assets/chunk-O5ABG6QK-DEZV1O19.js +0 -1
- package/web/assets/chunk-PK6DOVAG-BXv0JnsJ.js +0 -206
- package/web/assets/chunk-RNJOYNJ4-BiBkF9dN.js +0 -1
- package/web/assets/chunk-TBF5ZNIQ-BSl6s9lT.js +0 -1
- package/web/assets/chunk-TU3PZOEN-DE5Qhc0N.js +0 -1
- package/web/assets/chunk-TYMNRAUI-D1NDLIMG.js +0 -1
- package/web/assets/chunk-VELTKBKT-C9dVN39o.js +0 -1
- package/web/assets/chunk-W7ZLLLMY-Bu-cdLzs.js +0 -1
- package/web/assets/chunk-WSB5WSVC-Dor71SOz.js +0 -1
- package/web/assets/chunk-XGPFEOL4-CUonLRle.js +0 -1
- package/web/assets/classDiagram-PPOCWD7C-Cdd6UdVv.js +0 -1
- package/web/assets/classDiagram-v2-23LJLIIU-DNhxY2Ib.js +0 -1
- package/web/assets/dagre-E77IOHMT-Cfj_6e17.js +0 -4
- package/web/assets/diagram-H7BISOXX-BNvpsrBv.js +0 -43
- package/web/assets/diagram-JC5VWROH-Cn0rtDbJ.js +0 -24
- package/web/assets/diagram-LXUTUG65-CHfoVKNm.js +0 -10
- package/web/assets/diagram-WEHSV5V5-BLxHksnu.js +0 -24
- package/web/assets/flowDiagram-OTCZ4VVT-aAZw4c_M.js +0 -162
- package/web/assets/ganttDiagram-MUNLMDZQ-BEfC_7Or.js +0 -292
- package/web/assets/gitGraph-7Q5UKJZL-54BCDZD5-B6ZeRLP0.js +0 -1
- package/web/assets/gitGraphDiagram-3HKGZ4G3-CG0kC8Q5.js +0 -106
- package/web/assets/info-OMHHGYJF-BF2H5H6G-BIOsZy0W.js +0 -1
- package/web/assets/infoDiagram-MN7RKWGX-DUoMH-pq.js +0 -2
- package/web/assets/packet-4T2RLAQJ-EV4IVRXR-Bs7ysNMU.js +0 -1
- package/web/assets/pie-ZZUOXDRM-N23DN5KN-Csi8nnbH.js +0 -1
- package/web/assets/pieDiagram-3IATQBI2-QY-u7P6a.js +0 -30
- package/web/assets/quadrantDiagram-E256RVCF-Di4aNiU8.js +0 -7
- package/web/assets/radar-PYXPWWZC-P6TP7ZYP-DJlyXh2-.js +0 -1
- package/web/assets/sankeyDiagram-L3NBLAOT-D2fbMiIU.js +0 -10
- package/web/assets/sequenceDiagram-ZOUHS735-BNdkqguh.js +0 -157
- package/web/assets/stateDiagram-MLPALWAM-51_Q2w2L.js +0 -1
- package/web/assets/stateDiagram-v2-B5LQ5ZB2-8nHs2aNE.js +0 -1
- package/web/assets/treeView-SZITEDCU-5DXDK3XO-Cy6P0_CZ.js +0 -1
- package/web/assets/treemap-W4RFUUIX-WYLRDWKO-C_pp1R7A.js +0 -1
- package/web/assets/wardley-RL74JXVD-BCRCBASE-CMStJhpn.js +0 -1
- package/web/assets/wardleyDiagram-XU3VSMPF-ijlLF77s.js +0 -20
- /package/web/assets/{context-builder-CqQNhRj1.js → context-builder-CG-ydtp4.js} +0 -0
|
@@ -29,7 +29,8 @@ import { getLanguageFromFilename, SupportedLanguages } from '../../_shared/index
|
|
|
29
29
|
import { isRegistryPrimary } from './registry-primary-flag.js';
|
|
30
30
|
import { isVerboseIngestionEnabled } from './utils/verbose.js';
|
|
31
31
|
import { yieldToEventLoop } from './utils/event-loop.js';
|
|
32
|
-
import {
|
|
32
|
+
import { parseSourceSafe } from '../tree-sitter/safe-parse.js';
|
|
33
|
+
import { CLASS_CONTAINER_TYPES, FUNCTION_NODE_TYPES, findEnclosingClassInfo, genericFuncName, inferFunctionLabel, } from './utils/ast-helpers.js';
|
|
33
34
|
import { typeTagForId, constTagForId, buildCollisionGroups } from './utils/method-props.js';
|
|
34
35
|
import { countCallArguments, inferCallForm, extractReceiverName, extractReceiverNode, extractMixedChain, extractCallArgTypes, } from './utils/call-analysis.js';
|
|
35
36
|
import { buildTypeEnv, isSubclassOf } from './type-env.js';
|
|
@@ -38,6 +39,57 @@ import { normalizeFetchURL, routeMatches } from './route-extractors/nextjs.js';
|
|
|
38
39
|
import { extractTemplateComponents } from './vue-sfc-extractor.js';
|
|
39
40
|
import { extractReturnTypeName, stripNullable } from './type-extractors/shared.js';
|
|
40
41
|
import { logger } from '../logger.js';
|
|
42
|
+
// ── Property-prepass helpers (parity with parse-worker.ts) ──
|
|
43
|
+
// These mirror the sequential-path equivalents in parse-worker.ts so the main-
|
|
44
|
+
// thread `processCalls` pre-pass produces byte-identical Property nodes/symbols
|
|
45
|
+
// to the worker pool. Drift between the two paths breaks the
|
|
46
|
+
// `incremental ≡ --force` invariant the moment a repo crosses the worker
|
|
47
|
+
// threshold between runs.
|
|
48
|
+
/** Walk up to the nearest enclosing class/struct/interface AST node. */
|
|
49
|
+
const findEnclosingClassNode = (node) => {
|
|
50
|
+
let current = node.parent;
|
|
51
|
+
while (current) {
|
|
52
|
+
if (CLASS_CONTAINER_TYPES.has(current.type))
|
|
53
|
+
return current;
|
|
54
|
+
current = current.parent;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
};
|
|
58
|
+
/** No-op SymbolTable stub for FieldExtractorContext — matches parse-worker. */
|
|
59
|
+
const NOOP_SYMBOL_TABLE = {
|
|
60
|
+
lookupExact: () => undefined,
|
|
61
|
+
lookupExactFull: () => undefined,
|
|
62
|
+
lookupExactAll: () => [],
|
|
63
|
+
lookupCallableByName: () => [],
|
|
64
|
+
getFiles: () => [][Symbol.iterator](),
|
|
65
|
+
getStats: () => ({ fileCount: 0 }),
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Extract (and cache) field info for a class node. Cache is passed in so it
|
|
69
|
+
* stays scoped to a single `processCalls` invocation rather than leaking
|
|
70
|
+
* across analyze runs (worker uses module-level caching because each worker
|
|
71
|
+
* process is short-lived; the main thread is not).
|
|
72
|
+
*
|
|
73
|
+
* Cache key is `${filePath}:${classNode.startIndex}` — startIndex alone is a
|
|
74
|
+
* per-file byte offset, so almost every Ruby/Python file's leading class lands
|
|
75
|
+
* at byte 0 and would collide across files in the shared map.
|
|
76
|
+
*/
|
|
77
|
+
const getFieldInfo = (classNode, provider, context, cache) => {
|
|
78
|
+
if (!provider.fieldExtractor)
|
|
79
|
+
return undefined;
|
|
80
|
+
const cacheKey = `${context.filePath}:${classNode.startIndex}`;
|
|
81
|
+
const cached = cache.get(cacheKey);
|
|
82
|
+
if (cached)
|
|
83
|
+
return cached;
|
|
84
|
+
const result = provider.fieldExtractor.extract(classNode, context);
|
|
85
|
+
if (!result?.fields?.length)
|
|
86
|
+
return undefined;
|
|
87
|
+
const map = new Map();
|
|
88
|
+
for (const field of result.fields)
|
|
89
|
+
map.set(field.name, field);
|
|
90
|
+
cache.set(cacheKey, map);
|
|
91
|
+
return map;
|
|
92
|
+
};
|
|
41
93
|
/**
|
|
42
94
|
* Type labels treated as class-like **method-dispatch receivers** by the call
|
|
43
95
|
* resolver — the set walked by the MRO / heritage path for member and static
|
|
@@ -614,7 +666,7 @@ importedRawReturnTypesMap, heritageMap, bindingAccumulator) => {
|
|
|
614
666
|
if (!tree) {
|
|
615
667
|
const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
|
|
616
668
|
try {
|
|
617
|
-
tree = parser
|
|
669
|
+
tree = parseSourceSafe(parser, parseContent, undefined, {
|
|
618
670
|
bufferSize: getTreeSitterBufferSize(parseContent),
|
|
619
671
|
});
|
|
620
672
|
}
|
|
@@ -701,6 +753,111 @@ importedRawReturnTypesMap, heritageMap, bindingAccumulator) => {
|
|
|
701
753
|
}
|
|
702
754
|
prepared.push({ file, language, provider, tree, matches, parentMap, typeEnv });
|
|
703
755
|
}
|
|
756
|
+
// ── Property-registration pre-pass ──
|
|
757
|
+
// Register all routed properties (e.g. Ruby attr_accessor) BEFORE the
|
|
758
|
+
// resolution loop so cross-file field-type lookups (e.g.
|
|
759
|
+
// `user.address.save → Address#save`) succeed regardless of file
|
|
760
|
+
// processing order. This MUST stay in lockstep with the equivalent
|
|
761
|
+
// worker-path block in parse-worker.ts (kind === 'properties') — any
|
|
762
|
+
// divergence between the two paths breaks the `incremental ≡ --force`
|
|
763
|
+
// invariant once a repo crosses the worker threshold between runs.
|
|
764
|
+
const fieldInfoCache = new Map();
|
|
765
|
+
for (const { file, language, provider, matches, typeEnv } of prepared) {
|
|
766
|
+
const callRouter = provider.callRouter;
|
|
767
|
+
if (!callRouter)
|
|
768
|
+
continue;
|
|
769
|
+
matches.forEach((match) => {
|
|
770
|
+
const captureMap = {};
|
|
771
|
+
match.captures.forEach((c) => (captureMap[c.name] = c.node));
|
|
772
|
+
if (!captureMap['call'])
|
|
773
|
+
return;
|
|
774
|
+
const callNameNode = captureMap['call.name'];
|
|
775
|
+
if (!callNameNode)
|
|
776
|
+
return;
|
|
777
|
+
const routed = callRouter(callNameNode.text, captureMap['call']);
|
|
778
|
+
if (!routed || routed.kind !== 'properties')
|
|
779
|
+
return;
|
|
780
|
+
const propEnclosingInfo = findEnclosingClassInfo(captureMap['call'], file.path, provider.resolveEnclosingOwner);
|
|
781
|
+
const propEnclosingClassId = propEnclosingInfo?.classId ?? null;
|
|
782
|
+
// Enrich routed properties with FieldExtractor metadata so types
|
|
783
|
+
// discovered from constructor assignments (e.g. `@address = Address.new`)
|
|
784
|
+
// are propagated even when the routing payload itself lacks declaredType.
|
|
785
|
+
let routedFieldMap;
|
|
786
|
+
if (provider.fieldExtractor && typeEnv) {
|
|
787
|
+
const classNode = findEnclosingClassNode(captureMap['call']);
|
|
788
|
+
if (classNode) {
|
|
789
|
+
routedFieldMap = getFieldInfo(classNode, provider, {
|
|
790
|
+
typeEnv,
|
|
791
|
+
symbolTable: NOOP_SYMBOL_TABLE,
|
|
792
|
+
filePath: file.path,
|
|
793
|
+
language,
|
|
794
|
+
}, fieldInfoCache);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
const fileId = generateId('File', file.path);
|
|
798
|
+
for (const item of routed.items) {
|
|
799
|
+
const routedFieldInfo = routedFieldMap?.get(item.propName);
|
|
800
|
+
const propQualifiedName = propEnclosingInfo
|
|
801
|
+
? `${propEnclosingInfo.className}.${item.propName}`
|
|
802
|
+
: item.propName;
|
|
803
|
+
const nodeId = generateId('Property', `${file.path}:${propQualifiedName}`);
|
|
804
|
+
graph.addNode({
|
|
805
|
+
id: nodeId,
|
|
806
|
+
label: 'Property',
|
|
807
|
+
properties: {
|
|
808
|
+
name: item.propName,
|
|
809
|
+
filePath: file.path,
|
|
810
|
+
startLine: item.startLine,
|
|
811
|
+
endLine: item.endLine,
|
|
812
|
+
language,
|
|
813
|
+
isExported: true,
|
|
814
|
+
description: item.accessorType,
|
|
815
|
+
...(item.declaredType
|
|
816
|
+
? { declaredType: item.declaredType }
|
|
817
|
+
: routedFieldInfo?.type
|
|
818
|
+
? { declaredType: routedFieldInfo.type }
|
|
819
|
+
: {}),
|
|
820
|
+
...(routedFieldInfo?.visibility !== undefined
|
|
821
|
+
? { visibility: routedFieldInfo.visibility }
|
|
822
|
+
: {}),
|
|
823
|
+
...(routedFieldInfo?.isStatic !== undefined
|
|
824
|
+
? { isStatic: routedFieldInfo.isStatic }
|
|
825
|
+
: {}),
|
|
826
|
+
...(routedFieldInfo?.isReadonly !== undefined
|
|
827
|
+
? { isReadonly: routedFieldInfo.isReadonly }
|
|
828
|
+
: {}),
|
|
829
|
+
},
|
|
830
|
+
});
|
|
831
|
+
ctx.model.symbols.add(file.path, item.propName, nodeId, 'Property', {
|
|
832
|
+
...(propEnclosingClassId ? { ownerId: propEnclosingClassId } : {}),
|
|
833
|
+
...(item.declaredType
|
|
834
|
+
? { declaredType: item.declaredType }
|
|
835
|
+
: routedFieldInfo?.type
|
|
836
|
+
? { declaredType: routedFieldInfo.type }
|
|
837
|
+
: {}),
|
|
838
|
+
});
|
|
839
|
+
const relId = generateId('DEFINES', `${fileId}->${nodeId}`);
|
|
840
|
+
graph.addRelationship({
|
|
841
|
+
id: relId,
|
|
842
|
+
sourceId: fileId,
|
|
843
|
+
targetId: nodeId,
|
|
844
|
+
type: 'DEFINES',
|
|
845
|
+
confidence: 1.0,
|
|
846
|
+
reason: '',
|
|
847
|
+
});
|
|
848
|
+
if (propEnclosingClassId) {
|
|
849
|
+
graph.addRelationship({
|
|
850
|
+
id: generateId('HAS_PROPERTY', `${propEnclosingClassId}->${nodeId}`),
|
|
851
|
+
sourceId: propEnclosingClassId,
|
|
852
|
+
targetId: nodeId,
|
|
853
|
+
type: 'HAS_PROPERTY',
|
|
854
|
+
confidence: 1.0,
|
|
855
|
+
reason: '',
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
});
|
|
860
|
+
}
|
|
704
861
|
// ── Resolution loop: verify constructor bindings and resolve calls ──
|
|
705
862
|
// The accumulator (if present) is now fully populated from the preparation
|
|
706
863
|
// loop above, so verifyConstructorBindings sees all provider bindings
|
|
@@ -749,9 +906,10 @@ importedRawReturnTypesMap, heritageMap, bindingAccumulator) => {
|
|
|
749
906
|
if (receiverTypeName) {
|
|
750
907
|
const enclosing = findEnclosingFunction(captureMap['assignment'], file.path, ctx, provider);
|
|
751
908
|
const srcId = enclosing || generateId('File', file.path);
|
|
752
|
-
// Defer resolution
|
|
753
|
-
//
|
|
754
|
-
//
|
|
909
|
+
// Defer resolution so write-access tracking sees the FINAL graph
|
|
910
|
+
// state — properties from the pre-pass are present, but receiver-type
|
|
911
|
+
// resolution can still depend on inference that completes during the
|
|
912
|
+
// main loop. Resolve after all files have been processed.
|
|
755
913
|
pendingWrites.push({ receiverTypeName, propertyName, filePath: file.path, srcId });
|
|
756
914
|
}
|
|
757
915
|
// Assignment-only capture (no @call sibling): skip the rest of this
|
|
@@ -841,47 +999,8 @@ importedRawReturnTypesMap, heritageMap, bindingAccumulator) => {
|
|
|
841
999
|
case 'import':
|
|
842
1000
|
return;
|
|
843
1001
|
case 'properties': {
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
for (const item of routed.items) {
|
|
847
|
-
const nodeId = generateId('Property', `${file.path}:${item.propName}`);
|
|
848
|
-
graph.addNode({
|
|
849
|
-
id: nodeId,
|
|
850
|
-
label: 'Property',
|
|
851
|
-
properties: {
|
|
852
|
-
name: item.propName,
|
|
853
|
-
filePath: file.path,
|
|
854
|
-
startLine: item.startLine,
|
|
855
|
-
endLine: item.endLine,
|
|
856
|
-
language,
|
|
857
|
-
isExported: true,
|
|
858
|
-
description: item.accessorType,
|
|
859
|
-
},
|
|
860
|
-
});
|
|
861
|
-
ctx.model.symbols.add(file.path, item.propName, nodeId, 'Property', {
|
|
862
|
-
...(propEnclosingClassId ? { ownerId: propEnclosingClassId } : {}),
|
|
863
|
-
...(item.declaredType ? { declaredType: item.declaredType } : {}),
|
|
864
|
-
});
|
|
865
|
-
const relId = generateId('DEFINES', `${fileId}->${nodeId}`);
|
|
866
|
-
graph.addRelationship({
|
|
867
|
-
id: relId,
|
|
868
|
-
sourceId: fileId,
|
|
869
|
-
targetId: nodeId,
|
|
870
|
-
type: 'DEFINES',
|
|
871
|
-
confidence: 1.0,
|
|
872
|
-
reason: '',
|
|
873
|
-
});
|
|
874
|
-
if (propEnclosingClassId) {
|
|
875
|
-
graph.addRelationship({
|
|
876
|
-
id: generateId('HAS_PROPERTY', `${propEnclosingClassId}->${nodeId}`),
|
|
877
|
-
sourceId: propEnclosingClassId,
|
|
878
|
-
targetId: nodeId,
|
|
879
|
-
type: 'HAS_PROPERTY',
|
|
880
|
-
confidence: 1.0,
|
|
881
|
-
reason: '',
|
|
882
|
-
});
|
|
883
|
-
}
|
|
884
|
-
}
|
|
1002
|
+
// Properties already registered in the pre-pass above.
|
|
1003
|
+
// Skip to avoid duplicate nodes/edges.
|
|
885
1004
|
return;
|
|
886
1005
|
}
|
|
887
1006
|
case 'call':
|
|
@@ -2586,7 +2705,7 @@ export const extractFetchCallsFromFiles = async (files, astCache) => {
|
|
|
2586
2705
|
if (!tree) {
|
|
2587
2706
|
const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
|
|
2588
2707
|
try {
|
|
2589
|
-
tree = parser
|
|
2708
|
+
tree = parseSourceSafe(parser, parseContent, undefined, {
|
|
2590
2709
|
bufferSize: getTreeSitterBufferSize(parseContent),
|
|
2591
2710
|
});
|
|
2592
2711
|
}
|
|
@@ -20,6 +20,23 @@ const __dirname = dirname(__filename);
|
|
|
20
20
|
const leidenPath = resolve(__dirname, '..', '..', '..', 'vendor', 'leiden', 'index.cjs');
|
|
21
21
|
const _require = createRequire(import.meta.url);
|
|
22
22
|
const leiden = _require(leidenPath);
|
|
23
|
+
/**
|
|
24
|
+
* Deterministic PRNG (mulberry32) seed for the vendored Leiden algorithm.
|
|
25
|
+
* Vendored Leiden defaults `rng: Math.random`, which makes community
|
|
26
|
+
* assignment non-deterministic across runs. Passing a seeded RNG gives us
|
|
27
|
+
* reproducible community/modularity output, which is required for the
|
|
28
|
+
* incremental-indexing equivalence test (incremental ≡ full rebuild).
|
|
29
|
+
*/
|
|
30
|
+
const LEIDEN_SEED = 0xc0de;
|
|
31
|
+
function createSeededRng(seed) {
|
|
32
|
+
let s = seed >>> 0;
|
|
33
|
+
return () => {
|
|
34
|
+
s = (s + 0x6d2b79f5) >>> 0;
|
|
35
|
+
let t = Math.imul(s ^ (s >>> 15), 1 | s);
|
|
36
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
37
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
23
40
|
// ============================================================================
|
|
24
41
|
// COMMUNITY COLORS (for visualization)
|
|
25
42
|
// ============================================================================
|
|
@@ -83,6 +100,7 @@ export const processCommunities = async (knowledgeGraph, onProgress) => {
|
|
|
83
100
|
Promise.resolve(leiden.detailed(graph, {
|
|
84
101
|
resolution: isLarge ? 2.0 : 1.0,
|
|
85
102
|
maxIterations: isLarge ? 3 : 0,
|
|
103
|
+
rng: createSeededRng(LEIDEN_SEED),
|
|
86
104
|
})),
|
|
87
105
|
new Promise((_, reject) => setTimeout(() => reject(new Error('Leiden timeout')), LEIDEN_TIMEOUT_MS)),
|
|
88
106
|
]);
|
|
@@ -19,6 +19,7 @@ import { generateId } from '../../lib/utils.js';
|
|
|
19
19
|
import { getLanguageFromFilename } from '../../_shared/index.js';
|
|
20
20
|
import { isVerboseIngestionEnabled } from './utils/verbose.js';
|
|
21
21
|
import { yieldToEventLoop } from './utils/event-loop.js';
|
|
22
|
+
import { parseSourceSafe } from '../tree-sitter/safe-parse.js';
|
|
22
23
|
import { getProvider } from './languages/index.js';
|
|
23
24
|
import { getTreeSitterBufferSize } from './constants.js';
|
|
24
25
|
import { resolveExtendsType } from './model/heritage-map.js';
|
|
@@ -152,7 +153,7 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
|
|
|
152
153
|
// re-parses see the same input as the cached AST.
|
|
153
154
|
const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
|
|
154
155
|
try {
|
|
155
|
-
tree = parser
|
|
156
|
+
tree = parseSourceSafe(parser, parseContent, undefined, {
|
|
156
157
|
bufferSize: getTreeSitterBufferSize(parseContent),
|
|
157
158
|
});
|
|
158
159
|
}
|
|
@@ -300,7 +301,7 @@ export async function extractExtractedHeritageFromFiles(files, astCache) {
|
|
|
300
301
|
if (!tree) {
|
|
301
302
|
const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
|
|
302
303
|
try {
|
|
303
|
-
tree = parser
|
|
304
|
+
tree = parseSourceSafe(parser, parseContent, undefined, {
|
|
304
305
|
bufferSize: getTreeSitterBufferSize(parseContent),
|
|
305
306
|
});
|
|
306
307
|
}
|
|
@@ -5,6 +5,7 @@ import { generateId } from '../../lib/utils.js';
|
|
|
5
5
|
import { getLanguageFromFilename } from '../../_shared/index.js';
|
|
6
6
|
import { isVerboseIngestionEnabled } from './utils/verbose.js';
|
|
7
7
|
import { yieldToEventLoop } from './utils/event-loop.js';
|
|
8
|
+
import { parseSourceSafe } from '../tree-sitter/safe-parse.js';
|
|
8
9
|
import { getTreeSitterBufferSize } from './constants.js';
|
|
9
10
|
import { loadImportConfigs } from './language-config.js';
|
|
10
11
|
import { buildSuffixIndex } from './import-resolvers/utils.js';
|
|
@@ -243,7 +244,7 @@ export const processImports = async (graph, files, astCache, ctx, onProgress, re
|
|
|
243
244
|
if (!tree) {
|
|
244
245
|
const parseContent = provider.preprocessSource?.(file.content, file.path) ?? file.content;
|
|
245
246
|
try {
|
|
246
|
-
tree = parser
|
|
247
|
+
tree = parseSourceSafe(parser, parseContent, undefined, {
|
|
247
248
|
bufferSize: getTreeSitterBufferSize(parseContent),
|
|
248
249
|
});
|
|
249
250
|
}
|
|
@@ -28,3 +28,8 @@ export declare const resolveImportPath: (currentFile: string, importPath: string
|
|
|
28
28
|
export declare function resolveStandard(rawImportPath: string, filePath: string, ctx: ResolveCtx, language: SupportedLanguages): ImportResult;
|
|
29
29
|
/** Create a reusable standard-resolution strategy for a given language. */
|
|
30
30
|
export declare function createStandardStrategy(language: SupportedLanguages): ImportResolverStrategy;
|
|
31
|
+
/**
|
|
32
|
+
* Strip a JS-family extension from a path, returning the stem.
|
|
33
|
+
* Returns `null` if the path does not end with a JS-family extension.
|
|
34
|
+
*/
|
|
35
|
+
export declare function stripJsExtension(path: string): string | null;
|
|
@@ -108,7 +108,20 @@ export const resolveImportPath = (currentFile, importPath, allFiles, allFileList
|
|
|
108
108
|
const basePath = currentDir.join('/');
|
|
109
109
|
if (importPath.startsWith('.')) {
|
|
110
110
|
const resolved = tryResolveWithExtensions(basePath, allFiles);
|
|
111
|
-
|
|
111
|
+
if (resolved)
|
|
112
|
+
return cache(resolved);
|
|
113
|
+
// TypeScript ESM: imports use .js/.jsx/.mjs/.cjs but source files are
|
|
114
|
+
// .ts/.tsx/.mts/.cts. Strip the JS-family extension and re-resolve.
|
|
115
|
+
// NOTE: This fallback only applies to relative imports. Path alias imports
|
|
116
|
+
// (e.g. @/utils.js via tsconfig paths) do not yet strip .js extensions —
|
|
117
|
+
// that is a known limitation tracked for follow-up.
|
|
118
|
+
if (language === SupportedLanguages.TypeScript || language === SupportedLanguages.JavaScript) {
|
|
119
|
+
const stripped = stripJsExtension(basePath);
|
|
120
|
+
if (stripped !== null) {
|
|
121
|
+
return cache(tryResolveWithExtensions(stripped, allFiles));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return cache(null);
|
|
112
125
|
}
|
|
113
126
|
// ---- Generic package/absolute import resolution (suffix matching) ----
|
|
114
127
|
// Java wildcards are handled in processImports, not here
|
|
@@ -140,3 +153,16 @@ export function resolveStandard(rawImportPath, filePath, ctx, language) {
|
|
|
140
153
|
export function createStandardStrategy(language) {
|
|
141
154
|
return (raw, fp, ctx) => resolveStandard(raw, fp, ctx, language);
|
|
142
155
|
}
|
|
156
|
+
// ============================================================================
|
|
157
|
+
// ESM extension helpers
|
|
158
|
+
// ============================================================================
|
|
159
|
+
/** JS-family extensions that TypeScript ESM maps to TS equivalents. */
|
|
160
|
+
const JS_EXTENSION_PATTERN = /\.(js|jsx|mjs|cjs)$/;
|
|
161
|
+
/**
|
|
162
|
+
* Strip a JS-family extension from a path, returning the stem.
|
|
163
|
+
* Returns `null` if the path does not end with a JS-family extension.
|
|
164
|
+
*/
|
|
165
|
+
export function stripJsExtension(path) {
|
|
166
|
+
const match = JS_EXTENSION_PATTERN.exec(path);
|
|
167
|
+
return match ? path.slice(0, -match[0].length) : null;
|
|
168
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SyntaxNode } from '../../utils/ast-helpers.js';
|
|
2
|
+
export interface CArityInfo {
|
|
3
|
+
parameterCount?: number;
|
|
4
|
+
requiredParameterCount?: number;
|
|
5
|
+
parameterTypes?: string[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Compute declaration arity from a C function definition or declaration node.
|
|
9
|
+
*/
|
|
10
|
+
export declare function computeCDeclarationArity(node: SyntaxNode): CArityInfo;
|
|
11
|
+
/**
|
|
12
|
+
* Compute call-site arity from a call_expression node.
|
|
13
|
+
*/
|
|
14
|
+
export declare function computeCCallArity(node: SyntaxNode): number;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute declaration arity from a C function definition or declaration node.
|
|
3
|
+
*/
|
|
4
|
+
export function computeCDeclarationArity(node) {
|
|
5
|
+
// Find the function_declarator child (may be wrapped in pointer_declarator)
|
|
6
|
+
const funcDecl = findFuncDeclarator(node);
|
|
7
|
+
if (funcDecl === null)
|
|
8
|
+
return {};
|
|
9
|
+
const paramList = funcDecl.childForFieldName('parameters');
|
|
10
|
+
if (paramList === null)
|
|
11
|
+
return {};
|
|
12
|
+
const params = [];
|
|
13
|
+
for (let i = 0; i < paramList.childCount; i++) {
|
|
14
|
+
const child = paramList.child(i);
|
|
15
|
+
if (child === null)
|
|
16
|
+
continue;
|
|
17
|
+
if (child.type === 'parameter_declaration' || child.type === 'variadic_parameter') {
|
|
18
|
+
params.push(child);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// K&R old-style declaration: `int foo()` has an empty parameter_list with
|
|
22
|
+
// no parameter_declaration or variadic_parameter children. Per C89/C99,
|
|
23
|
+
// this means the function accepts an unspecified number/types of arguments —
|
|
24
|
+
// NOT zero arguments. Return unknown arity to avoid false 'incompatible'.
|
|
25
|
+
// `int foo(void)` is the explicit zero-parameter form and is handled below.
|
|
26
|
+
if (params.length === 0)
|
|
27
|
+
return {};
|
|
28
|
+
// (void) means zero parameters
|
|
29
|
+
if (params.length === 1 && params[0].type === 'parameter_declaration') {
|
|
30
|
+
const typeNode = params[0].childForFieldName('type');
|
|
31
|
+
const hasDeclarator = params[0].childForFieldName('declarator') !== null;
|
|
32
|
+
if (typeNode !== null && typeNode.text === 'void' && !hasDeclarator) {
|
|
33
|
+
return { parameterCount: 0, requiredParameterCount: 0, parameterTypes: [] };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const isVariadic = params.some((p) => p.type === 'variadic_parameter');
|
|
37
|
+
const nonVariadicCount = params.filter((p) => p.type !== 'variadic_parameter').length;
|
|
38
|
+
const types = [];
|
|
39
|
+
for (const p of params) {
|
|
40
|
+
if (p.type === 'variadic_parameter') {
|
|
41
|
+
types.push('...');
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const typeNode = p.childForFieldName('type');
|
|
45
|
+
types.push(typeNode?.text ?? 'unknown');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
parameterCount: isVariadic ? undefined : nonVariadicCount,
|
|
50
|
+
requiredParameterCount: nonVariadicCount,
|
|
51
|
+
parameterTypes: types,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Compute call-site arity from a call_expression node.
|
|
56
|
+
*/
|
|
57
|
+
export function computeCCallArity(node) {
|
|
58
|
+
const argList = node.childForFieldName('arguments');
|
|
59
|
+
if (argList === null)
|
|
60
|
+
return 0;
|
|
61
|
+
let count = 0;
|
|
62
|
+
for (let i = 0; i < argList.childCount; i++) {
|
|
63
|
+
const child = argList.child(i);
|
|
64
|
+
if (child === null)
|
|
65
|
+
continue;
|
|
66
|
+
// Skip punctuation (commas, parens)
|
|
67
|
+
if (child.type !== ',' && child.type !== '(' && child.type !== ')') {
|
|
68
|
+
count++;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return count;
|
|
72
|
+
}
|
|
73
|
+
function findFuncDeclarator(node) {
|
|
74
|
+
// Direct child
|
|
75
|
+
let decl = node.childForFieldName('declarator');
|
|
76
|
+
if (decl === null) {
|
|
77
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
78
|
+
const c = node.child(i);
|
|
79
|
+
if (c?.type === 'function_declarator')
|
|
80
|
+
return c;
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
// Unwrap pointer_declarator
|
|
85
|
+
while (decl.type === 'pointer_declarator') {
|
|
86
|
+
const next = decl.childForFieldName('declarator');
|
|
87
|
+
if (next === null)
|
|
88
|
+
break;
|
|
89
|
+
decl = next;
|
|
90
|
+
}
|
|
91
|
+
if (decl.type === 'function_declarator')
|
|
92
|
+
return decl;
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Callsite, SymbolDefinition } from '../../../../_shared/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* C arity compatibility: no overloading. Variadic functions detected
|
|
4
|
+
* via '...' in parameterTypes. Otherwise exact match or unknown.
|
|
5
|
+
*/
|
|
6
|
+
export declare function cArityCompatibility(def: SymbolDefinition, callsite: Callsite): 'compatible' | 'unknown' | 'incompatible';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* C arity compatibility: no overloading. Variadic functions detected
|
|
3
|
+
* via '...' in parameterTypes. Otherwise exact match or unknown.
|
|
4
|
+
*/
|
|
5
|
+
export function cArityCompatibility(def, callsite) {
|
|
6
|
+
const max = def.parameterCount;
|
|
7
|
+
const min = def.requiredParameterCount;
|
|
8
|
+
if (max === undefined && min === undefined)
|
|
9
|
+
return 'unknown';
|
|
10
|
+
if (!Number.isFinite(callsite.arity) || callsite.arity < 0)
|
|
11
|
+
return 'unknown';
|
|
12
|
+
const variadic = def.parameterTypes?.some((t) => t === '...') ?? false;
|
|
13
|
+
if (min !== undefined && callsite.arity < min)
|
|
14
|
+
return 'incompatible';
|
|
15
|
+
if (max !== undefined && callsite.arity > max && !variadic)
|
|
16
|
+
return 'incompatible';
|
|
17
|
+
return 'compatible';
|
|
18
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { findNodeAtRange, nodeToCapture, syntheticCapture, } from '../../utils/ast-helpers.js';
|
|
2
|
+
import { getCParser, getCScopeQuery } from './query.js';
|
|
3
|
+
import { getTreeSitterBufferSize } from '../../constants.js';
|
|
4
|
+
import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
|
|
5
|
+
import { splitCInclude } from './import-decomposer.js';
|
|
6
|
+
import { computeCDeclarationArity, computeCCallArity } from './arity-metadata.js';
|
|
7
|
+
import { markStaticName } from './static-linkage.js';
|
|
8
|
+
export function emitCScopeCaptures(sourceText, filePath, cachedTree) {
|
|
9
|
+
let tree = cachedTree;
|
|
10
|
+
if (tree === undefined) {
|
|
11
|
+
tree = parseSourceSafe(getCParser(), sourceText, undefined, {
|
|
12
|
+
bufferSize: getTreeSitterBufferSize(sourceText),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
const rawMatches = getCScopeQuery().matches(tree.rootNode);
|
|
16
|
+
const out = [];
|
|
17
|
+
// Track ranges where typedef-struct/union was captured as @declaration.struct/union
|
|
18
|
+
// so we can suppress the duplicate @declaration.typedef match at the same range.
|
|
19
|
+
const structTypedefRanges = new Set();
|
|
20
|
+
for (const m of rawMatches) {
|
|
21
|
+
const grouped = {};
|
|
22
|
+
for (const c of m.captures) {
|
|
23
|
+
const tag = '@' + c.name;
|
|
24
|
+
if (tag.startsWith('@_'))
|
|
25
|
+
continue;
|
|
26
|
+
grouped[tag] = nodeToCapture(tag, c.node);
|
|
27
|
+
}
|
|
28
|
+
if (Object.keys(grouped).length === 0)
|
|
29
|
+
continue;
|
|
30
|
+
// Handle #include statements
|
|
31
|
+
if (grouped['@import.statement'] !== undefined) {
|
|
32
|
+
const anchor = grouped['@import.statement'];
|
|
33
|
+
const includeNode = findNodeAtRange(tree.rootNode, anchor.range, 'preproc_include');
|
|
34
|
+
if (includeNode !== null) {
|
|
35
|
+
const split = splitCInclude(includeNode);
|
|
36
|
+
if (split !== null) {
|
|
37
|
+
out.push(split);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Track typedef-struct ranges to suppress duplicate typedef declarations
|
|
43
|
+
const structAnchor = grouped['@declaration.struct'] ?? grouped['@declaration.union'];
|
|
44
|
+
if (structAnchor !== undefined) {
|
|
45
|
+
const r = structAnchor.range;
|
|
46
|
+
structTypedefRanges.add(`${r.startLine}:${r.startCol}:${r.endLine}:${r.endCol}`);
|
|
47
|
+
}
|
|
48
|
+
// Suppress @declaration.typedef if the same range was already captured as struct/union
|
|
49
|
+
const typedefAnchor = grouped['@declaration.typedef'];
|
|
50
|
+
if (typedefAnchor !== undefined) {
|
|
51
|
+
const r = typedefAnchor.range;
|
|
52
|
+
const key = `${r.startLine}:${r.startCol}:${r.endLine}:${r.endCol}`;
|
|
53
|
+
if (structTypedefRanges.has(key))
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
// Enrich function declarations with arity metadata and detect static linkage
|
|
57
|
+
const declAnchor = grouped['@declaration.function'];
|
|
58
|
+
if (declAnchor !== undefined) {
|
|
59
|
+
const fnNode = findNodeAtRange(tree.rootNode, declAnchor.range, 'function_definition') ??
|
|
60
|
+
findNodeAtRange(tree.rootNode, declAnchor.range, 'declaration');
|
|
61
|
+
if (fnNode !== null) {
|
|
62
|
+
const arity = computeCDeclarationArity(fnNode);
|
|
63
|
+
if (arity.parameterCount !== undefined) {
|
|
64
|
+
grouped['@declaration.parameter-count'] = syntheticCapture('@declaration.parameter-count', fnNode, String(arity.parameterCount));
|
|
65
|
+
}
|
|
66
|
+
if (arity.requiredParameterCount !== undefined) {
|
|
67
|
+
grouped['@declaration.required-parameter-count'] = syntheticCapture('@declaration.required-parameter-count', fnNode, String(arity.requiredParameterCount));
|
|
68
|
+
}
|
|
69
|
+
if (arity.parameterTypes !== undefined) {
|
|
70
|
+
grouped['@declaration.parameter-types'] = syntheticCapture('@declaration.parameter-types', fnNode, JSON.stringify(arity.parameterTypes));
|
|
71
|
+
}
|
|
72
|
+
// Detect static storage class (file-local linkage)
|
|
73
|
+
if (hasStaticStorageClass(fnNode)) {
|
|
74
|
+
const nameText = grouped['@declaration.name']?.text;
|
|
75
|
+
if (nameText !== undefined) {
|
|
76
|
+
markStaticName(filePath, nameText);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Enrich call references with arity
|
|
82
|
+
const callAnchor = grouped['@reference.call.free'] ?? grouped['@reference.call.member'];
|
|
83
|
+
if (callAnchor !== undefined && grouped['@reference.arity'] === undefined) {
|
|
84
|
+
const callNode = findNodeAtRange(tree.rootNode, callAnchor.range, 'call_expression');
|
|
85
|
+
if (callNode !== null) {
|
|
86
|
+
grouped['@reference.arity'] = syntheticCapture('@reference.arity', callNode, String(computeCCallArity(callNode)));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
out.push(grouped);
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check if a C function_definition or declaration has `static` storage class.
|
|
95
|
+
* Walks direct children for a `storage_class_specifier` node with text `static`.
|
|
96
|
+
*/
|
|
97
|
+
function hasStaticStorageClass(node) {
|
|
98
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
99
|
+
const child = node.child(i);
|
|
100
|
+
if (child !== null && child.type === 'storage_class_specifier' && child.text === 'static') {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walk `repoPath` recursively and return relative paths of all `.h` files.
|
|
3
|
+
* Used by `loadResolutionConfig` so the C resolver can resolve `#include`
|
|
4
|
+
* targets that live in `.h` files (classified as C++ by language detection
|
|
5
|
+
* but importable from `.c` files).
|
|
6
|
+
*/
|
|
7
|
+
export declare function scanHeaderFiles(repoPath: string): ReadonlySet<string>;
|