@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.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 { defineAdapter } from "@kubb/core";
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
- getParametersSchema(operation, inKey) {
505
- const { contentType = operation.getContentType() } = this.#options;
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
- const params = Array.from(paramMap.values()).filter((v) => v.in === inKey);
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.includes(contentType) ? contentType : void 0;
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(schemaObject.$ref),
1062
- ref: schemaObject.$ref,
1182
+ name: extractRefName(schema.$ref),
1183
+ ref: schema.$ref,
1063
1184
  nullable,
1064
- description: schemaObject.description,
1065
- deprecated: schemaObject.deprecated,
1066
- readOnly: schemaObject.readOnly,
1067
- writeOnly: schemaObject.writeOnly,
1068
- pattern: schemaObject.type === "string" ? schemaObject.pattern : void 0,
1069
- example: schemaObject.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 propertiesNode = convertSchema({ schema: schemaWithoutUnion }, options);
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) => createSchema({
1169
- type: "intersection",
1170
- members: [convertSchema({ schema: s }, options), propertiesNode]
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 rawSchema.items === "object" && !Array.isArray(rawSchema.items) ? rawSchema.items : {},
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 resolvedSchema = applyDiscriminatorEnum(schema);
1345
- const properties = resolvedSchema.properties ? Object.entries(resolvedSchema.properties).map(([propName, propSchema]) => {
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
- ...convertSchema({
1353
- schema: resolvedPropSchema,
1354
- name: name ? pascalCase([
1355
- name,
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 = resolvedSchema.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 resolvedSchema ? resolvedSchema.patternProperties : void 0;
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
- return createSchema({
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: rawSchema.prefixItems.map((item) => convertSchema({ schema: item }, options)),
1396
- rest: rawSchema.items ? convertSchema({ schema: rawSchema.items }, options) : void 0,
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 rawSchema = schema;
1410
- const itemName = rawSchema.items?.enum?.length && name ? pascalCase([name, mergedOptions.enumSuffix].join(" ")) : void 0;
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: rawSchema.items ? [convertSchema({
1415
- schema: rawSchema.items,
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({ schema: {
1532
- ...schema,
1533
- type: t
1534
- } }, options)),
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
- required: param["required"] ?? false
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 = operation.getParameters().map((param) => {
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) : void 0;
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
- getImports
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 = defineAdapter((options) => {
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
- ...createOasParser(oas, {
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
  }