@kubb/adapter-oas 5.16.0 → 5.17.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
@@ -35,7 +35,7 @@ var compatibility = {
35
35
  "node": ">=22.22"
36
36
  };
37
37
  // package.json
38
- var version = "5.16.0";
38
+ var version = "5.17.0";
39
39
  // src/constants.ts
40
40
  /**
41
41
  * Default parser options applied when no explicit options are provided.
@@ -1220,6 +1220,30 @@ function resolveServerUrl(server, overrides) {
1220
1220
  }
1221
1221
  return url;
1222
1222
  }
1223
+ /**
1224
+ * Maps OpenAPI servers to `InputServer` entries: drops entries without a `url` and fills `{variable}` defaults.
1225
+ */
1226
+ function toInputServers(servers) {
1227
+ return servers.filter((entry) => entry.url).map(({ url, description, variables }) => {
1228
+ const declared = variables && Object.keys(variables).length > 0 ? { variables } : {};
1229
+ try {
1230
+ return {
1231
+ url: resolveServerUrl({
1232
+ url,
1233
+ variables
1234
+ }),
1235
+ description,
1236
+ ...declared
1237
+ };
1238
+ } catch {
1239
+ return {
1240
+ url,
1241
+ description,
1242
+ ...declared
1243
+ };
1244
+ }
1245
+ });
1246
+ }
1223
1247
  // src/model/mediaType.ts
1224
1248
  /**
1225
1249
  * The media type without its parameters, so `text/event-stream; charset=utf-8` matches the bare name.
@@ -1394,7 +1418,7 @@ function flattenSchema(schema) {
1394
1418
  /**
1395
1419
  * Links one freshly converted schema and its nested schemas to their RFC 6901 pointers
1396
1420
  * (`#/components/schemas/Pet/properties/owner/properties/name`), and reports the advisory
1397
- * diagnostics (`KUBB_UNSUPPORTED_FORMAT`, `KUBB_DEPRECATED`) against them.
1421
+ * diagnostics (`KUBB_UNSUPPORTED_FORMAT`, `KUBB_DEPRECATED`, `KUBB_DUPLICATE_DISCRIMINATOR`) against them.
1398
1422
  * Refs are not followed, so the resolved schema is handled under its own walk.
1399
1423
  * Reports land in the active build run, are a no-op outside one, and repeats are deduped by the build.
1400
1424
  */
@@ -1439,11 +1463,55 @@ function visit(node, pointer) {
1439
1463
  for (const member of node.members ?? []) visit(member, `${pointer}/not`);
1440
1464
  return;
1441
1465
  }
1466
+ if (node.type === "union" && node.discriminatorPropertyName) reportDuplicateDiscriminators(node, node.discriminatorPropertyName, pointer);
1442
1467
  if (node.type === "union" || node.type === "intersection") {
1443
1468
  const keyword = node.type === "intersection" ? "allOf" : node.strategy === "any" ? "anyOf" : "oneOf";
1444
1469
  for (const [index, member] of (node.members ?? []).entries()) visit(member, `${pointer}/${keyword}/${index}`);
1445
1470
  }
1446
1471
  }
1472
+ /**
1473
+ * Reports a declared discriminator whose value pins more than one member. The spec cannot tell
1474
+ * those members apart, and Zod's `z.discriminatedUnion` throws on the first parse.
1475
+ * One diagnostic per union, since the build dedupes by code and pointer.
1476
+ */
1477
+ function reportDuplicateDiscriminators(node, propertyName, pointer) {
1478
+ const keyword = node.strategy === "any" ? "anyOf" : "oneOf";
1479
+ const membersByValue = /* @__PURE__ */ new Map();
1480
+ for (const [index, member] of (node.members ?? []).entries()) {
1481
+ const label = memberName(member) ?? `${keyword}/${index}`;
1482
+ for (const value of memberValues(member, propertyName)) membersByValue.set(value, [...membersByValue.get(value) ?? [], label]);
1483
+ }
1484
+ const duplicates = [...membersByValue].filter(([, members]) => members.length > 1);
1485
+ if (!duplicates.length) return;
1486
+ _kubb_kit.Diagnostics.report({
1487
+ code: _kubb_kit.Diagnostics.code.duplicateDiscriminator,
1488
+ severity: "warning",
1489
+ message: duplicates.map(([value, members]) => `Discriminator "${propertyName}" value ${JSON.stringify(value)} matches more than one member (${members.join(", ")}).`).join(" "),
1490
+ help: `Give each member its own "${propertyName}" value, or drop the discriminator. Zod's z.discriminatedUnion throws on the first parse of this union.`,
1491
+ location: {
1492
+ kind: "schema",
1493
+ pointer
1494
+ }
1495
+ });
1496
+ }
1497
+ function memberValues(node, propertyName, seen = /* @__PURE__ */ new Set()) {
1498
+ if (seen.has(node)) return [];
1499
+ seen.add(node);
1500
+ const target = node.type === "ref" && node.schema ? node.schema : node;
1501
+ if (target.type === "union") return [...new Set(target.members?.flatMap((member) => memberValues(member, propertyName, seen)))];
1502
+ return intersect(_kubb_kit.ast.resolveSchemaProperties({
1503
+ node,
1504
+ propertyName
1505
+ }).map((property) => [..._kubb_kit.ast.getSchemaLiteralValues(property.schema)]));
1506
+ }
1507
+ function intersect(slices) {
1508
+ const pinned = slices.filter((values) => values.length > 0);
1509
+ return pinned.reduce((acc, values) => acc.filter((value) => values.includes(value)), pinned[0] ?? []);
1510
+ }
1511
+ function memberName(member) {
1512
+ if (member.type === "ref") return member.name ?? void 0;
1513
+ if (member.type === "intersection") return member.members?.map(memberName).find(Boolean);
1514
+ }
1447
1515
  // src/operation.ts
1448
1516
  function slugify(value) {
1449
1517
  return value.replace(/[^a-zA-Z0-9]/g, "-").replace(/-{2,}/g, "-").replace(/^-|-$/g, "");
@@ -1784,6 +1852,7 @@ function parseOperation({ operation, ...ctx }) {
1784
1852
  const fallback = operation.pathItem[key];
1785
1853
  return typeof fallback === "string" ? fallback : void 0;
1786
1854
  };
1855
+ const servers = operation.schema.servers ?? operation.pathItem.servers;
1787
1856
  return _kubb_kit.ast.factory.createOperation({
1788
1857
  pointer,
1789
1858
  operationId,
@@ -1797,7 +1866,8 @@ function parseOperation({ operation, ...ctx }) {
1797
1866
  parameters,
1798
1867
  requestBody,
1799
1868
  responses,
1800
- extensions: pickExtensions(operation.schema)
1869
+ extensions: pickExtensions(operation.schema),
1870
+ ...servers && { servers: toInputServers(servers) }
1801
1871
  });
1802
1872
  }
1803
1873
  // src/emit/createNode.ts
@@ -3355,25 +3425,7 @@ const adapterOas = (0, _kubb_core.defineExtension)({
3355
3425
  document,
3356
3426
  server
3357
3427
  }),
3358
- servers: (document.servers ?? []).filter((entry) => entry.url).map(({ url, description, variables }) => {
3359
- const declared = variables && Object.keys(variables).length > 0 ? { variables } : {};
3360
- try {
3361
- return {
3362
- url: resolveServerUrl({
3363
- url,
3364
- variables
3365
- }),
3366
- description,
3367
- ...declared
3368
- };
3369
- } catch {
3370
- return {
3371
- url,
3372
- description,
3373
- ...declared
3374
- };
3375
- }
3376
- }),
3428
+ servers: toInputServers(document.servers ?? []),
3377
3429
  securitySchemes: Object.entries(document.components?.securitySchemes ?? {}).flatMap(([name, value]) => {
3378
3430
  const scheme = refs.deref(value);
3379
3431
  return scheme?.type ? [{