@ptolemy2002/ts-utils 3.5.1 → 4.0.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/README.md +52 -12
- package/dist/index.d.ts +6 -21
- package/dist/index.js +88 -21
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -41,6 +41,9 @@ This type returns a union of all the keys in `T` that have a value assignable to
|
|
|
41
41
|
### PartialBy<T, K extends keyof T>
|
|
42
42
|
This type returns a type that is the same as `T` except that the keys in `K` are optional.
|
|
43
43
|
|
|
44
|
+
### RequiredBy<T, K extends keyof T>
|
|
45
|
+
This type returns a type that is the same as `T` except that the keys in `K` are required.
|
|
46
|
+
|
|
44
47
|
### AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }>
|
|
45
48
|
This type returns a type that is the same as `T` except that at least one key is required.
|
|
46
49
|
|
|
@@ -79,14 +82,14 @@ declare const advancedConditionSymbol: unique symbol;
|
|
|
79
82
|
|
|
80
83
|
type AdvancedCondition<T> = Branded<{
|
|
81
84
|
__isAdvancedCondition: true,
|
|
82
|
-
include?: T | false | ((v: T) => boolean) | (T | false | ((v: T) => boolean)
|
|
83
|
-
exclude?: T | false | ((v: T) => boolean) | (T | false | ((v: T) => boolean
|
|
85
|
+
include?: T | false | ((v: T) => boolean) | (T | false | ((v: T) => boolean))[],
|
|
86
|
+
exclude?: T | false | ((v: T) => boolean) | (T | false | ((v: T) => boolean))[],
|
|
84
87
|
match?: (a: T, b: T) => boolean
|
|
85
88
|
}, [typeof advancedConditionSymbol]>;
|
|
86
89
|
```
|
|
87
90
|
|
|
88
91
|
### SerializableAdvancedCondition<T>
|
|
89
|
-
This type is the same as `AdvancedCondition<T>` except that the `include` and `exclude` fields cannot be functions and the `match` field is
|
|
92
|
+
This type is the same as `AdvancedCondition<T>` except that the `include` and `exclude` fields cannot be functions and the `match` field is omitted, making it safe for JSON serialization, assuming that `T` is also JSON-serializable. Thus, you lose the ability to use custom matching logic when using this type.
|
|
90
93
|
|
|
91
94
|
This is assignable to any field that accepts an `AdvancedCondition<T>`.
|
|
92
95
|
|
|
@@ -190,25 +193,62 @@ The same as `valueConditionType`, except that it specifically takes a `Serializa
|
|
|
190
193
|
#### Returns
|
|
191
194
|
`SerializableValueConditionType` - The type of the condition.
|
|
192
195
|
|
|
193
|
-
###
|
|
196
|
+
### zodAdvancedConditionSchemaTemplate<T>
|
|
197
|
+
#### Description
|
|
198
|
+
Given a Zod schema for `T`, this function returns a Zod schema that validates an `AdvancedCondition<T>`. The parsed output is created with `createAdvancedCondition`, so the `__isAdvancedCondition` tag and the usual defaults are always present.
|
|
199
|
+
|
|
200
|
+
Input rules:
|
|
201
|
+
- The input must be an object with at least one of `include`, `exclude`, or `match` defined.
|
|
202
|
+
- `__isAdvancedCondition` may be provided, but only as `true`. It is not required, as the schema adds it.
|
|
203
|
+
- Unknown keys are rejected. This prevents arbitrary objects from being interpreted as an empty condition that matches everything.
|
|
204
|
+
|
|
205
|
+
Functions in `include`, `exclude`, and `match` are checked using `zodFunctionSchema` from `@ptolemy2002/zod-utils`. This has the following consequences:
|
|
206
|
+
- The functions are **called during parsing** with the sample values. Avoid passing functions with side effects.
|
|
207
|
+
- An `include` or `exclude` predicate must return a boolean when called with `sample1`.
|
|
208
|
+
- A `match` function must return `true` for `(sample1, sample1)` and `false` for `(sample1, sample2)`. Choose samples that no reasonable match function would consider equal.
|
|
209
|
+
- The functions in the output are wrappers that validate their arguments and return value on every call, throwing a `ZodError` if either is invalid.
|
|
210
|
+
|
|
211
|
+
#### Parameters
|
|
212
|
+
- `zt` (`ZodType<T>`) - The Zod schema representing the type `T`.
|
|
213
|
+
- `sample1` (`T`) - A sample value used to test functions during parsing.
|
|
214
|
+
- `sample2` (`T`) - A second sample value, different from `sample1`, used to test `match` functions.
|
|
215
|
+
|
|
216
|
+
#### Returns
|
|
217
|
+
`ZodType<AdvancedCondition<T>>` - A Zod schema that can be used to validate an `AdvancedCondition<T>`.
|
|
218
|
+
|
|
219
|
+
### zodSerializableAdvancedConditionSchemaTemplate<T>
|
|
220
|
+
#### Description
|
|
221
|
+
The same as `zodAdvancedConditionSchemaTemplate`, except that it validates a `SerializableAdvancedCondition<T>`. The parsed output is created with `createSerializableAdvancedCondition`. The input must have at least one of `include` or `exclude` defined. Functions are not allowed anywhere, and a `match` key is rejected like any other unknown key. Because no functions are ever called, no sample values are needed.
|
|
222
|
+
|
|
223
|
+
#### Parameters
|
|
224
|
+
- `zt` (`ZodType<T>`) - The Zod schema representing the type `T`.
|
|
225
|
+
|
|
226
|
+
#### Returns
|
|
227
|
+
`ZodType<SerializableAdvancedCondition<T>>` - A Zod schema that can be used to validate a `SerializableAdvancedCondition<T>`.
|
|
228
|
+
|
|
229
|
+
### zodValueConditionSchemaTemplate<T>
|
|
194
230
|
#### Description
|
|
195
|
-
|
|
231
|
+
Given a Zod schema for `T`, this function returns a Zod schema that validates a `ValueCondition<T>`, including arrays nested to any depth. Advanced conditions are validated with `zodAdvancedConditionSchemaTemplate`, so the same input rules apply to them. Function conditions are called once with `sample1` during parsing, must return a boolean, and are wrapped in the same way.
|
|
232
|
+
|
|
233
|
+
Options are tried in the same order `valueConditionMatches` checks them: array, function, advanced condition, then a plain value of type `T`. As a result, an object with at least one of `include`, `exclude`, or `match` and no other keys is always treated as an advanced condition, even if it would also be a valid `T`.
|
|
196
234
|
|
|
197
235
|
#### Parameters
|
|
198
|
-
- `zt` (`
|
|
236
|
+
- `zt` (`ZodType<T>`) - The Zod schema representing the type `T`.
|
|
237
|
+
- `sample1` (`T`) - A sample value used to test functions during parsing.
|
|
238
|
+
- `sample2` (`T`) - A second sample value, different from `sample1`, used to test `match` functions.
|
|
199
239
|
|
|
200
240
|
#### Returns
|
|
201
|
-
`
|
|
241
|
+
`ZodType<ValueCondition<T>>` - A Zod schema that can be used to validate a `ValueCondition<T>`.
|
|
202
242
|
|
|
203
|
-
### zodSerializableValueConditionSchemaTemplate<
|
|
243
|
+
### zodSerializableValueConditionSchemaTemplate<T>
|
|
204
244
|
#### Description
|
|
205
|
-
|
|
245
|
+
The same as `zodValueConditionSchemaTemplate`, except that it validates a `SerializableValueCondition<T>`. Function conditions are not allowed, and advanced conditions are validated with `zodSerializableAdvancedConditionSchemaTemplate`. Arrays may be nested to any depth.
|
|
206
246
|
|
|
207
247
|
#### Parameters
|
|
208
|
-
- `zt` (`
|
|
248
|
+
- `zt` (`ZodType<T>`) - The Zod schema representing the type `T`.
|
|
209
249
|
|
|
210
250
|
#### Returns
|
|
211
|
-
`
|
|
251
|
+
`ZodType<SerializableValueCondition<T>>` - A Zod schema that can be used to validate a `SerializableValueCondition<T>`.
|
|
212
252
|
|
|
213
253
|
### omit<T, K extends keyof T>
|
|
214
254
|
#### Description
|
|
@@ -230,7 +270,7 @@ An abstract class representing an object that can be treated as an array, but wi
|
|
|
230
270
|
## Peer Dependencies
|
|
231
271
|
- `is-callable^1.2.7`
|
|
232
272
|
- `@ptolemy2002/ts-brand-utils^1.0.0`
|
|
233
|
-
- `@ptolemy2002/
|
|
273
|
+
- `@ptolemy2002/zod-utils^1.7.0`
|
|
234
274
|
- `zod^4.3.6`
|
|
235
275
|
|
|
236
276
|
## Commands
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Branded, WithoutBrand } from "@ptolemy2002/ts-brand-utils";
|
|
2
|
-
import
|
|
2
|
+
import { ZodType } from "zod";
|
|
3
3
|
export type ValueOf<T> = T[keyof T];
|
|
4
4
|
export type MaybeTransformer<T, Args extends any[] = []> = T | ((...args: Args) => T);
|
|
5
5
|
export type MaybeTransformerRecord<T, Args extends any[] = []> = {
|
|
@@ -22,6 +22,7 @@ export type KeysNotMatchingEqualTypes<T, V> = {
|
|
|
22
22
|
[K in keyof T]-?: EqualTypes<T[K], V, never, K>;
|
|
23
23
|
}[keyof T];
|
|
24
24
|
export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
25
|
+
export type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
25
26
|
export type AtLeastOne<T, U = {
|
|
26
27
|
[K in keyof T]: Pick<T, K>;
|
|
27
28
|
}> = Partial<T> & U[keyof U];
|
|
@@ -50,26 +51,10 @@ export type ValueConditionType = "advanced" | "function" | "value" | (ValueCondi
|
|
|
50
51
|
export type SerializableValueConditionType = "advanced" | "value" | (SerializableValueConditionType | "false")[];
|
|
51
52
|
export declare function valueConditionType<T>(condition: ValueCondition<T>): ValueConditionType;
|
|
52
53
|
export declare function serializableValueConditionType<T>(condition: SerializableValueCondition<T>): SerializableValueConditionType;
|
|
53
|
-
export declare function
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
include?: false | z.core.$InferUnionOutput<ZT> | (false | z.core.$InferUnionOutput<ZT>)[];
|
|
58
|
-
exclude?: false | z.core.$InferUnionOutput<ZT> | (false | z.core.$InferUnionOutput<ZT>)[];
|
|
59
|
-
}>>;
|
|
60
|
-
export declare function zodSerializableValueConditionSchemaTemplate<ZT extends ZodType>(zt: ZT): z.ZodUnion<readonly [ZT, z.ZodArray<z.ZodUnion<readonly [ZT, z.ZodLiteral<false>, z.ZodPipe<z.ZodObject<{
|
|
61
|
-
include: z.ZodOptional<z.ZodUnion<readonly [ZT, z.ZodLiteral<false>, z.ZodArray<z.ZodUnion<readonly [ZT, z.ZodLiteral<false>]>>]>>;
|
|
62
|
-
exclude: z.ZodOptional<z.ZodUnion<readonly [ZT, z.ZodLiteral<false>, z.ZodArray<z.ZodUnion<readonly [ZT, z.ZodLiteral<false>]>>]>>;
|
|
63
|
-
}, z.core.$strip>, z.ZodTransform<SerializableAdvancedCondition<z.core.$InferUnionOutput<ZT>>, {
|
|
64
|
-
include?: false | z.core.$InferUnionOutput<ZT> | (false | z.core.$InferUnionOutput<ZT>)[];
|
|
65
|
-
exclude?: false | z.core.$InferUnionOutput<ZT> | (false | z.core.$InferUnionOutput<ZT>)[];
|
|
66
|
-
}>>]>>, z.ZodPipe<z.ZodObject<{
|
|
67
|
-
include: z.ZodOptional<z.ZodUnion<readonly [ZT, z.ZodLiteral<false>, z.ZodArray<z.ZodUnion<readonly [ZT, z.ZodLiteral<false>]>>]>>;
|
|
68
|
-
exclude: z.ZodOptional<z.ZodUnion<readonly [ZT, z.ZodLiteral<false>, z.ZodArray<z.ZodUnion<readonly [ZT, z.ZodLiteral<false>]>>]>>;
|
|
69
|
-
}, z.core.$strip>, z.ZodTransform<SerializableAdvancedCondition<z.core.$InferUnionOutput<ZT>>, {
|
|
70
|
-
include?: false | z.core.$InferUnionOutput<ZT> | (false | z.core.$InferUnionOutput<ZT>)[];
|
|
71
|
-
exclude?: false | z.core.$InferUnionOutput<ZT> | (false | z.core.$InferUnionOutput<ZT>)[];
|
|
72
|
-
}>>]>;
|
|
54
|
+
export declare function zodAdvancedConditionSchemaTemplate<T>(zt: ZodType<T>, sample1: T, sample2: T): ZodType<AdvancedCondition<T>>;
|
|
55
|
+
export declare function zodSerializableAdvancedConditionSchemaTemplate<T>(zt: ZodType<T>): ZodType<SerializableAdvancedCondition<T>>;
|
|
56
|
+
export declare function zodValueConditionSchemaTemplate<T>(zt: ZodType<T>, sample1: T, sample2: T): ZodType<ValueCondition<T>>;
|
|
57
|
+
export declare function zodSerializableValueConditionSchemaTemplate<T>(zt: ZodType<T>): ZodType<SerializableValueCondition<T>>;
|
|
73
58
|
export type Rename<T, K extends keyof T, N extends string> = Pick<T, Exclude<keyof T, K>> & {
|
|
74
59
|
[P in N]: T[K];
|
|
75
60
|
};
|
package/dist/index.js
CHANGED
|
@@ -10,12 +10,14 @@ exports.createSerializableAdvancedCondition = createSerializableAdvancedConditio
|
|
|
10
10
|
exports.valueConditionMatches = valueConditionMatches;
|
|
11
11
|
exports.valueConditionType = valueConditionType;
|
|
12
12
|
exports.serializableValueConditionType = serializableValueConditionType;
|
|
13
|
+
exports.zodAdvancedConditionSchemaTemplate = zodAdvancedConditionSchemaTemplate;
|
|
13
14
|
exports.zodSerializableAdvancedConditionSchemaTemplate = zodSerializableAdvancedConditionSchemaTemplate;
|
|
15
|
+
exports.zodValueConditionSchemaTemplate = zodValueConditionSchemaTemplate;
|
|
14
16
|
exports.zodSerializableValueConditionSchemaTemplate = zodSerializableValueConditionSchemaTemplate;
|
|
15
17
|
exports.omit = omit;
|
|
16
18
|
const is_callable_1 = __importDefault(require("is-callable"));
|
|
17
19
|
const ts_brand_utils_1 = require("@ptolemy2002/ts-brand-utils");
|
|
18
|
-
const
|
|
20
|
+
const zod_utils_1 = require("@ptolemy2002/zod-utils");
|
|
19
21
|
const zod_1 = __importDefault(require("zod"));
|
|
20
22
|
function isAdvancedCondition(value) {
|
|
21
23
|
return (typeof value === "object" &&
|
|
@@ -83,29 +85,94 @@ function serializableValueConditionType(condition) {
|
|
|
83
85
|
return "advanced";
|
|
84
86
|
return "value";
|
|
85
87
|
}
|
|
86
|
-
|
|
88
|
+
function zodAdvancedConditionSchemaTemplate(zt, sample1, sample2) {
|
|
89
|
+
const validatorFunctionSchema = (0, zod_utils_1.zodFunctionSchema)({
|
|
90
|
+
input: zod_1.default.tuple([zt]),
|
|
91
|
+
output: zod_1.default.boolean(),
|
|
92
|
+
trials: [
|
|
93
|
+
{
|
|
94
|
+
input: [sample1],
|
|
95
|
+
outputSchema: zod_1.default.boolean(),
|
|
96
|
+
error: "forbid"
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
});
|
|
100
|
+
// Options are ordered to mirror the checks in valueConditionMatches,
|
|
101
|
+
// since z.union returns the first option that succeeds.
|
|
102
|
+
const validatorItemSchema = zod_1.default.union([zod_1.default.literal(false), validatorFunctionSchema, zt]);
|
|
103
|
+
const validatorUnionSchema = zod_1.default.union([zod_1.default.array(validatorItemSchema), validatorItemSchema]);
|
|
104
|
+
// Strict and requiring at least one key so that arbitrary objects are not interpreted
|
|
105
|
+
// as an empty (match-all) condition.
|
|
106
|
+
// The tag is accepted but not required, as the transform always injects it.
|
|
107
|
+
return zod_1.default.strictObject({
|
|
108
|
+
__isAdvancedCondition: zod_1.default.literal(true).optional(),
|
|
109
|
+
include: validatorUnionSchema.optional(),
|
|
110
|
+
exclude: validatorUnionSchema.optional(),
|
|
111
|
+
match: (0, zod_utils_1.zodFunctionSchema)({
|
|
112
|
+
input: zod_1.default.tuple([zt, zt]),
|
|
113
|
+
output: zod_1.default.boolean(),
|
|
114
|
+
trials: [
|
|
115
|
+
{
|
|
116
|
+
id: "matches_same_object",
|
|
117
|
+
input: [sample1, sample1],
|
|
118
|
+
outputSchema: zod_1.default.literal(true),
|
|
119
|
+
error: "forbid"
|
|
120
|
+
},
|
|
121
|
+
// Requires sample1 and sample2 to be values that no reasonable
|
|
122
|
+
// match function would consider equal
|
|
123
|
+
{
|
|
124
|
+
id: "does_not_match_different_objects",
|
|
125
|
+
input: [sample1, sample2],
|
|
126
|
+
outputSchema: zod_1.default.literal(false),
|
|
127
|
+
error: "forbid"
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
}).optional()
|
|
131
|
+
}).refine((data) => data.include !== undefined || data.exclude !== undefined || data.match !== undefined, { message: "At least one of include, exclude, or match must be specified" }).transform(({ __isAdvancedCondition, ...data }) => createAdvancedCondition(data));
|
|
132
|
+
}
|
|
87
133
|
function zodSerializableAdvancedConditionSchemaTemplate(zt) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
exclude:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
134
|
+
const valueItemSchema = zod_1.default.union([zod_1.default.literal(false), zt]);
|
|
135
|
+
const valueUnionSchema = zod_1.default.union([zod_1.default.array(valueItemSchema), valueItemSchema]);
|
|
136
|
+
// Strict, so a "match" key (or any other unknown key) is rejected
|
|
137
|
+
return zod_1.default.strictObject({
|
|
138
|
+
__isAdvancedCondition: zod_1.default.literal(true).optional(),
|
|
139
|
+
include: valueUnionSchema.optional(),
|
|
140
|
+
exclude: valueUnionSchema.optional()
|
|
141
|
+
}).refine((data) => data.include !== undefined || data.exclude !== undefined, { message: "At least one of include or exclude must be specified" }).transform(({ __isAdvancedCondition, ...data }) => createSerializableAdvancedCondition(data));
|
|
142
|
+
}
|
|
143
|
+
function zodValueConditionSchemaTemplate(zt, sample1, sample2) {
|
|
144
|
+
// Options are ordered to mirror the checks in valueConditionMatches,
|
|
145
|
+
// since z.union returns the first option that succeeds.
|
|
146
|
+
const schema = zod_1.default.union([
|
|
147
|
+
zod_1.default.array(zod_1.default.union([zod_1.default.literal(false),
|
|
148
|
+
// This lazy evaluation is what allows recursion
|
|
149
|
+
zod_1.default.lazy(() => schema)])),
|
|
150
|
+
(0, zod_utils_1.zodFunctionSchema)({
|
|
151
|
+
input: zod_1.default.tuple([zt]),
|
|
152
|
+
output: zod_1.default.boolean(),
|
|
153
|
+
trials: [
|
|
154
|
+
{
|
|
155
|
+
input: [sample1],
|
|
156
|
+
outputSchema: zod_1.default.boolean()
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
}),
|
|
160
|
+
zodAdvancedConditionSchemaTemplate(zt, sample1, sample2),
|
|
161
|
+
zt
|
|
162
|
+
]);
|
|
163
|
+
return schema;
|
|
100
164
|
}
|
|
101
165
|
function zodSerializableValueConditionSchemaTemplate(zt) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
166
|
+
// Essentially same as above, but with no function option and deferring to the serializable advanced condition schema template
|
|
167
|
+
// instead of the regular advanced condition schema template
|
|
168
|
+
const schema = zod_1.default.union([
|
|
169
|
+
zod_1.default.array(zod_1.default.union([zod_1.default.literal(false),
|
|
170
|
+
// This lazy evaluation is what allows recursion
|
|
171
|
+
zod_1.default.lazy(() => schema)])),
|
|
172
|
+
zodSerializableAdvancedConditionSchemaTemplate(zt),
|
|
173
|
+
zt
|
|
174
|
+
]);
|
|
175
|
+
return schema;
|
|
109
176
|
}
|
|
110
177
|
function omit(obj, ...keys) {
|
|
111
178
|
const _ = { ...obj };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ptolemy2002/ts-utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -27,14 +27,14 @@
|
|
|
27
27
|
"release-major": "bash ./scripts/release.sh major"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@ptolemy2002/regex-utils": "^4.2.0",
|
|
31
30
|
"@ptolemy2002/ts-brand-utils": "^1.0.0",
|
|
31
|
+
"@ptolemy2002/zod-utils": "^1.7.0",
|
|
32
32
|
"is-callable": "^1.2.7",
|
|
33
33
|
"zod": "^4.3.6"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@ptolemy2002/regex-utils": "^4.2.0",
|
|
37
36
|
"@ptolemy2002/ts-brand-utils": "^1.0.0",
|
|
37
|
+
"@ptolemy2002/zod-utils": "^1.7.0",
|
|
38
38
|
"@types/is-callable": "~1.1.2",
|
|
39
39
|
"is-callable": "^1.2.7",
|
|
40
40
|
"zod": "^4.3.6"
|