@tstdl/base 0.93.55 → 0.93.57

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tstdl/base",
3
- "version": "0.93.55",
3
+ "version": "0.93.57",
4
4
  "author": "Patrick Hein",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -103,6 +103,7 @@
103
103
  "./schema/converters": "./schema/converters/index.js",
104
104
  "./schema/converters/open-api": "./schema/converters/open-api-converter.js",
105
105
  "./schema/converters/zod": "./schema/converters/zod-converter.js",
106
+ "./schema/converters/zod-v3": "./schema/converters/zod-v3-converter.js",
106
107
  "./serializer": "./serializer/index.js",
107
108
  "./serializer/handlers": "./serializer/handlers/index.js",
108
109
  "./signals": "./signals/index.js",
@@ -138,8 +138,7 @@ function convertToZodSchemaBase(schema, options) {
138
138
  // Zod nativeEnum or enum doesn't support numbers directly without hacks or native TS enums.
139
139
  // Use union of literals for mixed or number enums.
140
140
  if (isArray(s.enumeration) && s.enumeration.some((v) => isNumber(v))) {
141
- const types = s.allowedValues.map((value) => z.literal(value));
142
- return z.union(types);
141
+ return z.literal(s.allowedValues);
143
142
  }
144
143
  // enumeration is either EnumerationObject or string-only EnumerationArray, both is fine for z.enum
145
144
  // using `as`, as z.enum is overloaded and only one type per overload
@@ -212,7 +211,7 @@ function convertToZodSchemaBase(schema, options) {
212
211
  throw new NotSupportedError(`Schema "${schema.name}" cannot be converted to Zod schema.`);
213
212
  });
214
213
  if (isNotNull(schema.description)) {
215
- zodSchema = zodSchema.describe(schema.description);
214
+ zodSchema = zodSchema.meta({ description: schema.description });
216
215
  }
217
216
  return zodSchema;
218
217
  }
@@ -0,0 +1,10 @@
1
+ import { z, type ZodTypeDef } from 'zod/v3';
2
+ import type { SchemaTestable } from '../schema.js';
3
+ export type SchemaConversionOptions = {
4
+ /** Default coerce option if not specified in schema */
5
+ coerce?: boolean;
6
+ /** Default mask option if not specified in schema */
7
+ mask?: boolean;
8
+ };
9
+ /** WARNING: *DOES NOT* cover all schemas and options. Meant for usage in schema generators like genkit, not for full schema testing in APIs etc. */
10
+ export declare function convertToZodV3Schema<O, I = unknown>(testable: SchemaTestable<O>, options?: SchemaConversionOptions): z.ZodType<O, ZodTypeDef, I>;
@@ -0,0 +1,131 @@
1
+ import { match, P } from 'ts-pattern';
2
+ import { z } from 'zod/v3';
3
+ import { NotSupportedError } from '../../errors/not-supported.error.js';
4
+ import { objectEntries } from '../../utils/object/object.js';
5
+ import { isArray, isNotNull, isNumber } from '../../utils/type-guards.js';
6
+ import { any, AnySchema, ArraySchema, BigIntSchema, BooleanSchema, DateSchema, DefaultSchema, DeferredSchema, EnumerationSchema, InstanceSchema, LiteralSchema, NeverSchema, NullableSchema, NumberSchema, ObjectSchema, OneOrManySchema, OptionalSchema, ReadableStreamSchema, StringSchema, SymbolSchema, TransformSchema, UnionSchema, UnknownSchema } from '../schemas/index.js';
7
+ import { schemaTestableToSchema } from '../testable.js';
8
+ /** WARNING: *DOES NOT* cover all schemas and options. Meant for usage in schema generators like genkit, not for full schema testing in APIs etc. */
9
+ export function convertToZodV3Schema(testable, options) {
10
+ const schema = schemaTestableToSchema(testable);
11
+ return convertToZodSchemaBase(schema, options);
12
+ }
13
+ function convertToZodSchemaBase(schema, options) {
14
+ let zodSchema = match(schema)
15
+ .with(P.instanceOf(AnySchema), () => z.any())
16
+ .with(P.instanceOf(UnknownSchema), () => z.unknown())
17
+ .with(P.instanceOf(NeverSchema), () => z.never())
18
+ .with(P.instanceOf(NullableSchema), (s) => convertToZodSchemaBase(s.schema, options).nullable())
19
+ .with(P.instanceOf(OptionalSchema), (s) => convertToZodSchemaBase(s.schema, options).optional())
20
+ .with(P.instanceOf(OneOrManySchema), (s) => {
21
+ const innerSchema = convertToZodSchemaBase(s.schema, options);
22
+ return innerSchema.or(innerSchema.array());
23
+ })
24
+ .with(P.instanceOf(StringSchema), (s) => {
25
+ let zodSchema = (s.coerce ?? options?.coerce ?? false) ? z.coerce.string() : z.string();
26
+ if (isNumber(s.minimumLength)) {
27
+ zodSchema = zodSchema.min(s.minimumLength);
28
+ }
29
+ if (isNumber(s.maximumLength)) {
30
+ zodSchema = zodSchema.max(s.maximumLength);
31
+ }
32
+ if (isNotNull(s.pattern)) {
33
+ zodSchema = zodSchema.regex(s.pattern);
34
+ }
35
+ if (s.trim) {
36
+ zodSchema = zodSchema.trim();
37
+ }
38
+ if (s.lowercase) {
39
+ zodSchema = zodSchema.toLowerCase();
40
+ }
41
+ return zodSchema;
42
+ })
43
+ .with(P.instanceOf(NumberSchema), (s) => {
44
+ let zodSchema = (s.coerce ?? options?.coerce ?? false) ? z.coerce.number() : z.number();
45
+ if (s.integer) {
46
+ zodSchema = zodSchema.int();
47
+ }
48
+ if (isNumber(s.minimum)) {
49
+ zodSchema = zodSchema.gte(s.minimum);
50
+ }
51
+ if (isNumber(s.maximum)) {
52
+ zodSchema = zodSchema.lte(s.maximum);
53
+ }
54
+ return zodSchema;
55
+ })
56
+ .with(P.instanceOf(BooleanSchema), (s) => (s.coerce ?? options?.coerce ?? false) ? z.coerce.boolean() : z.boolean())
57
+ .with(P.instanceOf(BigIntSchema), (s) => (s.coerce ?? options?.coerce ?? false) ? z.coerce.bigint() : z.bigint())
58
+ .with(P.instanceOf(SymbolSchema), () => z.symbol())
59
+ .with(P.instanceOf(DateSchema), (s) => {
60
+ let zodSchema = (s.coerce ?? options?.coerce ?? false) ? z.coerce.date() : z.date();
61
+ if (isNotNull(s.minimum)) {
62
+ zodSchema = zodSchema.min(s.minimum);
63
+ }
64
+ if (isNotNull(s.maximum)) {
65
+ zodSchema = zodSchema.max(s.maximum);
66
+ }
67
+ return zodSchema;
68
+ })
69
+ .with(P.instanceOf(LiteralSchema), (s) => z.literal(s.value))
70
+ .with(P.instanceOf(ArraySchema), (s) => {
71
+ const itemSchema = convertToZodSchemaBase(s.itemSchema, options);
72
+ let zodSchema = z.array(itemSchema);
73
+ if (isNumber(s.minimum)) {
74
+ zodSchema = zodSchema.min(s.minimum);
75
+ }
76
+ if (isNumber(s.maximum)) {
77
+ zodSchema = zodSchema.max(s.maximum);
78
+ }
79
+ return zodSchema;
80
+ })
81
+ .with(P.instanceOf(ObjectSchema), (s) => {
82
+ const propertyEntries = objectEntries(s.properties);
83
+ // Handle generic records (no specific properties, but has unknownProperties/Key)
84
+ if ((propertyEntries.length == 0) && (isNotNull(s.unknownPropertiesKey) || isNotNull(s.unknownProperties))) {
85
+ return z.record(convertToZodV3Schema(s.unknownPropertiesKey ?? any()), convertToZodV3Schema(s.unknownProperties ?? any()));
86
+ }
87
+ const shape = {};
88
+ for (const [key, propertySchema] of propertyEntries) {
89
+ shape[key] = convertToZodSchemaBase(propertySchema, options);
90
+ }
91
+ const loose = isNotNull(s.unknownPropertiesKey) || isNotNull(s.unknownProperties);
92
+ let zodSchema = z.object(shape);
93
+ if (loose) {
94
+ zodSchema = zodSchema.passthrough();
95
+ }
96
+ if (!loose && !(s.mask ?? options?.mask ?? false)) {
97
+ zodSchema = zodSchema.strict();
98
+ }
99
+ if (isNotNull(s.unknownProperties)) {
100
+ zodSchema = zodSchema.catchall(convertToZodSchemaBase(s.unknownProperties, options));
101
+ }
102
+ return zodSchema;
103
+ })
104
+ .with(P.instanceOf(UnionSchema), (s) => {
105
+ const schemas = s.schemas.map((subSchema) => convertToZodSchemaBase(subSchema, options));
106
+ return z.union(schemas);
107
+ })
108
+ .with(P.instanceOf(EnumerationSchema), (s) => {
109
+ // Zod nativeEnum or enum doesn't support numbers directly without hacks or native TS enums.
110
+ // Use union of literals for mixed or number enums.
111
+ if (isArray(s.enumeration) && s.enumeration.some((v) => isNumber(v))) {
112
+ const literals = s.allowedValues.map((value) => z.literal(value));
113
+ return z.union(literals);
114
+ }
115
+ // enumeration is either EnumerationObject or string-only EnumerationArray, both is fine for z.enum
116
+ // using `as`, as z.enum is overloaded and only one type per overload
117
+ return z.enum(s.allowedValues);
118
+ })
119
+ .with(P.instanceOf(DefaultSchema), (s) => convertToZodSchemaBase(s.schema, options).default(s.defaultValue))
120
+ .with(P.instanceOf(TransformSchema), (s) => convertToZodSchemaBase(s.schema, options).transform((input) => s.transformFn(input)))
121
+ .with(P.instanceOf(DeferredSchema), (s) => z.lazy(() => convertToZodSchemaBase(s.schema, options)))
122
+ .with(P.instanceOf(ReadableStreamSchema), () => z.instanceof(ReadableStream))
123
+ .with(P.instanceOf(InstanceSchema), (s) => z.instanceof(s.type))
124
+ .otherwise(() => {
125
+ throw new NotSupportedError(`Schema "${schema.name}" cannot be converted to Zod schema.`);
126
+ });
127
+ if (isNotNull(schema.description)) {
128
+ zodSchema = zodSchema.describe(schema.description);
129
+ }
130
+ return zodSchema;
131
+ }