@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,297 @@
1
+ /**
2
+ * One Java compilation unit, read into the shape the resolver wants.
3
+ *
4
+ * The walk is hand-written rather than expressed as tree-sitter queries. A query
5
+ * returns matches; what this needs is *containment* — which class a method
6
+ * belongs to, which method a call sits in, which type a field was declared with —
7
+ * and containment is exactly what a match set discards. The TypeScript and Python
8
+ * extractors are both shaped this way for the same reason.
9
+ */
10
+ import type { Node } from "@descryy/adapter-treesitter";
11
+ export type TypeKind = "class" | "interface" | "enum" | "record" | "annotation";
12
+ export interface JavaRef {
13
+ /**
14
+ * `call` — a method invocation.
15
+ * `type` — a name in type position: a field's type, a parameter, a `new`.
16
+ * `member` — a name reached through a dotted access, `Status.PENDING`.
17
+ *
18
+ * `member` is a *candidate* and nothing more. `x.y` is a type reference when
19
+ * `x` names a type and a field read when it names a variable, and which one it
20
+ * is cannot be known until the enclosing scope is built. The parse records the
21
+ * question; the resolver answers it against the declarations it has, and drops
22
+ * the reference when the receiver turns out to be a variable.
23
+ */
24
+ readonly kind: "call" | "type" | "member";
25
+ /** The name being referred to: a method name, or a type's simple name. */
26
+ readonly name: string;
27
+ /**
28
+ * For a call, the text of the receiver: `undefined` when unqualified, `"this"`
29
+ * for `this.f()`, otherwise the identifier or dotted path as written.
30
+ */
31
+ readonly receiver: string | undefined;
32
+ readonly line: number;
33
+ /** The source text of the whole reference, for the ledger. */
34
+ readonly raw: string;
35
+ /**
36
+ * For a call, the first argument **when it is a bare string literal**.
37
+ *
38
+ * `undefined` covers three different situations on purpose — no arguments, a
39
+ * non-literal first argument, and a literal glued to something else — because
40
+ * the client-call reader treats all three identically: it declines. A path
41
+ * assembled at run time is not a path this adapter can read (DEC-127), and an
42
+ * endpoint template invented here would join a caller to a route it never
43
+ * calls.
44
+ *
45
+ * Only the first argument, because every client method this feeds takes the
46
+ * URL first: `getForEntity(url, type)`, `exchange(url, method, …)`,
47
+ * `uri(path)`. A reader that searched all arguments for something
48
+ * path-shaped would find request bodies.
49
+ *
50
+ * Optional rather than `string | undefined`, because a `type` or `member` ref
51
+ * has no arguments at all and writing `firstStringArgument: undefined` on
52
+ * every one of them would assert a question was asked and came back empty.
53
+ */
54
+ readonly firstStringArgument?: string;
55
+ /**
56
+ * The first argument's raw source text, captured whether or not it is a
57
+ * literal — DEC-242's `blockedBy`/`refusalClass` classification needs to see
58
+ * *what* blocked resolution (`System.getenv("BACKEND_URL")`, a bare parameter
59
+ * name) when {@link firstStringArgument} is absent. Same three-way
60
+ * `undefined` as that field: no arguments, or a `type`/`member` ref that was
61
+ * never asked. Unlike `firstStringArgument`, set for every non-literal shape
62
+ * too — the classifier, not this parse, decides what to do with it.
63
+ */
64
+ readonly firstArgumentText?: string;
65
+ }
66
+ /**
67
+ * An annotation as written, retained rather than reduced to a boolean.
68
+ *
69
+ * Until the Spring extractor there was exactly one consumer of annotations —
70
+ * `isTest` — and it collapsed them to a flag at parse time. A framework
71
+ * extractor cannot work from a flag: it needs the annotation's **name** to admit
72
+ * a route and its **arguments** to know the path, and the path is the whole
73
+ * finding.
74
+ *
75
+ * `name` is the simple name. `@GetMapping` and
76
+ * `@org.springframework.web.bind.annotation.GetMapping` are the same annotation
77
+ * written two ways, and the qualified form is kept in `qualified` so provenance
78
+ * can be checked against the import table without re-parsing.
79
+ */
80
+ export interface JavaAnnotation {
81
+ /** Simple name: `GetMapping`. */
82
+ readonly name: string;
83
+ /** As written, which may be qualified: `org.springframework...GetMapping`. */
84
+ readonly qualified: string;
85
+ readonly line: number;
86
+ /**
87
+ * The unnamed argument's string literals — `@GetMapping("/{id}")` gives one.
88
+ *
89
+ * **A list rather than a single value, because the array form is common and
90
+ * every element is a real declaration.** `@GetMapping({"/a", "/b"})` serves
91
+ * two paths, and taking only the first would silently halve the answer.
92
+ * Measured before this shape was chosen: `shopizer` writes **140** of its 356
93
+ * mappings in the array form against 216 plain, so a single-value reader loses
94
+ * 39% of one corpus with nothing in the output to show for it.
95
+ *
96
+ * Quotes stripped. Empty when the annotation is a marker, or when the argument
97
+ * is not a literal — a constant reference or a concatenation. **A non-literal
98
+ * argument yields nothing rather than its source text**: a path assembled at
99
+ * runtime is not a path this adapter can read, and DEC-127 refuses it rather
100
+ * than guessing.
101
+ */
102
+ readonly values: readonly string[];
103
+ /**
104
+ * Named arguments whose values are string literals — `path = "/x"`,
105
+ * `value = {"/a", "/b"}`. A list per key, for the reason above. Non-literal
106
+ * values are omitted.
107
+ *
108
+ * `method = RequestMethod.GET` is deliberately *not* here: it is a field
109
+ * access, not a literal. Verbs are read separately by the extractor, which
110
+ * knows the enum, because a parse that special-cased Spring's enum would be a
111
+ * framework leaking into the language layer.
112
+ */
113
+ readonly named: ReadonlyMap<string, readonly string[]>;
114
+ /** Every argument's raw source text, for the cases a literal reader must refuse. */
115
+ readonly rawArguments: readonly string[];
116
+ }
117
+ export interface JavaMethod {
118
+ readonly name: string;
119
+ /** Fully-qualified: `pkg.Outer.Inner.method`. Parameters are not part of it. */
120
+ readonly fqn: string;
121
+ readonly startLine: number;
122
+ readonly endLine: number;
123
+ readonly isTest: boolean;
124
+ /** Annotations on the declaration, in source order. See {@link JavaAnnotation}. */
125
+ readonly annotations: JavaAnnotation[];
126
+ /**
127
+ * The declared return type, read once with the same four answers a field gets.
128
+ *
129
+ * Spring's `@Controller` handlers are the reason. A bare `@Controller`
130
+ * returns *view names*, so DEC-127 refuses its handlers unless one opts out
131
+ * with `@ResponseBody` — and that rule disclosed, with a population, that it
132
+ * drops handlers returning `ResponseEntity<T>`, which are real API routes
133
+ * needing no such annotation. The blocker recorded there was that the parse
134
+ * did not carry the return type. It does now.
135
+ *
136
+ * `readTypeName` rather than a `string | undefined`: absent (a constructor),
137
+ * `void`, and unreadable are three different facts, and collapsing them into
138
+ * one sentinel is the defect this file already paid 126 wrong columns for.
139
+ */
140
+ readonly returnType: TypeRead;
141
+ readonly refs: JavaRef[];
142
+ /**
143
+ * Local variables and parameters, name -> declared type simple name.
144
+ *
145
+ * `null` marks a name declared twice with different types, or declared with
146
+ * `var`. A name whose type is uncertain resolves to nothing at all rather than
147
+ * to the first guess — the whole receiver-typing gain below rests on the
148
+ * declared type being *the* type, so an ambiguous entry must poison itself.
149
+ */
150
+ readonly locals: Map<string, string | null>;
151
+ /**
152
+ * Names declared in the method's own parameter list — a subset of
153
+ * {@link locals}'s keys, kept separately because DEC-242's `varies-per-call`
154
+ * classification needs *parameter*, not *local*: a call argument that is a
155
+ * bare parameter name is a caller-supplied value with no fixed answer to
156
+ * state; a local variable might still be assigned from a constant.
157
+ */
158
+ readonly parameterNames: Set<string>;
159
+ }
160
+ /**
161
+ * A field declaration, kept alongside the `fields` name→type map.
162
+ *
163
+ * The map exists for receiver typing and answers "what type is this name". JPA
164
+ * needs three more things the map cannot carry: the **annotations**, the
165
+ * **line**, and whether the declared type is a **primitive**.
166
+ *
167
+ * The last one is load-bearing and is DEC-127 §3's named hazard. `long` cannot
168
+ * hold null and `Long` can, so `long totalAmount` is a NOT NULL column with no
169
+ * annotation anywhere to say so. An extractor reading the type as text without
170
+ * knowing the distinction gets golden 06 wrong in the direction that matters —
171
+ * and golden 06 fails an adapter that reports the fields and loses `nullable`.
172
+ */
173
+ export interface JavaField {
174
+ readonly name: string;
175
+ /** Declared type's base name, generics stripped: `Long`, `long`, `String`. */
176
+ readonly declaredType: string | undefined;
177
+ /** True for the eight Java primitives, which can never be null. */
178
+ readonly primitive: boolean;
179
+ readonly line: number;
180
+ readonly annotations: JavaAnnotation[];
181
+ /**
182
+ * Keyword modifiers as written: `private`, `static`, `final`, `transient`.
183
+ *
184
+ * A field's *modifiers* decide whether it is persistent at all, and reading
185
+ * only its annotations cannot see that. JPA persists no `static` and no
186
+ * `transient` field — `private static final long serialVersionUID = 1L;` is
187
+ * on almost every entity in a real codebase and is not a column. Emitting it
188
+ * is a wrong answer with a plausible name, not a silence.
189
+ */
190
+ readonly modifiers: readonly string[];
191
+ }
192
+ export interface JavaType {
193
+ readonly simpleName: string;
194
+ readonly fqn: string;
195
+ readonly kind: TypeKind;
196
+ readonly startLine: number;
197
+ readonly endLine: number;
198
+ /** Supertype names exactly as written — simple or qualified. */
199
+ readonly extendsNames: string[];
200
+ readonly implementsNames: string[];
201
+ /** Annotations on the type declaration. See {@link JavaAnnotation}. */
202
+ readonly annotations: JavaAnnotation[];
203
+ readonly methods: JavaMethod[];
204
+ /** Field name -> declared type simple name, `null` when ambiguous. */
205
+ readonly fields: Map<string, string | null>;
206
+ /** Field declarations with their annotations. See {@link JavaField}. */
207
+ readonly fieldDeclarations: JavaField[];
208
+ /** Types named in field declarations, for `USES_TYPE`. */
209
+ readonly typeRefs: JavaRef[];
210
+ }
211
+ export interface JavaUnit {
212
+ readonly file: string;
213
+ readonly packageName: string;
214
+ /**
215
+ * The identity scope this unit's symbols hash under: `module/sourceSet/pkg`.
216
+ *
217
+ * Set by the adapter rather than by the parse, because deriving it needs the
218
+ * repository on disk. See `roots.ts` for why a Java package alone is not
219
+ * enough to identify a Java type.
220
+ */
221
+ readonly identityPackage: string;
222
+ /** Simple name -> fully-qualified name, from `import a.b.C;`. */
223
+ readonly singleTypeImports: Map<string, string>;
224
+ /**
225
+ * Member name -> declaring type, from `import static a.b.C.method;`.
226
+ *
227
+ * Java has no re-export, and this is the closest thing it has: an unqualified
228
+ * name in one file bound to a definition declared in another, with no new
229
+ * symbol created in between. It is also how every JUnit assertion is written,
230
+ * so without it a test file's calls are almost entirely unresolvable.
231
+ */
232
+ readonly staticMemberImports: Map<string, string>;
233
+ /** Package names from `import a.b.*;`. */
234
+ readonly wildcardImports: string[];
235
+ /** Every import as written, for `IMPORTS` edges and the ledger. */
236
+ readonly importLines: {
237
+ readonly fqn: string;
238
+ readonly wildcard: boolean;
239
+ readonly line: number;
240
+ }[];
241
+ readonly types: JavaType[];
242
+ readonly hasError: boolean;
243
+ }
244
+ /**
245
+ * What reading a type node produced — four answers, because there are four facts.
246
+ *
247
+ * This used to be `string | undefined`, and the `undefined` stood for three
248
+ * different things at once. **That cost 126 of `shopizer`'s 700 columns, in the
249
+ * wrong direction, silently:** `jpa.ts` needed to know whether a field's type was
250
+ * a primitive, asked this function for a name, got `undefined`, and read it as
251
+ * "not a primitive". Both readings of the sentinel were defensible and only one
252
+ * was right, which is the signature of a sentinel doing too much work.
253
+ *
254
+ * `bench/lib/README.md` names the rule and the repair: *every negative branch
255
+ * owes two different answers to two different questions — I looked and there is
256
+ * nothing, versus I did not look here. Give them different return values at
257
+ * construction time.* A guard at the one call site that got burned would have
258
+ * closed that call site and left the next reader to make the same inference from
259
+ * the same sentinel, with nothing failing.
260
+ *
261
+ * - `named` — a type with a declaration somewhere. The only kind an edge may
262
+ * point at.
263
+ * - `primitive` — one of the eight, or `void`. **There is no declaration, by
264
+ * design.** Not a gap, and the fact `jpa.ts` needs: a primitive column can
265
+ * never be null, whatever the annotations do or do not say.
266
+ * - `absent` — no type node at all. A constructor's return type. Nothing to look
267
+ * at, and nothing missing.
268
+ * - `unreadable` — a type node this reader could not name. A real gap, and the
269
+ * only one of the four that should ever grow.
270
+ */
271
+ export type TypeRead = {
272
+ readonly kind: "named";
273
+ readonly name: string;
274
+ } | {
275
+ readonly kind: "primitive";
276
+ readonly name: string;
277
+ } | {
278
+ readonly kind: "absent";
279
+ } | {
280
+ readonly kind: "unreadable";
281
+ };
282
+ /**
283
+ * Read a type node, stripped of everything that is not identity.
284
+ *
285
+ * `List<String>` is a use of `List`; `Owner[]` is a use of `Owner`; `a.b.C` is a
286
+ * use of `C` qualified by a package. Generic arguments are deliberately *not*
287
+ * followed here — the caller walks them separately when it wants them, so that a
288
+ * field of type `Map<String, Owner>` can record a dependency on `Owner` without
289
+ * `Map` and `Owner` being confused for one another.
290
+ *
291
+ * A caller wanting a name for an edge asks for `kind === "named"` and gets the
292
+ * same behaviour it always had. A caller wanting to know *why* there is no name
293
+ * can now find out. See {@link TypeRead}.
294
+ */
295
+ export declare function readTypeName(node: Node | null): TypeRead;
296
+ export declare function readUnit(root: Node, file: string, hasError: boolean): JavaUnit;
297
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}