@haddowg/json-api-codegen 1.4.0 → 1.6.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.
- package/dist/cli.d.mts +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/{index-Cnj374D6.d.mts → index-CU-kUx70.d.mts} +37 -18
- package/dist/index-CU-kUx70.d.mts.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-BE7OMLWG.mjs → src-C2INS1Wd.mjs} +234 -64
- package/dist/src-C2INS1Wd.mjs.map +1 -0
- package/package.json +2 -2
- package/dist/index-Cnj374D6.d.mts.map +0 -1
- package/dist/src-BE7OMLWG.mjs.map +0 -1
package/dist/cli.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as CodegenConfig } from "./index-
|
|
1
|
+
import { r as CodegenConfig } from "./index-CU-kUx70.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/cli.d.ts
|
|
4
4
|
declare const USAGE = "Usage: json-api-codegen --input <url|file> --output <file> [--server <name>] [--schemas <url|file>] [--check]";
|
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as generate, r as schemasOutputPath, t as check } from "./src-
|
|
2
|
+
import { n as generate, r as schemasOutputPath, t as check } from "./src-C2INS1Wd.mjs";
|
|
3
3
|
import { realpathSync } from "node:fs";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
//#region src/cli.ts
|
|
@@ -48,6 +48,7 @@ interface ParameterObject {
|
|
|
48
48
|
'x-profile'?: string;
|
|
49
49
|
}
|
|
50
50
|
interface OperationObject {
|
|
51
|
+
operationId?: string;
|
|
51
52
|
parameters?: readonly ParameterObject[];
|
|
52
53
|
requestBody?: RequestBodyObject;
|
|
53
54
|
responses?: Record<string, ResponseObject>;
|
|
@@ -76,12 +77,11 @@ interface OpenApiDocument {
|
|
|
76
77
|
//#endregion
|
|
77
78
|
//#region src/build-descriptor.d.ts
|
|
78
79
|
declare class DescriptorBuilder {
|
|
79
|
-
private readonly doc;
|
|
80
80
|
private readonly schemas;
|
|
81
81
|
private readonly paths;
|
|
82
82
|
/** Lazily-built wire-type -> collection-level paginator kind (for per-relation divergence, D6a). */
|
|
83
83
|
private typePaginators?;
|
|
84
|
-
constructor(
|
|
84
|
+
constructor(source: OpenApiDocument);
|
|
85
85
|
/**
|
|
86
86
|
* The collection-level paginator kind for a WIRE type (`tracks`), memoised. Resolves each
|
|
87
87
|
* resource schema's wire type (its `type.const`) to the paginator of its collection GET — the
|
|
@@ -89,13 +89,6 @@ declare class DescriptorBuilder {
|
|
|
89
89
|
*/
|
|
90
90
|
private typePaginator;
|
|
91
91
|
build(): ApiDescriptor;
|
|
92
|
-
/**
|
|
93
|
-
* Warn about relations a create or update body accepts but the resource never renders. A
|
|
94
|
-
* write-only relation (generator contract 5) is left out of the response schema, and the
|
|
95
|
-
* descriptor has no way to mark a relation as writable but unreadable, so it is missing from
|
|
96
|
-
* the client entirely rather than typed onto reads that never carry it.
|
|
97
|
-
*/
|
|
98
|
-
private warnWriteOnlyRelations;
|
|
99
92
|
/**
|
|
100
93
|
* The server-level Atomic Operations capability: the path whose `POST` requestBody
|
|
101
94
|
* declares the atomic ext media type ({@link ATOMIC_EXT}). `null` when no such endpoint
|
|
@@ -111,7 +104,26 @@ declare class DescriptorBuilder {
|
|
|
111
104
|
/** Follow a `$ref` to its identifier/resource schema and read `properties.type.const`. */
|
|
112
105
|
private resolveConst;
|
|
113
106
|
private attributes;
|
|
107
|
+
/**
|
|
108
|
+
* The relations of a type: every relation its resource renders, plus each write-only relation
|
|
109
|
+
* the create and update bodies accept. A write-only relation is one whose body property carries
|
|
110
|
+
* `writeOnly: true` (generator contract 8) or, in an older document, one the resource doesn't
|
|
111
|
+
* render. A pivot relation reads its response pivot off the rendered relationship and its
|
|
112
|
+
* request pivot off the write bodies.
|
|
113
|
+
*/
|
|
114
114
|
private relations;
|
|
115
|
+
/**
|
|
116
|
+
* The relationships the create and update bodies accept: each one's component `$ref` and
|
|
117
|
+
* whether the body marks it `writeOnly`.
|
|
118
|
+
*/
|
|
119
|
+
private writeRelationships;
|
|
120
|
+
/**
|
|
121
|
+
* Each relation's related and relationship paths, keyed by relation name, from the
|
|
122
|
+
* operationIds the projector stamps (`fetchRelated.<type>.<relation>`, …). A relation's path
|
|
123
|
+
* segment is its URI field name, which may differ from its name, so the paths are never
|
|
124
|
+
* derived from the name when an operationId names them.
|
|
125
|
+
*/
|
|
126
|
+
private relationEndpoints;
|
|
115
127
|
/**
|
|
116
128
|
* The per-relation mutation capability, derived from the HTTP methods the relationship
|
|
117
129
|
* endpoint (`{collection}/{id}/relationships/{rel}`) advertises. For a to-many:
|
|
@@ -152,12 +164,19 @@ declare class DescriptorBuilder {
|
|
|
152
164
|
/** Resolve a relationship component's `data` into a {@link RelationDescriptor}. */
|
|
153
165
|
private relationFromComponent;
|
|
154
166
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
|
|
167
|
+
* The request pivot of a pivot relation: read off the component a write body (or a
|
|
168
|
+
* relationship mutation) refs, falling back to the rendered relationship's pivot minus its
|
|
169
|
+
* `readOnly` fields when no request shape is published (before generator contract 8).
|
|
170
|
+
*/
|
|
171
|
+
private writePivot;
|
|
172
|
+
/**
|
|
173
|
+
* A {@link PivotDescriptor} from a member's `meta.pivot` schema: field hints, the required
|
|
174
|
+
* fields and the nullable ones. Generator contract 8 refs a `<Type><Rel>Pivot` (response) or
|
|
175
|
+
* `<Type><Rel>WritePivot` (request) component, each with its own `required`. An older document
|
|
176
|
+
* inlines one shared schema in the write context, so a read takes every field as rendered and a
|
|
177
|
+
* write drops the `readOnly` ones. `undefined` when the schema has no fields.
|
|
159
178
|
*/
|
|
160
|
-
private
|
|
179
|
+
private pivotDescriptor;
|
|
161
180
|
/** Pull the related type from the `$ref` entry of an `allOf` (the pivot shape). */
|
|
162
181
|
private constFromAllOf;
|
|
163
182
|
/** Resolve every `$ref` entry in a list to its wire type. */
|
|
@@ -241,7 +260,7 @@ declare function buildAtomic(doc: OpenApiDocument): AtomicDescriptor | null;
|
|
|
241
260
|
/** Below this the document predates the structures this codegen reads. */
|
|
242
261
|
declare const MINIMUM_CONTRACT = 1;
|
|
243
262
|
/** Above this the document carries structures this codegen does not read. */
|
|
244
|
-
declare const MAXIMUM_CONTRACT =
|
|
263
|
+
declare const MAXIMUM_CONTRACT = 9;
|
|
245
264
|
/**
|
|
246
265
|
* Check the document's `info.x-generator.contract` against the range this codegen reads. A
|
|
247
266
|
* document older than the range throws; a newer one returns a warning, because its new
|
|
@@ -262,7 +281,6 @@ interface VerbCollision {
|
|
|
262
281
|
*/
|
|
263
282
|
declare function detectVerbCollisions(descriptor: ApiDescriptor): VerbCollision[];
|
|
264
283
|
declare class Emitter {
|
|
265
|
-
private readonly doc;
|
|
266
284
|
private readonly descriptor;
|
|
267
285
|
private readonly atomic;
|
|
268
286
|
private readonly schemas;
|
|
@@ -287,7 +305,8 @@ declare class Emitter {
|
|
|
287
305
|
private readonly actionAliasNames;
|
|
288
306
|
/** Provenance of the source document, stamped into the generated header for drift tracking. */
|
|
289
307
|
private readonly provenance;
|
|
290
|
-
|
|
308
|
+
private readonly doc;
|
|
309
|
+
constructor(source: OpenApiDocument, descriptor: ApiDescriptor, atomic: AtomicDescriptor | null);
|
|
291
310
|
/** Map each declared wire type back to the `Base` of its resource schema. */
|
|
292
311
|
private indexBases;
|
|
293
312
|
emit(): string;
|
|
@@ -546,4 +565,4 @@ declare function generate(config: CodegenConfig): Promise<string>;
|
|
|
546
565
|
declare function check(config: CodegenConfig): Promise<CheckResult>;
|
|
547
566
|
//#endregion
|
|
548
567
|
export { InfoObject as A, MAXIMUM_CONTRACT as C, buildAtomic as D, DescriptorBuilder as E, PathItemObject as F, RequestBodyObject as I, ResponseObject as L, OpenApiDocument as M, OperationObject as N, buildDescriptor as O, ParameterObject as P, SchemaObject as R, emit as S, checkContract as T, emitErrorCodes as _, generate as a, VerbCollision as b, deriveProvenance as c, emitSchemas as d, SchemaBundle as f, ErrorCatalogue as g, DocumentedErrorCode as h, check as i, MediaTypeObject as j, HttpMethod as k, hashJson as l, readSchemas as m, CheckResult as n, schemasOutputPath as o, readDocument as p, CodegenConfig as r, Provenance as s, ArtifactDrift as t, provenanceLines as u, readErrorCatalogue as v, MINIMUM_CONTRACT as w, detectVerbCollisions as x, Emitter as y, SchemaOrBool as z };
|
|
549
|
-
//# sourceMappingURL=index-
|
|
568
|
+
//# sourceMappingURL=index-CU-kUx70.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-CU-kUx70.d.mts","names":[],"sources":["../src/openapi.ts","../src/build-descriptor.ts","../src/contract.ts","../src/emit.ts","../src/error-codes.ts","../src/reader.ts","../src/emit-schemas.ts","../src/provenance.ts","../src/index.ts"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as InfoObject, C as MAXIMUM_CONTRACT, D as buildAtomic, E as DescriptorBuilder, F as PathItemObject, I as RequestBodyObject, L as ResponseObject, M as OpenApiDocument, N as OperationObject, O as buildDescriptor, P as ParameterObject, R as SchemaObject, S as emit, T as checkContract, _ as emitErrorCodes, a as generate, b as VerbCollision, c as deriveProvenance, d as emitSchemas, f as SchemaBundle, g as ErrorCatalogue, h as DocumentedErrorCode, i as check, j as MediaTypeObject, k as HttpMethod, l as hashJson, m as readSchemas, n as CheckResult, o as schemasOutputPath, p as readDocument, r as CodegenConfig, s as Provenance, t as ArtifactDrift, u as provenanceLines, v as readErrorCatalogue, w as MINIMUM_CONTRACT, x as detectVerbCollisions, y as Emitter, z as SchemaOrBool } from "./index-
|
|
1
|
+
import { A as InfoObject, C as MAXIMUM_CONTRACT, D as buildAtomic, E as DescriptorBuilder, F as PathItemObject, I as RequestBodyObject, L as ResponseObject, M as OpenApiDocument, N as OperationObject, O as buildDescriptor, P as ParameterObject, R as SchemaObject, S as emit, T as checkContract, _ as emitErrorCodes, a as generate, b as VerbCollision, c as deriveProvenance, d as emitSchemas, f as SchemaBundle, g as ErrorCatalogue, h as DocumentedErrorCode, i as check, j as MediaTypeObject, k as HttpMethod, l as hashJson, m as readSchemas, n as CheckResult, o as schemasOutputPath, p as readDocument, r as CodegenConfig, s as Provenance, t as ArtifactDrift, u as provenanceLines, v as readErrorCatalogue, w as MINIMUM_CONTRACT, x as detectVerbCollisions, y as Emitter, z as SchemaOrBool } from "./index-CU-kUx70.mjs";
|
|
2
2
|
export { ArtifactDrift, CheckResult, CodegenConfig, DescriptorBuilder, type DocumentedErrorCode, Emitter, type ErrorCatalogue, type HttpMethod, type InfoObject, MAXIMUM_CONTRACT, MINIMUM_CONTRACT, type MediaTypeObject, type OpenApiDocument, type OperationObject, type ParameterObject, type PathItemObject, type Provenance, type RequestBodyObject, type ResponseObject, type SchemaBundle, type SchemaObject, type SchemaOrBool, type VerbCollision, buildAtomic, buildDescriptor, check, checkContract, deriveProvenance, detectVerbCollisions, emit, emitErrorCodes, emitSchemas, generate, hashJson, provenanceLines, readDocument, readErrorCatalogue, readSchemas, schemasOutputPath };
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as checkContract, a as readSchemas, b as buildDescriptor, c as detectVerbCollisions, d as hashJson, f as provenanceLines, g as MINIMUM_CONTRACT, h as MAXIMUM_CONTRACT, i as readDocument, l as emit, m as readErrorCatalogue, n as generate, o as emitSchemas, p as emitErrorCodes, r as schemasOutputPath, s as Emitter, t as check, u as deriveProvenance, v as DescriptorBuilder, y as buildAtomic } from "./src-
|
|
1
|
+
import { _ as checkContract, a as readSchemas, b as buildDescriptor, c as detectVerbCollisions, d as hashJson, f as provenanceLines, g as MINIMUM_CONTRACT, h as MAXIMUM_CONTRACT, i as readDocument, l as emit, m as readErrorCatalogue, n as generate, o as emitSchemas, p as emitErrorCodes, r as schemasOutputPath, s as Emitter, t as check, u as deriveProvenance, v as DescriptorBuilder, y as buildAtomic } from "./src-C2INS1Wd.mjs";
|
|
2
2
|
export { DescriptorBuilder, Emitter, MAXIMUM_CONTRACT, MINIMUM_CONTRACT, buildAtomic, buildDescriptor, check, checkContract, deriveProvenance, detectVerbCollisions, emit, emitErrorCodes, emitSchemas, generate, hashJson, provenanceLines, readDocument, readErrorCatalogue, readSchemas, schemasOutputPath };
|
|
@@ -3,6 +3,64 @@ import { dirname } from "node:path";
|
|
|
3
3
|
import { ATOMIC_EXT, CANONICAL_PAGE_KEYS, HANDLE_RESERVED } from "@haddowg/json-api-client";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import { parse } from "yaml";
|
|
6
|
+
//#region src/unwrap-refs.ts
|
|
7
|
+
/**
|
|
8
|
+
* Keywords that annotate a schema without constraining it. A single-entry `allOf` wrapper is
|
|
9
|
+
* read as its `$ref` only when the wrapper carries nothing else, plus any `x-` extension.
|
|
10
|
+
*/
|
|
11
|
+
const ANNOTATIONS = /* @__PURE__ */ new Set([
|
|
12
|
+
"title",
|
|
13
|
+
"description",
|
|
14
|
+
"example",
|
|
15
|
+
"examples",
|
|
16
|
+
"default",
|
|
17
|
+
"deprecated",
|
|
18
|
+
"readOnly",
|
|
19
|
+
"writeOnly",
|
|
20
|
+
"$comment"
|
|
21
|
+
]);
|
|
22
|
+
const unwrapped = /* @__PURE__ */ new WeakMap();
|
|
23
|
+
/**
|
|
24
|
+
* The document with every `{ allOf: [{ $ref }], ...annotations }` node rewritten as
|
|
25
|
+
* `{ $ref, ...annotations }`. From generator contract 9 the projector wraps a `$ref` that
|
|
26
|
+
* carries an `example`, `examples` or `default` this way, because OAS 3.0 tooling ignores a
|
|
27
|
+
* `$ref`'s siblings. Reading the wrapper as its `$ref` keeps every lookup that follows a `$ref`
|
|
28
|
+
* working, and keeps the annotations for the TSDoc. The input is not modified.
|
|
29
|
+
*/
|
|
30
|
+
function unwrapRefs(doc) {
|
|
31
|
+
let out = unwrapped.get(doc);
|
|
32
|
+
if (out === void 0) {
|
|
33
|
+
out = unwrapNode(doc);
|
|
34
|
+
unwrapped.set(doc, out);
|
|
35
|
+
unwrapped.set(out, out);
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
function unwrapNode(node) {
|
|
40
|
+
if (Array.isArray(node)) return node.map(unwrapNode);
|
|
41
|
+
if (typeof node !== "object" || node === null) return node;
|
|
42
|
+
const out = {};
|
|
43
|
+
for (const [key, value] of Object.entries(node)) out[key] = unwrapNode(value);
|
|
44
|
+
const ref = wrappedRef(out);
|
|
45
|
+
if (ref === void 0) return out;
|
|
46
|
+
const { allOf: _allOf, ...annotations } = out;
|
|
47
|
+
return {
|
|
48
|
+
$ref: ref,
|
|
49
|
+
...annotations
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** The `$ref` a node wraps in a single-entry `allOf`, when that is all the node constrains. */
|
|
53
|
+
function wrappedRef(node) {
|
|
54
|
+
const allOf = node["allOf"];
|
|
55
|
+
if (!Array.isArray(allOf) || allOf.length !== 1 || "$ref" in node) return;
|
|
56
|
+
const entry = allOf[0];
|
|
57
|
+
if (typeof entry !== "object" || entry === null) return;
|
|
58
|
+
const keys = Object.keys(entry);
|
|
59
|
+
const ref = entry["$ref"];
|
|
60
|
+
if (keys.length !== 1 || typeof ref !== "string") return;
|
|
61
|
+
return Object.keys(node).every((key) => key === "allOf" || ANNOTATIONS.has(key) || key.startsWith("x-")) ? ref : void 0;
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
6
64
|
//#region src/build-descriptor.ts
|
|
7
65
|
const REF_PREFIX$2 = "#/components/schemas/";
|
|
8
66
|
const JSON_API_MEDIA_TYPE$1 = "application/vnd.api+json";
|
|
@@ -19,19 +77,26 @@ function refName$1(ref) {
|
|
|
19
77
|
function isSchema$2(value) {
|
|
20
78
|
return typeof value === "object" && value !== null;
|
|
21
79
|
}
|
|
80
|
+
/** The operationId prefixes of a relation's related read and its relationship endpoint. */
|
|
81
|
+
const RELATED_OPERATION = "fetchRelated";
|
|
82
|
+
const RELATIONSHIP_OPERATIONS = [
|
|
83
|
+
"fetchRelationship",
|
|
84
|
+
"updateRelationship",
|
|
85
|
+
"addRelationship",
|
|
86
|
+
"removeRelationship"
|
|
87
|
+
];
|
|
22
88
|
/** The set of `type` keys a JSON type node declares, with `"null"` removed. */
|
|
23
89
|
function typeKeys(type) {
|
|
24
90
|
if (type === void 0) return [];
|
|
25
91
|
return (Array.isArray(type) ? type : [type]).filter((t) => t !== "null");
|
|
26
92
|
}
|
|
27
93
|
var DescriptorBuilder = class {
|
|
28
|
-
doc;
|
|
29
94
|
schemas;
|
|
30
95
|
paths;
|
|
31
96
|
/** Lazily-built wire-type -> collection-level paginator kind (for per-relation divergence, D6a). */
|
|
32
97
|
typePaginators;
|
|
33
|
-
constructor(
|
|
34
|
-
|
|
98
|
+
constructor(source) {
|
|
99
|
+
const doc = unwrapRefs(source);
|
|
35
100
|
this.schemas = doc.components?.schemas ?? {};
|
|
36
101
|
this.paths = doc.paths ?? {};
|
|
37
102
|
}
|
|
@@ -60,7 +125,7 @@ var DescriptorBuilder = class {
|
|
|
60
125
|
const actions = collection ? this.actions(collection) : {};
|
|
61
126
|
const descriptor = {
|
|
62
127
|
attributes: this.attributes(base),
|
|
63
|
-
relations: this.relations(schema, collection),
|
|
128
|
+
relations: this.relations(wireType, base, schema, collection),
|
|
64
129
|
paths: this.operationPaths(base),
|
|
65
130
|
paginator: this.paginator(base),
|
|
66
131
|
clientId: this.clientId(base)
|
|
@@ -75,27 +140,11 @@ var DescriptorBuilder = class {
|
|
|
75
140
|
if (filterable !== void 0) descriptor.filterable = filterable;
|
|
76
141
|
if (Object.keys(actions).length > 0) descriptor.actions = actions;
|
|
77
142
|
if (Object.keys(schema.properties ?? {}).every((prop) => prop === "type") && Object.keys(descriptor.paths).length === 0) continue;
|
|
78
|
-
this.warnWriteOnlyRelations(wireType, base, descriptor.relations);
|
|
79
143
|
out[wireType] = descriptor;
|
|
80
144
|
}
|
|
81
145
|
return sortRecord(out);
|
|
82
146
|
}
|
|
83
147
|
/**
|
|
84
|
-
* Warn about relations a create or update body accepts but the resource never renders. A
|
|
85
|
-
* write-only relation (generator contract 5) is left out of the response schema, and the
|
|
86
|
-
* descriptor has no way to mark a relation as writable but unreadable, so it is missing from
|
|
87
|
-
* the client entirely rather than typed onto reads that never carry it.
|
|
88
|
-
*/
|
|
89
|
-
warnWriteOnlyRelations(wireType, base, readable) {
|
|
90
|
-
const writeOnly = /* @__PURE__ */ new Set();
|
|
91
|
-
for (const request of [`${base}CreateRequest`, `${base}UpdateRequest`]) {
|
|
92
|
-
const data = this.schemas[request]?.properties?.["data"];
|
|
93
|
-
const relationships = isSchema$2(data) ? data.properties?.["relationships"] : void 0;
|
|
94
|
-
for (const name of Object.keys(isSchema$2(relationships) ? relationships.properties ?? {} : {})) if (!(name in readable)) writeOnly.add(name);
|
|
95
|
-
}
|
|
96
|
-
for (const name of writeOnly) console.warn(`json-api codegen: relationship "${name}" on "${wireType}" is accepted on writes but never rendered (a write-only relation); the client has no slot for a relation it can't read, so it is left out.`);
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
148
|
* The server-level Atomic Operations capability: the path whose `POST` requestBody
|
|
100
149
|
* declares the atomic ext media type ({@link ATOMIC_EXT}). `null` when no such endpoint
|
|
101
150
|
* exists. Server-level, so it rides {@link buildAtomic}, not the per-type descriptor.
|
|
@@ -131,31 +180,106 @@ var DescriptorBuilder = class {
|
|
|
131
180
|
for (const [name, prop] of Object.entries(props)) if (isSchema$2(prop)) out[name] = formatHint(prop);
|
|
132
181
|
return sortRecord(out);
|
|
133
182
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
183
|
+
/**
|
|
184
|
+
* The relations of a type: every relation its resource renders, plus each write-only relation
|
|
185
|
+
* the create and update bodies accept. A write-only relation is one whose body property carries
|
|
186
|
+
* `writeOnly: true` (generator contract 8) or, in an older document, one the resource doesn't
|
|
187
|
+
* render. A pivot relation reads its response pivot off the rendered relationship and its
|
|
188
|
+
* request pivot off the write bodies.
|
|
189
|
+
*/
|
|
190
|
+
relations(wireType, base, resource, collection) {
|
|
191
|
+
const relProps = isSchema$2(resource.properties?.["relationships"]) ? resource.properties["relationships"].properties ?? {} : {};
|
|
192
|
+
const writes = this.writeRelationships(base);
|
|
193
|
+
const endpoints = this.relationEndpoints(wireType);
|
|
137
194
|
const out = {};
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const descriptor = component ? this.relationFromComponent(component) : void 0;
|
|
142
|
-
if (descriptor === void 0) {
|
|
195
|
+
const add = (name, component, writeOnly) => {
|
|
196
|
+
const parsed = component ? this.relationFromComponent(component) : void 0;
|
|
197
|
+
if (parsed === void 0) {
|
|
143
198
|
console.warn(`json-api codegen: relationship "${name}" has an unrecognized linkage shape; dropping it from the descriptor.`);
|
|
144
|
-
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const descriptor = { ...parsed };
|
|
202
|
+
if (writeOnly) {
|
|
203
|
+
delete descriptor.readPivot;
|
|
204
|
+
descriptor.writeOnly = true;
|
|
145
205
|
}
|
|
146
|
-
|
|
206
|
+
if (descriptor.pivot === true) {
|
|
207
|
+
const writePivot = this.writePivot(writes.get(name)?.ref ?? endpoints.get(name)?.requestRef, component);
|
|
208
|
+
if (writePivot !== void 0) descriptor.writePivot = writePivot;
|
|
209
|
+
}
|
|
210
|
+
out[name] = collection === void 0 ? descriptor : this.withRelationExposure(descriptor, collection, name, endpoints.get(name));
|
|
211
|
+
};
|
|
212
|
+
for (const [name, prop] of Object.entries(relProps)) {
|
|
213
|
+
if (!isSchema$2(prop) || typeof prop.$ref !== "string" || writes.get(name)?.writeOnly) continue;
|
|
214
|
+
add(name, this.schemas[refName$1(prop.$ref) ?? ""], false);
|
|
147
215
|
}
|
|
216
|
+
for (const [name, write] of writes) if (write.writeOnly || !(name in relProps)) add(name, this.schemas[refName$1(write.ref) ?? ""], true);
|
|
148
217
|
return sortRecord(out);
|
|
149
218
|
}
|
|
150
219
|
/**
|
|
220
|
+
* The relationships the create and update bodies accept: each one's component `$ref` and
|
|
221
|
+
* whether the body marks it `writeOnly`.
|
|
222
|
+
*/
|
|
223
|
+
writeRelationships(base) {
|
|
224
|
+
const out = /* @__PURE__ */ new Map();
|
|
225
|
+
for (const request of [`${base}CreateRequest`, `${base}UpdateRequest`]) {
|
|
226
|
+
const data = this.schemas[request]?.properties?.["data"];
|
|
227
|
+
const relationships = isSchema$2(data) ? data.properties?.["relationships"] : void 0;
|
|
228
|
+
const props = isSchema$2(relationships) ? relationships.properties ?? {} : {};
|
|
229
|
+
for (const [name, prop] of Object.entries(props)) {
|
|
230
|
+
if (!isSchema$2(prop) || typeof prop.$ref !== "string") continue;
|
|
231
|
+
const writeOnly = prop["writeOnly"] === true || out.get(name)?.writeOnly === true;
|
|
232
|
+
out.set(name, {
|
|
233
|
+
ref: out.get(name)?.ref ?? prop.$ref,
|
|
234
|
+
writeOnly
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return out;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Each relation's related and relationship paths, keyed by relation name, from the
|
|
242
|
+
* operationIds the projector stamps (`fetchRelated.<type>.<relation>`, …). A relation's path
|
|
243
|
+
* segment is its URI field name, which may differ from its name, so the paths are never
|
|
244
|
+
* derived from the name when an operationId names them.
|
|
245
|
+
*/
|
|
246
|
+
relationEndpoints(wireType) {
|
|
247
|
+
const out = /* @__PURE__ */ new Map();
|
|
248
|
+
const entry = (rel) => {
|
|
249
|
+
let found = out.get(rel);
|
|
250
|
+
if (found === void 0) {
|
|
251
|
+
found = {};
|
|
252
|
+
out.set(rel, found);
|
|
253
|
+
}
|
|
254
|
+
return found;
|
|
255
|
+
};
|
|
256
|
+
for (const [path, item] of Object.entries(this.paths)) for (const [method, op] of Object.entries(item)) {
|
|
257
|
+
const id = op?.operationId;
|
|
258
|
+
if (typeof id !== "string") continue;
|
|
259
|
+
const dot = id.indexOf(".");
|
|
260
|
+
const prefix = id.slice(0, dot);
|
|
261
|
+
const rest = id.slice(dot + 1);
|
|
262
|
+
if (dot < 0 || !rest.startsWith(`${wireType}.`)) continue;
|
|
263
|
+
const rel = rest.slice(wireType.length + 1);
|
|
264
|
+
if (prefix === RELATED_OPERATION) entry(rel).related = path;
|
|
265
|
+
else if (RELATIONSHIP_OPERATIONS.includes(prefix)) {
|
|
266
|
+
const found = entry(rel);
|
|
267
|
+
found.relationship = path;
|
|
268
|
+
const ref = method === "get" ? void 0 : this.requestBodyRef(op);
|
|
269
|
+
if (ref !== void 0) found.requestRef = ref;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return out;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
151
275
|
* The per-relation mutation capability, derived from the HTTP methods the relationship
|
|
152
276
|
* endpoint (`{collection}/{id}/relationships/{rel}`) advertises. For a to-many:
|
|
153
277
|
* `add` <- POST, `remove` <- DELETE, `replace` <- PATCH. For a to-one: `set` <- PATCH.
|
|
154
278
|
* Only `true` verbs are emitted (a missing verb is simply absent). Returns `undefined`
|
|
155
279
|
* when the relation exposes no relationship endpoint at all.
|
|
156
280
|
*/
|
|
157
|
-
relationMutations(
|
|
158
|
-
const item = this.paths[
|
|
281
|
+
relationMutations(path, cardinality) {
|
|
282
|
+
const item = this.paths[path];
|
|
159
283
|
if (item === void 0) return;
|
|
160
284
|
const mutations = {};
|
|
161
285
|
if (cardinality === "many") {
|
|
@@ -175,19 +299,23 @@ var DescriptorBuilder = class {
|
|
|
175
299
|
* relationship endpoint exists, else `{}`) so the client gates a suppressed relation OFF rather
|
|
176
300
|
* than failing open (offering `.get()`/`.related()`/mutations that 404).
|
|
177
301
|
*/
|
|
178
|
-
withRelationExposure(descriptor, collection, name) {
|
|
302
|
+
withRelationExposure(descriptor, collection, name, endpoints) {
|
|
179
303
|
const out = { ...descriptor };
|
|
180
|
-
const
|
|
304
|
+
const relatedPath = endpoints?.related ?? `${collection}/{id}/${name}`;
|
|
305
|
+
const relationshipPath = endpoints?.relationship ?? `${collection}/{id}/relationships/${name}`;
|
|
306
|
+
const segment = (endpoints?.related ?? endpoints?.relationship)?.split("/").pop();
|
|
307
|
+
if (segment !== void 0 && segment !== name) out.uriField = segment;
|
|
308
|
+
const relatedGet = this.operation(relatedPath, "get");
|
|
181
309
|
if (relatedGet === void 0) out.related = false;
|
|
182
|
-
const mutations = this.relationMutations(
|
|
310
|
+
const mutations = this.relationMutations(relationshipPath, descriptor.cardinality);
|
|
183
311
|
if (mutations === void 0) {
|
|
184
312
|
out.relationship = false;
|
|
185
313
|
out.mutations = {};
|
|
186
314
|
} else out.mutations = mutations;
|
|
187
|
-
const countable = withCountParam(relatedGet) ?? withCountParam(this.operation(
|
|
315
|
+
const countable = withCountParam(relatedGet) ?? withCountParam(this.operation(relationshipPath, "get"));
|
|
188
316
|
if (countable !== void 0) out.countable = countable;
|
|
189
317
|
if (descriptor.cardinality === "many") {
|
|
190
|
-
const relatedPaginator = this.paginatorOf(relatedGet) === "none" ? this.paginatorOf(this.operation(
|
|
318
|
+
const relatedPaginator = this.paginatorOf(relatedGet) === "none" ? this.paginatorOf(this.operation(relationshipPath, "get")) : this.paginatorOf(relatedGet);
|
|
191
319
|
const relatedType = descriptor.types[0];
|
|
192
320
|
const typePaginator = relatedType !== void 0 ? this.typePaginator(relatedType) : "none";
|
|
193
321
|
if (relatedPaginator !== "none" && JSON.stringify(relatedPaginator) !== JSON.stringify(typePaginator)) out.paginator = relatedPaginator;
|
|
@@ -311,8 +439,8 @@ var DescriptorBuilder = class {
|
|
|
311
439
|
types: [type],
|
|
312
440
|
pivot: true
|
|
313
441
|
};
|
|
314
|
-
const
|
|
315
|
-
if (
|
|
442
|
+
const readPivot = this.pivotDescriptor(pivotNodeFromAllOf(items.allOf), "read");
|
|
443
|
+
if (readPivot !== void 0) relation.readPivot = readPivot;
|
|
316
444
|
return relation;
|
|
317
445
|
}
|
|
318
446
|
if (Array.isArray(items.anyOf)) return {
|
|
@@ -325,7 +453,7 @@ var DescriptorBuilder = class {
|
|
|
325
453
|
if (Array.isArray(data.anyOf)) {
|
|
326
454
|
const types = [];
|
|
327
455
|
let pivot = false;
|
|
328
|
-
let
|
|
456
|
+
let readPivot;
|
|
329
457
|
for (const entry of data.anyOf) if (typeof entry.$ref === "string") {
|
|
330
458
|
const type = this.resolveConst(entry.$ref);
|
|
331
459
|
if (type !== void 0) types.push(type);
|
|
@@ -334,7 +462,7 @@ var DescriptorBuilder = class {
|
|
|
334
462
|
if (type !== void 0) {
|
|
335
463
|
types.push(type);
|
|
336
464
|
pivot = true;
|
|
337
|
-
|
|
465
|
+
readPivot = this.pivotDescriptor(pivotNodeFromAllOf(entry.allOf), "read");
|
|
338
466
|
}
|
|
339
467
|
} else if (Array.isArray(entry.anyOf)) types.push(...this.constsFromRefs(entry.anyOf));
|
|
340
468
|
if (types.length === 0) return;
|
|
@@ -343,26 +471,44 @@ var DescriptorBuilder = class {
|
|
|
343
471
|
types,
|
|
344
472
|
pivot
|
|
345
473
|
};
|
|
346
|
-
if (
|
|
474
|
+
if (readPivot !== void 0) relation.readPivot = readPivot;
|
|
347
475
|
return relation;
|
|
348
476
|
}
|
|
349
477
|
}
|
|
350
478
|
/**
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
|
|
479
|
+
* The request pivot of a pivot relation: read off the component a write body (or a
|
|
480
|
+
* relationship mutation) refs, falling back to the rendered relationship's pivot minus its
|
|
481
|
+
* `readOnly` fields when no request shape is published (before generator contract 8).
|
|
482
|
+
*/
|
|
483
|
+
writePivot(ref, fallback) {
|
|
484
|
+
const component = ref === void 0 ? void 0 : this.schemas[refName$1(ref) ?? ""];
|
|
485
|
+
return this.pivotDescriptor(pivotNodeOf(component ?? fallback) ?? pivotNodeOf(fallback), "write");
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* A {@link PivotDescriptor} from a member's `meta.pivot` schema: field hints, the required
|
|
489
|
+
* fields and the nullable ones. Generator contract 8 refs a `<Type><Rel>Pivot` (response) or
|
|
490
|
+
* `<Type><Rel>WritePivot` (request) component, each with its own `required`. An older document
|
|
491
|
+
* inlines one shared schema in the write context, so a read takes every field as rendered and a
|
|
492
|
+
* write drops the `readOnly` ones. `undefined` when the schema has no fields.
|
|
355
493
|
*/
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
494
|
+
pivotDescriptor(node, side) {
|
|
495
|
+
if (node === void 0) return;
|
|
496
|
+
const shared = typeof node.$ref !== "string";
|
|
497
|
+
const schema = shared ? node : this.schemas[refName$1(node.$ref) ?? ""];
|
|
498
|
+
const fields = {};
|
|
499
|
+
const nullable = [];
|
|
500
|
+
for (const [name, prop] of Object.entries(schema?.properties ?? {})) {
|
|
501
|
+
if (!isSchema$2(prop) || prop[side === "read" ? "writeOnly" : "readOnly"] === true) continue;
|
|
502
|
+
fields[name] = formatHint(prop);
|
|
503
|
+
if (isNullable(prop)) nullable.push(name);
|
|
365
504
|
}
|
|
505
|
+
const names = Object.keys(fields);
|
|
506
|
+
if (names.length === 0) return;
|
|
507
|
+
const required = shared && side === "read" ? names : names.filter((name) => schema?.required?.includes(name));
|
|
508
|
+
const out = { fields: sortRecord(fields) };
|
|
509
|
+
if (required.length < names.length) out.required = required.sort();
|
|
510
|
+
if (nullable.length > 0) out.nullable = nullable.sort();
|
|
511
|
+
return out;
|
|
366
512
|
}
|
|
367
513
|
/** Pull the related type from the `$ref` entry of an `allOf` (the pivot shape). */
|
|
368
514
|
constFromAllOf(allOf) {
|
|
@@ -544,6 +690,30 @@ var DescriptorBuilder = class {
|
|
|
544
690
|
return op?.responses?.["200"]?.content?.["application/vnd.api+json"]?.schema?.$ref;
|
|
545
691
|
}
|
|
546
692
|
};
|
|
693
|
+
/** The `meta.pivot` schema node of a pivot `allOf` entry list, if any. */
|
|
694
|
+
function pivotNodeFromAllOf(allOf) {
|
|
695
|
+
for (const entry of allOf) {
|
|
696
|
+
const meta = entry.properties?.["meta"];
|
|
697
|
+
const pivot = isSchema$2(meta) ? meta.properties?.["pivot"] : void 0;
|
|
698
|
+
if (isSchema$2(pivot)) return pivot;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* The `meta.pivot` schema node of a relationship component or document: its to-many `items`
|
|
703
|
+
* `allOf`, or a to-one `anyOf` entry's `allOf`.
|
|
704
|
+
*/
|
|
705
|
+
function pivotNodeOf(component) {
|
|
706
|
+
const data = component.properties?.["data"];
|
|
707
|
+
if (!isSchema$2(data)) return;
|
|
708
|
+
if (Array.isArray(data.items?.allOf)) return pivotNodeFromAllOf(data.items.allOf);
|
|
709
|
+
for (const entry of data.anyOf ?? []) if (Array.isArray(entry.allOf)) return pivotNodeFromAllOf(entry.allOf);
|
|
710
|
+
}
|
|
711
|
+
/** Whether a schema admits `null`: a `null` type, or a `null` branch in `anyOf`/`oneOf`. */
|
|
712
|
+
function isNullable(schema) {
|
|
713
|
+
const type = schema.type;
|
|
714
|
+
if (type === "null" || Array.isArray(type) && type.includes("null")) return true;
|
|
715
|
+
return [...schema.anyOf ?? [], ...schema.oneOf ?? []].some((branch) => branch.type === "null");
|
|
716
|
+
}
|
|
547
717
|
/** A schema's wire format hint: explicit `format`, else the JSON type, else a ref-enum is `string`. */
|
|
548
718
|
function formatHint(schema) {
|
|
549
719
|
if (typeof schema.format === "string") return schema.format;
|
|
@@ -735,7 +905,7 @@ function stampedMenu(schema, stamp, warn) {
|
|
|
735
905
|
/** Below this the document predates the structures this codegen reads. */
|
|
736
906
|
const MINIMUM_CONTRACT = 1;
|
|
737
907
|
/** Above this the document carries structures this codegen does not read. */
|
|
738
|
-
const MAXIMUM_CONTRACT =
|
|
908
|
+
const MAXIMUM_CONTRACT = 9;
|
|
739
909
|
/**
|
|
740
910
|
* Check the document's `info.x-generator.contract` against the range this codegen reads. A
|
|
741
911
|
* document older than the range throws; a newer one returns a warning, because its new
|
|
@@ -745,8 +915,8 @@ const MAXIMUM_CONTRACT = 7;
|
|
|
745
915
|
function checkContract(doc) {
|
|
746
916
|
const contract = doc.info?.["x-generator"]?.contract;
|
|
747
917
|
if (typeof contract !== "number") return;
|
|
748
|
-
if (contract < 1) throw new Error(`the document declares contract ${contract}, which predates what this codegen reads (it supports 1 to
|
|
749
|
-
if (contract >
|
|
918
|
+
if (contract < 1) throw new Error(`the document declares contract ${contract}, which predates what this codegen reads (it supports 1 to 9). Use an older codegen release, or regenerate the document from a newer server.`);
|
|
919
|
+
if (contract > 9) return `the document declares contract ${contract} and this codegen reads up to 9. It describes capabilities that were not generated; upgrade the codegen to pick them up.`;
|
|
750
920
|
}
|
|
751
921
|
//#endregion
|
|
752
922
|
//#region src/error-codes.ts
|
|
@@ -1045,7 +1215,6 @@ function memberDoc(schema) {
|
|
|
1045
1215
|
return description ? `${description}\n\n${tags.join("\n")}` : tags.join("\n");
|
|
1046
1216
|
}
|
|
1047
1217
|
var Emitter = class {
|
|
1048
|
-
doc;
|
|
1049
1218
|
descriptor;
|
|
1050
1219
|
atomic;
|
|
1051
1220
|
schemas;
|
|
@@ -1070,13 +1239,14 @@ var Emitter = class {
|
|
|
1070
1239
|
actionAliasNames = /* @__PURE__ */ new Map();
|
|
1071
1240
|
/** Provenance of the source document, stamped into the generated header for drift tracking. */
|
|
1072
1241
|
provenance;
|
|
1073
|
-
|
|
1074
|
-
|
|
1242
|
+
doc;
|
|
1243
|
+
constructor(source, descriptor, atomic) {
|
|
1075
1244
|
this.descriptor = descriptor;
|
|
1076
1245
|
this.atomic = atomic;
|
|
1077
|
-
this.
|
|
1246
|
+
this.doc = unwrapRefs(source);
|
|
1247
|
+
this.schemas = this.doc.components?.schemas ?? {};
|
|
1078
1248
|
this.baseByType = this.indexBases();
|
|
1079
|
-
this.provenance = deriveProvenance(
|
|
1249
|
+
this.provenance = deriveProvenance(source);
|
|
1080
1250
|
}
|
|
1081
1251
|
/** Map each declared wire type back to the `Base` of its resource schema. */
|
|
1082
1252
|
indexBases() {
|
|
@@ -1662,4 +1832,4 @@ async function check(config) {
|
|
|
1662
1832
|
//#endregion
|
|
1663
1833
|
export { checkContract as _, readSchemas as a, buildDescriptor as b, detectVerbCollisions as c, hashJson as d, provenanceLines as f, MINIMUM_CONTRACT as g, MAXIMUM_CONTRACT as h, readDocument as i, emit as l, readErrorCatalogue as m, generate as n, emitSchemas as o, emitErrorCodes as p, schemasOutputPath as r, Emitter as s, check as t, deriveProvenance as u, DescriptorBuilder as v, buildAtomic as y };
|
|
1664
1834
|
|
|
1665
|
-
//# sourceMappingURL=src-
|
|
1835
|
+
//# sourceMappingURL=src-C2INS1Wd.mjs.map
|