@kubb/adapter-oas 5.15.4 → 5.16.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.d.cts CHANGED
@@ -1104,6 +1104,10 @@ type SchemaObject$1 = {
1104
1104
  * OAS 3.1: encoding applied to string content, such as `base64`.
1105
1105
  */
1106
1106
  contentEncoding?: string;
1107
+ /**
1108
+ * OAS 3.1: schema of the decoded value a string with `contentMediaType` holds.
1109
+ */
1110
+ contentSchema?: SchemaObject$1 | ReferenceObject$1;
1107
1111
  $ref?: string;
1108
1112
  /**
1109
1113
  * OAS 3.1: positional tuple items, replacing the multi-item `items` array from OAS 3.0.
@@ -1134,13 +1138,18 @@ type Document = OpenAPIV3_1.Document & Record<string, unknown>;
1134
1138
  */
1135
1139
  type OperationObject$1 = OpenAPIV3_1.OperationObject & Record<string, unknown>;
1136
1140
  /**
1137
- * Path item object holding the operations and shared parameters for a single URL path.
1141
+ * Path item object holding the operations and shared parameters for a single URL path, plus the
1142
+ * OpenAPI 3.2 `additionalOperations` map for HTTP methods outside the fixed fields.
1138
1143
  */
1139
- type PathItemObject$1 = OpenAPIV3_1.PathItemObject;
1144
+ type PathItemObject$1 = OpenAPIV3_1.PathItemObject & {
1145
+ additionalOperations?: Record<string, OperationObject$1>;
1146
+ };
1140
1147
  /**
1141
- * Discriminator object for `oneOf`/`anyOf` schemas in OpenAPI.
1148
+ * Discriminator object for `oneOf`/`anyOf` schemas, with the OpenAPI 3.2 `defaultMapping` fallback schema.
1142
1149
  */
1143
- type DiscriminatorObject$1 = OpenAPIV3_1.DiscriminatorObject;
1150
+ type DiscriminatorObject$1 = OpenAPIV3_1.DiscriminatorObject & {
1151
+ defaultMapping?: string;
1152
+ };
1144
1153
  /**
1145
1154
  * OpenAPI reference object pointing to a schema definition via `$ref`.
1146
1155
  */
@@ -1150,9 +1159,11 @@ type ReferenceObject$1 = OpenAPIV3_1.ReferenceObject;
1150
1159
  */
1151
1160
  type ResponseObject$1 = OpenAPIV3_1.ResponseObject;
1152
1161
  /**
1153
- * OpenAPI media type object that maps a content-type string to its schema.
1162
+ * OpenAPI media type object, with the OpenAPI 3.2 `itemSchema` of one item of a stream.
1154
1163
  */
1155
- type MediaTypeObject$1 = OpenAPIV3_1.MediaTypeObject;
1164
+ type MediaTypeObject$1 = OpenAPIV3_1.MediaTypeObject & {
1165
+ itemSchema?: SchemaObject$1 | ReferenceObject$1;
1166
+ };
1156
1167
  /**
1157
1168
  * Selects which entry in the spec's `servers` array becomes the base URL and
1158
1169
  * supplies values for its `{variable}` placeholders.
@@ -1186,7 +1197,8 @@ type AdapterOasOptions = {
1186
1197
  /**
1187
1198
  * Validate the OpenAPI spec with `@readme/openapi-parser` before parsing. Each problem is
1188
1199
  * reported as a `KUBB_INVALID_SPEC` warning and generation continues. Set to `false` to skip the
1189
- * check, which also makes generation faster on a large spec.
1200
+ * check, which also makes generation faster on a large spec. An OpenAPI 3.2 document is not
1201
+ * validated yet and gets one warning that says so.
1190
1202
  *
1191
1203
  * @default true
1192
1204
  */
@@ -1254,7 +1266,7 @@ type AdapterOas = AdapterFactoryOptions<'oas', AdapterOasOptions, AdapterOasReso
1254
1266
  */
1255
1267
  export declare const adapterOasName = "oas";
1256
1268
  /**
1257
- * Default Kubb adapter for OpenAPI 2.0, 3.0, and 3.1 specifications. Reads the
1269
+ * Default Kubb adapter for OpenAPI 2.0, 3.0, 3.1, and 3.2 specifications. Reads the
1258
1270
  * spec from `input` (a file path, URL, inline content, or parsed object), validates
1259
1271
  * it, resolves the base URL, and converts every schema and operation into the
1260
1272
  * universal AST that every downstream plugin consumes.
package/dist/index.d.ts CHANGED
@@ -1104,6 +1104,10 @@ type SchemaObject$1 = {
1104
1104
  * OAS 3.1: encoding applied to string content, such as `base64`.
1105
1105
  */
1106
1106
  contentEncoding?: string;
1107
+ /**
1108
+ * OAS 3.1: schema of the decoded value a string with `contentMediaType` holds.
1109
+ */
1110
+ contentSchema?: SchemaObject$1 | ReferenceObject$1;
1107
1111
  $ref?: string;
1108
1112
  /**
1109
1113
  * OAS 3.1: positional tuple items, replacing the multi-item `items` array from OAS 3.0.
@@ -1134,13 +1138,18 @@ type Document = OpenAPIV3_1.Document & Record<string, unknown>;
1134
1138
  */
1135
1139
  type OperationObject$1 = OpenAPIV3_1.OperationObject & Record<string, unknown>;
1136
1140
  /**
1137
- * Path item object holding the operations and shared parameters for a single URL path.
1141
+ * Path item object holding the operations and shared parameters for a single URL path, plus the
1142
+ * OpenAPI 3.2 `additionalOperations` map for HTTP methods outside the fixed fields.
1138
1143
  */
1139
- type PathItemObject$1 = OpenAPIV3_1.PathItemObject;
1144
+ type PathItemObject$1 = OpenAPIV3_1.PathItemObject & {
1145
+ additionalOperations?: Record<string, OperationObject$1>;
1146
+ };
1140
1147
  /**
1141
- * Discriminator object for `oneOf`/`anyOf` schemas in OpenAPI.
1148
+ * Discriminator object for `oneOf`/`anyOf` schemas, with the OpenAPI 3.2 `defaultMapping` fallback schema.
1142
1149
  */
1143
- type DiscriminatorObject$1 = OpenAPIV3_1.DiscriminatorObject;
1150
+ type DiscriminatorObject$1 = OpenAPIV3_1.DiscriminatorObject & {
1151
+ defaultMapping?: string;
1152
+ };
1144
1153
  /**
1145
1154
  * OpenAPI reference object pointing to a schema definition via `$ref`.
1146
1155
  */
@@ -1150,9 +1159,11 @@ type ReferenceObject$1 = OpenAPIV3_1.ReferenceObject;
1150
1159
  */
1151
1160
  type ResponseObject$1 = OpenAPIV3_1.ResponseObject;
1152
1161
  /**
1153
- * OpenAPI media type object that maps a content-type string to its schema.
1162
+ * OpenAPI media type object, with the OpenAPI 3.2 `itemSchema` of one item of a stream.
1154
1163
  */
1155
- type MediaTypeObject$1 = OpenAPIV3_1.MediaTypeObject;
1164
+ type MediaTypeObject$1 = OpenAPIV3_1.MediaTypeObject & {
1165
+ itemSchema?: SchemaObject$1 | ReferenceObject$1;
1166
+ };
1156
1167
  /**
1157
1168
  * Selects which entry in the spec's `servers` array becomes the base URL and
1158
1169
  * supplies values for its `{variable}` placeholders.
@@ -1186,7 +1197,8 @@ type AdapterOasOptions = {
1186
1197
  /**
1187
1198
  * Validate the OpenAPI spec with `@readme/openapi-parser` before parsing. Each problem is
1188
1199
  * reported as a `KUBB_INVALID_SPEC` warning and generation continues. Set to `false` to skip the
1189
- * check, which also makes generation faster on a large spec.
1200
+ * check, which also makes generation faster on a large spec. An OpenAPI 3.2 document is not
1201
+ * validated yet and gets one warning that says so.
1190
1202
  *
1191
1203
  * @default true
1192
1204
  */
@@ -1254,7 +1266,7 @@ type AdapterOas = AdapterFactoryOptions<'oas', AdapterOasOptions, AdapterOasReso
1254
1266
  */
1255
1267
  export declare const adapterOasName = "oas";
1256
1268
  /**
1257
- * Default Kubb adapter for OpenAPI 2.0, 3.0, and 3.1 specifications. Reads the
1269
+ * Default Kubb adapter for OpenAPI 2.0, 3.0, 3.1, and 3.2 specifications. Reads the
1258
1270
  * spec from `input` (a file path, URL, inline content, or parsed object), validates
1259
1271
  * it, resolves the base URL, and converts every schema and operation into the
1260
1272
  * universal AST that every downstream plugin consumes.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { defineExtension } from "@kubb/core";
2
- import { Diagnostics, ast, childName, enumPrimitive, enumPropName, extractRefName, macroDiscriminatorEnum, macroEnumName, macroSimplifyUnion, mergeAdjacentObjectsLazy } from "@kubb/kit";
2
+ import { Diagnostics, ast, childName, enumPrimitive, enumPropName, extractRefName, macroDedupeUnion, macroDiscriminatorEnum, macroEnumName, mergeAdjacentObjectsLazy } from "@kubb/kit";
3
3
  import { join } from "node:path";
4
4
  import { access, readFile } from "node:fs/promises";
5
5
  import { upgrade } from "@scalar/openapi-upgrader";
@@ -19,7 +19,7 @@ var compatibility = {
19
19
  "node": ">=22.22"
20
20
  };
21
21
  // package.json
22
- var version = "5.15.4";
22
+ var version = "5.16.0";
23
23
  // src/constants.ts
24
24
  /**
25
25
  * Default parser options applied when no explicit options are provided.
@@ -59,6 +59,17 @@ const SUPPORTED_METHODS = /* @__PURE__ */ new Set([
59
59
  "query"
60
60
  ]);
61
61
  /**
62
+ * Media types OpenAPI 3.2 reads as a stream of items (its "sequential media types"), each described by `itemSchema`.
63
+ */
64
+ const STREAM_MEDIA_TYPES = /* @__PURE__ */ new Set([
65
+ "application/jsonl",
66
+ "application/x-ndjson",
67
+ "application/json-seq",
68
+ "application/geo+json-seq",
69
+ "text/event-stream",
70
+ "multipart/mixed"
71
+ ]);
72
+ /**
62
73
  * Set of JSON Schema keywords that prevent a schema fragment from being inlined during `allOf` flattening.
63
74
  *
64
75
  * A fragment that contains any of these keys carries structural meaning of its own and must stay as a separate
@@ -383,6 +394,14 @@ function isNullable(schema) {
383
394
  return false;
384
395
  }
385
396
  /**
397
+ * Returns `true` for an OpenAPI 3.2 or later document. Swagger 2.0 and OpenAPI 3.0 documents are
398
+ * upgraded to 3.1 before parsing, so `openapi` is always set here.
399
+ */
400
+ function isOpenApi32(document) {
401
+ const [major = 0, minor = 0] = String(document.openapi).split(".").map(Number);
402
+ return major > 3 || major === 3 && minor >= 2;
403
+ }
404
+ /**
386
405
  * Returns the `x-*` keys of `source` as-is, or `undefined` when there are none.
387
406
  */
388
407
  function pickExtensions(source) {
@@ -449,7 +468,8 @@ const jsonMimeFragments = [
449
468
  * ```
450
469
  */
451
470
  function isJsonMimeType(mimeType) {
452
- return jsonMimeFragments.some((fragment) => mimeType.includes(fragment));
471
+ const lower = mimeType.toLowerCase();
472
+ return jsonMimeFragments.some((fragment) => lower.includes(fragment));
453
473
  }
454
474
  // src/refs.ts
455
475
  /**
@@ -873,6 +893,17 @@ function reportInvalidSpec(message) {
873
893
  * ```
874
894
  */
875
895
  async function validateDocument(document, { throwOnError = false } = {}) {
896
+ if (isOpenApi32(document)) {
897
+ const diagnostic = {
898
+ code: Diagnostics.code.invalidSpec,
899
+ severity: "warning",
900
+ message: "The document was not validated: `@readme/openapi-parser` does not support OpenAPI 3.2 yet.",
901
+ help: "Set `validate: false` on the adapter to skip this check until the validator supports OpenAPI 3.2."
902
+ };
903
+ if (throwOnError) throw new Diagnostics.Error(diagnostic);
904
+ Diagnostics.report(diagnostic);
905
+ return;
906
+ }
876
907
  const { compileErrors, validate } = await import("@readme/openapi-parser");
877
908
  let result;
878
909
  try {
@@ -902,6 +933,7 @@ function reportValidationErrors({ errors, additionalErrors }) {
902
933
  * validating in place where worker threads are missing, as in edge runtimes.
903
934
  */
904
935
  async function validateDocumentInWorker(document) {
936
+ if (isOpenApi32(document)) return validateDocument(document);
905
937
  let message;
906
938
  try {
907
939
  const { Worker } = await import("node:worker_threads");
@@ -1172,6 +1204,123 @@ function resolveServerUrl(server, overrides) {
1172
1204
  }
1173
1205
  return url;
1174
1206
  }
1207
+ // src/model/mediaType.ts
1208
+ /**
1209
+ * The media type without its parameters, so `text/event-stream; charset=utf-8` matches the bare name.
1210
+ */
1211
+ function baseMediaType(contentType) {
1212
+ return contentType.split(";")[0].trim().toLowerCase();
1213
+ }
1214
+ /**
1215
+ * Returns `true` for a media type read as a stream of items: one that OpenAPI 3.2 lists, or any that declares `itemSchema`.
1216
+ */
1217
+ function isStream(contentType, mediaType) {
1218
+ return STREAM_MEDIA_TYPES.has(baseMediaType(contentType)) || mediaType?.itemSchema !== void 0;
1219
+ }
1220
+ /**
1221
+ * Whether the media type is `text/event-stream`, with or without parameters.
1222
+ */
1223
+ function isEventStream(contentType) {
1224
+ return baseMediaType(contentType) === "text/event-stream";
1225
+ }
1226
+ /**
1227
+ * Replaces a `data` string that holds JSON with its `contentSchema`, so the event reads as parsed.
1228
+ */
1229
+ function withParsedData(schema, refs) {
1230
+ const data = schema.properties?.data;
1231
+ const resolved = data && isReference(data) ? refs.resolve(data.$ref, { report: false }) : data;
1232
+ if (!resolved?.contentSchema || !resolved.contentMediaType || !isJsonMimeType(resolved.contentMediaType)) return schema;
1233
+ return {
1234
+ ...schema,
1235
+ properties: {
1236
+ ...schema.properties,
1237
+ data: resolved.contentSchema
1238
+ }
1239
+ };
1240
+ }
1241
+ /**
1242
+ * Keywords next to `$ref` that only annotate it, so a reference that carries nothing else stays a reference.
1243
+ */
1244
+ const REF_ANNOTATIONS = /* @__PURE__ */ new Set([
1245
+ "$ref",
1246
+ "summary",
1247
+ "description",
1248
+ "$comment"
1249
+ ]);
1250
+ /**
1251
+ * Applies `extra` on top of `base` the way JSON Schema does: `properties` and `required` add up, other keywords of `extra` win.
1252
+ */
1253
+ function mergeSchemas(base, extra) {
1254
+ const required = [.../* @__PURE__ */ new Set([...Array.isArray(base.required) ? base.required : [], ...Array.isArray(extra.required) ? extra.required : []])];
1255
+ return {
1256
+ type: "object",
1257
+ ...base,
1258
+ ...extra,
1259
+ properties: {
1260
+ ...base.properties,
1261
+ ...extra.properties
1262
+ },
1263
+ ...required.length ? { required } : {}
1264
+ };
1265
+ }
1266
+ /**
1267
+ * Normalizes the OpenAPI 3.2 `text/event-stream` item schema into one schema per event.
1268
+ * - Keywords next to a `$ref` apply to the referenced schema.
1269
+ * - Shared `properties` merge into each inline `oneOf`/`anyOf` member.
1270
+ * - A JSON `data` string becomes its `contentSchema`.
1271
+ */
1272
+ function toEventSchema(schema, refs) {
1273
+ if (isReference(schema)) {
1274
+ const siblings = Object.fromEntries(Object.entries(schema).filter(([key]) => !REF_ANNOTATIONS.has(key)));
1275
+ const resolved = Object.keys(siblings).length ? refs.resolve(schema.$ref, { report: false }) : null;
1276
+ return resolved ? toEventSchema(mergeSchemas(resolved, siblings), refs) : schema;
1277
+ }
1278
+ const key = schema.oneOf?.length ? "oneOf" : schema.anyOf?.length ? "anyOf" : void 0;
1279
+ if (!key) return withParsedData(schema, refs);
1280
+ const members = schema[key];
1281
+ const { properties, required, ...rest } = schema;
1282
+ const merge = !!properties && !members.some(isReference);
1283
+ const shared = {
1284
+ properties,
1285
+ required
1286
+ };
1287
+ return {
1288
+ ...merge ? rest : schema,
1289
+ [key]: members.map((member) => isReference(member) ? member : withParsedData(merge ? mergeSchemas(shared, member) : member, refs))
1290
+ };
1291
+ }
1292
+ /**
1293
+ * Whether the schema, following `$ref`s, or a composition member of it declares an `event` or `data` property.
1294
+ */
1295
+ function declaresEventFields(schema, refs, seen) {
1296
+ if (isReference(schema)) {
1297
+ if (seen.has(schema.$ref)) return false;
1298
+ seen.add(schema.$ref);
1299
+ const resolved = refs.resolve(schema.$ref, { report: false });
1300
+ return !!resolved && declaresEventFields(resolved, refs, seen);
1301
+ }
1302
+ if (schema.properties && (Object.hasOwn(schema.properties, "event") || Object.hasOwn(schema.properties, "data"))) return true;
1303
+ return [
1304
+ ...schema.oneOf ?? [],
1305
+ ...schema.anyOf ?? [],
1306
+ ...schema.allOf ?? []
1307
+ ].some((member) => declaresEventFields(member, refs, seen));
1308
+ }
1309
+ /**
1310
+ * Returns `'event'` when the item declares `event` or `data`, directly or in a composition member, else `'data'`.
1311
+ */
1312
+ function getItemShape(schema, refs) {
1313
+ return declaresEventFields(schema, refs, /* @__PURE__ */ new Set()) ? "event" : "data";
1314
+ }
1315
+ /**
1316
+ * Returns the raw item schema: `itemSchema`, or `schema` on `text/event-stream` as 3.0 and 3.1 documents write one event.
1317
+ */
1318
+ function getItemSchema({ contentType, mediaType, refs, document }) {
1319
+ if (!mediaType || !isStream(contentType, mediaType)) return null;
1320
+ const raw = mediaType.itemSchema ?? (isEventStream(contentType) && !isOpenApi32(document) ? mediaType.schema : void 0);
1321
+ if (!raw) return null;
1322
+ return isEventStream(contentType) ? toEventSchema(raw, refs) : raw;
1323
+ }
1175
1324
  // src/emit/schemaShape.ts
1176
1325
  /**
1177
1326
  * Whether `format` maps to a dedicated type; `false` is what `KUBB_UNSUPPORTED_FORMAT` flags.
@@ -1284,6 +1433,13 @@ function slugify(value) {
1284
1433
  return value.replace(/[^a-zA-Z0-9]/g, "-").replace(/-{2,}/g, "-").replace(/^-|-$/g, "");
1285
1434
  }
1286
1435
  /**
1436
+ * Returns the operation's JSON pointer, under `additionalOperations` for an OpenAPI 3.2 method outside the fixed fields.
1437
+ */
1438
+ function getOperationPointer({ path, method }) {
1439
+ const pathPointer = `#/paths/${escapePointerToken(path)}`;
1440
+ return SUPPORTED_METHODS.has(method.toLowerCase()) ? `${pathPointer}/${method.toLowerCase()}` : `${pathPointer}/additionalOperations/${escapePointerToken(method)}`;
1441
+ }
1442
+ /**
1287
1443
  * Returns the operation's `operationId`, falling back to `<method>_<slugified-path>` when absent.
1288
1444
  */
1289
1445
  function getOperationId({ path, method, schema }) {
@@ -1336,7 +1492,7 @@ function getParameters({ operation, refs }) {
1336
1492
  }] : [];
1337
1493
  });
1338
1494
  const pathPointer = `#/paths/${escapePointerToken(operation.path)}`;
1339
- const operationParams = resolveParams(operation.schema?.parameters || [], `${pathPointer}/${operation.method.toLowerCase()}`);
1495
+ const operationParams = resolveParams(operation.schema?.parameters || [], getOperationPointer(operation));
1340
1496
  const pathLevelParams = resolveParams(operation.pathItem.parameters ?? [], pathPointer);
1341
1497
  const paramMap = /* @__PURE__ */ new Map();
1342
1498
  for (const entry of [...pathLevelParams, ...operationParams]) if (entry.param.name && entry.param.in) paramMap.set(`${entry.param.in}:${entry.param.name}`, entry);
@@ -1369,17 +1525,59 @@ function getEncoding(encoding) {
1369
1525
  });
1370
1526
  return entries.length ? Object.fromEntries(entries) : void 0;
1371
1527
  }
1372
- /** Schema for one media type of a `content` map, with the binary fallback for an emptied non-JSON entry. */
1373
- function getBodySchema({ content, contentType, refs }) {
1374
- const entry = contentType ? content?.[contentType] : void 0;
1375
- if (!entry) return null;
1376
- const binary = getBinaryFallbackSchema(contentType, entry.schema);
1528
+ /**
1529
+ * Returns the media type entry for `contentType`, resolving a `$ref` into `components.mediaTypes`. `null` when absent.
1530
+ */
1531
+ function getMediaType({ content, contentType, refs }) {
1532
+ return contentType ? refs.deref(content?.[contentType]) : null;
1533
+ }
1534
+ /**
1535
+ * Returns the schema for one media type of a `content` map, with the binary fallback for an emptied non-JSON
1536
+ * entry. For a stream this is the item schema, so `schema: string` next to `itemSchema` types one item.
1537
+ */
1538
+ function getBodySchema({ content, contentType, refs, document }) {
1539
+ const entry = getMediaType({
1540
+ content,
1541
+ contentType,
1542
+ refs
1543
+ });
1544
+ if (!contentType || !entry) return null;
1545
+ const schema = getItemSchema({
1546
+ contentType,
1547
+ mediaType: entry,
1548
+ refs,
1549
+ document
1550
+ }) ?? entry.schema;
1551
+ const binary = entry.itemSchema ? void 0 : getBinaryFallbackSchema(contentType, schema);
1377
1552
  if (binary) return binary;
1378
- return entry.schema ? refs.derefKeepingRef(entry.schema) : null;
1553
+ return schema ? refs.derefKeepingRef(schema) : null;
1554
+ }
1555
+ /** The `stream` field of a content node, set when the media type is a stream. `node` is the parsed item schema. */
1556
+ function getStreamField({ contentType, mediaType, refs, document, node }) {
1557
+ if (!isStream(contentType, mediaType)) return {};
1558
+ const raw = getItemSchema({
1559
+ contentType,
1560
+ mediaType,
1561
+ refs,
1562
+ document
1563
+ });
1564
+ return { stream: {
1565
+ ...raw ? { schema: node } : {},
1566
+ ...raw && isEventStream(contentType) ? { shape: getItemShape(raw, refs) } : {}
1567
+ } };
1568
+ }
1569
+ /** The media type keyword the body schema was read from, for the diagnostic pointer. */
1570
+ function schemaKeyword(mediaType) {
1571
+ return mediaType?.itemSchema ? "itemSchema" : "schema";
1572
+ }
1573
+ /** Pointer of a media type entry, following a `$ref` into `components.mediaTypes` so a diagnostic lands on the source. */
1574
+ function mediaTypePointer(content, contentType, fallback) {
1575
+ const entry = content?.[contentType];
1576
+ return isReference(entry) ? entry.$ref : fallback;
1379
1577
  }
1380
1578
  /**
1381
- * Builds an `Operation` for every supported HTTP method on every path, in document order.
1382
- * `x-` path keys and unresolvable path-item `$ref`s are skipped.
1579
+ * Builds an `Operation` for every supported HTTP method and every OpenAPI 3.2 `additionalOperations` entry on
1580
+ * every path, in document order. `x-` path keys and unresolvable path-item `$ref`s are skipped.
1383
1581
  */
1384
1582
  function getOperations(document, refs) {
1385
1583
  const operations = [];
@@ -1401,6 +1599,12 @@ function getOperations(document, refs) {
1401
1599
  pathItem
1402
1600
  });
1403
1601
  }
1602
+ for (const [method, schema] of Object.entries(pathItem.additionalOperations ?? {})) if (schema && typeof schema === "object" && !SUPPORTED_METHODS.has(method.toLowerCase())) operations.push({
1603
+ path,
1604
+ method,
1605
+ schema,
1606
+ pathItem
1607
+ });
1404
1608
  }
1405
1609
  return operations;
1406
1610
  }
@@ -1414,10 +1618,15 @@ function collectPropertyKeysByFlag(schema, flag) {
1414
1618
  }
1415
1619
  return keys.length ? keys : null;
1416
1620
  }
1417
- function parseParameter({ param, pointer, parentName, options, parseSchema }) {
1621
+ /** Converts one parameter into a `ParameterNode`, naming an inline schema after the operation and the parameter. */
1622
+ function parseParameter({ param, pointer, parentName, options, parseSchema, refs }) {
1418
1623
  const schemaName = parentName && param.name ? pascalCase(`${parentName} ${param.name}`) : void 0;
1419
1624
  const contentType = param.schema ? void 0 : Object.keys(param.content ?? {})[0];
1420
- const rawSchema = param.schema ?? (contentType ? param.content?.[contentType]?.schema : void 0);
1625
+ const rawSchema = param.schema ?? getMediaType({
1626
+ content: param.content,
1627
+ contentType,
1628
+ refs
1629
+ })?.schema;
1421
1630
  const schema = rawSchema ? parseSchema({
1422
1631
  schema: rawSchema,
1423
1632
  name: schemaName
@@ -1440,16 +1649,17 @@ function parseParameter({ param, pointer, parentName, options, parseSchema }) {
1440
1649
  * Converts an OAS `Operation` into an `OperationNode`.
1441
1650
  */
1442
1651
  function parseOperation({ operation, ...ctx }) {
1443
- const { refs, contentType, options, parseSchema } = ctx;
1652
+ const { document, refs, contentType, options, parseSchema } = ctx;
1444
1653
  const operationId = getOperationId(operation);
1445
1654
  const operationName = operationId ? pascalCase(operationId) : void 0;
1446
- const pointer = `#/paths/${escapePointerToken(operation.path)}/${operation.method.toLowerCase()}`;
1655
+ const pointer = getOperationPointer(operation);
1447
1656
  const parameters = getParameters({
1448
1657
  operation,
1449
1658
  refs
1450
1659
  }).map((entry) => parseParameter({
1451
1660
  options,
1452
1661
  parseSchema,
1662
+ refs,
1453
1663
  ...entry,
1454
1664
  parentName: operationName
1455
1665
  }));
@@ -1463,20 +1673,33 @@ function parseOperation({ operation, ...ctx }) {
1463
1673
  const schema = getBodySchema({
1464
1674
  content: body?.content,
1465
1675
  contentType: ct,
1466
- refs
1676
+ refs,
1677
+ document
1467
1678
  });
1468
1679
  if (!schema) return [];
1469
- const node = parseSchema({
1680
+ const mediaType = getMediaType({
1681
+ content: body?.content,
1682
+ contentType: ct,
1683
+ refs
1684
+ });
1685
+ const node = ast.optionality(parseSchema({
1470
1686
  schema,
1471
1687
  name: requestBodyName
1472
- });
1473
- scanSchema(node, `${pointer}/requestBody/content/${escapePointerToken(ct)}/schema`);
1474
- const encoding = getEncoding(body?.content?.[ct]?.encoding);
1688
+ }), bodyRequired);
1689
+ scanSchema(node, `${mediaTypePointer(body?.content, ct, `${pointer}/requestBody/content/${escapePointerToken(ct)}`)}/${schemaKeyword(mediaType)}`);
1690
+ const encoding = getEncoding(mediaType?.encoding);
1475
1691
  return [ast.factory.createContent({
1476
1692
  contentType: ct,
1477
- schema: ast.optionality(node, bodyRequired),
1693
+ schema: node,
1478
1694
  keysToOmit: collectPropertyKeysByFlag(schema, "readOnly"),
1479
- ...encoding && { encoding }
1695
+ ...encoding && { encoding },
1696
+ ...getStreamField({
1697
+ contentType: ct,
1698
+ mediaType,
1699
+ refs,
1700
+ document,
1701
+ node
1702
+ })
1480
1703
  })];
1481
1704
  });
1482
1705
  const requestBody = content.length > 0 || body?.description ? {
@@ -1494,6 +1717,12 @@ function parseOperation({ operation, ...ctx }) {
1494
1717
  const responseName = operationName ? `${operationName}Status${statusCode}` : void 0;
1495
1718
  const parseEntrySchema = (ct) => {
1496
1719
  const raw = getBodySchema({
1720
+ content: response?.content,
1721
+ contentType: ct,
1722
+ refs,
1723
+ document
1724
+ });
1725
+ const mediaType = getMediaType({
1497
1726
  content: response?.content,
1498
1727
  contentType: ct,
1499
1728
  refs
@@ -1502,10 +1731,17 @@ function parseOperation({ operation, ...ctx }) {
1502
1731
  schema: raw,
1503
1732
  name: responseName
1504
1733
  }) : ast.factory.createSchema({ type: options.emptySchemaType });
1505
- if (raw && ct) scanSchema(node, `${pointer}/responses/${statusCode}/content/${escapePointerToken(ct)}/schema`);
1734
+ if (raw && ct) scanSchema(node, `${mediaTypePointer(response?.content, ct, `${pointer}/responses/${statusCode}/content/${escapePointerToken(ct)}`)}/${schemaKeyword(mediaType)}`);
1506
1735
  return {
1507
1736
  schema: node,
1508
- keysToOmit: collectPropertyKeysByFlag(raw, "writeOnly")
1737
+ keysToOmit: collectPropertyKeysByFlag(raw, "writeOnly"),
1738
+ ...ct ? getStreamField({
1739
+ contentType: ct,
1740
+ mediaType,
1741
+ refs,
1742
+ document,
1743
+ node
1744
+ }) : {}
1509
1745
  };
1510
1746
  };
1511
1747
  const responseContent = (contentType ? [contentType] : Object.keys(response?.content ?? {})).map((ct) => ast.factory.createContent({
@@ -1536,7 +1772,7 @@ function parseOperation({ operation, ...ctx }) {
1536
1772
  pointer,
1537
1773
  operationId,
1538
1774
  protocol: "http",
1539
- method: operation.method.toUpperCase(),
1775
+ method: SUPPORTED_METHODS.has(operation.method) ? operation.method.toUpperCase() : operation.method,
1540
1776
  path: operation.path,
1541
1777
  tags: Array.isArray(operation.schema.tags) ? operation.schema.tags.map(String) : [],
1542
1778
  summary: pickDoc("summary") || void 0,
@@ -1631,6 +1867,14 @@ function createDiscriminantNode({ propertyName, values }) {
1631
1867
  });
1632
1868
  }
1633
1869
  /**
1870
+ * Returns the `$ref` of an OpenAPI 3.2 `defaultMapping`, written as a schema name or a `$ref`; `undefined` when none.
1871
+ */
1872
+ function getDefaultMappingRef(discriminator) {
1873
+ const value = discriminator?.defaultMapping;
1874
+ if (!value) return void 0;
1875
+ return value.includes("/") ? value : `${SCHEMA_REF_PREFIX}${value}`;
1876
+ }
1877
+ /**
1634
1878
  * Returns every discriminator key whose mapping value matches `ref`, in mapping order.
1635
1879
  *
1636
1880
  * A mapping may point several keys at the same schema, in which case the member has to be
@@ -1726,13 +1970,15 @@ function narrowUnionMembers({ unionMembers, discriminator, sharedPropertiesNode,
1726
1970
  }
1727
1971
  return constrains(variant) ? null : value;
1728
1972
  }
1973
+ const defaultRef = getDefaultMappingRef(discriminator);
1729
1974
  return unionMembers.map((s) => {
1730
1975
  const ref = isReference(s) ? s.$ref : void 0;
1731
- const mappedValues = findDiscriminators({
1976
+ const isDefault = ref !== void 0 && ref === defaultRef;
1977
+ const mappedValues = isDefault ? [] : findDiscriminators({
1732
1978
  mapping: discriminator?.mapping,
1733
1979
  ref
1734
1980
  });
1735
- const implicitValue = mappedValues.length ? null : implicitDiscriminantValue(s);
1981
+ const implicitValue = mappedValues.length || isDefault ? null : implicitDiscriminantValue(s);
1736
1982
  const propertyType = propertyTypeOf({
1737
1983
  schema: s,
1738
1984
  propertyName: discriminator?.propertyName ?? "",
@@ -1777,7 +2023,8 @@ function extractDiscriminatedAllOfMembers({ allOfMembers, name, refs }) {
1777
2023
  const parentUnion = deref?.oneOf ?? deref?.anyOf;
1778
2024
  if (!deref || !discriminator || isDiscriminator(deref) && !parentUnion) return true;
1779
2025
  const childRef = `${SCHEMA_REF_PREFIX}${name}`;
1780
- const values = findDiscriminators({
2026
+ const isDefault = childRef === getDefaultMappingRef(discriminator);
2027
+ const values = isDefault ? [] : findDiscriminators({
1781
2028
  mapping: discriminator.mapping,
1782
2029
  ref: childRef
1783
2030
  });
@@ -1800,7 +2047,7 @@ function extractDiscriminatedAllOfMembers({ allOfMembers, name, refs }) {
1800
2047
  })
1801
2048
  });
1802
2049
  }
1803
- return !(parentUnion && (values.length > 0 || parentUnion.some((member) => isReference(member) && member.$ref === childRef)));
2050
+ return !(parentUnion && (isDefault || values.length > 0 || parentUnion.some((member) => isReference(member) && member.$ref === childRef)));
1804
2051
  }),
1805
2052
  discriminantValues
1806
2053
  };
@@ -2122,10 +2369,12 @@ function convertUnion(context) {
2122
2369
  nullable,
2123
2370
  defaultValue
2124
2371
  };
2125
- const unionMembers = resolveUnionMembers([...schema.oneOf ?? [], ...schema.anyOf ?? []], schema.properties ?? {});
2126
- const strategy = schema.oneOf ? "one" : "any";
2127
- const explicitDiscriminatorPropertyName = isDiscriminator(schema) ? schema.discriminator.propertyName : void 0;
2128
2372
  const discriminator = isDiscriminator(schema) ? schema.discriminator : void 0;
2373
+ const declaredMembers = [...schema.oneOf ?? [], ...schema.anyOf ?? []];
2374
+ const defaultRef = getDefaultMappingRef(discriminator);
2375
+ const unionMembers = resolveUnionMembers(defaultRef && !declaredMembers.some((member) => isReference(member) && member.$ref === defaultRef) ? [...declaredMembers, { $ref: defaultRef }] : declaredMembers, schema.properties ?? {});
2376
+ const strategy = schema.oneOf ? "one" : "any";
2377
+ const explicitDiscriminatorPropertyName = discriminator?.propertyName;
2129
2378
  const { oneOf: _o, anyOf: _a, discriminator: _d, ...memberBaseSchema } = schema;
2130
2379
  const sharedPropertiesNode = schema.properties ? parse({
2131
2380
  schema: memberBaseSchema,
@@ -2178,7 +2427,7 @@ function convertUnion(context) {
2178
2427
  members,
2179
2428
  discriminatorPropertyName: explicitDiscriminatorPropertyName ?? ast.inferDiscriminatorPropertyName(members)
2180
2429
  });
2181
- return ast.applyMacros(unionNode, [macroSimplifyUnion], { depth: "shallow" });
2430
+ return ast.applyMacros(unionNode, [macroDedupeUnion], { depth: "shallow" });
2182
2431
  }
2183
2432
  /**
2184
2433
  * Converts an OAS 3.1 multi-type array (e.g. `type: ['string', 'number']`) into a `UnionSchemaNode`.
@@ -2655,6 +2904,10 @@ const schemaRules = [
2655
2904
  primitive: "string"
2656
2905
  })
2657
2906
  },
2907
+ {
2908
+ match: ({ schema, type }) => !type && !schema.enum?.length && (schema.contentMediaType !== void 0 || schema.contentSchema !== void 0),
2909
+ convert: convertString
2910
+ },
2658
2911
  {
2659
2912
  match: ({ schema, type }) => !type && (schema.minLength !== void 0 || schema.maxLength !== void 0 || schema.pattern !== void 0),
2660
2913
  convert: convertString
@@ -2949,7 +3202,7 @@ const locate = (source, location) => {
2949
3202
  */
2950
3203
  const adapterOasName = "oas";
2951
3204
  /**
2952
- * Default Kubb adapter for OpenAPI 2.0, 3.0, and 3.1 specifications. Reads the
3205
+ * Default Kubb adapter for OpenAPI 2.0, 3.0, 3.1, and 3.2 specifications. Reads the
2953
3206
  * spec from `input` (a file path, URL, inline content, or parsed object), validates
2954
3207
  * it, resolves the base URL, and converts every schema and operation into the
2955
3208
  * universal AST that every downstream plugin consumes.
@@ -3023,6 +3276,7 @@ const adapterOas = defineExtension({
3023
3276
  const discriminatorChildMap = discriminatorParentNodes.length > 0 ? buildDiscriminatorChildMap(discriminatorParentNodes) : null;
3024
3277
  const operationNodes = getOperations(document, refs).map((operation) => parseOperation({
3025
3278
  operation,
3279
+ document,
3026
3280
  refs,
3027
3281
  contentType,
3028
3282
  options: parserOptions,