@kubb/adapter-oas 5.16.0 → 5.16.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.16.0";
38
+ var version = "5.16.1";
39
39
  // src/constants.ts
40
40
  /**
41
41
  * Default parser options applied when no explicit options are provided.
@@ -1394,7 +1394,7 @@ function flattenSchema(schema) {
1394
1394
  /**
1395
1395
  * Links one freshly converted schema and its nested schemas to their RFC 6901 pointers
1396
1396
  * (`#/components/schemas/Pet/properties/owner/properties/name`), and reports the advisory
1397
- * diagnostics (`KUBB_UNSUPPORTED_FORMAT`, `KUBB_DEPRECATED`) against them.
1397
+ * diagnostics (`KUBB_UNSUPPORTED_FORMAT`, `KUBB_DEPRECATED`, `KUBB_DUPLICATE_DISCRIMINATOR`) against them.
1398
1398
  * Refs are not followed, so the resolved schema is handled under its own walk.
1399
1399
  * Reports land in the active build run, are a no-op outside one, and repeats are deduped by the build.
1400
1400
  */
@@ -1439,11 +1439,55 @@ function visit(node, pointer) {
1439
1439
  for (const member of node.members ?? []) visit(member, `${pointer}/not`);
1440
1440
  return;
1441
1441
  }
1442
+ if (node.type === "union" && node.discriminatorPropertyName) reportDuplicateDiscriminators(node, node.discriminatorPropertyName, pointer);
1442
1443
  if (node.type === "union" || node.type === "intersection") {
1443
1444
  const keyword = node.type === "intersection" ? "allOf" : node.strategy === "any" ? "anyOf" : "oneOf";
1444
1445
  for (const [index, member] of (node.members ?? []).entries()) visit(member, `${pointer}/${keyword}/${index}`);
1445
1446
  }
1446
1447
  }
1448
+ /**
1449
+ * Reports a declared discriminator whose value pins more than one member. The spec cannot tell
1450
+ * those members apart, and Zod's `z.discriminatedUnion` throws on the first parse.
1451
+ * One diagnostic per union, since the build dedupes by code and pointer.
1452
+ */
1453
+ function reportDuplicateDiscriminators(node, propertyName, pointer) {
1454
+ const keyword = node.strategy === "any" ? "anyOf" : "oneOf";
1455
+ const membersByValue = /* @__PURE__ */ new Map();
1456
+ for (const [index, member] of (node.members ?? []).entries()) {
1457
+ const label = memberName(member) ?? `${keyword}/${index}`;
1458
+ for (const value of memberValues(member, propertyName)) membersByValue.set(value, [...membersByValue.get(value) ?? [], label]);
1459
+ }
1460
+ const duplicates = [...membersByValue].filter(([, members]) => members.length > 1);
1461
+ if (!duplicates.length) return;
1462
+ _kubb_kit.Diagnostics.report({
1463
+ code: _kubb_kit.Diagnostics.code.duplicateDiscriminator,
1464
+ severity: "warning",
1465
+ message: duplicates.map(([value, members]) => `Discriminator "${propertyName}" value ${JSON.stringify(value)} matches more than one member (${members.join(", ")}).`).join(" "),
1466
+ help: `Give each member its own "${propertyName}" value, or drop the discriminator. Zod's z.discriminatedUnion throws on the first parse of this union.`,
1467
+ location: {
1468
+ kind: "schema",
1469
+ pointer
1470
+ }
1471
+ });
1472
+ }
1473
+ function memberValues(node, propertyName, seen = /* @__PURE__ */ new Set()) {
1474
+ if (seen.has(node)) return [];
1475
+ seen.add(node);
1476
+ const target = node.type === "ref" && node.schema ? node.schema : node;
1477
+ if (target.type === "union") return [...new Set(target.members?.flatMap((member) => memberValues(member, propertyName, seen)))];
1478
+ return intersect(_kubb_kit.ast.resolveSchemaProperties({
1479
+ node,
1480
+ propertyName
1481
+ }).map((property) => [..._kubb_kit.ast.getSchemaLiteralValues(property.schema)]));
1482
+ }
1483
+ function intersect(slices) {
1484
+ const pinned = slices.filter((values) => values.length > 0);
1485
+ return pinned.reduce((acc, values) => acc.filter((value) => values.includes(value)), pinned[0] ?? []);
1486
+ }
1487
+ function memberName(member) {
1488
+ if (member.type === "ref") return member.name ?? void 0;
1489
+ if (member.type === "intersection") return member.members?.map(memberName).find(Boolean);
1490
+ }
1447
1491
  // src/operation.ts
1448
1492
  function slugify(value) {
1449
1493
  return value.replace(/[^a-zA-Z0-9]/g, "-").replace(/-{2,}/g, "-").replace(/^-|-$/g, "");