@quolu/lattice 0.70.0 → 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/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/sensor-adapter.mjs +5 -1
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SYNTH_PROGRESS_STEPS = exports.SYNTH_PASSES = void 0;
|
|
4
|
+
exports.hasSynthesisPattern = hasSynthesisPattern;
|
|
4
5
|
exports.synthesizeCallbackEdges = synthesizeCallbackEdges;
|
|
5
6
|
const generated_detection_1 = require("../extraction/generated-detection");
|
|
6
7
|
const strip_comments_1 = require("./strip-comments");
|
|
7
8
|
const c_fnptr_synthesizer_1 = require("./c-fnptr-synthesizer");
|
|
8
9
|
const goframe_synthesizer_1 = require("./goframe-synthesizer");
|
|
10
|
+
const expo_router_synthesizer_1 = require("./expo-router-synthesizer");
|
|
11
|
+
const next_router_synthesizer_1 = require("./next-router-synthesizer");
|
|
12
|
+
const react_router_synthesizer_1 = require("./react-router-synthesizer");
|
|
13
|
+
const tanstack_router_synthesizer_1 = require("./tanstack-router-synthesizer");
|
|
14
|
+
const vue_router_synthesizer_1 = require("./vue-router-synthesizer");
|
|
15
|
+
const sveltekit_synthesizer_1 = require("./sveltekit-synthesizer");
|
|
9
16
|
const cooperative_yield_1 = require("./cooperative-yield");
|
|
17
|
+
const tier_synthesizer_1 = require("./tier-synthesizer");
|
|
18
|
+
const synth_utils_1 = require("./synth-utils");
|
|
19
|
+
const import_resolver_1 = require("./import-resolver");
|
|
20
|
+
const name_matcher_1 = require("./name-matcher");
|
|
10
21
|
const REGISTRAR_NAME = /^(on[A-Z]\w*|subscribe|addListener|addEventListener|register|watch|listen|addCallback)$/;
|
|
11
22
|
const DISPATCHER_NAME = /(emit|trigger|notify|dispatch|fire|publish|flush)/i;
|
|
12
23
|
const MAX_CALLBACKS_PER_CHANNEL = 40;
|
|
@@ -15,6 +26,7 @@ const ON_RE = /\.(?:on|once|addListener)\(\s*['"]([^'"]+)['"]\s*,\s*(?:function\
|
|
|
15
26
|
const EMIT_RE = /\.(?:emit|fire|dispatchEvent)\(\s*['"]([^'"]+)['"]/g;
|
|
16
27
|
const SETSTATE_RE = /this\.setState\s*\(/;
|
|
17
28
|
const FLUTTER_SETSTATE_RE = /\bsetState\s*\(/; // Flutter: setState((){…}) / this.setState
|
|
29
|
+
const JS_FAMILY = ['typescript', 'javascript', 'tsx', 'jsx'];
|
|
18
30
|
const JSX_TAG_RE = /<([A-Z][A-Za-z0-9_]*)[\s/>]/g;
|
|
19
31
|
const MAX_JSX_CHILDREN = 30;
|
|
20
32
|
// Vue SFC templates: kebab-case child components (<el-button> → ElButton) and
|
|
@@ -85,35 +97,6 @@ function sliceLines(content, startLine, endLine) {
|
|
|
85
97
|
return null;
|
|
86
98
|
return content.split('\n').slice(startLine - 1, endLine).join('\n');
|
|
87
99
|
}
|
|
88
|
-
/**
|
|
89
|
-
* Per-match line resolver over `src`, 1-based at `baseLine`. The inline
|
|
90
|
-
* `src.slice(0, idx).split('\n').length` idiom is O(source-length) PER MATCH,
|
|
91
|
-
* which goes quadratic on a match-dense source (a generated function full of
|
|
92
|
-
* `.push(` calls re-scanned tens of thousands of times was most of the #1235
|
|
93
|
-
* indexing wedge). Builds the newline index once — lazily, since most sources
|
|
94
|
-
* never produce a match — then answers each call with a binary search.
|
|
95
|
-
*/
|
|
96
|
-
function makeLineAt(src, baseLine) {
|
|
97
|
-
let nl = null;
|
|
98
|
-
return (idx) => {
|
|
99
|
-
if (!nl) {
|
|
100
|
-
nl = [];
|
|
101
|
-
for (let i = src.indexOf('\n'); i !== -1; i = src.indexOf('\n', i + 1))
|
|
102
|
-
nl.push(i);
|
|
103
|
-
}
|
|
104
|
-
// Count newlines strictly before idx.
|
|
105
|
-
let lo = 0;
|
|
106
|
-
let hi = nl.length;
|
|
107
|
-
while (lo < hi) {
|
|
108
|
-
const mid = (lo + hi) >> 1;
|
|
109
|
-
if (nl[mid] < idx)
|
|
110
|
-
lo = mid + 1;
|
|
111
|
-
else
|
|
112
|
-
hi = mid;
|
|
113
|
-
}
|
|
114
|
-
return baseLine + lo;
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
100
|
function registrarField(src) {
|
|
118
101
|
const m = src.match(/this\.(\w+)\.(?:add|push|set)\(/);
|
|
119
102
|
return m ? m[1] : null;
|
|
@@ -127,21 +110,6 @@ function dispatcherField(src) {
|
|
|
127
110
|
return forEach[1];
|
|
128
111
|
return null;
|
|
129
112
|
}
|
|
130
|
-
const FN_KINDS = new Set(['method', 'function', 'component']);
|
|
131
|
-
/** Innermost function/method node whose line range contains `line`. */
|
|
132
|
-
function enclosingFn(nodesInFile, line) {
|
|
133
|
-
let best = null;
|
|
134
|
-
for (const n of nodesInFile) {
|
|
135
|
-
if (!FN_KINDS.has(n.kind))
|
|
136
|
-
continue;
|
|
137
|
-
const end = n.endLine ?? n.startLine;
|
|
138
|
-
if (n.startLine <= line && end >= line) {
|
|
139
|
-
if (!best || n.startLine >= best.startLine)
|
|
140
|
-
best = n; // prefer the tightest (latest-starting) encloser
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return best;
|
|
144
|
-
}
|
|
145
113
|
/**
|
|
146
114
|
* Stream method + function nodes lazily. The synthesizers only scan-and-filter
|
|
147
115
|
* down to a tiny matched subset, so materializing every function/method (which
|
|
@@ -185,7 +153,7 @@ async function fieldChannelEdges(queries, ctx, onYield) {
|
|
|
185
153
|
const chDispatchers = dispatchers.filter((d) => d.node.filePath === reg.node.filePath && d.field === reg.field);
|
|
186
154
|
if (chDispatchers.length === 0)
|
|
187
155
|
continue;
|
|
188
|
-
const argRe = new RegExp(`${reg.node.name}\\s*\\(\\s*(
|
|
156
|
+
const argRe = new RegExp(`${reg.node.name}\\s*\\(\\s*(this\\.\\w+|\\w+)\\s*(?=[,)])`);
|
|
189
157
|
let added = 0;
|
|
190
158
|
for (const e of queries.getIncomingEdges(reg.node.id, ['calls'])) {
|
|
191
159
|
if (added >= MAX_CALLBACKS_PER_CHANNEL)
|
|
@@ -199,8 +167,15 @@ async function fieldChannelEdges(queries, ctx, onYield) {
|
|
|
199
167
|
const am = line?.match(argRe);
|
|
200
168
|
if (!am)
|
|
201
169
|
continue;
|
|
202
|
-
|
|
203
|
-
|
|
170
|
+
// Reuse the resolved value at this registration site: it retains the
|
|
171
|
+
// receiver's class/inheritance and import binding, unlike a name lookup.
|
|
172
|
+
const refs = queries.getOutgoingEdges(caller.id, ['references']).filter((r) => r.line === e.line && r.metadata?.fnRef === true && r.metadata.refName === am[1]);
|
|
173
|
+
if (refs.length !== 1)
|
|
174
|
+
continue;
|
|
175
|
+
const fn = queries.getNodeById(refs[0].target);
|
|
176
|
+
if (!fn || (fn.kind !== 'method' && fn.kind !== 'function'))
|
|
177
|
+
continue;
|
|
178
|
+
if (!am[1].startsWith('this.') && fn.filePath !== caller.filePath && refs[0].metadata?.resolvedBy !== 'import')
|
|
204
179
|
continue;
|
|
205
180
|
for (const disp of chDispatchers) {
|
|
206
181
|
if (disp.node.id === fn.id)
|
|
@@ -271,7 +246,7 @@ async function closureCollectionEdges(queries, ctx, onYield) {
|
|
|
271
246
|
const hasAppend = src.includes('.append(') || src.includes('.add(') || src.includes('.push(') || src.includes('.insert(');
|
|
272
247
|
if (!hasForEach && !hasAppend)
|
|
273
248
|
continue;
|
|
274
|
-
const lineAt = makeLineAt(src, m.startLine ?? 1);
|
|
249
|
+
const lineAt = (0, synth_utils_1.makeLineAt)(src, m.startLine ?? 1);
|
|
275
250
|
if (hasForEach) {
|
|
276
251
|
CC_DISPATCH_RE.lastIndex = 0;
|
|
277
252
|
let d;
|
|
@@ -345,12 +320,12 @@ async function eventEmitterEdges(ctx, onYield) {
|
|
|
345
320
|
if (!hasEmit && !hasOn)
|
|
346
321
|
continue;
|
|
347
322
|
const nodesInFile = ctx.getNodesInFile(file);
|
|
348
|
-
const lineOf = makeLineAt(content, 1);
|
|
323
|
+
const lineOf = (0, synth_utils_1.makeLineAt)(content, 1);
|
|
349
324
|
if (hasEmit) {
|
|
350
325
|
EMIT_RE.lastIndex = 0;
|
|
351
326
|
let m;
|
|
352
327
|
while ((m = EMIT_RE.exec(content))) {
|
|
353
|
-
const disp = enclosingFn(nodesInFile, lineOf(m.index));
|
|
328
|
+
const disp = (0, synth_utils_1.enclosingFn)(nodesInFile, lineOf(m.index));
|
|
354
329
|
if (!disp)
|
|
355
330
|
continue;
|
|
356
331
|
const set = emitsByEvent.get(m[1]) ?? new Set();
|
|
@@ -542,11 +517,9 @@ async function arkuiStateBuildEdges(queries, ctx, onYield) {
|
|
|
542
517
|
let scanned255 = 0;
|
|
543
518
|
const edges = [];
|
|
544
519
|
const seen = new Set();
|
|
545
|
-
for (const struct of queries.
|
|
520
|
+
for (const struct of queries.iterateNodesByKindIn('struct', ['arkts'])) {
|
|
546
521
|
if ((++scanned255 & 63) === 0)
|
|
547
522
|
await onYield();
|
|
548
|
-
if (struct.language !== 'arkts')
|
|
549
|
-
continue;
|
|
550
523
|
const children = queries.getOutgoingEdges(struct.id, ['contains'])
|
|
551
524
|
.map((e) => queries.getNodeById(e.target))
|
|
552
525
|
.filter((n) => !!n);
|
|
@@ -884,22 +857,17 @@ async function goImplementsEdges(queries, onYield) {
|
|
|
884
857
|
// never the whole struct kind — that array is O(nodes) on struct-heavy
|
|
885
858
|
// repos like the Linux kernel (#1212).
|
|
886
859
|
const goStructs = [];
|
|
887
|
-
for (const s of queries.
|
|
860
|
+
for (const s of queries.iterateNodesByKindIn('struct', ['go'])) {
|
|
888
861
|
if ((++scanned255 & 63) === 0)
|
|
889
862
|
await onYield();
|
|
890
|
-
|
|
891
|
-
goStructs.push(s);
|
|
863
|
+
goStructs.push(s);
|
|
892
864
|
}
|
|
893
865
|
const structMethods = new Map();
|
|
894
866
|
for (const s of goStructs)
|
|
895
867
|
structMethods.set(s.id, methodNameSet(s.id));
|
|
896
|
-
for (const iface of queries.
|
|
868
|
+
for (const iface of queries.iterateNodesByKindIn('interface', ['go'])) {
|
|
897
869
|
if ((++scanned255 & 63) === 0)
|
|
898
870
|
await onYield();
|
|
899
|
-
if ((++scanned255 & 63) === 0)
|
|
900
|
-
await onYield();
|
|
901
|
-
if (iface.language !== 'go')
|
|
902
|
-
continue;
|
|
903
871
|
const want = methodNameSet(iface.id);
|
|
904
872
|
if (want.size === 0)
|
|
905
873
|
continue; // empty interface (`any`) — would match everything
|
|
@@ -952,9 +920,10 @@ async function goImplementsEdges(queries, onYield) {
|
|
|
952
920
|
*
|
|
953
921
|
* Go guarantees a method's receiver type is declared in the SAME PACKAGE as the
|
|
954
922
|
* method, and a Go package is a single directory — so this is a deterministic
|
|
955
|
-
* structural link, not a heuristic: find the same-named type in the method's
|
|
956
|
-
* directory and add the missing `contains` edge
|
|
957
|
-
*
|
|
923
|
+
* structural link, not a heuristic: find the same-named type in the method's
|
|
924
|
+
* own directory and add the missing `contains` edge with no provenance, matching
|
|
925
|
+
* same-file extraction. Tag synthesis ownership so an incremental
|
|
926
|
+
* refresh can replace it alongside implicit `implements`. Skips methods that
|
|
958
927
|
* already have a type parent (the same-file case). (#583, cross-file half)
|
|
959
928
|
*/
|
|
960
929
|
async function goCrossFileMethodContainsEdges(queries, onYield) {
|
|
@@ -966,13 +935,9 @@ async function goCrossFileMethodContainsEdges(queries, onYield) {
|
|
|
966
935
|
const i = p.replace(/\\/g, '/').lastIndexOf('/');
|
|
967
936
|
return i >= 0 ? p.slice(0, i) : '';
|
|
968
937
|
};
|
|
969
|
-
for (const method of queries.
|
|
970
|
-
if ((++scanned255 & 63) === 0)
|
|
971
|
-
await onYield();
|
|
938
|
+
for (const method of queries.iterateNodesByKindIn('method', ['go'])) {
|
|
972
939
|
if ((++scanned255 & 63) === 0)
|
|
973
940
|
await onYield();
|
|
974
|
-
if (method.language !== 'go')
|
|
975
|
-
continue;
|
|
976
941
|
// The receiver type is encoded in the method's qualifiedName as `Recv::name`
|
|
977
942
|
// (extraction sets `${receiverType}::${name}` for receiver methods).
|
|
978
943
|
const qn = method.qualifiedName;
|
|
@@ -1007,7 +972,8 @@ async function goCrossFileMethodContainsEdges(queries, onYield) {
|
|
|
1007
972
|
if (seen.has(key))
|
|
1008
973
|
continue;
|
|
1009
974
|
seen.add(key);
|
|
1010
|
-
edges.push({ source: owner.id, target: method.id, kind: 'contains', line: method.startLine
|
|
975
|
+
edges.push({ source: owner.id, target: method.id, kind: 'contains', line: method.startLine,
|
|
976
|
+
metadata: { synthesizedBy: 'go-method-contains' } });
|
|
1011
977
|
}
|
|
1012
978
|
return edges;
|
|
1013
979
|
}
|
|
@@ -1106,10 +1072,31 @@ async function interfaceOverrideEdges(queries, onYield) {
|
|
|
1106
1072
|
methodsMemo.set(classId, methods);
|
|
1107
1073
|
return methods;
|
|
1108
1074
|
};
|
|
1075
|
+
// A Swift protocol's methods live in its extensions: requirements are not
|
|
1076
|
+
// extracted as methods, and `extension EventMonitor { func request(…) }` is
|
|
1077
|
+
// where the default implementations a conformer overrides are. A class-kind
|
|
1078
|
+
// node sharing a protocol's name is one of its extensions.
|
|
1079
|
+
const protocolMemo = new Map();
|
|
1080
|
+
const baseMethodsOf = (base) => {
|
|
1081
|
+
if (base.language !== 'swift' || base.kind !== 'interface')
|
|
1082
|
+
return methodsOf(base.id);
|
|
1083
|
+
const hit = protocolMemo.get(base.id);
|
|
1084
|
+
if (hit)
|
|
1085
|
+
return hit;
|
|
1086
|
+
const methods = [
|
|
1087
|
+
...methodsOf(base.id),
|
|
1088
|
+
...queries
|
|
1089
|
+
.getNodesByName(base.name)
|
|
1090
|
+
.filter((n) => n.language === 'swift' && n.kind === 'class')
|
|
1091
|
+
.flatMap((n) => methodsOf(n.id)),
|
|
1092
|
+
];
|
|
1093
|
+
protocolMemo.set(base.id, methods);
|
|
1094
|
+
return methods;
|
|
1095
|
+
};
|
|
1109
1096
|
// Concrete-side kinds vary by language: `class` covers Java / Kotlin /
|
|
1110
1097
|
// C# / TS / Swift-classes / Scala-classes; `struct` covers Swift value
|
|
1111
1098
|
// types that conform to protocols. Iterate both.
|
|
1112
|
-
const concreteKinds = ['class', 'struct'];
|
|
1099
|
+
const concreteKinds = ['class', 'struct', 'union'];
|
|
1113
1100
|
for (const kind of concreteKinds) {
|
|
1114
1101
|
for (const cls of queries.iterateNodesByKind(kind)) {
|
|
1115
1102
|
if ((++scanned255 & 63) === 0)
|
|
@@ -1140,7 +1127,7 @@ async function interfaceOverrideEdges(queries, onYield) {
|
|
|
1140
1127
|
implByName.set(m.name, [m]);
|
|
1141
1128
|
}
|
|
1142
1129
|
let added = 0;
|
|
1143
|
-
for (const bm of
|
|
1130
|
+
for (const bm of baseMethodsOf(base)) {
|
|
1144
1131
|
if (added >= MAX_CALLBACKS_PER_CHANNEL)
|
|
1145
1132
|
break;
|
|
1146
1133
|
for (const m of implByName.get(bm.name) ?? []) {
|
|
@@ -1206,11 +1193,9 @@ async function goGrpcStubImplEdges(queries, onYield) {
|
|
|
1206
1193
|
const methodNamesByStruct = new Map();
|
|
1207
1194
|
const methodNodesByStruct = new Map();
|
|
1208
1195
|
const goStructs = [];
|
|
1209
|
-
for (const s of queries.
|
|
1196
|
+
for (const s of queries.iterateNodesByKindIn('struct', ['go'])) {
|
|
1210
1197
|
if ((++scanned255 & 63) === 0)
|
|
1211
1198
|
await onYield();
|
|
1212
|
-
if (s.language !== 'go')
|
|
1213
|
-
continue;
|
|
1214
1199
|
goStructs.push(s);
|
|
1215
1200
|
const ms = queries
|
|
1216
1201
|
.getOutgoingEdges(s.id, ['contains'])
|
|
@@ -1282,6 +1267,60 @@ async function goGrpcStubImplEdges(queries, onYield) {
|
|
|
1282
1267
|
}
|
|
1283
1268
|
return edges;
|
|
1284
1269
|
}
|
|
1270
|
+
/** Kinds a JSX tag can name. A tag that resolves only to a type is markup we drop. */
|
|
1271
|
+
const JSX_CHILD_KINDS = new Set(['component', 'function', 'class']);
|
|
1272
|
+
/**
|
|
1273
|
+
* The languages a JSX tag can plausibly name a component in. Preferred over a
|
|
1274
|
+
* same-named symbol in another language, never required — a React Native tag
|
|
1275
|
+
* whose only match is the native class it bridges to (`requireNativeComponent`)
|
|
1276
|
+
* still links there.
|
|
1277
|
+
*/
|
|
1278
|
+
const JSX_CHILD_LANGUAGES = [...JS_FAMILY, 'vue', 'svelte'];
|
|
1279
|
+
/** `localName` → the project file it is imported from, for one file's imports. */
|
|
1280
|
+
function importedFrom(ctx, file, language) {
|
|
1281
|
+
const out = new Map();
|
|
1282
|
+
for (const im of ctx.getImportMappings(file, language)) {
|
|
1283
|
+
// The mappings name the module as written; the file it is comes from the
|
|
1284
|
+
// same resolution the import resolver uses (aliases, extensions, index files).
|
|
1285
|
+
const resolved = im.resolvedPath ?? (0, import_resolver_1.resolveImportPath)(im.source, file, language, ctx);
|
|
1286
|
+
if (resolved)
|
|
1287
|
+
out.set(im.localName, resolved);
|
|
1288
|
+
}
|
|
1289
|
+
return out;
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* The component a JSX tag names, among every node that shares the name.
|
|
1293
|
+
*
|
|
1294
|
+
* A tag is written in one file, and that file already says which `FrameCard` it
|
|
1295
|
+
* means: the one it declares, or the one it imports. Taking the FIRST node of
|
|
1296
|
+
* that name — which is what this did — is a coin flip once a name repeats, and
|
|
1297
|
+
* it costs twice over. The parent gets an edge to a component it never renders,
|
|
1298
|
+
* and the component it does render is left with no caller at all, so every walk
|
|
1299
|
+
* back from that subtree dead-ends: on an Expo app whose `<FrameCard/>` was one
|
|
1300
|
+
* of two, the folder sheet's `openBackgroundNoiseDetail` stood alone on Screens
|
|
1301
|
+
* with no screen behind it, while the edge pointed at an unrelated card in
|
|
1302
|
+
* another sheet.
|
|
1303
|
+
*
|
|
1304
|
+
* Same file first — a small component declared beside its use is the commonest
|
|
1305
|
+
* shape, and the one an import can never disambiguate. Then the file the name
|
|
1306
|
+
* is imported from. Then the language, which only decides a tie: a `.tsx` tag
|
|
1307
|
+
* naming both a TS component and a same-named Swift class means the TS one.
|
|
1308
|
+
*/
|
|
1309
|
+
function jsxChild(ctx, name, file, importsOf) {
|
|
1310
|
+
const candidates = ctx.getNodesByName(name).filter((n) => JSX_CHILD_KINDS.has(n.kind));
|
|
1311
|
+
if (candidates.length <= 1)
|
|
1312
|
+
return candidates[0];
|
|
1313
|
+
const local = candidates.find((n) => n.filePath === file);
|
|
1314
|
+
if (local)
|
|
1315
|
+
return local;
|
|
1316
|
+
const from = importsOf().get(name);
|
|
1317
|
+
if (from) {
|
|
1318
|
+
const imported = candidates.find((n) => n.filePath === from);
|
|
1319
|
+
if (imported)
|
|
1320
|
+
return imported;
|
|
1321
|
+
}
|
|
1322
|
+
return candidates.find((n) => JSX_CHILD_LANGUAGES.includes(n.language)) ?? candidates[0];
|
|
1323
|
+
}
|
|
1285
1324
|
/**
|
|
1286
1325
|
* Phase 5: React JSX child rendering. A component that returns `<Child .../>`
|
|
1287
1326
|
* mounts Child — React calls it — but JSX instantiation isn't a static call edge,
|
|
@@ -1305,7 +1344,14 @@ async function reactJsxChildEdges(ctx, onYield) {
|
|
|
1305
1344
|
const content = ctx.readFile(file);
|
|
1306
1345
|
if (!content || (!content.includes('</') && !content.includes('/>')))
|
|
1307
1346
|
continue; // JSX-file gate
|
|
1308
|
-
|
|
1347
|
+
// File-level language gate, not merely a project-level one: mixed C/JS
|
|
1348
|
+
// monorepos must not interpret `"<Foo/>"` inside C as JSX (#1560).
|
|
1349
|
+
const parents = ctx.getNodesInFile(file).filter((n) => PARENT_KINDS.has(n.kind) && JS_FAMILY.includes(n.language));
|
|
1350
|
+
if (parents.length === 0)
|
|
1351
|
+
continue;
|
|
1352
|
+
// Read once per file, and only when a name actually turns out ambiguous.
|
|
1353
|
+
let imports = null;
|
|
1354
|
+
const importsOf = () => (imports ??= importedFrom(ctx, file, parents[0].language));
|
|
1309
1355
|
for (const parent of parents) {
|
|
1310
1356
|
const src = sliceLines(content, parent.startLine, parent.endLine);
|
|
1311
1357
|
if (!src || (!src.includes('</') && !src.includes('/>')))
|
|
@@ -1319,8 +1365,8 @@ async function reactJsxChildEdges(ctx, onYield) {
|
|
|
1319
1365
|
for (const name of names) {
|
|
1320
1366
|
if (added >= MAX_JSX_CHILDREN)
|
|
1321
1367
|
break;
|
|
1322
|
-
const child = ctx
|
|
1323
|
-
if (!child || child.id === parent.id)
|
|
1368
|
+
const child = jsxChild(ctx, name, file, importsOf);
|
|
1369
|
+
if (!child || child.id === parent.id || (0, name_matcher_1.crossesCodeBoundary)(parent.language, child.language))
|
|
1324
1370
|
continue;
|
|
1325
1371
|
const key = `${parent.id}>${child.id}`;
|
|
1326
1372
|
if (seen.has(key))
|
|
@@ -1402,7 +1448,8 @@ async function vueTemplateEdges(ctx, onYield) {
|
|
|
1402
1448
|
}
|
|
1403
1449
|
let added = 0;
|
|
1404
1450
|
const addEdge = (target, meta) => {
|
|
1405
|
-
if (added >= MAX_JSX_CHILDREN || !target || target.id === comp.id
|
|
1451
|
+
if (added >= MAX_JSX_CHILDREN || !target || target.id === comp.id ||
|
|
1452
|
+
(0, name_matcher_1.crossesCodeBoundary)(comp.language, target.language))
|
|
1406
1453
|
return;
|
|
1407
1454
|
const k = `${comp.id}>${target.id}>${meta.synthesizedBy}`;
|
|
1408
1455
|
if (seen.has(k))
|
|
@@ -1479,10 +1526,13 @@ async function vueTemplateEdges(ctx, onYield) {
|
|
|
1479
1526
|
* DeviceEventEmitter.addListener("locationUpdate", handler);
|
|
1480
1527
|
*
|
|
1481
1528
|
* Synthesize: native dispatch site → JS handler, keyed by the literal
|
|
1482
|
-
* event name.
|
|
1483
|
-
*
|
|
1484
|
-
*
|
|
1485
|
-
*
|
|
1529
|
+
* event name. A NAMED handler (`addListener('x', handleX)`) is the target
|
|
1530
|
+
* when it is a node; an unnamed one — a parameter passed through, or an
|
|
1531
|
+
* inline `(data) => {…}` written in a `useEffect` — is attributed to the
|
|
1532
|
+
* enclosing function, where the event demonstrably lands. (The in-language
|
|
1533
|
+
* synthesizer stays named-only; this channel pairs across a language
|
|
1534
|
+
* boundary on a literal, which is the evidence that makes the wider
|
|
1535
|
+
* attribution safe.)
|
|
1486
1536
|
*
|
|
1487
1537
|
* Provenance `'heuristic'`, synthesizedBy `'rn-event-channel'`.
|
|
1488
1538
|
*/
|
|
@@ -1522,9 +1572,9 @@ async function rnEventEdges(ctx, onYield) {
|
|
|
1522
1572
|
if (!content)
|
|
1523
1573
|
continue;
|
|
1524
1574
|
const nodesInFile = ctx.getNodesInFile(file);
|
|
1525
|
-
const lineOf = makeLineAt(content, 1);
|
|
1575
|
+
const lineOf = (0, synth_utils_1.makeLineAt)(content, 1);
|
|
1526
1576
|
const addDispatcher = (event, line) => {
|
|
1527
|
-
const disp = enclosingFn(nodesInFile, line);
|
|
1577
|
+
const disp = (0, synth_utils_1.enclosingFn)(nodesInFile, line);
|
|
1528
1578
|
if (!disp)
|
|
1529
1579
|
return;
|
|
1530
1580
|
const set = nativeDispatchersByEvent.get(event) ?? new Set();
|
|
@@ -1590,6 +1640,8 @@ async function rnEventEdges(ctx, onYield) {
|
|
|
1590
1640
|
// function (the abstraction layer), giving a reachability-correct
|
|
1591
1641
|
// hop even when the actual user-side handler lives one call up.
|
|
1592
1642
|
const ADDLISTENER_ANY = /\.(?:on|once|addListener)\(\s*['"]([^'"]+)['"]\s*,\s*([A-Za-z_][\w.]*)/g;
|
|
1643
|
+
// The inline form: `.addListener('x', (data) => {…})` / `function () {…}`.
|
|
1644
|
+
const ADDLISTENER_INLINE = /\.(?:on|once|addListener)\(\s*['"]([^'"]+)['"]\s*,\s*(?:async\s*)?(?:\([^)]*\)\s*=>|[A-Za-z_$][\w$]*\s*=>|function\s*\()/g;
|
|
1593
1645
|
ADDLISTENER_ANY.lastIndex = 0;
|
|
1594
1646
|
let m;
|
|
1595
1647
|
while ((m = ADDLISTENER_ANY.exec(content))) {
|
|
@@ -1607,7 +1659,7 @@ async function rnEventEdges(ctx, onYield) {
|
|
|
1607
1659
|
// Fall back to the enclosing function — the subscribe-wrapper
|
|
1608
1660
|
// pattern means the event fires THROUGH this function on its
|
|
1609
1661
|
// way to user code. Reachability-correct attribution.
|
|
1610
|
-
const enclosing = enclosingFn(nodesInFile, lineOf(m.index));
|
|
1662
|
+
const enclosing = (0, synth_utils_1.enclosingFn)(nodesInFile, lineOf(m.index));
|
|
1611
1663
|
targetId = enclosing?.id ?? null;
|
|
1612
1664
|
}
|
|
1613
1665
|
if (!targetId) {
|
|
@@ -1637,6 +1689,26 @@ async function rnEventEdges(ctx, onYield) {
|
|
|
1637
1689
|
map.set(targetId, `${file}:${lineOf(m.index)}`);
|
|
1638
1690
|
jsHandlersByEvent.set(event, map);
|
|
1639
1691
|
}
|
|
1692
|
+
// Inline listeners — the shape a React component registers inside a
|
|
1693
|
+
// `useEffect`: `nativeEmitter.addListener('onCaptureComplete', (data) =>
|
|
1694
|
+
// { … router.push('/review') })`. There is no handler symbol to name,
|
|
1695
|
+
// so the subscription is attributed to the enclosing function exactly
|
|
1696
|
+
// as the unnamed-argument form above is: the native event lands in that
|
|
1697
|
+
// component, and its body is where a reader looks next. This channel
|
|
1698
|
+
// only — the in-language synthesizer keeps its named-handler policy.
|
|
1699
|
+
ADDLISTENER_INLINE.lastIndex = 0;
|
|
1700
|
+
while ((m = ADDLISTENER_INLINE.exec(content))) {
|
|
1701
|
+
const event = m[1];
|
|
1702
|
+
if (!event)
|
|
1703
|
+
continue;
|
|
1704
|
+
const enclosing = (0, synth_utils_1.enclosingFn)(nodesInFile, lineOf(m.index));
|
|
1705
|
+
if (!enclosing)
|
|
1706
|
+
continue;
|
|
1707
|
+
const map = jsHandlersByEvent.get(event) ?? new Map();
|
|
1708
|
+
if (!map.has(enclosing.id))
|
|
1709
|
+
map.set(enclosing.id, `${file}:${lineOf(m.index)}`);
|
|
1710
|
+
jsHandlersByEvent.set(event, map);
|
|
1711
|
+
}
|
|
1640
1712
|
}
|
|
1641
1713
|
}
|
|
1642
1714
|
const edges = [];
|
|
@@ -1783,11 +1855,9 @@ async function rnCrossPlatformEdges(queries, onYield) {
|
|
|
1783
1855
|
// impls in ≥2 native languages can pair, so the per-method JS-caller check
|
|
1784
1856
|
// below only runs for genuine cross-platform candidates.
|
|
1785
1857
|
const byName = new Map();
|
|
1786
|
-
for (const m of queries.
|
|
1858
|
+
for (const m of queries.iterateNodesByKindIn('method', [...NATIVE])) {
|
|
1787
1859
|
if ((++scanned255 & 63) === 0)
|
|
1788
1860
|
await onYield();
|
|
1789
|
-
if (!NATIVE.has(m.language))
|
|
1790
|
-
continue;
|
|
1791
1861
|
const key = norm(m.name);
|
|
1792
1862
|
const arr = byName.get(key);
|
|
1793
1863
|
if (arr)
|
|
@@ -1919,21 +1989,18 @@ async function mybatisJavaXmlEdges(queries, onYield) {
|
|
|
1919
1989
|
// stream below. Same rowid stream order as matching inline, so the edge
|
|
1920
1990
|
// output is byte-identical when mappers do exist.
|
|
1921
1991
|
const xmlMethods = [];
|
|
1922
|
-
for (const m of queries.
|
|
1992
|
+
for (const m of queries.iterateNodesByKindIn('method', ['xml'])) {
|
|
1923
1993
|
if ((++scanned255 & 63) === 0)
|
|
1924
1994
|
await onYield();
|
|
1925
|
-
|
|
1926
|
-
xmlMethods.push(m);
|
|
1995
|
+
xmlMethods.push(m);
|
|
1927
1996
|
}
|
|
1928
1997
|
if (xmlMethods.length === 0)
|
|
1929
1998
|
return edges;
|
|
1930
1999
|
// Index Java methods by `<ClassName>::<methodName>` for O(1) lookup.
|
|
1931
2000
|
const javaIndex = new Map();
|
|
1932
|
-
for (const m of queries.
|
|
2001
|
+
for (const m of queries.iterateNodesByKindIn('method', ['java', 'kotlin'])) {
|
|
1933
2002
|
if ((++scanned255 & 63) === 0)
|
|
1934
2003
|
await onYield();
|
|
1935
|
-
if (m.language !== 'java' && m.language !== 'kotlin')
|
|
1936
|
-
continue;
|
|
1937
2004
|
const parts = m.qualifiedName.split('::');
|
|
1938
2005
|
const last = parts[parts.length - 1];
|
|
1939
2006
|
const cls = parts[parts.length - 2];
|
|
@@ -2065,11 +2132,9 @@ async function ginMiddlewareChainEdges(queries, ctx, onYield) {
|
|
|
2065
2132
|
let scannedFiles = 0;
|
|
2066
2133
|
// 1. Find the chain dispatcher(s): a Go method that invokes a `handlers` slice by index.
|
|
2067
2134
|
const dispatchers = [];
|
|
2068
|
-
for (const n of queries.
|
|
2135
|
+
for (const n of queries.iterateNodesByKindIn('method', ['go'])) {
|
|
2069
2136
|
if ((++scanned255 & 63) === 0)
|
|
2070
2137
|
await onYield();
|
|
2071
|
-
if (n.language !== 'go')
|
|
2072
|
-
continue;
|
|
2073
2138
|
const content = ctx.readFile(n.filePath);
|
|
2074
2139
|
const src = content && sliceLines(content, n.startLine, n.endLine);
|
|
2075
2140
|
if (src && GIN_DISPATCH_RE.test(src))
|
|
@@ -2203,12 +2268,17 @@ async function svelteKitLoadEdges(ctx, onYield) {
|
|
|
2203
2268
|
if (!allFiles.has(loaderFile))
|
|
2204
2269
|
continue;
|
|
2205
2270
|
for (const hook of ctx.getNodesInFile(loaderFile)) {
|
|
2206
|
-
|
|
2271
|
+
// `load` and `actions` by name, and every function the loader file
|
|
2272
|
+
// declares — a form action is an arrow inside `actions`, and it is a
|
|
2273
|
+
// node of its own (`default`, `logout`), where the redirect that ends
|
|
2274
|
+
// the submission is actually written.
|
|
2275
|
+
const named = HOOK_KINDS.has(hook.kind) && HOOKS.has(hook.name);
|
|
2276
|
+
if (!named && hook.kind !== 'function' && hook.kind !== 'method')
|
|
2207
2277
|
continue;
|
|
2208
2278
|
edges.push({
|
|
2209
2279
|
source: page.id,
|
|
2210
2280
|
target: hook.id,
|
|
2211
|
-
kind: '
|
|
2281
|
+
kind: 'calls',
|
|
2212
2282
|
line: page.startLine,
|
|
2213
2283
|
provenance: 'heuristic',
|
|
2214
2284
|
metadata: {
|
|
@@ -2306,12 +2376,38 @@ async function reduxThunkEdges(queries, ctx, onYield) {
|
|
|
2306
2376
|
// the SAME file (the cross-file barrel-namespace variant, e.g. trezor's getMethod, is
|
|
2307
2377
|
// deferred). Gated on a real object literal with ≥2 entries that RESOLVE to callables (a
|
|
2308
2378
|
// `{ width: 5 }` literal resolves to nothing → no edges); fan-out capped.
|
|
2309
|
-
|
|
2310
|
-
|
|
2379
|
+
// Both scans only START a name at an identifier's first character (or at a `this.`): the
|
|
2380
|
+
// engine otherwise retries the greedy name at every later character of every identifier in
|
|
2381
|
+
// the file. A match found from inside an identifier always has one from the identifier's
|
|
2382
|
+
// start (same name tail, same continuation), so the result is unchanged — except where the
|
|
2383
|
+
// scan itself resumes mid-identifier after a dispatch ending in `.method`, which
|
|
2384
|
+
// `nextRegistryDispatch` covers with the unguarded pattern.
|
|
2385
|
+
const REGISTRY_NAME_START = String.raw `(?:(?<![A-Za-z_$])(?<![A-Za-z_$][\w$]+)|(?=this\.))`;
|
|
2386
|
+
const REGISTRY_ASSIGN_RE = new RegExp(String.raw `(?:(?:const|let|var)\s+([A-Za-z_$][\w$]*)|${REGISTRY_NAME_START}((?:this\.)?[A-Za-z_$][\w$]*))\s*=\s*\{`, 'g');
|
|
2387
|
+
const REGISTRY_DISPATCH_SRC = String.raw `(?:\bnew\s+)?((?:this\.)?[A-Za-z_$][\w$]*)\s*\[\s*([A-Za-z_$][\w$.]*)\s*\]\s*(?:\(|\.[A-Za-z_$])`;
|
|
2388
|
+
const REGISTRY_DISPATCH_AT = new RegExp(REGISTRY_DISPATCH_SRC, 'y');
|
|
2389
|
+
// `\bnew` can follow a `$` inside an identifier run, hence the extra `(?<!\w)` start.
|
|
2390
|
+
const REGISTRY_DISPATCH_RE = new RegExp(String.raw `(?:(?<!\w)|${REGISTRY_NAME_START})${REGISTRY_DISPATCH_SRC}`, 'g');
|
|
2391
|
+
const IDENT_RUN_CHAR = /[\w$]/;
|
|
2311
2392
|
const REGISTRY_MIN_ENTRIES = 2;
|
|
2312
2393
|
const REGISTRY_FANOUT_CAP = 40;
|
|
2313
2394
|
const REGISTRY_CLASS_ENTRY = new Set(['execute', 'run', 'handle', 'perform', 'process', 'call', 'apply', 'dispatch']);
|
|
2314
2395
|
const REGISTRY_JS_EXT = /\.(?:ts|tsx|js|jsx|mjs|cjs)$/;
|
|
2396
|
+
/** The first registry dispatch at or after `from`, exactly as a `g` scan of the unguarded
|
|
2397
|
+
* pattern resuming at `from` would find it. */
|
|
2398
|
+
function nextRegistryDispatch(src, from) {
|
|
2399
|
+
let at = from;
|
|
2400
|
+
if (at > 0 && at < src.length && IDENT_RUN_CHAR.test(src[at - 1]) && IDENT_RUN_CHAR.test(src[at])) {
|
|
2401
|
+
for (; at < src.length && IDENT_RUN_CHAR.test(src[at]); at++) {
|
|
2402
|
+
REGISTRY_DISPATCH_AT.lastIndex = at;
|
|
2403
|
+
const m = REGISTRY_DISPATCH_AT.exec(src);
|
|
2404
|
+
if (m)
|
|
2405
|
+
return m;
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
REGISTRY_DISPATCH_RE.lastIndex = at;
|
|
2409
|
+
return REGISTRY_DISPATCH_RE.exec(src);
|
|
2410
|
+
}
|
|
2315
2411
|
/** From the index of an opening `{`, return the brace-balanced body up to its matching `}`. */
|
|
2316
2412
|
function braceBody(src, openIdx) {
|
|
2317
2413
|
let depth = 0;
|
|
@@ -2400,13 +2496,12 @@ async function objectRegistryEdges(ctx, onYield) {
|
|
|
2400
2496
|
const safe = (0, strip_comments_1.stripCommentsForRegex)(content, /\.(?:jsx?|mjs|cjs)$/.test(file) ? 'javascript' : 'typescript');
|
|
2401
2497
|
// 1. Dispatch sites: `(new )?<ref>[<ident-key>]` followed by a call or a chained method.
|
|
2402
2498
|
// A quoted-string key (`['save']`) does NOT match — that's a static access, not dispatch.
|
|
2403
|
-
|
|
2499
|
+
const lineOf = (0, synth_utils_1.makeLineAt)(safe, 1);
|
|
2404
2500
|
const dispatches = [];
|
|
2405
|
-
let dm;
|
|
2406
|
-
while ((dm = REGISTRY_DISPATCH_RE.exec(safe))) {
|
|
2501
|
+
for (let dm = nextRegistryDispatch(safe, 0); dm; dm = nextRegistryDispatch(safe, dm.index + dm[0].length)) {
|
|
2407
2502
|
const win = safe.slice(dm.index, dm.index + 160);
|
|
2408
2503
|
const cm = /\]\s*\([^)]*\)\s*\.\s*([A-Za-z_$][\w$]*)/.exec(win) || /\]\s*\.\s*([A-Za-z_$][\w$]*)/.exec(win);
|
|
2409
|
-
dispatches.push({ ref: dm[1], line:
|
|
2504
|
+
dispatches.push({ ref: dm[1], line: lineOf(dm.index), chained: cm ? cm[1] : null });
|
|
2410
2505
|
}
|
|
2411
2506
|
if (!dispatches.length)
|
|
2412
2507
|
continue;
|
|
@@ -2427,7 +2522,7 @@ async function objectRegistryEdges(ctx, onYield) {
|
|
|
2427
2522
|
continue;
|
|
2428
2523
|
const names = registryEntryNames(body); // depth-0 `key: Identifier` entries only
|
|
2429
2524
|
if (names.length >= REGISTRY_MIN_ENTRIES) {
|
|
2430
|
-
registries.set(lhs, { names, line:
|
|
2525
|
+
registries.set(lhs, { names, line: lineOf(am.index) });
|
|
2431
2526
|
}
|
|
2432
2527
|
}
|
|
2433
2528
|
if (!registries.size)
|
|
@@ -2438,7 +2533,7 @@ async function objectRegistryEdges(ctx, onYield) {
|
|
|
2438
2533
|
const reg = registries.get(norm(d.ref));
|
|
2439
2534
|
if (!reg)
|
|
2440
2535
|
continue;
|
|
2441
|
-
const disp = enclosingFn(nodesInFile, d.line);
|
|
2536
|
+
const disp = (0, synth_utils_1.enclosingFn)(nodesInFile, d.line);
|
|
2442
2537
|
if (!disp)
|
|
2443
2538
|
continue;
|
|
2444
2539
|
let added = 0;
|
|
@@ -2597,7 +2692,7 @@ async function piniaStoreEdges(ctx, onYield) {
|
|
|
2597
2692
|
continue;
|
|
2598
2693
|
const method = cm[2];
|
|
2599
2694
|
const line = safe.slice(0, cm.index).split('\n').length;
|
|
2600
|
-
const disp = enclosingFn(nodesInFile, line) ?? fallbackDispatcher;
|
|
2695
|
+
const disp = (0, synth_utils_1.enclosingFn)(nodesInFile, line) ?? fallbackDispatcher;
|
|
2601
2696
|
if (!disp)
|
|
2602
2697
|
continue;
|
|
2603
2698
|
const target = ctx
|
|
@@ -2695,7 +2790,7 @@ async function vuexDispatchEdges(ctx, onYield) {
|
|
|
2695
2790
|
while ((m = VUEX_DISPATCH_RE.exec(safe)) && added < VUEX_FANOUT_CAP) {
|
|
2696
2791
|
const key = m[1];
|
|
2697
2792
|
const line = safe.slice(0, m.index).split('\n').length;
|
|
2698
|
-
const disp = enclosingFn(nodesInFile, line) ?? fallback;
|
|
2793
|
+
const disp = (0, synth_utils_1.enclosingFn)(nodesInFile, line) ?? fallback;
|
|
2699
2794
|
if (!disp)
|
|
2700
2795
|
continue;
|
|
2701
2796
|
const target = resolve(key, file);
|
|
@@ -2800,7 +2895,7 @@ async function celeryDispatchEdges(ctx, onYield) {
|
|
|
2800
2895
|
while ((m = CELERY_DISPATCH_RE.exec(safe)) && added < CELERY_FANOUT_CAP) {
|
|
2801
2896
|
const name = m[1];
|
|
2802
2897
|
const line = safe.slice(0, m.index).split('\n').length;
|
|
2803
|
-
const disp = enclosingFn(nodesInFile, line);
|
|
2898
|
+
const disp = (0, synth_utils_1.enclosingFn)(nodesInFile, line);
|
|
2804
2899
|
if (!disp)
|
|
2805
2900
|
continue; // module-level dispatch — no source symbol to attribute
|
|
2806
2901
|
const target = resolve(name, file);
|
|
@@ -2942,7 +3037,7 @@ async function springEventEdges(ctx, onYield) {
|
|
|
2942
3037
|
if (!targets || !targets.length)
|
|
2943
3038
|
continue;
|
|
2944
3039
|
const line = safe.slice(0, m.index).split('\n').length;
|
|
2945
|
-
const disp = enclosingFn(nodesInFile, line);
|
|
3040
|
+
const disp = (0, synth_utils_1.enclosingFn)(nodesInFile, line);
|
|
2946
3041
|
if (!disp)
|
|
2947
3042
|
continue;
|
|
2948
3043
|
for (const target of targets) {
|
|
@@ -3070,7 +3165,7 @@ async function mediatrDispatchEdges(ctx, onYield) {
|
|
|
3070
3165
|
if (!MEDIATR_RECEIVER_RE.test(m[1]))
|
|
3071
3166
|
continue; // not a mediator (MessagingCenter, HttpClient, …)
|
|
3072
3167
|
const line = safe.slice(0, m.index).split('\n').length;
|
|
3073
|
-
const disp = enclosingFn(nodesInFile, line);
|
|
3168
|
+
const disp = (0, synth_utils_1.enclosingFn)(nodesInFile, line);
|
|
3074
3169
|
if (!disp)
|
|
3075
3170
|
continue;
|
|
3076
3171
|
const type = resolveMediatrArgType(m[2], safeLines, disp.startLine, line);
|
|
@@ -3170,7 +3265,7 @@ async function sidekiqDispatchEdges(ctx, onYield) {
|
|
|
3170
3265
|
let added = 0;
|
|
3171
3266
|
while ((m = SIDEKIQ_DISPATCH_RE.exec(safe)) && added < SIDEKIQ_FANOUT_CAP) {
|
|
3172
3267
|
const line = safe.slice(0, m.index).split('\n').length;
|
|
3173
|
-
const disp = enclosingFn(nodesInFile, line);
|
|
3268
|
+
const disp = (0, synth_utils_1.enclosingFn)(nodesInFile, line);
|
|
3174
3269
|
if (!disp)
|
|
3175
3270
|
continue;
|
|
3176
3271
|
const target = resolve(m[1]);
|
|
@@ -3230,6 +3325,10 @@ const ERLANG_BEHAVIOUR_FANOUT_CAP = 24;
|
|
|
3230
3325
|
*/
|
|
3231
3326
|
function erlangArityAt(src, openIdx) {
|
|
3232
3327
|
let depth = 1;
|
|
3328
|
+
// `<<1,2,3>>` binary literals: commas inside are element separators, not
|
|
3329
|
+
// argument separators. Tracked separately from bracket depth because the
|
|
3330
|
+
// single-char `<`/`>` comparison operators must stay inert (#1358).
|
|
3331
|
+
let binDepth = 0;
|
|
3233
3332
|
let commas = 0;
|
|
3234
3333
|
let sawArg = false;
|
|
3235
3334
|
const limit = Math.min(src.length, openIdx + 4000);
|
|
@@ -3252,6 +3351,17 @@ function erlangArityAt(src, openIdx) {
|
|
|
3252
3351
|
sawArg = true;
|
|
3253
3352
|
continue;
|
|
3254
3353
|
}
|
|
3354
|
+
if (ch === '<' && src[i + 1] === '<') {
|
|
3355
|
+
binDepth++;
|
|
3356
|
+
i++;
|
|
3357
|
+
sawArg = true;
|
|
3358
|
+
continue;
|
|
3359
|
+
}
|
|
3360
|
+
if (ch === '>' && src[i + 1] === '>' && binDepth > 0) {
|
|
3361
|
+
binDepth--;
|
|
3362
|
+
i++;
|
|
3363
|
+
continue;
|
|
3364
|
+
}
|
|
3255
3365
|
if (ch === '(' || ch === '[' || ch === '{') {
|
|
3256
3366
|
depth++;
|
|
3257
3367
|
sawArg = true;
|
|
@@ -3263,7 +3373,7 @@ function erlangArityAt(src, openIdx) {
|
|
|
3263
3373
|
return sawArg ? commas + 1 : 0;
|
|
3264
3374
|
continue;
|
|
3265
3375
|
}
|
|
3266
|
-
if (ch === ',' && depth === 1) {
|
|
3376
|
+
if (ch === ',' && depth === 1 && binDepth === 0) {
|
|
3267
3377
|
commas++;
|
|
3268
3378
|
continue;
|
|
3269
3379
|
}
|
|
@@ -3347,13 +3457,11 @@ async function nixOptionPathEdges(queries, onYield) {
|
|
|
3347
3457
|
const byFile = new Map();
|
|
3348
3458
|
let scanned = 0;
|
|
3349
3459
|
for (const kind of ['variable', 'function']) {
|
|
3350
|
-
for (const node of queries.
|
|
3460
|
+
for (const node of queries.iterateNodesByKindIn(kind, ['nix'])) {
|
|
3351
3461
|
if ((++scanned255 & 63) === 0)
|
|
3352
3462
|
await onYield();
|
|
3353
3463
|
if ((++scanned & 0x3fff) === 0 && onYield)
|
|
3354
3464
|
await onYield();
|
|
3355
|
-
if (node.language !== 'nix')
|
|
3356
|
-
continue;
|
|
3357
3465
|
const segs = nixLeadingPlainSegments(node.name);
|
|
3358
3466
|
if (segs.length === 0)
|
|
3359
3467
|
continue;
|
|
@@ -3378,7 +3486,7 @@ async function nixOptionPathEdges(queries, onYield) {
|
|
|
3378
3486
|
// own namespace (`attrsOf (submodule { options = ...; })`) — its internals
|
|
3379
3487
|
// are not globally addressable, so the sentinel blocks registration below it
|
|
3380
3488
|
// while still excluding the region from write candidates.
|
|
3381
|
-
const SUBMODULE = '
|
|
3489
|
+
const SUBMODULE = '\u0000submodule';
|
|
3382
3490
|
const decls = new Map();
|
|
3383
3491
|
const writes = [];
|
|
3384
3492
|
const register = (path, rec) => {
|
|
@@ -3468,11 +3576,10 @@ async function erlangBehaviourDispatchEdges(queries, ctx, onYield) {
|
|
|
3468
3576
|
// Cheap language gate: no Erlang modules → no cost beyond one streamed
|
|
3469
3577
|
// kind scan (never a materialized array of every namespace — #1212).
|
|
3470
3578
|
const erlangModules = [];
|
|
3471
|
-
for (const n of queries.
|
|
3579
|
+
for (const n of queries.iterateNodesByKindIn('namespace', ['erlang'])) {
|
|
3472
3580
|
if ((++scanned255 & 63) === 0)
|
|
3473
3581
|
await onYield();
|
|
3474
|
-
|
|
3475
|
-
erlangModules.push(n);
|
|
3582
|
+
erlangModules.push(n);
|
|
3476
3583
|
}
|
|
3477
3584
|
if (erlangModules.length === 0)
|
|
3478
3585
|
return [];
|
|
@@ -3519,12 +3626,18 @@ async function erlangBehaviourDispatchEdges(queries, ctx, onYield) {
|
|
|
3519
3626
|
}
|
|
3520
3627
|
if (declaringBehaviours.size === 0)
|
|
3521
3628
|
return [];
|
|
3522
|
-
// Implementer target lookup, lazy per (behaviour, fn): implementers
|
|
3523
|
-
// from the `implements` edges extraction resolved, and the target is
|
|
3524
|
-
// implementer module's own exported `fn`
|
|
3629
|
+
// Implementer target lookup, lazy per (behaviour, fn, arity): implementers
|
|
3630
|
+
// come from the `implements` edges extraction resolved, and the target is
|
|
3631
|
+
// the implementer module's own exported `fn` node OF THE SITE'S ARITY —
|
|
3632
|
+
// function qualifiedNames carry arity (`mod::fn/2`, #1610), so the arity the
|
|
3633
|
+
// dispatch site used selects among same-named definitions.
|
|
3525
3634
|
const targetCache = new Map();
|
|
3526
|
-
const
|
|
3527
|
-
const
|
|
3635
|
+
const qnArity = (qn) => {
|
|
3636
|
+
const m = /\/(\d{1,3})$/.exec(qn);
|
|
3637
|
+
return m ? Number(m[1]) : -1;
|
|
3638
|
+
};
|
|
3639
|
+
const targetsOf = (behaviour, fn, arity) => {
|
|
3640
|
+
const cacheKey = `${behaviour.id}#${fn}/${arity}`;
|
|
3528
3641
|
let targets = targetCache.get(cacheKey);
|
|
3529
3642
|
if (targets)
|
|
3530
3643
|
return targets;
|
|
@@ -3535,7 +3648,10 @@ async function erlangBehaviourDispatchEdges(queries, ctx, onYield) {
|
|
|
3535
3648
|
continue;
|
|
3536
3649
|
const fnNode = ctx
|
|
3537
3650
|
.getNodesInFile(impl.filePath)
|
|
3538
|
-
.find((n) => n.kind === 'function' &&
|
|
3651
|
+
.find((n) => n.kind === 'function' &&
|
|
3652
|
+
n.name === fn &&
|
|
3653
|
+
qnArity(n.qualifiedName) === arity &&
|
|
3654
|
+
n.isExported !== false);
|
|
3539
3655
|
if (fnNode)
|
|
3540
3656
|
targets.push(fnNode);
|
|
3541
3657
|
}
|
|
@@ -3570,11 +3686,11 @@ async function erlangBehaviourDispatchEdges(queries, ctx, onYield) {
|
|
|
3570
3686
|
if (!behaviours || behaviours.length !== 1)
|
|
3571
3687
|
continue; // unknown or ambiguous
|
|
3572
3688
|
const behaviour = behaviours[0];
|
|
3573
|
-
const targets = targetsOf(behaviour, fn);
|
|
3689
|
+
const targets = targetsOf(behaviour, fn, arity);
|
|
3574
3690
|
if (targets.length === 0 || targets.length > ERLANG_BEHAVIOUR_FANOUT_CAP)
|
|
3575
3691
|
continue;
|
|
3576
3692
|
const line = safe.slice(0, m.index).split('\n').length;
|
|
3577
|
-
const disp = enclosingFn(nodesInFile, line);
|
|
3693
|
+
const disp = (0, synth_utils_1.enclosingFn)(nodesInFile, line);
|
|
3578
3694
|
if (!disp)
|
|
3579
3695
|
continue;
|
|
3580
3696
|
for (const target of targets) {
|
|
@@ -3729,7 +3845,7 @@ async function laravelEventEdges(ctx, onYield) {
|
|
|
3729
3845
|
if (!targets)
|
|
3730
3846
|
continue;
|
|
3731
3847
|
const line = safe.slice(0, m.index).split('\n').length;
|
|
3732
|
-
const disp = enclosingFn(nodesInFile, line);
|
|
3848
|
+
const disp = (0, synth_utils_1.enclosingFn)(nodesInFile, line);
|
|
3733
3849
|
if (!disp)
|
|
3734
3850
|
continue;
|
|
3735
3851
|
for (const target of targets.values()) {
|
|
@@ -3753,27 +3869,43 @@ async function laravelEventEdges(ctx, onYield) {
|
|
|
3753
3869
|
}
|
|
3754
3870
|
return edges;
|
|
3755
3871
|
}
|
|
3756
|
-
/**
|
|
3757
|
-
* Synthesize dispatcher→callback edges (field observers + EventEmitters +
|
|
3758
|
-
* React re-render + JSX children + Vue templates + SvelteKit load + RN event
|
|
3759
|
-
* channel + Fabric native-impl + MyBatis Java↔XML + Gin middleware chain +
|
|
3760
|
-
* Redux-thunk dispatch chain + object-literal registry dispatch + RTK Query
|
|
3761
|
-
* generated-hook → endpoint + Pinia useStore().action() + Vuex string dispatch +
|
|
3762
|
-
* Celery task .delay()/.apply_async() → task body + Spring publishEvent → @EventListener +
|
|
3763
|
-
* MediatR Send/Publish → IRequestHandler/INotificationHandler +
|
|
3764
|
-
* Sidekiq Worker.perform_async → #perform + Laravel event(new X) → listener handle).
|
|
3765
|
-
* Returns the count added. Never throws into indexing — callers wrap in try/catch.
|
|
3766
|
-
*/
|
|
3767
|
-
/**
|
|
3768
|
-
* Number of progress steps synthesizeCallbackEdges reports: one per `__mark()`
|
|
3769
|
-
* call (every synthesis pass, plus the dedupe-merge and edge-insert steps).
|
|
3770
|
-
* Cosmetic only — drift just makes the progress bar end early or jump — and a
|
|
3771
|
-
* test pins it to the actual step count (registry passes + the fixed
|
|
3772
|
-
* pre/post marks) so adding a pass without bumping this fails loudly instead
|
|
3773
|
-
* of silently skewing the bar.
|
|
3774
|
-
*/
|
|
3775
|
-
const JS_FAMILY = ['typescript', 'javascript', 'tsx', 'jsx'];
|
|
3776
3872
|
const ALWAYS = () => true;
|
|
3873
|
+
/** Conservative input gates for SYNTH_PASSES; keep these in sync when adding a pass. */
|
|
3874
|
+
function hasSynthesisPattern(filePath, content) {
|
|
3875
|
+
// These passes consume declarations/layouts as well as dispatch sites. A
|
|
3876
|
+
// header or markup edit can change a channel whose endpoints live elsewhere.
|
|
3877
|
+
if (/\.(?:vue|svelte|dfm|fmx|nix|xml)$/.test(filePath))
|
|
3878
|
+
return true;
|
|
3879
|
+
if (/\.(?:c|h|cc|cpp|cxx|hpp|hh|hxx|cppm|ipp|inl|tcc|def|inc|tbl)$/i.test(filePath) &&
|
|
3880
|
+
/\b(?:struct|union|typedef|virtual|override)\b|#\s*(?:include|define|if)|=|->|\[/.test(content))
|
|
3881
|
+
return true;
|
|
3882
|
+
if (/\b(?:class|interface|protocol|trait|impl|extends|implements|expect|actual)\b/.test(content))
|
|
3883
|
+
return true;
|
|
3884
|
+
if (/\.go$/.test(filePath) && /\b(?:struct|interface)\b|\bfunc\s*\(/.test(content))
|
|
3885
|
+
return true;
|
|
3886
|
+
if ((0, tier_synthesizer_1.hasCrossTierPattern)(content) || (0, tier_synthesizer_1.hasTestRequestPattern)(filePath, content))
|
|
3887
|
+
return true;
|
|
3888
|
+
if (/\b(?:render|build|setState|defineStore|createStore|createApi|Store|href|sendEvent|sendEventWithName)\b|<\/|\/>/.test(content))
|
|
3889
|
+
return true;
|
|
3890
|
+
if (/\.(?:forEach|append|add|push|insert|fire|dispatchEvent|addListener|Use|GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD|Any|Handle)\s*\(/.test(content))
|
|
3891
|
+
return true;
|
|
3892
|
+
if (/[\w$]\s*\[\s*[A-Za-z_$]/.test(content) || /\b(?:dispatch|commit)\s*\(/.test(content))
|
|
3893
|
+
return true;
|
|
3894
|
+
const patterns = [THUNK_DECL_RE, CELERY_TASK_DECORATOR_RE, CELERY_DISPATCH_RE,
|
|
3895
|
+
SPRING_LISTENER_ANNO_RE, SPRING_APP_LISTENER_RE, SPRING_PUBLISH_RE,
|
|
3896
|
+
MEDIATR_HANDLER_BASE_RE, MEDIATR_DISPATCH_RE, SIDEKIQ_WORKER_RE, SIDEKIQ_DISPATCH_RE,
|
|
3897
|
+
ERLANG_CALLBACK_DECL_RE, ERLANG_DISPATCH_RE, LARAVEL_DISPATCH_RE, ARKUI_EMITTER_CALL_RE,
|
|
3898
|
+
ARKUI_ROUTER_RE];
|
|
3899
|
+
for (const re of patterns) {
|
|
3900
|
+
re.lastIndex = 0;
|
|
3901
|
+
const matches = re.test(content);
|
|
3902
|
+
re.lastIndex = 0;
|
|
3903
|
+
if (matches)
|
|
3904
|
+
return true;
|
|
3905
|
+
}
|
|
3906
|
+
// Field-backed observers use method-name gates rather than fixed call names.
|
|
3907
|
+
return (content.match(/[A-Za-z_$][\w$]*/g) ?? []).some((name) => REGISTRAR_NAME.test(name) || DISPATCHER_NAME.test(name));
|
|
3908
|
+
}
|
|
3777
3909
|
/**
|
|
3778
3910
|
* The independent passes, in MERGE ORDER — the first-seen dedup in
|
|
3779
3911
|
* synthesizeCallbackEdges follows this array, so reordering entries changes
|
|
@@ -3784,9 +3916,18 @@ const ALWAYS = () => true;
|
|
|
3784
3916
|
exports.SYNTH_PASSES = [
|
|
3785
3917
|
{ name: 'fieldEdges', gate: ALWAYS, run: (q, c, y) => fieldChannelEdges(q, c, y) },
|
|
3786
3918
|
{ name: 'closureCollEdges', gate: ALWAYS, run: (q, c, y) => closureCollectionEdges(q, c, y) },
|
|
3919
|
+
// Cross-tier channels — a client's `fetch('/api/x')` onto its own route,
|
|
3920
|
+
// a queue job onto its consumer, a bus / socket event onto its handler.
|
|
3921
|
+
// Before the in-process emitter pass: the same (source, target) pair
|
|
3922
|
+
// keeps the more specific edge — the one that says which tier it crosses.
|
|
3923
|
+
{ name: 'tierEdges', gate: (has) => has(...JS_FAMILY), run: (_q, c, y) => (0, tier_synthesizer_1.crossTierEdges)(c, y) },
|
|
3924
|
+
// A Spring / Laravel test's request (`mockMvc.perform(post("/x"))`,
|
|
3925
|
+
// `$this->postJson('api/x')`) onto the route it reaches, so the handler
|
|
3926
|
+
// counts as tested.
|
|
3927
|
+
{ name: 'testRequestEdges', gate: (has) => has('java', 'kotlin', 'php'), run: (_q, c, y) => (0, tier_synthesizer_1.testRequestEdges)(c, y) },
|
|
3787
3928
|
{ name: 'emitterEdges', gate: ALWAYS, run: (_q, c, y) => eventEmitterEdges(c, y) },
|
|
3788
3929
|
{ name: 'renderEdges', gate: ALWAYS, run: (q, c, y) => reactRenderEdges(q, c, y) },
|
|
3789
|
-
{ name: 'jsxEdges', gate:
|
|
3930
|
+
{ name: 'jsxEdges', gate: (has) => has(...JS_FAMILY), run: (_q, c, y) => reactJsxChildEdges(c, y) },
|
|
3790
3931
|
{ name: 'vueEdges', gate: (has) => has('vue'), run: (_q, c, y) => vueTemplateEdges(c, y) },
|
|
3791
3932
|
{ name: 'svelteKitEdges', gate: (has) => has('svelte'), run: (_q, c, y) => svelteKitLoadEdges(c, y) },
|
|
3792
3933
|
{ name: 'pascalEdges', gate: ALWAYS, run: (_q, c, y) => pascalFormEdges(c, y) },
|
|
@@ -3840,8 +3981,31 @@ exports.SYNTH_PASSES = [
|
|
|
3840
3981
|
run: (q, c, y, sub) => (0, c_fnptr_synthesizer_1.cFnPointerDispatchEdges)(q, c, y, sub),
|
|
3841
3982
|
},
|
|
3842
3983
|
{ name: 'goframeEdges', gate: (has) => has('go'), run: (_q, c, y) => (0, goframe_synthesizer_1.goframeRouteEdges)(c, y) },
|
|
3984
|
+
// `router.push(await helper())` — the helper's return literals are the screens.
|
|
3985
|
+
{ name: 'expoRouterReturnEdges', gate: (has) => has(...JS_FAMILY), run: (_q, c, y) => (0, expo_router_synthesizer_1.expoRouterReturnEdges)(c, y) },
|
|
3986
|
+
// `<Link href="/x">` / an internal `<a href>` — markup, not a call; the component navigates.
|
|
3987
|
+
{ name: 'nextLinkEdges', gate: (has) => has(...JS_FAMILY), run: (_q, c, y) => (0, next_router_synthesizer_1.nextLinkEdges)(c, y) },
|
|
3988
|
+
{ name: 'reactRouterLinkEdges', gate: (has) => has(...JS_FAMILY), run: (_q, c, y) => (0, react_router_synthesizer_1.reactRouterLinkEdges)(c, y) },
|
|
3989
|
+
{ name: 'tanstackLinkEdges', gate: (has) => has(...JS_FAMILY), run: (_q, c, y) => (0, tanstack_router_synthesizer_1.tanstackLinkEdges)(c, y) },
|
|
3990
|
+
{ name: 'vueRouterLinkEdges', gate: (has) => has('vue', ...JS_FAMILY), run: (_q, c, y) => (0, vue_router_synthesizer_1.vueRouterLinkEdges)(c, y) },
|
|
3991
|
+
{ name: 'svelteKitPageEdges', gate: (has) => has('svelte'), run: (_q, c, y) => (0, sveltekit_synthesizer_1.svelteKitPageComponentEdges)(c, y) },
|
|
3992
|
+
{ name: 'svelteKitLinkEdges', gate: (has) => has('svelte'), run: (_q, c, y) => (0, sveltekit_synthesizer_1.svelteKitLinkEdges)(c, y) },
|
|
3843
3993
|
{ name: 'nixOptionEdges', gate: (has) => has('nix'), run: (q, _c, y) => nixOptionPathEdges(q, y) },
|
|
3844
3994
|
];
|
|
3995
|
+
/**
|
|
3996
|
+
* Rough relative cost of the passes that run longest on large repos. Only
|
|
3997
|
+
* the pooled dispatch ORDER reads it — heaviest first, so the longest passes
|
|
3998
|
+
* start before the short ones fill the workers; unlisted passes keep registry
|
|
3999
|
+
* order after these. A wrong hint costs wall time, never edges.
|
|
4000
|
+
*/
|
|
4001
|
+
const SYNTH_PASS_COST_HINT = {
|
|
4002
|
+
cFnPtrEdges: 100, registryEdges: 60, tierEdges: 55, jsxEdges: 25, rnEventEdgesList: 24,
|
|
4003
|
+
ifaceEdges: 18, flutterEdges: 16, cppEdges: 15, emitterEdges: 12, fieldEdges: 11,
|
|
4004
|
+
mybatisEdges: 10, vuexEdges: 8, closureCollEdges: 6, piniaEdges: 5, renderEdges: 4,
|
|
4005
|
+
};
|
|
4006
|
+
function synthPassCostHint(name) {
|
|
4007
|
+
return SYNTH_PASS_COST_HINT[name] ?? 0;
|
|
4008
|
+
}
|
|
3845
4009
|
/** Fixed non-registry steps: goMethodContains, goImplements, dedupe-merge, insertMergedEdges. */
|
|
3846
4010
|
const FIXED_SYNTH_STEPS = 4;
|
|
3847
4011
|
exports.SYNTH_PROGRESS_STEPS = exports.SYNTH_PASSES.length + FIXED_SYNTH_STEPS;
|
|
@@ -3853,7 +4017,10 @@ pool,
|
|
|
3853
4017
|
// WAL-valve writer backstop (WalCheckpointValve.backpressure), called at
|
|
3854
4018
|
// pool-idle points in the edge-insert loops below — the passes themselves
|
|
3855
4019
|
// only read; every write in this function happens with the pool idle.
|
|
3856
|
-
backpressure
|
|
4020
|
+
backpressure,
|
|
4021
|
+
// Main-thread work to run while the pool computes the passes (the main
|
|
4022
|
+
// thread otherwise only waits there) — e.g. building a deferred index.
|
|
4023
|
+
whilePoolBusy) {
|
|
3857
4024
|
// Each sub-pass below is a whole-graph scan, and there are ~30 of them, all
|
|
3858
4025
|
// running synchronously on the indexer's main thread. Their AGGREGATE can run
|
|
3859
4026
|
// for well over a minute on a large repo — long enough for the #850 liveness
|
|
@@ -3979,8 +4146,23 @@ backpressure) {
|
|
|
3979
4146
|
// synthesized edges; the index still completes.
|
|
3980
4147
|
const MAIN_RETRY_MAX_NODES = 1_500_000;
|
|
3981
4148
|
const graphNodes = queries.getNodeAndEdgeCount().nodes;
|
|
4149
|
+
// Files whose text could feed a pass (inputs that produce NO edges included,
|
|
4150
|
+
// e.g. an over-cap channel: deleting one may make the full pass viable). It
|
|
4151
|
+
// depends only on the files, so with a pool the main thread reads them while
|
|
4152
|
+
// the workers run the passes instead of after.
|
|
4153
|
+
const collectInputs = async () => {
|
|
4154
|
+
const found = [];
|
|
4155
|
+
for (const file of ctx.getAllFiles()) {
|
|
4156
|
+
const content = ctx.readFile(file);
|
|
4157
|
+
if (content !== null && hasSynthesisPattern(file, content))
|
|
4158
|
+
found.push(file);
|
|
4159
|
+
await yieldToLoop();
|
|
4160
|
+
}
|
|
4161
|
+
return found;
|
|
4162
|
+
};
|
|
4163
|
+
let inputs = null;
|
|
3982
4164
|
if (pool && gatedIn.length > 1) {
|
|
3983
|
-
|
|
4165
|
+
const runPooled = async (i) => {
|
|
3984
4166
|
const pass = exports.SYNTH_PASSES[i];
|
|
3985
4167
|
try {
|
|
3986
4168
|
const out = await pool.runSynthPass(pass.name);
|
|
@@ -3999,7 +4181,25 @@ backpressure) {
|
|
|
3999
4181
|
// mismatch): retry this one pass on the main thread.
|
|
4000
4182
|
await runPassOnMain(i);
|
|
4001
4183
|
}
|
|
4002
|
-
}
|
|
4184
|
+
};
|
|
4185
|
+
// One pass per worker at a time, heaviest first. Handing every pass out
|
|
4186
|
+
// at once split them by count, and a worker interleaves what it holds, so
|
|
4187
|
+
// a heavy pass finished only with its worker's whole share: on vscode the
|
|
4188
|
+
// 6s registry pass ended ~16s in. Pulling keeps workers busy until the
|
|
4189
|
+
// queue drains. Edges merge by registry index below, so order is free.
|
|
4190
|
+
const lanes = Math.min(pool.size ?? gatedIn.length, gatedIn.length);
|
|
4191
|
+
const queue = [...gatedIn].sort((a, b) => synthPassCostHint(exports.SYNTH_PASSES[b].name) - synthPassCostHint(exports.SYNTH_PASSES[a].name) || a - b);
|
|
4192
|
+
const lane = async () => {
|
|
4193
|
+
for (let i = queue.shift(); i !== undefined; i = queue.shift())
|
|
4194
|
+
await runPooled(i);
|
|
4195
|
+
};
|
|
4196
|
+
const fanOut = Promise.all(Array.from({ length: lanes }, lane));
|
|
4197
|
+
// Observed now, awaited below: a rejection while the scan runs must not
|
|
4198
|
+
// surface as an unhandled one.
|
|
4199
|
+
fanOut.catch(() => undefined);
|
|
4200
|
+
whilePoolBusy?.();
|
|
4201
|
+
inputs = await collectInputs();
|
|
4202
|
+
await fanOut;
|
|
4003
4203
|
}
|
|
4004
4204
|
else {
|
|
4005
4205
|
for (const i of gatedIn) {
|
|
@@ -4024,6 +4224,7 @@ backpressure) {
|
|
|
4024
4224
|
await yieldToLoop();
|
|
4025
4225
|
await foldIfOver();
|
|
4026
4226
|
}
|
|
4227
|
+
queries.replaceSynthesisInputs(inputs ?? await collectInputs());
|
|
4027
4228
|
__mark('insertMergedEdges');
|
|
4028
4229
|
return merged.length + goImpl.length + goMethodContains.length;
|
|
4029
4230
|
}
|