zod-nest 0.5.0 → 0.7.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.d.mts CHANGED
@@ -28,6 +28,40 @@ interface OverrideContext {
28
28
  }
29
29
  type Override = (ctx: OverrideContext) => void;
30
30
 
31
+ /**
32
+ * Composition layer — emits OpenAPI `allOf` for schemas derived via `extend`.
33
+ *
34
+ * **EXPERIMENTAL (v0.2)**: output shape may change as edge cases surface.
35
+ */
36
+
37
+ /**
38
+ * Lineage record for a composition-derived schema. Read by the override to
39
+ * emit `allOf` instead of a flat body.
40
+ *
41
+ * @experimental v0.2 — shape may change.
42
+ */
43
+ interface LineageEntry {
44
+ readonly op: 'extend';
45
+ readonly parent: z.ZodObject;
46
+ }
47
+ /**
48
+ * Wraps a derived `z.ZodObject` and records the parent → child link so
49
+ * emission rewrites the body to `allOf: [{ $ref: <parent> }, <delta>]`.
50
+ *
51
+ * @experimental v0.2 — output shape may change as the surface stabilizes.
52
+ *
53
+ * @example
54
+ * const Base = z.object({ id: z.string() }).meta({ id: 'Base' });
55
+ * const Child = extend(Base, (s) => s.extend({ role: z.string() }).meta({ id: 'Child' }));
56
+ */
57
+ declare const extend: <P extends z.ZodObject, S extends z.ZodObject>(parent: P, build: (p: P) => S) => S;
58
+ /**
59
+ * Read the lineage entry for a composition-derived schema, or `undefined`.
60
+ *
61
+ * @experimental v0.2 — `LineageEntry` shape may change.
62
+ */
63
+ declare const getLineage: (schema: z.ZodType) => LineageEntry | undefined;
64
+
31
65
  interface ZodNestRegistry {
32
66
  readonly zodRegistry: typeof z.globalRegistry;
33
67
  register(schema: z.ZodType, id: string): void;
@@ -470,4 +504,4 @@ declare class ZodNestDocumentError extends ZodNestError {
470
504
  constructor(code: ZodNestDocumentErrorCode, message: string, details?: Record<string, unknown>);
471
505
  }
472
506
 
473
- export { type ApplyZodNestOptions, COMPONENTS_SCHEMAS_PREFIX, type CreateSerializationException, type CreateValidationException, type CreateZodDtoOptions, DEFAULT_MAX_LOGGED_VALUE_BYTES, DEFAULT_REDACT_KEYS, type Io, type NormalizedZodNestOptions, type Override, type OverrideContext, type ResponseVariant, type ResponseVariantKind, type SchemaObject, type ToOpenApiOptions, type ToOpenApiResult, ZOD_DTO_SYMBOL, ZOD_NEST_DTO_EXTENSION, ZOD_NEST_ERROR_DUPLICATE_ID, ZOD_NEST_ERROR_EXTENSION, ZOD_NEST_OPTIONS, ZOD_RESPONSES_METADATA_KEY, type ZodDto, type ZodDtoMarker, ZodNestDocumentError, type ZodNestDocumentErrorCode, ZodNestError, ZodNestModule, type ZodNestModuleOptions, type ZodNestRegistry, ZodNestUnrepresentableError, ZodResponse, type ZodResponseDescription, type ZodResponseOptions, type ZodResponseType, ZodSerializationException, ZodSerializerInterceptor, ZodValidationException, ZodValidationPipe, type ZodValidationPipeArg, type ZodValidationPipeOptions, applyZodNest, createRegistry, createZodDto, defaultRegistry, defaultStatusFor, isZodDto, isZodDtoMarker, makeZodDtoMarker, resolveEffectiveStatus, toOpenApi };
507
+ export { type ApplyZodNestOptions, COMPONENTS_SCHEMAS_PREFIX, type CreateSerializationException, type CreateValidationException, type CreateZodDtoOptions, DEFAULT_MAX_LOGGED_VALUE_BYTES, DEFAULT_REDACT_KEYS, type Io, type LineageEntry, type NormalizedZodNestOptions, type Override, type OverrideContext, type ResponseVariant, type ResponseVariantKind, type SchemaObject, type ToOpenApiOptions, type ToOpenApiResult, ZOD_DTO_SYMBOL, ZOD_NEST_DTO_EXTENSION, ZOD_NEST_ERROR_DUPLICATE_ID, ZOD_NEST_ERROR_EXTENSION, ZOD_NEST_OPTIONS, ZOD_RESPONSES_METADATA_KEY, type ZodDto, type ZodDtoMarker, ZodNestDocumentError, type ZodNestDocumentErrorCode, ZodNestError, ZodNestModule, type ZodNestModuleOptions, type ZodNestRegistry, ZodNestUnrepresentableError, ZodResponse, type ZodResponseDescription, type ZodResponseOptions, type ZodResponseType, ZodSerializationException, ZodSerializerInterceptor, ZodValidationException, ZodValidationPipe, type ZodValidationPipeArg, type ZodValidationPipeOptions, applyZodNest, createRegistry, createZodDto, defaultRegistry, defaultStatusFor, extend, getLineage, isZodDto, isZodDtoMarker, makeZodDtoMarker, resolveEffectiveStatus, toOpenApi };
package/dist/index.d.ts CHANGED
@@ -28,6 +28,40 @@ interface OverrideContext {
28
28
  }
29
29
  type Override = (ctx: OverrideContext) => void;
30
30
 
31
+ /**
32
+ * Composition layer — emits OpenAPI `allOf` for schemas derived via `extend`.
33
+ *
34
+ * **EXPERIMENTAL (v0.2)**: output shape may change as edge cases surface.
35
+ */
36
+
37
+ /**
38
+ * Lineage record for a composition-derived schema. Read by the override to
39
+ * emit `allOf` instead of a flat body.
40
+ *
41
+ * @experimental v0.2 — shape may change.
42
+ */
43
+ interface LineageEntry {
44
+ readonly op: 'extend';
45
+ readonly parent: z.ZodObject;
46
+ }
47
+ /**
48
+ * Wraps a derived `z.ZodObject` and records the parent → child link so
49
+ * emission rewrites the body to `allOf: [{ $ref: <parent> }, <delta>]`.
50
+ *
51
+ * @experimental v0.2 — output shape may change as the surface stabilizes.
52
+ *
53
+ * @example
54
+ * const Base = z.object({ id: z.string() }).meta({ id: 'Base' });
55
+ * const Child = extend(Base, (s) => s.extend({ role: z.string() }).meta({ id: 'Child' }));
56
+ */
57
+ declare const extend: <P extends z.ZodObject, S extends z.ZodObject>(parent: P, build: (p: P) => S) => S;
58
+ /**
59
+ * Read the lineage entry for a composition-derived schema, or `undefined`.
60
+ *
61
+ * @experimental v0.2 — `LineageEntry` shape may change.
62
+ */
63
+ declare const getLineage: (schema: z.ZodType) => LineageEntry | undefined;
64
+
31
65
  interface ZodNestRegistry {
32
66
  readonly zodRegistry: typeof z.globalRegistry;
33
67
  register(schema: z.ZodType, id: string): void;
@@ -470,4 +504,4 @@ declare class ZodNestDocumentError extends ZodNestError {
470
504
  constructor(code: ZodNestDocumentErrorCode, message: string, details?: Record<string, unknown>);
471
505
  }
472
506
 
473
- export { type ApplyZodNestOptions, COMPONENTS_SCHEMAS_PREFIX, type CreateSerializationException, type CreateValidationException, type CreateZodDtoOptions, DEFAULT_MAX_LOGGED_VALUE_BYTES, DEFAULT_REDACT_KEYS, type Io, type NormalizedZodNestOptions, type Override, type OverrideContext, type ResponseVariant, type ResponseVariantKind, type SchemaObject, type ToOpenApiOptions, type ToOpenApiResult, ZOD_DTO_SYMBOL, ZOD_NEST_DTO_EXTENSION, ZOD_NEST_ERROR_DUPLICATE_ID, ZOD_NEST_ERROR_EXTENSION, ZOD_NEST_OPTIONS, ZOD_RESPONSES_METADATA_KEY, type ZodDto, type ZodDtoMarker, ZodNestDocumentError, type ZodNestDocumentErrorCode, ZodNestError, ZodNestModule, type ZodNestModuleOptions, type ZodNestRegistry, ZodNestUnrepresentableError, ZodResponse, type ZodResponseDescription, type ZodResponseOptions, type ZodResponseType, ZodSerializationException, ZodSerializerInterceptor, ZodValidationException, ZodValidationPipe, type ZodValidationPipeArg, type ZodValidationPipeOptions, applyZodNest, createRegistry, createZodDto, defaultRegistry, defaultStatusFor, isZodDto, isZodDtoMarker, makeZodDtoMarker, resolveEffectiveStatus, toOpenApi };
507
+ export { type ApplyZodNestOptions, COMPONENTS_SCHEMAS_PREFIX, type CreateSerializationException, type CreateValidationException, type CreateZodDtoOptions, DEFAULT_MAX_LOGGED_VALUE_BYTES, DEFAULT_REDACT_KEYS, type Io, type LineageEntry, type NormalizedZodNestOptions, type Override, type OverrideContext, type ResponseVariant, type ResponseVariantKind, type SchemaObject, type ToOpenApiOptions, type ToOpenApiResult, ZOD_DTO_SYMBOL, ZOD_NEST_DTO_EXTENSION, ZOD_NEST_ERROR_DUPLICATE_ID, ZOD_NEST_ERROR_EXTENSION, ZOD_NEST_OPTIONS, ZOD_RESPONSES_METADATA_KEY, type ZodDto, type ZodDtoMarker, ZodNestDocumentError, type ZodNestDocumentErrorCode, ZodNestError, ZodNestModule, type ZodNestModuleOptions, type ZodNestRegistry, ZodNestUnrepresentableError, ZodResponse, type ZodResponseDescription, type ZodResponseOptions, type ZodResponseType, ZodSerializationException, ZodSerializerInterceptor, ZodValidationException, ZodValidationPipe, type ZodValidationPipeArg, type ZodValidationPipeOptions, applyZodNest, createRegistry, createZodDto, defaultRegistry, defaultStatusFor, extend, getLineage, isZodDto, isZodDtoMarker, makeZodDtoMarker, resolveEffectiveStatus, toOpenApi };
package/dist/index.js CHANGED
@@ -24,9 +24,73 @@ var __decorateParam = (index, decorator) => (target, key) => decorator(target, k
24
24
 
25
25
  // src/schema/constants.ts
26
26
  var COMPONENTS_SCHEMAS_PREFIX = "#/components/schemas/";
27
+ var DEFS_PREFIX = "#/$defs/";
27
28
  var ZOD_NEST_ERROR_EXTENSION = "x-zod-nest-error";
28
29
  var ZOD_NEST_ERROR_DUPLICATE_ID = "duplicate-id";
29
30
  var ZOD_NEST_DTO_EXTENSION = "x-zod-nest-dto";
31
+ var lineageMap = /* @__PURE__ */ new WeakMap();
32
+ var propsMap = /* @__PURE__ */ new WeakMap();
33
+ var OPTIONAL_WRAPPER_TYPES = /* @__PURE__ */ new Set(["optional", "default"]);
34
+ var isOptionalProp = (propSchema) => OPTIONAL_WRAPPER_TYPES.has(propSchema._zod.def.type);
35
+ var computeShapeKeys = (schema) => {
36
+ const { shape } = schema;
37
+ const properties = Object.keys(shape);
38
+ const required = properties.filter((key) => {
39
+ const propSchema = shape[key];
40
+ return propSchema !== void 0 && !isOptionalProp(propSchema);
41
+ });
42
+ return { properties, required };
43
+ };
44
+ var extend = (parent, build) => {
45
+ const result = build(parent);
46
+ lineageMap.set(result, { op: "extend", parent });
47
+ if (!propsMap.has(parent)) {
48
+ propsMap.set(parent, computeShapeKeys(parent));
49
+ }
50
+ return result;
51
+ };
52
+ var getLineage = (schema) => lineageMap.get(schema);
53
+ var DEFAULT_BUILD_REF = (id) => `${DEFS_PREFIX}${id}`;
54
+ var createCompositionOverride = (opts) => {
55
+ const { buildRef } = opts;
56
+ return (ctx) => {
57
+ const { jsonSchema, zodSchema } = ctx;
58
+ const entry = lineageMap.get(zodSchema);
59
+ if (entry === void 0) {
60
+ return;
61
+ }
62
+ const parentCache = propsMap.get(entry.parent);
63
+ if (parentCache === void 0) {
64
+ return;
65
+ }
66
+ const parentId = zod.z.globalRegistry.get(entry.parent)?.id;
67
+ if (parentId === void 0) {
68
+ return;
69
+ }
70
+ const childProps = jsonSchema.properties ?? {};
71
+ const childRequired = jsonSchema.required ?? [];
72
+ const parentPropSet = new Set(parentCache.properties);
73
+ const parentReqSet = new Set(parentCache.required);
74
+ const deltaProps = {};
75
+ for (const [key, value] of Object.entries(childProps)) {
76
+ if (parentPropSet.has(key)) {
77
+ continue;
78
+ }
79
+ deltaProps[key] = value;
80
+ }
81
+ const deltaRequired = childRequired.filter((key) => !parentReqSet.has(key));
82
+ const delta = { type: "object", properties: deltaProps };
83
+ if (deltaRequired.length > 0) {
84
+ delta.required = deltaRequired;
85
+ }
86
+ delete jsonSchema.type;
87
+ delete jsonSchema.properties;
88
+ delete jsonSchema.required;
89
+ delete jsonSchema.additionalProperties;
90
+ jsonSchema.allOf = [{ $ref: buildRef(parentId) }, delta];
91
+ jsonSchema.unevaluatedProperties = false;
92
+ };
93
+ };
30
94
 
31
95
  // src/schema/errors.ts
32
96
  var ZodNestError = class extends Error {
@@ -55,7 +119,7 @@ var formatPath = (path) => {
55
119
  };
56
120
 
57
121
  // src/schema/override.ts
58
- var builtInOverride = ({ zodSchema, jsonSchema }) => {
122
+ var primitiveOverride = ({ zodSchema, jsonSchema }) => {
59
123
  const type = zodSchema._zod.def.type;
60
124
  if (type === "bigint") {
61
125
  jsonSchema.type = "integer";
@@ -104,7 +168,6 @@ var combine = (...overrides) => {
104
168
  };
105
169
 
106
170
  // src/schema/post-process.ts
107
- var DEFS_PREFIX = "#/$defs/";
108
171
  var rewriteRefs = (node, selfRef) => {
109
172
  if (Array.isArray(node)) {
110
173
  for (const item of node) {
@@ -147,7 +210,10 @@ var postProcess = (raw) => {
147
210
  // src/schema/engine.ts
148
211
  var buildToJsonSchemaOptions = (params) => {
149
212
  const strict = params.strict ?? true;
150
- const merged = combine(builtInOverride, params.override);
213
+ const compositionOverride = createCompositionOverride({
214
+ buildRef: params.uri ?? DEFAULT_BUILD_REF
215
+ });
216
+ const merged = combine(primitiveOverride, compositionOverride, params.override);
151
217
  const unrepresentableHits = [];
152
218
  const wrapped = (ctx) => {
153
219
  merged(ctx);
@@ -752,21 +818,33 @@ var runPass = (opts, io, knownIds) => {
752
818
  io,
753
819
  override: opts.override,
754
820
  strict: opts.strict,
755
- reused: "ref",
821
+ reused: "inline",
756
822
  uri: URI
757
823
  });
758
824
  const raw = zod.z.toJSONSchema(opts.registry.zodRegistry, built.options);
759
825
  built.consumeUnrepresentable();
760
826
  const filtered = /* @__PURE__ */ new Map();
761
- const schemas = raw.schemas ?? {};
762
827
  for (const id of knownIds) {
763
- if (Object.prototype.hasOwnProperty.call(schemas, id)) {
764
- filtered.set(id, schemas[id]);
828
+ if (Object.prototype.hasOwnProperty.call(raw.schemas, id)) {
829
+ filtered.set(id, raw.schemas[id]);
765
830
  }
766
831
  }
767
832
  return filtered;
768
833
  };
769
- var REF_PREFIX = "#/components/schemas/";
834
+
835
+ // src/document/http-methods.ts
836
+ var HTTP_METHODS = [
837
+ "get",
838
+ "put",
839
+ "post",
840
+ "delete",
841
+ "options",
842
+ "head",
843
+ "patch",
844
+ "trace"
845
+ ];
846
+
847
+ // src/document/collect-usage.ts
770
848
  var collectUsage = (doc, app) => {
771
849
  const classToDtoId = buildClassToDtoIdMap(doc);
772
850
  const inputExposedIds = collectInputExposedIds(doc, classToDtoId);
@@ -812,16 +890,6 @@ var collectInputExposedIds = (doc, classToDtoId) => {
812
890
  }
813
891
  return ids;
814
892
  };
815
- var HTTP_METHODS = [
816
- "get",
817
- "put",
818
- "post",
819
- "delete",
820
- "options",
821
- "head",
822
- "patch",
823
- "trace"
824
- ];
825
893
  var operationsOf = (pathItem) => {
826
894
  const out = [];
827
895
  for (const method of HTTP_METHODS) {
@@ -865,10 +933,10 @@ var collectRefFromSchema = (schema, classToDtoId, ids) => {
865
933
  return;
866
934
  }
867
935
  const ref = schema.$ref;
868
- if (typeof ref !== "string" || !ref.startsWith(REF_PREFIX)) {
936
+ if (typeof ref !== "string" || !ref.startsWith(COMPONENTS_SCHEMAS_PREFIX)) {
869
937
  return;
870
938
  }
871
- const className = ref.slice(REF_PREFIX.length);
939
+ const className = ref.slice(COMPONENTS_SCHEMAS_PREFIX.length);
872
940
  const dtoId = classToDtoId.get(className);
873
941
  if (dtoId !== void 0) {
874
942
  ids.add(dtoId);
@@ -883,9 +951,6 @@ var collectOutputExposedIds = (app) => {
883
951
  continue;
884
952
  }
885
953
  const proto = Object.getPrototypeOf(instance);
886
- if (proto === null) {
887
- continue;
888
- }
889
954
  for (const methodName of Object.getOwnPropertyNames(proto)) {
890
955
  if (methodName === "constructor") {
891
956
  continue;
@@ -957,15 +1022,14 @@ var walkRefs = (node, visit) => {
957
1022
  };
958
1023
 
959
1024
  // src/document/dangling-refs.ts
960
- var SCHEMA_PREFIX = "#/components/schemas/";
961
1025
  var assertNoDanglingRefs = (doc) => {
962
1026
  const schemas = doc.components?.schemas ?? {};
963
1027
  const dangling = [];
964
1028
  walkRefs(doc, (ref) => {
965
- if (!ref.startsWith(SCHEMA_PREFIX)) {
1029
+ if (!ref.startsWith(COMPONENTS_SCHEMAS_PREFIX)) {
966
1030
  return void 0;
967
1031
  }
968
- const target = ref.slice(SCHEMA_PREFIX.length);
1032
+ const target = ref.slice(COMPONENTS_SCHEMAS_PREFIX.length);
969
1033
  if (!(target in schemas)) {
970
1034
  dangling.push(ref);
971
1035
  }
@@ -1055,7 +1119,8 @@ var isMarkerPlaceholder = (value) => {
1055
1119
  if (properties === null || typeof properties !== "object") {
1056
1120
  return false;
1057
1121
  }
1058
- return "x-zod-nest-dto" in properties;
1122
+ const marker = properties[ZOD_NEST_DTO_EXTENSION];
1123
+ return isZodDtoMarker(marker);
1059
1124
  };
1060
1125
  var canonicalEqual = (a, b) => {
1061
1126
  if (a === b) {
@@ -1085,31 +1150,20 @@ var decorateIfPresent = (schemas, key) => {
1085
1150
  };
1086
1151
 
1087
1152
  // src/document/rewrite-refs.ts
1088
- var SCHEMA_PREFIX2 = "#/components/schemas/";
1089
1153
  var OUTPUT_SUFFIX2 = "Output";
1090
- var HTTP_METHODS2 = [
1091
- "get",
1092
- "put",
1093
- "post",
1094
- "delete",
1095
- "options",
1096
- "head",
1097
- "patch",
1098
- "trace"
1099
- ];
1100
1154
  var rewriteRefs2 = (params) => {
1101
1155
  const { doc, renames, divergentOutputIds } = params;
1102
1156
  if (renames.size > 0) {
1103
1157
  walkRefs(doc, (ref) => {
1104
- if (!ref.startsWith(SCHEMA_PREFIX2)) {
1158
+ if (!ref.startsWith(COMPONENTS_SCHEMAS_PREFIX)) {
1105
1159
  return void 0;
1106
1160
  }
1107
- const target = ref.slice(SCHEMA_PREFIX2.length);
1161
+ const target = ref.slice(COMPONENTS_SCHEMAS_PREFIX.length);
1108
1162
  const renamed = renames.get(target);
1109
1163
  if (renamed === void 0) {
1110
1164
  return void 0;
1111
1165
  }
1112
- return `${SCHEMA_PREFIX2}${renamed}`;
1166
+ return `${COMPONENTS_SCHEMAS_PREFIX}${renamed}`;
1113
1167
  });
1114
1168
  }
1115
1169
  if (divergentOutputIds.size === 0) {
@@ -1124,7 +1178,7 @@ var rewriteRefs2 = (params) => {
1124
1178
  }
1125
1179
  };
1126
1180
  var rewriteResponseSubtree = (pathItem, divergentOutputIds) => {
1127
- for (const method of HTTP_METHODS2) {
1181
+ for (const method of HTTP_METHODS) {
1128
1182
  const op = pathItem[method];
1129
1183
  if (op === null || typeof op !== "object") {
1130
1184
  continue;
@@ -1134,14 +1188,14 @@ var rewriteResponseSubtree = (pathItem, divergentOutputIds) => {
1134
1188
  continue;
1135
1189
  }
1136
1190
  walkRefs(responses, (ref) => {
1137
- if (!ref.startsWith(SCHEMA_PREFIX2)) {
1191
+ if (!ref.startsWith(COMPONENTS_SCHEMAS_PREFIX)) {
1138
1192
  return void 0;
1139
1193
  }
1140
- const target = ref.slice(SCHEMA_PREFIX2.length);
1194
+ const target = ref.slice(COMPONENTS_SCHEMAS_PREFIX.length);
1141
1195
  if (!divergentOutputIds.has(target)) {
1142
1196
  return void 0;
1143
1197
  }
1144
- return `${SCHEMA_PREFIX2}${target}${OUTPUT_SUFFIX2}`;
1198
+ return `${COMPONENTS_SCHEMAS_PREFIX}${target}${OUTPUT_SUFFIX2}`;
1145
1199
  });
1146
1200
  }
1147
1201
  };
@@ -1217,6 +1271,8 @@ exports.createRegistry = createRegistry;
1217
1271
  exports.createZodDto = createZodDto;
1218
1272
  exports.defaultRegistry = defaultRegistry;
1219
1273
  exports.defaultStatusFor = defaultStatusFor;
1274
+ exports.extend = extend;
1275
+ exports.getLineage = getLineage;
1220
1276
  exports.isZodDto = isZodDto;
1221
1277
  exports.isZodDtoMarker = isZodDtoMarker;
1222
1278
  exports.makeZodDtoMarker = makeZodDtoMarker;