@kubb/adapter-oas 4.36.1 → 5.0.0-alpha.10
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 +271 -113
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +37 -1
- package/dist/index.js +272 -114
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/adapter.ts +19 -2
- package/src/constants.ts +9 -5
- 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 +115 -159
- package/src/types.ts +6 -0
- package/src/utils.ts +168 -0
package/dist/index.cjs
CHANGED
|
@@ -289,9 +289,8 @@ const formatMap = {
|
|
|
289
289
|
};
|
|
290
290
|
/**
|
|
291
291
|
* Exhaustive list of media types that Kubb recognizes.
|
|
292
|
-
* Kept as a module-level constant to avoid re-allocating the array on every call.
|
|
293
292
|
*/
|
|
294
|
-
const knownMediaTypes = [
|
|
293
|
+
const knownMediaTypes = new Set([
|
|
295
294
|
"application/json",
|
|
296
295
|
"application/xml",
|
|
297
296
|
"application/x-www-form-urlencoded",
|
|
@@ -311,12 +310,22 @@ const knownMediaTypes = [
|
|
|
311
310
|
"image/svg+xml",
|
|
312
311
|
"audio/mpeg",
|
|
313
312
|
"video/mp4"
|
|
314
|
-
];
|
|
313
|
+
]);
|
|
315
314
|
/**
|
|
316
315
|
* Vendor extension keys used to attach human-readable labels to enum values.
|
|
317
316
|
* Checked in priority order: the first key found wins.
|
|
318
317
|
*/
|
|
319
318
|
const enumExtensionKeys = ["x-enumNames", "x-enum-varnames"];
|
|
319
|
+
/**
|
|
320
|
+
* Scalar primitive schema types used for union member simplification.
|
|
321
|
+
*/
|
|
322
|
+
const SCALAR_PRIMITIVE_TYPES = new Set([
|
|
323
|
+
"string",
|
|
324
|
+
"number",
|
|
325
|
+
"integer",
|
|
326
|
+
"bigint",
|
|
327
|
+
"boolean"
|
|
328
|
+
]);
|
|
320
329
|
//#endregion
|
|
321
330
|
//#region src/oas/Oas.ts
|
|
322
331
|
/**
|
|
@@ -529,8 +538,15 @@ var Oas = class extends oas.default {
|
|
|
529
538
|
if (!schema) return;
|
|
530
539
|
return this.dereferenceWithRef(schema);
|
|
531
540
|
}
|
|
532
|
-
|
|
533
|
-
|
|
541
|
+
/**
|
|
542
|
+
* Returns all resolved parameters for an operation, merging path-level and operation-level
|
|
543
|
+
* parameters and deduplicating by `in:name` (operation-level takes precedence).
|
|
544
|
+
*
|
|
545
|
+
* oas v31+ filters out `$ref` parameters in `getParameters()`, so this method accesses the
|
|
546
|
+
* raw `operation.schema.parameters` and path-item parameters directly and resolves `$ref`
|
|
547
|
+
* pointers via `dereferenceWithRef` to preserve backward compatibility.
|
|
548
|
+
*/
|
|
549
|
+
getParameters(operation) {
|
|
534
550
|
const resolveParams = (params) => params.map((p) => this.dereferenceWithRef(p)).filter((p) => !!p && typeof p === "object" && "in" in p && "name" in p);
|
|
535
551
|
const operationParams = resolveParams(operation.schema?.parameters || []);
|
|
536
552
|
const pathItem = this.api?.paths?.[operation.path];
|
|
@@ -538,7 +554,11 @@ var Oas = class extends oas.default {
|
|
|
538
554
|
const paramMap = /* @__PURE__ */ new Map();
|
|
539
555
|
for (const p of pathLevelParams) if (p.name && p.in) paramMap.set(`${p.in}:${p.name}`, p);
|
|
540
556
|
for (const p of operationParams) if (p.name && p.in) paramMap.set(`${p.in}:${p.name}`, p);
|
|
541
|
-
|
|
557
|
+
return Array.from(paramMap.values());
|
|
558
|
+
}
|
|
559
|
+
getParametersSchema(operation, inKey) {
|
|
560
|
+
const { contentType = operation.getContentType() } = this.#options;
|
|
561
|
+
const params = this.getParameters(operation).filter((v) => v.in === inKey);
|
|
542
562
|
if (!params.length) return null;
|
|
543
563
|
return params.reduce((schema, pathParameters) => {
|
|
544
564
|
const property = pathParameters.content?.[contentType]?.schema ?? pathParameters.schema;
|
|
@@ -928,6 +948,136 @@ function resolveCollisions(schemasWithMeta) {
|
|
|
928
948
|
};
|
|
929
949
|
}
|
|
930
950
|
//#endregion
|
|
951
|
+
//#region src/utils.ts
|
|
952
|
+
/**
|
|
953
|
+
* Extracts the schema name from a `$ref` string.
|
|
954
|
+
* For `#/components/schemas/Order` this returns `'Order'`.
|
|
955
|
+
* Falls back to the full ref string when no slash is present.
|
|
956
|
+
*/
|
|
957
|
+
function extractRefName($ref) {
|
|
958
|
+
return $ref.split("/").at(-1) ?? $ref;
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Replaces the discriminator property's schema inside an `ObjectSchemaNode`
|
|
962
|
+
* with an enum of the given `values`.
|
|
963
|
+
*
|
|
964
|
+
* - When `enumName` is provided the enum is named, which lets printers emit a
|
|
965
|
+
* standalone enum declaration + type reference (e.g. `PetTypeEnum`).
|
|
966
|
+
* - When `enumName` is omitted the enum stays anonymous, so printers inline it
|
|
967
|
+
* as a literal union (e.g. `'dog'`).
|
|
968
|
+
*
|
|
969
|
+
* Returns the node unchanged when it is not an object or lacks the target property.
|
|
970
|
+
*/
|
|
971
|
+
function applyDiscriminatorEnum({ node, propertyName, values, enumName }) {
|
|
972
|
+
if (node.type !== "object" || !node.properties?.length) return node;
|
|
973
|
+
if (!node.properties.some((prop) => prop.name === propertyName)) return node;
|
|
974
|
+
return (0, _kubb_ast.createSchema)({
|
|
975
|
+
...node,
|
|
976
|
+
properties: node.properties.map((prop) => {
|
|
977
|
+
if (prop.name !== propertyName) return prop;
|
|
978
|
+
const enumSchema = (0, _kubb_ast.createSchema)({
|
|
979
|
+
type: "enum",
|
|
980
|
+
primitive: "string",
|
|
981
|
+
enumValues: values,
|
|
982
|
+
name: enumName,
|
|
983
|
+
readOnly: prop.schema.readOnly,
|
|
984
|
+
writeOnly: prop.schema.writeOnly
|
|
985
|
+
});
|
|
986
|
+
return (0, _kubb_ast.createProperty)({
|
|
987
|
+
...prop,
|
|
988
|
+
schema: enumSchema
|
|
989
|
+
});
|
|
990
|
+
})
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Merges consecutive anonymous (`name`-less) `ObjectSchemaNode`s in `members` into a
|
|
995
|
+
* single object by combining their `properties` arrays.
|
|
996
|
+
*
|
|
997
|
+
* Only adjacent pairs are merged — non-object or named nodes act as boundaries.
|
|
998
|
+
* This collapses patterns like `Address & { streetNumber } & { streetName }` into
|
|
999
|
+
* `Address & { streetNumber; streetName }`.
|
|
1000
|
+
*/
|
|
1001
|
+
function mergeAdjacentAnonymousObjects(members) {
|
|
1002
|
+
return members.reduce((acc, member) => {
|
|
1003
|
+
const obj = (0, _kubb_ast.narrowSchema)(member, "object");
|
|
1004
|
+
if (obj && !obj.name) {
|
|
1005
|
+
const prev = acc[acc.length - 1];
|
|
1006
|
+
const prevObj = prev ? (0, _kubb_ast.narrowSchema)(prev, "object") : null;
|
|
1007
|
+
if (prevObj && !prevObj.name) {
|
|
1008
|
+
acc[acc.length - 1] = (0, _kubb_ast.createSchema)({
|
|
1009
|
+
...prevObj,
|
|
1010
|
+
properties: [...prevObj.properties ?? [], ...obj.properties ?? []]
|
|
1011
|
+
});
|
|
1012
|
+
return acc;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
acc.push(member);
|
|
1016
|
+
return acc;
|
|
1017
|
+
}, []);
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Simplifies a union member list by removing `enum` nodes whose `primitive` type is
|
|
1021
|
+
* already represented by a broader scalar node in the same union.
|
|
1022
|
+
*
|
|
1023
|
+
* For example `['placed', 'approved'] | string` collapses to `string` because
|
|
1024
|
+
* `string` subsumes all string literals. `'' | string` similarly becomes `string`.
|
|
1025
|
+
*
|
|
1026
|
+
* Only scalar primitives (`string`, `number`, `integer`, `bigint`, `boolean`) are
|
|
1027
|
+
* considered — object, array, and ref members are left untouched.
|
|
1028
|
+
*
|
|
1029
|
+
* Const-derived enums (those without an `enumType`, produced from an OpenAPI `const`
|
|
1030
|
+
* keyword) are **never** removed — `'accepted' | string` must stay as-is because the
|
|
1031
|
+
* literal is intentional.
|
|
1032
|
+
*/
|
|
1033
|
+
function simplifyUnionMembers(members) {
|
|
1034
|
+
const scalarPrimitives = new Set(members.filter((m) => SCALAR_PRIMITIVE_TYPES.has(m.type)).map((m) => m.type));
|
|
1035
|
+
if (!scalarPrimitives.size) return members;
|
|
1036
|
+
return members.filter((m) => {
|
|
1037
|
+
if (m.type !== "enum") return true;
|
|
1038
|
+
const prim = m.primitive;
|
|
1039
|
+
if (!prim) return true;
|
|
1040
|
+
if (!m.enumType) return true;
|
|
1041
|
+
if (scalarPrimitives.has(prim)) return false;
|
|
1042
|
+
if ((prim === "integer" || prim === "number") && (scalarPrimitives.has("integer") || scalarPrimitives.has("number"))) return false;
|
|
1043
|
+
return true;
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* `nameMapping`, and calls `resolve` to obtain the `{ name, path }` pair for
|
|
1048
|
+
* each import. When `oas` is supplied, only `$ref`s that are resolvable in the
|
|
1049
|
+
* spec are included; omit it to skip the existence check.
|
|
1050
|
+
*
|
|
1051
|
+
* This function is the pure, state-free alternative to `OasParser.getImports`.
|
|
1052
|
+
* Because it receives `nameMapping` explicitly it can be called without holding
|
|
1053
|
+
* a reference to the parser or the OAS instance.
|
|
1054
|
+
*
|
|
1055
|
+
* @example
|
|
1056
|
+
* ```ts
|
|
1057
|
+
* // Use adapter state directly — no parser reference needed
|
|
1058
|
+
* const imports = getImports({
|
|
1059
|
+
* node: schemaNode,
|
|
1060
|
+
* nameMapping: adapter.options.nameMapping,
|
|
1061
|
+
* resolve: (schemaName) => ({
|
|
1062
|
+
* name: schemaManager.getName(schemaName, { type: 'type' }),
|
|
1063
|
+
* path: schemaManager.getFile(schemaName).path,
|
|
1064
|
+
* }),
|
|
1065
|
+
* })
|
|
1066
|
+
* ```
|
|
1067
|
+
*/
|
|
1068
|
+
function getImports({ node, nameMapping, resolve }) {
|
|
1069
|
+
return (0, _kubb_ast.collect)(node, { schema(schemaNode) {
|
|
1070
|
+
if (schemaNode.type !== "ref" || !schemaNode.ref) return;
|
|
1071
|
+
const rawName = extractRefName(schemaNode.ref);
|
|
1072
|
+
const result = resolve(nameMapping.get(rawName) ?? rawName);
|
|
1073
|
+
if (!result) return;
|
|
1074
|
+
return {
|
|
1075
|
+
name: [result.name],
|
|
1076
|
+
path: result.path
|
|
1077
|
+
};
|
|
1078
|
+
} });
|
|
1079
|
+
}
|
|
1080
|
+
//#endregion
|
|
931
1081
|
//#region src/parser.ts
|
|
932
1082
|
/**
|
|
933
1083
|
* Default values for all `Options` fields.
|
|
@@ -948,14 +1098,6 @@ function formatToSchemaType(format) {
|
|
|
948
1098
|
return formatMap[format];
|
|
949
1099
|
}
|
|
950
1100
|
/**
|
|
951
|
-
* Extracts the final path segment of a JSON Pointer `$ref` string.
|
|
952
|
-
* For `#/components/schemas/Order` this returns `'Order'`.
|
|
953
|
-
* Falls back to the full ref string when no slash is present.
|
|
954
|
-
*/
|
|
955
|
-
function extractRefName($ref) {
|
|
956
|
-
return $ref.split("/").at(-1) ?? $ref;
|
|
957
|
-
}
|
|
958
|
-
/**
|
|
959
1101
|
* Maps an OAS primitive type string to its `PrimitiveSchemaType` equivalent.
|
|
960
1102
|
* Numeric types (`number`, `integer`, `bigint`) are returned unchanged;
|
|
961
1103
|
* `boolean` maps to `'boolean'`; everything else defaults to `'string'`.
|
|
@@ -970,27 +1112,7 @@ function getPrimitiveType(type) {
|
|
|
970
1112
|
* Returns `undefined` for content types not present in `KNOWN_MEDIA_TYPES`.
|
|
971
1113
|
*/
|
|
972
1114
|
function toMediaType(contentType) {
|
|
973
|
-
return knownMediaTypes.
|
|
974
|
-
}
|
|
975
|
-
/**
|
|
976
|
-
* When a discriminator is present, replaces the discriminator property's schema with
|
|
977
|
-
* an enum of the mapping keys so downstream code emits a precise literal-union type.
|
|
978
|
-
* Returns the original schema unchanged when there is no discriminator or no mapping.
|
|
979
|
-
*/
|
|
980
|
-
function applyDiscriminatorEnum(schema) {
|
|
981
|
-
if (!isDiscriminator(schema)) return schema;
|
|
982
|
-
const propName = schema.discriminator.propertyName;
|
|
983
|
-
if (!schema.properties?.[propName]) return schema;
|
|
984
|
-
return {
|
|
985
|
-
...schema,
|
|
986
|
-
properties: {
|
|
987
|
-
...schema.properties,
|
|
988
|
-
[propName]: {
|
|
989
|
-
...schema.properties[propName],
|
|
990
|
-
enum: schema.discriminator.mapping ? Object.keys(schema.discriminator.mapping) : void 0
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
};
|
|
1115
|
+
return knownMediaTypes.has(contentType) ? contentType : void 0;
|
|
994
1116
|
}
|
|
995
1117
|
/**
|
|
996
1118
|
* Creates an OAS parser that converts an OpenAPI/Swagger spec into
|
|
@@ -1083,18 +1205,17 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1083
1205
|
* reflected in generated JSDoc and type modifiers.
|
|
1084
1206
|
*/
|
|
1085
1207
|
function convertRef({ schema, nullable, defaultValue }) {
|
|
1086
|
-
const schemaObject = schema;
|
|
1087
1208
|
return (0, _kubb_ast.createSchema)({
|
|
1088
1209
|
type: "ref",
|
|
1089
|
-
name: extractRefName(
|
|
1090
|
-
ref:
|
|
1210
|
+
name: extractRefName(schema.$ref),
|
|
1211
|
+
ref: schema.$ref,
|
|
1091
1212
|
nullable,
|
|
1092
|
-
description:
|
|
1093
|
-
deprecated:
|
|
1094
|
-
readOnly:
|
|
1095
|
-
writeOnly:
|
|
1096
|
-
pattern:
|
|
1097
|
-
example:
|
|
1213
|
+
description: schema.description,
|
|
1214
|
+
deprecated: schema.deprecated,
|
|
1215
|
+
readOnly: schema.readOnly,
|
|
1216
|
+
writeOnly: schema.writeOnly,
|
|
1217
|
+
pattern: schema.type === "string" ? schema.pattern : void 0,
|
|
1218
|
+
example: schema.example,
|
|
1098
1219
|
default: defaultValue
|
|
1099
1220
|
});
|
|
1100
1221
|
}
|
|
@@ -1145,6 +1266,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1145
1266
|
const inMapping = Object.values(deref.discriminator.mapping ?? {}).some((v) => v === childRef);
|
|
1146
1267
|
return !inOneOf && !inMapping;
|
|
1147
1268
|
}).map((s) => convertSchema({ schema: s }, options));
|
|
1269
|
+
const syntheticStart = allOfMembers.length;
|
|
1148
1270
|
if (Array.isArray(schema.required) && schema.required.length) {
|
|
1149
1271
|
const outerKeys = schema.properties ? new Set(Object.keys(schema.properties)) : /* @__PURE__ */ new Set();
|
|
1150
1272
|
const missingRequired = schema.required.filter((key) => !outerKeys.has(key));
|
|
@@ -1169,7 +1291,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1169
1291
|
}
|
|
1170
1292
|
return (0, _kubb_ast.createSchema)({
|
|
1171
1293
|
type: "intersection",
|
|
1172
|
-
members: allOfMembers,
|
|
1294
|
+
members: [...allOfMembers.slice(0, syntheticStart), ...mergeAdjacentAnonymousObjects(allOfMembers.slice(syntheticStart))],
|
|
1173
1295
|
...buildSchemaBase(schema, name, nullable, defaultValue)
|
|
1174
1296
|
});
|
|
1175
1297
|
}
|
|
@@ -1189,20 +1311,34 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1189
1311
|
};
|
|
1190
1312
|
if (schema.properties) {
|
|
1191
1313
|
const { oneOf: _oneOf, anyOf: _anyOf, ...schemaWithoutUnion } = schema;
|
|
1192
|
-
const
|
|
1314
|
+
const discriminator = isDiscriminator(schema) ? schema.discriminator : void 0;
|
|
1315
|
+
const memberBaseSchema = discriminator ? Object.fromEntries(Object.entries(schemaWithoutUnion).filter(([key]) => key !== "discriminator")) : schemaWithoutUnion;
|
|
1193
1316
|
return (0, _kubb_ast.createSchema)({
|
|
1194
1317
|
type: "union",
|
|
1195
1318
|
...unionBase,
|
|
1196
|
-
members: unionMembers.map((s) =>
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1319
|
+
members: unionMembers.map((s) => {
|
|
1320
|
+
const ref = isReference(s) ? s.$ref : void 0;
|
|
1321
|
+
const discriminatorValue = discriminator?.mapping && ref ? Object.entries(discriminator.mapping).find(([, v]) => v === ref)?.[0] : void 0;
|
|
1322
|
+
let propertiesNode = convertSchema({
|
|
1323
|
+
schema: memberBaseSchema,
|
|
1324
|
+
name
|
|
1325
|
+
}, options);
|
|
1326
|
+
if (discriminatorValue && discriminator) propertiesNode = applyDiscriminatorEnum({
|
|
1327
|
+
node: propertiesNode,
|
|
1328
|
+
propertyName: discriminator.propertyName,
|
|
1329
|
+
values: [discriminatorValue]
|
|
1330
|
+
});
|
|
1331
|
+
return (0, _kubb_ast.createSchema)({
|
|
1332
|
+
type: "intersection",
|
|
1333
|
+
members: [convertSchema({ schema: s }, options), propertiesNode]
|
|
1334
|
+
});
|
|
1335
|
+
})
|
|
1200
1336
|
});
|
|
1201
1337
|
}
|
|
1202
1338
|
return (0, _kubb_ast.createSchema)({
|
|
1203
1339
|
type: "union",
|
|
1204
1340
|
...unionBase,
|
|
1205
|
-
members: unionMembers.map((s) => convertSchema({ schema: s }, options))
|
|
1341
|
+
members: simplifyUnionMembers(unionMembers.map((s) => convertSchema({ schema: s }, options)))
|
|
1206
1342
|
});
|
|
1207
1343
|
}
|
|
1208
1344
|
/**
|
|
@@ -1269,6 +1405,11 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1269
1405
|
primitive: specialPrimitive,
|
|
1270
1406
|
type: specialType
|
|
1271
1407
|
});
|
|
1408
|
+
if (specialType === "url") return (0, _kubb_ast.createSchema)({
|
|
1409
|
+
...base,
|
|
1410
|
+
primitive: "string",
|
|
1411
|
+
type: "url"
|
|
1412
|
+
});
|
|
1272
1413
|
return (0, _kubb_ast.createSchema)({
|
|
1273
1414
|
...base,
|
|
1274
1415
|
primitive: specialPrimitive,
|
|
@@ -1287,9 +1428,8 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1287
1428
|
*/
|
|
1288
1429
|
function convertEnum({ schema, name, nullable, type, options }) {
|
|
1289
1430
|
if (type === "array") {
|
|
1290
|
-
const rawSchema = schema;
|
|
1291
1431
|
const normalizedItems = {
|
|
1292
|
-
...typeof
|
|
1432
|
+
...typeof schema.items === "object" && !Array.isArray(schema.items) ? schema.items : {},
|
|
1293
1433
|
enum: schema.enum
|
|
1294
1434
|
};
|
|
1295
1435
|
const { enum: _enum, ...schemaWithoutEnum } = schema;
|
|
@@ -1369,22 +1509,28 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1369
1509
|
* - not required + nullable → `nullish: true`
|
|
1370
1510
|
*/
|
|
1371
1511
|
function convertObject({ schema, name, nullable, defaultValue, options, mergedOptions }) {
|
|
1372
|
-
const
|
|
1373
|
-
|
|
1374
|
-
const required = Array.isArray(resolvedSchema.required) ? resolvedSchema.required.includes(propName) : !!resolvedSchema.required;
|
|
1512
|
+
const properties = schema.properties ? Object.entries(schema.properties).map(([propName, propSchema]) => {
|
|
1513
|
+
const required = Array.isArray(schema.required) ? schema.required.includes(propName) : !!schema.required;
|
|
1375
1514
|
const resolvedPropSchema = propSchema;
|
|
1376
1515
|
const propNullable = isNullable(resolvedPropSchema);
|
|
1516
|
+
const basePropName = name ? pascalCase([name, propName].join(" ")) : void 0;
|
|
1517
|
+
const propNode = convertSchema({
|
|
1518
|
+
schema: resolvedPropSchema,
|
|
1519
|
+
name: basePropName
|
|
1520
|
+
}, options);
|
|
1521
|
+
const isEnumNode = !!(0, _kubb_ast.narrowSchema)(propNode, "enum");
|
|
1522
|
+
const derivedPropName = isEnumNode && name ? pascalCase([
|
|
1523
|
+
name,
|
|
1524
|
+
propName,
|
|
1525
|
+
mergedOptions.enumSuffix
|
|
1526
|
+
].filter(Boolean).join(" ")) : basePropName;
|
|
1377
1527
|
return (0, _kubb_ast.createProperty)({
|
|
1378
1528
|
name: propName,
|
|
1379
1529
|
schema: {
|
|
1380
|
-
...
|
|
1381
|
-
|
|
1382
|
-
name:
|
|
1383
|
-
|
|
1384
|
-
propName,
|
|
1385
|
-
mergedOptions.enumSuffix
|
|
1386
|
-
].filter(Boolean).join(" ")) : void 0
|
|
1387
|
-
}, options),
|
|
1530
|
+
...isEnumNode && derivedPropName !== basePropName ? {
|
|
1531
|
+
...propNode,
|
|
1532
|
+
name: derivedPropName
|
|
1533
|
+
} : propNode,
|
|
1388
1534
|
nullable: propNullable || void 0,
|
|
1389
1535
|
optional: !required && !propNullable ? true : void 0,
|
|
1390
1536
|
nullish: !required && propNullable ? true : void 0
|
|
@@ -1392,15 +1538,15 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1392
1538
|
required
|
|
1393
1539
|
});
|
|
1394
1540
|
}) : [];
|
|
1395
|
-
const additionalProperties =
|
|
1541
|
+
const additionalProperties = schema.additionalProperties;
|
|
1396
1542
|
let additionalPropertiesNode;
|
|
1397
1543
|
if (additionalProperties === true) additionalPropertiesNode = true;
|
|
1398
1544
|
else if (additionalProperties && Object.keys(additionalProperties).length > 0) additionalPropertiesNode = convertSchema({ schema: additionalProperties }, options);
|
|
1399
1545
|
else if (additionalProperties === false) additionalPropertiesNode = void 0;
|
|
1400
1546
|
else if (additionalProperties) additionalPropertiesNode = (0, _kubb_ast.createSchema)({ type: resolveTypeOption(mergedOptions.unknownType) });
|
|
1401
|
-
const rawPatternProperties = "patternProperties" in
|
|
1402
|
-
const patternProperties = rawPatternProperties ? Object.fromEntries(Object.entries(rawPatternProperties).map(([pattern, patternSchema]) => [pattern, patternSchema === true || Object.keys(patternSchema).length === 0 ? (0, _kubb_ast.createSchema)({ type: resolveTypeOption(mergedOptions.unknownType) }) : convertSchema({ schema: patternSchema }, options)])) : void 0;
|
|
1403
|
-
|
|
1547
|
+
const rawPatternProperties = "patternProperties" in schema ? schema.patternProperties : void 0;
|
|
1548
|
+
const patternProperties = rawPatternProperties ? Object.fromEntries(Object.entries(rawPatternProperties).map(([pattern, patternSchema]) => [pattern, patternSchema === true || typeof patternSchema === "object" && Object.keys(patternSchema).length === 0 ? (0, _kubb_ast.createSchema)({ type: resolveTypeOption(mergedOptions.unknownType) }) : convertSchema({ schema: patternSchema }, options)])) : void 0;
|
|
1549
|
+
const objectNode = (0, _kubb_ast.createSchema)({
|
|
1404
1550
|
type: "object",
|
|
1405
1551
|
primitive: "object",
|
|
1406
1552
|
properties,
|
|
@@ -1408,6 +1554,20 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1408
1554
|
patternProperties,
|
|
1409
1555
|
...buildSchemaBase(schema, name, nullable, defaultValue)
|
|
1410
1556
|
});
|
|
1557
|
+
if (isDiscriminator(schema) && schema.discriminator.mapping) {
|
|
1558
|
+
const discPropName = schema.discriminator.propertyName;
|
|
1559
|
+
return applyDiscriminatorEnum({
|
|
1560
|
+
node: objectNode,
|
|
1561
|
+
propertyName: discPropName,
|
|
1562
|
+
values: Object.keys(schema.discriminator.mapping),
|
|
1563
|
+
enumName: name ? pascalCase([
|
|
1564
|
+
name,
|
|
1565
|
+
discPropName,
|
|
1566
|
+
mergedOptions.enumSuffix
|
|
1567
|
+
].filter(Boolean).join(" ")) : void 0
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
return objectNode;
|
|
1411
1571
|
}
|
|
1412
1572
|
/**
|
|
1413
1573
|
* Converts an OAS 3.1 `prefixItems` tuple into a `TupleSchemaNode`.
|
|
@@ -1416,12 +1576,11 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1416
1576
|
* after the prefix items is mapped to the rest parameter of the tuple.
|
|
1417
1577
|
*/
|
|
1418
1578
|
function convertTuple({ schema, name, nullable, defaultValue, options }) {
|
|
1419
|
-
const rawSchema = schema;
|
|
1420
1579
|
return (0, _kubb_ast.createSchema)({
|
|
1421
1580
|
type: "tuple",
|
|
1422
1581
|
primitive: "array",
|
|
1423
|
-
items:
|
|
1424
|
-
rest:
|
|
1582
|
+
items: (schema.prefixItems ?? []).map((item) => convertSchema({ schema: item }, options)),
|
|
1583
|
+
rest: schema.items ? convertSchema({ schema: schema.items }, options) : void 0,
|
|
1425
1584
|
min: schema.minItems,
|
|
1426
1585
|
max: schema.maxItems,
|
|
1427
1586
|
...buildSchemaBase(schema, name, nullable, defaultValue)
|
|
@@ -1434,13 +1593,13 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1434
1593
|
* `enumSuffix` is forwarded so generators can emit a named enum declaration.
|
|
1435
1594
|
*/
|
|
1436
1595
|
function convertArray({ schema, name, nullable, defaultValue, options, mergedOptions }) {
|
|
1437
|
-
const
|
|
1438
|
-
const itemName =
|
|
1596
|
+
const rawItems = schema.items;
|
|
1597
|
+
const itemName = rawItems?.enum?.length && name ? pascalCase([name, mergedOptions.enumSuffix].join(" ")) : void 0;
|
|
1439
1598
|
return (0, _kubb_ast.createSchema)({
|
|
1440
1599
|
type: "array",
|
|
1441
1600
|
primitive: "array",
|
|
1442
|
-
items:
|
|
1443
|
-
schema:
|
|
1601
|
+
items: rawItems ? [convertSchema({
|
|
1602
|
+
schema: rawItems,
|
|
1444
1603
|
name: itemName
|
|
1445
1604
|
}, options)] : [],
|
|
1446
1605
|
min: schema.minItems,
|
|
@@ -1556,10 +1715,13 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1556
1715
|
const arrayNullable = schema.type.includes("null") || nullable || void 0;
|
|
1557
1716
|
if (nonNullTypes.length > 1) return (0, _kubb_ast.createSchema)({
|
|
1558
1717
|
type: "union",
|
|
1559
|
-
members: nonNullTypes.map((t) => convertSchema({
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1718
|
+
members: nonNullTypes.map((t) => convertSchema({
|
|
1719
|
+
schema: {
|
|
1720
|
+
...schema,
|
|
1721
|
+
type: t
|
|
1722
|
+
},
|
|
1723
|
+
name
|
|
1724
|
+
}, options)),
|
|
1563
1725
|
...buildSchemaBase(schema, name, arrayNullable, defaultValue)
|
|
1564
1726
|
});
|
|
1565
1727
|
}
|
|
@@ -1588,12 +1750,17 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1588
1750
|
* When the parameter has no `schema` or its schema is a `$ref`, falls back to `unknownType`.
|
|
1589
1751
|
*/
|
|
1590
1752
|
function parseParameter(options, param) {
|
|
1753
|
+
const required = param["required"] ?? false;
|
|
1591
1754
|
const schema = param["schema"] && !isReference(param["schema"]) ? convertSchema({ schema: param["schema"] }, options) : (0, _kubb_ast.createSchema)({ type: resolveTypeOption(options.unknownType) });
|
|
1592
1755
|
return (0, _kubb_ast.createParameter)({
|
|
1593
1756
|
name: param["name"],
|
|
1594
1757
|
in: param["in"],
|
|
1595
|
-
schema
|
|
1596
|
-
|
|
1758
|
+
schema: {
|
|
1759
|
+
...schema,
|
|
1760
|
+
description: param["description"] ?? schema.description,
|
|
1761
|
+
optional: !required || !!schema.optional ? true : void 0
|
|
1762
|
+
},
|
|
1763
|
+
required
|
|
1597
1764
|
});
|
|
1598
1765
|
}
|
|
1599
1766
|
/**
|
|
@@ -1601,15 +1768,13 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1601
1768
|
* request body, and all response codes into their AST node equivalents.
|
|
1602
1769
|
*/
|
|
1603
1770
|
function parseOperation(options, oas, operation) {
|
|
1604
|
-
const parameters =
|
|
1605
|
-
return parseParameter(options, oas.dereferenceWithRef(param));
|
|
1606
|
-
});
|
|
1771
|
+
const parameters = oas.getParameters(operation).map((param) => parseParameter(options, param));
|
|
1607
1772
|
const requestBodySchema = oas.getRequestSchema(operation);
|
|
1608
1773
|
const requestBody = requestBodySchema ? convertSchema({ schema: requestBodySchema }, options) : void 0;
|
|
1609
1774
|
const responses = operation.getResponseStatusCodes().map((statusCode) => {
|
|
1610
1775
|
const responseObj = operation.getResponseByStatusCode(statusCode);
|
|
1611
1776
|
const responseSchema = oas.getResponseSchema(operation, statusCode);
|
|
1612
|
-
const schema = responseSchema && Object.keys(responseSchema).length > 0 ? convertSchema({ schema: responseSchema }, options) :
|
|
1777
|
+
const schema = responseSchema && Object.keys(responseSchema).length > 0 ? convertSchema({ schema: responseSchema }, options) : (0, _kubb_ast.createSchema)({ type: resolveTypeOption(options.emptySchemaType) });
|
|
1613
1778
|
const description = typeof responseObj === "object" && responseObj !== null && !Array.isArray(responseObj) ? responseObj.description : void 0;
|
|
1614
1779
|
const rawContent = typeof responseObj === "object" && responseObj !== null && !Array.isArray(responseObj) ? responseObj.content : void 0;
|
|
1615
1780
|
return (0, _kubb_ast.createResponse)({
|
|
@@ -1622,7 +1787,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1622
1787
|
return (0, _kubb_ast.createOperation)({
|
|
1623
1788
|
operationId: operation.getOperationId(),
|
|
1624
1789
|
method: operation.method.toUpperCase(),
|
|
1625
|
-
path: operation.path,
|
|
1790
|
+
path: new URLPath(operation.path).URL,
|
|
1626
1791
|
tags: operation.getTags().map((tag) => tag.name),
|
|
1627
1792
|
summary: operation.getSummary() || void 0,
|
|
1628
1793
|
description: operation.getDescription() || void 0,
|
|
@@ -1679,31 +1844,11 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1679
1844
|
}
|
|
1680
1845
|
} });
|
|
1681
1846
|
}
|
|
1682
|
-
/**
|
|
1683
|
-
* Collects all `KubbFile.Import` descriptors needed by a `SchemaNode` tree.
|
|
1684
|
-
*
|
|
1685
|
-
* Walks the tree looking for `ref` nodes, verifies each `$ref` is resolvable in the spec,
|
|
1686
|
-
* applies collision-resolved names from `nameMapping`, and calls `resolve` to obtain the
|
|
1687
|
-
* import path and name. Returns an empty array for refs that cannot be resolved.
|
|
1688
|
-
*/
|
|
1689
|
-
function getImports(node, resolve) {
|
|
1690
|
-
return (0, _kubb_ast.collect)(node, { schema(schemaNode) {
|
|
1691
|
-
if (schemaNode.type !== "ref" || !schemaNode.ref) return;
|
|
1692
|
-
if (!oas.get(schemaNode.ref)) return;
|
|
1693
|
-
const rawName = extractRefName(schemaNode.ref);
|
|
1694
|
-
const result = resolve(nameMapping.get(rawName) ?? rawName);
|
|
1695
|
-
if (!result) return;
|
|
1696
|
-
return {
|
|
1697
|
-
name: [result.name],
|
|
1698
|
-
path: result.path
|
|
1699
|
-
};
|
|
1700
|
-
} });
|
|
1701
|
-
}
|
|
1702
1847
|
return {
|
|
1703
1848
|
parse,
|
|
1704
1849
|
convertSchema,
|
|
1705
1850
|
resolveRefs,
|
|
1706
|
-
|
|
1851
|
+
nameMapping
|
|
1707
1852
|
};
|
|
1708
1853
|
}
|
|
1709
1854
|
//#endregion
|
|
@@ -1727,8 +1872,9 @@ const adapterOasName = "oas";
|
|
|
1727
1872
|
* })
|
|
1728
1873
|
* ```
|
|
1729
1874
|
*/
|
|
1730
|
-
const adapterOas = (0, _kubb_core.
|
|
1875
|
+
const adapterOas = (0, _kubb_core.createAdapter)((options) => {
|
|
1731
1876
|
const { validate = true, oasClass, contentType, serverIndex, serverVariables, discriminator = "strict", collisionDetection = false, dateType = "string", integerType = "number", unknownType = "any", emptySchemaType = unknownType } = options;
|
|
1877
|
+
const nameMapping = /* @__PURE__ */ new Map();
|
|
1732
1878
|
return {
|
|
1733
1879
|
name: "oas",
|
|
1734
1880
|
options: {
|
|
@@ -1742,7 +1888,15 @@ const adapterOas = (0, _kubb_core.defineAdapter)((options) => {
|
|
|
1742
1888
|
dateType,
|
|
1743
1889
|
integerType,
|
|
1744
1890
|
unknownType,
|
|
1745
|
-
emptySchemaType
|
|
1891
|
+
emptySchemaType,
|
|
1892
|
+
nameMapping
|
|
1893
|
+
},
|
|
1894
|
+
getImports(node, resolve) {
|
|
1895
|
+
return getImports({
|
|
1896
|
+
node,
|
|
1897
|
+
nameMapping,
|
|
1898
|
+
resolve
|
|
1899
|
+
});
|
|
1746
1900
|
},
|
|
1747
1901
|
async parse(source) {
|
|
1748
1902
|
const oas = await parseFromConfig(sourceToFakeConfig(source), oasClass);
|
|
@@ -1756,11 +1910,14 @@ const adapterOas = (0, _kubb_core.defineAdapter)((options) => {
|
|
|
1756
1910
|
} catch (_err) {}
|
|
1757
1911
|
const server = serverIndex !== void 0 ? oas.api.servers?.at(serverIndex) : void 0;
|
|
1758
1912
|
const baseURL = server?.url ? resolveServerUrl(server, serverVariables) : void 0;
|
|
1913
|
+
const parser = createOasParser(oas, {
|
|
1914
|
+
contentType,
|
|
1915
|
+
collisionDetection
|
|
1916
|
+
});
|
|
1917
|
+
nameMapping.clear();
|
|
1918
|
+
for (const [key, value] of parser.nameMapping) nameMapping.set(key, value);
|
|
1759
1919
|
return (0, _kubb_ast.createRoot)({
|
|
1760
|
-
...
|
|
1761
|
-
contentType,
|
|
1762
|
-
collisionDetection
|
|
1763
|
-
}).parse({
|
|
1920
|
+
...parser.parse({
|
|
1764
1921
|
dateType,
|
|
1765
1922
|
integerType,
|
|
1766
1923
|
unknownType,
|
|
@@ -1768,6 +1925,7 @@ const adapterOas = (0, _kubb_core.defineAdapter)((options) => {
|
|
|
1768
1925
|
}),
|
|
1769
1926
|
meta: {
|
|
1770
1927
|
title: oas.api.info?.title,
|
|
1928
|
+
description: oas.api.info?.description,
|
|
1771
1929
|
version: oas.api.info?.version,
|
|
1772
1930
|
baseURL
|
|
1773
1931
|
}
|