zodselect 1.0.8 → 1.0.9

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.
@@ -91,13 +91,13 @@ describe('.buildSelectSchema()', () => {
91
91
  assert.strictEqual(getInnerType(select.shape.optionalField).def.type, 'boolean');
92
92
  });
93
93
  it('should handle direct recursion', () => {
94
- const RoleSchema = z.lazy(() => {
94
+ const roleSchema = z.lazy(() => {
95
95
  return (z.object({
96
96
  name: z.string(),
97
- roles: z.array(RoleSchema)
97
+ roles: z.array(roleSchema)
98
98
  }));
99
99
  });
100
- const select = buildSelectSchema(RoleSchema);
100
+ const select = buildSelectSchema(roleSchema);
101
101
  assert.deepStrictEqual(Object.keys(select.shape), ['name', 'roles']);
102
102
  const nameSelect = select.shape.name;
103
103
  assert.strictEqual(nameSelect.def.type, 'optional');
@@ -112,13 +112,13 @@ describe('.buildSelectSchema()', () => {
112
112
  assert.strictEqual(roleItem.def.type, 'object');
113
113
  });
114
114
  it('should support mutual recursion (cross-recursive)', () => {
115
- const A = z.lazy(() => z.object({
116
- b: B
115
+ const schemaA = z.lazy(() => z.object({
116
+ b: schemaB
117
117
  }));
118
- const B = z.lazy(() => z.object({
119
- a: A
118
+ const schemaB = z.lazy(() => z.object({
119
+ a: schemaA
120
120
  }));
121
- const select = buildSelectSchema(A);
121
+ const select = buildSelectSchema(schemaA);
122
122
  assert.strictEqual(select.shape.b.def.type, 'lazy');
123
123
  const bUnion = select.shape.b.def.getter();
124
124
  assert.strictEqual(bUnion.def.innerType.def.type, 'union');
@@ -126,11 +126,11 @@ describe('.buildSelectSchema()', () => {
126
126
  assert.strictEqual(bObj.shape.a.def.type, 'lazy');
127
127
  });
128
128
  it('should share the same instance in recursion (no infinite loop)', () => {
129
- const Role = z.lazy(() => z.object({
129
+ const role = z.lazy(() => z.object({
130
130
  name: z.string(),
131
- roles: z.array(Role)
131
+ roles: z.array(role)
132
132
  }));
133
- const select = buildSelectSchema(Role);
133
+ const select = buildSelectSchema(role);
134
134
  const rolesSelect = select.shape.roles;
135
135
  const unionSelect = rolesSelect.def.getter().def.innerType;
136
136
  const nestedRoleSelect = unionSelect.def.options[1].shape.roles;
@@ -4,16 +4,16 @@ import { z, ZodError } from 'zod';
4
4
  import { refineSchema } from './refine-schema.js';
5
5
  describe('.refineSchema()', () => {
6
6
  it('should retain required fields', () => {
7
- const UserSchema = z.object({
7
+ const userSchema = z.object({
8
8
  age: z.number().optional(),
9
9
  firstName: z.string(),
10
10
  lastName: z.string()
11
11
  });
12
- const RefinedSchema = refineSchema(UserSchema, {
12
+ const refinedSchema = refineSchema(userSchema, {
13
13
  firstName: true,
14
14
  lastName: true
15
15
  });
16
- const parsedData = RefinedSchema.parse({
16
+ const parsedData = refinedSchema.parse({
17
17
  firstName: 'John',
18
18
  lastName: 'Doe'
19
19
  });
@@ -21,74 +21,74 @@ describe('.refineSchema()', () => {
21
21
  assert.equal(parsedData.lastName, 'Doe');
22
22
  });
23
23
  it('should handle optional fields', () => {
24
- const UserSchema = z.object({
24
+ const userSchema = z.object({
25
25
  age: z.number().optional(),
26
26
  firstName: z.string(),
27
27
  lastName: z.string()
28
28
  });
29
- const RefinedSchema = refineSchema(UserSchema, {
29
+ const refinedSchema = refineSchema(userSchema, {
30
30
  age: true
31
31
  });
32
- const parsedData = RefinedSchema.parse({ age: 25 });
32
+ const parsedData = refinedSchema.parse({ age: 25 });
33
33
  assert.equal(parsedData.age, 25);
34
- const parsedWithoutAge = RefinedSchema.parse({});
34
+ const parsedWithoutAge = refinedSchema.parse({});
35
35
  assert.equal(parsedWithoutAge.age, undefined);
36
36
  });
37
37
  it('should handle nullable fields', () => {
38
- const RoleSchema = z.object({
38
+ const roleSchema = z.object({
39
39
  name: z.string()
40
40
  });
41
- const UserSchema = z.object({
41
+ const userSchema = z.object({
42
42
  firstName: z.string(),
43
- role: RoleSchema.nullable()
43
+ role: roleSchema.nullable()
44
44
  });
45
- const RefinedSchema = refineSchema(UserSchema, {
45
+ const refinedSchema = refineSchema(userSchema, {
46
46
  role: true
47
47
  });
48
- const parsedWithNullRole = RefinedSchema.parse({
48
+ const parsedWithNullRole = refinedSchema.parse({
49
49
  firstName: 'Alice',
50
50
  role: null
51
51
  });
52
52
  assert.equal(parsedWithNullRole.role, null);
53
53
  });
54
54
  it('should handle both optional and nullable fields', () => {
55
- const RoleSchema = z.object({
55
+ const roleSchema = z.object({
56
56
  name: z.string()
57
57
  });
58
- const UserSchema = z.object({
58
+ const userSchema = z.object({
59
59
  firstName: z.string(),
60
- role: RoleSchema.nullable().optional()
60
+ role: roleSchema.nullable().optional()
61
61
  });
62
- const RefinedSchema = refineSchema(UserSchema, {
62
+ const refinedSchema = refineSchema(userSchema, {
63
63
  role: {
64
64
  name: true
65
65
  }
66
66
  });
67
- const parsedWithRole = RefinedSchema.parse({
67
+ const parsedWithRole = refinedSchema.parse({
68
68
  firstName: 'Alice',
69
69
  role: { name: 'Admin' }
70
70
  });
71
71
  assert.deepStrictEqual(parsedWithRole.role, { name: 'Admin' });
72
- const parsedWithNullRole = RefinedSchema.parse({
72
+ const parsedWithNullRole = refinedSchema.parse({
73
73
  firstName: 'Alice',
74
74
  role: null
75
75
  });
76
76
  assert.strictEqual(parsedWithNullRole.role, null);
77
- const parsedWithoutRole = RefinedSchema.parse({ firstName: 'Alice' });
77
+ const parsedWithoutRole = refinedSchema.parse({ firstName: 'Alice' });
78
78
  assert.strictEqual(parsedWithoutRole.role, undefined);
79
79
  });
80
80
  it('should apply custom schema transformations', () => {
81
- const RoleSchema = z.object({
81
+ const roleSchema = z.object({
82
82
  name: z.string()
83
83
  });
84
- const UserSchema = z.object({
84
+ const userSchema = z.object({
85
85
  firstName: z.string(),
86
- role: RoleSchema
86
+ role: roleSchema
87
87
  });
88
- const RefinedSchema = refineSchema(UserSchema, {
89
- role: (schema) => schema.extend({ permissions: z.array(z.string()) })
88
+ const refinedSchema = refineSchema(userSchema, {
89
+ role: schema => schema.extend({ permissions: z.array(z.string()) })
90
90
  });
91
- const parsedData = RefinedSchema.parse({
91
+ const parsedData = refinedSchema.parse({
92
92
  firstName: 'Bob',
93
93
  role: { name: 'User', permissions: ['read', 'write'] }
94
94
  });
@@ -98,46 +98,46 @@ describe('.refineSchema()', () => {
98
98
  });
99
99
  });
100
100
  it('should handle nested arrays', () => {
101
- const RoleSchema = z.object({
101
+ const roleSchema = z.object({
102
102
  level: z.number(),
103
103
  title: z.string()
104
104
  });
105
- const UserSchema = z.object({
105
+ const userSchema = z.object({
106
106
  age: z.number().optional(),
107
107
  firstName: z.string(),
108
108
  lastName: z.string(),
109
109
  nestedArray: z.array(z.object({ name: z.string(), value: z.number() })).optional().nullable(),
110
- role: RoleSchema.nullable().optional(),
110
+ role: roleSchema.nullable().optional(),
111
111
  tags: z.array(z.string()).optional()
112
112
  });
113
- const RefinedSchema = refineSchema(UserSchema, {
113
+ const refinedSchema = refineSchema(userSchema, {
114
114
  nestedArray: {
115
115
  name: true
116
116
  }
117
117
  });
118
- const parsedData = RefinedSchema.parse({
118
+ const parsedData = refinedSchema.parse({
119
119
  firstName: 'Alice',
120
120
  lastName: 'Smith',
121
121
  nestedArray: [{ name: 'Feature1', value: 10 }, { name: 'Feature2', value: 20 }]
122
122
  });
123
123
  assert.deepStrictEqual(parsedData.nestedArray, [{ name: 'Feature1' }, { name: 'Feature2' }]);
124
124
  // Test optional array
125
- const parsedWithoutNestedArray = RefinedSchema.parse({
125
+ const parsedWithoutNestedArray = refinedSchema.parse({
126
126
  firstName: 'Alice',
127
127
  lastName: 'Smith'
128
128
  });
129
129
  assert.equal(parsedWithoutNestedArray.nestedArray, undefined);
130
130
  });
131
131
  it('should handle custom fields', () => {
132
- const UserSchema = z.object({
132
+ const userSchema = z.object({
133
133
  address: z.custom().optional(),
134
134
  firstName: z.string(),
135
135
  lastName: z.string()
136
136
  });
137
- const RefinedSchema = refineSchema(UserSchema, {
137
+ const refinedSchema = refineSchema(userSchema, {
138
138
  address: true
139
139
  });
140
- const parsedData = RefinedSchema.parse({
140
+ const parsedData = refinedSchema.parse({
141
141
  address: {
142
142
  city: 'Austin',
143
143
  state: 'TX',
@@ -155,45 +155,45 @@ describe('.refineSchema()', () => {
155
155
  });
156
156
  });
157
157
  it('should support unions of objects', () => {
158
- const Person = z.object({
158
+ const person = z.object({
159
159
  firstName: z.string(),
160
160
  lastName: z.string()
161
161
  });
162
- const Address = z.object({
162
+ const address = z.object({
163
163
  address: z.string(),
164
164
  city: z.string()
165
165
  });
166
- const Schema = refineSchema(z.union([Person, Address]), {
166
+ const schema = refineSchema(z.union([person, address]), {
167
167
  address: true,
168
168
  firstName: true
169
169
  });
170
- let parseResult = Schema.parse({
170
+ let parseResult = schema.parse({
171
171
  address: '123 Main Street',
172
172
  firstName: 'Jerry',
173
173
  lastName: 'Springer'
174
174
  });
175
175
  deepStrictEqual(parseResult, { firstName: 'Jerry' });
176
- parseResult = Schema.parse({
176
+ parseResult = schema.parse({
177
177
  address: '123 Main Street',
178
178
  city: 'Austin'
179
179
  });
180
180
  deepStrictEqual(parseResult, { address: '123 Main Street' });
181
181
  });
182
182
  it('should error if none of the types are matched', () => {
183
- const Person = z.object({
183
+ const person = z.object({
184
184
  firstName: z.string(),
185
185
  lastName: z.string()
186
186
  });
187
- const Address = z.object({
187
+ const address = z.object({
188
188
  address: z.string(),
189
189
  city: z.string()
190
190
  });
191
- const Schema = refineSchema(z.union([Person, Address]), {
191
+ const schema = refineSchema(z.union([person, address]), {
192
192
  address: true,
193
193
  firstName: true
194
194
  });
195
195
  throws(() => {
196
- Schema.parse({
196
+ schema.parse({
197
197
  lastName: 'Springer'
198
198
  });
199
199
  }, (err) => {
@@ -204,20 +204,20 @@ describe('.refineSchema()', () => {
204
204
  });
205
205
  });
206
206
  it('should support unions of objects and simple types', () => {
207
- const Person = z.object({
207
+ const person = z.object({
208
208
  firstName: z.string(),
209
209
  lastName: z.string()
210
210
  });
211
- const Schema = refineSchema(z.union([Person, z.string()]), {
211
+ const schema = refineSchema(z.union([person, z.string()]), {
212
212
  address: true,
213
213
  firstName: true
214
214
  });
215
- let parseResult = Schema.parse({
215
+ let parseResult = schema.parse({
216
216
  firstName: 'Jerry',
217
217
  lastName: 'Springer'
218
218
  });
219
219
  deepStrictEqual(parseResult, { firstName: 'Jerry' });
220
- parseResult = Schema.parse('123 Main Street');
220
+ parseResult = schema.parse('123 Main Street');
221
221
  deepStrictEqual(parseResult, '123 Main Street');
222
222
  });
223
223
  });
package/dist/select.d.ts CHANGED
@@ -7,6 +7,9 @@ type InferTuple<T extends ZodType<object> | ZodUnion, U extends readonly ZodSele
7
7
  };
8
8
  export type InferType<T extends ZodType<object> | ZodUnion, U extends ZodSelect<T>> = U extends ZodType<object> ? z.infer<U> : U extends ZodUnion ? z.infer<U> : T extends ZodUnion ? (U extends RefineZodUnion<T> ? z.infer<RefinedUnionSchema<T, U>> : z.infer<T>) : T extends ZodType<object> ? (U extends RefineObject<z.infer<T>, false> ? z.infer<RefinedTypeSchema<z.infer<T>, U>> : z.infer<T>) : z.infer<T>;
9
9
  export type MergeSelect<T extends ZodType<object> | ZodUnion, TSelect1 extends ZodSelect<T>, TSelect2 extends MultiSelect<T>> = TSelect2 extends undefined ? [TSelect1, T] : IsEqual<TSelect2, T, TSelect1, TSelect2 extends [ZodSelect<T>, ...ZodSelect<T>[]] ? [TSelect1, ...TSelect2] : [TSelect1, TSelect2]>;
10
- export type MultiSelect<T extends ZodType<object> | ZodUnion> = [ZodSelect<T>, ...ZodSelect<T>[]] | undefined | ZodSelect<T>;
10
+ export type MultiSelect<T extends ZodType<object> | ZodUnion> = [
11
+ ZodSelect<T>,
12
+ ...ZodSelect<T>[]
13
+ ] | undefined | ZodSelect<T>;
11
14
  export type ZodSelect<T extends ZodTuple | ZodType<object> | ZodUnion, TIsSimple extends boolean = false> = (T extends ZodUnion ? (RefineZodUnion<T> | ZodUnion) : T extends ZodTuple ? (RefineZodTuple<T> | ZodTuple) : T extends ZodType<object> ? (RefineObject<z.infer<T>, TIsSimple> | ZodType<object>) : never);
12
15
  export {};
@@ -30,8 +30,8 @@ describe('.utilities()', () => {
30
30
  assert.strictEqual(inner.def.type, 'string');
31
31
  });
32
32
  it('should unwrap lazy inside nested wrappers', () => {
33
- const LazySchema = z.lazy(() => z.string());
34
- const wrapped = LazySchema.optional().nullable().default('abc');
33
+ const lazySchema = z.lazy(() => z.string());
34
+ const wrapped = lazySchema.optional().nullable().default('abc');
35
35
  const inner = getInnerType(wrapped);
36
36
  assert.strictEqual(inner.def.type, 'string');
37
37
  });
@@ -56,20 +56,20 @@ describe('.utilities()', () => {
56
56
  });
57
57
  it('isZodRecord detects complex record schemas with optional fields', () => {
58
58
  // Create a sample RecordAttachmentSchema
59
- const RecordAttachmentSchema = z.object({
59
+ const recordAttachmentSchema = z.object({
60
60
  name: z.string(),
61
61
  size: z.number(),
62
62
  type: z.string()
63
63
  });
64
64
  // Create a record schema with optional field
65
- const attachmentsSchema = z.record(z.string(), RecordAttachmentSchema).optional();
65
+ const attachmentsSchema = z.record(z.string(), recordAttachmentSchema).optional();
66
66
  const nonRecordSchema = z.object({ field: z.string() });
67
67
  // Test record detection
68
- assert.ok(isZodRecord(z.record(z.string(), RecordAttachmentSchema)), 'Should detect record schema');
68
+ assert.ok(isZodRecord(z.record(z.string(), recordAttachmentSchema)), 'Should detect record schema');
69
69
  assert.ok(isZodRecord(attachmentsSchema.unwrap()), 'Should detect optional record schema when unwrapped');
70
70
  assert.ok(!isZodRecord(nonRecordSchema), 'Should not detect object schema as record');
71
71
  // Test with actual record data
72
- const validRecord = z.record(z.string(), RecordAttachmentSchema).parse({
72
+ const validRecord = z.record(z.string(), recordAttachmentSchema).parse({
73
73
  'file1': { name: 'test.pdf', size: 1024, type: 'application/pdf' },
74
74
  'file2': { name: 'image.jpg', size: 2048, type: 'image/jpeg' }
75
75
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zodselect",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
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",
@@ -25,21 +25,21 @@
25
25
  }
26
26
  },
27
27
  "devDependencies": {
28
- "@secure-data-systems/eslint-config": "^1.0.26",
29
- "@secure-data-systems/tsconfig": "^1.0.2",
28
+ "@secure-data-systems/eslint-config": "^1.0.33",
29
+ "@secure-data-systems/tsconfig": "^1.0.3",
30
30
  "@types/node": "^24.10.1",
31
- "glob": "^11.0.3",
32
- "tsx": "^4.20.6",
31
+ "tsx": "^4.21.0",
33
32
  "typescript": "^5.9.3"
34
33
  },
35
34
  "dependencies": {
36
- "zod": "^4.1.12"
35
+ "zod": "^4.1.13"
37
36
  },
38
37
  "scripts": {
39
38
  "build": "node scripts/build.mjs && tsc --project tsconfig.build.json",
39
+ "clean": "node scripts/clean.mjs",
40
40
  "deploy": "npm run build && node ./scripts/publish.mjs",
41
41
  "lint": "eslint . --c eslint.config.mjs",
42
42
  "lint:fix": "eslint . --c eslint.config.mjs --fix",
43
- "test": "glob -c \"tsx --tsconfig ./tsconfig.build.json --test\" \"./src/**/*.{spec,test}.ts\""
43
+ "test": "tsx --tsconfig ./tsconfig.build.json --test ./src/**/*.{spec,test}.ts ./test/**/*.{spec,test}.ts"
44
44
  }
45
45
  }