zodselect 1.2.2 → 1.2.3
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.
|
@@ -3,7 +3,8 @@ import { UnionToIntersection } from './refine-schema.js';
|
|
|
3
3
|
import { ZodSelect } from './select.js';
|
|
4
4
|
type Depth = [0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
5
5
|
type FieldSelectAll<T, TDepth extends number> = TDepth extends 0 ? true : Unwrap<T> extends ZodArray<infer TItem> ? ItemSelectAll<TItem, Depth[TDepth]> : ItemSelectAll<T, Depth[TDepth]>;
|
|
6
|
-
type ItemSelectAll<T, TDepth extends number> = Unwrap<T> extends ZodObject<infer TShape, any> ? ObjectSelectAll<TShape, TDepth> : Unwrap<T> extends ZodUnion<infer TOptions> ? UnionShape<TOptions> extends infer TShape extends ZodRawShape ? ObjectSelectAll<TShape, TDepth> : true : true;
|
|
6
|
+
type ItemSelectAll<T, TDepth extends number> = Unwrap<T> extends ZodObject<infer TShape, any> ? ObjectSelectAll<TShape, TDepth> : Unwrap<T> extends ZodUnion<infer TOptions> ? [NotObject<TOptions[number]>] extends [never] ? UnionShape<TOptions> extends infer TShape extends ZodRawShape ? ObjectSelectAll<TShape, TDepth> : true : true : true;
|
|
7
|
+
type NotObject<T> = T extends unknown ? Unwrap<T> extends ZodObject<any, any> ? never : T : never;
|
|
7
8
|
type ObjectSelectAll<TShape extends ZodRawShape, TDepth extends number> = {
|
|
8
9
|
[K in keyof TShape]-?: FieldSelectAll<TShape[K], TDepth>;
|
|
9
10
|
};
|
|
@@ -11,7 +12,7 @@ type ShapeOf<T> = T extends unknown ? Unwrap<T> extends ZodObject<infer TShape,
|
|
|
11
12
|
/** The shapes of a union's object variants, merged; `unknown` when it has none. */
|
|
12
13
|
type UnionShape<TOptions> = UnionToIntersection<TOptions extends readonly (infer TOption)[] ? ShapeOf<TOption> : never>;
|
|
13
14
|
type Unwrap<T> = T extends ZodCatch<infer I> | ZodDefault<infer I> | ZodNullable<infer I> | ZodOptional<infer I> ? Unwrap<I> : T extends ZodLazy<infer I> ? Unwrap<I> : T;
|
|
14
|
-
/** What {@link buildSelectObject} answers: nested for objects, unions
|
|
15
|
+
/** What {@link buildSelectObject} answers: nested for objects, unions of objects, and arrays of either; `true` for anything else. */
|
|
15
16
|
export type ZodSelectAll<T extends ZodType<object> | ZodUnion> = Unwrap<T> extends ZodObject<infer TShape, any> ? ObjectSelectAll<TShape, 10> : {
|
|
16
17
|
[K in keyof ZodSelect<T, true>]-?: true;
|
|
17
18
|
};
|
|
@@ -20,9 +21,10 @@ export type ZodSelectAll<T extends ZodType<object> | ZodUnion> = Unwrap<T> exten
|
|
|
20
21
|
*
|
|
21
22
|
* Every scalar key is set to `true`. Nested object fields, and arrays of
|
|
22
23
|
* objects, are recursively expanded into nested select objects. A union field
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* whose every variant is an object expands into their merged keys. A union
|
|
25
|
+
* with any other variant, such as a name that is a string or a structured
|
|
26
|
+
* name, remains `true`: its sub-fields would miss the plain value. Other arrays
|
|
27
|
+
* and records remain `true`.
|
|
26
28
|
* For union schemas the result is the merged set of keys across all variants.
|
|
27
29
|
*
|
|
28
30
|
* @example
|
|
@@ -5,9 +5,10 @@ import { getInnerType, isZodArray, isZodObject, isZodUnion } from './utilities.j
|
|
|
5
5
|
*
|
|
6
6
|
* Every scalar key is set to `true`. Nested object fields, and arrays of
|
|
7
7
|
* objects, are recursively expanded into nested select objects. A union field
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* whose every variant is an object expands into their merged keys. A union
|
|
9
|
+
* with any other variant, such as a name that is a string or a structured
|
|
10
|
+
* name, remains `true`: its sub-fields would miss the plain value. Other arrays
|
|
11
|
+
* and records remain `true`.
|
|
11
12
|
* For union schemas the result is the merged set of keys across all variants.
|
|
12
13
|
*
|
|
13
14
|
* @example
|
|
@@ -46,7 +47,7 @@ function collectKeys(schema, result, depth = 0) {
|
|
|
46
47
|
for (const key in schema.shape) {
|
|
47
48
|
const field = unwrapField(schema.shape[key]);
|
|
48
49
|
const fieldInner = isZodArray(field) ? unwrapField(field.def.element) : field;
|
|
49
|
-
if (isZodObject(fieldInner) ||
|
|
50
|
+
if (isZodObject(fieldInner) || isUnionOfObjects(fieldInner)) {
|
|
50
51
|
const nested = {};
|
|
51
52
|
collectKeys(fieldInner, nested, depth + 1);
|
|
52
53
|
result[key] = nested;
|
|
@@ -66,6 +67,6 @@ function collectKeys(schema, result, depth = 0) {
|
|
|
66
67
|
collectKeys(schema.def.right, result, depth);
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
|
-
function
|
|
70
|
-
return isZodUnion(schema) && schema.options.
|
|
70
|
+
function isUnionOfObjects(schema) {
|
|
71
|
+
return isZodUnion(schema) && schema.options.every(option => isZodObject(unwrapField(option)));
|
|
71
72
|
}
|
|
@@ -148,15 +148,15 @@ describe('.buildSelectObject()', () => {
|
|
|
148
148
|
assert.ok(isTyped);
|
|
149
149
|
assert.deepStrictEqual(select, { byKey: true, matrix: true, tags: true });
|
|
150
150
|
});
|
|
151
|
-
it('should
|
|
151
|
+
it('should select a union field whole when a variant is not an object', () => {
|
|
152
152
|
const schema = z.object({
|
|
153
153
|
file: z.union([z.object({ _id: z.string(), filename: z.string() }), z.string()]),
|
|
154
|
-
name: z.string()
|
|
154
|
+
name: z.union([z.string(), z.object({ first: z.string(), last: z.string() })])
|
|
155
155
|
});
|
|
156
156
|
const select = buildSelectObject(schema);
|
|
157
157
|
const isTyped = true;
|
|
158
158
|
assert.ok(isTyped);
|
|
159
|
-
assert.deepStrictEqual(select, { file:
|
|
159
|
+
assert.deepStrictEqual(select, { file: true, name: true });
|
|
160
160
|
});
|
|
161
161
|
it('should merge the keys of every object variant of a union field', () => {
|
|
162
162
|
const schema = z.object({
|
|
@@ -183,16 +183,6 @@ describe('.buildSelectObject()', () => {
|
|
|
183
183
|
assert.ok(isTyped);
|
|
184
184
|
assert.deepStrictEqual(select, { options: { a: true, b: true } });
|
|
185
185
|
});
|
|
186
|
-
it('should expand an attachment whose file is stored as an id and read as the file', () => {
|
|
187
|
-
const file = z.object({ _id: z.string(), contentType: z.string().optional(), filename: z.string() });
|
|
188
|
-
const revision = z.object({ file: z.union([file, z.string()]), uploadedBy: z.object({ _id: z.string(), username: z.string() }) });
|
|
189
|
-
const schema = z.object({ attachments: z.array(revision.extend({ history: z.array(revision).optional(), title: z.string().optional() })).optional() });
|
|
190
|
-
const select = buildSelectObject(schema);
|
|
191
|
-
const revisionSelect = { file: { _id: true, contentType: true, filename: true }, uploadedBy: { _id: true, username: true } };
|
|
192
|
-
const isTyped = true;
|
|
193
|
-
assert.ok(isTyped);
|
|
194
|
-
assert.deepStrictEqual(select, { attachments: { ...revisionSelect, history: revisionSelect, title: true } });
|
|
195
|
-
});
|
|
196
186
|
it('should be a select the schema accepts', () => {
|
|
197
187
|
const schema = z.object({
|
|
198
188
|
client: z.object({ _id: z.string(), name: z.string() }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zodselect",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "Type-safe selection utility built on top of Zod. Allows for strongly typed field selection, schema merging, and runtime refinement for frontend or backend use.",
|
|
5
5
|
"author": "SecureDataSystems",
|
|
6
6
|
"license": "MIT",
|