@kubb/adapter-oas 5.0.0-alpha.1 → 5.0.0-alpha.11
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 +432 -220
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +71 -27
- package/dist/index.js +433 -221
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/adapter.ts +28 -8
- package/src/constants.ts +19 -9
- package/src/oas/Oas.ts +16 -9
- package/src/oas/types.ts +19 -0
- package/src/oas/utils.ts +1 -1
- package/src/parser.ts +209 -228
- package/src/types.ts +41 -19
- package/src/utils.ts +168 -0
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./chunk--u3MIqq1.js";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { collect, createOperation, createParameter, createProperty, createResponse, createRoot, createSchema, narrowSchema, schemaTypes, transform } from "@kubb/ast";
|
|
4
|
-
import {
|
|
4
|
+
import { createAdapter } from "@kubb/core";
|
|
5
5
|
import { bundle, loadConfig } from "@redocly/openapi-core";
|
|
6
6
|
import yaml from "@stoplight/yaml";
|
|
7
7
|
import { isRef } from "oas/types";
|
|
@@ -11,6 +11,110 @@ import swagger2openapi from "swagger2openapi";
|
|
|
11
11
|
import jsonpointer from "jsonpointer";
|
|
12
12
|
import BaseOas from "oas";
|
|
13
13
|
import { matchesMimeType } from "oas/utils";
|
|
14
|
+
//#region src/constants.ts
|
|
15
|
+
/**
|
|
16
|
+
* Default values for all `Options` fields.
|
|
17
|
+
*/
|
|
18
|
+
const DEFAULT_PARSER_OPTIONS = {
|
|
19
|
+
dateType: "string",
|
|
20
|
+
integerType: "number",
|
|
21
|
+
unknownType: "any",
|
|
22
|
+
emptySchemaType: "any",
|
|
23
|
+
enumSuffix: "enum"
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* OpenAPI version string written into merged document stubs.
|
|
27
|
+
*/
|
|
28
|
+
const MERGE_OPENAPI_VERSION = "3.0.0";
|
|
29
|
+
/**
|
|
30
|
+
* Fallback `info.title` used when merging multiple API documents.
|
|
31
|
+
*/
|
|
32
|
+
const MERGE_DEFAULT_TITLE = "Merged API";
|
|
33
|
+
/**
|
|
34
|
+
* Fallback `info.version` used when merging multiple API documents.
|
|
35
|
+
*/
|
|
36
|
+
const MERGE_DEFAULT_VERSION = "1.0.0";
|
|
37
|
+
/**
|
|
38
|
+
* JSON Schema keywords that indicate structural composition.
|
|
39
|
+
* A schema fragment containing any of these keys must not be inlined into its
|
|
40
|
+
* parent during `allOf` flattening — it carries semantic meaning of its own.
|
|
41
|
+
*/
|
|
42
|
+
const structuralKeys = new Set([
|
|
43
|
+
"properties",
|
|
44
|
+
"items",
|
|
45
|
+
"additionalProperties",
|
|
46
|
+
"oneOf",
|
|
47
|
+
"anyOf",
|
|
48
|
+
"allOf",
|
|
49
|
+
"not"
|
|
50
|
+
]);
|
|
51
|
+
/**
|
|
52
|
+
* Maps OAS/JSON Schema `format` strings to their Kubb `SchemaType` equivalents.
|
|
53
|
+
*
|
|
54
|
+
* Only formats that need a type different from the raw OAS `type` are listed.
|
|
55
|
+
* `int64`, `date-time`, `date`, and `time` are handled separately because their
|
|
56
|
+
* mapping depends on runtime parser options.
|
|
57
|
+
*
|
|
58
|
+
* Note: `ipv4`, `ipv6`, and `hostname` map to `'url'` — the closest supported
|
|
59
|
+
* scalar type in the Kubb AST, even though these are not strictly URLs.
|
|
60
|
+
*/
|
|
61
|
+
const formatMap = {
|
|
62
|
+
uuid: "uuid",
|
|
63
|
+
email: "email",
|
|
64
|
+
"idn-email": "email",
|
|
65
|
+
uri: "url",
|
|
66
|
+
"uri-reference": "url",
|
|
67
|
+
url: "url",
|
|
68
|
+
ipv4: "url",
|
|
69
|
+
ipv6: "url",
|
|
70
|
+
hostname: "url",
|
|
71
|
+
"idn-hostname": "url",
|
|
72
|
+
binary: "blob",
|
|
73
|
+
byte: "blob",
|
|
74
|
+
int32: "integer",
|
|
75
|
+
float: "number",
|
|
76
|
+
double: "number"
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Exhaustive list of media types that Kubb recognizes.
|
|
80
|
+
*/
|
|
81
|
+
const knownMediaTypes = new Set([
|
|
82
|
+
"application/json",
|
|
83
|
+
"application/xml",
|
|
84
|
+
"application/x-www-form-urlencoded",
|
|
85
|
+
"application/octet-stream",
|
|
86
|
+
"application/pdf",
|
|
87
|
+
"application/zip",
|
|
88
|
+
"application/graphql",
|
|
89
|
+
"multipart/form-data",
|
|
90
|
+
"text/plain",
|
|
91
|
+
"text/html",
|
|
92
|
+
"text/csv",
|
|
93
|
+
"text/xml",
|
|
94
|
+
"image/png",
|
|
95
|
+
"image/jpeg",
|
|
96
|
+
"image/gif",
|
|
97
|
+
"image/webp",
|
|
98
|
+
"image/svg+xml",
|
|
99
|
+
"audio/mpeg",
|
|
100
|
+
"video/mp4"
|
|
101
|
+
]);
|
|
102
|
+
/**
|
|
103
|
+
* Vendor extension keys used to attach human-readable labels to enum values.
|
|
104
|
+
* Checked in priority order: the first key found wins.
|
|
105
|
+
*/
|
|
106
|
+
const enumExtensionKeys = ["x-enumNames", "x-enum-varnames"];
|
|
107
|
+
/**
|
|
108
|
+
* Scalar primitive schema types used for union member simplification.
|
|
109
|
+
*/
|
|
110
|
+
const SCALAR_PRIMITIVE_TYPES = new Set([
|
|
111
|
+
"string",
|
|
112
|
+
"number",
|
|
113
|
+
"integer",
|
|
114
|
+
"bigint",
|
|
115
|
+
"boolean"
|
|
116
|
+
]);
|
|
117
|
+
//#endregion
|
|
14
118
|
//#region src/oas/resolveServerUrl.ts
|
|
15
119
|
/**
|
|
16
120
|
* Resolves an OpenAPI server URL by substituting `{variable}` placeholders.
|
|
@@ -89,6 +193,27 @@ function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
|
|
|
89
193
|
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
90
194
|
}
|
|
91
195
|
//#endregion
|
|
196
|
+
//#region ../../internals/utils/src/names.ts
|
|
197
|
+
/**
|
|
198
|
+
* Returns a unique name by appending an incrementing numeric suffix when the name has already been used.
|
|
199
|
+
* Mutates `data` in-place as a usage counter so subsequent calls remain consistent.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* const seen: Record<string, number> = {}
|
|
203
|
+
* getUniqueName('Foo', seen) // 'Foo'
|
|
204
|
+
* getUniqueName('Foo', seen) // 'Foo2'
|
|
205
|
+
* getUniqueName('Foo', seen) // 'Foo3'
|
|
206
|
+
*/
|
|
207
|
+
function getUniqueName(originalName, data) {
|
|
208
|
+
let used = data[originalName] || 0;
|
|
209
|
+
if (used) {
|
|
210
|
+
data[originalName] = ++used;
|
|
211
|
+
originalName += used;
|
|
212
|
+
}
|
|
213
|
+
data[originalName] = 1;
|
|
214
|
+
return originalName;
|
|
215
|
+
}
|
|
216
|
+
//#endregion
|
|
92
217
|
//#region ../../internals/utils/src/reserved.ts
|
|
93
218
|
/**
|
|
94
219
|
* Returns `true` when `name` is a syntactically valid JavaScript variable name.
|
|
@@ -205,91 +330,6 @@ var URLPath = class {
|
|
|
205
330
|
}
|
|
206
331
|
};
|
|
207
332
|
//#endregion
|
|
208
|
-
//#region src/constants.ts
|
|
209
|
-
/**
|
|
210
|
-
* OpenAPI version string written into merged document stubs.
|
|
211
|
-
*/
|
|
212
|
-
const MERGE_OPENAPI_VERSION = "3.0.0";
|
|
213
|
-
/**
|
|
214
|
-
* Fallback `info.title` used when merging multiple API documents.
|
|
215
|
-
*/
|
|
216
|
-
const MERGE_DEFAULT_TITLE = "Merged API";
|
|
217
|
-
/**
|
|
218
|
-
* Fallback `info.version` used when merging multiple API documents.
|
|
219
|
-
*/
|
|
220
|
-
const MERGE_DEFAULT_VERSION = "1.0.0";
|
|
221
|
-
/**
|
|
222
|
-
* JSON Schema keywords that indicate structural composition.
|
|
223
|
-
* A schema fragment containing any of these keys must not be inlined into its
|
|
224
|
-
* parent during `allOf` flattening — it carries semantic meaning of its own.
|
|
225
|
-
*/
|
|
226
|
-
const structuralKeys = new Set([
|
|
227
|
-
"properties",
|
|
228
|
-
"items",
|
|
229
|
-
"additionalProperties",
|
|
230
|
-
"oneOf",
|
|
231
|
-
"anyOf",
|
|
232
|
-
"allOf",
|
|
233
|
-
"not"
|
|
234
|
-
]);
|
|
235
|
-
/**
|
|
236
|
-
* Maps OAS/JSON Schema `format` strings to their Kubb `SchemaType` equivalents.
|
|
237
|
-
*
|
|
238
|
-
* Only formats that need a type different from the raw OAS `type` are listed.
|
|
239
|
-
* `int64`, `date-time`, `date`, and `time` are handled separately because their
|
|
240
|
-
* mapping depends on runtime parser options.
|
|
241
|
-
*
|
|
242
|
-
* Note: `ipv4`, `ipv6`, and `hostname` map to `'url'` — the closest supported
|
|
243
|
-
* scalar type in the Kubb AST, even though these are not strictly URLs.
|
|
244
|
-
*/
|
|
245
|
-
const formatMap = {
|
|
246
|
-
uuid: "uuid",
|
|
247
|
-
email: "email",
|
|
248
|
-
"idn-email": "email",
|
|
249
|
-
uri: "url",
|
|
250
|
-
"uri-reference": "url",
|
|
251
|
-
url: "url",
|
|
252
|
-
ipv4: "url",
|
|
253
|
-
ipv6: "url",
|
|
254
|
-
hostname: "url",
|
|
255
|
-
"idn-hostname": "url",
|
|
256
|
-
binary: "blob",
|
|
257
|
-
byte: "blob",
|
|
258
|
-
int32: "integer",
|
|
259
|
-
float: "number",
|
|
260
|
-
double: "number"
|
|
261
|
-
};
|
|
262
|
-
/**
|
|
263
|
-
* Exhaustive list of media types that Kubb recognizes.
|
|
264
|
-
* Kept as a module-level constant to avoid re-allocating the array on every call.
|
|
265
|
-
*/
|
|
266
|
-
const knownMediaTypes = [
|
|
267
|
-
"application/json",
|
|
268
|
-
"application/xml",
|
|
269
|
-
"application/x-www-form-urlencoded",
|
|
270
|
-
"application/octet-stream",
|
|
271
|
-
"application/pdf",
|
|
272
|
-
"application/zip",
|
|
273
|
-
"application/graphql",
|
|
274
|
-
"multipart/form-data",
|
|
275
|
-
"text/plain",
|
|
276
|
-
"text/html",
|
|
277
|
-
"text/csv",
|
|
278
|
-
"text/xml",
|
|
279
|
-
"image/png",
|
|
280
|
-
"image/jpeg",
|
|
281
|
-
"image/gif",
|
|
282
|
-
"image/webp",
|
|
283
|
-
"image/svg+xml",
|
|
284
|
-
"audio/mpeg",
|
|
285
|
-
"video/mp4"
|
|
286
|
-
];
|
|
287
|
-
/**
|
|
288
|
-
* Vendor extension keys used to attach human-readable labels to enum values.
|
|
289
|
-
* Checked in priority order: the first key found wins.
|
|
290
|
-
*/
|
|
291
|
-
const enumExtensionKeys = ["x-enumNames", "x-enum-varnames"];
|
|
292
|
-
//#endregion
|
|
293
333
|
//#region src/oas/Oas.ts
|
|
294
334
|
/**
|
|
295
335
|
* Prefix used to create synthetic `$ref` values for anonymous (inline) discriminator schemas.
|
|
@@ -501,8 +541,15 @@ var Oas = class extends BaseOas {
|
|
|
501
541
|
if (!schema) return;
|
|
502
542
|
return this.dereferenceWithRef(schema);
|
|
503
543
|
}
|
|
504
|
-
|
|
505
|
-
|
|
544
|
+
/**
|
|
545
|
+
* Returns all resolved parameters for an operation, merging path-level and operation-level
|
|
546
|
+
* parameters and deduplicating by `in:name` (operation-level takes precedence).
|
|
547
|
+
*
|
|
548
|
+
* oas v31+ filters out `$ref` parameters in `getParameters()`, so this method accesses the
|
|
549
|
+
* raw `operation.schema.parameters` and path-item parameters directly and resolves `$ref`
|
|
550
|
+
* pointers via `dereferenceWithRef` to preserve backward compatibility.
|
|
551
|
+
*/
|
|
552
|
+
getParameters(operation) {
|
|
506
553
|
const resolveParams = (params) => params.map((p) => this.dereferenceWithRef(p)).filter((p) => !!p && typeof p === "object" && "in" in p && "name" in p);
|
|
507
554
|
const operationParams = resolveParams(operation.schema?.parameters || []);
|
|
508
555
|
const pathItem = this.api?.paths?.[operation.path];
|
|
@@ -510,7 +557,11 @@ var Oas = class extends BaseOas {
|
|
|
510
557
|
const paramMap = /* @__PURE__ */ new Map();
|
|
511
558
|
for (const p of pathLevelParams) if (p.name && p.in) paramMap.set(`${p.in}:${p.name}`, p);
|
|
512
559
|
for (const p of operationParams) if (p.name && p.in) paramMap.set(`${p.in}:${p.name}`, p);
|
|
513
|
-
|
|
560
|
+
return Array.from(paramMap.values());
|
|
561
|
+
}
|
|
562
|
+
getParametersSchema(operation, inKey) {
|
|
563
|
+
const { contentType = operation.getContentType() } = this.#options;
|
|
564
|
+
const params = this.getParameters(operation).filter((v) => v.in === inKey);
|
|
514
565
|
if (!params.length) return null;
|
|
515
566
|
return params.reduce((schema, pathParameters) => {
|
|
516
567
|
const property = pathParameters.content?.[contentType]?.schema ?? pathParameters.schema;
|
|
@@ -900,17 +951,137 @@ function resolveCollisions(schemasWithMeta) {
|
|
|
900
951
|
};
|
|
901
952
|
}
|
|
902
953
|
//#endregion
|
|
903
|
-
//#region src/
|
|
954
|
+
//#region src/utils.ts
|
|
904
955
|
/**
|
|
905
|
-
*
|
|
956
|
+
* Extracts the schema name from a `$ref` string.
|
|
957
|
+
* For `#/components/schemas/Order` this returns `'Order'`.
|
|
958
|
+
* Falls back to the full ref string when no slash is present.
|
|
906
959
|
*/
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
960
|
+
function extractRefName($ref) {
|
|
961
|
+
return $ref.split("/").at(-1) ?? $ref;
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Replaces the discriminator property's schema inside an `ObjectSchemaNode`
|
|
965
|
+
* with an enum of the given `values`.
|
|
966
|
+
*
|
|
967
|
+
* - When `enumName` is provided the enum is named, which lets printers emit a
|
|
968
|
+
* standalone enum declaration + type reference (e.g. `PetTypeEnum`).
|
|
969
|
+
* - When `enumName` is omitted the enum stays anonymous, so printers inline it
|
|
970
|
+
* as a literal union (e.g. `'dog'`).
|
|
971
|
+
*
|
|
972
|
+
* Returns the node unchanged when it is not an object or lacks the target property.
|
|
973
|
+
*/
|
|
974
|
+
function applyDiscriminatorEnum({ node, propertyName, values, enumName }) {
|
|
975
|
+
if (node.type !== "object" || !node.properties?.length) return node;
|
|
976
|
+
if (!node.properties.some((prop) => prop.name === propertyName)) return node;
|
|
977
|
+
return createSchema({
|
|
978
|
+
...node,
|
|
979
|
+
properties: node.properties.map((prop) => {
|
|
980
|
+
if (prop.name !== propertyName) return prop;
|
|
981
|
+
const enumSchema = createSchema({
|
|
982
|
+
type: "enum",
|
|
983
|
+
primitive: "string",
|
|
984
|
+
enumValues: values,
|
|
985
|
+
name: enumName,
|
|
986
|
+
readOnly: prop.schema.readOnly,
|
|
987
|
+
writeOnly: prop.schema.writeOnly
|
|
988
|
+
});
|
|
989
|
+
return createProperty({
|
|
990
|
+
...prop,
|
|
991
|
+
schema: enumSchema
|
|
992
|
+
});
|
|
993
|
+
})
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Merges consecutive anonymous (`name`-less) `ObjectSchemaNode`s in `members` into a
|
|
998
|
+
* single object by combining their `properties` arrays.
|
|
999
|
+
*
|
|
1000
|
+
* Only adjacent pairs are merged — non-object or named nodes act as boundaries.
|
|
1001
|
+
* This collapses patterns like `Address & { streetNumber } & { streetName }` into
|
|
1002
|
+
* `Address & { streetNumber; streetName }`.
|
|
1003
|
+
*/
|
|
1004
|
+
function mergeAdjacentAnonymousObjects(members) {
|
|
1005
|
+
return members.reduce((acc, member) => {
|
|
1006
|
+
const obj = narrowSchema(member, "object");
|
|
1007
|
+
if (obj && !obj.name) {
|
|
1008
|
+
const prev = acc[acc.length - 1];
|
|
1009
|
+
const prevObj = prev ? narrowSchema(prev, "object") : null;
|
|
1010
|
+
if (prevObj && !prevObj.name) {
|
|
1011
|
+
acc[acc.length - 1] = createSchema({
|
|
1012
|
+
...prevObj,
|
|
1013
|
+
properties: [...prevObj.properties ?? [], ...obj.properties ?? []]
|
|
1014
|
+
});
|
|
1015
|
+
return acc;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
acc.push(member);
|
|
1019
|
+
return acc;
|
|
1020
|
+
}, []);
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Simplifies a union member list by removing `enum` nodes whose `primitive` type is
|
|
1024
|
+
* already represented by a broader scalar node in the same union.
|
|
1025
|
+
*
|
|
1026
|
+
* For example `['placed', 'approved'] | string` collapses to `string` because
|
|
1027
|
+
* `string` subsumes all string literals. `'' | string` similarly becomes `string`.
|
|
1028
|
+
*
|
|
1029
|
+
* Only scalar primitives (`string`, `number`, `integer`, `bigint`, `boolean`) are
|
|
1030
|
+
* considered — object, array, and ref members are left untouched.
|
|
1031
|
+
*
|
|
1032
|
+
* Const-derived enums (those without an `enumType`, produced from an OpenAPI `const`
|
|
1033
|
+
* keyword) are **never** removed — `'accepted' | string` must stay as-is because the
|
|
1034
|
+
* literal is intentional.
|
|
1035
|
+
*/
|
|
1036
|
+
function simplifyUnionMembers(members) {
|
|
1037
|
+
const scalarPrimitives = new Set(members.filter((m) => SCALAR_PRIMITIVE_TYPES.has(m.type)).map((m) => m.type));
|
|
1038
|
+
if (!scalarPrimitives.size) return members;
|
|
1039
|
+
return members.filter((m) => {
|
|
1040
|
+
if (m.type !== "enum") return true;
|
|
1041
|
+
const prim = m.primitive;
|
|
1042
|
+
if (!prim) return true;
|
|
1043
|
+
if (!m.enumType) return true;
|
|
1044
|
+
if (scalarPrimitives.has(prim)) return false;
|
|
1045
|
+
if ((prim === "integer" || prim === "number") && (scalarPrimitives.has("integer") || scalarPrimitives.has("number"))) return false;
|
|
1046
|
+
return true;
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* `nameMapping`, and calls `resolve` to obtain the `{ name, path }` pair for
|
|
1051
|
+
* each import. When `oas` is supplied, only `$ref`s that are resolvable in the
|
|
1052
|
+
* spec are included; omit it to skip the existence check.
|
|
1053
|
+
*
|
|
1054
|
+
* This function is the pure, state-free alternative to `OasParser.getImports`.
|
|
1055
|
+
* Because it receives `nameMapping` explicitly it can be called without holding
|
|
1056
|
+
* a reference to the parser or the OAS instance.
|
|
1057
|
+
*
|
|
1058
|
+
* @example
|
|
1059
|
+
* ```ts
|
|
1060
|
+
* // Use adapter state directly — no parser reference needed
|
|
1061
|
+
* const imports = getImports({
|
|
1062
|
+
* node: schemaNode,
|
|
1063
|
+
* nameMapping: adapter.options.nameMapping,
|
|
1064
|
+
* resolve: (schemaName) => ({
|
|
1065
|
+
* name: schemaManager.getName(schemaName, { type: 'type' }),
|
|
1066
|
+
* path: schemaManager.getFile(schemaName).path,
|
|
1067
|
+
* }),
|
|
1068
|
+
* })
|
|
1069
|
+
* ```
|
|
1070
|
+
*/
|
|
1071
|
+
function getImports({ node, nameMapping, resolve }) {
|
|
1072
|
+
return collect(node, { schema(schemaNode) {
|
|
1073
|
+
if (schemaNode.type !== "ref" || !schemaNode.ref) return;
|
|
1074
|
+
const rawName = extractRefName(schemaNode.ref);
|
|
1075
|
+
const result = resolve(nameMapping.get(rawName) ?? rawName);
|
|
1076
|
+
if (!result) return;
|
|
1077
|
+
return {
|
|
1078
|
+
name: [result.name],
|
|
1079
|
+
path: result.path
|
|
1080
|
+
};
|
|
1081
|
+
} });
|
|
1082
|
+
}
|
|
1083
|
+
//#endregion
|
|
1084
|
+
//#region src/parser.ts
|
|
914
1085
|
/**
|
|
915
1086
|
* Looks up the Kubb `SchemaType` for a given OAS `format` string.
|
|
916
1087
|
* Returns `undefined` for formats not in `formatMap` (e.g. `int64`, `date-time`),
|
|
@@ -920,14 +1091,6 @@ function formatToSchemaType(format) {
|
|
|
920
1091
|
return formatMap[format];
|
|
921
1092
|
}
|
|
922
1093
|
/**
|
|
923
|
-
* Extracts the final path segment of a JSON Pointer `$ref` string.
|
|
924
|
-
* For `#/components/schemas/Order` this returns `'Order'`.
|
|
925
|
-
* Falls back to the full ref string when no slash is present.
|
|
926
|
-
*/
|
|
927
|
-
function extractRefName($ref) {
|
|
928
|
-
return $ref.split("/").at(-1) ?? $ref;
|
|
929
|
-
}
|
|
930
|
-
/**
|
|
931
1094
|
* Maps an OAS primitive type string to its `PrimitiveSchemaType` equivalent.
|
|
932
1095
|
* Numeric types (`number`, `integer`, `bigint`) are returned unchanged;
|
|
933
1096
|
* `boolean` maps to `'boolean'`; everything else defaults to `'string'`.
|
|
@@ -942,27 +1105,7 @@ function getPrimitiveType(type) {
|
|
|
942
1105
|
* Returns `undefined` for content types not present in `KNOWN_MEDIA_TYPES`.
|
|
943
1106
|
*/
|
|
944
1107
|
function toMediaType(contentType) {
|
|
945
|
-
return knownMediaTypes.
|
|
946
|
-
}
|
|
947
|
-
/**
|
|
948
|
-
* When a discriminator is present, replaces the discriminator property's schema with
|
|
949
|
-
* an enum of the mapping keys so downstream code emits a precise literal-union type.
|
|
950
|
-
* Returns the original schema unchanged when there is no discriminator or no mapping.
|
|
951
|
-
*/
|
|
952
|
-
function applyDiscriminatorEnum(schema) {
|
|
953
|
-
if (!isDiscriminator(schema)) return schema;
|
|
954
|
-
const propName = schema.discriminator.propertyName;
|
|
955
|
-
if (!schema.properties?.[propName]) return schema;
|
|
956
|
-
return {
|
|
957
|
-
...schema,
|
|
958
|
-
properties: {
|
|
959
|
-
...schema.properties,
|
|
960
|
-
[propName]: {
|
|
961
|
-
...schema.properties[propName],
|
|
962
|
-
enum: schema.discriminator.mapping ? Object.keys(schema.discriminator.mapping) : void 0
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
};
|
|
1108
|
+
return knownMediaTypes.has(contentType) ? contentType : void 0;
|
|
966
1109
|
}
|
|
967
1110
|
/**
|
|
968
1111
|
* Creates an OAS parser that converts an OpenAPI/Swagger spec into
|
|
@@ -988,6 +1131,8 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
988
1131
|
contentType,
|
|
989
1132
|
collisionDetection
|
|
990
1133
|
});
|
|
1134
|
+
const usedEnumNames = {};
|
|
1135
|
+
const isLegacyNaming = collisionDetection === false;
|
|
991
1136
|
/**
|
|
992
1137
|
* Maps an `'any' | 'unknown' | 'void'` option string to the corresponding `SchemaType` constant.
|
|
993
1138
|
* Used for both `unknownType` (unannotated schemas) and `emptySchemaType` (empty `{}` schemas).
|
|
@@ -1034,7 +1179,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1034
1179
|
* Shared metadata fields included in every `createSchema` call.
|
|
1035
1180
|
* Centralizes the common properties so sub-handlers don't repeat them.
|
|
1036
1181
|
*/
|
|
1037
|
-
function
|
|
1182
|
+
function renderSchemaBase(schema, name, nullable, defaultValue) {
|
|
1038
1183
|
return {
|
|
1039
1184
|
name,
|
|
1040
1185
|
nullable,
|
|
@@ -1055,18 +1200,17 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1055
1200
|
* reflected in generated JSDoc and type modifiers.
|
|
1056
1201
|
*/
|
|
1057
1202
|
function convertRef({ schema, nullable, defaultValue }) {
|
|
1058
|
-
const schemaObject = schema;
|
|
1059
1203
|
return createSchema({
|
|
1060
1204
|
type: "ref",
|
|
1061
|
-
name: extractRefName(
|
|
1062
|
-
ref:
|
|
1205
|
+
name: extractRefName(schema.$ref),
|
|
1206
|
+
ref: schema.$ref,
|
|
1063
1207
|
nullable,
|
|
1064
|
-
description:
|
|
1065
|
-
deprecated:
|
|
1066
|
-
readOnly:
|
|
1067
|
-
writeOnly:
|
|
1068
|
-
pattern:
|
|
1069
|
-
example:
|
|
1208
|
+
description: schema.description,
|
|
1209
|
+
deprecated: schema.deprecated,
|
|
1210
|
+
readOnly: schema.readOnly,
|
|
1211
|
+
writeOnly: schema.writeOnly,
|
|
1212
|
+
pattern: schema.type === "string" ? schema.pattern : void 0,
|
|
1213
|
+
example: schema.example,
|
|
1070
1214
|
default: defaultValue
|
|
1071
1215
|
});
|
|
1072
1216
|
}
|
|
@@ -1117,6 +1261,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1117
1261
|
const inMapping = Object.values(deref.discriminator.mapping ?? {}).some((v) => v === childRef);
|
|
1118
1262
|
return !inOneOf && !inMapping;
|
|
1119
1263
|
}).map((s) => convertSchema({ schema: s }, options));
|
|
1264
|
+
const syntheticStart = allOfMembers.length;
|
|
1120
1265
|
if (Array.isArray(schema.required) && schema.required.length) {
|
|
1121
1266
|
const outerKeys = schema.properties ? new Set(Object.keys(schema.properties)) : /* @__PURE__ */ new Set();
|
|
1122
1267
|
const missingRequired = schema.required.filter((key) => !outerKeys.has(key));
|
|
@@ -1141,8 +1286,8 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1141
1286
|
}
|
|
1142
1287
|
return createSchema({
|
|
1143
1288
|
type: "intersection",
|
|
1144
|
-
members: allOfMembers,
|
|
1145
|
-
...
|
|
1289
|
+
members: [...allOfMembers.slice(0, syntheticStart), ...mergeAdjacentAnonymousObjects(allOfMembers.slice(syntheticStart))],
|
|
1290
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1146
1291
|
});
|
|
1147
1292
|
}
|
|
1148
1293
|
/**
|
|
@@ -1156,25 +1301,39 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1156
1301
|
function convertUnion({ schema, name, nullable, defaultValue, options }) {
|
|
1157
1302
|
const unionMembers = [...schema.oneOf ?? [], ...schema.anyOf ?? []];
|
|
1158
1303
|
const unionBase = {
|
|
1159
|
-
...
|
|
1304
|
+
...renderSchemaBase(schema, name, nullable, defaultValue),
|
|
1160
1305
|
discriminatorPropertyName: isDiscriminator(schema) ? schema.discriminator.propertyName : void 0
|
|
1161
1306
|
};
|
|
1162
1307
|
if (schema.properties) {
|
|
1163
1308
|
const { oneOf: _oneOf, anyOf: _anyOf, ...schemaWithoutUnion } = schema;
|
|
1164
|
-
const
|
|
1309
|
+
const discriminator = isDiscriminator(schema) ? schema.discriminator : void 0;
|
|
1310
|
+
const sharedPropertiesNode = convertSchema({
|
|
1311
|
+
schema: discriminator ? Object.fromEntries(Object.entries(schemaWithoutUnion).filter(([key]) => key !== "discriminator")) : schemaWithoutUnion,
|
|
1312
|
+
name: isLegacyNaming ? void 0 : name
|
|
1313
|
+
}, options);
|
|
1165
1314
|
return createSchema({
|
|
1166
1315
|
type: "union",
|
|
1167
1316
|
...unionBase,
|
|
1168
|
-
members: unionMembers.map((s) =>
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1317
|
+
members: unionMembers.map((s) => {
|
|
1318
|
+
const ref = isReference(s) ? s.$ref : void 0;
|
|
1319
|
+
const discriminatorValue = discriminator?.mapping && ref ? Object.entries(discriminator.mapping).find(([, v]) => v === ref)?.[0] : void 0;
|
|
1320
|
+
let propertiesNode = sharedPropertiesNode;
|
|
1321
|
+
if (discriminatorValue && discriminator) propertiesNode = applyDiscriminatorEnum({
|
|
1322
|
+
node: propertiesNode,
|
|
1323
|
+
propertyName: discriminator.propertyName,
|
|
1324
|
+
values: [discriminatorValue]
|
|
1325
|
+
});
|
|
1326
|
+
return createSchema({
|
|
1327
|
+
type: "intersection",
|
|
1328
|
+
members: [convertSchema({ schema: s }, options), propertiesNode]
|
|
1329
|
+
});
|
|
1330
|
+
})
|
|
1172
1331
|
});
|
|
1173
1332
|
}
|
|
1174
1333
|
return createSchema({
|
|
1175
1334
|
type: "union",
|
|
1176
1335
|
...unionBase,
|
|
1177
|
-
members: unionMembers.map((s) => convertSchema({ schema: s }, options))
|
|
1336
|
+
members: simplifyUnionMembers(unionMembers.map((s) => convertSchema({ schema: s }, options)))
|
|
1178
1337
|
});
|
|
1179
1338
|
}
|
|
1180
1339
|
/**
|
|
@@ -1197,7 +1356,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1197
1356
|
type: "enum",
|
|
1198
1357
|
primitive: getPrimitiveType(typeof constValue === "number" ? "number" : typeof constValue === "boolean" ? "boolean" : "string"),
|
|
1199
1358
|
enumValues: [constValue],
|
|
1200
|
-
...
|
|
1359
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1201
1360
|
});
|
|
1202
1361
|
}
|
|
1203
1362
|
/**
|
|
@@ -1206,7 +1365,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1206
1365
|
* (i.e. `format: 'date-time'` with `dateType: false`).
|
|
1207
1366
|
*/
|
|
1208
1367
|
function convertFormat({ schema, name, nullable, defaultValue, mergedOptions }) {
|
|
1209
|
-
const base =
|
|
1368
|
+
const base = renderSchemaBase(schema, name, nullable, defaultValue);
|
|
1210
1369
|
if (schema.format === "int64") return createSchema({
|
|
1211
1370
|
type: mergedOptions.integerType === "bigint" ? "bigint" : "integer",
|
|
1212
1371
|
primitive: "integer",
|
|
@@ -1241,6 +1400,11 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1241
1400
|
primitive: specialPrimitive,
|
|
1242
1401
|
type: specialType
|
|
1243
1402
|
});
|
|
1403
|
+
if (specialType === "url") return createSchema({
|
|
1404
|
+
...base,
|
|
1405
|
+
primitive: "string",
|
|
1406
|
+
type: "url"
|
|
1407
|
+
});
|
|
1244
1408
|
return createSchema({
|
|
1245
1409
|
...base,
|
|
1246
1410
|
primitive: specialPrimitive,
|
|
@@ -1259,9 +1423,8 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1259
1423
|
*/
|
|
1260
1424
|
function convertEnum({ schema, name, nullable, type, options }) {
|
|
1261
1425
|
if (type === "array") {
|
|
1262
|
-
const rawSchema = schema;
|
|
1263
1426
|
const normalizedItems = {
|
|
1264
|
-
...typeof
|
|
1427
|
+
...typeof schema.items === "object" && !Array.isArray(schema.items) ? schema.items : {},
|
|
1265
1428
|
enum: schema.enum
|
|
1266
1429
|
};
|
|
1267
1430
|
const { enum: _enum, ...schemaWithoutEnum } = schema;
|
|
@@ -1340,23 +1503,62 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1340
1503
|
* - not required + not nullable → `optional: true`
|
|
1341
1504
|
* - not required + nullable → `nullish: true`
|
|
1342
1505
|
*/
|
|
1506
|
+
/**
|
|
1507
|
+
* Builds the propagation name for a child property during recursive schema conversion.
|
|
1508
|
+
*
|
|
1509
|
+
* - **Legacy naming** (`isLegacyNaming`): only the immediate property key is used
|
|
1510
|
+
* (e.g. `Params` for property `params`), keeping nested names short.
|
|
1511
|
+
* - **Default naming**: the parent name is prepended so the full path is encoded
|
|
1512
|
+
* (e.g. `OrderParams` when parent is `Order`).
|
|
1513
|
+
*/
|
|
1514
|
+
function resolveChildName(parentName, propName) {
|
|
1515
|
+
if (isLegacyNaming) return pascalCase(propName);
|
|
1516
|
+
return parentName ? pascalCase([parentName, propName].join(" ")) : void 0;
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* Derives the final name for an enum property schema node.
|
|
1520
|
+
*
|
|
1521
|
+
* The raw name always includes the enum suffix (e.g. `StatusEnum`).
|
|
1522
|
+
* In legacy mode an additional deduplication step appends a numeric suffix
|
|
1523
|
+
* when the same name has already been used (e.g. `ParamsStatusEnum2`).
|
|
1524
|
+
*/
|
|
1525
|
+
function resolveEnumPropName(parentName, propName, enumSuffix) {
|
|
1526
|
+
const raw = pascalCase([
|
|
1527
|
+
parentName,
|
|
1528
|
+
propName,
|
|
1529
|
+
enumSuffix
|
|
1530
|
+
].filter(Boolean).join(" "));
|
|
1531
|
+
return isLegacyNaming ? getUniqueName(raw, usedEnumNames) : raw;
|
|
1532
|
+
}
|
|
1533
|
+
/**
|
|
1534
|
+
* Given a freshly-converted property schema, returns the node with a correct
|
|
1535
|
+
* `name` attached — or stripped — depending on whether the node is a named
|
|
1536
|
+
* enum, a boolean const-enum (always inlined), or a regular schema.
|
|
1537
|
+
*/
|
|
1538
|
+
function applyEnumName(propNode, parentName, propName, enumSuffix) {
|
|
1539
|
+
const enumNode = narrowSchema(propNode, "enum");
|
|
1540
|
+
if (enumNode?.primitive === "boolean") return {
|
|
1541
|
+
...propNode,
|
|
1542
|
+
name: void 0
|
|
1543
|
+
};
|
|
1544
|
+
if (enumNode) return {
|
|
1545
|
+
...propNode,
|
|
1546
|
+
name: resolveEnumPropName(parentName, propName, enumSuffix)
|
|
1547
|
+
};
|
|
1548
|
+
return propNode;
|
|
1549
|
+
}
|
|
1343
1550
|
function convertObject({ schema, name, nullable, defaultValue, options, mergedOptions }) {
|
|
1344
|
-
const
|
|
1345
|
-
|
|
1346
|
-
const required = Array.isArray(resolvedSchema.required) ? resolvedSchema.required.includes(propName) : !!resolvedSchema.required;
|
|
1551
|
+
const properties = schema.properties ? Object.entries(schema.properties).map(([propName, propSchema]) => {
|
|
1552
|
+
const required = Array.isArray(schema.required) ? schema.required.includes(propName) : !!schema.required;
|
|
1347
1553
|
const resolvedPropSchema = propSchema;
|
|
1348
1554
|
const propNullable = isNullable(resolvedPropSchema);
|
|
1349
1555
|
return createProperty({
|
|
1350
1556
|
name: propName,
|
|
1351
1557
|
schema: {
|
|
1352
|
-
...convertSchema({
|
|
1558
|
+
...applyEnumName(convertSchema({
|
|
1353
1559
|
schema: resolvedPropSchema,
|
|
1354
|
-
name: name
|
|
1355
|
-
|
|
1356
|
-
propName,
|
|
1357
|
-
mergedOptions.enumSuffix
|
|
1358
|
-
].filter(Boolean).join(" ")) : void 0
|
|
1359
|
-
}, options),
|
|
1560
|
+
name: resolveChildName(name, propName)
|
|
1561
|
+
}, options), name, propName, mergedOptions.enumSuffix),
|
|
1360
1562
|
nullable: propNullable || void 0,
|
|
1361
1563
|
optional: !required && !propNullable ? true : void 0,
|
|
1362
1564
|
nullish: !required && propNullable ? true : void 0
|
|
@@ -1364,22 +1566,32 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1364
1566
|
required
|
|
1365
1567
|
});
|
|
1366
1568
|
}) : [];
|
|
1367
|
-
const additionalProperties =
|
|
1569
|
+
const additionalProperties = schema.additionalProperties;
|
|
1368
1570
|
let additionalPropertiesNode;
|
|
1369
1571
|
if (additionalProperties === true) additionalPropertiesNode = true;
|
|
1370
1572
|
else if (additionalProperties && Object.keys(additionalProperties).length > 0) additionalPropertiesNode = convertSchema({ schema: additionalProperties }, options);
|
|
1371
1573
|
else if (additionalProperties === false) additionalPropertiesNode = void 0;
|
|
1372
1574
|
else if (additionalProperties) additionalPropertiesNode = createSchema({ type: resolveTypeOption(mergedOptions.unknownType) });
|
|
1373
|
-
const rawPatternProperties = "patternProperties" in
|
|
1374
|
-
const patternProperties = rawPatternProperties ? Object.fromEntries(Object.entries(rawPatternProperties).map(([pattern, patternSchema]) => [pattern, patternSchema === true || Object.keys(patternSchema).length === 0 ? createSchema({ type: resolveTypeOption(mergedOptions.unknownType) }) : convertSchema({ schema: patternSchema }, options)])) : void 0;
|
|
1375
|
-
|
|
1575
|
+
const rawPatternProperties = "patternProperties" in schema ? schema.patternProperties : void 0;
|
|
1576
|
+
const patternProperties = rawPatternProperties ? Object.fromEntries(Object.entries(rawPatternProperties).map(([pattern, patternSchema]) => [pattern, patternSchema === true || typeof patternSchema === "object" && Object.keys(patternSchema).length === 0 ? createSchema({ type: resolveTypeOption(mergedOptions.unknownType) }) : convertSchema({ schema: patternSchema }, options)])) : void 0;
|
|
1577
|
+
const objectNode = createSchema({
|
|
1376
1578
|
type: "object",
|
|
1377
1579
|
primitive: "object",
|
|
1378
1580
|
properties,
|
|
1379
1581
|
additionalProperties: additionalPropertiesNode,
|
|
1380
1582
|
patternProperties,
|
|
1381
|
-
...
|
|
1583
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1382
1584
|
});
|
|
1585
|
+
if (isDiscriminator(schema) && schema.discriminator.mapping) {
|
|
1586
|
+
const discPropName = schema.discriminator.propertyName;
|
|
1587
|
+
return applyDiscriminatorEnum({
|
|
1588
|
+
node: objectNode,
|
|
1589
|
+
propertyName: discPropName,
|
|
1590
|
+
values: Object.keys(schema.discriminator.mapping),
|
|
1591
|
+
enumName: name ? resolveEnumPropName(name, discPropName, mergedOptions.enumSuffix) : void 0
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
return objectNode;
|
|
1383
1595
|
}
|
|
1384
1596
|
/**
|
|
1385
1597
|
* Converts an OAS 3.1 `prefixItems` tuple into a `TupleSchemaNode`.
|
|
@@ -1388,15 +1600,14 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1388
1600
|
* after the prefix items is mapped to the rest parameter of the tuple.
|
|
1389
1601
|
*/
|
|
1390
1602
|
function convertTuple({ schema, name, nullable, defaultValue, options }) {
|
|
1391
|
-
const rawSchema = schema;
|
|
1392
1603
|
return createSchema({
|
|
1393
1604
|
type: "tuple",
|
|
1394
1605
|
primitive: "array",
|
|
1395
|
-
items:
|
|
1396
|
-
rest:
|
|
1606
|
+
items: (schema.prefixItems ?? []).map((item) => convertSchema({ schema: item }, options)),
|
|
1607
|
+
rest: schema.items ? convertSchema({ schema: schema.items }, options) : void 0,
|
|
1397
1608
|
min: schema.minItems,
|
|
1398
1609
|
max: schema.maxItems,
|
|
1399
|
-
...
|
|
1610
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1400
1611
|
});
|
|
1401
1612
|
}
|
|
1402
1613
|
/**
|
|
@@ -1406,19 +1617,19 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1406
1617
|
* `enumSuffix` is forwarded so generators can emit a named enum declaration.
|
|
1407
1618
|
*/
|
|
1408
1619
|
function convertArray({ schema, name, nullable, defaultValue, options, mergedOptions }) {
|
|
1409
|
-
const
|
|
1410
|
-
const itemName =
|
|
1620
|
+
const rawItems = schema.items;
|
|
1621
|
+
const itemName = rawItems?.enum?.length && name ? resolveEnumPropName(void 0, name, mergedOptions.enumSuffix) : void 0;
|
|
1411
1622
|
return createSchema({
|
|
1412
1623
|
type: "array",
|
|
1413
1624
|
primitive: "array",
|
|
1414
|
-
items:
|
|
1415
|
-
schema:
|
|
1625
|
+
items: rawItems ? [convertSchema({
|
|
1626
|
+
schema: rawItems,
|
|
1416
1627
|
name: itemName
|
|
1417
1628
|
}, options)] : [],
|
|
1418
1629
|
min: schema.minItems,
|
|
1419
1630
|
max: schema.maxItems,
|
|
1420
1631
|
unique: schema.uniqueItems ?? void 0,
|
|
1421
|
-
...
|
|
1632
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1422
1633
|
});
|
|
1423
1634
|
}
|
|
1424
1635
|
/**
|
|
@@ -1431,7 +1642,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1431
1642
|
min: schema.minLength,
|
|
1432
1643
|
max: schema.maxLength,
|
|
1433
1644
|
pattern: schema.pattern,
|
|
1434
|
-
...
|
|
1645
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1435
1646
|
});
|
|
1436
1647
|
}
|
|
1437
1648
|
/**
|
|
@@ -1445,7 +1656,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1445
1656
|
max: schema.maximum,
|
|
1446
1657
|
exclusiveMinimum: typeof schema.exclusiveMinimum === "number" ? schema.exclusiveMinimum : void 0,
|
|
1447
1658
|
exclusiveMaximum: typeof schema.exclusiveMaximum === "number" ? schema.exclusiveMaximum : void 0,
|
|
1448
|
-
...
|
|
1659
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1449
1660
|
});
|
|
1450
1661
|
}
|
|
1451
1662
|
/**
|
|
@@ -1455,7 +1666,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1455
1666
|
return createSchema({
|
|
1456
1667
|
type: "boolean",
|
|
1457
1668
|
primitive: "boolean",
|
|
1458
|
-
...
|
|
1669
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1459
1670
|
});
|
|
1460
1671
|
}
|
|
1461
1672
|
/**
|
|
@@ -1490,7 +1701,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1490
1701
|
*/
|
|
1491
1702
|
function convertSchema({ schema, name }, options) {
|
|
1492
1703
|
const mergedOptions = {
|
|
1493
|
-
...
|
|
1704
|
+
...DEFAULT_PARSER_OPTIONS,
|
|
1494
1705
|
...options
|
|
1495
1706
|
};
|
|
1496
1707
|
const flattenedSchema = flattenSchema(schema);
|
|
@@ -1521,18 +1732,21 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1521
1732
|
if (schema.type === "string" && schema.contentMediaType === "application/octet-stream") return createSchema({
|
|
1522
1733
|
type: "blob",
|
|
1523
1734
|
primitive: "string",
|
|
1524
|
-
...
|
|
1735
|
+
...renderSchemaBase(schema, name, nullable, defaultValue)
|
|
1525
1736
|
});
|
|
1526
1737
|
if (Array.isArray(schema.type) && schema.type.length > 1) {
|
|
1527
1738
|
const nonNullTypes = schema.type.filter((t) => t !== "null");
|
|
1528
1739
|
const arrayNullable = schema.type.includes("null") || nullable || void 0;
|
|
1529
1740
|
if (nonNullTypes.length > 1) return createSchema({
|
|
1530
1741
|
type: "union",
|
|
1531
|
-
members: nonNullTypes.map((t) => convertSchema({
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1742
|
+
members: nonNullTypes.map((t) => convertSchema({
|
|
1743
|
+
schema: {
|
|
1744
|
+
...schema,
|
|
1745
|
+
type: t
|
|
1746
|
+
},
|
|
1747
|
+
name
|
|
1748
|
+
}, options)),
|
|
1749
|
+
...renderSchemaBase(schema, name, arrayNullable, defaultValue)
|
|
1536
1750
|
});
|
|
1537
1751
|
}
|
|
1538
1752
|
if (!type) {
|
|
@@ -1560,12 +1774,17 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1560
1774
|
* When the parameter has no `schema` or its schema is a `$ref`, falls back to `unknownType`.
|
|
1561
1775
|
*/
|
|
1562
1776
|
function parseParameter(options, param) {
|
|
1777
|
+
const required = param["required"] ?? false;
|
|
1563
1778
|
const schema = param["schema"] && !isReference(param["schema"]) ? convertSchema({ schema: param["schema"] }, options) : createSchema({ type: resolveTypeOption(options.unknownType) });
|
|
1564
1779
|
return createParameter({
|
|
1565
1780
|
name: param["name"],
|
|
1566
1781
|
in: param["in"],
|
|
1567
|
-
schema
|
|
1568
|
-
|
|
1782
|
+
schema: {
|
|
1783
|
+
...schema,
|
|
1784
|
+
description: param["description"] ?? schema.description,
|
|
1785
|
+
optional: !required || !!schema.optional ? true : void 0
|
|
1786
|
+
},
|
|
1787
|
+
required
|
|
1569
1788
|
});
|
|
1570
1789
|
}
|
|
1571
1790
|
/**
|
|
@@ -1573,15 +1792,13 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1573
1792
|
* request body, and all response codes into their AST node equivalents.
|
|
1574
1793
|
*/
|
|
1575
1794
|
function parseOperation(options, oas, operation) {
|
|
1576
|
-
const parameters =
|
|
1577
|
-
return parseParameter(options, oas.dereferenceWithRef(param));
|
|
1578
|
-
});
|
|
1795
|
+
const parameters = oas.getParameters(operation).map((param) => parseParameter(options, param));
|
|
1579
1796
|
const requestBodySchema = oas.getRequestSchema(operation);
|
|
1580
1797
|
const requestBody = requestBodySchema ? convertSchema({ schema: requestBodySchema }, options) : void 0;
|
|
1581
1798
|
const responses = operation.getResponseStatusCodes().map((statusCode) => {
|
|
1582
1799
|
const responseObj = operation.getResponseByStatusCode(statusCode);
|
|
1583
1800
|
const responseSchema = oas.getResponseSchema(operation, statusCode);
|
|
1584
|
-
const schema = responseSchema && Object.keys(responseSchema).length > 0 ? convertSchema({ schema: responseSchema }, options) :
|
|
1801
|
+
const schema = responseSchema && Object.keys(responseSchema).length > 0 ? convertSchema({ schema: responseSchema }, options) : createSchema({ type: resolveTypeOption(options.emptySchemaType) });
|
|
1585
1802
|
const description = typeof responseObj === "object" && responseObj !== null && !Array.isArray(responseObj) ? responseObj.description : void 0;
|
|
1586
1803
|
const rawContent = typeof responseObj === "object" && responseObj !== null && !Array.isArray(responseObj) ? responseObj.content : void 0;
|
|
1587
1804
|
return createResponse({
|
|
@@ -1594,7 +1811,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1594
1811
|
return createOperation({
|
|
1595
1812
|
operationId: operation.getOperationId(),
|
|
1596
1813
|
method: operation.method.toUpperCase(),
|
|
1597
|
-
path: operation.path,
|
|
1814
|
+
path: new URLPath(operation.path).URL,
|
|
1598
1815
|
tags: operation.getTags().map((tag) => tag.name),
|
|
1599
1816
|
summary: operation.getSummary() || void 0,
|
|
1600
1817
|
description: operation.getDescription() || void 0,
|
|
@@ -1610,7 +1827,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1610
1827
|
*/
|
|
1611
1828
|
function parse(options) {
|
|
1612
1829
|
const mergedOptions = {
|
|
1613
|
-
...
|
|
1830
|
+
...DEFAULT_PARSER_OPTIONS,
|
|
1614
1831
|
...options
|
|
1615
1832
|
};
|
|
1616
1833
|
const schemas = Object.entries(schemaObjects).map(([name, schemaObject]) => convertSchema({
|
|
@@ -1651,31 +1868,11 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1651
1868
|
}
|
|
1652
1869
|
} });
|
|
1653
1870
|
}
|
|
1654
|
-
/**
|
|
1655
|
-
* Collects all `KubbFile.Import` descriptors needed by a `SchemaNode` tree.
|
|
1656
|
-
*
|
|
1657
|
-
* Walks the tree looking for `ref` nodes, verifies each `$ref` is resolvable in the spec,
|
|
1658
|
-
* applies collision-resolved names from `nameMapping`, and calls `resolve` to obtain the
|
|
1659
|
-
* import path and name. Returns an empty array for refs that cannot be resolved.
|
|
1660
|
-
*/
|
|
1661
|
-
function getImports(node, resolve) {
|
|
1662
|
-
return collect(node, { schema(schemaNode) {
|
|
1663
|
-
if (schemaNode.type !== "ref" || !schemaNode.ref) return;
|
|
1664
|
-
if (!oas.get(schemaNode.ref)) return;
|
|
1665
|
-
const rawName = extractRefName(schemaNode.ref);
|
|
1666
|
-
const result = resolve(nameMapping.get(rawName) ?? rawName);
|
|
1667
|
-
if (!result) return;
|
|
1668
|
-
return {
|
|
1669
|
-
name: [result.name],
|
|
1670
|
-
path: result.path
|
|
1671
|
-
};
|
|
1672
|
-
} });
|
|
1673
|
-
}
|
|
1674
1871
|
return {
|
|
1675
1872
|
parse,
|
|
1676
1873
|
convertSchema,
|
|
1677
1874
|
resolveRefs,
|
|
1678
|
-
|
|
1875
|
+
nameMapping
|
|
1679
1876
|
};
|
|
1680
1877
|
}
|
|
1681
1878
|
//#endregion
|
|
@@ -1699,8 +1896,9 @@ const adapterOasName = "oas";
|
|
|
1699
1896
|
* })
|
|
1700
1897
|
* ```
|
|
1701
1898
|
*/
|
|
1702
|
-
const adapterOas =
|
|
1703
|
-
const { validate = true, oasClass, contentType, serverIndex, serverVariables, discriminator = "strict", collisionDetection =
|
|
1899
|
+
const adapterOas = createAdapter((options) => {
|
|
1900
|
+
const { validate = true, oasClass, contentType, serverIndex, serverVariables, discriminator = "strict", collisionDetection = true, dateType = DEFAULT_PARSER_OPTIONS.dateType, integerType = DEFAULT_PARSER_OPTIONS.integerType, unknownType = DEFAULT_PARSER_OPTIONS.unknownType, enumSuffix = DEFAULT_PARSER_OPTIONS.enumSuffix, emptySchemaType = unknownType || DEFAULT_PARSER_OPTIONS.emptySchemaType } = options;
|
|
1901
|
+
const nameMapping = /* @__PURE__ */ new Map();
|
|
1704
1902
|
return {
|
|
1705
1903
|
name: "oas",
|
|
1706
1904
|
options: {
|
|
@@ -1714,7 +1912,16 @@ const adapterOas = defineAdapter((options) => {
|
|
|
1714
1912
|
dateType,
|
|
1715
1913
|
integerType,
|
|
1716
1914
|
unknownType,
|
|
1717
|
-
emptySchemaType
|
|
1915
|
+
emptySchemaType,
|
|
1916
|
+
enumSuffix,
|
|
1917
|
+
nameMapping
|
|
1918
|
+
},
|
|
1919
|
+
getImports(node, resolve) {
|
|
1920
|
+
return getImports({
|
|
1921
|
+
node,
|
|
1922
|
+
nameMapping,
|
|
1923
|
+
resolve
|
|
1924
|
+
});
|
|
1718
1925
|
},
|
|
1719
1926
|
async parse(source) {
|
|
1720
1927
|
const oas = await parseFromConfig(sourceToFakeConfig(source), oasClass);
|
|
@@ -1728,18 +1935,23 @@ const adapterOas = defineAdapter((options) => {
|
|
|
1728
1935
|
} catch (_err) {}
|
|
1729
1936
|
const server = serverIndex !== void 0 ? oas.api.servers?.at(serverIndex) : void 0;
|
|
1730
1937
|
const baseURL = server?.url ? resolveServerUrl(server, serverVariables) : void 0;
|
|
1938
|
+
const parser = createOasParser(oas, {
|
|
1939
|
+
contentType,
|
|
1940
|
+
collisionDetection
|
|
1941
|
+
});
|
|
1942
|
+
nameMapping.clear();
|
|
1943
|
+
for (const [key, value] of parser.nameMapping) nameMapping.set(key, value);
|
|
1731
1944
|
return createRoot({
|
|
1732
|
-
...
|
|
1733
|
-
contentType,
|
|
1734
|
-
collisionDetection
|
|
1735
|
-
}).parse({
|
|
1945
|
+
...parser.parse({
|
|
1736
1946
|
dateType,
|
|
1737
1947
|
integerType,
|
|
1738
1948
|
unknownType,
|
|
1739
|
-
emptySchemaType
|
|
1949
|
+
emptySchemaType,
|
|
1950
|
+
enumSuffix
|
|
1740
1951
|
}),
|
|
1741
1952
|
meta: {
|
|
1742
1953
|
title: oas.api.info?.title,
|
|
1954
|
+
description: oas.api.info?.description,
|
|
1743
1955
|
version: oas.api.info?.version,
|
|
1744
1956
|
baseURL
|
|
1745
1957
|
}
|