@nanonets/graft 0.10.1 → 0.12.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.
Files changed (229) hide show
  1. package/README.md +32 -11
  2. package/dist/ai/crux.d.ts.map +1 -1
  3. package/dist/ai/crux.js +7 -6
  4. package/dist/ai/crux.js.map +1 -1
  5. package/dist/ai/failure.d.ts +49 -0
  6. package/dist/ai/failure.d.ts.map +1 -0
  7. package/dist/ai/failure.js +74 -0
  8. package/dist/ai/failure.js.map +1 -0
  9. package/dist/ai/llm/anthropic.d.ts.map +1 -1
  10. package/dist/ai/llm/anthropic.js +4 -1
  11. package/dist/ai/llm/anthropic.js.map +1 -1
  12. package/dist/ai/llm/claude-cli.d.ts +60 -0
  13. package/dist/ai/llm/claude-cli.d.ts.map +1 -0
  14. package/dist/ai/llm/claude-cli.js +417 -0
  15. package/dist/ai/llm/claude-cli.js.map +1 -0
  16. package/dist/ai/llm/openai.d.ts.map +1 -1
  17. package/dist/ai/llm/openai.js +2 -0
  18. package/dist/ai/llm/openai.js.map +1 -1
  19. package/dist/ai/llm/types.d.ts +9 -0
  20. package/dist/ai/llm/types.d.ts.map +1 -1
  21. package/dist/ai/llm/types.js +12 -1
  22. package/dist/ai/llm/types.js.map +1 -1
  23. package/dist/ask/ask.d.ts.map +1 -1
  24. package/dist/ask/ask.js +39 -45
  25. package/dist/ask/ask.js.map +1 -1
  26. package/dist/ask/fuse.d.ts +83 -46
  27. package/dist/ask/fuse.d.ts.map +1 -1
  28. package/dist/ask/fuse.js +165 -67
  29. package/dist/ask/fuse.js.map +1 -1
  30. package/dist/blast/blast-cli.d.ts +30 -0
  31. package/dist/blast/blast-cli.d.ts.map +1 -0
  32. package/dist/blast/blast-cli.js +163 -0
  33. package/dist/blast/blast-cli.js.map +1 -0
  34. package/dist/blast/blast.d.ts +119 -0
  35. package/dist/blast/blast.d.ts.map +1 -0
  36. package/dist/blast/blast.js +383 -0
  37. package/dist/blast/blast.js.map +1 -0
  38. package/dist/blast/diff.d.ts +53 -0
  39. package/dist/blast/diff.d.ts.map +1 -0
  40. package/dist/blast/diff.js +193 -0
  41. package/dist/blast/diff.js.map +1 -0
  42. package/dist/blast/modules.d.ts +33 -0
  43. package/dist/blast/modules.d.ts.map +1 -0
  44. package/dist/blast/modules.js +83 -0
  45. package/dist/blast/modules.js.map +1 -0
  46. package/dist/blast/name.d.ts +61 -0
  47. package/dist/blast/name.d.ts.map +1 -0
  48. package/dist/blast/name.js +233 -0
  49. package/dist/blast/name.js.map +1 -0
  50. package/dist/blast/render.d.ts +37 -0
  51. package/dist/blast/render.d.ts.map +1 -0
  52. package/dist/blast/render.js +300 -0
  53. package/dist/blast/render.js.map +1 -0
  54. package/dist/blast/viz.d.ts +17 -0
  55. package/dist/blast/viz.d.ts.map +1 -0
  56. package/dist/blast/viz.js +324 -0
  57. package/dist/blast/viz.js.map +1 -0
  58. package/dist/claude/hooks.d.ts.map +1 -1
  59. package/dist/claude/hooks.js +18 -2
  60. package/dist/claude/hooks.js.map +1 -1
  61. package/dist/claude/shim-template.d.ts.map +1 -1
  62. package/dist/claude/shim-template.js +45 -15
  63. package/dist/claude/shim-template.js.map +1 -1
  64. package/dist/claude/state.d.ts +5 -0
  65. package/dist/claude/state.d.ts.map +1 -1
  66. package/dist/claude/state.js.map +1 -1
  67. package/dist/cli-picker.d.ts +44 -5
  68. package/dist/cli-picker.d.ts.map +1 -1
  69. package/dist/cli-picker.js +73 -26
  70. package/dist/cli-picker.js.map +1 -1
  71. package/dist/cli.js +270 -14
  72. package/dist/cli.js.map +1 -1
  73. package/dist/context/build.d.ts +8 -0
  74. package/dist/context/build.d.ts.map +1 -1
  75. package/dist/context/build.js +57 -9
  76. package/dist/context/build.js.map +1 -1
  77. package/dist/context/check.d.ts.map +1 -1
  78. package/dist/context/check.js +7 -6
  79. package/dist/context/check.js.map +1 -1
  80. package/dist/context/node-file.d.ts.map +1 -1
  81. package/dist/context/node-file.js +9 -2
  82. package/dist/context/node-file.js.map +1 -1
  83. package/dist/graph/bindings.d.ts.map +1 -1
  84. package/dist/graph/bindings.js +171 -8
  85. package/dist/graph/bindings.js.map +1 -1
  86. package/dist/graph/build.d.ts.map +1 -1
  87. package/dist/graph/build.js +36 -16
  88. package/dist/graph/build.js.map +1 -1
  89. package/dist/graph/check.d.ts +4 -0
  90. package/dist/graph/check.d.ts.map +1 -1
  91. package/dist/graph/check.js +8 -1
  92. package/dist/graph/check.js.map +1 -1
  93. package/dist/graph/container.d.ts +63 -0
  94. package/dist/graph/container.d.ts.map +1 -0
  95. package/dist/graph/container.js +185 -0
  96. package/dist/graph/container.js.map +1 -0
  97. package/dist/graph/enrich.d.ts +18 -0
  98. package/dist/graph/enrich.d.ts.map +1 -1
  99. package/dist/graph/enrich.js +55 -2
  100. package/dist/graph/enrich.js.map +1 -1
  101. package/dist/graph/extract.d.ts +3 -1
  102. package/dist/graph/extract.d.ts.map +1 -1
  103. package/dist/graph/extract.js +215 -8
  104. package/dist/graph/extract.js.map +1 -1
  105. package/dist/graph/generic.d.ts +34 -1
  106. package/dist/graph/generic.d.ts.map +1 -1
  107. package/dist/graph/generic.js +152 -3
  108. package/dist/graph/generic.js.map +1 -1
  109. package/dist/graph/queries/clojure.scm +58 -0
  110. package/dist/graph/resolve.d.ts.map +1 -1
  111. package/dist/graph/resolve.js +132 -2
  112. package/dist/graph/resolve.js.map +1 -1
  113. package/dist/graph/scopes.d.ts +2 -2
  114. package/dist/graph/scopes.d.ts.map +1 -1
  115. package/dist/graph/scopes.js +8 -6
  116. package/dist/graph/scopes.js.map +1 -1
  117. package/dist/graph/source-files.d.ts +13 -4
  118. package/dist/graph/source-files.d.ts.map +1 -1
  119. package/dist/graph/source-files.js +35 -12
  120. package/dist/graph/source-files.js.map +1 -1
  121. package/dist/graph/types.d.ts +1 -1
  122. package/dist/graph/types.d.ts.map +1 -1
  123. package/dist/graph/workspace-cli.d.ts +2 -0
  124. package/dist/graph/workspace-cli.d.ts.map +1 -1
  125. package/dist/graph/workspace-cli.js +10 -4
  126. package/dist/graph/workspace-cli.js.map +1 -1
  127. package/dist/graph/workspace.d.ts +11 -6
  128. package/dist/graph/workspace.d.ts.map +1 -1
  129. package/dist/graph/workspace.js +24 -13
  130. package/dist/graph/workspace.js.map +1 -1
  131. package/dist/graph/write.d.ts.map +1 -1
  132. package/dist/graph/write.js +25 -2
  133. package/dist/graph/write.js.map +1 -1
  134. package/dist/hosts/antigravity.d.ts +7 -0
  135. package/dist/hosts/antigravity.d.ts.map +1 -0
  136. package/dist/hosts/antigravity.js +42 -0
  137. package/dist/hosts/antigravity.js.map +1 -0
  138. package/dist/hosts/init.d.ts.map +1 -1
  139. package/dist/hosts/init.js +6 -1
  140. package/dist/hosts/init.js.map +1 -1
  141. package/dist/hosts/mcp-config.d.ts.map +1 -1
  142. package/dist/hosts/mcp-config.js +7 -0
  143. package/dist/hosts/mcp-config.js.map +1 -1
  144. package/dist/hosts/plan.d.ts +1 -1
  145. package/dist/hosts/plan.d.ts.map +1 -1
  146. package/dist/hosts/plan.js +2 -0
  147. package/dist/hosts/plan.js.map +1 -1
  148. package/dist/hosts/registry.d.ts.map +1 -1
  149. package/dist/hosts/registry.js +13 -0
  150. package/dist/hosts/registry.js.map +1 -1
  151. package/dist/ingest/fs.d.ts +9 -2
  152. package/dist/ingest/fs.d.ts.map +1 -1
  153. package/dist/ingest/fs.js +100 -16
  154. package/dist/ingest/fs.js.map +1 -1
  155. package/dist/mcp/server.d.ts.map +1 -1
  156. package/dist/mcp/server.js +45 -2
  157. package/dist/mcp/server.js.map +1 -1
  158. package/dist/telemetry/contract.d.ts +90 -0
  159. package/dist/telemetry/contract.d.ts.map +1 -0
  160. package/dist/telemetry/contract.js +203 -0
  161. package/dist/telemetry/contract.js.map +1 -0
  162. package/dist/telemetry/flush.d.ts +21 -0
  163. package/dist/telemetry/flush.d.ts.map +1 -0
  164. package/dist/telemetry/flush.js +84 -0
  165. package/dist/telemetry/flush.js.map +1 -0
  166. package/dist/telemetry/gate.d.ts +16 -0
  167. package/dist/telemetry/gate.d.ts.map +1 -0
  168. package/dist/telemetry/gate.js +64 -0
  169. package/dist/telemetry/gate.js.map +1 -0
  170. package/dist/telemetry/identity.d.ts +33 -0
  171. package/dist/telemetry/identity.d.ts.map +1 -0
  172. package/dist/telemetry/identity.js +80 -0
  173. package/dist/telemetry/identity.js.map +1 -0
  174. package/dist/telemetry/index.d.ts +18 -0
  175. package/dist/telemetry/index.d.ts.map +1 -0
  176. package/dist/telemetry/index.js +16 -0
  177. package/dist/telemetry/index.js.map +1 -0
  178. package/dist/telemetry/key.d.ts +21 -0
  179. package/dist/telemetry/key.d.ts.map +1 -0
  180. package/dist/telemetry/key.js +49 -0
  181. package/dist/telemetry/key.js.map +1 -0
  182. package/dist/telemetry/notice.d.ts +19 -0
  183. package/dist/telemetry/notice.d.ts.map +1 -0
  184. package/dist/telemetry/notice.js +90 -0
  185. package/dist/telemetry/notice.js.map +1 -0
  186. package/dist/telemetry/queue.d.ts +35 -0
  187. package/dist/telemetry/queue.d.ts.map +1 -0
  188. package/dist/telemetry/queue.js +162 -0
  189. package/dist/telemetry/queue.js.map +1 -0
  190. package/dist/telemetry/send.d.ts +19 -0
  191. package/dist/telemetry/send.d.ts.map +1 -0
  192. package/dist/telemetry/send.js +84 -0
  193. package/dist/telemetry/send.js.map +1 -0
  194. package/dist/telemetry/sessions.d.ts +8 -0
  195. package/dist/telemetry/sessions.d.ts.map +1 -0
  196. package/dist/telemetry/sessions.js +81 -0
  197. package/dist/telemetry/sessions.js.map +1 -0
  198. package/dist/telemetry/track.d.ts +43 -0
  199. package/dist/telemetry/track.d.ts.map +1 -0
  200. package/dist/telemetry/track.js +108 -0
  201. package/dist/telemetry/track.js.map +1 -0
  202. package/dist/upkeep-run.d.ts +15 -0
  203. package/dist/upkeep-run.d.ts.map +1 -0
  204. package/dist/upkeep-run.js +60 -0
  205. package/dist/upkeep-run.js.map +1 -0
  206. package/dist/upkeep.d.ts +114 -0
  207. package/dist/upkeep.d.ts.map +1 -0
  208. package/dist/upkeep.js +232 -0
  209. package/dist/upkeep.js.map +1 -0
  210. package/dist/util/num.d.ts +3 -0
  211. package/dist/util/num.d.ts.map +1 -0
  212. package/dist/util/num.js +20 -0
  213. package/dist/util/num.js.map +1 -0
  214. package/dist/util/state.d.ts +11 -4
  215. package/dist/util/state.d.ts.map +1 -1
  216. package/dist/util/state.js +9 -0
  217. package/dist/util/state.js.map +1 -1
  218. package/dist/viewer/app.js +1 -1
  219. package/dist/viewer/index.html +1 -0
  220. package/dist/viewer/style.css +23 -2
  221. package/dist/viz/assemble.d.ts +33 -0
  222. package/dist/viz/assemble.d.ts.map +1 -1
  223. package/dist/viz/assemble.js.map +1 -1
  224. package/dist/viz/export.d.ts +39 -0
  225. package/dist/viz/export.d.ts.map +1 -0
  226. package/dist/viz/export.js +98 -0
  227. package/dist/viz/export.js.map +1 -0
  228. package/package.json +6 -5
  229. 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;AACvE,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;CAC7E;AAED,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;CAClB;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,CAmFtB"}
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"}
@@ -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 = { cached: 0, computed: 0, stale: 0, pending: 0, errors: [] };
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. */
@@ -1 +1 @@
1
- {"version":3,"file":"enrich.js","sourceRoot":"","sources":["../../src/graph/enrich.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"enrich.js","sourceRoot":"","sources":["../../src/graph/enrich.ts"],"names":[],"mappings":"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"}
@@ -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":"AAeA,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,CAAC;AAqCvE,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;AAwHD,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"}
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"}
@@ -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
- : tsExported(node),
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 !== definition && node !== definitionValue && isFunctionBoundary(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") === node || parent.childForFieldName("name") === node;
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") === node;
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
- const t = node.childForFieldName("type");
650
- return t ? { name: t.text, viaMember: false } : null;
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");