@haddowg/json-api-codegen 1.6.0 → 1.7.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-CU-kUx70.d.mts → index-CeSU_OuC.d.mts} +55 -3
- package/dist/index-CeSU_OuC.d.mts.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-C2INS1Wd.mjs → src-DhZyiWge.mjs} +408 -50
- package/dist/src-DhZyiWge.mjs.map +1 -0
- package/package.json +2 -2
- package/dist/index-CU-kUx70.d.mts.map +0 -1
- package/dist/src-C2INS1Wd.mjs.map +0 -1
|
@@ -374,11 +374,63 @@ var DescriptorBuilder = class {
|
|
|
374
374
|
const contentType = rawContentType(op);
|
|
375
375
|
if (contentType !== void 0) action.contentType = contentType;
|
|
376
376
|
}
|
|
377
|
+
const rawOutput = this.rawOutput(op);
|
|
378
|
+
if (rawOutput.length > 0) action.rawOutput = rawOutput;
|
|
379
|
+
const requestContent = Object.entries(op.requestBody?.content ?? {});
|
|
380
|
+
if (requestContent.length > 1) action.inputMedia = requestContent.map(([mediaType, media]) => ({
|
|
381
|
+
mediaType,
|
|
382
|
+
kind: this.inputMediaKind(mediaType, media.schema)
|
|
383
|
+
}));
|
|
377
384
|
out[name] = action;
|
|
378
385
|
}
|
|
379
386
|
return sortRecord(out);
|
|
380
387
|
}
|
|
381
388
|
/**
|
|
389
|
+
* The non-JSON:API media types an action answers with under its 2xx responses, each once, in
|
|
390
|
+
* the document's order, with how the client reads its body.
|
|
391
|
+
*/
|
|
392
|
+
rawOutput(op) {
|
|
393
|
+
const out = [];
|
|
394
|
+
for (const [code, response] of Object.entries(op.responses ?? {})) {
|
|
395
|
+
if (!code.startsWith("2")) continue;
|
|
396
|
+
for (const [mediaType, media] of Object.entries(response.content ?? {})) {
|
|
397
|
+
if (isJsonApiMediaType(mediaType) || out.some((entry) => entry.mediaType === mediaType)) continue;
|
|
398
|
+
out.push({
|
|
399
|
+
mediaType,
|
|
400
|
+
kind: this.rawMediaKind(mediaType, media.schema)
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return out;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* How the client reads or sends a non-JSON:API body: `binary` for `format: binary` (or no schema
|
|
408
|
+
* on a type that isn't text or JSON), `text` for any other string schema (or no schema on a
|
|
409
|
+
* `text/*` type), `json` for any other schema (or no schema on a JSON type).
|
|
410
|
+
*/
|
|
411
|
+
rawMediaKind(mediaType, schema) {
|
|
412
|
+
const resolved = this.resolveSchema(schema);
|
|
413
|
+
if (resolved === void 0) {
|
|
414
|
+
if (mediaType.startsWith("text/")) return "text";
|
|
415
|
+
return isJsonMediaType(mediaType) ? "json" : "binary";
|
|
416
|
+
}
|
|
417
|
+
if (resolved.type === "string") return resolved.format === "binary" ? "binary" : "text";
|
|
418
|
+
return "json";
|
|
419
|
+
}
|
|
420
|
+
/** How the client sends one of an action's several request media types. */
|
|
421
|
+
inputMediaKind(mediaType, schema) {
|
|
422
|
+
if (isJsonApiMediaType(mediaType)) return "document";
|
|
423
|
+
if (mediaType.startsWith("multipart/")) return "multipart";
|
|
424
|
+
if (mediaType === "application/x-www-form-urlencoded") return "form";
|
|
425
|
+
return this.rawMediaKind(mediaType, schema);
|
|
426
|
+
}
|
|
427
|
+
/** A schema with a component `$ref` followed, else the schema as is. */
|
|
428
|
+
resolveSchema(schema) {
|
|
429
|
+
if (schema === void 0 || typeof schema.$ref !== "string") return schema;
|
|
430
|
+
const name = refName$1(schema.$ref);
|
|
431
|
+
return name === void 0 ? schema : this.schemas[name] ?? schema;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
382
434
|
* The wire type (and cardinality) of a document component's primary `data` — a `$ref` to a
|
|
383
435
|
* resource, an inline object carrying `properties.type.const` (a create-request body), or an
|
|
384
436
|
* array of resource/identifier refs (a collection). `undefined` when the type can't be resolved.
|
|
@@ -767,6 +819,15 @@ function paramItemsEnum(op, paramName) {
|
|
|
767
819
|
function isAtomicMediaType(mediaType) {
|
|
768
820
|
return mediaType.startsWith(JSON_API_MEDIA_TYPE$1) && mediaType.includes(ATOMIC_EXT);
|
|
769
821
|
}
|
|
822
|
+
/** Whether a media type is JSON:API, with or without `ext` / `profile` parameters. */
|
|
823
|
+
function isJsonApiMediaType(mediaType) {
|
|
824
|
+
return mediaType.split(";")[0].trim().toLowerCase() === JSON_API_MEDIA_TYPE$1;
|
|
825
|
+
}
|
|
826
|
+
/** Whether a non-JSON:API media type carries JSON: `application/json` or a `+json` suffix. */
|
|
827
|
+
function isJsonMediaType(mediaType) {
|
|
828
|
+
const essence = mediaType.split(";")[0].trim().toLowerCase();
|
|
829
|
+
return essence === "application/json" || essence.endsWith("+json");
|
|
830
|
+
}
|
|
770
831
|
/** The HTTP methods an action operation may be advertised under, in resolution preference order. */
|
|
771
832
|
const ACTION_METHODS = [
|
|
772
833
|
"post",
|
|
@@ -905,7 +966,7 @@ function stampedMenu(schema, stamp, warn) {
|
|
|
905
966
|
/** Below this the document predates the structures this codegen reads. */
|
|
906
967
|
const MINIMUM_CONTRACT = 1;
|
|
907
968
|
/** Above this the document carries structures this codegen does not read. */
|
|
908
|
-
const MAXIMUM_CONTRACT =
|
|
969
|
+
const MAXIMUM_CONTRACT = 11;
|
|
909
970
|
/**
|
|
910
971
|
* Check the document's `info.x-generator.contract` against the range this codegen reads. A
|
|
911
972
|
* document older than the range throws; a newer one returns a warning, because its new
|
|
@@ -915,8 +976,108 @@ const MAXIMUM_CONTRACT = 9;
|
|
|
915
976
|
function checkContract(doc) {
|
|
916
977
|
const contract = doc.info?.["x-generator"]?.contract;
|
|
917
978
|
if (typeof contract !== "number") return;
|
|
918
|
-
if (contract < 1) throw new Error(`the document declares contract ${contract}, which predates what this codegen reads (it supports 1 to
|
|
919
|
-
if (contract >
|
|
979
|
+
if (contract < 1) throw new Error(`the document declares contract ${contract}, which predates what this codegen reads (it supports 1 to 11). Use an older codegen release, or regenerate the document from a newer server.`);
|
|
980
|
+
if (contract > 11) return `the document declares contract ${contract} and this codegen reads up to 11. It describes capabilities that were not generated; upgrade the codegen to pick them up.`;
|
|
981
|
+
}
|
|
982
|
+
//#endregion
|
|
983
|
+
//#region src/source.ts
|
|
984
|
+
/**
|
|
985
|
+
* Helpers for writing strings read from the OpenAPI document into generated TypeScript. Every
|
|
986
|
+
* name, literal and comment the emitters take from the document goes through one of these.
|
|
987
|
+
*/
|
|
988
|
+
const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
989
|
+
/** Line terminators as JavaScript counts them. */
|
|
990
|
+
const LINE_BREAK = /\r\n|[\n\r\u2028\u2029]/;
|
|
991
|
+
/** A string as a TS string literal. U+2028/U+2029 are escaped too, which JSON leaves raw. */
|
|
992
|
+
function stringLiteral(value) {
|
|
993
|
+
return JSON.stringify(value).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
994
|
+
}
|
|
995
|
+
/** True when a string is a bare identifier. */
|
|
996
|
+
function isIdentifier(value) {
|
|
997
|
+
return IDENTIFIER.test(value);
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* A property key for an object literal or an interface: bare when it's an identifier, quoted
|
|
1001
|
+
* otherwise. `__proto__` is written as a computed key, which a runtime literal keeps as an own
|
|
1002
|
+
* property instead of setting the prototype.
|
|
1003
|
+
*/
|
|
1004
|
+
function propertyKey(name) {
|
|
1005
|
+
if (name === "__proto__") return `[${stringLiteral(name)}]`;
|
|
1006
|
+
return isIdentifier(name) ? name : stringLiteral(name);
|
|
1007
|
+
}
|
|
1008
|
+
/** Text that can sit inside a block comment: any `*\/` is broken up so it can't close it. */
|
|
1009
|
+
function commentText(text) {
|
|
1010
|
+
return text.replace(/\*\//g, "* /");
|
|
1011
|
+
}
|
|
1012
|
+
/** {@link commentText} split into lines, for a multi-line block comment. */
|
|
1013
|
+
function commentLines(text) {
|
|
1014
|
+
return commentText(text).split(LINE_BREAK);
|
|
1015
|
+
}
|
|
1016
|
+
/** {@link commentText} on one line, for a single comment line such as the provenance header. */
|
|
1017
|
+
function commentLine(text) {
|
|
1018
|
+
return commentText(text).split(LINE_BREAK).join(" ");
|
|
1019
|
+
}
|
|
1020
|
+
/** Words a type alias can't be named: reserved words and the built-in type names. */
|
|
1021
|
+
const RESERVED_TYPE_NAMES = /* @__PURE__ */ new Set([
|
|
1022
|
+
"any",
|
|
1023
|
+
"bigint",
|
|
1024
|
+
"boolean",
|
|
1025
|
+
"break",
|
|
1026
|
+
"case",
|
|
1027
|
+
"catch",
|
|
1028
|
+
"class",
|
|
1029
|
+
"const",
|
|
1030
|
+
"continue",
|
|
1031
|
+
"debugger",
|
|
1032
|
+
"default",
|
|
1033
|
+
"delete",
|
|
1034
|
+
"do",
|
|
1035
|
+
"else",
|
|
1036
|
+
"enum",
|
|
1037
|
+
"export",
|
|
1038
|
+
"extends",
|
|
1039
|
+
"false",
|
|
1040
|
+
"finally",
|
|
1041
|
+
"for",
|
|
1042
|
+
"function",
|
|
1043
|
+
"if",
|
|
1044
|
+
"implements",
|
|
1045
|
+
"import",
|
|
1046
|
+
"in",
|
|
1047
|
+
"instanceof",
|
|
1048
|
+
"interface",
|
|
1049
|
+
"let",
|
|
1050
|
+
"never",
|
|
1051
|
+
"new",
|
|
1052
|
+
"null",
|
|
1053
|
+
"number",
|
|
1054
|
+
"object",
|
|
1055
|
+
"package",
|
|
1056
|
+
"private",
|
|
1057
|
+
"protected",
|
|
1058
|
+
"public",
|
|
1059
|
+
"return",
|
|
1060
|
+
"static",
|
|
1061
|
+
"string",
|
|
1062
|
+
"super",
|
|
1063
|
+
"switch",
|
|
1064
|
+
"symbol",
|
|
1065
|
+
"this",
|
|
1066
|
+
"throw",
|
|
1067
|
+
"true",
|
|
1068
|
+
"try",
|
|
1069
|
+
"typeof",
|
|
1070
|
+
"undefined",
|
|
1071
|
+
"unknown",
|
|
1072
|
+
"var",
|
|
1073
|
+
"void",
|
|
1074
|
+
"while",
|
|
1075
|
+
"with",
|
|
1076
|
+
"yield"
|
|
1077
|
+
]);
|
|
1078
|
+
/** True when `name` can be used as is for an exported type. */
|
|
1079
|
+
function isTypeName(name) {
|
|
1080
|
+
return isIdentifier(name) && !RESERVED_TYPE_NAMES.has(name);
|
|
920
1081
|
}
|
|
921
1082
|
//#endregion
|
|
922
1083
|
//#region src/error-codes.ts
|
|
@@ -981,24 +1142,20 @@ function readErrorCatalogue(doc) {
|
|
|
981
1142
|
/** A TSDoc block for one code: its description, then each example detail as an `@example`. */
|
|
982
1143
|
function codeDoc(entry, indent) {
|
|
983
1144
|
const lines = [];
|
|
984
|
-
if (entry.description !== void 0) lines.push(...entry.description
|
|
1145
|
+
if (entry.description !== void 0) lines.push(...commentLines(entry.description));
|
|
985
1146
|
for (const example of entry.examples) {
|
|
986
1147
|
if (lines.length > 0) lines.push("");
|
|
987
1148
|
const text = typeof example === "string" ? example : JSON.stringify(example);
|
|
988
|
-
lines.push(
|
|
1149
|
+
lines.push(...commentLines(`@example ${text}`));
|
|
989
1150
|
}
|
|
990
1151
|
if (lines.length === 0) return;
|
|
991
|
-
if (lines.length === 1) return `${indent}/** ${lines[0]
|
|
1152
|
+
if (lines.length === 1) return `${indent}/** ${lines[0]} */`;
|
|
992
1153
|
return [
|
|
993
1154
|
`${indent}/**`,
|
|
994
|
-
...lines.map((line) => `${indent} * ${line
|
|
1155
|
+
...lines.map((line) => `${indent} * ${line}`.trimEnd()),
|
|
995
1156
|
`${indent} */`
|
|
996
1157
|
].join("\n");
|
|
997
1158
|
}
|
|
998
|
-
/** A bare object key when the code is a valid identifier, else a quoted one. */
|
|
999
|
-
function codeKey(code) {
|
|
1000
|
-
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(code) ? code : JSON.stringify(code);
|
|
1001
|
-
}
|
|
1002
1159
|
/**
|
|
1003
1160
|
* Emit `ErrorCodes`, a const object keyed by every documented code with its TSDoc on the key
|
|
1004
1161
|
* (editors show TSDoc on an object key, not on a string-literal union member), the `ErrorCode`
|
|
@@ -1021,7 +1178,7 @@ function emitErrorCodes(catalogue) {
|
|
|
1021
1178
|
"export const ErrorCodes = {",
|
|
1022
1179
|
...catalogue.codes.flatMap((entry) => {
|
|
1023
1180
|
const doc = codeDoc(entry, " ");
|
|
1024
|
-
const member = ` ${
|
|
1181
|
+
const member = ` ${propertyKey(entry.code)}: ${stringLiteral(entry.code)},`;
|
|
1025
1182
|
return doc === void 0 ? [member] : [doc, member];
|
|
1026
1183
|
}),
|
|
1027
1184
|
"} as const",
|
|
@@ -1033,7 +1190,7 @@ function emitErrorCodes(catalogue) {
|
|
|
1033
1190
|
"export type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes]"
|
|
1034
1191
|
].join("\n");
|
|
1035
1192
|
const statusLines = [...catalogue.byStatus].map(([status, codes]) => {
|
|
1036
|
-
const members = codes.map((c) =>
|
|
1193
|
+
const members = codes.map((c) => stringLiteral(c));
|
|
1037
1194
|
const line = ` ${status}: ${members.length === 0 ? "never" : members.join(" | ")}`;
|
|
1038
1195
|
return line.length <= 100 ? line : ` ${status}:\n${members.map((m) => ` | ${m}`).join("\n")}`;
|
|
1039
1196
|
});
|
|
@@ -1090,12 +1247,12 @@ function deriveProvenance(doc) {
|
|
|
1090
1247
|
}
|
|
1091
1248
|
/**
|
|
1092
1249
|
* Render the provenance record as the JSDoc header lines stamped into a generated artifact
|
|
1093
|
-
* (each already prefixed with ` * `). Deterministic: no timestamp, so re-generating from the
|
|
1250
|
+
* (each already prefixed with ` * `), with the document's text kept to one comment line. Deterministic: no timestamp, so re-generating from the
|
|
1094
1251
|
* same spec yields byte-identical output.
|
|
1095
1252
|
*/
|
|
1096
1253
|
function provenanceLines(provenance) {
|
|
1097
|
-
const lines = [` * Source spec: ${provenance.source}`, ` * Spec hash: ${provenance.hash}`];
|
|
1098
|
-
if (provenance.server !== void 0) lines.splice(1, 0, ` * Server: ${provenance.server}`);
|
|
1254
|
+
const lines = [` * Source spec: ${commentLine(provenance.source)}`, ` * Spec hash: ${provenance.hash}`];
|
|
1255
|
+
if (provenance.server !== void 0) lines.splice(1, 0, ` * Server: ${commentLine(provenance.server)}`);
|
|
1099
1256
|
return lines;
|
|
1100
1257
|
}
|
|
1101
1258
|
//#endregion
|
|
@@ -1140,17 +1297,25 @@ function isSchema(value) {
|
|
|
1140
1297
|
function pascalCase(value) {
|
|
1141
1298
|
return value.split(/[^a-zA-Z0-9]+/).filter((part) => part.length > 0).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
1142
1299
|
}
|
|
1143
|
-
/**
|
|
1144
|
-
function
|
|
1145
|
-
|
|
1146
|
-
}
|
|
1147
|
-
/** True when a string is a safe bare object-key identifier. */
|
|
1148
|
-
function isIdentifier(value) {
|
|
1149
|
-
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value);
|
|
1150
|
-
}
|
|
1151
|
-
function objectKey(value) {
|
|
1152
|
-
return isIdentifier(value) ? value : quote(value);
|
|
1300
|
+
/** The identifier stem for a wire type's interfaces, `Type`-prefixed when it would start with a digit. */
|
|
1301
|
+
function typeStem(type) {
|
|
1302
|
+
const pascal = pascalCase(type);
|
|
1303
|
+
return /^[A-Za-z]/.test(pascal) ? pascal : `Type${pascal}`;
|
|
1153
1304
|
}
|
|
1305
|
+
/** Names the generated module declares or relies on, which an enum alias must not take. */
|
|
1306
|
+
const MODULE_NAMES = [
|
|
1307
|
+
"ActionTypes",
|
|
1308
|
+
"ApiDescriptor",
|
|
1309
|
+
"Attributes",
|
|
1310
|
+
"ClientOptions",
|
|
1311
|
+
"ErrorCode",
|
|
1312
|
+
"ErrorCodeByStatus",
|
|
1313
|
+
"ErrorCodeGuard",
|
|
1314
|
+
"ErrorCodes",
|
|
1315
|
+
"Record",
|
|
1316
|
+
"ResourceMap",
|
|
1317
|
+
"WriteAttributes"
|
|
1318
|
+
];
|
|
1154
1319
|
/**
|
|
1155
1320
|
* Render a description as a JSDoc comment at the given indent — single-line when it fits,
|
|
1156
1321
|
* a block otherwise. Returns `undefined` for empty text. Neutralises any `*\/` so a
|
|
@@ -1159,7 +1324,7 @@ function objectKey(value) {
|
|
|
1159
1324
|
function jsDoc(text, indent) {
|
|
1160
1325
|
const trimmed = text?.trim();
|
|
1161
1326
|
if (!trimmed) return;
|
|
1162
|
-
const lines = trimmed
|
|
1327
|
+
const lines = commentLines(trimmed);
|
|
1163
1328
|
if (lines.length === 1) return `${indent}/** ${lines[0]} */`;
|
|
1164
1329
|
return [
|
|
1165
1330
|
`${indent}/**`,
|
|
@@ -1214,6 +1379,34 @@ function memberDoc(schema) {
|
|
|
1214
1379
|
if (tags.length === 0) return description;
|
|
1215
1380
|
return description ? `${description}\n\n${tags.join("\n")}` : tags.join("\n");
|
|
1216
1381
|
}
|
|
1382
|
+
/** An `ActionTypes` media map: `{ 'text/csv': Alias; … }`. */
|
|
1383
|
+
function mediaMap(aliases) {
|
|
1384
|
+
return `{ ${[...aliases].map(([mediaType, alias]) => `${stringLiteral(mediaType)}: ${alias}`).join("; ")} }`;
|
|
1385
|
+
}
|
|
1386
|
+
/** The schema of `mediaType` under an operation's first 2xx response that lists it. */
|
|
1387
|
+
function firstSuccessSchema(op, mediaType) {
|
|
1388
|
+
for (const [code, response] of Object.entries(op?.responses ?? {})) {
|
|
1389
|
+
const media = code.startsWith("2") ? response.content?.[mediaType] : void 0;
|
|
1390
|
+
if (media !== void 0) return media.schema;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* An action's summary and description as JSDoc, leaving out the prose the projector writes for an
|
|
1395
|
+
* action whose author gave none ("Invoke the `name` action", "Invokes the `name` custom action on
|
|
1396
|
+
* …"), which says nothing the name doesn't.
|
|
1397
|
+
*/
|
|
1398
|
+
function actionDoc(name, op) {
|
|
1399
|
+
const summary = op?.summary?.trim();
|
|
1400
|
+
const description = op?.description?.trim();
|
|
1401
|
+
const parts = [];
|
|
1402
|
+
if (summary && summary !== `Invoke the \`${name}\` action`) parts.push(summary);
|
|
1403
|
+
const generated = new RegExp(`^Invokes the \`${escapeRegExp(name)}\` custom action on [^.]*\\.$`);
|
|
1404
|
+
if (description && !generated.test(description)) parts.push(description);
|
|
1405
|
+
return parts.length === 0 ? void 0 : parts.join("\n\n");
|
|
1406
|
+
}
|
|
1407
|
+
function escapeRegExp(value) {
|
|
1408
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1409
|
+
}
|
|
1217
1410
|
var Emitter = class {
|
|
1218
1411
|
descriptor;
|
|
1219
1412
|
atomic;
|
|
@@ -1229,6 +1422,10 @@ var Emitter = class {
|
|
|
1229
1422
|
* already-named attribute type. Populated as interfaces are emitted.
|
|
1230
1423
|
*/
|
|
1231
1424
|
emittedInterfaces = /* @__PURE__ */ new Set();
|
|
1425
|
+
/** Enum component name -> the alias name it's emitted under. */
|
|
1426
|
+
enumNames = /* @__PURE__ */ new Map();
|
|
1427
|
+
/** Type names already spoken for: the module's own, the per-type interfaces and enum aliases. */
|
|
1428
|
+
takenNames;
|
|
1232
1429
|
/** Component names mid-expansion in {@link tsType} — a cycle guard for self/mutually-referential `$ref`s. */
|
|
1233
1430
|
expanding = /* @__PURE__ */ new Set();
|
|
1234
1431
|
/**
|
|
@@ -1237,6 +1434,10 @@ var Emitter = class {
|
|
|
1237
1434
|
* type-map only references aliases that exist (a `none` input/output contributes neither).
|
|
1238
1435
|
*/
|
|
1239
1436
|
actionAliasNames = /* @__PURE__ */ new Map();
|
|
1437
|
+
/** Raw body components already emitted as a named alias, by component name. */
|
|
1438
|
+
rawBodyAliases = /* @__PURE__ */ new Map();
|
|
1439
|
+
/** JSDoc for entries of the `resourceMap` literal, keyed by their path joined with `/`. */
|
|
1440
|
+
literalDocs = /* @__PURE__ */ new Map();
|
|
1240
1441
|
/** Provenance of the source document, stamped into the generated header for drift tracking. */
|
|
1241
1442
|
provenance;
|
|
1242
1443
|
doc;
|
|
@@ -1247,6 +1448,50 @@ var Emitter = class {
|
|
|
1247
1448
|
this.schemas = this.doc.components?.schemas ?? {};
|
|
1248
1449
|
this.baseByType = this.indexBases();
|
|
1249
1450
|
this.provenance = deriveProvenance(source);
|
|
1451
|
+
this.takenNames = new Set(MODULE_NAMES);
|
|
1452
|
+
for (const type of Object.keys(descriptor)) {
|
|
1453
|
+
const stem = typeStem(type);
|
|
1454
|
+
for (const suffix of [
|
|
1455
|
+
"Attributes",
|
|
1456
|
+
"CreateAttributes",
|
|
1457
|
+
"UpdateAttributes"
|
|
1458
|
+
]) this.takenNames.add(`${stem}${suffix}`);
|
|
1459
|
+
for (const [name, action] of Object.entries(descriptor[type]?.actions ?? {})) {
|
|
1460
|
+
this.takenNames.add(`${stem}${pascalCase(name)}Input`);
|
|
1461
|
+
this.takenNames.add(`${stem}${pascalCase(name)}Output`);
|
|
1462
|
+
for (const { mediaType } of action.rawOutput ?? []) this.takenNames.add(`${stem}${pascalCase(name)}${pascalCase(mediaType)}Output`);
|
|
1463
|
+
for (const { mediaType } of action.inputMedia ?? []) this.takenNames.add(`${stem}${pascalCase(name)}${pascalCase(mediaType)}Input`);
|
|
1464
|
+
const single = action.contentType;
|
|
1465
|
+
if (single !== void 0 && (single.startsWith("multipart/") || single === "application/x-www-form-urlencoded")) this.takenNames.add(`${stem}${pascalCase(name)}${pascalCase(single)}Input`);
|
|
1466
|
+
const doc = actionDoc(name, this.actionOperation(action));
|
|
1467
|
+
if (doc !== void 0) this.literalDocs.set(`${type}/actions/${name}`, doc);
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
/** The operation an action is invoked over: its declared method, else `POST`. */
|
|
1472
|
+
actionOperation(action) {
|
|
1473
|
+
const method = (action.method ?? "POST").toLowerCase();
|
|
1474
|
+
return this.doc.paths?.[action.path]?.[method];
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* The alias an enum component is emitted under: its own name when that's a usable type name,
|
|
1478
|
+
* else one derived from it (with a warning), kept clear of every other name in the module.
|
|
1479
|
+
*/
|
|
1480
|
+
enumName(component) {
|
|
1481
|
+
const known = this.enumNames.get(component);
|
|
1482
|
+
if (known !== void 0) return known;
|
|
1483
|
+
let name = component;
|
|
1484
|
+
if (!isTypeName(component) || this.takenNames.has(component)) {
|
|
1485
|
+
const pascal = pascalCase(component);
|
|
1486
|
+
let stem = /^[A-Za-z]/.test(pascal) ? pascal : `Enum${pascal}`;
|
|
1487
|
+
if (!isTypeName(stem) || this.takenNames.has(stem)) stem = `${stem}Enum`;
|
|
1488
|
+
name = stem;
|
|
1489
|
+
for (let n = 2; this.takenNames.has(name); n++) name = `${stem}${n}`;
|
|
1490
|
+
console.warn(`Enum component ${stringLiteral(component)} can't be used as a TypeScript type name; emitting it as ${name}.`);
|
|
1491
|
+
}
|
|
1492
|
+
this.takenNames.add(name);
|
|
1493
|
+
this.enumNames.set(component, name);
|
|
1494
|
+
return name;
|
|
1250
1495
|
}
|
|
1251
1496
|
/** Map each declared wire type back to the `Base` of its resource schema. */
|
|
1252
1497
|
indexBases() {
|
|
@@ -1307,7 +1552,7 @@ var Emitter = class {
|
|
|
1307
1552
|
const base = this.baseByType.get(type);
|
|
1308
1553
|
const props = base ? this.schemas[`${base}Attributes`]?.properties : void 0;
|
|
1309
1554
|
const fields = Object.keys(this.descriptor[type].attributes);
|
|
1310
|
-
return this.renderInterface(`${
|
|
1555
|
+
return this.renderInterface(`${typeStem(type)}Attributes`, props, fields, () => true);
|
|
1311
1556
|
}
|
|
1312
1557
|
/**
|
|
1313
1558
|
* The per-type WRITE attribute interfaces — `<Pascal>CreateAttributes` and
|
|
@@ -1319,7 +1564,7 @@ var Emitter = class {
|
|
|
1319
1564
|
writeAttributeInterfaces(type) {
|
|
1320
1565
|
const base = this.baseByType.get(type);
|
|
1321
1566
|
if (base === void 0) return [];
|
|
1322
|
-
const pascal =
|
|
1567
|
+
const pascal = typeStem(type);
|
|
1323
1568
|
const out = [];
|
|
1324
1569
|
const create = this.schemas[`${base}CreateAttributes`];
|
|
1325
1570
|
if (create !== void 0) {
|
|
@@ -1346,7 +1591,7 @@ var Emitter = class {
|
|
|
1346
1591
|
for (const type of Object.keys(this.descriptor)) {
|
|
1347
1592
|
const actions = this.descriptor[type]?.actions;
|
|
1348
1593
|
if (actions === void 0) continue;
|
|
1349
|
-
const pascal =
|
|
1594
|
+
const pascal = typeStem(type);
|
|
1350
1595
|
for (const [actionName, action] of Object.entries(actions)) {
|
|
1351
1596
|
const member = `${pascal}${pascalCase(actionName)}`;
|
|
1352
1597
|
const names = {};
|
|
@@ -1360,7 +1605,35 @@ var Emitter = class {
|
|
|
1360
1605
|
out.push(`export type ${member}Output = ${outputType}`);
|
|
1361
1606
|
names.output = `${member}Output`;
|
|
1362
1607
|
}
|
|
1363
|
-
|
|
1608
|
+
const op = this.actionOperation(action);
|
|
1609
|
+
for (const { mediaType, kind } of action.rawOutput ?? []) if (kind === "json") {
|
|
1610
|
+
const schema = firstSuccessSchema(op, mediaType);
|
|
1611
|
+
names.responses ??= /* @__PURE__ */ new Map();
|
|
1612
|
+
names.responses.set(mediaType, this.rawBodyAlias(schema, `${member}${pascalCase(mediaType)}Output`, out));
|
|
1613
|
+
}
|
|
1614
|
+
const singleKind = !(action.input === "raw" && action.inputMedia === void 0) ? void 0 : action.contentType?.startsWith("multipart/") === true ? "multipart" : action.contentType === "application/x-www-form-urlencoded" ? "form" : void 0;
|
|
1615
|
+
const listed = action.inputMedia ?? (singleKind === void 0 || action.contentType === void 0 ? [] : [{
|
|
1616
|
+
mediaType: action.contentType,
|
|
1617
|
+
kind: singleKind
|
|
1618
|
+
}]);
|
|
1619
|
+
for (const { mediaType, kind } of listed) {
|
|
1620
|
+
const schema = op?.requestBody?.content?.[mediaType]?.schema;
|
|
1621
|
+
if (kind === "json") {
|
|
1622
|
+
names.requests ??= /* @__PURE__ */ new Map();
|
|
1623
|
+
names.requests.set(mediaType, this.rawBodyAlias(schema, `${member}${pascalCase(mediaType)}Input`, out));
|
|
1624
|
+
} else if (kind === "multipart" || kind === "form") {
|
|
1625
|
+
const fields = this.formFieldsType(schema, kind);
|
|
1626
|
+
if (fields !== void 0) {
|
|
1627
|
+
const alias = `${member}${pascalCase(mediaType)}Input`;
|
|
1628
|
+
const doc = schema === void 0 ? void 0 : jsDoc(schema.description, "");
|
|
1629
|
+
const declaration = `export type ${alias} = ${fields}`;
|
|
1630
|
+
out.push(doc === void 0 ? declaration : `${doc}\n${declaration}`);
|
|
1631
|
+
names.requests ??= /* @__PURE__ */ new Map();
|
|
1632
|
+
names.requests.set(mediaType, alias);
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
if (names.input !== void 0 || names.output !== void 0 || names.responses !== void 0 || names.requests !== void 0) {
|
|
1364
1637
|
let byAction = this.actionAliasNames.get(type);
|
|
1365
1638
|
if (byAction === void 0) {
|
|
1366
1639
|
byAction = /* @__PURE__ */ new Map();
|
|
@@ -1373,6 +1646,83 @@ var Emitter = class {
|
|
|
1373
1646
|
return out;
|
|
1374
1647
|
}
|
|
1375
1648
|
/**
|
|
1649
|
+
* The alias a JSON-like raw body is typed by. A `$ref` to a component is emitted once under the
|
|
1650
|
+
* component's own name when that name is free; anything else gets `fallback`. The alias source
|
|
1651
|
+
* is pushed onto `out` the first time.
|
|
1652
|
+
*/
|
|
1653
|
+
rawBodyAlias(schema, fallback, out) {
|
|
1654
|
+
const target = typeof schema?.$ref === "string" ? refName(schema.$ref) : void 0;
|
|
1655
|
+
const resolved = target === void 0 ? void 0 : this.schemas[target];
|
|
1656
|
+
if (target !== void 0 && resolved !== void 0) {
|
|
1657
|
+
const known = this.rawBodyAliases.get(target);
|
|
1658
|
+
if (known !== void 0) return known;
|
|
1659
|
+
if (isTypeName(target) && !this.takenNames.has(target) && !Array.isArray(resolved.enum)) {
|
|
1660
|
+
this.takenNames.add(target);
|
|
1661
|
+
this.rawBodyAliases.set(target, target);
|
|
1662
|
+
out.push(this.rawBodyDeclaration(target, resolved));
|
|
1663
|
+
this.emittedInterfaces.add(target);
|
|
1664
|
+
return target;
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
out.push(this.rawBodyDeclaration(fallback, schema));
|
|
1668
|
+
return fallback;
|
|
1669
|
+
}
|
|
1670
|
+
/**
|
|
1671
|
+
* The typed fields of a multipart or URL-encoded request body whose object schema lists
|
|
1672
|
+
* `properties`, which the client encodes into a `FormData` or `URLSearchParams`. `undefined`
|
|
1673
|
+
* when the schema lists none, so the body stays a raw `FormData` or `URLSearchParams`.
|
|
1674
|
+
*/
|
|
1675
|
+
formFieldsType(schema, kind) {
|
|
1676
|
+
let target = schema;
|
|
1677
|
+
if (typeof target?.$ref === "string") target = this.schemas[refName(target.$ref) ?? ""];
|
|
1678
|
+
const props = target?.properties;
|
|
1679
|
+
if (target === void 0 || props === void 0) return;
|
|
1680
|
+
const required = new Set(target.required ?? []);
|
|
1681
|
+
const members = [];
|
|
1682
|
+
const valueTypes = [];
|
|
1683
|
+
for (const [name, prop] of Object.entries(props)) {
|
|
1684
|
+
if (!isSchema(prop)) continue;
|
|
1685
|
+
const type = this.formFieldType(prop, kind);
|
|
1686
|
+
valueTypes.push(type);
|
|
1687
|
+
members.push(`${propertyKey(name)}${required.has(name) ? "" : "?"}: ${type}`);
|
|
1688
|
+
}
|
|
1689
|
+
if (members.length === 0) return;
|
|
1690
|
+
const extra = target["additionalProperties"];
|
|
1691
|
+
if (extra === true || isSchema(extra)) {
|
|
1692
|
+
const additional = isSchema(extra) ? this.formFieldType(extra, kind) : this.formFieldType({}, kind);
|
|
1693
|
+
const all = [...new Set([...valueTypes, additional].flatMap((type) => type.split(" | ")))];
|
|
1694
|
+
members.push(`[field: string]: ${all.join(" | ")} | undefined`);
|
|
1695
|
+
}
|
|
1696
|
+
return `{ ${members.join("; ")} }`;
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* One form field's type: `Blob | File` for a binary part of a multipart body, an array of
|
|
1700
|
+
* its item type for an array, else the scalar's own type. A field with no usable type takes
|
|
1701
|
+
* any scalar a form can carry.
|
|
1702
|
+
*/
|
|
1703
|
+
formFieldType(schema, kind) {
|
|
1704
|
+
const any = kind === "multipart" ? "string | number | boolean | Blob" : "string | number | boolean";
|
|
1705
|
+
let target = schema;
|
|
1706
|
+
if (typeof target.$ref === "string") {
|
|
1707
|
+
const resolved = this.schemas[refName(target.$ref) ?? ""];
|
|
1708
|
+
if (resolved !== void 0 && !Array.isArray(resolved.enum)) target = resolved;
|
|
1709
|
+
}
|
|
1710
|
+
if (kind === "multipart" && target.format === "binary") return "Blob | File";
|
|
1711
|
+
if (target.type === "array") {
|
|
1712
|
+
const item = target.items === void 0 ? any : this.formFieldType(target.items, kind);
|
|
1713
|
+
return item.includes(" ") ? `(${item})[]` : `${item}[]`;
|
|
1714
|
+
}
|
|
1715
|
+
const type = this.tsType(target);
|
|
1716
|
+
return type === "unknown" || type.includes("{") || type.startsWith("Record<") ? any : type;
|
|
1717
|
+
}
|
|
1718
|
+
/** `export type Name = …` for a raw body schema, with its description as JSDoc. */
|
|
1719
|
+
rawBodyDeclaration(name, schema) {
|
|
1720
|
+
const type = schema === void 0 ? "unknown" : this.tsType(schema);
|
|
1721
|
+
const doc = schema === void 0 ? void 0 : jsDoc(schema.description, "");
|
|
1722
|
+
const declaration = `export type ${name} = ${type}`;
|
|
1723
|
+
return doc === void 0 ? declaration : `${doc}\n${declaration}`;
|
|
1724
|
+
}
|
|
1725
|
+
/**
|
|
1376
1726
|
* Emit the `ActionTypes` interface wiring the emitted per-action aliases onto the typed
|
|
1377
1727
|
* action surface — `type -> actionName -> { input?; output? }`, the client's fourth type
|
|
1378
1728
|
* argument. So `client.albums.id(id).actions.reissue(body)` takes `AlbumsReissueInput` and
|
|
@@ -1390,9 +1740,11 @@ var Emitter = class {
|
|
|
1390
1740
|
const members = [];
|
|
1391
1741
|
if (names.input !== void 0) members.push(`input: ${names.input}`);
|
|
1392
1742
|
if (names.output !== void 0) members.push(`output: ${names.output}`);
|
|
1393
|
-
|
|
1743
|
+
if (names.responses !== void 0) members.push(`responses: ${mediaMap(names.responses)}`);
|
|
1744
|
+
if (names.requests !== void 0) members.push(`requests: ${mediaMap(names.requests)}`);
|
|
1745
|
+
actionLines.push(` ${propertyKey(actionName)}: { ${members.join("; ")} }`);
|
|
1394
1746
|
}
|
|
1395
|
-
typeLines.push(` ${
|
|
1747
|
+
typeLines.push(` ${propertyKey(type)}: {\n${actionLines.join("\n")}\n }`);
|
|
1396
1748
|
}
|
|
1397
1749
|
if (typeLines.length === 0) return "export interface ActionTypes {}";
|
|
1398
1750
|
return `export interface ActionTypes {\n${typeLines.join("\n")}\n}`;
|
|
@@ -1440,10 +1792,10 @@ var Emitter = class {
|
|
|
1440
1792
|
if (schema.oneOf !== void 0) for (const arm of schema.oneOf) {
|
|
1441
1793
|
const kind = isSchema(arm.properties?.["kind"]) ? arm.properties["kind"].const : void 0;
|
|
1442
1794
|
const members = this.pageMemberLimits(arm, " ");
|
|
1443
|
-
if (typeof kind === "string" && members.length > 0) body.push(` ${
|
|
1795
|
+
if (typeof kind === "string" && members.length > 0) body.push(` ${propertyKey(kind)}: {\n${members.join("\n")}\n },`);
|
|
1444
1796
|
}
|
|
1445
1797
|
else body = this.pageMemberLimits(schema, " ");
|
|
1446
|
-
if (body.length > 0) typeLines.push(` ${
|
|
1798
|
+
if (body.length > 0) typeLines.push(` ${propertyKey(type)}: {\n${body.join("\n")}\n },`);
|
|
1447
1799
|
}
|
|
1448
1800
|
return `${[
|
|
1449
1801
|
"/**",
|
|
@@ -1468,7 +1820,7 @@ var Emitter = class {
|
|
|
1468
1820
|
if (limits.length === 0) continue;
|
|
1469
1821
|
const doc = jsDoc(memberDoc(prop), indent);
|
|
1470
1822
|
if (doc !== void 0) lines.push(doc);
|
|
1471
|
-
lines.push(`${indent}${
|
|
1823
|
+
lines.push(`${indent}${propertyKey(name)}: { ${limits.join(", ")} },`);
|
|
1472
1824
|
}
|
|
1473
1825
|
return lines;
|
|
1474
1826
|
}
|
|
@@ -1485,7 +1837,7 @@ var Emitter = class {
|
|
|
1485
1837
|
const doc = isSchema(schema) ? jsDoc(memberDoc(schema), " ") : void 0;
|
|
1486
1838
|
if (doc) lines.push(doc);
|
|
1487
1839
|
const optional = required(field) ? "" : "?";
|
|
1488
|
-
lines.push(` ${
|
|
1840
|
+
lines.push(` ${propertyKey(field)}${optional}: ${tsType}`);
|
|
1489
1841
|
}
|
|
1490
1842
|
this.emittedInterfaces.add(name);
|
|
1491
1843
|
if (lines.length === 0) return `export interface ${name} {}`;
|
|
@@ -1498,7 +1850,7 @@ var Emitter = class {
|
|
|
1498
1850
|
const resolved = target ? this.schemas[target] : void 0;
|
|
1499
1851
|
if (target && resolved && Array.isArray(resolved.enum)) {
|
|
1500
1852
|
this.usedEnums.set(target, resolved);
|
|
1501
|
-
return target;
|
|
1853
|
+
return this.enumName(target);
|
|
1502
1854
|
}
|
|
1503
1855
|
if (target && this.emittedInterfaces.has(target)) return target;
|
|
1504
1856
|
if (resolved === void 0 || target === void 0 || this.expanding.has(target)) return "unknown";
|
|
@@ -1523,7 +1875,7 @@ var Emitter = class {
|
|
|
1523
1875
|
}
|
|
1524
1876
|
/** The non-nullable TS type for the declared JSON type(s). */
|
|
1525
1877
|
baseTsType(schema, types) {
|
|
1526
|
-
if (Array.isArray(schema.enum) && schema.enum.length > 0) return schema.enum.map((value) =>
|
|
1878
|
+
if (Array.isArray(schema.enum) && schema.enum.length > 0) return schema.enum.map((value) => stringLiteral(String(value))).join(" | ");
|
|
1527
1879
|
if (types.length === 0) return "unknown";
|
|
1528
1880
|
const mapped = types.map((t) => this.scalarOrComposite(schema, t));
|
|
1529
1881
|
return [...new Set(mapped)].join(" | ");
|
|
@@ -1548,7 +1900,7 @@ var Emitter = class {
|
|
|
1548
1900
|
for (const [name, prop] of Object.entries(props)) {
|
|
1549
1901
|
if (!isSchema(prop)) continue;
|
|
1550
1902
|
const optional = required.has(name) ? "" : "?";
|
|
1551
|
-
members.push(`${
|
|
1903
|
+
members.push(`${propertyKey(name)}${optional}: ${this.tsType(prop)}`);
|
|
1552
1904
|
}
|
|
1553
1905
|
if (members.length === 0) return "Record<string, unknown>";
|
|
1554
1906
|
return `{ ${members.join("; ")} }`;
|
|
@@ -1565,7 +1917,8 @@ var Emitter = class {
|
|
|
1565
1917
|
if (this.usedEnums.size === 0) return;
|
|
1566
1918
|
return [...this.usedEnums.keys()].sort().map((name) => {
|
|
1567
1919
|
const schema = this.usedEnums.get(name);
|
|
1568
|
-
const
|
|
1920
|
+
const union = (schema.enum ?? []).map((value) => stringLiteral(String(value))).join(" | ");
|
|
1921
|
+
const alias = `export type ${this.enumName(name)} = ${union}`;
|
|
1569
1922
|
const doc = jsDoc(this.enumDoc(schema), "");
|
|
1570
1923
|
return doc ? `${doc}\n${alias}` : alias;
|
|
1571
1924
|
}).join("\n\n");
|
|
@@ -1588,7 +1941,7 @@ var Emitter = class {
|
|
|
1588
1941
|
* argument to the runtime factory).
|
|
1589
1942
|
*/
|
|
1590
1943
|
attributesMap() {
|
|
1591
|
-
return `export interface Attributes {\n${Object.keys(this.descriptor).map((type) => ` ${
|
|
1944
|
+
return `export interface Attributes {\n${Object.keys(this.descriptor).map((type) => ` ${propertyKey(type)}: ${typeStem(type)}Attributes`).join("\n")}\n}`;
|
|
1592
1945
|
}
|
|
1593
1946
|
/**
|
|
1594
1947
|
* Emit the `WriteAttributes` interface mapping each writable wire type to its
|
|
@@ -1603,21 +1956,21 @@ var Emitter = class {
|
|
|
1603
1956
|
const hasCreate = base !== void 0 && this.schemas[`${base}CreateAttributes`] !== void 0;
|
|
1604
1957
|
const hasUpdate = base !== void 0 && this.schemas[`${base}UpdateAttributes`] !== void 0;
|
|
1605
1958
|
if (!hasCreate && !hasUpdate) continue;
|
|
1606
|
-
const pascal =
|
|
1959
|
+
const pascal = typeStem(type);
|
|
1607
1960
|
const members = [];
|
|
1608
1961
|
if (hasCreate) members.push(`create: ${pascal}CreateAttributes`);
|
|
1609
1962
|
if (hasUpdate) members.push(`update: ${pascal}UpdateAttributes`);
|
|
1610
|
-
lines.push(` ${
|
|
1963
|
+
lines.push(` ${propertyKey(type)}: { ${members.join("; ")} }`);
|
|
1611
1964
|
}
|
|
1612
1965
|
if (lines.length === 0) return "export interface WriteAttributes {}";
|
|
1613
1966
|
return `export interface WriteAttributes {\n${lines.join("\n")}\n}`;
|
|
1614
1967
|
}
|
|
1615
1968
|
/** Emit the descriptor as a literal `as const satisfies ApiDescriptor`. */
|
|
1616
1969
|
resourceMap() {
|
|
1617
|
-
return `export const resourceMap = ${this.literal(this.descriptor, 0)} as const satisfies ApiDescriptor`;
|
|
1970
|
+
return `export const resourceMap = ${this.literal(this.descriptor, 0, "")} as const satisfies ApiDescriptor`;
|
|
1618
1971
|
}
|
|
1619
1972
|
/** Render a JSON-serialisable descriptor value as deterministic TS object-literal source. */
|
|
1620
|
-
literal(value, depth) {
|
|
1973
|
+
literal(value, depth, path) {
|
|
1621
1974
|
const indent = " ".repeat(depth);
|
|
1622
1975
|
const inner = " ".repeat(depth + 1);
|
|
1623
1976
|
if (Array.isArray(value)) {
|
|
@@ -1627,9 +1980,14 @@ var Emitter = class {
|
|
|
1627
1980
|
if (value !== null && typeof value === "object") {
|
|
1628
1981
|
const entries = Object.entries(value);
|
|
1629
1982
|
if (entries.length === 0) return "{}";
|
|
1630
|
-
return `{\n${entries.map(([key, v]) =>
|
|
1983
|
+
return `{\n${entries.map(([key, v]) => {
|
|
1984
|
+
const childPath = path === void 0 ? void 0 : path === "" ? key : `${path}/${key}`;
|
|
1985
|
+
const line = `${inner}${propertyKey(key)}: ${this.literal(v, depth + 1, childPath)}`;
|
|
1986
|
+
const doc = childPath === void 0 ? void 0 : this.literalDocs.get(childPath);
|
|
1987
|
+
return doc === void 0 ? line : `${jsDoc(doc, inner)}\n${line}`;
|
|
1988
|
+
}).join(",\n")}\n${indent}}`;
|
|
1631
1989
|
}
|
|
1632
|
-
return JSON.stringify(value);
|
|
1990
|
+
return typeof value === "string" ? stringLiteral(value) : JSON.stringify(value);
|
|
1633
1991
|
}
|
|
1634
1992
|
boundFactory() {
|
|
1635
1993
|
return [
|
|
@@ -1688,7 +2046,7 @@ function header(bundle) {
|
|
|
1688
2046
|
].join("\n");
|
|
1689
2047
|
}
|
|
1690
2048
|
function body(bundle) {
|
|
1691
|
-
return `export const schemas = ${JSON.stringify(bundle, null, 2)} as const`;
|
|
2049
|
+
return `export const schemas = ${JSON.stringify(bundle, null, 2).replace(/^(\s*)"__proto__":/gm, "$1[\"__proto__\"]:").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029")} as const`;
|
|
1692
2050
|
}
|
|
1693
2051
|
//#endregion
|
|
1694
2052
|
//#region src/reader.ts
|
|
@@ -1832,4 +2190,4 @@ async function check(config) {
|
|
|
1832
2190
|
//#endregion
|
|
1833
2191
|
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 };
|
|
1834
2192
|
|
|
1835
|
-
//# sourceMappingURL=src-
|
|
2193
|
+
//# sourceMappingURL=src-DhZyiWge.mjs.map
|