@tstdl/base 0.93.50 → 0.93.53
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/ai/ai.service.js +1 -1
- package/browser/utils.js +2 -2
- package/object-storage/google/google.object-storage-provider.d.ts +44 -0
- package/object-storage/google/google.object-storage-provider.js +81 -0
- package/object-storage/google/google.object-storage.d.ts +32 -0
- package/object-storage/google/google.object-storage.js +220 -0
- package/object-storage/google/google.object.d.ts +16 -0
- package/object-storage/google/google.object.js +69 -0
- package/object-storage/google/index.d.ts +3 -0
- package/object-storage/google/index.js +3 -0
- package/object-storage/object-storage.d.ts +7 -4
- package/object-storage/s3/s3.object-storage-provider.js +1 -1
- package/object-storage/s3/s3.object-storage.d.ts +3 -3
- package/object-storage/s3/s3.object-storage.js +21 -11
- package/object-storage/s3/s3.object.d.ts +1 -1
- package/object-storage/s3/s3.object.js +1 -1
- package/orm/sqls.js +3 -3
- package/package.json +2 -2
- package/schema/converters/zod-converter.d.ts +8 -2
- package/schema/converters/zod-converter.js +182 -136
- package/schema/schemas/bigint.js +2 -2
- package/schema/schemas/boolean.d.ts +1 -0
- package/schema/schemas/boolean.js +16 -16
- package/schema/schemas/constraint.d.ts +19 -0
- package/schema/schemas/constraint.js +36 -0
- package/schema/schemas/index.d.ts +1 -0
- package/schema/schemas/index.js +1 -0
- package/schema/schemas/object.d.ts +3 -1
- package/schema/schemas/object.js +54 -28
- package/schema/schemas/simple.d.ts +6 -1
- package/schema/schemas/simple.js +11 -2
- package/schema/schemas/string.d.ts +4 -2
- package/schema/schemas/string.js +10 -5
- package/schema/schemas/transform.d.ts +4 -0
- package/schema/schemas/transform.js +4 -0
- package/schema/schemas/uint8-array.d.ts +1 -0
- package/schema/schemas/uint8-array.js +10 -7
- package/templates/template.model.js +2 -2
- package/test6.js +112 -29
- package/types/types.d.ts +1 -1
- package/utils/base64.js +1 -2
- package/utils/encoding.js +2 -5
- package/utils/format-error.js +1 -1
- package/utils/object/object.js +7 -1
- package/utils/z-base32.js +2 -4
package/orm/sqls.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { and, Column, eq, sql, isNotNull as sqlIsNotNull, Table } from 'drizzle-orm';
|
|
8
8
|
import { match, P } from 'ts-pattern';
|
|
9
9
|
import { mapObjectValues, objectEntries, objectValues } from '../utils/object/object.js';
|
|
10
|
-
import { assertDefined, isDefined, isInstanceOf, isNotNull, isNull, isNumber, isString } from '../utils/type-guards.js';
|
|
10
|
+
import { assertDefined, isArray, isDefined, isInstanceOf, isNotNull, isNull, isNumber, isString } from '../utils/type-guards.js';
|
|
11
11
|
import { getEnumName } from './enums.js';
|
|
12
12
|
/** Drizzle SQL helper for getting the current transaction's timestamp. Returns a Date object. */
|
|
13
13
|
export const TRANSACTION_TIMESTAMP = sql `transaction_timestamp()`;
|
|
@@ -268,7 +268,7 @@ export function tsRankCd(tsvector, tsquery, options) {
|
|
|
268
268
|
export function tsHeadline(language, document, tsquery, options) {
|
|
269
269
|
const documentSql = isString(document) ? sql `${document}` : document;
|
|
270
270
|
if (isDefined(options)) {
|
|
271
|
-
const optionsString =
|
|
271
|
+
const optionsString = objectEntries(options).map(([key, value]) => `${key[0].toUpperCase()}${key.slice(1)}=${String(value)}`).join(', ');
|
|
272
272
|
return sql `ts_headline(${language}, ${documentSql}, ${tsquery}, '${sql.raw(optionsString)}')`;
|
|
273
273
|
}
|
|
274
274
|
return sql `ts_headline(${language}, ${documentSql}, ${tsquery})`;
|
|
@@ -322,7 +322,7 @@ export function strictWordDistance(left, right) {
|
|
|
322
322
|
return sql `(${left} <<<-> ${right})`;
|
|
323
323
|
}
|
|
324
324
|
export function jsonbBuildObject(properties) {
|
|
325
|
-
const entries =
|
|
325
|
+
const entries = isArray(properties) ? properties : objectEntries(properties);
|
|
326
326
|
const chunks = entries
|
|
327
327
|
.filter(([_, propValue]) => isDefined(propValue))
|
|
328
328
|
.map(([propKey, propValue]) => sql `'${sql.raw(propKey)}', ${propValue}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tstdl/base",
|
|
3
|
-
"version": "0.93.
|
|
3
|
+
"version": "0.93.53",
|
|
4
4
|
"author": "Patrick Hein",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -152,7 +152,7 @@
|
|
|
152
152
|
"nodemailer": "^7.0",
|
|
153
153
|
"pg": "^8.16",
|
|
154
154
|
"playwright": "^1.57",
|
|
155
|
-
"preact": "^10.
|
|
155
|
+
"preact": "^10.28",
|
|
156
156
|
"preact-render-to-string": "^6.6",
|
|
157
157
|
"sharp": "^0.34",
|
|
158
158
|
"undici": "^7.16",
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { z } from 'zod';
|
|
2
2
|
import type { SchemaTestable } from '../schema.js';
|
|
3
|
-
export
|
|
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
|
+
export declare function convertToZodSchema<O, I = unknown>(testable: SchemaTestable<O>, options?: SchemaConversionOptions): z.ZodType<O, I>;
|
|
@@ -1,172 +1,218 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { match, P } from 'ts-pattern';
|
|
2
|
+
import { z } from 'zod';
|
|
2
3
|
import { NotSupportedError } from '../../errors/not-supported.error.js';
|
|
4
|
+
import { JsonPath } from '../../json-path/json-path.js';
|
|
3
5
|
import { objectEntries, objectKeys } from '../../utils/object/object.js';
|
|
4
|
-
import { isArray, isNotNull, isNumber, isString } from '../../utils/type-guards.js';
|
|
5
|
-
import {
|
|
6
|
+
import { isArray, isInstanceOf, isNotNull, isNumber, isString } from '../../utils/type-guards.js';
|
|
7
|
+
import { SchemaError } from '../schema.error.js';
|
|
8
|
+
import { any, AnySchema, ArraySchema, BigIntSchema, BooleanSchema, ConstraintSchema, DateSchema, DefaultSchema, DeferredSchema, EnumerationSchema, FunctionSchema, InstanceSchema, LiteralSchema, NeverSchema, NullableSchema, NumberSchema, ObjectSchema, OneOrManySchema, OptionalSchema, ReadableStreamSchema, RegExpSchema, StringSchema, SymbolSchema, TransformSchema, Uint8ArraySchema, UnionSchema, UnknownSchema } from '../schemas/index.js';
|
|
6
9
|
import { schemaTestableToSchema } from '../testable.js';
|
|
7
|
-
export function convertToZodSchema(testable) {
|
|
10
|
+
export function convertToZodSchema(testable, options) {
|
|
8
11
|
const schema = schemaTestableToSchema(testable);
|
|
9
|
-
return convertToZodSchemaBase(schema);
|
|
12
|
+
return convertToZodSchemaBase(schema, options);
|
|
10
13
|
}
|
|
11
|
-
function convertToZodSchemaBase(schema) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
if (schema instanceof OneOrManySchema) {
|
|
28
|
-
return convertToZodSchema(schema.schema);
|
|
29
|
-
}
|
|
30
|
-
if (schema instanceof StringSchema) {
|
|
31
|
-
const checks = [];
|
|
32
|
-
if (isNumber(schema.minimumLength)) {
|
|
33
|
-
checks.push(z.minLength(schema.minimumLength));
|
|
14
|
+
function convertToZodSchemaBase(schema, options) {
|
|
15
|
+
let zodSchema = match(schema)
|
|
16
|
+
.with(P.instanceOf(AnySchema), () => z.any())
|
|
17
|
+
.with(P.instanceOf(UnknownSchema), () => z.unknown())
|
|
18
|
+
.with(P.instanceOf(NeverSchema), () => z.never())
|
|
19
|
+
.with(P.instanceOf(NullableSchema), (s) => convertToZodSchemaBase(s.schema, options).nullable())
|
|
20
|
+
.with(P.instanceOf(OptionalSchema), (s) => convertToZodSchemaBase(s.schema, options).optional())
|
|
21
|
+
.with(P.instanceOf(OneOrManySchema), (s) => {
|
|
22
|
+
const innerSchema = convertToZodSchemaBase(s.schema, options);
|
|
23
|
+
return innerSchema.or(innerSchema.array());
|
|
24
|
+
})
|
|
25
|
+
.with(P.instanceOf(StringSchema), (s) => {
|
|
26
|
+
let zodSchema = (s.coerce ?? options?.coerce ?? false) ? z.coerce.string() : z.string();
|
|
27
|
+
if (isNumber(s.minimumLength)) {
|
|
28
|
+
zodSchema = zodSchema.min(s.minimumLength);
|
|
34
29
|
}
|
|
35
|
-
if (isNumber(
|
|
36
|
-
|
|
30
|
+
if (isNumber(s.maximumLength)) {
|
|
31
|
+
zodSchema = zodSchema.max(s.maximumLength);
|
|
37
32
|
}
|
|
38
|
-
if (isNotNull(
|
|
39
|
-
|
|
33
|
+
if (isNotNull(s.pattern)) {
|
|
34
|
+
zodSchema = zodSchema.regex(s.pattern);
|
|
40
35
|
}
|
|
41
|
-
if (
|
|
42
|
-
|
|
36
|
+
if (s.trim) {
|
|
37
|
+
zodSchema = zodSchema.trim();
|
|
43
38
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
if (schema instanceof NumberSchema) {
|
|
48
|
-
const checks = [];
|
|
49
|
-
if (isNumber(schema.minimum)) {
|
|
50
|
-
checks.push(z.gte(schema.minimum));
|
|
39
|
+
if (s.lowercase) {
|
|
40
|
+
zodSchema = zodSchema.toLowerCase();
|
|
51
41
|
}
|
|
52
|
-
|
|
53
|
-
|
|
42
|
+
return zodSchema;
|
|
43
|
+
})
|
|
44
|
+
.with(P.instanceOf(NumberSchema), (s) => {
|
|
45
|
+
let zodSchema = (s.coerce ?? options?.coerce ?? false) ? z.coerce.number() : z.number();
|
|
46
|
+
if (s.integer) {
|
|
47
|
+
zodSchema = zodSchema.int();
|
|
54
48
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
if (schema instanceof BooleanSchema) {
|
|
59
|
-
return z.boolean();
|
|
60
|
-
}
|
|
61
|
-
if (schema instanceof BigIntSchema) {
|
|
62
|
-
return z.bigint();
|
|
63
|
-
}
|
|
64
|
-
if (schema instanceof SymbolSchema) {
|
|
65
|
-
return z.symbol();
|
|
66
|
-
}
|
|
67
|
-
if (schema instanceof DateSchema) {
|
|
68
|
-
const checks = [];
|
|
69
|
-
if (isNotNull(schema.minimum)) {
|
|
70
|
-
checks.push(z.gte(schema.minimum));
|
|
49
|
+
if (isNumber(s.minimum)) {
|
|
50
|
+
zodSchema = zodSchema.gte(s.minimum);
|
|
71
51
|
}
|
|
72
|
-
if (
|
|
73
|
-
|
|
52
|
+
if (isNumber(s.maximum)) {
|
|
53
|
+
zodSchema = zodSchema.lte(s.maximum);
|
|
74
54
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (isNumber(schema.minimum)) {
|
|
85
|
-
checks.push(z.minSize(schema.minimum));
|
|
55
|
+
return zodSchema;
|
|
56
|
+
})
|
|
57
|
+
.with(P.instanceOf(BooleanSchema), (s) => (s.coerce ?? options?.coerce ?? false) ? z.coerce.boolean() : z.boolean())
|
|
58
|
+
.with(P.instanceOf(BigIntSchema), (s) => (s.coerce ?? options?.coerce ?? false) ? z.coerce.bigint() : z.bigint())
|
|
59
|
+
.with(P.instanceOf(SymbolSchema), () => z.symbol())
|
|
60
|
+
.with(P.instanceOf(DateSchema), (s) => {
|
|
61
|
+
let zodSchema = (s.coerce ?? options?.coerce ?? false) ? z.coerce.date() : z.date();
|
|
62
|
+
if (isNotNull(s.minimum)) {
|
|
63
|
+
zodSchema = zodSchema.min(s.minimum);
|
|
86
64
|
}
|
|
87
|
-
if (
|
|
88
|
-
|
|
65
|
+
if (isNotNull(s.maximum)) {
|
|
66
|
+
zodSchema = zodSchema.max(s.maximum);
|
|
89
67
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
68
|
+
return zodSchema;
|
|
69
|
+
})
|
|
70
|
+
.with(P.instanceOf(LiteralSchema), (s) => z.literal(s.value))
|
|
71
|
+
.with(P.instanceOf(ArraySchema), (s) => {
|
|
72
|
+
const itemSchema = convertToZodSchemaBase(s.itemSchema, options);
|
|
73
|
+
let zodSchema = z.array(itemSchema);
|
|
74
|
+
if (isNumber(s.minimum)) {
|
|
75
|
+
zodSchema = zodSchema.min(s.minimum);
|
|
76
|
+
}
|
|
77
|
+
if (isNumber(s.maximum)) {
|
|
78
|
+
zodSchema = zodSchema.max(s.maximum);
|
|
79
|
+
}
|
|
80
|
+
return zodSchema;
|
|
81
|
+
})
|
|
82
|
+
.with(P.instanceOf(ObjectSchema), (s) => {
|
|
83
|
+
const propertyEntries = objectEntries(s.properties);
|
|
84
|
+
// Handle generic records (no specific properties, but has unknownProperties/Key)
|
|
85
|
+
if ((propertyEntries.length == 0) && (isNotNull(s.unknownPropertiesKey) || isNotNull(s.unknownProperties))) {
|
|
86
|
+
return z.record(convertToZodSchema(s.unknownPropertiesKey ?? any()), convertToZodSchema(s.unknownProperties ?? any()));
|
|
97
87
|
}
|
|
98
88
|
const shape = {};
|
|
99
89
|
for (const [key, propertySchema] of propertyEntries) {
|
|
100
|
-
shape[key] =
|
|
101
|
-
}
|
|
102
|
-
const loose = isNotNull(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
90
|
+
shape[key] = convertToZodSchemaBase(propertySchema, options);
|
|
91
|
+
}
|
|
92
|
+
const loose = isNotNull(s.unknownPropertiesKey) || isNotNull(s.unknownProperties);
|
|
93
|
+
let zodSchema = loose ? z.looseObject(shape) : z.object(shape);
|
|
94
|
+
if (!loose && !(s.mask ?? options?.mask ?? false)) {
|
|
95
|
+
zodSchema = zodSchema.strict();
|
|
96
|
+
}
|
|
97
|
+
if (isNotNull(s.unknownProperties)) {
|
|
98
|
+
zodSchema = zodSchema.catchall(convertToZodSchemaBase(s.unknownProperties, options));
|
|
99
|
+
}
|
|
100
|
+
// Apply custom validation for unknown properties if they are defined
|
|
101
|
+
if (isNotNull(s.unknownPropertiesKey)) {
|
|
102
|
+
const propertiesKeySchema = convertToZodSchemaBase(s.unknownPropertiesKey, options);
|
|
111
103
|
const knownPropertyKeys = new Set(objectKeys(shape));
|
|
112
|
-
return zodSchema.check(
|
|
113
|
-
for (const
|
|
104
|
+
return zodSchema.check((context) => {
|
|
105
|
+
for (const key of objectKeys(context.value)) {
|
|
114
106
|
if (knownPropertyKeys.has(key)) {
|
|
115
107
|
continue;
|
|
116
108
|
}
|
|
117
109
|
const keyParseResult = propertiesKeySchema.safeParse(key);
|
|
118
|
-
const valueParseResult = propertiesSchema.safeParse(value);
|
|
119
110
|
if (!keyParseResult.success) {
|
|
120
|
-
context.
|
|
111
|
+
context.issues.push({
|
|
121
112
|
code: 'invalid_key',
|
|
122
113
|
origin: 'record',
|
|
123
114
|
issues: keyParseResult.error.issues,
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
if (!valueParseResult.success) {
|
|
127
|
-
context.addIssue({
|
|
128
|
-
code: 'custom',
|
|
129
|
-
input: value,
|
|
130
|
-
path: [key],
|
|
131
|
-
message: valueParseResult.error.message,
|
|
115
|
+
input: key,
|
|
132
116
|
});
|
|
133
117
|
}
|
|
134
118
|
}
|
|
135
|
-
})
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (isNotNull(s.minimumPropertiesCount)) {
|
|
122
|
+
zodSchema = zodSchema.refine((obj) => objectKeys(obj).length >= s.minimumPropertiesCount, {
|
|
123
|
+
message: `Object must have at least ${s.minimumPropertiesCount} properties.`,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
if (isNotNull(s.maximumPropertiesCount)) {
|
|
127
|
+
zodSchema = zodSchema.refine((obj) => objectKeys(obj).length <= s.maximumPropertiesCount, {
|
|
128
|
+
message: `Object must have at most ${s.maximumPropertiesCount} properties.`,
|
|
129
|
+
});
|
|
136
130
|
}
|
|
137
131
|
return zodSchema;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const schemas =
|
|
132
|
+
})
|
|
133
|
+
.with(P.instanceOf(UnionSchema), (s) => {
|
|
134
|
+
const schemas = s.schemas.map((subSchema) => convertToZodSchemaBase(subSchema, options));
|
|
141
135
|
return z.union(schemas);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
136
|
+
})
|
|
137
|
+
.with(P.instanceOf(EnumerationSchema), (s) => {
|
|
138
|
+
// Zod nativeEnum or enum doesn't support numbers directly without hacks or native TS enums.
|
|
139
|
+
// Use union of literals for mixed or number enums.
|
|
140
|
+
if (isArray(s.enumeration) && s.enumeration.some((v) => isNumber(v))) {
|
|
141
|
+
const types = s.allowedValues.map((value) => z.literal(value));
|
|
146
142
|
return z.union(types);
|
|
147
143
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
144
|
+
// enumeration is either EnumerationObject or string-only EnumerationArray, both is fine for z.enum
|
|
145
|
+
// using `as`, as z.enum is overloaded and only one type per overload
|
|
146
|
+
return z.enum(s.enumeration);
|
|
147
|
+
})
|
|
148
|
+
.with(P.instanceOf(FunctionSchema), (s) => {
|
|
149
|
+
let zodSchema = z.function();
|
|
150
|
+
if (isNotNull(s.parameterSchemas)) {
|
|
151
|
+
const args = s.parameterSchemas.map((parameterSchema) => convertToZodSchema(parameterSchema, options));
|
|
152
|
+
zodSchema = zodSchema.input(...args);
|
|
153
|
+
}
|
|
154
|
+
if (isNotNull(s.returnValueSchema)) {
|
|
155
|
+
zodSchema = zodSchema.output(convertToZodSchema(s.returnValueSchema, options));
|
|
156
|
+
}
|
|
157
|
+
return zodSchema;
|
|
158
|
+
})
|
|
159
|
+
.with(P.instanceOf(DefaultSchema), (s) => convertToZodSchemaBase(s.schema, options).default(s.defaultValue))
|
|
160
|
+
.with(P.instanceOf(TransformSchema), (s) => convertToZodSchemaBase(s.schema, options).transform((input) => s.transformFn(input)))
|
|
161
|
+
.with(P.instanceOf(DeferredSchema), (s) => z.lazy(() => convertToZodSchemaBase(s.schema, options)))
|
|
162
|
+
.with(P.instanceOf(Uint8ArraySchema), (s) => {
|
|
163
|
+
let zodSchema = z.instanceof(Uint8Array);
|
|
164
|
+
if (isNumber(s.minimumLength)) {
|
|
165
|
+
zodSchema = zodSchema.refine((value) => (value.byteLength >= s.minimumLength), {
|
|
166
|
+
message: `Size must be at least ${s.minimumLength} bytes.`,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
if (isNumber(s.maximumLength)) {
|
|
170
|
+
zodSchema = zodSchema.refine((value) => (value.byteLength <= s.maximumLength), {
|
|
171
|
+
message: `Size must be at most ${s.maximumLength} bytes.`,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if ((s.coerce ?? options?.coerce ?? false) && isNotNull(s.coerceType)) {
|
|
175
|
+
zodSchema = z.preprocess((value, context) => {
|
|
176
|
+
if (isString(value)) {
|
|
177
|
+
try {
|
|
178
|
+
return Uint8ArraySchema.coerce(value, s.coerceType);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
context.addIssue({ code: 'invalid_format', format: s.coerceType, input: value });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return value;
|
|
185
|
+
}, zodSchema);
|
|
186
|
+
}
|
|
187
|
+
return zodSchema;
|
|
188
|
+
})
|
|
189
|
+
.with(P.instanceOf(ReadableStreamSchema), () => z.instanceof(ReadableStream))
|
|
190
|
+
.with(P.instanceOf(RegExpSchema), (s) => {
|
|
191
|
+
let zodSchema = z.instanceof(RegExp);
|
|
192
|
+
if (s.coerce ?? options?.coerce ?? false) {
|
|
193
|
+
zodSchema = z.preprocess((value) => {
|
|
194
|
+
if (isString(value)) {
|
|
195
|
+
return new RegExp(value, 'u');
|
|
196
|
+
}
|
|
197
|
+
return value;
|
|
198
|
+
}, zodSchema);
|
|
199
|
+
}
|
|
200
|
+
return zodSchema;
|
|
201
|
+
})
|
|
202
|
+
.with(P.instanceOf(InstanceSchema), (s) => z.instanceof(s.type))
|
|
203
|
+
.with(P.instanceOf(ConstraintSchema), (s) => convertToZodSchemaBase(s.schema, options).superRefine((value, context) => {
|
|
204
|
+
const result = s.constraintFn(value, { path: JsonPath.ROOT, options: { coerce: options?.coerce, mask: options?.mask } });
|
|
205
|
+
if (result == true) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const message = isString(result) ? result : isInstanceOf(result, SchemaError) ? result.message : 'Constraint validation failed.';
|
|
209
|
+
context.addIssue({ code: 'custom', message, input: value });
|
|
210
|
+
}))
|
|
211
|
+
.otherwise(() => {
|
|
212
|
+
throw new NotSupportedError(`Schema "${schema.name}" cannot be converted to Zod schema.`);
|
|
213
|
+
});
|
|
214
|
+
if (isNotNull(schema.description)) {
|
|
215
|
+
zodSchema = zodSchema.describe(schema.description);
|
|
216
|
+
}
|
|
217
|
+
return zodSchema;
|
|
172
218
|
}
|
package/schema/schemas/bigint.js
CHANGED
|
@@ -24,8 +24,8 @@ export class BigIntSchema extends SimpleSchema {
|
|
|
24
24
|
catch (error) {
|
|
25
25
|
return { success: false, error: SchemaError.couldNotCoerce('bigint', 'string', path, { fast: coerceOptions.fastErrors, customMessage: error.message }) };
|
|
26
26
|
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -4,6 +4,7 @@ export type BooleanSchemaOptions = SimpleSchemaOptions<boolean>;
|
|
|
4
4
|
export declare class BooleanSchema extends SimpleSchema<boolean> {
|
|
5
5
|
readonly name = "boolean";
|
|
6
6
|
constructor(options?: BooleanSchemaOptions);
|
|
7
|
+
static coerce(value: unknown): boolean | null;
|
|
7
8
|
}
|
|
8
9
|
export declare function boolean(options?: BooleanSchemaOptions): BooleanSchema;
|
|
9
10
|
export declare function BooleanProperty(options?: BooleanSchemaOptions & SchemaDecoratorOptions): SchemaPropertyDecorator;
|
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
import { isBoolean, isString } from '../../utils/type-guards.js';
|
|
2
2
|
import { PropertySchema } from '../decorators/index.js';
|
|
3
3
|
import { SimpleSchema } from './simple.js';
|
|
4
|
+
const truthyValues = new Set([1, 1n, true, 'true', '1', 'yes', 'on', 'y', 'enabled']);
|
|
5
|
+
const falsyValues = new Set([0, 0n, false, 'false', '0', 'no', 'off', 'n', 'disabled']);
|
|
4
6
|
export class BooleanSchema extends SimpleSchema {
|
|
5
7
|
name = 'boolean';
|
|
6
8
|
constructor(options) {
|
|
7
9
|
super('boolean', isBoolean, options, {
|
|
8
10
|
coercers: {
|
|
9
11
|
all: (value) => {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
case 1n:
|
|
14
|
-
case 'true':
|
|
15
|
-
case '1':
|
|
16
|
-
case 'yes':
|
|
17
|
-
return { success: true, value: true, valid: true };
|
|
18
|
-
case 0:
|
|
19
|
-
case 0n:
|
|
20
|
-
case 'false':
|
|
21
|
-
case '0':
|
|
22
|
-
case 'no':
|
|
23
|
-
return { success: true, value: false, valid: true };
|
|
24
|
-
default:
|
|
25
|
-
return { success: false };
|
|
12
|
+
const coerceValue = BooleanSchema.coerce(value);
|
|
13
|
+
if (coerceValue === null) {
|
|
14
|
+
return { success: false };
|
|
26
15
|
}
|
|
16
|
+
return { success: true, value: coerceValue, valid: true };
|
|
27
17
|
},
|
|
28
18
|
},
|
|
29
19
|
});
|
|
30
20
|
}
|
|
21
|
+
static coerce(value) {
|
|
22
|
+
const normalizedValue = isString(value) ? value.toLowerCase().trim() : value;
|
|
23
|
+
if (truthyValues.has(normalizedValue)) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
if (falsyValues.has(normalizedValue)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
31
|
}
|
|
32
32
|
export function boolean(options) {
|
|
33
33
|
return new BooleanSchema(options);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { JsonPath } from '../../json-path/json-path.js';
|
|
2
|
+
import { SchemaError } from '../schema.error.js';
|
|
3
|
+
import { Schema, type SchemaTestable, type SchemaTestOptions, type SchemaTestResult } from '../schema.js';
|
|
4
|
+
type ConstraintFnContext = {
|
|
5
|
+
path: JsonPath;
|
|
6
|
+
options: SchemaTestOptions;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Adds a constraint function to an existing schema.
|
|
10
|
+
*/
|
|
11
|
+
export declare class ConstraintSchema<T> extends Schema<T> {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly schema: Schema<T>;
|
|
14
|
+
readonly constraintFn: (value: T, context: ConstraintFnContext) => boolean | string | SchemaError;
|
|
15
|
+
constructor(schema: SchemaTestable<T>, constraintFn: (value: T, context: ConstraintFnContext) => boolean | SchemaError);
|
|
16
|
+
_test(value: any, path: JsonPath, options: SchemaTestOptions): SchemaTestResult<T>;
|
|
17
|
+
}
|
|
18
|
+
export declare function constraint<T>(schema: Schema<T>, constraintFn: (value: T) => boolean | SchemaError): ConstraintSchema<T>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { lazyProperty } from '../../utils/object/lazy-property.js';
|
|
2
|
+
import { isInstanceOf, isString } from '../../utils/type-guards.js';
|
|
3
|
+
import { SchemaError } from '../schema.error.js';
|
|
4
|
+
import { Schema } from '../schema.js';
|
|
5
|
+
import { schemaTestableToSchema } from '../testable.js';
|
|
6
|
+
/**
|
|
7
|
+
* Adds a constraint function to an existing schema.
|
|
8
|
+
*/
|
|
9
|
+
export class ConstraintSchema extends Schema {
|
|
10
|
+
name;
|
|
11
|
+
schema;
|
|
12
|
+
constraintFn;
|
|
13
|
+
constructor(schema, constraintFn) {
|
|
14
|
+
super();
|
|
15
|
+
this.schema = schemaTestableToSchema(schema);
|
|
16
|
+
this.constraintFn = constraintFn;
|
|
17
|
+
lazyProperty(this, 'name', () => `Constraint[${this.schema.name}]`);
|
|
18
|
+
}
|
|
19
|
+
_test(value, path, options) {
|
|
20
|
+
const result = this.schema._test(value, path, options);
|
|
21
|
+
if (!result.valid) {
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
const constraintResult = this.constraintFn(result.value, { path, options });
|
|
25
|
+
if (constraintResult == true) {
|
|
26
|
+
return { valid: true, value: result.value };
|
|
27
|
+
}
|
|
28
|
+
const error = isInstanceOf(constraintResult, SchemaError)
|
|
29
|
+
? constraintResult
|
|
30
|
+
: new SchemaError(isString(constraintResult) ? constraintResult : `Value not passing constraint`, path, { fast: options.fastErrors });
|
|
31
|
+
return { valid: false, error };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function constraint(schema, constraintFn) {
|
|
35
|
+
return new ConstraintSchema(schema, constraintFn);
|
|
36
|
+
}
|
package/schema/schemas/index.js
CHANGED
|
@@ -35,8 +35,10 @@ export type ObjectSchemaPropertiesType<TP extends ObjectSchemaProperties> = Simp
|
|
|
35
35
|
}>;
|
|
36
36
|
export declare const tryGetSchemaFromReflection: typeof _tryGetSchemaFromReflection;
|
|
37
37
|
export declare class ObjectSchema<T extends Record = Record> extends Schema<T> {
|
|
38
|
-
private readonly
|
|
38
|
+
private readonly propertyEntries;
|
|
39
|
+
private readonly knownPropertyKeys;
|
|
39
40
|
private readonly allowUnknownProperties;
|
|
41
|
+
private readonly resultValueConstructor;
|
|
40
42
|
readonly name: string;
|
|
41
43
|
readonly properties: NormalizedObjectSchemaProperties<T>;
|
|
42
44
|
readonly mask: boolean | null;
|