@unerr-ai/unerr 0.2.0 → 0.2.2
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 +6 -0
- package/dist/cli.js +37236 -35793
- package/package.json +6 -1
- package/dist/behaviors/agent-llm-bridge.js +0 -166
- package/dist/behaviors/architecture-guard.js +0 -256
- package/dist/behaviors/auto-doc.js +0 -247
- package/dist/behaviors/cascade-guard.js +0 -289
- package/dist/behaviors/change-narrative.js +0 -270
- package/dist/behaviors/convention-drift.js +0 -290
- package/dist/behaviors/framework.js +0 -235
- package/dist/behaviors/guard-formatter.js +0 -44
- package/dist/behaviors/incomplete-work.js +0 -270
- package/dist/behaviors/loop-breaker.js +0 -300
- package/dist/behaviors/session-continuity.js +0 -208
- package/dist/commands/branches.js +0 -97
- package/dist/commands/check-commit.js +0 -225
- package/dist/commands/compress-output.js +0 -64
- package/dist/commands/config-verify.js +0 -243
- package/dist/commands/daemon.js +0 -905
- package/dist/commands/dashboard.js +0 -52
- package/dist/commands/debug.js +0 -200
- package/dist/commands/enrich.js +0 -184
- package/dist/commands/exec.js +0 -233
- package/dist/commands/gain.js +0 -156
- package/dist/commands/hook.js +0 -88
- package/dist/commands/index.js +0 -88
- package/dist/commands/init.js +0 -74
- package/dist/commands/install.js +0 -505
- package/dist/commands/learn.js +0 -116
- package/dist/commands/manifest.js +0 -193
- package/dist/commands/rewind.js +0 -103
- package/dist/commands/serve.js +0 -19
- package/dist/commands/setup-wizard.js +0 -414
- package/dist/commands/skills.js +0 -64
- package/dist/commands/stats.js +0 -20
- package/dist/commands/status.js +0 -654
- package/dist/commands/timeline.js +0 -139
- package/dist/commands/uninstall.js +0 -230
- package/dist/components/App.js +0 -109
- package/dist/components/Banner.js +0 -12
- package/dist/components/ConfirmPrompt.js +0 -25
- package/dist/components/DriftSummary.js +0 -23
- package/dist/components/GradeBadge.js +0 -15
- package/dist/components/HealthCard.js +0 -18
- package/dist/components/InkSpinner.js +0 -22
- package/dist/components/InputBox.js +0 -17
- package/dist/components/KeyValue.js +0 -13
- package/dist/components/MessageList.js +0 -14
- package/dist/components/ProgressBar.js +0 -26
- package/dist/components/Section.js +0 -16
- package/dist/components/SessionSummaryCard.js +0 -73
- package/dist/components/StartupDisplay.js +0 -24
- package/dist/components/StatusDashboard.js +0 -57
- package/dist/components/StatusLine.js +0 -8
- package/dist/components/StepLine.js +0 -22
- package/dist/components/Theme.js +0 -20
- package/dist/components/ToolProgress.js +0 -8
- package/dist/components/ViolationList.js +0 -21
- package/dist/components/render.js +0 -13
- package/dist/config/agent-registry.js +0 -237
- package/dist/config/claude-settings-hooks.js +0 -304
- package/dist/config/hook-installer.js +0 -65
- package/dist/config/instruction-writer.js +0 -388
- package/dist/config/mcp-config-writer.js +0 -266
- package/dist/config/settings.js +0 -174
- package/dist/config/tool-detector.js +0 -42
- package/dist/config/value-surfacing.js +0 -119
- package/dist/core/context-assembly.js +0 -108
- package/dist/core/conversation.js +0 -33
- package/dist/core/local-chat-provider.js +0 -475
- package/dist/core/provider-factory.js +0 -55
- package/dist/core/providers.js +0 -90
- package/dist/core/query-engine.js +0 -174
- package/dist/daemon/api.js +0 -312
- package/dist/daemon/autostart.js +0 -119
- package/dist/daemon/bootstrap.js +0 -39
- package/dist/daemon/client.js +0 -164
- package/dist/daemon/detect-ci.js +0 -81
- package/dist/daemon/platform-linux.js +0 -146
- package/dist/daemon/platform-macos.js +0 -134
- package/dist/daemon/platform-windows.js +0 -116
- package/dist/daemon/process-manager.js +0 -299
- package/dist/daemon/protocol.js +0 -23
- package/dist/daemon/registry.js +0 -270
- package/dist/daemon/settings-schema.js +0 -72
- package/dist/daemon/system-health.js +0 -134
- package/dist/daemon/version-checker.js +0 -262
- package/dist/daemon/warm-start.js +0 -223
- package/dist/entrypoints/cli.js +0 -1043
- package/dist/entrypoints/daemon.js +0 -380
- package/dist/entrypoints/repl.js +0 -147
- package/dist/hooks/adapters/claude-code.js +0 -90
- package/dist/hooks/adapters/cline.js +0 -100
- package/dist/hooks/adapters/cursor.js +0 -98
- package/dist/hooks/hook-dedup.js +0 -79
- package/dist/hooks/hook-runner.js +0 -113
- package/dist/hooks/navigation-hooks.js +0 -175
- package/dist/hooks/prompt-hooks.js +0 -63
- package/dist/hooks/shell-hooks.js +0 -47
- package/dist/ignore.js +0 -111
- package/dist/intelligence/approach-suggester.js +0 -61
- package/dist/intelligence/ast-extractor.js +0 -2615
- package/dist/intelligence/ast-worker.js +0 -34
- package/dist/intelligence/background-indexer.js +0 -121
- package/dist/intelligence/blast-radius.js +0 -200
- package/dist/intelligence/community-detection.js +0 -691
- package/dist/intelligence/community-detector.js +0 -184
- package/dist/intelligence/computation-scheduler.js +0 -75
- package/dist/intelligence/confidence-propagation.js +0 -47
- package/dist/intelligence/convention-detector.js +0 -242
- package/dist/intelligence/convention-learner.js +0 -205
- package/dist/intelligence/convention-matcher.js +0 -205
- package/dist/intelligence/cozo-schema.js +0 -376
- package/dist/intelligence/decision-point-detector.js +0 -90
- package/dist/intelligence/deep-dive-tools.js +0 -586
- package/dist/intelligence/durability-scorer.js +0 -84
- package/dist/intelligence/exploration-cost.js +0 -204
- package/dist/intelligence/exploration-pattern-tracker.js +0 -61
- package/dist/intelligence/fact-generator.js +0 -322
- package/dist/intelligence/facts-schema.js +0 -90
- package/dist/intelligence/file-intelligence.js +0 -59
- package/dist/intelligence/graph-holder.js +0 -220
- package/dist/intelligence/graph-temporal-joiner.js +0 -238
- package/dist/intelligence/health-grade.js +0 -423
- package/dist/intelligence/health-grader.js +0 -200
- package/dist/intelligence/health-map-data.js +0 -259
- package/dist/intelligence/import-symbols.js +0 -136
- package/dist/intelligence/incremental-indexer.js +0 -658
- package/dist/intelligence/indexer/centrality.js +0 -62
- package/dist/intelligence/indexer/cfg-context.js +0 -95
- package/dist/intelligence/indexer/confidence.js +0 -34
- package/dist/intelligence/indexer/cross-file-resolver.js +0 -104
- package/dist/intelligence/indexer/edge-repair.js +0 -89
- package/dist/intelligence/indexer/entity-key.js +0 -17
- package/dist/intelligence/indexer/export-map.js +0 -132
- package/dist/intelligence/indexer/git-cochange.js +0 -128
- package/dist/intelligence/indexer/graph-patch.js +0 -147
- package/dist/intelligence/indexer/incremental.js +0 -78
- package/dist/intelligence/indexer/ingest.js +0 -160
- package/dist/intelligence/indexer/language-detect.js +0 -226
- package/dist/intelligence/indexer/metadata.js +0 -63
- package/dist/intelligence/indexer/mutation-tracker.js +0 -79
- package/dist/intelligence/indexer/orchestrator.js +0 -155
- package/dist/intelligence/indexer/plugin-interface.js +0 -31
- package/dist/intelligence/indexer/plugins/csharp.js +0 -440
- package/dist/intelligence/indexer/plugins/go.js +0 -335
- package/dist/intelligence/indexer/plugins/java.js +0 -370
- package/dist/intelligence/indexer/plugins/python.js +0 -358
- package/dist/intelligence/indexer/plugins/regex-fallback.js +0 -82
- package/dist/intelligence/indexer/plugins/ruby.js +0 -290
- package/dist/intelligence/indexer/plugins/rust.js +0 -484
- package/dist/intelligence/indexer/plugins/tier2-generic.js +0 -310
- package/dist/intelligence/indexer/plugins/typescript.js +0 -456
- package/dist/intelligence/indexer/resource-monitor.js +0 -93
- package/dist/intelligence/indexer/scip/decoder.js +0 -253
- package/dist/intelligence/indexer/scip/detector.js +0 -232
- package/dist/intelligence/indexer/scip/downloader.js +0 -427
- package/dist/intelligence/indexer/scip/fallback.js +0 -34
- package/dist/intelligence/indexer/scip/merger.js +0 -109
- package/dist/intelligence/indexer/scip/orchestrator.js +0 -433
- package/dist/intelligence/indexer/scip/runner.js +0 -98
- package/dist/intelligence/indexer/snapshot.js +0 -66
- package/dist/intelligence/indexer/test-detector.js +0 -196
- package/dist/intelligence/indexer/watch-integration.js +0 -61
- package/dist/intelligence/indexer/worker.js +0 -85
- package/dist/intelligence/local-convention-detector.js +0 -437
- package/dist/intelligence/local-embeddings.js +0 -190
- package/dist/intelligence/local-graph.js +0 -1946
- package/dist/intelligence/local-indexer.js +0 -1575
- package/dist/intelligence/local-llm.js +0 -163
- package/dist/intelligence/local-rule-generator.js +0 -154
- package/dist/intelligence/local-snapshot.js +0 -213
- package/dist/intelligence/negative-knowledge.js +0 -103
- package/dist/intelligence/persistent-db.js +0 -85
- package/dist/intelligence/query-router.js +0 -2556
- package/dist/intelligence/risk-classifier.js +0 -116
- package/dist/intelligence/rule-evaluator.js +0 -380
- package/dist/intelligence/rule-generator.js +0 -49
- package/dist/intelligence/search-index.js +0 -173
- package/dist/intelligence/semantic/docstring-extractor.js +0 -67
- package/dist/intelligence/semantic/embedding-store.js +0 -52
- package/dist/intelligence/semantic/enrichment-orchestrator.js +0 -48
- package/dist/intelligence/semantic/git-message-miner.js +0 -114
- package/dist/intelligence/semantic/identifier-tokenizer.js +0 -51
- package/dist/intelligence/semantic/node2vec-embeddings.js +0 -71
- package/dist/intelligence/semantic/node2vec-walks.js +0 -103
- package/dist/intelligence/semantic/path-domain-inference.js +0 -112
- package/dist/intelligence/semantic/similarity-engine.js +0 -60
- package/dist/intelligence/semantic/tfidf-vectors.js +0 -88
- package/dist/intelligence/session-brief-builder.js +0 -159
- package/dist/intelligence/session-context.js +0 -221
- package/dist/intelligence/session-health-monitor.js +0 -211
- package/dist/intelligence/session-narrative.js +0 -197
- package/dist/intelligence/session-pattern-analyzer.js +0 -218
- package/dist/intelligence/signal-scorer.js +0 -390
- package/dist/intelligence/signal-show-store.js +0 -182
- package/dist/intelligence/smart-truncate.js +0 -158
- package/dist/intelligence/subgraph-cache.js +0 -88
- package/dist/intelligence/temporal-facts.js +0 -494
- package/dist/intelligence/token-estimator.js +0 -100
- package/dist/intelligence/tool-injector.js +0 -87
- package/dist/intelligence/tree-sitter-loader.js +0 -71
- package/dist/intelligence/worker-pool.js +0 -116
- package/dist/proxy/arg-validator.js +0 -79
- package/dist/proxy/auto-bootstrap.js +0 -167
- package/dist/proxy/bridge.js +0 -147
- package/dist/proxy/budget-enforcer.js +0 -70
- package/dist/proxy/compression-quality-monitor.js +0 -160
- package/dist/proxy/compression-stats.js +0 -51
- package/dist/proxy/context-rot-detector.js +0 -137
- package/dist/proxy/drift-detector.js +0 -139
- package/dist/proxy/efficiency-tracker.js +0 -79
- package/dist/proxy/fact-ranking.js +0 -154
- package/dist/proxy/format-encoder.js +0 -266
- package/dist/proxy/http-transport.js +0 -90
- package/dist/proxy/lifecycle-actor.js +0 -55
- package/dist/proxy/lifecycle-machine.js +0 -187
- package/dist/proxy/log-tailer.js +0 -265
- package/dist/proxy/model-pricing.js +0 -98
- package/dist/proxy/network-firewall.js +0 -141
- package/dist/proxy/nudge-state.js +0 -93
- package/dist/proxy/output-compressor.js +0 -185
- package/dist/proxy/pid-lock.js +0 -291
- package/dist/proxy/proxy-context.js +0 -11
- package/dist/proxy/proxy.js +0 -2633
- package/dist/proxy/response-enrichment.js +0 -32
- package/dist/proxy/response-envelope.js +0 -313
- package/dist/proxy/session-dedup.js +0 -82
- package/dist/proxy/session-legend.js +0 -30
- package/dist/proxy/session-persistence.js +0 -210
- package/dist/proxy/session-resume.js +0 -94
- package/dist/proxy/session-stats.js +0 -513
- package/dist/proxy/shell-classifier.js +0 -1346
- package/dist/proxy/shell-compression-log.js +0 -93
- package/dist/proxy/shell-compressor.js +0 -390
- package/dist/proxy/shell-graph-boost.js +0 -202
- package/dist/proxy/shell-monitor-map.js +0 -18
- package/dist/proxy/shell-stats.js +0 -54
- package/dist/proxy/shell-strategies/cloud.js +0 -215
- package/dist/proxy/shell-strategies/diff.js +0 -159
- package/dist/proxy/shell-strategies/error-diagnostic.js +0 -796
- package/dist/proxy/shell-strategies/filter-dsl.js +0 -358
- package/dist/proxy/shell-strategies/git-status.js +0 -177
- package/dist/proxy/shell-strategies/key-value.js +0 -193
- package/dist/proxy/shell-strategies/log-text.js +0 -154
- package/dist/proxy/shell-strategies/omni.js +0 -188
- package/dist/proxy/shell-strategies/progress.js +0 -55
- package/dist/proxy/shell-strategies/redact.js +0 -76
- package/dist/proxy/shell-strategies/structured.js +0 -241
- package/dist/proxy/shell-strategies/tabular.js +0 -243
- package/dist/proxy/shell-strategies/test-results-types.js +0 -13
- package/dist/proxy/shell-strategies/test-results.js +0 -784
- package/dist/proxy/shell-strategies/tree-paths.js +0 -144
- package/dist/proxy/shell-strategies/yaml.js +0 -182
- package/dist/proxy/shell-tee.js +0 -111
- package/dist/proxy/signal-dedup.js +0 -171
- package/dist/proxy/startup-renderer.js +0 -158
- package/dist/proxy/task-token-display.js +0 -38
- package/dist/proxy/token-counter.js +0 -61
- package/dist/proxy/tool-clusters.js +0 -273
- package/dist/proxy/tool-definitions.js +0 -525
- package/dist/proxy/transport-mux.js +0 -229
- package/dist/proxy/wire-cap.js +0 -268
- package/dist/rules/developer.mozilla.org.json +0 -9
- package/dist/rules/github.com.json +0 -21
- package/dist/schemas/api/skills.js +0 -19
- package/dist/schemas/common/errors.js +0 -7
- package/dist/schemas/common/headers.js +0 -5
- package/dist/schemas/entities/edge.js +0 -25
- package/dist/schemas/entities/entity.js +0 -22
- package/dist/schemas/entities/rule.js +0 -18
- package/dist/schemas/index.js +0 -14
- package/dist/server/event-bus.js +0 -59
- package/dist/server/http.js +0 -156
- package/dist/server/middleware.js +0 -70
- package/dist/server/routes/drift.js +0 -97
- package/dist/server/routes/intelligence.js +0 -1217
- package/dist/server/routes/reasoning-quality.js +0 -444
- package/dist/server/routes/session.js +0 -86
- package/dist/server/routes/stream.js +0 -120
- package/dist/server/routes/system.js +0 -73
- package/dist/server/routes/temporal.js +0 -170
- package/dist/server/routes/timeline.js +0 -232
- package/dist/server/routes/token-flow.js +0 -403
- package/dist/skills/effectiveness-tracker.js +0 -93
- package/dist/skills/local-pack.js +0 -380
- package/dist/skills/resolver.js +0 -495
- package/dist/state-detector.js +0 -83
- package/dist/timeline/intent-detector.js +0 -263
- package/dist/timeline/loop-miner.js +0 -140
- package/dist/timeline/open-threads.js +0 -49
- package/dist/timeline/signal-reinforcer.js +0 -62
- package/dist/timeline/timeline-bootstrap.js +0 -151
- package/dist/timeline/timeline-store.js +0 -618
- package/dist/tools/coding/bash.js +0 -49
- package/dist/tools/coding/file-edit.js +0 -72
- package/dist/tools/coding/file-outline.js +0 -227
- package/dist/tools/coding/file-read-protocol.js +0 -425
- package/dist/tools/coding/file-read.js +0 -35
- package/dist/tools/coding/file-write.js +0 -43
- package/dist/tools/coding/glob-tool.js +0 -109
- package/dist/tools/coding/grep.js +0 -162
- package/dist/tools/coding/index.js +0 -27
- package/dist/tools/intelligence/index.js +0 -269
- package/dist/tools/intelligence/record-fact.js +0 -48
- package/dist/tools/intelligence/timeline-markers.js +0 -130
- package/dist/tools/registry.js +0 -47
- package/dist/tools/types.js +0 -8
- package/dist/tracking/auto-snapshot-triggers.js +0 -246
- package/dist/tracking/branch-context.js +0 -115
- package/dist/tracking/branch-snapshot.js +0 -217
- package/dist/tracking/causal-bridge.js +0 -317
- package/dist/tracking/circuit-breaker.js +0 -147
- package/dist/tracking/commit-watcher.js +0 -114
- package/dist/tracking/context-ledger.js +0 -119
- package/dist/tracking/correction-detector.js +0 -324
- package/dist/tracking/drift-tracker.js +0 -874
- package/dist/tracking/durability-tracker.js +0 -94
- package/dist/tracking/entity-rewind.js +0 -200
- package/dist/tracking/file-hash-state.js +0 -114
- package/dist/tracking/git-attribution.js +0 -132
- package/dist/tracking/git-trailers.js +0 -171
- package/dist/tracking/intelligence-counter.js +0 -46
- package/dist/tracking/intent-correlator.js +0 -202
- package/dist/tracking/intent-encoder.js +0 -52
- package/dist/tracking/intent-token-tracker.js +0 -159
- package/dist/tracking/ledger-archiver.js +0 -94
- package/dist/tracking/ledger-chains.js +0 -245
- package/dist/tracking/metrics-store.js +0 -361
- package/dist/tracking/native-watcher.js +0 -131
- package/dist/tracking/offline-rewind.js +0 -295
- package/dist/tracking/pending-violations.js +0 -74
- package/dist/tracking/persistence-effectiveness.js +0 -167
- package/dist/tracking/prompt-durability.js +0 -202
- package/dist/tracking/quality-signals.js +0 -213
- package/dist/tracking/redactor.js +0 -73
- package/dist/tracking/rewind-engine.js +0 -161
- package/dist/tracking/session-history.js +0 -128
- package/dist/tracking/session-receipt.js +0 -88
- package/dist/tracking/session-summary-writer.js +0 -157
- package/dist/tracking/shadow-ledger.js +0 -321
- package/dist/tracking/stash-manager.js +0 -258
- package/dist/tracking/timeline-fork.js +0 -213
- package/dist/tracking/timeline.js +0 -69
- package/dist/tracking/token-flow.js +0 -276
- package/dist/tracking/turn-segmenter.js +0 -122
- package/dist/tracking/weekly-accumulator.js +0 -179
- package/dist/tracking/working-snapshots.js +0 -188
- package/dist/tracking/workspace-manifest.js +0 -176
- package/dist/transport/http.js +0 -102
- package/dist/utils/counterfactual.js +0 -65
- package/dist/utils/deep-link.js +0 -34
- package/dist/utils/detect.js +0 -193
- package/dist/utils/exec.js +0 -73
- package/dist/utils/file-logger.js +0 -87
- package/dist/utils/format-error.js +0 -29
- package/dist/utils/git.js +0 -181
- package/dist/utils/log.js +0 -57
- package/dist/utils/logger.js +0 -35
- package/dist/utils/mcp-content-json.js +0 -8
- package/dist/utils/session-logger.js +0 -154
- package/dist/utils/startup-log.js +0 -512
- package/dist/utils/ui.js +0 -56
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* State Mutation Detector — tracks assignments to member expressions.
|
|
3
|
-
*
|
|
4
|
-
* Detects when code modifies object state:
|
|
5
|
-
* - this.x = value → "writes" edge from method to property
|
|
6
|
-
* - obj.field = value → "writes" edge from scope to external entity
|
|
7
|
-
* - array[i] = value → mutation detected
|
|
8
|
-
*
|
|
9
|
-
* These "writes" edges are critical for blast radius computation:
|
|
10
|
-
* a function that mutates shared state has a wider blast radius.
|
|
11
|
-
*/
|
|
12
|
-
/**
|
|
13
|
-
* Detect state mutations within a function/method body.
|
|
14
|
-
*/
|
|
15
|
-
export function detectMutations(bodyNode) {
|
|
16
|
-
const mutations = [];
|
|
17
|
-
function visit(node) {
|
|
18
|
-
if (node.type === "assignment_expression" ||
|
|
19
|
-
node.type === "augmented_assignment_expression") {
|
|
20
|
-
const left = node.childForFieldName("left") ?? node.namedChildren[0];
|
|
21
|
-
if (left?.type === "member_expression") {
|
|
22
|
-
const object = left.childForFieldName("object") ?? left.namedChildren[0];
|
|
23
|
-
const property = left.childForFieldName("property") ?? left.namedChildren[1];
|
|
24
|
-
if (object && property) {
|
|
25
|
-
const isThis = object.text === "this";
|
|
26
|
-
mutations.push({
|
|
27
|
-
target: left.text,
|
|
28
|
-
isThisMutation: isThis,
|
|
29
|
-
line: node.startPosition.row + 1,
|
|
30
|
-
propertyName: property.text,
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
if (left?.type === "subscript_expression") {
|
|
35
|
-
const object = left.namedChildren[0];
|
|
36
|
-
if (object) {
|
|
37
|
-
mutations.push({
|
|
38
|
-
target: object.text,
|
|
39
|
-
isThisMutation: object.text === "this",
|
|
40
|
-
line: node.startPosition.row + 1,
|
|
41
|
-
propertyName: "[index]",
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
if (node.type === "update_expression") {
|
|
47
|
-
const arg = node.namedChildren[0];
|
|
48
|
-
if (arg?.type === "member_expression") {
|
|
49
|
-
const object = arg.childForFieldName("object") ?? arg.namedChildren[0];
|
|
50
|
-
const property = arg.childForFieldName("property") ?? arg.namedChildren[1];
|
|
51
|
-
if (object && property) {
|
|
52
|
-
mutations.push({
|
|
53
|
-
target: arg.text,
|
|
54
|
-
isThisMutation: object.text === "this",
|
|
55
|
-
line: node.startPosition.row + 1,
|
|
56
|
-
propertyName: property.text,
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
for (const child of node.namedChildren) {
|
|
62
|
-
visit(child);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
visit(bodyNode);
|
|
66
|
-
return mutations;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Convert mutation sites into "writes" edges.
|
|
70
|
-
*/
|
|
71
|
-
export function mutationsToEdges(mutations, scopeKey, filePath) {
|
|
72
|
-
return mutations.map((m) => ({
|
|
73
|
-
from_key: scopeKey,
|
|
74
|
-
to_key: `property:${m.target}`,
|
|
75
|
-
type: "writes",
|
|
76
|
-
file_path: filePath,
|
|
77
|
-
line: m.line,
|
|
78
|
-
}));
|
|
79
|
-
}
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Indexer Orchestrator — file discovery → plugin dispatch → results merge.
|
|
3
|
-
*
|
|
4
|
-
* Discovers source files, selects the appropriate language plugin, parses
|
|
5
|
-
* via tree-sitter, extracts entities + edges, and returns the merged result.
|
|
6
|
-
*
|
|
7
|
-
* Supports both single-file and batch-file indexing.
|
|
8
|
-
* Worker pool integration is optional (see worker.ts).
|
|
9
|
-
*/
|
|
10
|
-
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
11
|
-
import { join, relative } from "node:path";
|
|
12
|
-
import { createModuleLogger } from "../../utils/logger.js";
|
|
13
|
-
import { parseSource } from "../tree-sitter-loader.js";
|
|
14
|
-
import { getPluginForFile, } from "./plugin-interface.js";
|
|
15
|
-
const log = createModuleLogger("indexer");
|
|
16
|
-
const DEFAULT_IGNORE = new Set([
|
|
17
|
-
"node_modules",
|
|
18
|
-
".git",
|
|
19
|
-
".unerr",
|
|
20
|
-
"dist",
|
|
21
|
-
"build",
|
|
22
|
-
"out",
|
|
23
|
-
".next",
|
|
24
|
-
".nuxt",
|
|
25
|
-
"coverage",
|
|
26
|
-
"__pycache__",
|
|
27
|
-
".venv",
|
|
28
|
-
"vendor",
|
|
29
|
-
]);
|
|
30
|
-
/**
|
|
31
|
-
* Path-prefix exclusions (relative to projectRoot). Used in addition to
|
|
32
|
-
* the basename-only DEFAULT_IGNORE check above to handle agent worktrees
|
|
33
|
-
* precisely without over-matching user-named `worktrees/` folders.
|
|
34
|
-
*/
|
|
35
|
-
const EXCLUDED_PATH_PREFIXES = [
|
|
36
|
-
".claude/worktrees",
|
|
37
|
-
".cursor/worktrees",
|
|
38
|
-
".idea/worktrees",
|
|
39
|
-
];
|
|
40
|
-
function isExcludedPath(relPath) {
|
|
41
|
-
for (const prefix of EXCLUDED_PATH_PREFIXES) {
|
|
42
|
-
if (relPath === prefix || relPath.startsWith(`${prefix}/`))
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
const MAX_FILE_SIZE = 500 * 1024;
|
|
48
|
-
/**
|
|
49
|
-
* Discover all indexable source files in a project.
|
|
50
|
-
*/
|
|
51
|
-
export function discoverFiles(projectRoot, ignorePatterns = DEFAULT_IGNORE) {
|
|
52
|
-
const files = [];
|
|
53
|
-
function walk(dir) {
|
|
54
|
-
let entries;
|
|
55
|
-
try {
|
|
56
|
-
entries = readdirSync(dir);
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
for (const entry of entries) {
|
|
62
|
-
if (entry.startsWith(".") && entry !== ".")
|
|
63
|
-
continue;
|
|
64
|
-
if (ignorePatterns.has(entry))
|
|
65
|
-
continue;
|
|
66
|
-
const fullPath = join(dir, entry);
|
|
67
|
-
// Path-aware exclusion (e.g. `.claude/worktrees/`).
|
|
68
|
-
if (isExcludedPath(relative(projectRoot, fullPath)))
|
|
69
|
-
continue;
|
|
70
|
-
let stat;
|
|
71
|
-
try {
|
|
72
|
-
stat = statSync(fullPath);
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
if (stat.isDirectory()) {
|
|
78
|
-
walk(fullPath);
|
|
79
|
-
}
|
|
80
|
-
else if (stat.isFile()) {
|
|
81
|
-
const plugin = getPluginForFile(fullPath);
|
|
82
|
-
if (plugin && stat.size <= MAX_FILE_SIZE) {
|
|
83
|
-
files.push(relative(projectRoot, fullPath));
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
walk(projectRoot);
|
|
89
|
-
return files;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Index a single file. Returns extraction results.
|
|
93
|
-
*/
|
|
94
|
-
export async function indexFile(filePath, projectRoot) {
|
|
95
|
-
const plugin = getPluginForFile(filePath);
|
|
96
|
-
if (!plugin)
|
|
97
|
-
return null;
|
|
98
|
-
const absolutePath = filePath.startsWith("/")
|
|
99
|
-
? filePath
|
|
100
|
-
: join(projectRoot, filePath);
|
|
101
|
-
let source;
|
|
102
|
-
try {
|
|
103
|
-
source = readFileSync(absolutePath, "utf-8");
|
|
104
|
-
}
|
|
105
|
-
catch {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
if (source.length > MAX_FILE_SIZE)
|
|
109
|
-
return null;
|
|
110
|
-
try {
|
|
111
|
-
const tree = await parseSource(source, plugin.grammarWasmName);
|
|
112
|
-
const relativePath = filePath.startsWith("/")
|
|
113
|
-
? relative(projectRoot, filePath)
|
|
114
|
-
: filePath;
|
|
115
|
-
const extraction = plugin.extract(tree, relativePath, source);
|
|
116
|
-
const imports = plugin.resolveImports(tree, relativePath);
|
|
117
|
-
tree.delete();
|
|
118
|
-
return { extraction, imports };
|
|
119
|
-
}
|
|
120
|
-
catch (err) {
|
|
121
|
-
log.debug(`Failed to index ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Index all files in a project. Returns merged results.
|
|
127
|
-
*/
|
|
128
|
-
export async function indexProject(options) {
|
|
129
|
-
const start = performance.now();
|
|
130
|
-
const { projectRoot, ignorePatterns } = options;
|
|
131
|
-
const files = discoverFiles(projectRoot, ignorePatterns ?? DEFAULT_IGNORE);
|
|
132
|
-
const allEntities = [];
|
|
133
|
-
const allEdges = [];
|
|
134
|
-
const allImports = [];
|
|
135
|
-
let errorCount = 0;
|
|
136
|
-
for (const file of files) {
|
|
137
|
-
const result = await indexFile(file, projectRoot);
|
|
138
|
-
if (result) {
|
|
139
|
-
allEntities.push(...result.extraction.entities);
|
|
140
|
-
allEdges.push(...result.extraction.edges);
|
|
141
|
-
allImports.push(...result.imports);
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
errorCount++;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return {
|
|
148
|
-
entities: allEntities,
|
|
149
|
-
edges: allEdges,
|
|
150
|
-
imports: allImports,
|
|
151
|
-
fileCount: files.length,
|
|
152
|
-
errorCount,
|
|
153
|
-
durationMs: performance.now() - start,
|
|
154
|
-
};
|
|
155
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Language Plugin Interface — contract for all language extractors.
|
|
3
|
-
*
|
|
4
|
-
* Each plugin handles one language family and provides:
|
|
5
|
-
* - Entity extraction from a Tree-sitter AST
|
|
6
|
-
* - Intra-file edge extraction (contains, calls, extends, implements)
|
|
7
|
-
* - Import resolution (source path + imported symbols)
|
|
8
|
-
*
|
|
9
|
-
* Plugins are registered in the registry and looked up by file extension.
|
|
10
|
-
*/
|
|
11
|
-
const pluginRegistry = new Map();
|
|
12
|
-
const extensionIndex = new Map();
|
|
13
|
-
export function registerPlugin(plugin) {
|
|
14
|
-
pluginRegistry.set(plugin.id, plugin);
|
|
15
|
-
for (const ext of plugin.extensions) {
|
|
16
|
-
extensionIndex.set(ext, plugin);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
export function getPluginForFile(filePath) {
|
|
20
|
-
const dot = filePath.lastIndexOf(".");
|
|
21
|
-
if (dot < 0)
|
|
22
|
-
return null;
|
|
23
|
-
const ext = filePath.slice(dot);
|
|
24
|
-
return extensionIndex.get(ext) ?? null;
|
|
25
|
-
}
|
|
26
|
-
export function getPlugin(id) {
|
|
27
|
-
return pluginRegistry.get(id) ?? null;
|
|
28
|
-
}
|
|
29
|
-
export function getAllPlugins() {
|
|
30
|
-
return [...pluginRegistry.values()];
|
|
31
|
-
}
|
|
@@ -1,440 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* C# Language Plugin — entity, edge, and import extraction
|
|
3
|
-
* from Tree-sitter AST.
|
|
4
|
-
*
|
|
5
|
-
* Handles: .cs
|
|
6
|
-
*
|
|
7
|
-
* Entity extraction: classes, methods, interfaces, enums, structs, namespaces
|
|
8
|
-
* Edge extraction: contains, calls, extends, implements
|
|
9
|
-
* Import resolution: using directives
|
|
10
|
-
*/
|
|
11
|
-
import { bodyHash, entityKey } from "../entity-key.js";
|
|
12
|
-
function textOf(node) {
|
|
13
|
-
return node?.text ?? "";
|
|
14
|
-
}
|
|
15
|
-
function hasModifier(node, modifier) {
|
|
16
|
-
for (const child of node.children) {
|
|
17
|
-
if (child.type === "modifier") {
|
|
18
|
-
if (textOf(child) === modifier)
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
if (textOf(child) === modifier)
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
for (const child of node.namedChildren) {
|
|
25
|
-
if (child.type === "modifier_list" || child.type === "modifiers") {
|
|
26
|
-
for (const mod of child.children) {
|
|
27
|
-
if (textOf(mod) === modifier)
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
function isPublic(node) {
|
|
35
|
-
return hasModifier(node, "public");
|
|
36
|
-
}
|
|
37
|
-
function isAsync(node) {
|
|
38
|
-
return hasModifier(node, "async");
|
|
39
|
-
}
|
|
40
|
-
function isStatic(node) {
|
|
41
|
-
return hasModifier(node, "static");
|
|
42
|
-
}
|
|
43
|
-
function extractDoc(node) {
|
|
44
|
-
const prev = node.previousSibling;
|
|
45
|
-
if (!prev)
|
|
46
|
-
return null;
|
|
47
|
-
if (prev.type === "comment") {
|
|
48
|
-
const text = textOf(prev);
|
|
49
|
-
if (text.startsWith("///") || text.startsWith("/**")) {
|
|
50
|
-
return text.slice(0, 500);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
let doc = "";
|
|
54
|
-
let sibling = node.previousSibling;
|
|
55
|
-
while (sibling?.type === "comment") {
|
|
56
|
-
const text = textOf(sibling);
|
|
57
|
-
if (text.startsWith("///")) {
|
|
58
|
-
doc = `${text}\n${doc}`;
|
|
59
|
-
sibling = sibling.previousSibling;
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
break;
|
|
63
|
-
}
|
|
64
|
-
return doc.length > 0 ? doc.trim().slice(0, 500) : null;
|
|
65
|
-
}
|
|
66
|
-
function countParameters(node) {
|
|
67
|
-
const params = node.childForFieldName("parameters");
|
|
68
|
-
if (!params)
|
|
69
|
-
return 0;
|
|
70
|
-
return params.namedChildren.filter((c) => c.type === "parameter" || c.type === "params_keyword").length;
|
|
71
|
-
}
|
|
72
|
-
function extractSignature(node, name, kind) {
|
|
73
|
-
if (kind === "class")
|
|
74
|
-
return `class ${name}`;
|
|
75
|
-
if (kind === "interface")
|
|
76
|
-
return `interface ${name}`;
|
|
77
|
-
if (kind === "enum")
|
|
78
|
-
return `enum ${name}`;
|
|
79
|
-
if (kind === "namespace")
|
|
80
|
-
return `namespace ${name}`;
|
|
81
|
-
const params = node.childForFieldName("parameters");
|
|
82
|
-
const returnType = node.childForFieldName("type") ?? node.childForFieldName("returns");
|
|
83
|
-
const paramsText = params ? textOf(params) : "()";
|
|
84
|
-
const returnText = returnType ? `${textOf(returnType)} ` : "void ";
|
|
85
|
-
if (kind === "constructor")
|
|
86
|
-
return `${name}${paramsText}`;
|
|
87
|
-
return `${returnText}${name}${paramsText}`;
|
|
88
|
-
}
|
|
89
|
-
function getBody(node) {
|
|
90
|
-
const body = node.childForFieldName("body");
|
|
91
|
-
return body ? textOf(body) : "";
|
|
92
|
-
}
|
|
93
|
-
function getName(node) {
|
|
94
|
-
const nameNode = node.childForFieldName("name");
|
|
95
|
-
if (nameNode)
|
|
96
|
-
return textOf(nameNode);
|
|
97
|
-
return null;
|
|
98
|
-
}
|
|
99
|
-
function currentScope(ctx) {
|
|
100
|
-
return ctx.scopeStack.length > 0
|
|
101
|
-
? ctx.scopeStack[ctx.scopeStack.length - 1].key
|
|
102
|
-
: "";
|
|
103
|
-
}
|
|
104
|
-
function addEntity(ctx, node, kind, name, opts = {}) {
|
|
105
|
-
const scope = currentScope(ctx);
|
|
106
|
-
const key = entityKey(ctx.filePath, kind, name, scope);
|
|
107
|
-
const doc = extractDoc(node);
|
|
108
|
-
const body = getBody(node);
|
|
109
|
-
ctx.entities.push({
|
|
110
|
-
key,
|
|
111
|
-
kind,
|
|
112
|
-
name,
|
|
113
|
-
file_path: ctx.filePath,
|
|
114
|
-
start_line: node.startPosition.row + 1,
|
|
115
|
-
end_line: node.endPosition.row + 1,
|
|
116
|
-
signature: opts.signature ?? extractSignature(node, name, kind),
|
|
117
|
-
body_hash: bodyHash(body || textOf(node)),
|
|
118
|
-
exported: opts.exported ?? isPublic(node),
|
|
119
|
-
parent_key: scope || null,
|
|
120
|
-
language: "csharp",
|
|
121
|
-
is_async: opts.isAsync ?? false,
|
|
122
|
-
parameter_count: opts.paramCount ?? 0,
|
|
123
|
-
doc,
|
|
124
|
-
});
|
|
125
|
-
if (scope) {
|
|
126
|
-
ctx.edges.push({
|
|
127
|
-
from_key: scope,
|
|
128
|
-
to_key: key,
|
|
129
|
-
type: "contains",
|
|
130
|
-
file_path: ctx.filePath,
|
|
131
|
-
line: node.startPosition.row + 1,
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
return key;
|
|
135
|
-
}
|
|
136
|
-
function extractBaseTypes(node, entityKey, ctx) {
|
|
137
|
-
const baseList = node.childForFieldName("bases") ?? node.childForFieldName("base_list");
|
|
138
|
-
if (!baseList) {
|
|
139
|
-
for (const child of node.namedChildren) {
|
|
140
|
-
if (child.type === "base_list") {
|
|
141
|
-
extractBaseList(child, entityKey, ctx);
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
extractBaseList(baseList, entityKey, ctx);
|
|
148
|
-
}
|
|
149
|
-
function extractBaseList(baseList, key, ctx) {
|
|
150
|
-
for (const child of baseList.namedChildren) {
|
|
151
|
-
const typeName = textOf(child).split("<")[0]?.trim();
|
|
152
|
-
if (!typeName || typeName === ":")
|
|
153
|
-
continue;
|
|
154
|
-
const startsWithI = typeName.length > 1 &&
|
|
155
|
-
typeName[0] === "I" &&
|
|
156
|
-
typeName.charCodeAt(1) >= 65 &&
|
|
157
|
-
typeName.charCodeAt(1) <= 90;
|
|
158
|
-
const edgeType = startsWithI ? "implements" : "extends";
|
|
159
|
-
ctx.edges.push({
|
|
160
|
-
from_key: key,
|
|
161
|
-
to_key: `unresolved:${typeName}`,
|
|
162
|
-
type: edgeType,
|
|
163
|
-
file_path: ctx.filePath,
|
|
164
|
-
line: child.startPosition.row + 1,
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
function visitNode(node, ctx) {
|
|
169
|
-
switch (node.type) {
|
|
170
|
-
case "namespace_declaration":
|
|
171
|
-
case "file_scoped_namespace_declaration": {
|
|
172
|
-
const name = getName(node);
|
|
173
|
-
if (!name)
|
|
174
|
-
break;
|
|
175
|
-
const key = addEntity(ctx, node, "namespace", name, {
|
|
176
|
-
exported: true,
|
|
177
|
-
signature: `namespace ${name}`,
|
|
178
|
-
});
|
|
179
|
-
ctx.scopeStack.push({ key, name });
|
|
180
|
-
visitChildren(node, ctx);
|
|
181
|
-
ctx.scopeStack.pop();
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
case "class_declaration": {
|
|
185
|
-
const name = getName(node);
|
|
186
|
-
if (!name)
|
|
187
|
-
break;
|
|
188
|
-
const key = addEntity(ctx, node, "class", name, {
|
|
189
|
-
exported: isPublic(node),
|
|
190
|
-
signature: `class ${name}`,
|
|
191
|
-
});
|
|
192
|
-
extractBaseTypes(node, key, ctx);
|
|
193
|
-
ctx.scopeStack.push({ key, name });
|
|
194
|
-
visitChildren(node, ctx);
|
|
195
|
-
ctx.scopeStack.pop();
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
case "struct_declaration": {
|
|
199
|
-
const name = getName(node);
|
|
200
|
-
if (!name)
|
|
201
|
-
break;
|
|
202
|
-
const key = addEntity(ctx, node, "class", name, {
|
|
203
|
-
exported: isPublic(node),
|
|
204
|
-
signature: `struct ${name}`,
|
|
205
|
-
});
|
|
206
|
-
extractBaseTypes(node, key, ctx);
|
|
207
|
-
ctx.scopeStack.push({ key, name });
|
|
208
|
-
visitChildren(node, ctx);
|
|
209
|
-
ctx.scopeStack.pop();
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
case "interface_declaration": {
|
|
213
|
-
const name = getName(node);
|
|
214
|
-
if (!name)
|
|
215
|
-
break;
|
|
216
|
-
const key = addEntity(ctx, node, "interface", name, {
|
|
217
|
-
exported: isPublic(node),
|
|
218
|
-
signature: `interface ${name}`,
|
|
219
|
-
});
|
|
220
|
-
extractBaseTypes(node, key, ctx);
|
|
221
|
-
ctx.scopeStack.push({ key, name });
|
|
222
|
-
visitChildren(node, ctx);
|
|
223
|
-
ctx.scopeStack.pop();
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
case "enum_declaration": {
|
|
227
|
-
const name = getName(node);
|
|
228
|
-
if (!name)
|
|
229
|
-
break;
|
|
230
|
-
addEntity(ctx, node, "enum", name, {
|
|
231
|
-
exported: isPublic(node),
|
|
232
|
-
signature: `enum ${name}`,
|
|
233
|
-
});
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
case "method_declaration": {
|
|
237
|
-
const name = getName(node);
|
|
238
|
-
if (!name)
|
|
239
|
-
break;
|
|
240
|
-
const key = addEntity(ctx, node, "method", name, {
|
|
241
|
-
exported: isPublic(node),
|
|
242
|
-
isAsync: isAsync(node),
|
|
243
|
-
paramCount: countParameters(node),
|
|
244
|
-
});
|
|
245
|
-
ctx.scopeStack.push({ key, name });
|
|
246
|
-
visitChildren(node, ctx);
|
|
247
|
-
ctx.scopeStack.pop();
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
case "constructor_declaration": {
|
|
251
|
-
const name = getName(node) ??
|
|
252
|
-
ctx.scopeStack[ctx.scopeStack.length - 1]?.name ??
|
|
253
|
-
"ctor";
|
|
254
|
-
const key = addEntity(ctx, node, "constructor", name, {
|
|
255
|
-
exported: isPublic(node),
|
|
256
|
-
paramCount: countParameters(node),
|
|
257
|
-
});
|
|
258
|
-
ctx.scopeStack.push({ key, name });
|
|
259
|
-
visitChildren(node, ctx);
|
|
260
|
-
ctx.scopeStack.pop();
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
case "property_declaration": {
|
|
264
|
-
const name = getName(node);
|
|
265
|
-
if (!name)
|
|
266
|
-
break;
|
|
267
|
-
addEntity(ctx, node, "property", name, {
|
|
268
|
-
exported: isPublic(node),
|
|
269
|
-
signature: name,
|
|
270
|
-
});
|
|
271
|
-
break;
|
|
272
|
-
}
|
|
273
|
-
case "invocation_expression": {
|
|
274
|
-
const fn = node.namedChildren[0];
|
|
275
|
-
if (fn && ctx.scopeStack.length > 0) {
|
|
276
|
-
const calleeName = extractCalleeName(fn);
|
|
277
|
-
if (calleeName) {
|
|
278
|
-
ctx.edges.push({
|
|
279
|
-
from_key: currentScope(ctx),
|
|
280
|
-
to_key: `unresolved:${calleeName}`,
|
|
281
|
-
type: "calls",
|
|
282
|
-
file_path: ctx.filePath,
|
|
283
|
-
line: node.startPosition.row + 1,
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
break;
|
|
288
|
-
}
|
|
289
|
-
case "object_creation_expression": {
|
|
290
|
-
const typeNode = node.childForFieldName("type") ?? node.namedChildren[0];
|
|
291
|
-
if (typeNode && ctx.scopeStack.length > 0) {
|
|
292
|
-
const typeName = textOf(typeNode).split("<")[0]?.trim();
|
|
293
|
-
if (typeName) {
|
|
294
|
-
ctx.edges.push({
|
|
295
|
-
from_key: currentScope(ctx),
|
|
296
|
-
to_key: `unresolved:${typeName}`,
|
|
297
|
-
type: "calls",
|
|
298
|
-
file_path: ctx.filePath,
|
|
299
|
-
line: node.startPosition.row + 1,
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
break;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
visitChildren(node, ctx);
|
|
307
|
-
}
|
|
308
|
-
function visitChildren(node, ctx) {
|
|
309
|
-
for (const child of node.namedChildren) {
|
|
310
|
-
visitNode(child, ctx);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
function extractCalleeName(node) {
|
|
314
|
-
if (node.type === "identifier")
|
|
315
|
-
return textOf(node);
|
|
316
|
-
if (node.type === "member_access_expression") {
|
|
317
|
-
const name = node.childForFieldName("name");
|
|
318
|
-
return name ? textOf(name) : null;
|
|
319
|
-
}
|
|
320
|
-
if (node.type === "generic_name") {
|
|
321
|
-
const name = node.childForFieldName("name") ?? node.namedChildren[0];
|
|
322
|
-
return name ? textOf(name) : null;
|
|
323
|
-
}
|
|
324
|
-
return null;
|
|
325
|
-
}
|
|
326
|
-
function extractImports(tree, filePath) {
|
|
327
|
-
const imports = [];
|
|
328
|
-
function visit(node) {
|
|
329
|
-
if (node.type === "using_directive") {
|
|
330
|
-
const line = node.startPosition.row + 1;
|
|
331
|
-
const isStaticUsing = node.children.some((c) => textOf(c) === "static");
|
|
332
|
-
const nameNode = node.namedChildren.find((c) => c.type === "qualified_name" ||
|
|
333
|
-
c.type === "identifier" ||
|
|
334
|
-
c.type === "name_equals");
|
|
335
|
-
if (!nameNode) {
|
|
336
|
-
for (const child of node.namedChildren) {
|
|
337
|
-
if (child.type !== "predefined_type") {
|
|
338
|
-
const fullName = textOf(child);
|
|
339
|
-
if (fullName) {
|
|
340
|
-
const parts = fullName.split(".");
|
|
341
|
-
imports.push({
|
|
342
|
-
source: fullName,
|
|
343
|
-
symbols: [parts[parts.length - 1]],
|
|
344
|
-
isDefault: false,
|
|
345
|
-
isNamespace: true,
|
|
346
|
-
line,
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
if (nameNode.type === "name_equals") {
|
|
354
|
-
const alias = nameNode.childForFieldName("name") ?? nameNode.namedChildren[0];
|
|
355
|
-
const target = node.namedChildren.find((c) => c !== nameNode &&
|
|
356
|
-
(c.type === "qualified_name" || c.type === "identifier"));
|
|
357
|
-
if (alias && target) {
|
|
358
|
-
imports.push({
|
|
359
|
-
source: textOf(target),
|
|
360
|
-
symbols: [textOf(target).split(".").pop()],
|
|
361
|
-
isDefault: false,
|
|
362
|
-
isNamespace: false,
|
|
363
|
-
localName: textOf(alias),
|
|
364
|
-
line,
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
const fullName = textOf(nameNode);
|
|
370
|
-
const parts = fullName.split(".");
|
|
371
|
-
const lastPart = parts[parts.length - 1];
|
|
372
|
-
if (isStaticUsing) {
|
|
373
|
-
imports.push({
|
|
374
|
-
source: fullName,
|
|
375
|
-
symbols: ["*"],
|
|
376
|
-
isDefault: false,
|
|
377
|
-
isNamespace: true,
|
|
378
|
-
line,
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
imports.push({
|
|
383
|
-
source: fullName,
|
|
384
|
-
symbols: [lastPart],
|
|
385
|
-
isDefault: false,
|
|
386
|
-
isNamespace: true,
|
|
387
|
-
localName: lastPart,
|
|
388
|
-
line,
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
for (const child of node.namedChildren) {
|
|
393
|
-
visit(child);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
visit(tree.rootNode);
|
|
397
|
-
return imports;
|
|
398
|
-
}
|
|
399
|
-
export const csharpPlugin = {
|
|
400
|
-
id: "csharp",
|
|
401
|
-
extensions: [".cs"],
|
|
402
|
-
grammarWasmName: "tree-sitter-c_sharp.wasm",
|
|
403
|
-
extract(tree, filePath, source) {
|
|
404
|
-
const ctx = {
|
|
405
|
-
filePath,
|
|
406
|
-
source,
|
|
407
|
-
entities: [],
|
|
408
|
-
edges: [],
|
|
409
|
-
scopeStack: [],
|
|
410
|
-
};
|
|
411
|
-
for (const child of tree.rootNode.namedChildren) {
|
|
412
|
-
visitNode(child, ctx);
|
|
413
|
-
}
|
|
414
|
-
return { entities: ctx.entities, edges: ctx.edges };
|
|
415
|
-
},
|
|
416
|
-
resolveImports(tree, filePath) {
|
|
417
|
-
return extractImports(tree, filePath);
|
|
418
|
-
},
|
|
419
|
-
detectCalls(bodyNode) {
|
|
420
|
-
const calls = [];
|
|
421
|
-
function visit(node) {
|
|
422
|
-
if (node.type === "invocation_expression") {
|
|
423
|
-
const fn = node.namedChildren[0];
|
|
424
|
-
const name = fn ? extractCalleeName(fn) : null;
|
|
425
|
-
if (name) {
|
|
426
|
-
calls.push({
|
|
427
|
-
calleeName: name,
|
|
428
|
-
line: node.startPosition.row + 1,
|
|
429
|
-
isAwait: node.parent?.type === "await_expression",
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
for (const child of node.namedChildren) {
|
|
434
|
-
visit(child);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
visit(bodyNode);
|
|
438
|
-
return calls;
|
|
439
|
-
},
|
|
440
|
-
};
|