@quolu/lattice 0.69.5 → 0.71.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +5 -1
- package/package.json +1 -1
- package/sensor/dist/bin/lattice-sensor.js +746 -323
- package/sensor/dist/bin/viewer-gate.d.ts +17 -0
- package/sensor/dist/bin/viewer-gate.d.ts.map +1 -0
- package/sensor/dist/bin/viewer-gate.js +31 -0
- package/sensor/dist/bin/viewer-gate.js.map +1 -0
- package/sensor/dist/context/formatter.d.ts +7 -1
- package/sensor/dist/context/formatter.d.ts.map +1 -1
- package/sensor/dist/context/formatter.js +12 -6
- package/sensor/dist/context/formatter.js.map +1 -1
- package/sensor/dist/context/index.d.ts +12 -0
- package/sensor/dist/context/index.d.ts.map +1 -1
- package/sensor/dist/context/index.js +103 -16
- package/sensor/dist/context/index.js.map +1 -1
- package/sensor/dist/db/index.d.ts +23 -2
- package/sensor/dist/db/index.d.ts.map +1 -1
- package/sensor/dist/db/index.js +109 -31
- package/sensor/dist/db/index.js.map +1 -1
- package/sensor/dist/db/migrations.d.ts +1 -1
- package/sensor/dist/db/migrations.d.ts.map +1 -1
- package/sensor/dist/db/migrations.js +68 -1
- package/sensor/dist/db/migrations.js.map +1 -1
- package/sensor/dist/db/queries.d.ts +583 -6
- package/sensor/dist/db/queries.d.ts.map +1 -1
- package/sensor/dist/db/queries.js +1425 -57
- package/sensor/dist/db/queries.js.map +1 -1
- package/sensor/dist/db/schema.sql +27 -4
- package/sensor/dist/db/sqlite-adapter.d.ts +2 -0
- package/sensor/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/sensor/dist/db/sqlite-adapter.js +56 -7
- package/sensor/dist/db/sqlite-adapter.js.map +1 -1
- package/sensor/dist/db/synthesis-stage.d.ts +12 -0
- package/sensor/dist/db/synthesis-stage.d.ts.map +1 -0
- package/sensor/dist/db/synthesis-stage.js +93 -0
- package/sensor/dist/db/synthesis-stage.js.map +1 -0
- package/sensor/dist/db/wal-valve.d.ts +32 -12
- package/sensor/dist/db/wal-valve.d.ts.map +1 -1
- package/sensor/dist/db/wal-valve.js +65 -22
- package/sensor/dist/db/wal-valve.js.map +1 -1
- package/sensor/dist/db/wsl-shared-index.d.ts +53 -0
- package/sensor/dist/db/wsl-shared-index.d.ts.map +1 -0
- package/sensor/dist/db/wsl-shared-index.js +121 -0
- package/sensor/dist/db/wsl-shared-index.js.map +1 -0
- package/sensor/dist/directory.d.ts +126 -2
- package/sensor/dist/directory.d.ts.map +1 -1
- package/sensor/dist/directory.js +285 -16
- package/sensor/dist/directory.js.map +1 -1
- package/sensor/dist/errors.d.ts +14 -0
- package/sensor/dist/errors.d.ts.map +1 -1
- package/sensor/dist/errors.js +16 -1
- package/sensor/dist/errors.js.map +1 -1
- package/sensor/dist/extraction/cfml-extractor.d.ts +1 -0
- package/sensor/dist/extraction/cfml-extractor.d.ts.map +1 -1
- package/sensor/dist/extraction/cfml-extractor.js +15 -3
- package/sensor/dist/extraction/cfml-extractor.js.map +1 -1
- package/sensor/dist/extraction/dfm-extractor.d.ts.map +1 -1
- package/sensor/dist/extraction/dfm-extractor.js +14 -10
- package/sensor/dist/extraction/dfm-extractor.js.map +1 -1
- package/sensor/dist/extraction/extraction-version.d.ts +1 -1
- package/sensor/dist/extraction/extraction-version.d.ts.map +1 -1
- package/sensor/dist/extraction/extraction-version.js +3 -1
- package/sensor/dist/extraction/extraction-version.js.map +1 -1
- package/sensor/dist/extraction/function-ref.d.ts +6 -4
- package/sensor/dist/extraction/function-ref.d.ts.map +1 -1
- package/sensor/dist/extraction/function-ref.js +35 -14
- package/sensor/dist/extraction/function-ref.js.map +1 -1
- package/sensor/dist/extraction/generated-detection.d.ts +48 -12
- package/sensor/dist/extraction/generated-detection.d.ts.map +1 -1
- package/sensor/dist/extraction/generated-detection.js +176 -11
- package/sensor/dist/extraction/generated-detection.js.map +1 -1
- package/sensor/dist/extraction/grammars.d.ts +38 -0
- package/sensor/dist/extraction/grammars.d.ts.map +1 -1
- package/sensor/dist/extraction/grammars.js +115 -3
- package/sensor/dist/extraction/grammars.js.map +1 -1
- package/sensor/dist/extraction/index.d.ts +218 -14
- package/sensor/dist/extraction/index.d.ts.map +1 -1
- package/sensor/dist/extraction/index.js +887 -175
- package/sensor/dist/extraction/index.js.map +1 -1
- package/sensor/dist/extraction/languages/c-cpp.d.ts +58 -0
- package/sensor/dist/extraction/languages/c-cpp.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/c-cpp.js +310 -19
- package/sensor/dist/extraction/languages/c-cpp.js.map +1 -1
- package/sensor/dist/extraction/languages/dart.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/dart.js +8 -3
- package/sensor/dist/extraction/languages/dart.js.map +1 -1
- package/sensor/dist/extraction/languages/erlang.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/erlang.js +58 -22
- package/sensor/dist/extraction/languages/erlang.js.map +1 -1
- package/sensor/dist/extraction/languages/javascript.js +1 -1
- package/sensor/dist/extraction/languages/javascript.js.map +1 -1
- package/sensor/dist/extraction/languages/kotlin.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/kotlin.js +169 -36
- package/sensor/dist/extraction/languages/kotlin.js.map +1 -1
- package/sensor/dist/extraction/languages/lua.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/lua.js +4 -1
- package/sensor/dist/extraction/languages/lua.js.map +1 -1
- package/sensor/dist/extraction/languages/objc.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/objc.js +4 -0
- package/sensor/dist/extraction/languages/objc.js.map +1 -1
- package/sensor/dist/extraction/languages/python.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/python.js +71 -0
- package/sensor/dist/extraction/languages/python.js.map +1 -1
- package/sensor/dist/extraction/languages/rust.d.ts +20 -0
- package/sensor/dist/extraction/languages/rust.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/rust.js +50 -20
- package/sensor/dist/extraction/languages/rust.js.map +1 -1
- package/sensor/dist/extraction/languages/scala.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/scala.js +18 -3
- package/sensor/dist/extraction/languages/scala.js.map +1 -1
- package/sensor/dist/extraction/languages/swift.d.ts +15 -0
- package/sensor/dist/extraction/languages/swift.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/swift.js +50 -0
- package/sensor/dist/extraction/languages/swift.js.map +1 -1
- package/sensor/dist/extraction/languages/typescript.d.ts.map +1 -1
- package/sensor/dist/extraction/languages/typescript.js +9 -2
- package/sensor/dist/extraction/languages/typescript.js.map +1 -1
- package/sensor/dist/extraction/liquid-extractor.d.ts +18 -0
- package/sensor/dist/extraction/liquid-extractor.d.ts.map +1 -1
- package/sensor/dist/extraction/liquid-extractor.js +98 -22
- package/sensor/dist/extraction/liquid-extractor.js.map +1 -1
- package/sensor/dist/extraction/mybatis-extractor.d.ts.map +1 -1
- package/sensor/dist/extraction/mybatis-extractor.js +6 -4
- package/sensor/dist/extraction/mybatis-extractor.js.map +1 -1
- package/sensor/dist/extraction/parse-pool.d.ts +7 -0
- package/sensor/dist/extraction/parse-pool.d.ts.map +1 -1
- package/sensor/dist/extraction/parse-pool.js +20 -1
- package/sensor/dist/extraction/parse-pool.js.map +1 -1
- package/sensor/dist/extraction/syntax-tokens.d.ts +103 -0
- package/sensor/dist/extraction/syntax-tokens.d.ts.map +1 -0
- package/sensor/dist/extraction/syntax-tokens.js +381 -0
- package/sensor/dist/extraction/syntax-tokens.js.map +1 -0
- package/sensor/dist/extraction/tree-sitter-helpers.d.ts +5 -0
- package/sensor/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
- package/sensor/dist/extraction/tree-sitter-helpers.js +17 -0
- package/sensor/dist/extraction/tree-sitter-helpers.js.map +1 -1
- package/sensor/dist/extraction/tree-sitter-types.d.ts +31 -3
- package/sensor/dist/extraction/tree-sitter-types.d.ts.map +1 -1
- package/sensor/dist/extraction/tree-sitter.d.ts +101 -18
- package/sensor/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/sensor/dist/extraction/tree-sitter.js +928 -134
- package/sensor/dist/extraction/tree-sitter.js.map +1 -1
- package/sensor/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
- package/sensor/dist/file-limits.d.ts +40 -0
- package/sensor/dist/file-limits.d.ts.map +1 -0
- package/sensor/dist/file-limits.js +147 -0
- package/sensor/dist/file-limits.js.map +1 -0
- package/sensor/dist/graph/branch-guards.d.ts +265 -0
- package/sensor/dist/graph/branch-guards.d.ts.map +1 -0
- package/sensor/dist/graph/branch-guards.js +2325 -0
- package/sensor/dist/graph/branch-guards.js.map +1 -0
- package/sensor/dist/graph/dead-code.d.ts +251 -0
- package/sensor/dist/graph/dead-code.d.ts.map +1 -0
- package/sensor/dist/graph/dead-code.js +776 -0
- package/sensor/dist/graph/dead-code.js.map +1 -0
- package/sensor/dist/graph/dynamic-boundary-report.d.ts +121 -0
- package/sensor/dist/graph/dynamic-boundary-report.d.ts.map +1 -0
- package/sensor/dist/graph/dynamic-boundary-report.js +283 -0
- package/sensor/dist/graph/dynamic-boundary-report.js.map +1 -0
- package/sensor/dist/graph/index.d.ts +4 -0
- package/sensor/dist/graph/index.d.ts.map +1 -1
- package/sensor/dist/graph/index.js +16 -1
- package/sensor/dist/graph/index.js.map +1 -1
- package/sensor/dist/graph/named-symbol-flow.d.ts +125 -0
- package/sensor/dist/graph/named-symbol-flow.d.ts.map +1 -0
- package/sensor/dist/graph/named-symbol-flow.js +552 -0
- package/sensor/dist/graph/named-symbol-flow.js.map +1 -0
- package/sensor/dist/graph/queries.d.ts.map +1 -1
- package/sensor/dist/graph/queries.js +2 -0
- package/sensor/dist/graph/queries.js.map +1 -1
- package/sensor/dist/graph/symbol-lookup.d.ts +83 -0
- package/sensor/dist/graph/symbol-lookup.d.ts.map +1 -0
- package/sensor/dist/graph/symbol-lookup.js +181 -0
- package/sensor/dist/graph/symbol-lookup.js.map +1 -0
- package/sensor/dist/graph/traversal.d.ts +9 -0
- package/sensor/dist/graph/traversal.d.ts.map +1 -1
- package/sensor/dist/graph/traversal.js +62 -36
- package/sensor/dist/graph/traversal.js.map +1 -1
- package/sensor/dist/graph/type-hierarchy.d.ts +155 -0
- package/sensor/dist/graph/type-hierarchy.d.ts.map +1 -0
- package/sensor/dist/graph/type-hierarchy.js +382 -0
- package/sensor/dist/graph/type-hierarchy.js.map +1 -0
- package/sensor/dist/index.d.ts +272 -10
- package/sensor/dist/index.d.ts.map +1 -1
- package/sensor/dist/index.js +510 -34
- package/sensor/dist/index.js.map +1 -1
- package/sensor/dist/mcp/answer-freshness.d.ts +10 -0
- package/sensor/dist/mcp/answer-freshness.d.ts.map +1 -0
- package/sensor/dist/mcp/answer-freshness.js +68 -0
- package/sensor/dist/mcp/answer-freshness.js.map +1 -0
- package/sensor/dist/mcp/daemon-manager.d.ts +1 -1
- package/sensor/dist/mcp/daemon-manager.d.ts.map +1 -1
- package/sensor/dist/mcp/daemon-manager.js +17 -1
- package/sensor/dist/mcp/daemon-manager.js.map +1 -1
- package/sensor/dist/mcp/daemon-paths.d.ts +8 -0
- package/sensor/dist/mcp/daemon-paths.d.ts.map +1 -1
- package/sensor/dist/mcp/daemon-paths.js +65 -2
- package/sensor/dist/mcp/daemon-paths.js.map +1 -1
- package/sensor/dist/mcp/daemon-registry.d.ts +17 -4
- package/sensor/dist/mcp/daemon-registry.d.ts.map +1 -1
- package/sensor/dist/mcp/daemon-registry.js +133 -23
- package/sensor/dist/mcp/daemon-registry.js.map +1 -1
- package/sensor/dist/mcp/daemon.d.ts +26 -13
- package/sensor/dist/mcp/daemon.d.ts.map +1 -1
- package/sensor/dist/mcp/daemon.js +126 -32
- package/sensor/dist/mcp/daemon.js.map +1 -1
- package/sensor/dist/mcp/dynamic-boundaries.d.ts +1 -10
- package/sensor/dist/mcp/dynamic-boundaries.d.ts.map +1 -1
- package/sensor/dist/mcp/dynamic-boundaries.js +46 -42
- package/sensor/dist/mcp/dynamic-boundaries.js.map +1 -1
- package/sensor/dist/mcp/engine.d.ts +31 -9
- package/sensor/dist/mcp/engine.d.ts.map +1 -1
- package/sensor/dist/mcp/engine.js +190 -79
- package/sensor/dist/mcp/engine.js.map +1 -1
- package/sensor/dist/mcp/explore-dedup.d.ts +140 -0
- package/sensor/dist/mcp/explore-dedup.d.ts.map +1 -0
- package/sensor/dist/mcp/explore-dedup.js +239 -0
- package/sensor/dist/mcp/explore-dedup.js.map +1 -0
- package/sensor/dist/mcp/explore-diagnostics.d.ts +289 -0
- package/sensor/dist/mcp/explore-diagnostics.d.ts.map +1 -0
- package/sensor/dist/mcp/explore-diagnostics.js +558 -0
- package/sensor/dist/mcp/explore-diagnostics.js.map +1 -0
- package/sensor/dist/mcp/explore-session-state.d.ts +217 -0
- package/sensor/dist/mcp/explore-session-state.d.ts.map +1 -0
- package/sensor/dist/mcp/explore-session-state.js +322 -0
- package/sensor/dist/mcp/explore-session-state.js.map +1 -0
- package/sensor/dist/mcp/index-freshness-worker.d.ts +2 -0
- package/sensor/dist/mcp/index-freshness-worker.d.ts.map +1 -0
- package/sensor/dist/mcp/index-freshness-worker.js +30 -0
- package/sensor/dist/mcp/index-freshness-worker.js.map +1 -0
- package/sensor/dist/mcp/index-freshness.d.ts +7 -0
- package/sensor/dist/mcp/index-freshness.d.ts.map +1 -0
- package/sensor/dist/mcp/index-freshness.js +94 -0
- package/sensor/dist/mcp/index-freshness.js.map +1 -0
- package/sensor/dist/mcp/index.d.ts +3 -1
- package/sensor/dist/mcp/index.d.ts.map +1 -1
- package/sensor/dist/mcp/index.js +109 -12
- package/sensor/dist/mcp/index.js.map +1 -1
- package/sensor/dist/mcp/liveness-watchdog.d.ts +4 -1
- package/sensor/dist/mcp/liveness-watchdog.d.ts.map +1 -1
- package/sensor/dist/mcp/liveness-watchdog.js +11 -2
- package/sensor/dist/mcp/liveness-watchdog.js.map +1 -1
- package/sensor/dist/mcp/project-lifecycle.d.ts +9 -0
- package/sensor/dist/mcp/project-lifecycle.d.ts.map +1 -0
- package/sensor/dist/mcp/project-lifecycle.js +182 -0
- package/sensor/dist/mcp/project-lifecycle.js.map +1 -0
- package/sensor/dist/mcp/proxy.d.ts.map +1 -1
- package/sensor/dist/mcp/proxy.js +15 -1
- package/sensor/dist/mcp/proxy.js.map +1 -1
- package/sensor/dist/mcp/query-pool.d.ts +2 -2
- package/sensor/dist/mcp/query-pool.d.ts.map +1 -1
- package/sensor/dist/mcp/query-pool.js +9 -7
- package/sensor/dist/mcp/query-pool.js.map +1 -1
- package/sensor/dist/mcp/query-worker.js +2 -2
- package/sensor/dist/mcp/query-worker.js.map +1 -1
- package/sensor/dist/mcp/server-instructions.d.ts +2 -2
- package/sensor/dist/mcp/server-instructions.d.ts.map +1 -1
- package/sensor/dist/mcp/server-instructions.js +13 -6
- package/sensor/dist/mcp/server-instructions.js.map +1 -1
- package/sensor/dist/mcp/session.d.ts +16 -0
- package/sensor/dist/mcp/session.d.ts.map +1 -1
- package/sensor/dist/mcp/session.js +36 -13
- package/sensor/dist/mcp/session.js.map +1 -1
- package/sensor/dist/mcp/startup-handshake.d.ts +3 -1
- package/sensor/dist/mcp/startup-handshake.d.ts.map +1 -1
- package/sensor/dist/mcp/startup-handshake.js +10 -2
- package/sensor/dist/mcp/startup-handshake.js.map +1 -1
- package/sensor/dist/mcp/tools.d.ts +496 -38
- package/sensor/dist/mcp/tools.d.ts.map +1 -1
- package/sensor/dist/mcp/tools.js +4021 -772
- package/sensor/dist/mcp/tools.js.map +1 -1
- package/sensor/dist/mcp/writer-lock.d.ts +61 -0
- package/sensor/dist/mcp/writer-lock.d.ts.map +1 -0
- package/sensor/dist/mcp/writer-lock.js +260 -0
- package/sensor/dist/mcp/writer-lock.js.map +1 -0
- package/sensor/dist/project-config.d.ts +23 -0
- package/sensor/dist/project-config.d.ts.map +1 -1
- package/sensor/dist/project-config.js +39 -2
- package/sensor/dist/project-config.js.map +1 -1
- package/sensor/dist/resolution/alias-binding.d.ts +56 -0
- package/sensor/dist/resolution/alias-binding.d.ts.map +1 -0
- package/sensor/dist/resolution/alias-binding.js +127 -0
- package/sensor/dist/resolution/alias-binding.js.map +1 -0
- package/sensor/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
- package/sensor/dist/resolution/c-fnptr-synthesizer.js +21 -19
- package/sensor/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
- package/sensor/dist/resolution/callback-synthesizer.d.ts +23 -1
- package/sensor/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/sensor/dist/resolution/callback-synthesizer.js +356 -155
- package/sensor/dist/resolution/callback-synthesizer.js.map +1 -1
- package/sensor/dist/resolution/cpp-constructor.d.ts +4 -0
- package/sensor/dist/resolution/cpp-constructor.d.ts.map +1 -0
- package/sensor/dist/resolution/cpp-constructor.js +123 -0
- package/sensor/dist/resolution/cpp-constructor.js.map +1 -0
- package/sensor/dist/resolution/cpp-macro-visibility.d.ts +12 -0
- package/sensor/dist/resolution/cpp-macro-visibility.d.ts.map +1 -0
- package/sensor/dist/resolution/cpp-macro-visibility.js +342 -0
- package/sensor/dist/resolution/cpp-macro-visibility.js.map +1 -0
- package/sensor/dist/resolution/expo-router-synthesizer.d.ts +32 -0
- package/sensor/dist/resolution/expo-router-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/expo-router-synthesizer.js +189 -0
- package/sensor/dist/resolution/expo-router-synthesizer.js.map +1 -0
- package/sensor/dist/resolution/frameworks/csharp.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/csharp.js +96 -2
- package/sensor/dist/resolution/frameworks/csharp.js.map +1 -1
- package/sensor/dist/resolution/frameworks/expo-router.d.ts +189 -0
- package/sensor/dist/resolution/frameworks/expo-router.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/expo-router.js +785 -0
- package/sensor/dist/resolution/frameworks/expo-router.js.map +1 -0
- package/sensor/dist/resolution/frameworks/express.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/express.js +251 -16
- package/sensor/dist/resolution/frameworks/express.js.map +1 -1
- package/sensor/dist/resolution/frameworks/index.d.ts +5 -0
- package/sensor/dist/resolution/frameworks/index.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/index.js +29 -1
- package/sensor/dist/resolution/frameworks/index.js.map +1 -1
- package/sensor/dist/resolution/frameworks/java.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/java.js +79 -47
- package/sensor/dist/resolution/frameworks/java.js.map +1 -1
- package/sensor/dist/resolution/frameworks/laravel.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/laravel.js +294 -4
- package/sensor/dist/resolution/frameworks/laravel.js.map +1 -1
- package/sensor/dist/resolution/frameworks/nestjs.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/nestjs.js +6 -14
- package/sensor/dist/resolution/frameworks/nestjs.js.map +1 -1
- package/sensor/dist/resolution/frameworks/nextjs.d.ts +76 -0
- package/sensor/dist/resolution/frameworks/nextjs.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/nextjs.js +328 -0
- package/sensor/dist/resolution/frameworks/nextjs.js.map +1 -0
- package/sensor/dist/resolution/frameworks/object-literal.d.ts +32 -0
- package/sensor/dist/resolution/frameworks/object-literal.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/object-literal.js +139 -0
- package/sensor/dist/resolution/frameworks/object-literal.js.map +1 -0
- package/sensor/dist/resolution/frameworks/package-deps.d.ts +14 -0
- package/sensor/dist/resolution/frameworks/package-deps.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/package-deps.js +78 -0
- package/sensor/dist/resolution/frameworks/package-deps.js.map +1 -0
- package/sensor/dist/resolution/frameworks/python.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/python.js +166 -0
- package/sensor/dist/resolution/frameworks/python.js.map +1 -1
- package/sensor/dist/resolution/frameworks/react-native.d.ts +26 -0
- package/sensor/dist/resolution/frameworks/react-native.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/react-native.js +153 -14
- package/sensor/dist/resolution/frameworks/react-native.js.map +1 -1
- package/sensor/dist/resolution/frameworks/react-router.d.ts +46 -0
- package/sensor/dist/resolution/frameworks/react-router.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/react-router.js +187 -0
- package/sensor/dist/resolution/frameworks/react-router.js.map +1 -0
- package/sensor/dist/resolution/frameworks/react.d.ts +2 -1
- package/sensor/dist/resolution/frameworks/react.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/react.js +188 -139
- package/sensor/dist/resolution/frameworks/react.js.map +1 -1
- package/sensor/dist/resolution/frameworks/svelte.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/svelte.js +6 -1
- package/sensor/dist/resolution/frameworks/svelte.js.map +1 -1
- package/sensor/dist/resolution/frameworks/sveltekit-router.d.ts +36 -0
- package/sensor/dist/resolution/frameworks/sveltekit-router.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/sveltekit-router.js +156 -0
- package/sensor/dist/resolution/frameworks/sveltekit-router.js.map +1 -0
- package/sensor/dist/resolution/frameworks/swift.d.ts.map +1 -1
- package/sensor/dist/resolution/frameworks/swift.js +140 -99
- package/sensor/dist/resolution/frameworks/swift.js.map +1 -1
- package/sensor/dist/resolution/frameworks/tanstack-router.d.ts +84 -0
- package/sensor/dist/resolution/frameworks/tanstack-router.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/tanstack-router.js +437 -0
- package/sensor/dist/resolution/frameworks/tanstack-router.js.map +1 -0
- package/sensor/dist/resolution/frameworks/vue-router.d.ts +82 -0
- package/sensor/dist/resolution/frameworks/vue-router.d.ts.map +1 -0
- package/sensor/dist/resolution/frameworks/vue-router.js +377 -0
- package/sensor/dist/resolution/frameworks/vue-router.js.map +1 -0
- package/sensor/dist/resolution/import-resolver.d.ts +38 -0
- package/sensor/dist/resolution/import-resolver.d.ts.map +1 -1
- package/sensor/dist/resolution/import-resolver.js +394 -28
- package/sensor/dist/resolution/import-resolver.js.map +1 -1
- package/sensor/dist/resolution/index.d.ts +89 -25
- package/sensor/dist/resolution/index.d.ts.map +1 -1
- package/sensor/dist/resolution/index.js +573 -148
- package/sensor/dist/resolution/index.js.map +1 -1
- package/sensor/dist/resolution/js-builtins.d.ts +13 -0
- package/sensor/dist/resolution/js-builtins.d.ts.map +1 -0
- package/sensor/dist/resolution/js-builtins.js +46 -0
- package/sensor/dist/resolution/js-builtins.js.map +1 -0
- package/sensor/dist/resolution/name-matcher.d.ts +99 -22
- package/sensor/dist/resolution/name-matcher.d.ts.map +1 -1
- package/sensor/dist/resolution/name-matcher.js +2220 -86
- package/sensor/dist/resolution/name-matcher.js.map +1 -1
- package/sensor/dist/resolution/next-router-synthesizer.d.ts +27 -0
- package/sensor/dist/resolution/next-router-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/next-router-synthesizer.js +113 -0
- package/sensor/dist/resolution/next-router-synthesizer.js.map +1 -0
- package/sensor/dist/resolution/path-aliases.d.ts +6 -4
- package/sensor/dist/resolution/path-aliases.d.ts.map +1 -1
- package/sensor/dist/resolution/path-aliases.js +125 -17
- package/sensor/dist/resolution/path-aliases.js.map +1 -1
- package/sensor/dist/resolution/react-router-synthesizer.d.ts +33 -0
- package/sensor/dist/resolution/react-router-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/react-router-synthesizer.js +126 -0
- package/sensor/dist/resolution/react-router-synthesizer.js.map +1 -0
- package/sensor/dist/resolution/resolver-pool.d.ts +2 -0
- package/sensor/dist/resolution/resolver-pool.d.ts.map +1 -1
- package/sensor/dist/resolution/resolver-pool.js +4 -0
- package/sensor/dist/resolution/resolver-pool.js.map +1 -1
- package/sensor/dist/resolution/strip-comments.d.ts +6 -0
- package/sensor/dist/resolution/strip-comments.d.ts.map +1 -1
- package/sensor/dist/resolution/strip-comments.js +58 -0
- package/sensor/dist/resolution/strip-comments.js.map +1 -1
- package/sensor/dist/resolution/sveltekit-synthesizer.d.ts +58 -0
- package/sensor/dist/resolution/sveltekit-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/sveltekit-synthesizer.js +173 -0
- package/sensor/dist/resolution/sveltekit-synthesizer.js.map +1 -0
- package/sensor/dist/resolution/swift-type-visibility.d.ts +52 -0
- package/sensor/dist/resolution/swift-type-visibility.d.ts.map +1 -0
- package/sensor/dist/resolution/swift-type-visibility.js +328 -0
- package/sensor/dist/resolution/swift-type-visibility.js.map +1 -0
- package/sensor/dist/resolution/synth-utils.d.ts +26 -0
- package/sensor/dist/resolution/synth-utils.d.ts.map +1 -0
- package/sensor/dist/resolution/synth-utils.js +75 -0
- package/sensor/dist/resolution/synth-utils.js.map +1 -0
- package/sensor/dist/resolution/tanstack-router-synthesizer.d.ts +31 -0
- package/sensor/dist/resolution/tanstack-router-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/tanstack-router-synthesizer.js +114 -0
- package/sensor/dist/resolution/tanstack-router-synthesizer.js.map +1 -0
- package/sensor/dist/resolution/tier-synthesizer.d.ts +54 -0
- package/sensor/dist/resolution/tier-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/tier-synthesizer.js +1294 -0
- package/sensor/dist/resolution/tier-synthesizer.js.map +1 -0
- package/sensor/dist/resolution/types.d.ts +78 -2
- package/sensor/dist/resolution/types.d.ts.map +1 -1
- package/sensor/dist/resolution/types.js +64 -0
- package/sensor/dist/resolution/types.js.map +1 -1
- package/sensor/dist/resolution/vue-router-synthesizer.d.ts +30 -0
- package/sensor/dist/resolution/vue-router-synthesizer.d.ts.map +1 -0
- package/sensor/dist/resolution/vue-router-synthesizer.js +115 -0
- package/sensor/dist/resolution/vue-router-synthesizer.js.map +1 -0
- package/sensor/dist/search/identifier-segments.d.ts +10 -0
- package/sensor/dist/search/identifier-segments.d.ts.map +1 -1
- package/sensor/dist/search/identifier-segments.js +29 -0
- package/sensor/dist/search/identifier-segments.js.map +1 -1
- package/sensor/dist/search/query-paths.d.ts +106 -0
- package/sensor/dist/search/query-paths.d.ts.map +1 -0
- package/sensor/dist/search/query-paths.js +513 -0
- package/sensor/dist/search/query-paths.js.map +1 -0
- package/sensor/dist/search/query-utils.d.ts +22 -2
- package/sensor/dist/search/query-utils.d.ts.map +1 -1
- package/sensor/dist/search/query-utils.js +56 -16
- package/sensor/dist/search/query-utils.js.map +1 -1
- package/sensor/dist/sync/watch-policy.d.ts +14 -0
- package/sensor/dist/sync/watch-policy.d.ts.map +1 -1
- package/sensor/dist/sync/watch-policy.js +19 -0
- package/sensor/dist/sync/watch-policy.js.map +1 -1
- package/sensor/dist/sync/watcher.d.ts +74 -35
- package/sensor/dist/sync/watcher.d.ts.map +1 -1
- package/sensor/dist/sync/watcher.js +281 -99
- package/sensor/dist/sync/watcher.js.map +1 -1
- package/sensor/dist/telemetry/index.d.ts +4 -2
- package/sensor/dist/telemetry/index.d.ts.map +1 -1
- package/sensor/dist/telemetry/index.js +92 -41
- package/sensor/dist/telemetry/index.js.map +1 -1
- package/sensor/dist/types.d.ts +18 -2
- package/sensor/dist/types.d.ts.map +1 -1
- package/sensor/dist/types.js +2 -0
- package/sensor/dist/types.js.map +1 -1
- package/sensor/dist/ui-server/api/deadcode.d.ts +84 -0
- package/sensor/dist/ui-server/api/deadcode.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/deadcode.js +136 -0
- package/sensor/dist/ui-server/api/deadcode.js.map +1 -0
- package/sensor/dist/ui-server/api/effects.d.ts +94 -0
- package/sensor/dist/ui-server/api/effects.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/effects.js +527 -0
- package/sensor/dist/ui-server/api/effects.js.map +1 -0
- package/sensor/dist/ui-server/api/entrypoints.d.ts +92 -0
- package/sensor/dist/ui-server/api/entrypoints.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/entrypoints.js +361 -0
- package/sensor/dist/ui-server/api/entrypoints.js.map +1 -0
- package/sensor/dist/ui-server/api/events.d.ts +183 -0
- package/sensor/dist/ui-server/api/events.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/events.js +430 -0
- package/sensor/dist/ui-server/api/events.js.map +1 -0
- package/sensor/dist/ui-server/api/file.d.ts +66 -0
- package/sensor/dist/ui-server/api/file.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/file.js +235 -0
- package/sensor/dist/ui-server/api/file.js.map +1 -0
- package/sensor/dist/ui-server/api/filecode.d.ts +126 -0
- package/sensor/dist/ui-server/api/filecode.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/filecode.js +205 -0
- package/sensor/dist/ui-server/api/filecode.js.map +1 -0
- package/sensor/dist/ui-server/api/flow.d.ts +226 -0
- package/sensor/dist/ui-server/api/flow.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/flow.js +612 -0
- package/sensor/dist/ui-server/api/flow.js.map +1 -0
- package/sensor/dist/ui-server/api/hierarchy.d.ts +81 -0
- package/sensor/dist/ui-server/api/hierarchy.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/hierarchy.js +92 -0
- package/sensor/dist/ui-server/api/hierarchy.js.map +1 -0
- package/sensor/dist/ui-server/api/index.d.ts +90 -0
- package/sensor/dist/ui-server/api/index.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/index.js +332 -0
- package/sensor/dist/ui-server/api/index.js.map +1 -0
- package/sensor/dist/ui-server/api/map.d.ts +256 -0
- package/sensor/dist/ui-server/api/map.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/map.js +760 -0
- package/sensor/dist/ui-server/api/map.js.map +1 -0
- package/sensor/dist/ui-server/api/node.d.ts +81 -0
- package/sensor/dist/ui-server/api/node.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/node.js +388 -0
- package/sensor/dist/ui-server/api/node.js.map +1 -0
- package/sensor/dist/ui-server/api/nodes.d.ts +25 -0
- package/sensor/dist/ui-server/api/nodes.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/nodes.js +45 -0
- package/sensor/dist/ui-server/api/nodes.js.map +1 -0
- package/sensor/dist/ui-server/api/program.d.ts +139 -0
- package/sensor/dist/ui-server/api/program.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/program.js +315 -0
- package/sensor/dist/ui-server/api/program.js.map +1 -0
- package/sensor/dist/ui-server/api/respond.d.ts +76 -0
- package/sensor/dist/ui-server/api/respond.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/respond.js +186 -0
- package/sensor/dist/ui-server/api/respond.js.map +1 -0
- package/sensor/dist/ui-server/api/route-roots.d.ts +39 -0
- package/sensor/dist/ui-server/api/route-roots.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/route-roots.js +96 -0
- package/sensor/dist/ui-server/api/route-roots.js.map +1 -0
- package/sensor/dist/ui-server/api/routes.d.ts +59 -0
- package/sensor/dist/ui-server/api/routes.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/routes.js +108 -0
- package/sensor/dist/ui-server/api/routes.js.map +1 -0
- package/sensor/dist/ui-server/api/screens.d.ts +117 -0
- package/sensor/dist/ui-server/api/screens.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/screens.js +611 -0
- package/sensor/dist/ui-server/api/screens.js.map +1 -0
- package/sensor/dist/ui-server/api/search.d.ts +29 -0
- package/sensor/dist/ui-server/api/search.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/search.js +232 -0
- package/sensor/dist/ui-server/api/search.js.map +1 -0
- package/sensor/dist/ui-server/api/session.d.ts +52 -0
- package/sensor/dist/ui-server/api/session.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/session.js +196 -0
- package/sensor/dist/ui-server/api/session.js.map +1 -0
- package/sensor/dist/ui-server/api/source.d.ts +200 -0
- package/sensor/dist/ui-server/api/source.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/source.js +422 -0
- package/sensor/dist/ui-server/api/source.js.map +1 -0
- package/sensor/dist/ui-server/api/stats.d.ts +27 -0
- package/sensor/dist/ui-server/api/stats.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/stats.js +164 -0
- package/sensor/dist/ui-server/api/stats.js.map +1 -0
- package/sensor/dist/ui-server/api/steps.d.ts +274 -0
- package/sensor/dist/ui-server/api/steps.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/steps.js +1544 -0
- package/sensor/dist/ui-server/api/steps.js.map +1 -0
- package/sensor/dist/ui-server/api/trail-store.d.ts +142 -0
- package/sensor/dist/ui-server/api/trail-store.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/trail-store.js +325 -0
- package/sensor/dist/ui-server/api/trail-store.js.map +1 -0
- package/sensor/dist/ui-server/api/trails.d.ts +163 -0
- package/sensor/dist/ui-server/api/trails.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/trails.js +369 -0
- package/sensor/dist/ui-server/api/trails.js.map +1 -0
- package/sensor/dist/ui-server/api/when.d.ts +133 -0
- package/sensor/dist/ui-server/api/when.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/when.js +275 -0
- package/sensor/dist/ui-server/api/when.js.map +1 -0
- package/sensor/dist/ui-server/api/wire.d.ts +179 -0
- package/sensor/dist/ui-server/api/wire.d.ts.map +1 -0
- package/sensor/dist/ui-server/api/wire.js +231 -0
- package/sensor/dist/ui-server/api/wire.js.map +1 -0
- package/sensor/dist/ui-server/assets.d.ts +40 -0
- package/sensor/dist/ui-server/assets.d.ts.map +1 -0
- package/sensor/dist/ui-server/assets.js +110 -0
- package/sensor/dist/ui-server/assets.js.map +1 -0
- package/sensor/dist/ui-server/constants.d.ts +32 -0
- package/sensor/dist/ui-server/constants.d.ts.map +1 -0
- package/sensor/dist/ui-server/constants.js +35 -0
- package/sensor/dist/ui-server/constants.js.map +1 -0
- package/sensor/dist/ui-server/highlight/index.d.ts +113 -0
- package/sensor/dist/ui-server/highlight/index.d.ts.map +1 -0
- package/sensor/dist/ui-server/highlight/index.js +307 -0
- package/sensor/dist/ui-server/highlight/index.js.map +1 -0
- package/sensor/dist/ui-server/highlight/languages.d.ts +36 -0
- package/sensor/dist/ui-server/highlight/languages.d.ts.map +1 -0
- package/sensor/dist/ui-server/highlight/languages.js +50 -0
- package/sensor/dist/ui-server/highlight/languages.js.map +1 -0
- package/sensor/dist/ui-server/index.d.ts +92 -0
- package/sensor/dist/ui-server/index.d.ts.map +1 -0
- package/sensor/dist/ui-server/index.js +399 -0
- package/sensor/dist/ui-server/index.js.map +1 -0
- package/sensor/dist/ui-server/open-browser.d.ts +31 -0
- package/sensor/dist/ui-server/open-browser.d.ts.map +1 -0
- package/sensor/dist/ui-server/open-browser.js +79 -0
- package/sensor/dist/ui-server/open-browser.js.map +1 -0
- package/sensor/dist/ui-server/security.d.ts +127 -0
- package/sensor/dist/ui-server/security.d.ts.map +1 -0
- package/sensor/dist/ui-server/security.js +332 -0
- package/sensor/dist/ui-server/security.js.map +1 -0
- package/sensor/dist/ui-server/static.d.ts +45 -0
- package/sensor/dist/ui-server/static.d.ts.map +1 -0
- package/sensor/dist/ui-server/static.js +165 -0
- package/sensor/dist/ui-server/static.js.map +1 -0
- package/sensor/dist/utils.d.ts +14 -2
- package/sensor/dist/utils.d.ts.map +1 -1
- package/sensor/dist/utils.js +25 -10
- package/sensor/dist/utils.js.map +1 -1
- package/src/cli-help.mjs +4 -2
- package/src/sensor-adapter.mjs +5 -1
- package/src/todo-cli.mjs +88 -11
|
@@ -47,6 +47,7 @@ const function_ref_1 = require("./function-ref");
|
|
|
47
47
|
const generated_detection_1 = require("./generated-detection");
|
|
48
48
|
const languages_1 = require("./languages");
|
|
49
49
|
const c_cpp_1 = require("./languages/c-cpp");
|
|
50
|
+
const rust_1 = require("./languages/rust");
|
|
50
51
|
const liquid_extractor_1 = require("./liquid-extractor");
|
|
51
52
|
const razor_extractor_1 = require("./razor-extractor");
|
|
52
53
|
const svelte_extractor_1 = require("./svelte-extractor");
|
|
@@ -73,6 +74,19 @@ const RTK_HOOK_NAME_RE = /^use[A-Z][A-Za-z0-9]*(?:Query|Mutation)$/;
|
|
|
73
74
|
/** React HOC callees whose result is itself a component — a PascalCase const
|
|
74
75
|
* initialized with one of these is a component, not a constant (#841). */
|
|
75
76
|
const REACT_COMPONENT_HOCS = new Set(['forwardRef', 'memo', 'React.forwardRef', 'React.memo']);
|
|
77
|
+
/**
|
|
78
|
+
* Method node types that spell a SIGNATURE — a declaration with no body (#1638).
|
|
79
|
+
*
|
|
80
|
+
* They are a method of whatever type declares them and nothing on their own, so
|
|
81
|
+
* they must not take `extractMethod`'s "no class-like parent, so treat it as a
|
|
82
|
+
* free function" fallback. The other `methodTypes` can: a `method_definition`
|
|
83
|
+
* outside a class really is a function. This one appears outside a class only
|
|
84
|
+
* inside a type literal (`type Handle = { stop(): void }`), whose members
|
|
85
|
+
* `extractTypeAlias` already extracts and attaches to the alias (#359) — take
|
|
86
|
+
* the fallback and the file gains a phantom top-level `function stop` beside
|
|
87
|
+
* the real `Handle::stop`.
|
|
88
|
+
*/
|
|
89
|
+
const SIGNATURE_METHOD_NODE_TYPES = new Set(['method_signature']);
|
|
76
90
|
/** Vue store collections whose object-literal members are the symbols an agent
|
|
77
91
|
* looks for. Extracted as function nodes so `actions`/`mutations`/`getters` are
|
|
78
92
|
* findable + readable (the foundation under any later dispatch-bridge synth). */
|
|
@@ -187,7 +201,7 @@ function extractNameRaw(node, source, extractor) {
|
|
|
187
201
|
// not from identifiers in their body. Without this, single-expression arrow
|
|
188
202
|
// functions like `const fn = () => someIdentifier` get named "someIdentifier"
|
|
189
203
|
// instead of "fn", because the fallback below finds the body identifier.
|
|
190
|
-
if (node.type === 'arrow_function' || node.type === 'function_expression') {
|
|
204
|
+
if (node.type === 'arrow_function' || node.type === 'function_expression' || node.type === 'generator_function') {
|
|
191
205
|
return '<anonymous>';
|
|
192
206
|
}
|
|
193
207
|
// Fall back to first identifier child
|
|
@@ -385,12 +399,107 @@ const LITERAL_RECEIVER_TYPES = new Set([
|
|
|
385
399
|
'list', 'list_literal', 'array', 'array_literal', 'array_creation_expression',
|
|
386
400
|
'dictionary', 'dict_literal', 'object', 'tuple', 'set',
|
|
387
401
|
]);
|
|
402
|
+
/**
|
|
403
|
+
* Languages whose member calls go through the TS/JS grammars.
|
|
404
|
+
*/
|
|
405
|
+
const TS_JS_CHAIN_LANGUAGES = new Set(['typescript', 'tsx', 'javascript', 'jsx']);
|
|
406
|
+
/** Receiver node types (TS/JS grammars) that continue a member chain downward. */
|
|
407
|
+
const TS_JS_CHAIN_RECEIVER_TYPES = new Set(['member_expression', 'subscript_expression']);
|
|
408
|
+
/** The field of a `this.<field>.<method>()` receiver: public or ES private (#1496, #1987). */
|
|
409
|
+
const THIS_FIELD_PROPERTY_TYPES = new Set(['property_identifier', 'private_property_identifier']);
|
|
410
|
+
/**
|
|
411
|
+
* Identifier-rooted member chains have no inferred property type (#1566),
|
|
412
|
+
* including host API chains (#1707). Keep the existing `window.MyNamespace`
|
|
413
|
+
* escape for project globals; call-result and `this` receivers have their own
|
|
414
|
+
* paths and are outside this guard.
|
|
415
|
+
*/
|
|
416
|
+
function isUnresolvedTsJsChain(node, source) {
|
|
417
|
+
let cur = node;
|
|
418
|
+
while (cur && TS_JS_CHAIN_RECEIVER_TYPES.has(cur.type)) {
|
|
419
|
+
cur = (0, tree_sitter_helpers_1.getChildByField)(cur, 'object');
|
|
420
|
+
}
|
|
421
|
+
return !!cur && cur.type === 'identifier' && (0, tree_sitter_helpers_1.getNodeText)(cur, source) !== 'window';
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* TS/JS wrappers that leave a member call's receiver the same object:
|
|
425
|
+
* `(x).m()`, `x!.m()`, `(x as T).m()`, `(x satisfies T).m()`, `(<T>x).m()`
|
|
426
|
+
* and `(await x).m()` all call `m` on what `x` holds.
|
|
427
|
+
*/
|
|
428
|
+
const TS_JS_TRANSPARENT_RECEIVER_TYPES = new Set([
|
|
429
|
+
'parenthesized_expression', 'non_null_expression', 'as_expression',
|
|
430
|
+
'satisfies_expression', 'type_assertion', 'await_expression',
|
|
431
|
+
]);
|
|
432
|
+
/**
|
|
433
|
+
* Strip {@link TS_JS_TRANSPARENT_RECEIVER_TYPES} wrappers off a receiver.
|
|
434
|
+
* tree-sitter-typescript parses `a && b!.c()` as `(a && b)!.c()`; the `!`
|
|
435
|
+
* belongs to the right operand, so a non-null over a binary expression peels
|
|
436
|
+
* to that operand.
|
|
437
|
+
*/
|
|
438
|
+
function peelTsJsReceiver(node) {
|
|
439
|
+
let cur = node;
|
|
440
|
+
while (TS_JS_TRANSPARENT_RECEIVER_TYPES.has(cur.type)) {
|
|
441
|
+
let inner = cur.type === 'type_assertion'
|
|
442
|
+
? cur.namedChild(cur.namedChildCount - 1)
|
|
443
|
+
: cur.namedChild(0);
|
|
444
|
+
if (cur.type === 'non_null_expression') {
|
|
445
|
+
while (inner?.type === 'binary_expression')
|
|
446
|
+
inner = (0, tree_sitter_helpers_1.getChildByField)(inner, 'right');
|
|
447
|
+
}
|
|
448
|
+
if (!inner)
|
|
449
|
+
break;
|
|
450
|
+
cur = inner;
|
|
451
|
+
}
|
|
452
|
+
return cur;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Whether a TS/JS receiver still collapses to the bare method name: `this` /
|
|
456
|
+
* `super` (the resolver reads the owner off the enclosing class), a member
|
|
457
|
+
* chain rooted at either or at `window` (the project-global escape of
|
|
458
|
+
* {@link isUnresolvedTsJsChain}), and `new C()` (its class is written at the
|
|
459
|
+
* call).
|
|
460
|
+
*/
|
|
461
|
+
function keepsBareTsJsReceiver(node, source) {
|
|
462
|
+
let cur = node;
|
|
463
|
+
while (cur && TS_JS_CHAIN_RECEIVER_TYPES.has(cur.type)) {
|
|
464
|
+
const object = (0, tree_sitter_helpers_1.getChildByField)(cur, 'object');
|
|
465
|
+
cur = object ? peelTsJsReceiver(object) : null;
|
|
466
|
+
}
|
|
467
|
+
if (!cur)
|
|
468
|
+
return false;
|
|
469
|
+
if (cur.type === 'this' || cur.type === 'super')
|
|
470
|
+
return true;
|
|
471
|
+
if (cur.type === 'identifier')
|
|
472
|
+
return (0, tree_sitter_helpers_1.getNodeText)(cur, source) === 'window';
|
|
473
|
+
return cur === node && cur.type === 'new_expression';
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* React hooks that bind a NAME to a handler function (`const onPress =
|
|
477
|
+
* useCallback(() => {…}, [])`). The arrow inside is extracted as a function
|
|
478
|
+
* node named by the declarator — see `reactHookBoundName`.
|
|
479
|
+
*/
|
|
480
|
+
const REACT_HANDLER_HOOKS = /^(?:React\.)?use(?:Callback|EffectEvent|Event)$/;
|
|
388
481
|
class TreeSitterExtractor {
|
|
482
|
+
/**
|
|
483
|
+
* The node's prose, from either place it can live: a preceding comment
|
|
484
|
+
* sibling (every language) or a docstring inside the body (Python's bare
|
|
485
|
+
* first-statement string, and the same shape in other languages that opt in
|
|
486
|
+
* via `getBodyDocstring`). When a node carries both, they are joined rather
|
|
487
|
+
* than one winning — they are two separate things the author wrote about the
|
|
488
|
+
* same symbol, and the column holds free text (#1905).
|
|
489
|
+
*/
|
|
490
|
+
docstringFor(node) {
|
|
491
|
+
const preceding = (0, tree_sitter_helpers_1.getPrecedingDocstring)(node, this.source);
|
|
492
|
+
const body = this.extractor?.getBodyDocstring?.(node, this.source);
|
|
493
|
+
if (preceding && body)
|
|
494
|
+
return `${preceding}\n\n${body}`;
|
|
495
|
+
return body || preceding;
|
|
496
|
+
}
|
|
389
497
|
filePath;
|
|
390
498
|
language;
|
|
391
499
|
source;
|
|
392
500
|
tree = null;
|
|
393
501
|
nodes = [];
|
|
502
|
+
nodeIds = new tree_sitter_helpers_1.NodeIdAllocator();
|
|
394
503
|
edges = [];
|
|
395
504
|
unresolvedReferences = [];
|
|
396
505
|
// Value-reference edges (default ON; set LATTICE_SENSOR_VALUE_REFS=0 to disable; see flushValueRefs).
|
|
@@ -506,6 +615,9 @@ class TreeSitterExtractor {
|
|
|
506
615
|
isExported: false,
|
|
507
616
|
updatedAt: Date.now(),
|
|
508
617
|
};
|
|
618
|
+
const fileDocstring = this.extractor?.getBodyDocstring?.(this.tree.rootNode, this.source);
|
|
619
|
+
if (fileDocstring)
|
|
620
|
+
fileNode.docstring = fileDocstring;
|
|
509
621
|
this.nodes.push(fileNode);
|
|
510
622
|
// Push file node onto stack so top-level declarations get contains edges
|
|
511
623
|
this.nodeStack.push(fileNode.id);
|
|
@@ -524,6 +636,16 @@ class TreeSitterExtractor {
|
|
|
524
636
|
if (packageNodeId)
|
|
525
637
|
this.nodeStack.pop();
|
|
526
638
|
this.nodeStack.pop();
|
|
639
|
+
// hasError is routine for several grammars; warn only when no symbols survived.
|
|
640
|
+
const symbolCount = this.nodes.filter((n) => n.kind !== 'file').length;
|
|
641
|
+
if (this.tree?.rootNode.hasError && symbolCount === 0) {
|
|
642
|
+
this.errors.push({
|
|
643
|
+
message: `${this.filePath}: parse produced no symbols (tree has errors) — ` +
|
|
644
|
+
`the file is indexed but contributes nothing to the graph`,
|
|
645
|
+
severity: 'warning',
|
|
646
|
+
code: 'parse_error',
|
|
647
|
+
});
|
|
648
|
+
}
|
|
527
649
|
}
|
|
528
650
|
catch (error) {
|
|
529
651
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -589,6 +711,7 @@ class TreeSitterExtractor {
|
|
|
589
711
|
return;
|
|
590
712
|
const nodeType = node.type;
|
|
591
713
|
if (depth > 0 && (this.extractor?.functionTypes.includes(nodeType) ||
|
|
714
|
+
((this.language === 'lua' || this.language === 'luau') && nodeType === 'function_definition') ||
|
|
592
715
|
nodeType === 'arrow_function' ||
|
|
593
716
|
nodeType === 'function_expression' ||
|
|
594
717
|
nodeType === 'lambda_literal' ||
|
|
@@ -983,7 +1106,14 @@ class TreeSitterExtractor {
|
|
|
983
1106
|
if (n.type === 'identifier' || n.type === 'constant' ||
|
|
984
1107
|
n.type === 'name' || n.type === 'simple_identifier') {
|
|
985
1108
|
const refName = (0, tree_sitter_helpers_1.getNodeText)(n, this.source);
|
|
986
|
-
|
|
1109
|
+
// C/C++: the callee of a call is a call, not a value read — even when a
|
|
1110
|
+
// same-named function-like macro (`#define helper(x) …`) is a file-scope
|
|
1111
|
+
// constant. The call edge resolves it; a value ref here would be a second,
|
|
1112
|
+
// wrong reading of the same token (upstream #2070 made such macros nodes).
|
|
1113
|
+
const calleePosition = (this.language === 'c' || this.language === 'cpp')
|
|
1114
|
+
&& n.parent?.type === 'call_expression'
|
|
1115
|
+
&& (0, tree_sitter_helpers_1.getChildByField)(n.parent, 'function')?.startIndex === n.startIndex;
|
|
1116
|
+
const targetId = calleePosition ? undefined : targets.get(refName);
|
|
987
1117
|
// Skip self and same-name targets: a symbol referencing a file-scope
|
|
988
1118
|
// sibling of its own name (the two halves of a conditional `try: X=…;
|
|
989
1119
|
// except: X=…`) is never a meaningful value read.
|
|
@@ -1039,6 +1169,25 @@ class TreeSitterExtractor {
|
|
|
1039
1169
|
if (skipChildren)
|
|
1040
1170
|
return;
|
|
1041
1171
|
}
|
|
1172
|
+
if (this.language === 'cpp' && (0, c_cpp_1.isCppConstructorDeclaration)(node)) {
|
|
1173
|
+
this.extractMethod(node);
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
// C/C++ function-like macros (`#define TRACE(x) ...`) become `constant`
|
|
1177
|
+
// nodes carrying the directive as their signature. A macro is a value,
|
|
1178
|
+
// never an executable callee: the resolver reads these to recognize a
|
|
1179
|
+
// call whose name is a macro visible in the translation unit and refuses
|
|
1180
|
+
// to bind it to a same-named function elsewhere (#1838). Mirrored in the
|
|
1181
|
+
// kernel (ccpp/mod.rs visit_node).
|
|
1182
|
+
if ((this.language === 'c' || this.language === 'cpp') && nodeType === 'preproc_function_def') {
|
|
1183
|
+
const name = (0, tree_sitter_helpers_1.getChildByField)(node, 'name');
|
|
1184
|
+
if (name) {
|
|
1185
|
+
this.createNode('constant', (0, tree_sitter_helpers_1.getNodeText)(name, this.source), node, {
|
|
1186
|
+
signature: (0, tree_sitter_helpers_1.getNodeText)(node, this.source).trim(),
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1042
1191
|
// C++ namespace blocks: carry the namespace name as a qualifiedName prefix
|
|
1043
1192
|
// while walking the body, so `namespace flash { void compute_attn(); }`
|
|
1044
1193
|
// indexes compute_attn with qualifiedName `flash::compute_attn` and a
|
|
@@ -1097,6 +1246,9 @@ class TreeSitterExtractor {
|
|
|
1097
1246
|
else if (classification === 'trait') {
|
|
1098
1247
|
this.extractClass(node, 'trait');
|
|
1099
1248
|
}
|
|
1249
|
+
else if (classification === 'module') {
|
|
1250
|
+
this.extractClass(node, 'module');
|
|
1251
|
+
}
|
|
1100
1252
|
else {
|
|
1101
1253
|
this.extractClass(node);
|
|
1102
1254
|
}
|
|
@@ -1107,12 +1259,23 @@ class TreeSitterExtractor {
|
|
|
1107
1259
|
this.extractClass(node);
|
|
1108
1260
|
skipChildren = true;
|
|
1109
1261
|
}
|
|
1110
|
-
// Check for method declarations (only if not already handled by functionTypes)
|
|
1111
|
-
|
|
1262
|
+
// Check for method declarations (only if not already handled by functionTypes).
|
|
1263
|
+
// A bodiless SIGNATURE only counts as one where a type declares it — see
|
|
1264
|
+
// SIGNATURE_METHOD_NODE_TYPES for what falling through would otherwise mint.
|
|
1265
|
+
else if (this.extractor.methodTypes.includes(nodeType)
|
|
1266
|
+
&& (!(TS_JS_CHAIN_LANGUAGES.has(this.language) || this.language === 'arkts')
|
|
1267
|
+
|| !SIGNATURE_METHOD_NODE_TYPES.has(nodeType) || this.isInsideClassLikeNode())) {
|
|
1112
1268
|
// TS/JS class fields parse as a methodTypes node; only function-valued
|
|
1113
1269
|
// fields are methods — a plain field (`public fonts: Fonts;`) is a
|
|
1114
|
-
// property (#808).
|
|
1115
|
-
|
|
1270
|
+
// property (#808). C++ lists `field_declaration` so pure-virtual methods
|
|
1271
|
+
// mint nodes (#1727); non-callable ones return 'skip' and fall through to
|
|
1272
|
+
// the children walk. classifyMethodNode is absent for other languages.
|
|
1273
|
+
const methodClass = this.extractor.classifyMethodNode?.(node) ?? 'method';
|
|
1274
|
+
if (methodClass === 'skip') {
|
|
1275
|
+
// Not a method — leave skipChildren false so data-member initializers
|
|
1276
|
+
// still contribute call/instantiation edges under the enclosing class.
|
|
1277
|
+
}
|
|
1278
|
+
else if (methodClass === 'property') {
|
|
1116
1279
|
const propNode = this.extractProperty(node);
|
|
1117
1280
|
// Walk the initializer so its calls/instantiations attribute to the
|
|
1118
1281
|
// property (`history = createHistory()` → history calls
|
|
@@ -1145,6 +1308,11 @@ class TreeSitterExtractor {
|
|
|
1145
1308
|
this.extractStruct(node);
|
|
1146
1309
|
skipChildren = true; // extractStruct visits body children
|
|
1147
1310
|
}
|
|
1311
|
+
// Check for union declarations
|
|
1312
|
+
else if (this.extractor.unionTypes?.includes(nodeType)) {
|
|
1313
|
+
this.extractUnion(node);
|
|
1314
|
+
skipChildren = true; // extractUnion visits body children
|
|
1315
|
+
}
|
|
1148
1316
|
// Check for enum declarations
|
|
1149
1317
|
else if (this.extractor.enumTypes.includes(nodeType)) {
|
|
1150
1318
|
this.extractEnum(node);
|
|
@@ -1350,20 +1518,16 @@ class TreeSitterExtractor {
|
|
|
1350
1518
|
else if (nodeType === 'impl_item') {
|
|
1351
1519
|
this.extractRustImplItem(node);
|
|
1352
1520
|
}
|
|
1353
|
-
//
|
|
1354
|
-
//
|
|
1355
|
-
//
|
|
1356
|
-
//
|
|
1357
|
-
//
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
this.extractTypeAnnotations(node, parentId);
|
|
1364
|
-
}
|
|
1365
|
-
// don't skipChildren — nested signatures still need traversal
|
|
1366
|
-
}
|
|
1521
|
+
// NOTE: `property_signature` / `method_signature` used to be handled here,
|
|
1522
|
+
// hanging their type annotations off the ENCLOSING INTERFACE — the only
|
|
1523
|
+
// anchor available while the members themselves went unextracted. Since
|
|
1524
|
+
// #1638 they are in the TS extractor's `methodTypes` / `propertyTypes`, so
|
|
1525
|
+
// the branches above claim them first (under the same `isInsideClassLikeNode`
|
|
1526
|
+
// guard this branch had, so nothing it used to reach is now missed) and this
|
|
1527
|
+
// one was dead. The `references` edges survive — `extractMethod` and
|
|
1528
|
+
// `extractProperty` each call `extractTypeAnnotations` — but now hang off
|
|
1529
|
+
// the member, which is the more precise anchor: `Api::fetch → PageId` says
|
|
1530
|
+
// which member wants the type, where `Api → PageId` only said the file did.
|
|
1367
1531
|
// Visit children (unless the extract method already visited them)
|
|
1368
1532
|
if (!skipChildren) {
|
|
1369
1533
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
@@ -1383,7 +1547,7 @@ class TreeSitterExtractor {
|
|
|
1383
1547
|
if (!name) {
|
|
1384
1548
|
return null;
|
|
1385
1549
|
}
|
|
1386
|
-
const id =
|
|
1550
|
+
const id = this.nodeIds.generate(this.filePath, kind, name, node.startPosition.row + 1, node.startPosition.column);
|
|
1387
1551
|
// Some grammars (e.g. Dart) model a function/method body as a *sibling* of
|
|
1388
1552
|
// the signature node, so the declaration node's own range is just the
|
|
1389
1553
|
// signature line. Extend endLine to the resolved body when it sits beyond
|
|
@@ -1537,7 +1701,7 @@ class TreeSitterExtractor {
|
|
|
1537
1701
|
}
|
|
1538
1702
|
/**
|
|
1539
1703
|
* Check if the current node stack indicates we are inside a class-like node
|
|
1540
|
-
* (class, struct, interface, trait). File nodes do not count as class-like.
|
|
1704
|
+
* (class, struct, union, interface, trait). File nodes do not count as class-like.
|
|
1541
1705
|
*/
|
|
1542
1706
|
isInsideClassLikeNode() {
|
|
1543
1707
|
if (this.nodeStack.length === 0)
|
|
@@ -1550,6 +1714,7 @@ class TreeSitterExtractor {
|
|
|
1550
1714
|
return false;
|
|
1551
1715
|
return (parentNode.kind === 'class' ||
|
|
1552
1716
|
parentNode.kind === 'struct' ||
|
|
1717
|
+
parentNode.kind === 'union' ||
|
|
1553
1718
|
parentNode.kind === 'interface' ||
|
|
1554
1719
|
parentNode.kind === 'trait' ||
|
|
1555
1720
|
parentNode.kind === 'enum' ||
|
|
@@ -1584,13 +1749,15 @@ class TreeSitterExtractor {
|
|
|
1584
1749
|
// — SvelteKit actions). Inline-object arrows reached by the general walker
|
|
1585
1750
|
// get no override, so they still fall through to the <anonymous> skip below.
|
|
1586
1751
|
let name = nameOverride ?? extractName(node, this.source, this.extractor);
|
|
1752
|
+
// A CommonJS export assignment names the function it holds — see below.
|
|
1753
|
+
let commonJsExport = false;
|
|
1587
1754
|
// For arrow functions and function expressions assigned to variables,
|
|
1588
1755
|
// resolve the name from the parent variable_declarator.
|
|
1589
1756
|
// e.g. `export const useAuth = () => { ... }` — the arrow_function node
|
|
1590
1757
|
// has no `name` field; the name lives on the variable_declarator.
|
|
1591
1758
|
if (!nameOverride &&
|
|
1592
1759
|
name === '<anonymous>' &&
|
|
1593
|
-
(node.type === 'arrow_function' || node.type === 'function_expression')) {
|
|
1760
|
+
(node.type === 'arrow_function' || node.type === 'function_expression' || node.type === 'generator_function')) {
|
|
1594
1761
|
const parent = node.parent;
|
|
1595
1762
|
if (parent?.type === 'variable_declarator') {
|
|
1596
1763
|
const varName = (0, tree_sitter_helpers_1.getChildByField)(parent, 'name');
|
|
@@ -1598,6 +1765,19 @@ class TreeSitterExtractor {
|
|
|
1598
1765
|
name = (0, tree_sitter_helpers_1.getNodeText)(varName, this.source);
|
|
1599
1766
|
}
|
|
1600
1767
|
}
|
|
1768
|
+
else if (parent?.type === 'assignment_expression') {
|
|
1769
|
+
// `exports.getItems = async (req, res) => {…}` / `module.exports.x =
|
|
1770
|
+
// function () {…}` — the CommonJS controller style. The function is
|
|
1771
|
+
// anonymous only syntactically: the export property is the name every
|
|
1772
|
+
// `router.get('/items', getItems)` resolves. Without a node the handler
|
|
1773
|
+
// is invisible to callers/impact and its calls attribute to the file
|
|
1774
|
+
// (#1675). Same treatment `const X = () => {}` already gets.
|
|
1775
|
+
const exportName = this.commonJsExportName(parent, node);
|
|
1776
|
+
if (exportName) {
|
|
1777
|
+
name = exportName;
|
|
1778
|
+
commonJsExport = true;
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1601
1781
|
}
|
|
1602
1782
|
if (name === '<anonymous>') {
|
|
1603
1783
|
// Don't emit a node for the anonymous wrapper itself, but still visit its
|
|
@@ -1622,10 +1802,10 @@ class TreeSitterExtractor {
|
|
|
1622
1802
|
}
|
|
1623
1803
|
return;
|
|
1624
1804
|
}
|
|
1625
|
-
const docstring =
|
|
1805
|
+
const docstring = this.docstringFor(node);
|
|
1626
1806
|
const signature = this.extractor.getSignature?.(node, this.source);
|
|
1627
1807
|
const visibility = this.extractor.getVisibility?.(node);
|
|
1628
|
-
const isExported = this.extractor.isExported?.(node, this.source);
|
|
1808
|
+
const isExported = commonJsExport || this.extractor.isExported?.(node, this.source);
|
|
1629
1809
|
const isAsync = this.extractor.isAsync?.(node);
|
|
1630
1810
|
const isStatic = this.extractor.isStatic?.(node);
|
|
1631
1811
|
const returnType = this.extractor.getReturnType?.(node, this.source);
|
|
@@ -1735,7 +1915,7 @@ class TreeSitterExtractor {
|
|
|
1735
1915
|
if (this.extractor.skipBodilessClass && !resolvedBody)
|
|
1736
1916
|
return;
|
|
1737
1917
|
const name = extractName(node, this.source, this.extractor);
|
|
1738
|
-
const docstring =
|
|
1918
|
+
const docstring = this.docstringFor(node);
|
|
1739
1919
|
const visibility = this.extractor.getVisibility?.(node);
|
|
1740
1920
|
const isExported = this.extractor.isExported?.(node, this.source);
|
|
1741
1921
|
const classNode = this.createNode(kind, name, node, {
|
|
@@ -1807,11 +1987,14 @@ class TreeSitterExtractor {
|
|
|
1807
1987
|
}
|
|
1808
1988
|
return;
|
|
1809
1989
|
}
|
|
1810
|
-
const docstring =
|
|
1990
|
+
const docstring = this.docstringFor(node);
|
|
1811
1991
|
const signature = this.extractor.getSignature?.(node, this.source);
|
|
1812
1992
|
const visibility = this.extractor.getVisibility?.(node);
|
|
1813
1993
|
const isAsync = this.extractor.isAsync?.(node);
|
|
1814
1994
|
const isStatic = this.extractor.isStatic?.(node);
|
|
1995
|
+
// Only persist abstract when true — a false return must not mint `isAbstract: false`
|
|
1996
|
+
// on every ordinary method (breaks kernel↔wasm parity JSON equality).
|
|
1997
|
+
const isAbstract = this.extractor.isAbstract?.(node) ? true : undefined;
|
|
1815
1998
|
const returnType = this.extractor.getReturnType?.(node, this.source);
|
|
1816
1999
|
const extraProps = {
|
|
1817
2000
|
docstring,
|
|
@@ -1819,6 +2002,7 @@ class TreeSitterExtractor {
|
|
|
1819
2002
|
visibility,
|
|
1820
2003
|
isAsync,
|
|
1821
2004
|
isStatic,
|
|
2005
|
+
isAbstract,
|
|
1822
2006
|
returnType,
|
|
1823
2007
|
};
|
|
1824
2008
|
if (receiverType) {
|
|
@@ -1832,7 +2016,7 @@ class TreeSitterExtractor {
|
|
|
1832
2016
|
if (receiverType && !this.isInsideClassLikeNode()) {
|
|
1833
2017
|
const ownerNode = this.nodes.find((n) => n.name === receiverType &&
|
|
1834
2018
|
n.filePath === this.filePath &&
|
|
1835
|
-
(n.kind === 'struct' || n.kind === 'class' || n.kind === 'enum' || n.kind === 'trait'));
|
|
2019
|
+
(n.kind === 'struct' || n.kind === 'union' || n.kind === 'class' || n.kind === 'enum' || n.kind === 'trait'));
|
|
1836
2020
|
if (ownerNode) {
|
|
1837
2021
|
this.edges.push({
|
|
1838
2022
|
source: ownerNode.id,
|
|
@@ -1861,7 +2045,7 @@ class TreeSitterExtractor {
|
|
|
1861
2045
|
if (!this.extractor)
|
|
1862
2046
|
return;
|
|
1863
2047
|
const name = extractName(node, this.source, this.extractor);
|
|
1864
|
-
const docstring =
|
|
2048
|
+
const docstring = this.docstringFor(node);
|
|
1865
2049
|
const isExported = this.extractor.isExported?.(node, this.source);
|
|
1866
2050
|
const kind = this.extractor.interfaceKind ?? 'interface';
|
|
1867
2051
|
const interfaceNode = this.createNode(kind, name, node, {
|
|
@@ -1890,38 +2074,53 @@ class TreeSitterExtractor {
|
|
|
1890
2074
|
* Extract a struct
|
|
1891
2075
|
*/
|
|
1892
2076
|
extractStruct(node) {
|
|
2077
|
+
this.extractAggregate(node, 'struct');
|
|
2078
|
+
}
|
|
2079
|
+
/** Extract a union while sharing the member-walk behavior of aggregate types. */
|
|
2080
|
+
extractUnion(node) {
|
|
2081
|
+
this.extractAggregate(node, 'union');
|
|
2082
|
+
}
|
|
2083
|
+
/** Extract a struct-like declaration without conflating its semantic kind. */
|
|
2084
|
+
extractAggregate(node, kind) {
|
|
1893
2085
|
if (!this.extractor)
|
|
1894
2086
|
return;
|
|
1895
2087
|
// Skip forward declarations and type references (no body = not a definition)
|
|
1896
2088
|
// — EXCEPT C# positional records (`record struct M(decimal Amount);`),
|
|
1897
2089
|
// complete definitions with no body block. (#831)
|
|
2090
|
+
//
|
|
2091
|
+
// `allowBodilessStruct` is the per-language escape hatch for the same
|
|
2092
|
+
// situation: a bodiless struct that IS a complete definition (Rust's unit
|
|
2093
|
+
// struct `struct Unit;`). Opposite polarity from `skipBodilessClass`
|
|
2094
|
+
// (#1093) because the two defaults differ — a bodiless CLASS is kept
|
|
2095
|
+
// unless a language opts into skipping, a bodiless STRUCT is skipped
|
|
2096
|
+
// unless a language opts into keeping.
|
|
1898
2097
|
const body = (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
|
|
1899
|
-
if (!body && node.type !== 'record_declaration')
|
|
2098
|
+
if (!body && node.type !== 'record_declaration' && !this.extractor.allowBodilessStruct)
|
|
1900
2099
|
return;
|
|
1901
2100
|
const name = extractName(node, this.source, this.extractor);
|
|
1902
|
-
const docstring =
|
|
2101
|
+
const docstring = this.docstringFor(node);
|
|
1903
2102
|
const visibility = this.extractor.getVisibility?.(node);
|
|
1904
2103
|
const isExported = this.extractor.isExported?.(node, this.source);
|
|
1905
|
-
const
|
|
2104
|
+
const aggregateNode = this.createNode(kind, name, node, {
|
|
1906
2105
|
docstring,
|
|
1907
2106
|
visibility,
|
|
1908
2107
|
isExported,
|
|
1909
2108
|
});
|
|
1910
|
-
if (!
|
|
2109
|
+
if (!aggregateNode)
|
|
1911
2110
|
return;
|
|
1912
2111
|
// Rust `#[derive]`/attributes precede the struct as siblings — without this
|
|
1913
2112
|
// the widened extent (v11) never covers them and a cut struct silently
|
|
1914
2113
|
// loses its derives.
|
|
1915
|
-
this.extractDecoratorsFor(node,
|
|
2114
|
+
this.extractDecoratorsFor(node, aggregateNode.id);
|
|
1916
2115
|
// Extract inheritance (e.g. Swift: struct HTTPMethod: RawRepresentable)
|
|
1917
|
-
this.extractInheritance(node,
|
|
2116
|
+
this.extractInheritance(node, aggregateNode.id);
|
|
1918
2117
|
// C# primary-constructor parameter dependencies (`struct P(int x)`, and
|
|
1919
2118
|
// `record struct M(decimal Amount)` which the grammar nests here).
|
|
1920
|
-
this.extractCsharpPrimaryCtorParamRefs(node,
|
|
2119
|
+
this.extractCsharpPrimaryCtorParamRefs(node, aggregateNode.id);
|
|
1921
2120
|
// Push to stack for field extraction (bodiless positional records have
|
|
1922
2121
|
// no members to visit)
|
|
1923
2122
|
if (body) {
|
|
1924
|
-
this.nodeStack.push(
|
|
2123
|
+
this.nodeStack.push(aggregateNode.id);
|
|
1925
2124
|
for (let i = 0; i < body.namedChildCount; i++) {
|
|
1926
2125
|
const child = body.namedChild(i);
|
|
1927
2126
|
if (child) {
|
|
@@ -1943,7 +2142,7 @@ class TreeSitterExtractor {
|
|
|
1943
2142
|
if (!body)
|
|
1944
2143
|
return;
|
|
1945
2144
|
const name = extractName(node, this.source, this.extractor);
|
|
1946
|
-
const docstring =
|
|
2145
|
+
const docstring = this.docstringFor(node);
|
|
1947
2146
|
const visibility = this.extractor.getVisibility?.(node);
|
|
1948
2147
|
const isExported = this.extractor.isExported?.(node, this.source);
|
|
1949
2148
|
const enumNode = this.createNode('enum', name, node, {
|
|
@@ -2003,7 +2202,7 @@ class TreeSitterExtractor {
|
|
|
2003
2202
|
extractProperty(node) {
|
|
2004
2203
|
if (!this.extractor)
|
|
2005
2204
|
return null;
|
|
2006
|
-
const docstring =
|
|
2205
|
+
const docstring = this.docstringFor(node);
|
|
2007
2206
|
const visibility = this.extractor.getVisibility?.(node);
|
|
2008
2207
|
const isStatic = this.extractor.isStatic?.(node) ?? false;
|
|
2009
2208
|
const hookName = this.extractor.extractPropertyName?.(node, this.source);
|
|
@@ -2022,7 +2221,17 @@ class TreeSitterExtractor {
|
|
|
2022
2221
|
// and the initializer VALUE, which the generic finder below would
|
|
2023
2222
|
// wrongly pick — so fields use the type field only (#808). Other
|
|
2024
2223
|
// languages (C# property_declaration) keep the generic scan.
|
|
2025
|
-
|
|
2224
|
+
//
|
|
2225
|
+
// A `property_signature` (an interface member, #1638) carries a `type`
|
|
2226
|
+
// field and no value, so it reads the type field too. It cannot take the
|
|
2227
|
+
// generic scan: that scan's exclusion list covers `identifier` but not the
|
|
2228
|
+
// `property_identifier` an interface member is named with, so it stops on
|
|
2229
|
+
// the name and `interface Stats { counts: Record<string, number> }` yields
|
|
2230
|
+
// `signature: "counts counts"` instead of the type. Named explicitly
|
|
2231
|
+
// rather than folded into the field test so no other language's
|
|
2232
|
+
// `property_declaration` moves off the generic scan.
|
|
2233
|
+
const isTsJsField = node.type === 'public_field_definition' || node.type === 'field_definition'
|
|
2234
|
+
|| node.type === 'property_signature';
|
|
2026
2235
|
const typeNode = isTsJsField
|
|
2027
2236
|
? (0, tree_sitter_helpers_1.getChildByField)(node, 'type')
|
|
2028
2237
|
: node.namedChildren.find(c => c.type !== 'modifier' && c.type !== 'modifiers'
|
|
@@ -2056,7 +2265,7 @@ class TreeSitterExtractor {
|
|
|
2056
2265
|
extractField(node) {
|
|
2057
2266
|
if (!this.extractor)
|
|
2058
2267
|
return;
|
|
2059
|
-
const docstring =
|
|
2268
|
+
const docstring = this.docstringFor(node);
|
|
2060
2269
|
const visibility = this.extractor.getVisibility?.(node);
|
|
2061
2270
|
const isStatic = this.extractor.isStatic?.(node) ?? false;
|
|
2062
2271
|
// A class field that is actually a CONSTANT (Java `static final`, C# `const`
|
|
@@ -2136,6 +2345,21 @@ class TreeSitterExtractor {
|
|
|
2136
2345
|
// and the language-aware path in `extractTypeAnnotations` descends
|
|
2137
2346
|
// into that wrapper (#381).
|
|
2138
2347
|
this.extractTypeAnnotations(node, fieldNode.id);
|
|
2348
|
+
// Walk the initializer ATTRIBUTED to the declared field (#693, the
|
|
2349
|
+
// Go fix; same shape as the TS/JS class-field walk above). The
|
|
2350
|
+
// dispatcher only scanned this subtree for function-as-value
|
|
2351
|
+
// candidates, so a lambda / method reference / anonymous class in
|
|
2352
|
+
// `private final Runnable r = () -> target();` contributed NO call
|
|
2353
|
+
// edge at all and `target` looked callerless. Keyed on the `value`
|
|
2354
|
+
// FIELD, which only Java's `variable_declarator` carries — C#,
|
|
2355
|
+
// VB.NET and PHP spell their initializer differently and are
|
|
2356
|
+
// deliberately untouched here.
|
|
2357
|
+
const valueNode = (0, tree_sitter_helpers_1.getChildByField)(decl, 'value');
|
|
2358
|
+
if (valueNode) {
|
|
2359
|
+
this.nodeStack.push(fieldNode.id);
|
|
2360
|
+
this.visitFunctionBody(valueNode, fieldNode.id);
|
|
2361
|
+
this.nodeStack.pop();
|
|
2362
|
+
}
|
|
2139
2363
|
}
|
|
2140
2364
|
}
|
|
2141
2365
|
}
|
|
@@ -2171,6 +2395,13 @@ class TreeSitterExtractor {
|
|
|
2171
2395
|
if (key && value && (value.type === 'arrow_function' || value.type === 'function_expression')) {
|
|
2172
2396
|
this.extractFunction(value, this.objectKeyName(key));
|
|
2173
2397
|
}
|
|
2398
|
+
else if (value?.type === 'call_expression') {
|
|
2399
|
+
// `key: Effect.fn("…")(function* () {…})` — see curriedWrapperBoundName.
|
|
2400
|
+
const fn = (0, tree_sitter_helpers_1.getChildByField)(value, 'arguments')?.namedChild(0);
|
|
2401
|
+
const bound = fn ? this.curriedWrapperBoundName(fn) : null;
|
|
2402
|
+
if (fn && bound)
|
|
2403
|
+
this.extractFunction(fn, bound);
|
|
2404
|
+
}
|
|
2174
2405
|
}
|
|
2175
2406
|
else if (member.type === 'method_definition') {
|
|
2176
2407
|
// Method shorthand: `{ fetchUser() {...} }`. extractMethod deliberately
|
|
@@ -2183,6 +2414,21 @@ class TreeSitterExtractor {
|
|
|
2183
2414
|
}
|
|
2184
2415
|
}
|
|
2185
2416
|
}
|
|
2417
|
+
/**
|
|
2418
|
+
* A top-level binding exported by a LATER statement rather than at its
|
|
2419
|
+
* declaration: `export default NAME`, `export { NAME }`, `export { NAME as
|
|
2420
|
+
* default }`. The declaration's own `isExported` (an `export_statement`
|
|
2421
|
+
* ancestor) cannot see these, so a store written as `const useStore =
|
|
2422
|
+
* create(…)` + `export default useStore` read as unexported and its actions
|
|
2423
|
+
* were never extracted. One anchored regex over the file source; JS-family
|
|
2424
|
+
* callers only.
|
|
2425
|
+
*/
|
|
2426
|
+
isExportedLater(name) {
|
|
2427
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(name))
|
|
2428
|
+
return false;
|
|
2429
|
+
const re = new RegExp(`^[ \\t]*export\\s+(?:default\\s+${name}\\s*;?[ \\t]*$|\\{[^}]*\\b${name}\\b[^}]*\\})`, 'm');
|
|
2430
|
+
return re.test(this.source);
|
|
2431
|
+
}
|
|
2186
2432
|
/** Property-key text with surrounding quotes stripped (`'foo'` → `foo`). */
|
|
2187
2433
|
objectKeyName(key) {
|
|
2188
2434
|
return (0, tree_sitter_helpers_1.getNodeText)(key, this.source).replace(/^['"`]|['"`]$/g, '');
|
|
@@ -2587,7 +2833,7 @@ class TreeSitterExtractor {
|
|
|
2587
2833
|
// Go: var_declaration, short_var_declaration, const_declaration
|
|
2588
2834
|
const isConst = this.extractor.isConst?.(node) ?? false;
|
|
2589
2835
|
const kind = isConst ? 'constant' : 'variable';
|
|
2590
|
-
const docstring =
|
|
2836
|
+
const docstring = this.docstringFor(node);
|
|
2591
2837
|
const isExported = this.extractor.isExported?.(node, this.source) ?? false;
|
|
2592
2838
|
// Extract variable declarators based on language
|
|
2593
2839
|
if (this.language === 'typescript' || this.language === 'javascript' ||
|
|
@@ -2615,7 +2861,7 @@ class TreeSitterExtractor {
|
|
|
2615
2861
|
}
|
|
2616
2862
|
const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
|
|
2617
2863
|
// Arrow functions / function expressions: extract as function instead of variable
|
|
2618
|
-
if (valueNode && (valueNode.type === 'arrow_function' || valueNode.type === 'function_expression')) {
|
|
2864
|
+
if (valueNode && (valueNode.type === 'arrow_function' || valueNode.type === 'function_expression' || valueNode.type === 'generator_function')) {
|
|
2619
2865
|
this.extractFunction(valueNode);
|
|
2620
2866
|
continue;
|
|
2621
2867
|
}
|
|
@@ -2665,7 +2911,10 @@ class TreeSitterExtractor {
|
|
|
2665
2911
|
// never nodes — so `node`/`callers` on `fetchUser` return "not
|
|
2666
2912
|
// found" and the agent Reads the store to reconstruct the flow.
|
|
2667
2913
|
// Scoped to EXPORTED consts to exclude inline-object noise
|
|
2668
|
-
// (`ctx.set({...})`) the object-method skip deliberately avoids
|
|
2914
|
+
// (`ctx.set({...})`) the object-method skip deliberately avoids —
|
|
2915
|
+
// where "exported" includes the two-statement form `const useStore
|
|
2916
|
+
// = create(…)` … `export default useStore` (see isExportedLater),
|
|
2917
|
+
// the shape most React Native stores are written in.
|
|
2669
2918
|
const objectOfFns = valueNode && (valueNode.type === 'object' || valueNode.type === 'object_expression')
|
|
2670
2919
|
? valueNode
|
|
2671
2920
|
: valueNode?.type === 'call_expression'
|
|
@@ -2677,7 +2926,7 @@ class TreeSitterExtractor {
|
|
|
2677
2926
|
// whose functions are body-local consts — it must fall through to a
|
|
2678
2927
|
// normal body walk (extracting those consts), not be skipped here.
|
|
2679
2928
|
const hasInlineFns = !!objectOfFns && this.objectHasInlineFunctions(objectOfFns);
|
|
2680
|
-
const extractObjectMethods = isExported && !!objectOfFns && hasInlineFns;
|
|
2929
|
+
const extractObjectMethods = (isExported || this.isExportedLater(name)) && !!objectOfFns && hasInlineFns;
|
|
2681
2930
|
// RTK Query: `createApi`/`injectEndpoints` define endpoints as
|
|
2682
2931
|
// object-literal properties whose values are `build.query/mutation(...)`
|
|
2683
2932
|
// calls — nested under an `endpoints` arrow, so neither the
|
|
@@ -2704,19 +2953,25 @@ class TreeSitterExtractor {
|
|
|
2704
2953
|
VUE_STORE_COLLECTION_NAMES.has(name) && this.looksLikeVueStoreFile()) {
|
|
2705
2954
|
storeCollections.push(objectOfFns);
|
|
2706
2955
|
}
|
|
2707
|
-
// Visit the initializer body for calls
|
|
2708
|
-
//
|
|
2709
|
-
// / createApi / store-collection
|
|
2710
|
-
//
|
|
2711
|
-
//
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2956
|
+
// Visit the initializer body for calls, ATTRIBUTED to the declared
|
|
2957
|
+
// symbol (#693) — EXCEPT the shapes whose members are extracted
|
|
2958
|
+
// one-by-one below (the store-factory / createApi / store-collection
|
|
2959
|
+
// objects), where walking the whole initializer would re-visit each
|
|
2960
|
+
// member arrow and double-count its calls.
|
|
2961
|
+
//
|
|
2962
|
+
// Two things were wrong here before. The walk ran with only the FILE
|
|
2963
|
+
// on the stack, so `const cfg = load()` recorded the FILE as load's
|
|
2964
|
+
// caller — the exact leak Go's #693 fixed. And an object literal was
|
|
2965
|
+
// skipped outright, so `const obj = { handler: () => target() }`
|
|
2966
|
+
// contributed nothing at all unless the const was exported (only then
|
|
2967
|
+
// does extractObjectLiteralFunctions mint the members).
|
|
2968
|
+
const membersExtractedSeparately = extractObjectMethods || !!rtkEndpoints || !!piniaSetup || storeCollections.length > 0;
|
|
2969
|
+
if (valueNode && !membersExtractedSeparately) {
|
|
2970
|
+
if (varNode)
|
|
2971
|
+
this.nodeStack.push(varNode.id);
|
|
2719
2972
|
this.visitFunctionBody(valueNode, '');
|
|
2973
|
+
if (varNode)
|
|
2974
|
+
this.nodeStack.pop();
|
|
2720
2975
|
}
|
|
2721
2976
|
if (extractObjectMethods && objectOfFns) {
|
|
2722
2977
|
this.extractObjectLiteralFunctions(objectOfFns);
|
|
@@ -2740,17 +2995,32 @@ class TreeSitterExtractor {
|
|
|
2740
2995
|
const right = (0, tree_sitter_helpers_1.getChildByField)(node, 'right') || node.namedChild(1);
|
|
2741
2996
|
// Ruby constant assignments (`MAX = 3`) have a `constant`-typed LHS, not
|
|
2742
2997
|
// `identifier`; without this they were never extracted as symbols at all.
|
|
2998
|
+
let assigned = null;
|
|
2743
2999
|
if (left && (left.type === 'identifier' || left.type === 'constant')) {
|
|
2744
3000
|
const name = (0, tree_sitter_helpers_1.getNodeText)(left, this.source);
|
|
2745
3001
|
// Skip if name starts with lowercase and looks like a function call result
|
|
2746
3002
|
// Python constants are usually UPPER_CASE
|
|
2747
3003
|
const initValue = right ? (0, tree_sitter_helpers_1.getNodeText)(right, this.source).slice(0, 100) : undefined;
|
|
2748
3004
|
const initSignature = initValue ? `= ${initValue}${initValue.length >= 100 ? '...' : ''}` : undefined;
|
|
2749
|
-
this.createNode(kind, name, node, {
|
|
3005
|
+
assigned = this.createNode(kind, name, node, {
|
|
2750
3006
|
docstring,
|
|
2751
3007
|
signature: initSignature,
|
|
2752
3008
|
});
|
|
2753
3009
|
}
|
|
3010
|
+
// Walk the initializer ATTRIBUTED to the assigned name (#693). A
|
|
3011
|
+
// module-level `app = FastAPI()` / `ENGINE = create_engine(url)` /
|
|
3012
|
+
// `handler = lambda: run()` dropped every call on the right-hand side, so
|
|
3013
|
+
// whatever the module builds at import time linked to nothing. A tuple
|
|
3014
|
+
// target (`a, b = f(), g()`) mints no symbol, so its RHS is walked at the
|
|
3015
|
+
// enclosing scope rather than lost. Python only: Ruby shares this branch
|
|
3016
|
+
// and gets its own turn.
|
|
3017
|
+
if (this.language === 'python' && right) {
|
|
3018
|
+
if (assigned)
|
|
3019
|
+
this.nodeStack.push(assigned.id);
|
|
3020
|
+
this.visitFunctionBody(right, '');
|
|
3021
|
+
if (assigned)
|
|
3022
|
+
this.nodeStack.pop();
|
|
3023
|
+
}
|
|
2754
3024
|
}
|
|
2755
3025
|
else if (this.language === 'go') {
|
|
2756
3026
|
// Go: var_declaration, short_var_declaration, const_declaration
|
|
@@ -2816,15 +3086,26 @@ class TreeSitterExtractor {
|
|
|
2816
3086
|
const varList = assign.namedChildren.find((c) => c.type === 'variable_list');
|
|
2817
3087
|
const exprList = assign.namedChildren.find((c) => c.type === 'expression_list');
|
|
2818
3088
|
const values = exprList ? exprList.namedChildren : [];
|
|
2819
|
-
const
|
|
2820
|
-
|
|
2821
|
-
const name = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
|
|
2822
|
-
if (!name)
|
|
2823
|
-
return;
|
|
3089
|
+
const targets = varList ? varList.namedChildren : [];
|
|
3090
|
+
targets.forEach((nameNode, i) => {
|
|
2824
3091
|
const valueNode = values[i];
|
|
3092
|
+
const target = this.luaAssignmentTarget(nameNode);
|
|
3093
|
+
if (!target)
|
|
3094
|
+
return;
|
|
3095
|
+
if (valueNode?.type === 'function_definition') {
|
|
3096
|
+
this.extractLuaFunctionValue(valueNode, target.name, target.receiver, docstring);
|
|
3097
|
+
return;
|
|
3098
|
+
}
|
|
3099
|
+
if (valueNode?.type === 'table_constructor') {
|
|
3100
|
+
this.extractLuaTableFunctions(valueNode, target.fullName);
|
|
3101
|
+
}
|
|
3102
|
+
// A dotted assignment updates a table member; it is not a standalone
|
|
3103
|
+
// variable node. Function-valued members were handled above.
|
|
3104
|
+
if (target.receiver || node.type === 'assignment_statement')
|
|
3105
|
+
return;
|
|
2825
3106
|
const initValue = valueNode ? (0, tree_sitter_helpers_1.getNodeText)(valueNode, this.source).slice(0, 100) : undefined;
|
|
2826
3107
|
const initSignature = initValue ? `= ${initValue}${initValue.length >= 100 ? '...' : ''}` : undefined;
|
|
2827
|
-
this.createNode(kind, name, nameNode, { docstring, signature: initSignature, isExported });
|
|
3108
|
+
this.createNode(kind, target.name, nameNode, { docstring, signature: initSignature, isExported });
|
|
2828
3109
|
});
|
|
2829
3110
|
}
|
|
2830
3111
|
else if (this.language === 'c') {
|
|
@@ -2889,6 +3170,8 @@ class TreeSitterExtractor {
|
|
|
2889
3170
|
else {
|
|
2890
3171
|
// Generic fallback for other languages
|
|
2891
3172
|
// Try to find identifier children
|
|
3173
|
+
const nameField = (0, tree_sitter_helpers_1.getChildByField)(node, 'name');
|
|
3174
|
+
let declared = null;
|
|
2892
3175
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
2893
3176
|
const child = node.namedChild(i);
|
|
2894
3177
|
if (child?.type === 'identifier' || child?.type === 'variable_declarator') {
|
|
@@ -2896,13 +3179,103 @@ class TreeSitterExtractor {
|
|
|
2896
3179
|
? (0, tree_sitter_helpers_1.getNodeText)(child, this.source)
|
|
2897
3180
|
: extractName(child, this.source, this.extractor);
|
|
2898
3181
|
if (name && name !== '<anonymous>') {
|
|
2899
|
-
this.createNode(kind, name, child, {
|
|
3182
|
+
const created = this.createNode(kind, name, child, {
|
|
2900
3183
|
docstring,
|
|
2901
3184
|
isExported,
|
|
2902
3185
|
});
|
|
3186
|
+
if (created && nameField && child.startIndex === nameField.startIndex) {
|
|
3187
|
+
declared = created;
|
|
3188
|
+
}
|
|
2903
3189
|
}
|
|
2904
3190
|
}
|
|
2905
3191
|
}
|
|
3192
|
+
// Walk the initializer ATTRIBUTED to the declared symbol (#693). Rust
|
|
3193
|
+
// only for now: `const N: usize = compute()` and
|
|
3194
|
+
// `static REGISTRY: Lazy<T> = Lazy::new(|| build())` dropped every call
|
|
3195
|
+
// inside the initializer, so a handler table or a lazily-built singleton
|
|
3196
|
+
// linked to nothing. The other languages sharing this fallback spell
|
|
3197
|
+
// their initializer differently and get their own turn.
|
|
3198
|
+
if (this.language === 'rust') {
|
|
3199
|
+
const valueNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'value');
|
|
3200
|
+
if (valueNode) {
|
|
3201
|
+
if (declared)
|
|
3202
|
+
this.nodeStack.push(declared.id);
|
|
3203
|
+
this.visitFunctionBody(valueNode, '');
|
|
3204
|
+
if (declared)
|
|
3205
|
+
this.nodeStack.pop();
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
}
|
|
3209
|
+
}
|
|
3210
|
+
/** Resolve a Lua assignment target into its callable name and optional table receiver. */
|
|
3211
|
+
luaAssignmentTarget(node) {
|
|
3212
|
+
if (node.type === 'identifier') {
|
|
3213
|
+
const name = (0, tree_sitter_helpers_1.getNodeText)(node, this.source).trim();
|
|
3214
|
+
return name ? { name, fullName: name } : null;
|
|
3215
|
+
}
|
|
3216
|
+
if (node.type !== 'dot_index_expression' &&
|
|
3217
|
+
node.type !== 'method_index_expression' &&
|
|
3218
|
+
node.type !== 'bracket_index_expression')
|
|
3219
|
+
return null;
|
|
3220
|
+
const table = (0, tree_sitter_helpers_1.getChildByField)(node, 'table');
|
|
3221
|
+
const field = (0, tree_sitter_helpers_1.getChildByField)(node, 'field') ?? (0, tree_sitter_helpers_1.getChildByField)(node, 'method');
|
|
3222
|
+
if (!table || !field)
|
|
3223
|
+
return null;
|
|
3224
|
+
const receiver = (0, tree_sitter_helpers_1.getNodeText)(table, this.source).trim();
|
|
3225
|
+
const name = this.luaStaticFieldName(field, node.type === 'bracket_index_expression');
|
|
3226
|
+
if (!receiver || !name)
|
|
3227
|
+
return null;
|
|
3228
|
+
return { name, receiver, fullName: `${receiver}.${name}` };
|
|
3229
|
+
}
|
|
3230
|
+
/** A statically-known Lua field name; dynamic bracket keys are not callable identities. */
|
|
3231
|
+
luaStaticFieldName(node, bracketed) {
|
|
3232
|
+
if (node.type === 'identifier') {
|
|
3233
|
+
return bracketed ? '' : (0, tree_sitter_helpers_1.getNodeText)(node, this.source).trim();
|
|
3234
|
+
}
|
|
3235
|
+
if (node.type === 'string') {
|
|
3236
|
+
const content = node.namedChildren.find((child) => child.type === 'string_content');
|
|
3237
|
+
return content ? (0, tree_sitter_helpers_1.getNodeText)(content, this.source).trim() : '';
|
|
3238
|
+
}
|
|
3239
|
+
return '';
|
|
3240
|
+
}
|
|
3241
|
+
/** Extract an anonymous Lua function using the name supplied by its assignment target. */
|
|
3242
|
+
extractLuaFunctionValue(node, name, receiver, docstring) {
|
|
3243
|
+
if (!this.extractor)
|
|
3244
|
+
return;
|
|
3245
|
+
const signature = this.extractor.getSignature?.(node, this.source);
|
|
3246
|
+
const extra = { docstring, signature };
|
|
3247
|
+
if (receiver)
|
|
3248
|
+
extra.qualifiedName = this.composeReceiverQualifiedName(receiver, name);
|
|
3249
|
+
else
|
|
3250
|
+
extra.isExported = this.extractor.isExported?.(node, this.source);
|
|
3251
|
+
const functionNode = this.createNode(receiver ? 'method' : 'function', name, node, extra);
|
|
3252
|
+
if (!functionNode)
|
|
3253
|
+
return;
|
|
3254
|
+
this.nodeStack.push(functionNode.id);
|
|
3255
|
+
const body = (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
|
|
3256
|
+
if (body)
|
|
3257
|
+
this.visitFunctionBody(body, functionNode.id);
|
|
3258
|
+
this.nodeStack.pop();
|
|
3259
|
+
}
|
|
3260
|
+
/** Extract function-valued keyed fields from a Lua table, including nested tables. */
|
|
3261
|
+
extractLuaTableFunctions(table, receiver) {
|
|
3262
|
+
for (const field of table.namedChildren) {
|
|
3263
|
+
if (field.type !== 'field')
|
|
3264
|
+
continue;
|
|
3265
|
+
const nameNode = (0, tree_sitter_helpers_1.getChildByField)(field, 'name');
|
|
3266
|
+
const valueNode = (0, tree_sitter_helpers_1.getChildByField)(field, 'value');
|
|
3267
|
+
if (!nameNode || !valueNode)
|
|
3268
|
+
continue;
|
|
3269
|
+
const bracketed = (0, tree_sitter_helpers_1.getNodeText)(field, this.source).trimStart().startsWith('[');
|
|
3270
|
+
const name = this.luaStaticFieldName(nameNode, bracketed);
|
|
3271
|
+
if (!name)
|
|
3272
|
+
continue;
|
|
3273
|
+
if (valueNode.type === 'function_definition') {
|
|
3274
|
+
this.extractLuaFunctionValue(valueNode, name, receiver);
|
|
3275
|
+
}
|
|
3276
|
+
else if (valueNode.type === 'table_constructor') {
|
|
3277
|
+
this.extractLuaTableFunctions(valueNode, `${receiver}.${name}`);
|
|
3278
|
+
}
|
|
2906
3279
|
}
|
|
2907
3280
|
}
|
|
2908
3281
|
/**
|
|
@@ -2917,23 +3290,23 @@ class TreeSitterExtractor {
|
|
|
2917
3290
|
const name = extractName(node, this.source, this.extractor);
|
|
2918
3291
|
if (name === '<anonymous>')
|
|
2919
3292
|
return false;
|
|
2920
|
-
const docstring =
|
|
3293
|
+
const docstring = this.docstringFor(node);
|
|
2921
3294
|
const isExported = this.extractor.isExported?.(node, this.source);
|
|
2922
3295
|
// Check if this type alias is actually a struct or interface definition
|
|
2923
3296
|
// (e.g. Go: `type Foo struct { ... }` is a type_spec wrapping struct_type)
|
|
2924
3297
|
const resolvedKind = this.extractor.resolveTypeAliasKind?.(node, this.source);
|
|
2925
|
-
if (resolvedKind === 'struct') {
|
|
2926
|
-
const
|
|
2927
|
-
if (!
|
|
3298
|
+
if (resolvedKind === 'struct' || resolvedKind === 'union') {
|
|
3299
|
+
const aggregateNode = this.createNode(resolvedKind, name, node, { docstring, isExported });
|
|
3300
|
+
if (!aggregateNode)
|
|
2928
3301
|
return true;
|
|
2929
3302
|
// Visit body children for field extraction
|
|
2930
|
-
this.nodeStack.push(
|
|
2931
|
-
// Try Go-style 'type' field first, then find inner
|
|
3303
|
+
this.nodeStack.push(aggregateNode.id);
|
|
3304
|
+
// Try Go-style 'type' field first, then find the matching inner aggregate child.
|
|
2932
3305
|
const typeChild = (0, tree_sitter_helpers_1.getChildByField)(node, 'type')
|
|
2933
|
-
|| this.findChildByTypes(node, this.extractor.structTypes);
|
|
3306
|
+
|| this.findChildByTypes(node, resolvedKind === 'union' ? (this.extractor.unionTypes ?? []) : this.extractor.structTypes);
|
|
2934
3307
|
if (typeChild) {
|
|
2935
3308
|
// Extract struct embedding (e.g. Go: `type DB struct { *Head; Queryable }`)
|
|
2936
|
-
this.extractInheritance(typeChild,
|
|
3309
|
+
this.extractInheritance(typeChild, aggregateNode.id);
|
|
2937
3310
|
const body = (0, tree_sitter_helpers_1.getChildByField)(typeChild, this.extractor.bodyField) || typeChild;
|
|
2938
3311
|
for (let i = 0; i < body.namedChildCount; i++) {
|
|
2939
3312
|
const child = body.namedChild(i);
|
|
@@ -3081,7 +3454,7 @@ class TreeSitterExtractor {
|
|
|
3081
3454
|
const memberKind = child.type === 'method_signature'
|
|
3082
3455
|
? 'method'
|
|
3083
3456
|
: this.isTsFunctionTypedProperty(child) ? 'method' : 'property';
|
|
3084
|
-
const docstring =
|
|
3457
|
+
const docstring = this.docstringFor(child);
|
|
3085
3458
|
const signature = (0, tree_sitter_helpers_1.getNodeText)(child, this.source);
|
|
3086
3459
|
this.createNode(memberKind, memberName, child, {
|
|
3087
3460
|
docstring,
|
|
@@ -3935,15 +4308,18 @@ class TreeSitterExtractor {
|
|
|
3935
4308
|
}
|
|
3936
4309
|
// Erlang: a local call is `call(expr: atom, args)`; a remote call nests it
|
|
3937
4310
|
// under `remote(module: remote_module, fun: call)` — the module qualifier
|
|
3938
|
-
// lives on the PARENT.
|
|
3939
|
-
//
|
|
3940
|
-
//
|
|
3941
|
-
//
|
|
3942
|
-
//
|
|
3943
|
-
//
|
|
3944
|
-
// `
|
|
3945
|
-
//
|
|
3946
|
-
//
|
|
4311
|
+
// lives on the PARENT. Arity is part of a function's identity (#1610), so
|
|
4312
|
+
// refs carry the call-site arity: remote calls are emitted as `mod::fn/2`,
|
|
4313
|
+
// byte-identical to the qualifiedName the module namespace + arity suffix
|
|
4314
|
+
// gives every function (see languages/erlang.ts), so they resolve via
|
|
4315
|
+
// matchByQualifiedName; local calls are emitted `fn/2` and resolved by the
|
|
4316
|
+
// erlang arity step in matchReference (same-file first). A var/macro callee
|
|
4317
|
+
// or module (`F(X)`, `?M(X)`, `Mod:handle(X)`) has no static target —
|
|
4318
|
+
// except `?MODULE:fn(X)`, which the bare-name-with-arity + same-file
|
|
4319
|
+
// preference resolves correctly. `fun name/1` / `fun mod:name/1` values
|
|
4320
|
+
// are function REFERENCES (callback registration) carrying their own
|
|
4321
|
+
// written arity, and record construction/update/index/field-access are
|
|
4322
|
+
// `references` to the record's struct node.
|
|
3947
4323
|
if (this.language === 'erlang') {
|
|
3948
4324
|
const line = node.startPosition.row + 1;
|
|
3949
4325
|
const column = node.startPosition.column;
|
|
@@ -3977,9 +4353,13 @@ class TreeSitterExtractor {
|
|
|
3977
4353
|
if (!macroName || (0, tree_sitter_helpers_1.getNodeText)(macroName, this.source) !== 'MODULE')
|
|
3978
4354
|
return;
|
|
3979
4355
|
}
|
|
4356
|
+
// Arity from the call site's own argument list — part of the callee's
|
|
4357
|
+
// identity, and what disambiguates `f/1` from `f/2` (#1610).
|
|
4358
|
+
const callArgsNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'args');
|
|
4359
|
+
const callArity = callArgsNode ? callArgsNode.namedChildCount : 0;
|
|
3980
4360
|
this.unresolvedReferences.push({
|
|
3981
4361
|
fromNodeId: callerId,
|
|
3982
|
-
referenceName: calleeName
|
|
4362
|
+
referenceName: `${calleeName}/${callArity}`,
|
|
3983
4363
|
referenceKind: 'calls',
|
|
3984
4364
|
line,
|
|
3985
4365
|
column,
|
|
@@ -4000,9 +4380,10 @@ class TreeSitterExtractor {
|
|
|
4000
4380
|
const target = argsNode?.namedChild(0) ?? null;
|
|
4001
4381
|
const targetModule = target ? this.resolveErlangGenServerTarget(target) : null;
|
|
4002
4382
|
if (targetModule) {
|
|
4383
|
+
// OTP fixes the handler arities: handle_call/3, handle_cast/2.
|
|
4003
4384
|
this.unresolvedReferences.push({
|
|
4004
4385
|
fromNodeId: callerId,
|
|
4005
|
-
referenceName: `${targetModule}::${fnBare === 'cast' ? 'handle_cast' : 'handle_call'}`,
|
|
4386
|
+
referenceName: `${targetModule}::${fnBare === 'cast' ? 'handle_cast/2' : 'handle_call/3'}`,
|
|
4006
4387
|
referenceKind: 'calls',
|
|
4007
4388
|
line,
|
|
4008
4389
|
column,
|
|
@@ -4034,9 +4415,17 @@ class TreeSitterExtractor {
|
|
|
4034
4415
|
(0, tree_sitter_helpers_1.getNodeText)((0, tree_sitter_helpers_1.getChildByField)(m, 'name'), this.source) === 'MODULE';
|
|
4035
4416
|
if (m.type !== 'atom' && !isLocalModule)
|
|
4036
4417
|
continue;
|
|
4418
|
+
// Arity of the spawned/applied function = the length of the
|
|
4419
|
+
// static args-list literal directly after the (M, F) pair, when
|
|
4420
|
+
// present (`spawn_link(?MODULE, request_process, [Req, Env])` →
|
|
4421
|
+
// /2). A var/absent list leaves the ref arity-less; the
|
|
4422
|
+
// qualified matcher then resolves it only when the module
|
|
4423
|
+
// defines exactly one arity of that name.
|
|
4424
|
+
const mfaList = argExprs[i + 2];
|
|
4425
|
+
const arityTail = mfaList?.type === 'list' ? `/${mfaList.namedChildCount}` : '';
|
|
4037
4426
|
this.unresolvedReferences.push({
|
|
4038
4427
|
fromNodeId: callerId,
|
|
4039
|
-
referenceName: isLocalModule ? erlAtom(f) : `${erlAtom(m)}::${erlAtom(f)}
|
|
4428
|
+
referenceName: (isLocalModule ? erlAtom(f) : `${erlAtom(m)}::${erlAtom(f)}`) + arityTail,
|
|
4040
4429
|
referenceKind: 'calls',
|
|
4041
4430
|
line: f.startPosition.row + 1,
|
|
4042
4431
|
column: f.startPosition.column,
|
|
@@ -4059,6 +4448,12 @@ class TreeSitterExtractor {
|
|
|
4059
4448
|
return;
|
|
4060
4449
|
refName = `${erlAtom(moduleAtom)}::${refName}`;
|
|
4061
4450
|
}
|
|
4451
|
+
// `fun f/1` writes its arity — carry it so the ref lands on the
|
|
4452
|
+
// matching arity's node (#1610).
|
|
4453
|
+
const funArityNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'arity');
|
|
4454
|
+
const funArityValue = funArityNode ? (0, tree_sitter_helpers_1.getChildByField)(funArityNode, 'value') : null;
|
|
4455
|
+
if (funArityValue)
|
|
4456
|
+
refName = `${refName}/${(0, tree_sitter_helpers_1.getNodeText)(funArityValue, this.source)}`;
|
|
4062
4457
|
this.unresolvedReferences.push({
|
|
4063
4458
|
fromNodeId: callerId,
|
|
4064
4459
|
referenceName: refName,
|
|
@@ -4603,10 +4998,17 @@ class TreeSitterExtractor {
|
|
|
4603
4998
|
// This helps the resolver distinguish method calls from bare function calls
|
|
4604
4999
|
// (e.g., Python's console.print() vs builtin print())
|
|
4605
5000
|
// Skip self/this/cls as they don't aid resolution
|
|
4606
|
-
const
|
|
5001
|
+
const rawReceiver = (0, tree_sitter_helpers_1.getChildByField)(func, 'object') ||
|
|
4607
5002
|
(0, tree_sitter_helpers_1.getChildByField)(func, 'operand') ||
|
|
4608
5003
|
(0, tree_sitter_helpers_1.getChildByField)(func, 'argument') ||
|
|
4609
5004
|
func.namedChild(0);
|
|
5005
|
+
// TS/JS: look through wrappers that keep the receiver the same
|
|
5006
|
+
// object (`(x).m()`, `x!.m()`, `(x as T).m()`, `(await f()).m()`),
|
|
5007
|
+
// so the branches below see the identifier / call / chain the
|
|
5008
|
+
// call is really made on.
|
|
5009
|
+
const receiver = rawReceiver && TS_JS_CHAIN_LANGUAGES.has(this.language)
|
|
5010
|
+
? peelTsJsReceiver(rawReceiver)
|
|
5011
|
+
: rawReceiver;
|
|
4610
5012
|
// A LITERAL receiver — `", ".join(...)`, `"x".toUpperCase()`,
|
|
4611
5013
|
// `5.times`, `[].concat(...)` — calls a builtin of the literal's
|
|
4612
5014
|
// type, never a project symbol. The bare-name fallback below let
|
|
@@ -4627,6 +5029,37 @@ class TreeSitterExtractor {
|
|
|
4627
5029
|
calleeName = methodName;
|
|
4628
5030
|
}
|
|
4629
5031
|
}
|
|
5032
|
+
else if (this.language === 'rust' && receiver && receiver.type === 'self') {
|
|
5033
|
+
// Rust `self.method()`. Keep the `self.` prefix, exactly as the
|
|
5034
|
+
// field shape below does (#1585): the resolver reads the owner
|
|
5035
|
+
// off the CALLING method's qualified name and resolves the
|
|
5036
|
+
// method on that type. Collapsing to the bare method name handed
|
|
5037
|
+
// the resolver a name with no owner, which it then matched among
|
|
5038
|
+
// all same-named methods by file proximity — so `self.reset()`
|
|
5039
|
+
// inside `impl Target` landed on a `Decoy::reset` that happened
|
|
5040
|
+
// to sit nearer, with nothing in the edge to show it was a guess
|
|
5041
|
+
// (#1861). Mirrored in the kernel's extract_call (rustlang.rs).
|
|
5042
|
+
calleeName = `self.${methodName}`;
|
|
5043
|
+
}
|
|
5044
|
+
else if (this.language === 'rust' &&
|
|
5045
|
+
receiver &&
|
|
5046
|
+
receiver.type === 'field_expression' &&
|
|
5047
|
+
(0, tree_sitter_helpers_1.getChildByField)(receiver, 'value')?.type === 'self' &&
|
|
5048
|
+
(0, tree_sitter_helpers_1.getChildByField)(receiver, 'field')?.type === 'field_identifier') {
|
|
5049
|
+
// Rust `self.<field>.<method>()` — a call through a field of the
|
|
5050
|
+
// enclosing type (#1585). Keep the `self.` prefix: the resolver
|
|
5051
|
+
// recognizes the shape, reads the field's declared type off the
|
|
5052
|
+
// owner struct's declaration, and resolves the method on THAT
|
|
5053
|
+
// type — or leaves the ref unresolved when the type is external
|
|
5054
|
+
// or unknown. Previously this collapsed to the bare method name,
|
|
5055
|
+
// which exact-matched whichever same-named method was nearest —
|
|
5056
|
+
// often the calling method itself, a self-edge not in the source.
|
|
5057
|
+
// Deeper chains (`self.a.b.m()`), `self.f().m()` and parenthesized
|
|
5058
|
+
// receivers keep the bare name. Mirrored in the kernel's
|
|
5059
|
+
// extract_call (rustlang.rs).
|
|
5060
|
+
const fieldName = (0, tree_sitter_helpers_1.getNodeText)((0, tree_sitter_helpers_1.getChildByField)(receiver, 'field'), this.source);
|
|
5061
|
+
calleeName = `self.${fieldName}.${methodName}`;
|
|
5062
|
+
}
|
|
4630
5063
|
else if ((this.language === 'cpp' ||
|
|
4631
5064
|
this.language === 'c' ||
|
|
4632
5065
|
this.language === 'kotlin' ||
|
|
@@ -4702,6 +5135,56 @@ class TreeSitterExtractor {
|
|
|
4702
5135
|
// name, which either failed to resolve or resolved ambiguously.
|
|
4703
5136
|
calleeName = `${(0, tree_sitter_helpers_1.getNodeText)(receiver, this.source)}.${methodName}`;
|
|
4704
5137
|
}
|
|
5138
|
+
else if ((this.language === 'typescript' ||
|
|
5139
|
+
this.language === 'javascript' ||
|
|
5140
|
+
this.language === 'tsx' ||
|
|
5141
|
+
this.language === 'jsx') &&
|
|
5142
|
+
receiver &&
|
|
5143
|
+
receiver.type === 'member_expression' &&
|
|
5144
|
+
(0, tree_sitter_helpers_1.getChildByField)(receiver, 'object')?.type === 'this' &&
|
|
5145
|
+
THIS_FIELD_PROPERTY_TYPES.has((0, tree_sitter_helpers_1.getChildByField)(receiver, 'property')?.type ?? '')) {
|
|
5146
|
+
// TS/JS call through a field of the enclosing class —
|
|
5147
|
+
// `this.mailer.send()` (#1496). Keep the `this.<field>` prefix:
|
|
5148
|
+
// the resolver reads the field's declared type off the class's
|
|
5149
|
+
// own declaration (`private mailer: Mailer`, `mailer = new
|
|
5150
|
+
// Mailer()`) and resolves the method on THAT type — or leaves the
|
|
5151
|
+
// ref unresolved when the type is external or unknown. Previously
|
|
5152
|
+
// this collapsed to the bare method name, which exact-matched
|
|
5153
|
+
// whichever same-named method was nearest — the calling method
|
|
5154
|
+
// itself when the two share a name, a self-edge not in the
|
|
5155
|
+
// source. Same discipline as Rust's `self.<field>` (#1585).
|
|
5156
|
+
// Mirrored in the kernel's extract_call (tsjs/extractors.rs).
|
|
5157
|
+
// An ES private field (`this.#items.add()`) is the same shape;
|
|
5158
|
+
// its name keeps the `#` (#1987).
|
|
5159
|
+
const fieldName = (0, tree_sitter_helpers_1.getNodeText)((0, tree_sitter_helpers_1.getChildByField)(receiver, 'property'), this.source);
|
|
5160
|
+
calleeName = `this.${fieldName}.${methodName}`;
|
|
5161
|
+
}
|
|
5162
|
+
else if ((this.language === 'typescript' ||
|
|
5163
|
+
this.language === 'javascript' ||
|
|
5164
|
+
this.language === 'tsx' ||
|
|
5165
|
+
this.language === 'jsx' ||
|
|
5166
|
+
this.language === 'python') &&
|
|
5167
|
+
receiver &&
|
|
5168
|
+
(receiver.type === 'call_expression' || receiver.type === 'call')) {
|
|
5169
|
+
// Receiver that is itself a call — `d.setdefault(k, []).append(v)`,
|
|
5170
|
+
// `make().run()`, `res.json().data` (#1683). The bare method name
|
|
5171
|
+
// this used to emit exact-matched any top-level project symbol of
|
|
5172
|
+
// that name and fabricated a call edge from an unrelated function
|
|
5173
|
+
// (`append`, `get`, `run`…). Keep the inner callee, encoded as
|
|
5174
|
+
// `<inner>().<method>` like the Java/Kotlin/C++ chains: the
|
|
5175
|
+
// marker never appears in an ordinary ref, so nothing name-matches
|
|
5176
|
+
// it, and a chain resolver can later infer the receiver's type
|
|
5177
|
+
// from what the inner call returns. An inner callee that is not a
|
|
5178
|
+
// plain name or member chain (`(await x)()`, `arr[0]()`) has no
|
|
5179
|
+
// static receiver at all — emit nothing: a silent miss, never a
|
|
5180
|
+
// wrong edge. The inner call is visited on its own either way.
|
|
5181
|
+
// Mirrored in the kernel (tsjs/extractors.rs, python.rs).
|
|
5182
|
+
const innerFn = (0, tree_sitter_helpers_1.getChildByField)(receiver, 'function');
|
|
5183
|
+
const innerCallee = innerFn ? (0, tree_sitter_helpers_1.getNodeText)(innerFn, this.source).replace(/\s+/g, '') : '';
|
|
5184
|
+
if (!/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*$/.test(innerCallee))
|
|
5185
|
+
return;
|
|
5186
|
+
calleeName = `${innerCallee}().${methodName}`;
|
|
5187
|
+
}
|
|
4705
5188
|
else if (this.language === 'go' &&
|
|
4706
5189
|
receiver &&
|
|
4707
5190
|
receiver.type === 'selector_expression' &&
|
|
@@ -4716,6 +5199,30 @@ class TreeSitterExtractor {
|
|
|
4716
5199
|
// inference (see matchGoFieldChainCall) or stay unresolved.
|
|
4717
5200
|
calleeName = `${(0, tree_sitter_helpers_1.getNodeText)(receiver, this.source).replace(/\s+/g, '')}.${methodName}`;
|
|
4718
5201
|
}
|
|
5202
|
+
else if (TS_JS_CHAIN_LANGUAGES.has(this.language) &&
|
|
5203
|
+
receiver &&
|
|
5204
|
+
TS_JS_CHAIN_RECEIVER_TYPES.has(receiver.type) &&
|
|
5205
|
+
isUnresolvedTsJsChain(receiver, this.source)) {
|
|
5206
|
+
// Keep the source call for effect reporting, but never collapse
|
|
5207
|
+
// it to a guessed method. The resolver only lets frameworks
|
|
5208
|
+
// with receiver evidence handle these qualified chains.
|
|
5209
|
+
const chain = (0, tree_sitter_helpers_1.getNodeText)(func, this.source).replace(/\s+/g, '').replace(/\?\./g, '.');
|
|
5210
|
+
if (!/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*){2,}$/.test(chain))
|
|
5211
|
+
return;
|
|
5212
|
+
calleeName = chain;
|
|
5213
|
+
}
|
|
5214
|
+
else if (TS_JS_CHAIN_LANGUAGES.has(this.language) &&
|
|
5215
|
+
receiver &&
|
|
5216
|
+
!keepsBareTsJsReceiver(receiver, this.source)) {
|
|
5217
|
+
// Any other TS/JS receiver is an expression with no static
|
|
5218
|
+
// type here — `(a ?? b).map()`, `f().list.map()`,
|
|
5219
|
+
// `arr[0].run()`, `(() => {}).call()`. The bare method name this
|
|
5220
|
+
// used to emit exact-matched whichever project method shared the
|
|
5221
|
+
// name (`(await list()).map()` onto an adapter class's `map`).
|
|
5222
|
+
// Emit nothing: a silent miss, never a wrong edge. Mirrored in
|
|
5223
|
+
// the kernel's extract_call (tsjs/extractors.rs).
|
|
5224
|
+
return;
|
|
5225
|
+
}
|
|
4719
5226
|
else {
|
|
4720
5227
|
calleeName = methodName;
|
|
4721
5228
|
}
|
|
@@ -4919,43 +5426,103 @@ class TreeSitterExtractor {
|
|
|
4919
5426
|
}
|
|
4920
5427
|
}
|
|
4921
5428
|
/**
|
|
4922
|
-
*
|
|
4923
|
-
* that invokes a constructor — `Calculator calc(0)` (direct-init) or
|
|
4924
|
-
* `Widget w{1, 2}` (brace-init) — as opposed to a plain variable or a
|
|
4925
|
-
* function declaration? Used to emit an `instantiates` edge for the
|
|
5429
|
+
* C++ stack construction — `Calculator calc(0)` / `Widget w{1, 2}` — is
|
|
4926
5430
|
* call-less construction syntax (#1035); heap `new T(...)` is handled
|
|
4927
5431
|
* separately by INSTANTIATION_KINDS.
|
|
4928
5432
|
*
|
|
4929
|
-
*
|
|
4930
|
-
*
|
|
4931
|
-
*
|
|
4932
|
-
*
|
|
4933
|
-
*
|
|
4934
|
-
*
|
|
4935
|
-
*
|
|
4936
|
-
*
|
|
4937
|
-
*
|
|
4938
|
-
*
|
|
4939
|
-
*
|
|
5433
|
+
* The `type` field must be a class-like NAMED type (`type_identifier`,
|
|
5434
|
+
* `template_type`, or `qualified_identifier`). Primitives (`int x(0)`),
|
|
5435
|
+
* `auto` (`placeholder_type_specifier` — that form always carries a real
|
|
5436
|
+
* `call_expression`, already handled), and sized specifiers are excluded —
|
|
5437
|
+
* they construct no class. `extern T x;` declares, it constructs nothing.
|
|
5438
|
+
*
|
|
5439
|
+
* Per declarator:
|
|
5440
|
+
* - a bare `identifier` is default construction (`T item;`) — arity 0;
|
|
5441
|
+
* - an `init_declarator` whose `value` is an `argument_list` (`(args)`) or
|
|
5442
|
+
* `initializer_list` (`{args}`) carries constructor arguments — arity is
|
|
5443
|
+
* the argument count. An array declarator's braces hold ELEMENTS, not
|
|
5444
|
+
* constructor arguments, so each braced element has its own arity;
|
|
5445
|
+
* - pointer / reference / function declarators construct nothing:
|
|
5446
|
+
* `T* p{}` is a null pointer, `T& r{x}` binds a reference, and the
|
|
5447
|
+
* most-vexing-parse `T c();` is a function declaration.
|
|
5448
|
+
*
|
|
5449
|
+
* `instantiates` (the type) is retained for initialized declarations,
|
|
5450
|
+
* preserving the #1035 dependency edges. `calls` (`T::T/arity`, resolved to
|
|
5451
|
+
* the constructor by src/resolution/cpp-constructor.ts, #1839) is emitted
|
|
5452
|
+
* for every declarator with an arity, default construction included.
|
|
5453
|
+
* Mirrored in the kernel (ccpp/mod.rs cpp_stack_constructions).
|
|
4940
5454
|
*/
|
|
4941
|
-
|
|
5455
|
+
cppStackConstructions(node) {
|
|
5456
|
+
const none = { instantiates: false, arities: [] };
|
|
4942
5457
|
const typeNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'type');
|
|
4943
5458
|
if (!typeNode ||
|
|
4944
5459
|
(typeNode.type !== 'type_identifier' &&
|
|
4945
5460
|
typeNode.type !== 'template_type' &&
|
|
4946
5461
|
typeNode.type !== 'qualified_identifier')) {
|
|
4947
|
-
return
|
|
5462
|
+
return none;
|
|
4948
5463
|
}
|
|
5464
|
+
let instantiates = false;
|
|
5465
|
+
const arities = [];
|
|
4949
5466
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
4950
5467
|
const child = node.namedChild(i);
|
|
4951
|
-
if (child
|
|
5468
|
+
if (!child)
|
|
5469
|
+
continue;
|
|
5470
|
+
if (child.type === 'storage_class_specifier' && (0, tree_sitter_helpers_1.getNodeText)(child, this.source) === 'extern')
|
|
5471
|
+
return none;
|
|
5472
|
+
if (child.type === 'identifier' || child.type === 'array_declarator') {
|
|
5473
|
+
if (child.type === 'array_declarator' && !this.cppObjectArray(child))
|
|
5474
|
+
continue;
|
|
5475
|
+
arities.push(0);
|
|
5476
|
+
continue;
|
|
5477
|
+
}
|
|
5478
|
+
if (child.type !== 'init_declarator')
|
|
5479
|
+
continue;
|
|
5480
|
+
const declarator = (0, tree_sitter_helpers_1.getChildByField)(child, 'declarator');
|
|
5481
|
+
if (declarator?.type !== 'identifier' && declarator?.type !== 'array_declarator')
|
|
4952
5482
|
continue;
|
|
4953
5483
|
const value = (0, tree_sitter_helpers_1.getChildByField)(child, 'value');
|
|
4954
|
-
if (value
|
|
4955
|
-
|
|
5484
|
+
if (!value || (value.type !== 'argument_list' && value.type !== 'initializer_list'))
|
|
5485
|
+
continue;
|
|
5486
|
+
instantiates = true;
|
|
5487
|
+
if (declarator.type === 'identifier') {
|
|
5488
|
+
arities.push(value.namedChildren.filter((c) => c.type !== 'comment').length);
|
|
5489
|
+
}
|
|
5490
|
+
else if (this.cppObjectArray(declarator)) {
|
|
5491
|
+
const dimensions = [];
|
|
5492
|
+
let array = declarator;
|
|
5493
|
+
while (array?.type === 'array_declarator') {
|
|
5494
|
+
const size = (0, tree_sitter_helpers_1.getChildByField)(array, 'size')?.text ?? '';
|
|
5495
|
+
dimensions.unshift(/^\d+$/.test(size) && Number.isSafeInteger(Number(size)) ? Number(size) : NaN);
|
|
5496
|
+
array = (0, tree_sitter_helpers_1.getChildByField)(array, 'declarator');
|
|
5497
|
+
}
|
|
5498
|
+
const elements = (list, depth) => {
|
|
5499
|
+
const entries = list.namedChildren.filter((c) => c.type !== 'comment');
|
|
5500
|
+
let elided = false;
|
|
5501
|
+
for (const entry of entries) {
|
|
5502
|
+
if (depth + 1 < dimensions.length) {
|
|
5503
|
+
if (entry.type === 'initializer_list')
|
|
5504
|
+
elements(entry, depth + 1);
|
|
5505
|
+
else
|
|
5506
|
+
elided = true; // Unbraced multidimensional layout needs type information.
|
|
5507
|
+
}
|
|
5508
|
+
else {
|
|
5509
|
+
arities.push(entry.type === 'initializer_list'
|
|
5510
|
+
? entry.namedChildren.filter((c) => c.type !== 'comment').length : 1);
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5513
|
+
if (!elided && (entries.length === 0 || dimensions[depth] > entries.length))
|
|
5514
|
+
arities.push(0);
|
|
5515
|
+
};
|
|
5516
|
+
elements(value, 0);
|
|
4956
5517
|
}
|
|
4957
5518
|
}
|
|
4958
|
-
return
|
|
5519
|
+
return { instantiates, arities };
|
|
5520
|
+
}
|
|
5521
|
+
cppObjectArray(node) {
|
|
5522
|
+
let element = (0, tree_sitter_helpers_1.getChildByField)(node, 'declarator');
|
|
5523
|
+
while (element?.type === 'array_declarator')
|
|
5524
|
+
element = (0, tree_sitter_helpers_1.getChildByField)(element, 'declarator');
|
|
5525
|
+
return element?.type === 'identifier';
|
|
4959
5526
|
}
|
|
4960
5527
|
/**
|
|
4961
5528
|
* Static-member / value-read pass. A type/enum/class used only via a member
|
|
@@ -5123,6 +5690,24 @@ class TreeSitterExtractor {
|
|
|
5123
5690
|
if (extentRow === null || row < extentRow)
|
|
5124
5691
|
extentRow = row;
|
|
5125
5692
|
};
|
|
5693
|
+
// Rust outer attributes are siblings, not children of the function.
|
|
5694
|
+
// Preserve Tauri's runtime registration for the dead-code decorator rule.
|
|
5695
|
+
if (this.language === 'rust' && declNode.type === 'function_item') {
|
|
5696
|
+
for (let sibling = declNode.previousNamedSibling; sibling; sibling = sibling.previousNamedSibling) {
|
|
5697
|
+
if (sibling.type === 'line_comment' || sibling.type === 'block_comment')
|
|
5698
|
+
continue;
|
|
5699
|
+
if (sibling.type !== 'attribute_item')
|
|
5700
|
+
break;
|
|
5701
|
+
const attribute = sibling.namedChild(0);
|
|
5702
|
+
const name = attribute?.namedChild(0)?.text.replace(/\s/g, '');
|
|
5703
|
+
if (name === 'tauri::command') {
|
|
5704
|
+
const decorated = this.nodes.find(n => n.id === decoratedId);
|
|
5705
|
+
if (decorated)
|
|
5706
|
+
decorated.decorators = ['tauri::command'];
|
|
5707
|
+
break;
|
|
5708
|
+
}
|
|
5709
|
+
}
|
|
5710
|
+
}
|
|
5126
5711
|
const consider = (n) => {
|
|
5127
5712
|
if (!n)
|
|
5128
5713
|
return;
|
|
@@ -5375,11 +5960,166 @@ class TreeSitterExtractor {
|
|
|
5375
5960
|
}
|
|
5376
5961
|
targets.add(target);
|
|
5377
5962
|
}
|
|
5963
|
+
/**
|
|
5964
|
+
* Whether an anonymous function is the whole value of a `variable_declarator`
|
|
5965
|
+
* with a plain identifier name — `const NAME = () => {…}` / `= function () {…}`.
|
|
5966
|
+
* JS-family only.
|
|
5967
|
+
*/
|
|
5968
|
+
declaratorBoundFunction(node) {
|
|
5969
|
+
if (this.language !== 'typescript' &&
|
|
5970
|
+
this.language !== 'javascript' &&
|
|
5971
|
+
this.language !== 'tsx' &&
|
|
5972
|
+
this.language !== 'jsx') {
|
|
5973
|
+
return false;
|
|
5974
|
+
}
|
|
5975
|
+
if (node.type !== 'arrow_function' && node.type !== 'function_expression')
|
|
5976
|
+
return false;
|
|
5977
|
+
const declarator = node.parent;
|
|
5978
|
+
if (!declarator || declarator.type !== 'variable_declarator')
|
|
5979
|
+
return false;
|
|
5980
|
+
const value = (0, tree_sitter_helpers_1.getChildByField)(declarator, 'value');
|
|
5981
|
+
if (!value || value.startIndex !== node.startIndex || value.endIndex !== node.endIndex)
|
|
5982
|
+
return false;
|
|
5983
|
+
return (0, tree_sitter_helpers_1.getChildByField)(declarator, 'name')?.type === 'identifier';
|
|
5984
|
+
}
|
|
5985
|
+
/**
|
|
5986
|
+
* The property a CommonJS export assignment binds a function to —
|
|
5987
|
+
* `exports.NAME = <node>` or `module.exports.NAME = <node>` — or null for
|
|
5988
|
+
* any other assignment. JS-family only; the node must be the assignment's
|
|
5989
|
+
* whole right-hand side.
|
|
5990
|
+
*/
|
|
5991
|
+
commonJsExportName(assignment, value) {
|
|
5992
|
+
if (this.language !== 'typescript' &&
|
|
5993
|
+
this.language !== 'javascript' &&
|
|
5994
|
+
this.language !== 'tsx' &&
|
|
5995
|
+
this.language !== 'jsx') {
|
|
5996
|
+
return null;
|
|
5997
|
+
}
|
|
5998
|
+
const right = (0, tree_sitter_helpers_1.getChildByField)(assignment, 'right');
|
|
5999
|
+
if (!right || right.startIndex !== value.startIndex || right.endIndex !== value.endIndex)
|
|
6000
|
+
return null;
|
|
6001
|
+
const left = (0, tree_sitter_helpers_1.getChildByField)(assignment, 'left');
|
|
6002
|
+
if (!left || left.type !== 'member_expression')
|
|
6003
|
+
return null;
|
|
6004
|
+
const object = (0, tree_sitter_helpers_1.getChildByField)(left, 'object');
|
|
6005
|
+
const property = (0, tree_sitter_helpers_1.getChildByField)(left, 'property');
|
|
6006
|
+
if (!object || !property || property.type !== 'property_identifier')
|
|
6007
|
+
return null;
|
|
6008
|
+
const objectText = (0, tree_sitter_helpers_1.getNodeText)(object, this.source);
|
|
6009
|
+
if (objectText !== 'exports' && objectText !== 'module.exports')
|
|
6010
|
+
return null;
|
|
6011
|
+
return (0, tree_sitter_helpers_1.getNodeText)(property, this.source);
|
|
6012
|
+
}
|
|
6013
|
+
/**
|
|
6014
|
+
* The declarator name a React handler hook binds an anonymous function to —
|
|
6015
|
+
* `const NAME = useCallback(<node>, [...])` — or null for any other shape.
|
|
6016
|
+
* JS-family only; the node must be the hook call's FIRST argument, and the
|
|
6017
|
+
* call's value must be bound directly by a `variable_declarator`.
|
|
6018
|
+
*/
|
|
6019
|
+
reactHookBoundName(node) {
|
|
6020
|
+
if (this.language !== 'typescript' &&
|
|
6021
|
+
this.language !== 'javascript' &&
|
|
6022
|
+
this.language !== 'tsx' &&
|
|
6023
|
+
this.language !== 'jsx') {
|
|
6024
|
+
return null;
|
|
6025
|
+
}
|
|
6026
|
+
if (node.type !== 'arrow_function' && node.type !== 'function_expression')
|
|
6027
|
+
return null;
|
|
6028
|
+
const args = node.parent;
|
|
6029
|
+
if (!args || args.type !== 'arguments')
|
|
6030
|
+
return null;
|
|
6031
|
+
const first = args.namedChild(0);
|
|
6032
|
+
if (!first || first.startIndex !== node.startIndex || first.endIndex !== node.endIndex)
|
|
6033
|
+
return null;
|
|
6034
|
+
const call = args.parent;
|
|
6035
|
+
if (!call || call.type !== 'call_expression')
|
|
6036
|
+
return null;
|
|
6037
|
+
const callee = (0, tree_sitter_helpers_1.getChildByField)(call, 'function');
|
|
6038
|
+
if (!callee || !REACT_HANDLER_HOOKS.test((0, tree_sitter_helpers_1.getNodeText)(callee, this.source)))
|
|
6039
|
+
return null;
|
|
6040
|
+
const declarator = call.parent;
|
|
6041
|
+
if (!declarator || declarator.type !== 'variable_declarator')
|
|
6042
|
+
return null;
|
|
6043
|
+
const nameNode = (0, tree_sitter_helpers_1.getChildByField)(declarator, 'name');
|
|
6044
|
+
return nameNode?.type === 'identifier' ? (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source) : null;
|
|
6045
|
+
}
|
|
6046
|
+
/**
|
|
6047
|
+
* The declarator name for an anonymous function passed to a CURRIED wrapper
|
|
6048
|
+
* call — `const NAME = factory(...)(function () {…})` — or the property key
|
|
6049
|
+
* when the call is an object member, `{ NAME: factory(...)(fn) }`; else null.
|
|
6050
|
+
*
|
|
6051
|
+
* `reactHookBoundName` above already names a function through the declarator
|
|
6052
|
+
* that binds it; the shape is general, but that method is deliberately
|
|
6053
|
+
* bounded to the three React handler hooks. This is the same shape with a
|
|
6054
|
+
* different, equally decidable bound: the callee is itself a call, i.e. a
|
|
6055
|
+
* factory that returns the wrapper (#1747).
|
|
6056
|
+
*
|
|
6057
|
+
* Requiring the callee to be a call is what keeps this narrow. It admits
|
|
6058
|
+
* `Effect.fn("Session.run")(function* () {…})`, `connect(mapState)(fn)` and
|
|
6059
|
+
* a project's own `wrap("name")(fn)`, and it does not admit the one-call
|
|
6060
|
+
* forms where the argument is a computation rather than a body worth a node
|
|
6061
|
+
* of its own — `useMemo(() => 1 + 1, [])`, `arr.map(() => …)` — which stay
|
|
6062
|
+
* anonymous exactly as before.
|
|
6063
|
+
*
|
|
6064
|
+
* Generators are included here and not in `reactHookBoundName`: a React
|
|
6065
|
+
* handler is never a generator, while `function*` is the common form in the
|
|
6066
|
+
* ecosystem this shape comes from.
|
|
6067
|
+
*/
|
|
6068
|
+
curriedWrapperBoundName(node) {
|
|
6069
|
+
if (this.language !== 'typescript' &&
|
|
6070
|
+
this.language !== 'javascript' &&
|
|
6071
|
+
this.language !== 'tsx' &&
|
|
6072
|
+
this.language !== 'jsx') {
|
|
6073
|
+
return null;
|
|
6074
|
+
}
|
|
6075
|
+
if (node.type !== 'arrow_function' &&
|
|
6076
|
+
node.type !== 'function_expression' &&
|
|
6077
|
+
node.type !== 'generator_function') {
|
|
6078
|
+
return null;
|
|
6079
|
+
}
|
|
6080
|
+
const args = node.parent;
|
|
6081
|
+
if (!args || args.type !== 'arguments')
|
|
6082
|
+
return null;
|
|
6083
|
+
const first = args.namedChild(0);
|
|
6084
|
+
if (!first || first.startIndex !== node.startIndex || first.endIndex !== node.endIndex)
|
|
6085
|
+
return null;
|
|
6086
|
+
const call = args.parent;
|
|
6087
|
+
if (!call || call.type !== 'call_expression')
|
|
6088
|
+
return null;
|
|
6089
|
+
// The bound that replaces the hook allowlist: the thing being called is
|
|
6090
|
+
// itself a call, so this is the second application of a curried wrapper.
|
|
6091
|
+
const callee = (0, tree_sitter_helpers_1.getChildByField)(call, 'function');
|
|
6092
|
+
if (!callee || callee.type !== 'call_expression')
|
|
6093
|
+
return null;
|
|
6094
|
+
const binder = call.parent;
|
|
6095
|
+
if (!binder)
|
|
6096
|
+
return null;
|
|
6097
|
+
// `{ getMode: Effect.fn("…")(function* () {…}) }` — a service is often an
|
|
6098
|
+
// object a factory returns, so the wrapper's result lands in a `pair`. The
|
|
6099
|
+
// property key names it, as extractObjectLiteralFunctions names
|
|
6100
|
+
// `key: () => {}`.
|
|
6101
|
+
if (binder.type === 'pair') {
|
|
6102
|
+
const key = (0, tree_sitter_helpers_1.getChildByField)(binder, 'key');
|
|
6103
|
+
const value = (0, tree_sitter_helpers_1.getChildByField)(binder, 'value');
|
|
6104
|
+
if (!key || !value || value.startIndex !== call.startIndex || value.endIndex !== call.endIndex)
|
|
6105
|
+
return null;
|
|
6106
|
+
return this.objectKeyName(key);
|
|
6107
|
+
}
|
|
6108
|
+
if (binder.type !== 'variable_declarator')
|
|
6109
|
+
return null;
|
|
6110
|
+
const nameNode = (0, tree_sitter_helpers_1.getChildByField)(binder, 'name');
|
|
6111
|
+
return nameNode?.type === 'identifier' ? (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source) : null;
|
|
6112
|
+
}
|
|
5378
6113
|
visitFunctionBody(body, _functionId) {
|
|
5379
6114
|
if (!this.extractor)
|
|
5380
6115
|
return;
|
|
5381
6116
|
const visitForCallsAndStructure = (node) => {
|
|
5382
6117
|
const nodeType = node.type;
|
|
6118
|
+
// A function-like macro defined inside a body is still a macro (#1838).
|
|
6119
|
+
if ((this.language === 'c' || this.language === 'cpp') && nodeType === 'preproc_function_def') {
|
|
6120
|
+
this.visitNode(node);
|
|
6121
|
+
return;
|
|
6122
|
+
}
|
|
5383
6123
|
// Function-as-value capture (#756) — function bodies are walked here,
|
|
5384
6124
|
// not in visitNode, so the capture hook must fire in both walkers.
|
|
5385
6125
|
this.maybeCaptureFnRefs(node, nodeType);
|
|
@@ -5429,8 +6169,30 @@ class TreeSitterExtractor {
|
|
|
5429
6169
|
// (which strips template args / namespace and emits the `instantiates`
|
|
5430
6170
|
// ref). Children still recurse below, so a nested ctor-arg call
|
|
5431
6171
|
// (`Calculator calc(make())`) keeps its own `calls` ref.
|
|
5432
|
-
if (nodeType === 'declaration' && this.language === 'cpp'
|
|
5433
|
-
this.
|
|
6172
|
+
if (nodeType === 'declaration' && this.language === 'cpp') {
|
|
6173
|
+
const { instantiates, arities } = this.cppStackConstructions(node);
|
|
6174
|
+
if (instantiates)
|
|
6175
|
+
this.extractInstantiation(node);
|
|
6176
|
+
// One `calls` ref per constructed object, naming the constructor and
|
|
6177
|
+
// its argument count (`ns::T::T/1`) so the resolver can pick the
|
|
6178
|
+
// overload — a type is not a callee (#1839).
|
|
6179
|
+
const callerId = this.nodeStack[this.nodeStack.length - 1];
|
|
6180
|
+
const typeNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'type');
|
|
6181
|
+
if (callerId && typeNode && arities.length) {
|
|
6182
|
+
const className = (0, c_cpp_1.stripCppTemplateArgs)((0, tree_sitter_helpers_1.getNodeText)(typeNode, this.source));
|
|
6183
|
+
const name = className.split('::').filter(Boolean).pop();
|
|
6184
|
+
if (name) {
|
|
6185
|
+
for (const arity of arities) {
|
|
6186
|
+
this.unresolvedReferences.push({
|
|
6187
|
+
fromNodeId: callerId,
|
|
6188
|
+
referenceName: `${className}::${name}/${arity}`,
|
|
6189
|
+
referenceKind: 'calls',
|
|
6190
|
+
line: node.startPosition.row + 1,
|
|
6191
|
+
column: node.startPosition.column,
|
|
6192
|
+
});
|
|
6193
|
+
}
|
|
6194
|
+
}
|
|
6195
|
+
}
|
|
5434
6196
|
}
|
|
5435
6197
|
// C++ local function-pointer bindings (see cppLocalFnPtrs): record
|
|
5436
6198
|
// `auto kernel = &fn<…>;` declarations and `kernel = &other_fn<…>;`
|
|
@@ -5488,6 +6250,43 @@ class TreeSitterExtractor {
|
|
|
5488
6250
|
this.extractFunction(node);
|
|
5489
6251
|
return;
|
|
5490
6252
|
}
|
|
6253
|
+
// `const handleSubmit = useCallback(() => {…}, [deps])` — React's
|
|
6254
|
+
// memoised handler. The function is anonymous only syntactically: the
|
|
6255
|
+
// arrow is the first argument of a call whose result the declarator
|
|
6256
|
+
// binds, and that binding is the name every `onPress={handleSubmit}`
|
|
6257
|
+
// and `addListener('x', handleSubmit)` uses. Without a node of its own
|
|
6258
|
+
// the handler's calls attribute to the component and the JSX prop or
|
|
6259
|
+
// event registration has nothing to resolve to — the trigger of a flow
|
|
6260
|
+
// is invisible. Bounded to the hooks React documents for handlers
|
|
6261
|
+
// (`useCallback`, `useEffectEvent`, the experimental `useEvent`):
|
|
6262
|
+
// `useMemo` / `useEffect` callbacks are computations, not handlers.
|
|
6263
|
+
const hookBound = this.reactHookBoundName(node);
|
|
6264
|
+
if (hookBound) {
|
|
6265
|
+
this.extractFunction(node, hookBound);
|
|
6266
|
+
return;
|
|
6267
|
+
}
|
|
6268
|
+
// `const run = Effect.fn("Session.run")(function* () {…})` (#1747) —
|
|
6269
|
+
// the same declarator binding through a curried wrapper. Without a node
|
|
6270
|
+
// the body's calls attribute to the enclosing container, so the file or
|
|
6271
|
+
// the outer function picks up an outgoing edge that belongs to this
|
|
6272
|
+
// function and the callee's caller list names the wrong thing.
|
|
6273
|
+
const wrapperBound = this.curriedWrapperBoundName(node);
|
|
6274
|
+
if (wrapperBound) {
|
|
6275
|
+
this.extractFunction(node, wrapperBound);
|
|
6276
|
+
return;
|
|
6277
|
+
}
|
|
6278
|
+
// `const handleClear = () => {…}` inside a body (#1669) — the same
|
|
6279
|
+
// binding that names a function at module scope names one here, and in
|
|
6280
|
+
// a React component it is how every handler that skips `useCallback`
|
|
6281
|
+
// is written. Without a node the handler is absent from callers /
|
|
6282
|
+
// impact ("Symbol not found" reads like "no callers") and its calls
|
|
6283
|
+
// attribute to the component. extractFunction resolves the name from
|
|
6284
|
+
// the declarator; a destructuring or otherwise unnamed binding stays
|
|
6285
|
+
// anonymous and falls through.
|
|
6286
|
+
if (this.declaratorBoundFunction(node)) {
|
|
6287
|
+
this.extractFunction(node);
|
|
6288
|
+
return;
|
|
6289
|
+
}
|
|
5491
6290
|
}
|
|
5492
6291
|
// Extract structural nodes found inside function bodies.
|
|
5493
6292
|
// Each extract method visits its own children, so we return after extracting.
|
|
@@ -5501,6 +6300,8 @@ class TreeSitterExtractor {
|
|
|
5501
6300
|
this.extractInterface(node);
|
|
5502
6301
|
else if (classification === 'trait')
|
|
5503
6302
|
this.extractClass(node, 'trait');
|
|
6303
|
+
else if (classification === 'module')
|
|
6304
|
+
this.extractClass(node, 'module');
|
|
5504
6305
|
else
|
|
5505
6306
|
this.extractClass(node);
|
|
5506
6307
|
return;
|
|
@@ -5509,6 +6310,10 @@ class TreeSitterExtractor {
|
|
|
5509
6310
|
this.extractStruct(node);
|
|
5510
6311
|
return;
|
|
5511
6312
|
}
|
|
6313
|
+
if (this.extractor.unionTypes?.includes(nodeType)) {
|
|
6314
|
+
this.extractUnion(node);
|
|
6315
|
+
return;
|
|
6316
|
+
}
|
|
5512
6317
|
if (this.extractor.enumTypes.includes(nodeType)) {
|
|
5513
6318
|
this.extractEnum(node);
|
|
5514
6319
|
return;
|
|
@@ -5917,31 +6722,20 @@ class TreeSitterExtractor {
|
|
|
5917
6722
|
* For plain `impl Type { ... }` (no trait), no inheritance edge is needed.
|
|
5918
6723
|
*/
|
|
5919
6724
|
extractRustImplItem(node) {
|
|
5920
|
-
//
|
|
5921
|
-
|
|
5922
|
-
|
|
6725
|
+
// `impl Trait for Type` carries the trait in the grammar's `trait` field;
|
|
6726
|
+
// an inherent `impl Type { … }` has none and needs no inheritance edge.
|
|
6727
|
+
const traitNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'trait');
|
|
6728
|
+
if (!traitNode)
|
|
5923
6729
|
return;
|
|
5924
|
-
//
|
|
5925
|
-
//
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
6730
|
+
// Full text, so a scoped path (`std::fmt::Display`) and a generic trait
|
|
6731
|
+
// (`From<u32>`) keep their spelling.
|
|
6732
|
+
const traitName = (0, tree_sitter_helpers_1.getNodeText)(traitNode, this.source);
|
|
6733
|
+
// The implementing type from the `type` field (#1588). The old positional
|
|
6734
|
+
// scan took the LAST type-shaped child, which for a parameterized
|
|
6735
|
+
// implementing type (`BufSource<T>`, `Parents<'a>`, `&Foo`) was the trait.
|
|
6736
|
+
const typeName = (0, rust_1.rustImplTypeName)((0, tree_sitter_helpers_1.getChildByField)(node, 'type'), this.source);
|
|
6737
|
+
if (!typeName)
|
|
5929
6738
|
return;
|
|
5930
|
-
const traitNode = typeIdents[0];
|
|
5931
|
-
const typeNode = typeIdents[typeIdents.length - 1];
|
|
5932
|
-
// Get the trait name (handle scoped paths like std::fmt::Display)
|
|
5933
|
-
const traitName = traitNode.type === 'scoped_type_identifier'
|
|
5934
|
-
? this.source.substring(traitNode.startIndex, traitNode.endIndex)
|
|
5935
|
-
: (0, tree_sitter_helpers_1.getNodeText)(traitNode, this.source);
|
|
5936
|
-
// Get the implementing type name (extract inner type_identifier for generics)
|
|
5937
|
-
let typeName;
|
|
5938
|
-
if (typeNode.type === 'generic_type') {
|
|
5939
|
-
const inner = typeNode.namedChildren.find((c) => c.type === 'type_identifier');
|
|
5940
|
-
typeName = inner ? (0, tree_sitter_helpers_1.getNodeText)(inner, this.source) : (0, tree_sitter_helpers_1.getNodeText)(typeNode, this.source);
|
|
5941
|
-
}
|
|
5942
|
-
else {
|
|
5943
|
-
typeName = (0, tree_sitter_helpers_1.getNodeText)(typeNode, this.source);
|
|
5944
|
-
}
|
|
5945
6739
|
// Find the struct/type node for the implementing type
|
|
5946
6740
|
const typeNodeId = this.findNodeByName(typeName);
|
|
5947
6741
|
if (typeNodeId) {
|
|
@@ -5959,7 +6753,7 @@ class TreeSitterExtractor {
|
|
|
5959
6753
|
*/
|
|
5960
6754
|
findNodeByName(name) {
|
|
5961
6755
|
for (const node of this.nodes) {
|
|
5962
|
-
if (node.name === name && (node.kind === 'struct' || node.kind === 'enum' || node.kind === 'class')) {
|
|
6756
|
+
if (node.name === name && (node.kind === 'struct' || node.kind === 'union' || node.kind === 'enum' || node.kind === 'class')) {
|
|
5963
6757
|
return node.id;
|
|
5964
6758
|
}
|
|
5965
6759
|
}
|