@kubb/adapter-oas 5.17.0 → 5.17.1

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
@@ -35,7 +35,7 @@ var compatibility = {
35
35
  "node": ">=22.22"
36
36
  };
37
37
  // package.json
38
- var version = "5.17.0";
38
+ var version = "5.17.1";
39
39
  // src/constants.ts
40
40
  /**
41
41
  * Default parser options applied when no explicit options are provided.
@@ -445,17 +445,32 @@ function isBinary(schema) {
445
445
  return schema.contentMediaType === "application/octet-stream" && schema.contentEncoding === void 0 && (schema.type === void 0 || schema.type === "string");
446
446
  }
447
447
  /**
448
+ * Keywords that only annotate a schema. A schema with nothing else does not constrain the value.
449
+ */
450
+ const annotationKeywords = /* @__PURE__ */ new Set([
451
+ "title",
452
+ "description",
453
+ "default",
454
+ "example",
455
+ "examples",
456
+ "deprecated",
457
+ "readOnly",
458
+ "writeOnly",
459
+ "externalDocs"
460
+ ]);
461
+ /**
448
462
  * Returns the binary schema for a non-JSON entry the OAS 3.1 upgrade emptied out, or `undefined`
449
463
  * when the entry carries a schema of its own. The upgrade rewrites `format: 'binary'` into
450
464
  * `contentMediaType` and drops it whenever it only repeats the media type key, for any binary
451
465
  * media type (`application/octet-stream`, `application/pdf`, `image/png`, ...), not just
452
466
  * `application/octet-stream`. Without the fallback such a body resolves to the empty schema type
453
- * instead of a blob.
467
+ * instead of a blob. Annotations such as `description` survive the upgrade and are kept.
454
468
  */
455
469
  function getBinaryFallbackSchema(mediaType, schema) {
456
470
  if (!mediaType || isJsonMimeType(mediaType)) return void 0;
457
- if (schema && Object.keys(schema).length > 0) return void 0;
471
+ if (schema && Object.keys(schema).some((key) => !annotationKeywords.has(key) && !key.startsWith("x-"))) return void 0;
458
472
  return {
473
+ ...schema,
459
474
  type: "string",
460
475
  contentMediaType: "application/octet-stream"
461
476
  };
@@ -1425,6 +1440,39 @@ function flattenSchema(schema) {
1425
1440
  function scanSchema(node, pointer = node.pointer) {
1426
1441
  if (pointer) visit(node, pointer);
1427
1442
  }
1443
+ let formatTally;
1444
+ /**
1445
+ * Runs `fn` and reports `KUBB_UNSUPPORTED_FORMAT` once per format with the number of schemas that use it,
1446
+ * instead of once per schema. `format` is an open value in OpenAPI, so a large spec would otherwise print
1447
+ * thousands of warnings that say the same thing. `fn` must be synchronous.
1448
+ */
1449
+ function groupUnsupportedFormats(fn) {
1450
+ formatTally = /* @__PURE__ */ new Map();
1451
+ try {
1452
+ return fn();
1453
+ } finally {
1454
+ const tally = formatTally;
1455
+ formatTally = void 0;
1456
+ for (const [format, pointers] of tally) reportUnsupportedFormat(format, [...pointers]);
1457
+ }
1458
+ }
1459
+ function tallyFormat(format, pointer) {
1460
+ if (!formatTally) return reportUnsupportedFormat(format, [pointer]);
1461
+ formatTally.set(format, (formatTally.get(format) ?? /* @__PURE__ */ new Set()).add(pointer));
1462
+ }
1463
+ function reportUnsupportedFormat(format, pointers) {
1464
+ const count = pointers.length;
1465
+ _kubb_kit.Diagnostics.report({
1466
+ code: _kubb_kit.Diagnostics.code.unsupportedFormat,
1467
+ severity: "warning",
1468
+ 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.`,
1469
+ help: `Use a format Kubb supports, or handle "${format}" with a custom parser or plugin.`,
1470
+ location: {
1471
+ kind: "schema",
1472
+ pointer: pointers[0]
1473
+ }
1474
+ });
1475
+ }
1428
1476
  function visit(node, pointer) {
1429
1477
  node.pointer ??= pointer;
1430
1478
  if (node.deprecated) _kubb_kit.Diagnostics.report({
@@ -1436,16 +1484,7 @@ function visit(node, pointer) {
1436
1484
  pointer
1437
1485
  }
1438
1486
  });
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
- });
1487
+ if (typeof node.format === "string" && !isHandledFormat(node.format)) tallyFormat(node.format, pointer);
1449
1488
  if (node.type === "object") {
1450
1489
  for (const property of node.properties) visit(property.schema, `${pointer}/properties/${escapePointerToken(property.name)}`);
1451
1490
  if (node.additionalProperties && typeof node.additionalProperties === "object") visit(node.additionalProperties, `${pointer}/additionalProperties`);
@@ -1554,18 +1593,6 @@ function getResponseByStatusCode({ operation, refs, statusCode }) {
1554
1593
  function getRequestBody({ operation, refs }) {
1555
1594
  return refs.deref(operation.schema.requestBody);
1556
1595
  }
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
1596
  /** Merges path-level and operation-level parameters; operation-level wins per `in:name`. */
1570
1597
  function getParameters({ operation, refs }) {
1571
1598
  const resolveParams = (params, pointer) => params.flatMap((entry, index) => {
@@ -1828,15 +1855,13 @@ function parseOperation({ operation, ...ctx }) {
1828
1855
  }) : {}
1829
1856
  };
1830
1857
  };
1831
- const responseContent = (contentType ? [contentType] : Object.keys(response?.content ?? {})).map((ct) => _kubb_kit.ast.factory.createContent({
1858
+ const declaredContentTypes = Object.keys(response?.content ?? {});
1859
+ const responseContent = (contentType && declaredContentTypes.length ? [contentType] : declaredContentTypes).map((ct) => _kubb_kit.ast.factory.createContent({
1832
1860
  contentType: ct,
1833
1861
  ...parseEntrySchema(ct)
1834
1862
  }));
1835
1863
  if (responseContent.length === 0) responseContent.push(_kubb_kit.ast.factory.createContent({
1836
- contentType: getRequestContentType({
1837
- operation,
1838
- refs
1839
- }),
1864
+ contentType: "",
1840
1865
  ...parseEntrySchema(contentType)
1841
1866
  }));
1842
1867
  return _kubb_kit.ast.factory.createResponse({
@@ -2016,6 +2041,15 @@ function removeInheritedDiscriminator({ members, refs }) {
2016
2041
  });
2017
2042
  }
2018
2043
  /**
2044
+ * Whether a member can carry the discriminator property. A discriminator is only a hint, so an array
2045
+ * or primitive member keeps its own type instead of an intersection no value can satisfy.
2046
+ */
2047
+ function isObjectLike(member, refs) {
2048
+ const type = (isReference(member) ? refs.resolve(member.$ref, { report: false }) : member)?.type;
2049
+ if (type === void 0) return true;
2050
+ return Array.isArray(type) ? type.includes("object") : type === "object";
2051
+ }
2052
+ /**
2019
2053
  * Narrows each `oneOf`/`anyOf` member with its discriminant value, intersecting the member's own
2020
2054
  * node with either the shared-properties slice carrying that value, or a synthetic discriminant
2021
2055
  * literal. The referenced child schema's own definition is left untouched — narrowing happens only
@@ -2078,7 +2112,7 @@ function narrowUnionMembers({ unionMembers, discriminator, sharedPropertiesNode,
2078
2112
  schema: s,
2079
2113
  name
2080
2114
  });
2081
- if (!discriminatorValues.length || !discriminator) return memberNode;
2115
+ if (!discriminatorValues.length || !discriminator || !isObjectLike(s, refs)) return memberNode;
2082
2116
  const narrowedDiscriminatorNode = sharedPropertiesNode ? pickDiscriminatorPropertyNode(_kubb_kit.ast.applyMacros(sharedPropertiesNode, [(0, _kubb_kit.macroDiscriminatorEnum)({
2083
2117
  propertyName: discriminator.propertyName,
2084
2118
  values: discriminatorValues
@@ -3478,18 +3512,19 @@ const adapterOas = (0, _kubb_core.defineExtension)({
3478
3512
  parsedDocument = document;
3479
3513
  const refs = createRefs(document);
3480
3514
  const { schemas, renames, pointers } = getSchemas(document, { contentType }, refs);
3481
- return parseInput({
3515
+ const parseSchema = createSchemaParser({
3516
+ document,
3517
+ refs,
3518
+ renames,
3519
+ options: parserOptions
3520
+ });
3521
+ return groupUnsupportedFormats(() => parseInput({
3482
3522
  document,
3483
3523
  refs,
3484
3524
  schemas,
3485
3525
  pointers,
3486
- parseSchema: createSchemaParser({
3487
- document,
3488
- refs,
3489
- renames,
3490
- options: parserOptions
3491
- })
3492
- });
3526
+ parseSchema
3527
+ }));
3493
3528
  })();
3494
3529
  inputCache.set(source, {
3495
3530
  promise,