@kubb/adapter-oas 5.0.0-beta.93 → 5.0.0-beta.94
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 +644 -645
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +644 -645
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
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;
|
|
@@ -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,636 @@ 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 }) {
|
|
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
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1259
|
+
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1260
|
+
type: "ref",
|
|
1261
|
+
name: (0, _kubb_ast.extractRefName)(schema.$ref),
|
|
1262
|
+
ref: schema.$ref,
|
|
1263
|
+
schema: resolvedSchema
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Converts an `allOf` schema into a flattened node or an `IntersectionSchemaNode`.
|
|
1272
1268
|
*/
|
|
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
|
-
});
|
|
1269
|
+
function convertAllOf({ schema, name, nullable, defaultValue, rawOptions, parse, document }) {
|
|
1270
|
+
if (schema.allOf.length === 1 && !schema.properties && !(Array.isArray(schema.required) && schema.required.length) && schema.additionalProperties === void 0) {
|
|
1271
|
+
const [memberSchema] = schema.allOf;
|
|
1272
|
+
const memberNode = parse({
|
|
1273
|
+
schema: memberSchema,
|
|
1274
|
+
name
|
|
1275
|
+
}, rawOptions);
|
|
1276
|
+
const { kind: _kind, ...memberNodeProps } = memberNode;
|
|
1277
|
+
const mergedNullable = nullable || memberNode.nullable || void 0;
|
|
1278
|
+
const mergedDefault = schema.default === null && mergedNullable ? void 0 : schema.default ?? memberNode.default;
|
|
1336
1279
|
return _kubb_ast.ast.factory.createSchema({
|
|
1337
|
-
...
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1280
|
+
...memberNodeProps,
|
|
1281
|
+
name,
|
|
1282
|
+
title: schema.title ?? memberNode.title,
|
|
1283
|
+
description: schema.description ?? memberNode.description,
|
|
1284
|
+
deprecated: schema.deprecated ?? memberNode.deprecated,
|
|
1285
|
+
nullable: mergedNullable,
|
|
1286
|
+
readOnly: schema.readOnly ?? memberNode.readOnly,
|
|
1287
|
+
writeOnly: schema.writeOnly ?? memberNode.writeOnly,
|
|
1288
|
+
default: mergedDefault,
|
|
1289
|
+
examples: extractExamples(schema) ?? memberNode.examples,
|
|
1290
|
+
pattern: schema.pattern ?? ("pattern" in memberNode ? memberNode.pattern : void 0),
|
|
1291
|
+
format: schema.format ?? memberNode.format
|
|
1342
1292
|
});
|
|
1343
1293
|
}
|
|
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
|
|
1294
|
+
const filteredDiscriminantValues = [];
|
|
1295
|
+
const allOfMembers = schema.allOf.filter((item) => {
|
|
1296
|
+
if (!isReference(item) || !name) return true;
|
|
1297
|
+
const deref = resolveRef(document, item.$ref);
|
|
1298
|
+
if (!deref || !isDiscriminator(deref)) return true;
|
|
1299
|
+
const parentUnion = deref.oneOf ?? deref.anyOf;
|
|
1300
|
+
if (!parentUnion) return true;
|
|
1301
|
+
const childRef = `${SCHEMA_REF_PREFIX}${name}`;
|
|
1302
|
+
const inOneOf = parentUnion.some((oneOfItem) => isReference(oneOfItem) && oneOfItem.$ref === childRef);
|
|
1303
|
+
const inMapping = Object.values(deref.discriminator.mapping ?? {}).some((v) => v === childRef);
|
|
1304
|
+
if (inOneOf || inMapping) {
|
|
1305
|
+
const discriminatorValue = findDiscriminator(deref.discriminator.mapping, childRef);
|
|
1306
|
+
if (discriminatorValue) filteredDiscriminantValues.push({
|
|
1307
|
+
propertyName: deref.discriminator.propertyName,
|
|
1308
|
+
value: discriminatorValue
|
|
1370
1309
|
});
|
|
1310
|
+
return false;
|
|
1371
1311
|
}
|
|
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
|
-
},
|
|
1312
|
+
return true;
|
|
1313
|
+
}).map((s) => parse({
|
|
1314
|
+
schema: s,
|
|
1315
|
+
name
|
|
1316
|
+
}, rawOptions));
|
|
1317
|
+
const syntheticStart = allOfMembers.length;
|
|
1318
|
+
if (Array.isArray(schema.required) && schema.required.length) {
|
|
1319
|
+
const outerKeys = schema.properties ? new Set(Object.keys(schema.properties)) : /* @__PURE__ */ new Set();
|
|
1320
|
+
const missingRequired = schema.required.filter((key) => !outerKeys.has(key));
|
|
1321
|
+
if (missingRequired.length) {
|
|
1322
|
+
const resolvedMembers = schema.allOf.flatMap((item) => {
|
|
1323
|
+
if (!isReference(item)) return [item];
|
|
1324
|
+
const deref = resolveRef(document, item.$ref);
|
|
1325
|
+
return deref && !isReference(deref) ? [deref] : [];
|
|
1326
|
+
});
|
|
1327
|
+
for (const key of missingRequired) for (const resolved of resolvedMembers) {
|
|
1328
|
+
const prop = resolved.properties?.[key];
|
|
1329
|
+
if (prop) {
|
|
1330
|
+
const memberSchema = {
|
|
1331
|
+
properties: { [key]: prop },
|
|
1332
|
+
required: [key]
|
|
1333
|
+
};
|
|
1334
|
+
allOfMembers.push(parse({
|
|
1335
|
+
schema: memberSchema,
|
|
1411
1336
|
name
|
|
1412
1337
|
}, rawOptions));
|
|
1413
1338
|
break;
|
|
1414
1339
|
}
|
|
1415
1340
|
}
|
|
1416
1341
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
}
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1342
|
+
}
|
|
1343
|
+
if (schema.properties) {
|
|
1344
|
+
const { allOf: _allOf, ...schemaWithoutAllOf } = schema;
|
|
1345
|
+
allOfMembers.push(parse({ schema: schemaWithoutAllOf }, rawOptions));
|
|
1346
|
+
}
|
|
1347
|
+
for (const { propertyName, value } of filteredDiscriminantValues) allOfMembers.push(createDiscriminantNode({
|
|
1348
|
+
propertyName,
|
|
1349
|
+
value
|
|
1350
|
+
}));
|
|
1351
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1352
|
+
type: "intersection",
|
|
1353
|
+
members: [...(0, _kubb_ast.mergeAdjacentObjectsLazy)(allOfMembers.slice(0, syntheticStart)), ...(0, _kubb_ast.mergeAdjacentObjectsLazy)(allOfMembers.slice(syntheticStart))],
|
|
1354
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* Converts a `oneOf` / `anyOf` schema into a `UnionSchemaNode`.
|
|
1359
|
+
*/
|
|
1360
|
+
function convertUnion({ schema, name, nullable, defaultValue, rawOptions, parse, document }) {
|
|
1361
|
+
function pickDiscriminatorPropertyNode(node, propertyName) {
|
|
1362
|
+
const discriminatorProperty = _kubb_ast.ast.narrowSchema(node, "object")?.properties?.find((property) => property.name === propertyName);
|
|
1363
|
+
if (!discriminatorProperty) return null;
|
|
1425
1364
|
return _kubb_ast.ast.factory.createSchema({
|
|
1426
|
-
type: "
|
|
1427
|
-
|
|
1428
|
-
|
|
1365
|
+
type: "object",
|
|
1366
|
+
primitive: "object",
|
|
1367
|
+
properties: [discriminatorProperty]
|
|
1429
1368
|
});
|
|
1430
1369
|
}
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1370
|
+
function resolveRefSilent($ref) {
|
|
1371
|
+
if (!$ref.startsWith("#")) return null;
|
|
1372
|
+
return decodeURIComponent($ref.substring(1)).split("/").filter(Boolean).reduce((obj, key) => obj?.[key], document) ?? null;
|
|
1373
|
+
}
|
|
1374
|
+
function implicitDiscriminantValue(member) {
|
|
1375
|
+
if (!discriminator || discriminator.mapping || !isReference(member)) return null;
|
|
1376
|
+
const value = (0, _kubb_ast.extractRefName)(member.$ref);
|
|
1377
|
+
if (!value) return null;
|
|
1378
|
+
const variant = resolveRefSilent(member.$ref);
|
|
1379
|
+
if (!variant) return null;
|
|
1380
|
+
const propertyName = discriminator.propertyName;
|
|
1381
|
+
const seen = /* @__PURE__ */ new Set([member.$ref]);
|
|
1382
|
+
function constrains(v) {
|
|
1383
|
+
const prop = v.properties?.[propertyName];
|
|
1384
|
+
const resolved = prop && isReference(prop) ? resolveRefSilent(prop.$ref) : prop;
|
|
1385
|
+
if (resolved && (Array.isArray(resolved.enum) || resolved.const !== void 0)) return true;
|
|
1386
|
+
const composition = v.allOf ?? v.oneOf ?? v.anyOf;
|
|
1387
|
+
if (!composition) return false;
|
|
1388
|
+
return composition.some((m) => {
|
|
1389
|
+
if (!isReference(m)) return constrains(m);
|
|
1390
|
+
if (seen.has(m.$ref)) return false;
|
|
1391
|
+
seen.add(m.$ref);
|
|
1392
|
+
const r = resolveRefSilent(m.$ref);
|
|
1393
|
+
return r ? constrains(r) : false;
|
|
1442
1394
|
});
|
|
1443
1395
|
}
|
|
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;
|
|
1396
|
+
return constrains(variant) ? null : value;
|
|
1397
|
+
}
|
|
1398
|
+
const unionMembers = [...schema.oneOf ?? [], ...schema.anyOf ?? []];
|
|
1399
|
+
const strategy = schema.oneOf ? "one" : "any";
|
|
1400
|
+
const unionBase = {
|
|
1401
|
+
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1402
|
+
discriminatorPropertyName: isDiscriminator(schema) ? schema.discriminator.propertyName : void 0,
|
|
1403
|
+
strategy
|
|
1404
|
+
};
|
|
1405
|
+
const discriminator = isDiscriminator(schema) ? schema.discriminator : void 0;
|
|
1406
|
+
const { oneOf: _o, anyOf: _a, discriminator: _d, ...memberBaseSchema } = schema;
|
|
1407
|
+
const sharedPropertiesNode = schema.properties ? parse({
|
|
1408
|
+
schema: memberBaseSchema,
|
|
1409
|
+
name
|
|
1410
|
+
}, rawOptions) : void 0;
|
|
1411
|
+
if (sharedPropertiesNode || discriminator) {
|
|
1412
|
+
const members = unionMembers.map((s) => {
|
|
1413
|
+
const ref = isReference(s) ? s.$ref : void 0;
|
|
1414
|
+
const discriminatorValue = findDiscriminator(discriminator?.mapping, ref) ?? implicitDiscriminantValue(s);
|
|
1415
|
+
const memberNode = parse({
|
|
1416
|
+
schema: s,
|
|
1417
|
+
name
|
|
1418
|
+
}, rawOptions);
|
|
1419
|
+
if (!discriminatorValue || !discriminator) return memberNode;
|
|
1420
|
+
const narrowedDiscriminatorNode = sharedPropertiesNode ? pickDiscriminatorPropertyNode(_kubb_ast.ast.applyMacros(sharedPropertiesNode, [(0, _kubb_ast.macroDiscriminatorEnum)({
|
|
1421
|
+
propertyName: discriminator.propertyName,
|
|
1422
|
+
values: [discriminatorValue]
|
|
1423
|
+
})], { depth: "shallow" }), discriminator.propertyName) : void 0;
|
|
1512
1424
|
return _kubb_ast.ast.factory.createSchema({
|
|
1513
1425
|
type: "intersection",
|
|
1514
|
-
|
|
1515
|
-
|
|
1426
|
+
members: [memberNode, narrowedDiscriminatorNode ?? createDiscriminantNode({
|
|
1427
|
+
propertyName: discriminator.propertyName,
|
|
1428
|
+
value: discriminatorValue
|
|
1429
|
+
})]
|
|
1516
1430
|
});
|
|
1517
|
-
}
|
|
1431
|
+
});
|
|
1518
1432
|
const unionNode = _kubb_ast.ast.factory.createSchema({
|
|
1519
1433
|
type: "union",
|
|
1520
1434
|
...unionBase,
|
|
1521
|
-
members
|
|
1522
|
-
schema: s,
|
|
1523
|
-
name
|
|
1524
|
-
}, rawOptions))
|
|
1435
|
+
members
|
|
1525
1436
|
});
|
|
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");
|
|
1437
|
+
if (!sharedPropertiesNode) return unionNode;
|
|
1535
1438
|
return _kubb_ast.ast.factory.createSchema({
|
|
1536
|
-
type: "
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1439
|
+
type: "intersection",
|
|
1440
|
+
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1441
|
+
members: [unionNode, sharedPropertiesNode]
|
|
1540
1442
|
});
|
|
1541
1443
|
}
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1444
|
+
const unionNode = _kubb_ast.ast.factory.createSchema({
|
|
1445
|
+
type: "union",
|
|
1446
|
+
...unionBase,
|
|
1447
|
+
members: unionMembers.map((s) => parse({
|
|
1448
|
+
schema: s,
|
|
1449
|
+
name
|
|
1450
|
+
}, rawOptions))
|
|
1451
|
+
});
|
|
1452
|
+
return _kubb_ast.ast.applyMacros(unionNode, [_kubb_ast.macroSimplifyUnion], { depth: "shallow" });
|
|
1453
|
+
}
|
|
1454
|
+
/**
|
|
1455
|
+
* Converts an OAS 3.1 `const` schema into a null scalar or a single-value `EnumSchemaNode`.
|
|
1456
|
+
*/
|
|
1457
|
+
function convertConst({ schema, name, nullable, defaultValue }) {
|
|
1458
|
+
const constValue = schema.const;
|
|
1459
|
+
if (constValue === null) return createNullNode(schema, name);
|
|
1460
|
+
const constPrimitive = getPrimitiveType(typeof constValue === "number" ? "number" : typeof constValue === "boolean" ? "boolean" : "string");
|
|
1461
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1462
|
+
type: "enum",
|
|
1463
|
+
primitive: constPrimitive,
|
|
1464
|
+
enumValues: [constValue],
|
|
1465
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
/**
|
|
1469
|
+
* Converts a format-annotated schema into a special-type `SchemaNode`.
|
|
1470
|
+
* Returns `null` when the format should fall through to string handling (`dateType: false`).
|
|
1471
|
+
*/
|
|
1472
|
+
function convertFormat({ schema, name, nullable, defaultValue, options }) {
|
|
1473
|
+
const base = buildSchemaNode(schema, name, nullable, defaultValue);
|
|
1474
|
+
if (schema.format === "int64") return _kubb_ast.ast.factory.createSchema({
|
|
1475
|
+
type: options.integerType === "bigint" ? "bigint" : "integer",
|
|
1476
|
+
primitive: "integer",
|
|
1477
|
+
...base,
|
|
1478
|
+
min: schema.minimum,
|
|
1479
|
+
max: schema.maximum,
|
|
1480
|
+
exclusiveMinimum: typeof schema.exclusiveMinimum === "number" ? schema.exclusiveMinimum : void 0,
|
|
1481
|
+
exclusiveMaximum: typeof schema.exclusiveMaximum === "number" ? schema.exclusiveMaximum : void 0
|
|
1482
|
+
});
|
|
1483
|
+
if (schema.format === "date-time" || schema.format === "date" || schema.format === "time") {
|
|
1484
|
+
const dateType = getDateType(options, schema.format);
|
|
1485
|
+
if (!dateType) return null;
|
|
1486
|
+
if (dateType.type === "datetime") return _kubb_ast.ast.factory.createSchema({
|
|
1551
1487
|
...base,
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1488
|
+
primitive: "string",
|
|
1489
|
+
type: "datetime",
|
|
1490
|
+
offset: dateType.offset,
|
|
1491
|
+
local: dateType.local
|
|
1556
1492
|
});
|
|
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
1493
|
return _kubb_ast.ast.factory.createSchema({
|
|
1579
1494
|
...base,
|
|
1580
|
-
primitive:
|
|
1581
|
-
type:
|
|
1582
|
-
|
|
1583
|
-
min: schema.minLength,
|
|
1584
|
-
max: schema.maxLength
|
|
1585
|
-
} : {}
|
|
1495
|
+
primitive: "string",
|
|
1496
|
+
type: dateType.type,
|
|
1497
|
+
representation: dateType.representation
|
|
1586
1498
|
});
|
|
1587
1499
|
}
|
|
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
|
-
}
|
|
1500
|
+
const specialType = getSchemaType(schema.format);
|
|
1501
|
+
if (!specialType) return null;
|
|
1502
|
+
const specialPrimitive = specialType === "number" || specialType === "integer" || specialType === "bigint" ? specialType : "string";
|
|
1503
|
+
const hasLength = specialType === "url" || specialType === "uuid" || specialType === "email";
|
|
1504
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1505
|
+
...base,
|
|
1506
|
+
primitive: specialPrimitive,
|
|
1507
|
+
type: specialType,
|
|
1508
|
+
...hasLength ? {
|
|
1509
|
+
min: schema.minLength,
|
|
1510
|
+
max: schema.maxLength
|
|
1511
|
+
} : {}
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
1514
|
+
/**
|
|
1515
|
+
* Converts an `enum` schema into an `EnumSchemaNode`.
|
|
1516
|
+
*/
|
|
1517
|
+
function convertEnum({ schema, name, nullable, type, rawOptions, parse }) {
|
|
1518
|
+
if (type === "array") return parse({
|
|
1519
|
+
schema: normalizeArrayEnum(schema),
|
|
1520
|
+
name
|
|
1521
|
+
}, rawOptions);
|
|
1522
|
+
const nullInEnum = schema.enum.includes(null);
|
|
1523
|
+
const filteredValues = nullInEnum ? schema.enum.filter((v) => v !== null) : schema.enum;
|
|
1524
|
+
if (nullInEnum && filteredValues.length === 0) return createNullNode(schema, name);
|
|
1525
|
+
const enumNullable = nullable || nullInEnum || void 0;
|
|
1526
|
+
const enumDefault = schema.default === null && enumNullable ? void 0 : schema.default;
|
|
1527
|
+
const enumPrimitive = getPrimitiveType(type);
|
|
1528
|
+
const enumBase = {
|
|
1529
|
+
type: "enum",
|
|
1530
|
+
primitive: enumPrimitive,
|
|
1531
|
+
...buildSchemaNode(schema, name, enumNullable, enumDefault)
|
|
1532
|
+
};
|
|
1533
|
+
const extensionKey = enumExtensionKeys.find((key) => key in schema);
|
|
1534
|
+
const descriptionKey = enumDescriptionKeys.find((key) => key in schema);
|
|
1535
|
+
if (extensionKey || descriptionKey || enumPrimitive === "number" || enumPrimitive === "integer" || enumPrimitive === "boolean") {
|
|
1536
|
+
const enumPrimitiveType = enumPrimitive === "number" || enumPrimitive === "integer" ? "number" : enumPrimitive === "boolean" ? "boolean" : "string";
|
|
1537
|
+
const rawEnumNames = extensionKey ? schema[extensionKey] : void 0;
|
|
1538
|
+
const rawEnumDescriptions = descriptionKey ? schema[descriptionKey] : void 0;
|
|
1539
|
+
const uniqueValues = [...new Set(filteredValues)];
|
|
1540
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
1630
1541
|
return _kubb_ast.ast.factory.createSchema({
|
|
1631
1542
|
...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)
|
|
1543
|
+
primitive: enumPrimitiveType,
|
|
1544
|
+
namedEnumValues: uniqueValues.map((value, index) => ({
|
|
1545
|
+
name: String(rawEnumNames?.[index] ?? value),
|
|
1546
|
+
value,
|
|
1547
|
+
primitive: enumPrimitiveType,
|
|
1548
|
+
description: rawEnumDescriptions?.[index]
|
|
1549
|
+
})).filter((entry) => {
|
|
1550
|
+
if (seenNames.has(entry.name)) return false;
|
|
1551
|
+
seenNames.add(entry.name);
|
|
1552
|
+
return true;
|
|
1553
|
+
})
|
|
1705
1554
|
});
|
|
1706
1555
|
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1556
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1557
|
+
...enumBase,
|
|
1558
|
+
enumValues: [...new Set(filteredValues)]
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
/**
|
|
1562
|
+
* Converts an object-like schema into an `ObjectSchemaNode`.
|
|
1563
|
+
*/
|
|
1564
|
+
function convertObject({ schema, name, nullable, defaultValue, rawOptions, options, parse }) {
|
|
1565
|
+
const properties = schema.properties ? Object.entries(schema.properties).map(([propName, propSchema]) => {
|
|
1566
|
+
const required = Array.isArray(schema.required) ? schema.required.includes(propName) : !!schema.required;
|
|
1567
|
+
const resolvedPropSchema = propSchema;
|
|
1568
|
+
const propNullable = isNullable(resolvedPropSchema);
|
|
1569
|
+
const schemaNode = nameEnums(parse({
|
|
1570
|
+
schema: resolvedPropSchema,
|
|
1571
|
+
name: (0, _kubb_ast.childName)(name, propName)
|
|
1572
|
+
}, rawOptions), {
|
|
1573
|
+
parentName: name,
|
|
1574
|
+
propName,
|
|
1575
|
+
enumSuffix: options.enumSuffix
|
|
1725
1576
|
});
|
|
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)
|
|
1577
|
+
return _kubb_ast.ast.factory.createProperty({
|
|
1578
|
+
name: propName,
|
|
1579
|
+
schema: {
|
|
1580
|
+
...schemaNode,
|
|
1581
|
+
nullable: schemaNode.type === "null" ? void 0 : propNullable || void 0
|
|
1582
|
+
},
|
|
1583
|
+
required
|
|
1738
1584
|
});
|
|
1585
|
+
}) : [];
|
|
1586
|
+
const additionalProperties = schema.additionalProperties;
|
|
1587
|
+
const additionalPropertiesNode = (() => {
|
|
1588
|
+
if (additionalProperties === true) return true;
|
|
1589
|
+
if (additionalProperties === false) return false;
|
|
1590
|
+
if (additionalProperties && Object.keys(additionalProperties).length > 0) return parse({ schema: additionalProperties }, rawOptions);
|
|
1591
|
+
if (additionalProperties) return _kubb_ast.ast.factory.createSchema({ type: options.unknownType });
|
|
1592
|
+
})();
|
|
1593
|
+
const rawPatternProperties = "patternProperties" in schema ? schema.patternProperties : void 0;
|
|
1594
|
+
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;
|
|
1595
|
+
const objectNode = _kubb_ast.ast.factory.createSchema({
|
|
1596
|
+
type: "object",
|
|
1597
|
+
primitive: "object",
|
|
1598
|
+
properties,
|
|
1599
|
+
additionalProperties: additionalPropertiesNode,
|
|
1600
|
+
patternProperties,
|
|
1601
|
+
minProperties: schema.minProperties,
|
|
1602
|
+
maxProperties: schema.maxProperties,
|
|
1603
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1604
|
+
});
|
|
1605
|
+
if (isDiscriminator(schema) && schema.discriminator.mapping) {
|
|
1606
|
+
const discPropName = schema.discriminator.propertyName;
|
|
1607
|
+
const values = Object.keys(schema.discriminator.mapping);
|
|
1608
|
+
const enumName = name ? (0, _kubb_ast.enumPropName)(name, discPropName, options.enumSuffix) : void 0;
|
|
1609
|
+
return _kubb_ast.ast.applyMacros(objectNode, [(0, _kubb_ast.macroDiscriminatorEnum)({
|
|
1610
|
+
propertyName: discPropName,
|
|
1611
|
+
values,
|
|
1612
|
+
enumName
|
|
1613
|
+
})], { depth: "shallow" });
|
|
1739
1614
|
}
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1615
|
+
return objectNode;
|
|
1616
|
+
}
|
|
1617
|
+
/**
|
|
1618
|
+
* Converts an OAS 3.1 `prefixItems` tuple into a `TupleSchemaNode`.
|
|
1619
|
+
*/
|
|
1620
|
+
function convertTuple({ schema, name, nullable, defaultValue, rawOptions, parse }) {
|
|
1621
|
+
const tupleItems = (schema.prefixItems ?? []).map((item) => parse({ schema: item }, rawOptions));
|
|
1622
|
+
const rest = schema.items === false ? void 0 : !schema.items || schema.items === true ? _kubb_ast.ast.factory.createSchema({ type: "any" }) : parse({ schema: schema.items }, rawOptions);
|
|
1623
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1624
|
+
type: "tuple",
|
|
1625
|
+
primitive: "array",
|
|
1626
|
+
items: tupleItems,
|
|
1627
|
+
rest,
|
|
1628
|
+
min: schema.minItems,
|
|
1629
|
+
max: schema.maxItems,
|
|
1630
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1631
|
+
});
|
|
1632
|
+
}
|
|
1633
|
+
/**
|
|
1634
|
+
* Converts a `type: 'array'` schema into an `ArraySchemaNode`.
|
|
1635
|
+
*/
|
|
1636
|
+
function convertArray({ schema, name, nullable, defaultValue, rawOptions, options, parse }) {
|
|
1637
|
+
const rawItems = schema.items;
|
|
1638
|
+
const itemName = rawItems?.enum?.length && name ? (0, _kubb_ast.enumPropName)(null, name, options.enumSuffix) : name;
|
|
1639
|
+
const items = rawItems ? [parse({
|
|
1640
|
+
schema: rawItems,
|
|
1641
|
+
name: itemName
|
|
1642
|
+
}, rawOptions)] : [];
|
|
1643
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1644
|
+
type: "array",
|
|
1645
|
+
primitive: "array",
|
|
1646
|
+
items,
|
|
1647
|
+
min: schema.minItems,
|
|
1648
|
+
max: schema.maxItems,
|
|
1649
|
+
unique: schema.uniqueItems ?? void 0,
|
|
1650
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1651
|
+
});
|
|
1652
|
+
}
|
|
1653
|
+
/**
|
|
1654
|
+
* Converts a `type: 'string'` schema into a `StringSchemaNode`.
|
|
1655
|
+
*/
|
|
1656
|
+
function convertString({ schema, name, nullable, defaultValue }) {
|
|
1657
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1658
|
+
type: "string",
|
|
1659
|
+
primitive: "string",
|
|
1660
|
+
min: schema.minLength,
|
|
1661
|
+
max: schema.maxLength,
|
|
1662
|
+
pattern: schema.pattern,
|
|
1663
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1664
|
+
});
|
|
1665
|
+
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Converts a `type: 'number'` or `type: 'integer'` schema.
|
|
1668
|
+
*/
|
|
1669
|
+
function convertNumeric({ schema, name, nullable, defaultValue }, type) {
|
|
1670
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1671
|
+
type,
|
|
1672
|
+
primitive: type,
|
|
1673
|
+
min: schema.minimum,
|
|
1674
|
+
max: schema.maximum,
|
|
1675
|
+
exclusiveMinimum: typeof schema.exclusiveMinimum === "number" ? schema.exclusiveMinimum : void 0,
|
|
1676
|
+
exclusiveMaximum: typeof schema.exclusiveMaximum === "number" ? schema.exclusiveMaximum : void 0,
|
|
1677
|
+
multipleOf: schema.multipleOf,
|
|
1678
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1679
|
+
});
|
|
1680
|
+
}
|
|
1681
|
+
/**
|
|
1682
|
+
* Converts a `type: 'boolean'` schema.
|
|
1683
|
+
*/
|
|
1684
|
+
function convertBoolean({ schema, name, nullable, defaultValue }) {
|
|
1685
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1686
|
+
type: "boolean",
|
|
1687
|
+
primitive: "boolean",
|
|
1688
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1689
|
+
});
|
|
1690
|
+
}
|
|
1691
|
+
/**
|
|
1692
|
+
* Converts a binary string schema (`type: 'string'`, `contentMediaType: 'application/octet-stream'`)
|
|
1693
|
+
* into a `blob` node.
|
|
1694
|
+
*/
|
|
1695
|
+
function convertBinary({ schema, name, nullable, defaultValue }) {
|
|
1696
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1697
|
+
type: "blob",
|
|
1698
|
+
primitive: "string",
|
|
1699
|
+
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1700
|
+
});
|
|
1701
|
+
}
|
|
1702
|
+
/**
|
|
1703
|
+
* Converts an OAS 3.1 multi-type array (e.g. `type: ['string', 'number']`) into a `UnionSchemaNode`.
|
|
1704
|
+
*
|
|
1705
|
+
* Returns `null` when only one non-`null` type remains (e.g. `['string', 'null']`), so `parse`
|
|
1706
|
+
* falls through and handles it as that single type with nullability already folded in.
|
|
1707
|
+
*/
|
|
1708
|
+
function convertMultiType({ schema, name, nullable, defaultValue, rawOptions, parse }) {
|
|
1709
|
+
const types = schema.type;
|
|
1710
|
+
const nonNullTypes = types.filter((t) => t !== "null");
|
|
1711
|
+
if (nonNullTypes.length <= 1) return null;
|
|
1712
|
+
const arrayNullable = types.includes("null") || nullable || void 0;
|
|
1713
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1714
|
+
type: "union",
|
|
1715
|
+
members: nonNullTypes.map((t) => {
|
|
1716
|
+
return parse({
|
|
1717
|
+
schema: {
|
|
1718
|
+
...schema,
|
|
1719
|
+
type: t
|
|
1720
|
+
},
|
|
1721
|
+
name
|
|
1722
|
+
}, rawOptions);
|
|
1723
|
+
}),
|
|
1724
|
+
...buildSchemaNode(schema, name, arrayNullable, defaultValue)
|
|
1725
|
+
});
|
|
1726
|
+
}
|
|
1727
|
+
/**
|
|
1728
|
+
* Ordered schema rule table. Order is significant: composition keywords (`$ref`, `allOf`,
|
|
1729
|
+
* `oneOf`/`anyOf`) take precedence over `const`/`format`, which take precedence over the plain
|
|
1730
|
+
* `type`. The first matching rule that produces a node wins. See {@link SchemaRule} for the
|
|
1731
|
+
* match/convert/fall-through contract.
|
|
1732
|
+
*/
|
|
1733
|
+
const schemaRules = [
|
|
1734
|
+
{
|
|
1735
|
+
match: ({ schema }) => isReference(schema),
|
|
1736
|
+
convert: convertRef
|
|
1737
|
+
},
|
|
1738
|
+
{
|
|
1739
|
+
match: ({ schema }) => !!schema.allOf?.length,
|
|
1740
|
+
convert: convertAllOf
|
|
1741
|
+
},
|
|
1742
|
+
{
|
|
1743
|
+
match: ({ schema }) => !!(schema.oneOf?.length || schema.anyOf?.length),
|
|
1744
|
+
convert: convertUnion
|
|
1745
|
+
},
|
|
1746
|
+
{
|
|
1747
|
+
match: ({ schema }) => "const" in schema && schema.const !== void 0,
|
|
1748
|
+
convert: convertConst
|
|
1749
|
+
},
|
|
1750
|
+
{
|
|
1751
|
+
match: ({ schema }) => !!schema.format,
|
|
1752
|
+
convert: convertFormat
|
|
1753
|
+
},
|
|
1754
|
+
{
|
|
1755
|
+
match: ({ schema }) => isBinary(schema),
|
|
1756
|
+
convert: convertBinary
|
|
1757
|
+
},
|
|
1758
|
+
{
|
|
1759
|
+
match: ({ schema }) => Array.isArray(schema.type) && schema.type.length > 1,
|
|
1760
|
+
convert: convertMultiType
|
|
1761
|
+
},
|
|
1762
|
+
{
|
|
1763
|
+
match: ({ schema, type }) => !type && (schema.minLength !== void 0 || schema.maxLength !== void 0 || schema.pattern !== void 0),
|
|
1764
|
+
convert: convertString
|
|
1765
|
+
},
|
|
1766
|
+
{
|
|
1767
|
+
match: ({ schema, type }) => !type && (schema.minimum !== void 0 || schema.maximum !== void 0),
|
|
1768
|
+
convert: (ctx) => convertNumeric(ctx, "number")
|
|
1769
|
+
},
|
|
1770
|
+
{
|
|
1771
|
+
match: ({ schema }) => !!schema.enum?.length,
|
|
1772
|
+
convert: convertEnum
|
|
1773
|
+
},
|
|
1774
|
+
{
|
|
1775
|
+
match: ({ schema, type }) => type === "object" || !!schema.properties || !!schema.additionalProperties || "patternProperties" in schema,
|
|
1776
|
+
convert: convertObject
|
|
1777
|
+
},
|
|
1778
|
+
{
|
|
1779
|
+
match: ({ schema }) => "prefixItems" in schema,
|
|
1780
|
+
convert: convertTuple
|
|
1781
|
+
},
|
|
1782
|
+
{
|
|
1783
|
+
match: ({ schema, type }) => type === "array" || "items" in schema,
|
|
1784
|
+
convert: convertArray
|
|
1785
|
+
},
|
|
1786
|
+
{
|
|
1787
|
+
match: ({ type }) => type === "string",
|
|
1788
|
+
convert: convertString
|
|
1789
|
+
},
|
|
1790
|
+
{
|
|
1791
|
+
match: ({ type }) => type === "number",
|
|
1792
|
+
convert: (ctx) => convertNumeric(ctx, "number")
|
|
1793
|
+
},
|
|
1794
|
+
{
|
|
1795
|
+
match: ({ type }) => type === "integer",
|
|
1796
|
+
convert: (ctx) => convertNumeric(ctx, "integer")
|
|
1797
|
+
},
|
|
1798
|
+
{
|
|
1799
|
+
match: ({ type }) => type === "boolean",
|
|
1800
|
+
convert: convertBoolean
|
|
1801
|
+
},
|
|
1802
|
+
{
|
|
1803
|
+
match: ({ type }) => type === "null",
|
|
1804
|
+
convert: ({ schema, name, nullable }) => createNullNode(schema, name, nullable)
|
|
1754
1805
|
}
|
|
1806
|
+
];
|
|
1807
|
+
//#endregion
|
|
1808
|
+
//#region src/parser.ts
|
|
1809
|
+
/**
|
|
1810
|
+
* Creates the schema and operation converters bound to one OpenAPI document.
|
|
1811
|
+
*
|
|
1812
|
+
* Owns the per-instance `$ref` state (cycle detection, resolved-node cache, existence cache) and
|
|
1813
|
+
* the `parseSchema` recursion seam, then dispatches each schema through the ordered `schemaRules`
|
|
1814
|
+
* table from `converters.ts`. Every converter is a standalone function that recurses through the
|
|
1815
|
+
* `parse` function passed to it, so this file only wires state to the converters.
|
|
1816
|
+
*
|
|
1817
|
+
* @internal
|
|
1818
|
+
*/
|
|
1819
|
+
function createSchemaParser(ctx) {
|
|
1820
|
+
const document = ctx.document;
|
|
1755
1821
|
/**
|
|
1756
|
-
*
|
|
1822
|
+
* Tracks `$ref` paths that are currently being resolved to prevent infinite
|
|
1823
|
+
* recursion when schemas contain circular references (e.g. `Pet → parent → Pet`).
|
|
1757
1824
|
*/
|
|
1758
|
-
|
|
1759
|
-
return _kubb_ast.ast.factory.createSchema({
|
|
1760
|
-
type: "boolean",
|
|
1761
|
-
primitive: "boolean",
|
|
1762
|
-
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1763
|
-
});
|
|
1764
|
-
}
|
|
1825
|
+
const resolvingRefs = /* @__PURE__ */ new Set();
|
|
1765
1826
|
/**
|
|
1766
|
-
*
|
|
1767
|
-
*
|
|
1827
|
+
* Cache of `$ref` schemas already resolved in this parser instance, keyed by ref path.
|
|
1828
|
+
*
|
|
1829
|
+
* Without it, a shared schema (e.g. `customer`) is re-expanded for every `$ref` that points at
|
|
1830
|
+
* it. In cross-referenced specs like Stripe (~1400 schemas) that becomes exponential blowup,
|
|
1831
|
+
* since one schema can be referenced from dozens of parents, each re-walking its whole subtree.
|
|
1832
|
+
* Memoizing by ref path drops the work from O(2^depth) to O(N) unique schema names.
|
|
1768
1833
|
*/
|
|
1769
|
-
|
|
1770
|
-
return _kubb_ast.ast.factory.createSchema({
|
|
1771
|
-
type: "blob",
|
|
1772
|
-
primitive: "string",
|
|
1773
|
-
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1774
|
-
});
|
|
1775
|
-
}
|
|
1834
|
+
const resolvedRefCache = /* @__PURE__ */ new Map();
|
|
1776
1835
|
/**
|
|
1777
|
-
*
|
|
1778
|
-
*
|
|
1779
|
-
*
|
|
1780
|
-
* falls through and handles it as that single type with nullability already folded in.
|
|
1836
|
+
* Memoized record of whether a `$ref` path resolves to a node the document actually defines.
|
|
1837
|
+
* A circular ref still resolves to an existing target, so this stays `true` for cycles and only
|
|
1838
|
+
* goes `false` for a `$ref` that points at a component the spec never declares.
|
|
1781
1839
|
*/
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
name
|
|
1795
|
-
}, rawOptions)),
|
|
1796
|
-
...buildSchemaNode(schema, name, arrayNullable, defaultValue)
|
|
1797
|
-
});
|
|
1840
|
+
const refExistence = /* @__PURE__ */ new Map();
|
|
1841
|
+
function refExists(refPath) {
|
|
1842
|
+
if (!refExistence.has(refPath)) {
|
|
1843
|
+
let exists = false;
|
|
1844
|
+
try {
|
|
1845
|
+
exists = !!resolveRef(document, refPath);
|
|
1846
|
+
} catch {
|
|
1847
|
+
exists = false;
|
|
1848
|
+
}
|
|
1849
|
+
refExistence.set(refPath, exists);
|
|
1850
|
+
}
|
|
1851
|
+
return refExistence.get(refPath) ?? false;
|
|
1798
1852
|
}
|
|
1799
1853
|
/**
|
|
1800
|
-
*
|
|
1801
|
-
* `
|
|
1802
|
-
*
|
|
1803
|
-
* match/convert/fall-through contract.
|
|
1854
|
+
* Resolves a `$ref` to its parsed node, guarding against cycles and memoizing per instance.
|
|
1855
|
+
* Returns `null` when the ref is currently being resolved (a cycle) or cannot be resolved
|
|
1856
|
+
* (e.g. a minimal document in a unit test).
|
|
1804
1857
|
*/
|
|
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)
|
|
1858
|
+
function resolveRefNode(refPath, rawOptions) {
|
|
1859
|
+
if (resolvingRefs.has(refPath)) return null;
|
|
1860
|
+
if (!resolvedRefCache.has(refPath)) {
|
|
1861
|
+
let resolved = null;
|
|
1862
|
+
try {
|
|
1863
|
+
const referenced = resolveRef(document, refPath);
|
|
1864
|
+
if (referenced) {
|
|
1865
|
+
resolvingRefs.add(refPath);
|
|
1866
|
+
resolved = parseSchema({ schema: referenced }, rawOptions);
|
|
1867
|
+
resolvingRefs.delete(refPath);
|
|
1868
|
+
}
|
|
1869
|
+
} catch {}
|
|
1870
|
+
resolvedRefCache.set(refPath, resolved);
|
|
1877
1871
|
}
|
|
1878
|
-
|
|
1872
|
+
return resolvedRefCache.get(refPath) ?? null;
|
|
1873
|
+
}
|
|
1879
1874
|
/**
|
|
1880
1875
|
* Converts an OAS `SchemaObject` into a `SchemaNode`.
|
|
1881
1876
|
*
|
|
@@ -1894,18 +1889,22 @@ function createSchemaParser(ctx) {
|
|
|
1894
1889
|
name
|
|
1895
1890
|
}, rawOptions);
|
|
1896
1891
|
const nullable = isNullable(schema) || void 0;
|
|
1897
|
-
const
|
|
1892
|
+
const context = {
|
|
1898
1893
|
schema,
|
|
1899
1894
|
name,
|
|
1900
1895
|
nullable,
|
|
1901
1896
|
defaultValue: schema.default === null && nullable ? void 0 : schema.default,
|
|
1902
1897
|
type: Array.isArray(schema.type) ? schema.type[0] : schema.type,
|
|
1903
1898
|
rawOptions,
|
|
1904
|
-
options
|
|
1899
|
+
options,
|
|
1900
|
+
parse: parseSchema,
|
|
1901
|
+
document,
|
|
1902
|
+
resolveRefNode,
|
|
1903
|
+
refExists
|
|
1905
1904
|
};
|
|
1906
1905
|
for (const rule of schemaRules) {
|
|
1907
|
-
if (!rule.match(
|
|
1908
|
-
const node = rule.convert(
|
|
1906
|
+
if (!rule.match(context)) continue;
|
|
1907
|
+
const node = rule.convert(context);
|
|
1909
1908
|
if (node) return node;
|
|
1910
1909
|
}
|
|
1911
1910
|
const emptyType = options.emptySchemaType;
|