@saluzi/codegraph 0.1.0 → 0.2.1
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/LICENSE +21 -0
- package/README.md +885 -0
- package/dist/bin/codegraph.d.ts +2 -1
- package/dist/bin/codegraph.d.ts.map +1 -0
- package/dist/bin/codegraph.js +2248 -0
- package/dist/bin/codegraph.js.map +1 -0
- package/dist/bin/command-supervision.d.ts +49 -0
- package/dist/bin/command-supervision.d.ts.map +1 -0
- package/dist/bin/command-supervision.js +95 -0
- package/dist/bin/command-supervision.js.map +1 -0
- package/dist/bin/fatal-handler.d.ts +20 -0
- package/dist/bin/fatal-handler.d.ts.map +1 -0
- package/dist/bin/fatal-handler.js +118 -0
- package/dist/bin/fatal-handler.js.map +1 -0
- package/dist/bin/node-version-check.d.ts.map +1 -0
- package/dist/bin/node-version-check.js +79 -0
- package/dist/bin/node-version-check.js.map +1 -0
- package/dist/bin/uninstall.d.ts.map +1 -0
- package/dist/bin/uninstall.js +36 -0
- package/dist/bin/uninstall.js.map +1 -0
- package/dist/context/formatter.d.ts +6 -9
- package/dist/context/formatter.d.ts.map +1 -0
- package/dist/context/formatter.js +25 -6
- package/dist/context/formatter.js.map +1 -0
- package/dist/context/index.d.ts +102 -100
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +252 -6
- package/dist/context/index.js.map +1 -0
- package/dist/context/markers.d.ts +19 -0
- package/dist/context/markers.d.ts.map +1 -0
- package/dist/context/markers.js +22 -0
- package/dist/context/markers.js.map +1 -0
- package/dist/db/index.d.ts +185 -85
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +257 -14
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrations.d.ts +15 -18
- package/dist/db/migrations.d.ts.map +1 -0
- package/dist/db/migrations.js +82 -1
- package/dist/db/migrations.js.map +1 -0
- package/dist/db/queries.d.ts +503 -281
- package/dist/db/queries.d.ts.map +1 -0
- package/dist/db/queries.js +644 -107
- package/dist/db/queries.js.map +1 -0
- package/dist/db/schema.sql +69 -26
- package/dist/db/sqlite-adapter.d.ts +26 -22
- package/dist/db/sqlite-adapter.d.ts.map +1 -0
- package/dist/db/sqlite-adapter.js +11 -35
- package/dist/db/sqlite-adapter.js.map +1 -0
- package/dist/db/wal-valve.d.ts +106 -0
- package/dist/db/wal-valve.d.ts.map +1 -0
- package/dist/db/wal-valve.js +208 -0
- package/dist/db/wal-valve.js.map +1 -0
- package/dist/directory.d.ts +140 -19
- package/dist/directory.d.ts.map +1 -0
- package/dist/directory.js +568 -35
- package/dist/directory.js.map +1 -0
- package/dist/errors.d.ts +32 -45
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js.map +1 -0
- package/dist/extraction/astro-extractor.d.ts +79 -0
- package/dist/extraction/astro-extractor.d.ts.map +1 -0
- package/dist/extraction/astro-extractor.js +320 -0
- package/dist/extraction/astro-extractor.js.map +1 -0
- package/dist/extraction/cfml-extractor.d.ts +107 -0
- package/dist/extraction/cfml-extractor.d.ts.map +1 -0
- package/dist/extraction/cfml-extractor.js +494 -0
- package/dist/extraction/cfml-extractor.js.map +1 -0
- package/dist/extraction/dfm-extractor.d.ts +17 -17
- package/dist/extraction/dfm-extractor.d.ts.map +1 -0
- package/dist/extraction/dfm-extractor.js.map +1 -0
- package/dist/extraction/extraction-version.d.ts +25 -0
- package/dist/extraction/extraction-version.d.ts.map +1 -0
- package/dist/extraction/extraction-version.js +28 -0
- package/dist/extraction/extraction-version.js.map +1 -0
- package/dist/extraction/function-ref.d.ts +118 -0
- package/dist/extraction/function-ref.d.ts.map +1 -0
- package/dist/extraction/function-ref.js +727 -0
- package/dist/extraction/function-ref.js.map +1 -0
- package/dist/extraction/generated-detection.d.ts +30 -0
- package/dist/extraction/generated-detection.d.ts.map +1 -0
- package/dist/extraction/generated-detection.js +83 -0
- package/dist/extraction/generated-detection.js.map +1 -0
- package/dist/extraction/grammars.d.ts +74 -30
- package/dist/extraction/grammars.d.ts.map +1 -0
- package/dist/extraction/grammars.js +289 -15
- package/dist/extraction/grammars.js.map +1 -0
- package/dist/extraction/index.d.ts +193 -109
- package/dist/extraction/index.d.ts.map +1 -0
- package/dist/extraction/index.js +1485 -362
- package/dist/extraction/index.js.map +1 -0
- package/dist/extraction/languages/arkts.d.ts +3 -0
- package/dist/extraction/languages/arkts.d.ts.map +1 -0
- package/dist/extraction/languages/arkts.js +127 -0
- package/dist/extraction/languages/arkts.js.map +1 -0
- package/dist/extraction/languages/c-cpp.d.ts +110 -4
- package/dist/extraction/languages/c-cpp.d.ts.map +1 -0
- package/dist/extraction/languages/c-cpp.js +713 -2
- package/dist/extraction/languages/c-cpp.js.map +1 -0
- package/dist/extraction/languages/cfquery.d.ts +12 -0
- package/dist/extraction/languages/cfquery.d.ts.map +1 -0
- package/dist/extraction/languages/cfquery.js +28 -0
- package/dist/extraction/languages/cfquery.js.map +1 -0
- package/dist/extraction/languages/cfscript.d.ts +3 -0
- package/dist/extraction/languages/cfscript.d.ts.map +1 -0
- package/dist/extraction/languages/cfscript.js +73 -0
- package/dist/extraction/languages/cfscript.js.map +1 -0
- package/dist/extraction/languages/cobol.d.ts +33 -0
- package/dist/extraction/languages/cobol.d.ts.map +1 -0
- package/dist/extraction/languages/cobol.js +499 -0
- package/dist/extraction/languages/cobol.js.map +1 -0
- package/dist/extraction/languages/csharp.d.ts +25 -3
- package/dist/extraction/languages/csharp.d.ts.map +1 -0
- package/dist/extraction/languages/csharp.js +106 -3
- package/dist/extraction/languages/csharp.js.map +1 -0
- package/dist/extraction/languages/dart.d.ts +3 -3
- package/dist/extraction/languages/dart.d.ts.map +1 -0
- package/dist/extraction/languages/dart.js +183 -1
- package/dist/extraction/languages/dart.js.map +1 -0
- package/dist/extraction/languages/erlang.d.ts +3 -0
- package/dist/extraction/languages/erlang.d.ts.map +1 -0
- package/dist/extraction/languages/erlang.js +350 -0
- package/dist/extraction/languages/erlang.js.map +1 -0
- package/dist/extraction/languages/go.d.ts +3 -3
- package/dist/extraction/languages/go.d.ts.map +1 -0
- package/dist/extraction/languages/go.js +55 -2
- package/dist/extraction/languages/go.js.map +1 -0
- package/dist/extraction/languages/index.d.ts +4 -4
- package/dist/extraction/languages/index.d.ts.map +1 -0
- package/dist/extraction/languages/index.js +22 -0
- package/dist/extraction/languages/index.js.map +1 -0
- package/dist/extraction/languages/java.d.ts +3 -3
- package/dist/extraction/languages/java.d.ts.map +1 -0
- package/dist/extraction/languages/java.js +252 -1
- package/dist/extraction/languages/java.js.map +1 -0
- package/dist/extraction/languages/javascript.d.ts +3 -3
- package/dist/extraction/languages/javascript.d.ts.map +1 -0
- package/dist/extraction/languages/javascript.js +16 -0
- package/dist/extraction/languages/javascript.js.map +1 -0
- package/dist/extraction/languages/kotlin.d.ts +3 -3
- package/dist/extraction/languages/kotlin.d.ts.map +1 -0
- package/dist/extraction/languages/kotlin.js +126 -0
- package/dist/extraction/languages/kotlin.js.map +1 -0
- package/dist/extraction/languages/lua.d.ts +3 -3
- package/dist/extraction/languages/lua.d.ts.map +1 -0
- package/dist/extraction/languages/lua.js.map +1 -0
- package/dist/extraction/languages/luau.d.ts +3 -3
- package/dist/extraction/languages/luau.d.ts.map +1 -0
- package/dist/extraction/languages/luau.js.map +1 -0
- package/dist/extraction/languages/nix.d.ts +3 -0
- package/dist/extraction/languages/nix.d.ts.map +1 -0
- package/dist/extraction/languages/nix.js +294 -0
- package/dist/extraction/languages/nix.js.map +1 -0
- package/dist/extraction/languages/objc.d.ts +3 -0
- package/dist/extraction/languages/objc.d.ts.map +1 -0
- package/dist/extraction/languages/objc.js +175 -0
- package/dist/extraction/languages/objc.js.map +1 -0
- package/dist/extraction/languages/pascal.d.ts +3 -3
- package/dist/extraction/languages/pascal.d.ts.map +1 -0
- package/dist/extraction/languages/pascal.js +11 -0
- package/dist/extraction/languages/pascal.js.map +1 -0
- package/dist/extraction/languages/php.d.ts +3 -3
- package/dist/extraction/languages/php.d.ts.map +1 -0
- package/dist/extraction/languages/php.js +90 -1
- package/dist/extraction/languages/php.js.map +1 -0
- package/dist/extraction/languages/python.d.ts +3 -3
- package/dist/extraction/languages/python.d.ts.map +1 -0
- package/dist/extraction/languages/python.js.map +1 -0
- package/dist/extraction/languages/r.d.ts +3 -0
- package/dist/extraction/languages/r.d.ts.map +1 -0
- package/dist/extraction/languages/r.js +314 -0
- package/dist/extraction/languages/r.js.map +1 -0
- package/dist/extraction/languages/ruby.d.ts +3 -3
- package/dist/extraction/languages/ruby.d.ts.map +1 -0
- package/dist/extraction/languages/ruby.js +35 -0
- package/dist/extraction/languages/ruby.js.map +1 -0
- package/dist/extraction/languages/rust.d.ts +3 -3
- package/dist/extraction/languages/rust.d.ts.map +1 -0
- package/dist/extraction/languages/rust.js +35 -2
- package/dist/extraction/languages/rust.js.map +1 -0
- package/dist/extraction/languages/scala.d.ts +3 -3
- package/dist/extraction/languages/scala.d.ts.map +1 -0
- package/dist/extraction/languages/scala.js +80 -10
- package/dist/extraction/languages/scala.js.map +1 -0
- package/dist/extraction/languages/solidity.d.ts +3 -0
- package/dist/extraction/languages/solidity.d.ts.map +1 -0
- package/dist/extraction/languages/solidity.js +293 -0
- package/dist/extraction/languages/solidity.js.map +1 -0
- package/dist/extraction/languages/swift.d.ts +3 -3
- package/dist/extraction/languages/swift.d.ts.map +1 -0
- package/dist/extraction/languages/swift.js +61 -0
- package/dist/extraction/languages/swift.js.map +1 -0
- package/dist/extraction/languages/terraform.d.ts +3 -0
- package/dist/extraction/languages/terraform.d.ts.map +1 -0
- package/dist/extraction/languages/terraform.js +641 -0
- package/dist/extraction/languages/terraform.js.map +1 -0
- package/dist/extraction/languages/typescript.d.ts +16 -3
- package/dist/extraction/languages/typescript.d.ts.map +1 -0
- package/dist/extraction/languages/typescript.js +38 -0
- package/dist/extraction/languages/typescript.js.map +1 -0
- package/dist/extraction/languages/vbnet.d.ts +11 -0
- package/dist/extraction/languages/vbnet.d.ts.map +1 -0
- package/dist/extraction/languages/vbnet.js +141 -0
- package/dist/extraction/languages/vbnet.js.map +1 -0
- package/dist/extraction/liquid-extractor.d.ts +48 -41
- package/dist/extraction/liquid-extractor.d.ts.map +1 -0
- package/dist/extraction/liquid-extractor.js +53 -9
- package/dist/extraction/liquid-extractor.js.map +1 -0
- package/dist/extraction/mybatis-extractor.d.ts +68 -0
- package/dist/extraction/mybatis-extractor.d.ts.map +1 -0
- package/dist/extraction/mybatis-extractor.js +300 -0
- package/dist/extraction/mybatis-extractor.js.map +1 -0
- package/dist/extraction/parse-pool.d.ts +152 -0
- package/dist/extraction/parse-pool.d.ts.map +1 -0
- package/dist/extraction/parse-pool.js +387 -0
- package/dist/extraction/parse-pool.js.map +1 -0
- package/dist/extraction/parse-worker.d.ts +2 -2
- package/dist/extraction/parse-worker.d.ts.map +1 -0
- package/dist/extraction/parse-worker.js +13 -3
- package/dist/extraction/parse-worker.js.map +1 -0
- package/dist/extraction/razor-extractor.d.ts +42 -0
- package/dist/extraction/razor-extractor.d.ts.map +1 -0
- package/dist/extraction/razor-extractor.js +285 -0
- package/dist/extraction/razor-extractor.js.map +1 -0
- package/dist/extraction/svelte-extractor.d.ts +42 -42
- package/dist/extraction/svelte-extractor.d.ts.map +1 -0
- package/dist/extraction/svelte-extractor.js +6 -3
- package/dist/extraction/svelte-extractor.js.map +1 -0
- package/dist/extraction/tree-sitter-helpers.d.ts +7 -18
- package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -0
- package/dist/extraction/tree-sitter-helpers.js +60 -10
- package/dist/extraction/tree-sitter-helpers.js.map +1 -0
- package/dist/extraction/tree-sitter-types.d.ts +224 -157
- package/dist/extraction/tree-sitter-types.d.ts.map +1 -0
- package/dist/extraction/tree-sitter-types.js.map +1 -0
- package/dist/extraction/tree-sitter.d.ts +689 -221
- package/dist/extraction/tree-sitter.d.ts.map +1 -0
- package/dist/extraction/tree-sitter.js +4193 -117
- package/dist/extraction/tree-sitter.js.map +1 -0
- package/dist/extraction/vue-extractor.d.ts +40 -25
- package/dist/extraction/vue-extractor.d.ts.map +1 -0
- package/dist/extraction/vue-extractor.js +94 -3
- package/dist/extraction/vue-extractor.js.map +1 -0
- package/dist/extraction/wasm/tree-sitter-arkts.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-lua.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-terraform.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
- package/dist/extraction/wasm-runtime-flags.d.ts +6 -14
- package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -0
- package/dist/extraction/wasm-runtime-flags.js +1 -0
- package/dist/extraction/wasm-runtime-flags.js.map +1 -0
- package/dist/graph/index.d.ts +3 -3
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/queries.d.ts +96 -99
- package/dist/graph/queries.d.ts.map +1 -0
- package/dist/graph/queries.js +13 -40
- package/dist/graph/queries.js.map +1 -0
- package/dist/graph/traversal.d.ts +117 -127
- package/dist/graph/traversal.d.ts.map +1 -0
- package/dist/graph/traversal.js +92 -21
- package/dist/graph/traversal.js.map +1 -0
- package/dist/index.d.ts +615 -481
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +709 -18
- package/dist/index.js.map +1 -0
- package/dist/installer/config-writer.d.ts +13 -14
- package/dist/installer/config-writer.d.ts.map +1 -0
- package/dist/installer/config-writer.js +91 -0
- package/dist/installer/config-writer.js.map +1 -0
- package/dist/installer/index.d.ts +84 -82
- package/dist/installer/index.d.ts.map +1 -0
- package/dist/installer/index.js +619 -0
- package/dist/installer/index.js.map +1 -0
- package/dist/installer/instructions-template.d.ts +35 -24
- package/dist/installer/instructions-template.d.ts.map +1 -0
- package/dist/installer/instructions-template.js +53 -0
- package/dist/installer/instructions-template.js.map +1 -0
- package/dist/installer/targets/antigravity.d.ts +57 -0
- package/dist/installer/targets/antigravity.d.ts.map +1 -0
- package/dist/installer/targets/antigravity.js +308 -0
- package/dist/installer/targets/antigravity.js.map +1 -0
- package/dist/installer/targets/claude.d.ts +34 -27
- package/dist/installer/targets/claude.d.ts.map +1 -0
- package/dist/installer/targets/claude.js +454 -0
- package/dist/installer/targets/claude.js.map +1 -0
- package/dist/installer/targets/codex.d.ts +3 -3
- package/dist/installer/targets/codex.d.ts.map +1 -0
- package/dist/installer/targets/codex.js +185 -0
- package/dist/installer/targets/codex.js.map +1 -0
- package/dist/installer/targets/cursor.d.ts +3 -3
- package/dist/installer/targets/cursor.d.ts.map +1 -0
- package/dist/installer/targets/cursor.js +254 -0
- package/dist/installer/targets/cursor.js.map +1 -0
- package/dist/installer/targets/gemini.d.ts +26 -0
- package/dist/installer/targets/gemini.d.ts.map +1 -0
- package/dist/installer/targets/gemini.js +165 -0
- package/dist/installer/targets/gemini.js.map +1 -0
- package/dist/installer/targets/hermes.d.ts +3 -3
- package/dist/installer/targets/hermes.d.ts.map +1 -0
- package/dist/installer/targets/hermes.js +359 -0
- package/dist/installer/targets/hermes.js.map +1 -0
- package/dist/installer/targets/kiro.d.ts +27 -0
- package/dist/installer/targets/kiro.d.ts.map +1 -0
- package/dist/installer/targets/kiro.js +178 -0
- package/dist/installer/targets/kiro.js.map +1 -0
- package/dist/installer/targets/opencode.d.ts +12 -4
- package/dist/installer/targets/opencode.d.ts.map +1 -0
- package/dist/installer/targets/opencode.js +288 -0
- package/dist/installer/targets/opencode.js.map +1 -0
- package/dist/installer/targets/registry.d.ts +9 -12
- package/dist/installer/targets/registry.d.ts.map +1 -0
- package/dist/installer/targets/registry.js +91 -0
- package/dist/installer/targets/registry.js.map +1 -0
- package/dist/installer/targets/shared.d.ts +38 -29
- package/dist/installer/targets/shared.d.ts.map +1 -0
- package/dist/installer/targets/shared.js +264 -0
- package/dist/installer/targets/shared.js.map +1 -0
- package/dist/installer/targets/toml.d.ts +11 -23
- package/dist/installer/targets/toml.d.ts.map +1 -0
- package/dist/installer/targets/toml.js +147 -0
- package/dist/installer/targets/toml.js.map +1 -0
- package/dist/installer/targets/types.d.ts +62 -76
- package/dist/installer/targets/types.d.ts.map +1 -0
- package/dist/installer/targets/types.js +16 -0
- package/dist/installer/targets/types.js.map +1 -0
- package/dist/mcp/daemon-manager.d.ts +42 -0
- package/dist/mcp/daemon-manager.d.ts.map +1 -0
- package/dist/mcp/daemon-manager.js +129 -0
- package/dist/mcp/daemon-manager.js.map +1 -0
- package/dist/mcp/daemon-paths.d.ts +73 -0
- package/dist/mcp/daemon-paths.d.ts.map +1 -0
- package/dist/mcp/daemon-paths.js +165 -0
- package/dist/mcp/daemon-paths.js.map +1 -0
- package/dist/mcp/daemon-registry.d.ts +47 -0
- package/dist/mcp/daemon-registry.d.ts.map +1 -0
- package/dist/mcp/daemon-registry.js +233 -0
- package/dist/mcp/daemon-registry.js.map +1 -0
- package/dist/mcp/daemon.d.ts +290 -0
- package/dist/mcp/daemon.d.ts.map +1 -0
- package/dist/mcp/daemon.js +862 -0
- package/dist/mcp/daemon.js.map +1 -0
- package/dist/mcp/dynamic-boundaries.d.ts +41 -0
- package/dist/mcp/dynamic-boundaries.d.ts.map +1 -0
- package/dist/mcp/dynamic-boundaries.js +360 -0
- package/dist/mcp/dynamic-boundaries.js.map +1 -0
- package/dist/mcp/early-ppid.d.ts +26 -0
- package/dist/mcp/early-ppid.d.ts.map +1 -0
- package/dist/mcp/early-ppid.js +29 -0
- package/dist/mcp/early-ppid.js.map +1 -0
- package/dist/mcp/engine.d.ts +122 -0
- package/dist/mcp/engine.d.ts.map +1 -0
- package/dist/mcp/engine.js +350 -0
- package/dist/mcp/engine.js.map +1 -0
- package/dist/mcp/index.d.ts +89 -74
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +506 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/liveness-watchdog.d.ts +35 -0
- package/dist/mcp/liveness-watchdog.d.ts.map +1 -0
- package/dist/mcp/liveness-watchdog.js +267 -0
- package/dist/mcp/liveness-watchdog.js.map +1 -0
- package/dist/mcp/ppid-watchdog.d.ts +62 -0
- package/dist/mcp/ppid-watchdog.d.ts.map +1 -0
- package/dist/mcp/ppid-watchdog.js +64 -0
- package/dist/mcp/ppid-watchdog.js.map +1 -0
- package/dist/mcp/proxy.d.ts +87 -0
- package/dist/mcp/proxy.d.ts.map +1 -0
- package/dist/mcp/proxy.js +667 -0
- package/dist/mcp/proxy.js.map +1 -0
- package/dist/mcp/query-pool.d.ts +108 -0
- package/dist/mcp/query-pool.d.ts.map +1 -0
- package/dist/mcp/query-pool.js +315 -0
- package/dist/mcp/query-pool.js.map +1 -0
- package/dist/mcp/query-worker.d.ts +24 -0
- package/dist/mcp/query-worker.d.ts.map +1 -0
- package/dist/mcp/query-worker.js +87 -0
- package/dist/mcp/query-worker.js.map +1 -0
- package/dist/mcp/server-instructions.d.ts +22 -8
- package/dist/mcp/server-instructions.d.ts.map +1 -0
- package/dist/mcp/server-instructions.js +106 -0
- package/dist/mcp/server-instructions.js.map +1 -0
- package/dist/mcp/session.d.ts +93 -0
- package/dist/mcp/session.d.ts.map +1 -0
- package/dist/mcp/session.js +357 -0
- package/dist/mcp/session.js.map +1 -0
- package/dist/mcp/startup-handshake.d.ts +44 -0
- package/dist/mcp/startup-handshake.d.ts.map +1 -0
- package/dist/mcp/startup-handshake.js +73 -0
- package/dist/mcp/startup-handshake.js.map +1 -0
- package/dist/mcp/stdin-teardown.d.ts +27 -0
- package/dist/mcp/stdin-teardown.d.ts.map +1 -0
- package/dist/mcp/stdin-teardown.js +49 -0
- package/dist/mcp/stdin-teardown.js.map +1 -0
- package/dist/mcp/tools.d.ts +557 -213
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +4477 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/transport.d.ts +158 -87
- package/dist/mcp/transport.d.ts.map +1 -0
- package/dist/mcp/transport.js +377 -0
- package/dist/mcp/transport.js.map +1 -0
- package/dist/mcp/version.d.ts +19 -0
- package/dist/mcp/version.d.ts.map +1 -0
- package/dist/mcp/version.js +71 -0
- package/dist/mcp/version.js.map +1 -0
- package/dist/project-config.d.ts +94 -0
- package/dist/project-config.d.ts.map +1 -0
- package/dist/project-config.js +374 -0
- package/dist/project-config.js.map +1 -0
- package/dist/resolution/c-fnptr-synthesizer.d.ts +6 -0
- package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -0
- package/dist/resolution/c-fnptr-synthesizer.js +1062 -0
- package/dist/resolution/c-fnptr-synthesizer.js.map +1 -0
- package/dist/resolution/callback-synthesizer.d.ts +15 -0
- package/dist/resolution/callback-synthesizer.d.ts.map +1 -0
- package/dist/resolution/callback-synthesizer.js +3938 -0
- package/dist/resolution/callback-synthesizer.js.map +1 -0
- package/dist/resolution/cooperative-yield.d.ts +32 -0
- package/dist/resolution/cooperative-yield.d.ts.map +1 -0
- package/dist/resolution/cooperative-yield.js +42 -0
- package/dist/resolution/cooperative-yield.js.map +1 -0
- package/dist/resolution/frameworks/astro.d.ts +9 -0
- package/dist/resolution/frameworks/astro.d.ts.map +1 -0
- package/dist/resolution/frameworks/astro.js +169 -0
- package/dist/resolution/frameworks/astro.js.map +1 -0
- package/dist/resolution/frameworks/cargo-workspace.d.ts +3 -5
- package/dist/resolution/frameworks/cargo-workspace.d.ts.map +1 -0
- package/dist/resolution/frameworks/cargo-workspace.js.map +1 -0
- package/dist/resolution/frameworks/cics.d.ts +20 -0
- package/dist/resolution/frameworks/cics.d.ts.map +1 -0
- package/dist/resolution/frameworks/cics.js +90 -0
- package/dist/resolution/frameworks/cics.js.map +1 -0
- package/dist/resolution/frameworks/csharp.d.ts +3 -3
- package/dist/resolution/frameworks/csharp.d.ts.map +1 -0
- package/dist/resolution/frameworks/csharp.js +36 -8
- package/dist/resolution/frameworks/csharp.js.map +1 -0
- package/dist/resolution/frameworks/drupal.d.ts +3 -3
- package/dist/resolution/frameworks/drupal.d.ts.map +1 -0
- package/dist/resolution/frameworks/drupal.js +44 -12
- package/dist/resolution/frameworks/drupal.js.map +1 -0
- package/dist/resolution/frameworks/expo-modules.d.ts +3 -0
- package/dist/resolution/frameworks/expo-modules.d.ts.map +1 -0
- package/dist/resolution/frameworks/expo-modules.js +148 -0
- package/dist/resolution/frameworks/expo-modules.js.map +1 -0
- package/dist/resolution/frameworks/express.d.ts +3 -3
- package/dist/resolution/frameworks/express.d.ts.map +1 -0
- package/dist/resolution/frameworks/express.js +102 -19
- package/dist/resolution/frameworks/express.js.map +1 -0
- package/dist/resolution/frameworks/fabric.d.ts +3 -0
- package/dist/resolution/frameworks/fabric.d.ts.map +1 -0
- package/dist/resolution/frameworks/fabric.js +354 -0
- package/dist/resolution/frameworks/fabric.js.map +1 -0
- package/dist/resolution/frameworks/go.d.ts +3 -3
- package/dist/resolution/frameworks/go.d.ts.map +1 -0
- package/dist/resolution/frameworks/go.js +6 -3
- package/dist/resolution/frameworks/go.js.map +1 -0
- package/dist/resolution/frameworks/goframe.d.ts +41 -0
- package/dist/resolution/frameworks/goframe.d.ts.map +1 -0
- package/dist/resolution/frameworks/goframe.js +112 -0
- package/dist/resolution/frameworks/goframe.js.map +1 -0
- package/dist/resolution/frameworks/index.d.ts +29 -31
- package/dist/resolution/frameworks/index.d.ts.map +1 -0
- package/dist/resolution/frameworks/index.js +39 -1
- package/dist/resolution/frameworks/index.js.map +1 -0
- package/dist/resolution/frameworks/java.d.ts +3 -3
- package/dist/resolution/frameworks/java.d.ts.map +1 -0
- package/dist/resolution/frameworks/java.js +352 -12
- package/dist/resolution/frameworks/java.js.map +1 -0
- package/dist/resolution/frameworks/laravel.d.ts +4 -4
- package/dist/resolution/frameworks/laravel.d.ts.map +1 -0
- package/dist/resolution/frameworks/laravel.js +17 -8
- package/dist/resolution/frameworks/laravel.js.map +1 -0
- package/dist/resolution/frameworks/nestjs.d.ts +3 -3
- package/dist/resolution/frameworks/nestjs.d.ts.map +1 -0
- package/dist/resolution/frameworks/nestjs.js +324 -0
- package/dist/resolution/frameworks/nestjs.js.map +1 -0
- package/dist/resolution/frameworks/play.d.ts +19 -0
- package/dist/resolution/frameworks/play.d.ts.map +1 -0
- package/dist/resolution/frameworks/play.js +111 -0
- package/dist/resolution/frameworks/play.js.map +1 -0
- package/dist/resolution/frameworks/python.d.ts +5 -5
- package/dist/resolution/frameworks/python.d.ts.map +1 -0
- package/dist/resolution/frameworks/python.js +138 -16
- package/dist/resolution/frameworks/python.js.map +1 -0
- package/dist/resolution/frameworks/react-native.d.ts +3 -0
- package/dist/resolution/frameworks/react-native.d.ts.map +1 -0
- package/dist/resolution/frameworks/react-native.js +410 -0
- package/dist/resolution/frameworks/react-native.js.map +1 -0
- package/dist/resolution/frameworks/react.d.ts +3 -3
- package/dist/resolution/frameworks/react.d.ts.map +1 -0
- package/dist/resolution/frameworks/react.js +122 -60
- package/dist/resolution/frameworks/react.js.map +1 -0
- package/dist/resolution/frameworks/ruby.d.ts +3 -3
- package/dist/resolution/frameworks/ruby.d.ts.map +1 -0
- package/dist/resolution/frameworks/ruby.js +106 -2
- package/dist/resolution/frameworks/ruby.js.map +1 -0
- package/dist/resolution/frameworks/rust.d.ts +3 -3
- package/dist/resolution/frameworks/rust.d.ts.map +1 -0
- package/dist/resolution/frameworks/rust.js +102 -5
- package/dist/resolution/frameworks/rust.js.map +1 -0
- package/dist/resolution/frameworks/svelte.d.ts +3 -3
- package/dist/resolution/frameworks/svelte.d.ts.map +1 -0
- package/dist/resolution/frameworks/svelte.js +5 -1
- package/dist/resolution/frameworks/svelte.js.map +1 -0
- package/dist/resolution/frameworks/swift-objc.d.ts +37 -0
- package/dist/resolution/frameworks/swift-objc.d.ts.map +1 -0
- package/dist/resolution/frameworks/swift-objc.js +252 -0
- package/dist/resolution/frameworks/swift-objc.js.map +1 -0
- package/dist/resolution/frameworks/swift.d.ts +5 -5
- package/dist/resolution/frameworks/swift.d.ts.map +1 -0
- package/dist/resolution/frameworks/swift.js +30 -6
- package/dist/resolution/frameworks/swift.js.map +1 -0
- package/dist/resolution/frameworks/terraform.d.ts +38 -0
- package/dist/resolution/frameworks/terraform.d.ts.map +1 -0
- package/dist/resolution/frameworks/terraform.js +277 -0
- package/dist/resolution/frameworks/terraform.js.map +1 -0
- package/dist/resolution/frameworks/vue.d.ts +3 -3
- package/dist/resolution/frameworks/vue.d.ts.map +1 -0
- package/dist/resolution/frameworks/vue.js +24 -27
- package/dist/resolution/frameworks/vue.js.map +1 -0
- package/dist/resolution/go-module.d.ts +26 -0
- package/dist/resolution/go-module.d.ts.map +1 -0
- package/dist/resolution/go-module.js +78 -0
- package/dist/resolution/go-module.js.map +1 -0
- package/dist/resolution/goframe-synthesizer.d.ts +29 -0
- package/dist/resolution/goframe-synthesizer.d.ts.map +1 -0
- package/dist/resolution/goframe-synthesizer.js +163 -0
- package/dist/resolution/goframe-synthesizer.js.map +1 -0
- package/dist/resolution/import-resolver.d.ts +53 -29
- package/dist/resolution/import-resolver.d.ts.map +1 -0
- package/dist/resolution/import-resolver.js +1319 -8
- package/dist/resolution/import-resolver.js.map +1 -0
- package/dist/resolution/index.d.ts +243 -103
- package/dist/resolution/index.d.ts.map +1 -0
- package/dist/resolution/index.js +1055 -53
- package/dist/resolution/index.js.map +1 -0
- package/dist/resolution/lru-cache.d.ts +9 -9
- package/dist/resolution/lru-cache.d.ts.map +1 -0
- package/dist/resolution/lru-cache.js.map +1 -0
- package/dist/resolution/name-matcher.d.ts +91 -29
- package/dist/resolution/name-matcher.d.ts.map +1 -0
- package/dist/resolution/name-matcher.js +1478 -32
- package/dist/resolution/name-matcher.js.map +1 -0
- package/dist/resolution/path-aliases.d.ts +23 -27
- package/dist/resolution/path-aliases.d.ts.map +1 -0
- package/dist/resolution/path-aliases.js.map +1 -0
- package/dist/resolution/strip-comments.d.ts +3 -16
- package/dist/resolution/strip-comments.d.ts.map +1 -0
- package/dist/resolution/strip-comments.js +51 -0
- package/dist/resolution/strip-comments.js.map +1 -0
- package/dist/resolution/swift-objc-bridge.d.ts +134 -0
- package/dist/resolution/swift-objc-bridge.d.ts.map +1 -0
- package/dist/resolution/swift-objc-bridge.js +256 -0
- package/dist/resolution/swift-objc-bridge.js.map +1 -0
- package/dist/resolution/types.d.ts +217 -136
- package/dist/resolution/types.d.ts.map +1 -0
- package/dist/resolution/types.js.map +1 -0
- package/dist/resolution/workspace-packages.d.ts +58 -0
- package/dist/resolution/workspace-packages.d.ts.map +1 -0
- package/dist/resolution/workspace-packages.js +346 -0
- package/dist/resolution/workspace-packages.js.map +1 -0
- package/dist/search/identifier-segments.d.ts +60 -0
- package/dist/search/identifier-segments.d.ts.map +1 -0
- package/dist/search/identifier-segments.js +176 -0
- package/dist/search/identifier-segments.js.map +1 -0
- package/dist/search/query-parser.d.ts +14 -18
- package/dist/search/query-parser.d.ts.map +1 -0
- package/dist/search/query-parser.js.map +1 -0
- package/dist/search/query-utils.d.ts +45 -17
- package/dist/search/query-utils.d.ts.map +1 -0
- package/dist/search/query-utils.js +113 -47
- package/dist/search/query-utils.js.map +1 -0
- package/dist/sync/git-hooks.d.ts +13 -22
- package/dist/sync/git-hooks.d.ts.map +1 -0
- package/dist/sync/git-hooks.js +4 -0
- package/dist/sync/git-hooks.js.map +1 -0
- package/dist/sync/index.d.ts +6 -12
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +8 -1
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/watch-policy.d.ts +8 -11
- package/dist/sync/watch-policy.d.ts.map +1 -0
- package/dist/sync/watch-policy.js.map +1 -0
- package/dist/sync/watcher.d.ts +335 -63
- package/dist/sync/watcher.d.ts.map +1 -0
- package/dist/sync/watcher.js +709 -53
- package/dist/sync/watcher.js.map +1 -0
- package/dist/sync/worktree.d.ts +63 -0
- package/dist/sync/worktree.d.ts.map +1 -0
- package/dist/sync/worktree.js +182 -0
- package/dist/sync/worktree.js.map +1 -0
- package/dist/telemetry/index.d.ts +143 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +541 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/types.d.ts +308 -326
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/glyphs.d.ts +20 -20
- package/dist/ui/glyphs.d.ts.map +1 -0
- package/dist/ui/glyphs.js +78 -0
- package/dist/ui/glyphs.js.map +1 -0
- package/dist/ui/shimmer-progress.d.ts +7 -7
- package/dist/ui/shimmer-progress.d.ts.map +1 -0
- package/dist/ui/shimmer-progress.js +90 -0
- package/dist/ui/shimmer-progress.js.map +1 -0
- package/dist/ui/shimmer-worker.d.ts +2 -2
- package/dist/ui/shimmer-worker.d.ts.map +1 -0
- package/dist/ui/shimmer-worker.js +118 -0
- package/dist/ui/shimmer-worker.js.map +1 -0
- package/dist/ui/types.d.ts +14 -17
- package/dist/ui/types.d.ts.map +1 -0
- package/dist/ui/types.js +3 -0
- package/dist/ui/types.js.map +1 -0
- package/dist/upgrade/index.d.ts +164 -0
- package/dist/upgrade/index.d.ts.map +1 -0
- package/dist/upgrade/index.js +646 -0
- package/dist/upgrade/index.js.map +1 -0
- package/dist/upgrade/remove-binary.d.ts +87 -0
- package/dist/upgrade/remove-binary.d.ts.map +1 -0
- package/dist/upgrade/remove-binary.js +289 -0
- package/dist/upgrade/remove-binary.js.map +1 -0
- package/dist/upgrade/update-check.d.ts +92 -0
- package/dist/upgrade/update-check.d.ts.map +1 -0
- package/dist/upgrade/update-check.js +258 -0
- package/dist/upgrade/update-check.js.map +1 -0
- package/dist/utils.d.ts +116 -123
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +83 -49
- package/dist/utils.js.map +1 -0
- package/package.json +42 -10
- package/scripts/add-lang/bench.sh +60 -0
- package/scripts/add-lang/check-grammar.mjs +75 -0
- package/scripts/add-lang/dump-ast.mjs +103 -0
- package/scripts/add-lang/verify-extraction.mjs +70 -0
- package/scripts/agent-eval/ab-adoption.sh +91 -0
- package/scripts/agent-eval/ab-hook.sh +86 -0
- package/scripts/agent-eval/ab-impl.sh +78 -0
- package/scripts/agent-eval/ab-new-vs-baseline.sh +102 -0
- package/scripts/agent-eval/ab-sufficiency.sh +78 -0
- package/scripts/agent-eval/arms-F.sh +21 -0
- package/scripts/agent-eval/arms-matrix.sh +37 -0
- package/scripts/agent-eval/audit.sh +68 -0
- package/scripts/agent-eval/bench-readme.sh +28 -0
- package/scripts/agent-eval/bench-why-repo.sh +22 -0
- package/scripts/agent-eval/block-read-hook.sh +19 -0
- package/scripts/agent-eval/hook-settings.json +15 -0
- package/scripts/agent-eval/itrun.sh +120 -0
- package/scripts/agent-eval/offload-eval-3arm.sh +72 -0
- package/scripts/agent-eval/offload-eval-cost.mjs +133 -0
- package/scripts/agent-eval/offload-eval-effort.mjs +108 -0
- package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -0
- package/scripts/agent-eval/offload-eval-frontload.sh +47 -0
- package/scripts/agent-eval/offload-eval-ground-truth.json +18 -0
- package/scripts/agent-eval/offload-eval-hook.mjs +84 -0
- package/scripts/agent-eval/offload-eval-judge.mjs +103 -0
- package/scripts/agent-eval/offload-eval-matrix.sh +20 -0
- package/scripts/agent-eval/offload-eval-metrics.mjs +94 -0
- package/scripts/agent-eval/offload-eval-refs1.sh +50 -0
- package/scripts/agent-eval/offload-eval-setup.sh +24 -0
- package/scripts/agent-eval/offload-eval-styles.sh +72 -0
- package/scripts/agent-eval/offload-eval-summarize.mjs +68 -0
- package/scripts/agent-eval/offload-eval.md +76 -0
- package/scripts/agent-eval/parse-arms.mjs +116 -0
- package/scripts/agent-eval/parse-bench-readme.mjs +84 -0
- package/scripts/agent-eval/parse-run.mjs +45 -0
- package/scripts/agent-eval/parse-session.mjs +93 -0
- package/scripts/agent-eval/probe-context.mjs +21 -0
- package/scripts/agent-eval/probe-explore.mjs +40 -0
- package/scripts/agent-eval/probe-node.mjs +20 -0
- package/scripts/agent-eval/probe-sweep.mjs +119 -0
- package/scripts/agent-eval/probe-trace.mjs +20 -0
- package/scripts/agent-eval/redirect-read-hook.sh +38 -0
- package/scripts/agent-eval/repro-concurrent-explore.mjs +119 -0
- package/scripts/agent-eval/repro-daemon-clients.mjs +125 -0
- package/scripts/agent-eval/run-agent.sh +34 -0
- package/scripts/agent-eval/run-all.sh +75 -0
- package/scripts/agent-eval/run-arms.sh +56 -0
- package/scripts/agent-eval/seq-matrix.mjs +137 -0
- package/scripts/build-bundle.sh +123 -0
- package/scripts/extract-release-notes.mjs +130 -0
- package/scripts/local-install.sh +41 -0
- package/scripts/npm-sdk.js +75 -0
- package/scripts/npm-shim.js +275 -0
- package/scripts/pack-npm.sh +119 -0
- package/scripts/prepare-release.mjs +270 -0
- package/dist/extraction/wasm/tree-sitter-c.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-cpp.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-dart.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-go.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-java.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-javascript.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-kotlin.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-php.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-python.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-ruby.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-rust.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-swift.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-tsx.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-typescript.wasm +0 -0
- package/dist/installer/claude-md-template.d.ts +0 -19
|
@@ -38,33 +38,69 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
38
38
|
};
|
|
39
39
|
})();
|
|
40
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.isNixPathImportRef = isNixPathImportRef;
|
|
41
42
|
exports.resolveImportPath = resolveImportPath;
|
|
43
|
+
exports.clearCppIncludeDirCache = clearCppIncludeDirCache;
|
|
44
|
+
exports.loadCppIncludeDirs = loadCppIncludeDirs;
|
|
45
|
+
exports.isPhpIncludePathRef = isPhpIncludePathRef;
|
|
46
|
+
exports.isCobolCopybookRef = isCobolCopybookRef;
|
|
42
47
|
exports.extractImportMappings = extractImportMappings;
|
|
43
48
|
exports.clearImportMappingCache = clearImportMappingCache;
|
|
44
49
|
exports.extractReExports = extractReExports;
|
|
50
|
+
exports.resolveJvmImport = resolveJvmImport;
|
|
45
51
|
exports.resolveViaImport = resolveViaImport;
|
|
52
|
+
const fs = __importStar(require("fs"));
|
|
46
53
|
const path = __importStar(require("path"));
|
|
47
54
|
const path_aliases_1 = require("./path-aliases");
|
|
55
|
+
const workspace_packages_1 = require("./workspace-packages");
|
|
48
56
|
/**
|
|
49
57
|
* Extension resolution order by language
|
|
50
58
|
*/
|
|
51
59
|
const EXTENSION_RESOLUTION = {
|
|
52
60
|
typescript: ['.ts', '.tsx', '.d.ts', '.js', '.jsx', '/index.ts', '/index.tsx', '/index.js'],
|
|
61
|
+
// ArkTS imports both `.ets` components and plain `.ts` logic modules —
|
|
62
|
+
// HarmonyOS projects are always a mix. `/Index.ets` (capital I) is ohpm's
|
|
63
|
+
// module-entry convention, hit when a bare workspace import ("data") is
|
|
64
|
+
// rewritten to the member's directory; lowercase variants for safety.
|
|
65
|
+
arkts: ['.ets', '.ts', '.d.ts', '.js', '/Index.ets', '/index.ets', '/index.ts', '/index.js'],
|
|
53
66
|
javascript: ['.js', '.jsx', '.mjs', '.cjs', '/index.js', '/index.jsx'],
|
|
54
67
|
tsx: ['.tsx', '.ts', '.d.ts', '.js', '.jsx', '/index.tsx', '/index.ts', '/index.js'],
|
|
55
68
|
jsx: ['.jsx', '.js', '/index.jsx', '/index.js'],
|
|
69
|
+
// SFC consumers import plain TS/JS, sibling components, and barrels
|
|
70
|
+
// (`./lib` → `./lib/index.ts`). Without a list, relative imports from a
|
|
71
|
+
// `.svelte`/`.vue` file resolve to nothing, so barrel callers vanish (#629).
|
|
72
|
+
svelte: ['.ts', '.js', '.svelte', '.tsx', '.jsx', '/index.ts', '/index.js', '/index.svelte'],
|
|
73
|
+
vue: ['.ts', '.js', '.vue', '.tsx', '.jsx', '/index.ts', '/index.js', '/index.vue'],
|
|
74
|
+
astro: ['.ts', '.js', '.astro', '.tsx', '.jsx', '/index.ts', '/index.js', '/index.astro'],
|
|
56
75
|
python: ['.py', '/__init__.py'],
|
|
57
76
|
go: ['.go'],
|
|
58
77
|
rust: ['.rs', '/mod.rs'],
|
|
59
78
|
java: ['.java'],
|
|
79
|
+
c: ['.h', '.c'],
|
|
80
|
+
cpp: ['.h', '.hpp', '.hxx', '.cpp', '.cc', '.cxx'],
|
|
60
81
|
csharp: ['.cs'],
|
|
61
82
|
php: ['.php'],
|
|
62
83
|
ruby: ['.rb'],
|
|
84
|
+
objc: ['.h', '.m', '.mm'],
|
|
85
|
+
nix: ['.nix', '/default.nix'],
|
|
63
86
|
};
|
|
87
|
+
function isNixPathImportRef(ref) {
|
|
88
|
+
return (ref.language === 'nix' &&
|
|
89
|
+
ref.referenceKind === 'imports' &&
|
|
90
|
+
(ref.referenceName.startsWith('./') || ref.referenceName.startsWith('../')) &&
|
|
91
|
+
!/[\s{}()[\];"'<>$]/.test(ref.referenceName));
|
|
92
|
+
}
|
|
64
93
|
/**
|
|
65
94
|
* Resolve an import path to an actual file
|
|
66
95
|
*/
|
|
67
96
|
function resolveImportPath(importPath, fromFile, language, context) {
|
|
97
|
+
// COBOL COPY/EXEC SQL INCLUDE names a copybook member, not a path — the
|
|
98
|
+
// compiler searches a library, so we match against indexed file basenames.
|
|
99
|
+
// Must run before isExternalImport: a bare member name would otherwise be
|
|
100
|
+
// misclassified as an external package.
|
|
101
|
+
if (language === 'cobol') {
|
|
102
|
+
return resolveCobolCopybook(importPath, fromFile, context);
|
|
103
|
+
}
|
|
68
104
|
// Skip external/npm packages — but pass the context so the
|
|
69
105
|
// bare-specifier heuristic can consult the project's tsconfig
|
|
70
106
|
// alias map first (custom prefixes like `@components/*` would
|
|
@@ -79,8 +115,102 @@ function resolveImportPath(importPath, fromFile, language, context) {
|
|
|
79
115
|
return resolveRelativeImport(importPath, fromDir, language, context);
|
|
80
116
|
}
|
|
81
117
|
// Handle absolute/aliased imports (like @/ or src/)
|
|
82
|
-
|
|
118
|
+
const aliased = resolveAliasedImport(importPath, projectRoot, language, context);
|
|
119
|
+
if (aliased)
|
|
120
|
+
return aliased;
|
|
121
|
+
// C/C++ include directory search: when neither relative nor aliased
|
|
122
|
+
// resolution found a match, search -I directories from
|
|
123
|
+
// compile_commands.json or heuristic probing.
|
|
124
|
+
if (language === 'c' || language === 'cpp') {
|
|
125
|
+
return resolveCppIncludePath(importPath, language, context);
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
83
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* COBOL copybook lookup: `COPY CVACT01Y` (or `EXEC SQL INCLUDE X`) names a
|
|
131
|
+
* library member resolved by the compiler's copybook search path, so we match
|
|
132
|
+
* the member against indexed file basenames, case-insensitively. `.cpy` wins
|
|
133
|
+
* over a same-named program; a same-directory hit wins within a tier. The
|
|
134
|
+
* stem index is built once per resolution context (a per-ref scan of every
|
|
135
|
+
* file node would go quadratic on copybook-heavy repos).
|
|
136
|
+
*/
|
|
137
|
+
const cobolCopybookIndexes = new WeakMap();
|
|
138
|
+
function resolveCobolCopybook(member, fromFile, context) {
|
|
139
|
+
let index = cobolCopybookIndexes.get(context);
|
|
140
|
+
if (!index) {
|
|
141
|
+
index = new Map();
|
|
142
|
+
for (const fileNode of context.getNodesByKind('file')) {
|
|
143
|
+
const normalized = fileNode.filePath.replace(/\\/g, '/');
|
|
144
|
+
const base = normalized.split('/').pop() ?? '';
|
|
145
|
+
const dot = base.lastIndexOf('.');
|
|
146
|
+
const stem = (dot > 0 ? base.slice(0, dot) : base).toLowerCase();
|
|
147
|
+
const paths = index.get(stem);
|
|
148
|
+
if (paths)
|
|
149
|
+
paths.push(fileNode.filePath);
|
|
150
|
+
else
|
|
151
|
+
index.set(stem, [fileNode.filePath]);
|
|
152
|
+
}
|
|
153
|
+
cobolCopybookIndexes.set(context, index);
|
|
154
|
+
}
|
|
155
|
+
const candidates = index.get(member.toLowerCase());
|
|
156
|
+
if (!candidates || candidates.length === 0)
|
|
157
|
+
return null;
|
|
158
|
+
const fromDir = fromFile.replace(/\\/g, '/').split('/').slice(0, -1).join('/');
|
|
159
|
+
let best = null;
|
|
160
|
+
let bestScore = -1;
|
|
161
|
+
for (const candidate of candidates) {
|
|
162
|
+
const normalized = candidate.replace(/\\/g, '/');
|
|
163
|
+
const ext = normalized.slice(normalized.lastIndexOf('.')).toLowerCase();
|
|
164
|
+
let score = 0;
|
|
165
|
+
if (ext === '.cpy')
|
|
166
|
+
score += 4;
|
|
167
|
+
else if (ext === '.cbl' || ext === '.cob' || ext === '.cobol')
|
|
168
|
+
score += 2;
|
|
169
|
+
if (normalized.split('/').slice(0, -1).join('/') === fromDir)
|
|
170
|
+
score += 1;
|
|
171
|
+
if (score > bestScore) {
|
|
172
|
+
bestScore = score;
|
|
173
|
+
best = candidate;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return best;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* C and C++ standard library header names (without delimiters).
|
|
180
|
+
* Used by isExternalImport to filter system includes from resolution.
|
|
181
|
+
*/
|
|
182
|
+
const C_CPP_STDLIB_HEADERS = new Set([
|
|
183
|
+
// C standard library headers
|
|
184
|
+
'assert.h', 'complex.h', 'ctype.h', 'errno.h', 'fenv.h', 'float.h',
|
|
185
|
+
'inttypes.h', 'iso646.h', 'limits.h', 'locale.h', 'math.h', 'setjmp.h',
|
|
186
|
+
'signal.h', 'stdalign.h', 'stdarg.h', 'stdatomic.h', 'stdbool.h',
|
|
187
|
+
'stddef.h', 'stdint.h', 'stdio.h', 'stdlib.h', 'stdnoreturn.h',
|
|
188
|
+
'string.h', 'tgmath.h', 'threads.h', 'time.h', 'uchar.h', 'wchar.h',
|
|
189
|
+
'wctype.h',
|
|
190
|
+
// C++ C-library wrappers (cname form)
|
|
191
|
+
'cassert', 'ccomplex', 'cctype', 'cerrno', 'cfenv', 'cfloat',
|
|
192
|
+
'cinttypes', 'ciso646', 'climits', 'clocale', 'cmath', 'csetjmp',
|
|
193
|
+
'csignal', 'cstdalign', 'cstdarg', 'cstdbool', 'cstddef', 'cstdint',
|
|
194
|
+
'cstdio', 'cstdlib', 'cstring', 'ctgmath', 'ctime', 'cuchar',
|
|
195
|
+
'cwchar', 'cwctype',
|
|
196
|
+
// C++ STL headers
|
|
197
|
+
'algorithm', 'any', 'array', 'atomic', 'barrier', 'bit', 'bitset',
|
|
198
|
+
'charconv', 'chrono', 'codecvt', 'compare', 'complex', 'concepts',
|
|
199
|
+
'condition_variable', 'coroutine', 'deque', 'exception', 'execution',
|
|
200
|
+
'expected', 'filesystem', 'format', 'forward_list', 'fstream',
|
|
201
|
+
'functional', 'future', 'generator', 'initializer_list', 'iomanip',
|
|
202
|
+
'ios', 'iosfwd', 'iostream', 'istream', 'iterator', 'latch',
|
|
203
|
+
'limits', 'list', 'locale', 'map', 'mdspan', 'memory', 'memory_resource',
|
|
204
|
+
'mutex', 'new', 'numbers', 'numeric', 'optional', 'ostream', 'print',
|
|
205
|
+
'queue', 'random', 'ranges', 'ratio', 'regex', 'scoped_allocator',
|
|
206
|
+
'semaphore', 'set', 'shared_mutex', 'source_location', 'span',
|
|
207
|
+
'spanstream', 'sstream', 'stack', 'stacktrace', 'stdexcept',
|
|
208
|
+
'stdfloat', 'stop_token', 'streambuf', 'string', 'string_view',
|
|
209
|
+
'strstream', 'syncstream', 'system_error', 'thread', 'tuple',
|
|
210
|
+
'type_traits', 'typeindex', 'typeinfo', 'unordered_map',
|
|
211
|
+
'unordered_set', 'utility', 'valarray', 'variant', 'vector',
|
|
212
|
+
'version',
|
|
213
|
+
]);
|
|
84
214
|
/**
|
|
85
215
|
* Check if an import is external (npm package, etc.)
|
|
86
216
|
*
|
|
@@ -94,8 +224,16 @@ function isExternalImport(importPath, language, context) {
|
|
|
94
224
|
if (importPath.startsWith('.')) {
|
|
95
225
|
return false;
|
|
96
226
|
}
|
|
227
|
+
// Workspace-member imports (`@scope/ui`, `@scope/ui/widgets`) are LOCAL to
|
|
228
|
+
// a monorepo even though they look like bare npm specifiers. Consult the
|
|
229
|
+
// workspace map first so they aren't misclassified as external (#629). The
|
|
230
|
+
// map is null for single-package repos, so this is a no-op there.
|
|
231
|
+
const workspaces = context?.getWorkspacePackages?.();
|
|
232
|
+
if (workspaces && (0, workspace_packages_1.resolveWorkspaceImport)(importPath, workspaces)) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
97
235
|
// Common external patterns
|
|
98
|
-
if (language === 'typescript' || language === 'javascript' || language === 'tsx' || language === 'jsx') {
|
|
236
|
+
if (language === 'typescript' || language === 'javascript' || language === 'tsx' || language === 'jsx' || language === 'arkts') {
|
|
99
237
|
// Node built-ins
|
|
100
238
|
if (['fs', 'path', 'os', 'crypto', 'http', 'https', 'url', 'util', 'events', 'stream', 'child_process', 'buffer'].includes(importPath)) {
|
|
101
239
|
return true;
|
|
@@ -122,10 +260,35 @@ function isExternalImport(importPath, language, context) {
|
|
|
122
260
|
}
|
|
123
261
|
}
|
|
124
262
|
if (language === 'go') {
|
|
125
|
-
//
|
|
126
|
-
if (
|
|
127
|
-
return
|
|
263
|
+
// Relative imports (rare in idiomatic Go but the grammar allows them).
|
|
264
|
+
if (importPath.startsWith('.')) {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
// In-module imports look like `<module-path>/sub/pkg` — local to
|
|
268
|
+
// this project. Without the module-path check we'd flag every
|
|
269
|
+
// cross-package call in a Go monorepo as external (issue #388).
|
|
270
|
+
const mod = context?.getGoModule?.();
|
|
271
|
+
if (mod && (importPath === mod.modulePath || importPath.startsWith(mod.modulePath + '/'))) {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
// `internal/` packages stay local even when go.mod is missing —
|
|
275
|
+
// preserves the pre-#388 escape hatch for repos without a parsed module path.
|
|
276
|
+
if (importPath.includes('/internal/')) {
|
|
277
|
+
return false;
|
|
128
278
|
}
|
|
279
|
+
// Anything else is the Go standard library or a third-party module.
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
if (language === 'c' || language === 'cpp') {
|
|
283
|
+
// C/C++ standard library headers — both C-style (<stdio.h>) and
|
|
284
|
+
// C++-style (<cstdio>, <vector>) forms. Checked against the import
|
|
285
|
+
// path (which the extractor strips of <> or "" delimiters).
|
|
286
|
+
if (C_CPP_STDLIB_HEADERS.has(importPath))
|
|
287
|
+
return true;
|
|
288
|
+
// C++ headers without .h extension (e.g. "vector", "string")
|
|
289
|
+
const withoutExt = importPath.replace(/\.h$/, '');
|
|
290
|
+
if (C_CPP_STDLIB_HEADERS.has(withoutExt))
|
|
291
|
+
return true;
|
|
129
292
|
}
|
|
130
293
|
return false;
|
|
131
294
|
}
|
|
@@ -135,6 +298,25 @@ function isExternalImport(importPath, language, context) {
|
|
|
135
298
|
function resolveRelativeImport(importPath, fromDir, language, context) {
|
|
136
299
|
const projectRoot = context.getProjectRoot();
|
|
137
300
|
const extensions = EXTENSION_RESOLUTION[language] || [];
|
|
301
|
+
// Python dotted-relative imports (`from .certs import x`, `from ..pkg.mod
|
|
302
|
+
// import y`): leading dots are PACKAGE levels (1 = current package), and the
|
|
303
|
+
// remainder is a dotted submodule path. `path.resolve(dir, '.certs')` would
|
|
304
|
+
// treat `.certs` as a literal hidden filename, so translate the Python form
|
|
305
|
+
// to a real filesystem-relative path before resolving.
|
|
306
|
+
if (language === 'python' && importPath.startsWith('.')) {
|
|
307
|
+
const dots = importPath.length - importPath.replace(/^\.+/, '').length;
|
|
308
|
+
const up = '../'.repeat(Math.max(0, dots - 1)); // 1 dot = current dir
|
|
309
|
+
const rest = importPath.slice(dots).replace(/\./g, '/'); // 'sub.mod' -> 'sub/mod'
|
|
310
|
+
const pyBase = path.resolve(fromDir, up + rest);
|
|
311
|
+
const pyRel = path.relative(projectRoot, pyBase).replace(/\\/g, '/');
|
|
312
|
+
for (const ext of extensions) {
|
|
313
|
+
if (context.fileExists(pyRel + ext))
|
|
314
|
+
return pyRel + ext;
|
|
315
|
+
}
|
|
316
|
+
if (pyRel && context.fileExists(pyRel))
|
|
317
|
+
return pyRel;
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
138
320
|
// Try the path as-is first
|
|
139
321
|
const basePath = path.resolve(fromDir, importPath);
|
|
140
322
|
const relativePath = path.relative(projectRoot, basePath).replace(/\\/g, '/');
|
|
@@ -184,6 +366,18 @@ function resolveAliasedImport(importPath, projectRoot, language, context) {
|
|
|
184
366
|
return hit;
|
|
185
367
|
}
|
|
186
368
|
}
|
|
369
|
+
// 1.5 Workspace packages (`@scope/ui/widgets` → `packages/ui/widgets`).
|
|
370
|
+
// Resolves a monorepo member import to the member's directory; the
|
|
371
|
+
// extension/index permutations below then find its barrel (#629).
|
|
372
|
+
const workspaces = context.getWorkspacePackages?.();
|
|
373
|
+
if (workspaces) {
|
|
374
|
+
const base = (0, workspace_packages_1.resolveWorkspaceImport)(importPath, workspaces);
|
|
375
|
+
if (base) {
|
|
376
|
+
const hit = tryWithExt(base);
|
|
377
|
+
if (hit)
|
|
378
|
+
return hit;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
187
381
|
// 2. Hard-coded fallback list. Kept for projects that use these
|
|
188
382
|
// conventional aliases without declaring them in tsconfig.
|
|
189
383
|
const fallbackAliases = {
|
|
@@ -204,12 +398,276 @@ function resolveAliasedImport(importPath, projectRoot, language, context) {
|
|
|
204
398
|
// 3. Direct path.
|
|
205
399
|
return tryWithExt(importPath);
|
|
206
400
|
}
|
|
401
|
+
/**
|
|
402
|
+
* C/C++ include directory cache (keyed by project root).
|
|
403
|
+
* Loaded once per resolver instance, shared across calls.
|
|
404
|
+
*/
|
|
405
|
+
const cppIncludeDirCache = new Map();
|
|
406
|
+
/**
|
|
407
|
+
* Clear the C/C++ include directory cache (call between indexing runs)
|
|
408
|
+
*/
|
|
409
|
+
function clearCppIncludeDirCache() {
|
|
410
|
+
cppIncludeDirCache.clear();
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Discover C/C++ include search directories for a project.
|
|
414
|
+
*
|
|
415
|
+
* Strategy:
|
|
416
|
+
* 1. Look for compile_commands.json (Clang compilation database) in the
|
|
417
|
+
* project root and common build subdirectories. Parse -I and -isystem
|
|
418
|
+
* flags from compiler commands.
|
|
419
|
+
* 2. If no compilation database is found, probe for common convention
|
|
420
|
+
* directories (include/, src/, lib/, api/) and top-level directories
|
|
421
|
+
* containing .h/.hpp files.
|
|
422
|
+
*
|
|
423
|
+
* Returns paths relative to projectRoot.
|
|
424
|
+
*/
|
|
425
|
+
function loadCppIncludeDirs(projectRoot) {
|
|
426
|
+
const cached = cppIncludeDirCache.get(projectRoot);
|
|
427
|
+
if (cached !== undefined)
|
|
428
|
+
return cached;
|
|
429
|
+
const dirs = loadCppIncludeDirsFromCompileDB(projectRoot)
|
|
430
|
+
|| loadCppIncludeDirsHeuristic(projectRoot);
|
|
431
|
+
cppIncludeDirCache.set(projectRoot, dirs);
|
|
432
|
+
return dirs;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Try to load include directories from compile_commands.json.
|
|
436
|
+
* Returns null if no compilation database is found (so the heuristic
|
|
437
|
+
* fallback can run). Returns an array (possibly empty) otherwise.
|
|
438
|
+
*/
|
|
439
|
+
function loadCppIncludeDirsFromCompileDB(projectRoot) {
|
|
440
|
+
const candidates = [
|
|
441
|
+
path.join(projectRoot, 'compile_commands.json'),
|
|
442
|
+
path.join(projectRoot, 'build', 'compile_commands.json'),
|
|
443
|
+
path.join(projectRoot, 'cmake-build-debug', 'compile_commands.json'),
|
|
444
|
+
path.join(projectRoot, 'cmake-build-release', 'compile_commands.json'),
|
|
445
|
+
path.join(projectRoot, 'out', 'compile_commands.json'),
|
|
446
|
+
];
|
|
447
|
+
let dbPath;
|
|
448
|
+
for (const c of candidates) {
|
|
449
|
+
try {
|
|
450
|
+
if (fs.existsSync(c)) {
|
|
451
|
+
dbPath = c;
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
catch {
|
|
456
|
+
// ignore
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
if (!dbPath)
|
|
460
|
+
return null;
|
|
461
|
+
try {
|
|
462
|
+
const content = fs.readFileSync(dbPath, 'utf-8');
|
|
463
|
+
const entries = JSON.parse(content);
|
|
464
|
+
if (!Array.isArray(entries))
|
|
465
|
+
return null;
|
|
466
|
+
const dirSet = new Set();
|
|
467
|
+
for (const entry of entries) {
|
|
468
|
+
const dir = entry.directory || projectRoot;
|
|
469
|
+
const args = entry.arguments || (entry.command ? shlexSplit(entry.command) : []);
|
|
470
|
+
for (let i = 0; i < args.length; i++) {
|
|
471
|
+
const arg = args[i];
|
|
472
|
+
let includeDir;
|
|
473
|
+
// -I<dir> (no space)
|
|
474
|
+
if (arg.startsWith('-I') && arg.length > 2) {
|
|
475
|
+
includeDir = arg.substring(2);
|
|
476
|
+
}
|
|
477
|
+
// -isystem <dir> (space-separated)
|
|
478
|
+
else if ((arg === '-isystem' || arg === '-I') && i + 1 < args.length) {
|
|
479
|
+
includeDir = args[i + 1];
|
|
480
|
+
i++; // skip next arg
|
|
481
|
+
}
|
|
482
|
+
if (includeDir) {
|
|
483
|
+
// Normalize: resolve relative to the compilation directory
|
|
484
|
+
const absPath = path.isAbsolute(includeDir)
|
|
485
|
+
? includeDir
|
|
486
|
+
: path.resolve(dir, includeDir);
|
|
487
|
+
const relPath = path.relative(projectRoot, absPath).replace(/\\/g, '/');
|
|
488
|
+
// Skip system directories and paths outside the project
|
|
489
|
+
// (relative paths starting with .. or absolute paths like
|
|
490
|
+
// /usr/include or C:\usr on Windows)
|
|
491
|
+
if (!relPath.startsWith('..') && relPath.length > 0 && !path.isAbsolute(relPath)) {
|
|
492
|
+
dirSet.add(relPath);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return Array.from(dirSet);
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Minimal shlex-style split for compiler command strings.
|
|
505
|
+
* Handles double-quoted and single-quoted arguments.
|
|
506
|
+
*/
|
|
507
|
+
function shlexSplit(cmd) {
|
|
508
|
+
const result = [];
|
|
509
|
+
let i = 0;
|
|
510
|
+
while (i < cmd.length) {
|
|
511
|
+
// Skip whitespace
|
|
512
|
+
while (i < cmd.length && /\s/.test(cmd[i]))
|
|
513
|
+
i++;
|
|
514
|
+
if (i >= cmd.length)
|
|
515
|
+
break;
|
|
516
|
+
const ch = cmd[i];
|
|
517
|
+
if (ch === '"') {
|
|
518
|
+
i++;
|
|
519
|
+
let arg = '';
|
|
520
|
+
while (i < cmd.length && cmd[i] !== '"') {
|
|
521
|
+
if (cmd[i] === '\\' && i + 1 < cmd.length) {
|
|
522
|
+
i++;
|
|
523
|
+
arg += cmd[i];
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
arg += cmd[i];
|
|
527
|
+
}
|
|
528
|
+
i++;
|
|
529
|
+
}
|
|
530
|
+
i++; // closing quote
|
|
531
|
+
result.push(arg);
|
|
532
|
+
}
|
|
533
|
+
else if (ch === "'") {
|
|
534
|
+
i++;
|
|
535
|
+
let arg = '';
|
|
536
|
+
while (i < cmd.length && cmd[i] !== "'") {
|
|
537
|
+
arg += cmd[i];
|
|
538
|
+
i++;
|
|
539
|
+
}
|
|
540
|
+
i++; // closing quote
|
|
541
|
+
result.push(arg);
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
let arg = '';
|
|
545
|
+
while (i < cmd.length && !/\s/.test(cmd[i])) {
|
|
546
|
+
arg += cmd[i];
|
|
547
|
+
i++;
|
|
548
|
+
}
|
|
549
|
+
result.push(arg);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return result;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Heuristic include directory discovery when no compile_commands.json exists.
|
|
556
|
+
* Checks common convention directories and scans top-level dirs for headers.
|
|
557
|
+
*/
|
|
558
|
+
function loadCppIncludeDirsHeuristic(projectRoot) {
|
|
559
|
+
const dirs = [];
|
|
560
|
+
const conventionDirs = ['include', 'src', 'lib', 'api', 'inc'];
|
|
561
|
+
try {
|
|
562
|
+
const entries = fs.readdirSync(projectRoot, { withFileTypes: true });
|
|
563
|
+
for (const entry of entries) {
|
|
564
|
+
if (!entry.isDirectory())
|
|
565
|
+
continue;
|
|
566
|
+
const name = entry.name;
|
|
567
|
+
// Convention directories
|
|
568
|
+
if (conventionDirs.includes(name.toLowerCase())) {
|
|
569
|
+
dirs.push(name);
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
// Any top-level directory containing .h or .hpp files
|
|
573
|
+
try {
|
|
574
|
+
const subFiles = fs.readdirSync(path.join(projectRoot, name));
|
|
575
|
+
if (subFiles.some(f => /\.(h|hpp|hxx|hh)$/i.test(f))) {
|
|
576
|
+
dirs.push(name);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
catch {
|
|
580
|
+
// ignore permission errors
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
catch {
|
|
585
|
+
// ignore
|
|
586
|
+
}
|
|
587
|
+
return dirs;
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Resolve a C/C++ include path by searching include directories.
|
|
591
|
+
* Called as a fallback after relative and aliased resolution fail.
|
|
592
|
+
*/
|
|
593
|
+
function resolveCppIncludePath(importPath, language, context) {
|
|
594
|
+
const includeDirs = context.getCppIncludeDirs?.() ?? [];
|
|
595
|
+
const extensions = EXTENSION_RESOLUTION[language] ?? [];
|
|
596
|
+
for (const dir of includeDirs) {
|
|
597
|
+
const normalizedDir = dir.replace(/\\/g, '/');
|
|
598
|
+
for (const ext of extensions) {
|
|
599
|
+
const candidate = normalizedDir + '/' + importPath + ext;
|
|
600
|
+
if (context.fileExists(candidate))
|
|
601
|
+
return candidate;
|
|
602
|
+
}
|
|
603
|
+
// Try as-is (already has extension)
|
|
604
|
+
const candidate = normalizedDir + '/' + importPath;
|
|
605
|
+
if (context.fileExists(candidate))
|
|
606
|
+
return candidate;
|
|
607
|
+
}
|
|
608
|
+
return null;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Is this reference a PHP include/require PATH (vs a namespace `use` symbol)?
|
|
612
|
+
*
|
|
613
|
+
* include/require emit a file path ("lib.php", "inc/db.php", "../x.php"),
|
|
614
|
+
* whereas namespace use is an FQN (App\Foo\Bar) or a bare class symbol
|
|
615
|
+
* (Closure). PHP identifiers contain neither '/' nor '.', so a slash or dot
|
|
616
|
+
* marks a path-shaped include. Such references resolve to files only — never
|
|
617
|
+
* to a same-named symbol — so callers must not fall back to the name-matcher.
|
|
618
|
+
*/
|
|
619
|
+
function isPhpIncludePathRef(ref) {
|
|
620
|
+
return (ref.language === 'php' &&
|
|
621
|
+
ref.referenceKind === 'imports' &&
|
|
622
|
+
(ref.referenceName.includes('/') || ref.referenceName.includes('.')));
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Is this a COBOL COPY / EXEC SQL INCLUDE copybook reference? These resolve
|
|
626
|
+
* to files only (or stay unresolved for compiler-supplied members) — never
|
|
627
|
+
* to a same-named symbol via the name-matcher.
|
|
628
|
+
*/
|
|
629
|
+
function isCobolCopybookRef(ref) {
|
|
630
|
+
return ref.language === 'cobol' && ref.referenceKind === 'imports';
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Resolve a PHP include/require path to a project-relative file path.
|
|
634
|
+
*
|
|
635
|
+
* PHP resolves includes relative to the including file's directory (the
|
|
636
|
+
* common case for procedural codebases); php.ini `include_path` is not
|
|
637
|
+
* modeled. Callers pass an already-extracted static literal path.
|
|
638
|
+
*/
|
|
639
|
+
function resolvePhpIncludePath(includePath, fromFile, context) {
|
|
640
|
+
const projectRoot = context.getProjectRoot();
|
|
641
|
+
const fromDir = path.dirname(path.join(projectRoot, fromFile));
|
|
642
|
+
const basePath = path.resolve(fromDir, includePath);
|
|
643
|
+
const relativePath = path.relative(projectRoot, basePath).replace(/\\/g, '/');
|
|
644
|
+
if (context.fileExists(relativePath))
|
|
645
|
+
return relativePath;
|
|
646
|
+
// The literal may omit the .php extension (e.g. include "config").
|
|
647
|
+
for (const ext of EXTENSION_RESOLUTION.php ?? []) {
|
|
648
|
+
if (context.fileExists(relativePath + ext))
|
|
649
|
+
return relativePath + ext;
|
|
650
|
+
}
|
|
651
|
+
return null;
|
|
652
|
+
}
|
|
207
653
|
/**
|
|
208
654
|
* Extract import mappings from a file
|
|
209
655
|
*/
|
|
210
656
|
function extractImportMappings(_filePath, content, language) {
|
|
211
657
|
const mappings = [];
|
|
212
|
-
if (language === 'typescript' || language === 'javascript' || language === 'tsx' || language === 'jsx') {
|
|
658
|
+
if (language === 'typescript' || language === 'javascript' || language === 'tsx' || language === 'jsx' || language === 'arkts') {
|
|
659
|
+
mappings.push(...extractJSImports(content));
|
|
660
|
+
}
|
|
661
|
+
else if (language === 'svelte' || language === 'vue' || language === 'astro') {
|
|
662
|
+
// Svelte/Vue single-file components import via plain ES6 inside their
|
|
663
|
+
// `<script>` block (Astro: the `---` frontmatter). Without this, a
|
|
664
|
+
// `.svelte`/`.vue`/`.astro` consumer produces
|
|
665
|
+
// zero import mappings, so `resolveViaImport` can't run and a barrel
|
|
666
|
+
// import (`import { Foo } from './lib'`) falls back to name-matching —
|
|
667
|
+
// which silently fails whenever the re-export alias differs from the
|
|
668
|
+
// component's real name, yielding a false 0 callers (#629). The ES6
|
|
669
|
+
// import regex only matches `import … from '…'`, so running it over the
|
|
670
|
+
// whole SFC (markup + styles included) is safe.
|
|
213
671
|
mappings.push(...extractJSImports(content));
|
|
214
672
|
}
|
|
215
673
|
else if (language === 'python') {
|
|
@@ -218,9 +676,15 @@ function extractImportMappings(_filePath, content, language) {
|
|
|
218
676
|
else if (language === 'go') {
|
|
219
677
|
mappings.push(...extractGoImports(content));
|
|
220
678
|
}
|
|
679
|
+
else if (language === 'java' || language === 'kotlin') {
|
|
680
|
+
mappings.push(...extractJavaImports(content));
|
|
681
|
+
}
|
|
221
682
|
else if (language === 'php') {
|
|
222
683
|
mappings.push(...extractPHPImports(content));
|
|
223
684
|
}
|
|
685
|
+
else if (language === 'c' || language === 'cpp') {
|
|
686
|
+
mappings.push(...extractCppImports(content));
|
|
687
|
+
}
|
|
224
688
|
return mappings;
|
|
225
689
|
}
|
|
226
690
|
/**
|
|
@@ -406,6 +870,50 @@ function extractGoImports(content) {
|
|
|
406
870
|
}
|
|
407
871
|
return mappings;
|
|
408
872
|
}
|
|
873
|
+
/**
|
|
874
|
+
* Extract Java / Kotlin import mappings.
|
|
875
|
+
*
|
|
876
|
+
* Java/Kotlin imports carry the full qualified name of the imported
|
|
877
|
+
* symbol — `import com.example.dao.converter.FooConverter;` — which is
|
|
878
|
+
* exactly the disambiguation signal we need when two packages both
|
|
879
|
+
* declare a `FooConverter`. Pre-#314 the resolver had no Java branch
|
|
880
|
+
* here at all, so this mapping was empty and cross-module name
|
|
881
|
+
* collisions were resolved by file-path proximity (often wrongly).
|
|
882
|
+
*
|
|
883
|
+
* `import static com.example.Foo.bar;` is parsed as a local-name `bar`
|
|
884
|
+
* pointing at FQN `com.example.Foo.bar` so static-method call sites
|
|
885
|
+
* (`bar(...)`) can resolve through the same import lookup.
|
|
886
|
+
*/
|
|
887
|
+
function extractJavaImports(content) {
|
|
888
|
+
const mappings = [];
|
|
889
|
+
// Strip line and block comments so `// import foo;` doesn't false-match.
|
|
890
|
+
const stripped = content
|
|
891
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
892
|
+
.replace(/\/\/[^\n]*/g, '');
|
|
893
|
+
// `import [static] <fqn>[.*];`
|
|
894
|
+
const re = /^\s*import\s+(static\s+)?([\w.]+(?:\.\*)?)\s*;/gm;
|
|
895
|
+
let match;
|
|
896
|
+
while ((match = re.exec(stripped)) !== null) {
|
|
897
|
+
const fqn = match[2];
|
|
898
|
+
// `import com.example.*;` — wildcard. We can't materialize a single
|
|
899
|
+
// local name; skip and let name-matching handle members reachable
|
|
900
|
+
// through the wildcard. (Future enhancement: enumerate package files.)
|
|
901
|
+
if (fqn.endsWith('.*'))
|
|
902
|
+
continue;
|
|
903
|
+
const parts = fqn.split('.');
|
|
904
|
+
const localName = parts[parts.length - 1];
|
|
905
|
+
if (!localName)
|
|
906
|
+
continue;
|
|
907
|
+
mappings.push({
|
|
908
|
+
localName,
|
|
909
|
+
exportedName: localName,
|
|
910
|
+
source: fqn,
|
|
911
|
+
isDefault: false,
|
|
912
|
+
isNamespace: false,
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
return mappings;
|
|
916
|
+
}
|
|
409
917
|
/**
|
|
410
918
|
* Extract PHP import mappings (use statements)
|
|
411
919
|
*/
|
|
@@ -427,6 +935,34 @@ function extractPHPImports(content) {
|
|
|
427
935
|
}
|
|
428
936
|
return mappings;
|
|
429
937
|
}
|
|
938
|
+
/**
|
|
939
|
+
* Extract C/C++ import mappings from #include directives.
|
|
940
|
+
*
|
|
941
|
+
* #include brings all symbols from the included header into scope
|
|
942
|
+
* (namespace import), so each mapping uses isNamespace: true and
|
|
943
|
+
* exportedName: '*'. The localName is set to the header's basename
|
|
944
|
+
* without extension so that symbol references like `MyClass` can
|
|
945
|
+
* match against any include that might provide it.
|
|
946
|
+
*/
|
|
947
|
+
function extractCppImports(content) {
|
|
948
|
+
const mappings = [];
|
|
949
|
+
// Match both #include <...> and #include "..."
|
|
950
|
+
const includeRegex = /^\s*#\s*include\s+[<"]([^>"]+)[>"]/gm;
|
|
951
|
+
let match;
|
|
952
|
+
while ((match = includeRegex.exec(content)) !== null) {
|
|
953
|
+
const modulePath = match[1];
|
|
954
|
+
// Basename without extension for localName matching
|
|
955
|
+
const basename = modulePath.split('/').pop().replace(/\.(h|hpp|hxx|hh|inl|ipp|cxx|cc|cpp)$/, '');
|
|
956
|
+
mappings.push({
|
|
957
|
+
localName: basename || modulePath,
|
|
958
|
+
exportedName: '*',
|
|
959
|
+
source: modulePath,
|
|
960
|
+
isDefault: false,
|
|
961
|
+
isNamespace: true,
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
return mappings;
|
|
965
|
+
}
|
|
430
966
|
// Cache import mappings per file to avoid re-reading and re-parsing
|
|
431
967
|
const importMappingCache = new Map();
|
|
432
968
|
/**
|
|
@@ -434,6 +970,7 @@ const importMappingCache = new Map();
|
|
|
434
970
|
*/
|
|
435
971
|
function clearImportMappingCache() {
|
|
436
972
|
importMappingCache.clear();
|
|
973
|
+
cppIncludeDirCache.clear();
|
|
437
974
|
}
|
|
438
975
|
/**
|
|
439
976
|
* Strip JS line + block comments from `content` while preserving
|
|
@@ -507,7 +1044,8 @@ function extractReExports(content, language) {
|
|
|
507
1044
|
if (language !== 'typescript' &&
|
|
508
1045
|
language !== 'javascript' &&
|
|
509
1046
|
language !== 'tsx' &&
|
|
510
|
-
language !== 'jsx'
|
|
1047
|
+
language !== 'jsx' &&
|
|
1048
|
+
language !== 'arkts') {
|
|
511
1049
|
return [];
|
|
512
1050
|
}
|
|
513
1051
|
const out = [];
|
|
@@ -556,12 +1094,269 @@ function extractReExports(content, language) {
|
|
|
556
1094
|
/**
|
|
557
1095
|
* Resolve a reference using import mappings
|
|
558
1096
|
*/
|
|
1097
|
+
/**
|
|
1098
|
+
* JVM (Java / Kotlin) imports use fully-qualified names (`import
|
|
1099
|
+
* com.example.foo.Bar`) decoupled from filenames, so the JS/Python
|
|
1100
|
+
* style filesystem path lookup misses them whenever the file isn't
|
|
1101
|
+
* named after its primary symbol (Kotlin `Utils.kt` exporting `Bar`,
|
|
1102
|
+
* top-level fns, extension fns). Resolve them through the
|
|
1103
|
+
* `qualifiedName` index instead — populated by the package_header /
|
|
1104
|
+
* package_declaration namespace wrappers in the extractor.
|
|
1105
|
+
*/
|
|
1106
|
+
function resolveJvmImport(ref, context) {
|
|
1107
|
+
if (ref.referenceKind !== 'imports')
|
|
1108
|
+
return null;
|
|
1109
|
+
if (ref.language !== 'java' && ref.language !== 'kotlin')
|
|
1110
|
+
return null;
|
|
1111
|
+
const fqn = ref.referenceName;
|
|
1112
|
+
const lastDot = fqn.lastIndexOf('.');
|
|
1113
|
+
if (lastDot <= 0)
|
|
1114
|
+
return null;
|
|
1115
|
+
const pkg = fqn.substring(0, lastDot);
|
|
1116
|
+
const sym = fqn.substring(lastDot + 1);
|
|
1117
|
+
// Wildcard imports (`com.example.*`) deliberately punt to name-matcher.
|
|
1118
|
+
if (sym === '*')
|
|
1119
|
+
return null;
|
|
1120
|
+
const candidates = context.getNodesByQualifiedName(`${pkg}::${sym}`);
|
|
1121
|
+
if (candidates.length === 0)
|
|
1122
|
+
return null;
|
|
1123
|
+
// Kotlin Multiplatform: an `expect` declaration and its `actual`s share one
|
|
1124
|
+
// FQN across source sets (commonMain / androidMain / appleMain). Taking the
|
|
1125
|
+
// first candidate let a single platform `actual` absorb every common-side
|
|
1126
|
+
// import, so the `expect` (the canonical API a commonMain file imports)
|
|
1127
|
+
// looked unused. Prefer the candidate CLOSEST to the importing file by
|
|
1128
|
+
// directory proximity — a commonMain import resolves to the commonMain
|
|
1129
|
+
// declaration — with the `expect` side as a tiebreak.
|
|
1130
|
+
const best = candidates.length === 1 ? candidates[0] : pickClosestJvmCandidate(candidates, ref.filePath);
|
|
1131
|
+
return {
|
|
1132
|
+
original: ref,
|
|
1133
|
+
targetNodeId: best.id,
|
|
1134
|
+
confidence: 0.95,
|
|
1135
|
+
resolvedBy: 'import',
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
/**
|
|
1139
|
+
* Pick the same-FQN candidate closest to `fromPath` by shared directory
|
|
1140
|
+
* prefix, preferring an `expect` declaration on a tie. Used to keep a Kotlin
|
|
1141
|
+
* Multiplatform `expect`/`actual` import resolving within the importer's own
|
|
1142
|
+
* source set instead of an arbitrary platform `actual`.
|
|
1143
|
+
*/
|
|
1144
|
+
function pickClosestJvmCandidate(candidates, fromPath) {
|
|
1145
|
+
const fromDirs = fromPath.split('/').slice(0, -1);
|
|
1146
|
+
const sharedPrefix = (p) => {
|
|
1147
|
+
const d = p.split('/').slice(0, -1);
|
|
1148
|
+
let shared = 0;
|
|
1149
|
+
for (let i = 0; i < Math.min(fromDirs.length, d.length); i++) {
|
|
1150
|
+
if (fromDirs[i] === d[i])
|
|
1151
|
+
shared++;
|
|
1152
|
+
else
|
|
1153
|
+
break;
|
|
1154
|
+
}
|
|
1155
|
+
return shared;
|
|
1156
|
+
};
|
|
1157
|
+
const isExpect = (n) => Array.isArray(n.decorators) && n.decorators.includes('expect');
|
|
1158
|
+
let best = candidates[0];
|
|
1159
|
+
let bestProx = sharedPrefix(best.filePath);
|
|
1160
|
+
for (let i = 1; i < candidates.length; i++) {
|
|
1161
|
+
const c = candidates[i];
|
|
1162
|
+
const prox = sharedPrefix(c.filePath);
|
|
1163
|
+
if (prox > bestProx || (prox === bestProx && isExpect(c) && !isExpect(best))) {
|
|
1164
|
+
best = c;
|
|
1165
|
+
bestProx = prox;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
return best;
|
|
1169
|
+
}
|
|
559
1170
|
function resolveViaImport(ref, context) {
|
|
1171
|
+
// C/C++ #include references — resolve directly to the included file
|
|
1172
|
+
// (file→file edge), bypassing symbol lookup. The extractor emits these
|
|
1173
|
+
// with `referenceKind: 'imports'` and `referenceName: <include path>`
|
|
1174
|
+
// (e.g. "uint256.h" or "common/args.h"). Without this branch the
|
|
1175
|
+
// include-dir scan path inside resolveImportPath never produces an
|
|
1176
|
+
// edge — resolveViaImport's symbol lookup below would search the
|
|
1177
|
+
// resolved file for a symbol named like the file extension and fail.
|
|
1178
|
+
if ((ref.language === 'c' || ref.language === 'cpp') && ref.referenceKind === 'imports') {
|
|
1179
|
+
// C/C++ quoted includes (`#include "X.h"`) resolve relative to the
|
|
1180
|
+
// INCLUDING file's own directory first (the C standard's quoted-include
|
|
1181
|
+
// search order). Prefer a same-directory header over an -I directory or a
|
|
1182
|
+
// same-named header on another platform (windows/code/RNCAsyncStorage.h vs
|
|
1183
|
+
// apple/.../RNCAsyncStorage.h) — the include-dir heuristic below would
|
|
1184
|
+
// otherwise pick an arbitrary same-named header, leaving the real local one
|
|
1185
|
+
// with no dependents.
|
|
1186
|
+
const slash = ref.filePath.lastIndexOf('/');
|
|
1187
|
+
const fromDir = slash >= 0 ? ref.filePath.slice(0, slash) : '';
|
|
1188
|
+
const siblingPath = path.posix.normalize(fromDir ? `${fromDir}/${ref.referenceName}` : ref.referenceName);
|
|
1189
|
+
const siblingBase = siblingPath.split('/').pop();
|
|
1190
|
+
const sibling = context
|
|
1191
|
+
.getNodesByName(siblingBase)
|
|
1192
|
+
.find((n) => n.kind === 'file' && n.filePath === siblingPath);
|
|
1193
|
+
if (sibling) {
|
|
1194
|
+
return { original: ref, targetNodeId: sibling.id, confidence: 0.92, resolvedBy: 'import' };
|
|
1195
|
+
}
|
|
1196
|
+
const resolvedPath = resolveImportPath(ref.referenceName, ref.filePath, ref.language, context);
|
|
1197
|
+
if (!resolvedPath)
|
|
1198
|
+
return null;
|
|
1199
|
+
const basename = resolvedPath.split('/').pop();
|
|
1200
|
+
const fileNodes = context.getNodesByName(basename).filter((n) => n.kind === 'file');
|
|
1201
|
+
const fileNode = fileNodes.find((n) => n.filePath === resolvedPath);
|
|
1202
|
+
if (fileNode) {
|
|
1203
|
+
return {
|
|
1204
|
+
original: ref,
|
|
1205
|
+
targetNodeId: fileNode.id,
|
|
1206
|
+
confidence: 0.9,
|
|
1207
|
+
resolvedBy: 'import',
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
return null;
|
|
1211
|
+
}
|
|
1212
|
+
// COBOL COPY / EXEC SQL INCLUDE — resolve the copybook member to a
|
|
1213
|
+
// file→file edge, mirroring the C/C++ include branch above. A member that
|
|
1214
|
+
// matches no indexed file (compiler-supplied copybooks like SQLCA/DFHAID)
|
|
1215
|
+
// stays unresolved — callers must not fall back to the symbol name-matcher,
|
|
1216
|
+
// which would connect it to a same-named import symbol elsewhere.
|
|
1217
|
+
if (isCobolCopybookRef(ref)) {
|
|
1218
|
+
const resolvedPath = resolveImportPath(ref.referenceName, ref.filePath, ref.language, context);
|
|
1219
|
+
if (!resolvedPath)
|
|
1220
|
+
return null;
|
|
1221
|
+
const basename = resolvedPath.split('/').pop();
|
|
1222
|
+
const fileNode = context
|
|
1223
|
+
.getNodesByName(basename)
|
|
1224
|
+
.find((n) => n.kind === 'file' && n.filePath === resolvedPath);
|
|
1225
|
+
if (fileNode) {
|
|
1226
|
+
return {
|
|
1227
|
+
original: ref,
|
|
1228
|
+
targetNodeId: fileNode.id,
|
|
1229
|
+
confidence: 0.9,
|
|
1230
|
+
resolvedBy: 'import',
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
return null;
|
|
1234
|
+
}
|
|
1235
|
+
// PHP include/require — resolve the static string path to a file→file
|
|
1236
|
+
// edge, mirroring the C/C++ branch above. Distinguish include PATHS from
|
|
1237
|
+
// namespace `use` symbols by shape: an include path contains a slash or a
|
|
1238
|
+
// file extension ("lib.php", "inc/db.php", "../x.php"), whereas a namespace
|
|
1239
|
+
// use is an FQN (App\Foo\Bar) or a bare class symbol (Closure) — PHP
|
|
1240
|
+
// identifiers contain neither '/' nor '.'. Only path-shaped references are
|
|
1241
|
+
// includes; symbol references fall through to the namespace resolution.
|
|
1242
|
+
if (isPhpIncludePathRef(ref)) {
|
|
1243
|
+
const resolvedPath = resolvePhpIncludePath(ref.referenceName, ref.filePath, context);
|
|
1244
|
+
if (resolvedPath) {
|
|
1245
|
+
const basename = resolvedPath.split('/').pop();
|
|
1246
|
+
const fileNode = context
|
|
1247
|
+
.getNodesByName(basename)
|
|
1248
|
+
.find((n) => n.kind === 'file' && n.filePath === resolvedPath);
|
|
1249
|
+
if (fileNode) {
|
|
1250
|
+
return {
|
|
1251
|
+
original: ref,
|
|
1252
|
+
targetNodeId: fileNode.id,
|
|
1253
|
+
confidence: 0.9,
|
|
1254
|
+
resolvedBy: 'import',
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
// A path-shaped include that doesn't resolve to a known project file is a
|
|
1259
|
+
// dead end. Return unresolved rather than falling through to the symbol
|
|
1260
|
+
// name-matcher, which would mis-connect e.g. "inc/db.php" to an unrelated
|
|
1261
|
+
// db.php elsewhere in the tree — a wrong edge is worse than a missing one.
|
|
1262
|
+
return null;
|
|
1263
|
+
}
|
|
1264
|
+
// Nix static project-path imports (`import ./x.nix`, `builtins.import ./dir`,
|
|
1265
|
+
// `import ./x.nix {}`) resolve to file nodes only. Do not resolve
|
|
1266
|
+
// angle-bracket channels, attribute expressions, variables, or other dynamic
|
|
1267
|
+
// expressions as project files.
|
|
1268
|
+
if (isNixPathImportRef(ref)) {
|
|
1269
|
+
const resolvedPath = resolveImportPath(ref.referenceName, ref.filePath, ref.language, context);
|
|
1270
|
+
if (!resolvedPath)
|
|
1271
|
+
return null;
|
|
1272
|
+
const basename = resolvedPath.split('/').pop();
|
|
1273
|
+
const fileNode = context
|
|
1274
|
+
.getNodesByName(basename)
|
|
1275
|
+
.find((n) => n.kind === 'file' && n.filePath === resolvedPath);
|
|
1276
|
+
if (fileNode) {
|
|
1277
|
+
return {
|
|
1278
|
+
original: ref,
|
|
1279
|
+
targetNodeId: fileNode.id,
|
|
1280
|
+
confidence: 0.9,
|
|
1281
|
+
resolvedBy: 'import',
|
|
1282
|
+
};
|
|
1283
|
+
}
|
|
1284
|
+
return null;
|
|
1285
|
+
}
|
|
560
1286
|
// Use cached import mappings (avoids re-reading and re-parsing per ref)
|
|
561
1287
|
const imports = context.getImportMappings(ref.filePath, ref.language);
|
|
562
1288
|
if (imports.length === 0 && !context.readFile(ref.filePath)) {
|
|
563
1289
|
return null;
|
|
564
1290
|
}
|
|
1291
|
+
// Go cross-package calls: `pkga.FuncX(...)` extracts to referenceName
|
|
1292
|
+
// `pkga.FuncX` and the import `github.com/example/myproject/pkga`
|
|
1293
|
+
// maps to a *package directory* containing one or more .go files.
|
|
1294
|
+
// The generic file-based lookup below can't follow that — issue #388.
|
|
1295
|
+
if (ref.language === 'go') {
|
|
1296
|
+
const goResult = resolveGoCrossPackageReference(ref, imports, context);
|
|
1297
|
+
if (goResult)
|
|
1298
|
+
return goResult;
|
|
1299
|
+
}
|
|
1300
|
+
// Java / Kotlin: imports are FQNs (`import com.example.Foo;`) — no
|
|
1301
|
+
// resolvable file path the JS/TS-style chain below could follow. Look
|
|
1302
|
+
// up the symbol by name and filter to the candidate whose file path
|
|
1303
|
+
// matches the imported FQN. This is the disambiguation signal that
|
|
1304
|
+
// breaks the same-name class collision the path-proximity matcher
|
|
1305
|
+
// can't resolve (issue #314).
|
|
1306
|
+
if (ref.language === 'java' || ref.language === 'kotlin') {
|
|
1307
|
+
const javaResult = resolveJavaImportedReference(ref, imports, context);
|
|
1308
|
+
if (javaResult)
|
|
1309
|
+
return javaResult;
|
|
1310
|
+
}
|
|
1311
|
+
// Python qualified access through an imported MODULE: `certs.where()` after
|
|
1312
|
+
// `from . import certs`, `mod.func()` after `import mod`. The receiver names a
|
|
1313
|
+
// submodule (a file), not a symbol, so the generic symbol lookup below would
|
|
1314
|
+
// search the *package* for `certs` instead of looking inside the module.
|
|
1315
|
+
if (ref.language === 'python') {
|
|
1316
|
+
const pyResult = resolvePythonModuleMember(ref, imports, context);
|
|
1317
|
+
if (pyResult)
|
|
1318
|
+
return pyResult;
|
|
1319
|
+
// Absolute dotted module import: `import conduit.apps.articles.signals`
|
|
1320
|
+
// (the standard Django AppConfig.ready() signal-registration pattern, and
|
|
1321
|
+
// any side-effect `import pkg.mod`). Map the dotted path to its file.
|
|
1322
|
+
const pyModResult = resolvePythonAbsoluteModule(ref, context);
|
|
1323
|
+
if (pyModResult)
|
|
1324
|
+
return pyModResult;
|
|
1325
|
+
}
|
|
1326
|
+
// Rust qualified path: resolve the module prefix of `crate::m::Item` /
|
|
1327
|
+
// `self::sub::Item` / `super::m::func` to a file, then find the leaf symbol in
|
|
1328
|
+
// it. Disambiguates common-name `pub use self::read::read` re-exports that
|
|
1329
|
+
// name-matching would land on the wrong same-named symbol.
|
|
1330
|
+
if (ref.language === 'rust' && ref.referenceName.includes('::')) {
|
|
1331
|
+
const rustResult = resolveRustPathReference(ref, context);
|
|
1332
|
+
if (rustResult)
|
|
1333
|
+
return rustResult;
|
|
1334
|
+
}
|
|
1335
|
+
// Lua / Luau `require(...)`: a dotted module path (`a.b.c` from
|
|
1336
|
+
// `require("a.b.c")`) or an instance-path leaf (`Signal` from
|
|
1337
|
+
// `require(script.Parent.Signal)`) — map it to a module file. There's no static
|
|
1338
|
+
// import statement, so the generic path-matcher can't bridge the dot↔slash /
|
|
1339
|
+
// leaf↔basename gap; resolve it explicitly to the module file.
|
|
1340
|
+
if ((ref.language === 'lua' || ref.language === 'luau') && ref.referenceKind === 'imports') {
|
|
1341
|
+
const luaResult = resolveLuaRequire(ref, context);
|
|
1342
|
+
if (luaResult)
|
|
1343
|
+
return luaResult;
|
|
1344
|
+
}
|
|
1345
|
+
// Whole-module / namespace imports → link the importing file to the module
|
|
1346
|
+
// file. Python `from . import certs` / `import mod`, and TS/JS `import * as ns
|
|
1347
|
+
// from './x'` (so a namespace touched only via a value-member read still
|
|
1348
|
+
// records the dependency). A named TS/JS import returns null here and falls
|
|
1349
|
+
// through to symbol resolution below.
|
|
1350
|
+
if (ref.language === 'python' ||
|
|
1351
|
+
ref.language === 'typescript' ||
|
|
1352
|
+
ref.language === 'tsx' ||
|
|
1353
|
+
ref.language === 'javascript' ||
|
|
1354
|
+
ref.language === 'jsx' ||
|
|
1355
|
+
ref.language === 'arkts') {
|
|
1356
|
+
const moduleFile = resolveModuleImportToFile(ref, imports, context);
|
|
1357
|
+
if (moduleFile)
|
|
1358
|
+
return moduleFile;
|
|
1359
|
+
}
|
|
565
1360
|
// Check if the reference name matches any import
|
|
566
1361
|
for (const imp of imports) {
|
|
567
1362
|
if (imp.localName === ref.referenceName || ref.referenceName.startsWith(imp.localName + '.')) {
|
|
@@ -574,6 +1369,24 @@ function resolveViaImport(ref, context) {
|
|
|
574
1369
|
: null;
|
|
575
1370
|
const targetNode = findExportedSymbol(resolvedPath, { isDefault: imp.isDefault, isNamespace: imp.isNamespace, exportedName, memberName }, ref.language, context, new Set());
|
|
576
1371
|
if (targetNode) {
|
|
1372
|
+
// `Foo.bar()` / `Foo.CONST` — a NAMED (non-namespace) class import
|
|
1373
|
+
// accessed through a member. `findExportedSymbol` resolved `Foo` to
|
|
1374
|
+
// the class itself; descend into it so the reference links to the
|
|
1375
|
+
// member `bar`, not the class. Without this the edge points at the
|
|
1376
|
+
// class and `createEdges` then mis-promotes the call to an
|
|
1377
|
+
// `instantiates` edge, so the static method shows zero callers and a
|
|
1378
|
+
// hollow impact radius. (#825)
|
|
1379
|
+
if (!imp.isNamespace && ref.referenceName.startsWith(imp.localName + '.')) {
|
|
1380
|
+
const memberNode = resolveStaticMember(targetNode, ref, imp.localName, context);
|
|
1381
|
+
if (memberNode) {
|
|
1382
|
+
return {
|
|
1383
|
+
original: ref,
|
|
1384
|
+
targetNodeId: memberNode.id,
|
|
1385
|
+
confidence: 0.9,
|
|
1386
|
+
resolvedBy: 'import',
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
577
1390
|
return {
|
|
578
1391
|
original: ref,
|
|
579
1392
|
targetNodeId: targetNode.id,
|
|
@@ -586,6 +1399,459 @@ function resolveViaImport(ref, context) {
|
|
|
586
1399
|
}
|
|
587
1400
|
return null;
|
|
588
1401
|
}
|
|
1402
|
+
/**
|
|
1403
|
+
* Resolve a Python qualified reference whose receiver is an imported MODULE:
|
|
1404
|
+
* `certs.where()` after `from . import certs`, `mod.func()` after `import mod`
|
|
1405
|
+
* or `from pkg import mod`. The receiver names a submodule (a file), not a
|
|
1406
|
+
* symbol, so the generic symbol lookup in `resolveViaImport` can't follow it —
|
|
1407
|
+
* it would search the *package* for `certs`/`mod` instead of looking inside the
|
|
1408
|
+
* module. This is the Python half of the cross-package qualified-call problem
|
|
1409
|
+
* (cf. `resolveGoCrossPackageReference` for Go's `pkg.Func`, issue #388).
|
|
1410
|
+
*
|
|
1411
|
+
* Builds the module's dotted import path from the binding — `from . import
|
|
1412
|
+
* certs` → `.certs`; `from pkg import mod` → `pkg.mod`; `import mod` → `mod` —
|
|
1413
|
+
* resolves it to the module file, and finds the member defined there. Returns
|
|
1414
|
+
* null when no module file exists at that path, so attribute access on an
|
|
1415
|
+
* imported *value* (`helper.attr` where `helper` is a function) falls through
|
|
1416
|
+
* to the other strategies untouched.
|
|
1417
|
+
*/
|
|
1418
|
+
function resolvePythonModuleMember(ref, imports, context) {
|
|
1419
|
+
const dotIdx = ref.referenceName.indexOf('.');
|
|
1420
|
+
if (dotIdx <= 0)
|
|
1421
|
+
return null;
|
|
1422
|
+
const receiver = ref.referenceName.substring(0, dotIdx);
|
|
1423
|
+
// The immediate member of the module (first segment after the receiver).
|
|
1424
|
+
const member = ref.referenceName.substring(dotIdx + 1).split('.')[0];
|
|
1425
|
+
if (!member)
|
|
1426
|
+
return null;
|
|
1427
|
+
for (const imp of imports) {
|
|
1428
|
+
if (imp.localName !== receiver)
|
|
1429
|
+
continue;
|
|
1430
|
+
// `import mod` / `import numpy as np` bind the module at `source` itself;
|
|
1431
|
+
// `from . import certs` / `from pkg import mod` bind a SUBMODULE whose
|
|
1432
|
+
// dotted path is the source joined with the imported name.
|
|
1433
|
+
const modulePath = imp.isNamespace
|
|
1434
|
+
? imp.source
|
|
1435
|
+
: imp.source.endsWith('.')
|
|
1436
|
+
? imp.source + imp.localName
|
|
1437
|
+
: imp.source + '.' + imp.localName;
|
|
1438
|
+
// resolveImportPath only maps RELATIVE dotted paths (`.mod`, `..pkg.mod`); an
|
|
1439
|
+
// ABSOLUTE package path (`pkg.module` from `from pkg import module`, or a bare
|
|
1440
|
+
// `import pkg.mod`) resolves to null there, so fall back to the dotted-module
|
|
1441
|
+
// file lookup — the same asymmetry resolveModuleImportToFile already handles
|
|
1442
|
+
// for the file→file import edge. Without this, a `module.func()` call after
|
|
1443
|
+
// `from pkg import module` dropped its `calls` edge even though the import
|
|
1444
|
+
// edge resolved (#578).
|
|
1445
|
+
let resolvedPath = resolveImportPath(modulePath, ref.filePath, ref.language, context);
|
|
1446
|
+
if (!resolvedPath) {
|
|
1447
|
+
resolvedPath = findPythonModuleFile(modulePath, context, ref.filePath)?.filePath ?? null;
|
|
1448
|
+
}
|
|
1449
|
+
if (!resolvedPath || resolvedPath === ref.filePath)
|
|
1450
|
+
continue;
|
|
1451
|
+
// Find the member as a top-level definition in the module file. Exclude
|
|
1452
|
+
// `method` so `mod.foo` never lands on a same-named class method.
|
|
1453
|
+
const target = context.getNodesInFile(resolvedPath).find((n) => n.name === member &&
|
|
1454
|
+
(n.kind === 'function' ||
|
|
1455
|
+
n.kind === 'class' ||
|
|
1456
|
+
n.kind === 'variable' ||
|
|
1457
|
+
n.kind === 'constant'));
|
|
1458
|
+
if (target) {
|
|
1459
|
+
return { original: ref, targetNodeId: target.id, confidence: 0.85, resolvedBy: 'import' };
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
return null;
|
|
1463
|
+
}
|
|
1464
|
+
/**
|
|
1465
|
+
* Resolve a whole-MODULE import to that module's file (a file→file dependency).
|
|
1466
|
+
* The imported name is a module, not a symbol, so there's nothing to resolve to
|
|
1467
|
+
* — but importing a module IS a dependency on it. Covers:
|
|
1468
|
+
* - Python submodule imports — `from . import certs`, `from pkg import sub`;
|
|
1469
|
+
* - namespace imports — Python `import mod` / `import numpy as np`, and
|
|
1470
|
+
* TS/JS `import * as ns from './x'`.
|
|
1471
|
+
*
|
|
1472
|
+
* It is also the robust backstop for {@link resolvePythonModuleMember} and for
|
|
1473
|
+
* TS namespace usage: it records the dependency even when the used member is
|
|
1474
|
+
* re-exported elsewhere (requests' `certs.where`, re-exported from `certifi`),
|
|
1475
|
+
* the usage is module-level code that isn't extracted as a call, or a TS
|
|
1476
|
+
* namespace is touched only via a value-member read (`ns.SOME_CONST`).
|
|
1477
|
+
*
|
|
1478
|
+
* Only fires for dot-free `imports`-kind refs whose module path resolves to a
|
|
1479
|
+
* real file. A NAMED TS/JS import (`import { widget }`) is not a module, so it
|
|
1480
|
+
* returns null and normal symbol resolution handles it.
|
|
1481
|
+
*/
|
|
1482
|
+
/**
|
|
1483
|
+
* Resolve a Lua/Luau `require(...)` to its module file. The reference name is
|
|
1484
|
+
* either a dotted module path (`telescope.config` → `telescope/config.lua`) or a
|
|
1485
|
+
* Roblox instance-path leaf (`Signal` from `require(script.Parent.Signal)` →
|
|
1486
|
+
* `Signal.luau`). We try `<path>.lua|.luau` and `<path>/init.lua|.luau`, matched
|
|
1487
|
+
* by path suffix (the module root — `lua/`, `src/`, … — is project-specific).
|
|
1488
|
+
* Among suffix matches, the one sharing the longest directory prefix with the
|
|
1489
|
+
* requiring file wins (instance-path requires resolve within the same package).
|
|
1490
|
+
*/
|
|
1491
|
+
function resolveLuaRequire(ref, context) {
|
|
1492
|
+
const name = ref.referenceName;
|
|
1493
|
+
if (!name)
|
|
1494
|
+
return null;
|
|
1495
|
+
const base = name.includes('.') ? name.replace(/\./g, '/') : name;
|
|
1496
|
+
const suffixes = [`${base}.lua`, `${base}.luau`, `${base}/init.lua`, `${base}/init.luau`];
|
|
1497
|
+
const files = context.getAllFiles();
|
|
1498
|
+
const shared = (a, b) => {
|
|
1499
|
+
let i = 0;
|
|
1500
|
+
while (i < a.length && i < b.length && a[i] === b[i])
|
|
1501
|
+
i++;
|
|
1502
|
+
return i;
|
|
1503
|
+
};
|
|
1504
|
+
for (const suffix of suffixes) {
|
|
1505
|
+
const matches = files.filter((f) => f === suffix || f.endsWith('/' + suffix));
|
|
1506
|
+
if (matches.length === 0)
|
|
1507
|
+
continue;
|
|
1508
|
+
matches.sort((x, y) => shared(y, ref.filePath) - shared(x, ref.filePath));
|
|
1509
|
+
const best = matches[0];
|
|
1510
|
+
if (best === ref.filePath)
|
|
1511
|
+
continue;
|
|
1512
|
+
const fileNode = context.getNodesInFile(best).find((n) => n.kind === 'file');
|
|
1513
|
+
if (fileNode) {
|
|
1514
|
+
// Confidence ≥ 0.9 so this deterministic path/suffix match wins over
|
|
1515
|
+
// name-matching, which otherwise resolves the require to the import node
|
|
1516
|
+
// itself (a same-name self-match).
|
|
1517
|
+
return { original: ref, targetNodeId: fileNode.id, confidence: 0.9, resolvedBy: 'import' };
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
return null;
|
|
1521
|
+
}
|
|
1522
|
+
function resolveModuleImportToFile(ref, imports, context) {
|
|
1523
|
+
if (ref.referenceKind !== 'imports')
|
|
1524
|
+
return null;
|
|
1525
|
+
if (ref.referenceName.includes('.'))
|
|
1526
|
+
return null;
|
|
1527
|
+
for (const imp of imports) {
|
|
1528
|
+
if (imp.localName !== ref.referenceName)
|
|
1529
|
+
continue;
|
|
1530
|
+
let modulePath;
|
|
1531
|
+
if (imp.isNamespace || imp.isDefault) {
|
|
1532
|
+
// `import * as ns from './x'` (namespace) or `import x from './x'`
|
|
1533
|
+
// (default) — the dependency is on the MODULE FILE. A default import binds
|
|
1534
|
+
// a (possibly renamed) local to whatever the module's default export is
|
|
1535
|
+
// (`import articlesController from './article.controller'` ← `export
|
|
1536
|
+
// default router`), so the binding name can't be found as a symbol — link
|
|
1537
|
+
// the file the import resolves to instead. External modules don't resolve
|
|
1538
|
+
// (no file), so `import React from 'react'` creates no edge.
|
|
1539
|
+
modulePath = imp.source;
|
|
1540
|
+
}
|
|
1541
|
+
else if (ref.language === 'python') {
|
|
1542
|
+
// `from . import certs` — the imported NAME is a submodule of the source.
|
|
1543
|
+
modulePath = imp.source.endsWith('.')
|
|
1544
|
+
? imp.source + imp.localName
|
|
1545
|
+
: imp.source + '.' + imp.localName;
|
|
1546
|
+
}
|
|
1547
|
+
else {
|
|
1548
|
+
// A named TS/JS import binds a symbol, not a module — leave it alone.
|
|
1549
|
+
continue;
|
|
1550
|
+
}
|
|
1551
|
+
const resolvedPath = resolveImportPath(modulePath, ref.filePath, ref.language, context);
|
|
1552
|
+
if (resolvedPath && resolvedPath !== ref.filePath) {
|
|
1553
|
+
const fileNode = context.getNodesInFile(resolvedPath).find((n) => n.kind === 'file');
|
|
1554
|
+
if (fileNode) {
|
|
1555
|
+
return { original: ref, targetNodeId: fileNode.id, confidence: 0.9, resolvedBy: 'import' };
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
// Python absolute `from a.b import submodule` (a FastAPI router aggregator's
|
|
1559
|
+
// `from app.api.routes import authentication`): resolveImportPath only maps
|
|
1560
|
+
// RELATIVE dotted paths to a file, so resolve the absolute dotted module
|
|
1561
|
+
// directly to its file node.
|
|
1562
|
+
if (ref.language === 'python') {
|
|
1563
|
+
const modFile = findPythonModuleFile(modulePath, context, ref.filePath);
|
|
1564
|
+
if (modFile) {
|
|
1565
|
+
return { original: ref, targetNodeId: modFile.id, confidence: 0.9, resolvedBy: 'import' };
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
return null;
|
|
1570
|
+
}
|
|
1571
|
+
/**
|
|
1572
|
+
* Find the file node for a Python dotted module path `a.b.c` — a module file
|
|
1573
|
+
* ending in `a/b/c.py`, or a package `a/b/c/__init__.py` (suffix-matched, so a
|
|
1574
|
+
* package rooted under `src/` etc. still resolves). Returns null for
|
|
1575
|
+
* stdlib/external modules (no matching repo file node), so `import os` creates
|
|
1576
|
+
* no edge. Shared by absolute `import a.b.c` and absolute `from a.b import c`
|
|
1577
|
+
* (where `c` is a submodule) resolution.
|
|
1578
|
+
*/
|
|
1579
|
+
function findPythonModuleFile(mod, context, excludeFilePath) {
|
|
1580
|
+
if (!mod || mod.startsWith('.'))
|
|
1581
|
+
return null; // relative imports handled elsewhere
|
|
1582
|
+
const rel = mod.replace(/\./g, '/');
|
|
1583
|
+
const lastSeg = mod.split('.').pop();
|
|
1584
|
+
const endsWith = (p, want) => p === want || p.endsWith('/' + want);
|
|
1585
|
+
const moduleFile = context
|
|
1586
|
+
.getNodesByName(`${lastSeg}.py`)
|
|
1587
|
+
.find((n) => n.kind === 'file' && n.filePath !== excludeFilePath && endsWith(n.filePath, `${rel}.py`));
|
|
1588
|
+
if (moduleFile)
|
|
1589
|
+
return moduleFile;
|
|
1590
|
+
const pkgFile = context
|
|
1591
|
+
.getNodesByName('__init__.py')
|
|
1592
|
+
.find((n) => n.kind === 'file' && n.filePath !== excludeFilePath && endsWith(n.filePath, `${rel}/__init__.py`));
|
|
1593
|
+
return pkgFile ?? null;
|
|
1594
|
+
}
|
|
1595
|
+
/**
|
|
1596
|
+
* Resolve a Python ABSOLUTE dotted module import (`import a.b.c`) to its file —
|
|
1597
|
+
* the Django `AppConfig.ready(): import myapp.signals` pattern and any
|
|
1598
|
+
* side-effect module import.
|
|
1599
|
+
*/
|
|
1600
|
+
function resolvePythonAbsoluteModule(ref, context) {
|
|
1601
|
+
if (ref.referenceKind !== 'imports')
|
|
1602
|
+
return null;
|
|
1603
|
+
// Only a DOTTED `import a.b.c` ref carries its full module path. A bare leaf
|
|
1604
|
+
// (`from app.api.routes import authentication`) is ambiguous on its own — three
|
|
1605
|
+
// `authentication.py` files may exist — so leave it to resolveModuleImportToFile,
|
|
1606
|
+
// which uses the import's source (`app.api.routes`) to build the full path.
|
|
1607
|
+
if (!ref.referenceName.includes('.'))
|
|
1608
|
+
return null;
|
|
1609
|
+
const hit = findPythonModuleFile(ref.referenceName, context, ref.filePath);
|
|
1610
|
+
return hit ? { original: ref, targetNodeId: hit.id, confidence: 0.9, resolvedBy: 'import' } : null;
|
|
1611
|
+
}
|
|
1612
|
+
/**
|
|
1613
|
+
* Resolve a Rust qualified reference `A::B::C` by mapping the MODULE prefix
|
|
1614
|
+
* (`A::B`) to a file and finding the leaf symbol (`C`) in it. This is the Rust
|
|
1615
|
+
* analog of {@link resolvePythonModuleMember} / {@link resolveGoCrossPackageReference}
|
|
1616
|
+
* and the precise answer to common-name re-exports (`pub use self::read::read`)
|
|
1617
|
+
* that name-matching can't disambiguate. Returns null when the prefix isn't a
|
|
1618
|
+
* real module path (e.g. `Widget::new` — `Widget` is a struct, not a module),
|
|
1619
|
+
* so associated-function calls and enum-variant paths fall through untouched.
|
|
1620
|
+
*/
|
|
1621
|
+
function resolveRustPathReference(ref, context) {
|
|
1622
|
+
const segments = ref.referenceName.split('::').filter((s) => s.length > 0);
|
|
1623
|
+
if (segments.length < 2)
|
|
1624
|
+
return null;
|
|
1625
|
+
const leaf = segments[segments.length - 1];
|
|
1626
|
+
const modSegs = segments.slice(0, -1);
|
|
1627
|
+
const file = resolveRustModuleFile(modSegs, ref.filePath, context);
|
|
1628
|
+
if (!file || file === ref.filePath)
|
|
1629
|
+
return null;
|
|
1630
|
+
const target = context.getNodesInFile(file).find((n) => n.name === leaf &&
|
|
1631
|
+
(n.kind === 'function' ||
|
|
1632
|
+
n.kind === 'struct' ||
|
|
1633
|
+
n.kind === 'enum' ||
|
|
1634
|
+
n.kind === 'trait' ||
|
|
1635
|
+
n.kind === 'type_alias' ||
|
|
1636
|
+
n.kind === 'constant' ||
|
|
1637
|
+
n.kind === 'method' ||
|
|
1638
|
+
n.kind === 'class' ||
|
|
1639
|
+
n.kind === 'interface'));
|
|
1640
|
+
if (target) {
|
|
1641
|
+
return { original: ref, targetNodeId: target.id, confidence: 0.9, resolvedBy: 'import' };
|
|
1642
|
+
}
|
|
1643
|
+
return null;
|
|
1644
|
+
}
|
|
1645
|
+
/** The crate-root directory (holds `lib.rs`/`main.rs`), walking up from a file. */
|
|
1646
|
+
function rustCrateRootDir(fromFileAbs, context) {
|
|
1647
|
+
const projectRoot = context.getProjectRoot();
|
|
1648
|
+
const toRel = (p) => path.relative(projectRoot, p).replace(/\\/g, '/');
|
|
1649
|
+
let dir = path.dirname(fromFileAbs);
|
|
1650
|
+
for (let i = 0; i < 64; i++) {
|
|
1651
|
+
if (context.fileExists(toRel(path.join(dir, 'lib.rs'))) ||
|
|
1652
|
+
context.fileExists(toRel(path.join(dir, 'main.rs')))) {
|
|
1653
|
+
return dir;
|
|
1654
|
+
}
|
|
1655
|
+
const parent = path.dirname(dir);
|
|
1656
|
+
if (parent === dir)
|
|
1657
|
+
return null;
|
|
1658
|
+
dir = parent;
|
|
1659
|
+
}
|
|
1660
|
+
return null;
|
|
1661
|
+
}
|
|
1662
|
+
/** Directory under which the current file's module declares its SUBMODULES. */
|
|
1663
|
+
function rustSelfModuleDir(fromFileAbs) {
|
|
1664
|
+
const base = path.basename(fromFileAbs);
|
|
1665
|
+
const dir = path.dirname(fromFileAbs);
|
|
1666
|
+
// mod.rs / lib.rs / main.rs own their directory; `foo.rs`'s submodules live in `foo/`.
|
|
1667
|
+
if (base === 'mod.rs' || base === 'lib.rs' || base === 'main.rs')
|
|
1668
|
+
return dir;
|
|
1669
|
+
return path.join(dir, base.replace(/\.rs$/, ''));
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* Resolve a Rust module path (segments WITHOUT the leaf symbol) to the file of
|
|
1673
|
+
* the last module segment — `crate::a::b` → `<crate>/a/b.rs` (or `.../b/mod.rs`).
|
|
1674
|
+
* Anchors on `crate` / `self` / `super`; a bare path is tried crate-relative.
|
|
1675
|
+
*/
|
|
1676
|
+
function resolveRustModuleFile(segments, fromFile, context) {
|
|
1677
|
+
if (segments.length === 0)
|
|
1678
|
+
return null;
|
|
1679
|
+
const projectRoot = context.getProjectRoot();
|
|
1680
|
+
const fromAbs = path.join(projectRoot, fromFile);
|
|
1681
|
+
const toRel = (p) => path.relative(projectRoot, p).replace(/\\/g, '/');
|
|
1682
|
+
// Walk a sequence of module segments down from `startDir`, mapping each to a
|
|
1683
|
+
// `<seg>.rs` or `<seg>/mod.rs` file. Returns the leaf module's file, or null
|
|
1684
|
+
// if `startDir` is null or any segment has no file on disk.
|
|
1685
|
+
const resolveUnder = (startDir, rest) => {
|
|
1686
|
+
if (!startDir)
|
|
1687
|
+
return null;
|
|
1688
|
+
let dir = startDir;
|
|
1689
|
+
let targetFile = null;
|
|
1690
|
+
for (const seg of rest) {
|
|
1691
|
+
if (seg === 'self' || seg === 'crate' || seg === 'super')
|
|
1692
|
+
continue;
|
|
1693
|
+
const asFile = toRel(path.join(dir, seg + '.rs'));
|
|
1694
|
+
const asMod = toRel(path.join(dir, seg, 'mod.rs'));
|
|
1695
|
+
if (context.fileExists(asFile))
|
|
1696
|
+
targetFile = asFile;
|
|
1697
|
+
else if (context.fileExists(asMod))
|
|
1698
|
+
targetFile = asMod;
|
|
1699
|
+
else
|
|
1700
|
+
return null;
|
|
1701
|
+
dir = path.join(dir, seg);
|
|
1702
|
+
}
|
|
1703
|
+
return targetFile;
|
|
1704
|
+
};
|
|
1705
|
+
const first = segments[0];
|
|
1706
|
+
if (first === 'crate') {
|
|
1707
|
+
return resolveUnder(rustCrateRootDir(fromAbs, context), segments.slice(1));
|
|
1708
|
+
}
|
|
1709
|
+
if (first === 'self') {
|
|
1710
|
+
return resolveUnder(rustSelfModuleDir(fromAbs), segments.slice(1));
|
|
1711
|
+
}
|
|
1712
|
+
if (first === 'super') {
|
|
1713
|
+
let supers = 0;
|
|
1714
|
+
while (segments[supers] === 'super')
|
|
1715
|
+
supers++;
|
|
1716
|
+
let dir = rustSelfModuleDir(fromAbs);
|
|
1717
|
+
for (let s = 0; s < supers && dir; s++)
|
|
1718
|
+
dir = path.dirname(dir);
|
|
1719
|
+
return resolveUnder(dir, segments.slice(supers));
|
|
1720
|
+
}
|
|
1721
|
+
// Bare path. In expression position (`submodule::item()` — the router-assembly
|
|
1722
|
+
// and general cross-module-call pattern) the prefix is a SUBMODULE of the
|
|
1723
|
+
// current module, i.e. 2018 `self::`-relative — so try self-relative FIRST.
|
|
1724
|
+
// Fall back to crate-relative for 2015-edition / crate-root items. External
|
|
1725
|
+
// crate paths (`serde::de::Error`) miss both and fall through to name-matching.
|
|
1726
|
+
return (resolveUnder(rustSelfModuleDir(fromAbs), segments) ??
|
|
1727
|
+
resolveUnder(rustCrateRootDir(fromAbs, context), segments));
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Resolve a Java/Kotlin reference whose receiver is the simple name of
|
|
1731
|
+
* an imported FQN: `Foo.bar(...)` where `import com.example.Foo;`. The
|
|
1732
|
+
* imported FQN converts to a file-path suffix (`com/example/Foo.java`
|
|
1733
|
+
* or `.kt`) which uniquely identifies the right symbol when multiple
|
|
1734
|
+
* classes share the same simple name.
|
|
1735
|
+
*
|
|
1736
|
+
* Also handles bare references to the imported class itself
|
|
1737
|
+
* (`new Foo()` extraction emits `Foo` as a `references`/`instantiates`
|
|
1738
|
+
* ref) and `import static <Foo>.bar` style imports of a single member.
|
|
1739
|
+
*/
|
|
1740
|
+
function resolveJavaImportedReference(ref, imports, context) {
|
|
1741
|
+
if (imports.length === 0)
|
|
1742
|
+
return null;
|
|
1743
|
+
const ext = ref.language === 'kotlin' ? '.kt' : '.java';
|
|
1744
|
+
for (const imp of imports) {
|
|
1745
|
+
const matchesBare = imp.localName === ref.referenceName;
|
|
1746
|
+
const matchesQualified = ref.referenceName.startsWith(imp.localName + '.');
|
|
1747
|
+
if (!matchesBare && !matchesQualified)
|
|
1748
|
+
continue;
|
|
1749
|
+
// Convert FQN to a file-path suffix. `com.example.Foo` ->
|
|
1750
|
+
// `com/example/Foo.java` (or `.kt`). The actual file may live
|
|
1751
|
+
// under any source root (`src/main/java/`, `src/`, etc.), so match
|
|
1752
|
+
// by suffix rather than exact path.
|
|
1753
|
+
const fqnPath = imp.source.replace(/\./g, '/') + ext;
|
|
1754
|
+
// Which symbol name to look up: the class itself, or a member.
|
|
1755
|
+
const memberName = matchesBare
|
|
1756
|
+
? imp.localName
|
|
1757
|
+
: ref.referenceName.substring(imp.localName.length + 1);
|
|
1758
|
+
const candidates = context.getNodesByName(memberName);
|
|
1759
|
+
for (const node of candidates) {
|
|
1760
|
+
if (node.language !== ref.language)
|
|
1761
|
+
continue;
|
|
1762
|
+
const fp = node.filePath.replace(/\\/g, '/');
|
|
1763
|
+
if (fp.endsWith(fqnPath) || fp.endsWith('/' + fqnPath)) {
|
|
1764
|
+
return {
|
|
1765
|
+
original: ref,
|
|
1766
|
+
targetNodeId: node.id,
|
|
1767
|
+
confidence: 0.9,
|
|
1768
|
+
resolvedBy: 'import',
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
// `import static com.example.Foo.bar;` — the FQN's tail is the
|
|
1773
|
+
// member name, the part before is the owner class. Look up the
|
|
1774
|
+
// member named `<imp.localName>` (e.g. `bar`) and prefer the
|
|
1775
|
+
// candidate whose file matches the parent FQN's path.
|
|
1776
|
+
if (matchesBare) {
|
|
1777
|
+
const dot = imp.source.lastIndexOf('.');
|
|
1778
|
+
if (dot > 0) {
|
|
1779
|
+
const ownerFqn = imp.source.substring(0, dot);
|
|
1780
|
+
const ownerPath = ownerFqn.replace(/\./g, '/') + ext;
|
|
1781
|
+
for (const node of candidates) {
|
|
1782
|
+
if (node.language !== ref.language)
|
|
1783
|
+
continue;
|
|
1784
|
+
const fp = node.filePath.replace(/\\/g, '/');
|
|
1785
|
+
if (fp.endsWith(ownerPath) || fp.endsWith('/' + ownerPath)) {
|
|
1786
|
+
return {
|
|
1787
|
+
original: ref,
|
|
1788
|
+
targetNodeId: node.id,
|
|
1789
|
+
confidence: 0.9,
|
|
1790
|
+
resolvedBy: 'import',
|
|
1791
|
+
};
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
return null;
|
|
1798
|
+
}
|
|
1799
|
+
/**
|
|
1800
|
+
* Resolve a Go cross-package qualified reference (`pkga.FuncX`) by matching
|
|
1801
|
+
* the package alias against an in-module import, stripping the module prefix
|
|
1802
|
+
* to a project-relative directory, and locating the exported symbol in any
|
|
1803
|
+
* `.go` file under that directory. Returns `null` for stdlib / third-party
|
|
1804
|
+
* imports (no `go.mod`-relative match) so the rest of `resolveViaImport`
|
|
1805
|
+
* can still try the file-based path.
|
|
1806
|
+
*/
|
|
1807
|
+
function resolveGoCrossPackageReference(ref, imports, context) {
|
|
1808
|
+
const mod = context.getGoModule?.();
|
|
1809
|
+
if (!mod)
|
|
1810
|
+
return null;
|
|
1811
|
+
// Qualified call: receiver before `.`, member after. A bare reference
|
|
1812
|
+
// (no dot) is a same-file/in-package call — handled elsewhere.
|
|
1813
|
+
const dotIdx = ref.referenceName.indexOf('.');
|
|
1814
|
+
if (dotIdx <= 0)
|
|
1815
|
+
return null;
|
|
1816
|
+
const receiver = ref.referenceName.substring(0, dotIdx);
|
|
1817
|
+
const memberName = ref.referenceName.substring(dotIdx + 1);
|
|
1818
|
+
if (!memberName)
|
|
1819
|
+
return null;
|
|
1820
|
+
for (const imp of imports) {
|
|
1821
|
+
if (imp.localName !== receiver)
|
|
1822
|
+
continue;
|
|
1823
|
+
// Only in-module imports map to a known directory.
|
|
1824
|
+
if (imp.source !== mod.modulePath && !imp.source.startsWith(mod.modulePath + '/')) {
|
|
1825
|
+
continue;
|
|
1826
|
+
}
|
|
1827
|
+
const pkgDir = imp.source === mod.modulePath
|
|
1828
|
+
? ''
|
|
1829
|
+
: imp.source.substring(mod.modulePath.length + 1);
|
|
1830
|
+
// Look up the member by name and pick the candidate whose file lives
|
|
1831
|
+
// directly in the package directory. Match the immediate parent dir
|
|
1832
|
+
// exactly so a call to `pkga.FuncX` doesn't accidentally land on a
|
|
1833
|
+
// `FuncX` declared in `pkga/subpkg/`.
|
|
1834
|
+
const candidates = context.getNodesByName(memberName);
|
|
1835
|
+
for (const node of candidates) {
|
|
1836
|
+
if (node.language !== 'go')
|
|
1837
|
+
continue;
|
|
1838
|
+
if (!node.isExported)
|
|
1839
|
+
continue;
|
|
1840
|
+
const fp = node.filePath.replace(/\\/g, '/');
|
|
1841
|
+
const lastSlash = fp.lastIndexOf('/');
|
|
1842
|
+
const fileDir = lastSlash >= 0 ? fp.substring(0, lastSlash) : '';
|
|
1843
|
+
if (fileDir === pkgDir) {
|
|
1844
|
+
return {
|
|
1845
|
+
original: ref,
|
|
1846
|
+
targetNodeId: node.id,
|
|
1847
|
+
confidence: 0.9,
|
|
1848
|
+
resolvedBy: 'import',
|
|
1849
|
+
};
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
return null;
|
|
1854
|
+
}
|
|
589
1855
|
/** Recursive depth cap for re-export chain following. Real codebases
|
|
590
1856
|
* rarely chain barrels more than 2–3 deep; 8 is a generous safety
|
|
591
1857
|
* net that still bounds worst-case work. */
|
|
@@ -609,7 +1875,14 @@ function findExportedSymbol(filePath, want, language, context, visited, depth =
|
|
|
609
1875
|
const nodesInFile = context.getNodesInFile(filePath);
|
|
610
1876
|
// 1. Direct hit: the symbol is declared in this file.
|
|
611
1877
|
if (want.isDefault) {
|
|
612
|
-
|
|
1878
|
+
// Svelte/Vue single-file components ARE the module's default export,
|
|
1879
|
+
// but are extracted as kind 'component' (not function/class). Prefer
|
|
1880
|
+
// the component node; fall back to an exported function/class for the
|
|
1881
|
+
// `.ts`/`.tsx` `export default fn`/`class` case. Without the component
|
|
1882
|
+
// branch, an `export { default as X } from './X.svelte'` barrel never
|
|
1883
|
+
// resolves and the component shows a false 0 callers (#629).
|
|
1884
|
+
const direct = nodesInFile.find((n) => n.isExported && n.kind === 'component') ??
|
|
1885
|
+
nodesInFile.find((n) => n.isExported && (n.kind === 'function' || n.kind === 'class'));
|
|
613
1886
|
if (direct)
|
|
614
1887
|
return direct;
|
|
615
1888
|
}
|
|
@@ -660,4 +1933,42 @@ function findExportedSymbol(filePath, want, language, context, visited, depth =
|
|
|
660
1933
|
}
|
|
661
1934
|
return undefined;
|
|
662
1935
|
}
|
|
1936
|
+
/** Node kinds that own static members reachable as `Container.member`. */
|
|
1937
|
+
const STATIC_MEMBER_CONTAINERS = new Set([
|
|
1938
|
+
'class', 'struct', 'interface', 'enum', 'trait', 'protocol',
|
|
1939
|
+
]);
|
|
1940
|
+
/**
|
|
1941
|
+
* Resolve `Container.member` — a static method/property access on a NAMED class
|
|
1942
|
+
* import (`import { Foo } …; Foo.bar()`) — to the member node, given the
|
|
1943
|
+
* already-resolved container class.
|
|
1944
|
+
*
|
|
1945
|
+
* Members carry a `Container::member` qualifiedName, so we look up
|
|
1946
|
+
* `${container.qualifiedName}::${member}` within the container's own file (the
|
|
1947
|
+
* file filter disambiguates same-named classes in other modules). Returns
|
|
1948
|
+
* undefined when the container isn't a member-owning kind or the member isn't
|
|
1949
|
+
* found, so the caller falls back to the container itself (prior behavior) —
|
|
1950
|
+
* languages whose members aren't `::`-qualified, and genuine class references,
|
|
1951
|
+
* are unaffected. See #825.
|
|
1952
|
+
*/
|
|
1953
|
+
function resolveStaticMember(container, ref, localName, context) {
|
|
1954
|
+
if (!STATIC_MEMBER_CONTAINERS.has(container.kind))
|
|
1955
|
+
return undefined;
|
|
1956
|
+
// First segment after the receiver: `Foo.bar.baz` → `bar`.
|
|
1957
|
+
const member = ref.referenceName.slice(localName.length + 1).split('.')[0];
|
|
1958
|
+
if (!member)
|
|
1959
|
+
return undefined;
|
|
1960
|
+
const candidates = context
|
|
1961
|
+
.getNodesByQualifiedName(`${container.qualifiedName}::${member}`)
|
|
1962
|
+
.filter((n) => n.filePath === container.filePath);
|
|
1963
|
+
if (candidates.length === 0)
|
|
1964
|
+
return undefined;
|
|
1965
|
+
// When the reference is a call, prefer a callable member if several nodes
|
|
1966
|
+
// share the qualifiedName (e.g. a static property and a method).
|
|
1967
|
+
if (ref.referenceKind === 'calls') {
|
|
1968
|
+
const callable = candidates.find((n) => n.kind === 'method' || n.kind === 'function');
|
|
1969
|
+
if (callable)
|
|
1970
|
+
return callable;
|
|
1971
|
+
}
|
|
1972
|
+
return candidates[0];
|
|
1973
|
+
}
|
|
663
1974
|
//# sourceMappingURL=import-resolver.js.map
|