zod-nest 1.5.0 → 1.5.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/helpers/index.js +7 -1
- package/dist/helpers/index.js.map +1 -1
- package/dist/helpers/index.mjs +7 -1
- package/dist/helpers/index.mjs.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/helpers/index.js
CHANGED
|
@@ -87,10 +87,16 @@ var opaque = /* @__PURE__ */ __name((opts) => ({
|
|
|
87
87
|
var customOverrideMap = /* @__PURE__ */ new WeakMap();
|
|
88
88
|
var isWrapper = /* @__PURE__ */ __name((arg) => "input" in arg || "output" in arg, "isWrapper");
|
|
89
89
|
var overrideJSONSchema = /* @__PURE__ */ __name((schema, arg) => {
|
|
90
|
-
const overrideSchema = isWrapper(arg) ?
|
|
90
|
+
const overrideSchema = isWrapper(arg) ? {
|
|
91
|
+
...arg
|
|
92
|
+
} : {
|
|
91
93
|
input: arg,
|
|
92
94
|
output: arg
|
|
93
95
|
};
|
|
96
|
+
const schemaDescription = schema.description;
|
|
97
|
+
if (typeof schemaDescription === "string") {
|
|
98
|
+
overrideSchema.description = schemaDescription;
|
|
99
|
+
}
|
|
94
100
|
customOverrideMap.set(schema, overrideSchema);
|
|
95
101
|
return schema;
|
|
96
102
|
}, "overrideJSONSchema");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/helpers/fragments.ts","../../src/schema/custom-override.ts","../../src/helpers/presets.ts"],"names":["dateTimeFragment","type","format","dateFragment","timeFragment","uuidFragment","emailFragment","uriFragment","hostnameFragment","ipv4Fragment","ipv6Fragment","binaryFragment","byteFragment","int32Fragment","int64Fragment","floatFragment","doubleFragment","opaqueFragment","additionalProperties","enrich","base","extras","binary","opts","opaque","customOverrideMap","WeakMap","isWrapper","arg","overrideJSONSchema","schema","overrideSchema","input","output","set","FileSchema","z","instanceof","File","BlobSchema","Blob","BufferSchema","Buffer"],"mappings":"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","file":"index.js","sourcesContent":["import type { SchemaObject } from '../schema/openapi.types.js';\n\n/**\n * Common JSON Schema fragment catalog — reusable building blocks for assembling\n * fragments by hand: alongside `z.custom<T>()`, in `overrideJSONSchema` calls,\n * in custom override callbacks, in tests that build expected fragments.\n *\n * The catalog overlaps with what Zod constructs already emit (`z.uuid()` →\n * `uuidFragment` shape, `z.email()` → `emailFragment` shape, etc.) — the\n * helpers don't *replace* those Zod constructs; they're a parallel catalog\n * for programmatic fragment assembly.\n *\n * Each fragment is `as const satisfies SchemaObject` so its literal type\n * powers the dispatch in {@link enrich} — passing wrong-family options\n * fails at compile time.\n */\n\n// ---------------------------------------------------------------------------\n// Layer 1 — Fragment catalog\n// ---------------------------------------------------------------------------\n\n// String formats (RFC-defined)\nexport const dateTimeFragment = {\n type: 'string',\n format: 'date-time',\n} as const satisfies SchemaObject;\nexport const dateFragment = { type: 'string', format: 'date' } as const satisfies SchemaObject;\nexport const timeFragment = { type: 'string', format: 'time' } as const satisfies SchemaObject;\nexport const uuidFragment = { type: 'string', format: 'uuid' } as const satisfies SchemaObject;\nexport const emailFragment = { type: 'string', format: 'email' } as const satisfies SchemaObject;\nexport const uriFragment = { type: 'string', format: 'uri' } as const satisfies SchemaObject;\nexport const hostnameFragment = {\n type: 'string',\n format: 'hostname',\n} as const satisfies SchemaObject;\nexport const ipv4Fragment = { type: 'string', format: 'ipv4' } as const satisfies SchemaObject;\nexport const ipv6Fragment = { type: 'string', format: 'ipv6' } as const satisfies SchemaObject;\n\n// Binary / encoded payloads\nexport const binaryFragment = { type: 'string', format: 'binary' } as const satisfies SchemaObject;\nexport const byteFragment = { type: 'string', format: 'byte' } as const satisfies SchemaObject;\n\n// Numeric formats (OpenAPI 3.1)\nexport const int32Fragment = { type: 'integer', format: 'int32' } as const satisfies SchemaObject;\nexport const int64Fragment = { type: 'integer', format: 'int64' } as const satisfies SchemaObject;\nexport const floatFragment = { type: 'number', format: 'float' } as const satisfies SchemaObject;\nexport const doubleFragment = { type: 'number', format: 'double' } as const satisfies SchemaObject;\n\n// Object passthrough\nexport const opaqueFragment = {\n type: 'object',\n additionalProperties: true,\n} as const satisfies SchemaObject;\n\n// ---------------------------------------------------------------------------\n// Layer 2 — Per-family option types\n// ---------------------------------------------------------------------------\n\nexport interface StringFormatOptions {\n description?: string;\n examples?: string[];\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n}\n\nexport interface BinaryFragmentOptions {\n description?: string;\n contentMediaType?: string;\n contentEncoding?: string;\n}\n\nexport interface NumberFormatOptions {\n description?: string;\n examples?: number[];\n minimum?: number;\n maximum?: number;\n exclusiveMinimum?: number;\n exclusiveMaximum?: number;\n multipleOf?: number;\n}\n\nexport interface OpaqueFragmentOptions {\n description?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Layer 3 — Type-strict generic enrich\n// ---------------------------------------------------------------------------\n\n// `binary` discriminates before the generic string-format branch because its\n// option set diverges (contentMediaType / contentEncoding instead of length\n// constraints). Order matters here.\ntype OptionsFor<T> = T extends { readonly format: 'binary' }\n ? BinaryFragmentOptions\n : T extends {\n readonly format:\n | 'date-time'\n | 'date'\n | 'time'\n | 'uuid'\n | 'email'\n | 'uri'\n | 'hostname'\n | 'ipv4'\n | 'ipv6'\n | 'byte';\n }\n ? StringFormatOptions\n : T extends { readonly format: 'int32' | 'int64' | 'float' | 'double' }\n ? NumberFormatOptions\n : T extends { readonly type: 'object'; readonly additionalProperties: true }\n ? OpaqueFragmentOptions\n : never;\n\n/**\n * Merge a catalog fragment with extras whose shape is dictated by the base\n * fragment's family. Passing wrong-family extras (e.g. a `contentMediaType`\n * onto `uuidFragment`) is a compile-time error.\n *\n * Returns a fresh `SchemaObject` — the original fragment is never mutated.\n */\nexport const enrich = <T extends SchemaObject>(base: T, extras: OptionsFor<T>): SchemaObject => ({\n ...base,\n ...extras,\n});\n\n// ---------------------------------------------------------------------------\n// Layer 3b — Sugar functions\n// ---------------------------------------------------------------------------\n\n/**\n * Binary-content fragment with typed enrichment. Sugar for\n * `enrich(binaryFragment, opts)` — exists because the `binary` option set\n * (`contentMediaType` / `contentEncoding`) is nuanced enough to deserve a\n * dedicated entry point and discoverable via auto-complete.\n *\n * @example\n * overrideJSONSchema(z.instanceof(File), binary());\n * overrideJSONSchema(z.instanceof(File), binary({ contentMediaType: 'application/pdf' }));\n */\nexport const binary = (opts?: BinaryFragmentOptions): SchemaObject => ({\n ...binaryFragment,\n ...opts,\n});\n\n/**\n * Opaque-object fragment with typed enrichment. Sugar for\n * `enrich(opaqueFragment, opts)` — exists for parity with {@link binary}\n * and because opaque passthrough payloads commonly carry a description\n * explaining why the API doesn't introspect them.\n *\n * @example\n * overrideJSONSchema(z.unknown(), opaque({ description: 'JWT passthrough' }));\n */\nexport const opaque = (opts?: OpaqueFragmentOptions): SchemaObject => ({\n ...opaqueFragment,\n ...opts,\n});\n","import type { z } from 'zod';\nimport type { $ZodType } from 'zod/v4/core';\nimport type { SchemaObject } from './openapi.types.js';\nimport type { Override } from './override.js';\n\n/**\n * Argument shape for {@link overrideJSONSchema}. Two forms:\n *\n * - A raw `SchemaObject` — applied to both input and output emission.\n * - A `{ input?, output? }` wrapper — distinct fragments per emission side,\n * for coercion shapes where input and output diverge (e.g.\n * `z.union([z.array(item), item.transform((v) => [v])])` accepts\n * `T | T[]` on input but always emits `T[]` on output).\n *\n * The wrapper form is detected by the presence of an `input` or `output`\n * key. Neither is a JSON Schema / OpenAPI 3.1 keyword, so the discriminator\n * is unambiguous in practice.\n */\nexport type OverrideJSONSchemaArg = SchemaObject | { input?: SchemaObject; output?: SchemaObject };\n\nexport interface StoredFragments {\n input?: SchemaObject;\n output?: SchemaObject;\n}\n\n/**\n * Per-instance JSON Schema registration store. Keyed by the Zod core type\n * (`$ZodType`) because that's what the override sees on `ctx.zodSchema`;\n * `z.ZodType` widens to `$ZodType` without a cast at the public API boundary.\n * Same WeakMap pattern as `composition.ts`'s `lineageMap`\n * (CLAUDE.md: \"transient, per-instance → WeakMap\").\n *\n * Value holds the per-direction fragments separately so the override factory\n * can pick the right one without surfacing `io` on `OverrideContext`.\n */\nconst customOverrideMap = new WeakMap<$ZodType, StoredFragments>();\n\nconst isWrapper = (\n arg: OverrideJSONSchemaArg,\n): arg is { input?: SchemaObject; output?: SchemaObject } => 'input' in arg || 'output' in arg;\n\n/**\n * Register a fixed JSON Schema fragment for a specific Zod schema instance.\n *\n * Designed for shapes JSON Schema can't model directly — `z.custom<T>()` and\n * `z.instanceof(...)` (e.g. multipart `File` fields) — which Zod emits as `{}`,\n * tripping `ZodNestUnrepresentableError` in strict mode. Also useful for\n * coercion shapes where input and output diverge (`singleOrArray`-style\n * helpers).\n *\n * Two call shapes:\n *\n * ```ts\n * // 1. Single fragment — applied verbatim to both input and output emission.\n * overrideJSONSchema(FileSchema, { type: 'string', format: 'binary' });\n *\n * // 2. Divergent fragments — separate fragments per emission side. Omit a\n * // side to leave Zod's default emission untouched on that side.\n * overrideJSONSchema(arrayOrItem, {\n * input: { anyOf: [arrFrag, itemFrag] },\n * output: arrFrag,\n * });\n * ```\n *\n * Idempotent: subsequent calls for the same schema overwrite the prior\n * registration (last-write-wins).\n */\nexport const overrideJSONSchema = <T extends z.ZodType>(\n schema: T,\n arg: OverrideJSONSchemaArg,\n): T => {\n const overrideSchema = isWrapper(arg) ? arg : { input: arg, output: arg };\n\n customOverrideMap.set(schema, overrideSchema);\n\n return schema;\n};\n\n/**\n * Read-only lookup into the registration store. Used by the engine to detect\n * when a pipe-typed schema covers its inner descent target with a relevant-io\n * fragment — see `buildToJsonSchemaOptions` in `engine.ts`. Returning a\n * possibly-`undefined` `StoredFragments` keeps the engine ignorant of the\n * underlying WeakMap.\n */\nexport const peekRegistration = (schema: $ZodType): StoredFragments | undefined =>\n customOverrideMap.get(schema);\n\n/**\n * Internal override factory consulted by the engine. Closes over the current\n * emission direction so the lookup can pick the right registered fragment\n * without surfacing `io` on the `OverrideContext` public contract. Mirrors\n * `createCompositionOverride` at `engine.ts:98`.\n *\n * Mutates `ctx.jsonSchema` in-place (clears existing keys, then assigns the\n * fragment) because Zod's override pipeline doesn't propagate\n * `ctx.jsonSchema = newObj` reassignments — only mutations on the existing\n * object reach the caller (see `composition.ts` for the same constraint).\n *\n * No-ops if the schema isn't registered, or if the registered record has no\n * fragment for the current `io` direction.\n */\nexport const createCustomOverride = (io: 'input' | 'output'): Override => {\n return ({ zodSchema, jsonSchema }) => {\n const record = customOverrideMap.get(zodSchema);\n if (record === undefined) {\n return;\n }\n const fragment = record[io];\n if (fragment === undefined) {\n return;\n }\n for (const key of Object.keys(jsonSchema)) {\n Reflect.deleteProperty(jsonSchema, key);\n }\n Object.assign(jsonSchema, fragment);\n };\n};\n","import { z } from 'zod';\n\nimport { overrideJSONSchema } from '../schema/custom-override.js';\nimport { binaryFragment } from './fragments.js';\n\n/**\n * Pre-registered Zod schemas for the common binary runtime types. Each\n * schema is wired through `overrideJSONSchema` so it emits `binaryFragment`\n * verbatim in OpenAPI — drop into a DTO without further setup.\n *\n * Node 22+ provides `File`, `Blob`, and `Buffer` as globals (zod-nest's\n * `engines.node >=22`), so `z.instanceof(...)` at module load is safe.\n *\n * @example\n * import { FileSchema } from 'zod-nest/helpers';\n *\n * class UploadDto extends createZodDto(\n * z.object({ file: FileSchema }),\n * ) {}\n */\n\nexport const FileSchema = overrideJSONSchema(z.instanceof(File), binaryFragment);\n\nexport const BlobSchema = overrideJSONSchema(z.instanceof(Blob), binaryFragment);\n\nexport const BufferSchema = overrideJSONSchema(z.instanceof(Buffer), binaryFragment);\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/helpers/fragments.ts","../../src/schema/custom-override.ts","../../src/helpers/presets.ts"],"names":["dateTimeFragment","type","format","dateFragment","timeFragment","uuidFragment","emailFragment","uriFragment","hostnameFragment","ipv4Fragment","ipv6Fragment","binaryFragment","byteFragment","int32Fragment","int64Fragment","floatFragment","doubleFragment","opaqueFragment","additionalProperties","enrich","base","extras","binary","opts","opaque","customOverrideMap","WeakMap","isWrapper","arg","overrideJSONSchema","schema","overrideSchema","input","output","schemaDescription","description","set","FileSchema","z","instanceof","File","BlobSchema","Blob","BufferSchema","Buffer"],"mappings":"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","file":"index.js","sourcesContent":["import type { SchemaObject } from '../schema/openapi.types.js';\n\n/**\n * Common JSON Schema fragment catalog — reusable building blocks for assembling\n * fragments by hand: alongside `z.custom<T>()`, in `overrideJSONSchema` calls,\n * in custom override callbacks, in tests that build expected fragments.\n *\n * The catalog overlaps with what Zod constructs already emit (`z.uuid()` →\n * `uuidFragment` shape, `z.email()` → `emailFragment` shape, etc.) — the\n * helpers don't *replace* those Zod constructs; they're a parallel catalog\n * for programmatic fragment assembly.\n *\n * Each fragment is `as const satisfies SchemaObject` so its literal type\n * powers the dispatch in {@link enrich} — passing wrong-family options\n * fails at compile time.\n */\n\n// ---------------------------------------------------------------------------\n// Layer 1 — Fragment catalog\n// ---------------------------------------------------------------------------\n\n// String formats (RFC-defined)\nexport const dateTimeFragment = {\n type: 'string',\n format: 'date-time',\n} as const satisfies SchemaObject;\nexport const dateFragment = { type: 'string', format: 'date' } as const satisfies SchemaObject;\nexport const timeFragment = { type: 'string', format: 'time' } as const satisfies SchemaObject;\nexport const uuidFragment = { type: 'string', format: 'uuid' } as const satisfies SchemaObject;\nexport const emailFragment = { type: 'string', format: 'email' } as const satisfies SchemaObject;\nexport const uriFragment = { type: 'string', format: 'uri' } as const satisfies SchemaObject;\nexport const hostnameFragment = {\n type: 'string',\n format: 'hostname',\n} as const satisfies SchemaObject;\nexport const ipv4Fragment = { type: 'string', format: 'ipv4' } as const satisfies SchemaObject;\nexport const ipv6Fragment = { type: 'string', format: 'ipv6' } as const satisfies SchemaObject;\n\n// Binary / encoded payloads\nexport const binaryFragment = { type: 'string', format: 'binary' } as const satisfies SchemaObject;\nexport const byteFragment = { type: 'string', format: 'byte' } as const satisfies SchemaObject;\n\n// Numeric formats (OpenAPI 3.1)\nexport const int32Fragment = { type: 'integer', format: 'int32' } as const satisfies SchemaObject;\nexport const int64Fragment = { type: 'integer', format: 'int64' } as const satisfies SchemaObject;\nexport const floatFragment = { type: 'number', format: 'float' } as const satisfies SchemaObject;\nexport const doubleFragment = { type: 'number', format: 'double' } as const satisfies SchemaObject;\n\n// Object passthrough\nexport const opaqueFragment = {\n type: 'object',\n additionalProperties: true,\n} as const satisfies SchemaObject;\n\n// ---------------------------------------------------------------------------\n// Layer 2 — Per-family option types\n// ---------------------------------------------------------------------------\n\nexport interface StringFormatOptions {\n description?: string;\n examples?: string[];\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n}\n\nexport interface BinaryFragmentOptions {\n description?: string;\n contentMediaType?: string;\n contentEncoding?: string;\n}\n\nexport interface NumberFormatOptions {\n description?: string;\n examples?: number[];\n minimum?: number;\n maximum?: number;\n exclusiveMinimum?: number;\n exclusiveMaximum?: number;\n multipleOf?: number;\n}\n\nexport interface OpaqueFragmentOptions {\n description?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Layer 3 — Type-strict generic enrich\n// ---------------------------------------------------------------------------\n\n// `binary` discriminates before the generic string-format branch because its\n// option set diverges (contentMediaType / contentEncoding instead of length\n// constraints). Order matters here.\ntype OptionsFor<T> = T extends { readonly format: 'binary' }\n ? BinaryFragmentOptions\n : T extends {\n readonly format:\n | 'date-time'\n | 'date'\n | 'time'\n | 'uuid'\n | 'email'\n | 'uri'\n | 'hostname'\n | 'ipv4'\n | 'ipv6'\n | 'byte';\n }\n ? StringFormatOptions\n : T extends { readonly format: 'int32' | 'int64' | 'float' | 'double' }\n ? NumberFormatOptions\n : T extends { readonly type: 'object'; readonly additionalProperties: true }\n ? OpaqueFragmentOptions\n : never;\n\n/**\n * Merge a catalog fragment with extras whose shape is dictated by the base\n * fragment's family. Passing wrong-family extras (e.g. a `contentMediaType`\n * onto `uuidFragment`) is a compile-time error.\n *\n * Returns a fresh `SchemaObject` — the original fragment is never mutated.\n */\nexport const enrich = <T extends SchemaObject>(base: T, extras: OptionsFor<T>): SchemaObject => ({\n ...base,\n ...extras,\n});\n\n// ---------------------------------------------------------------------------\n// Layer 3b — Sugar functions\n// ---------------------------------------------------------------------------\n\n/**\n * Binary-content fragment with typed enrichment. Sugar for\n * `enrich(binaryFragment, opts)` — exists because the `binary` option set\n * (`contentMediaType` / `contentEncoding`) is nuanced enough to deserve a\n * dedicated entry point and discoverable via auto-complete.\n *\n * @example\n * overrideJSONSchema(z.instanceof(File), binary());\n * overrideJSONSchema(z.instanceof(File), binary({ contentMediaType: 'application/pdf' }));\n */\nexport const binary = (opts?: BinaryFragmentOptions): SchemaObject => ({\n ...binaryFragment,\n ...opts,\n});\n\n/**\n * Opaque-object fragment with typed enrichment. Sugar for\n * `enrich(opaqueFragment, opts)` — exists for parity with {@link binary}\n * and because opaque passthrough payloads commonly carry a description\n * explaining why the API doesn't introspect them.\n *\n * @example\n * overrideJSONSchema(z.unknown(), opaque({ description: 'JWT passthrough' }));\n */\nexport const opaque = (opts?: OpaqueFragmentOptions): SchemaObject => ({\n ...opaqueFragment,\n ...opts,\n});\n","import type { z } from 'zod';\nimport type { $ZodType } from 'zod/v4/core';\nimport type { SchemaObject } from './openapi.types.js';\nimport type { Override } from './override.js';\n\n/**\n * Argument shape for {@link overrideJSONSchema}. Two forms:\n *\n * - A raw `SchemaObject` — applied to both input and output emission.\n * - A `{ input?, output? }` wrapper — distinct fragments per emission side,\n * for coercion shapes where input and output diverge (e.g.\n * `z.union([z.array(item), item.transform((v) => [v])])` accepts\n * `T | T[]` on input but always emits `T[]` on output).\n *\n * The wrapper form is detected by the presence of an `input` or `output`\n * key. Neither is a JSON Schema / OpenAPI 3.1 keyword, so the discriminator\n * is unambiguous in practice.\n */\nexport type OverrideJSONSchemaArg = SchemaObject | { input?: SchemaObject; output?: SchemaObject };\n\nexport interface StoredFragments {\n input?: SchemaObject;\n output?: SchemaObject;\n /**\n * Description captured from the Zod schema at `overrideJSONSchema(...)` call\n * time (`.describe(...)` / `.meta({ description })` both write to\n * `z.globalRegistry`). Applied as a fallback at emission time when the\n * per-direction fragment doesn't supply its own `description`. Fragment-\n * supplied descriptions still win.\n */\n description?: string;\n}\n\n/**\n * Per-instance JSON Schema registration store. Keyed by the Zod core type\n * (`$ZodType`) because that's what the override sees on `ctx.zodSchema`;\n * `z.ZodType` widens to `$ZodType` without a cast at the public API boundary.\n * Same WeakMap pattern as `composition.ts`'s `lineageMap`\n * (CLAUDE.md: \"transient, per-instance → WeakMap\").\n *\n * Value holds the per-direction fragments separately so the override factory\n * can pick the right one without surfacing `io` on `OverrideContext`.\n */\nconst customOverrideMap = new WeakMap<$ZodType, StoredFragments>();\n\nconst isWrapper = (\n arg: OverrideJSONSchemaArg,\n): arg is { input?: SchemaObject; output?: SchemaObject } => 'input' in arg || 'output' in arg;\n\n/**\n * Register a fixed JSON Schema fragment for a specific Zod schema instance.\n *\n * Designed for shapes JSON Schema can't model directly — `z.custom<T>()` and\n * `z.instanceof(...)` (e.g. multipart `File` fields) — which Zod emits as `{}`,\n * tripping `ZodNestUnrepresentableError` in strict mode. Also useful for\n * coercion shapes where input and output diverge (`singleOrArray`-style\n * helpers).\n *\n * Two call shapes:\n *\n * ```ts\n * // 1. Single fragment — applied verbatim to both input and output emission.\n * overrideJSONSchema(FileSchema, { type: 'string', format: 'binary' });\n *\n * // 2. Divergent fragments — separate fragments per emission side. Omit a\n * // side to leave Zod's default emission untouched on that side.\n * overrideJSONSchema(arrayOrItem, {\n * input: { anyOf: [arrFrag, itemFrag] },\n * output: arrFrag,\n * });\n * ```\n *\n * Idempotent: subsequent calls for the same schema overwrite the prior\n * registration (last-write-wins).\n */\nexport const overrideJSONSchema = <T extends z.ZodType>(\n schema: T,\n arg: OverrideJSONSchemaArg,\n): T => {\n const overrideSchema: StoredFragments = isWrapper(arg) ? { ...arg } : { input: arg, output: arg };\n\n const schemaDescription = schema.description;\n if (typeof schemaDescription === 'string') {\n overrideSchema.description = schemaDescription;\n }\n\n customOverrideMap.set(schema, overrideSchema);\n\n return schema;\n};\n\n/**\n * Read-only lookup into the registration store. Used by the engine to detect\n * when a pipe-typed schema covers its inner descent target with a relevant-io\n * fragment — see `buildToJsonSchemaOptions` in `engine.ts`. Returning a\n * possibly-`undefined` `StoredFragments` keeps the engine ignorant of the\n * underlying WeakMap.\n */\nexport const peekRegistration = (schema: $ZodType): StoredFragments | undefined =>\n customOverrideMap.get(schema);\n\n/**\n * Internal override factory consulted by the engine. Closes over the current\n * emission direction so the lookup can pick the right registered fragment\n * without surfacing `io` on the `OverrideContext` public contract. Mirrors\n * `createCompositionOverride` at `engine.ts:98`.\n *\n * Mutates `ctx.jsonSchema` in-place (clears existing keys, then assigns the\n * fragment) because Zod's override pipeline doesn't propagate\n * `ctx.jsonSchema = newObj` reassignments — only mutations on the existing\n * object reach the caller (see `composition.ts` for the same constraint).\n *\n * Falls back to the schema's captured `description` (from `.describe(...)` /\n * `.meta({ description })`) when the per-direction fragment doesn't supply\n * one. Captured at `overrideJSONSchema(...)` call time so the inheritance\n * doesn't depend on Zod's emission-time metadata pass. `title` is\n * deliberately not inherited.\n *\n * No-ops if the schema isn't registered, or if the registered record has no\n * fragment for the current `io` direction.\n */\nexport const createCustomOverride = (io: 'input' | 'output'): Override => {\n return ({ zodSchema, jsonSchema }) => {\n const record = customOverrideMap.get(zodSchema);\n if (record === undefined) {\n return;\n }\n const fragment = record[io];\n if (fragment === undefined) {\n return;\n }\n for (const key of Object.keys(jsonSchema)) {\n Reflect.deleteProperty(jsonSchema, key);\n }\n Object.assign(jsonSchema, fragment);\n if (fragment.description === undefined && record.description !== undefined) {\n jsonSchema.description = record.description;\n }\n };\n};\n","import { z } from 'zod';\n\nimport { overrideJSONSchema } from '../schema/custom-override.js';\nimport { binaryFragment } from './fragments.js';\n\n/**\n * Pre-registered Zod schemas for the common binary runtime types. Each\n * schema is wired through `overrideJSONSchema` so it emits `binaryFragment`\n * verbatim in OpenAPI — drop into a DTO without further setup.\n *\n * Node 22+ provides `File`, `Blob`, and `Buffer` as globals (zod-nest's\n * `engines.node >=22`), so `z.instanceof(...)` at module load is safe.\n *\n * @example\n * import { FileSchema } from 'zod-nest/helpers';\n *\n * class UploadDto extends createZodDto(\n * z.object({ file: FileSchema }),\n * ) {}\n */\n\nexport const FileSchema = overrideJSONSchema(z.instanceof(File), binaryFragment);\n\nexport const BlobSchema = overrideJSONSchema(z.instanceof(Blob), binaryFragment);\n\nexport const BufferSchema = overrideJSONSchema(z.instanceof(Buffer), binaryFragment);\n"]}
|
package/dist/helpers/index.mjs
CHANGED
|
@@ -85,10 +85,16 @@ var opaque = /* @__PURE__ */ __name((opts) => ({
|
|
|
85
85
|
var customOverrideMap = /* @__PURE__ */ new WeakMap();
|
|
86
86
|
var isWrapper = /* @__PURE__ */ __name((arg) => "input" in arg || "output" in arg, "isWrapper");
|
|
87
87
|
var overrideJSONSchema = /* @__PURE__ */ __name((schema, arg) => {
|
|
88
|
-
const overrideSchema = isWrapper(arg) ?
|
|
88
|
+
const overrideSchema = isWrapper(arg) ? {
|
|
89
|
+
...arg
|
|
90
|
+
} : {
|
|
89
91
|
input: arg,
|
|
90
92
|
output: arg
|
|
91
93
|
};
|
|
94
|
+
const schemaDescription = schema.description;
|
|
95
|
+
if (typeof schemaDescription === "string") {
|
|
96
|
+
overrideSchema.description = schemaDescription;
|
|
97
|
+
}
|
|
92
98
|
customOverrideMap.set(schema, overrideSchema);
|
|
93
99
|
return schema;
|
|
94
100
|
}, "overrideJSONSchema");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/helpers/fragments.ts","../../src/schema/custom-override.ts","../../src/helpers/presets.ts"],"names":["dateTimeFragment","type","format","dateFragment","timeFragment","uuidFragment","emailFragment","uriFragment","hostnameFragment","ipv4Fragment","ipv6Fragment","binaryFragment","byteFragment","int32Fragment","int64Fragment","floatFragment","doubleFragment","opaqueFragment","additionalProperties","enrich","base","extras","binary","opts","opaque","customOverrideMap","WeakMap","isWrapper","arg","overrideJSONSchema","schema","overrideSchema","input","output","set","FileSchema","z","instanceof","File","BlobSchema","Blob","BufferSchema","Buffer"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { SchemaObject } from '../schema/openapi.types.js';\n\n/**\n * Common JSON Schema fragment catalog — reusable building blocks for assembling\n * fragments by hand: alongside `z.custom<T>()`, in `overrideJSONSchema` calls,\n * in custom override callbacks, in tests that build expected fragments.\n *\n * The catalog overlaps with what Zod constructs already emit (`z.uuid()` →\n * `uuidFragment` shape, `z.email()` → `emailFragment` shape, etc.) — the\n * helpers don't *replace* those Zod constructs; they're a parallel catalog\n * for programmatic fragment assembly.\n *\n * Each fragment is `as const satisfies SchemaObject` so its literal type\n * powers the dispatch in {@link enrich} — passing wrong-family options\n * fails at compile time.\n */\n\n// ---------------------------------------------------------------------------\n// Layer 1 — Fragment catalog\n// ---------------------------------------------------------------------------\n\n// String formats (RFC-defined)\nexport const dateTimeFragment = {\n type: 'string',\n format: 'date-time',\n} as const satisfies SchemaObject;\nexport const dateFragment = { type: 'string', format: 'date' } as const satisfies SchemaObject;\nexport const timeFragment = { type: 'string', format: 'time' } as const satisfies SchemaObject;\nexport const uuidFragment = { type: 'string', format: 'uuid' } as const satisfies SchemaObject;\nexport const emailFragment = { type: 'string', format: 'email' } as const satisfies SchemaObject;\nexport const uriFragment = { type: 'string', format: 'uri' } as const satisfies SchemaObject;\nexport const hostnameFragment = {\n type: 'string',\n format: 'hostname',\n} as const satisfies SchemaObject;\nexport const ipv4Fragment = { type: 'string', format: 'ipv4' } as const satisfies SchemaObject;\nexport const ipv6Fragment = { type: 'string', format: 'ipv6' } as const satisfies SchemaObject;\n\n// Binary / encoded payloads\nexport const binaryFragment = { type: 'string', format: 'binary' } as const satisfies SchemaObject;\nexport const byteFragment = { type: 'string', format: 'byte' } as const satisfies SchemaObject;\n\n// Numeric formats (OpenAPI 3.1)\nexport const int32Fragment = { type: 'integer', format: 'int32' } as const satisfies SchemaObject;\nexport const int64Fragment = { type: 'integer', format: 'int64' } as const satisfies SchemaObject;\nexport const floatFragment = { type: 'number', format: 'float' } as const satisfies SchemaObject;\nexport const doubleFragment = { type: 'number', format: 'double' } as const satisfies SchemaObject;\n\n// Object passthrough\nexport const opaqueFragment = {\n type: 'object',\n additionalProperties: true,\n} as const satisfies SchemaObject;\n\n// ---------------------------------------------------------------------------\n// Layer 2 — Per-family option types\n// ---------------------------------------------------------------------------\n\nexport interface StringFormatOptions {\n description?: string;\n examples?: string[];\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n}\n\nexport interface BinaryFragmentOptions {\n description?: string;\n contentMediaType?: string;\n contentEncoding?: string;\n}\n\nexport interface NumberFormatOptions {\n description?: string;\n examples?: number[];\n minimum?: number;\n maximum?: number;\n exclusiveMinimum?: number;\n exclusiveMaximum?: number;\n multipleOf?: number;\n}\n\nexport interface OpaqueFragmentOptions {\n description?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Layer 3 — Type-strict generic enrich\n// ---------------------------------------------------------------------------\n\n// `binary` discriminates before the generic string-format branch because its\n// option set diverges (contentMediaType / contentEncoding instead of length\n// constraints). Order matters here.\ntype OptionsFor<T> = T extends { readonly format: 'binary' }\n ? BinaryFragmentOptions\n : T extends {\n readonly format:\n | 'date-time'\n | 'date'\n | 'time'\n | 'uuid'\n | 'email'\n | 'uri'\n | 'hostname'\n | 'ipv4'\n | 'ipv6'\n | 'byte';\n }\n ? StringFormatOptions\n : T extends { readonly format: 'int32' | 'int64' | 'float' | 'double' }\n ? NumberFormatOptions\n : T extends { readonly type: 'object'; readonly additionalProperties: true }\n ? OpaqueFragmentOptions\n : never;\n\n/**\n * Merge a catalog fragment with extras whose shape is dictated by the base\n * fragment's family. Passing wrong-family extras (e.g. a `contentMediaType`\n * onto `uuidFragment`) is a compile-time error.\n *\n * Returns a fresh `SchemaObject` — the original fragment is never mutated.\n */\nexport const enrich = <T extends SchemaObject>(base: T, extras: OptionsFor<T>): SchemaObject => ({\n ...base,\n ...extras,\n});\n\n// ---------------------------------------------------------------------------\n// Layer 3b — Sugar functions\n// ---------------------------------------------------------------------------\n\n/**\n * Binary-content fragment with typed enrichment. Sugar for\n * `enrich(binaryFragment, opts)` — exists because the `binary` option set\n * (`contentMediaType` / `contentEncoding`) is nuanced enough to deserve a\n * dedicated entry point and discoverable via auto-complete.\n *\n * @example\n * overrideJSONSchema(z.instanceof(File), binary());\n * overrideJSONSchema(z.instanceof(File), binary({ contentMediaType: 'application/pdf' }));\n */\nexport const binary = (opts?: BinaryFragmentOptions): SchemaObject => ({\n ...binaryFragment,\n ...opts,\n});\n\n/**\n * Opaque-object fragment with typed enrichment. Sugar for\n * `enrich(opaqueFragment, opts)` — exists for parity with {@link binary}\n * and because opaque passthrough payloads commonly carry a description\n * explaining why the API doesn't introspect them.\n *\n * @example\n * overrideJSONSchema(z.unknown(), opaque({ description: 'JWT passthrough' }));\n */\nexport const opaque = (opts?: OpaqueFragmentOptions): SchemaObject => ({\n ...opaqueFragment,\n ...opts,\n});\n","import type { z } from 'zod';\nimport type { $ZodType } from 'zod/v4/core';\nimport type { SchemaObject } from './openapi.types.js';\nimport type { Override } from './override.js';\n\n/**\n * Argument shape for {@link overrideJSONSchema}. Two forms:\n *\n * - A raw `SchemaObject` — applied to both input and output emission.\n * - A `{ input?, output? }` wrapper — distinct fragments per emission side,\n * for coercion shapes where input and output diverge (e.g.\n * `z.union([z.array(item), item.transform((v) => [v])])` accepts\n * `T | T[]` on input but always emits `T[]` on output).\n *\n * The wrapper form is detected by the presence of an `input` or `output`\n * key. Neither is a JSON Schema / OpenAPI 3.1 keyword, so the discriminator\n * is unambiguous in practice.\n */\nexport type OverrideJSONSchemaArg = SchemaObject | { input?: SchemaObject; output?: SchemaObject };\n\nexport interface StoredFragments {\n input?: SchemaObject;\n output?: SchemaObject;\n}\n\n/**\n * Per-instance JSON Schema registration store. Keyed by the Zod core type\n * (`$ZodType`) because that's what the override sees on `ctx.zodSchema`;\n * `z.ZodType` widens to `$ZodType` without a cast at the public API boundary.\n * Same WeakMap pattern as `composition.ts`'s `lineageMap`\n * (CLAUDE.md: \"transient, per-instance → WeakMap\").\n *\n * Value holds the per-direction fragments separately so the override factory\n * can pick the right one without surfacing `io` on `OverrideContext`.\n */\nconst customOverrideMap = new WeakMap<$ZodType, StoredFragments>();\n\nconst isWrapper = (\n arg: OverrideJSONSchemaArg,\n): arg is { input?: SchemaObject; output?: SchemaObject } => 'input' in arg || 'output' in arg;\n\n/**\n * Register a fixed JSON Schema fragment for a specific Zod schema instance.\n *\n * Designed for shapes JSON Schema can't model directly — `z.custom<T>()` and\n * `z.instanceof(...)` (e.g. multipart `File` fields) — which Zod emits as `{}`,\n * tripping `ZodNestUnrepresentableError` in strict mode. Also useful for\n * coercion shapes where input and output diverge (`singleOrArray`-style\n * helpers).\n *\n * Two call shapes:\n *\n * ```ts\n * // 1. Single fragment — applied verbatim to both input and output emission.\n * overrideJSONSchema(FileSchema, { type: 'string', format: 'binary' });\n *\n * // 2. Divergent fragments — separate fragments per emission side. Omit a\n * // side to leave Zod's default emission untouched on that side.\n * overrideJSONSchema(arrayOrItem, {\n * input: { anyOf: [arrFrag, itemFrag] },\n * output: arrFrag,\n * });\n * ```\n *\n * Idempotent: subsequent calls for the same schema overwrite the prior\n * registration (last-write-wins).\n */\nexport const overrideJSONSchema = <T extends z.ZodType>(\n schema: T,\n arg: OverrideJSONSchemaArg,\n): T => {\n const overrideSchema = isWrapper(arg) ? arg : { input: arg, output: arg };\n\n customOverrideMap.set(schema, overrideSchema);\n\n return schema;\n};\n\n/**\n * Read-only lookup into the registration store. Used by the engine to detect\n * when a pipe-typed schema covers its inner descent target with a relevant-io\n * fragment — see `buildToJsonSchemaOptions` in `engine.ts`. Returning a\n * possibly-`undefined` `StoredFragments` keeps the engine ignorant of the\n * underlying WeakMap.\n */\nexport const peekRegistration = (schema: $ZodType): StoredFragments | undefined =>\n customOverrideMap.get(schema);\n\n/**\n * Internal override factory consulted by the engine. Closes over the current\n * emission direction so the lookup can pick the right registered fragment\n * without surfacing `io` on the `OverrideContext` public contract. Mirrors\n * `createCompositionOverride` at `engine.ts:98`.\n *\n * Mutates `ctx.jsonSchema` in-place (clears existing keys, then assigns the\n * fragment) because Zod's override pipeline doesn't propagate\n * `ctx.jsonSchema = newObj` reassignments — only mutations on the existing\n * object reach the caller (see `composition.ts` for the same constraint).\n *\n * No-ops if the schema isn't registered, or if the registered record has no\n * fragment for the current `io` direction.\n */\nexport const createCustomOverride = (io: 'input' | 'output'): Override => {\n return ({ zodSchema, jsonSchema }) => {\n const record = customOverrideMap.get(zodSchema);\n if (record === undefined) {\n return;\n }\n const fragment = record[io];\n if (fragment === undefined) {\n return;\n }\n for (const key of Object.keys(jsonSchema)) {\n Reflect.deleteProperty(jsonSchema, key);\n }\n Object.assign(jsonSchema, fragment);\n };\n};\n","import { z } from 'zod';\n\nimport { overrideJSONSchema } from '../schema/custom-override.js';\nimport { binaryFragment } from './fragments.js';\n\n/**\n * Pre-registered Zod schemas for the common binary runtime types. Each\n * schema is wired through `overrideJSONSchema` so it emits `binaryFragment`\n * verbatim in OpenAPI — drop into a DTO without further setup.\n *\n * Node 22+ provides `File`, `Blob`, and `Buffer` as globals (zod-nest's\n * `engines.node >=22`), so `z.instanceof(...)` at module load is safe.\n *\n * @example\n * import { FileSchema } from 'zod-nest/helpers';\n *\n * class UploadDto extends createZodDto(\n * z.object({ file: FileSchema }),\n * ) {}\n */\n\nexport const FileSchema = overrideJSONSchema(z.instanceof(File), binaryFragment);\n\nexport const BlobSchema = overrideJSONSchema(z.instanceof(Blob), binaryFragment);\n\nexport const BufferSchema = overrideJSONSchema(z.instanceof(Buffer), binaryFragment);\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/helpers/fragments.ts","../../src/schema/custom-override.ts","../../src/helpers/presets.ts"],"names":["dateTimeFragment","type","format","dateFragment","timeFragment","uuidFragment","emailFragment","uriFragment","hostnameFragment","ipv4Fragment","ipv6Fragment","binaryFragment","byteFragment","int32Fragment","int64Fragment","floatFragment","doubleFragment","opaqueFragment","additionalProperties","enrich","base","extras","binary","opts","opaque","customOverrideMap","WeakMap","isWrapper","arg","overrideJSONSchema","schema","overrideSchema","input","output","schemaDescription","description","set","FileSchema","z","instanceof","File","BlobSchema","Blob","BufferSchema","Buffer"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { SchemaObject } from '../schema/openapi.types.js';\n\n/**\n * Common JSON Schema fragment catalog — reusable building blocks for assembling\n * fragments by hand: alongside `z.custom<T>()`, in `overrideJSONSchema` calls,\n * in custom override callbacks, in tests that build expected fragments.\n *\n * The catalog overlaps with what Zod constructs already emit (`z.uuid()` →\n * `uuidFragment` shape, `z.email()` → `emailFragment` shape, etc.) — the\n * helpers don't *replace* those Zod constructs; they're a parallel catalog\n * for programmatic fragment assembly.\n *\n * Each fragment is `as const satisfies SchemaObject` so its literal type\n * powers the dispatch in {@link enrich} — passing wrong-family options\n * fails at compile time.\n */\n\n// ---------------------------------------------------------------------------\n// Layer 1 — Fragment catalog\n// ---------------------------------------------------------------------------\n\n// String formats (RFC-defined)\nexport const dateTimeFragment = {\n type: 'string',\n format: 'date-time',\n} as const satisfies SchemaObject;\nexport const dateFragment = { type: 'string', format: 'date' } as const satisfies SchemaObject;\nexport const timeFragment = { type: 'string', format: 'time' } as const satisfies SchemaObject;\nexport const uuidFragment = { type: 'string', format: 'uuid' } as const satisfies SchemaObject;\nexport const emailFragment = { type: 'string', format: 'email' } as const satisfies SchemaObject;\nexport const uriFragment = { type: 'string', format: 'uri' } as const satisfies SchemaObject;\nexport const hostnameFragment = {\n type: 'string',\n format: 'hostname',\n} as const satisfies SchemaObject;\nexport const ipv4Fragment = { type: 'string', format: 'ipv4' } as const satisfies SchemaObject;\nexport const ipv6Fragment = { type: 'string', format: 'ipv6' } as const satisfies SchemaObject;\n\n// Binary / encoded payloads\nexport const binaryFragment = { type: 'string', format: 'binary' } as const satisfies SchemaObject;\nexport const byteFragment = { type: 'string', format: 'byte' } as const satisfies SchemaObject;\n\n// Numeric formats (OpenAPI 3.1)\nexport const int32Fragment = { type: 'integer', format: 'int32' } as const satisfies SchemaObject;\nexport const int64Fragment = { type: 'integer', format: 'int64' } as const satisfies SchemaObject;\nexport const floatFragment = { type: 'number', format: 'float' } as const satisfies SchemaObject;\nexport const doubleFragment = { type: 'number', format: 'double' } as const satisfies SchemaObject;\n\n// Object passthrough\nexport const opaqueFragment = {\n type: 'object',\n additionalProperties: true,\n} as const satisfies SchemaObject;\n\n// ---------------------------------------------------------------------------\n// Layer 2 — Per-family option types\n// ---------------------------------------------------------------------------\n\nexport interface StringFormatOptions {\n description?: string;\n examples?: string[];\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n}\n\nexport interface BinaryFragmentOptions {\n description?: string;\n contentMediaType?: string;\n contentEncoding?: string;\n}\n\nexport interface NumberFormatOptions {\n description?: string;\n examples?: number[];\n minimum?: number;\n maximum?: number;\n exclusiveMinimum?: number;\n exclusiveMaximum?: number;\n multipleOf?: number;\n}\n\nexport interface OpaqueFragmentOptions {\n description?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Layer 3 — Type-strict generic enrich\n// ---------------------------------------------------------------------------\n\n// `binary` discriminates before the generic string-format branch because its\n// option set diverges (contentMediaType / contentEncoding instead of length\n// constraints). Order matters here.\ntype OptionsFor<T> = T extends { readonly format: 'binary' }\n ? BinaryFragmentOptions\n : T extends {\n readonly format:\n | 'date-time'\n | 'date'\n | 'time'\n | 'uuid'\n | 'email'\n | 'uri'\n | 'hostname'\n | 'ipv4'\n | 'ipv6'\n | 'byte';\n }\n ? StringFormatOptions\n : T extends { readonly format: 'int32' | 'int64' | 'float' | 'double' }\n ? NumberFormatOptions\n : T extends { readonly type: 'object'; readonly additionalProperties: true }\n ? OpaqueFragmentOptions\n : never;\n\n/**\n * Merge a catalog fragment with extras whose shape is dictated by the base\n * fragment's family. Passing wrong-family extras (e.g. a `contentMediaType`\n * onto `uuidFragment`) is a compile-time error.\n *\n * Returns a fresh `SchemaObject` — the original fragment is never mutated.\n */\nexport const enrich = <T extends SchemaObject>(base: T, extras: OptionsFor<T>): SchemaObject => ({\n ...base,\n ...extras,\n});\n\n// ---------------------------------------------------------------------------\n// Layer 3b — Sugar functions\n// ---------------------------------------------------------------------------\n\n/**\n * Binary-content fragment with typed enrichment. Sugar for\n * `enrich(binaryFragment, opts)` — exists because the `binary` option set\n * (`contentMediaType` / `contentEncoding`) is nuanced enough to deserve a\n * dedicated entry point and discoverable via auto-complete.\n *\n * @example\n * overrideJSONSchema(z.instanceof(File), binary());\n * overrideJSONSchema(z.instanceof(File), binary({ contentMediaType: 'application/pdf' }));\n */\nexport const binary = (opts?: BinaryFragmentOptions): SchemaObject => ({\n ...binaryFragment,\n ...opts,\n});\n\n/**\n * Opaque-object fragment with typed enrichment. Sugar for\n * `enrich(opaqueFragment, opts)` — exists for parity with {@link binary}\n * and because opaque passthrough payloads commonly carry a description\n * explaining why the API doesn't introspect them.\n *\n * @example\n * overrideJSONSchema(z.unknown(), opaque({ description: 'JWT passthrough' }));\n */\nexport const opaque = (opts?: OpaqueFragmentOptions): SchemaObject => ({\n ...opaqueFragment,\n ...opts,\n});\n","import type { z } from 'zod';\nimport type { $ZodType } from 'zod/v4/core';\nimport type { SchemaObject } from './openapi.types.js';\nimport type { Override } from './override.js';\n\n/**\n * Argument shape for {@link overrideJSONSchema}. Two forms:\n *\n * - A raw `SchemaObject` — applied to both input and output emission.\n * - A `{ input?, output? }` wrapper — distinct fragments per emission side,\n * for coercion shapes where input and output diverge (e.g.\n * `z.union([z.array(item), item.transform((v) => [v])])` accepts\n * `T | T[]` on input but always emits `T[]` on output).\n *\n * The wrapper form is detected by the presence of an `input` or `output`\n * key. Neither is a JSON Schema / OpenAPI 3.1 keyword, so the discriminator\n * is unambiguous in practice.\n */\nexport type OverrideJSONSchemaArg = SchemaObject | { input?: SchemaObject; output?: SchemaObject };\n\nexport interface StoredFragments {\n input?: SchemaObject;\n output?: SchemaObject;\n /**\n * Description captured from the Zod schema at `overrideJSONSchema(...)` call\n * time (`.describe(...)` / `.meta({ description })` both write to\n * `z.globalRegistry`). Applied as a fallback at emission time when the\n * per-direction fragment doesn't supply its own `description`. Fragment-\n * supplied descriptions still win.\n */\n description?: string;\n}\n\n/**\n * Per-instance JSON Schema registration store. Keyed by the Zod core type\n * (`$ZodType`) because that's what the override sees on `ctx.zodSchema`;\n * `z.ZodType` widens to `$ZodType` without a cast at the public API boundary.\n * Same WeakMap pattern as `composition.ts`'s `lineageMap`\n * (CLAUDE.md: \"transient, per-instance → WeakMap\").\n *\n * Value holds the per-direction fragments separately so the override factory\n * can pick the right one without surfacing `io` on `OverrideContext`.\n */\nconst customOverrideMap = new WeakMap<$ZodType, StoredFragments>();\n\nconst isWrapper = (\n arg: OverrideJSONSchemaArg,\n): arg is { input?: SchemaObject; output?: SchemaObject } => 'input' in arg || 'output' in arg;\n\n/**\n * Register a fixed JSON Schema fragment for a specific Zod schema instance.\n *\n * Designed for shapes JSON Schema can't model directly — `z.custom<T>()` and\n * `z.instanceof(...)` (e.g. multipart `File` fields) — which Zod emits as `{}`,\n * tripping `ZodNestUnrepresentableError` in strict mode. Also useful for\n * coercion shapes where input and output diverge (`singleOrArray`-style\n * helpers).\n *\n * Two call shapes:\n *\n * ```ts\n * // 1. Single fragment — applied verbatim to both input and output emission.\n * overrideJSONSchema(FileSchema, { type: 'string', format: 'binary' });\n *\n * // 2. Divergent fragments — separate fragments per emission side. Omit a\n * // side to leave Zod's default emission untouched on that side.\n * overrideJSONSchema(arrayOrItem, {\n * input: { anyOf: [arrFrag, itemFrag] },\n * output: arrFrag,\n * });\n * ```\n *\n * Idempotent: subsequent calls for the same schema overwrite the prior\n * registration (last-write-wins).\n */\nexport const overrideJSONSchema = <T extends z.ZodType>(\n schema: T,\n arg: OverrideJSONSchemaArg,\n): T => {\n const overrideSchema: StoredFragments = isWrapper(arg) ? { ...arg } : { input: arg, output: arg };\n\n const schemaDescription = schema.description;\n if (typeof schemaDescription === 'string') {\n overrideSchema.description = schemaDescription;\n }\n\n customOverrideMap.set(schema, overrideSchema);\n\n return schema;\n};\n\n/**\n * Read-only lookup into the registration store. Used by the engine to detect\n * when a pipe-typed schema covers its inner descent target with a relevant-io\n * fragment — see `buildToJsonSchemaOptions` in `engine.ts`. Returning a\n * possibly-`undefined` `StoredFragments` keeps the engine ignorant of the\n * underlying WeakMap.\n */\nexport const peekRegistration = (schema: $ZodType): StoredFragments | undefined =>\n customOverrideMap.get(schema);\n\n/**\n * Internal override factory consulted by the engine. Closes over the current\n * emission direction so the lookup can pick the right registered fragment\n * without surfacing `io` on the `OverrideContext` public contract. Mirrors\n * `createCompositionOverride` at `engine.ts:98`.\n *\n * Mutates `ctx.jsonSchema` in-place (clears existing keys, then assigns the\n * fragment) because Zod's override pipeline doesn't propagate\n * `ctx.jsonSchema = newObj` reassignments — only mutations on the existing\n * object reach the caller (see `composition.ts` for the same constraint).\n *\n * Falls back to the schema's captured `description` (from `.describe(...)` /\n * `.meta({ description })`) when the per-direction fragment doesn't supply\n * one. Captured at `overrideJSONSchema(...)` call time so the inheritance\n * doesn't depend on Zod's emission-time metadata pass. `title` is\n * deliberately not inherited.\n *\n * No-ops if the schema isn't registered, or if the registered record has no\n * fragment for the current `io` direction.\n */\nexport const createCustomOverride = (io: 'input' | 'output'): Override => {\n return ({ zodSchema, jsonSchema }) => {\n const record = customOverrideMap.get(zodSchema);\n if (record === undefined) {\n return;\n }\n const fragment = record[io];\n if (fragment === undefined) {\n return;\n }\n for (const key of Object.keys(jsonSchema)) {\n Reflect.deleteProperty(jsonSchema, key);\n }\n Object.assign(jsonSchema, fragment);\n if (fragment.description === undefined && record.description !== undefined) {\n jsonSchema.description = record.description;\n }\n };\n};\n","import { z } from 'zod';\n\nimport { overrideJSONSchema } from '../schema/custom-override.js';\nimport { binaryFragment } from './fragments.js';\n\n/**\n * Pre-registered Zod schemas for the common binary runtime types. Each\n * schema is wired through `overrideJSONSchema` so it emits `binaryFragment`\n * verbatim in OpenAPI — drop into a DTO without further setup.\n *\n * Node 22+ provides `File`, `Blob`, and `Buffer` as globals (zod-nest's\n * `engines.node >=22`), so `z.instanceof(...)` at module load is safe.\n *\n * @example\n * import { FileSchema } from 'zod-nest/helpers';\n *\n * class UploadDto extends createZodDto(\n * z.object({ file: FileSchema }),\n * ) {}\n */\n\nexport const FileSchema = overrideJSONSchema(z.instanceof(File), binaryFragment);\n\nexport const BlobSchema = overrideJSONSchema(z.instanceof(Blob), binaryFragment);\n\nexport const BufferSchema = overrideJSONSchema(z.instanceof(Buffer), binaryFragment);\n"]}
|
package/dist/index.js
CHANGED
|
@@ -109,10 +109,16 @@ var createCompositionOverride = /* @__PURE__ */ __name((opts) => {
|
|
|
109
109
|
var customOverrideMap = /* @__PURE__ */ new WeakMap();
|
|
110
110
|
var isWrapper = /* @__PURE__ */ __name((arg) => "input" in arg || "output" in arg, "isWrapper");
|
|
111
111
|
var overrideJSONSchema = /* @__PURE__ */ __name((schema, arg) => {
|
|
112
|
-
const overrideSchema = isWrapper(arg) ?
|
|
112
|
+
const overrideSchema = isWrapper(arg) ? {
|
|
113
|
+
...arg
|
|
114
|
+
} : {
|
|
113
115
|
input: arg,
|
|
114
116
|
output: arg
|
|
115
117
|
};
|
|
118
|
+
const schemaDescription = schema.description;
|
|
119
|
+
if (typeof schemaDescription === "string") {
|
|
120
|
+
overrideSchema.description = schemaDescription;
|
|
121
|
+
}
|
|
116
122
|
customOverrideMap.set(schema, overrideSchema);
|
|
117
123
|
return schema;
|
|
118
124
|
}, "overrideJSONSchema");
|
|
@@ -131,6 +137,9 @@ var createCustomOverride = /* @__PURE__ */ __name((io) => {
|
|
|
131
137
|
Reflect.deleteProperty(jsonSchema, key);
|
|
132
138
|
}
|
|
133
139
|
Object.assign(jsonSchema, fragment);
|
|
140
|
+
if (fragment.description === void 0 && record.description !== void 0) {
|
|
141
|
+
jsonSchema.description = record.description;
|
|
142
|
+
}
|
|
134
143
|
};
|
|
135
144
|
}, "createCustomOverride");
|
|
136
145
|
|