@kubb/plugin-zod 5.4.0-canary.20260926T081722 → 5.4.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
@@ -747,6 +747,7 @@ function mapSchemaItems(node, transform) {
747
747
  //#region src/components/Zod.tsx
748
748
  function Zod({ name, node, printer, inferTypeName, typeGuards, isName, assertName, mini, cyclic, compile }) {
749
749
  const output = printer.print(node);
750
+ const printerImports = printer.drainImports();
750
751
  if (!output) return;
751
752
  const needsAnnotation = cyclic && node.type !== "object";
752
753
  const isBare = kubb_kit.ast.isBareRef(node, printer.options.keysToOmit);
@@ -756,6 +757,17 @@ function Zod({ name, node, printer, inferTypeName, typeGuards, isName, assertNam
756
757
  const shouldGenerateIs = isName && (typeof typeGuards === "object" ? typeGuards.is ?? true : Boolean(typeGuards));
757
758
  const shouldGenerateAssert = assertName && (typeof typeGuards === "object" ? typeGuards.assert ?? true : Boolean(typeGuards));
758
759
  return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx_jsx_runtime.Fragment, { children: [
760
+ printerImports.map((imp) => /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
761
+ name: imp.name,
762
+ path: imp.path,
763
+ root: imp.root,
764
+ isTypeOnly: imp.isTypeOnly,
765
+ isNameSpace: imp.isNameSpace
766
+ }, [
767
+ name,
768
+ imp.path,
769
+ imp.name
770
+ ].join("-"))),
759
771
  /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
760
772
  name,
761
773
  isExportable: true,
@@ -821,13 +833,38 @@ function shouldCoerce(coercion, type) {
821
833
  if (coercion === true) return true;
822
834
  return !!coercion[type];
823
835
  }
836
+ function hasPropertyNames(node) {
837
+ return "propertyNames" in node && Boolean(node.propertyNames);
838
+ }
839
+ /**
840
+ * Whether the schema node represents a closed or finite set of keys (e.g. enum, literal,
841
+ * or union of enums/literals).
842
+ *
843
+ * In Zod v4, passing a closed key schema to `z.record()` enforces exhaustiveness (all keys
844
+ * must exist in the input). OpenAPI 3.1 `propertyNames` only validates present keys without
845
+ * requiring all keys to exist, so closed key schemas use `z.partialRecord()` instead.
846
+ */
847
+ function isClosedKeySchema(node) {
848
+ if (!node) return false;
849
+ const resolved = (0, kubb_kit.syncSchemaRef)(node);
850
+ if (resolved.type === "enum") return true;
851
+ if (resolved.type === "union") {
852
+ const members = resolved.members ?? [];
853
+ return members.length > 0 && members.every(isClosedKeySchema);
854
+ }
855
+ return false;
856
+ }
824
857
  /**
825
858
  * Whether the node is a plain inline object whose shape can be lifted into an `.extend({ … })`
826
859
  * argument. A catchall, `patternProperties`, or a nullable/optional wrapper cannot, so those stay
827
860
  * on `.and(…)`.
828
861
  */
829
862
  function isPlainInlineObject(node) {
830
- return node.type === "object" && !node.nullable && !node.optional && !node.nullish && node.additionalProperties === void 0 && !node.patternProperties;
863
+ if (node.type !== "object") return false;
864
+ if (node.nullable || node.optional || node.nullish) return false;
865
+ const hasAdditionalProperties = node.additionalProperties !== void 0;
866
+ const hasPatternProperties = Boolean(node.patternProperties);
867
+ return !hasAdditionalProperties && !hasPatternProperties && !hasPropertyNames(node);
831
868
  }
832
869
  /**
833
870
  * Whether a node renders as a bare Zod object — one that accepts `.extend(…)` and can be a
@@ -838,7 +875,12 @@ function isPlainInlineObject(node) {
838
875
  */
839
876
  function isObjectSchemaNode(node, cyclicSchemas) {
840
877
  if (node.nullable || node.optional || node.nullish) return false;
841
- if (node.type === "object") return true;
878
+ if (node.type === "object") {
879
+ const hasProperties = Boolean(node.properties?.length);
880
+ const hasTypedAdditionalProperties = Boolean(node.additionalProperties && node.additionalProperties !== true);
881
+ const hasPatternProperties = Boolean(node.patternProperties);
882
+ return !(!hasProperties && (hasTypedAdditionalProperties || hasPatternProperties || hasPropertyNames(node)));
883
+ }
842
884
  if (node.type === "ref") {
843
885
  const refName = kubb_kit.ast.resolveRefName(node);
844
886
  if (refName && cyclicSchemas?.has(refName)) return false;
@@ -1175,7 +1217,8 @@ function variesByDirection({ node, printerOptions }) {
1175
1217
  direction
1176
1218
  },
1177
1219
  transform: () => null,
1178
- base: () => null
1220
+ base: () => null,
1221
+ import: () => {}
1179
1222
  };
1180
1223
  return handler.call(context, node);
1181
1224
  };
@@ -1212,6 +1255,7 @@ function containsDirectionalNode({ node, printerOptions, seen = /* @__PURE__ */
1212
1255
  if ("items" in node && node.items) children.push(...node.items);
1213
1256
  if ("members" in node && node.members) children.push(...node.members);
1214
1257
  if ("additionalProperties" in node && node.additionalProperties && node.additionalProperties !== true) children.push(node.additionalProperties);
1258
+ if ("propertyNames" in node && node.propertyNames) children.push(node.propertyNames);
1215
1259
  return children.some((child) => containsDirectionalNode({
1216
1260
  node: child,
1217
1261
  printerOptions,
@@ -1376,14 +1420,23 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
1376
1420
  object(node) {
1377
1421
  const entries = node.properties ?? [];
1378
1422
  const patterns = node.patternProperties ? Object.entries(node.patternProperties) : [];
1423
+ const propertyNamesNode = "propertyNames" in node ? node.propertyNames : void 0;
1424
+ const propertyNamesKeySchema = propertyNamesNode ? this.transform(propertyNamesNode) : null;
1379
1425
  const isStrict = node.additionalProperties === false && patterns.length === 0;
1380
- const objectBase = `${isStrict ? "z.strictObject" : "z.object"}(${buildZodObjectShape(this, node)})`;
1426
+ const isLoose = node.additionalProperties === true;
1427
+ const objectBase = `${isStrict ? "z.strictObject" : isLoose ? "z.looseObject" : "z.object"}(${buildZodObjectShape(this, node)})`;
1381
1428
  return (() => {
1429
+ const recordFn = isClosedKeySchema(propertyNamesNode) ? "z.partialRecord" : "z.record";
1382
1430
  if (node.additionalProperties && node.additionalProperties !== true) {
1383
1431
  const catchallType = this.transform(node.additionalProperties);
1432
+ if (entries.length === 0) return catchallType ? `${recordFn}(${propertyNamesKeySchema || "z.string()"}, ${catchallType})` : objectBase;
1384
1433
  return catchallType ? `${objectBase}.catchall(${catchallType})` : objectBase;
1385
1434
  }
1386
- if (node.additionalProperties === true) return `${objectBase}.catchall(${this.transform(kubb_kit.ast.factory.createSchema({ type: "unknown" }))})`;
1435
+ if (entries.length === 0 && patterns.length === 0 && propertyNamesKeySchema && !isStrict) {
1436
+ const unknownType = this.transform(kubb_kit.ast.factory.createSchema({ type: "unknown" }));
1437
+ return `${recordFn}(${propertyNamesKeySchema}, ${unknownType})`;
1438
+ }
1439
+ if (node.additionalProperties === true) return objectBase;
1387
1440
  if (isStrict) return objectBase;
1388
1441
  if (patterns.length > 0) {
1389
1442
  const values = patterns.map(([, valueSchema]) => {
@@ -1639,13 +1692,19 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
1639
1692
  object(node) {
1640
1693
  const entries = node.properties ?? [];
1641
1694
  const patterns = node.patternProperties ? Object.entries(node.patternProperties) : [];
1695
+ const propertyNamesNode = "propertyNames" in node ? node.propertyNames : void 0;
1696
+ const propertyNamesKeySchema = propertyNamesNode ? this.transform(propertyNamesNode) : null;
1642
1697
  const isStrict = node.additionalProperties === false && patterns.length === 0;
1643
- const objectBase = `${isStrict ? "z.strictObject" : "z.object"}(${buildZodMiniObjectShape(this, node)})`;
1698
+ const isLoose = node.additionalProperties === true;
1699
+ const objectBase = `${isStrict ? "z.strictObject" : isLoose ? "z.looseObject" : "z.object"}(${buildZodMiniObjectShape(this, node)})`;
1700
+ const recordFn = isClosedKeySchema(propertyNamesNode) ? "z.partialRecord" : "z.record";
1644
1701
  if (node.additionalProperties && node.additionalProperties !== true) {
1645
1702
  const catchallType = this.transform(node.additionalProperties);
1703
+ if (entries.length === 0) return catchallType ? `${recordFn}(${propertyNamesKeySchema || "z.string()"}, ${catchallType})` : objectBase;
1646
1704
  return catchallType ? `z.catchall(${objectBase}, ${catchallType})` : objectBase;
1647
1705
  }
1648
- if (node.additionalProperties === true) return `z.catchall(${objectBase}, ${this.transform(kubb_kit.ast.factory.createSchema({ type: "unknown" }))})`;
1706
+ if (entries.length === 0 && patterns.length === 0 && propertyNamesKeySchema && !isStrict) return `${recordFn}(${propertyNamesKeySchema}, ${this.transform(kubb_kit.ast.factory.createSchema({ type: "unknown" }))})`;
1707
+ if (node.additionalProperties === true) return objectBase;
1649
1708
  if (isStrict) return objectBase;
1650
1709
  if (patterns.length > 0) {
1651
1710
  const values = patterns.map(([, valueSchema]) => {