@kubb/adapter-oas 5.0.0-beta.93 → 5.0.0-beta.95
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/index.cjs +663 -671
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +9 -21
- package/dist/index.js +664 -672
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -28,8 +28,8 @@ node_path = __toESM(node_path, 1);
|
|
|
28
28
|
let node_fs_promises = require("node:fs/promises");
|
|
29
29
|
let _readme_openapi_parser = require("@readme/openapi-parser");
|
|
30
30
|
let _scalar_openapi_upgrader = require("@scalar/openapi-upgrader");
|
|
31
|
-
let yaml = require("yaml");
|
|
32
31
|
let api_ref_bundler = require("api-ref-bundler");
|
|
32
|
+
let yaml = require("yaml");
|
|
33
33
|
//#region src/constants.ts
|
|
34
34
|
/**
|
|
35
35
|
* Default parser options applied when no explicit options are provided.
|
|
@@ -367,7 +367,7 @@ async function read(path) {
|
|
|
367
367
|
return (0, node_fs_promises.readFile)(path, { encoding: "utf8" });
|
|
368
368
|
}
|
|
369
369
|
//#endregion
|
|
370
|
-
//#region src/
|
|
370
|
+
//#region src/factory.ts
|
|
371
371
|
const urlRegExp = /^https?:\/+/i;
|
|
372
372
|
async function readSource(sourcePath) {
|
|
373
373
|
if (urlRegExp.test(sourcePath)) {
|
|
@@ -410,8 +410,6 @@ async function bundleDocument(pathOrUrl) {
|
|
|
410
410
|
await resolver(pathOrUrl);
|
|
411
411
|
return await (0, api_ref_bundler.bundle)(pathOrUrl, resolver);
|
|
412
412
|
}
|
|
413
|
-
//#endregion
|
|
414
|
-
//#region src/factory.ts
|
|
415
413
|
/**
|
|
416
414
|
* Loads and bundles an OpenAPI document, returning the raw `Document`.
|
|
417
415
|
*
|
|
@@ -481,19 +479,12 @@ async function validateDocument(document, { throwOnError = false } = {}) {
|
|
|
481
479
|
}
|
|
482
480
|
}
|
|
483
481
|
//#endregion
|
|
484
|
-
//#region src/
|
|
482
|
+
//#region src/oas.ts
|
|
485
483
|
/**
|
|
486
484
|
* Returns `true` when a schema should be treated as nullable.
|
|
487
485
|
*
|
|
488
486
|
* Recognizes all nullable signals across OAS versions: `nullable: true` (OAS 3.0),
|
|
489
487
|
* `x-nullable: true` (vendor extension), `type: 'null'`, and `type: ['null', ...]` (OAS 3.1).
|
|
490
|
-
*
|
|
491
|
-
* @example
|
|
492
|
-
* ```ts
|
|
493
|
-
* isNullable({ type: 'string', nullable: true }) // true
|
|
494
|
-
* isNullable({ type: ['string', 'null'] }) // true
|
|
495
|
-
* isNullable({ type: 'string' }) // false
|
|
496
|
-
* ```
|
|
497
488
|
*/
|
|
498
489
|
function isNullable(schema) {
|
|
499
490
|
if ((schema?.nullable ?? schema?.["x-nullable"]) === true) return true;
|
|
@@ -504,24 +495,13 @@ function isNullable(schema) {
|
|
|
504
495
|
}
|
|
505
496
|
/**
|
|
506
497
|
* Returns `true` when `obj` is an OpenAPI `$ref` pointer object.
|
|
507
|
-
*
|
|
508
|
-
* @example
|
|
509
|
-
* ```ts
|
|
510
|
-
* isReference({ $ref: '#/components/schemas/Pet' }) // true
|
|
511
|
-
* isReference({ type: 'string' }) // false
|
|
512
|
-
* ```
|
|
513
498
|
*/
|
|
514
499
|
function isReference(obj) {
|
|
515
500
|
return !!obj && typeof obj === "object" && "$ref" in obj;
|
|
516
501
|
}
|
|
517
502
|
/**
|
|
518
|
-
* Returns `true` when `obj` is a schema with a structured OAS 3.x `discriminator` object
|
|
519
|
-
*
|
|
520
|
-
* @example
|
|
521
|
-
* ```ts
|
|
522
|
-
* isDiscriminator({ discriminator: { propertyName: 'type', mapping: {} } }) // true
|
|
523
|
-
* isDiscriminator({ discriminator: 'type' }) // false (Swagger 2 string form)
|
|
524
|
-
* ```
|
|
503
|
+
* Returns `true` when `obj` is a schema with a structured OAS 3.x `discriminator` object,
|
|
504
|
+
* excluding the Swagger 2 string form.
|
|
525
505
|
*/
|
|
526
506
|
function isDiscriminator(obj) {
|
|
527
507
|
const record = obj;
|
|
@@ -529,18 +509,10 @@ function isDiscriminator(obj) {
|
|
|
529
509
|
}
|
|
530
510
|
/**
|
|
531
511
|
* Returns `true` when a schema is a binary payload: an octet-stream string body.
|
|
532
|
-
*
|
|
533
|
-
* @example
|
|
534
|
-
* ```ts
|
|
535
|
-
* isBinary({ type: 'string', contentMediaType: 'application/octet-stream' }) // true
|
|
536
|
-
* isBinary({ type: 'string' }) // false
|
|
537
|
-
* ```
|
|
538
512
|
*/
|
|
539
513
|
function isBinary(schema) {
|
|
540
514
|
return schema.type === "string" && schema.contentMediaType === "application/octet-stream";
|
|
541
515
|
}
|
|
542
|
-
//#endregion
|
|
543
|
-
//#region src/mime.ts
|
|
544
516
|
/**
|
|
545
517
|
* MIME type fragments that mark a media type as JSON-like.
|
|
546
518
|
*
|
|
@@ -633,6 +605,23 @@ function dereferenceWithRef(document, schema) {
|
|
|
633
605
|
};
|
|
634
606
|
return schema;
|
|
635
607
|
}
|
|
608
|
+
/**
|
|
609
|
+
* Resolves a `$ref` slot in place: when `container[key]` holds a `$ref`, replaces it with the
|
|
610
|
+
* resolved value and returns that value. Returns `null` when the slot is empty, cannot be resolved,
|
|
611
|
+
* or is still a `$ref` after resolving. A non-`$ref` value is returned untouched, without writing.
|
|
612
|
+
*
|
|
613
|
+
* @example
|
|
614
|
+
* ```ts
|
|
615
|
+
* derefInPlace<ResponseObject>({ document, container: operation.schema.responses, key: '200' })
|
|
616
|
+
* ```
|
|
617
|
+
*/
|
|
618
|
+
function derefInPlace({ document, container, key }) {
|
|
619
|
+
const value = container[key];
|
|
620
|
+
if (!isReference(value)) return value ? value : null;
|
|
621
|
+
const resolved = resolveRef(document, value.$ref);
|
|
622
|
+
container[key] = resolved;
|
|
623
|
+
return resolved && !isReference(resolved) ? resolved : null;
|
|
624
|
+
}
|
|
636
625
|
//#endregion
|
|
637
626
|
//#region src/operation.ts
|
|
638
627
|
/**
|
|
@@ -664,31 +653,22 @@ function getResponseStatusCodes({ schema }) {
|
|
|
664
653
|
function getResponseByStatusCode({ document, operation, statusCode }) {
|
|
665
654
|
const responses = operation.schema.responses;
|
|
666
655
|
if (!responses || isReference(responses)) return false;
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
if (!resolved || isReference(resolved)) return false;
|
|
673
|
-
return resolved;
|
|
674
|
-
}
|
|
675
|
-
return response;
|
|
656
|
+
return derefInPlace({
|
|
657
|
+
document,
|
|
658
|
+
container: responses,
|
|
659
|
+
key: statusCode
|
|
660
|
+
}) ?? false;
|
|
676
661
|
}
|
|
677
662
|
/**
|
|
678
663
|
* Resolves the request body (dereferencing a `$ref` in place) and returns its content map, or
|
|
679
664
|
* `undefined` when the operation has no request body.
|
|
680
665
|
*/
|
|
681
666
|
function getRequestBodyContent({ document, operation }) {
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
schema.requestBody = resolved;
|
|
688
|
-
if (!resolved || isReference(resolved)) return;
|
|
689
|
-
requestBody = resolved;
|
|
690
|
-
}
|
|
691
|
-
return requestBody.content;
|
|
667
|
+
return derefInPlace({
|
|
668
|
+
document,
|
|
669
|
+
container: operation.schema,
|
|
670
|
+
key: "requestBody"
|
|
671
|
+
})?.content;
|
|
692
672
|
}
|
|
693
673
|
/**
|
|
694
674
|
* Returns the request body media type. With `mediaType` set, returns that entry or `false`.
|
|
@@ -737,14 +717,12 @@ function getOperations(document) {
|
|
|
737
717
|
if (!paths) return operations;
|
|
738
718
|
for (const path of Object.keys(paths)) {
|
|
739
719
|
if (path.startsWith("x-")) continue;
|
|
740
|
-
|
|
720
|
+
const pathItem = derefInPlace({
|
|
721
|
+
document,
|
|
722
|
+
container: paths,
|
|
723
|
+
key: path
|
|
724
|
+
});
|
|
741
725
|
if (!pathItem) continue;
|
|
742
|
-
if (isReference(pathItem)) {
|
|
743
|
-
const resolved = resolveRef(document, pathItem.$ref);
|
|
744
|
-
paths[path] = resolved;
|
|
745
|
-
if (!resolved || isReference(resolved)) continue;
|
|
746
|
-
pathItem = resolved;
|
|
747
|
-
}
|
|
748
726
|
const item = pathItem;
|
|
749
727
|
for (const method of Object.keys(item)) {
|
|
750
728
|
if (!SUPPORTED_METHODS.has(method)) continue;
|
|
@@ -872,6 +850,15 @@ function getResponseBody(responseBody, contentType) {
|
|
|
872
850
|
if (!availableContentType) return false;
|
|
873
851
|
return body.content[availableContentType];
|
|
874
852
|
}
|
|
853
|
+
function resolveResponseRefs(document, operation) {
|
|
854
|
+
const responses = operation.schema.responses;
|
|
855
|
+
if (!responses) return;
|
|
856
|
+
for (const key in responses) derefInPlace({
|
|
857
|
+
document,
|
|
858
|
+
container: responses,
|
|
859
|
+
key
|
|
860
|
+
});
|
|
861
|
+
}
|
|
875
862
|
/**
|
|
876
863
|
* Returns the response schema for a given operation and HTTP status code.
|
|
877
864
|
*
|
|
@@ -883,14 +870,6 @@ function getResponseBody(responseBody, contentType) {
|
|
|
883
870
|
* getResponseSchema(document, operation, '4XX') // {}
|
|
884
871
|
* ```
|
|
885
872
|
*/
|
|
886
|
-
function resolveResponseRefs(document, operation) {
|
|
887
|
-
const responses = operation.schema.responses;
|
|
888
|
-
if (!responses) return;
|
|
889
|
-
for (const key in responses) {
|
|
890
|
-
const schema = responses[key];
|
|
891
|
-
if (schema && isReference(schema)) responses[key] = resolveRef(document, schema.$ref);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
873
|
function getResponseSchema(document, operation, statusCode, options = {}) {
|
|
895
874
|
resolveResponseRefs(document, operation);
|
|
896
875
|
const responseBody = getResponseBody(getResponseByStatusCode({
|
|
@@ -929,6 +908,16 @@ function getRequestSchema(document, operation, options = {}) {
|
|
|
929
908
|
return dereferenceWithRef(document, schema);
|
|
930
909
|
}
|
|
931
910
|
/**
|
|
911
|
+
* Returns `true` when `fragment` carries any JSON Schema keyword that makes it
|
|
912
|
+
* structurally significant on its own (see `structuralKeys`).
|
|
913
|
+
*
|
|
914
|
+
* A fragment with a structural keyword can't be safely merged into a parent schema.
|
|
915
|
+
*/
|
|
916
|
+
function hasStructuralKeywords(fragment) {
|
|
917
|
+
for (const key in fragment) if (structuralKeys.has(key)) return true;
|
|
918
|
+
return false;
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
932
921
|
* Flattens a keyword-only `allOf` into its parent schema.
|
|
933
922
|
*
|
|
934
923
|
* Only flattens when every member is a plain fragment, with no `$ref` and no structural keywords
|
|
@@ -947,16 +936,6 @@ function getRequestSchema(document, operation, options = {}) {
|
|
|
947
936
|
* // returned unchanged, contains a $ref
|
|
948
937
|
* ```
|
|
949
938
|
*/
|
|
950
|
-
/**
|
|
951
|
-
* Returns `true` when `fragment` carries any JSON Schema keyword that makes it
|
|
952
|
-
* structurally significant on its own (see `structuralKeys`).
|
|
953
|
-
*
|
|
954
|
-
* A fragment with a structural keyword can't be safely merged into a parent schema.
|
|
955
|
-
*/
|
|
956
|
-
function hasStructuralKeywords(fragment) {
|
|
957
|
-
for (const key in fragment) if (structuralKeys.has(key)) return true;
|
|
958
|
-
return false;
|
|
959
|
-
}
|
|
960
939
|
function flattenSchema(schema) {
|
|
961
940
|
if (!schema?.allOf || schema.allOf.length === 0) return schema ?? null;
|
|
962
941
|
const allOfFragments = schema.allOf;
|
|
@@ -1058,7 +1037,7 @@ function resolveSchemaRef(document, schema) {
|
|
|
1058
1037
|
*
|
|
1059
1038
|
* @example
|
|
1060
1039
|
* ```ts
|
|
1061
|
-
* const { schemas,
|
|
1040
|
+
* const { schemas, renames } = getSchemas(document, { contentType: 'application/json' })
|
|
1062
1041
|
* ```
|
|
1063
1042
|
*/
|
|
1064
1043
|
function getSchemas(document, { contentType }) {
|
|
@@ -1083,7 +1062,7 @@ function getSchemas(document, { contentType }) {
|
|
|
1083
1062
|
normalizedNames.set(key, bucket);
|
|
1084
1063
|
}
|
|
1085
1064
|
const schemas = {};
|
|
1086
|
-
const
|
|
1065
|
+
const renames = /* @__PURE__ */ new Map();
|
|
1087
1066
|
for (const [, items] of normalizedNames) {
|
|
1088
1067
|
const isSingle = items.length === 1;
|
|
1089
1068
|
let hasMultipleSources = false;
|
|
@@ -1098,12 +1077,12 @@ function getSchemas(document, { contentType }) {
|
|
|
1098
1077
|
const suffix = isSingle ? "" : hasMultipleSources ? semanticSuffixes[item.source] : index === 0 ? "" : String(index + 1);
|
|
1099
1078
|
const uniqueName = item.originalName + suffix;
|
|
1100
1079
|
schemas[uniqueName] = item.schema;
|
|
1101
|
-
|
|
1080
|
+
if (suffix) renames.set(`#/components/${item.source}/${item.originalName}`, uniqueName);
|
|
1102
1081
|
});
|
|
1103
1082
|
}
|
|
1104
1083
|
return {
|
|
1105
1084
|
schemas: sortSchemas(schemas),
|
|
1106
|
-
|
|
1085
|
+
renames
|
|
1107
1086
|
};
|
|
1108
1087
|
}
|
|
1109
1088
|
/**
|
|
@@ -1208,7 +1187,7 @@ function getResponseBodyContentTypes(document, operation, statusCode) {
|
|
|
1208
1187
|
return body.content ? Object.keys(body.content) : [];
|
|
1209
1188
|
}
|
|
1210
1189
|
//#endregion
|
|
1211
|
-
//#region src/
|
|
1190
|
+
//#region src/converters.ts
|
|
1212
1191
|
/**
|
|
1213
1192
|
* Normalizes malformed `{ type: 'array', enum: [...] }` schemas by moving enum values into items.
|
|
1214
1193
|
*
|
|
@@ -1232,7 +1211,7 @@ function normalizeArrayEnum(schema) {
|
|
|
1232
1211
|
* Builds a `null` scalar node carrying the schema's documentation. Shared by the `const: null`
|
|
1233
1212
|
* and the drf-spectacular `NullEnum` (`{ enum: [null] }`) branches, which render identically.
|
|
1234
1213
|
*/
|
|
1235
|
-
function
|
|
1214
|
+
function createNullNode(schema, name, nullable) {
|
|
1236
1215
|
return _kubb_ast.ast.factory.createSchema({
|
|
1237
1216
|
type: "null",
|
|
1238
1217
|
primitive: "null",
|
|
@@ -1262,620 +1241,638 @@ function nameEnums(node, options) {
|
|
|
1262
1241
|
return named;
|
|
1263
1242
|
}
|
|
1264
1243
|
/**
|
|
1265
|
-
*
|
|
1244
|
+
* Converts a `$ref` schema into a `RefSchemaNode`.
|
|
1266
1245
|
*
|
|
1267
|
-
*
|
|
1268
|
-
*
|
|
1269
|
-
*
|
|
1270
|
-
*
|
|
1271
|
-
|
|
1246
|
+
* The resolved schema is stored in `node.schema`. Usage-site sibling fields
|
|
1247
|
+
* (description, readOnly, nullable, etc.) are stored directly on the ref node.
|
|
1248
|
+
* Use `syncSchemaRef(node)` in printers to get a merged view of both.
|
|
1249
|
+
* Circular refs are detected in `resolveRefNode` and leave `schema` as `null`.
|
|
1250
|
+
*/
|
|
1251
|
+
function convertRef({ schema, name, nullable, defaultValue, rawOptions, document, resolveRefNode, refExists, renames }) {
|
|
1252
|
+
const refPath = schema.$ref;
|
|
1253
|
+
const resolvedSchema = refPath ? resolveRefNode(refPath, rawOptions) : null;
|
|
1254
|
+
if (refPath && document.components && !refExists(refPath)) return _kubb_ast.ast.factory.createSchema({
|
|
1255
|
+
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1256
|
+
type: "unknown"
|
|
1257
|
+
});
|
|
1258
|
+
const targetName = renames?.get(schema.$ref);
|
|
1259
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1260
|
+
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1261
|
+
type: "ref",
|
|
1262
|
+
name: (0, _kubb_ast.extractRefName)(schema.$ref),
|
|
1263
|
+
ref: schema.$ref,
|
|
1264
|
+
...targetName ? { targetName } : {},
|
|
1265
|
+
schema: resolvedSchema
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Converts an `allOf` schema into a flattened node or an `IntersectionSchemaNode`.
|
|
1272
1270
|
*/
|
|
1273
|
-
function
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
* Without it, a shared schema (e.g. `customer`) is re-expanded for every `$ref` that points at
|
|
1284
|
-
* it. In cross-referenced specs like Stripe (~1400 schemas) that becomes exponential blowup,
|
|
1285
|
-
* since one schema can be referenced from dozens of parents, each re-walking its whole subtree.
|
|
1286
|
-
* Memoizing by ref path drops the work from O(2^depth) to O(N) unique schema names.
|
|
1287
|
-
*/
|
|
1288
|
-
const resolvedRefCache = /* @__PURE__ */ new Map();
|
|
1289
|
-
/**
|
|
1290
|
-
* Memoized record of whether a `$ref` path resolves to a node the document actually defines.
|
|
1291
|
-
* A circular ref still resolves to an existing target, so this stays `true` for cycles and only
|
|
1292
|
-
* goes `false` for a `$ref` that points at a component the spec never declares.
|
|
1293
|
-
*/
|
|
1294
|
-
const refExistence = /* @__PURE__ */ new Map();
|
|
1295
|
-
function refExists(refPath) {
|
|
1296
|
-
if (!refExistence.has(refPath)) {
|
|
1297
|
-
let exists = false;
|
|
1298
|
-
try {
|
|
1299
|
-
exists = !!resolveRef(document, refPath);
|
|
1300
|
-
} catch {
|
|
1301
|
-
exists = false;
|
|
1302
|
-
}
|
|
1303
|
-
refExistence.set(refPath, exists);
|
|
1304
|
-
}
|
|
1305
|
-
return refExistence.get(refPath) ?? false;
|
|
1306
|
-
}
|
|
1307
|
-
/**
|
|
1308
|
-
* Converts a `$ref` schema into a `RefSchemaNode`.
|
|
1309
|
-
*
|
|
1310
|
-
* The resolved schema is stored in `node.schema`. Usage-site sibling fields
|
|
1311
|
-
* (description, readOnly, nullable, etc.) are stored directly on the ref node.
|
|
1312
|
-
* Use `syncSchemaRef(node)` in printers to get a merged view of both.
|
|
1313
|
-
* Circular refs are detected via `resolvingRefs` and leave `schema` as `undefined`.
|
|
1314
|
-
*/
|
|
1315
|
-
function convertRef({ schema, name, nullable, defaultValue, rawOptions }) {
|
|
1316
|
-
let resolvedSchema = null;
|
|
1317
|
-
const refPath = schema.$ref;
|
|
1318
|
-
if (refPath && !resolvingRefs.has(refPath)) {
|
|
1319
|
-
if (!resolvedRefCache.has(refPath)) {
|
|
1320
|
-
try {
|
|
1321
|
-
const referenced = resolveRef(document, refPath);
|
|
1322
|
-
if (referenced) {
|
|
1323
|
-
resolvingRefs.add(refPath);
|
|
1324
|
-
resolvedSchema = parseSchema({ schema: referenced }, rawOptions);
|
|
1325
|
-
resolvingRefs.delete(refPath);
|
|
1326
|
-
}
|
|
1327
|
-
} catch {}
|
|
1328
|
-
resolvedRefCache.set(refPath, resolvedSchema);
|
|
1329
|
-
}
|
|
1330
|
-
resolvedSchema = resolvedRefCache.get(refPath) ?? null;
|
|
1331
|
-
}
|
|
1332
|
-
if (refPath && document.components && !refExists(refPath)) return _kubb_ast.ast.factory.createSchema({
|
|
1333
|
-
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1334
|
-
type: "unknown"
|
|
1335
|
-
});
|
|
1271
|
+
function convertAllOf({ schema, name, nullable, defaultValue, rawOptions, parse, document }) {
|
|
1272
|
+
if (schema.allOf.length === 1 && !schema.properties && !(Array.isArray(schema.required) && schema.required.length) && schema.additionalProperties === void 0) {
|
|
1273
|
+
const [memberSchema] = schema.allOf;
|
|
1274
|
+
const memberNode = parse({
|
|
1275
|
+
schema: memberSchema,
|
|
1276
|
+
name
|
|
1277
|
+
}, rawOptions);
|
|
1278
|
+
const { kind: _kind, ...memberNodeProps } = memberNode;
|
|
1279
|
+
const mergedNullable = nullable || memberNode.nullable || void 0;
|
|
1280
|
+
const mergedDefault = schema.default === null && mergedNullable ? void 0 : schema.default ?? memberNode.default;
|
|
1336
1281
|
return _kubb_ast.ast.factory.createSchema({
|
|
1337
|
-
...
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1282
|
+
...memberNodeProps,
|
|
1283
|
+
name,
|
|
1284
|
+
title: schema.title ?? memberNode.title,
|
|
1285
|
+
description: schema.description ?? memberNode.description,
|
|
1286
|
+
deprecated: schema.deprecated ?? memberNode.deprecated,
|
|
1287
|
+
nullable: mergedNullable,
|
|
1288
|
+
readOnly: schema.readOnly ?? memberNode.readOnly,
|
|
1289
|
+
writeOnly: schema.writeOnly ?? memberNode.writeOnly,
|
|
1290
|
+
default: mergedDefault,
|
|
1291
|
+
examples: extractExamples(schema) ?? memberNode.examples,
|
|
1292
|
+
pattern: schema.pattern ?? ("pattern" in memberNode ? memberNode.pattern : void 0),
|
|
1293
|
+
format: schema.format ?? memberNode.format
|
|
1342
1294
|
});
|
|
1343
1295
|
}
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
if (
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
const
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
name,
|
|
1360
|
-
title: schema.title ?? memberNode.title,
|
|
1361
|
-
description: schema.description ?? memberNode.description,
|
|
1362
|
-
deprecated: schema.deprecated ?? memberNode.deprecated,
|
|
1363
|
-
nullable: mergedNullable,
|
|
1364
|
-
readOnly: schema.readOnly ?? memberNode.readOnly,
|
|
1365
|
-
writeOnly: schema.writeOnly ?? memberNode.writeOnly,
|
|
1366
|
-
default: mergedDefault,
|
|
1367
|
-
examples: extractExamples(schema) ?? memberNode.examples,
|
|
1368
|
-
pattern: schema.pattern ?? ("pattern" in memberNode ? memberNode.pattern : void 0),
|
|
1369
|
-
format: schema.format ?? memberNode.format
|
|
1296
|
+
const filteredDiscriminantValues = [];
|
|
1297
|
+
const allOfMembers = schema.allOf.filter((item) => {
|
|
1298
|
+
if (!isReference(item) || !name) return true;
|
|
1299
|
+
const deref = resolveRef(document, item.$ref);
|
|
1300
|
+
if (!deref || !isDiscriminator(deref)) return true;
|
|
1301
|
+
const parentUnion = deref.oneOf ?? deref.anyOf;
|
|
1302
|
+
if (!parentUnion) return true;
|
|
1303
|
+
const childRef = `${SCHEMA_REF_PREFIX}${name}`;
|
|
1304
|
+
const inOneOf = parentUnion.some((oneOfItem) => isReference(oneOfItem) && oneOfItem.$ref === childRef);
|
|
1305
|
+
const inMapping = Object.values(deref.discriminator.mapping ?? {}).some((v) => v === childRef);
|
|
1306
|
+
if (inOneOf || inMapping) {
|
|
1307
|
+
const discriminatorValue = findDiscriminator(deref.discriminator.mapping, childRef);
|
|
1308
|
+
if (discriminatorValue) filteredDiscriminantValues.push({
|
|
1309
|
+
propertyName: deref.discriminator.propertyName,
|
|
1310
|
+
value: discriminatorValue
|
|
1370
1311
|
});
|
|
1312
|
+
return false;
|
|
1371
1313
|
}
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
if (Array.isArray(schema.required) && schema.required.length) {
|
|
1397
|
-
const outerKeys = schema.properties ? new Set(Object.keys(schema.properties)) : /* @__PURE__ */ new Set();
|
|
1398
|
-
const missingRequired = schema.required.filter((key) => !outerKeys.has(key));
|
|
1399
|
-
if (missingRequired.length) {
|
|
1400
|
-
const resolvedMembers = schema.allOf.flatMap((item) => {
|
|
1401
|
-
if (!isReference(item)) return [item];
|
|
1402
|
-
const deref = resolveRef(document, item.$ref);
|
|
1403
|
-
return deref && !isReference(deref) ? [deref] : [];
|
|
1404
|
-
});
|
|
1405
|
-
for (const key of missingRequired) for (const resolved of resolvedMembers) if (resolved.properties?.[key]) {
|
|
1406
|
-
allOfMembers.push(parseSchema({
|
|
1407
|
-
schema: {
|
|
1408
|
-
properties: { [key]: resolved.properties[key] },
|
|
1409
|
-
required: [key]
|
|
1410
|
-
},
|
|
1314
|
+
return true;
|
|
1315
|
+
}).map((s) => parse({
|
|
1316
|
+
schema: s,
|
|
1317
|
+
name
|
|
1318
|
+
}, rawOptions));
|
|
1319
|
+
const syntheticStart = allOfMembers.length;
|
|
1320
|
+
if (Array.isArray(schema.required) && schema.required.length) {
|
|
1321
|
+
const outerKeys = schema.properties ? new Set(Object.keys(schema.properties)) : /* @__PURE__ */ new Set();
|
|
1322
|
+
const missingRequired = schema.required.filter((key) => !outerKeys.has(key));
|
|
1323
|
+
if (missingRequired.length) {
|
|
1324
|
+
const resolvedMembers = schema.allOf.flatMap((item) => {
|
|
1325
|
+
if (!isReference(item)) return [item];
|
|
1326
|
+
const deref = resolveRef(document, item.$ref);
|
|
1327
|
+
return deref && !isReference(deref) ? [deref] : [];
|
|
1328
|
+
});
|
|
1329
|
+
for (const key of missingRequired) for (const resolved of resolvedMembers) {
|
|
1330
|
+
const prop = resolved.properties?.[key];
|
|
1331
|
+
if (prop) {
|
|
1332
|
+
const memberSchema = {
|
|
1333
|
+
properties: { [key]: prop },
|
|
1334
|
+
required: [key]
|
|
1335
|
+
};
|
|
1336
|
+
allOfMembers.push(parse({
|
|
1337
|
+
schema: memberSchema,
|
|
1411
1338
|
name
|
|
1412
1339
|
}, rawOptions));
|
|
1413
1340
|
break;
|
|
1414
1341
|
}
|
|
1415
1342
|
}
|
|
1416
1343
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
}
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1344
|
+
}
|
|
1345
|
+
if (schema.properties) {
|
|
1346
|
+
const { allOf: _allOf, ...schemaWithoutAllOf } = schema;
|
|
1347
|
+
allOfMembers.push(parse({ schema: schemaWithoutAllOf }, rawOptions));
|
|
1348
|
+
}
|
|
1349
|
+
for (const { propertyName, value } of filteredDiscriminantValues) allOfMembers.push(createDiscriminantNode({
|
|
1350
|
+
propertyName,
|
|
1351
|
+
value
|
|
1352
|
+
}));
|
|
1353
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1354
|
+
type: "intersection",
|
|
1355
|
+
members: [...(0, _kubb_ast.mergeAdjacentObjectsLazy)(allOfMembers.slice(0, syntheticStart)), ...(0, _kubb_ast.mergeAdjacentObjectsLazy)(allOfMembers.slice(syntheticStart))],
|
|
1356
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
/**
|
|
1360
|
+
* Converts a `oneOf` / `anyOf` schema into a `UnionSchemaNode`.
|
|
1361
|
+
*/
|
|
1362
|
+
function convertUnion({ schema, name, nullable, defaultValue, rawOptions, parse, document }) {
|
|
1363
|
+
function pickDiscriminatorPropertyNode(node, propertyName) {
|
|
1364
|
+
const discriminatorProperty = _kubb_ast.ast.narrowSchema(node, "object")?.properties?.find((property) => property.name === propertyName);
|
|
1365
|
+
if (!discriminatorProperty) return null;
|
|
1425
1366
|
return _kubb_ast.ast.factory.createSchema({
|
|
1426
|
-
type: "
|
|
1427
|
-
|
|
1428
|
-
|
|
1367
|
+
type: "object",
|
|
1368
|
+
primitive: "object",
|
|
1369
|
+
properties: [discriminatorProperty]
|
|
1429
1370
|
});
|
|
1430
1371
|
}
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1372
|
+
function resolveRefSilent($ref) {
|
|
1373
|
+
if (!$ref.startsWith("#")) return null;
|
|
1374
|
+
return decodeURIComponent($ref.substring(1)).split("/").filter(Boolean).reduce((obj, key) => obj?.[key], document) ?? null;
|
|
1375
|
+
}
|
|
1376
|
+
function implicitDiscriminantValue(member) {
|
|
1377
|
+
if (!discriminator || discriminator.mapping || !isReference(member)) return null;
|
|
1378
|
+
const value = (0, _kubb_ast.extractRefName)(member.$ref);
|
|
1379
|
+
if (!value) return null;
|
|
1380
|
+
const variant = resolveRefSilent(member.$ref);
|
|
1381
|
+
if (!variant) return null;
|
|
1382
|
+
const propertyName = discriminator.propertyName;
|
|
1383
|
+
const seen = /* @__PURE__ */ new Set([member.$ref]);
|
|
1384
|
+
function constrains(v) {
|
|
1385
|
+
const prop = v.properties?.[propertyName];
|
|
1386
|
+
const resolved = prop && isReference(prop) ? resolveRefSilent(prop.$ref) : prop;
|
|
1387
|
+
if (resolved && (Array.isArray(resolved.enum) || resolved.const !== void 0)) return true;
|
|
1388
|
+
const composition = v.allOf ?? v.oneOf ?? v.anyOf;
|
|
1389
|
+
if (!composition) return false;
|
|
1390
|
+
return composition.some((m) => {
|
|
1391
|
+
if (!isReference(m)) return constrains(m);
|
|
1392
|
+
if (seen.has(m.$ref)) return false;
|
|
1393
|
+
seen.add(m.$ref);
|
|
1394
|
+
const r = resolveRefSilent(m.$ref);
|
|
1395
|
+
return r ? constrains(r) : false;
|
|
1442
1396
|
});
|
|
1443
1397
|
}
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
const unionMembers = [...schema.oneOf ?? [], ...schema.anyOf ?? []];
|
|
1473
|
-
const strategy = schema.oneOf ? "one" : "any";
|
|
1474
|
-
const unionBase = {
|
|
1475
|
-
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1476
|
-
discriminatorPropertyName: isDiscriminator(schema) ? schema.discriminator.propertyName : void 0,
|
|
1477
|
-
strategy
|
|
1478
|
-
};
|
|
1479
|
-
const discriminator = isDiscriminator(schema) ? schema.discriminator : void 0;
|
|
1480
|
-
const { oneOf: _o, anyOf: _a, discriminator: _d, ...memberBaseSchema } = schema;
|
|
1481
|
-
const sharedPropertiesNode = schema.properties ? parseSchema({
|
|
1482
|
-
schema: memberBaseSchema,
|
|
1483
|
-
name
|
|
1484
|
-
}, rawOptions) : void 0;
|
|
1485
|
-
if (sharedPropertiesNode || discriminator) {
|
|
1486
|
-
const members = unionMembers.map((s) => {
|
|
1487
|
-
const ref = isReference(s) ? s.$ref : void 0;
|
|
1488
|
-
const discriminatorValue = findDiscriminator(discriminator?.mapping, ref) ?? implicitDiscriminantValue(s);
|
|
1489
|
-
const memberNode = parseSchema({
|
|
1490
|
-
schema: s,
|
|
1491
|
-
name
|
|
1492
|
-
}, rawOptions);
|
|
1493
|
-
if (!discriminatorValue || !discriminator) return memberNode;
|
|
1494
|
-
const narrowedDiscriminatorNode = sharedPropertiesNode ? pickDiscriminatorPropertyNode(_kubb_ast.ast.applyMacros(sharedPropertiesNode, [(0, _kubb_ast.macroDiscriminatorEnum)({
|
|
1495
|
-
propertyName: discriminator.propertyName,
|
|
1496
|
-
values: [discriminatorValue]
|
|
1497
|
-
})], { depth: "shallow" }), discriminator.propertyName) : void 0;
|
|
1498
|
-
return _kubb_ast.ast.factory.createSchema({
|
|
1499
|
-
type: "intersection",
|
|
1500
|
-
members: [memberNode, narrowedDiscriminatorNode ?? createDiscriminantNode({
|
|
1501
|
-
propertyName: discriminator.propertyName,
|
|
1502
|
-
value: discriminatorValue
|
|
1503
|
-
})]
|
|
1504
|
-
});
|
|
1505
|
-
});
|
|
1506
|
-
const unionNode = _kubb_ast.ast.factory.createSchema({
|
|
1507
|
-
type: "union",
|
|
1508
|
-
...unionBase,
|
|
1509
|
-
members
|
|
1510
|
-
});
|
|
1511
|
-
if (!sharedPropertiesNode) return unionNode;
|
|
1398
|
+
return constrains(variant) ? null : value;
|
|
1399
|
+
}
|
|
1400
|
+
const unionMembers = [...schema.oneOf ?? [], ...schema.anyOf ?? []];
|
|
1401
|
+
const strategy = schema.oneOf ? "one" : "any";
|
|
1402
|
+
const unionBase = {
|
|
1403
|
+
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1404
|
+
discriminatorPropertyName: isDiscriminator(schema) ? schema.discriminator.propertyName : void 0,
|
|
1405
|
+
strategy
|
|
1406
|
+
};
|
|
1407
|
+
const discriminator = isDiscriminator(schema) ? schema.discriminator : void 0;
|
|
1408
|
+
const { oneOf: _o, anyOf: _a, discriminator: _d, ...memberBaseSchema } = schema;
|
|
1409
|
+
const sharedPropertiesNode = schema.properties ? parse({
|
|
1410
|
+
schema: memberBaseSchema,
|
|
1411
|
+
name
|
|
1412
|
+
}, rawOptions) : void 0;
|
|
1413
|
+
if (sharedPropertiesNode || discriminator) {
|
|
1414
|
+
const members = unionMembers.map((s) => {
|
|
1415
|
+
const ref = isReference(s) ? s.$ref : void 0;
|
|
1416
|
+
const discriminatorValue = findDiscriminator(discriminator?.mapping, ref) ?? implicitDiscriminantValue(s);
|
|
1417
|
+
const memberNode = parse({
|
|
1418
|
+
schema: s,
|
|
1419
|
+
name
|
|
1420
|
+
}, rawOptions);
|
|
1421
|
+
if (!discriminatorValue || !discriminator) return memberNode;
|
|
1422
|
+
const narrowedDiscriminatorNode = sharedPropertiesNode ? pickDiscriminatorPropertyNode(_kubb_ast.ast.applyMacros(sharedPropertiesNode, [(0, _kubb_ast.macroDiscriminatorEnum)({
|
|
1423
|
+
propertyName: discriminator.propertyName,
|
|
1424
|
+
values: [discriminatorValue]
|
|
1425
|
+
})], { depth: "shallow" }), discriminator.propertyName) : void 0;
|
|
1512
1426
|
return _kubb_ast.ast.factory.createSchema({
|
|
1513
1427
|
type: "intersection",
|
|
1514
|
-
|
|
1515
|
-
|
|
1428
|
+
members: [memberNode, narrowedDiscriminatorNode ?? createDiscriminantNode({
|
|
1429
|
+
propertyName: discriminator.propertyName,
|
|
1430
|
+
value: discriminatorValue
|
|
1431
|
+
})]
|
|
1516
1432
|
});
|
|
1517
|
-
}
|
|
1433
|
+
});
|
|
1518
1434
|
const unionNode = _kubb_ast.ast.factory.createSchema({
|
|
1519
1435
|
type: "union",
|
|
1520
1436
|
...unionBase,
|
|
1521
|
-
members
|
|
1522
|
-
schema: s,
|
|
1523
|
-
name
|
|
1524
|
-
}, rawOptions))
|
|
1437
|
+
members
|
|
1525
1438
|
});
|
|
1526
|
-
|
|
1527
|
-
}
|
|
1528
|
-
/**
|
|
1529
|
-
* Converts an OAS 3.1 `const` schema into a null scalar or a single-value `EnumSchemaNode`.
|
|
1530
|
-
*/
|
|
1531
|
-
function convertConst({ schema, name, nullable, defaultValue }) {
|
|
1532
|
-
const constValue = schema.const;
|
|
1533
|
-
if (constValue === null) return createNullSchema(schema, name);
|
|
1534
|
-
const constPrimitive = getPrimitiveType(typeof constValue === "number" ? "number" : typeof constValue === "boolean" ? "boolean" : "string");
|
|
1439
|
+
if (!sharedPropertiesNode) return unionNode;
|
|
1535
1440
|
return _kubb_ast.ast.factory.createSchema({
|
|
1536
|
-
type: "
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1441
|
+
type: "intersection",
|
|
1442
|
+
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1443
|
+
members: [unionNode, sharedPropertiesNode]
|
|
1540
1444
|
});
|
|
1541
1445
|
}
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1446
|
+
const unionNode = _kubb_ast.ast.factory.createSchema({
|
|
1447
|
+
type: "union",
|
|
1448
|
+
...unionBase,
|
|
1449
|
+
members: unionMembers.map((s) => parse({
|
|
1450
|
+
schema: s,
|
|
1451
|
+
name
|
|
1452
|
+
}, rawOptions))
|
|
1453
|
+
});
|
|
1454
|
+
return _kubb_ast.ast.applyMacros(unionNode, [_kubb_ast.macroSimplifyUnion], { depth: "shallow" });
|
|
1455
|
+
}
|
|
1456
|
+
/**
|
|
1457
|
+
* Converts an OAS 3.1 `const` schema into a null scalar or a single-value `EnumSchemaNode`.
|
|
1458
|
+
*/
|
|
1459
|
+
function convertConst({ schema, name, nullable, defaultValue }) {
|
|
1460
|
+
const constValue = schema.const;
|
|
1461
|
+
if (constValue === null) return createNullNode(schema, name);
|
|
1462
|
+
const constPrimitive = getPrimitiveType(typeof constValue === "number" ? "number" : typeof constValue === "boolean" ? "boolean" : "string");
|
|
1463
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1464
|
+
type: "enum",
|
|
1465
|
+
primitive: constPrimitive,
|
|
1466
|
+
enumValues: [constValue],
|
|
1467
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Converts a format-annotated schema into a special-type `SchemaNode`.
|
|
1472
|
+
* Returns `null` when the format should fall through to string handling (`dateType: false`).
|
|
1473
|
+
*/
|
|
1474
|
+
function convertFormat({ schema, name, nullable, defaultValue, options }) {
|
|
1475
|
+
const base = buildSchemaNode(schema, name, nullable, defaultValue);
|
|
1476
|
+
if (schema.format === "int64") return _kubb_ast.ast.factory.createSchema({
|
|
1477
|
+
type: options.integerType === "bigint" ? "bigint" : "integer",
|
|
1478
|
+
primitive: "integer",
|
|
1479
|
+
...base,
|
|
1480
|
+
min: schema.minimum,
|
|
1481
|
+
max: schema.maximum,
|
|
1482
|
+
exclusiveMinimum: typeof schema.exclusiveMinimum === "number" ? schema.exclusiveMinimum : void 0,
|
|
1483
|
+
exclusiveMaximum: typeof schema.exclusiveMaximum === "number" ? schema.exclusiveMaximum : void 0
|
|
1484
|
+
});
|
|
1485
|
+
if (schema.format === "date-time" || schema.format === "date" || schema.format === "time") {
|
|
1486
|
+
const dateType = getDateType(options, schema.format);
|
|
1487
|
+
if (!dateType) return null;
|
|
1488
|
+
if (dateType.type === "datetime") return _kubb_ast.ast.factory.createSchema({
|
|
1551
1489
|
...base,
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1490
|
+
primitive: "string",
|
|
1491
|
+
type: "datetime",
|
|
1492
|
+
offset: dateType.offset,
|
|
1493
|
+
local: dateType.local
|
|
1556
1494
|
});
|
|
1557
|
-
if (schema.format === "date-time" || schema.format === "date" || schema.format === "time") {
|
|
1558
|
-
const dateType = getDateType(options, schema.format);
|
|
1559
|
-
if (!dateType) return null;
|
|
1560
|
-
if (dateType.type === "datetime") return _kubb_ast.ast.factory.createSchema({
|
|
1561
|
-
...base,
|
|
1562
|
-
primitive: "string",
|
|
1563
|
-
type: "datetime",
|
|
1564
|
-
offset: dateType.offset,
|
|
1565
|
-
local: dateType.local
|
|
1566
|
-
});
|
|
1567
|
-
return _kubb_ast.ast.factory.createSchema({
|
|
1568
|
-
...base,
|
|
1569
|
-
primitive: "string",
|
|
1570
|
-
type: dateType.type,
|
|
1571
|
-
representation: dateType.representation
|
|
1572
|
-
});
|
|
1573
|
-
}
|
|
1574
|
-
const specialType = getSchemaType(schema.format);
|
|
1575
|
-
if (!specialType) return null;
|
|
1576
|
-
const specialPrimitive = specialType === "number" || specialType === "integer" || specialType === "bigint" ? specialType : "string";
|
|
1577
|
-
const hasLength = specialType === "url" || specialType === "uuid" || specialType === "email";
|
|
1578
1495
|
return _kubb_ast.ast.factory.createSchema({
|
|
1579
1496
|
...base,
|
|
1580
|
-
primitive:
|
|
1581
|
-
type:
|
|
1582
|
-
|
|
1583
|
-
min: schema.minLength,
|
|
1584
|
-
max: schema.maxLength
|
|
1585
|
-
} : {}
|
|
1497
|
+
primitive: "string",
|
|
1498
|
+
type: dateType.type,
|
|
1499
|
+
representation: dateType.representation
|
|
1586
1500
|
});
|
|
1587
1501
|
}
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
}
|
|
1502
|
+
const specialType = getSchemaType(schema.format);
|
|
1503
|
+
if (!specialType) return null;
|
|
1504
|
+
const specialPrimitive = specialType === "number" || specialType === "integer" || specialType === "bigint" ? specialType : "string";
|
|
1505
|
+
const hasLength = specialType === "url" || specialType === "uuid" || specialType === "email";
|
|
1506
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1507
|
+
...base,
|
|
1508
|
+
primitive: specialPrimitive,
|
|
1509
|
+
type: specialType,
|
|
1510
|
+
...hasLength ? {
|
|
1511
|
+
min: schema.minLength,
|
|
1512
|
+
max: schema.maxLength
|
|
1513
|
+
} : {}
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
/**
|
|
1517
|
+
* Converts an `enum` schema into an `EnumSchemaNode`.
|
|
1518
|
+
*/
|
|
1519
|
+
function convertEnum({ schema, name, nullable, type, rawOptions, parse }) {
|
|
1520
|
+
if (type === "array") return parse({
|
|
1521
|
+
schema: normalizeArrayEnum(schema),
|
|
1522
|
+
name
|
|
1523
|
+
}, rawOptions);
|
|
1524
|
+
const nullInEnum = schema.enum.includes(null);
|
|
1525
|
+
const filteredValues = nullInEnum ? schema.enum.filter((v) => v !== null) : schema.enum;
|
|
1526
|
+
if (nullInEnum && filteredValues.length === 0) return createNullNode(schema, name);
|
|
1527
|
+
const enumNullable = nullable || nullInEnum || void 0;
|
|
1528
|
+
const enumDefault = schema.default === null && enumNullable ? void 0 : schema.default;
|
|
1529
|
+
const enumPrimitive = getPrimitiveType(type);
|
|
1530
|
+
const enumBase = {
|
|
1531
|
+
type: "enum",
|
|
1532
|
+
primitive: enumPrimitive,
|
|
1533
|
+
...buildSchemaNode(schema, name, enumNullable, enumDefault)
|
|
1534
|
+
};
|
|
1535
|
+
const extensionKey = enumExtensionKeys.find((key) => key in schema);
|
|
1536
|
+
const descriptionKey = enumDescriptionKeys.find((key) => key in schema);
|
|
1537
|
+
if (extensionKey || descriptionKey || enumPrimitive === "number" || enumPrimitive === "integer" || enumPrimitive === "boolean") {
|
|
1538
|
+
const enumPrimitiveType = enumPrimitive === "number" || enumPrimitive === "integer" ? "number" : enumPrimitive === "boolean" ? "boolean" : "string";
|
|
1539
|
+
const rawEnumNames = extensionKey ? schema[extensionKey] : void 0;
|
|
1540
|
+
const rawEnumDescriptions = descriptionKey ? schema[descriptionKey] : void 0;
|
|
1541
|
+
const uniqueValues = [...new Set(filteredValues)];
|
|
1542
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
1630
1543
|
return _kubb_ast.ast.factory.createSchema({
|
|
1631
1544
|
...enumBase,
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
const schemaNode = nameEnums(parseSchema({
|
|
1644
|
-
schema: resolvedPropSchema,
|
|
1645
|
-
name: (0, _kubb_ast.childName)(name, propName)
|
|
1646
|
-
}, rawOptions), {
|
|
1647
|
-
parentName: name,
|
|
1648
|
-
propName,
|
|
1649
|
-
enumSuffix: options.enumSuffix
|
|
1650
|
-
});
|
|
1651
|
-
return _kubb_ast.ast.factory.createProperty({
|
|
1652
|
-
name: propName,
|
|
1653
|
-
schema: {
|
|
1654
|
-
...schemaNode,
|
|
1655
|
-
nullable: schemaNode.type === "null" ? void 0 : propNullable || void 0
|
|
1656
|
-
},
|
|
1657
|
-
required
|
|
1658
|
-
});
|
|
1659
|
-
}) : [];
|
|
1660
|
-
const additionalProperties = schema.additionalProperties;
|
|
1661
|
-
const additionalPropertiesNode = (() => {
|
|
1662
|
-
if (additionalProperties === true) return true;
|
|
1663
|
-
if (additionalProperties === false) return false;
|
|
1664
|
-
if (additionalProperties && Object.keys(additionalProperties).length > 0) return parseSchema({ schema: additionalProperties }, rawOptions);
|
|
1665
|
-
if (additionalProperties) return _kubb_ast.ast.factory.createSchema({ type: options.unknownType });
|
|
1666
|
-
})();
|
|
1667
|
-
const rawPatternProperties = "patternProperties" in schema ? schema.patternProperties : void 0;
|
|
1668
|
-
const patternProperties = rawPatternProperties ? Object.fromEntries(Object.entries(rawPatternProperties).map(([pattern, patternSchema]) => [pattern, patternSchema === true || typeof patternSchema === "object" && Object.keys(patternSchema).length === 0 ? _kubb_ast.ast.factory.createSchema({ type: options.unknownType }) : parseSchema({ schema: patternSchema }, rawOptions)])) : void 0;
|
|
1669
|
-
const objectNode = _kubb_ast.ast.factory.createSchema({
|
|
1670
|
-
type: "object",
|
|
1671
|
-
primitive: "object",
|
|
1672
|
-
properties,
|
|
1673
|
-
additionalProperties: additionalPropertiesNode,
|
|
1674
|
-
patternProperties,
|
|
1675
|
-
minProperties: schema.minProperties,
|
|
1676
|
-
maxProperties: schema.maxProperties,
|
|
1677
|
-
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1678
|
-
});
|
|
1679
|
-
if (isDiscriminator(schema) && schema.discriminator.mapping) {
|
|
1680
|
-
const discPropName = schema.discriminator.propertyName;
|
|
1681
|
-
const values = Object.keys(schema.discriminator.mapping);
|
|
1682
|
-
const enumName = name ? (0, _kubb_ast.enumPropName)(name, discPropName, options.enumSuffix) : void 0;
|
|
1683
|
-
return _kubb_ast.ast.applyMacros(objectNode, [(0, _kubb_ast.macroDiscriminatorEnum)({
|
|
1684
|
-
propertyName: discPropName,
|
|
1685
|
-
values,
|
|
1686
|
-
enumName
|
|
1687
|
-
})], { depth: "shallow" });
|
|
1688
|
-
}
|
|
1689
|
-
return objectNode;
|
|
1690
|
-
}
|
|
1691
|
-
/**
|
|
1692
|
-
* Converts an OAS 3.1 `prefixItems` tuple into a `TupleSchemaNode`.
|
|
1693
|
-
*/
|
|
1694
|
-
function convertTuple({ schema, name, nullable, defaultValue, rawOptions }) {
|
|
1695
|
-
const tupleItems = (schema.prefixItems ?? []).map((item) => parseSchema({ schema: item }, rawOptions));
|
|
1696
|
-
const rest = schema.items === false ? void 0 : !schema.items || schema.items === true ? _kubb_ast.ast.factory.createSchema({ type: "any" }) : parseSchema({ schema: schema.items }, rawOptions);
|
|
1697
|
-
return _kubb_ast.ast.factory.createSchema({
|
|
1698
|
-
type: "tuple",
|
|
1699
|
-
primitive: "array",
|
|
1700
|
-
items: tupleItems,
|
|
1701
|
-
rest,
|
|
1702
|
-
min: schema.minItems,
|
|
1703
|
-
max: schema.maxItems,
|
|
1704
|
-
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1545
|
+
primitive: enumPrimitiveType,
|
|
1546
|
+
namedEnumValues: uniqueValues.map((value, index) => ({
|
|
1547
|
+
name: String(rawEnumNames?.[index] ?? value),
|
|
1548
|
+
value,
|
|
1549
|
+
primitive: enumPrimitiveType,
|
|
1550
|
+
description: rawEnumDescriptions?.[index]
|
|
1551
|
+
})).filter((entry) => {
|
|
1552
|
+
if (seenNames.has(entry.name)) return false;
|
|
1553
|
+
seenNames.add(entry.name);
|
|
1554
|
+
return true;
|
|
1555
|
+
})
|
|
1705
1556
|
});
|
|
1706
1557
|
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1558
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1559
|
+
...enumBase,
|
|
1560
|
+
enumValues: [...new Set(filteredValues)]
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Converts an object-like schema into an `ObjectSchemaNode`.
|
|
1565
|
+
*/
|
|
1566
|
+
function convertObject({ schema, name, nullable, defaultValue, rawOptions, options, parse }) {
|
|
1567
|
+
const properties = schema.properties ? Object.entries(schema.properties).map(([propName, propSchema]) => {
|
|
1568
|
+
const required = Array.isArray(schema.required) ? schema.required.includes(propName) : !!schema.required;
|
|
1569
|
+
const resolvedPropSchema = propSchema;
|
|
1570
|
+
const propNullable = isNullable(resolvedPropSchema);
|
|
1571
|
+
const schemaNode = nameEnums(parse({
|
|
1572
|
+
schema: resolvedPropSchema,
|
|
1573
|
+
name: (0, _kubb_ast.childName)(name, propName)
|
|
1574
|
+
}, rawOptions), {
|
|
1575
|
+
parentName: name,
|
|
1576
|
+
propName,
|
|
1577
|
+
enumSuffix: options.enumSuffix
|
|
1725
1578
|
});
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
primitive: "string",
|
|
1734
|
-
min: schema.minLength,
|
|
1735
|
-
max: schema.maxLength,
|
|
1736
|
-
pattern: schema.pattern,
|
|
1737
|
-
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1579
|
+
return _kubb_ast.ast.factory.createProperty({
|
|
1580
|
+
name: propName,
|
|
1581
|
+
schema: {
|
|
1582
|
+
...schemaNode,
|
|
1583
|
+
nullable: schemaNode.type === "null" ? void 0 : propNullable || void 0
|
|
1584
|
+
},
|
|
1585
|
+
required
|
|
1738
1586
|
});
|
|
1587
|
+
}) : [];
|
|
1588
|
+
const additionalProperties = schema.additionalProperties;
|
|
1589
|
+
const additionalPropertiesNode = (() => {
|
|
1590
|
+
if (additionalProperties === true) return true;
|
|
1591
|
+
if (additionalProperties === false) return false;
|
|
1592
|
+
if (additionalProperties && Object.keys(additionalProperties).length > 0) return parse({ schema: additionalProperties }, rawOptions);
|
|
1593
|
+
if (additionalProperties) return _kubb_ast.ast.factory.createSchema({ type: options.unknownType });
|
|
1594
|
+
})();
|
|
1595
|
+
const rawPatternProperties = "patternProperties" in schema ? schema.patternProperties : void 0;
|
|
1596
|
+
const patternProperties = rawPatternProperties ? Object.fromEntries(Object.entries(rawPatternProperties).map(([pattern, patternSchema]) => [pattern, patternSchema === true || typeof patternSchema === "object" && Object.keys(patternSchema).length === 0 ? _kubb_ast.ast.factory.createSchema({ type: options.unknownType }) : parse({ schema: patternSchema }, rawOptions)])) : void 0;
|
|
1597
|
+
const objectNode = _kubb_ast.ast.factory.createSchema({
|
|
1598
|
+
type: "object",
|
|
1599
|
+
primitive: "object",
|
|
1600
|
+
properties,
|
|
1601
|
+
additionalProperties: additionalPropertiesNode,
|
|
1602
|
+
patternProperties,
|
|
1603
|
+
minProperties: schema.minProperties,
|
|
1604
|
+
maxProperties: schema.maxProperties,
|
|
1605
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1606
|
+
});
|
|
1607
|
+
if (isDiscriminator(schema) && schema.discriminator.mapping) {
|
|
1608
|
+
const discPropName = schema.discriminator.propertyName;
|
|
1609
|
+
const values = Object.keys(schema.discriminator.mapping);
|
|
1610
|
+
const enumName = name ? (0, _kubb_ast.enumPropName)(name, discPropName, options.enumSuffix) : void 0;
|
|
1611
|
+
return _kubb_ast.ast.applyMacros(objectNode, [(0, _kubb_ast.macroDiscriminatorEnum)({
|
|
1612
|
+
propertyName: discPropName,
|
|
1613
|
+
values,
|
|
1614
|
+
enumName
|
|
1615
|
+
})], { depth: "shallow" });
|
|
1739
1616
|
}
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1617
|
+
return objectNode;
|
|
1618
|
+
}
|
|
1619
|
+
/**
|
|
1620
|
+
* Converts an OAS 3.1 `prefixItems` tuple into a `TupleSchemaNode`.
|
|
1621
|
+
*/
|
|
1622
|
+
function convertTuple({ schema, name, nullable, defaultValue, rawOptions, parse }) {
|
|
1623
|
+
const tupleItems = (schema.prefixItems ?? []).map((item) => parse({ schema: item }, rawOptions));
|
|
1624
|
+
const rest = schema.items === false ? void 0 : !schema.items || schema.items === true ? _kubb_ast.ast.factory.createSchema({ type: "any" }) : parse({ schema: schema.items }, rawOptions);
|
|
1625
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1626
|
+
type: "tuple",
|
|
1627
|
+
primitive: "array",
|
|
1628
|
+
items: tupleItems,
|
|
1629
|
+
rest,
|
|
1630
|
+
min: schema.minItems,
|
|
1631
|
+
max: schema.maxItems,
|
|
1632
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1633
|
+
});
|
|
1634
|
+
}
|
|
1635
|
+
/**
|
|
1636
|
+
* Converts a `type: 'array'` schema into an `ArraySchemaNode`.
|
|
1637
|
+
*/
|
|
1638
|
+
function convertArray({ schema, name, nullable, defaultValue, rawOptions, options, parse }) {
|
|
1639
|
+
const rawItems = schema.items;
|
|
1640
|
+
const itemName = rawItems?.enum?.length && name ? (0, _kubb_ast.enumPropName)(null, name, options.enumSuffix) : name;
|
|
1641
|
+
const items = rawItems ? [parse({
|
|
1642
|
+
schema: rawItems,
|
|
1643
|
+
name: itemName
|
|
1644
|
+
}, rawOptions)] : [];
|
|
1645
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1646
|
+
type: "array",
|
|
1647
|
+
primitive: "array",
|
|
1648
|
+
items,
|
|
1649
|
+
min: schema.minItems,
|
|
1650
|
+
max: schema.maxItems,
|
|
1651
|
+
unique: schema.uniqueItems ?? void 0,
|
|
1652
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
/**
|
|
1656
|
+
* Converts a `type: 'string'` schema into a `StringSchemaNode`.
|
|
1657
|
+
*/
|
|
1658
|
+
function convertString({ schema, name, nullable, defaultValue }) {
|
|
1659
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1660
|
+
type: "string",
|
|
1661
|
+
primitive: "string",
|
|
1662
|
+
min: schema.minLength,
|
|
1663
|
+
max: schema.maxLength,
|
|
1664
|
+
pattern: schema.pattern,
|
|
1665
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1666
|
+
});
|
|
1667
|
+
}
|
|
1668
|
+
/**
|
|
1669
|
+
* Converts a `type: 'number'` or `type: 'integer'` schema.
|
|
1670
|
+
*/
|
|
1671
|
+
function convertNumeric({ schema, name, nullable, defaultValue }, type) {
|
|
1672
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1673
|
+
type,
|
|
1674
|
+
primitive: type,
|
|
1675
|
+
min: schema.minimum,
|
|
1676
|
+
max: schema.maximum,
|
|
1677
|
+
exclusiveMinimum: typeof schema.exclusiveMinimum === "number" ? schema.exclusiveMinimum : void 0,
|
|
1678
|
+
exclusiveMaximum: typeof schema.exclusiveMaximum === "number" ? schema.exclusiveMaximum : void 0,
|
|
1679
|
+
multipleOf: schema.multipleOf,
|
|
1680
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
/**
|
|
1684
|
+
* Converts a `type: 'boolean'` schema.
|
|
1685
|
+
*/
|
|
1686
|
+
function convertBoolean({ schema, name, nullable, defaultValue }) {
|
|
1687
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1688
|
+
type: "boolean",
|
|
1689
|
+
primitive: "boolean",
|
|
1690
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
/**
|
|
1694
|
+
* Converts a binary string schema (`type: 'string'`, `contentMediaType: 'application/octet-stream'`)
|
|
1695
|
+
* into a `blob` node.
|
|
1696
|
+
*/
|
|
1697
|
+
function convertBinary({ schema, name, nullable, defaultValue }) {
|
|
1698
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1699
|
+
type: "blob",
|
|
1700
|
+
primitive: "string",
|
|
1701
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1702
|
+
});
|
|
1703
|
+
}
|
|
1704
|
+
/**
|
|
1705
|
+
* Converts an OAS 3.1 multi-type array (e.g. `type: ['string', 'number']`) into a `UnionSchemaNode`.
|
|
1706
|
+
*
|
|
1707
|
+
* Returns `null` when only one non-`null` type remains (e.g. `['string', 'null']`), so `parse`
|
|
1708
|
+
* falls through and handles it as that single type with nullability already folded in.
|
|
1709
|
+
*/
|
|
1710
|
+
function convertMultiType({ schema, name, nullable, defaultValue, rawOptions, parse }) {
|
|
1711
|
+
const types = schema.type;
|
|
1712
|
+
const nonNullTypes = types.filter((t) => t !== "null");
|
|
1713
|
+
if (nonNullTypes.length <= 1) return null;
|
|
1714
|
+
const arrayNullable = types.includes("null") || nullable || void 0;
|
|
1715
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1716
|
+
type: "union",
|
|
1717
|
+
members: nonNullTypes.map((t) => {
|
|
1718
|
+
return parse({
|
|
1719
|
+
schema: {
|
|
1720
|
+
...schema,
|
|
1721
|
+
type: t
|
|
1722
|
+
},
|
|
1723
|
+
name
|
|
1724
|
+
}, rawOptions);
|
|
1725
|
+
}),
|
|
1726
|
+
...buildSchemaNode(schema, name, arrayNullable, defaultValue)
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Ordered schema rule table. Order is significant: composition keywords (`$ref`, `allOf`,
|
|
1731
|
+
* `oneOf`/`anyOf`) take precedence over `const`/`format`, which take precedence over the plain
|
|
1732
|
+
* `type`. The first matching rule that produces a node wins. See {@link SchemaRule} for the
|
|
1733
|
+
* match/convert/fall-through contract.
|
|
1734
|
+
*/
|
|
1735
|
+
const schemaRules = [
|
|
1736
|
+
{
|
|
1737
|
+
match: ({ schema }) => isReference(schema),
|
|
1738
|
+
convert: convertRef
|
|
1739
|
+
},
|
|
1740
|
+
{
|
|
1741
|
+
match: ({ schema }) => !!schema.allOf?.length,
|
|
1742
|
+
convert: convertAllOf
|
|
1743
|
+
},
|
|
1744
|
+
{
|
|
1745
|
+
match: ({ schema }) => !!(schema.oneOf?.length || schema.anyOf?.length),
|
|
1746
|
+
convert: convertUnion
|
|
1747
|
+
},
|
|
1748
|
+
{
|
|
1749
|
+
match: ({ schema }) => "const" in schema && schema.const !== void 0,
|
|
1750
|
+
convert: convertConst
|
|
1751
|
+
},
|
|
1752
|
+
{
|
|
1753
|
+
match: ({ schema }) => !!schema.format,
|
|
1754
|
+
convert: convertFormat
|
|
1755
|
+
},
|
|
1756
|
+
{
|
|
1757
|
+
match: ({ schema }) => isBinary(schema),
|
|
1758
|
+
convert: convertBinary
|
|
1759
|
+
},
|
|
1760
|
+
{
|
|
1761
|
+
match: ({ schema }) => Array.isArray(schema.type) && schema.type.length > 1,
|
|
1762
|
+
convert: convertMultiType
|
|
1763
|
+
},
|
|
1764
|
+
{
|
|
1765
|
+
match: ({ schema, type }) => !type && (schema.minLength !== void 0 || schema.maxLength !== void 0 || schema.pattern !== void 0),
|
|
1766
|
+
convert: convertString
|
|
1767
|
+
},
|
|
1768
|
+
{
|
|
1769
|
+
match: ({ schema, type }) => !type && (schema.minimum !== void 0 || schema.maximum !== void 0),
|
|
1770
|
+
convert: (ctx) => convertNumeric(ctx, "number")
|
|
1771
|
+
},
|
|
1772
|
+
{
|
|
1773
|
+
match: ({ schema }) => !!schema.enum?.length,
|
|
1774
|
+
convert: convertEnum
|
|
1775
|
+
},
|
|
1776
|
+
{
|
|
1777
|
+
match: ({ schema, type }) => type === "object" || !!schema.properties || !!schema.additionalProperties || "patternProperties" in schema,
|
|
1778
|
+
convert: convertObject
|
|
1779
|
+
},
|
|
1780
|
+
{
|
|
1781
|
+
match: ({ schema }) => "prefixItems" in schema,
|
|
1782
|
+
convert: convertTuple
|
|
1783
|
+
},
|
|
1784
|
+
{
|
|
1785
|
+
match: ({ schema, type }) => type === "array" || "items" in schema,
|
|
1786
|
+
convert: convertArray
|
|
1787
|
+
},
|
|
1788
|
+
{
|
|
1789
|
+
match: ({ type }) => type === "string",
|
|
1790
|
+
convert: convertString
|
|
1791
|
+
},
|
|
1792
|
+
{
|
|
1793
|
+
match: ({ type }) => type === "number",
|
|
1794
|
+
convert: (ctx) => convertNumeric(ctx, "number")
|
|
1795
|
+
},
|
|
1796
|
+
{
|
|
1797
|
+
match: ({ type }) => type === "integer",
|
|
1798
|
+
convert: (ctx) => convertNumeric(ctx, "integer")
|
|
1799
|
+
},
|
|
1800
|
+
{
|
|
1801
|
+
match: ({ type }) => type === "boolean",
|
|
1802
|
+
convert: convertBoolean
|
|
1803
|
+
},
|
|
1804
|
+
{
|
|
1805
|
+
match: ({ type }) => type === "null",
|
|
1806
|
+
convert: ({ schema, name, nullable }) => createNullNode(schema, name, nullable)
|
|
1754
1807
|
}
|
|
1808
|
+
];
|
|
1809
|
+
//#endregion
|
|
1810
|
+
//#region src/parser.ts
|
|
1811
|
+
/**
|
|
1812
|
+
* Creates the schema and operation converters bound to one OpenAPI document.
|
|
1813
|
+
*
|
|
1814
|
+
* Owns the per-instance `$ref` state (cycle detection, resolved-node cache, existence cache) and
|
|
1815
|
+
* the `parseSchema` recursion seam, then dispatches each schema through the ordered `schemaRules`
|
|
1816
|
+
* table from `converters.ts`. Every converter is a standalone function that recurses through the
|
|
1817
|
+
* `parse` function passed to it, so this file only wires state to the converters.
|
|
1818
|
+
*
|
|
1819
|
+
* @internal
|
|
1820
|
+
*/
|
|
1821
|
+
function createSchemaParser(ctx) {
|
|
1822
|
+
const document = ctx.document;
|
|
1755
1823
|
/**
|
|
1756
|
-
*
|
|
1824
|
+
* Tracks `$ref` paths that are currently being resolved to prevent infinite
|
|
1825
|
+
* recursion when schemas contain circular references (e.g. `Pet → parent → Pet`).
|
|
1757
1826
|
*/
|
|
1758
|
-
|
|
1759
|
-
return _kubb_ast.ast.factory.createSchema({
|
|
1760
|
-
type: "boolean",
|
|
1761
|
-
primitive: "boolean",
|
|
1762
|
-
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1763
|
-
});
|
|
1764
|
-
}
|
|
1827
|
+
const resolvingRefs = /* @__PURE__ */ new Set();
|
|
1765
1828
|
/**
|
|
1766
|
-
*
|
|
1767
|
-
*
|
|
1829
|
+
* Cache of `$ref` schemas already resolved in this parser instance, keyed by ref path.
|
|
1830
|
+
*
|
|
1831
|
+
* Without it, a shared schema (e.g. `customer`) is re-expanded for every `$ref` that points at
|
|
1832
|
+
* it. In cross-referenced specs like Stripe (~1400 schemas) that becomes exponential blowup,
|
|
1833
|
+
* since one schema can be referenced from dozens of parents, each re-walking its whole subtree.
|
|
1834
|
+
* Memoizing by ref path drops the work from O(2^depth) to O(N) unique schema names.
|
|
1768
1835
|
*/
|
|
1769
|
-
|
|
1770
|
-
return _kubb_ast.ast.factory.createSchema({
|
|
1771
|
-
type: "blob",
|
|
1772
|
-
primitive: "string",
|
|
1773
|
-
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1774
|
-
});
|
|
1775
|
-
}
|
|
1836
|
+
const resolvedRefCache = /* @__PURE__ */ new Map();
|
|
1776
1837
|
/**
|
|
1777
|
-
*
|
|
1778
|
-
*
|
|
1779
|
-
*
|
|
1780
|
-
* falls through and handles it as that single type with nullability already folded in.
|
|
1838
|
+
* Memoized record of whether a `$ref` path resolves to a node the document actually defines.
|
|
1839
|
+
* A circular ref still resolves to an existing target, so this stays `true` for cycles and only
|
|
1840
|
+
* goes `false` for a `$ref` that points at a component the spec never declares.
|
|
1781
1841
|
*/
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
name
|
|
1795
|
-
}, rawOptions)),
|
|
1796
|
-
...buildSchemaNode(schema, name, arrayNullable, defaultValue)
|
|
1797
|
-
});
|
|
1842
|
+
const refExistence = /* @__PURE__ */ new Map();
|
|
1843
|
+
function refExists(refPath) {
|
|
1844
|
+
if (!refExistence.has(refPath)) {
|
|
1845
|
+
let exists = false;
|
|
1846
|
+
try {
|
|
1847
|
+
exists = !!resolveRef(document, refPath);
|
|
1848
|
+
} catch {
|
|
1849
|
+
exists = false;
|
|
1850
|
+
}
|
|
1851
|
+
refExistence.set(refPath, exists);
|
|
1852
|
+
}
|
|
1853
|
+
return refExistence.get(refPath) ?? false;
|
|
1798
1854
|
}
|
|
1799
1855
|
/**
|
|
1800
|
-
*
|
|
1801
|
-
* `
|
|
1802
|
-
*
|
|
1803
|
-
* match/convert/fall-through contract.
|
|
1856
|
+
* Resolves a `$ref` to its parsed node, guarding against cycles and memoizing per instance.
|
|
1857
|
+
* Returns `null` when the ref is currently being resolved (a cycle) or cannot be resolved
|
|
1858
|
+
* (e.g. a minimal document in a unit test).
|
|
1804
1859
|
*/
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
{
|
|
1819
|
-
match: ({ schema }) => "const" in schema && schema.const !== void 0,
|
|
1820
|
-
convert: convertConst
|
|
1821
|
-
},
|
|
1822
|
-
{
|
|
1823
|
-
match: ({ schema }) => !!schema.format,
|
|
1824
|
-
convert: convertFormat
|
|
1825
|
-
},
|
|
1826
|
-
{
|
|
1827
|
-
match: ({ schema }) => isBinary(schema),
|
|
1828
|
-
convert: convertBlob
|
|
1829
|
-
},
|
|
1830
|
-
{
|
|
1831
|
-
match: ({ schema }) => Array.isArray(schema.type) && schema.type.length > 1,
|
|
1832
|
-
convert: convertMultiType
|
|
1833
|
-
},
|
|
1834
|
-
{
|
|
1835
|
-
match: ({ schema, type }) => !type && (schema.minLength !== void 0 || schema.maxLength !== void 0 || schema.pattern !== void 0),
|
|
1836
|
-
convert: convertString
|
|
1837
|
-
},
|
|
1838
|
-
{
|
|
1839
|
-
match: ({ schema, type }) => !type && (schema.minimum !== void 0 || schema.maximum !== void 0),
|
|
1840
|
-
convert: (ctx) => convertNumeric(ctx, "number")
|
|
1841
|
-
},
|
|
1842
|
-
{
|
|
1843
|
-
match: ({ schema }) => !!schema.enum?.length,
|
|
1844
|
-
convert: convertEnum
|
|
1845
|
-
},
|
|
1846
|
-
{
|
|
1847
|
-
match: ({ schema, type }) => type === "object" || !!schema.properties || !!schema.additionalProperties || "patternProperties" in schema,
|
|
1848
|
-
convert: convertObject
|
|
1849
|
-
},
|
|
1850
|
-
{
|
|
1851
|
-
match: ({ schema }) => "prefixItems" in schema,
|
|
1852
|
-
convert: convertTuple
|
|
1853
|
-
},
|
|
1854
|
-
{
|
|
1855
|
-
match: ({ schema, type }) => type === "array" || "items" in schema,
|
|
1856
|
-
convert: convertArray
|
|
1857
|
-
},
|
|
1858
|
-
{
|
|
1859
|
-
match: ({ type }) => type === "string",
|
|
1860
|
-
convert: convertString
|
|
1861
|
-
},
|
|
1862
|
-
{
|
|
1863
|
-
match: ({ type }) => type === "number",
|
|
1864
|
-
convert: (ctx) => convertNumeric(ctx, "number")
|
|
1865
|
-
},
|
|
1866
|
-
{
|
|
1867
|
-
match: ({ type }) => type === "integer",
|
|
1868
|
-
convert: (ctx) => convertNumeric(ctx, "integer")
|
|
1869
|
-
},
|
|
1870
|
-
{
|
|
1871
|
-
match: ({ type }) => type === "boolean",
|
|
1872
|
-
convert: convertBoolean
|
|
1873
|
-
},
|
|
1874
|
-
{
|
|
1875
|
-
match: ({ type }) => type === "null",
|
|
1876
|
-
convert: ({ schema, name, nullable }) => createNullSchema(schema, name, nullable)
|
|
1860
|
+
function resolveRefNode(refPath, rawOptions) {
|
|
1861
|
+
if (resolvingRefs.has(refPath)) return null;
|
|
1862
|
+
if (!resolvedRefCache.has(refPath)) {
|
|
1863
|
+
let resolved = null;
|
|
1864
|
+
try {
|
|
1865
|
+
const referenced = resolveRef(document, refPath);
|
|
1866
|
+
if (referenced) {
|
|
1867
|
+
resolvingRefs.add(refPath);
|
|
1868
|
+
resolved = parseSchema({ schema: referenced }, rawOptions);
|
|
1869
|
+
resolvingRefs.delete(refPath);
|
|
1870
|
+
}
|
|
1871
|
+
} catch {}
|
|
1872
|
+
resolvedRefCache.set(refPath, resolved);
|
|
1877
1873
|
}
|
|
1878
|
-
|
|
1874
|
+
return resolvedRefCache.get(refPath) ?? null;
|
|
1875
|
+
}
|
|
1879
1876
|
/**
|
|
1880
1877
|
* Converts an OAS `SchemaObject` into a `SchemaNode`.
|
|
1881
1878
|
*
|
|
@@ -1894,18 +1891,23 @@ function createSchemaParser(ctx) {
|
|
|
1894
1891
|
name
|
|
1895
1892
|
}, rawOptions);
|
|
1896
1893
|
const nullable = isNullable(schema) || void 0;
|
|
1897
|
-
const
|
|
1894
|
+
const context = {
|
|
1898
1895
|
schema,
|
|
1899
1896
|
name,
|
|
1900
1897
|
nullable,
|
|
1901
1898
|
defaultValue: schema.default === null && nullable ? void 0 : schema.default,
|
|
1902
1899
|
type: Array.isArray(schema.type) ? schema.type[0] : schema.type,
|
|
1903
1900
|
rawOptions,
|
|
1904
|
-
options
|
|
1901
|
+
options,
|
|
1902
|
+
parse: parseSchema,
|
|
1903
|
+
document,
|
|
1904
|
+
resolveRefNode,
|
|
1905
|
+
refExists,
|
|
1906
|
+
renames: ctx.renames
|
|
1905
1907
|
};
|
|
1906
1908
|
for (const rule of schemaRules) {
|
|
1907
|
-
if (!rule.match(
|
|
1908
|
-
const node = rule.convert(
|
|
1909
|
+
if (!rule.match(context)) continue;
|
|
1910
|
+
const node = rule.convert(context);
|
|
1909
1911
|
if (node) return node;
|
|
1910
1912
|
}
|
|
1911
1913
|
const emptyType = options.emptySchemaType;
|
|
@@ -2202,7 +2204,6 @@ const adapterOas = (0, _kubb_core.createAdapter)((options) => {
|
|
|
2202
2204
|
emptySchemaType,
|
|
2203
2205
|
enumSuffix
|
|
2204
2206
|
};
|
|
2205
|
-
let nameMapping = /* @__PURE__ */ new Map();
|
|
2206
2207
|
let parsedDocument = null;
|
|
2207
2208
|
const documentCache = /* @__PURE__ */ new WeakMap();
|
|
2208
2209
|
const schemasCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -2223,16 +2224,16 @@ const adapterOas = (0, _kubb_core.createAdapter)((options) => {
|
|
|
2223
2224
|
const cached = schemasCache.get(document);
|
|
2224
2225
|
if (cached) return cached;
|
|
2225
2226
|
const result = getSchemas(document, { contentType });
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
return result.schemas;
|
|
2227
|
+
schemasCache.set(document, result);
|
|
2228
|
+
return result;
|
|
2229
2229
|
}
|
|
2230
|
-
function ensureSchemaParser(document) {
|
|
2230
|
+
function ensureSchemaParser({ document, renames }) {
|
|
2231
2231
|
const cached = schemaParserCache.get(document);
|
|
2232
2232
|
if (cached) return cached;
|
|
2233
2233
|
const parser = createSchemaParser({
|
|
2234
2234
|
document,
|
|
2235
|
-
contentType
|
|
2235
|
+
contentType,
|
|
2236
|
+
renames
|
|
2236
2237
|
});
|
|
2237
2238
|
schemaParserCache.set(document, parser);
|
|
2238
2239
|
return parser;
|
|
@@ -2314,8 +2315,7 @@ const adapterOas = (0, _kubb_core.createAdapter)((options) => {
|
|
|
2314
2315
|
integerType,
|
|
2315
2316
|
unknownType,
|
|
2316
2317
|
emptySchemaType,
|
|
2317
|
-
enumSuffix
|
|
2318
|
-
nameMapping
|
|
2318
|
+
enumSuffix
|
|
2319
2319
|
};
|
|
2320
2320
|
},
|
|
2321
2321
|
get document() {
|
|
@@ -2325,24 +2325,16 @@ const adapterOas = (0, _kubb_core.createAdapter)((options) => {
|
|
|
2325
2325
|
await assertInputExists(input);
|
|
2326
2326
|
await validateDocument(await parseDocument(input), options);
|
|
2327
2327
|
},
|
|
2328
|
-
getImports(node, resolve) {
|
|
2329
|
-
return (0, _kubb_ast.collect)(node, { schema(schemaNode) {
|
|
2330
|
-
const schemaRef = (0, _kubb_ast.narrowSchema)(schemaNode, "ref");
|
|
2331
|
-
if (!schemaRef?.ref) return null;
|
|
2332
|
-
const result = resolve(nameMapping.get(schemaRef.ref) ?? (0, _kubb_ast.extractRefName)(schemaRef.ref));
|
|
2333
|
-
if (!result) return null;
|
|
2334
|
-
return _kubb_ast.ast.factory.createImport({
|
|
2335
|
-
name: [result.name],
|
|
2336
|
-
path: result.path
|
|
2337
|
-
});
|
|
2338
|
-
} });
|
|
2339
|
-
},
|
|
2340
2328
|
async parse(source) {
|
|
2341
2329
|
const document = await ensureDocument(source);
|
|
2330
|
+
const { schemas, renames } = ensureSchemas(document);
|
|
2342
2331
|
return parseInput({
|
|
2343
2332
|
document,
|
|
2344
|
-
schemas
|
|
2345
|
-
parser: ensureSchemaParser(
|
|
2333
|
+
schemas,
|
|
2334
|
+
parser: ensureSchemaParser({
|
|
2335
|
+
document,
|
|
2336
|
+
renames
|
|
2337
|
+
})
|
|
2346
2338
|
});
|
|
2347
2339
|
}
|
|
2348
2340
|
};
|