gitnexus 1.6.8-rc.8 → 1.6.8
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 +3 -3
- package/dist/_shared/graph/types.d.ts +31 -1
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/language-detection.d.ts.map +1 -1
- package/dist/_shared/language-detection.js +11 -1
- package/dist/_shared/language-detection.js.map +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
- package/dist/_shared/lbug/schema-constants.js +6 -0
- package/dist/_shared/lbug/schema-constants.js.map +1 -1
- package/dist/_shared/scope-resolution/parsed-file.d.ts +21 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/symbol-definition.d.ts +6 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
- package/dist/cli/ai-context.d.ts +31 -1
- package/dist/cli/ai-context.js +18 -16
- package/dist/cli/analyze-config.js +11 -0
- package/dist/cli/analyze.d.ts +14 -0
- package/dist/cli/analyze.js +98 -0
- package/dist/cli/embedding-dims.d.ts +33 -0
- package/dist/cli/embedding-dims.js +39 -0
- package/dist/cli/eval-server.d.ts +8 -0
- package/dist/cli/eval-server.js +242 -2
- package/dist/cli/help-i18n.js +19 -0
- package/dist/cli/i18n/en.d.ts +15 -1
- package/dist/cli/i18n/en.js +15 -1
- package/dist/cli/i18n/resources.d.ts +29 -1
- package/dist/cli/i18n/zh-CN.d.ts +14 -0
- package/dist/cli/i18n/zh-CN.js +15 -1
- package/dist/cli/index.js +89 -1
- package/dist/cli/mcp.d.ts +6 -1
- package/dist/cli/mcp.js +26 -1
- package/dist/cli/optional-grammars.d.ts +6 -8
- package/dist/cli/optional-grammars.js +8 -11
- package/dist/cli/setup.d.ts +3 -1
- package/dist/cli/setup.js +67 -17
- package/dist/cli/skill-gen.js +2 -1
- package/dist/cli/tool.d.ts +19 -1
- package/dist/cli/tool.js +96 -3
- package/dist/core/embeddings/hf-env.d.ts +0 -66
- package/dist/core/embeddings/http-client.d.ts +7 -0
- package/dist/core/embeddings/http-client.js +5 -3
- package/dist/core/embeddings/server-mapping.d.ts +1 -1
- package/dist/core/embeddings/server-mapping.js +7 -3
- package/dist/core/graph/import-cycles.d.ts +10 -0
- package/dist/core/graph/import-cycles.js +103 -0
- package/dist/core/group/cross-impact.d.ts +2 -1
- package/dist/core/group/cross-impact.js +5 -1
- package/dist/core/group/extractors/grpc-patterns/proto.js +10 -6
- package/dist/core/group/extractors/http-patterns/kotlin.js +7 -7
- package/dist/core/group/extractors/http-route-extractor.d.ts +24 -0
- package/dist/core/group/extractors/http-route-extractor.js +22 -4
- package/dist/core/group/extractors/include-extractor.js +22 -13
- package/dist/core/group/sync.d.ts +27 -1
- package/dist/core/group/sync.js +0 -0
- package/dist/core/incremental/subgraph-extract.js +18 -1
- package/dist/core/ingestion/cfg/cfg-builder.d.ts +114 -0
- package/dist/core/ingestion/cfg/cfg-builder.js +196 -0
- package/dist/core/ingestion/cfg/collect.d.ts +51 -0
- package/dist/core/ingestion/cfg/collect.js +77 -0
- package/dist/core/ingestion/cfg/control-dependence.d.ts +58 -0
- package/dist/core/ingestion/cfg/control-dependence.js +182 -0
- package/dist/core/ingestion/cfg/control-flow-context.d.ts +106 -0
- package/dist/core/ingestion/cfg/control-flow-context.js +124 -0
- package/dist/core/ingestion/cfg/emit.d.ts +293 -0
- package/dist/core/ingestion/cfg/emit.js +646 -0
- package/dist/core/ingestion/cfg/post-dominators.d.ts +79 -0
- package/dist/core/ingestion/cfg/post-dominators.js +176 -0
- package/dist/core/ingestion/cfg/reaching-def-reason-codec.d.ts +106 -0
- package/dist/core/ingestion/cfg/reaching-def-reason-codec.js +133 -0
- package/dist/core/ingestion/cfg/reaching-defs-graph.d.ts +18 -0
- package/dist/core/ingestion/cfg/reaching-defs-graph.js +312 -0
- package/dist/core/ingestion/cfg/reaching-defs.d.ts +162 -0
- package/dist/core/ingestion/cfg/reaching-defs.js +785 -0
- package/dist/core/ingestion/cfg/synthetic-escape.d.ts +124 -0
- package/dist/core/ingestion/cfg/synthetic-escape.js +300 -0
- package/dist/core/ingestion/cfg/traversal-result.d.ts +20 -0
- package/dist/core/ingestion/cfg/traversal-result.js +2 -0
- package/dist/core/ingestion/cfg/types.d.ts +274 -0
- package/dist/core/ingestion/cfg/types.js +13 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.d.ts +111 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.js +541 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp.d.ts +74 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp.js +584 -0
- package/dist/core/ingestion/cfg/visitors/call-site-harvest.d.ts +195 -0
- package/dist/core/ingestion/cfg/visitors/call-site-harvest.js +350 -0
- package/dist/core/ingestion/cfg/visitors/csharp-harvest.d.ts +124 -0
- package/dist/core/ingestion/cfg/visitors/csharp-harvest.js +589 -0
- package/dist/core/ingestion/cfg/visitors/csharp.d.ts +87 -0
- package/dist/core/ingestion/cfg/visitors/csharp.js +867 -0
- package/dist/core/ingestion/cfg/visitors/dart-harvest.d.ts +278 -0
- package/dist/core/ingestion/cfg/visitors/dart-harvest.js +870 -0
- package/dist/core/ingestion/cfg/visitors/dart.d.ts +119 -0
- package/dist/core/ingestion/cfg/visitors/dart.js +836 -0
- package/dist/core/ingestion/cfg/visitors/go-harvest.d.ts +160 -0
- package/dist/core/ingestion/cfg/visitors/go-harvest.js +621 -0
- package/dist/core/ingestion/cfg/visitors/go.d.ts +108 -0
- package/dist/core/ingestion/cfg/visitors/go.js +638 -0
- package/dist/core/ingestion/cfg/visitors/java-harvest.d.ts +108 -0
- package/dist/core/ingestion/cfg/visitors/java-harvest.js +513 -0
- package/dist/core/ingestion/cfg/visitors/java.d.ts +101 -0
- package/dist/core/ingestion/cfg/visitors/java.js +812 -0
- package/dist/core/ingestion/cfg/visitors/kotlin-harvest.d.ts +253 -0
- package/dist/core/ingestion/cfg/visitors/kotlin-harvest.js +719 -0
- package/dist/core/ingestion/cfg/visitors/kotlin.d.ts +121 -0
- package/dist/core/ingestion/cfg/visitors/kotlin.js +809 -0
- package/dist/core/ingestion/cfg/visitors/php-harvest.d.ts +172 -0
- package/dist/core/ingestion/cfg/visitors/php-harvest.js +626 -0
- package/dist/core/ingestion/cfg/visitors/php.d.ts +96 -0
- package/dist/core/ingestion/cfg/visitors/php.js +721 -0
- package/dist/core/ingestion/cfg/visitors/python-harvest.d.ts +212 -0
- package/dist/core/ingestion/cfg/visitors/python-harvest.js +739 -0
- package/dist/core/ingestion/cfg/visitors/python.d.ts +103 -0
- package/dist/core/ingestion/cfg/visitors/python.js +558 -0
- package/dist/core/ingestion/cfg/visitors/ruby-harvest.d.ts +223 -0
- package/dist/core/ingestion/cfg/visitors/ruby-harvest.js +587 -0
- package/dist/core/ingestion/cfg/visitors/ruby.d.ts +112 -0
- package/dist/core/ingestion/cfg/visitors/ruby.js +756 -0
- package/dist/core/ingestion/cfg/visitors/rust-harvest.d.ts +324 -0
- package/dist/core/ingestion/cfg/visitors/rust-harvest.js +873 -0
- package/dist/core/ingestion/cfg/visitors/rust.d.ts +95 -0
- package/dist/core/ingestion/cfg/visitors/rust.js +558 -0
- package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.d.ts +87 -0
- package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.js +116 -0
- package/dist/core/ingestion/cfg/visitors/swift-harvest.d.ts +255 -0
- package/dist/core/ingestion/cfg/visitors/swift-harvest.js +679 -0
- package/dist/core/ingestion/cfg/visitors/swift.d.ts +116 -0
- package/dist/core/ingestion/cfg/visitors/swift.js +787 -0
- package/dist/core/ingestion/cfg/visitors/typescript-harvest.d.ts +149 -0
- package/dist/core/ingestion/cfg/visitors/typescript-harvest.js +1056 -0
- package/dist/core/ingestion/cfg/visitors/typescript.d.ts +66 -0
- package/dist/core/ingestion/cfg/visitors/typescript.js +583 -0
- package/dist/core/ingestion/import-resolvers/utils.js +2 -0
- package/dist/core/ingestion/language-provider.d.ts +23 -2
- package/dist/core/ingestion/languages/c-cpp.js +17 -5
- package/dist/core/ingestion/languages/cobol.js +4 -0
- package/dist/core/ingestion/languages/cpp/arity-metadata.js +41 -2
- package/dist/core/ingestion/languages/cpp/captures.js +50 -1
- package/dist/core/ingestion/languages/cpp/conversion-rank.d.ts +2 -0
- package/dist/core/ingestion/languages/cpp/conversion-rank.js +89 -0
- package/dist/core/ingestion/languages/cpp/header-scan.d.ts +1 -1
- package/dist/core/ingestion/languages/cpp/header-scan.js +2 -2
- package/dist/core/ingestion/languages/cpp/inline-namespaces.js +7 -2
- package/dist/core/ingestion/languages/cpp/member-lookup.js +2 -1
- package/dist/core/ingestion/languages/cpp/query.js +23 -0
- package/dist/core/ingestion/languages/cpp/scope-resolver.js +2 -1
- package/dist/core/ingestion/languages/csharp.js +2 -0
- package/dist/core/ingestion/languages/dart.js +2 -0
- package/dist/core/ingestion/languages/go.js +2 -0
- package/dist/core/ingestion/languages/java.js +3 -0
- package/dist/core/ingestion/languages/kotlin/query.js +3 -2
- package/dist/core/ingestion/languages/kotlin.js +8 -1
- package/dist/core/ingestion/languages/php.js +2 -0
- package/dist/core/ingestion/languages/python.js +2 -0
- package/dist/core/ingestion/languages/ruby.js +2 -0
- package/dist/core/ingestion/languages/rust.js +2 -0
- package/dist/core/ingestion/languages/swift.js +2 -0
- package/dist/core/ingestion/languages/typescript.js +5 -0
- package/dist/core/ingestion/languages/vue.js +6 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.js +6 -13
- package/dist/core/ingestion/method-extractors/generic.js +1 -0
- package/dist/core/ingestion/method-types.d.ts +2 -0
- package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
- package/dist/core/ingestion/model/symbol-table.js +1 -0
- package/dist/core/ingestion/mro-processor.js +109 -0
- package/dist/core/ingestion/parsing-processor.js +44 -0
- package/dist/core/ingestion/pipeline-phases/call-summaries.d.ts +26 -0
- package/dist/core/ingestion/pipeline-phases/call-summaries.js +46 -0
- package/dist/core/ingestion/pipeline-phases/index.d.ts +2 -0
- package/dist/core/ingestion/pipeline-phases/index.js +2 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +0 -21
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +18 -1
- package/dist/core/ingestion/pipeline-phases/routes.d.ts +10 -0
- package/dist/core/ingestion/pipeline-phases/routes.js +30 -1
- package/dist/core/ingestion/pipeline-phases/taint-summaries.d.ts +30 -0
- package/dist/core/ingestion/pipeline-phases/taint-summaries.js +81 -0
- package/dist/core/ingestion/pipeline.d.ts +92 -10
- package/dist/core/ingestion/pipeline.js +11 -2
- package/dist/core/ingestion/scope-extractor.js +12 -2
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +9 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.d.ts +75 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +67 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +12 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +14 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +6 -1
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +13 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +9 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +28 -2
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +4 -0
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +9 -0
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +6 -1
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +174 -40
- package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +24 -0
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +276 -190
- package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +43 -3
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +75 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +349 -1
- package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
- package/dist/core/ingestion/taint/call-summary-codec.d.ts +75 -0
- package/dist/core/ingestion/taint/call-summary-codec.js +128 -0
- package/dist/core/ingestion/taint/call-summary-emit.d.ts +43 -0
- package/dist/core/ingestion/taint/call-summary-emit.js +70 -0
- package/dist/core/ingestion/taint/call-summary-harvest.d.ts +77 -0
- package/dist/core/ingestion/taint/call-summary-harvest.js +179 -0
- package/dist/core/ingestion/taint/call-summary-model.d.ts +47 -0
- package/dist/core/ingestion/taint/call-summary-model.js +25 -0
- package/dist/core/ingestion/taint/emit.d.ts +125 -0
- package/dist/core/ingestion/taint/emit.js +208 -0
- package/dist/core/ingestion/taint/interproc-emit.d.ts +50 -0
- package/dist/core/ingestion/taint/interproc-emit.js +88 -0
- package/dist/core/ingestion/taint/interproc-solver.d.ts +110 -0
- package/dist/core/ingestion/taint/interproc-solver.js +312 -0
- package/dist/core/ingestion/taint/match.d.ts +153 -0
- package/dist/core/ingestion/taint/match.js +278 -0
- package/dist/core/ingestion/taint/path-codec.d.ts +134 -0
- package/dist/core/ingestion/taint/path-codec.js +190 -0
- package/dist/core/ingestion/taint/propagate.d.ts +216 -0
- package/dist/core/ingestion/taint/propagate.js +659 -0
- package/dist/core/ingestion/taint/site-safety.d.ts +29 -0
- package/dist/core/ingestion/taint/site-safety.js +98 -0
- package/dist/core/ingestion/taint/source-sink-config.d.ts +107 -23
- package/dist/core/ingestion/taint/source-sink-config.js +35 -12
- package/dist/core/ingestion/taint/source-sink-registry.d.ts +6 -4
- package/dist/core/ingestion/taint/source-sink-registry.js +6 -4
- package/dist/core/ingestion/taint/summary-harvest-driver.d.ts +80 -0
- package/dist/core/ingestion/taint/summary-harvest-driver.js +179 -0
- package/dist/core/ingestion/taint/summary-harvest.d.ts +89 -0
- package/dist/core/ingestion/taint/summary-harvest.js +537 -0
- package/dist/core/ingestion/taint/summary-model.d.ts +200 -0
- package/dist/core/ingestion/taint/summary-model.js +86 -0
- package/dist/core/ingestion/taint/typescript-model.d.ts +38 -0
- package/dist/core/ingestion/taint/typescript-model.js +102 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +21 -0
- package/dist/core/ingestion/utils/env.d.ts +7 -0
- package/dist/core/ingestion/utils/env.js +12 -0
- package/dist/core/ingestion/utils/method-props.js +1 -0
- package/dist/core/ingestion/workers/clone-safety.d.ts +109 -0
- package/dist/core/ingestion/workers/clone-safety.js +465 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +23 -0
- package/dist/core/ingestion/workers/parse-worker.js +81 -53
- package/dist/core/ingestion/workers/post-result.d.ts +22 -0
- package/dist/core/ingestion/workers/post-result.js +87 -0
- package/dist/core/ingestion/workers/result-merge.d.ts +20 -0
- package/dist/core/ingestion/workers/result-merge.js +43 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +15 -40
- package/dist/core/ingestion/workers/worker-pool.js +43 -16
- package/dist/core/lbug/csv-generator.d.ts +51 -3
- package/dist/core/lbug/csv-generator.js +369 -255
- package/dist/core/lbug/lbug-adapter.d.ts +58 -18
- package/dist/core/lbug/lbug-adapter.js +346 -84
- package/dist/core/lbug/lbug-config.d.ts +19 -0
- package/dist/core/lbug/lbug-config.js +29 -0
- package/dist/core/lbug/pdg-emit-sink.d.ts +127 -0
- package/dist/core/lbug/pdg-emit-sink.js +358 -0
- package/dist/core/lbug/pool-adapter.d.ts +35 -0
- package/dist/core/lbug/pool-adapter.js +90 -1
- package/dist/core/lbug/rel-pair-routing.d.ts +54 -0
- package/dist/core/lbug/rel-pair-routing.js +140 -0
- package/dist/core/lbug/schema.d.ts +2 -2
- package/dist/core/lbug/schema.js +3 -0
- package/dist/core/logger.d.ts +0 -5
- package/dist/core/run-analyze.d.ts +96 -0
- package/dist/core/run-analyze.js +207 -3
- package/dist/core/tree-sitter/parser-loader.js +5 -4
- package/dist/core/tree-sitter/safe-parse.d.ts +0 -5
- package/dist/core/tree-sitter/vendored-grammars.d.ts +39 -0
- package/dist/core/tree-sitter/vendored-grammars.js +57 -0
- package/dist/core/wiki/generator.js +3 -1
- package/dist/core/wiki/graph-queries.d.ts +6 -0
- package/dist/core/wiki/graph-queries.js +9 -1
- package/dist/mcp/http-transport.d.ts +134 -0
- package/dist/mcp/http-transport.js +503 -0
- package/dist/mcp/local/local-backend.d.ts +110 -24
- package/dist/mcp/local/local-backend.js +1225 -19
- package/dist/mcp/local/pdg-impact.d.ts +384 -0
- package/dist/mcp/local/pdg-impact.js +1972 -0
- package/dist/mcp/resources.js +13 -1
- package/dist/mcp/tools.d.ts +12 -0
- package/dist/mcp/tools.js +214 -7
- package/dist/server/analyze-launch.d.ts +29 -0
- package/dist/server/analyze-launch.js +137 -0
- package/dist/server/analyze-upload.d.ts +33 -0
- package/dist/server/analyze-upload.js +123 -0
- package/dist/server/analyze-worker-ipc.d.ts +58 -0
- package/dist/server/analyze-worker-ipc.js +16 -0
- package/dist/server/analyze-worker.d.ts +17 -1
- package/dist/server/analyze-worker.js +7 -1
- package/dist/server/api.d.ts +17 -0
- package/dist/server/api.js +132 -168
- package/dist/server/git-clone.d.ts +43 -2
- package/dist/server/git-clone.js +211 -16
- package/dist/server/mcp-http.d.ts +5 -6
- package/dist/server/mcp-http.js +9 -82
- package/dist/server/middleware.d.ts +40 -0
- package/dist/server/middleware.js +92 -0
- package/dist/server/private-ip.d.ts +1 -0
- package/dist/server/private-ip.js +15 -0
- package/dist/server/upload-ingest.d.ts +56 -0
- package/dist/server/upload-ingest.js +276 -0
- package/dist/server/upload-paths.d.ts +37 -0
- package/dist/server/upload-paths.js +57 -0
- package/dist/server/upload-sweep.d.ts +20 -0
- package/dist/server/upload-sweep.js +57 -0
- package/dist/storage/git.js +5 -8
- package/dist/storage/parse-cache.d.ts +22 -1
- package/dist/storage/parse-cache.js +44 -10
- package/dist/storage/repo-manager.d.ts +121 -10
- package/dist/storage/repo-manager.js +43 -5
- package/dist/types/pipeline.d.ts +9 -0
- package/hooks/antigravity/gitnexus-antigravity-hook.cjs +110 -10
- package/hooks/claude/gitnexus-hook.cjs +110 -13
- package/hooks/claude/hook-db-lock-probe.cjs +513 -26
- package/package.json +8 -2
- package/scripts/assert-publish-grammar-coverage.cjs +31 -0
- package/scripts/build-tree-sitter-grammars.cjs +16 -10
- package/scripts/cross-platform-tests.ts +1 -0
- package/skills/gitnexus-debugging.md +16 -4
- package/skills/gitnexus-exploring.md +3 -3
- package/skills/gitnexus-guide.md +33 -0
- package/skills/gitnexus-pdg-query.md +89 -0
- package/skills/gitnexus-refactoring.md +1 -1
- package/skills/gitnexus-taint-analysis.md +178 -0
- package/vendor/tree-sitter-c/package.json +1 -1
- package/vendor/tree-sitter-dart/package.json +1 -1
- package/vendor/tree-sitter-kotlin/package.json +1 -1
- package/vendor/tree-sitter-proto/package.json +1 -1
- package/vendor/tree-sitter-swift/package.json +1 -1
- package/web/assets/{agent-CKPMqImC.js → agent-D3Xd7zZE.js} +123 -123
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +1 -0
- package/web/assets/architectureDiagram-UL44E2DR-ChH9xW-N.js +36 -0
- package/web/assets/{blockDiagram-7IZFK4PR-B4niSLvR.js → blockDiagram-7IZFK4PR-BkWhpzWB.js} +1 -1
- package/web/assets/{c4Diagram-Y2BXMSZH-DIzEXalR.js → c4Diagram-Y2BXMSZH-DtBvpzWD.js} +1 -1
- package/web/assets/{chunk-3SSMPTDK-BzGeeheI.js → chunk-3SSMPTDK-B4_etUhr.js} +2 -2
- package/web/assets/{chunk-5IMINLNL-CnTLsXIV.js → chunk-5IMINLNL-DOdTeQri.js} +1 -1
- package/web/assets/{chunk-5VCL7Z4A-w1BCx98Z.js → chunk-5VCL7Z4A-CQ-2dYWj.js} +1 -1
- package/web/assets/chunk-6764PJDD-DpIS7hxD.js +1 -0
- package/web/assets/{chunk-67TQ5CYL-CChC2cAv.js → chunk-67TQ5CYL-4sNPJU1q.js} +3 -3
- package/web/assets/{chunk-7W6UQGC5-CgFyfZ6k.js → chunk-7W6UQGC5-KyEG0HQg.js} +1 -1
- package/web/assets/{chunk-AZZRMDJM-5E9ARdDQ.js → chunk-AZZRMDJM-y-xJBuMz.js} +1 -1
- package/web/assets/{chunk-INKRHTLW-ELpfuk9h.js → chunk-INKRHTLW-Nu4ri9P-.js} +1 -1
- package/web/assets/{chunk-JQRUD6KW-Dcq_Qnyy.js → chunk-JQRUD6KW-Dbva2Z17.js} +1 -1
- package/web/assets/{chunk-KGFNY3KK-W-VR57xb.js → chunk-KGFNY3KK-JGMJvKCK.js} +1 -1
- package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +161 -0
- package/web/assets/{chunk-KNLZD3CH-BuZBOcso.js → chunk-KNLZD3CH-BGlP6X9R.js} +1 -1
- package/web/assets/{chunk-KRXBNO2N-DH2NPM7I.js → chunk-KRXBNO2N-BW5o0KUN.js} +1 -1
- package/web/assets/{chunk-LCXTWHL2-Dfmux4m1.js → chunk-LCXTWHL2-zoomRtWX.js} +1 -1
- package/web/assets/{chunk-LII3EMHJ-3X33tCpU.js → chunk-LII3EMHJ-D-jm-dLa.js} +1 -1
- package/web/assets/{chunk-QA3QBVWF-D5Ha3GgB.js → chunk-QA3QBVWF-BgRW3SXd.js} +1 -1
- package/web/assets/{chunk-RG4AUYOV-CAkzcoRj.js → chunk-RG4AUYOV-DD0B2N2B.js} +1 -1
- package/web/assets/{chunk-T2UQINTJ-kGYG7ppP.js → chunk-T2UQINTJ-DSBqkzH7.js} +1 -1
- package/web/assets/chunk-T5OCTHI4-DdZvN-9i.js +1 -0
- package/web/assets/{chunk-UY5QBCOK-Du-c56gs.js → chunk-UY5QBCOK-DyF0vyGd.js} +1 -1
- package/web/assets/{chunk-W44A43WB-lrCpuupA.js → chunk-W44A43WB-JqMLIpR0.js} +1 -1
- package/web/assets/{chunk-ZXARS5L4-CSZRiyOf.js → chunk-ZXARS5L4-CxN8oiwI.js} +1 -1
- package/web/assets/classDiagram-KGZ6W3CR-DJm9BgF-.js +1 -0
- package/web/assets/classDiagram-v2-72OJOZXJ-DJm9BgF-.js +1 -0
- package/web/assets/{context-builder-_HS0v2ma.js → context-builder-BHiFUA8O.js} +10 -2
- package/web/assets/{cose-bilkent-UX7MHV2Q-BHv2bbtl.js → cose-bilkent-UX7MHV2Q-D71wNYRJ.js} +1 -1
- package/web/assets/dagre-ND4H6XIP-BIkxmhcu.js +4 -0
- package/web/assets/diagram-3NCE3AQN-BTa6iH0T.js +43 -0
- package/web/assets/diagram-GF46GFSD-DZDV0vBj.js +24 -0
- package/web/assets/{diagram-HNR7UZ2L-fUWreZzx.js → diagram-HNR7UZ2L-DFCfd5LI.js} +2 -2
- package/web/assets/diagram-QXG6HAR7-BzM--Jj0.js +24 -0
- package/web/assets/diagram-WEQXMOUZ-DFFwz0k4.js +10 -0
- package/web/assets/{erDiagram-L5TCEMPS-QN2eEP1e.js → erDiagram-L5TCEMPS-CfHMJJqo.js} +1 -1
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +1 -0
- package/web/assets/{flowDiagram-H6V6AXG4-CXbXImlN.js → flowDiagram-H6V6AXG4-Be805QiJ.js} +3 -3
- package/web/assets/{ganttDiagram-JCBTUEKG-BHQssTz6.js → ganttDiagram-JCBTUEKG-D3iL2Aet.js} +1 -1
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +1 -0
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +106 -0
- package/web/assets/index-BvYev1UJ.js +635 -0
- package/web/assets/index-_lgn7hs5.css +2 -0
- package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +1 -0
- package/web/assets/infoDiagram-3YFTVSEB-Y7BKSoke.js +2 -0
- package/web/assets/{ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js → ishikawaDiagram-BNXS4ZKH-CT4SHFuI.js} +1 -1
- package/web/assets/{journeyDiagram-M6C3CM3L-DNPYCpvq.js → journeyDiagram-M6C3CM3L-CvArszLo.js} +1 -1
- package/web/assets/{kanban-definition-75IXJCU3-DgDi9oJT.js → kanban-definition-75IXJCU3-C6yDxr7N.js} +3 -3
- package/web/assets/{katex-K3KEBU37-CrVLz8l7.js → katex-K3KEBU37-CTc5BslQ.js} +1 -1
- package/web/assets/{mindmap-definition-2TDM6QVE-CwR5sBB-.js → mindmap-definition-2TDM6QVE-BOc2WEne.js} +1 -1
- package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +1 -0
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +1 -0
- package/web/assets/{pieDiagram-CU6KROY3-By8g6f6B.js → pieDiagram-CU6KROY3-Cvc0f_Pd.js} +1 -1
- package/web/assets/{quadrantDiagram-VICAPDV7-bAm6Hi_5.js → quadrantDiagram-VICAPDV7-yXSZ2lLz.js} +1 -1
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +1 -0
- package/web/assets/{requirementDiagram-JXO7QTGE-7oDcJ1_J.js → requirementDiagram-JXO7QTGE-BRcZvHs4.js} +1 -1
- package/web/assets/{sankeyDiagram-URQDO5SZ-LFJz53u5.js → sankeyDiagram-URQDO5SZ-1qEjlFIB.js} +1 -1
- package/web/assets/{sequenceDiagram-VS2MUI6T-FySeKCUy.js → sequenceDiagram-VS2MUI6T-PcSCuvrB.js} +3 -3
- package/web/assets/stateDiagram-7D4R322I-D6qYSV1E.js +1 -0
- package/web/assets/stateDiagram-v2-36443NZ5-Bg-ImOSX.js +1 -0
- package/web/assets/{timeline-definition-O6YCAMPW-Ds2CnVZK.js → timeline-definition-O6YCAMPW-QWkh01xw.js} +1 -1
- package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +1 -0
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +1 -0
- package/web/assets/{vennDiagram-MWXL3ELB-DUIEwXWp.js → vennDiagram-MWXL3ELB-ak4DfwuM.js} +3 -3
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +1 -0
- package/web/assets/{wardleyDiagram-CUQ6CDDI-DEiFPQih.js → wardleyDiagram-CUQ6CDDI-CTzR4Loq.js} +1 -1
- package/web/assets/{xychartDiagram-N2JHSOCM-BUbayhST.js → xychartDiagram-N2JHSOCM-DA1BEaQz.js} +1 -1
- package/web/index.html +13 -15
- package/scripts/materialize-vendor-grammars.cjs +0 -97
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +0 -1
- package/web/assets/architectureDiagram-UL44E2DR-D1EXI0zA.js +0 -36
- package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +0 -4
- package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +0 -1
- package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +0 -159
- package/web/assets/chunk-6764PJDD-ChwMM2z4.js +0 -1
- package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +0 -10
- package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +0 -1
- package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +0 -1
- package/web/assets/chunk-CilyBKbf.js +0 -1
- package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +0 -1
- package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +0 -1
- package/web/assets/chunk-RERM46MO-DQNbXtfw.js +0 -1
- package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +0 -1
- package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +0 -1
- package/web/assets/chunk-T5OCTHI4--9wWpVws.js +0 -1
- package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +0 -1
- package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +0 -1
- package/web/assets/classDiagram-KGZ6W3CR-Bv93af_b.js +0 -1
- package/web/assets/classDiagram-v2-72OJOZXJ-CLfEqHUa.js +0 -1
- package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +0 -4
- package/web/assets/diagram-3NCE3AQN-BqAtKUpW.js +0 -43
- package/web/assets/diagram-GF46GFSD-CaBG6n6o.js +0 -24
- package/web/assets/diagram-QXG6HAR7-CZ-O3rcV.js +0 -24
- package/web/assets/diagram-WEQXMOUZ-P4lSL4GH.js +0 -10
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +0 -1
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +0 -1
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +0 -106
- package/web/assets/index-BKWA-m7o.css +0 -2
- package/web/assets/index-CG6q8eTs.js +0 -626
- package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +0 -1
- package/web/assets/infoDiagram-3YFTVSEB-DmLICZx1.js +0 -2
- package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +0 -1
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +0 -1
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +0 -1
- package/web/assets/stateDiagram-7D4R322I-CB2nABwH.js +0 -1
- package/web/assets/stateDiagram-v2-36443NZ5-COBGd2RL.js +0 -1
- package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +0 -1
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +0 -1
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +0 -1
- /package/web/assets/{chunk-AQ6EADP3-CCFje6lL.js → chunk-AQ6EADP3-CZhslHi-.js} +0 -0
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
import { CallSiteFactAccumulator as FactAccumulator } from './call-site-harvest.js';
|
|
2
|
+
/** Node types that own a nested CFG — their subtrees are opaque to harvesting. */
|
|
3
|
+
const NESTED_FUNCTION_TYPES = new Set([
|
|
4
|
+
'method',
|
|
5
|
+
'singleton_method',
|
|
6
|
+
'do_block',
|
|
7
|
+
'block',
|
|
8
|
+
'lambda',
|
|
9
|
+
]);
|
|
10
|
+
/** Parameter container node types (method + block + lambda). */
|
|
11
|
+
const PARAM_CONTAINER_TYPES = new Set([
|
|
12
|
+
'method_parameters',
|
|
13
|
+
'block_parameters',
|
|
14
|
+
'lambda_parameters',
|
|
15
|
+
]);
|
|
16
|
+
/** Parameter leaf node types whose `name` field (or bare identifier) is the binder. */
|
|
17
|
+
const NAMED_PARAM_TYPES = new Set([
|
|
18
|
+
'optional_parameter',
|
|
19
|
+
'splat_parameter',
|
|
20
|
+
'hash_splat_parameter',
|
|
21
|
+
'block_parameter',
|
|
22
|
+
'keyword_parameter',
|
|
23
|
+
]);
|
|
24
|
+
export class RubyHarvester {
|
|
25
|
+
fnNode;
|
|
26
|
+
bindings = [];
|
|
27
|
+
/** Single function-scope name → binding index (documented over-approximation). */
|
|
28
|
+
table = new Map();
|
|
29
|
+
synthetic = new Map();
|
|
30
|
+
fnId;
|
|
31
|
+
/** >0 while walking a conditionally-evaluated subexpression — defs become may-defs. */
|
|
32
|
+
conditionalDepth = 0;
|
|
33
|
+
/**
|
|
34
|
+
* `call` node id → binding indices its single-target result is assigned to
|
|
35
|
+
* (`x = f()` ⇒ `[x]`). Populated just before the value walk reaches the call
|
|
36
|
+
* (see {@link registerResultDefs}) and consumed by {@link visitCall}. Mirrors
|
|
37
|
+
* the Python / Kotlin / Go harvesters' `resultDefTargets`.
|
|
38
|
+
*/
|
|
39
|
+
resultDefTargets = new Map();
|
|
40
|
+
constructor(fnNode) {
|
|
41
|
+
this.fnNode = fnNode;
|
|
42
|
+
this.fnId = fnNode.id;
|
|
43
|
+
this.declareParams(fnNode);
|
|
44
|
+
const body = this.bodyOf(fnNode);
|
|
45
|
+
if (body)
|
|
46
|
+
this.prescan(body);
|
|
47
|
+
}
|
|
48
|
+
/** The completed binding table — pass to `CfgBuilder.finish`. */
|
|
49
|
+
bindingTable() {
|
|
50
|
+
return this.bindings;
|
|
51
|
+
}
|
|
52
|
+
/** The function/block/lambda body node. */
|
|
53
|
+
bodyOf(fnNode) {
|
|
54
|
+
return fnNode.childForFieldName('body') ?? undefined;
|
|
55
|
+
}
|
|
56
|
+
// ── phase 1: declaration pre-scan ────────────────────────────────────────
|
|
57
|
+
declare(nameNode, kind) {
|
|
58
|
+
const name = nameNode.text;
|
|
59
|
+
if (!name || name === '_' || this.table.has(name))
|
|
60
|
+
return;
|
|
61
|
+
this.table.set(name, this.bindings.length);
|
|
62
|
+
this.bindings.push({
|
|
63
|
+
name,
|
|
64
|
+
declLine: nameNode.startPosition.row + 1,
|
|
65
|
+
declColumn: nameNode.startPosition.column,
|
|
66
|
+
kind,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/** Declare every parameter binder (method / block / lambda). */
|
|
70
|
+
declareParams(fnNode) {
|
|
71
|
+
const params = this.paramsOf(fnNode);
|
|
72
|
+
if (!params)
|
|
73
|
+
return;
|
|
74
|
+
for (let i = 0; i < params.namedChildCount; i++) {
|
|
75
|
+
const p = params.namedChild(i);
|
|
76
|
+
if (p)
|
|
77
|
+
this.declareParam(p);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** The `parameters` field (or first parameter-container child) of a function node. */
|
|
81
|
+
paramsOf(fnNode) {
|
|
82
|
+
const field = fnNode.childForFieldName('parameters');
|
|
83
|
+
if (field)
|
|
84
|
+
return field;
|
|
85
|
+
return fnNode.namedChildren.find((c) => PARAM_CONTAINER_TYPES.has(c.type));
|
|
86
|
+
}
|
|
87
|
+
/** Declare the binder identifier of one parameter node. */
|
|
88
|
+
declareParam(p) {
|
|
89
|
+
if (p.type === 'identifier') {
|
|
90
|
+
this.declare(p, 'param');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (NAMED_PARAM_TYPES.has(p.type)) {
|
|
94
|
+
const name = p.childForFieldName('name') ?? p.namedChildren.find((c) => c.type === 'identifier');
|
|
95
|
+
if (name)
|
|
96
|
+
this.declare(name, 'param');
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// Destructured / grouped block param — declare any identifier leaves.
|
|
100
|
+
for (let i = 0; i < p.namedChildCount; i++) {
|
|
101
|
+
const c = p.namedChild(i);
|
|
102
|
+
if (c?.type === 'identifier')
|
|
103
|
+
this.declare(c, 'param');
|
|
104
|
+
else if (c)
|
|
105
|
+
this.declareParam(c);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Pre-scan the function body once, declaring every in-function local name.
|
|
110
|
+
* Recurses into compound statements but NOT into nested function/block/lambda
|
|
111
|
+
* bodies (opaque).
|
|
112
|
+
*/
|
|
113
|
+
prescan(node) {
|
|
114
|
+
const t = node.type;
|
|
115
|
+
if (NESTED_FUNCTION_TYPES.has(t) && node.id !== this.fnId)
|
|
116
|
+
return;
|
|
117
|
+
switch (t) {
|
|
118
|
+
case 'assignment': {
|
|
119
|
+
const left = node.childForFieldName('left');
|
|
120
|
+
if (left)
|
|
121
|
+
this.declareTargets(left);
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
case 'operator_assignment': {
|
|
125
|
+
const left = node.childForFieldName('left');
|
|
126
|
+
if (left)
|
|
127
|
+
this.declareTargets(left);
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
case 'for': {
|
|
131
|
+
const pattern = node.childForFieldName('pattern');
|
|
132
|
+
if (pattern)
|
|
133
|
+
this.declareTargets(pattern);
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case 'rescue': {
|
|
137
|
+
this.declareRescueVar(node);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
default:
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
// A nested `do_block`/`block`/`lambda` body is opaque, but its OWN block
|
|
144
|
+
// parameters are declared (they are not local to THIS function, yet the
|
|
145
|
+
// single-table model harvests them where used) — handled by declareParam in
|
|
146
|
+
// the visitor's per-block harvester instance, not here. We only recurse to
|
|
147
|
+
// collect assignment/for/rescue local targets in THIS function body.
|
|
148
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
149
|
+
const c = node.namedChild(i);
|
|
150
|
+
if (c)
|
|
151
|
+
this.prescan(c);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/** `rescue [Exc] => e` — declare `e` (a `catch`-kind def). */
|
|
155
|
+
declareRescueVar(clause) {
|
|
156
|
+
const variable = clause.childForFieldName('variable');
|
|
157
|
+
const id = variable?.namedChildren.find((c) => c.type === 'identifier') ?? variable;
|
|
158
|
+
if (id?.type === 'identifier')
|
|
159
|
+
this.declare(id, 'catch');
|
|
160
|
+
}
|
|
161
|
+
/** Declare identifier leaves of an assignment / loop target (skip non-local LHS). */
|
|
162
|
+
declareTargets(target) {
|
|
163
|
+
const t = target.type;
|
|
164
|
+
if (t === 'identifier') {
|
|
165
|
+
this.declare(target, 'let');
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (t === 'left_assignment_list') {
|
|
169
|
+
for (let i = 0; i < target.namedChildCount; i++) {
|
|
170
|
+
const c = target.namedChild(i);
|
|
171
|
+
if (c)
|
|
172
|
+
this.declareTargets(c);
|
|
173
|
+
}
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (t === 'splat_parameter' || t === 'rest_assignment') {
|
|
177
|
+
const id = target.namedChildren.find((c) => c.type === 'identifier');
|
|
178
|
+
if (id)
|
|
179
|
+
this.declare(id, 'let');
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
// instance/class/global var, constant, element/attribute target — not a
|
|
183
|
+
// function-scoped scalar def (the root identifier is a use only).
|
|
184
|
+
}
|
|
185
|
+
// ── phase 2: per-statement fact extraction ───────────────────────────────
|
|
186
|
+
/** Def/use facts for one statement (or construct-header expression) node. */
|
|
187
|
+
facts(node) {
|
|
188
|
+
const acc = new FactAccumulator(node.startPosition.row + 1);
|
|
189
|
+
this.walkValue(node, acc);
|
|
190
|
+
return acc.finish();
|
|
191
|
+
}
|
|
192
|
+
/** Facts for an expression whose WHOLE evaluation is conditional (case tests). */
|
|
193
|
+
factsConditional(node) {
|
|
194
|
+
const acc = new FactAccumulator(node.startPosition.row + 1);
|
|
195
|
+
this.conditional(() => this.walkValue(node, acc));
|
|
196
|
+
return acc.finish();
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Facts for a `for PATTERN in VALUE` head: the loop target(s) are defs, the
|
|
200
|
+
* iterated expression is a use.
|
|
201
|
+
*/
|
|
202
|
+
loopHeadFacts(forNode) {
|
|
203
|
+
const acc = new FactAccumulator(forNode.startPosition.row + 1);
|
|
204
|
+
const pattern = forNode.childForFieldName('pattern');
|
|
205
|
+
const value = forNode.childForFieldName('value');
|
|
206
|
+
if (value)
|
|
207
|
+
this.walkValue(value, acc);
|
|
208
|
+
if (pattern)
|
|
209
|
+
this.defTargets(pattern, acc);
|
|
210
|
+
return acc.finish();
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Def-ONLY facts for a value-position assignment (`x = if … / case …`, #2205):
|
|
214
|
+
* just the LHS target(s), attached to the continuation block the branch arms
|
|
215
|
+
* rejoin. The branch condition + arm-value USES are harvested onto the branch's
|
|
216
|
+
* own blocks (visitIf / visitCase), so this must not re-walk the RHS.
|
|
217
|
+
*/
|
|
218
|
+
assignmentDefFacts(stmt) {
|
|
219
|
+
const acc = new FactAccumulator(stmt.startPosition.row + 1);
|
|
220
|
+
const left = stmt.childForFieldName('left');
|
|
221
|
+
if (left)
|
|
222
|
+
this.defTargets(left, acc);
|
|
223
|
+
return acc.defCount() ? acc.finish() : undefined;
|
|
224
|
+
}
|
|
225
|
+
/** Facts for a `rescue [Exc] => e` header: `e` is a def, the exception list a use. */
|
|
226
|
+
rescueHeadFacts(clause) {
|
|
227
|
+
const acc = new FactAccumulator(clause.startPosition.row + 1);
|
|
228
|
+
const exceptions = clause.childForFieldName('exceptions');
|
|
229
|
+
if (exceptions)
|
|
230
|
+
this.walkValue(exceptions, acc);
|
|
231
|
+
const variable = clause.childForFieldName('variable');
|
|
232
|
+
const id = variable?.namedChildren.find((c) => c.type === 'identifier');
|
|
233
|
+
if (id)
|
|
234
|
+
this.def(id, acc);
|
|
235
|
+
return acc.finish();
|
|
236
|
+
}
|
|
237
|
+
/** ENTRY-block facts for the parameters (defs only — incl. default-value uses). */
|
|
238
|
+
paramFacts() {
|
|
239
|
+
const params = this.paramsOf(this.fnNode);
|
|
240
|
+
if (!params)
|
|
241
|
+
return undefined;
|
|
242
|
+
const acc = new FactAccumulator(this.fnNode.startPosition.row + 1);
|
|
243
|
+
for (let i = 0; i < params.namedChildCount; i++) {
|
|
244
|
+
const p = params.namedChild(i);
|
|
245
|
+
if (p)
|
|
246
|
+
this.defParam(p, acc);
|
|
247
|
+
}
|
|
248
|
+
return acc.defCount() || acc.useCount() ? acc.finish() : undefined;
|
|
249
|
+
}
|
|
250
|
+
/** Def the binder of one parameter node and use any default-value expr. */
|
|
251
|
+
defParam(p, acc) {
|
|
252
|
+
if (p.type === 'identifier') {
|
|
253
|
+
this.def(p, acc);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (p.type === 'optional_parameter' || p.type === 'keyword_parameter') {
|
|
257
|
+
const value = p.childForFieldName('value');
|
|
258
|
+
if (value)
|
|
259
|
+
this.walkValue(value, acc);
|
|
260
|
+
const name = p.childForFieldName('name');
|
|
261
|
+
if (name)
|
|
262
|
+
this.def(name, acc);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (NAMED_PARAM_TYPES.has(p.type)) {
|
|
266
|
+
const name = p.childForFieldName('name') ?? p.namedChildren.find((c) => c.type === 'identifier');
|
|
267
|
+
if (name)
|
|
268
|
+
this.def(name, acc);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
for (let i = 0; i < p.namedChildCount; i++) {
|
|
272
|
+
const c = p.namedChild(i);
|
|
273
|
+
if (c?.type === 'identifier')
|
|
274
|
+
this.def(c, acc);
|
|
275
|
+
else if (c)
|
|
276
|
+
this.defParam(c, acc);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
resolve(nameNode) {
|
|
280
|
+
const name = nameNode.text;
|
|
281
|
+
const idx = this.table.get(name);
|
|
282
|
+
if (idx !== undefined)
|
|
283
|
+
return idx;
|
|
284
|
+
let s = this.synthetic.get(name);
|
|
285
|
+
if (s === undefined) {
|
|
286
|
+
s = this.bindings.length;
|
|
287
|
+
this.synthetic.set(name, s);
|
|
288
|
+
this.bindings.push({ name, declLine: 0, declColumn: 0, kind: 'module', synthetic: true });
|
|
289
|
+
}
|
|
290
|
+
return s;
|
|
291
|
+
}
|
|
292
|
+
def(nameNode, acc) {
|
|
293
|
+
if (nameNode.text === '_')
|
|
294
|
+
return;
|
|
295
|
+
if (this.conditionalDepth > 0)
|
|
296
|
+
acc.addMayDef(this.resolve(nameNode));
|
|
297
|
+
else
|
|
298
|
+
acc.addDef(this.resolve(nameNode));
|
|
299
|
+
}
|
|
300
|
+
use(nameNode, acc) {
|
|
301
|
+
if (nameNode.text === '_')
|
|
302
|
+
return;
|
|
303
|
+
// Resolve only known LOCAL names; an unknown bare identifier is a method
|
|
304
|
+
// call (resolves to a `module` synthetic — never a false local).
|
|
305
|
+
acc.addUse(this.resolve(nameNode));
|
|
306
|
+
}
|
|
307
|
+
/** Run `fn` with defs demoted to may-defs (conditionally-evaluated context). */
|
|
308
|
+
conditional(fn) {
|
|
309
|
+
this.conditionalDepth++;
|
|
310
|
+
try {
|
|
311
|
+
fn();
|
|
312
|
+
}
|
|
313
|
+
finally {
|
|
314
|
+
this.conditionalDepth--;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Def each identifier leaf of an assignment / loop target; route non-local
|
|
319
|
+
* targets (`@x`, index/attribute writes) to the value walk (root is a use).
|
|
320
|
+
*/
|
|
321
|
+
defTargets(target, acc) {
|
|
322
|
+
const t = target.type;
|
|
323
|
+
if (t === 'identifier') {
|
|
324
|
+
this.def(target, acc);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (t === 'left_assignment_list') {
|
|
328
|
+
for (let i = 0; i < target.namedChildCount; i++) {
|
|
329
|
+
const c = target.namedChild(i);
|
|
330
|
+
if (c)
|
|
331
|
+
this.defTargets(c, acc);
|
|
332
|
+
}
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
if (t === 'splat_parameter' || t === 'rest_assignment') {
|
|
336
|
+
const id = target.namedChildren.find((c) => c.type === 'identifier');
|
|
337
|
+
if (id)
|
|
338
|
+
this.def(id, acc);
|
|
339
|
+
else
|
|
340
|
+
this.walkValue(target, acc);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
// instance/class/global var, constant, element/attribute target — uses only.
|
|
344
|
+
this.walkValue(target, acc);
|
|
345
|
+
}
|
|
346
|
+
/** Value-position walk: collect uses; route def positions to the target handler. */
|
|
347
|
+
walkValue(node, acc) {
|
|
348
|
+
const t = node.type;
|
|
349
|
+
if (NESTED_FUNCTION_TYPES.has(t) && node.id !== this.fnId)
|
|
350
|
+
return; // opaque
|
|
351
|
+
switch (t) {
|
|
352
|
+
case 'identifier':
|
|
353
|
+
this.use(node, acc);
|
|
354
|
+
return;
|
|
355
|
+
// Non-local variables and constants — recorded as neither a scalar def nor
|
|
356
|
+
// a local use (they are not function-scoped locals); nothing to add.
|
|
357
|
+
case 'instance_variable':
|
|
358
|
+
case 'class_variable':
|
|
359
|
+
case 'global_variable':
|
|
360
|
+
case 'constant':
|
|
361
|
+
case 'self':
|
|
362
|
+
return;
|
|
363
|
+
case 'assignment': {
|
|
364
|
+
const left = node.childForFieldName('left');
|
|
365
|
+
const right = node.childForFieldName('right');
|
|
366
|
+
// Register result-defs BEFORE walking the value so the nested call site
|
|
367
|
+
// (reached during the value walk) carries them — single plain-identifier
|
|
368
|
+
// target only (`x = f()`); a multi-target / `@ivar` / index LHS attaches
|
|
369
|
+
// nothing (the per-target mapping is ambiguous).
|
|
370
|
+
if (left?.type === 'identifier' && right)
|
|
371
|
+
this.registerResultDefs(right, [left]);
|
|
372
|
+
if (right)
|
|
373
|
+
this.walkValue(right, acc);
|
|
374
|
+
if (left)
|
|
375
|
+
this.defTargets(left, acc);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
case 'operator_assignment': {
|
|
379
|
+
const left = node.childForFieldName('left');
|
|
380
|
+
const right = node.childForFieldName('right');
|
|
381
|
+
if (right)
|
|
382
|
+
this.walkValue(right, acc);
|
|
383
|
+
if (left) {
|
|
384
|
+
if (left.type === 'identifier') {
|
|
385
|
+
this.use(left, acc);
|
|
386
|
+
this.def(left, acc);
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
this.walkValue(left, acc); // non-local lvalue — use only
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
case 'binary': {
|
|
395
|
+
// `a && b` / `a || b` / `and` / `or` — the right operand is conditionally
|
|
396
|
+
// evaluated, so any def inside it is a may-def; uses are still recorded.
|
|
397
|
+
const left = node.childForFieldName('left');
|
|
398
|
+
const right = node.childForFieldName('right');
|
|
399
|
+
const op = node.childForFieldName('operator')?.text ?? '';
|
|
400
|
+
if (left)
|
|
401
|
+
this.walkValue(left, acc);
|
|
402
|
+
if (right) {
|
|
403
|
+
if (op === '&&' || op === '||' || op === 'and' || op === 'or') {
|
|
404
|
+
this.conditional(() => this.walkValue(right, acc));
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
this.walkValue(right, acc);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
case 'call':
|
|
413
|
+
// `recv.meth(args)` / `meth(args)` / `puts x` / `obj.field` — every Ruby
|
|
414
|
+
// call shape. Records a taint site (callee path, receiver, per-arg
|
|
415
|
+
// occurrences, result defs, spread) plus the SAME uses the old default
|
|
416
|
+
// descent recorded (receiver chain root + arguments). A nested block
|
|
417
|
+
// child is its OWN function CFG (opaque — the `block` field is not walked).
|
|
418
|
+
this.visitCall(node, acc);
|
|
419
|
+
return;
|
|
420
|
+
default:
|
|
421
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
422
|
+
const c = node.namedChild(i);
|
|
423
|
+
if (c)
|
|
424
|
+
this.walkValue(c, acc);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
// ── taint-site harvest ────────────────────────────────────────────────────
|
|
429
|
+
/**
|
|
430
|
+
* When `value` is a `call`, remember that call site should carry `resultDefs`
|
|
431
|
+
* — the binding indices of `targets` (def-position identifiers). Consumed by
|
|
432
|
+
* {@link visitCall} once the value walk reaches the node. Single plain-identifier
|
|
433
|
+
* target only (the caller restricts to it); the blank target (`_`) binds nothing
|
|
434
|
+
* and is skipped.
|
|
435
|
+
*/
|
|
436
|
+
registerResultDefs(value, targets) {
|
|
437
|
+
if (value.type !== 'call')
|
|
438
|
+
return;
|
|
439
|
+
const defs = [];
|
|
440
|
+
for (const target of targets) {
|
|
441
|
+
if (target.type !== 'identifier' || target.text === '_')
|
|
442
|
+
continue;
|
|
443
|
+
defs.push(this.resolve(target));
|
|
444
|
+
}
|
|
445
|
+
if (defs.length > 0)
|
|
446
|
+
this.resultDefTargets.set(value.id, defs);
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Explicit `call` handler. Records a call site (callee path, receiver, per-arg
|
|
450
|
+
* occurrence entries, result defs, spread marker) while reproducing EXACTLY the
|
|
451
|
+
* uses the old default descent recorded (receiver chain root + arguments). Ruby
|
|
452
|
+
* has no `new` — every site is `kind: 'call'`. The `at` anchor is the `call`
|
|
453
|
+
* node's start, byte-aligned with the `@reference.call.free/.member` CALLS
|
|
454
|
+
* anchor (which captures the whole `call` node), so the resolved-id join lands
|
|
455
|
+
* by exact position (see file header ANCHOR ALIGNMENT).
|
|
456
|
+
*/
|
|
457
|
+
visitCall(node, acc) {
|
|
458
|
+
const receiver = node.childForFieldName('receiver');
|
|
459
|
+
const method = node.childForFieldName('method');
|
|
460
|
+
const args = node.childForFieldName('arguments');
|
|
461
|
+
const siteIdx = acc.openCallSite('call', [
|
|
462
|
+
node.startPosition.row + 1,
|
|
463
|
+
node.startPosition.column,
|
|
464
|
+
]);
|
|
465
|
+
acc.pushFrame(siteIdx);
|
|
466
|
+
if (receiver) {
|
|
467
|
+
// Member / chained call (`obj.method`, `a.b.c`, `obj&.m`). Walk the receiver
|
|
468
|
+
// chain to its root binding (the receiver use + any mid-chain member reads)
|
|
469
|
+
// and build the dotted callee path `root.….method`.
|
|
470
|
+
const chain = this.walkReceiverChain(receiver, acc);
|
|
471
|
+
if (chain.rootIdx !== undefined)
|
|
472
|
+
acc.setSiteReceiver(siteIdx, chain.rootIdx);
|
|
473
|
+
const path = this.calleePath(chain.path, method);
|
|
474
|
+
if (path !== undefined)
|
|
475
|
+
acc.setSiteCallee(siteIdx, path);
|
|
476
|
+
}
|
|
477
|
+
else if (method) {
|
|
478
|
+
// Free / implicit-receiver call (`foo(a)`, `puts x`, `attr_accessor :x`).
|
|
479
|
+
// The method NAME is a statement-level use (a known local resolves to its
|
|
480
|
+
// binding, an unknown method to a `module` synthetic) but NOT a value
|
|
481
|
+
// occurrence in any enclosing argument.
|
|
482
|
+
if (method.text !== '_')
|
|
483
|
+
acc.addUseWithoutOccurrence(this.resolve(method));
|
|
484
|
+
acc.setSiteCallee(siteIdx, method.text);
|
|
485
|
+
}
|
|
486
|
+
const resultDefs = this.resultDefTargets.get(node.id);
|
|
487
|
+
if (resultDefs !== undefined)
|
|
488
|
+
acc.setSiteResultDefs(siteIdx, resultDefs);
|
|
489
|
+
if (args)
|
|
490
|
+
this.walkArguments(args, siteIdx, acc);
|
|
491
|
+
acc.popFrame();
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Walk a member-call receiver, returning the chain ROOT binding (recorded as a
|
|
495
|
+
* use) and the dotted prefix path (`a.b` in `a.b.c()`), plus a member-read site
|
|
496
|
+
* for each NON-final access in the chain. A receiver that is itself a `call`
|
|
497
|
+
* (Ruby nests `a.b.c` as `call(call(a,b),c)`) recurses; a bare identifier root
|
|
498
|
+
* is the receiver binding; a `self` / non-identifier root has no static path.
|
|
499
|
+
*/
|
|
500
|
+
walkReceiverChain(receiver, acc) {
|
|
501
|
+
// Collect the access names along the receiver chain (outermost-last), and the
|
|
502
|
+
// chain root node, by unwinding nested `call` receivers.
|
|
503
|
+
const accesses = [];
|
|
504
|
+
let cur = receiver;
|
|
505
|
+
for (;;) {
|
|
506
|
+
if (cur.type === 'call' && cur.childForFieldName('arguments') === null) {
|
|
507
|
+
// A no-args member `call` in receiver position is a member ACCESS
|
|
508
|
+
// (`a.b` in `a.b.c`) — its method name extends the path; recurse on its
|
|
509
|
+
// own receiver. A receiver `call` WITH arguments is an opaque call result
|
|
510
|
+
// (`foo(a).bar` — handled by the `else` below as a nested call site).
|
|
511
|
+
const m = cur.childForFieldName('method');
|
|
512
|
+
const inner = cur.childForFieldName('receiver');
|
|
513
|
+
accesses.unshift(m?.text ?? '');
|
|
514
|
+
if (!inner)
|
|
515
|
+
break;
|
|
516
|
+
cur = inner;
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
let rootIdx;
|
|
522
|
+
let rootSegment;
|
|
523
|
+
if (cur.type === 'identifier' && cur.text !== '_') {
|
|
524
|
+
rootIdx = this.resolve(cur);
|
|
525
|
+
acc.addUse(rootIdx);
|
|
526
|
+
rootSegment = cur.text;
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
// `self` / `@ivar` / a call-rooted receiver (`foo(a).bar`) / literal — walk
|
|
530
|
+
// for uses + nested sites; no static root segment.
|
|
531
|
+
this.walkValue(cur, acc);
|
|
532
|
+
}
|
|
533
|
+
// The INNERMOST access (`a.b` in `a.b.c()`) is a value-position member read;
|
|
534
|
+
// the trailing access (the receiver's own method) is part of the callee path,
|
|
535
|
+
// not a separate read.
|
|
536
|
+
if (rootIdx !== undefined && accesses.length >= 1) {
|
|
537
|
+
acc.addMemberRead(rootIdx, accesses[0]);
|
|
538
|
+
}
|
|
539
|
+
const path = rootSegment !== undefined && accesses.every((a) => a !== '')
|
|
540
|
+
? [rootSegment, ...accesses].join('.')
|
|
541
|
+
: undefined;
|
|
542
|
+
return { rootIdx, path };
|
|
543
|
+
}
|
|
544
|
+
/** Dotted callee path `prefix.method` (or undefined when the prefix is opaque). */
|
|
545
|
+
calleePath(prefix, method) {
|
|
546
|
+
const m = method?.text;
|
|
547
|
+
if (m === undefined || m.length === 0)
|
|
548
|
+
return undefined;
|
|
549
|
+
if (prefix === undefined)
|
|
550
|
+
return undefined;
|
|
551
|
+
return `${prefix}.${m}`;
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Walk an `argument_list`, tagging each positional / keyword / splat argument's
|
|
555
|
+
* occurrence position. A `pair` (`k: v`) records only the VALUE occurrence (the
|
|
556
|
+
* `hash_key_symbol` key is not a use). A `splat_argument` (`*xs`) /
|
|
557
|
+
* `hash_splat_argument` (`**kw`) marks the first spread position so the matcher
|
|
558
|
+
* degrades soundly; its inner value still walks. A `block_argument` (`&blk`)
|
|
559
|
+
* passes a block — its inner value is a use occurrence.
|
|
560
|
+
*/
|
|
561
|
+
walkArguments(args, siteIdx, acc) {
|
|
562
|
+
let pos = 0;
|
|
563
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
564
|
+
const arg = args.namedChild(i);
|
|
565
|
+
if (!arg || arg.type === 'comment')
|
|
566
|
+
continue;
|
|
567
|
+
acc.setFrameArg(pos);
|
|
568
|
+
if (arg.type === 'splat_argument' || arg.type === 'hash_splat_argument') {
|
|
569
|
+
acc.setSiteSpread(siteIdx, pos);
|
|
570
|
+
const inner = arg.namedChild(0);
|
|
571
|
+
if (inner)
|
|
572
|
+
this.walkValue(inner, acc);
|
|
573
|
+
}
|
|
574
|
+
else if (arg.type === 'pair') {
|
|
575
|
+
// `k: v` — only the value is an occurrence; the symbol key is not a use.
|
|
576
|
+
const value = arg.childForFieldName('value') ?? arg.namedChild(arg.namedChildCount - 1);
|
|
577
|
+
if (value)
|
|
578
|
+
this.walkValue(value, acc);
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
// Positional arg, `block_argument` (`&blk`), or a nested expression.
|
|
582
|
+
this.walkValue(arg, acc);
|
|
583
|
+
}
|
|
584
|
+
pos++;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|