@nanonets/graft 0.10.1 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -11
- package/dist/ai/crux.d.ts.map +1 -1
- package/dist/ai/crux.js +7 -6
- package/dist/ai/crux.js.map +1 -1
- package/dist/ai/failure.d.ts +49 -0
- package/dist/ai/failure.d.ts.map +1 -0
- package/dist/ai/failure.js +74 -0
- package/dist/ai/failure.js.map +1 -0
- package/dist/ai/llm/anthropic.d.ts.map +1 -1
- package/dist/ai/llm/anthropic.js +4 -1
- package/dist/ai/llm/anthropic.js.map +1 -1
- package/dist/ai/llm/claude-cli.d.ts +60 -0
- package/dist/ai/llm/claude-cli.d.ts.map +1 -0
- package/dist/ai/llm/claude-cli.js +417 -0
- package/dist/ai/llm/claude-cli.js.map +1 -0
- package/dist/ai/llm/openai.d.ts.map +1 -1
- package/dist/ai/llm/openai.js +2 -0
- package/dist/ai/llm/openai.js.map +1 -1
- package/dist/ai/llm/types.d.ts +9 -0
- package/dist/ai/llm/types.d.ts.map +1 -1
- package/dist/ai/llm/types.js +12 -1
- package/dist/ai/llm/types.js.map +1 -1
- package/dist/ask/ask.d.ts.map +1 -1
- package/dist/ask/ask.js +39 -45
- package/dist/ask/ask.js.map +1 -1
- package/dist/ask/fuse.d.ts +83 -46
- package/dist/ask/fuse.d.ts.map +1 -1
- package/dist/ask/fuse.js +165 -67
- package/dist/ask/fuse.js.map +1 -1
- package/dist/blast/blast-cli.d.ts +30 -0
- package/dist/blast/blast-cli.d.ts.map +1 -0
- package/dist/blast/blast-cli.js +163 -0
- package/dist/blast/blast-cli.js.map +1 -0
- package/dist/blast/blast.d.ts +119 -0
- package/dist/blast/blast.d.ts.map +1 -0
- package/dist/blast/blast.js +383 -0
- package/dist/blast/blast.js.map +1 -0
- package/dist/blast/diff.d.ts +53 -0
- package/dist/blast/diff.d.ts.map +1 -0
- package/dist/blast/diff.js +193 -0
- package/dist/blast/diff.js.map +1 -0
- package/dist/blast/modules.d.ts +33 -0
- package/dist/blast/modules.d.ts.map +1 -0
- package/dist/blast/modules.js +83 -0
- package/dist/blast/modules.js.map +1 -0
- package/dist/blast/name.d.ts +61 -0
- package/dist/blast/name.d.ts.map +1 -0
- package/dist/blast/name.js +233 -0
- package/dist/blast/name.js.map +1 -0
- package/dist/blast/render.d.ts +37 -0
- package/dist/blast/render.d.ts.map +1 -0
- package/dist/blast/render.js +300 -0
- package/dist/blast/render.js.map +1 -0
- package/dist/blast/viz.d.ts +17 -0
- package/dist/blast/viz.d.ts.map +1 -0
- package/dist/blast/viz.js +324 -0
- package/dist/blast/viz.js.map +1 -0
- package/dist/claude/hooks.d.ts.map +1 -1
- package/dist/claude/hooks.js +18 -2
- package/dist/claude/hooks.js.map +1 -1
- package/dist/claude/shim-template.d.ts.map +1 -1
- package/dist/claude/shim-template.js +45 -15
- package/dist/claude/shim-template.js.map +1 -1
- package/dist/claude/state.d.ts +5 -0
- package/dist/claude/state.d.ts.map +1 -1
- package/dist/claude/state.js.map +1 -1
- package/dist/cli-picker.d.ts +44 -5
- package/dist/cli-picker.d.ts.map +1 -1
- package/dist/cli-picker.js +73 -26
- package/dist/cli-picker.js.map +1 -1
- package/dist/cli.js +270 -14
- package/dist/cli.js.map +1 -1
- package/dist/context/build.d.ts +8 -0
- package/dist/context/build.d.ts.map +1 -1
- package/dist/context/build.js +57 -9
- package/dist/context/build.js.map +1 -1
- package/dist/context/check.d.ts.map +1 -1
- package/dist/context/check.js +7 -6
- package/dist/context/check.js.map +1 -1
- package/dist/context/node-file.d.ts.map +1 -1
- package/dist/context/node-file.js +9 -2
- package/dist/context/node-file.js.map +1 -1
- package/dist/graph/bindings.d.ts.map +1 -1
- package/dist/graph/bindings.js +171 -8
- package/dist/graph/bindings.js.map +1 -1
- package/dist/graph/build.d.ts.map +1 -1
- package/dist/graph/build.js +36 -16
- package/dist/graph/build.js.map +1 -1
- package/dist/graph/check.d.ts +4 -0
- package/dist/graph/check.d.ts.map +1 -1
- package/dist/graph/check.js +8 -1
- package/dist/graph/check.js.map +1 -1
- package/dist/graph/container.d.ts +63 -0
- package/dist/graph/container.d.ts.map +1 -0
- package/dist/graph/container.js +185 -0
- package/dist/graph/container.js.map +1 -0
- package/dist/graph/enrich.d.ts +18 -0
- package/dist/graph/enrich.d.ts.map +1 -1
- package/dist/graph/enrich.js +55 -2
- package/dist/graph/enrich.js.map +1 -1
- package/dist/graph/extract.d.ts +3 -1
- package/dist/graph/extract.d.ts.map +1 -1
- package/dist/graph/extract.js +215 -8
- package/dist/graph/extract.js.map +1 -1
- package/dist/graph/generic.d.ts +34 -1
- package/dist/graph/generic.d.ts.map +1 -1
- package/dist/graph/generic.js +152 -3
- package/dist/graph/generic.js.map +1 -1
- package/dist/graph/queries/clojure.scm +58 -0
- package/dist/graph/resolve.d.ts.map +1 -1
- package/dist/graph/resolve.js +132 -2
- package/dist/graph/resolve.js.map +1 -1
- package/dist/graph/scopes.d.ts +2 -2
- package/dist/graph/scopes.d.ts.map +1 -1
- package/dist/graph/scopes.js +8 -6
- package/dist/graph/scopes.js.map +1 -1
- package/dist/graph/source-files.d.ts +13 -4
- package/dist/graph/source-files.d.ts.map +1 -1
- package/dist/graph/source-files.js +35 -12
- package/dist/graph/source-files.js.map +1 -1
- package/dist/graph/types.d.ts +1 -1
- package/dist/graph/types.d.ts.map +1 -1
- package/dist/graph/workspace-cli.d.ts +2 -0
- package/dist/graph/workspace-cli.d.ts.map +1 -1
- package/dist/graph/workspace-cli.js +10 -4
- package/dist/graph/workspace-cli.js.map +1 -1
- package/dist/graph/workspace.d.ts +11 -6
- package/dist/graph/workspace.d.ts.map +1 -1
- package/dist/graph/workspace.js +24 -13
- package/dist/graph/workspace.js.map +1 -1
- package/dist/graph/write.d.ts.map +1 -1
- package/dist/graph/write.js +25 -2
- package/dist/graph/write.js.map +1 -1
- package/dist/hosts/antigravity.d.ts +7 -0
- package/dist/hosts/antigravity.d.ts.map +1 -0
- package/dist/hosts/antigravity.js +42 -0
- package/dist/hosts/antigravity.js.map +1 -0
- package/dist/hosts/init.d.ts.map +1 -1
- package/dist/hosts/init.js +6 -1
- package/dist/hosts/init.js.map +1 -1
- package/dist/hosts/mcp-config.d.ts.map +1 -1
- package/dist/hosts/mcp-config.js +7 -0
- package/dist/hosts/mcp-config.js.map +1 -1
- package/dist/hosts/plan.d.ts +1 -1
- package/dist/hosts/plan.d.ts.map +1 -1
- package/dist/hosts/plan.js +2 -0
- package/dist/hosts/plan.js.map +1 -1
- package/dist/hosts/registry.d.ts.map +1 -1
- package/dist/hosts/registry.js +13 -0
- package/dist/hosts/registry.js.map +1 -1
- package/dist/ingest/fs.d.ts +9 -2
- package/dist/ingest/fs.d.ts.map +1 -1
- package/dist/ingest/fs.js +100 -16
- package/dist/ingest/fs.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +45 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/telemetry/contract.d.ts +90 -0
- package/dist/telemetry/contract.d.ts.map +1 -0
- package/dist/telemetry/contract.js +203 -0
- package/dist/telemetry/contract.js.map +1 -0
- package/dist/telemetry/flush.d.ts +21 -0
- package/dist/telemetry/flush.d.ts.map +1 -0
- package/dist/telemetry/flush.js +84 -0
- package/dist/telemetry/flush.js.map +1 -0
- package/dist/telemetry/gate.d.ts +16 -0
- package/dist/telemetry/gate.d.ts.map +1 -0
- package/dist/telemetry/gate.js +64 -0
- package/dist/telemetry/gate.js.map +1 -0
- package/dist/telemetry/identity.d.ts +33 -0
- package/dist/telemetry/identity.d.ts.map +1 -0
- package/dist/telemetry/identity.js +80 -0
- package/dist/telemetry/identity.js.map +1 -0
- package/dist/telemetry/index.d.ts +18 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +16 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/key.d.ts +21 -0
- package/dist/telemetry/key.d.ts.map +1 -0
- package/dist/telemetry/key.js +49 -0
- package/dist/telemetry/key.js.map +1 -0
- package/dist/telemetry/notice.d.ts +19 -0
- package/dist/telemetry/notice.d.ts.map +1 -0
- package/dist/telemetry/notice.js +90 -0
- package/dist/telemetry/notice.js.map +1 -0
- package/dist/telemetry/queue.d.ts +35 -0
- package/dist/telemetry/queue.d.ts.map +1 -0
- package/dist/telemetry/queue.js +162 -0
- package/dist/telemetry/queue.js.map +1 -0
- package/dist/telemetry/send.d.ts +19 -0
- package/dist/telemetry/send.d.ts.map +1 -0
- package/dist/telemetry/send.js +84 -0
- package/dist/telemetry/send.js.map +1 -0
- package/dist/telemetry/sessions.d.ts +8 -0
- package/dist/telemetry/sessions.d.ts.map +1 -0
- package/dist/telemetry/sessions.js +81 -0
- package/dist/telemetry/sessions.js.map +1 -0
- package/dist/telemetry/track.d.ts +43 -0
- package/dist/telemetry/track.d.ts.map +1 -0
- package/dist/telemetry/track.js +108 -0
- package/dist/telemetry/track.js.map +1 -0
- package/dist/upkeep-run.d.ts +15 -0
- package/dist/upkeep-run.d.ts.map +1 -0
- package/dist/upkeep-run.js +60 -0
- package/dist/upkeep-run.js.map +1 -0
- package/dist/upkeep.d.ts +114 -0
- package/dist/upkeep.d.ts.map +1 -0
- package/dist/upkeep.js +232 -0
- package/dist/upkeep.js.map +1 -0
- package/dist/util/num.d.ts +3 -0
- package/dist/util/num.d.ts.map +1 -0
- package/dist/util/num.js +20 -0
- package/dist/util/num.js.map +1 -0
- package/dist/util/state.d.ts +11 -4
- package/dist/util/state.d.ts.map +1 -1
- package/dist/util/state.js +9 -0
- package/dist/util/state.js.map +1 -1
- package/dist/viewer/app.js +1 -1
- package/dist/viewer/index.html +1 -0
- package/dist/viewer/style.css +23 -2
- package/dist/viz/assemble.d.ts +33 -0
- package/dist/viz/assemble.d.ts.map +1 -1
- package/dist/viz/assemble.js.map +1 -1
- package/dist/viz/export.d.ts +39 -0
- package/dist/viz/export.d.ts.map +1 -0
- package/dist/viz/export.js +98 -0
- package/dist/viz/export.js.map +1 -0
- package/package.json +6 -5
- package/scripts/stamp-telemetry-key.mjs +53 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enrich.d.ts","sourceRoot":"","sources":["../../src/graph/enrich.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"enrich.d.ts","sourceRoot":"","sources":["../../src/graph/enrich.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,eAAe,CAAC;AAEvE,OAAO,KAAK,EAAQ,MAAM,EAAE,MAAM,YAAY,CAAC;AAQ/C,MAAM,WAAW,aAAa;IAC5B,sFAAsF;IACtF,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,oGAAoG;IACpG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yFAAyF;IACzF,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC5E;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AASD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;iCAE6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,YAAY,EAAE,MAAM,CAAC;IACrB;;4EAEwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,WAAW,CAAC,CAkItB"}
|
package/dist/graph/enrich.js
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
|
+
import { LlmFailureGate } from "../ai/failure.js";
|
|
1
2
|
/** Cap on the stored crux: an over-long pick is trimmed to its leading slice. */
|
|
2
3
|
const MAX_CRUX_LINES = 12;
|
|
3
4
|
/** Files summarized at once. Each is an independent LLM call; order is preserved. */
|
|
4
5
|
const DEFAULT_CONCURRENCY = 5;
|
|
6
|
+
/** How often the crux pass flushes partial progress to disk. Read at call time (not
|
|
7
|
+
* module load) so a test seam `GRAFT_CRUX_CHECKPOINT_MS=0` (flush on every completed
|
|
8
|
+
* file) takes effect. */
|
|
9
|
+
function checkpointMs() {
|
|
10
|
+
return Number(process.env.GRAFT_CRUX_CHECKPOINT_MS ?? 15000);
|
|
11
|
+
}
|
|
5
12
|
export async function enrichGraph(nodes, prior, sources, opts = {}) {
|
|
6
|
-
const stats = {
|
|
13
|
+
const stats = {
|
|
14
|
+
cached: 0,
|
|
15
|
+
computed: 0,
|
|
16
|
+
stale: 0,
|
|
17
|
+
pending: 0,
|
|
18
|
+
errors: [],
|
|
19
|
+
failedFiles: 0,
|
|
20
|
+
skippedFiles: 0,
|
|
21
|
+
};
|
|
7
22
|
// Which nodes actually need an LLM call this run (after cache carry-over).
|
|
8
23
|
const dirty = [];
|
|
9
24
|
for (const node of nodes) {
|
|
@@ -52,17 +67,45 @@ export async function enrichGraph(nodes, prior, sources, opts = {}) {
|
|
|
52
67
|
const files = [...byFile.keys()];
|
|
53
68
|
const limit = Math.max(1, opts.concurrency ?? DEFAULT_CONCURRENCY);
|
|
54
69
|
let done = 0;
|
|
70
|
+
const flushEvery = checkpointMs();
|
|
71
|
+
let lastCheckpoint = Date.now();
|
|
72
|
+
// Shared with the concept pass (`context/build.ts`), so both agree on when a
|
|
73
|
+
// provider has stopped working. Counted across the whole pass, not per worker:
|
|
74
|
+
// with `-j 5` the interleaving is what a user sees as "everything is failing now".
|
|
75
|
+
const gate = new LlmFailureGate();
|
|
55
76
|
await mapWithConcurrency(files, limit, async (path) => {
|
|
56
77
|
const fileNodes = byFile.get(path);
|
|
57
78
|
const source = sources.get(path);
|
|
58
79
|
const lineCount = source.split("\n").length;
|
|
80
|
+
// Once the pass is fatal, the remaining files are not attempted: every call
|
|
81
|
+
// would fail the same way, and on a metered gateway each one still costs a
|
|
82
|
+
// request. They are counted so the caller can report what was left undone.
|
|
83
|
+
if (gate.stopped) {
|
|
84
|
+
gate.skip();
|
|
85
|
+
for (const node of fileNodes) {
|
|
86
|
+
if (node.summary_state === "stale")
|
|
87
|
+
stats.stale++;
|
|
88
|
+
else
|
|
89
|
+
stats.pending++;
|
|
90
|
+
}
|
|
91
|
+
// Still reported, so the caller's progress counter reaches `total` instead of
|
|
92
|
+
// freezing at the file that broke — the abort is announced by the build's
|
|
93
|
+
// summary, not by a stalled line.
|
|
94
|
+
opts.onProgress?.({ index: done++, total: files.length, node: path });
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
59
97
|
const refs = fileNodes.map((n) => {
|
|
60
98
|
const [startLine, endLine] = spanLines(n.span, lineCount);
|
|
61
99
|
return { id: n.id, kind: n.kind, signature: n.signature, startLine, endLine };
|
|
62
100
|
});
|
|
63
101
|
const { results, error } = await collectFileCrux(summarizer, path, source, refs);
|
|
64
|
-
if (error)
|
|
102
|
+
if (error) {
|
|
65
103
|
stats.errors.push(`${path}: ${error}`);
|
|
104
|
+
gate.record(error);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
gate.succeeded();
|
|
108
|
+
}
|
|
66
109
|
for (const node of fileNodes) {
|
|
67
110
|
const r = results.size > 0 ? results.get(node.id) : undefined;
|
|
68
111
|
if (!r) {
|
|
@@ -80,7 +123,17 @@ export async function enrichGraph(nodes, prior, sources, opts = {}) {
|
|
|
80
123
|
}
|
|
81
124
|
// Report on completion so the counter climbs monotonically under concurrency.
|
|
82
125
|
opts.onProgress?.({ index: done++, total: files.length, node: path });
|
|
126
|
+
// Flush partial crux to disk periodically, so a killed --deep run keeps what it
|
|
127
|
+
// has already computed (#128). Throttled by wall-clock; the caller's checkpoint
|
|
128
|
+
// writes wiring.json atomically, and the next run folds it back in by body_hash.
|
|
129
|
+
if (opts.checkpoint && Date.now() - lastCheckpoint >= flushEvery) {
|
|
130
|
+
lastCheckpoint = Date.now();
|
|
131
|
+
opts.checkpoint();
|
|
132
|
+
}
|
|
83
133
|
});
|
|
134
|
+
stats.failedFiles = gate.failed;
|
|
135
|
+
stats.skippedFiles = gate.skipped;
|
|
136
|
+
stats.fatal = gate.fatal;
|
|
84
137
|
return stats;
|
|
85
138
|
}
|
|
86
139
|
/** Run `fn` over `items` with at most `limit` in flight, preserving result order. */
|
package/dist/graph/enrich.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enrich.js","sourceRoot":"","sources":["../../src/graph/enrich.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"enrich.js","sourceRoot":"","sources":["../../src/graph/enrich.ts"],"names":[],"mappings":"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"}
|
package/dist/graph/extract.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type FileBindings } from "./bindings.js";
|
|
2
2
|
import type { Kind, NodeV1, Relation } from "./types.js";
|
|
3
|
-
export type Language = "typescript" | "tsx" | "python" | "go" | "java";
|
|
3
|
+
export type Language = "typescript" | "tsx" | "python" | "go" | "java" | "php";
|
|
4
|
+
/** Every file extension a depth-tier (hand-written) extractor claims. */
|
|
5
|
+
export declare function depthExtensions(): string[];
|
|
4
6
|
/** Map a file path to a supported language, or null if unsupported. */
|
|
5
7
|
export declare function languageOf(path: string): Language | null;
|
|
6
8
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/graph/extract.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/graph/extract.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAqD,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AACrG,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEzD,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,KAAK,GAAG,QAAQ,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;AAsC/E,yEAAyE;AACzE,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAExD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE3D;AAED;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;yEACqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;2BAGuB;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAgJD,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,aAAa,EAAE,IAAI,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,YAAY,CAAC;IACvB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3E;AAuBD,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,aAAa,CAiDtF;AAED;;;;;wEAKwE;AACxE,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAMhE"}
|
package/dist/graph/extract.js
CHANGED
|
@@ -11,6 +11,7 @@ import TypeScript from "tree-sitter-typescript";
|
|
|
11
11
|
import Python from "tree-sitter-python";
|
|
12
12
|
import Go from "tree-sitter-go";
|
|
13
13
|
import Java from "tree-sitter-java";
|
|
14
|
+
import PHP from "tree-sitter-php";
|
|
14
15
|
import { basename } from "node:path";
|
|
15
16
|
import { contentHash } from "../util/id.js";
|
|
16
17
|
import { collectBindings, goReceiverVarOf, resolveRecvType } from "./bindings.js";
|
|
@@ -42,11 +43,16 @@ const EXTENSIONS = [
|
|
|
42
43
|
{ ext: ".py", grammar: "python", label: "python" },
|
|
43
44
|
{ ext: ".go", grammar: "go", label: "go" },
|
|
44
45
|
{ ext: ".java", grammar: "java", label: "java" },
|
|
46
|
+
{ ext: ".php", grammar: "php", label: "php" },
|
|
45
47
|
];
|
|
46
48
|
function entryFor(path) {
|
|
47
49
|
const p = path.toLowerCase();
|
|
48
50
|
return EXTENSIONS.find((e) => p.endsWith(e.ext));
|
|
49
51
|
}
|
|
52
|
+
/** Every file extension a depth-tier (hand-written) extractor claims. */
|
|
53
|
+
export function depthExtensions() {
|
|
54
|
+
return EXTENSIONS.map((e) => e.ext);
|
|
55
|
+
}
|
|
50
56
|
/** Map a file path to a supported language, or null if unsupported. */
|
|
51
57
|
export function languageOf(path) {
|
|
52
58
|
return entryFor(path)?.grammar ?? null;
|
|
@@ -127,25 +133,40 @@ const JAVA_KINDS = {
|
|
|
127
133
|
enum_declaration: "enum",
|
|
128
134
|
record_declaration: "struct",
|
|
129
135
|
annotation_type_declaration: "interface",
|
|
136
|
+
annotation_type_element_declaration: "method",
|
|
130
137
|
method_declaration: "method",
|
|
131
138
|
constructor_declaration: "method",
|
|
132
139
|
};
|
|
133
140
|
/** Java type declarations: they set `enclosingClass` for the methods nested in them,
|
|
134
141
|
* which "class"-only logic would miss for a record's or interface's members. */
|
|
135
142
|
const JAVA_TYPE_KINDS = new Set(["class", "interface", "enum", "struct"]);
|
|
143
|
+
// PHP: definition node types are all distinct (no py-style function→method
|
|
144
|
+
// promotion needed — a class body uses `method_declaration`, not
|
|
145
|
+
// `function_definition`). `trait_declaration` maps to the PHP-only `trait` kind.
|
|
146
|
+
const PHP_KINDS = {
|
|
147
|
+
function_definition: "function",
|
|
148
|
+
method_declaration: "method",
|
|
149
|
+
class_declaration: "class",
|
|
150
|
+
interface_declaration: "interface",
|
|
151
|
+
trait_declaration: "trait",
|
|
152
|
+
enum_declaration: "enum",
|
|
153
|
+
};
|
|
136
154
|
const KINDS_BY_LANG = {
|
|
137
155
|
typescript: TS_KINDS,
|
|
138
156
|
tsx: TS_KINDS,
|
|
139
157
|
python: PY_KINDS,
|
|
140
158
|
go: GO_KINDS,
|
|
141
159
|
java: JAVA_KINDS,
|
|
160
|
+
php: PHP_KINDS,
|
|
142
161
|
};
|
|
143
162
|
/**
|
|
144
163
|
* The node type(s) that constitute a call site, per language.
|
|
145
164
|
*
|
|
146
165
|
* Java is the reason this is a set rather than a string: `method_invocation` and
|
|
147
166
|
* `object_creation_expression` (`new Foo()`) are separate node types, and a Java
|
|
148
|
-
* codebase's constructor calls are a large share of its real edges.
|
|
167
|
+
* codebase's constructor calls are a large share of its real edges. PHP is
|
|
168
|
+
* likewise multi-shape: a call is a function / member / nullsafe-member / scoped
|
|
169
|
+
* call, never a single `call_expression`.
|
|
149
170
|
*/
|
|
150
171
|
const CALL_TYPES = {
|
|
151
172
|
typescript: new Set(["call_expression"]),
|
|
@@ -153,6 +174,12 @@ const CALL_TYPES = {
|
|
|
153
174
|
python: new Set(["call"]),
|
|
154
175
|
go: new Set(["call_expression"]),
|
|
155
176
|
java: new Set(["method_invocation", "object_creation_expression"]),
|
|
177
|
+
php: new Set([
|
|
178
|
+
"function_call_expression",
|
|
179
|
+
"member_call_expression",
|
|
180
|
+
"nullsafe_member_call_expression",
|
|
181
|
+
"scoped_call_expression",
|
|
182
|
+
]),
|
|
156
183
|
};
|
|
157
184
|
const FUNCTION_VALUE_TYPES = new Set([
|
|
158
185
|
"arrow_function",
|
|
@@ -167,6 +194,7 @@ const GRAMMARS = {
|
|
|
167
194
|
python: Python,
|
|
168
195
|
go: Go,
|
|
169
196
|
java: Java,
|
|
197
|
+
php: PHP.php,
|
|
170
198
|
};
|
|
171
199
|
/** tree-sitter's string `parse()` fails with "Invalid argument" on any input
|
|
172
200
|
* ≥ 32 KB, which silently drops large files — often the most important ones (a
|
|
@@ -268,7 +296,9 @@ function walk(node, ctx, out, edges, minted) {
|
|
|
268
296
|
? goExported(desc.name)
|
|
269
297
|
: ctx.lang === "java"
|
|
270
298
|
? javaExported(node)
|
|
271
|
-
:
|
|
299
|
+
: ctx.lang === "php"
|
|
300
|
+
? phpExported(node)
|
|
301
|
+
: tsExported(node),
|
|
272
302
|
origin: "ast",
|
|
273
303
|
body_hash: contentHash(desc.hashNode.text),
|
|
274
304
|
body_text: searchBody(desc.hashNode.text),
|
|
@@ -334,6 +364,17 @@ function walk(node, ctx, out, edges, minted) {
|
|
|
334
364
|
// above already recorded them, so do not descend and emit false references.
|
|
335
365
|
return;
|
|
336
366
|
}
|
|
367
|
+
else if (ctx.lang === "php" && node.type === "use_declaration") {
|
|
368
|
+
// Trait composition inside a class body (`use HasFactory, Notifiable;`).
|
|
369
|
+
// Modelled as `implements`: like an interface, a trait is a contract of
|
|
370
|
+
// behaviour the class mixes in (Graft's Relation set has no `uses`).
|
|
371
|
+
for (const t of node.namedChildren) {
|
|
372
|
+
if (t.type === "name" || t.type === "qualified_name") {
|
|
373
|
+
edges.push({ source: ctx.parentId, relation: "implements", name: t.text.replace(/^.*\\/, ""), file: ctx.rel });
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
337
378
|
else if (node.type === "identifier" &&
|
|
338
379
|
!isDirectCallee(node, callTypes) &&
|
|
339
380
|
!isDeclarationName(node)) {
|
|
@@ -385,6 +426,19 @@ function collectTsImportBindings(node, specifier, out) {
|
|
|
385
426
|
for (const child of node.namedChildren)
|
|
386
427
|
collectTsImportBindings(child, specifier, out);
|
|
387
428
|
}
|
|
429
|
+
/**
|
|
430
|
+
* Do these two wrappers stand for the same syntax node? `===` does not answer that:
|
|
431
|
+
* node-tree-sitter materializes `SyntaxNode` objects on demand and caches them
|
|
432
|
+
* weakly, so reaching one node twice can return two different JS objects. Comparing
|
|
433
|
+
* wrappers makes a purely syntactic question depend on collector timing — two cold
|
|
434
|
+
* builds of unchanged source then disagree on `references` edges (#116).
|
|
435
|
+
*
|
|
436
|
+
* `id` is the stable identity, unique within one tree, so the tree is compared too.
|
|
437
|
+
* A `Tree` is one object per parse (unlike its nodes), so `===` is right for it.
|
|
438
|
+
*/
|
|
439
|
+
function sameSyntaxNode(a, b) {
|
|
440
|
+
return !!a && !!b && a.tree === b.tree && a.id === b.id;
|
|
441
|
+
}
|
|
388
442
|
/**
|
|
389
443
|
* A parameter or local declaration wins over an import inside that function.
|
|
390
444
|
* Drop that imported binding for the whole function rather than create a false
|
|
@@ -396,7 +450,7 @@ function withoutShadowedImports(imports, definition) {
|
|
|
396
450
|
const shadowed = new Set();
|
|
397
451
|
const definitionValue = definition.childForFieldName("value");
|
|
398
452
|
const visit = (node) => {
|
|
399
|
-
if (node
|
|
453
|
+
if (!sameSyntaxNode(node, definition) && !sameSyntaxNode(node, definitionValue) && isFunctionBoundary(node)) {
|
|
400
454
|
const name = node.childForFieldName("name");
|
|
401
455
|
if (name?.type === "identifier")
|
|
402
456
|
shadowed.add(name.text);
|
|
@@ -438,12 +492,13 @@ function isDirectCallee(node, callTypes) {
|
|
|
438
492
|
const parent = node.parent;
|
|
439
493
|
if (!parent || !callTypes.has(parent.type))
|
|
440
494
|
return false;
|
|
441
|
-
return parent.childForFieldName("function")
|
|
495
|
+
return (sameSyntaxNode(parent.childForFieldName("function"), node) ||
|
|
496
|
+
sameSyntaxNode(parent.childForFieldName("name"), node));
|
|
442
497
|
}
|
|
443
498
|
/** Definition/declaration identifiers name a new binding; they do not use one. */
|
|
444
499
|
function isDeclarationName(node) {
|
|
445
500
|
const parent = node.parent;
|
|
446
|
-
return parent?.childForFieldName("name")
|
|
501
|
+
return sameSyntaxNode(parent?.childForFieldName("name"), node);
|
|
447
502
|
}
|
|
448
503
|
/** Recognize the definition shapes: mapped node types, Go's type/method forms, and
|
|
449
504
|
* TS arrow-consts. */
|
|
@@ -452,6 +507,19 @@ function describe(node, ctx) {
|
|
|
452
507
|
return describeGo(node, ctx);
|
|
453
508
|
if (ctx.lang === "java")
|
|
454
509
|
return describeJava(node, ctx);
|
|
510
|
+
// PHP closures: `$h = function () {…}` / `fn() => …`, and bare callbacks
|
|
511
|
+
// (`$routes->get('/x', function () {…})`). Captured as function nodes so a
|
|
512
|
+
// closure-only file (a routing table, a DI container) keeps its structure
|
|
513
|
+
// and the calls inside attribute to the closure, not the file.
|
|
514
|
+
if (ctx.lang === "php" && (node.type === "anonymous_function" || node.type === "arrow_function")) {
|
|
515
|
+
const body = node.childForFieldName("body");
|
|
516
|
+
return {
|
|
517
|
+
name: phpClosureName(node),
|
|
518
|
+
kind: "function",
|
|
519
|
+
headerEnd: body ? body.startIndex : node.endIndex,
|
|
520
|
+
hashNode: node,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
455
523
|
const mapped = ctx.kinds[node.type];
|
|
456
524
|
if (mapped) {
|
|
457
525
|
const name = node.childForFieldName("name")?.text;
|
|
@@ -580,6 +648,31 @@ function goExported(name) {
|
|
|
580
648
|
const first = own[0] ?? "";
|
|
581
649
|
return first !== first.toLowerCase() && first === first.toUpperCase();
|
|
582
650
|
}
|
|
651
|
+
/** PHP visibility: a class member is "exported" unless it is `private`/`protected`.
|
|
652
|
+
* Top-level functions/classes carry no visibility modifier and are always visible. */
|
|
653
|
+
function phpExported(node) {
|
|
654
|
+
const vis = node.namedChildren.find((c) => c.type === "visibility_modifier");
|
|
655
|
+
return vis ? vis.text === "public" : true;
|
|
656
|
+
}
|
|
657
|
+
/** Name for a PHP closure / arrow-fn: the variable it's assigned to
|
|
658
|
+
* (`$handler = fn(...)` -> `handler`, mirroring how TS names arrow-consts),
|
|
659
|
+
* else the anonymous `{closure}` (deduplicated per file by mintId).
|
|
660
|
+
*
|
|
661
|
+
* The "is this the assignment's right-hand side" check compares tree-sitter node
|
|
662
|
+
* `.id` (a stable per-tree node identity) rather than `===` on the wrapper
|
|
663
|
+
* objects: the binding does not guarantee that two traversals to the same
|
|
664
|
+
* underlying node hand back the same JS wrapper, so `right === node` can be false
|
|
665
|
+
* even when they are the same node — producing a stray `{closure}` name that
|
|
666
|
+
* makes `graft check` report the graph STALE against its own stored output. */
|
|
667
|
+
function phpClosureName(node) {
|
|
668
|
+
const parent = node.parent;
|
|
669
|
+
if (parent?.type === "assignment_expression" && parent.childForFieldName("right")?.id === node.id) {
|
|
670
|
+
const left = parent.childForFieldName("left");
|
|
671
|
+
if (left?.type === "variable_name")
|
|
672
|
+
return left.text.replace(/^\$/, "");
|
|
673
|
+
}
|
|
674
|
+
return "{closure}";
|
|
675
|
+
}
|
|
583
676
|
function heritageEdges(node, classId, ctx) {
|
|
584
677
|
const edges = [];
|
|
585
678
|
if (ctx.lang === "java") {
|
|
@@ -609,6 +702,21 @@ function heritageEdges(node, classId, ctx) {
|
|
|
609
702
|
}
|
|
610
703
|
return edges;
|
|
611
704
|
}
|
|
705
|
+
if (ctx.lang === "php") {
|
|
706
|
+
// `class C extends B implements I, J` → base_clause (extends) +
|
|
707
|
+
// class_interface_clause (implements); names may be namespace-qualified.
|
|
708
|
+
for (const clause of node.namedChildren) {
|
|
709
|
+
const relation = clause.type === "base_clause" ? "extends" : clause.type === "class_interface_clause" ? "implements" : null;
|
|
710
|
+
if (!relation)
|
|
711
|
+
continue;
|
|
712
|
+
for (const t of clause.namedChildren) {
|
|
713
|
+
if (t.type === "name" || t.type === "qualified_name") {
|
|
714
|
+
edges.push({ source: classId, relation, name: t.text.replace(/^.*\\/, ""), file: ctx.rel });
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return edges;
|
|
719
|
+
}
|
|
612
720
|
const heritage = node.namedChildren.find((c) => c.type === "class_heritage");
|
|
613
721
|
for (const clause of heritage?.namedChildren ?? []) {
|
|
614
722
|
const relation = clause.type === "implements_clause"
|
|
@@ -645,9 +753,10 @@ function calleeName(node, lang) {
|
|
|
645
753
|
// Java call site and the language would extract nodes with no call edges at all.
|
|
646
754
|
if (lang === "java") {
|
|
647
755
|
if (node.type === "object_creation_expression") {
|
|
648
|
-
// `new Foo()` — the constructed type is the call target
|
|
649
|
-
|
|
650
|
-
|
|
756
|
+
// `new Foo()` — the constructed type is the call target, named as the graph
|
|
757
|
+
// names it.
|
|
758
|
+
const name = javaConstructedTypeName(node.childForFieldName("type"));
|
|
759
|
+
return name ? { name, viaMember: false } : null;
|
|
651
760
|
}
|
|
652
761
|
const nameNode = node.childForFieldName("name");
|
|
653
762
|
if (!nameNode)
|
|
@@ -663,6 +772,8 @@ function calleeName(node, lang) {
|
|
|
663
772
|
return { name: nameNode.text, viaMember: true, receiver: "this" };
|
|
664
773
|
return { name: nameNode.text, viaMember: true, receiver: javaReceiver(obj) };
|
|
665
774
|
}
|
|
775
|
+
if (lang === "php")
|
|
776
|
+
return phpCallee(node);
|
|
666
777
|
const fn = node.childForFieldName("function");
|
|
667
778
|
if (!fn)
|
|
668
779
|
return null;
|
|
@@ -693,6 +804,41 @@ function javaArgCount(node) {
|
|
|
693
804
|
const args = node.childForFieldName("arguments");
|
|
694
805
|
return args ? args.namedChildren.length : undefined;
|
|
695
806
|
}
|
|
807
|
+
/**
|
|
808
|
+
* The name a `new` CONSTRUCTS, as the graph names it — or null when this pass cannot
|
|
809
|
+
* say, in which case the construction resolves to nothing.
|
|
810
|
+
*
|
|
811
|
+
* Erasing type arguments is the only transformation here, because it is the only one
|
|
812
|
+
* that provably does not change which type is being named:
|
|
813
|
+
*
|
|
814
|
+
* Box -> Box
|
|
815
|
+
* Box<String> -> Box (the node is `Box`; the arguments are not part of it)
|
|
816
|
+
* Box<> -> Box
|
|
817
|
+
*
|
|
818
|
+
* A QUALIFIED name is deliberately dropped rather than reduced to its final segment:
|
|
819
|
+
*
|
|
820
|
+
* java.io.File -> null (not the repo's own `File`)
|
|
821
|
+
* Beta.Builder -> null (not `Alpha.Builder` in the same file)
|
|
822
|
+
*
|
|
823
|
+
* Collapsing those was the first attempt at this fix, and it traded lost edges for
|
|
824
|
+
* WRONG ones — `new java.io.File(…)` resolved to an unrelated in-repo `File`, and a
|
|
825
|
+
* nested `Beta.Builder` bound to a sibling `Alpha.Builder` at `extracted` confidence,
|
|
826
|
+
* because the same-file tiebreak takes the first candidate. Dropping keeps this pass
|
|
827
|
+
* on the resolver's own rule: resolve precisely, or not at all.
|
|
828
|
+
*
|
|
829
|
+
* Deliberately NOT shared with bindings.ts's `javaTypeName`. That one answers "what
|
|
830
|
+
* type does this variable HOLD", where reducing `java.util.List` to `List` is a local
|
|
831
|
+
* heuristic with different stakes; this one answers "what type is being constructed",
|
|
832
|
+
* and the two questions do not have the same safe answer. Supporting qualified
|
|
833
|
+
* construction properly needs an import-aware type index, not a longer helper.
|
|
834
|
+
*/
|
|
835
|
+
function javaConstructedTypeName(node) {
|
|
836
|
+
if (!node)
|
|
837
|
+
return null;
|
|
838
|
+
if (node.type === "generic_type")
|
|
839
|
+
return javaConstructedTypeName(node.namedChildren[0]);
|
|
840
|
+
return node.type === "type_identifier" ? node.text : null;
|
|
841
|
+
}
|
|
696
842
|
/** A Java call's receiver text: a bare identifier (`repo.save()`), `this`, or
|
|
697
843
|
* `this.x` for a field access (`this.repo.save()`). A chained call or a qualified
|
|
698
844
|
* static reference yields none — there is no confident local clue to bind. */
|
|
@@ -725,6 +871,58 @@ function pyReceiver(fn) {
|
|
|
725
871
|
}
|
|
726
872
|
return undefined;
|
|
727
873
|
}
|
|
874
|
+
/**
|
|
875
|
+
* PHP call shapes: `foo()` (function_call_expression), `$obj->m()` /
|
|
876
|
+
* `$obj?->m()` (member/nullsafe_member_call_expression), and `Cls::m()`
|
|
877
|
+
* (scoped_call_expression). The called name is the trailing `name`; the
|
|
878
|
+
* receiver, when locally knowable (`$this`, `self`/`static`/`parent`), feeds
|
|
879
|
+
* receiver-typed resolution the same way Python's `self` and Go's receiver do.
|
|
880
|
+
*/
|
|
881
|
+
function phpCallee(node) {
|
|
882
|
+
if (node.type === "function_call_expression") {
|
|
883
|
+
const fn = node.childForFieldName("function");
|
|
884
|
+
const name = fn ? phpName(fn) : null;
|
|
885
|
+
return name ? { name, viaMember: false } : null;
|
|
886
|
+
}
|
|
887
|
+
const nameNode = node.childForFieldName("name");
|
|
888
|
+
if (!nameNode)
|
|
889
|
+
return null;
|
|
890
|
+
if (node.type === "scoped_call_expression") {
|
|
891
|
+
return { name: nameNode.text, viaMember: true, receiver: phpScopeReceiver(node.childForFieldName("scope")) };
|
|
892
|
+
}
|
|
893
|
+
// member_call_expression / nullsafe_member_call_expression
|
|
894
|
+
return { name: nameNode.text, viaMember: true, receiver: phpObjReceiver(node.childForFieldName("object")) };
|
|
895
|
+
}
|
|
896
|
+
/** A PHP callee identifier: bare `name`, or the trailing segment of a
|
|
897
|
+
* `qualified_name` (`\App\helpers\slug` → `slug`). Dynamic calls (`$fn()`) → null. */
|
|
898
|
+
function phpName(node) {
|
|
899
|
+
if (node.type === "name")
|
|
900
|
+
return node.text;
|
|
901
|
+
if (node.type === "qualified_name")
|
|
902
|
+
return node.text.replace(/^.*\\/, "") || null;
|
|
903
|
+
return null;
|
|
904
|
+
}
|
|
905
|
+
/** `$obj->m()` receiver: `$this` normalizes to `this` (→ enclosing class); any
|
|
906
|
+
* other variable is returned verbatim for a bindings lookup. */
|
|
907
|
+
function phpObjReceiver(obj) {
|
|
908
|
+
if (obj?.type !== "variable_name")
|
|
909
|
+
return undefined;
|
|
910
|
+
return obj.text === "$this" ? "this" : obj.text;
|
|
911
|
+
}
|
|
912
|
+
/** `Cls::m()` receiver: `self`/`static`/`parent` normalize to `self` (→ enclosing
|
|
913
|
+
* class); an explicit class name is the trailing segment of its qualified path. */
|
|
914
|
+
function phpScopeReceiver(scope) {
|
|
915
|
+
if (!scope)
|
|
916
|
+
return undefined;
|
|
917
|
+
const text = scope.text;
|
|
918
|
+
if (scope.type === "relative_scope" || text === "self" || text === "static" || text === "parent")
|
|
919
|
+
return "self";
|
|
920
|
+
if (scope.type === "name")
|
|
921
|
+
return text;
|
|
922
|
+
if (scope.type === "qualified_name")
|
|
923
|
+
return text.replace(/^.*\\/, "");
|
|
924
|
+
return undefined;
|
|
925
|
+
}
|
|
728
926
|
/** ts `member_expression` node's receiver text: `this`, `this.x`, or a bare identifier. */
|
|
729
927
|
function tsReceiver(fn) {
|
|
730
928
|
const obj = fn.childForFieldName("object");
|
|
@@ -747,9 +945,18 @@ function isImport(node, lang) {
|
|
|
747
945
|
return node.type === "import_spec";
|
|
748
946
|
if (lang === "java")
|
|
749
947
|
return node.type === "import_declaration";
|
|
948
|
+
// PHP: one edge per imported symbol — the clause leaf inside a (possibly
|
|
949
|
+
// grouped) `use A\B, C\D;` / `use A\{B, C};` declaration.
|
|
950
|
+
if (lang === "php")
|
|
951
|
+
return node.type === "namespace_use_clause";
|
|
750
952
|
return node.type === "import_statement" || node.type === "import_from_statement";
|
|
751
953
|
}
|
|
752
954
|
function importSpecifier(node, lang) {
|
|
955
|
+
if (lang === "php") {
|
|
956
|
+
// namespace_use_clause → its `qualified_name`/`name`, e.g. `App\Models\Animal`.
|
|
957
|
+
const q = node.namedChildren.find((c) => c.type === "qualified_name" || c.type === "name");
|
|
958
|
+
return q ? q.text.replace(/^\\/, "") : null;
|
|
959
|
+
}
|
|
753
960
|
if (lang === "python") {
|
|
754
961
|
const m = node.childForFieldName("module_name") ??
|
|
755
962
|
node.namedChildren.find((c) => c.type === "dotted_name" || c.type === "relative_import");
|