@descryy/adapter-go 0.4.1 → 0.5.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/dist/gorm.js ADDED
@@ -0,0 +1,140 @@
1
+ /**
2
+ * GORM — Go's `orm-extractor`.
3
+ *
4
+ * ## Admission is a struct tag, and that has one useful consequence
5
+ *
6
+ * Go has no annotations, so the mapping is declared in a `gorm:"…"` tag — read
7
+ * from the source text. The ORM library therefore never has to be present at
8
+ * all, which is the same standing the Java corpus's uninstalled
9
+ * `jakarta.persistence` import has, reached by a different route.
10
+ *
11
+ * `CreateOrderRequest` in the conformance corpus has the same three members as
12
+ * `Order`. The tag is the only thing separating a table row from a transport
13
+ * shape, and separating them by name is what precision over recall forbids
14
+ * (golden 07's note, DEC-043, DEC-056).
15
+ *
16
+ * ## The table comes from `TableName()`, never from the NamingStrategy
17
+ *
18
+ * GORM derives an untagged type's table from the struct name — snake_cased,
19
+ * pluralised, with a configurable prefix. That is a convention set in
20
+ * application code this adapter never reads, so it is **refused**, exactly as
21
+ * `adapter-java`'s `tableOf()` refuses Hibernate's naming strategy (DEC-127
22
+ * §2). A `TableName()` method returning a literal is a declaration and is read.
23
+ *
24
+ * ## Nullability is the pointer
25
+ *
26
+ * Go has no nullable `int64`. A pointer field is how GORM represents a NULL
27
+ * column and it is the documented mechanism, so the TYPE is the declaration and
28
+ * there is nothing to infer. `gorm:"not null"` is read where written and
29
+ * narrows a pointer field to not-nullable, because that is a constraint the
30
+ * database enforces.
31
+ *
32
+ * ## No DATABASE_TABLE / DATABASE_COLUMN, and the reason is specific to Go
33
+ *
34
+ * A `column:` tag DOES declare a physical name, so it is tempting to mint on it.
35
+ * The problem is that the tag is optional and most real structs omit it, leaving
36
+ * the name to the NamingStrategy. Minting only for the tagged fields would
37
+ * produce a DATABASE_TABLE carrying the three columns that happen to be tagged
38
+ * out of the thirty that exist — a node that reads as a complete table and is
39
+ * not one. Refused wholesale rather than minted for the declared subset.
40
+ *
41
+ * Ruby and Rust differ because `db/schema.rb` and Diesel's `table!` are
42
+ * COMPLETE: every column of the table is in them, by construction.
43
+ */
44
+ /** The `gorm:"…"` payload of a struct tag, or `undefined`. */
45
+ function gormTag(tag) {
46
+ if (tag === undefined)
47
+ return undefined;
48
+ const match = /\bgorm\s*:\s*"([^"]*)"/.exec(tag);
49
+ return match?.[1];
50
+ }
51
+ /**
52
+ * Is this type declared to be a GORM model?
53
+ *
54
+ * One `gorm` tag anywhere in the struct, or an embedded `gorm.Model` — which is
55
+ * the library's own base and is as explicit as a tag.
56
+ */
57
+ export function isGormModel(type) {
58
+ if (type.form !== "struct")
59
+ return false;
60
+ if (type.embeds.some((name) => name === "Model" || name.endsWith(".Model"))) {
61
+ // `gorm.Model` embeds ID/CreatedAt/UpdatedAt/DeletedAt. Only accepted when
62
+ // the embed names gorm specifically — a bare `Model` from another package
63
+ // would be a name heuristic.
64
+ if (type.embeds.includes("gorm.Model"))
65
+ return true;
66
+ }
67
+ for (const detail of type.fieldDetail.values()) {
68
+ if (gormTag(detail.tag) !== undefined)
69
+ return true;
70
+ }
71
+ return false;
72
+ }
73
+ /**
74
+ * The mapped shape.
75
+ *
76
+ * `methods` is every function whose receiver is this type, so `TableName()` can
77
+ * be found without this module knowing how the adapter indexes them.
78
+ */
79
+ export function gormShapeOf(type, methods) {
80
+ const tableName = methods.find((fn) => fn.name === "TableName")?.returnedLiteral;
81
+ const fields = [];
82
+ for (const [name, declaredType] of type.fields) {
83
+ const detail = type.fieldDetail.get(name);
84
+ if (detail === undefined)
85
+ continue;
86
+ const tag = gormTag(detail.tag);
87
+ if (tag !== undefined && /(^|;)\s*-\s*(;|$)/.test(tag))
88
+ continue; // `gorm:"-"` is not a column
89
+ if (tag !== undefined && /\bnot\s*null\b/i.test(tag)) {
90
+ fields.push({ name, nullable: false, nullableFrom: "tag" });
91
+ continue;
92
+ }
93
+ fields.push(detail.pointer
94
+ ? { name, nullable: true, nullableFrom: "pointer" }
95
+ : { name, nullable: false, nullableFrom: "value-type" });
96
+ void declaredType;
97
+ }
98
+ return {
99
+ table: tableName ?? null,
100
+ fields: [...fields].sort((a, b) => a.name.localeCompare(b.name)),
101
+ };
102
+ }
103
+ /**
104
+ * Field reads in one function, per model.
105
+ *
106
+ * Go's parser already records `X.Y` access as a `member` ref, so the only thing
107
+ * needed here is the receiver's declared type — and only a WRITTEN one counts.
108
+ * `order := fetch(id)` states nothing at the binding site.
109
+ */
110
+ export function fieldReadsIn(fn, resolveModel) {
111
+ const byModel = new Map();
112
+ for (const ref of fn.refs) {
113
+ if (ref.kind !== "member" || ref.receiver === undefined)
114
+ continue;
115
+ const written = fn.locals.get(ref.receiver);
116
+ if (written === undefined || written === null)
117
+ continue;
118
+ const model = resolveModel(written);
119
+ if (model === undefined)
120
+ continue;
121
+ // A `member` ref's `name` is the access AS WRITTEN — `order.TotalAmount`,
122
+ // not `TotalAmount`. Golden 07 compares field NAMES, so the receiver is
123
+ // stripped and only the first segment beyond it is the field this struct
124
+ // declares: in `order.Customer.Name`, `Customer` is Order's field and
125
+ // `Name` belongs to whatever type that is.
126
+ const prefix = `${ref.receiver}.`;
127
+ const member = ref.name.startsWith(prefix) ? ref.name.slice(prefix.length) : ref.name;
128
+ const direct = member.split(".")[0];
129
+ if (direct === undefined || direct === "")
130
+ continue;
131
+ let fields = byModel.get(model);
132
+ if (fields === undefined) {
133
+ fields = new Set();
134
+ byModel.set(model, fields);
135
+ }
136
+ fields.add(direct);
137
+ }
138
+ return [...byModel.entries()].map(([model, fields]) => ({ model, fields: [...fields].sort() }));
139
+ }
140
+ //# sourceMappingURL=gorm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gorm.js","sourceRoot":"","sources":["../src/gorm.ts"],"names":[],"mappings":"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"}
package/dist/grpc.d.ts CHANGED
@@ -48,12 +48,41 @@ export interface GrpcMethodConst {
48
48
  readonly method: string;
49
49
  readonly path: string;
50
50
  }
51
+ /**
52
+ * The registration's second argument — the value implementing the service —
53
+ * in the two shapes this reader can name a type from without a type checker:
54
+ *
55
+ * `kind: "literal"` `&orderServer{}` / `orderServer{}` — the type is
56
+ * written at the call site itself, `&`/parens unwound.
57
+ * `kind: "name"` `srv` — a bare identifier. Its declared type is not
58
+ * written here; the extract pass resolves it against
59
+ * the enclosing function's locals and the package's
60
+ * vars, the same way it resolves every other receiver.
61
+ *
62
+ * Anything else (a call result, a selector, a type assertion on something
63
+ * other than a composite literal) is not a shape this reader names a type
64
+ * from — `impl` stays `undefined` on the registration, and the extract pass
65
+ * discloses that explicitly rather than staying silent about it.
66
+ */
67
+ export type GrpcImpl = {
68
+ readonly kind: "literal";
69
+ readonly typeWritten: string;
70
+ } | {
71
+ readonly kind: "name";
72
+ readonly name: string;
73
+ };
51
74
  /** `Register<Service>Server(...)` — one per call site, however it was reached. */
52
75
  export interface GrpcRegistration {
53
76
  readonly service: string;
54
77
  /** The package alias the call was made through, or `undefined` for a bare, same-package call. */
55
78
  readonly targetPackageAlias: string | undefined;
56
79
  readonly line: number;
80
+ /**
81
+ * The `impl` argument's own written shape — see {@link GrpcImpl}.
82
+ * `undefined` when the call did not write exactly two arguments, or the
83
+ * second is not a shape this reader can name a type from at all.
84
+ */
85
+ readonly impl: GrpcImpl | undefined;
57
86
  }
58
87
  /** Every `_FullMethodName` const declared at this file's package level. */
59
88
  export declare function readGrpcMethodConsts(root: Node): GrpcMethodConst[];
@@ -1 +1 @@
1
- {"version":3,"file":"grpc.d.ts","sourceRoot":"","sources":["../src/grpc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAC;AAIxD,6FAA6F;AAC7F,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,kFAAkF;AAClF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iGAAiG;IACjG,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAID,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,eAAe,EAAE,CA6BlE;AAID,4FAA4F;AAC5F,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,gBAAgB,EAAE,CAyBpE"}
1
+ {"version":3,"file":"grpc.d.ts","sourceRoot":"","sources":["../src/grpc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAC;AAKxD,6FAA6F;AAC7F,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErI,kFAAkF;AAClF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iGAAiG;IACjG,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;CACrC;AAaD,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,eAAe,EAAE,CA6BlE;AAID,4FAA4F;AAC5F,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,gBAAgB,EAAE,CAgCpE"}
package/dist/grpc.js CHANGED
@@ -42,6 +42,18 @@
42
42
  * invented privately here — see `DEC-NEXT-grpc-route-identity.md`.
43
43
  */
44
44
  import { literalOf } from "./routes.js";
45
+ import { receiverTypeAtSite } from "./parse.js";
46
+ /** The registration's second argument, read for a type name — never a guess, `undefined` when unreadable. */
47
+ function implArgOf(node) {
48
+ if (node === null)
49
+ return undefined;
50
+ const literalType = receiverTypeAtSite(node);
51
+ if (literalType !== undefined)
52
+ return { kind: "literal", typeWritten: literalType };
53
+ if (node.type === "identifier")
54
+ return { kind: "name", name: node.text };
55
+ return undefined;
56
+ }
45
57
  const FULL_METHOD_NAME_CONST = /^([A-Za-z0-9]+)_([A-Za-z0-9]+)_FullMethodName$/;
46
58
  /** Every `_FullMethodName` const declared at this file's package level. */
47
59
  export function readGrpcMethodConsts(root) {
@@ -85,10 +97,17 @@ export function readGrpcRegistrations(root) {
85
97
  if (node.type === "call_expression") {
86
98
  const callee = node.childForFieldName("function");
87
99
  const line = node.startPosition.row + 1;
100
+ // `Register<Service>Server(server, impl)` — always exactly two
101
+ // arguments in every file `protoc-gen-go-grpc` generates. Anything
102
+ // else means the second position isn't `impl` at all, and `implArgOf`
103
+ // is not asked to guess at it.
104
+ const args = node.childForFieldName("arguments");
105
+ const implNode = args !== null && args.namedChildCount === 2 ? args.namedChild(1) : null;
106
+ const impl = implArgOf(implNode);
88
107
  if (callee !== null && callee.type === "identifier") {
89
108
  const match = REGISTER_SERVER_CALL.exec(callee.text);
90
109
  if (match !== null)
91
- out.push({ service: match[1], targetPackageAlias: undefined, line });
110
+ out.push({ service: match[1], targetPackageAlias: undefined, line, impl });
92
111
  }
93
112
  else if (callee !== null && callee.type === "selector_expression") {
94
113
  const base = callee.childForFieldName("operand");
@@ -96,7 +115,7 @@ export function readGrpcRegistrations(root) {
96
115
  if (base !== null && base.type === "identifier" && member !== null) {
97
116
  const match = REGISTER_SERVER_CALL.exec(member.text);
98
117
  if (match !== null)
99
- out.push({ service: match[1], targetPackageAlias: base.text, line });
118
+ out.push({ service: match[1], targetPackageAlias: base.text, line, impl });
100
119
  }
101
120
  }
102
121
  }
package/dist/grpc.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"grpc.js","sourceRoot":"","sources":["../src/grpc.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"grpc.js","sourceRoot":"","sources":["../src/grpc.ts"],"names":[],"mappings":"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"}
package/dist/parse.d.ts CHANGED
@@ -63,6 +63,16 @@ export interface GoFunc extends GoScope {
63
63
  readonly subtests: GoSubtest[];
64
64
  /** Declared result type names, in order. `undefined` where not a named type. */
65
65
  readonly results: (string | undefined)[];
66
+ /**
67
+ * The single interpreted string literal a one-statement `return "…"` body
68
+ * returns, when that is the whole function.
69
+ *
70
+ * Narrow on purpose: this is how Go declares a value that other languages put
71
+ * in an annotation — GORM's `TableName()`, and nothing else so far. A body
72
+ * with any other shape states nothing this reader can read, and gets
73
+ * `undefined` rather than a guess.
74
+ */
75
+ readonly returnedLiteral: string | undefined;
66
76
  /** Outbound HTTP calls read from this function's body — DEC-262's fork, Go's half. */
67
77
  readonly clientCalls: readonly GoClientCallSite[];
68
78
  /** Recognised-but-refused outbound HTTP calls, each with its reason. */
@@ -84,6 +94,19 @@ export interface GoType {
84
94
  readonly embeds: string[];
85
95
  /** Field name -> declared type name, `null` when ambiguous. */
86
96
  readonly fields: Map<string, string | null>;
97
+ /**
98
+ * Per-field detail a framework extractor needs and CALLS resolution does not:
99
+ * the struct TAG as written, and whether the type is a pointer.
100
+ *
101
+ * Strictly additive to {@link fields}, which keeps its exact meaning. Go has
102
+ * no annotations, so a tag is the only place a mapping can be declared — and
103
+ * a pointer is how every Go ORM represents a nullable column, which makes the
104
+ * type itself the declaration rather than a thing to infer.
105
+ */
106
+ readonly fieldDetail: Map<string, {
107
+ readonly tag: string | undefined;
108
+ readonly pointer: boolean;
109
+ }>;
87
110
  readonly typeRefs: GoRef[];
88
111
  }
89
112
  export interface GoFile {
@@ -104,6 +127,14 @@ export interface GoFile {
104
127
  readonly aliases: GoAlias[];
105
128
  /** Package-level `var`/`const` -> written type. DEC-081's second shape; package scope wasn't tracked before. */
106
129
  readonly packageVars: Map<string, string>;
130
+ /**
131
+ * Package-level `const`/`var` -> its string-literal VALUE, which is the
132
+ * only base table Go's per-file parse can offer DEC-164's reader. A
133
+ * constant declared in a sibling file of the same package is visible to Go
134
+ * and not to this map — a disclosed recall gap, never a precision one, and
135
+ * `client-base.ts`'s header says so.
136
+ */
137
+ readonly packageConsts: Map<string, string>;
107
138
  /** Route registrations read from this file — DEC-117. */
108
139
  readonly routes: GoRoute[];
109
140
  /** Registrations recognised and refused, each with its reason. */
@@ -123,5 +154,15 @@ export declare function buildConstraintOf(text: string): string | undefined;
123
154
  export declare function isUniverse(name: string): boolean;
124
155
  /** `*T`, `[]T`, `map[K]T`, `chan T` — the name underneath. */
125
156
  export declare function baseTypeName(node: Node | null): string | undefined;
157
+ /**
158
+ * Receiver type when written: a type assertion, or parenthesised composite
159
+ * literal. Both previously became `(computed)`.
160
+ *
161
+ * Exported for `grpc.ts`: a `Register<Service>Server(server, &impl{})`
162
+ * registration's `impl` argument is exactly this same shape — a composite
163
+ * literal, usually behind `&` — and reading it a second, subtly different
164
+ * way in a second file is how two readers of the same construct drift apart.
165
+ */
166
+ export declare function receiverTypeAtSite(node: Node): string | undefined;
126
167
  export declare function readFile(root: Node, file: string, hasError: boolean): GoFile;
127
168
  //# sourceMappingURL=parse.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
package/dist/parse.js CHANGED
@@ -114,8 +114,16 @@ function receiverName(node) {
114
114
  // `(*x).f`, `x[0].f`, `f().g` — nothing wrote a name here.
115
115
  return "(computed)";
116
116
  }
117
- /** Receiver type when written: a type assertion, or parenthesised composite literal. Both previously became `(computed)`. */
118
- function receiverTypeAtSite(node) {
117
+ /**
118
+ * Receiver type when written: a type assertion, or parenthesised composite
119
+ * literal. Both previously became `(computed)`.
120
+ *
121
+ * Exported for `grpc.ts`: a `Register<Service>Server(server, &impl{})`
122
+ * registration's `impl` argument is exactly this same shape — a composite
123
+ * literal, usually behind `&` — and reading it a second, subtly different
124
+ * way in a second file is how two readers of the same construct drift apart.
125
+ */
126
+ export function receiverTypeAtSite(node) {
119
127
  if (node.type === "parenthesized_expression") {
120
128
  const inner = node.namedChild(0);
121
129
  return inner === null ? undefined : receiverTypeAtSite(inner);
@@ -171,6 +179,7 @@ export function readFile(root, file, hasError) {
171
179
  funcs: [],
172
180
  aliases: [],
173
181
  packageVars: new Map(),
182
+ packageConsts: new Map(),
174
183
  routes: [],
175
184
  routeRefusals: [],
176
185
  grpcMethodConsts: [],
@@ -180,6 +189,8 @@ export function readFile(root, file, hasError) {
180
189
  buildConstraint: undefined,
181
190
  };
182
191
  let packageName = "";
192
+ /** Function bodies whose HTTP read is deferred until the whole file is known. */
193
+ const pending = [];
183
194
  for (let i = 0; i < root.namedChildCount; i += 1) {
184
195
  const statement = root.namedChild(i);
185
196
  if (statement === null)
@@ -207,9 +218,13 @@ export function readFile(root, file, hasError) {
207
218
  continue;
208
219
  }
209
220
  if (statement.type === "function_declaration" || statement.type === "method_declaration") {
210
- readFunc(statement, unit, file);
221
+ readFunc(statement, unit, file, pending);
211
222
  }
212
223
  }
224
+ // After the loop, for the same reason the route read below is: the file's
225
+ // own `const` block and `import` table may sit anywhere relative to the
226
+ // function that uses them.
227
+ readClients(unit, pending);
213
228
  // After the loop, because provenance is decided by the import table and the
214
229
  // import declaration may sit anywhere above the call that uses it.
215
230
  const read = readGoRoutes(root, unit);
@@ -258,6 +273,15 @@ function readImports(node, unit) {
258
273
  unit.imports.set(alias ?? defaultImportAlias(path), path);
259
274
  }
260
275
  }
276
+ /** The text of an unescaped Go string literal, or `undefined`. Mirrors `client.ts`'s `literalOf` — an escape means this reader would have to evaluate it. */
277
+ function stringLiteralOf(node) {
278
+ if (node.type !== "interpreted_string_literal" && node.type !== "raw_string_literal")
279
+ return undefined;
280
+ const text = node.text;
281
+ if (text.includes("\\"))
282
+ return undefined;
283
+ return text.replace(/^["`]|["`]$/g, "");
284
+ }
261
285
  /** Package-level values with a written type: explicit, or a composite literal. A call/expression is left out — no guessing. */
262
286
  function readPackageVars(node, unit) {
263
287
  for (let i = 0; i < node.namedChildCount; i += 1) {
@@ -277,16 +301,24 @@ function readPackageVars(node, unit) {
277
301
  const name = names[0];
278
302
  if (name === undefined)
279
303
  continue;
304
+ const values = spec.childForFieldName("value");
305
+ const value = values !== null && values.namedChildCount === 1 ? values.namedChild(0) : null;
306
+ // DEC-164's base table. Recorded even when a type is written, because
307
+ // `const apiV1Base string = "..."` is the same constant as the untyped
308
+ // form and the two must not answer differently.
309
+ if (value !== null) {
310
+ const literal = stringLiteralOf(value);
311
+ if (literal !== undefined && !unit.packageConsts.has(name.text))
312
+ unit.packageConsts.set(name.text, literal);
313
+ }
280
314
  const declared = baseTypeName(spec.childForFieldName("type"));
281
315
  if (declared !== undefined) {
282
316
  unit.packageVars.set(name.text, declared);
283
317
  continue;
284
318
  }
285
- const values = spec.childForFieldName("value");
286
- if (values === null || values.namedChildCount !== 1)
319
+ if (value === null)
287
320
  continue;
288
- const value = values.namedChild(0);
289
- const written = value === null ? undefined : receiverTypeAtSite(value);
321
+ const written = receiverTypeAtSite(value);
290
322
  if (written !== undefined)
291
323
  unit.packageVars.set(name.text, written);
292
324
  }
@@ -345,6 +377,7 @@ function readType(spec, unit) {
345
377
  endLine: spec.endPosition.row + 1,
346
378
  embeds: [],
347
379
  fields: new Map(),
380
+ fieldDetail: new Map(),
348
381
  typeRefs: [],
349
382
  };
350
383
  if (typeNode?.type === "struct_type") {
@@ -370,6 +403,17 @@ function readType(spec, unit) {
370
403
  }
371
404
  for (const name of names)
372
405
  declare(type.fields, name.text, declared);
406
+ // `\`gorm:"column:discount_code"\`` — a raw string literal sibling of the
407
+ // type. Recorded verbatim; what any particular tag MEANS belongs to a
408
+ // framework extractor, not to this reader.
409
+ const tagNode = field.namedChildren.find((child) => child?.type === "raw_string_literal");
410
+ const pointer = fieldType?.type === "pointer_type";
411
+ for (const name of names) {
412
+ type.fieldDetail.set(name.text, {
413
+ tag: tagNode === undefined || tagNode === null ? undefined : tagNode.text,
414
+ pointer,
415
+ });
416
+ }
373
417
  const written = [];
374
418
  allTypeNames(fieldType, written, params);
375
419
  for (const each of written) {
@@ -415,7 +459,7 @@ function isTestFunc(name, file) {
415
459
  }
416
460
  /** The types whose `Run` method declares a subtest. */
417
461
  const TEST_RECEIVERS = new Set(["testing.T", "testing.B", "testing.F"]);
418
- function readFunc(node, unit, file) {
462
+ function readFunc(node, unit, file, pending) {
419
463
  const nameNode = node.childForFieldName("name");
420
464
  if (nameNode === null)
421
465
  return;
@@ -440,6 +484,7 @@ function readFunc(node, unit, file) {
440
484
  parameterNames: new Set(),
441
485
  subtests: [],
442
486
  results: resultTypes(node.childForFieldName("result")),
487
+ returnedLiteral: soleReturnedLiteral(node.childForFieldName("body")),
443
488
  };
444
489
  if (receiverList !== null) {
445
490
  const declaration = receiverList.namedChild(0);
@@ -461,8 +506,6 @@ function readFunc(node, unit, file) {
461
506
  fn.refs.push({ kind: "type", name: each, receiver: undefined, line: fn.startLine, raw: result.text.slice(0, 120) });
462
507
  }
463
508
  }
464
- let clientCalls = [];
465
- let clientRefusals = [];
466
509
  const body = node.childForFieldName("body");
467
510
  if (body !== null) {
468
511
  walkBody(body, fn, {
@@ -471,13 +514,88 @@ function readFunc(node, unit, file) {
471
514
  suite: fn.isTest ? [name] : [],
472
515
  inTest: fn.isTest,
473
516
  });
474
- // After `walkBody`, so `fn.locals` has every param and `:=`/`var`
475
- // declaration, including a `*http.Client` built partway through the body.
476
- const client = readGoClientCalls(body, unit, fn.locals, fn.isTest, fn.parameterNames);
477
- clientCalls = client.calls;
478
- clientRefusals = client.refusals;
479
517
  }
480
- unit.funcs.push({ ...fn, clientCalls, clientRefusals });
518
+ // The HTTP read is DEFERRED to `readClients`, after the whole file is read.
519
+ //
520
+ // It used to run right here, and that put it before the file's own `const`
521
+ // block whenever the constant was written below the function that splices
522
+ // it — so DEC-164's base table answered "not bound" for a base plainly in
523
+ // view. The origin rule needs the same thing one step further: every base
524
+ // in the file, before any single call site can be judged.
525
+ unit.funcs.push({ ...fn, clientCalls: [], clientRefusals: [] });
526
+ if (body !== null)
527
+ pending.push({ index: unit.funcs.length - 1, body });
528
+ }
529
+ /**
530
+ * ONE WALK, READ TWICE — DEC-164's origin rule needs every base in the file
531
+ * before any single call site can be judged.
532
+ *
533
+ * `client-base.ts` admits an absolute call path only at an origin some base in
534
+ * this same file resolves to, and a base in a function above is still evidence
535
+ * about this call. The first read collects those origins; the second re-reads
536
+ * with them in hand, which is the only verdict the evidence can change. With
537
+ * no absolute base anywhere the set stays empty and the two reads agree, so
538
+ * the second one costs a tree walk and changes nothing — the same trade
539
+ * `adapter-typescript` makes.
540
+ */
541
+ function readClients(unit, pending) {
542
+ if (pending.length === 0)
543
+ return;
544
+ const origins = new Set();
545
+ for (const { index, body } of pending) {
546
+ const fn = unit.funcs[index];
547
+ if (fn === undefined)
548
+ continue;
549
+ const first = readGoClientCalls(body, unit, fn.locals, fn.isTest, fn.parameterNames, unit.packageConsts);
550
+ for (const call of first.calls) {
551
+ if (call.baseOrigin !== undefined)
552
+ origins.add(call.baseOrigin);
553
+ }
554
+ }
555
+ for (const { index, body } of pending) {
556
+ const fn = unit.funcs[index];
557
+ if (fn === undefined)
558
+ continue;
559
+ const client = readGoClientCalls(body, unit, fn.locals, fn.isTest, fn.parameterNames, unit.packageConsts, origins);
560
+ unit.funcs[index] = { ...fn, clientCalls: client.calls, clientRefusals: client.refusals };
561
+ }
562
+ }
563
+ /**
564
+ * `func (Order) TableName() string { return "orders" }` — the literal, or
565
+ * `undefined` for a body of any other shape.
566
+ *
567
+ * Requires the body to be exactly one `return` of exactly one interpreted
568
+ * string literal. Anything conditional, computed or concatenated is a runtime
569
+ * fact with nothing written down to read.
570
+ */
571
+ function soleReturnedLiteral(body) {
572
+ if (body === null || body.namedChildCount !== 1)
573
+ return undefined;
574
+ // A `block`'s single named child is a `statement_list`, not the statement —
575
+ // found by probing the grammar rather than assuming it, after the first cut
576
+ // of this read silently returned `undefined` for every method.
577
+ let statement = body.namedChild(0);
578
+ if (statement !== null && statement.type === "statement_list") {
579
+ if (statement.namedChildCount !== 1)
580
+ return undefined;
581
+ statement = statement.namedChild(0);
582
+ }
583
+ if (statement === null || statement.type !== "return_statement")
584
+ return undefined;
585
+ const list = statement.namedChild(0);
586
+ const value = list !== null && list.type === "expression_list" && list.namedChildCount === 1
587
+ ? list.namedChild(0)
588
+ : list;
589
+ if (value === null || value.type !== "interpreted_string_literal")
590
+ return undefined;
591
+ for (let i = 0; i < value.namedChildCount; i += 1) {
592
+ const child = value.namedChild(i);
593
+ // An escape sequence means the written text is not the value; refused
594
+ // rather than reported wrong.
595
+ if (child !== null && child.type !== "interpreted_string_literal_content")
596
+ return undefined;
597
+ }
598
+ return value.text.slice(1, -1);
481
599
  }
482
600
  /** Declared result types, in order. `(a, b Foo)` contributes one entry per name; position is what `x, err := f()` binds by. */
483
601
  function resultTypes(result) {