@descryy/adapter-java 0.1.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.
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The Java `LanguageAdapter` — all seven methods, breadth tier.
3
+ *
4
+ * The parser is tree-sitter's Java grammar over the shared WASM harness. There
5
+ * is no JDT and no SCIP, and `capabilities()` says so rather than leaving it to
6
+ * be inferred from an empty result.
7
+ *
8
+ * Framework extractors for **Spring** (`spring.ts`) and **JPA** (`jpa.ts`) are
9
+ * bound. Both read declarations rather than names, and both are the FLOOR under
10
+ * DEC-115 — framework introspection would be a promotion over the same node ids
11
+ * and needs a runnable application, which no corpus here is.
12
+ */
13
+ import { type LanguageAdapter, type ResolutionLevel } from "@descryy/ir";
14
+ import { toRepoRelative } from "@descryy/adapter-common";
15
+ import { LANGUAGE } from "./extract.ts";
16
+ export declare const ADAPTER_ID = "adapter-java";
17
+ export declare const ADAPTER_VERSION = "0.1.0";
18
+ export declare const DEFAULT_JAVA_GLOBS: readonly ["**/*.java"];
19
+ export interface JavaAdapterOptions {
20
+ readonly globs?: readonly string[];
21
+ readonly maxResolution?: ResolutionLevel;
22
+ }
23
+ export interface JavaAdapter extends LanguageAdapter {
24
+ readonly id: string;
25
+ readonly version: string;
26
+ }
27
+ export declare function createJavaAdapter(options?: JavaAdapterOptions): JavaAdapter;
28
+ /** Content hash of a repo-relative file, for `FileRef`. */
29
+ export declare function hashOf(root: string, relative: string): string;
30
+ export { LANGUAGE, toRepoRelative };
31
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,EAML,KAAK,eAAe,EAGpB,KAAK,eAAe,EAIrB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAyB,cAAc,EAAwB,MAAM,yBAAyB,CAAC;AAItG,OAAO,EAA4B,QAAQ,EAAmB,MAAM,cAAc,CAAC;AAGnF,eAAO,MAAM,UAAU,iBAAiB,CAAC;AACzC,eAAO,MAAM,eAAe,UAAU,CAAC;AACvC,eAAO,MAAM,kBAAkB,wBAAyB,CAAC;AA8CzD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,eAAe,CAAC;CAC1C;AAYD,MAAM,WAAW,WAAY,SAAQ,eAAe;IAClD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAwO/E;AAED,2DAA2D;AAC3D,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM7D;AAED,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC"}
@@ -0,0 +1,298 @@
1
+ /**
2
+ * The Java `LanguageAdapter` — all seven methods, breadth tier.
3
+ *
4
+ * The parser is tree-sitter's Java grammar over the shared WASM harness. There
5
+ * is no JDT and no SCIP, and `capabilities()` says so rather than leaving it to
6
+ * be inferred from an empty result.
7
+ *
8
+ * Framework extractors for **Spring** (`spring.ts`) and **JPA** (`jpa.ts`) are
9
+ * bound. Both read declarations rather than names, and both are the FLOOR under
10
+ * DEC-115 — framework introspection would be a promotion over the same node ids
11
+ * and needs a runnable application, which no corpus here is.
12
+ */
13
+ import { createHash } from "node:crypto";
14
+ import { createRequire } from "node:module";
15
+ import { existsSync, readFileSync } from "node:fs";
16
+ import { join } from "node:path";
17
+ import { CLIENT_CALL_EXTRACTOR, ORM_EXTRACTOR, ROUTE_EXTRACTOR, } from "@descryy/ir";
18
+ import { discover, isolateFile, toRepoRelative } from "@descryy/adapter-common";
19
+ import { parserFor, parseText } from "@descryy/adapter-treesitter";
20
+ import { readUnit } from "./parse.js";
21
+ import { extract, DEFAULT_PACKAGE, LANGUAGE } from "./extract.js";
22
+ import { anchorOf, identityPackage, sourceRootOf } from "./roots.js";
23
+ export const ADAPTER_ID = "adapter-java";
24
+ export const ADAPTER_VERSION = "0.1.0";
25
+ export const DEFAULT_JAVA_GLOBS = ["**/*.java"];
26
+ const PRODUCED_BY = `${ADAPTER_ID}@${ADAPTER_VERSION}`;
27
+ /**
28
+ * The grammar, found the same way whether this module was compiled or stripped.
29
+ *
30
+ * A copy is shipped beside the compiled output so an installed package needs
31
+ * nothing resolved at run time. But `node --test` and the conformance runner
32
+ * load `src/*.ts` directly, where `import.meta.dirname` is `src` and the copy is
33
+ * in `dist` — so the declared dependency is the fallback, and it is the one that
34
+ * makes the source path work at all.
35
+ */
36
+ function grammarPath() {
37
+ const beside = join(import.meta.dirname, "tree-sitter-java.wasm");
38
+ if (existsSync(beside))
39
+ return beside;
40
+ return createRequire(import.meta.url).resolve("tree-sitter-java/tree-sitter-java.wasm");
41
+ }
42
+ /**
43
+ * Directories that hold build output rather than source.
44
+ *
45
+ * A Java repository routinely contains a generated or copied duplicate of its
46
+ * own classes, and analysing both produces two declarations of one type — a
47
+ * duplicate node id, the failure DEC-077 records arriving by another road.
48
+ */
49
+ const BUILD_DIRECTORIES = ["/target/", "/build/", "/out/", "/bin/", "/.gradle/"];
50
+ /**
51
+ * Is this path build output rather than source?
52
+ *
53
+ * The name test alone is not safe, and that is not hypothetical: `build`, `bin`
54
+ * and `target` are ordinary package names, so `src/main/java/com/x/build/Cfg.java`
55
+ * is a source file that a bare substring match silently deletes from the graph.
56
+ * A declared source root settles it — anything under `src/` is source no matter
57
+ * what its packages are called, and the name test applies only outside one.
58
+ *
59
+ * This is the general form of the rule rather than the one that happened to work
60
+ * on the repositories in front of it.
61
+ */
62
+ function isBuildOutput(file) {
63
+ const path = `/${file}`;
64
+ if (path.includes("/src/"))
65
+ return false;
66
+ return BUILD_DIRECTORIES.some((directory) => path.includes(directory));
67
+ }
68
+ export function createJavaAdapter(options = {}) {
69
+ const globs = options.globs ?? DEFAULT_JAVA_GLOBS;
70
+ const ceiling = options.maxResolution ?? 2;
71
+ let session;
72
+ let parser;
73
+ const filesUnder = (root) => discover(root.absolutePath, globs).filter((file) => !isBuildOutput(file));
74
+ return {
75
+ id: ADAPTER_ID,
76
+ version: ADAPTER_VERSION,
77
+ async detect(root) {
78
+ const files = filesUnder(root);
79
+ const evidence = [];
80
+ if (files.length > 0)
81
+ evidence.push(`${files.length} .java files outside build directories`);
82
+ for (const manifest of ["pom.xml", "build.gradle", "build.gradle.kts", "settings.gradle"]) {
83
+ try {
84
+ readFileSync(join(root.absolutePath, manifest));
85
+ evidence.push(`${manifest} at the repository root`);
86
+ }
87
+ catch {
88
+ // Absent. A build manifest is corroboration, not a requirement — a
89
+ // source tree with no manifest is still Java.
90
+ }
91
+ }
92
+ return { detected: files.length > 0, roots: files.length > 0 ? [root.absolutePath] : [], evidence };
93
+ },
94
+ capabilities() {
95
+ return {
96
+ maxResolution: ceiling,
97
+ /**
98
+ * `API_ROUTE`, `API_ENDPOINT` and `MODEL` are now claimed, because the
99
+ * Spring and JPA extractors earn them from **declarations** — an
100
+ * annotation the framework itself acts on — rather than from a name.
101
+ * DEC-043's objection was to the name heuristic, not to the node types.
102
+ *
103
+ * `DTO` stays absent, and golden 07's note says why: in the corpus
104
+ * `Order` and `CreateOrderRequest` are structurally identical and
105
+ * separable only by their names. `@Entity` distinguishes the model;
106
+ * nothing distinguishes the DTO, so nothing claims it.
107
+ *
108
+ * `frameworkExtractors` and `frameworkCapabilities` are declared
109
+ * together, in the change that ships the extractors and not before:
110
+ * `run.ts` skips a pattern requiring a capability only while nothing is
111
+ * bound, so declaring early turns skips into failures.
112
+ *
113
+ * `USES_API` and `client-call-extractor` (`frameworkCapabilities`) are
114
+ * both claimed. `client.ts` (D-FIX-3, DEC-241) genuinely extracts real
115
+ * `USES_API` edges from `RestTemplate`/`WebClient` calls with a literal
116
+ * path, measured live on `shopizer` (9 edges) and `spring-petclinic`
117
+ * (0 edges, an honest zero — see DEC-260).
118
+ *
119
+ * `CLIENT_CALL_EXTRACTOR` was declared, reverted, then declared again —
120
+ * DEC-262 and DEC-246 both have the measurement, in that order.
121
+ * DEC-262 found it correctly unverifiable by the corpus as it then
122
+ * stood: golden pattern 08's caller role (`order_page`) requires a real
123
+ * HTTP call, and the Java fixture's `OrderPage.render()` called
124
+ * `routes.getOrder(id)` in-process, not through any HTTP client shape
125
+ * at all — no fixture change could earn a pass without inventing that
126
+ * shape. DEC-246 built it: `OrderPage.render()` now calls
127
+ * `restTemplate.getForObject("/orders/{id}", ...)`, the same URI-
128
+ * template form Python's and Kotlin's `order_page` already use for the
129
+ * identical role, and pattern 08 now **passes**, not merely skips.
130
+ *
131
+ * `client-base-extractor` stays absent — `client.ts` reads a call's own
132
+ * literal path, never a base URL composed separately, so patterns
133
+ * 08a/08b/08c (DEC-164's strict base-resolution contract) are a
134
+ * different, unaddressed row.
135
+ */
136
+ nodeTypes: ["MODULE", "CLASS", "FUNCTION", "TEST_CASE", "API_ROUTE", "API_ENDPOINT", "MODEL"],
137
+ edgeTypes: [
138
+ "IMPORTS",
139
+ "CALLS",
140
+ "TESTS",
141
+ "INHERITS",
142
+ "IMPLEMENTS",
143
+ "USES_TYPE",
144
+ "SERVES_API",
145
+ "USES_API",
146
+ ],
147
+ hasCallHierarchy: false,
148
+ hasTypeHierarchy: false,
149
+ /**
150
+ * Directories this ecosystem installs dependencies or build output into —
151
+ * DEC-110's end state. The engine used to hold `node_modules`/`vendor`/`target`
152
+ * in a hardcoded list; it holds none of them now and consumes this instead.
153
+ *
154
+ * Maven writes `target/`, Gradle writes `build/`, by those tools' own convention.
155
+ * Declared from the build tools rather than from an existing exclusion, because
156
+ * this adapter has none — its file walk is source-root driven.
157
+ *
158
+ * Names only — the walk matches one path component, so a path or glob matches
159
+ * nothing. Nothing dotted — those are skipped structurally already.
160
+ */
161
+ noiseDirectories: ["target", "build"],
162
+ // `jaxrs` and `spring-data-mongodb` were added under `language-problems.md`
163
+ // §3's rows 1-3: JAX-RS gets its own route reader in `spring.ts`
164
+ // (`jaxrsRoutes`) rather than being folded into `spring`'s name, because
165
+ // it is a materially different framework reachable without Spring at
166
+ // all; `spring-data-mongodb` names `jpa.ts`'s `@Document` admission
167
+ // rather than a new file, since the field/nullability machinery is
168
+ // shared verbatim with JPA.
169
+ frameworkExtractors: ["spring", "jaxrs", "jpa", "spring-data-mongodb", "client-call-extractor"],
170
+ frameworkCapabilities: [ROUTE_EXTRACTOR, ORM_EXTRACTOR, CLIENT_CALL_EXTRACTOR],
171
+ };
172
+ },
173
+ async prepare(ctx) {
174
+ const files = filesUnder(ctx.root);
175
+ parser ??= await parserFor(grammarPath());
176
+ const units = [];
177
+ const failures = [];
178
+ const unfinished = [];
179
+ const anchors = new Map();
180
+ for (const file of files) {
181
+ if (ctx.signal.aborted)
182
+ break;
183
+ let text;
184
+ try {
185
+ text = readFileSync(join(ctx.root.absolutePath, file), "utf8");
186
+ }
187
+ catch (error) {
188
+ failures.push({ kind: "unreadable", file, detail: error instanceof Error ? error.message : String(error) });
189
+ continue;
190
+ }
191
+ const outcome = parseText(parser, file, text);
192
+ if (outcome.tree === undefined) {
193
+ if (outcome.failure !== undefined)
194
+ failures.push(outcome.failure);
195
+ continue;
196
+ }
197
+ // Isolated: a throw in the walk used to cost the run rather than the file.
198
+ const read = isolateFile(file, () => readUnit(outcome.tree.rootNode, file, outcome.tree.rootNode.hasError));
199
+ if (read.failure !== undefined) {
200
+ unfinished.push(read.failure);
201
+ outcome.tree.delete();
202
+ continue;
203
+ }
204
+ const unit = read.value;
205
+ // The build module and source set are on disk, not in the syntax, so
206
+ // they are resolved here and cached — one `existsSync` walk per source
207
+ // root rather than per file.
208
+ const sourceRoot = sourceRootOf(file, unit.packageName);
209
+ let anchor = sourceRoot === undefined ? undefined : anchors.get(sourceRoot);
210
+ if (anchor === undefined && sourceRoot !== undefined) {
211
+ anchor = anchorOf(ctx.root.absolutePath, sourceRoot);
212
+ anchors.set(sourceRoot, anchor);
213
+ }
214
+ units.push({
215
+ ...unit,
216
+ identityPackage: anchor === undefined
217
+ ? // The file does not sit where its package declaration says it
218
+ // should. Rather than invent a module for it, it anchors on its
219
+ // package alone and the ambiguity that may cause is disclosed by
220
+ // the resolver rather than hidden by a guess here.
221
+ unit.packageName === "" ? DEFAULT_PACKAGE : unit.packageName
222
+ : identityPackage(anchor, unit.packageName, DEFAULT_PACKAGE),
223
+ });
224
+ outcome.tree.delete();
225
+ }
226
+ // Every level this adapter offers rests on the same parse: imports are in
227
+ // the source, so R1 is reached whenever parsing succeeded at all. There is
228
+ // no rung between 0 and the ceiling to fall back to.
229
+ const reached = units.length === 0 ? 0 : ceiling;
230
+ session = { root: ctx.root, files, units, reached, failures, unfinished };
231
+ return reached;
232
+ },
233
+ async parseFiles(files) {
234
+ // Independent of `prepare` by contract: R0 must be achievable with nothing
235
+ // resolved. The unit is the parsed record when one exists and an empty
236
+ // placeholder otherwise, because the caller owns the file list.
237
+ const byFile = new Map((session?.units ?? []).map((unit) => [unit.file, unit]));
238
+ return files.map((file) => ({ file, tree: byFile.get(file.path) ?? {} }));
239
+ },
240
+ extractNodes() {
241
+ return current().nodes;
242
+ },
243
+ extractEdges() {
244
+ return current().edges;
245
+ },
246
+ async emit(ctx) {
247
+ const reached = await this.prepare(ctx);
248
+ const active = session;
249
+ const extraction = current();
250
+ const failedFiles = new Set([...active.failures.map((f) => f.file), ...active.unfinished.map((f) => f.file)]);
251
+ return {
252
+ repo: ctx.root.repo,
253
+ ...(ctx.root.workspace === undefined ? {} : { workspace: ctx.root.workspace }),
254
+ commitSha: ctx.root.commitSha,
255
+ producedBy: PRODUCED_BY,
256
+ sourceFiles: active.files.filter((f) => !failedFiles.has(f)),
257
+ skippedFiles: [
258
+ ...active.failures.map((f) => ({ file: f.file, reason: f.kind, detail: f.detail })),
259
+ // `other`: it parsed, and what failed is our walk of it. The detail says which.
260
+ ...active.unfinished.map((f) => ({ file: f.file, reason: "other", detail: f.detail })),
261
+ ],
262
+ reachedResolution: reached,
263
+ nodes: extraction.nodes,
264
+ edges: extraction.edges,
265
+ unresolved: extraction.unresolved,
266
+ };
267
+ },
268
+ async dispose() {
269
+ session = undefined;
270
+ parser?.delete();
271
+ parser = undefined;
272
+ },
273
+ };
274
+ function current() {
275
+ const active = session;
276
+ if (active === undefined || active.units.length === 0) {
277
+ return { nodes: [], edges: [], unresolved: [] };
278
+ }
279
+ return extract({
280
+ repo: active.root.repo,
281
+ scope: { repo: active.root.repo, ...(active.root.workspace === undefined ? {} : { workspace: active.root.workspace }) },
282
+ producedBy: PRODUCED_BY,
283
+ reached: active.reached,
284
+ units: active.units,
285
+ });
286
+ }
287
+ }
288
+ /** Content hash of a repo-relative file, for `FileRef`. */
289
+ export function hashOf(root, relative) {
290
+ try {
291
+ return createHash("sha256").update(readFileSync(join(root, relative))).digest("hex").slice(0, 32);
292
+ }
293
+ catch {
294
+ return "";
295
+ }
296
+ }
297
+ export { LANGUAGE, toRepoRelative };
298
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * The caller's half of the HTTP boundary: `USES_API`, golden pattern 08.
3
+ *
4
+ * `SERVES_API` is minted in `extract.ts` from a route's annotations. This reads
5
+ * the other end — an outbound call with a statically knowable path — and mints
6
+ * the **same** `API_ENDPOINT` node from the same `endpointQsp`, so the two join
7
+ * without either side knowing the other ran. DEC-115's one hard constraint: two
8
+ * producers that mint different ids do not conflict, they silently fail to join.
9
+ *
10
+ * FUNCTION ──USES_API──▶ API_ENDPOINT ◀──SERVES_API── API_ROUTE
11
+ *
12
+ * ## What these edges actually mean, and why it must be said in the edge
13
+ *
14
+ * Measured before this was written (`bench/client-call-census.mjs`, DEC-189):
15
+ * across `shopizer`, `mall`, `morphia`, `okhttp` and `spring-petclinic` there
16
+ * are **16** client call sites carrying a repository-relative literal path.
17
+ * **Twelve are in test files, four are on a mock transport, and none are
18
+ * production code.**
19
+ *
20
+ * So in Java these edges are almost entirely `TEST_CASE`-shaped: an integration
21
+ * test driving `TestRestTemplate` at the application's own routes. That is real
22
+ * and it is useful — it answers *which routes have integration coverage*, which
23
+ * is the **Verification status** axis (AI layer §20, §42), a separate axis from
24
+ * the confidence label. It is **not** service-to-service coupling, and a
25
+ * consumer reading it as "this service calls that service" would be wrong.
26
+ *
27
+ * The distinction therefore travels **in the edge**, as `attrs.callerKind`, not
28
+ * in a comment here. A count in a decision record is invisible to a consumer;
29
+ * `attrs` is what the edge carries. (`attrs` is not read above the IR — which is
30
+ * exactly why the same fact is also stated in the disclosure below, where a
31
+ * reader will see it.)
32
+ *
33
+ * ## Why the receiver's type is required
34
+ *
35
+ * `execute`, `put`, `delete` and `uri` are ordinary method names. Admitting a
36
+ * call on its name alone would emit `USES_API` for `list.put("/tmp/x")`, and a
37
+ * wrong edge here joins a caller to a route it never calls — which root-cause
38
+ * traversal then follows. So a call is admitted only when its receiver's
39
+ * **declared type** is a known client. That is R2 evidence: a reference resolved
40
+ * to a definition through a written annotation, exactly as the rest of this
41
+ * adapter reads receivers.
42
+ *
43
+ * The cost is disclosed rather than hidden: a chained builder
44
+ * (`new Request.Builder().url("/")`) has no receiver with a written type and is
45
+ * refused. All four such sites in the corpora are `mockWebServer`, so nothing
46
+ * real is lost today — but the refusal is a rule, not a measurement, and it will
47
+ * cost real call sites in a codebase that chains.
48
+ *
49
+ * ## Ledger row D-FIX-3: a known client this reader does not extract
50
+ *
51
+ * Everything above requires the receiver's type to already be in
52
+ * {@link CLIENT_TYPES} before any refusal fires — so a call through a client
53
+ * this adapter has never heard of took neither branch. It matched no name in
54
+ * {@link URL_FIRST}'s companion set below, `typeOfReceiver` was never asked,
55
+ * and the reference fell out of the loop with `continue` before reaching a
56
+ * single `refuse(...)` call. **Zero edges and zero ledger rows is the same
57
+ * output a repository with no HTTP calls at all produces.** Sherpa's
58
+ * TypeScript diagnosis found the identical shape — 26 wrapped-`axios` call
59
+ * sites across 14 files, none reaching the refusal ledger — and it is the
60
+ * reason this row exists rather than being filed as ordinary recall.
61
+ *
62
+ * {@link BUILDER_CLIENT_TYPES} closes it for the two client families measured
63
+ * on the reference corpora (`bench/client-call-census.mjs`'s `CLIENTS.java`
64
+ * list, `okhttp3.OkHttpClient` and `java.net.http.HttpClient`) — **not by
65
+ * reading their calls**, but by recognising the receiver type and filing a
66
+ * refusal for every call through it. Both clients pass the outbound request as
67
+ * a **separately constructed object** (`Request`, `HttpRequest`) rather than a
68
+ * literal argument on the call itself, so building real extraction for them is
69
+ * a different, larger row — a second `firstStringArgument`-shaped read through
70
+ * a builder chain — and is out of scope here. What is in scope is closing the
71
+ * silence: **every** call through a receiver whose declared type names one of
72
+ * these clients is now accounted for, either as an edge (impossible for these
73
+ * two, by construction) or as a ledger row.
74
+ *
75
+ * ### Why the trigger is receiver-type resolution, not a file-level import scan
76
+ *
77
+ * The population D-FIX-3 was scoped against is "a file that imports a known
78
+ * HTTP client and makes calls the extractor did not claim." Read literally,
79
+ * that would fire on **every** method call in a file that merely imports
80
+ * `okhttp3.OkHttpClient` anywhere — including calls with no relation to it —
81
+ * which is exactly the "fires on everything" failure the row warns against.
82
+ * This adapter already has a narrower, previously-measured discriminator for
83
+ * the identical question: `typeOfReceiver`, R2 evidence, a written declaration
84
+ * this reader can point at. Reusing it means the new population is *provably*
85
+ * bounded to calls whose receiver is declared as one of these types — no
86
+ * broader — and it costs nothing new: `writtenReceiverType` in `extract.ts`
87
+ * already resolves an arbitrary type name syntactically, whether or not this
88
+ * adapter goes on to model it, so `OkHttpClient` and `HttpClient` resolve
89
+ * exactly as `RestTemplate` does today.
90
+ *
91
+ * ### The reconciliation this row makes an assertion rather than a discipline
92
+ *
93
+ * `candidateClientRefs` (below) recomputes, independently of the loop in
94
+ * {@link clientCalls}, which references in a method are candidates at all —
95
+ * same predicate, factored out so a future edit to the loop cannot silently
96
+ * narrow what counts as a candidate without the test that calls both noticing.
97
+ * `test/client.test.ts` asserts `calls.length + refusals.length ===
98
+ * candidateClientRefs(method).length` on every fixture, which is the shape
99
+ * DEC-098 found missing the hard way: a guard that dropped 113 of 140 call
100
+ * sites with no edge, no row, and no failing test.
101
+ */
102
+ import { type IdentityScope, type IRNode } from "@descryy/ir";
103
+ import type { JavaMethod, JavaRef } from "./parse.ts";
104
+ export interface ClientCall {
105
+ /** The `FUNCTION` node making the call. */
106
+ readonly fromId: string;
107
+ readonly method: string;
108
+ readonly template: string;
109
+ readonly verb: string;
110
+ readonly line: number;
111
+ /** `test` when the enclosing method is a test case, else `production`. */
112
+ readonly callerKind: "test" | "production";
113
+ }
114
+ export interface ClientRefusal {
115
+ readonly fromId: string;
116
+ readonly raw: string;
117
+ readonly line: number;
118
+ readonly reason: string;
119
+ /** DEC-242's `attrs.blockedBy` — the literal blocking expression, or `null`. */
120
+ readonly blockedBy: string | null;
121
+ /** DEC-242's `attrs.refusalClass` — `undefined` means unclassified, never askable. */
122
+ readonly refusalClass: BaseRefusalClass | "out-of-scope" | undefined;
123
+ /**
124
+ * Diagnostic only, not part of DEC-242 — see `adapter-rust/src/client.ts`'s
125
+ * own doc for what this is and why it is not shipped as part of the
126
+ * contract. Present only on the generic fallthrough of `diagnoseArgument`.
127
+ */
128
+ readonly argumentKind?: "field" | "call" | "concatenation" | "other";
129
+ }
130
+ export type BaseRefusalClass = "value-unknown" | "varies-per-call" | "capability-gap";
131
+ /**
132
+ * Every reference in a method that {@link clientCalls} will act on — an edge,
133
+ * a refusal, or (only past this point, where the receiver's type is unknown)
134
+ * a true silence. Factored out of the loop below so the reconciliation
135
+ * assertion in `test/client.test.ts` recomputes candidacy independently of
136
+ * whatever the loop does with each candidate: a future edit that narrows the
137
+ * loop's own filter without touching this function fails the test instead of
138
+ * silently dropping call sites the way DEC-098's `containerOf` guard did.
139
+ *
140
+ * Receiver-type resolution is deliberately **not** done here — it needs
141
+ * `extract.ts`'s scope tables, which this module does not have — so a
142
+ * candidate here may still turn out to be a true silence in
143
+ * {@link clientCalls} if `typeOfReceiver` returns `undefined`. That is the
144
+ * one gap this reconciliation cannot close, and it is the same gap every
145
+ * other refusal ledger in this project discloses rather than guesses past:
146
+ * an unresolved receiver is not evidence the call is or is not a client.
147
+ */
148
+ export declare function candidateClientRefs(method: JavaMethod): readonly (JavaRef & {
149
+ readonly receiver: string;
150
+ })[];
151
+ /**
152
+ * Read one method's calls for outbound HTTP.
153
+ *
154
+ * `typeOfReceiver` resolves a receiver name to its declared type's simple name
155
+ * and is supplied by the caller, because the scope rules for that live in
156
+ * `extract.ts` and a second copy of them would drift — the failure that
157
+ * `scopesFor`'s own header records.
158
+ */
159
+ export declare function clientCalls(method: JavaMethod, fromId: string, typeOfReceiver: (name: string) => string | undefined, inTestSourceSet: boolean): {
160
+ readonly calls: readonly ClientCall[];
161
+ readonly refusals: readonly ClientRefusal[];
162
+ };
163
+ /**
164
+ * The `API_ENDPOINT` a call joins to — minted identically to the route side.
165
+ *
166
+ * Shares `endpointQsp` with `extract.ts`'s `SERVES_API` block rather than
167
+ * recomputing the id, because the two must agree exactly and the failure when
168
+ * they do not is silent.
169
+ */
170
+ export declare function endpointFor(scope: IdentityScope, call: ClientCall, producedBy: string, normalise: (template: string) => string): IRNode;
171
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoGG;AAEH,OAAO,EAAuB,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAEnF,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAkItD,MAAM,WAAW,UAAU;IACzB,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAAC;CAC5C;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,sFAAsF;IACtF,QAAQ,CAAC,YAAY,EAAE,gBAAgB,GAAG,cAAc,GAAG,SAAS,CAAC;IACrE;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,eAAe,GAAG,OAAO,CAAC;CACtE;AAoBD,MAAM,MAAM,gBAAgB,GAAG,eAAe,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAgFtF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,GACjB,SAAS,CAAC,OAAO,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,CAQtD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,EACpD,eAAe,EAAE,OAAO,GACvB;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAA;CAAE,CA+JxF;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,GACtC,MAAM,CAaR"}