@kubb/adapter-oas 5.0.0-beta.64 → 5.0.0-beta.66

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.ts CHANGED
@@ -1133,7 +1133,7 @@ type SchemaObject$1 = {
1133
1133
  * Allowed values for this schema.
1134
1134
  */
1135
1135
  enum?: Array<string | number | boolean | null>;
1136
- } & (OpenAPIV3.SchemaObject | OpenAPIV3_1.SchemaObject | JSONSchema4 | JSONSchema6 | JSONSchema7);
1136
+ } & (OpenAPIV3_1.SchemaObject | JSONSchema4 | JSONSchema6 | JSONSchema7);
1137
1137
  /**
1138
1138
  * HTTP method in the lowercase form an OpenAPI path item uses for its keys.
1139
1139
  */
@@ -1141,27 +1141,27 @@ type HttpMethod = Lowercase<ast.HttpMethod>;
1141
1141
  /**
1142
1142
  * Normalized OpenAPI document after parsing.
1143
1143
  */
1144
- type Document = (OpenAPIV3.Document | OpenAPIV3_1.Document) & Record<string, unknown>;
1144
+ type Document = OpenAPIV3_1.Document & Record<string, unknown>;
1145
1145
  /**
1146
1146
  * Single operation object (the `get`/`post`/… entry on a path item) plus any vendor extensions.
1147
1147
  */
1148
- type OperationObject$1 = (OpenAPIV3.OperationObject | OpenAPIV3_1.OperationObject) & Record<string, unknown>;
1148
+ type OperationObject$1 = OpenAPIV3_1.OperationObject & Record<string, unknown>;
1149
1149
  /**
1150
1150
  * Discriminator object for `oneOf`/`anyOf` schemas in OpenAPI.
1151
1151
  */
1152
- type DiscriminatorObject$1 = OpenAPIV3.DiscriminatorObject | OpenAPIV3_1.DiscriminatorObject;
1152
+ type DiscriminatorObject$1 = OpenAPIV3_1.DiscriminatorObject;
1153
1153
  /**
1154
1154
  * OpenAPI reference object pointing to a schema definition via `$ref`.
1155
1155
  */
1156
- type ReferenceObject$1 = OpenAPIV3.ReferenceObject;
1156
+ type ReferenceObject$1 = OpenAPIV3_1.ReferenceObject;
1157
1157
  /**
1158
1158
  * OpenAPI response object holding the content and headers for one status code.
1159
1159
  */
1160
- type ResponseObject$1 = OpenAPIV3.ResponseObject | OpenAPIV3_1.ResponseObject;
1160
+ type ResponseObject$1 = OpenAPIV3_1.ResponseObject;
1161
1161
  /**
1162
1162
  * OpenAPI media type object that maps a content-type string to its schema.
1163
1163
  */
1164
- type MediaTypeObject$1 = OpenAPIV3.MediaTypeObject | OpenAPIV3_1.MediaTypeObject;
1164
+ type MediaTypeObject$1 = OpenAPIV3_1.MediaTypeObject;
1165
1165
  /**
1166
1166
  * Configuration for the OpenAPI adapter: spec validation, content-type selection,
1167
1167
  * server URL resolution, and how schema types are derived.
package/dist/index.js CHANGED
@@ -53,18 +53,6 @@ const SUPPORTED_METHODS = new Set([
53
53
  "trace"
54
54
  ]);
55
55
  /**
56
- * OpenAPI version string written into the stub document created during multi-spec merges.
57
- */
58
- const MERGE_OPENAPI_VERSION = "3.0.0";
59
- /**
60
- * Fallback `info.title` placed in the stub document when merging multiple API files.
61
- */
62
- const MERGE_DEFAULT_TITLE = "Merged API";
63
- /**
64
- * Fallback `info.version` placed in the stub document when merging multiple API files.
65
- */
66
- const MERGE_DEFAULT_VERSION = "1.0.0";
67
- /**
68
56
  * Set of JSON Schema keywords that prevent a schema fragment from being inlined during `allOf` flattening.
69
57
  *
70
58
  * A fragment that contains any of these keys carries structural meaning of its own and must stay as a separate
@@ -144,15 +132,6 @@ const formatMap = {
144
132
  * ```
145
133
  */
146
134
  const enumExtensionKeys = ["x-enumNames", "x-enum-varnames"];
147
- /**
148
- * Maps the `unknownType`/`emptySchemaType` option string to its `ScalarSchemaType` constant.
149
- * A `Map` (over a plain object) lets callers test key membership with `.has()`.
150
- */
151
- const typeOptionMap = new Map([
152
- ["any", ast.schemaTypes.any],
153
- ["unknown", ast.schemaTypes.unknown],
154
- ["void", ast.schemaTypes.void]
155
- ]);
156
135
  //#endregion
157
136
  //#region ../../internals/utils/src/casing.ts
158
137
  /**
@@ -293,27 +272,6 @@ async function read(path) {
293
272
  return readFile(path, { encoding: "utf8" });
294
273
  }
295
274
  //#endregion
296
- //#region ../../internals/utils/src/object.ts
297
- /**
298
- * Recursively merges `source` into `target`, combining nested plain objects.
299
- * Arrays and non-object values from `source` override the corresponding values in `target`.
300
- *
301
- * @example
302
- * ```ts
303
- * mergeDeep({ a: { x: 1 } }, { a: { y: 2 } })
304
- * // { a: { x: 1, y: 2 } }
305
- * ```
306
- */
307
- function mergeDeep(target, source) {
308
- const result = { ...target };
309
- for (const key of Object.keys(source)) {
310
- const sv = source[key];
311
- const tv = result[key];
312
- result[key] = sv !== null && typeof sv === "object" && !Array.isArray(sv) && tv !== null && typeof tv === "object" && !Array.isArray(tv) ? mergeDeep(tv, sv) : sv;
313
- }
314
- return result;
315
- }
316
- //#endregion
317
275
  //#region ../../internals/utils/src/reserved.ts
318
276
  /**
319
277
  * JavaScript and Java reserved words.
@@ -565,58 +523,25 @@ async function bundleDocument(pathOrUrl) {
565
523
  /**
566
524
  * Loads and bundles an OpenAPI document, returning the raw `Document`.
567
525
  *
568
- * Accepts a file path string or an already-parsed document object. File paths and URLs are
569
- * bundled via `api-ref-bundler`, hoisting external file schemas into named `components.schemas`
570
- * entries so generators can emit named types and imports. Swagger 2.0 documents are
571
- * automatically up-converted to OpenAPI 3.0 via `@scalar/openapi-upgrader`.
526
+ * A string is a file path or URL: it is bundled via `api-ref-bundler`, hoisting external file
527
+ * schemas into named `components.schemas` entries so generators can emit named types and imports.
528
+ * An object is treated as an already-parsed document. Swagger 2.0 and OpenAPI 3.0 documents are
529
+ * up-converted to OpenAPI 3.1 via `@scalar/openapi-upgrader`.
572
530
  *
573
531
  * @example
574
532
  * ```ts
575
533
  * const document = await parseDocument('./openapi.yaml')
576
- * const document = await parse(rawDocumentObject, { canBundle: false })
534
+ * const document = await parseDocument(rawDocumentObject)
577
535
  * ```
578
536
  */
579
- async function parseDocument(pathOrApi, { canBundle = true } = {}) {
580
- if (typeof pathOrApi === "string" && canBundle) return parseDocument(await bundleDocument(pathOrApi), { canBundle: false });
581
- return upgrade(typeof pathOrApi === "string" ? parse(pathOrApi) : pathOrApi, "3.0");
582
- }
583
- /**
584
- * Deep-merges multiple OpenAPI documents into a single `Document`.
585
- *
586
- * Each document is parsed independently, then deep-merged into one in array order.
587
- * Throws when the input array is empty.
588
- *
589
- * @example
590
- * ```ts
591
- * const document = await mergeDocuments(['./pets.yaml', './orders.yaml'])
592
- * ```
593
- */
594
- async function mergeDocuments(pathOrApi) {
595
- const documents = await Promise.all(pathOrApi.map((p) => parseDocument(p, { canBundle: false })));
596
- if (documents.length === 0) throw new Diagnostics.Error({
597
- code: Diagnostics.code.inputRequired,
598
- severity: "error",
599
- message: "No OAS documents were provided for merging.",
600
- help: "Pass at least one path or document to `input.path`.",
601
- location: { kind: "config" }
602
- });
603
- const seed = {
604
- openapi: MERGE_OPENAPI_VERSION,
605
- info: {
606
- title: MERGE_DEFAULT_TITLE,
607
- version: MERGE_DEFAULT_VERSION
608
- },
609
- paths: {},
610
- components: { schemas: {} }
611
- };
612
- return parseDocument(documents.reduce((acc, current) => mergeDeep(acc, current), seed));
537
+ async function parseDocument(pathOrApi) {
538
+ if (typeof pathOrApi === "string") return parseDocument(await bundleDocument(pathOrApi));
539
+ return upgrade(pathOrApi, "3.1");
613
540
  }
614
541
  /**
615
542
  * Creates a `Document` from an `AdapterSource`.
616
543
  *
617
- * Handles all three source types:
618
544
  * - `{ type: 'path' }` resolves and bundles a local file path or remote URL.
619
- * - `{ type: 'paths' }` merges multiple file paths into a single document.
620
545
  * - `{ type: 'data' }` parses an inline string (YAML/JSON) or raw object.
621
546
  *
622
547
  * @example
@@ -626,11 +551,7 @@ async function mergeDocuments(pathOrApi) {
626
551
  * ```
627
552
  */
628
553
  async function parseFromConfig(source) {
629
- if (source.type === "data") {
630
- if (typeof source.data === "object") return parseDocument(structuredClone(source.data));
631
- return parseDocument(source.data, { canBundle: false });
632
- }
633
- if (source.type === "paths") return mergeDocuments(source.paths);
554
+ if (source.type === "data") return parseDocument(typeof source.data === "string" ? parse(source.data) : structuredClone(source.data));
634
555
  if (Url.canParse(source.path)) return parseDocument(source.path);
635
556
  const resolved = path.resolve(path.dirname(source.path), source.path);
636
557
  await assertInputExists(resolved);
@@ -689,7 +610,7 @@ function createRefNode(node, target) {
689
610
  deprecated: node.deprecated,
690
611
  description: node.description,
691
612
  default: node.default,
692
- example: node.example
613
+ examples: node.examples
693
614
  });
694
615
  }
695
616
  /**
@@ -1358,14 +1279,16 @@ function getResponseBody(responseBody, contentType) {
1358
1279
  * getResponseSchema(document, operation, '4XX') // {}
1359
1280
  * ```
1360
1281
  */
1361
- function getResponseSchema(document, operation, statusCode, options = {}) {
1362
- if (operation.schema.responses) {
1363
- const responses = operation.schema.responses;
1364
- for (const key in responses) {
1365
- const schema = responses[key];
1366
- if (schema && isReference(schema)) responses[key] = resolveRef(document, schema.$ref);
1367
- }
1282
+ function resolveResponseRefs(document, operation) {
1283
+ const responses = operation.schema.responses;
1284
+ if (!responses) return;
1285
+ for (const key in responses) {
1286
+ const schema = responses[key];
1287
+ if (schema && isReference(schema)) responses[key] = resolveRef(document, schema.$ref);
1368
1288
  }
1289
+ }
1290
+ function getResponseSchema(document, operation, statusCode, options = {}) {
1291
+ resolveResponseRefs(document, operation);
1369
1292
  const responseBody = getResponseBody(getResponseByStatusCode({
1370
1293
  document,
1371
1294
  operation,
@@ -1392,7 +1315,12 @@ function getRequestSchema(document, operation, options = {}) {
1392
1315
  mediaType: options.contentType
1393
1316
  });
1394
1317
  if (requestBody === false) return null;
1318
+ const mediaType = Array.isArray(requestBody) ? requestBody[0] : options.contentType;
1395
1319
  const schema = Array.isArray(requestBody) ? requestBody[1].schema : requestBody.schema;
1320
+ if (mediaType === "application/octet-stream" && (!schema || Object.keys(schema).length === 0)) return {
1321
+ type: "string",
1322
+ contentMediaType: "application/octet-stream"
1323
+ };
1396
1324
  if (!schema) return null;
1397
1325
  return dereferenceWithRef(document, schema);
1398
1326
  }
@@ -1509,9 +1437,6 @@ const semanticSuffixes = {
1509
1437
  responses: "Response",
1510
1438
  requestBodies: "Request"
1511
1439
  };
1512
- function getSemanticSuffix(source) {
1513
- return semanticSuffixes[source];
1514
- }
1515
1440
  function resolveSchemaRef(document, schema) {
1516
1441
  if (!isReference(schema)) return schema;
1517
1442
  const resolved = resolveRef(document, schema.$ref);
@@ -1566,7 +1491,7 @@ function getSchemas(document, { contentType }) {
1566
1491
  }
1567
1492
  }
1568
1493
  items.forEach((item, index) => {
1569
- const suffix = isSingle ? "" : hasMultipleSources ? getSemanticSuffix(item.source) : index === 0 ? "" : String(index + 1);
1494
+ const suffix = isSingle ? "" : hasMultipleSources ? semanticSuffixes[item.source] : index === 0 ? "" : String(index + 1);
1570
1495
  const uniqueName = item.originalName + suffix;
1571
1496
  schemas[uniqueName] = item.schema;
1572
1497
  nameMapping.set(`#/components/${item.source}/${item.originalName}`, uniqueName);
@@ -1613,6 +1538,15 @@ function getDateType(options, format) {
1613
1538
  /**
1614
1539
  * Collects the shared metadata fields passed to every `createSchema` call.
1615
1540
  */
1541
+ /**
1542
+ * Reads schema examples as an array. OAS 3.1 uses an `examples` array, but specs (including ones
1543
+ * labeled 3.1) still use the singular OAS 3.0 `example`, which the upgrader only converts on the
1544
+ * 3.0 -> 3.1 hop. Normalize both into one array so the AST node exposes only `examples`.
1545
+ */
1546
+ function extractExamples(schema) {
1547
+ if (Array.isArray(schema.examples)) return schema.examples;
1548
+ return schema.example !== void 0 ? [schema.example] : void 0;
1549
+ }
1616
1550
  function buildSchemaNode(schema, name, nullable, defaultValue) {
1617
1551
  return {
1618
1552
  name,
@@ -1623,7 +1557,7 @@ function buildSchemaNode(schema, name, nullable, defaultValue) {
1623
1557
  readOnly: schema.readOnly,
1624
1558
  writeOnly: schema.writeOnly,
1625
1559
  default: defaultValue,
1626
- example: schema.example,
1560
+ examples: extractExamples(schema),
1627
1561
  format: schema.format
1628
1562
  };
1629
1563
  }
@@ -1659,13 +1593,7 @@ function getRequestBodyContentTypes(document, operation) {
1659
1593
  * ```
1660
1594
  */
1661
1595
  function getResponseBodyContentTypes(document, operation, statusCode) {
1662
- if (operation.schema.responses) {
1663
- const responses = operation.schema.responses;
1664
- for (const key in responses) {
1665
- const schema = responses[key];
1666
- if (schema && isReference(schema)) responses[key] = resolveRef(document, schema.$ref);
1667
- }
1668
- }
1596
+ resolveResponseRefs(document, operation);
1669
1597
  const responseObj = getResponseByStatusCode({
1670
1598
  document,
1671
1599
  operation,
@@ -1809,7 +1737,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
1809
1737
  readOnly: schema.readOnly ?? memberNode.readOnly,
1810
1738
  writeOnly: schema.writeOnly ?? memberNode.writeOnly,
1811
1739
  default: mergedDefault,
1812
- example: schema.example ?? memberNode.example,
1740
+ examples: extractExamples(schema) ?? memberNode.examples,
1813
1741
  pattern: schema.pattern ?? ("pattern" in memberNode ? memberNode.pattern : void 0),
1814
1742
  format: schema.format ?? memberNode.format
1815
1743
  });
@@ -2053,7 +1981,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2053
1981
  readOnly: schema.readOnly,
2054
1982
  writeOnly: schema.writeOnly,
2055
1983
  default: enumDefault,
2056
- example: schema.example,
1984
+ examples: extractExamples(schema),
2057
1985
  format: schema.format
2058
1986
  };
2059
1987
  const extensionKey = enumExtensionKeys.find((key) => key in schema);
@@ -2111,10 +2039,10 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2111
2039
  if (additionalProperties === true) return true;
2112
2040
  if (additionalProperties === false) return false;
2113
2041
  if (additionalProperties && Object.keys(additionalProperties).length > 0) return parseSchema({ schema: additionalProperties }, rawOptions);
2114
- if (additionalProperties) return ast.factory.createSchema({ type: typeOptionMap.get(options.unknownType) });
2042
+ if (additionalProperties) return ast.factory.createSchema({ type: options.unknownType });
2115
2043
  })();
2116
2044
  const rawPatternProperties = "patternProperties" in schema ? schema.patternProperties : void 0;
2117
- const patternProperties = rawPatternProperties ? Object.fromEntries(Object.entries(rawPatternProperties).map(([pattern, patternSchema]) => [pattern, patternSchema === true || typeof patternSchema === "object" && Object.keys(patternSchema).length === 0 ? ast.factory.createSchema({ type: typeOptionMap.get(options.unknownType) }) : parseSchema({ schema: patternSchema }, rawOptions)])) : void 0;
2045
+ const patternProperties = rawPatternProperties ? Object.fromEntries(Object.entries(rawPatternProperties).map(([pattern, patternSchema]) => [pattern, patternSchema === true || typeof patternSchema === "object" && Object.keys(patternSchema).length === 0 ? ast.factory.createSchema({ type: options.unknownType }) : parseSchema({ schema: patternSchema }, rawOptions)])) : void 0;
2118
2046
  const objectNode = ast.factory.createSchema({
2119
2047
  type: "object",
2120
2048
  primitive: "object",
@@ -2390,7 +2318,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2390
2318
  const node = rule.convert(schemaCtx);
2391
2319
  if (node) return node;
2392
2320
  }
2393
- const emptyType = typeOptionMap.get(options.emptySchemaType);
2321
+ const emptyType = options.emptySchemaType;
2394
2322
  return ast.factory.createSchema({
2395
2323
  type: emptyType,
2396
2324
  name,
@@ -2409,7 +2337,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2409
2337
  const schema = param["schema"] ? parseSchema({
2410
2338
  schema: param["schema"],
2411
2339
  name: schemaName
2412
- }, options) : ast.factory.createSchema({ type: typeOptionMap.get(options.unknownType) });
2340
+ }, options) : ast.factory.createSchema({ type: options.unknownType });
2413
2341
  return ast.factory.createParameter({
2414
2342
  name: paramName,
2415
2343
  in: param["in"],
@@ -2497,7 +2425,7 @@ function createSchemaParser(ctx, dialect = oasDialect) {
2497
2425
  schema: raw && Object.keys(raw).length > 0 ? parseSchema({
2498
2426
  schema: raw,
2499
2427
  name: responseName
2500
- }, options) : ast.factory.createSchema({ type: typeOptionMap.get(options.emptySchemaType) }),
2428
+ }, options) : ast.factory.createSchema({ type: options.emptySchemaType }),
2501
2429
  keysToOmit: collectPropertyKeysByFlag(raw, "writeOnly")
2502
2430
  };
2503
2431
  };