@kubb/adapter-oas 5.0.0-beta.91 → 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 +660 -763
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.js +660 -763
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -28,18 +28,11 @@ 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.
|
|
36
|
-
*
|
|
37
|
-
* @example
|
|
38
|
-
* ```ts
|
|
39
|
-
* import { DEFAULT_PARSER_OPTIONS, parseOas } from '@kubb/adapter-oas'
|
|
40
|
-
*
|
|
41
|
-
* const { root } = parseOas(document, { ...DEFAULT_PARSER_OPTIONS, dateType: 'date' })
|
|
42
|
-
* ```
|
|
43
36
|
*/
|
|
44
37
|
const DEFAULT_PARSER_OPTIONS = {
|
|
45
38
|
dateType: "string",
|
|
@@ -78,14 +71,6 @@ const SUPPORTED_METHODS = /* @__PURE__ */ new Set([
|
|
|
78
71
|
*
|
|
79
72
|
* A fragment that contains any of these keys carries structural meaning of its own and must stay as a separate
|
|
80
73
|
* intersection member rather than being merged into the parent.
|
|
81
|
-
*
|
|
82
|
-
* @example
|
|
83
|
-
* ```ts
|
|
84
|
-
* import { structuralKeys } from '@kubb/adapter-oas'
|
|
85
|
-
*
|
|
86
|
-
* const isStructural = Object.keys(fragment).some((key) => structuralKeys.has(key))
|
|
87
|
-
* // true when fragment has e.g. 'properties' or 'oneOf'
|
|
88
|
-
* ```
|
|
89
74
|
*/
|
|
90
75
|
const structuralKeys = /* @__PURE__ */ new Set([
|
|
91
76
|
"properties",
|
|
@@ -115,15 +100,6 @@ const specialCasedFormats = /* @__PURE__ */ new Set([
|
|
|
115
100
|
* Formats that depend on runtime options (`int64`, `date-time`, `date`, `time`) are handled
|
|
116
101
|
* separately in the parser. `ipv4` and `ipv6` map to their own dedicated schema types. `hostname`
|
|
117
102
|
* and `idn-hostname` map to `'url'` as the closest generic string-format type.
|
|
118
|
-
*
|
|
119
|
-
* @example
|
|
120
|
-
* ```ts
|
|
121
|
-
* import { formatMap } from '@kubb/adapter-oas'
|
|
122
|
-
*
|
|
123
|
-
* formatMap['uuid'] // 'uuid'
|
|
124
|
-
* formatMap['binary'] // 'blob'
|
|
125
|
-
* formatMap['float'] // 'number'
|
|
126
|
-
* ```
|
|
127
103
|
*/
|
|
128
104
|
const formatMap = {
|
|
129
105
|
uuid: "uuid",
|
|
@@ -144,24 +120,10 @@ const formatMap = {
|
|
|
144
120
|
};
|
|
145
121
|
/**
|
|
146
122
|
* Vendor extension keys that attach human-readable labels to enum values, checked in priority order.
|
|
147
|
-
*
|
|
148
|
-
* @example
|
|
149
|
-
* ```ts
|
|
150
|
-
* import { enumExtensionKeys } from '@kubb/adapter-oas'
|
|
151
|
-
*
|
|
152
|
-
* const key = enumExtensionKeys.find((k) => k in schema) // 'x-enumNames' | 'x-enum-varnames' | undefined
|
|
153
|
-
* ```
|
|
154
123
|
*/
|
|
155
124
|
const enumExtensionKeys = ["x-enumNames", "x-enum-varnames"];
|
|
156
125
|
/**
|
|
157
126
|
* Vendor extension keys that attach human-readable descriptions to enum values, checked in priority order.
|
|
158
|
-
*
|
|
159
|
-
* @example
|
|
160
|
-
* ```ts
|
|
161
|
-
* import { enumDescriptionKeys } from '@kubb/adapter-oas'
|
|
162
|
-
*
|
|
163
|
-
* const key = enumDescriptionKeys.find((k) => k in schema) // 'x-enumDescriptions' | 'x-enum-descriptions' | undefined
|
|
164
|
-
* ```
|
|
165
127
|
*/
|
|
166
128
|
const enumDescriptionKeys = ["x-enumDescriptions", "x-enum-descriptions"];
|
|
167
129
|
//#endregion
|
|
@@ -405,7 +367,7 @@ async function read(path) {
|
|
|
405
367
|
return (0, node_fs_promises.readFile)(path, { encoding: "utf8" });
|
|
406
368
|
}
|
|
407
369
|
//#endregion
|
|
408
|
-
//#region src/
|
|
370
|
+
//#region src/factory.ts
|
|
409
371
|
const urlRegExp = /^https?:\/+/i;
|
|
410
372
|
async function readSource(sourcePath) {
|
|
411
373
|
if (urlRegExp.test(sourcePath)) {
|
|
@@ -448,8 +410,6 @@ async function bundleDocument(pathOrUrl) {
|
|
|
448
410
|
await resolver(pathOrUrl);
|
|
449
411
|
return await (0, api_ref_bundler.bundle)(pathOrUrl, resolver);
|
|
450
412
|
}
|
|
451
|
-
//#endregion
|
|
452
|
-
//#region src/factory.ts
|
|
453
413
|
/**
|
|
454
414
|
* Loads and bundles an OpenAPI document, returning the raw `Document`.
|
|
455
415
|
*
|
|
@@ -519,19 +479,12 @@ async function validateDocument(document, { throwOnError = false } = {}) {
|
|
|
519
479
|
}
|
|
520
480
|
}
|
|
521
481
|
//#endregion
|
|
522
|
-
//#region src/
|
|
482
|
+
//#region src/oas.ts
|
|
523
483
|
/**
|
|
524
484
|
* Returns `true` when a schema should be treated as nullable.
|
|
525
485
|
*
|
|
526
486
|
* Recognizes all nullable signals across OAS versions: `nullable: true` (OAS 3.0),
|
|
527
487
|
* `x-nullable: true` (vendor extension), `type: 'null'`, and `type: ['null', ...]` (OAS 3.1).
|
|
528
|
-
*
|
|
529
|
-
* @example
|
|
530
|
-
* ```ts
|
|
531
|
-
* isNullable({ type: 'string', nullable: true }) // true
|
|
532
|
-
* isNullable({ type: ['string', 'null'] }) // true
|
|
533
|
-
* isNullable({ type: 'string' }) // false
|
|
534
|
-
* ```
|
|
535
488
|
*/
|
|
536
489
|
function isNullable(schema) {
|
|
537
490
|
if ((schema?.nullable ?? schema?.["x-nullable"]) === true) return true;
|
|
@@ -542,31 +495,24 @@ function isNullable(schema) {
|
|
|
542
495
|
}
|
|
543
496
|
/**
|
|
544
497
|
* Returns `true` when `obj` is an OpenAPI `$ref` pointer object.
|
|
545
|
-
*
|
|
546
|
-
* @example
|
|
547
|
-
* ```ts
|
|
548
|
-
* isReference({ $ref: '#/components/schemas/Pet' }) // true
|
|
549
|
-
* isReference({ type: 'string' }) // false
|
|
550
|
-
* ```
|
|
551
498
|
*/
|
|
552
499
|
function isReference(obj) {
|
|
553
500
|
return !!obj && typeof obj === "object" && "$ref" in obj;
|
|
554
501
|
}
|
|
555
502
|
/**
|
|
556
|
-
* Returns `true` when `obj` is a schema with a structured OAS 3.x `discriminator` object
|
|
557
|
-
*
|
|
558
|
-
* @example
|
|
559
|
-
* ```ts
|
|
560
|
-
* isDiscriminator({ discriminator: { propertyName: 'type', mapping: {} } }) // true
|
|
561
|
-
* isDiscriminator({ discriminator: 'type' }) // false (Swagger 2 string form)
|
|
562
|
-
* ```
|
|
503
|
+
* Returns `true` when `obj` is a schema with a structured OAS 3.x `discriminator` object,
|
|
504
|
+
* excluding the Swagger 2 string form.
|
|
563
505
|
*/
|
|
564
506
|
function isDiscriminator(obj) {
|
|
565
507
|
const record = obj;
|
|
566
508
|
return !!obj && !!record["discriminator"] && typeof record["discriminator"] !== "string";
|
|
567
509
|
}
|
|
568
|
-
|
|
569
|
-
|
|
510
|
+
/**
|
|
511
|
+
* Returns `true` when a schema is a binary payload: an octet-stream string body.
|
|
512
|
+
*/
|
|
513
|
+
function isBinary(schema) {
|
|
514
|
+
return schema.type === "string" && schema.contentMediaType === "application/octet-stream";
|
|
515
|
+
}
|
|
570
516
|
/**
|
|
571
517
|
* MIME type fragments that mark a media type as JSON-like.
|
|
572
518
|
*
|
|
@@ -659,6 +605,23 @@ function dereferenceWithRef(document, schema) {
|
|
|
659
605
|
};
|
|
660
606
|
return schema;
|
|
661
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
|
+
}
|
|
662
625
|
//#endregion
|
|
663
626
|
//#region src/operation.ts
|
|
664
627
|
/**
|
|
@@ -690,31 +653,22 @@ function getResponseStatusCodes({ schema }) {
|
|
|
690
653
|
function getResponseByStatusCode({ document, operation, statusCode }) {
|
|
691
654
|
const responses = operation.schema.responses;
|
|
692
655
|
if (!responses || isReference(responses)) return false;
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
if (!resolved || isReference(resolved)) return false;
|
|
699
|
-
return resolved;
|
|
700
|
-
}
|
|
701
|
-
return response;
|
|
656
|
+
return derefInPlace({
|
|
657
|
+
document,
|
|
658
|
+
container: responses,
|
|
659
|
+
key: statusCode
|
|
660
|
+
}) ?? false;
|
|
702
661
|
}
|
|
703
662
|
/**
|
|
704
663
|
* Resolves the request body (dereferencing a `$ref` in place) and returns its content map, or
|
|
705
664
|
* `undefined` when the operation has no request body.
|
|
706
665
|
*/
|
|
707
666
|
function getRequestBodyContent({ document, operation }) {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
schema.requestBody = resolved;
|
|
714
|
-
if (!resolved || isReference(resolved)) return;
|
|
715
|
-
requestBody = resolved;
|
|
716
|
-
}
|
|
717
|
-
return requestBody.content;
|
|
667
|
+
return derefInPlace({
|
|
668
|
+
document,
|
|
669
|
+
container: operation.schema,
|
|
670
|
+
key: "requestBody"
|
|
671
|
+
})?.content;
|
|
718
672
|
}
|
|
719
673
|
/**
|
|
720
674
|
* Returns the request body media type. With `mediaType` set, returns that entry or `false`.
|
|
@@ -763,14 +717,12 @@ function getOperations(document) {
|
|
|
763
717
|
if (!paths) return operations;
|
|
764
718
|
for (const path of Object.keys(paths)) {
|
|
765
719
|
if (path.startsWith("x-")) continue;
|
|
766
|
-
|
|
720
|
+
const pathItem = derefInPlace({
|
|
721
|
+
document,
|
|
722
|
+
container: paths,
|
|
723
|
+
key: path
|
|
724
|
+
});
|
|
767
725
|
if (!pathItem) continue;
|
|
768
|
-
if (isReference(pathItem)) {
|
|
769
|
-
const resolved = resolveRef(document, pathItem.$ref);
|
|
770
|
-
paths[path] = resolved;
|
|
771
|
-
if (!resolved || isReference(resolved)) continue;
|
|
772
|
-
pathItem = resolved;
|
|
773
|
-
}
|
|
774
726
|
const item = pathItem;
|
|
775
727
|
for (const method of Object.keys(item)) {
|
|
776
728
|
if (!SUPPORTED_METHODS.has(method)) continue;
|
|
@@ -786,37 +738,6 @@ function getOperations(document) {
|
|
|
786
738
|
return operations;
|
|
787
739
|
}
|
|
788
740
|
//#endregion
|
|
789
|
-
//#region src/dialect.ts
|
|
790
|
-
/**
|
|
791
|
-
* The OpenAPI / Swagger dialect, the default used by `@kubb/adapter-oas`.
|
|
792
|
-
*
|
|
793
|
-
* Implements the spec-agnostic {@link ast.SchemaDialect} contract: it isolates the
|
|
794
|
-
* decisions that differ between specs (nullability, `$ref`, discriminator, binary,
|
|
795
|
-
* ref resolution) so the converter pipeline and dispatch rules stay shared. A
|
|
796
|
-
* future adapter (e.g. AsyncAPI) ships its own dialect, `type: ['null', …]`
|
|
797
|
-
* nullability, no discriminator object, binary via `contentEncoding` and reuses
|
|
798
|
-
* the rest unchanged.
|
|
799
|
-
*
|
|
800
|
-
* Formats (`uuid`, `email`, dates, …) are intentionally NOT here: they are shared
|
|
801
|
-
* JSON Schema vocabulary, so the converters keep that common case.
|
|
802
|
-
*
|
|
803
|
-
* @example
|
|
804
|
-
* ```ts
|
|
805
|
-
* const parser = createSchemaParser(context) // uses oasDialect
|
|
806
|
-
* const parser = createSchemaParser(context, oasDialect) // explicit
|
|
807
|
-
* ```
|
|
808
|
-
*/
|
|
809
|
-
const oasDialect = _kubb_ast.ast.defineDialect({
|
|
810
|
-
name: "oas",
|
|
811
|
-
schema: {
|
|
812
|
-
isNullable,
|
|
813
|
-
isReference,
|
|
814
|
-
isDiscriminator,
|
|
815
|
-
isBinary: (schema) => schema.type === "string" && schema.contentMediaType === "application/octet-stream",
|
|
816
|
-
resolveRef
|
|
817
|
-
}
|
|
818
|
-
});
|
|
819
|
-
//#endregion
|
|
820
741
|
//#region src/resolvers.ts
|
|
821
742
|
/**
|
|
822
743
|
* Reads the server URL from the document's `servers` array at `server.index`,
|
|
@@ -924,19 +845,19 @@ function getResponseBody(responseBody, contentType) {
|
|
|
924
845
|
if (!(contentType in body.content)) return false;
|
|
925
846
|
return body.content[contentType];
|
|
926
847
|
}
|
|
927
|
-
let availableContentType;
|
|
928
848
|
const contentTypes = Object.keys(body.content);
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
849
|
+
const availableContentType = contentTypes.find(isJsonMimeType) ?? contentTypes[0];
|
|
850
|
+
if (!availableContentType) return false;
|
|
851
|
+
return body.content[availableContentType];
|
|
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
|
+
});
|
|
940
861
|
}
|
|
941
862
|
/**
|
|
942
863
|
* Returns the response schema for a given operation and HTTP status code.
|
|
@@ -949,14 +870,6 @@ function getResponseBody(responseBody, contentType) {
|
|
|
949
870
|
* getResponseSchema(document, operation, '4XX') // {}
|
|
950
871
|
* ```
|
|
951
872
|
*/
|
|
952
|
-
function resolveResponseRefs(document, operation) {
|
|
953
|
-
const responses = operation.schema.responses;
|
|
954
|
-
if (!responses) return;
|
|
955
|
-
for (const key in responses) {
|
|
956
|
-
const schema = responses[key];
|
|
957
|
-
if (schema && isReference(schema)) responses[key] = resolveRef(document, schema.$ref);
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
873
|
function getResponseSchema(document, operation, statusCode, options = {}) {
|
|
961
874
|
resolveResponseRefs(document, operation);
|
|
962
875
|
const responseBody = getResponseBody(getResponseByStatusCode({
|
|
@@ -965,7 +878,7 @@ function getResponseSchema(document, operation, statusCode, options = {}) {
|
|
|
965
878
|
statusCode
|
|
966
879
|
}), options.contentType);
|
|
967
880
|
if (responseBody === false) return {};
|
|
968
|
-
const schema =
|
|
881
|
+
const schema = responseBody.schema;
|
|
969
882
|
if (!schema) return {};
|
|
970
883
|
return dereferenceWithRef(document, schema);
|
|
971
884
|
}
|
|
@@ -995,6 +908,16 @@ function getRequestSchema(document, operation, options = {}) {
|
|
|
995
908
|
return dereferenceWithRef(document, schema);
|
|
996
909
|
}
|
|
997
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
|
+
/**
|
|
998
921
|
* Flattens a keyword-only `allOf` into its parent schema.
|
|
999
922
|
*
|
|
1000
923
|
* Only flattens when every member is a plain fragment, with no `$ref` and no structural keywords
|
|
@@ -1013,16 +936,6 @@ function getRequestSchema(document, operation, options = {}) {
|
|
|
1013
936
|
* // returned unchanged, contains a $ref
|
|
1014
937
|
* ```
|
|
1015
938
|
*/
|
|
1016
|
-
/**
|
|
1017
|
-
* Returns `true` when `fragment` carries any JSON Schema keyword that makes it
|
|
1018
|
-
* structurally significant on its own (see `structuralKeys`).
|
|
1019
|
-
*
|
|
1020
|
-
* A fragment with a structural keyword can't be safely merged into a parent schema.
|
|
1021
|
-
*/
|
|
1022
|
-
function hasStructuralKeywords(fragment) {
|
|
1023
|
-
for (const key in fragment) if (structuralKeys.has(key)) return true;
|
|
1024
|
-
return false;
|
|
1025
|
-
}
|
|
1026
939
|
function flattenSchema(schema) {
|
|
1027
940
|
if (!schema?.allOf || schema.allOf.length === 0) return schema ?? null;
|
|
1028
941
|
const allOfFragments = schema.allOf;
|
|
@@ -1274,7 +1187,7 @@ function getResponseBodyContentTypes(document, operation, statusCode) {
|
|
|
1274
1187
|
return body.content ? Object.keys(body.content) : [];
|
|
1275
1188
|
}
|
|
1276
1189
|
//#endregion
|
|
1277
|
-
//#region src/
|
|
1190
|
+
//#region src/converters.ts
|
|
1278
1191
|
/**
|
|
1279
1192
|
* Normalizes malformed `{ type: 'array', enum: [...] }` schemas by moving enum values into items.
|
|
1280
1193
|
*
|
|
@@ -1298,7 +1211,7 @@ function normalizeArrayEnum(schema) {
|
|
|
1298
1211
|
* Builds a `null` scalar node carrying the schema's documentation. Shared by the `const: null`
|
|
1299
1212
|
* and the drf-spectacular `NullEnum` (`{ enum: [null] }`) branches, which render identically.
|
|
1300
1213
|
*/
|
|
1301
|
-
function
|
|
1214
|
+
function createNullNode(schema, name, nullable) {
|
|
1302
1215
|
return _kubb_ast.ast.factory.createSchema({
|
|
1303
1216
|
type: "null",
|
|
1304
1217
|
primitive: "null",
|
|
@@ -1328,653 +1241,636 @@ function nameEnums(node, options) {
|
|
|
1328
1241
|
return named;
|
|
1329
1242
|
}
|
|
1330
1243
|
/**
|
|
1331
|
-
*
|
|
1332
|
-
*
|
|
1333
|
-
* Returns closures that share mutable state (`resolvingRefs` set for cycle detection).
|
|
1334
|
-
* Each converter branch (`convertRef`, `convertAllOf`, etc.) mutually recursively calls `parseSchema`,
|
|
1335
|
-
* which works because function declarations hoist.
|
|
1244
|
+
* Converts a `$ref` schema into a `RefSchemaNode`.
|
|
1336
1245
|
*
|
|
1337
|
-
*
|
|
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`.
|
|
1338
1250
|
*/
|
|
1339
|
-
function
|
|
1340
|
-
const
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
exists = false;
|
|
1368
|
-
}
|
|
1369
|
-
refExistence.set(refPath, exists);
|
|
1370
|
-
}
|
|
1371
|
-
return refExistence.get(refPath) ?? false;
|
|
1372
|
-
}
|
|
1373
|
-
/**
|
|
1374
|
-
* Converts a `$ref` schema into a `RefSchemaNode`.
|
|
1375
|
-
*
|
|
1376
|
-
* The resolved schema is stored in `node.schema`. Usage-site sibling fields
|
|
1377
|
-
* (description, readOnly, nullable, etc.) are stored directly on the ref node.
|
|
1378
|
-
* Use `syncSchemaRef(node)` in printers to get a merged view of both.
|
|
1379
|
-
* Circular refs are detected via `resolvingRefs` and leave `schema` as `undefined`.
|
|
1380
|
-
*/
|
|
1381
|
-
function convertRef({ schema, name, nullable, defaultValue, rawOptions }) {
|
|
1382
|
-
let resolvedSchema = null;
|
|
1383
|
-
const refPath = schema.$ref;
|
|
1384
|
-
if (refPath && !resolvingRefs.has(refPath)) {
|
|
1385
|
-
if (!resolvedRefCache.has(refPath)) {
|
|
1386
|
-
try {
|
|
1387
|
-
const referenced = dialect.schema.resolveRef(document, refPath);
|
|
1388
|
-
if (referenced) {
|
|
1389
|
-
resolvingRefs.add(refPath);
|
|
1390
|
-
resolvedSchema = parseSchema({ schema: referenced }, rawOptions);
|
|
1391
|
-
resolvingRefs.delete(refPath);
|
|
1392
|
-
}
|
|
1393
|
-
} catch {}
|
|
1394
|
-
resolvedRefCache.set(refPath, resolvedSchema);
|
|
1395
|
-
}
|
|
1396
|
-
resolvedSchema = resolvedRefCache.get(refPath) ?? null;
|
|
1397
|
-
}
|
|
1398
|
-
if (refPath && document.components && !refExists(refPath)) return _kubb_ast.ast.factory.createSchema({
|
|
1399
|
-
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1400
|
-
type: "unknown"
|
|
1401
|
-
});
|
|
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`.
|
|
1268
|
+
*/
|
|
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;
|
|
1402
1279
|
return _kubb_ast.ast.factory.createSchema({
|
|
1403
|
-
...
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
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
|
|
1408
1292
|
});
|
|
1409
1293
|
}
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
if (
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
const
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
name,
|
|
1426
|
-
title: schema.title ?? memberNode.title,
|
|
1427
|
-
description: schema.description ?? memberNode.description,
|
|
1428
|
-
deprecated: schema.deprecated ?? memberNode.deprecated,
|
|
1429
|
-
nullable: mergedNullable,
|
|
1430
|
-
readOnly: schema.readOnly ?? memberNode.readOnly,
|
|
1431
|
-
writeOnly: schema.writeOnly ?? memberNode.writeOnly,
|
|
1432
|
-
default: mergedDefault,
|
|
1433
|
-
examples: extractExamples(schema) ?? memberNode.examples,
|
|
1434
|
-
pattern: schema.pattern ?? ("pattern" in memberNode ? memberNode.pattern : void 0),
|
|
1435
|
-
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
|
|
1436
1309
|
});
|
|
1310
|
+
return false;
|
|
1437
1311
|
}
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
if (Array.isArray(schema.required) && schema.required.length) {
|
|
1463
|
-
const outerKeys = schema.properties ? new Set(Object.keys(schema.properties)) : /* @__PURE__ */ new Set();
|
|
1464
|
-
const missingRequired = schema.required.filter((key) => !outerKeys.has(key));
|
|
1465
|
-
if (missingRequired.length) {
|
|
1466
|
-
const resolvedMembers = schema.allOf.flatMap((item) => {
|
|
1467
|
-
if (!dialect.schema.isReference(item)) return [item];
|
|
1468
|
-
const deref = dialect.schema.resolveRef(document, item.$ref);
|
|
1469
|
-
return deref && !dialect.schema.isReference(deref) ? [deref] : [];
|
|
1470
|
-
});
|
|
1471
|
-
for (const key of missingRequired) for (const resolved of resolvedMembers) if (resolved.properties?.[key]) {
|
|
1472
|
-
allOfMembers.push(parseSchema({
|
|
1473
|
-
schema: {
|
|
1474
|
-
properties: { [key]: resolved.properties[key] },
|
|
1475
|
-
required: [key]
|
|
1476
|
-
},
|
|
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,
|
|
1477
1336
|
name
|
|
1478
1337
|
}, rawOptions));
|
|
1479
1338
|
break;
|
|
1480
1339
|
}
|
|
1481
1340
|
}
|
|
1482
1341
|
}
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
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;
|
|
1491
1364
|
return _kubb_ast.ast.factory.createSchema({
|
|
1492
|
-
type: "
|
|
1493
|
-
|
|
1494
|
-
|
|
1365
|
+
type: "object",
|
|
1366
|
+
primitive: "object",
|
|
1367
|
+
properties: [discriminatorProperty]
|
|
1495
1368
|
});
|
|
1496
1369
|
}
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
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;
|
|
1508
1394
|
});
|
|
1509
1395
|
}
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
const unionMembers = [...schema.oneOf ?? [], ...schema.anyOf ?? []];
|
|
1539
|
-
const strategy = schema.oneOf ? "one" : "any";
|
|
1540
|
-
const unionBase = {
|
|
1541
|
-
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1542
|
-
discriminatorPropertyName: dialect.schema.isDiscriminator(schema) ? schema.discriminator.propertyName : void 0,
|
|
1543
|
-
strategy
|
|
1544
|
-
};
|
|
1545
|
-
const discriminator = dialect.schema.isDiscriminator(schema) ? schema.discriminator : void 0;
|
|
1546
|
-
const { oneOf: _o, anyOf: _a, discriminator: _d, ...memberBaseSchema } = schema;
|
|
1547
|
-
const sharedPropertiesNode = schema.properties ? parseSchema({
|
|
1548
|
-
schema: memberBaseSchema,
|
|
1549
|
-
name
|
|
1550
|
-
}, rawOptions) : void 0;
|
|
1551
|
-
if (sharedPropertiesNode || discriminator) {
|
|
1552
|
-
const members = unionMembers.map((s) => {
|
|
1553
|
-
const ref = dialect.schema.isReference(s) ? s.$ref : void 0;
|
|
1554
|
-
const discriminatorValue = findDiscriminator(discriminator?.mapping, ref) ?? implicitDiscriminantValue(s);
|
|
1555
|
-
const memberNode = parseSchema({
|
|
1556
|
-
schema: s,
|
|
1557
|
-
name
|
|
1558
|
-
}, rawOptions);
|
|
1559
|
-
if (!discriminatorValue || !discriminator) return memberNode;
|
|
1560
|
-
const narrowedDiscriminatorNode = sharedPropertiesNode ? pickDiscriminatorPropertyNode(_kubb_ast.ast.applyMacros(sharedPropertiesNode, [(0, _kubb_ast.macroDiscriminatorEnum)({
|
|
1561
|
-
propertyName: discriminator.propertyName,
|
|
1562
|
-
values: [discriminatorValue]
|
|
1563
|
-
})], { depth: "shallow" }), discriminator.propertyName) : void 0;
|
|
1564
|
-
return _kubb_ast.ast.factory.createSchema({
|
|
1565
|
-
type: "intersection",
|
|
1566
|
-
members: [memberNode, narrowedDiscriminatorNode ?? createDiscriminantNode({
|
|
1567
|
-
propertyName: discriminator.propertyName,
|
|
1568
|
-
value: discriminatorValue
|
|
1569
|
-
})]
|
|
1570
|
-
});
|
|
1571
|
-
});
|
|
1572
|
-
const unionNode = _kubb_ast.ast.factory.createSchema({
|
|
1573
|
-
type: "union",
|
|
1574
|
-
...unionBase,
|
|
1575
|
-
members
|
|
1576
|
-
});
|
|
1577
|
-
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;
|
|
1578
1424
|
return _kubb_ast.ast.factory.createSchema({
|
|
1579
1425
|
type: "intersection",
|
|
1580
|
-
|
|
1581
|
-
|
|
1426
|
+
members: [memberNode, narrowedDiscriminatorNode ?? createDiscriminantNode({
|
|
1427
|
+
propertyName: discriminator.propertyName,
|
|
1428
|
+
value: discriminatorValue
|
|
1429
|
+
})]
|
|
1582
1430
|
});
|
|
1583
|
-
}
|
|
1431
|
+
});
|
|
1584
1432
|
const unionNode = _kubb_ast.ast.factory.createSchema({
|
|
1585
1433
|
type: "union",
|
|
1586
1434
|
...unionBase,
|
|
1587
|
-
members
|
|
1588
|
-
schema: s,
|
|
1589
|
-
name
|
|
1590
|
-
}, rawOptions))
|
|
1435
|
+
members
|
|
1591
1436
|
});
|
|
1592
|
-
|
|
1593
|
-
}
|
|
1594
|
-
/**
|
|
1595
|
-
* Converts an OAS 3.1 `const` schema into a null scalar or a single-value `EnumSchemaNode`.
|
|
1596
|
-
*/
|
|
1597
|
-
function convertConst({ schema, name, nullable, defaultValue }) {
|
|
1598
|
-
const constValue = schema.const;
|
|
1599
|
-
if (constValue === null) return createNullSchema(schema, name);
|
|
1600
|
-
const constPrimitive = getPrimitiveType(typeof constValue === "number" ? "number" : typeof constValue === "boolean" ? "boolean" : "string");
|
|
1437
|
+
if (!sharedPropertiesNode) return unionNode;
|
|
1601
1438
|
return _kubb_ast.ast.factory.createSchema({
|
|
1602
|
-
type: "
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1439
|
+
type: "intersection",
|
|
1440
|
+
...buildSchemaNode(schema, name, nullable, defaultValue),
|
|
1441
|
+
members: [unionNode, sharedPropertiesNode]
|
|
1606
1442
|
});
|
|
1607
1443
|
}
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
type: "url",
|
|
1652
|
-
min: schema.minLength,
|
|
1653
|
-
max: schema.maxLength
|
|
1654
|
-
});
|
|
1655
|
-
if (specialType === "ipv4") return _kubb_ast.ast.factory.createSchema({
|
|
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({
|
|
1656
1487
|
...base,
|
|
1657
1488
|
primitive: "string",
|
|
1658
|
-
type: "
|
|
1489
|
+
type: "datetime",
|
|
1490
|
+
offset: dateType.offset,
|
|
1491
|
+
local: dateType.local
|
|
1659
1492
|
});
|
|
1660
|
-
|
|
1493
|
+
return _kubb_ast.ast.factory.createSchema({
|
|
1661
1494
|
...base,
|
|
1662
1495
|
primitive: "string",
|
|
1663
|
-
type:
|
|
1496
|
+
type: dateType.type,
|
|
1497
|
+
representation: dateType.representation
|
|
1664
1498
|
});
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1499
|
+
}
|
|
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 ? {
|
|
1669
1509
|
min: schema.minLength,
|
|
1670
1510
|
max: schema.maxLength
|
|
1671
|
-
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
writeOnly: schema.writeOnly,
|
|
1702
|
-
default: enumDefault,
|
|
1703
|
-
examples: extractExamples(schema),
|
|
1704
|
-
format: schema.format
|
|
1705
|
-
};
|
|
1706
|
-
const extensionKey = enumExtensionKeys.find((key) => key in schema);
|
|
1707
|
-
const descriptionKey = enumDescriptionKeys.find((key) => key in schema);
|
|
1708
|
-
if (extensionKey || descriptionKey || enumPrimitive === "number" || enumPrimitive === "integer" || enumPrimitive === "boolean") {
|
|
1709
|
-
const enumPrimitiveType = enumPrimitive === "number" || enumPrimitive === "integer" ? "number" : enumPrimitive === "boolean" ? "boolean" : "string";
|
|
1710
|
-
const rawEnumNames = extensionKey ? schema[extensionKey] : void 0;
|
|
1711
|
-
const rawEnumDescriptions = descriptionKey ? schema[descriptionKey] : void 0;
|
|
1712
|
-
const uniqueValues = [...new Set(filteredValues)];
|
|
1713
|
-
const seenNames = /* @__PURE__ */ new Set();
|
|
1714
|
-
return _kubb_ast.ast.factory.createSchema({
|
|
1715
|
-
...enumBase,
|
|
1716
|
-
primitive: enumPrimitiveType,
|
|
1717
|
-
namedEnumValues: uniqueValues.map((value, index) => ({
|
|
1718
|
-
name: String(rawEnumNames?.[index] ?? value),
|
|
1719
|
-
value,
|
|
1720
|
-
primitive: enumPrimitiveType,
|
|
1721
|
-
description: rawEnumDescriptions?.[index]
|
|
1722
|
-
})).filter((entry) => {
|
|
1723
|
-
if (seenNames.has(entry.name)) return false;
|
|
1724
|
-
seenNames.add(entry.name);
|
|
1725
|
-
return true;
|
|
1726
|
-
})
|
|
1727
|
-
});
|
|
1728
|
-
}
|
|
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();
|
|
1729
1541
|
return _kubb_ast.ast.factory.createSchema({
|
|
1730
1542
|
...enumBase,
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
const schemaNode = nameEnums(parseSchema({
|
|
1743
|
-
schema: resolvedPropSchema,
|
|
1744
|
-
name: (0, _kubb_ast.childName)(name, propName)
|
|
1745
|
-
}, rawOptions), {
|
|
1746
|
-
parentName: name,
|
|
1747
|
-
propName,
|
|
1748
|
-
enumSuffix: options.enumSuffix
|
|
1749
|
-
});
|
|
1750
|
-
return _kubb_ast.ast.factory.createProperty({
|
|
1751
|
-
name: propName,
|
|
1752
|
-
schema: {
|
|
1753
|
-
...schemaNode,
|
|
1754
|
-
nullable: schemaNode.type === "null" ? void 0 : propNullable || void 0
|
|
1755
|
-
},
|
|
1756
|
-
required
|
|
1757
|
-
});
|
|
1758
|
-
}) : [];
|
|
1759
|
-
const additionalProperties = schema.additionalProperties;
|
|
1760
|
-
const additionalPropertiesNode = (() => {
|
|
1761
|
-
if (additionalProperties === true) return true;
|
|
1762
|
-
if (additionalProperties === false) return false;
|
|
1763
|
-
if (additionalProperties && Object.keys(additionalProperties).length > 0) return parseSchema({ schema: additionalProperties }, rawOptions);
|
|
1764
|
-
if (additionalProperties) return _kubb_ast.ast.factory.createSchema({ type: options.unknownType });
|
|
1765
|
-
})();
|
|
1766
|
-
const rawPatternProperties = "patternProperties" in schema ? schema.patternProperties : void 0;
|
|
1767
|
-
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;
|
|
1768
|
-
const objectNode = _kubb_ast.ast.factory.createSchema({
|
|
1769
|
-
type: "object",
|
|
1770
|
-
primitive: "object",
|
|
1771
|
-
properties,
|
|
1772
|
-
additionalProperties: additionalPropertiesNode,
|
|
1773
|
-
patternProperties,
|
|
1774
|
-
minProperties: schema.minProperties,
|
|
1775
|
-
maxProperties: schema.maxProperties,
|
|
1776
|
-
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1777
|
-
});
|
|
1778
|
-
if (dialect.schema.isDiscriminator(schema) && schema.discriminator.mapping) {
|
|
1779
|
-
const discPropName = schema.discriminator.propertyName;
|
|
1780
|
-
const values = Object.keys(schema.discriminator.mapping);
|
|
1781
|
-
const enumName = name ? (0, _kubb_ast.enumPropName)(name, discPropName, options.enumSuffix) : void 0;
|
|
1782
|
-
return _kubb_ast.ast.applyMacros(objectNode, [(0, _kubb_ast.macroDiscriminatorEnum)({
|
|
1783
|
-
propertyName: discPropName,
|
|
1784
|
-
values,
|
|
1785
|
-
enumName
|
|
1786
|
-
})], { depth: "shallow" });
|
|
1787
|
-
}
|
|
1788
|
-
return objectNode;
|
|
1789
|
-
}
|
|
1790
|
-
/**
|
|
1791
|
-
* Converts an OAS 3.1 `prefixItems` tuple into a `TupleSchemaNode`.
|
|
1792
|
-
*/
|
|
1793
|
-
function convertTuple({ schema, name, nullable, defaultValue, rawOptions }) {
|
|
1794
|
-
const tupleItems = (schema.prefixItems ?? []).map((item) => parseSchema({ schema: item }, rawOptions));
|
|
1795
|
-
const rest = schema.items === false ? void 0 : !schema.items || schema.items === true ? _kubb_ast.ast.factory.createSchema({ type: "any" }) : parseSchema({ schema: schema.items }, rawOptions);
|
|
1796
|
-
return _kubb_ast.ast.factory.createSchema({
|
|
1797
|
-
type: "tuple",
|
|
1798
|
-
primitive: "array",
|
|
1799
|
-
items: tupleItems,
|
|
1800
|
-
rest,
|
|
1801
|
-
min: schema.minItems,
|
|
1802
|
-
max: schema.maxItems,
|
|
1803
|
-
...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
|
+
})
|
|
1804
1554
|
});
|
|
1805
1555
|
}
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
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
|
|
1824
1576
|
});
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
primitive: "string",
|
|
1833
|
-
min: schema.minLength,
|
|
1834
|
-
max: schema.maxLength,
|
|
1835
|
-
pattern: schema.pattern,
|
|
1836
|
-
...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
|
|
1837
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" });
|
|
1838
1614
|
}
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
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)
|
|
1853
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;
|
|
1854
1821
|
/**
|
|
1855
|
-
*
|
|
1822
|
+
* Tracks `$ref` paths that are currently being resolved to prevent infinite
|
|
1823
|
+
* recursion when schemas contain circular references (e.g. `Pet → parent → Pet`).
|
|
1856
1824
|
*/
|
|
1857
|
-
|
|
1858
|
-
return _kubb_ast.ast.factory.createSchema({
|
|
1859
|
-
type: "boolean",
|
|
1860
|
-
primitive: "boolean",
|
|
1861
|
-
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1862
|
-
});
|
|
1863
|
-
}
|
|
1825
|
+
const resolvingRefs = /* @__PURE__ */ new Set();
|
|
1864
1826
|
/**
|
|
1865
|
-
*
|
|
1866
|
-
*
|
|
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.
|
|
1867
1833
|
*/
|
|
1868
|
-
|
|
1869
|
-
return _kubb_ast.ast.factory.createSchema({
|
|
1870
|
-
type: "blob",
|
|
1871
|
-
primitive: "string",
|
|
1872
|
-
...buildSchemaNode(schema, name, nullable, defaultValue)
|
|
1873
|
-
});
|
|
1874
|
-
}
|
|
1834
|
+
const resolvedRefCache = /* @__PURE__ */ new Map();
|
|
1875
1835
|
/**
|
|
1876
|
-
*
|
|
1877
|
-
*
|
|
1878
|
-
*
|
|
1879
|
-
* 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.
|
|
1880
1839
|
*/
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
name
|
|
1894
|
-
}, rawOptions)),
|
|
1895
|
-
...buildSchemaNode(schema, name, arrayNullable, defaultValue)
|
|
1896
|
-
});
|
|
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;
|
|
1897
1852
|
}
|
|
1898
1853
|
/**
|
|
1899
|
-
*
|
|
1900
|
-
* `
|
|
1901
|
-
*
|
|
1902
|
-
* 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).
|
|
1903
1857
|
*/
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
{
|
|
1918
|
-
match: ({ schema }) => "const" in schema && schema.const !== void 0,
|
|
1919
|
-
convert: convertConst
|
|
1920
|
-
},
|
|
1921
|
-
{
|
|
1922
|
-
match: ({ schema }) => !!schema.format,
|
|
1923
|
-
convert: convertFormat
|
|
1924
|
-
},
|
|
1925
|
-
{
|
|
1926
|
-
match: ({ schema }) => dialect.schema.isBinary(schema),
|
|
1927
|
-
convert: convertBlob
|
|
1928
|
-
},
|
|
1929
|
-
{
|
|
1930
|
-
match: ({ schema }) => Array.isArray(schema.type) && schema.type.length > 1,
|
|
1931
|
-
convert: convertMultiType
|
|
1932
|
-
},
|
|
1933
|
-
{
|
|
1934
|
-
match: ({ schema, type }) => !type && (schema.minLength !== void 0 || schema.maxLength !== void 0 || schema.pattern !== void 0),
|
|
1935
|
-
convert: convertString
|
|
1936
|
-
},
|
|
1937
|
-
{
|
|
1938
|
-
match: ({ schema, type }) => !type && (schema.minimum !== void 0 || schema.maximum !== void 0),
|
|
1939
|
-
convert: (ctx) => convertNumeric(ctx, "number")
|
|
1940
|
-
},
|
|
1941
|
-
{
|
|
1942
|
-
match: ({ schema }) => !!schema.enum?.length,
|
|
1943
|
-
convert: convertEnum
|
|
1944
|
-
},
|
|
1945
|
-
{
|
|
1946
|
-
match: ({ schema, type }) => type === "object" || !!schema.properties || !!schema.additionalProperties || "patternProperties" in schema,
|
|
1947
|
-
convert: convertObject
|
|
1948
|
-
},
|
|
1949
|
-
{
|
|
1950
|
-
match: ({ schema }) => "prefixItems" in schema,
|
|
1951
|
-
convert: convertTuple
|
|
1952
|
-
},
|
|
1953
|
-
{
|
|
1954
|
-
match: ({ schema, type }) => type === "array" || "items" in schema,
|
|
1955
|
-
convert: convertArray
|
|
1956
|
-
},
|
|
1957
|
-
{
|
|
1958
|
-
match: ({ type }) => type === "string",
|
|
1959
|
-
convert: convertString
|
|
1960
|
-
},
|
|
1961
|
-
{
|
|
1962
|
-
match: ({ type }) => type === "number",
|
|
1963
|
-
convert: (ctx) => convertNumeric(ctx, "number")
|
|
1964
|
-
},
|
|
1965
|
-
{
|
|
1966
|
-
match: ({ type }) => type === "integer",
|
|
1967
|
-
convert: (ctx) => convertNumeric(ctx, "integer")
|
|
1968
|
-
},
|
|
1969
|
-
{
|
|
1970
|
-
match: ({ type }) => type === "boolean",
|
|
1971
|
-
convert: convertBoolean
|
|
1972
|
-
},
|
|
1973
|
-
{
|
|
1974
|
-
match: ({ type }) => type === "null",
|
|
1975
|
-
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);
|
|
1976
1871
|
}
|
|
1977
|
-
|
|
1872
|
+
return resolvedRefCache.get(refPath) ?? null;
|
|
1873
|
+
}
|
|
1978
1874
|
/**
|
|
1979
1875
|
* Converts an OAS `SchemaObject` into a `SchemaNode`.
|
|
1980
1876
|
*
|
|
@@ -1992,19 +1888,23 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
1992
1888
|
schema: flattenedSchema,
|
|
1993
1889
|
name
|
|
1994
1890
|
}, rawOptions);
|
|
1995
|
-
const nullable =
|
|
1996
|
-
const
|
|
1891
|
+
const nullable = isNullable(schema) || void 0;
|
|
1892
|
+
const context = {
|
|
1997
1893
|
schema,
|
|
1998
1894
|
name,
|
|
1999
1895
|
nullable,
|
|
2000
1896
|
defaultValue: schema.default === null && nullable ? void 0 : schema.default,
|
|
2001
1897
|
type: Array.isArray(schema.type) ? schema.type[0] : schema.type,
|
|
2002
1898
|
rawOptions,
|
|
2003
|
-
options
|
|
1899
|
+
options,
|
|
1900
|
+
parse: parseSchema,
|
|
1901
|
+
document,
|
|
1902
|
+
resolveRefNode,
|
|
1903
|
+
refExists
|
|
2004
1904
|
};
|
|
2005
1905
|
for (const rule of schemaRules) {
|
|
2006
|
-
if (!rule.match(
|
|
2007
|
-
const node = rule.convert(
|
|
1906
|
+
if (!rule.match(context)) continue;
|
|
1907
|
+
const node = rule.convert(context);
|
|
2008
1908
|
if (node) return node;
|
|
2009
1909
|
}
|
|
2010
1910
|
const emptyType = options.emptySchemaType;
|
|
@@ -2062,7 +1962,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2062
1962
|
const keys = [];
|
|
2063
1963
|
for (const key in schema.properties) {
|
|
2064
1964
|
const prop = schema.properties[key];
|
|
2065
|
-
if (prop && !
|
|
1965
|
+
if (prop && !isReference(prop) && prop[flag]) keys.push(key);
|
|
2066
1966
|
}
|
|
2067
1967
|
return keys.length ? keys : null;
|
|
2068
1968
|
}
|
|
@@ -2129,7 +2029,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
|
|
|
2129
2029
|
});
|
|
2130
2030
|
});
|
|
2131
2031
|
const pathItem = document.paths?.[operation.path];
|
|
2132
|
-
const pathItemDoc = pathItem && !
|
|
2032
|
+
const pathItemDoc = pathItem && !isReference(pathItem) ? pathItem : void 0;
|
|
2133
2033
|
const pickDoc = (key) => {
|
|
2134
2034
|
const own = operation.schema[key];
|
|
2135
2035
|
if (typeof own === "string") return own;
|
|
@@ -2321,13 +2221,10 @@ const adapterOas = (0, _kubb_core.createAdapter)((options) => {
|
|
|
2321
2221
|
function ensureSchemas(document) {
|
|
2322
2222
|
const cached = schemasCache.get(document);
|
|
2323
2223
|
if (cached) return cached;
|
|
2324
|
-
const
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
});
|
|
2329
|
-
schemasCache.set(document, promise);
|
|
2330
|
-
return promise;
|
|
2224
|
+
const result = getSchemas(document, { contentType });
|
|
2225
|
+
nameMapping = result.nameMapping;
|
|
2226
|
+
schemasCache.set(document, result.schemas);
|
|
2227
|
+
return result.schemas;
|
|
2331
2228
|
}
|
|
2332
2229
|
function ensureSchemaParser(document) {
|
|
2333
2230
|
const cached = schemaParserCache.get(document);
|
|
@@ -2443,7 +2340,7 @@ const adapterOas = (0, _kubb_core.createAdapter)((options) => {
|
|
|
2443
2340
|
const document = await ensureDocument(source);
|
|
2444
2341
|
return parseInput({
|
|
2445
2342
|
document,
|
|
2446
|
-
schemas:
|
|
2343
|
+
schemas: ensureSchemas(document),
|
|
2447
2344
|
parser: ensureSchemaParser(document)
|
|
2448
2345
|
});
|
|
2449
2346
|
}
|