@kubb/adapter-oas 5.17.0 → 5.18.0

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 CHANGED
@@ -23,6 +23,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  let _kubb_core = require("@kubb/core");
24
24
  let _kubb_kit = require("@kubb/kit");
25
25
  let node_path = require("node:path");
26
+ let node_url = require("node:url");
26
27
  let node_fs_promises = require("node:fs/promises");
27
28
  let _scalar_openapi_upgrader = require("@scalar/openapi-upgrader");
28
29
  let api_ref_bundler = require("api-ref-bundler");
@@ -35,7 +36,7 @@ var compatibility = {
35
36
  "node": ">=22.22"
36
37
  };
37
38
  // package.json
38
- var version = "5.17.0";
39
+ var version = "5.18.0";
39
40
  // src/constants.ts
40
41
  /**
41
42
  * Default parser options applied when no explicit options are provided.
@@ -417,6 +418,21 @@ function isOpenApi32(document) {
417
418
  const [major = 0, minor = 0] = String(document.openapi).split(".").map(Number);
418
419
  return major > 3 || major === 3 && minor >= 2;
419
420
  }
421
+ function pickStrings(source, keys) {
422
+ if (!source || typeof source !== "object") return void 0;
423
+ const entries = keys.flatMap((key) => {
424
+ const value = source[key];
425
+ return typeof value === "string" ? [[key, value]] : [];
426
+ });
427
+ return entries.length ? Object.fromEntries(entries) : void 0;
428
+ }
429
+ function getExternalDocs(source) {
430
+ const docs = pickStrings(source, ["url", "description"]);
431
+ return docs?.url ? {
432
+ url: docs.url,
433
+ ...docs.description !== void 0 && { description: docs.description }
434
+ } : void 0;
435
+ }
420
436
  /**
421
437
  * Returns the `x-*` keys of `source` as-is, or `undefined` when there are none.
422
438
  */
@@ -431,12 +447,12 @@ function isReference(obj) {
431
447
  return !!obj && typeof obj === "object" && "$ref" in obj;
432
448
  }
433
449
  /**
434
- * Returns `true` when `obj` is a schema with a structured OAS 3.x `discriminator` object,
435
- * excluding the Swagger 2 string form.
450
+ * Returns `true` when `obj` is a schema with a structured OAS 3.x `discriminator` object that names a
451
+ * `propertyName`, excluding the Swagger 2 string form and a 3.2 discriminator that only sets `defaultMapping`.
436
452
  */
437
453
  function isDiscriminator(obj) {
438
- const record = obj;
439
- return !!obj && !!record["discriminator"] && typeof record["discriminator"] !== "string";
454
+ const discriminator = obj?.["discriminator"];
455
+ return !!discriminator && typeof discriminator === "object" && typeof discriminator.propertyName === "string";
440
456
  }
441
457
  /**
442
458
  * Returns `true` when a schema is a raw binary payload.
@@ -445,17 +461,32 @@ function isBinary(schema) {
445
461
  return schema.contentMediaType === "application/octet-stream" && schema.contentEncoding === void 0 && (schema.type === void 0 || schema.type === "string");
446
462
  }
447
463
  /**
464
+ * Keywords that only annotate a schema. A schema with nothing else does not constrain the value.
465
+ */
466
+ const annotationKeywords = /* @__PURE__ */ new Set([
467
+ "title",
468
+ "description",
469
+ "default",
470
+ "example",
471
+ "examples",
472
+ "deprecated",
473
+ "readOnly",
474
+ "writeOnly",
475
+ "externalDocs"
476
+ ]);
477
+ /**
448
478
  * Returns the binary schema for a non-JSON entry the OAS 3.1 upgrade emptied out, or `undefined`
449
479
  * when the entry carries a schema of its own. The upgrade rewrites `format: 'binary'` into
450
480
  * `contentMediaType` and drops it whenever it only repeats the media type key, for any binary
451
481
  * media type (`application/octet-stream`, `application/pdf`, `image/png`, ...), not just
452
482
  * `application/octet-stream`. Without the fallback such a body resolves to the empty schema type
453
- * instead of a blob.
483
+ * instead of a blob. Annotations such as `description` survive the upgrade and are kept.
454
484
  */
455
485
  function getBinaryFallbackSchema(mediaType, schema) {
456
486
  if (!mediaType || isJsonMimeType(mediaType)) return void 0;
457
- if (schema && Object.keys(schema).length > 0) return void 0;
487
+ if (schema && Object.keys(schema).some((key) => !annotationKeywords.has(key) && !key.startsWith("x-"))) return void 0;
458
488
  return {
489
+ ...schema,
459
490
  type: "string",
460
491
  contentMediaType: "application/octet-stream"
461
492
  };
@@ -594,6 +625,65 @@ function createRefs(document) {
594
625
  derefKeepingRef
595
626
  };
596
627
  }
628
+ // src/load/schemaIds.ts
629
+ const DATA_KEYS = /* @__PURE__ */ new Set([
630
+ "example",
631
+ "examples",
632
+ "const",
633
+ "enum",
634
+ "default"
635
+ ]);
636
+ const NAMED_ENTRY_KEYS = /* @__PURE__ */ new Set([
637
+ "properties",
638
+ "patternProperties",
639
+ "$defs",
640
+ "definitions",
641
+ "schemas",
642
+ "dependentSchemas"
643
+ ]);
644
+ function walk(node, pointer, visit, parentKey) {
645
+ if (!node || typeof node !== "object") return;
646
+ if (!Array.isArray(node)) visit(node, pointer);
647
+ const named = parentKey !== void 0 && NAMED_ENTRY_KEYS.has(parentKey);
648
+ for (const [key, value] of Object.entries(node)) {
649
+ if (!named && (DATA_KEYS.has(key) || key.startsWith("x-"))) continue;
650
+ walk(value, `${pointer}/${escapePointerToken(key)}`, visit, Array.isArray(node) ? parentKey : key);
651
+ }
652
+ }
653
+ /**
654
+ * The declaration in the nearest enclosing schema, else the only one, else `undefined`.
655
+ */
656
+ function pick(declarations, pointer) {
657
+ if (!declarations) return void 0;
658
+ const enclosing = declarations.filter((target) => pointer === target || pointer.startsWith(`${target}/`));
659
+ if (enclosing.length) return enclosing.reduce((a, b) => b.length > a.length ? b : a);
660
+ return declarations.length === 1 ? declarations[0] : void 0;
661
+ }
662
+ /**
663
+ * Rewrites, in place, each `$ref` to an `$id`, `$anchor` or `$dynamicAnchor`, and each `$dynamicRef`, into a
664
+ * `#/...` pointer, so it is not fetched. Instance data and `x-` extensions are left as written.
665
+ *
666
+ * shortcut: `$id` matches the `$ref` string exactly and `$dynamicRef` resolves statically to the nearest
667
+ * enclosing anchor, so a relative `$id` base or a recursively extended schema is not followed, upgrade when a spec needs that.
668
+ */
669
+ function resolveSchemaIds(document) {
670
+ const targets = /* @__PURE__ */ new Map();
671
+ const declare = (key, pointer) => targets.set(key, [...targets.get(key) ?? [], pointer]);
672
+ walk(document, "#", (node, pointer) => {
673
+ if (typeof node["$id"] === "string") declare(node["$id"], pointer);
674
+ for (const key of ["$anchor", "$dynamicAnchor"]) if (typeof node[key] === "string") declare(`#${node[key]}`, pointer);
675
+ });
676
+ if (!targets.size) return;
677
+ walk(document, "#", (node, pointer) => {
678
+ const ref = typeof node["$ref"] === "string" ? pick(targets.get(node["$ref"]), pointer) : void 0;
679
+ if (ref) node["$ref"] = ref;
680
+ const dynamicRef = typeof node["$dynamicRef"] === "string" ? pick(targets.get(node["$dynamicRef"]), pointer) : void 0;
681
+ if (dynamicRef && node["$ref"] === void 0) {
682
+ node["$ref"] = dynamicRef;
683
+ delete node["$dynamicRef"];
684
+ }
685
+ });
686
+ }
597
687
  // src/load/source.ts
598
688
  const urlRegExp = /^https?:\/+/i;
599
689
  /**
@@ -763,6 +853,21 @@ function isExtensionPath(path) {
763
853
  return path.some((token, index) => String(token).startsWith("x-") && !namedEntryKeys.has(String(path[index - 1])));
764
854
  }
765
855
  /**
856
+ * Returns the base for relative `$ref`s: the 3.2 `$self` resolved against `pathOrUrl`, else `pathOrUrl`.
857
+ */
858
+ function getBaseUri(pathOrUrl, root) {
859
+ const self = root && typeof root === "object" ? root.$self : void 0;
860
+ if (typeof self !== "string" || !self) return pathOrUrl;
861
+ try {
862
+ if (urlRegExp.test(self)) return new URL(self).href;
863
+ if (/^file:/i.test(self)) return (0, node_url.fileURLToPath)(self);
864
+ if (/^[a-z][a-z\d+.-]*:/i.test(self)) return pathOrUrl;
865
+ return urlRegExp.test(pathOrUrl) ? new URL(self, pathOrUrl).href : (0, node_path.resolve)((0, node_path.dirname)(pathOrUrl), self);
866
+ } catch {
867
+ return pathOrUrl;
868
+ }
869
+ }
870
+ /**
766
871
  * Bundles a multi-file OpenAPI document into a single document via `api-ref-bundler`.
767
872
  *
768
873
  * External file schemas are hoisted into named `components.schemas` entries, so a property
@@ -775,8 +880,9 @@ function isExtensionPath(path) {
775
880
  * all-internal document it is a no-op that still walks the whole tree to confirm that, which
776
881
  * costs real time on a large spec.
777
882
  *
778
- * `document` stands in for the file at `pathOrUrl`, such as inline input. Every other file or URL
779
- * read, including one that fails, lands in `sources`. A `$ref` that cannot be read reports
883
+ * `document` stands in for the file at `pathOrUrl`, such as inline input. Relative `$ref`s resolve
884
+ * against the OpenAPI 3.2 `$self` when the document sets one. Every other file or URL read,
885
+ * including one that fails, lands in `sources`. A `$ref` that cannot be read reports
780
886
  * `KUBB_REF_NOT_FOUND` at the key that holds it, as a warning when it sits inside an `x-` extension.
781
887
  *
782
888
  * @example Local file
@@ -788,8 +894,10 @@ function isExtensionPath(path) {
788
894
  async function bundleDocument(pathOrUrl, { document, sources = [] } = {}) {
789
895
  const cache = /* @__PURE__ */ new Map();
790
896
  const toKey = (sourcePath) => urlRegExp.test(sourcePath) ? new URL(sourcePath).href : sourcePath;
897
+ let entry = pathOrUrl;
898
+ let entryDocument = document;
791
899
  const resolver = (sourcePath) => {
792
- if (document && sourcePath === pathOrUrl) return Promise.resolve(document);
900
+ if (entryDocument !== void 0 && toKey(sourcePath) === toKey(entry)) return Promise.resolve(entryDocument);
793
901
  const key = toKey(sourcePath);
794
902
  const cached = cache.get(key);
795
903
  if (cached) return cached;
@@ -799,9 +907,12 @@ async function bundleDocument(pathOrUrl, { document, sources = [] } = {}) {
799
907
  return result;
800
908
  };
801
909
  const root = await resolver(pathOrUrl);
910
+ resolveSchemaIds(root);
802
911
  if (typeof root === "object" && root !== null && !hasExternalRef(root)) return root;
803
- return await (0, api_ref_bundler.bundle)(pathOrUrl, resolver, { hooks: { onError: (message, { path, state }) => {
804
- const pointer = toKey(state.baseFile) === toKey(pathOrUrl) ? `#/${path.map((token) => escapePointerToken(String(token))).join("/")}` : void 0;
912
+ entry = getBaseUri(pathOrUrl, root);
913
+ entryDocument = root;
914
+ return await (0, api_ref_bundler.bundle)(entry, resolver, { hooks: { onError: (message, { path, state }) => {
915
+ const pointer = toKey(state.baseFile) === toKey(entry) ? `#/${path.map((token) => escapePointerToken(String(token))).join("/")}` : void 0;
805
916
  const diagnostic = {
806
917
  code: _kubb_kit.Diagnostics.code.refNotFound,
807
918
  severity: isExtensionPath(path) ? "warning" : "error",
@@ -840,10 +951,12 @@ async function parseFromConfig(source, sources = []) {
840
951
  origin: "the inline `input` string",
841
952
  help: "Fix the syntax at the reported line. Kubb reads `input` as an inline spec, not a file path, because it starts with `{`, `[`, `openapi:`, or `swagger:`, or spans several lines."
842
953
  }) : structuredClone(source.data);
843
- return source.root && hasExternalRef(data) ? bundleDocument((0, node_path.join)(source.root, inlineInputName), {
954
+ if (source.root && hasExternalRef(data)) return bundleDocument((0, node_path.join)(source.root, inlineInputName), {
844
955
  document: data,
845
956
  sources
846
- }) : data;
957
+ });
958
+ resolveSchemaIds(data);
959
+ return data;
847
960
  }
848
961
  await assertInputExists(source.path);
849
962
  return bundleDocument(source.path, { sources });
@@ -1168,6 +1281,80 @@ function getSchemas(document, { contentType }, refs) {
1168
1281
  pointers
1169
1282
  };
1170
1283
  }
1284
+ // src/model/security.ts
1285
+ const SCHEME_POINTER = "#/components/securitySchemes/";
1286
+ const API_KEY_LOCATIONS = /* @__PURE__ */ new Set([
1287
+ "header",
1288
+ "query",
1289
+ "cookie"
1290
+ ]);
1291
+ function getCredential(scheme) {
1292
+ if (scheme.type === "apiKey") return scheme.name && scheme.in && API_KEY_LOCATIONS.has(scheme.in) ? {
1293
+ type: "apiKey",
1294
+ in: scheme.in,
1295
+ name: scheme.name
1296
+ } : void 0;
1297
+ if (scheme.type === "http") return scheme.scheme ? {
1298
+ type: "http",
1299
+ scheme: scheme.scheme.toLowerCase(),
1300
+ ...scheme.bearerFormat && { bearerFormat: scheme.bearerFormat }
1301
+ } : void 0;
1302
+ if (scheme.type === "openIdConnect") return {
1303
+ type: "openIdConnect",
1304
+ ...scheme.openIdConnectUrl && { url: scheme.openIdConnectUrl }
1305
+ };
1306
+ if (scheme.type === "oauth2") {
1307
+ const flows = Object.entries(scheme.flows ?? {}).map(([name, flow]) => {
1308
+ const scopes = flow && typeof flow === "object" && flow.scopes && typeof flow.scopes === "object" ? { scopes: flow.scopes } : {};
1309
+ return [name, {
1310
+ ...pickStrings(flow, [
1311
+ "authorizationUrl",
1312
+ "deviceAuthorizationUrl",
1313
+ "tokenUrl",
1314
+ "refreshUrl"
1315
+ ]),
1316
+ ...scopes
1317
+ }];
1318
+ });
1319
+ return {
1320
+ type: "oauth2",
1321
+ flows: Object.fromEntries(flows),
1322
+ ...scheme.oauth2MetadataUrl && { metadataUrl: scheme.oauth2MetadataUrl }
1323
+ };
1324
+ }
1325
+ return scheme.type === "mutualTLS" ? { type: "mutualTLS" } : void 0;
1326
+ }
1327
+ /**
1328
+ * Maps `components.securitySchemes` to `AuthScheme` entries, leaving out a scheme a client cannot place.
1329
+ */
1330
+ function toAuthSchemes(schemes, refs) {
1331
+ return Object.entries(schemes ?? {}).flatMap(([name, value]) => {
1332
+ const scheme = refs.deref(value);
1333
+ const credential = scheme && getCredential(scheme);
1334
+ if (!scheme || !credential) return [];
1335
+ return [{
1336
+ name,
1337
+ ...scheme.description && { description: scheme.description },
1338
+ ...scheme.deprecated && { deprecated: true },
1339
+ credential
1340
+ }];
1341
+ });
1342
+ }
1343
+ /**
1344
+ * Maps security requirements to `AuthRequirement` entries. A 3.2 URI key becomes the scheme name.
1345
+ */
1346
+ function toAuthRequirements(requirements, document) {
1347
+ if (!Array.isArray(requirements)) return void 0;
1348
+ const schemes = document.components?.securitySchemes ?? {};
1349
+ const toName = (key) => {
1350
+ const index = key.indexOf(SCHEME_POINTER);
1351
+ return Object.hasOwn(schemes, key) || index === -1 ? key : unescapePointerToken(key.slice(index + 29));
1352
+ };
1353
+ return requirements.filter((requirement) => !!requirement && typeof requirement === "object").map((requirement) => Object.entries(requirement).map(([key, scopes]) => ({
1354
+ scheme: toName(key),
1355
+ ...Array.isArray(scopes) && scopes.length && { scopes: scopes.map(String) }
1356
+ })));
1357
+ }
1171
1358
  // src/model/server.ts
1172
1359
  /**
1173
1360
  * Reads the server URL from the document's `servers` array at `server.index`,
@@ -1224,8 +1411,11 @@ function resolveServerUrl(server, overrides) {
1224
1411
  * Maps OpenAPI servers to `InputServer` entries: drops entries without a `url` and fills `{variable}` defaults.
1225
1412
  */
1226
1413
  function toInputServers(servers) {
1227
- return servers.filter((entry) => entry.url).map(({ url, description, variables }) => {
1228
- const declared = variables && Object.keys(variables).length > 0 ? { variables } : {};
1414
+ return servers.filter((entry) => entry.url).map(({ url, name, description, variables }) => {
1415
+ const declared = {
1416
+ ...name !== void 0 && { name },
1417
+ ...variables && Object.keys(variables).length > 0 && { variables }
1418
+ };
1229
1419
  try {
1230
1420
  return {
1231
1421
  url: resolveServerUrl({
@@ -1244,6 +1434,20 @@ function toInputServers(servers) {
1244
1434
  }
1245
1435
  });
1246
1436
  }
1437
+ // src/model/tag.ts
1438
+ function toInputTags(tags) {
1439
+ return tags.filter((tag) => typeof tag.name === "string").map(({ name, summary, description, parent, kind, externalDocs }) => {
1440
+ const docs = getExternalDocs(externalDocs);
1441
+ return {
1442
+ name,
1443
+ ...typeof summary === "string" && { summary },
1444
+ ...typeof description === "string" && { description },
1445
+ ...typeof parent === "string" && { parent },
1446
+ ...typeof kind === "string" && { kind },
1447
+ ...docs && { externalDocs: docs }
1448
+ };
1449
+ });
1450
+ }
1247
1451
  // src/model/mediaType.ts
1248
1452
  /**
1249
1453
  * The media type without its parameters, so `text/event-stream; charset=utf-8` matches the bare name.
@@ -1425,6 +1629,39 @@ function flattenSchema(schema) {
1425
1629
  function scanSchema(node, pointer = node.pointer) {
1426
1630
  if (pointer) visit(node, pointer);
1427
1631
  }
1632
+ let formatTally;
1633
+ /**
1634
+ * Runs `fn` and reports `KUBB_UNSUPPORTED_FORMAT` once per format with the number of schemas that use it,
1635
+ * instead of once per schema. `format` is an open value in OpenAPI, so a large spec would otherwise print
1636
+ * thousands of warnings that say the same thing. `fn` must be synchronous.
1637
+ */
1638
+ function groupUnsupportedFormats(fn) {
1639
+ formatTally = /* @__PURE__ */ new Map();
1640
+ try {
1641
+ return fn();
1642
+ } finally {
1643
+ const tally = formatTally;
1644
+ formatTally = void 0;
1645
+ for (const [format, pointers] of tally) reportUnsupportedFormat(format, [...pointers]);
1646
+ }
1647
+ }
1648
+ function tallyFormat(format, pointer) {
1649
+ if (!formatTally) return reportUnsupportedFormat(format, [pointer]);
1650
+ formatTally.set(format, (formatTally.get(format) ?? /* @__PURE__ */ new Set()).add(pointer));
1651
+ }
1652
+ function reportUnsupportedFormat(format, pointers) {
1653
+ const count = pointers.length;
1654
+ _kubb_kit.Diagnostics.report({
1655
+ code: _kubb_kit.Diagnostics.code.unsupportedFormat,
1656
+ severity: "warning",
1657
+ message: count === 1 ? `Kubb does not map the format "${format}" to a specific type, so it falls back to the base type.` : `Kubb does not map the format "${format}" to a specific type, so ${count} schemas fall back to the base type.`,
1658
+ help: `Use a format Kubb supports, or handle "${format}" with a custom parser or plugin.`,
1659
+ location: {
1660
+ kind: "schema",
1661
+ pointer: pointers[0]
1662
+ }
1663
+ });
1664
+ }
1428
1665
  function visit(node, pointer) {
1429
1666
  node.pointer ??= pointer;
1430
1667
  if (node.deprecated) _kubb_kit.Diagnostics.report({
@@ -1436,16 +1673,7 @@ function visit(node, pointer) {
1436
1673
  pointer
1437
1674
  }
1438
1675
  });
1439
- if (typeof node.format === "string" && !isHandledFormat(node.format)) _kubb_kit.Diagnostics.report({
1440
- code: _kubb_kit.Diagnostics.code.unsupportedFormat,
1441
- severity: "warning",
1442
- message: `Kubb does not map the format "${node.format}" to a specific type, so it falls back to the base type.`,
1443
- help: `Use a format Kubb supports, or handle "${node.format}" with a custom parser or plugin.`,
1444
- location: {
1445
- kind: "schema",
1446
- pointer
1447
- }
1448
- });
1676
+ if (typeof node.format === "string" && !isHandledFormat(node.format)) tallyFormat(node.format, pointer);
1449
1677
  if (node.type === "object") {
1450
1678
  for (const property of node.properties) visit(property.schema, `${pointer}/properties/${escapePointerToken(property.name)}`);
1451
1679
  if (node.additionalProperties && typeof node.additionalProperties === "object") visit(node.additionalProperties, `${pointer}/additionalProperties`);
@@ -1554,18 +1782,6 @@ function getResponseByStatusCode({ operation, refs, statusCode }) {
1554
1782
  function getRequestBody({ operation, refs }) {
1555
1783
  return refs.deref(operation.schema.requestBody);
1556
1784
  }
1557
- /**
1558
- * Returns the primary request content type. Prefers a JSON-like media type (the last one wins
1559
- * when several are declared), then the first declared one, defaulting to `'application/json'`.
1560
- */
1561
- function getRequestContentType({ operation, refs }) {
1562
- const content = getRequestBody({
1563
- operation,
1564
- refs
1565
- })?.content;
1566
- const mediaTypes = content ? Object.keys(content) : [];
1567
- return mediaTypes.findLast(isJsonMimeType) ?? mediaTypes[0] ?? "application/json";
1568
- }
1569
1785
  /** Merges path-level and operation-level parameters; operation-level wins per `in:name`. */
1570
1786
  function getParameters({ operation, refs }) {
1571
1787
  const resolveParams = (params, pointer) => params.flatMap((entry, index) => {
@@ -1589,7 +1805,8 @@ const PARAMETER_STYLES = /* @__PURE__ */ new Set([
1589
1805
  "simple",
1590
1806
  "spaceDelimited",
1591
1807
  "pipeDelimited",
1592
- "deepObject"
1808
+ "deepObject",
1809
+ "cookie"
1593
1810
  ]);
1594
1811
  function pickStyleFields({ style, explode, allowReserved }) {
1595
1812
  return {
@@ -1598,16 +1815,45 @@ function pickStyleFields({ style, explode, allowReserved }) {
1598
1815
  ...allowReserved !== void 0 ? { allowReserved } : {}
1599
1816
  };
1600
1817
  }
1601
- /** The `encoding` of a media type, reduced to the entries that set a field Kubb carries. A `style` outside the OpenAPI set is dropped. */
1602
- function getEncoding(encoding) {
1603
- const entries = Object.entries(encoding ?? {}).flatMap(([property, { contentType, ...rest }]) => {
1604
- const node = {
1605
- ...contentType !== void 0 ? { contentType } : {},
1606
- ...pickStyleFields(rest)
1607
- };
1818
+ function getEncodingFields({ encoding, prefixEncoding, itemEncoding }) {
1819
+ const entries = Object.entries(encoding ?? {}).flatMap(([property, entry]) => {
1820
+ const node = toEncodingNode(entry);
1608
1821
  return Object.keys(node).length ? [[property, node]] : [];
1609
1822
  });
1610
- return entries.length ? Object.fromEntries(entries) : void 0;
1823
+ const item = itemEncoding && toEncodingNode(itemEncoding);
1824
+ return {
1825
+ ...entries.length && { encoding: Object.fromEntries(entries) },
1826
+ ...prefixEncoding?.length && { prefixEncoding: prefixEncoding.map(toEncodingNode) },
1827
+ ...item && Object.keys(item).length && { itemEncoding: item }
1828
+ };
1829
+ }
1830
+ function toEncodingNode({ contentType, encoding, prefixEncoding, itemEncoding, ...rest }) {
1831
+ return {
1832
+ ...contentType !== void 0 && { contentType },
1833
+ ...pickStyleFields(rest),
1834
+ ...getEncodingFields({
1835
+ encoding,
1836
+ prefixEncoding,
1837
+ itemEncoding
1838
+ })
1839
+ };
1840
+ }
1841
+ function getExamples({ example, examples }, refs) {
1842
+ const named = Object.entries(examples ?? {}).flatMap(([name, entry]) => {
1843
+ const resolved = refs.deref(entry);
1844
+ if (!resolved) return [];
1845
+ const { summary, description, dataValue, value, serializedValue } = resolved;
1846
+ const data = dataValue !== void 0 ? dataValue : value;
1847
+ return [{
1848
+ name,
1849
+ ...typeof summary === "string" && { summary },
1850
+ ...typeof description === "string" && { description },
1851
+ ...data !== void 0 && { value: data },
1852
+ ...typeof serializedValue === "string" && { serializedValue }
1853
+ }];
1854
+ });
1855
+ if (named.length) return { examples: named };
1856
+ return example !== void 0 ? { examples: [{ value: example }] } : {};
1611
1857
  }
1612
1858
  /**
1613
1859
  * Returns the media type entry for `contentType`, resolving a `$ref` into `components.mediaTypes`. `null` when absent.
@@ -1636,6 +1882,24 @@ function getBodySchema({ content, contentType, refs, document }) {
1636
1882
  if (binary) return binary;
1637
1883
  return schema ? refs.derefKeepingRef(schema) : null;
1638
1884
  }
1885
+ function getLinks(links, refs) {
1886
+ const entries = Object.entries(links ?? {}).flatMap(([name, value]) => {
1887
+ const link = refs.deref(value);
1888
+ if (!link) return [];
1889
+ const server = link.server ? toInputServers([link.server])[0] : void 0;
1890
+ return [[name, {
1891
+ ...pickStrings(link, [
1892
+ "operationId",
1893
+ "operationRef",
1894
+ "description"
1895
+ ]),
1896
+ ...link.parameters && { parameters: link.parameters },
1897
+ ..."requestBody" in link && { requestBody: link.requestBody },
1898
+ ...server && { server }
1899
+ }]];
1900
+ });
1901
+ return entries.length ? Object.fromEntries(entries) : void 0;
1902
+ }
1639
1903
  /** The `stream` field of a content node, set when the media type is a stream. `node` is the parsed item schema. */
1640
1904
  function getStreamField({ contentType, mediaType, refs, document, node }) {
1641
1905
  if (!isStream(contentType, mediaType)) return {};
@@ -1706,11 +1970,12 @@ function collectPropertyKeysByFlag(schema, flag) {
1706
1970
  function parseParameter({ param, pointer, parentName, options, parseSchema, refs }) {
1707
1971
  const schemaName = parentName && param.name ? pascalCase(`${parentName} ${param.name}`) : void 0;
1708
1972
  const contentType = param.schema ? void 0 : Object.keys(param.content ?? {})[0];
1709
- const rawSchema = param.schema ?? getMediaType({
1973
+ const mediaType = getMediaType({
1710
1974
  content: param.content,
1711
1975
  contentType,
1712
1976
  refs
1713
- })?.schema;
1977
+ });
1978
+ const rawSchema = param.schema ?? mediaType?.schema;
1714
1979
  const schema = rawSchema ? parseSchema({
1715
1980
  schema: rawSchema,
1716
1981
  name: schemaName
@@ -1726,7 +1991,10 @@ function parseParameter({ param, pointer, parentName, options, parseSchema, refs
1726
1991
  },
1727
1992
  required: param.required ?? false,
1728
1993
  ...pickStyleFields(param),
1729
- ...contentType !== void 0 ? { contentType } : {}
1994
+ ...contentType !== void 0 ? { contentType } : {},
1995
+ ...getExamples(mediaType ?? param, refs),
1996
+ ...param.deprecated && { deprecated: true },
1997
+ ...param.allowEmptyValue && { allowEmptyValue: true }
1730
1998
  });
1731
1999
  }
1732
2000
  /**
@@ -1771,12 +2039,12 @@ function parseOperation({ operation, ...ctx }) {
1771
2039
  name: requestBodyName
1772
2040
  }), bodyRequired);
1773
2041
  scanSchema(node, `${mediaTypePointer(body?.content, ct, `${pointer}/requestBody/content/${escapePointerToken(ct)}`)}/${schemaKeyword(mediaType)}`);
1774
- const encoding = getEncoding(mediaType?.encoding);
1775
2042
  return [_kubb_kit.ast.factory.createContent({
1776
2043
  contentType: ct,
1777
2044
  schema: node,
1778
2045
  keysToOmit: collectPropertyKeysByFlag(schema, "readOnly"),
1779
- ...encoding && { encoding },
2046
+ ...mediaType && getEncodingFields(mediaType),
2047
+ ...mediaType && getExamples(mediaType, refs),
1780
2048
  ...getStreamField({
1781
2049
  contentType: ct,
1782
2050
  mediaType,
@@ -1819,6 +2087,8 @@ function parseOperation({ operation, ...ctx }) {
1819
2087
  return {
1820
2088
  schema: node,
1821
2089
  keysToOmit: collectPropertyKeysByFlag(raw, "writeOnly"),
2090
+ ...mediaType && getEncodingFields(mediaType),
2091
+ ...mediaType && getExamples(mediaType, refs),
1822
2092
  ...ct ? getStreamField({
1823
2093
  contentType: ct,
1824
2094
  mediaType,
@@ -1828,22 +2098,41 @@ function parseOperation({ operation, ...ctx }) {
1828
2098
  }) : {}
1829
2099
  };
1830
2100
  };
1831
- const responseContent = (contentType ? [contentType] : Object.keys(response?.content ?? {})).map((ct) => _kubb_kit.ast.factory.createContent({
2101
+ const declaredContentTypes = Object.keys(response?.content ?? {});
2102
+ const responseContent = (contentType && declaredContentTypes.length ? [contentType] : declaredContentTypes).map((ct) => _kubb_kit.ast.factory.createContent({
1832
2103
  contentType: ct,
1833
2104
  ...parseEntrySchema(ct)
1834
2105
  }));
1835
2106
  if (responseContent.length === 0) responseContent.push(_kubb_kit.ast.factory.createContent({
1836
- contentType: getRequestContentType({
1837
- operation,
1838
- refs
1839
- }),
2107
+ contentType: "",
1840
2108
  ...parseEntrySchema(contentType)
1841
2109
  }));
2110
+ const responsePointer = `${pointer}/responses/${statusCode}`;
2111
+ const headers = Object.entries(response?.headers ?? {}).flatMap(([name, value]) => {
2112
+ const header = name.toLowerCase() === "content-type" ? null : refs.deref(value);
2113
+ if (!header) return [];
2114
+ return [parseParameter({
2115
+ param: {
2116
+ ...header,
2117
+ name,
2118
+ in: "header"
2119
+ },
2120
+ pointer: `${responsePointer}/headers/${escapePointerToken(name)}`,
2121
+ parentName: responseName,
2122
+ options,
2123
+ parseSchema,
2124
+ refs
2125
+ })];
2126
+ });
2127
+ const links = getLinks(response?.links, refs);
1842
2128
  return _kubb_kit.ast.factory.createResponse({
1843
- pointer: `${pointer}/responses/${statusCode}`,
2129
+ pointer: responsePointer,
1844
2130
  statusCode,
2131
+ summary: response?.summary,
1845
2132
  description: response?.description,
1846
- content: responseContent
2133
+ content: responseContent,
2134
+ ...headers.length && { headers },
2135
+ ...links && { links }
1847
2136
  });
1848
2137
  });
1849
2138
  const pickDoc = (key) => {
@@ -1853,6 +2142,7 @@ function parseOperation({ operation, ...ctx }) {
1853
2142
  return typeof fallback === "string" ? fallback : void 0;
1854
2143
  };
1855
2144
  const servers = operation.schema.servers ?? operation.pathItem.servers;
2145
+ const auth = toAuthRequirements(operation.schema.security ?? document.security, document);
1856
2146
  return _kubb_kit.ast.factory.createOperation({
1857
2147
  pointer,
1858
2148
  operationId,
@@ -1863,11 +2153,13 @@ function parseOperation({ operation, ...ctx }) {
1863
2153
  summary: pickDoc("summary") || void 0,
1864
2154
  description: pickDoc("description") || void 0,
1865
2155
  deprecated: operation.schema.deprecated || void 0,
2156
+ externalDocs: getExternalDocs(operation.schema.externalDocs),
1866
2157
  parameters,
1867
2158
  requestBody,
1868
2159
  responses,
1869
2160
  extensions: pickExtensions(operation.schema),
1870
- ...servers && { servers: toInputServers(servers) }
2161
+ ...servers && { servers: toInputServers(servers) },
2162
+ ...auth && { auth }
1871
2163
  });
1872
2164
  }
1873
2165
  // src/emit/createNode.ts
@@ -1888,6 +2180,7 @@ function createNode({ schema, name, nullable, defaultValue }, extras) {
1888
2180
  default: defaultValue,
1889
2181
  examples: extractExamples(schema),
1890
2182
  format: schema.format,
2183
+ externalDocs: getExternalDocs(schema.externalDocs),
1891
2184
  ...extras
1892
2185
  });
1893
2186
  }
@@ -2016,6 +2309,15 @@ function removeInheritedDiscriminator({ members, refs }) {
2016
2309
  });
2017
2310
  }
2018
2311
  /**
2312
+ * Whether a member can carry the discriminator property. A discriminator is only a hint, so an array
2313
+ * or primitive member keeps its own type instead of an intersection no value can satisfy.
2314
+ */
2315
+ function isObjectLike(member, refs) {
2316
+ const type = (isReference(member) ? refs.resolve(member.$ref, { report: false }) : member)?.type;
2317
+ if (type === void 0) return true;
2318
+ return Array.isArray(type) ? type.includes("object") : type === "object";
2319
+ }
2320
+ /**
2019
2321
  * Narrows each `oneOf`/`anyOf` member with its discriminant value, intersecting the member's own
2020
2322
  * node with either the shared-properties slice carrying that value, or a synthetic discriminant
2021
2323
  * literal. The referenced child schema's own definition is left untouched — narrowing happens only
@@ -2078,7 +2380,7 @@ function narrowUnionMembers({ unionMembers, discriminator, sharedPropertiesNode,
2078
2380
  schema: s,
2079
2381
  name
2080
2382
  });
2081
- if (!discriminatorValues.length || !discriminator) return memberNode;
2383
+ if (!discriminatorValues.length || !discriminator || !isObjectLike(s, refs)) return memberNode;
2082
2384
  const narrowedDiscriminatorNode = sharedPropertiesNode ? pickDiscriminatorPropertyNode(_kubb_kit.ast.applyMacros(sharedPropertiesNode, [(0, _kubb_kit.macroDiscriminatorEnum)({
2083
2385
  propertyName: discriminator.propertyName,
2084
2386
  values: discriminatorValues
@@ -2343,13 +2645,15 @@ const annotationKeys = /* @__PURE__ */ new Set([
2343
2645
  ]);
2344
2646
  /**
2345
2647
  * Moves `allOf` members that hold only annotations or `if`/`then`/`else` onto the parent, so they do
2346
- * not become `unknown`. The parent's own values win, and the conditional keywords are not enforced.
2648
+ * not become `unknown`. The parent's own values win. The parser reads their `if`/`then`/`else` into `conditionals`.
2347
2649
  */
2650
+ function isAnnotationMember(member) {
2651
+ return !!member && typeof member === "object" && !isReference(member) && Object.keys(member).every((key) => annotationKeys.has(key));
2652
+ }
2348
2653
  function mergeAnnotations(schema) {
2349
2654
  const members = schema.allOf;
2350
- const isAnnotation = (member) => !isReference(member) && Object.keys(member).every((key) => annotationKeys.has(key));
2351
- const annotations = members.filter(isAnnotation);
2352
- const rest = members.filter((member) => !isAnnotation(member));
2655
+ const annotations = members.filter(isAnnotationMember);
2656
+ const rest = members.filter((member) => !isAnnotationMember(member));
2353
2657
  return annotations.length && rest.length ? {
2354
2658
  ...Object.assign({}, ...annotations),
2355
2659
  ...schema,
@@ -2382,7 +2686,8 @@ function convertAllOf({ schema: original, name, nullable, defaultValue, parse, r
2382
2686
  default: mergedDefault,
2383
2687
  examples: extractExamples(schema) ?? memberNode.examples,
2384
2688
  pattern: schema.pattern ?? ("pattern" in memberNode ? memberNode.pattern : void 0),
2385
- format: schema.format ?? memberNode.format
2689
+ format: schema.format ?? memberNode.format,
2690
+ externalDocs: getExternalDocs(schema.externalDocs) ?? memberNode.externalDocs
2386
2691
  });
2387
2692
  }
2388
2693
  const { members: discriminatedAllOf, discriminantValues } = extractDiscriminatedAllOfMembers({
@@ -2457,7 +2762,7 @@ function convertUnion(context) {
2457
2762
  };
2458
2763
  const discriminator = isDiscriminator(schema) ? schema.discriminator : void 0;
2459
2764
  const declaredMembers = [...schema.oneOf ?? [], ...schema.anyOf ?? []];
2460
- const defaultRef = getDefaultMappingRef(discriminator);
2765
+ const defaultRef = getDefaultMappingRef(typeof schema.discriminator === "object" ? schema.discriminator : void 0);
2461
2766
  const unionMembers = resolveUnionMembers(defaultRef && !declaredMembers.some((member) => isReference(member) && member.$ref === defaultRef) ? [...declaredMembers, { $ref: defaultRef }] : declaredMembers, schema.properties ?? {});
2462
2767
  const strategy = schema.oneOf ? "one" : "any";
2463
2768
  const explicitDiscriminatorPropertyName = discriminator?.propertyName;
@@ -2569,11 +2874,18 @@ function getPrimitiveType(type) {
2569
2874
  }
2570
2875
  /** Shared by number, integer and bigint nodes; the exclusive bounds keep only the OAS 3.1 numeric form. */
2571
2876
  function getNumericConstraints(schema) {
2877
+ const exclusiveMinimum = typeof schema.exclusiveMinimum === "number" ? schema.exclusiveMinimum : void 0;
2878
+ const exclusiveMaximum = typeof schema.exclusiveMaximum === "number" ? schema.exclusiveMaximum : void 0;
2879
+ const hasExclusive = exclusiveMinimum !== void 0 || exclusiveMaximum !== void 0;
2572
2880
  return {
2573
2881
  min: schema.minimum,
2574
2882
  max: schema.maximum,
2575
- exclusiveMinimum: typeof schema.exclusiveMinimum === "number" ? schema.exclusiveMinimum : void 0,
2576
- exclusiveMaximum: typeof schema.exclusiveMaximum === "number" ? schema.exclusiveMaximum : void 0,
2883
+ ...hasExclusive && { exclusive: {
2884
+ ...exclusiveMinimum !== void 0 && { min: exclusiveMinimum },
2885
+ ...exclusiveMaximum !== void 0 && { max: exclusiveMaximum }
2886
+ } },
2887
+ exclusiveMinimum,
2888
+ exclusiveMaximum,
2577
2889
  multipleOf: schema.multipleOf
2578
2890
  };
2579
2891
  }
@@ -2582,11 +2894,11 @@ function getNumericConstraints(schema) {
2582
2894
  */
2583
2895
  function isWithinBounds({ value, schema }) {
2584
2896
  if (typeof value !== "number") return true;
2585
- const { min, max, exclusiveMinimum, exclusiveMaximum, multipleOf } = getNumericConstraints(schema);
2897
+ const { min, max, exclusive, multipleOf } = getNumericConstraints(schema);
2586
2898
  if (min !== void 0 && value < min) return false;
2587
2899
  if (max !== void 0 && value > max) return false;
2588
- if (exclusiveMinimum !== void 0 && value <= exclusiveMinimum) return false;
2589
- if (exclusiveMaximum !== void 0 && value >= exclusiveMaximum) return false;
2900
+ if (exclusive?.min !== void 0 && value <= exclusive.min) return false;
2901
+ if (exclusive?.max !== void 0 && value >= exclusive.max) return false;
2590
2902
  if (multipleOf !== void 0 && Math.abs(value / multipleOf - Math.round(value / multipleOf)) > 1e-9) return false;
2591
2903
  return true;
2592
2904
  }
@@ -2744,6 +3056,15 @@ function convertFormattedEnum(context) {
2744
3056
  }))
2745
3057
  });
2746
3058
  }
3059
+ function getStringContent({ schema, parse }) {
3060
+ const { contentMediaType: mediaType, contentEncoding: encoding, contentSchema } = schema;
3061
+ if (mediaType === void 0 && encoding === void 0 && !contentSchema) return {};
3062
+ return { content: {
3063
+ ...mediaType !== void 0 && { mediaType },
3064
+ ...encoding !== void 0 && { encoding },
3065
+ ...contentSchema && { schema: parse({ schema: contentSchema }) }
3066
+ } };
3067
+ }
2747
3068
  /**
2748
3069
  * Converts a `type: 'string'` schema into a `StringSchemaNode`.
2749
3070
  */
@@ -2754,7 +3075,8 @@ function convertString(context) {
2754
3075
  primitive: "string",
2755
3076
  min: schema.minLength,
2756
3077
  max: schema.maxLength,
2757
- pattern: schema.pattern
3078
+ pattern: schema.pattern,
3079
+ ...getStringContent(context)
2758
3080
  });
2759
3081
  }
2760
3082
  /**
@@ -2768,6 +3090,15 @@ function convertNumeric(context, type) {
2768
3090
  });
2769
3091
  }
2770
3092
  // src/emit/converters/structural.ts
3093
+ function getContains(schema, parse) {
3094
+ const { contains, minContains, maxContains } = schema;
3095
+ if (!contains || typeof contains !== "object") return {};
3096
+ return { contains: {
3097
+ schema: parse({ schema: contains }),
3098
+ ...typeof minContains === "number" && { min: minContains },
3099
+ ...typeof maxContains === "number" && { max: maxContains }
3100
+ } };
3101
+ }
2771
3102
  /**
2772
3103
  * Resolves a `true` or empty-object map schema (`additionalProperties`/`patternProperties`) to
2773
3104
  * `options.unknownType`, otherwise parses it as a regular schema.
@@ -2820,7 +3151,7 @@ function convertObject({ schema, name, nullable, defaultValue, options, parse, r
2820
3151
  required
2821
3152
  });
2822
3153
  }) : [];
2823
- const additionalProperties = schema.additionalProperties;
3154
+ const additionalProperties = schema.additionalProperties ?? schema.unevaluatedProperties;
2824
3155
  const additionalPropertiesNode = (() => {
2825
3156
  if (additionalProperties === true) return true;
2826
3157
  if (additionalProperties) return resolveMapSchema(additionalProperties, {
@@ -2850,6 +3181,8 @@ function convertObject({ schema, name, nullable, defaultValue, options, parse, r
2850
3181
  additionalProperties: additionalPropertiesNode,
2851
3182
  patternProperties,
2852
3183
  propertyNames,
3184
+ min: schema.minProperties,
3185
+ max: schema.maxProperties,
2853
3186
  minProperties: schema.minProperties,
2854
3187
  maxProperties: schema.maxProperties
2855
3188
  });
@@ -2880,7 +3213,8 @@ function convertObject({ schema, name, nullable, defaultValue, options, parse, r
2880
3213
  */
2881
3214
  function convertTuple({ schema, name, nullable, defaultValue, options, parse }) {
2882
3215
  const tupleItems = (schema.prefixItems ?? []).map((item) => parse({ schema: item }));
2883
- const rest = schema.items === false ? void 0 : !schema.items || schema.items === true ? _kubb_kit.ast.factory.createSchema({ type: options.unknownType }) : parse({ schema: schema.items });
3216
+ const tail = schema.items ?? schema.unevaluatedItems;
3217
+ const rest = tail === false ? void 0 : !tail || tail === true ? _kubb_kit.ast.factory.createSchema({ type: options.unknownType }) : parse({ schema: tail });
2884
3218
  return createNode({
2885
3219
  schema,
2886
3220
  name,
@@ -2892,7 +3226,8 @@ function convertTuple({ schema, name, nullable, defaultValue, options, parse })
2892
3226
  items: tupleItems,
2893
3227
  rest,
2894
3228
  min: schema.minItems,
2895
- max: schema.maxItems
3229
+ max: schema.maxItems,
3230
+ ...getContains(schema, parse)
2896
3231
  });
2897
3232
  }
2898
3233
  /**
@@ -2916,7 +3251,8 @@ function convertArray({ schema, name, nullable, defaultValue, options, parse })
2916
3251
  items,
2917
3252
  min: schema.minItems,
2918
3253
  max: schema.maxItems,
2919
- unique: schema.uniqueItems ?? void 0
3254
+ unique: schema.uniqueItems ?? void 0,
3255
+ ...getContains(schema, parse)
2920
3256
  });
2921
3257
  }
2922
3258
  // src/emit/parseSchema.ts
@@ -3044,6 +3380,20 @@ const schemaRules = [
3044
3380
  ];
3045
3381
  // src/parser.ts
3046
3382
  /**
3383
+ * `unevaluated*` also sees what composition siblings evaluate, so with such a sibling it is dropped to keep the schema open.
3384
+ */
3385
+ function hasUnevaluatedSiblings(schema) {
3386
+ if (schema.unevaluatedProperties === void 0 && schema.unevaluatedItems === void 0) return false;
3387
+ return [
3388
+ schema.allOf,
3389
+ schema.anyOf,
3390
+ schema.oneOf,
3391
+ schema.if,
3392
+ schema.dependentSchemas,
3393
+ schema.$ref
3394
+ ].some((value) => value !== void 0);
3395
+ }
3396
+ /**
3047
3397
  * Creates the schema converter bound to one OpenAPI document: `parseSchema` dispatches each
3048
3398
  * schema through the ordered `schemaRules` table, with the parser options merged once.
3049
3399
  *
@@ -3061,6 +3411,13 @@ function createSchemaParser(ctx) {
3061
3411
  schema: flattenedSchema,
3062
3412
  name
3063
3413
  });
3414
+ if (hasUnevaluatedSiblings(schema)) {
3415
+ const { unevaluatedProperties: _properties, unevaluatedItems: _items, ...open } = schema;
3416
+ return parseSchema({
3417
+ schema: open,
3418
+ name
3419
+ });
3420
+ }
3064
3421
  const nullable = isNullable(schema) || void 0;
3065
3422
  const context = {
3066
3423
  schema,
@@ -3074,8 +3431,62 @@ function createSchemaParser(ctx) {
3074
3431
  refs,
3075
3432
  renames
3076
3433
  };
3077
- for (const rule of schemaRules) if (rule.match(context)) return rule.convert(context);
3078
- return createNode(context, { type: options.emptySchemaType });
3434
+ const rule = schemaRules.find((entry) => entry.match(context));
3435
+ return withConditionals(rule ? rule.convert(context) : createNode(context, { type: options.emptySchemaType }), schema);
3436
+ }
3437
+ function requireKeys(keys) {
3438
+ const unknown = _kubb_kit.ast.factory.createSchema({ type: _kubb_kit.ast.schemaTypes.unknown });
3439
+ return _kubb_kit.ast.factory.createSchema({
3440
+ type: _kubb_kit.ast.schemaTypes.object,
3441
+ primitive: "object",
3442
+ properties: keys.map((name) => _kubb_kit.ast.factory.createProperty({
3443
+ name,
3444
+ required: true,
3445
+ schema: unknown
3446
+ }))
3447
+ });
3448
+ }
3449
+ /**
3450
+ * Adds `if`/`then`/`else`, `dependentRequired` and `dependentSchemas` to the node as `conditionals`.
3451
+ */
3452
+ function withConditionals(node, schema) {
3453
+ const conditionals = [schema, ...Array.isArray(schema.allOf) ? schema.allOf.filter(isAnnotationMember) : []].flatMap(toConditionals);
3454
+ return conditionals.length ? {
3455
+ ...node,
3456
+ conditionals
3457
+ } : node;
3458
+ }
3459
+ function toConditionals(schema) {
3460
+ const branch = (value) => {
3461
+ if (!value || typeof value !== "object") return void 0;
3462
+ const { required, type, ...rest } = value;
3463
+ if (Array.isArray(required) && required.length && (type === void 0 || type === "object") && !Object.keys(rest).length) return requireKeys(required);
3464
+ return parseSchema({ schema: value });
3465
+ };
3466
+ const entries = (value) => value && typeof value === "object" ? Object.entries(value) : [];
3467
+ const conditionals = [];
3468
+ const condition = branch(schema.if);
3469
+ if (condition) {
3470
+ const thenNode = branch(schema.then);
3471
+ const elseNode = branch(schema.else);
3472
+ conditionals.push({
3473
+ if: condition,
3474
+ ...thenNode && { then: thenNode },
3475
+ ...elseNode && { else: elseNode }
3476
+ });
3477
+ }
3478
+ for (const [key, required] of entries(schema.dependentRequired)) if (Array.isArray(required) && required.length && required.every((name) => typeof name === "string")) conditionals.push({
3479
+ if: requireKeys([key]),
3480
+ then: requireKeys(required)
3481
+ });
3482
+ for (const [key, dependent] of entries(schema.dependentSchemas)) {
3483
+ const thenNode = branch(dependent);
3484
+ if (thenNode) conditionals.push({
3485
+ if: requireKeys([key]),
3486
+ then: thenNode
3487
+ });
3488
+ }
3489
+ return conditionals;
3079
3490
  }
3080
3491
  return parseSchema;
3081
3492
  }
@@ -3414,6 +3825,7 @@ const adapterOas = (0, _kubb_core.defineExtension)({
3414
3825
  schemaNodes.push(promotedEnums ? refPromotedEnums(node, promotedEnums) : node);
3415
3826
  }
3416
3827
  const operations = promotedEnums ? operationNodes.map((node) => refPromotedEnums(node, promotedEnums)) : operationNodes;
3828
+ const authSchemes = toAuthSchemes(document.components?.securitySchemes, refs);
3417
3829
  return _kubb_kit.ast.factory.createInput({
3418
3830
  schemas: schemaNodes,
3419
3831
  operations,
@@ -3421,23 +3833,25 @@ const adapterOas = (0, _kubb_core.defineExtension)({
3421
3833
  title: document.info?.title,
3422
3834
  description: document.info?.description,
3423
3835
  version: document.info?.version,
3836
+ summary: document.info?.summary,
3837
+ termsOfService: document.info?.termsOfService,
3838
+ contact: pickStrings(document.info?.contact, [
3839
+ "name",
3840
+ "url",
3841
+ "email"
3842
+ ]),
3843
+ license: typeof document.info?.license?.name === "string" ? {
3844
+ ...pickStrings(document.info.license, ["identifier", "url"]),
3845
+ name: document.info.license.name
3846
+ } : void 0,
3847
+ externalDocs: getExternalDocs(document.externalDocs),
3424
3848
  baseURL: resolveBaseUrl({
3425
3849
  document,
3426
3850
  server
3427
3851
  }),
3428
3852
  servers: toInputServers(document.servers ?? []),
3429
- securitySchemes: Object.entries(document.components?.securitySchemes ?? {}).flatMap(([name, value]) => {
3430
- const scheme = refs.deref(value);
3431
- return scheme?.type ? [{
3432
- name,
3433
- type: scheme.type,
3434
- description: scheme.description,
3435
- scheme: scheme.scheme,
3436
- bearerFormat: scheme.bearerFormat,
3437
- in: scheme.in,
3438
- parameterName: scheme.name
3439
- }] : [];
3440
- }),
3853
+ ...document.tags?.length && { tags: toInputTags(document.tags) },
3854
+ ...authSchemes.length && { auth: authSchemes },
3441
3855
  extensions: pickExtensions(document)
3442
3856
  }
3443
3857
  });
@@ -3478,18 +3892,19 @@ const adapterOas = (0, _kubb_core.defineExtension)({
3478
3892
  parsedDocument = document;
3479
3893
  const refs = createRefs(document);
3480
3894
  const { schemas, renames, pointers } = getSchemas(document, { contentType }, refs);
3481
- return parseInput({
3895
+ const parseSchema = createSchemaParser({
3896
+ document,
3897
+ refs,
3898
+ renames,
3899
+ options: parserOptions
3900
+ });
3901
+ return groupUnsupportedFormats(() => parseInput({
3482
3902
  document,
3483
3903
  refs,
3484
3904
  schemas,
3485
3905
  pointers,
3486
- parseSchema: createSchemaParser({
3487
- document,
3488
- refs,
3489
- renames,
3490
- options: parserOptions
3491
- })
3492
- });
3906
+ parseSchema
3907
+ }));
3493
3908
  })();
3494
3909
  inputCache.set(source, {
3495
3910
  promise,