@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.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";
|
|
@@ -261,9 +261,8 @@ const formatMap = {
|
|
|
261
261
|
};
|
|
262
262
|
/**
|
|
263
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
264
|
*/
|
|
266
|
-
const knownMediaTypes = [
|
|
265
|
+
const knownMediaTypes = new Set([
|
|
267
266
|
"application/json",
|
|
268
267
|
"application/xml",
|
|
269
268
|
"application/x-www-form-urlencoded",
|
|
@@ -283,12 +282,22 @@ const knownMediaTypes = [
|
|
|
283
282
|
"image/svg+xml",
|
|
284
283
|
"audio/mpeg",
|
|
285
284
|
"video/mp4"
|
|
286
|
-
];
|
|
285
|
+
]);
|
|
287
286
|
/**
|
|
288
287
|
* Vendor extension keys used to attach human-readable labels to enum values.
|
|
289
288
|
* Checked in priority order: the first key found wins.
|
|
290
289
|
*/
|
|
291
290
|
const enumExtensionKeys = ["x-enumNames", "x-enum-varnames"];
|
|
291
|
+
/**
|
|
292
|
+
* Scalar primitive schema types used for union member simplification.
|
|
293
|
+
*/
|
|
294
|
+
const SCALAR_PRIMITIVE_TYPES = new Set([
|
|
295
|
+
"string",
|
|
296
|
+
"number",
|
|
297
|
+
"integer",
|
|
298
|
+
"bigint",
|
|
299
|
+
"boolean"
|
|
300
|
+
]);
|
|
292
301
|
//#endregion
|
|
293
302
|
//#region src/oas/Oas.ts
|
|
294
303
|
/**
|
|
@@ -501,8 +510,15 @@ var Oas = class extends BaseOas {
|
|
|
501
510
|
if (!schema) return;
|
|
502
511
|
return this.dereferenceWithRef(schema);
|
|
503
512
|
}
|
|
504
|
-
|
|
505
|
-
|
|
513
|
+
/**
|
|
514
|
+
* Returns all resolved parameters for an operation, merging path-level and operation-level
|
|
515
|
+
* parameters and deduplicating by `in:name` (operation-level takes precedence).
|
|
516
|
+
*
|
|
517
|
+
* oas v31+ filters out `$ref` parameters in `getParameters()`, so this method accesses the
|
|
518
|
+
* raw `operation.schema.parameters` and path-item parameters directly and resolves `$ref`
|
|
519
|
+
* pointers via `dereferenceWithRef` to preserve backward compatibility.
|
|
520
|
+
*/
|
|
521
|
+
getParameters(operation) {
|
|
506
522
|
const resolveParams = (params) => params.map((p) => this.dereferenceWithRef(p)).filter((p) => !!p && typeof p === "object" && "in" in p && "name" in p);
|
|
507
523
|
const operationParams = resolveParams(operation.schema?.parameters || []);
|
|
508
524
|
const pathItem = this.api?.paths?.[operation.path];
|
|
@@ -510,7 +526,11 @@ var Oas = class extends BaseOas {
|
|
|
510
526
|
const paramMap = /* @__PURE__ */ new Map();
|
|
511
527
|
for (const p of pathLevelParams) if (p.name && p.in) paramMap.set(`${p.in}:${p.name}`, p);
|
|
512
528
|
for (const p of operationParams) if (p.name && p.in) paramMap.set(`${p.in}:${p.name}`, p);
|
|
513
|
-
|
|
529
|
+
return Array.from(paramMap.values());
|
|
530
|
+
}
|
|
531
|
+
getParametersSchema(operation, inKey) {
|
|
532
|
+
const { contentType = operation.getContentType() } = this.#options;
|
|
533
|
+
const params = this.getParameters(operation).filter((v) => v.in === inKey);
|
|
514
534
|
if (!params.length) return null;
|
|
515
535
|
return params.reduce((schema, pathParameters) => {
|
|
516
536
|
const property = pathParameters.content?.[contentType]?.schema ?? pathParameters.schema;
|
|
@@ -900,6 +920,136 @@ function resolveCollisions(schemasWithMeta) {
|
|
|
900
920
|
};
|
|
901
921
|
}
|
|
902
922
|
//#endregion
|
|
923
|
+
//#region src/utils.ts
|
|
924
|
+
/**
|
|
925
|
+
* Extracts the schema name from a `$ref` string.
|
|
926
|
+
* For `#/components/schemas/Order` this returns `'Order'`.
|
|
927
|
+
* Falls back to the full ref string when no slash is present.
|
|
928
|
+
*/
|
|
929
|
+
function extractRefName($ref) {
|
|
930
|
+
return $ref.split("/").at(-1) ?? $ref;
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Replaces the discriminator property's schema inside an `ObjectSchemaNode`
|
|
934
|
+
* with an enum of the given `values`.
|
|
935
|
+
*
|
|
936
|
+
* - When `enumName` is provided the enum is named, which lets printers emit a
|
|
937
|
+
* standalone enum declaration + type reference (e.g. `PetTypeEnum`).
|
|
938
|
+
* - When `enumName` is omitted the enum stays anonymous, so printers inline it
|
|
939
|
+
* as a literal union (e.g. `'dog'`).
|
|
940
|
+
*
|
|
941
|
+
* Returns the node unchanged when it is not an object or lacks the target property.
|
|
942
|
+
*/
|
|
943
|
+
function applyDiscriminatorEnum({ node, propertyName, values, enumName }) {
|
|
944
|
+
if (node.type !== "object" || !node.properties?.length) return node;
|
|
945
|
+
if (!node.properties.some((prop) => prop.name === propertyName)) return node;
|
|
946
|
+
return createSchema({
|
|
947
|
+
...node,
|
|
948
|
+
properties: node.properties.map((prop) => {
|
|
949
|
+
if (prop.name !== propertyName) return prop;
|
|
950
|
+
const enumSchema = createSchema({
|
|
951
|
+
type: "enum",
|
|
952
|
+
primitive: "string",
|
|
953
|
+
enumValues: values,
|
|
954
|
+
name: enumName,
|
|
955
|
+
readOnly: prop.schema.readOnly,
|
|
956
|
+
writeOnly: prop.schema.writeOnly
|
|
957
|
+
});
|
|
958
|
+
return createProperty({
|
|
959
|
+
...prop,
|
|
960
|
+
schema: enumSchema
|
|
961
|
+
});
|
|
962
|
+
})
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* Merges consecutive anonymous (`name`-less) `ObjectSchemaNode`s in `members` into a
|
|
967
|
+
* single object by combining their `properties` arrays.
|
|
968
|
+
*
|
|
969
|
+
* Only adjacent pairs are merged — non-object or named nodes act as boundaries.
|
|
970
|
+
* This collapses patterns like `Address & { streetNumber } & { streetName }` into
|
|
971
|
+
* `Address & { streetNumber; streetName }`.
|
|
972
|
+
*/
|
|
973
|
+
function mergeAdjacentAnonymousObjects(members) {
|
|
974
|
+
return members.reduce((acc, member) => {
|
|
975
|
+
const obj = narrowSchema(member, "object");
|
|
976
|
+
if (obj && !obj.name) {
|
|
977
|
+
const prev = acc[acc.length - 1];
|
|
978
|
+
const prevObj = prev ? narrowSchema(prev, "object") : null;
|
|
979
|
+
if (prevObj && !prevObj.name) {
|
|
980
|
+
acc[acc.length - 1] = createSchema({
|
|
981
|
+
...prevObj,
|
|
982
|
+
properties: [...prevObj.properties ?? [], ...obj.properties ?? []]
|
|
983
|
+
});
|
|
984
|
+
return acc;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
acc.push(member);
|
|
988
|
+
return acc;
|
|
989
|
+
}, []);
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Simplifies a union member list by removing `enum` nodes whose `primitive` type is
|
|
993
|
+
* already represented by a broader scalar node in the same union.
|
|
994
|
+
*
|
|
995
|
+
* For example `['placed', 'approved'] | string` collapses to `string` because
|
|
996
|
+
* `string` subsumes all string literals. `'' | string` similarly becomes `string`.
|
|
997
|
+
*
|
|
998
|
+
* Only scalar primitives (`string`, `number`, `integer`, `bigint`, `boolean`) are
|
|
999
|
+
* considered — object, array, and ref members are left untouched.
|
|
1000
|
+
*
|
|
1001
|
+
* Const-derived enums (those without an `enumType`, produced from an OpenAPI `const`
|
|
1002
|
+
* keyword) are **never** removed — `'accepted' | string` must stay as-is because the
|
|
1003
|
+
* literal is intentional.
|
|
1004
|
+
*/
|
|
1005
|
+
function simplifyUnionMembers(members) {
|
|
1006
|
+
const scalarPrimitives = new Set(members.filter((m) => SCALAR_PRIMITIVE_TYPES.has(m.type)).map((m) => m.type));
|
|
1007
|
+
if (!scalarPrimitives.size) return members;
|
|
1008
|
+
return members.filter((m) => {
|
|
1009
|
+
if (m.type !== "enum") return true;
|
|
1010
|
+
const prim = m.primitive;
|
|
1011
|
+
if (!prim) return true;
|
|
1012
|
+
if (!m.enumType) return true;
|
|
1013
|
+
if (scalarPrimitives.has(prim)) return false;
|
|
1014
|
+
if ((prim === "integer" || prim === "number") && (scalarPrimitives.has("integer") || scalarPrimitives.has("number"))) return false;
|
|
1015
|
+
return true;
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* `nameMapping`, and calls `resolve` to obtain the `{ name, path }` pair for
|
|
1020
|
+
* each import. When `oas` is supplied, only `$ref`s that are resolvable in the
|
|
1021
|
+
* spec are included; omit it to skip the existence check.
|
|
1022
|
+
*
|
|
1023
|
+
* This function is the pure, state-free alternative to `OasParser.getImports`.
|
|
1024
|
+
* Because it receives `nameMapping` explicitly it can be called without holding
|
|
1025
|
+
* a reference to the parser or the OAS instance.
|
|
1026
|
+
*
|
|
1027
|
+
* @example
|
|
1028
|
+
* ```ts
|
|
1029
|
+
* // Use adapter state directly — no parser reference needed
|
|
1030
|
+
* const imports = getImports({
|
|
1031
|
+
* node: schemaNode,
|
|
1032
|
+
* nameMapping: adapter.options.nameMapping,
|
|
1033
|
+
* resolve: (schemaName) => ({
|
|
1034
|
+
* name: schemaManager.getName(schemaName, { type: 'type' }),
|
|
1035
|
+
* path: schemaManager.getFile(schemaName).path,
|
|
1036
|
+
* }),
|
|
1037
|
+
* })
|
|
1038
|
+
* ```
|
|
1039
|
+
*/
|
|
1040
|
+
function getImports({ node, nameMapping, resolve }) {
|
|
1041
|
+
return collect(node, { schema(schemaNode) {
|
|
1042
|
+
if (schemaNode.type !== "ref" || !schemaNode.ref) return;
|
|
1043
|
+
const rawName = extractRefName(schemaNode.ref);
|
|
1044
|
+
const result = resolve(nameMapping.get(rawName) ?? rawName);
|
|
1045
|
+
if (!result) return;
|
|
1046
|
+
return {
|
|
1047
|
+
name: [result.name],
|
|
1048
|
+
path: result.path
|
|
1049
|
+
};
|
|
1050
|
+
} });
|
|
1051
|
+
}
|
|
1052
|
+
//#endregion
|
|
903
1053
|
//#region src/parser.ts
|
|
904
1054
|
/**
|
|
905
1055
|
* Default values for all `Options` fields.
|
|
@@ -920,14 +1070,6 @@ function formatToSchemaType(format) {
|
|
|
920
1070
|
return formatMap[format];
|
|
921
1071
|
}
|
|
922
1072
|
/**
|
|
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
1073
|
* Maps an OAS primitive type string to its `PrimitiveSchemaType` equivalent.
|
|
932
1074
|
* Numeric types (`number`, `integer`, `bigint`) are returned unchanged;
|
|
933
1075
|
* `boolean` maps to `'boolean'`; everything else defaults to `'string'`.
|
|
@@ -942,27 +1084,7 @@ function getPrimitiveType(type) {
|
|
|
942
1084
|
* Returns `undefined` for content types not present in `KNOWN_MEDIA_TYPES`.
|
|
943
1085
|
*/
|
|
944
1086
|
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
|
-
};
|
|
1087
|
+
return knownMediaTypes.has(contentType) ? contentType : void 0;
|
|
966
1088
|
}
|
|
967
1089
|
/**
|
|
968
1090
|
* Creates an OAS parser that converts an OpenAPI/Swagger spec into
|
|
@@ -1055,18 +1177,17 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1055
1177
|
* reflected in generated JSDoc and type modifiers.
|
|
1056
1178
|
*/
|
|
1057
1179
|
function convertRef({ schema, nullable, defaultValue }) {
|
|
1058
|
-
const schemaObject = schema;
|
|
1059
1180
|
return createSchema({
|
|
1060
1181
|
type: "ref",
|
|
1061
|
-
name: extractRefName(
|
|
1062
|
-
ref:
|
|
1182
|
+
name: extractRefName(schema.$ref),
|
|
1183
|
+
ref: schema.$ref,
|
|
1063
1184
|
nullable,
|
|
1064
|
-
description:
|
|
1065
|
-
deprecated:
|
|
1066
|
-
readOnly:
|
|
1067
|
-
writeOnly:
|
|
1068
|
-
pattern:
|
|
1069
|
-
example:
|
|
1185
|
+
description: schema.description,
|
|
1186
|
+
deprecated: schema.deprecated,
|
|
1187
|
+
readOnly: schema.readOnly,
|
|
1188
|
+
writeOnly: schema.writeOnly,
|
|
1189
|
+
pattern: schema.type === "string" ? schema.pattern : void 0,
|
|
1190
|
+
example: schema.example,
|
|
1070
1191
|
default: defaultValue
|
|
1071
1192
|
});
|
|
1072
1193
|
}
|
|
@@ -1117,6 +1238,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1117
1238
|
const inMapping = Object.values(deref.discriminator.mapping ?? {}).some((v) => v === childRef);
|
|
1118
1239
|
return !inOneOf && !inMapping;
|
|
1119
1240
|
}).map((s) => convertSchema({ schema: s }, options));
|
|
1241
|
+
const syntheticStart = allOfMembers.length;
|
|
1120
1242
|
if (Array.isArray(schema.required) && schema.required.length) {
|
|
1121
1243
|
const outerKeys = schema.properties ? new Set(Object.keys(schema.properties)) : /* @__PURE__ */ new Set();
|
|
1122
1244
|
const missingRequired = schema.required.filter((key) => !outerKeys.has(key));
|
|
@@ -1141,7 +1263,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1141
1263
|
}
|
|
1142
1264
|
return createSchema({
|
|
1143
1265
|
type: "intersection",
|
|
1144
|
-
members: allOfMembers,
|
|
1266
|
+
members: [...allOfMembers.slice(0, syntheticStart), ...mergeAdjacentAnonymousObjects(allOfMembers.slice(syntheticStart))],
|
|
1145
1267
|
...buildSchemaBase(schema, name, nullable, defaultValue)
|
|
1146
1268
|
});
|
|
1147
1269
|
}
|
|
@@ -1161,20 +1283,34 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1161
1283
|
};
|
|
1162
1284
|
if (schema.properties) {
|
|
1163
1285
|
const { oneOf: _oneOf, anyOf: _anyOf, ...schemaWithoutUnion } = schema;
|
|
1164
|
-
const
|
|
1286
|
+
const discriminator = isDiscriminator(schema) ? schema.discriminator : void 0;
|
|
1287
|
+
const memberBaseSchema = discriminator ? Object.fromEntries(Object.entries(schemaWithoutUnion).filter(([key]) => key !== "discriminator")) : schemaWithoutUnion;
|
|
1165
1288
|
return createSchema({
|
|
1166
1289
|
type: "union",
|
|
1167
1290
|
...unionBase,
|
|
1168
|
-
members: unionMembers.map((s) =>
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1291
|
+
members: unionMembers.map((s) => {
|
|
1292
|
+
const ref = isReference(s) ? s.$ref : void 0;
|
|
1293
|
+
const discriminatorValue = discriminator?.mapping && ref ? Object.entries(discriminator.mapping).find(([, v]) => v === ref)?.[0] : void 0;
|
|
1294
|
+
let propertiesNode = convertSchema({
|
|
1295
|
+
schema: memberBaseSchema,
|
|
1296
|
+
name
|
|
1297
|
+
}, options);
|
|
1298
|
+
if (discriminatorValue && discriminator) propertiesNode = applyDiscriminatorEnum({
|
|
1299
|
+
node: propertiesNode,
|
|
1300
|
+
propertyName: discriminator.propertyName,
|
|
1301
|
+
values: [discriminatorValue]
|
|
1302
|
+
});
|
|
1303
|
+
return createSchema({
|
|
1304
|
+
type: "intersection",
|
|
1305
|
+
members: [convertSchema({ schema: s }, options), propertiesNode]
|
|
1306
|
+
});
|
|
1307
|
+
})
|
|
1172
1308
|
});
|
|
1173
1309
|
}
|
|
1174
1310
|
return createSchema({
|
|
1175
1311
|
type: "union",
|
|
1176
1312
|
...unionBase,
|
|
1177
|
-
members: unionMembers.map((s) => convertSchema({ schema: s }, options))
|
|
1313
|
+
members: simplifyUnionMembers(unionMembers.map((s) => convertSchema({ schema: s }, options)))
|
|
1178
1314
|
});
|
|
1179
1315
|
}
|
|
1180
1316
|
/**
|
|
@@ -1241,6 +1377,11 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1241
1377
|
primitive: specialPrimitive,
|
|
1242
1378
|
type: specialType
|
|
1243
1379
|
});
|
|
1380
|
+
if (specialType === "url") return createSchema({
|
|
1381
|
+
...base,
|
|
1382
|
+
primitive: "string",
|
|
1383
|
+
type: "url"
|
|
1384
|
+
});
|
|
1244
1385
|
return createSchema({
|
|
1245
1386
|
...base,
|
|
1246
1387
|
primitive: specialPrimitive,
|
|
@@ -1259,9 +1400,8 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1259
1400
|
*/
|
|
1260
1401
|
function convertEnum({ schema, name, nullable, type, options }) {
|
|
1261
1402
|
if (type === "array") {
|
|
1262
|
-
const rawSchema = schema;
|
|
1263
1403
|
const normalizedItems = {
|
|
1264
|
-
...typeof
|
|
1404
|
+
...typeof schema.items === "object" && !Array.isArray(schema.items) ? schema.items : {},
|
|
1265
1405
|
enum: schema.enum
|
|
1266
1406
|
};
|
|
1267
1407
|
const { enum: _enum, ...schemaWithoutEnum } = schema;
|
|
@@ -1341,22 +1481,28 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1341
1481
|
* - not required + nullable → `nullish: true`
|
|
1342
1482
|
*/
|
|
1343
1483
|
function convertObject({ schema, name, nullable, defaultValue, options, mergedOptions }) {
|
|
1344
|
-
const
|
|
1345
|
-
|
|
1346
|
-
const required = Array.isArray(resolvedSchema.required) ? resolvedSchema.required.includes(propName) : !!resolvedSchema.required;
|
|
1484
|
+
const properties = schema.properties ? Object.entries(schema.properties).map(([propName, propSchema]) => {
|
|
1485
|
+
const required = Array.isArray(schema.required) ? schema.required.includes(propName) : !!schema.required;
|
|
1347
1486
|
const resolvedPropSchema = propSchema;
|
|
1348
1487
|
const propNullable = isNullable(resolvedPropSchema);
|
|
1488
|
+
const basePropName = name ? pascalCase([name, propName].join(" ")) : void 0;
|
|
1489
|
+
const propNode = convertSchema({
|
|
1490
|
+
schema: resolvedPropSchema,
|
|
1491
|
+
name: basePropName
|
|
1492
|
+
}, options);
|
|
1493
|
+
const isEnumNode = !!narrowSchema(propNode, "enum");
|
|
1494
|
+
const derivedPropName = isEnumNode && name ? pascalCase([
|
|
1495
|
+
name,
|
|
1496
|
+
propName,
|
|
1497
|
+
mergedOptions.enumSuffix
|
|
1498
|
+
].filter(Boolean).join(" ")) : basePropName;
|
|
1349
1499
|
return createProperty({
|
|
1350
1500
|
name: propName,
|
|
1351
1501
|
schema: {
|
|
1352
|
-
...
|
|
1353
|
-
|
|
1354
|
-
name:
|
|
1355
|
-
|
|
1356
|
-
propName,
|
|
1357
|
-
mergedOptions.enumSuffix
|
|
1358
|
-
].filter(Boolean).join(" ")) : void 0
|
|
1359
|
-
}, options),
|
|
1502
|
+
...isEnumNode && derivedPropName !== basePropName ? {
|
|
1503
|
+
...propNode,
|
|
1504
|
+
name: derivedPropName
|
|
1505
|
+
} : propNode,
|
|
1360
1506
|
nullable: propNullable || void 0,
|
|
1361
1507
|
optional: !required && !propNullable ? true : void 0,
|
|
1362
1508
|
nullish: !required && propNullable ? true : void 0
|
|
@@ -1364,15 +1510,15 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1364
1510
|
required
|
|
1365
1511
|
});
|
|
1366
1512
|
}) : [];
|
|
1367
|
-
const additionalProperties =
|
|
1513
|
+
const additionalProperties = schema.additionalProperties;
|
|
1368
1514
|
let additionalPropertiesNode;
|
|
1369
1515
|
if (additionalProperties === true) additionalPropertiesNode = true;
|
|
1370
1516
|
else if (additionalProperties && Object.keys(additionalProperties).length > 0) additionalPropertiesNode = convertSchema({ schema: additionalProperties }, options);
|
|
1371
1517
|
else if (additionalProperties === false) additionalPropertiesNode = void 0;
|
|
1372
1518
|
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
|
-
|
|
1519
|
+
const rawPatternProperties = "patternProperties" in schema ? schema.patternProperties : void 0;
|
|
1520
|
+
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;
|
|
1521
|
+
const objectNode = createSchema({
|
|
1376
1522
|
type: "object",
|
|
1377
1523
|
primitive: "object",
|
|
1378
1524
|
properties,
|
|
@@ -1380,6 +1526,20 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1380
1526
|
patternProperties,
|
|
1381
1527
|
...buildSchemaBase(schema, name, nullable, defaultValue)
|
|
1382
1528
|
});
|
|
1529
|
+
if (isDiscriminator(schema) && schema.discriminator.mapping) {
|
|
1530
|
+
const discPropName = schema.discriminator.propertyName;
|
|
1531
|
+
return applyDiscriminatorEnum({
|
|
1532
|
+
node: objectNode,
|
|
1533
|
+
propertyName: discPropName,
|
|
1534
|
+
values: Object.keys(schema.discriminator.mapping),
|
|
1535
|
+
enumName: name ? pascalCase([
|
|
1536
|
+
name,
|
|
1537
|
+
discPropName,
|
|
1538
|
+
mergedOptions.enumSuffix
|
|
1539
|
+
].filter(Boolean).join(" ")) : void 0
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
return objectNode;
|
|
1383
1543
|
}
|
|
1384
1544
|
/**
|
|
1385
1545
|
* Converts an OAS 3.1 `prefixItems` tuple into a `TupleSchemaNode`.
|
|
@@ -1388,12 +1548,11 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1388
1548
|
* after the prefix items is mapped to the rest parameter of the tuple.
|
|
1389
1549
|
*/
|
|
1390
1550
|
function convertTuple({ schema, name, nullable, defaultValue, options }) {
|
|
1391
|
-
const rawSchema = schema;
|
|
1392
1551
|
return createSchema({
|
|
1393
1552
|
type: "tuple",
|
|
1394
1553
|
primitive: "array",
|
|
1395
|
-
items:
|
|
1396
|
-
rest:
|
|
1554
|
+
items: (schema.prefixItems ?? []).map((item) => convertSchema({ schema: item }, options)),
|
|
1555
|
+
rest: schema.items ? convertSchema({ schema: schema.items }, options) : void 0,
|
|
1397
1556
|
min: schema.minItems,
|
|
1398
1557
|
max: schema.maxItems,
|
|
1399
1558
|
...buildSchemaBase(schema, name, nullable, defaultValue)
|
|
@@ -1406,13 +1565,13 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1406
1565
|
* `enumSuffix` is forwarded so generators can emit a named enum declaration.
|
|
1407
1566
|
*/
|
|
1408
1567
|
function convertArray({ schema, name, nullable, defaultValue, options, mergedOptions }) {
|
|
1409
|
-
const
|
|
1410
|
-
const itemName =
|
|
1568
|
+
const rawItems = schema.items;
|
|
1569
|
+
const itemName = rawItems?.enum?.length && name ? pascalCase([name, mergedOptions.enumSuffix].join(" ")) : void 0;
|
|
1411
1570
|
return createSchema({
|
|
1412
1571
|
type: "array",
|
|
1413
1572
|
primitive: "array",
|
|
1414
|
-
items:
|
|
1415
|
-
schema:
|
|
1573
|
+
items: rawItems ? [convertSchema({
|
|
1574
|
+
schema: rawItems,
|
|
1416
1575
|
name: itemName
|
|
1417
1576
|
}, options)] : [],
|
|
1418
1577
|
min: schema.minItems,
|
|
@@ -1528,10 +1687,13 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1528
1687
|
const arrayNullable = schema.type.includes("null") || nullable || void 0;
|
|
1529
1688
|
if (nonNullTypes.length > 1) return createSchema({
|
|
1530
1689
|
type: "union",
|
|
1531
|
-
members: nonNullTypes.map((t) => convertSchema({
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1690
|
+
members: nonNullTypes.map((t) => convertSchema({
|
|
1691
|
+
schema: {
|
|
1692
|
+
...schema,
|
|
1693
|
+
type: t
|
|
1694
|
+
},
|
|
1695
|
+
name
|
|
1696
|
+
}, options)),
|
|
1535
1697
|
...buildSchemaBase(schema, name, arrayNullable, defaultValue)
|
|
1536
1698
|
});
|
|
1537
1699
|
}
|
|
@@ -1560,12 +1722,17 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1560
1722
|
* When the parameter has no `schema` or its schema is a `$ref`, falls back to `unknownType`.
|
|
1561
1723
|
*/
|
|
1562
1724
|
function parseParameter(options, param) {
|
|
1725
|
+
const required = param["required"] ?? false;
|
|
1563
1726
|
const schema = param["schema"] && !isReference(param["schema"]) ? convertSchema({ schema: param["schema"] }, options) : createSchema({ type: resolveTypeOption(options.unknownType) });
|
|
1564
1727
|
return createParameter({
|
|
1565
1728
|
name: param["name"],
|
|
1566
1729
|
in: param["in"],
|
|
1567
|
-
schema
|
|
1568
|
-
|
|
1730
|
+
schema: {
|
|
1731
|
+
...schema,
|
|
1732
|
+
description: param["description"] ?? schema.description,
|
|
1733
|
+
optional: !required || !!schema.optional ? true : void 0
|
|
1734
|
+
},
|
|
1735
|
+
required
|
|
1569
1736
|
});
|
|
1570
1737
|
}
|
|
1571
1738
|
/**
|
|
@@ -1573,15 +1740,13 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1573
1740
|
* request body, and all response codes into their AST node equivalents.
|
|
1574
1741
|
*/
|
|
1575
1742
|
function parseOperation(options, oas, operation) {
|
|
1576
|
-
const parameters =
|
|
1577
|
-
return parseParameter(options, oas.dereferenceWithRef(param));
|
|
1578
|
-
});
|
|
1743
|
+
const parameters = oas.getParameters(operation).map((param) => parseParameter(options, param));
|
|
1579
1744
|
const requestBodySchema = oas.getRequestSchema(operation);
|
|
1580
1745
|
const requestBody = requestBodySchema ? convertSchema({ schema: requestBodySchema }, options) : void 0;
|
|
1581
1746
|
const responses = operation.getResponseStatusCodes().map((statusCode) => {
|
|
1582
1747
|
const responseObj = operation.getResponseByStatusCode(statusCode);
|
|
1583
1748
|
const responseSchema = oas.getResponseSchema(operation, statusCode);
|
|
1584
|
-
const schema = responseSchema && Object.keys(responseSchema).length > 0 ? convertSchema({ schema: responseSchema }, options) :
|
|
1749
|
+
const schema = responseSchema && Object.keys(responseSchema).length > 0 ? convertSchema({ schema: responseSchema }, options) : createSchema({ type: resolveTypeOption(options.emptySchemaType) });
|
|
1585
1750
|
const description = typeof responseObj === "object" && responseObj !== null && !Array.isArray(responseObj) ? responseObj.description : void 0;
|
|
1586
1751
|
const rawContent = typeof responseObj === "object" && responseObj !== null && !Array.isArray(responseObj) ? responseObj.content : void 0;
|
|
1587
1752
|
return createResponse({
|
|
@@ -1594,7 +1759,7 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1594
1759
|
return createOperation({
|
|
1595
1760
|
operationId: operation.getOperationId(),
|
|
1596
1761
|
method: operation.method.toUpperCase(),
|
|
1597
|
-
path: operation.path,
|
|
1762
|
+
path: new URLPath(operation.path).URL,
|
|
1598
1763
|
tags: operation.getTags().map((tag) => tag.name),
|
|
1599
1764
|
summary: operation.getSummary() || void 0,
|
|
1600
1765
|
description: operation.getDescription() || void 0,
|
|
@@ -1651,31 +1816,11 @@ function createOasParser(oas, { contentType, collisionDetection } = {}) {
|
|
|
1651
1816
|
}
|
|
1652
1817
|
} });
|
|
1653
1818
|
}
|
|
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
1819
|
return {
|
|
1675
1820
|
parse,
|
|
1676
1821
|
convertSchema,
|
|
1677
1822
|
resolveRefs,
|
|
1678
|
-
|
|
1823
|
+
nameMapping
|
|
1679
1824
|
};
|
|
1680
1825
|
}
|
|
1681
1826
|
//#endregion
|
|
@@ -1699,8 +1844,9 @@ const adapterOasName = "oas";
|
|
|
1699
1844
|
* })
|
|
1700
1845
|
* ```
|
|
1701
1846
|
*/
|
|
1702
|
-
const adapterOas =
|
|
1847
|
+
const adapterOas = createAdapter((options) => {
|
|
1703
1848
|
const { validate = true, oasClass, contentType, serverIndex, serverVariables, discriminator = "strict", collisionDetection = false, dateType = "string", integerType = "number", unknownType = "any", emptySchemaType = unknownType } = options;
|
|
1849
|
+
const nameMapping = /* @__PURE__ */ new Map();
|
|
1704
1850
|
return {
|
|
1705
1851
|
name: "oas",
|
|
1706
1852
|
options: {
|
|
@@ -1714,7 +1860,15 @@ const adapterOas = defineAdapter((options) => {
|
|
|
1714
1860
|
dateType,
|
|
1715
1861
|
integerType,
|
|
1716
1862
|
unknownType,
|
|
1717
|
-
emptySchemaType
|
|
1863
|
+
emptySchemaType,
|
|
1864
|
+
nameMapping
|
|
1865
|
+
},
|
|
1866
|
+
getImports(node, resolve) {
|
|
1867
|
+
return getImports({
|
|
1868
|
+
node,
|
|
1869
|
+
nameMapping,
|
|
1870
|
+
resolve
|
|
1871
|
+
});
|
|
1718
1872
|
},
|
|
1719
1873
|
async parse(source) {
|
|
1720
1874
|
const oas = await parseFromConfig(sourceToFakeConfig(source), oasClass);
|
|
@@ -1728,11 +1882,14 @@ const adapterOas = defineAdapter((options) => {
|
|
|
1728
1882
|
} catch (_err) {}
|
|
1729
1883
|
const server = serverIndex !== void 0 ? oas.api.servers?.at(serverIndex) : void 0;
|
|
1730
1884
|
const baseURL = server?.url ? resolveServerUrl(server, serverVariables) : void 0;
|
|
1885
|
+
const parser = createOasParser(oas, {
|
|
1886
|
+
contentType,
|
|
1887
|
+
collisionDetection
|
|
1888
|
+
});
|
|
1889
|
+
nameMapping.clear();
|
|
1890
|
+
for (const [key, value] of parser.nameMapping) nameMapping.set(key, value);
|
|
1731
1891
|
return createRoot({
|
|
1732
|
-
...
|
|
1733
|
-
contentType,
|
|
1734
|
-
collisionDetection
|
|
1735
|
-
}).parse({
|
|
1892
|
+
...parser.parse({
|
|
1736
1893
|
dateType,
|
|
1737
1894
|
integerType,
|
|
1738
1895
|
unknownType,
|
|
@@ -1740,6 +1897,7 @@ const adapterOas = defineAdapter((options) => {
|
|
|
1740
1897
|
}),
|
|
1741
1898
|
meta: {
|
|
1742
1899
|
title: oas.api.info?.title,
|
|
1900
|
+
description: oas.api.info?.description,
|
|
1743
1901
|
version: oas.api.info?.version,
|
|
1744
1902
|
baseURL
|
|
1745
1903
|
}
|