@optave/codegraph 3.12.0 → 3.15.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.md +83 -46
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +38 -40
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/rules/b2.d.ts +7 -0
- package/dist/ast-analysis/rules/b2.d.ts.map +1 -0
- package/dist/ast-analysis/rules/b2.js +240 -0
- package/dist/ast-analysis/rules/b2.js.map +1 -0
- package/dist/ast-analysis/rules/b3.d.ts +6 -0
- package/dist/ast-analysis/rules/b3.d.ts.map +1 -0
- package/dist/ast-analysis/rules/b3.js +105 -0
- package/dist/ast-analysis/rules/b3.js.map +1 -0
- package/dist/ast-analysis/rules/b4.d.ts +9 -0
- package/dist/ast-analysis/rules/b4.d.ts.map +1 -0
- package/dist/ast-analysis/rules/b4.js +361 -0
- package/dist/ast-analysis/rules/b4.js.map +1 -0
- package/dist/ast-analysis/rules/b5.d.ts +4 -0
- package/dist/ast-analysis/rules/b5.d.ts.map +1 -0
- package/dist/ast-analysis/rules/b5.js +52 -0
- package/dist/ast-analysis/rules/b5.js.map +1 -0
- package/dist/ast-analysis/rules/c.d.ts +4 -0
- package/dist/ast-analysis/rules/c.d.ts.map +1 -0
- package/dist/ast-analysis/rules/c.js +143 -0
- package/dist/ast-analysis/rules/c.js.map +1 -0
- package/dist/ast-analysis/rules/index.d.ts.map +1 -1
- package/dist/ast-analysis/rules/index.js +34 -0
- package/dist/ast-analysis/rules/index.js.map +1 -1
- package/dist/ast-analysis/rules/javascript.d.ts.map +1 -1
- package/dist/ast-analysis/rules/javascript.js +3 -0
- package/dist/ast-analysis/rules/javascript.js.map +1 -1
- package/dist/ast-analysis/shared.d.ts.map +1 -1
- package/dist/ast-analysis/shared.js +2 -0
- package/dist/ast-analysis/shared.js.map +1 -1
- package/dist/ast-analysis/visitor-utils.d.ts +1 -0
- package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
- package/dist/ast-analysis/visitor-utils.js +5 -0
- package/dist/ast-analysis/visitor-utils.js.map +1 -1
- package/dist/ast-analysis/visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitor.js +60 -47
- package/dist/ast-analysis/visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/cfg-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/cfg-visitor.js +126 -76
- package/dist/ast-analysis/visitors/cfg-visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.js +27 -15
- package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/dataflow-visitor.js +54 -21
- package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +2 -1
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/batch.d.ts.map +1 -1
- package/dist/cli/commands/batch.js +1 -0
- package/dist/cli/commands/batch.js.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +6 -1
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/config.d.ts +3 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +275 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/roles.d.ts.map +1 -1
- package/dist/cli/commands/roles.js +6 -1
- package/dist/cli/commands/roles.js.map +1 -1
- package/dist/cli/commands/triage.js +1 -1
- package/dist/cli/commands/triage.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +10 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/shared/options.d.ts +2 -1
- package/dist/cli/shared/options.d.ts.map +1 -1
- package/dist/cli/shared/options.js +11 -1
- package/dist/cli/shared/options.js.map +1 -1
- package/dist/cli/types.d.ts +2 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/db/better-sqlite3.d.ts +2 -1
- package/dist/db/better-sqlite3.d.ts.map +1 -1
- package/dist/db/better-sqlite3.js.map +1 -1
- package/dist/db/connection.d.ts +7 -1
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +20 -5
- package/dist/db/connection.js.map +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +69 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/repository/build-stmts.d.ts.map +1 -1
- package/dist/db/repository/build-stmts.js +18 -0
- package/dist/db/repository/build-stmts.js.map +1 -1
- package/dist/db/repository/dataflow.d.ts +5 -0
- package/dist/db/repository/dataflow.d.ts.map +1 -1
- package/dist/db/repository/dataflow.js +14 -0
- package/dist/db/repository/dataflow.js.map +1 -1
- package/dist/db/repository/index.d.ts +1 -1
- package/dist/db/repository/index.d.ts.map +1 -1
- package/dist/db/repository/index.js +1 -1
- package/dist/db/repository/index.js.map +1 -1
- package/dist/db/repository/native-repository.d.ts.map +1 -1
- package/dist/db/repository/native-repository.js +47 -34
- package/dist/db/repository/native-repository.js.map +1 -1
- package/dist/domain/analysis/context.d.ts +2 -2
- package/dist/domain/analysis/dependencies.d.ts +2 -2
- package/dist/domain/analysis/diff-impact.d.ts +2 -2
- package/dist/domain/analysis/fn-impact.d.ts +3 -1
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
- package/dist/domain/analysis/fn-impact.js +4 -0
- package/dist/domain/analysis/fn-impact.js.map +1 -1
- package/dist/domain/analysis/implementations.d.ts +2 -2
- package/dist/domain/analysis/module-map.d.ts.map +1 -1
- package/dist/domain/analysis/module-map.js +32 -5
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/analysis/roles.d.ts +7 -1
- package/dist/domain/analysis/roles.d.ts.map +1 -1
- package/dist/domain/analysis/roles.js +16 -0
- package/dist/domain/analysis/roles.js.map +1 -1
- package/dist/domain/analysis/symbol-lookup.d.ts +4 -4
- package/dist/domain/graph/builder/call-resolver.d.ts +29 -13
- package/dist/domain/graph/builder/call-resolver.d.ts.map +1 -1
- package/dist/domain/graph/builder/call-resolver.js +125 -205
- package/dist/domain/graph/builder/call-resolver.js.map +1 -1
- package/dist/domain/graph/builder/cha.d.ts +9 -1
- package/dist/domain/graph/builder/cha.d.ts.map +1 -1
- package/dist/domain/graph/builder/cha.js +17 -2
- package/dist/domain/graph/builder/cha.js.map +1 -1
- package/dist/domain/graph/builder/context.d.ts +1 -0
- package/dist/domain/graph/builder/context.d.ts.map +1 -1
- package/dist/domain/graph/builder/context.js.map +1 -1
- package/dist/domain/graph/builder/helpers.d.ts +24 -1
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +174 -65
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +166 -97
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +46 -5
- package/dist/domain/graph/builder/pipeline.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.d.ts +0 -2
- package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.js +554 -538
- package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
- package/dist/domain/graph/builder/stages/collect-files.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/collect-files.js +10 -7
- package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.js +3 -2
- package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.js +4 -0
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/native-orchestrator.js +952 -343
- package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/resolver/points-to.d.ts.map +1 -1
- package/dist/domain/graph/resolver/points-to.js +105 -57
- package/dist/domain/graph/resolver/points-to.js.map +1 -1
- package/dist/domain/graph/resolver/strategy.d.ts +61 -0
- package/dist/domain/graph/resolver/strategy.d.ts.map +1 -0
- package/dist/domain/graph/resolver/strategy.js +222 -0
- package/dist/domain/graph/resolver/strategy.js.map +1 -0
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +16 -9
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +16 -5
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +58 -17
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/queries.d.ts +1 -1
- package/dist/domain/queries.d.ts.map +1 -1
- package/dist/domain/queries.js +1 -1
- package/dist/domain/queries.js.map +1 -1
- package/dist/domain/wasm-worker-entry.js +13 -2
- package/dist/domain/wasm-worker-entry.js.map +1 -1
- package/dist/domain/wasm-worker-pool.d.ts.map +1 -1
- package/dist/domain/wasm-worker-pool.js +26 -5
- package/dist/domain/wasm-worker-pool.js.map +1 -1
- package/dist/domain/wasm-worker-protocol.d.ts +8 -0
- package/dist/domain/wasm-worker-protocol.d.ts.map +1 -1
- package/dist/extractors/cpp.d.ts.map +1 -1
- package/dist/extractors/cpp.js +42 -1
- package/dist/extractors/cpp.js.map +1 -1
- package/dist/extractors/cuda.d.ts.map +1 -1
- package/dist/extractors/cuda.js +42 -1
- package/dist/extractors/cuda.js.map +1 -1
- package/dist/extractors/dart.js +48 -3
- package/dist/extractors/dart.js.map +1 -1
- package/dist/extractors/groovy.js +62 -3
- package/dist/extractors/groovy.js.map +1 -1
- package/dist/extractors/helpers.d.ts +15 -2
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +45 -1
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +85 -8
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +686 -169
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/kotlin.js +58 -3
- package/dist/extractors/kotlin.js.map +1 -1
- package/dist/extractors/objc.js +25 -2
- package/dist/extractors/objc.js.map +1 -1
- package/dist/extractors/scala.js +62 -2
- package/dist/extractors/scala.js.map +1 -1
- package/dist/extractors/swift.js +52 -3
- package/dist/extractors/swift.js.map +1 -1
- package/dist/features/audit.js +26 -23
- package/dist/features/audit.js.map +1 -1
- package/dist/features/boundaries.d.ts.map +1 -1
- package/dist/features/boundaries.js +12 -9
- package/dist/features/boundaries.js.map +1 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +25 -18
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/check.d.ts.map +1 -1
- package/dist/features/check.js +18 -5
- package/dist/features/check.js.map +1 -1
- package/dist/features/communities.d.ts +4 -2
- package/dist/features/communities.d.ts.map +1 -1
- package/dist/features/communities.js +6 -4
- package/dist/features/communities.js.map +1 -1
- package/dist/features/dataflow.d.ts +60 -0
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +530 -6
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/manifesto.d.ts.map +1 -1
- package/dist/features/manifesto.js +59 -72
- package/dist/features/manifesto.js.map +1 -1
- package/dist/features/sequence.d.ts.map +1 -1
- package/dist/features/sequence.js +27 -22
- package/dist/features/sequence.js.map +1 -1
- package/dist/features/snapshot.d.ts.map +1 -1
- package/dist/features/snapshot.js +36 -28
- package/dist/features/snapshot.js.map +1 -1
- package/dist/features/structure-query.d.ts +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +6 -6
- package/dist/features/structure-query.js.map +1 -1
- package/dist/features/structure.d.ts.map +1 -1
- package/dist/features/structure.js +150 -62
- package/dist/features/structure.js.map +1 -1
- package/dist/features/triage.d.ts.map +1 -1
- package/dist/features/triage.js +18 -11
- package/dist/features/triage.js.map +1 -1
- package/dist/graph/algorithms/bfs.d.ts +1 -1
- package/dist/graph/algorithms/bfs.d.ts.map +1 -1
- package/dist/graph/algorithms/bfs.js +14 -13
- package/dist/graph/algorithms/bfs.js.map +1 -1
- package/dist/graph/algorithms/tarjan.d.ts.map +1 -1
- package/dist/graph/algorithms/tarjan.js +5 -0
- package/dist/graph/algorithms/tarjan.js.map +1 -1
- package/dist/graph/builders/dependency.js +28 -22
- package/dist/graph/builders/dependency.js.map +1 -1
- package/dist/graph/classifiers/roles.d.ts +10 -1
- package/dist/graph/classifiers/roles.d.ts.map +1 -1
- package/dist/graph/classifiers/roles.js +60 -6
- package/dist/graph/classifiers/roles.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/config.d.ts +87 -4
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +424 -22
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/registry.d.ts +27 -7
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +79 -5
- package/dist/infrastructure/registry.js.map +1 -1
- package/dist/infrastructure/update-check.d.ts.map +1 -1
- package/dist/infrastructure/update-check.js +49 -31
- package/dist/infrastructure/update-check.js.map +1 -1
- package/dist/mcp/server.d.ts +2 -10
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/ast-query.d.ts +1 -1
- package/dist/mcp/tools/ast-query.d.ts.map +1 -1
- package/dist/mcp/tools/audit.d.ts +1 -1
- package/dist/mcp/tools/audit.d.ts.map +1 -1
- package/dist/mcp/tools/batch-query.d.ts +1 -1
- package/dist/mcp/tools/batch-query.d.ts.map +1 -1
- package/dist/mcp/tools/branch-compare.d.ts +1 -1
- package/dist/mcp/tools/branch-compare.d.ts.map +1 -1
- package/dist/mcp/tools/brief.d.ts +1 -1
- package/dist/mcp/tools/brief.d.ts.map +1 -1
- package/dist/mcp/tools/cfg.d.ts +1 -1
- package/dist/mcp/tools/cfg.d.ts.map +1 -1
- package/dist/mcp/tools/check.d.ts +1 -1
- package/dist/mcp/tools/check.d.ts.map +1 -1
- package/dist/mcp/tools/co-changes.d.ts +1 -1
- package/dist/mcp/tools/co-changes.d.ts.map +1 -1
- package/dist/mcp/tools/code-owners.d.ts +1 -1
- package/dist/mcp/tools/code-owners.d.ts.map +1 -1
- package/dist/mcp/tools/communities.d.ts +1 -1
- package/dist/mcp/tools/communities.d.ts.map +1 -1
- package/dist/mcp/tools/complexity.d.ts +1 -1
- package/dist/mcp/tools/complexity.d.ts.map +1 -1
- package/dist/mcp/tools/context.d.ts +1 -1
- package/dist/mcp/tools/context.d.ts.map +1 -1
- package/dist/mcp/tools/dataflow.d.ts +1 -1
- package/dist/mcp/tools/dataflow.d.ts.map +1 -1
- package/dist/mcp/tools/diff-impact.d.ts +1 -1
- package/dist/mcp/tools/diff-impact.d.ts.map +1 -1
- package/dist/mcp/tools/execution-flow.d.ts +1 -1
- package/dist/mcp/tools/execution-flow.d.ts.map +1 -1
- package/dist/mcp/tools/export-graph.d.ts +1 -1
- package/dist/mcp/tools/export-graph.d.ts.map +1 -1
- package/dist/mcp/tools/file-deps.d.ts +1 -1
- package/dist/mcp/tools/file-deps.d.ts.map +1 -1
- package/dist/mcp/tools/file-exports.d.ts +1 -1
- package/dist/mcp/tools/file-exports.d.ts.map +1 -1
- package/dist/mcp/tools/find-cycles.d.ts +1 -1
- package/dist/mcp/tools/find-cycles.d.ts.map +1 -1
- package/dist/mcp/tools/fn-impact.d.ts +1 -1
- package/dist/mcp/tools/fn-impact.d.ts.map +1 -1
- package/dist/mcp/tools/impact-analysis.d.ts +1 -1
- package/dist/mcp/tools/impact-analysis.d.ts.map +1 -1
- package/dist/mcp/tools/implementations.d.ts +1 -1
- package/dist/mcp/tools/implementations.d.ts.map +1 -1
- package/dist/mcp/tools/index.d.ts +2 -5
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/interfaces.d.ts +1 -1
- package/dist/mcp/tools/interfaces.d.ts.map +1 -1
- package/dist/mcp/tools/list-functions.d.ts +1 -1
- package/dist/mcp/tools/list-functions.d.ts.map +1 -1
- package/dist/mcp/tools/list-repos.d.ts +1 -1
- package/dist/mcp/tools/list-repos.d.ts.map +1 -1
- package/dist/mcp/tools/module-map.d.ts +1 -1
- package/dist/mcp/tools/module-map.d.ts.map +1 -1
- package/dist/mcp/tools/node-roles.d.ts +1 -1
- package/dist/mcp/tools/node-roles.d.ts.map +1 -1
- package/dist/mcp/tools/path.d.ts +1 -1
- package/dist/mcp/tools/path.d.ts.map +1 -1
- package/dist/mcp/tools/query.d.ts +1 -1
- package/dist/mcp/tools/query.d.ts.map +1 -1
- package/dist/mcp/tools/semantic-search.d.ts +1 -1
- package/dist/mcp/tools/semantic-search.d.ts.map +1 -1
- package/dist/mcp/tools/sequence.d.ts +1 -1
- package/dist/mcp/tools/sequence.d.ts.map +1 -1
- package/dist/mcp/tools/structure.d.ts +1 -1
- package/dist/mcp/tools/structure.d.ts.map +1 -1
- package/dist/mcp/tools/symbol-children.d.ts +1 -1
- package/dist/mcp/tools/symbol-children.d.ts.map +1 -1
- package/dist/mcp/tools/triage.d.ts +1 -1
- package/dist/mcp/tools/triage.d.ts.map +1 -1
- package/dist/mcp/tools/where.d.ts +1 -1
- package/dist/mcp/tools/where.d.ts.map +1 -1
- package/dist/mcp/types.d.ts +19 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +6 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/presentation/queries-cli/index.d.ts +1 -1
- package/dist/presentation/queries-cli/index.d.ts.map +1 -1
- package/dist/presentation/queries-cli/index.js +1 -1
- package/dist/presentation/queries-cli/index.js.map +1 -1
- package/dist/presentation/queries-cli/overview.d.ts +1 -0
- package/dist/presentation/queries-cli/overview.d.ts.map +1 -1
- package/dist/presentation/queries-cli/overview.js +20 -1
- package/dist/presentation/queries-cli/overview.js.map +1 -1
- package/dist/presentation/queries-cli.d.ts +1 -1
- package/dist/presentation/queries-cli.d.ts.map +1 -1
- package/dist/presentation/queries-cli.js +1 -1
- package/dist/presentation/queries-cli.js.map +1 -1
- package/dist/presentation/structure.d.ts +1 -1
- package/dist/presentation/structure.d.ts.map +1 -1
- package/dist/presentation/structure.js +2 -2
- package/dist/presentation/structure.js.map +1 -1
- package/dist/presentation/viewer.d.ts.map +1 -1
- package/dist/presentation/viewer.js +45 -32
- package/dist/presentation/viewer.js.map +1 -1
- package/dist/shared/constants.d.ts +21 -0
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.js +25 -0
- package/dist/shared/constants.js.map +1 -1
- package/dist/shared/normalize.d.ts.map +1 -1
- package/dist/shared/normalize.js +12 -22
- package/dist/shared/normalize.js.map +1 -1
- package/dist/shared/paginate.d.ts +4 -17
- package/dist/shared/paginate.d.ts.map +1 -1
- package/dist/shared/paginate.js.map +1 -1
- package/dist/types.d.ts +113 -1
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-erlang.wasm +0 -0
- package/grammars/tree-sitter-gleam.wasm +0 -0
- package/package.json +7 -8
- package/src/ast-analysis/engine.ts +43 -63
- package/src/ast-analysis/rules/b2.ts +263 -0
- package/src/ast-analysis/rules/b3.ts +127 -0
- package/src/ast-analysis/rules/b4.ts +378 -0
- package/src/ast-analysis/rules/b5.ts +65 -0
- package/src/ast-analysis/rules/c.ts +157 -0
- package/src/ast-analysis/rules/index.ts +34 -0
- package/src/ast-analysis/rules/javascript.ts +3 -0
- package/src/ast-analysis/shared.ts +2 -0
- package/src/ast-analysis/visitor-utils.ts +5 -0
- package/src/ast-analysis/visitor.ts +82 -52
- package/src/ast-analysis/visitors/cfg-visitor.ts +198 -84
- package/src/ast-analysis/visitors/complexity-visitor.ts +44 -16
- package/src/ast-analysis/visitors/dataflow-visitor.ts +68 -29
- package/src/cli/commands/audit.ts +2 -1
- package/src/cli/commands/batch.ts +1 -0
- package/src/cli/commands/build.ts +6 -1
- package/src/cli/commands/config.ts +353 -0
- package/src/cli/commands/roles.ts +6 -1
- package/src/cli/commands/triage.ts +1 -1
- package/src/cli/index.ts +10 -0
- package/src/cli/shared/options.ts +11 -1
- package/src/cli/types.ts +2 -0
- package/src/db/better-sqlite3.ts +5 -4
- package/src/db/connection.ts +23 -5
- package/src/db/index.ts +1 -0
- package/src/db/migrations.ts +69 -1
- package/src/db/repository/build-stmts.ts +30 -0
- package/src/db/repository/dataflow.ts +16 -0
- package/src/db/repository/index.ts +1 -1
- package/src/db/repository/native-repository.ts +56 -40
- package/src/domain/analysis/fn-impact.ts +4 -0
- package/src/domain/analysis/module-map.ts +38 -6
- package/src/domain/analysis/roles.ts +23 -0
- package/src/domain/graph/builder/call-resolver.ts +156 -218
- package/src/domain/graph/builder/cha.ts +18 -1
- package/src/domain/graph/builder/context.ts +1 -0
- package/src/domain/graph/builder/helpers.ts +205 -67
- package/src/domain/graph/builder/incremental.ts +249 -119
- package/src/domain/graph/builder/pipeline.ts +59 -6
- package/src/domain/graph/builder/stages/build-edges.ts +783 -652
- package/src/domain/graph/builder/stages/collect-files.ts +12 -6
- package/src/domain/graph/builder/stages/detect-changes.ts +4 -2
- package/src/domain/graph/builder/stages/finalize.ts +4 -0
- package/src/domain/graph/builder/stages/native-orchestrator.ts +1214 -398
- package/src/domain/graph/builder/stages/resolve-imports.ts +1 -1
- package/src/domain/graph/resolver/points-to.ts +182 -59
- package/src/domain/graph/resolver/strategy.ts +265 -0
- package/src/domain/graph/watcher.ts +19 -9
- package/src/domain/parser.ts +57 -16
- package/src/domain/queries.ts +1 -1
- package/src/domain/wasm-worker-entry.ts +13 -2
- package/src/domain/wasm-worker-pool.ts +29 -4
- package/src/domain/wasm-worker-protocol.ts +5 -0
- package/src/extractors/cpp.ts +44 -1
- package/src/extractors/cuda.ts +44 -1
- package/src/extractors/dart.ts +48 -3
- package/src/extractors/groovy.ts +62 -2
- package/src/extractors/helpers.ts +48 -2
- package/src/extractors/java.ts +88 -8
- package/src/extractors/javascript.ts +693 -167
- package/src/extractors/kotlin.ts +57 -3
- package/src/extractors/objc.ts +25 -1
- package/src/extractors/scala.ts +63 -1
- package/src/extractors/swift.ts +46 -3
- package/src/features/audit.ts +43 -34
- package/src/features/boundaries.ts +17 -9
- package/src/features/cfg.ts +31 -22
- package/src/features/check.ts +21 -5
- package/src/features/communities.ts +28 -19
- package/src/features/dataflow.ts +755 -6
- package/src/features/manifesto.ts +76 -75
- package/src/features/sequence.ts +29 -23
- package/src/features/snapshot.ts +36 -25
- package/src/features/structure-query.ts +7 -7
- package/src/features/structure.ts +185 -55
- package/src/features/triage.ts +28 -15
- package/src/graph/algorithms/bfs.ts +13 -12
- package/src/graph/algorithms/tarjan.ts +5 -0
- package/src/graph/builders/dependency.ts +35 -23
- package/src/graph/classifiers/roles.ts +74 -7
- package/src/index.ts +5 -1
- package/src/infrastructure/config.ts +511 -23
- package/src/infrastructure/registry.ts +117 -12
- package/src/infrastructure/update-check.ts +55 -33
- package/src/mcp/server.ts +2 -8
- package/src/mcp/tools/ast-query.ts +1 -1
- package/src/mcp/tools/audit.ts +1 -1
- package/src/mcp/tools/batch-query.ts +1 -1
- package/src/mcp/tools/branch-compare.ts +1 -1
- package/src/mcp/tools/brief.ts +1 -1
- package/src/mcp/tools/cfg.ts +1 -1
- package/src/mcp/tools/check.ts +1 -1
- package/src/mcp/tools/co-changes.ts +1 -1
- package/src/mcp/tools/code-owners.ts +1 -1
- package/src/mcp/tools/communities.ts +1 -1
- package/src/mcp/tools/complexity.ts +1 -1
- package/src/mcp/tools/context.ts +1 -1
- package/src/mcp/tools/dataflow.ts +1 -1
- package/src/mcp/tools/diff-impact.ts +1 -1
- package/src/mcp/tools/execution-flow.ts +1 -1
- package/src/mcp/tools/export-graph.ts +1 -1
- package/src/mcp/tools/file-deps.ts +1 -1
- package/src/mcp/tools/file-exports.ts +1 -1
- package/src/mcp/tools/find-cycles.ts +1 -1
- package/src/mcp/tools/fn-impact.ts +1 -1
- package/src/mcp/tools/impact-analysis.ts +1 -1
- package/src/mcp/tools/implementations.ts +1 -1
- package/src/mcp/tools/index.ts +2 -5
- package/src/mcp/tools/interfaces.ts +1 -1
- package/src/mcp/tools/list-functions.ts +1 -1
- package/src/mcp/tools/list-repos.ts +1 -1
- package/src/mcp/tools/module-map.ts +1 -1
- package/src/mcp/tools/node-roles.ts +1 -1
- package/src/mcp/tools/path.ts +1 -1
- package/src/mcp/tools/query.ts +1 -1
- package/src/mcp/tools/semantic-search.ts +1 -1
- package/src/mcp/tools/sequence.ts +1 -1
- package/src/mcp/tools/structure.ts +1 -1
- package/src/mcp/tools/symbol-children.ts +1 -1
- package/src/mcp/tools/triage.ts +1 -1
- package/src/mcp/tools/where.ts +1 -1
- package/src/mcp/types.ts +21 -0
- package/src/presentation/queries-cli/index.ts +1 -1
- package/src/presentation/queries-cli/overview.ts +35 -1
- package/src/presentation/queries-cli.ts +1 -0
- package/src/presentation/structure.ts +3 -3
- package/src/presentation/viewer.ts +98 -87
- package/src/shared/constants.ts +26 -0
- package/src/shared/normalize.ts +13 -22
- package/src/shared/paginate.ts +4 -18
- package/src/types.ts +127 -1
|
@@ -64,6 +64,13 @@ const BUILTIN_GLOBALS = new Set([
|
|
|
64
64
|
const MAX_PROPAGATION_DEPTH = 3;
|
|
65
65
|
/** Confidence penalty applied per propagation hop (1.0 → 0.9 → 0.8 → 0.7). */
|
|
66
66
|
export const PROPAGATION_HOP_PENALTY = 0.1;
|
|
67
|
+
/**
|
|
68
|
+
* Confidence score for a return type inferred from `return new Constructor()` with no
|
|
69
|
+
* explicit TypeScript annotation. Registered as `analysis.typeInferenceConfidence` in
|
|
70
|
+
* `src/infrastructure/config.ts` DEFAULTS — kept in sync manually until config is
|
|
71
|
+
* threaded through to `extractSymbols`.
|
|
72
|
+
*/
|
|
73
|
+
const INFERRED_RETURN_TYPE_CONFIDENCE = 0.85;
|
|
67
74
|
/**
|
|
68
75
|
* Extract symbols from a JS/TS parsed AST.
|
|
69
76
|
* When a compiled tree-sitter Query is provided (from parser.js),
|
|
@@ -124,7 +131,22 @@ function handleClassCapture(c, definitions, classes) {
|
|
|
124
131
|
}
|
|
125
132
|
/** Handle method_definition capture. */
|
|
126
133
|
function handleMethodCapture(c, definitions) {
|
|
127
|
-
const
|
|
134
|
+
const methNameNode = c.meth_name;
|
|
135
|
+
let methName;
|
|
136
|
+
if (methNameNode.type === 'computed_property_name') {
|
|
137
|
+
// Extract the inner string literal from `['methodName']` or `["methodName"]`.
|
|
138
|
+
// Non-string computed keys (e.g. `[Symbol.iterator]`) cannot be resolved at
|
|
139
|
+
// dot-notation call sites, so skip them entirely.
|
|
140
|
+
const inner = methNameNode.child(1); // child(0)='[', child(1)=string, child(2)=']'
|
|
141
|
+
if (!inner || (inner.type !== 'string' && inner.type !== 'string_fragment'))
|
|
142
|
+
return;
|
|
143
|
+
methName = inner.text.replace(/^['"]|['"]$/g, '');
|
|
144
|
+
if (!methName)
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
methName = methNameNode.text;
|
|
149
|
+
}
|
|
128
150
|
const parentClass = findParentClass(c.meth_node);
|
|
129
151
|
const fullName = parentClass ? `${parentClass}.${methName}` : methName;
|
|
130
152
|
const methChildren = extractParameters(c.meth_node);
|
|
@@ -237,13 +259,16 @@ function dispatchQueryMatch(c, definitions, calls, imports, classes, exps) {
|
|
|
237
259
|
handleExportCapture(c, exps, imports);
|
|
238
260
|
}
|
|
239
261
|
else if (c.callfn_node) {
|
|
240
|
-
calls.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
262
|
+
// Route through extractCallInfo so special identifier calls (eval) get classified.
|
|
263
|
+
const callfnInfo = extractCallInfo(c.callfn_name, c.callfn_node);
|
|
264
|
+
if (callfnInfo)
|
|
265
|
+
calls.push(callfnInfo);
|
|
244
266
|
calls.push(...extractCallbackReferenceCalls(c.callfn_node));
|
|
245
267
|
}
|
|
246
268
|
else if (c.callmem_node) {
|
|
269
|
+
// extractCallInfo → extractMemberExprCallInfo applies the plain-identifier guard for
|
|
270
|
+
// .call/.apply/.bind: when the object is a bare identifier (e.g. `fn.call(ctx)`),
|
|
271
|
+
// the call is emitted as static (no dynamic flag), matching the walk path and native engine.
|
|
247
272
|
const callInfo = extractCallInfo(c.callmem_fn, c.callmem_node);
|
|
248
273
|
if (callInfo)
|
|
249
274
|
calls.push(callInfo);
|
|
@@ -259,10 +284,21 @@ function dispatchQueryMatch(c, definitions, calls, imports, classes, exps) {
|
|
|
259
284
|
calls.push(...extractCallbackReferenceCalls(c.callsub_node));
|
|
260
285
|
}
|
|
261
286
|
else if (c.newfn_node) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
287
|
+
if (c.newfn_name.text === 'Function') {
|
|
288
|
+
// new Function(body) — dynamic code execution; classify as eval kind
|
|
289
|
+
calls.push({
|
|
290
|
+
name: '<dynamic:eval>',
|
|
291
|
+
line: nodeStartLine(c.newfn_node),
|
|
292
|
+
dynamic: true,
|
|
293
|
+
dynamicKind: 'eval',
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
calls.push({
|
|
298
|
+
name: c.newfn_name.text,
|
|
299
|
+
line: nodeStartLine(c.newfn_node),
|
|
300
|
+
});
|
|
301
|
+
}
|
|
266
302
|
}
|
|
267
303
|
else if (c.newmem_node) {
|
|
268
304
|
const callInfo = extractCallInfo(c.newmem_fn, c.newmem_node);
|
|
@@ -318,8 +354,11 @@ function extractSymbolsQuery(tree, query) {
|
|
|
318
354
|
forOfBindings,
|
|
319
355
|
arrayCallbackBindings,
|
|
320
356
|
});
|
|
321
|
-
// Extract definitions from destructured bindings (query patterns don't match object_pattern)
|
|
322
|
-
|
|
357
|
+
// Extract definitions from destructured bindings (query patterns don't match object_pattern).
|
|
358
|
+
// Also collects CJS require bindings (const { X } = require('…')) into a separate list so
|
|
359
|
+
// importedNames can classify them as import artifacts without creating DB edges (#1661).
|
|
360
|
+
const cjsRequireBindings = [];
|
|
361
|
+
extractDestructuredBindingsWalk(tree.rootNode, definitions, cjsRequireBindings);
|
|
323
362
|
// Everything without bespoke traversal semantics is collected in ONE pass:
|
|
324
363
|
// dynamic import() calls, prototype-method definitions, param bindings,
|
|
325
364
|
// array-element bindings, object-prop bindings, `new X()` names,
|
|
@@ -360,6 +399,7 @@ function extractSymbolsQuery(tree, query) {
|
|
|
360
399
|
thisCallBindings,
|
|
361
400
|
newExpressions,
|
|
362
401
|
...(definePropertyReceivers.size > 0 ? { definePropertyReceivers } : {}),
|
|
402
|
+
...(cjsRequireBindings.length > 0 ? { cjsRequireBindings } : {}),
|
|
363
403
|
};
|
|
364
404
|
}
|
|
365
405
|
/** Node types that define a function scope — constants inside these are skipped. */
|
|
@@ -406,6 +446,7 @@ function extractConstantsWalk(node, definitions) {
|
|
|
406
446
|
declNode = inner;
|
|
407
447
|
}
|
|
408
448
|
extractConstDeclarators(declNode, definitions);
|
|
449
|
+
extractLetVarObjLiteralDeclarators(declNode, definitions);
|
|
409
450
|
// Recurse into non-function, non-export-statement children (blocks, if-statements, etc.)
|
|
410
451
|
if (child.type !== 'export_statement') {
|
|
411
452
|
extractConstantsWalk(child, definitions);
|
|
@@ -419,8 +460,11 @@ function extractConstantsWalk(node, definitions) {
|
|
|
419
460
|
/**
|
|
420
461
|
* Walk the AST to find destructured const bindings (query patterns don't match object_pattern).
|
|
421
462
|
* e.g. `const { handleToken, checkPermissions } = initAuth(config)`
|
|
463
|
+
*
|
|
464
|
+
* When `cjsRequireBindings` is provided, also records `const { X } = require('./path')` patterns
|
|
465
|
+
* so the edge builder can classify X as an import artifact rather than a local definition (#1661).
|
|
422
466
|
*/
|
|
423
|
-
function extractDestructuredBindingsWalk(node, definitions) {
|
|
467
|
+
function extractDestructuredBindingsWalk(node, definitions, cjsRequireBindings) {
|
|
424
468
|
for (let i = 0; i < node.childCount; i++) {
|
|
425
469
|
const child = node.child(i);
|
|
426
470
|
if (!child)
|
|
@@ -443,11 +487,56 @@ function extractDestructuredBindingsWalk(node, definitions) {
|
|
|
443
487
|
const nameN = declarator.childForFieldName('name');
|
|
444
488
|
if (nameN && nameN.type === 'object_pattern') {
|
|
445
489
|
extractDestructuredBindings(nameN, nodeStartLine(declNode), nodeEndLine(declNode), definitions);
|
|
490
|
+
// Record CJS require bindings so importedNames can classify these names
|
|
491
|
+
// as import artifacts, preventing false local-definition blocking (#1661).
|
|
492
|
+
if (cjsRequireBindings) {
|
|
493
|
+
const valueN = declarator.childForFieldName('value');
|
|
494
|
+
if (valueN?.type === 'call_expression') {
|
|
495
|
+
const fn = valueN.childForFieldName('function');
|
|
496
|
+
if (fn?.text === 'require') {
|
|
497
|
+
const args = valueN.childForFieldName('arguments');
|
|
498
|
+
const strArg = args && findChild(args, 'string');
|
|
499
|
+
if (strArg) {
|
|
500
|
+
const modPath = strArg.text.replace(/['"]/g, '');
|
|
501
|
+
const names = [];
|
|
502
|
+
for (let k = 0; k < nameN.childCount; k++) {
|
|
503
|
+
const prop = nameN.child(k);
|
|
504
|
+
if (!prop)
|
|
505
|
+
continue;
|
|
506
|
+
if (prop.type === 'shorthand_property_identifier_pattern' ||
|
|
507
|
+
prop.type === 'shorthand_property_identifier') {
|
|
508
|
+
names.push(prop.text);
|
|
509
|
+
}
|
|
510
|
+
else if (prop.type === 'pair_pattern' || prop.type === 'pair') {
|
|
511
|
+
const val = prop.childForFieldName('value');
|
|
512
|
+
if (val?.type === 'identifier' ||
|
|
513
|
+
val?.type === 'shorthand_property_identifier_pattern') {
|
|
514
|
+
names.push(val.text);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
if (names.length > 0) {
|
|
519
|
+
cjsRequireBindings.push({ names, source: modPath });
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
else if (nameN && nameN.type === 'array_pattern') {
|
|
527
|
+
// `const [x, y] = ...` — emit a single constant node whose name is the
|
|
528
|
+
// full array pattern text (e.g. `[x, y]`), matching native engine behaviour.
|
|
529
|
+
definitions.push({
|
|
530
|
+
name: nameN.text,
|
|
531
|
+
kind: 'constant',
|
|
532
|
+
line: nodeStartLine(declNode),
|
|
533
|
+
endLine: nodeEndLine(declNode),
|
|
534
|
+
});
|
|
446
535
|
}
|
|
447
536
|
}
|
|
448
537
|
}
|
|
449
538
|
if (child.type !== 'export_statement') {
|
|
450
|
-
extractDestructuredBindingsWalk(child, definitions);
|
|
539
|
+
extractDestructuredBindingsWalk(child, definitions, cjsRequireBindings);
|
|
451
540
|
}
|
|
452
541
|
}
|
|
453
542
|
}
|
|
@@ -491,6 +580,33 @@ function extractConstDeclarators(declNode, definitions) {
|
|
|
491
580
|
}
|
|
492
581
|
}
|
|
493
582
|
}
|
|
583
|
+
/**
|
|
584
|
+
* Extract qualified method definitions from `let`/`var` object-literal declarations.
|
|
585
|
+
* Mirrors `match_js_objlit_qualified_method_defs` in `javascript.rs`, which emits
|
|
586
|
+
* qualified definitions for `method_definition` (all declaration kinds) and
|
|
587
|
+
* `pair+arrow/function` (`let`/`var` only, since `const` is already handled by
|
|
588
|
+
* `extractConstDeclarators` → `extractObjectLiteralFunctions`).
|
|
589
|
+
*
|
|
590
|
+
* Called from extractConstantsWalk which already provides the function-scope guard.
|
|
591
|
+
* `var q1 = { m1() {} }` → emits Definition { name: 'q1.m1', kind: 'function' }
|
|
592
|
+
*/
|
|
593
|
+
function extractLetVarObjLiteralDeclarators(declNode, definitions) {
|
|
594
|
+
const t = declNode.type;
|
|
595
|
+
if (t !== 'lexical_declaration' && t !== 'variable_declaration')
|
|
596
|
+
return;
|
|
597
|
+
if (declNode.text.startsWith('const '))
|
|
598
|
+
return; // handled by extractConstDeclarators
|
|
599
|
+
for (let j = 0; j < declNode.childCount; j++) {
|
|
600
|
+
const declarator = declNode.child(j);
|
|
601
|
+
if (declarator?.type !== 'variable_declarator')
|
|
602
|
+
continue;
|
|
603
|
+
const nameN = declarator.childForFieldName('name');
|
|
604
|
+
const valueN = declarator.childForFieldName('value');
|
|
605
|
+
if (nameN?.type !== 'identifier' || !valueN || valueN.type !== 'object')
|
|
606
|
+
continue;
|
|
607
|
+
extractObjectLiteralFunctions(valueN, nameN.text, definitions);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
494
610
|
/**
|
|
495
611
|
* Recursive walk to find dynamic import() calls.
|
|
496
612
|
* Query patterns match call_expression with identifier/member_expression/subscript_expression
|
|
@@ -667,6 +783,9 @@ function walkJavaScriptNode(node, ctx) {
|
|
|
667
783
|
case 'enum_declaration':
|
|
668
784
|
handleEnumDecl(node, ctx);
|
|
669
785
|
break;
|
|
786
|
+
case 'decorator':
|
|
787
|
+
handleDecorator(node, ctx.calls);
|
|
788
|
+
break;
|
|
670
789
|
case 'call_expression':
|
|
671
790
|
handleCallExpr(node, ctx);
|
|
672
791
|
break;
|
|
@@ -730,8 +849,23 @@ function handleClassDecl(node, ctx) {
|
|
|
730
849
|
function handleMethodDef(node, ctx) {
|
|
731
850
|
const nameNode = node.childForFieldName('name');
|
|
732
851
|
if (nameNode) {
|
|
852
|
+
let methName;
|
|
853
|
+
if (nameNode.type === 'computed_property_name') {
|
|
854
|
+
// Extract the inner string literal from `['methodName']` or `["methodName"]`.
|
|
855
|
+
// Non-string computed keys (e.g. `[Symbol.iterator]`) cannot be resolved at
|
|
856
|
+
// dot-notation call sites, so skip them entirely.
|
|
857
|
+
const inner = nameNode.child(1); // child(0)='[', child(1)=string, child(2)=']'
|
|
858
|
+
if (!inner || (inner.type !== 'string' && inner.type !== 'string_fragment'))
|
|
859
|
+
return;
|
|
860
|
+
methName = inner.text.replace(/^['"]|['"]$/g, '');
|
|
861
|
+
if (!methName)
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
else {
|
|
865
|
+
methName = nameNode.text;
|
|
866
|
+
}
|
|
733
867
|
const parentClass = findParentClass(node);
|
|
734
|
-
const fullName = parentClass ? `${parentClass}.${
|
|
868
|
+
const fullName = parentClass ? `${parentClass}.${methName}` : methName;
|
|
735
869
|
const methChildren = extractParameters(node);
|
|
736
870
|
const methVis = extractVisibility(node);
|
|
737
871
|
ctx.definitions.push({
|
|
@@ -905,6 +1039,17 @@ function handleVariableDecl(node, ctx) {
|
|
|
905
1039
|
extractObjectLiteralFunctions(valueN, nameN.text, ctx.definitions);
|
|
906
1040
|
}
|
|
907
1041
|
}
|
|
1042
|
+
else if (!isConst &&
|
|
1043
|
+
nameN.type === 'identifier' &&
|
|
1044
|
+
valueN.type === 'object' &&
|
|
1045
|
+
!hasFunctionScopeAncestor(node)) {
|
|
1046
|
+
// `let`/`var` object literals: extract qualified method definitions so that
|
|
1047
|
+
// `obj.method()` calls resolve correctly. Mirrors Rust match_js_objlit_qualified_method_defs
|
|
1048
|
+
// which emits method_definition qualified names for ALL declaration kinds and
|
|
1049
|
+
// pair+arrow/function for let/var only (const is already handled above).
|
|
1050
|
+
// Scope guard prevents local object properties from polluting the global index.
|
|
1051
|
+
extractObjectLiteralFunctions(valueN, nameN.text, ctx.definitions);
|
|
1052
|
+
}
|
|
908
1053
|
else if (isConst && nameN.type === 'object_pattern' && !hasFunctionScopeAncestor(node)) {
|
|
909
1054
|
// Destructured bindings: const { handleToken, checkPermissions } = initAuth(...)
|
|
910
1055
|
// Each destructured property becomes a function definition so it can be
|
|
@@ -914,6 +1059,50 @@ function handleVariableDecl(node, ctx) {
|
|
|
914
1059
|
// Scope guard mirrors extractDestructuredBindingsWalk (query path) and
|
|
915
1060
|
// handle_var_decl (Rust path) — skips bindings inside function bodies.
|
|
916
1061
|
extractDestructuredBindings(nameN, nodeStartLine(node), nodeEndLine(node), ctx.definitions);
|
|
1062
|
+
// Record CJS require bindings for import-artifact classification (#1661).
|
|
1063
|
+
if (valueN?.type === 'call_expression') {
|
|
1064
|
+
const fn = valueN.childForFieldName('function');
|
|
1065
|
+
if (fn?.text === 'require') {
|
|
1066
|
+
const args = valueN.childForFieldName('arguments');
|
|
1067
|
+
const strArg = args && findChild(args, 'string');
|
|
1068
|
+
if (strArg) {
|
|
1069
|
+
const modPath = strArg.text.replace(/['"]/g, '');
|
|
1070
|
+
const names = [];
|
|
1071
|
+
for (let k = 0; k < nameN.childCount; k++) {
|
|
1072
|
+
const prop = nameN.child(k);
|
|
1073
|
+
if (!prop)
|
|
1074
|
+
continue;
|
|
1075
|
+
if (prop.type === 'shorthand_property_identifier_pattern' ||
|
|
1076
|
+
prop.type === 'shorthand_property_identifier') {
|
|
1077
|
+
names.push(prop.text);
|
|
1078
|
+
}
|
|
1079
|
+
else if (prop.type === 'pair_pattern' || prop.type === 'pair') {
|
|
1080
|
+
const val = prop.childForFieldName('value');
|
|
1081
|
+
if (val?.type === 'identifier' ||
|
|
1082
|
+
val?.type === 'shorthand_property_identifier_pattern') {
|
|
1083
|
+
names.push(val.text);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
if (names.length > 0) {
|
|
1088
|
+
if (!ctx.cjsRequireBindings)
|
|
1089
|
+
ctx.cjsRequireBindings = [];
|
|
1090
|
+
ctx.cjsRequireBindings.push({ names, source: modPath });
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
else if (isConst && nameN.type === 'array_pattern' && !hasFunctionScopeAncestor(node)) {
|
|
1097
|
+
// Array destructuring: `const [x, y] = ...` — emit a single constant node
|
|
1098
|
+
// whose name is the full array pattern text (e.g. `[x, y]`), matching
|
|
1099
|
+
// native engine behaviour. Scope guard mirrors the object_pattern branch above.
|
|
1100
|
+
ctx.definitions.push({
|
|
1101
|
+
name: nameN.text,
|
|
1102
|
+
kind: 'constant',
|
|
1103
|
+
line: nodeStartLine(node),
|
|
1104
|
+
endLine: nodeEndLine(node),
|
|
1105
|
+
});
|
|
917
1106
|
}
|
|
918
1107
|
}
|
|
919
1108
|
}
|
|
@@ -958,8 +1147,22 @@ function extractObjectLiteralFunctions(objNode, varName, definitions) {
|
|
|
958
1147
|
else if (child.type === 'method_definition') {
|
|
959
1148
|
const nameNode = child.childForFieldName('name');
|
|
960
1149
|
if (nameNode) {
|
|
1150
|
+
let methodName;
|
|
1151
|
+
if (nameNode.type === 'computed_property_name') {
|
|
1152
|
+
// Strip brackets+quotes from `['methodName']` to get a resolvable name.
|
|
1153
|
+
// Skip non-string computed keys (e.g. [Symbol.iterator]).
|
|
1154
|
+
const inner = nameNode.child(1);
|
|
1155
|
+
if (!inner || (inner.type !== 'string' && inner.type !== 'string_fragment'))
|
|
1156
|
+
continue;
|
|
1157
|
+
methodName = inner.text.replace(/^['"]|['"]$/g, '');
|
|
1158
|
+
if (!methodName)
|
|
1159
|
+
continue;
|
|
1160
|
+
}
|
|
1161
|
+
else {
|
|
1162
|
+
methodName = nameNode.text;
|
|
1163
|
+
}
|
|
961
1164
|
definitions.push({
|
|
962
|
-
name: `${varName}.${
|
|
1165
|
+
name: `${varName}.${methodName}`,
|
|
963
1166
|
kind: 'function',
|
|
964
1167
|
line: nodeStartLine(child),
|
|
965
1168
|
endLine: nodeEndLine(child),
|
|
@@ -1054,7 +1257,18 @@ function handleNewExpr(node, ctx) {
|
|
|
1054
1257
|
if (!ctor)
|
|
1055
1258
|
return;
|
|
1056
1259
|
if (ctor.type === 'identifier') {
|
|
1057
|
-
|
|
1260
|
+
if (ctor.text === 'Function') {
|
|
1261
|
+
// new Function(body) — dynamic code execution; undecidable static target
|
|
1262
|
+
ctx.calls.push({
|
|
1263
|
+
name: '<dynamic:eval>',
|
|
1264
|
+
line: nodeStartLine(node),
|
|
1265
|
+
dynamic: true,
|
|
1266
|
+
dynamicKind: 'eval',
|
|
1267
|
+
});
|
|
1268
|
+
}
|
|
1269
|
+
else {
|
|
1270
|
+
ctx.calls.push({ name: ctor.text, line: nodeStartLine(node) });
|
|
1271
|
+
}
|
|
1058
1272
|
}
|
|
1059
1273
|
else if (ctor.type === 'member_expression') {
|
|
1060
1274
|
const callInfo = extractCallInfo(ctor, node);
|
|
@@ -1062,6 +1276,39 @@ function handleNewExpr(node, ctx) {
|
|
|
1062
1276
|
ctx.calls.push(callInfo);
|
|
1063
1277
|
}
|
|
1064
1278
|
}
|
|
1279
|
+
/**
|
|
1280
|
+
* Handle a TypeScript/JS decorator node.
|
|
1281
|
+
*
|
|
1282
|
+
* Only handles bare-identifier and bare-member-expression decorators
|
|
1283
|
+
* (`@Foo`, `@Foo.bar`) since decorated call expressions (`@Foo()`, `@Foo.bar()`)
|
|
1284
|
+
* are already visited as `call_expression` children by the recursive walker.
|
|
1285
|
+
*/
|
|
1286
|
+
function handleDecorator(node, calls) {
|
|
1287
|
+
// Decorators wrap their expression; find the first non-@ child
|
|
1288
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
1289
|
+
const child = node.child(i);
|
|
1290
|
+
if (!child || child.type === '@')
|
|
1291
|
+
continue;
|
|
1292
|
+
const t = child.type;
|
|
1293
|
+
if (t === 'identifier') {
|
|
1294
|
+
// @Foo — the identifier is the decorator factory; emit as reflection call
|
|
1295
|
+
calls.push({
|
|
1296
|
+
name: child.text,
|
|
1297
|
+
line: nodeStartLine(node),
|
|
1298
|
+
dynamic: true,
|
|
1299
|
+
dynamicKind: 'reflection',
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
else if (t === 'member_expression') {
|
|
1303
|
+
// @Foo.bar — emit as reflection; always mark dynamic since it's decorator dispatch
|
|
1304
|
+
const callInfo = extractCallInfo(child, node);
|
|
1305
|
+
if (callInfo)
|
|
1306
|
+
calls.push({ ...callInfo, dynamic: true, dynamicKind: 'reflection' });
|
|
1307
|
+
}
|
|
1308
|
+
// call_expression / other — handled by the recursive walker automatically
|
|
1309
|
+
break;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1065
1312
|
/** Handle a dynamic import() call expression and add to imports if static. */
|
|
1066
1313
|
function handleDynamicImportCall(node, imports) {
|
|
1067
1314
|
const args = node.childForFieldName('arguments') || findChild(node, 'arguments');
|
|
@@ -1417,8 +1664,8 @@ function storeReturnType(fnNode, fnName, returnTypeMap) {
|
|
|
1417
1664
|
const inferred = findReturnNewExprType(body);
|
|
1418
1665
|
if (inferred) {
|
|
1419
1666
|
const existing = returnTypeMap.get(fnName);
|
|
1420
|
-
if (!existing ||
|
|
1421
|
-
returnTypeMap.set(fnName, { type: inferred, confidence:
|
|
1667
|
+
if (!existing || INFERRED_RETURN_TYPE_CONFIDENCE > existing.confidence)
|
|
1668
|
+
returnTypeMap.set(fnName, { type: inferred, confidence: INFERRED_RETURN_TYPE_CONFIDENCE });
|
|
1422
1669
|
}
|
|
1423
1670
|
}
|
|
1424
1671
|
}
|
|
@@ -1665,9 +1912,25 @@ function runContextCollectorWalk(rootNode, out) {
|
|
|
1665
1912
|
// Qualify with the enclosing class name so the PTS key matches
|
|
1666
1913
|
// callerName from findCaller (which uses def.name = 'ClassName.method').
|
|
1667
1914
|
const enclosingClass = classStack.length > 0 ? classStack[classStack.length - 1] : null;
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1915
|
+
let rawName;
|
|
1916
|
+
if (nameNode.type === 'computed_property_name') {
|
|
1917
|
+
const inner = nameNode.child(1);
|
|
1918
|
+
if (!inner || (inner.type !== 'string' && inner.type !== 'string_fragment')) {
|
|
1919
|
+
// Non-string computed key — skip adding to funcStack (no resolvable name).
|
|
1920
|
+
rawName = '';
|
|
1921
|
+
}
|
|
1922
|
+
else {
|
|
1923
|
+
rawName = inner.text.replace(/^['"]|['"]$/g, '');
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
else {
|
|
1927
|
+
rawName = nameNode.text;
|
|
1928
|
+
}
|
|
1929
|
+
if (rawName) {
|
|
1930
|
+
const qualifiedName = enclosingClass ? `${enclosingClass}.${rawName}` : rawName;
|
|
1931
|
+
funcStack.push(qualifiedName);
|
|
1932
|
+
pushedFunc = true;
|
|
1933
|
+
}
|
|
1671
1934
|
}
|
|
1672
1935
|
}
|
|
1673
1936
|
else if (t === 'variable_declarator') {
|
|
@@ -1709,6 +1972,9 @@ function runContextCollectorWalk(rootNode, out) {
|
|
|
1709
1972
|
else if (t === 'required_parameter' || t === 'optional_parameter') {
|
|
1710
1973
|
handleParamTypeMap(node, out.typeMap);
|
|
1711
1974
|
}
|
|
1975
|
+
else if (t === 'public_field_definition' || t === 'field_definition') {
|
|
1976
|
+
handleFieldDefTypeMap(node, out.typeMap, typeMapClass);
|
|
1977
|
+
}
|
|
1712
1978
|
else if (t === 'assignment_expression') {
|
|
1713
1979
|
handlePropWriteTypeMap(node, out.typeMap, typeMapClass);
|
|
1714
1980
|
}
|
|
@@ -1740,54 +2006,186 @@ function runContextCollectorWalk(rootNode, out) {
|
|
|
1740
2006
|
};
|
|
1741
2007
|
walk(rootNode, 0, null, null);
|
|
1742
2008
|
}
|
|
1743
|
-
/**
|
|
1744
|
-
function
|
|
1745
|
-
|
|
1746
|
-
|
|
2009
|
+
/**
|
|
2010
|
+
* Record function-reference bindings from a variable_declarator's value node.
|
|
2011
|
+
*
|
|
2012
|
+
* Captures three patterns (Phase 8.3):
|
|
2013
|
+
* - `const fn = handler` (identifier alias)
|
|
2014
|
+
* - `const fn = obj.method` (member_expression alias)
|
|
2015
|
+
* - `const f = fn.bind(ctx)` (bind creates a bound alias)
|
|
2016
|
+
*
|
|
2017
|
+
* Must be called before any type-analysis early returns so every declarator
|
|
2018
|
+
* contributes to fnRefBindings regardless of whether it has a type annotation.
|
|
2019
|
+
*/
|
|
2020
|
+
function collectFnRefBindings(lhsName, valueN, fnRefBindings) {
|
|
2021
|
+
if (valueN.type === 'identifier' && !BUILTIN_GLOBALS.has(valueN.text)) {
|
|
2022
|
+
fnRefBindings.push({ lhs: lhsName, rhs: valueN.text });
|
|
1747
2023
|
return;
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
2024
|
+
}
|
|
2025
|
+
if (valueN.type === 'member_expression') {
|
|
2026
|
+
const prop = valueN.childForFieldName('property');
|
|
2027
|
+
const obj = valueN.childForFieldName('object');
|
|
2028
|
+
// Guard: only static property access (property_identifier or identifier), not
|
|
2029
|
+
// computed subscript expressions like obj[expr] where prop.text would be the
|
|
2030
|
+
// full expression rather than a simple name — those can never match pts keys.
|
|
2031
|
+
if (prop &&
|
|
2032
|
+
(prop.type === 'property_identifier' || prop.type === 'identifier') &&
|
|
2033
|
+
obj?.type === 'identifier' &&
|
|
2034
|
+
!BUILTIN_GLOBALS.has(obj.text)) {
|
|
2035
|
+
fnRefBindings.push({ lhs: lhsName, rhs: prop.text, rhsReceiver: obj.text });
|
|
2036
|
+
}
|
|
2037
|
+
return;
|
|
2038
|
+
}
|
|
2039
|
+
if (valueN.type === 'call_expression') {
|
|
2040
|
+
// `const f = fn.bind(ctx)` — bind returns a bound copy of fn; track f → fn so
|
|
2041
|
+
// pts(f) ⊇ pts(fn) and subsequent `f(args)` calls resolve to fn.
|
|
2042
|
+
// Note: only flat-identifier binds (fn.bind) are tracked here; method-receiver
|
|
2043
|
+
// binds like `obj.method.bind(ctx)` are not captured (boundFn must be an identifier).
|
|
2044
|
+
const callFn = valueN.childForFieldName('function');
|
|
2045
|
+
if (callFn?.type === 'member_expression') {
|
|
2046
|
+
const bindProp = callFn.childForFieldName('property');
|
|
2047
|
+
if (bindProp?.text === 'bind') {
|
|
2048
|
+
const boundFn = callFn.childForFieldName('object');
|
|
2049
|
+
if (boundFn?.type === 'identifier' && !BUILTIN_GLOBALS.has(boundFn.text)) {
|
|
2050
|
+
fnRefBindings.push({ lhs: lhsName, rhs: boundFn.text });
|
|
2051
|
+
}
|
|
1768
2052
|
}
|
|
1769
2053
|
}
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
/**
|
|
2057
|
+
* Handle the `call_expression` branch of variable_declarator type-map seeding.
|
|
2058
|
+
*
|
|
2059
|
+
* Processes three sub-cases in priority order:
|
|
2060
|
+
* 1. Object.create({ ... }) — seeds composite pts keys from the prototype object (Phase 8.3e)
|
|
2061
|
+
* 2. Inter-procedural return-type propagation via returnTypeMap (Phase 8.2)
|
|
2062
|
+
* 3. Factory method heuristic: `const x = Foo.create()` → type Foo at confidence 0.7
|
|
2063
|
+
*/
|
|
2064
|
+
function handleCallExprTypeMap(lhsName, valueN, typeMap, returnTypeMap, callAssignments) {
|
|
2065
|
+
const createFn = valueN.childForFieldName('function');
|
|
2066
|
+
// Phase 8.3e: Object.create({ f1, f2 }) — seed composite pts keys obj.f1 → f1, etc.
|
|
2067
|
+
if (createFn?.type === 'member_expression') {
|
|
2068
|
+
const createObj = createFn.childForFieldName('object');
|
|
2069
|
+
const createProp = createFn.childForFieldName('property');
|
|
2070
|
+
if (createObj?.text === 'Object' && createProp?.text === 'create') {
|
|
2071
|
+
const createArgs = valueN.childForFieldName('arguments') || findChild(valueN, 'arguments');
|
|
2072
|
+
if (createArgs) {
|
|
2073
|
+
let proto = null;
|
|
2074
|
+
for (let i = 0; i < createArgs.childCount; i++) {
|
|
2075
|
+
const n = createArgs.child(i);
|
|
2076
|
+
if (n && n.type !== '(' && n.type !== ')' && n.type !== ',') {
|
|
2077
|
+
proto = n;
|
|
2078
|
+
break;
|
|
1782
2079
|
}
|
|
1783
2080
|
}
|
|
2081
|
+
if (proto?.type === 'object') {
|
|
2082
|
+
seedProtoProperties(lhsName, proto, typeMap);
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
return;
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
// Phase 8.2: inter-procedural propagation — try to resolve return type from
|
|
2089
|
+
// the local returnTypeMap before falling back to factory heuristics.
|
|
2090
|
+
if (returnTypeMap) {
|
|
2091
|
+
const result = resolveCallExprReturnType(valueN, typeMap, returnTypeMap, 0);
|
|
2092
|
+
if (result) {
|
|
2093
|
+
setTypeMapEntry(typeMap, lhsName, result.type, result.confidence);
|
|
2094
|
+
return;
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
// Record for cross-file resolution in build-edges.ts (imported functions)
|
|
2098
|
+
if (callAssignments) {
|
|
2099
|
+
recordCallAssignment(valueN, lhsName, typeMap, callAssignments);
|
|
2100
|
+
}
|
|
2101
|
+
// Factory method heuristic: const x = Foo.create() → type Foo, confidence 0.7
|
|
2102
|
+
if (createFn?.type === 'member_expression') {
|
|
2103
|
+
const obj = createFn.childForFieldName('object');
|
|
2104
|
+
if (obj?.type === 'identifier') {
|
|
2105
|
+
const objName = obj.text;
|
|
2106
|
+
if (objName[0] && objName[0] !== objName[0].toLowerCase() && !BUILTIN_GLOBALS.has(objName)) {
|
|
2107
|
+
setTypeMapEntry(typeMap, lhsName, objName, 0.7);
|
|
1784
2108
|
}
|
|
1785
2109
|
}
|
|
1786
2110
|
}
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
2111
|
+
}
|
|
2112
|
+
/**
|
|
2113
|
+
* Seed composite pts keys from a module-level object literal assignment (Phase 8.3f).
|
|
2114
|
+
*
|
|
2115
|
+
* `const obj = { baz: () => {} }` → typeMap['obj.baz'] = 'obj.baz'
|
|
2116
|
+
* `const obj = { baz }` (shorthand) → typeMap['obj.baz'] = 'baz' (bare identifier target)
|
|
2117
|
+
* `const obj = { baz: otherFn }` → typeMap['obj.baz'] = 'otherFn' (identifier alias)
|
|
2118
|
+
* `const obj = { baz() {} }` (method shorthand) → typeMap['obj.baz'] = 'obj.baz'
|
|
2119
|
+
*
|
|
2120
|
+
* For function/arrow values, the value is the qualified name ('obj.baz') because
|
|
2121
|
+
* extractObjectLiteralFunctions registers definitions under that qualified name to avoid
|
|
2122
|
+
* polluting the global index with bare property names like 'init', 'run', or 'render'.
|
|
2123
|
+
* Enables accessor this-dispatch: when typeMap['getter:this'] = 'obj',
|
|
2124
|
+
* resolving this.baz() inside getter → typeMap['obj.baz'] → 'obj.baz' → lookup.byName('obj.baz').
|
|
2125
|
+
*
|
|
2126
|
+
* Scope guard: caller must ensure `node` is not inside a function body
|
|
2127
|
+
* (mirrors Rust handle_var_decl's find_parent_of_types check — function-scoped
|
|
2128
|
+
* `const localObj = { fn: ... }` must not shadow a module-level `const obj`).
|
|
2129
|
+
*/
|
|
2130
|
+
function handleObjectLiteralTypeMap(lhsName, valueN, typeMap) {
|
|
2131
|
+
for (let i = 0; i < valueN.childCount; i++) {
|
|
2132
|
+
const child = valueN.child(i);
|
|
2133
|
+
if (!child)
|
|
2134
|
+
continue;
|
|
2135
|
+
if (child.type === 'shorthand_property_identifier') {
|
|
2136
|
+
setTypeMapEntry(typeMap, `${lhsName}.${child.text}`, child.text, 0.85);
|
|
2137
|
+
}
|
|
2138
|
+
else if (child.type === 'pair') {
|
|
2139
|
+
const keyNode = child.childForFieldName('key');
|
|
2140
|
+
const valNode = child.childForFieldName('value');
|
|
2141
|
+
if (!keyNode || !valNode)
|
|
2142
|
+
continue;
|
|
2143
|
+
const keyName = keyNode.type === 'string' ? keyNode.text.replace(/^['"]|['"]$/g, '') : keyNode.text;
|
|
2144
|
+
if (!keyName)
|
|
2145
|
+
continue;
|
|
2146
|
+
const qualifiedKey = `${lhsName}.${keyName}`;
|
|
2147
|
+
if (valNode.type === 'arrow_function' ||
|
|
2148
|
+
valNode.type === 'function_expression' ||
|
|
2149
|
+
valNode.type === 'function') {
|
|
2150
|
+
// Store the qualified name so the resolver finds the qualified definition.
|
|
2151
|
+
setTypeMapEntry(typeMap, qualifiedKey, qualifiedKey, 0.85);
|
|
2152
|
+
}
|
|
2153
|
+
else if (valNode.type === 'identifier') {
|
|
2154
|
+
setTypeMapEntry(typeMap, qualifiedKey, valNode.text, 0.85);
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
else if (child.type === 'method_definition') {
|
|
2158
|
+
// Method shorthand: `const obj = { baz() {} }` → typeMap['obj.baz'] = 'obj.baz'
|
|
2159
|
+
// extractObjectLiteralFunctions registers a definition under the qualified name;
|
|
2160
|
+
// seed the matching typeMap entry so the two-step accessor dispatch finds it.
|
|
2161
|
+
const nameNode = child.childForFieldName('name');
|
|
2162
|
+
if (!nameNode)
|
|
2163
|
+
continue;
|
|
2164
|
+
setTypeMapEntry(typeMap, `${lhsName}.${nameNode.text}`, `${lhsName}.${nameNode.text}`, 0.85);
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
/**
|
|
2169
|
+
* Extract type info from a variable_declarator: type annotation, constructor, or factory.
|
|
2170
|
+
*
|
|
2171
|
+
* Orchestrates four concerns in priority order:
|
|
2172
|
+
* 1. fnRefBindings — always collected first (before any early return)
|
|
2173
|
+
* 2. new_expression — constructor wins over annotation (runtime type is authoritative)
|
|
2174
|
+
* 3. type_annotation — confidence 0.9 for static analysis
|
|
2175
|
+
* 4. call_expression / object literal — delegated to handleCallExprTypeMap /
|
|
2176
|
+
* handleObjectLiteralTypeMap
|
|
2177
|
+
*/
|
|
2178
|
+
function handleVarDeclaratorTypeMap(node, typeMap, returnTypeMap, callAssignments, fnRefBindings) {
|
|
2179
|
+
const nameN = node.childForFieldName('name');
|
|
2180
|
+
if (nameN?.type !== 'identifier')
|
|
2181
|
+
return;
|
|
2182
|
+
const typeAnno = findChild(node, 'type_annotation');
|
|
2183
|
+
const valueN = node.childForFieldName('value');
|
|
2184
|
+
// 1. fnRefBindings — must run before any early return so every declarator contributes.
|
|
2185
|
+
if (fnRefBindings && valueN) {
|
|
2186
|
+
collectFnRefBindings(nameN.text, valueN, fnRefBindings);
|
|
2187
|
+
}
|
|
2188
|
+
// 2. Constructor wins over annotation: `const x: Base = new Derived()` resolves to Derived.
|
|
1791
2189
|
if (valueN?.type === 'new_expression') {
|
|
1792
2190
|
const ctorType = extractNewExprTypeName(valueN);
|
|
1793
2191
|
if (ctorType) {
|
|
@@ -1795,7 +2193,7 @@ function handleVarDeclaratorTypeMap(node, typeMap, returnTypeMap, callAssignment
|
|
|
1795
2193
|
return;
|
|
1796
2194
|
}
|
|
1797
2195
|
}
|
|
1798
|
-
// Type annotation
|
|
2196
|
+
// 3. Type annotation — confidence 0.9.
|
|
1799
2197
|
if (typeAnno) {
|
|
1800
2198
|
const typeName = extractSimpleTypeName(typeAnno);
|
|
1801
2199
|
if (typeName) {
|
|
@@ -1807,109 +2205,14 @@ function handleVarDeclaratorTypeMap(node, typeMap, returnTypeMap, callAssignment
|
|
|
1807
2205
|
return;
|
|
1808
2206
|
if (valueN.type === 'new_expression')
|
|
1809
2207
|
return;
|
|
2208
|
+
// 4a. call_expression — Object.create / return-type propagation / factory heuristic.
|
|
1810
2209
|
if (valueN.type === 'call_expression') {
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
if (createFn?.type === 'member_expression') {
|
|
1814
|
-
const createObj = createFn.childForFieldName('object');
|
|
1815
|
-
const createProp = createFn.childForFieldName('property');
|
|
1816
|
-
if (createObj?.text === 'Object' && createProp?.text === 'create') {
|
|
1817
|
-
const createArgs = valueN.childForFieldName('arguments') || findChild(valueN, 'arguments');
|
|
1818
|
-
if (createArgs) {
|
|
1819
|
-
let proto = null;
|
|
1820
|
-
for (let i = 0; i < createArgs.childCount; i++) {
|
|
1821
|
-
const n = createArgs.child(i);
|
|
1822
|
-
if (n && n.type !== '(' && n.type !== ')' && n.type !== ',') {
|
|
1823
|
-
proto = n;
|
|
1824
|
-
break;
|
|
1825
|
-
}
|
|
1826
|
-
}
|
|
1827
|
-
if (proto?.type === 'object') {
|
|
1828
|
-
seedProtoProperties(nameN.text, proto, typeMap);
|
|
1829
|
-
}
|
|
1830
|
-
}
|
|
1831
|
-
return;
|
|
1832
|
-
}
|
|
1833
|
-
}
|
|
1834
|
-
// Phase 8.2: inter-procedural propagation — try to resolve return type from
|
|
1835
|
-
// the local returnTypeMap before falling back to factory heuristics.
|
|
1836
|
-
if (returnTypeMap) {
|
|
1837
|
-
const result = resolveCallExprReturnType(valueN, typeMap, returnTypeMap, 0);
|
|
1838
|
-
if (result) {
|
|
1839
|
-
setTypeMapEntry(typeMap, nameN.text, result.type, result.confidence);
|
|
1840
|
-
return;
|
|
1841
|
-
}
|
|
1842
|
-
}
|
|
1843
|
-
// Record for cross-file resolution in build-edges.ts (imported functions)
|
|
1844
|
-
if (callAssignments) {
|
|
1845
|
-
recordCallAssignment(valueN, nameN.text, typeMap, callAssignments);
|
|
1846
|
-
}
|
|
1847
|
-
// Factory method heuristic: const x = Foo.create() → type Foo, confidence 0.7
|
|
1848
|
-
const fn = valueN.childForFieldName('function');
|
|
1849
|
-
if (fn?.type === 'member_expression') {
|
|
1850
|
-
const obj = fn.childForFieldName('object');
|
|
1851
|
-
if (obj?.type === 'identifier') {
|
|
1852
|
-
const objName = obj.text;
|
|
1853
|
-
if (objName[0] &&
|
|
1854
|
-
objName[0] !== objName[0].toLowerCase() &&
|
|
1855
|
-
!BUILTIN_GLOBALS.has(objName)) {
|
|
1856
|
-
setTypeMapEntry(typeMap, nameN.text, objName, 0.7);
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
2210
|
+
handleCallExprTypeMap(nameN.text, valueN, typeMap, returnTypeMap, callAssignments);
|
|
2211
|
+
return;
|
|
1860
2212
|
}
|
|
1861
|
-
//
|
|
1862
|
-
// `const obj = { baz: () => {} }` → typeMap['obj.baz'] = 'obj.baz'
|
|
1863
|
-
// `const obj = { baz }` (shorthand) → typeMap['obj.baz'] = 'baz' (bare identifier target)
|
|
1864
|
-
// `const obj = { baz: otherFn }` → typeMap['obj.baz'] = 'otherFn' (identifier alias)
|
|
1865
|
-
//
|
|
1866
|
-
// For function/arrow values, the value is the qualified name ('obj.baz') because
|
|
1867
|
-
// extractObjectLiteralFunctions now registers definitions under that qualified name to avoid
|
|
1868
|
-
// polluting the global index with bare property names like 'init', 'run', or 'render'.
|
|
1869
|
-
// Enables accessor this-dispatch: when typeMap['getter:this'] = 'obj',
|
|
1870
|
-
// resolving this.baz() inside getter → typeMap['obj.baz'] → 'obj.baz' → lookup.byName('obj.baz').
|
|
1871
|
-
//
|
|
1872
|
-
// Scope guard: mirrors Rust handle_var_decl's find_parent_of_types check — skip object literals
|
|
1873
|
-
// inside function bodies so function-scoped `const localObj = { fn: ... }` never seeds
|
|
1874
|
-
// the typeMap (which would shadow a module-level `const obj` with the same property names).
|
|
2213
|
+
// 4b. Object literal — seed composite pts keys for module-level const objects.
|
|
1875
2214
|
if (valueN.type === 'object' && !hasFunctionScopeAncestor(node)) {
|
|
1876
|
-
|
|
1877
|
-
const child = valueN.child(i);
|
|
1878
|
-
if (!child)
|
|
1879
|
-
continue;
|
|
1880
|
-
if (child.type === 'shorthand_property_identifier') {
|
|
1881
|
-
setTypeMapEntry(typeMap, `${nameN.text}.${child.text}`, child.text, 0.85);
|
|
1882
|
-
}
|
|
1883
|
-
else if (child.type === 'pair') {
|
|
1884
|
-
const keyNode = child.childForFieldName('key');
|
|
1885
|
-
const valNode = child.childForFieldName('value');
|
|
1886
|
-
if (!keyNode || !valNode)
|
|
1887
|
-
continue;
|
|
1888
|
-
const keyName = keyNode.type === 'string' ? keyNode.text.replace(/^['"]|['"]$/g, '') : keyNode.text;
|
|
1889
|
-
if (!keyName)
|
|
1890
|
-
continue;
|
|
1891
|
-
const qualifiedKey = `${nameN.text}.${keyName}`;
|
|
1892
|
-
if (valNode.type === 'arrow_function' ||
|
|
1893
|
-
valNode.type === 'function_expression' ||
|
|
1894
|
-
valNode.type === 'function') {
|
|
1895
|
-
// Store the qualified name so the resolver finds the qualified definition.
|
|
1896
|
-
setTypeMapEntry(typeMap, qualifiedKey, qualifiedKey, 0.85);
|
|
1897
|
-
}
|
|
1898
|
-
else if (valNode.type === 'identifier') {
|
|
1899
|
-
setTypeMapEntry(typeMap, qualifiedKey, valNode.text, 0.85);
|
|
1900
|
-
}
|
|
1901
|
-
}
|
|
1902
|
-
else if (child.type === 'method_definition') {
|
|
1903
|
-
// Method shorthand: `const obj = { baz() {} }` → typeMap['obj.baz'] = 'obj.baz'
|
|
1904
|
-
// extractObjectLiteralFunctions registers a definition under the qualified name;
|
|
1905
|
-
// seed the matching typeMap entry so the two-step accessor dispatch finds it.
|
|
1906
|
-
const nameNode = child.childForFieldName('name');
|
|
1907
|
-
if (!nameNode)
|
|
1908
|
-
continue;
|
|
1909
|
-
const qualifiedKey = `${nameN.text}.${nameNode.text}`;
|
|
1910
|
-
setTypeMapEntry(typeMap, qualifiedKey, qualifiedKey, 0.85);
|
|
1911
|
-
}
|
|
1912
|
-
}
|
|
2215
|
+
handleObjectLiteralTypeMap(nameN.text, valueN, typeMap);
|
|
1913
2216
|
}
|
|
1914
2217
|
}
|
|
1915
2218
|
/** Extract type info from a required_parameter or optional_parameter. */
|
|
@@ -1924,6 +2227,51 @@ function handleParamTypeMap(node, typeMap) {
|
|
|
1924
2227
|
setTypeMapEntry(typeMap, nameNode.text, typeName, 0.9);
|
|
1925
2228
|
}
|
|
1926
2229
|
}
|
|
2230
|
+
/**
|
|
2231
|
+
* Extract type info from a class field declaration: `private repo: Repository<User>`.
|
|
2232
|
+
*
|
|
2233
|
+
* Seeds a class-scoped key `ClassName.field` (confidence 0.9) as the primary entry
|
|
2234
|
+
* so that two classes with identically-named fields don't overwrite each other's
|
|
2235
|
+
* typeMap entry (issue #1458). The resolver's `CallerClass.X` fallback (call-resolver.ts
|
|
2236
|
+
* line 110) looks up exactly this key.
|
|
2237
|
+
*
|
|
2238
|
+
* Bare `field` and `this.field` keys are kept at lower confidence (0.6) as fallbacks
|
|
2239
|
+
* for single-class files where the resolver may not have a callerClass context.
|
|
2240
|
+
*
|
|
2241
|
+
* Mirrors the field_definition branch of match_js_type_map in
|
|
2242
|
+
* crates/codegraph-core/src/extractors/javascript.rs.
|
|
2243
|
+
*/
|
|
2244
|
+
function handleFieldDefTypeMap(node, typeMap, currentClass) {
|
|
2245
|
+
const nameNode = node.childForFieldName('name') ||
|
|
2246
|
+
node.childForFieldName('property') ||
|
|
2247
|
+
findChild(node, 'property_identifier');
|
|
2248
|
+
if (!nameNode)
|
|
2249
|
+
return;
|
|
2250
|
+
const kind = nameNode.type;
|
|
2251
|
+
if (kind !== 'property_identifier' &&
|
|
2252
|
+
kind !== 'identifier' &&
|
|
2253
|
+
kind !== 'private_property_identifier')
|
|
2254
|
+
return;
|
|
2255
|
+
const typeAnno = findChild(node, 'type_annotation');
|
|
2256
|
+
if (!typeAnno)
|
|
2257
|
+
return;
|
|
2258
|
+
const typeName = extractSimpleTypeName(typeAnno);
|
|
2259
|
+
if (!typeName)
|
|
2260
|
+
return;
|
|
2261
|
+
if (currentClass) {
|
|
2262
|
+
// Primary: class-scoped key prevents cross-class collision (issue #1458).
|
|
2263
|
+
setTypeMapEntry(typeMap, `${currentClass}.${nameNode.text}`, typeName, 0.9);
|
|
2264
|
+
// Fallback: bare keys at lower confidence for single-class files or when
|
|
2265
|
+
// the resolver does not have a callerClass in scope.
|
|
2266
|
+
setTypeMapEntry(typeMap, nameNode.text, typeName, 0.6);
|
|
2267
|
+
setTypeMapEntry(typeMap, `this.${nameNode.text}`, typeName, 0.6);
|
|
2268
|
+
}
|
|
2269
|
+
else {
|
|
2270
|
+
// No enclosing class declaration (e.g. class expression) — use bare keys only.
|
|
2271
|
+
setTypeMapEntry(typeMap, nameNode.text, typeName, 0.9);
|
|
2272
|
+
setTypeMapEntry(typeMap, `this.${nameNode.text}`, typeName, 0.9);
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
1927
2275
|
/**
|
|
1928
2276
|
* Phase 8.3d: seed the pts map from object property writes.
|
|
1929
2277
|
*
|
|
@@ -2450,6 +2798,31 @@ function extractReceiverName(objNode) {
|
|
|
2450
2798
|
function extractCallInfo(fn, callNode) {
|
|
2451
2799
|
const fnType = fn.type;
|
|
2452
2800
|
if (fnType === 'identifier') {
|
|
2801
|
+
if (fn.text === 'eval') {
|
|
2802
|
+
// eval(code) — dynamic code execution; capture first arg if it's a string literal
|
|
2803
|
+
const args = callNode.childForFieldName('arguments') || findChild(callNode, 'arguments');
|
|
2804
|
+
let keyExpr;
|
|
2805
|
+
if (args) {
|
|
2806
|
+
for (let i = 0; i < args.childCount; i++) {
|
|
2807
|
+
const child = args.child(i);
|
|
2808
|
+
if (!child)
|
|
2809
|
+
continue;
|
|
2810
|
+
const t = child.type;
|
|
2811
|
+
if (t === '(' || t === ')' || t === ',')
|
|
2812
|
+
continue;
|
|
2813
|
+
if (t === 'string' || t === 'template_string')
|
|
2814
|
+
keyExpr = child.text;
|
|
2815
|
+
break;
|
|
2816
|
+
}
|
|
2817
|
+
}
|
|
2818
|
+
return {
|
|
2819
|
+
name: '<dynamic:eval>',
|
|
2820
|
+
line: nodeStartLine(callNode),
|
|
2821
|
+
dynamic: true,
|
|
2822
|
+
dynamicKind: 'eval',
|
|
2823
|
+
keyExpr,
|
|
2824
|
+
};
|
|
2825
|
+
}
|
|
2453
2826
|
return { name: fn.text, line: nodeStartLine(callNode) };
|
|
2454
2827
|
}
|
|
2455
2828
|
if (fnType === 'member_expression') {
|
|
@@ -2460,6 +2833,46 @@ function extractCallInfo(fn, callNode) {
|
|
|
2460
2833
|
}
|
|
2461
2834
|
return null;
|
|
2462
2835
|
}
|
|
2836
|
+
/** Return the first non-punctuation argument node from a call_expression. */
|
|
2837
|
+
function getFirstCallArg(callNode) {
|
|
2838
|
+
const args = callNode.childForFieldName('arguments') || findChild(callNode, 'arguments');
|
|
2839
|
+
if (!args)
|
|
2840
|
+
return null;
|
|
2841
|
+
for (let i = 0; i < args.childCount; i++) {
|
|
2842
|
+
const child = args.child(i);
|
|
2843
|
+
if (!child)
|
|
2844
|
+
continue;
|
|
2845
|
+
const t = child.type;
|
|
2846
|
+
if (t === '(' || t === ')' || t === ',')
|
|
2847
|
+
continue;
|
|
2848
|
+
return child;
|
|
2849
|
+
}
|
|
2850
|
+
return null;
|
|
2851
|
+
}
|
|
2852
|
+
/** Extract the logical callee from a Reflect.apply/call/construct first-arg. */
|
|
2853
|
+
function extractReflectCalleeFromArg(firstArg, callLine) {
|
|
2854
|
+
if (firstArg?.type === 'identifier') {
|
|
2855
|
+
return { name: firstArg.text, line: callLine, dynamic: true, dynamicKind: 'reflection' };
|
|
2856
|
+
}
|
|
2857
|
+
if (firstArg?.type === 'member_expression') {
|
|
2858
|
+
const innerProp = firstArg.childForFieldName('property');
|
|
2859
|
+
if (innerProp?.type === 'identifier') {
|
|
2860
|
+
return {
|
|
2861
|
+
name: innerProp.text,
|
|
2862
|
+
line: callLine,
|
|
2863
|
+
dynamic: true,
|
|
2864
|
+
dynamicKind: 'reflection',
|
|
2865
|
+
receiver: extractReceiverName(firstArg.childForFieldName('object')),
|
|
2866
|
+
};
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
return {
|
|
2870
|
+
name: '<dynamic:unresolved>',
|
|
2871
|
+
line: callLine,
|
|
2872
|
+
dynamic: true,
|
|
2873
|
+
dynamicKind: 'unresolved-dynamic',
|
|
2874
|
+
};
|
|
2875
|
+
}
|
|
2463
2876
|
/** Extract call info from a member_expression function node (obj.method()). */
|
|
2464
2877
|
function extractMemberExprCallInfo(fn, callNode) {
|
|
2465
2878
|
const obj = fn.childForFieldName('object');
|
|
@@ -2468,29 +2881,107 @@ function extractMemberExprCallInfo(fn, callNode) {
|
|
|
2468
2881
|
return null;
|
|
2469
2882
|
const callLine = nodeStartLine(callNode);
|
|
2470
2883
|
const propText = prop.text;
|
|
2471
|
-
|
|
2884
|
+
const isReflect = obj?.type === 'identifier' && obj.text === 'Reflect';
|
|
2885
|
+
// Reflect.apply(fn, thisArg, args) — extract the first arg as callee
|
|
2886
|
+
// Note: Reflect.call does not exist in the ECMAScript spec (only Reflect.apply, construct, get, etc.)
|
|
2887
|
+
if (isReflect && propText === 'apply') {
|
|
2888
|
+
return extractReflectCalleeFromArg(getFirstCallArg(callNode), callLine);
|
|
2889
|
+
}
|
|
2890
|
+
// Reflect.construct(Target, args) — extract the constructor as the callee
|
|
2891
|
+
if (isReflect && propText === 'construct') {
|
|
2892
|
+
return extractReflectCalleeFromArg(getFirstCallArg(callNode), callLine);
|
|
2893
|
+
}
|
|
2894
|
+
// Reflect.get(target, prop) — property access via reflection
|
|
2895
|
+
if (isReflect && propText === 'get') {
|
|
2896
|
+
const args = callNode.childForFieldName('arguments') || findChild(callNode, 'arguments');
|
|
2897
|
+
if (args) {
|
|
2898
|
+
let argIdx = 0;
|
|
2899
|
+
let firstArg = null;
|
|
2900
|
+
let secondArg = null;
|
|
2901
|
+
for (let i = 0; i < args.childCount; i++) {
|
|
2902
|
+
const child = args.child(i);
|
|
2903
|
+
if (!child)
|
|
2904
|
+
continue;
|
|
2905
|
+
const t = child.type;
|
|
2906
|
+
if (t === '(' || t === ')' || t === ',')
|
|
2907
|
+
continue;
|
|
2908
|
+
if (argIdx === 0)
|
|
2909
|
+
firstArg = child;
|
|
2910
|
+
else if (argIdx === 1)
|
|
2911
|
+
secondArg = child;
|
|
2912
|
+
argIdx++;
|
|
2913
|
+
}
|
|
2914
|
+
if (secondArg) {
|
|
2915
|
+
const receiver = firstArg ? extractReceiverName(firstArg) : undefined;
|
|
2916
|
+
const st = secondArg.type;
|
|
2917
|
+
if (st === 'string' || st === 'string_fragment') {
|
|
2918
|
+
const propName = secondArg.text.replace(/['"]/g, '');
|
|
2919
|
+
if (propName) {
|
|
2920
|
+
return {
|
|
2921
|
+
name: propName,
|
|
2922
|
+
line: callLine,
|
|
2923
|
+
dynamic: true,
|
|
2924
|
+
dynamicKind: 'computed-literal',
|
|
2925
|
+
keyExpr: secondArg.text,
|
|
2926
|
+
receiver,
|
|
2927
|
+
};
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
if (st === 'identifier') {
|
|
2931
|
+
return {
|
|
2932
|
+
name: '<dynamic:computed-key>',
|
|
2933
|
+
line: callLine,
|
|
2934
|
+
dynamic: true,
|
|
2935
|
+
dynamicKind: 'computed-key',
|
|
2936
|
+
keyExpr: secondArg.text,
|
|
2937
|
+
receiver,
|
|
2938
|
+
};
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
return {
|
|
2943
|
+
name: '<dynamic:unresolved>',
|
|
2944
|
+
line: callLine,
|
|
2945
|
+
dynamic: true,
|
|
2946
|
+
dynamicKind: 'unresolved-dynamic',
|
|
2947
|
+
};
|
|
2948
|
+
}
|
|
2949
|
+
// .call()/.apply()/.bind() — this-rebinding; the wrapped function is the real callee.
|
|
2950
|
+
// When the object is a plain identifier (e.g. `f.call({})`), the target is statically
|
|
2951
|
+
// known so we emit a static call (no dynamic flag). This keeps parity with the native
|
|
2952
|
+
// Rust engine, which also resolves these as dyn=0, and prevents the dynZeroEdgeRows
|
|
2953
|
+
// upgrade path in emitDirectCallEdgesForCall from wrongly converting a dyn=0 edge
|
|
2954
|
+
// (emitted by a prior direct `f()` call) to dyn=1.
|
|
2955
|
+
// When the object is a member_expression (e.g. `obj.method.call({})`), we still mark
|
|
2956
|
+
// it dynamic/reflection because the inner callee requires a second resolution hop.
|
|
2472
2957
|
if (propText === 'call' || propText === 'apply' || propText === 'bind') {
|
|
2473
2958
|
if (obj && obj.type === 'identifier')
|
|
2474
|
-
return { name: obj.text, line: callLine
|
|
2959
|
+
return { name: obj.text, line: callLine };
|
|
2475
2960
|
if (obj && obj.type === 'member_expression') {
|
|
2476
2961
|
const innerProp = obj.childForFieldName('property');
|
|
2477
2962
|
if (innerProp)
|
|
2478
|
-
return { name: innerProp.text, line: callLine, dynamic: true };
|
|
2963
|
+
return { name: innerProp.text, line: callLine, dynamic: true, dynamicKind: 'reflection' };
|
|
2479
2964
|
}
|
|
2480
2965
|
}
|
|
2481
|
-
// Computed property: obj["method"]()
|
|
2966
|
+
// Computed string property: obj["method"]() — target is a literal; resolvable
|
|
2482
2967
|
const propType = prop.type;
|
|
2483
2968
|
if (propType === 'string' || propType === 'string_fragment') {
|
|
2484
2969
|
const methodName = propText.replace(/['"]/g, '');
|
|
2485
2970
|
if (methodName) {
|
|
2486
2971
|
const receiver = extractReceiverName(obj);
|
|
2487
|
-
return {
|
|
2972
|
+
return {
|
|
2973
|
+
name: methodName,
|
|
2974
|
+
line: callLine,
|
|
2975
|
+
dynamic: true,
|
|
2976
|
+
dynamicKind: 'computed-literal',
|
|
2977
|
+
receiver,
|
|
2978
|
+
};
|
|
2488
2979
|
}
|
|
2489
2980
|
}
|
|
2490
2981
|
const receiver = extractReceiverName(obj);
|
|
2491
2982
|
return { name: propText, line: callLine, receiver };
|
|
2492
2983
|
}
|
|
2493
|
-
/** Extract call info from a subscript_expression function node (obj[
|
|
2984
|
+
/** Extract call info from a subscript_expression function node (obj[key]()). */
|
|
2494
2985
|
function extractSubscriptCallInfo(fn, callNode) {
|
|
2495
2986
|
const obj = fn.childForFieldName('object');
|
|
2496
2987
|
const index = fn.childForFieldName('index');
|
|
@@ -2505,11 +2996,30 @@ function extractSubscriptCallInfo(fn, callNode) {
|
|
|
2505
2996
|
name: methodName,
|
|
2506
2997
|
line: nodeStartLine(callNode),
|
|
2507
2998
|
dynamic: true,
|
|
2999
|
+
dynamicKind: 'computed-literal',
|
|
2508
3000
|
receiver,
|
|
2509
3001
|
};
|
|
2510
3002
|
}
|
|
2511
3003
|
}
|
|
2512
|
-
|
|
3004
|
+
// obj[variable]() — key is a variable; may be resolvable via pts (RES-1), else flagged
|
|
3005
|
+
if (indexType === 'identifier') {
|
|
3006
|
+
const receiver = extractReceiverName(obj);
|
|
3007
|
+
return {
|
|
3008
|
+
name: '<dynamic:computed-key>',
|
|
3009
|
+
line: nodeStartLine(callNode),
|
|
3010
|
+
dynamic: true,
|
|
3011
|
+
dynamicKind: 'computed-key',
|
|
3012
|
+
keyExpr: index.text,
|
|
3013
|
+
receiver,
|
|
3014
|
+
};
|
|
3015
|
+
}
|
|
3016
|
+
// Any other index expression (binary, call, template with ${}…) — not statically resolvable
|
|
3017
|
+
return {
|
|
3018
|
+
name: '<dynamic:unresolved>',
|
|
3019
|
+
line: nodeStartLine(callNode),
|
|
3020
|
+
dynamic: true,
|
|
3021
|
+
dynamicKind: 'unresolved-dynamic',
|
|
3022
|
+
};
|
|
2513
3023
|
}
|
|
2514
3024
|
/**
|
|
2515
3025
|
* Callee names that idiomatically accept callback references. Used to gate
|
|
@@ -2798,6 +3308,11 @@ function runCollectorWalk(rootNode, targets) {
|
|
|
2798
3308
|
targets.newExpressions.push(name);
|
|
2799
3309
|
break;
|
|
2800
3310
|
}
|
|
3311
|
+
case 'decorator': {
|
|
3312
|
+
if (targets.calls)
|
|
3313
|
+
handleDecorator(node, targets.calls);
|
|
3314
|
+
break;
|
|
3315
|
+
}
|
|
2801
3316
|
case 'field_definition':
|
|
2802
3317
|
case 'public_field_definition':
|
|
2803
3318
|
if (targets.classMemberDefs)
|
|
@@ -3092,11 +3607,13 @@ function handlePrototypeAssignment(lhs, rhs, definitions, typeMap) {
|
|
|
3092
3607
|
function emitPrototypeMethod(className, methodName, rhs, definitions, typeMap) {
|
|
3093
3608
|
const fullName = `${className}.${methodName}`;
|
|
3094
3609
|
if (rhs.type === 'function_expression' || rhs.type === 'arrow_function') {
|
|
3610
|
+
const params = extractParameters(rhs);
|
|
3095
3611
|
definitions.push({
|
|
3096
3612
|
name: fullName,
|
|
3097
3613
|
kind: 'method',
|
|
3098
3614
|
line: nodeStartLine(rhs),
|
|
3099
3615
|
endLine: nodeEndLine(rhs),
|
|
3616
|
+
children: params.length > 0 ? params : undefined,
|
|
3100
3617
|
});
|
|
3101
3618
|
}
|
|
3102
3619
|
else if (rhs.type === 'identifier' && !BUILTIN_GLOBALS.has(rhs.text)) {
|