@dzeio/schema 0.6.0 → 0.8.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/dist/Schema.d.mts CHANGED
@@ -3,6 +3,7 @@ import { StandardSchemaV1 } from '@standard-schema/spec';
3
3
  declare abstract class SchemaItem<Output = any, Input = Output> implements StandardSchemaV1<Input, Output> {
4
4
  readonly _output: Output;
5
5
  readonly _input: Input;
6
+ static id: string;
6
7
  '~standard': StandardSchemaV1.Props<Input, Output>;
7
8
  /**
8
9
  * Function calls saved for serialization
@@ -67,6 +68,7 @@ declare abstract class SchemaItem<Output = any, Input = Output> implements Stand
67
68
  unwrap?(): SchemaItem;
68
69
  parse(input: unknown, options?: ValidationOptions): ValidationResult<Output>;
69
70
  toJSON(): SchemaJSON;
71
+ private deepSerializeItem;
70
72
  addValidation(fn: ((input: Output) => boolean) | {
71
73
  fn: (input: Output) => boolean;
72
74
  error?: string;
@@ -128,7 +130,7 @@ type ValidationResultOld<T> = {
128
130
  */
129
131
  interface SchemaJSON {
130
132
  /** Id of the schema item (name of the constructor) */
131
- i: string
133
+ _i: string
132
134
  /** Attributes */
133
135
  a?: Array<string> | undefined
134
136
  /** Children schema items */
@@ -159,12 +161,16 @@ type ModelInfer$1<M extends Model> = {
159
161
  [key in keyof M]: SchemaInfer<M[key]>
160
162
  }
161
163
 
164
+ type Literal = string | number | bigint | boolean | null | undefined
165
+
162
166
  declare class SchemaAny extends SchemaItem {
167
+ static id: string;
163
168
  isOfType(_input: unknown): _input is any;
164
169
  }
165
170
 
166
171
  type DateFormat = 'default' | 'iso8601' | 'yy-mm-dd' | 'jj/mm/yy';
167
172
  declare class SchemaDate extends SchemaItem<Date> {
173
+ static id: string;
168
174
  parseString(format?: DateFormat): this;
169
175
  isOfType(input: unknown): input is Date;
170
176
  }
@@ -172,6 +178,7 @@ declare class SchemaDate extends SchemaItem<Date> {
172
178
  declare class SchemaRecord<Keys extends SchemaItem<string | number | symbol>, Values extends SchemaItem> extends SchemaItem<Record<SchemaInfer<Keys>, SchemaInfer<Values>>> {
173
179
  private readonly keys;
174
180
  private readonly values;
181
+ static id: string;
175
182
  constructor(keys: Keys, values: Values);
176
183
  isOfType(input: unknown): input is Record<SchemaInfer<Keys>, SchemaInfer<Values>>;
177
184
  protected parseSubItems(input: unknown, options?: ValidationOptions): {
@@ -182,11 +189,13 @@ declare class SchemaRecord<Keys extends SchemaItem<string | number | symbol>, Va
182
189
 
183
190
  declare class SchemaArray<Child extends SchemaItem, Output = SchemaInfer<Child>, Input = SchemaInputInfer<Child>> extends SchemaItem<Array<Output>, Array<Input>> {
184
191
  readonly values: Child;
192
+ static id: string;
185
193
  constructor(values: Child);
186
194
  /**
187
195
  * transform the array so it only contains one of each elements
188
196
  */
189
197
  unique(): this;
198
+ clean(): this;
190
199
  /**
191
200
  * split a string into an array
192
201
  * @param [separator] default:`,` the separator to use
@@ -202,6 +211,7 @@ declare class SchemaArray<Child extends SchemaItem, Output = SchemaInfer<Child>,
202
211
  }
203
212
 
204
213
  declare class SchemaBoolean extends SchemaItem<boolean> {
214
+ static id: string;
205
215
  /**
206
216
  * @param [trueValue='true'] the truhty value (default to `'true'`)
207
217
  * @param [falseValue='false'] the falthy value (default to `'false'`)
@@ -216,21 +226,26 @@ interface EnumLike {
216
226
  }
217
227
  declare class SchemaEnum<E extends EnumLike> extends SchemaItem<E[keyof E]> {
218
228
  private readonly templateEnum;
229
+ static id: string;
219
230
  private readonly type;
220
231
  constructor(templateEnum: E);
221
232
  isOfType(input: unknown): input is E[keyof E];
222
233
  }
223
234
 
224
- declare class SchemaLiteral<Type> extends SchemaItem<Type> {
225
- private readonly value;
226
- constructor(value: Type);
227
- isOfType(input: unknown): input is Type;
235
+ declare class SchemaLiteral<Types extends Array<Literal>> extends SchemaItem<Types[number]> {
236
+ static id: string;
237
+ private readonly values;
238
+ constructor(...values: Types);
239
+ isOfType(input: unknown): input is Types[number];
228
240
  }
229
241
 
230
242
  declare class SchemaNullable<Child extends SchemaItem, Output = SchemaInfer<Child>, Input = SchemaInputInfer<Child>> extends SchemaItem<Output | undefined, Input | null | undefined> {
231
243
  private readonly child;
244
+ static id: string;
232
245
  constructor(child: Child);
233
246
  falsyAsNull(): this;
247
+ emptyAsNull(): this;
248
+ emptyFileAsNull(): this;
234
249
  unwrap(): Child;
235
250
  isOfType(input: unknown): input is Output | undefined;
236
251
  protected getSubInputs(input: unknown): Array<{
@@ -245,6 +260,7 @@ declare class SchemaNullable<Child extends SchemaItem, Output = SchemaInfer<Chil
245
260
  }
246
261
 
247
262
  declare class SchemaNumber extends SchemaItem<number> {
263
+ static id: string;
248
264
  /**
249
265
  * validate that the number is less or equal than {@link value}
250
266
  * @param value the maxumum value (inclusive)
@@ -283,7 +299,7 @@ type ModelInfer<M extends Record<string, SchemaItem>> = {
283
299
  };
284
300
  declare class SchemaObject<T extends Record<string, SchemaItem> = any> extends SchemaItem<ModelInfer<T>> {
285
301
  readonly model: T;
286
- id: string;
302
+ static id: string;
287
303
  constructor(model: T);
288
304
  isOfType(input: unknown): input is ModelInfer<T>;
289
305
  protected getSubInputs(input: unknown): Array<{
@@ -294,6 +310,7 @@ declare class SchemaObject<T extends Record<string, SchemaItem> = any> extends S
294
310
  }
295
311
 
296
312
  declare class SchemaString extends SchemaItem<string> {
313
+ static id: string;
297
314
  /**
298
315
  * force the input text to be a minimum of `value` size
299
316
  * @param value the minimum length of the text
@@ -323,12 +340,18 @@ declare class SchemaString extends SchemaItem<string> {
323
340
  * @param message the message to display on an error
324
341
  */
325
342
  regex(regex: RegExp, message?: string): this;
343
+ /**
344
+ * force the input text to be an email
345
+ * @param message the message to display on an error
346
+ */
347
+ email(message?: string): this;
326
348
  minLength(value: number, message?: string): this;
327
349
  maxLength(value: number, message?: string): this;
328
350
  isOfType(input: unknown): input is string;
329
351
  }
330
352
 
331
353
  declare class SchemaUnion<Children extends Array<SchemaItem>, Outputs = SchemaInfer<Children[number]>, Inputs = SchemaInputInfer<Children[number]>> extends SchemaItem<Outputs, Inputs> {
354
+ static id: string;
332
355
  private readonly schemas;
333
356
  constructor(...schemas: Children);
334
357
  isOfType(input: unknown): input is Outputs;
@@ -343,6 +366,7 @@ type Prettify<T> = T extends unknown ? {
343
366
  } : never;
344
367
  type UnionToIntersection<U> = (U extends U ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
345
368
  declare class SchemaIntersection<Children extends Array<SchemaItem>, Outputs = Prettify<UnionToIntersection<SchemaInfer<Children[number]>>>, Inputs = Prettify<UnionToIntersection<SchemaInfer<Children[number]>>>> extends SchemaItem<Outputs, Inputs> {
369
+ static id: string;
346
370
  private readonly schemas;
347
371
  constructor(...schemas: Children);
348
372
  isOfType(input: unknown): input is Outputs;
@@ -356,6 +380,7 @@ declare class SchemaDefault<Child extends SchemaItem, Output = SchemaInfer<Child
356
380
  private readonly child;
357
381
  private readonly defaultVal;
358
382
  private readonly strict;
383
+ static id: string;
359
384
  constructor(child: Child, defaultVal: Output, strict?: boolean);
360
385
  unwrap(): Child;
361
386
  isOfType(input: unknown): input is Output;
@@ -367,6 +392,7 @@ declare class SchemaDefault<Child extends SchemaItem, Output = SchemaInfer<Child
367
392
  }
368
393
 
369
394
  declare class SchemaFile extends SchemaItem<File> {
395
+ static id: string;
370
396
  constructor();
371
397
  extension(ext: string, error?: string): this;
372
398
  maxSize(size: number, error?: string): this;
@@ -376,6 +402,7 @@ declare class SchemaFile extends SchemaItem<File> {
376
402
  type TupleToOutputs<Tuple extends Array<SchemaItem>, Result extends Array<any> = []> = number extends Tuple['length'] ? Array<SchemaInfer<Tuple[number]>> : Tuple[Result['length']] extends undefined ? Result : TupleToOutputs<Tuple, [...Result, SchemaInfer<Tuple[Result['length']]>]>;
377
403
  type TupleToInputs<Tuple extends Array<SchemaItem>, Result extends Array<any> = []> = number extends Tuple['length'] ? Array<SchemaInputInfer<Tuple[number]>> : Tuple[Result['length']] extends undefined ? Result : TupleToInputs<Tuple, [...Result, SchemaInputInfer<Tuple[Result['length']]>]>;
378
404
  declare class SchemaTuple<Children extends Array<SchemaItem>, Outputs = TupleToOutputs<Children>, Inputs = TupleToInputs<Children>> extends SchemaItem<Outputs, Inputs> {
405
+ static id: string;
379
406
  private readonly children;
380
407
  constructor(...children: Children);
381
408
  isOfType(input: unknown): input is Outputs;
@@ -387,18 +414,23 @@ declare class SchemaTuple<Children extends Array<SchemaItem>, Outputs = TupleToO
387
414
  }
388
415
 
389
416
  declare class SchemaUndefined extends SchemaItem<undefined> {
417
+ static id: string;
390
418
  isOfType(input: unknown): input is undefined;
391
419
  }
392
420
  declare class SchemaNull extends SchemaItem<null> {
421
+ static id: string;
393
422
  isOfType(input: unknown): input is null;
394
423
  }
395
424
  declare class SchemaVoid extends SchemaItem<void> {
425
+ static id: string;
396
426
  isOfType(input: unknown): input is void;
397
427
  }
398
428
  declare class SchemaNullish extends SchemaItem<null | undefined> {
429
+ static id: string;
399
430
  isOfType(input: unknown): input is null | undefined;
400
431
  }
401
432
  declare class SchemaNever extends SchemaItem<never> {
433
+ static id: string;
402
434
  isOfType(_input: unknown): _input is never;
403
435
  }
404
436
 
@@ -414,31 +446,13 @@ declare function parseForm<T extends SchemaItem>(model: T, form: HTMLFormElement
414
446
  * Decorator for modifier functions on SchemaItems to save them in the "savedCalls" property for the serialization
415
447
  */
416
448
  declare function parsable(): (target: object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<any>) => TypedPropertyDescriptor<any>;
417
- type SchemaItemStatic = new (...args: Array<any>) => SchemaItem;
418
- declare const Types: {
419
- readonly Any: typeof SchemaAny;
420
- readonly Array: typeof SchemaArray;
421
- readonly Tuple: typeof SchemaTuple;
422
- readonly Boolean: typeof SchemaBoolean;
423
- readonly Date: typeof SchemaDate;
424
- readonly Enum: typeof SchemaEnum;
425
- readonly Literal: typeof SchemaLiteral;
426
- readonly Nullable: typeof SchemaNullable;
427
- readonly Object: typeof SchemaObject;
428
- readonly Record: typeof SchemaRecord;
429
- readonly String: typeof SchemaString;
430
- readonly Union: typeof SchemaUnion;
431
- readonly Intersection: typeof SchemaIntersection;
432
- readonly Default: typeof SchemaDefault;
433
- readonly Undefined: typeof SchemaUndefined;
434
- readonly Void: typeof SchemaVoid;
435
- readonly Null: typeof SchemaNull;
436
- readonly Nullish: typeof SchemaNullish;
449
+ type SchemaItemStatic = (new (...args: Array<any>) => SchemaItem) & {
450
+ id: string;
437
451
  };
438
452
  declare class Schema<T extends Record<string, SchemaItem> = Record<string, SchemaItem>> extends SchemaObject<T> {
439
453
  private static readonly registeredModules;
440
454
  static register(module: SchemaItemStatic): void;
441
- static getModule(name: string): SchemaItemStatic | undefined;
455
+ static getModule(name: string): SchemaItemStatic;
442
456
  static any(): SchemaAny;
443
457
  static array<Type extends SchemaItem>(...inputs: ConstructorParameters<typeof SchemaArray<Type>>): SchemaArray<Type>;
444
458
  static boolean(...inputs: ConstructorParameters<typeof SchemaBoolean>): SchemaBoolean;
@@ -449,7 +463,7 @@ declare class Schema<T extends Record<string, SchemaItem> = Record<string, Schem
449
463
  * @param input the literal value (note: append `as const` else the typing won't work correctly)
450
464
  * @returns
451
465
  */
452
- static literal<Type>(input: Type): SchemaLiteral<Type>;
466
+ static literal<Type extends Array<Literal>>(...inputs: ConstructorParameters<typeof SchemaLiteral<Type>>): SchemaLiteral<Type>;
453
467
  static nullable<Type extends SchemaItem>(...inputs: ConstructorParameters<typeof SchemaNullable<Type>>): SchemaNullable<Type>;
454
468
  static number(...inputs: ConstructorParameters<typeof SchemaNumber>): SchemaNumber;
455
469
  static object<Type extends Record<string, SchemaItem>>(...inputs: ConstructorParameters<typeof SchemaObject<Type>>): SchemaObject<Type>;
@@ -468,6 +482,7 @@ declare class Schema<T extends Record<string, SchemaItem> = Record<string, Schem
468
482
  static void(...inputs: ConstructorParameters<typeof SchemaVoid>): SchemaVoid;
469
483
  static never(...inputs: ConstructorParameters<typeof SchemaNever>): SchemaNever;
470
484
  static fromJSON(json: SchemaJSON): SchemaItem;
485
+ static deepParseSchemaJSON(item: unknown): unknown;
471
486
  static isSchemaJSON(data: unknown): data is SchemaJSON;
472
487
  /**
473
488
  * @deprecated use helper `parseQuery`
@@ -488,4 +503,4 @@ declare class Schema<T extends Record<string, SchemaItem> = Record<string, Schem
488
503
  }
489
504
  declare const s: typeof Schema;
490
505
 
491
- export { type Infer, type InputInfer, type Model, type ModelInfer$1 as ModelInfer, SchemaAny, SchemaArray, SchemaBoolean, SchemaDate, SchemaDefault, SchemaEnum, SchemaFile, type SchemaInfer, type SchemaInputInfer, SchemaIntersection, SchemaItem, type SchemaItemJSON, type SchemaJSON, SchemaLiteral, SchemaNever, SchemaNull, SchemaNullable, SchemaNullish, SchemaNumber, SchemaObject, SchemaRecord, SchemaString, SchemaUndefined, SchemaUnion, SchemaVoid, Types, type ValidationError, type ValidationOptions, type ValidationResult, type ValidationResultOld, Schema as default, isNull, parsable, parseForm, parseFormData, parseQuery, s };
506
+ export { type Infer, type InputInfer, type Literal, type Model, type ModelInfer$1 as ModelInfer, SchemaAny, SchemaArray, SchemaBoolean, SchemaDate, SchemaDefault, SchemaEnum, SchemaFile, type SchemaInfer, type SchemaInputInfer, SchemaIntersection, SchemaItem, type SchemaItemJSON, type SchemaJSON, SchemaLiteral, SchemaNever, SchemaNull, SchemaNullable, SchemaNullish, SchemaNumber, SchemaObject, SchemaRecord, SchemaString, SchemaUndefined, SchemaUnion, SchemaVoid, type ValidationError, type ValidationOptions, type ValidationResult, type ValidationResultOld, Schema as default, isNull, parsable, parseForm, parseFormData, parseQuery, s };
package/dist/Schema.d.ts CHANGED
@@ -3,6 +3,7 @@ import { StandardSchemaV1 } from '@standard-schema/spec';
3
3
  declare abstract class SchemaItem<Output = any, Input = Output> implements StandardSchemaV1<Input, Output> {
4
4
  readonly _output: Output;
5
5
  readonly _input: Input;
6
+ static id: string;
6
7
  '~standard': StandardSchemaV1.Props<Input, Output>;
7
8
  /**
8
9
  * Function calls saved for serialization
@@ -67,6 +68,7 @@ declare abstract class SchemaItem<Output = any, Input = Output> implements Stand
67
68
  unwrap?(): SchemaItem;
68
69
  parse(input: unknown, options?: ValidationOptions): ValidationResult<Output>;
69
70
  toJSON(): SchemaJSON;
71
+ private deepSerializeItem;
70
72
  addValidation(fn: ((input: Output) => boolean) | {
71
73
  fn: (input: Output) => boolean;
72
74
  error?: string;
@@ -128,7 +130,7 @@ type ValidationResultOld<T> = {
128
130
  */
129
131
  interface SchemaJSON {
130
132
  /** Id of the schema item (name of the constructor) */
131
- i: string
133
+ _i: string
132
134
  /** Attributes */
133
135
  a?: Array<string> | undefined
134
136
  /** Children schema items */
@@ -159,12 +161,16 @@ type ModelInfer$1<M extends Model> = {
159
161
  [key in keyof M]: SchemaInfer<M[key]>
160
162
  }
161
163
 
164
+ type Literal = string | number | bigint | boolean | null | undefined
165
+
162
166
  declare class SchemaAny extends SchemaItem {
167
+ static id: string;
163
168
  isOfType(_input: unknown): _input is any;
164
169
  }
165
170
 
166
171
  type DateFormat = 'default' | 'iso8601' | 'yy-mm-dd' | 'jj/mm/yy';
167
172
  declare class SchemaDate extends SchemaItem<Date> {
173
+ static id: string;
168
174
  parseString(format?: DateFormat): this;
169
175
  isOfType(input: unknown): input is Date;
170
176
  }
@@ -172,6 +178,7 @@ declare class SchemaDate extends SchemaItem<Date> {
172
178
  declare class SchemaRecord<Keys extends SchemaItem<string | number | symbol>, Values extends SchemaItem> extends SchemaItem<Record<SchemaInfer<Keys>, SchemaInfer<Values>>> {
173
179
  private readonly keys;
174
180
  private readonly values;
181
+ static id: string;
175
182
  constructor(keys: Keys, values: Values);
176
183
  isOfType(input: unknown): input is Record<SchemaInfer<Keys>, SchemaInfer<Values>>;
177
184
  protected parseSubItems(input: unknown, options?: ValidationOptions): {
@@ -182,11 +189,13 @@ declare class SchemaRecord<Keys extends SchemaItem<string | number | symbol>, Va
182
189
 
183
190
  declare class SchemaArray<Child extends SchemaItem, Output = SchemaInfer<Child>, Input = SchemaInputInfer<Child>> extends SchemaItem<Array<Output>, Array<Input>> {
184
191
  readonly values: Child;
192
+ static id: string;
185
193
  constructor(values: Child);
186
194
  /**
187
195
  * transform the array so it only contains one of each elements
188
196
  */
189
197
  unique(): this;
198
+ clean(): this;
190
199
  /**
191
200
  * split a string into an array
192
201
  * @param [separator] default:`,` the separator to use
@@ -202,6 +211,7 @@ declare class SchemaArray<Child extends SchemaItem, Output = SchemaInfer<Child>,
202
211
  }
203
212
 
204
213
  declare class SchemaBoolean extends SchemaItem<boolean> {
214
+ static id: string;
205
215
  /**
206
216
  * @param [trueValue='true'] the truhty value (default to `'true'`)
207
217
  * @param [falseValue='false'] the falthy value (default to `'false'`)
@@ -216,21 +226,26 @@ interface EnumLike {
216
226
  }
217
227
  declare class SchemaEnum<E extends EnumLike> extends SchemaItem<E[keyof E]> {
218
228
  private readonly templateEnum;
229
+ static id: string;
219
230
  private readonly type;
220
231
  constructor(templateEnum: E);
221
232
  isOfType(input: unknown): input is E[keyof E];
222
233
  }
223
234
 
224
- declare class SchemaLiteral<Type> extends SchemaItem<Type> {
225
- private readonly value;
226
- constructor(value: Type);
227
- isOfType(input: unknown): input is Type;
235
+ declare class SchemaLiteral<Types extends Array<Literal>> extends SchemaItem<Types[number]> {
236
+ static id: string;
237
+ private readonly values;
238
+ constructor(...values: Types);
239
+ isOfType(input: unknown): input is Types[number];
228
240
  }
229
241
 
230
242
  declare class SchemaNullable<Child extends SchemaItem, Output = SchemaInfer<Child>, Input = SchemaInputInfer<Child>> extends SchemaItem<Output | undefined, Input | null | undefined> {
231
243
  private readonly child;
244
+ static id: string;
232
245
  constructor(child: Child);
233
246
  falsyAsNull(): this;
247
+ emptyAsNull(): this;
248
+ emptyFileAsNull(): this;
234
249
  unwrap(): Child;
235
250
  isOfType(input: unknown): input is Output | undefined;
236
251
  protected getSubInputs(input: unknown): Array<{
@@ -245,6 +260,7 @@ declare class SchemaNullable<Child extends SchemaItem, Output = SchemaInfer<Chil
245
260
  }
246
261
 
247
262
  declare class SchemaNumber extends SchemaItem<number> {
263
+ static id: string;
248
264
  /**
249
265
  * validate that the number is less or equal than {@link value}
250
266
  * @param value the maxumum value (inclusive)
@@ -283,7 +299,7 @@ type ModelInfer<M extends Record<string, SchemaItem>> = {
283
299
  };
284
300
  declare class SchemaObject<T extends Record<string, SchemaItem> = any> extends SchemaItem<ModelInfer<T>> {
285
301
  readonly model: T;
286
- id: string;
302
+ static id: string;
287
303
  constructor(model: T);
288
304
  isOfType(input: unknown): input is ModelInfer<T>;
289
305
  protected getSubInputs(input: unknown): Array<{
@@ -294,6 +310,7 @@ declare class SchemaObject<T extends Record<string, SchemaItem> = any> extends S
294
310
  }
295
311
 
296
312
  declare class SchemaString extends SchemaItem<string> {
313
+ static id: string;
297
314
  /**
298
315
  * force the input text to be a minimum of `value` size
299
316
  * @param value the minimum length of the text
@@ -323,12 +340,18 @@ declare class SchemaString extends SchemaItem<string> {
323
340
  * @param message the message to display on an error
324
341
  */
325
342
  regex(regex: RegExp, message?: string): this;
343
+ /**
344
+ * force the input text to be an email
345
+ * @param message the message to display on an error
346
+ */
347
+ email(message?: string): this;
326
348
  minLength(value: number, message?: string): this;
327
349
  maxLength(value: number, message?: string): this;
328
350
  isOfType(input: unknown): input is string;
329
351
  }
330
352
 
331
353
  declare class SchemaUnion<Children extends Array<SchemaItem>, Outputs = SchemaInfer<Children[number]>, Inputs = SchemaInputInfer<Children[number]>> extends SchemaItem<Outputs, Inputs> {
354
+ static id: string;
332
355
  private readonly schemas;
333
356
  constructor(...schemas: Children);
334
357
  isOfType(input: unknown): input is Outputs;
@@ -343,6 +366,7 @@ type Prettify<T> = T extends unknown ? {
343
366
  } : never;
344
367
  type UnionToIntersection<U> = (U extends U ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
345
368
  declare class SchemaIntersection<Children extends Array<SchemaItem>, Outputs = Prettify<UnionToIntersection<SchemaInfer<Children[number]>>>, Inputs = Prettify<UnionToIntersection<SchemaInfer<Children[number]>>>> extends SchemaItem<Outputs, Inputs> {
369
+ static id: string;
346
370
  private readonly schemas;
347
371
  constructor(...schemas: Children);
348
372
  isOfType(input: unknown): input is Outputs;
@@ -356,6 +380,7 @@ declare class SchemaDefault<Child extends SchemaItem, Output = SchemaInfer<Child
356
380
  private readonly child;
357
381
  private readonly defaultVal;
358
382
  private readonly strict;
383
+ static id: string;
359
384
  constructor(child: Child, defaultVal: Output, strict?: boolean);
360
385
  unwrap(): Child;
361
386
  isOfType(input: unknown): input is Output;
@@ -367,6 +392,7 @@ declare class SchemaDefault<Child extends SchemaItem, Output = SchemaInfer<Child
367
392
  }
368
393
 
369
394
  declare class SchemaFile extends SchemaItem<File> {
395
+ static id: string;
370
396
  constructor();
371
397
  extension(ext: string, error?: string): this;
372
398
  maxSize(size: number, error?: string): this;
@@ -376,6 +402,7 @@ declare class SchemaFile extends SchemaItem<File> {
376
402
  type TupleToOutputs<Tuple extends Array<SchemaItem>, Result extends Array<any> = []> = number extends Tuple['length'] ? Array<SchemaInfer<Tuple[number]>> : Tuple[Result['length']] extends undefined ? Result : TupleToOutputs<Tuple, [...Result, SchemaInfer<Tuple[Result['length']]>]>;
377
403
  type TupleToInputs<Tuple extends Array<SchemaItem>, Result extends Array<any> = []> = number extends Tuple['length'] ? Array<SchemaInputInfer<Tuple[number]>> : Tuple[Result['length']] extends undefined ? Result : TupleToInputs<Tuple, [...Result, SchemaInputInfer<Tuple[Result['length']]>]>;
378
404
  declare class SchemaTuple<Children extends Array<SchemaItem>, Outputs = TupleToOutputs<Children>, Inputs = TupleToInputs<Children>> extends SchemaItem<Outputs, Inputs> {
405
+ static id: string;
379
406
  private readonly children;
380
407
  constructor(...children: Children);
381
408
  isOfType(input: unknown): input is Outputs;
@@ -387,18 +414,23 @@ declare class SchemaTuple<Children extends Array<SchemaItem>, Outputs = TupleToO
387
414
  }
388
415
 
389
416
  declare class SchemaUndefined extends SchemaItem<undefined> {
417
+ static id: string;
390
418
  isOfType(input: unknown): input is undefined;
391
419
  }
392
420
  declare class SchemaNull extends SchemaItem<null> {
421
+ static id: string;
393
422
  isOfType(input: unknown): input is null;
394
423
  }
395
424
  declare class SchemaVoid extends SchemaItem<void> {
425
+ static id: string;
396
426
  isOfType(input: unknown): input is void;
397
427
  }
398
428
  declare class SchemaNullish extends SchemaItem<null | undefined> {
429
+ static id: string;
399
430
  isOfType(input: unknown): input is null | undefined;
400
431
  }
401
432
  declare class SchemaNever extends SchemaItem<never> {
433
+ static id: string;
402
434
  isOfType(_input: unknown): _input is never;
403
435
  }
404
436
 
@@ -414,31 +446,13 @@ declare function parseForm<T extends SchemaItem>(model: T, form: HTMLFormElement
414
446
  * Decorator for modifier functions on SchemaItems to save them in the "savedCalls" property for the serialization
415
447
  */
416
448
  declare function parsable(): (target: object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<any>) => TypedPropertyDescriptor<any>;
417
- type SchemaItemStatic = new (...args: Array<any>) => SchemaItem;
418
- declare const Types: {
419
- readonly Any: typeof SchemaAny;
420
- readonly Array: typeof SchemaArray;
421
- readonly Tuple: typeof SchemaTuple;
422
- readonly Boolean: typeof SchemaBoolean;
423
- readonly Date: typeof SchemaDate;
424
- readonly Enum: typeof SchemaEnum;
425
- readonly Literal: typeof SchemaLiteral;
426
- readonly Nullable: typeof SchemaNullable;
427
- readonly Object: typeof SchemaObject;
428
- readonly Record: typeof SchemaRecord;
429
- readonly String: typeof SchemaString;
430
- readonly Union: typeof SchemaUnion;
431
- readonly Intersection: typeof SchemaIntersection;
432
- readonly Default: typeof SchemaDefault;
433
- readonly Undefined: typeof SchemaUndefined;
434
- readonly Void: typeof SchemaVoid;
435
- readonly Null: typeof SchemaNull;
436
- readonly Nullish: typeof SchemaNullish;
449
+ type SchemaItemStatic = (new (...args: Array<any>) => SchemaItem) & {
450
+ id: string;
437
451
  };
438
452
  declare class Schema<T extends Record<string, SchemaItem> = Record<string, SchemaItem>> extends SchemaObject<T> {
439
453
  private static readonly registeredModules;
440
454
  static register(module: SchemaItemStatic): void;
441
- static getModule(name: string): SchemaItemStatic | undefined;
455
+ static getModule(name: string): SchemaItemStatic;
442
456
  static any(): SchemaAny;
443
457
  static array<Type extends SchemaItem>(...inputs: ConstructorParameters<typeof SchemaArray<Type>>): SchemaArray<Type>;
444
458
  static boolean(...inputs: ConstructorParameters<typeof SchemaBoolean>): SchemaBoolean;
@@ -449,7 +463,7 @@ declare class Schema<T extends Record<string, SchemaItem> = Record<string, Schem
449
463
  * @param input the literal value (note: append `as const` else the typing won't work correctly)
450
464
  * @returns
451
465
  */
452
- static literal<Type>(input: Type): SchemaLiteral<Type>;
466
+ static literal<Type extends Array<Literal>>(...inputs: ConstructorParameters<typeof SchemaLiteral<Type>>): SchemaLiteral<Type>;
453
467
  static nullable<Type extends SchemaItem>(...inputs: ConstructorParameters<typeof SchemaNullable<Type>>): SchemaNullable<Type>;
454
468
  static number(...inputs: ConstructorParameters<typeof SchemaNumber>): SchemaNumber;
455
469
  static object<Type extends Record<string, SchemaItem>>(...inputs: ConstructorParameters<typeof SchemaObject<Type>>): SchemaObject<Type>;
@@ -468,6 +482,7 @@ declare class Schema<T extends Record<string, SchemaItem> = Record<string, Schem
468
482
  static void(...inputs: ConstructorParameters<typeof SchemaVoid>): SchemaVoid;
469
483
  static never(...inputs: ConstructorParameters<typeof SchemaNever>): SchemaNever;
470
484
  static fromJSON(json: SchemaJSON): SchemaItem;
485
+ static deepParseSchemaJSON(item: unknown): unknown;
471
486
  static isSchemaJSON(data: unknown): data is SchemaJSON;
472
487
  /**
473
488
  * @deprecated use helper `parseQuery`
@@ -488,4 +503,4 @@ declare class Schema<T extends Record<string, SchemaItem> = Record<string, Schem
488
503
  }
489
504
  declare const s: typeof Schema;
490
505
 
491
- export { type Infer, type InputInfer, type Model, type ModelInfer$1 as ModelInfer, SchemaAny, SchemaArray, SchemaBoolean, SchemaDate, SchemaDefault, SchemaEnum, SchemaFile, type SchemaInfer, type SchemaInputInfer, SchemaIntersection, SchemaItem, type SchemaItemJSON, type SchemaJSON, SchemaLiteral, SchemaNever, SchemaNull, SchemaNullable, SchemaNullish, SchemaNumber, SchemaObject, SchemaRecord, SchemaString, SchemaUndefined, SchemaUnion, SchemaVoid, Types, type ValidationError, type ValidationOptions, type ValidationResult, type ValidationResultOld, Schema as default, isNull, parsable, parseForm, parseFormData, parseQuery, s };
506
+ export { type Infer, type InputInfer, type Literal, type Model, type ModelInfer$1 as ModelInfer, SchemaAny, SchemaArray, SchemaBoolean, SchemaDate, SchemaDefault, SchemaEnum, SchemaFile, type SchemaInfer, type SchemaInputInfer, SchemaIntersection, SchemaItem, type SchemaItemJSON, type SchemaJSON, SchemaLiteral, SchemaNever, SchemaNull, SchemaNullable, SchemaNullish, SchemaNumber, SchemaObject, SchemaRecord, SchemaString, SchemaUndefined, SchemaUnion, SchemaVoid, type ValidationError, type ValidationOptions, type ValidationResult, type ValidationResultOld, Schema as default, isNull, parsable, parseForm, parseFormData, parseQuery, s };
package/dist/Schema.js CHANGED
@@ -49,7 +49,6 @@ __export(Schema_exports, {
49
49
  SchemaUndefined: () => SchemaUndefined,
50
50
  SchemaUnion: () => SchemaUnion,
51
51
  SchemaVoid: () => SchemaVoid,
52
- Types: () => Types,
53
52
  default: () => Schema,
54
53
  isNull: () => isNull,
55
54
  parsable: () => parsable,
@@ -180,7 +179,7 @@ var _SchemaItem = class _SchemaItem {
180
179
  if (!this.isOfType(input)) {
181
180
  return {
182
181
  valid: false,
183
- errors: [{ message: "invalid type" }]
182
+ errors: [{ message: this.invalidError }]
184
183
  };
185
184
  }
186
185
  const validationErrors = [];
@@ -212,14 +211,24 @@ var _SchemaItem = class _SchemaItem {
212
211
  toJSON() {
213
212
  var _a;
214
213
  const res = {
215
- i: this.constructor.name,
214
+ _i: this.constructor.id,
216
215
  a: this.attributes.length > 0 ? this.attributes : void 0,
217
- c: (_a = this.items) == null ? void 0 : _a.map((it) => it instanceof _SchemaItem ? it.toJSON() : it),
216
+ c: (_a = this.items) == null ? void 0 : _a.map((it) => this.deepSerializeItem(it)),
218
217
  f: this.savedCalls.map((it) => it.args ? { n: it.name, a: Array.from(it.args) } : { n: it.name })
219
218
  };
220
219
  (0, import_object_util.objectClean)(res, { deep: false });
221
220
  return res;
222
221
  }
222
+ deepSerializeItem(item) {
223
+ if (item instanceof _SchemaItem) {
224
+ return item.toJSON();
225
+ } else if (Array.isArray(item)) {
226
+ return item.map((it) => this.deepSerializeItem(it));
227
+ } else if ((0, import_object_util.isObject)(item)) {
228
+ return (0, import_object_util.objectRemap)(item, (value, key) => ({ value: this.deepSerializeItem(value), key }));
229
+ }
230
+ return item;
231
+ }
223
232
  addValidation(fn, error) {
224
233
  this.validations.push(typeof fn === "function" ? { fn, error } : fn);
225
234
  return this;
@@ -283,6 +292,10 @@ var SchemaArray = class extends SchemaItem {
283
292
  this.postProcess.push((input) => input.filter((it, idx) => input.indexOf(it) === idx));
284
293
  return this;
285
294
  }
295
+ clean() {
296
+ this.postProcess.push((input) => input.filter((it) => !isNull(it)));
297
+ return this;
298
+ }
286
299
  split(separator = ",") {
287
300
  this.addPreProcess((it) => typeof it === "string" ? it.split(separator) : it);
288
301
  return this;
@@ -297,9 +310,13 @@ var SchemaArray = class extends SchemaItem {
297
310
  return Array.isArray(input) ? input.map((entry, index) => ({ item: this.values, value: entry, path: index.toString() })) : [];
298
311
  }
299
312
  };
313
+ SchemaArray.id = "array";
300
314
  __decorateClass([
301
315
  parsable()
302
316
  ], SchemaArray.prototype, "unique", 1);
317
+ __decorateClass([
318
+ parsable()
319
+ ], SchemaArray.prototype, "clean", 1);
303
320
  __decorateClass([
304
321
  parsable()
305
322
  ], SchemaArray.prototype, "split", 1);
@@ -325,6 +342,7 @@ var SchemaBoolean = class extends SchemaItem {
325
342
  return typeof input === "boolean";
326
343
  }
327
344
  };
345
+ SchemaBoolean.id = "boolean";
328
346
  __decorateClass([
329
347
  parsable()
330
348
  ], SchemaBoolean.prototype, "parseString", 1);
@@ -339,6 +357,14 @@ var SchemaNullable = class extends SchemaItem {
339
357
  this.addPreProcess((it) => !it ? void 0 : it);
340
358
  return this;
341
359
  }
360
+ emptyAsNull() {
361
+ this.addPreProcess((it) => it === "" ? void 0 : it);
362
+ return this;
363
+ }
364
+ emptyFileAsNull() {
365
+ this.addPreProcess((it) => it instanceof File && it.size === 0 ? void 0 : it);
366
+ return this;
367
+ }
342
368
  unwrap() {
343
369
  return this.child;
344
370
  }
@@ -355,9 +381,16 @@ var SchemaNullable = class extends SchemaItem {
355
381
  return super.parseSubItems(input, options);
356
382
  }
357
383
  };
384
+ SchemaNullable.id = "nullable";
358
385
  __decorateClass([
359
386
  parsable()
360
387
  ], SchemaNullable.prototype, "falsyAsNull", 1);
388
+ __decorateClass([
389
+ parsable()
390
+ ], SchemaNullable.prototype, "emptyAsNull", 1);
391
+ __decorateClass([
392
+ parsable()
393
+ ], SchemaNullable.prototype, "emptyFileAsNull", 1);
361
394
 
362
395
  // src/items/object.ts
363
396
  var import_object_util2 = require("@dzeio/object-util");
@@ -365,7 +398,6 @@ var SchemaObject = class extends SchemaItem {
365
398
  constructor(model) {
366
399
  super([model]);
367
400
  this.model = model;
368
- this.id = "object";
369
401
  }
370
402
  isOfType(input) {
371
403
  return (0, import_object_util2.isObject)(input) && !(0, import_object_util2.objectFind)(this.model, (item, key) => !item.isOfType(input[key]));
@@ -374,6 +406,7 @@ var SchemaObject = class extends SchemaItem {
374
406
  return (0, import_object_util2.isObject)(input) ? (0, import_object_util2.objectMap)(this.model, (schema, key) => ({ item: schema, value: input[key], path: key.toString() })) : [];
375
407
  }
376
408
  };
409
+ SchemaObject.id = "object";
377
410
 
378
411
  // src/helpers.ts
379
412
  function isNull(value) {
@@ -384,7 +417,8 @@ function parseQuery(schema, query, opts) {
384
417
  for (const [key, value] of query) {
385
418
  const keys = key.split(".").map((it) => /^\d+$/g.test(it) ? Number.parseInt(it, 10) : it);
386
419
  const schemaItem = getSchemaItemAtPath(schema, keys);
387
- const finalValue = schemaItem instanceof SchemaArray ? query.getAll(key) : value;
420
+ const allValues = query.getAll(key);
421
+ const finalValue = schemaItem && schemaItem.parse(allValues).valid ? allValues : value;
388
422
  (0, import_object_util3.objectSet)(record, keys, finalValue);
389
423
  }
390
424
  return schema.parse(record, opts);
@@ -394,7 +428,8 @@ function parseFormData(schema, data, opts) {
394
428
  for (const [key, value] of data) {
395
429
  const keys = key.split(".").map((it) => /^\d+$/g.test(it) ? Number.parseInt(it, 10) : it);
396
430
  const schemaItem = getSchemaItemAtPath(schema, keys);
397
- const finalValue = schemaItem instanceof SchemaArray ? data.getAll(key) : value;
431
+ const allValues = data.getAll(key);
432
+ const finalValue = schemaItem && schemaItem.parse(allValues).valid ? allValues : value;
398
433
  (0, import_object_util3.objectSet)(record, keys, finalValue);
399
434
  }
400
435
  const handleBoolean = (value, keys) => {
@@ -456,6 +491,7 @@ var SchemaAny = class extends SchemaItem {
456
491
  return true;
457
492
  }
458
493
  };
494
+ SchemaAny.id = "any";
459
495
 
460
496
  // src/items/date.ts
461
497
  var SchemaDate = class extends SchemaItem {
@@ -499,6 +535,7 @@ var SchemaDate = class extends SchemaItem {
499
535
  return input instanceof Date;
500
536
  }
501
537
  };
538
+ SchemaDate.id = "date";
502
539
  __decorateClass([
503
540
  parsable()
504
541
  ], SchemaDate.prototype, "parseString", 1);
@@ -537,6 +574,7 @@ var SchemaRecord = class extends SchemaItem {
537
574
  return result;
538
575
  }
539
576
  };
577
+ SchemaRecord.id = "record";
540
578
 
541
579
  // src/items/enum.ts
542
580
  var SchemaEnum = class extends SchemaItem {
@@ -557,18 +595,20 @@ var SchemaEnum = class extends SchemaItem {
557
595
  return typeof input === this.type;
558
596
  }
559
597
  };
598
+ SchemaEnum.id = "enum";
560
599
 
561
600
  // src/items/literal.ts
562
601
  var SchemaLiteral = class extends SchemaItem {
563
- constructor(value) {
564
- super([value]);
565
- this.value = value;
566
- this.validations.push({ fn: (it) => it === this.value });
602
+ constructor(...values) {
603
+ super(values);
604
+ this.values = values;
605
+ this.validations.push({ fn: (it) => this.values.includes(it) });
567
606
  }
568
607
  isOfType(input) {
569
- return typeof input === typeof this.value;
608
+ return this.values.some((it) => typeof input === typeof it);
570
609
  }
571
610
  };
611
+ SchemaLiteral.id = "literal";
572
612
 
573
613
  // src/items/number.ts
574
614
  var SchemaNumber = class extends SchemaItem {
@@ -622,6 +662,7 @@ var SchemaNumber = class extends SchemaItem {
622
662
  return this.lte(...params);
623
663
  }
624
664
  };
665
+ SchemaNumber.id = "number";
625
666
  __decorateClass([
626
667
  parsable()
627
668
  ], SchemaNumber.prototype, "lte", 1);
@@ -681,6 +722,15 @@ var SchemaString = class extends SchemaItem {
681
722
  });
682
723
  return this;
683
724
  }
725
+ email(message) {
726
+ this.addValidation({
727
+ fn(input) {
728
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input);
729
+ },
730
+ error: message
731
+ });
732
+ return this;
733
+ }
684
734
  minLength(value, message) {
685
735
  return this.min(value, message);
686
736
  }
@@ -691,6 +741,7 @@ var SchemaString = class extends SchemaItem {
691
741
  return typeof input === "string";
692
742
  }
693
743
  };
744
+ SchemaString.id = "string";
694
745
  __decorateClass([
695
746
  parsable()
696
747
  ], SchemaString.prototype, "min", 1);
@@ -706,6 +757,9 @@ __decorateClass([
706
757
  __decorateClass([
707
758
  parsable()
708
759
  ], SchemaString.prototype, "regex", 1);
760
+ __decorateClass([
761
+ parsable()
762
+ ], SchemaString.prototype, "email", 1);
709
763
 
710
764
  // src/items/union.ts
711
765
  var SchemaUnion = class extends SchemaItem {
@@ -729,6 +783,7 @@ var SchemaUnion = class extends SchemaItem {
729
783
  return result;
730
784
  }
731
785
  };
786
+ SchemaUnion.id = "union";
732
787
 
733
788
  // src/items/intersection.ts
734
789
  var import_object_util5 = require("@dzeio/object-util");
@@ -757,6 +812,7 @@ var SchemaIntersection = class extends SchemaItem {
757
812
  return result;
758
813
  }
759
814
  };
815
+ SchemaIntersection.id = "intersection";
760
816
 
761
817
  // src/items/default.ts
762
818
  var SchemaDefault = class extends SchemaItem {
@@ -776,6 +832,7 @@ var SchemaDefault = class extends SchemaItem {
776
832
  return [{ item: this.child, value: isNull(input) || !this.strict && !input ? this.defaultVal : input, path: void 0 }];
777
833
  }
778
834
  };
835
+ SchemaDefault.id = "default";
779
836
 
780
837
  // src/items/file.ts
781
838
  var SchemaFile = class extends SchemaItem {
@@ -795,6 +852,7 @@ var SchemaFile = class extends SchemaItem {
795
852
  return input instanceof File;
796
853
  }
797
854
  };
855
+ SchemaFile.id = "file";
798
856
  __decorateClass([
799
857
  parsable()
800
858
  ], SchemaFile.prototype, "extension", 1);
@@ -823,6 +881,7 @@ var SchemaTuple = class extends SchemaItem {
823
881
  return Array.isArray(input) ? this.children.map((entry, index) => ({ value: input[index], item: entry, path: index.toString() })) : [];
824
882
  }
825
883
  };
884
+ SchemaTuple.id = "tuple";
826
885
 
827
886
  // src/items/nullish.ts
828
887
  var SchemaUndefined = class extends SchemaItem {
@@ -830,28 +889,34 @@ var SchemaUndefined = class extends SchemaItem {
830
889
  return typeof input === "undefined";
831
890
  }
832
891
  };
892
+ SchemaUndefined.id = "undefined";
833
893
  var SchemaNull = class extends SchemaItem {
834
894
  isOfType(input) {
835
895
  return input === null;
836
896
  }
837
897
  };
898
+ SchemaNull.id = "null";
838
899
  var SchemaVoid = class extends SchemaItem {
839
900
  isOfType(input) {
840
901
  return typeof input === "undefined";
841
902
  }
842
903
  };
904
+ SchemaVoid.id = "void";
843
905
  var SchemaNullish = class extends SchemaItem {
844
906
  isOfType(input) {
845
907
  return isNull(input);
846
908
  }
847
909
  };
910
+ SchemaNullish.id = "nullish";
848
911
  var SchemaNever = class extends SchemaItem {
849
912
  isOfType(_input) {
850
913
  return false;
851
914
  }
852
915
  };
916
+ SchemaNever.id = "never";
853
917
 
854
918
  // src/Schema.ts
919
+ var import_object_util6 = require("@dzeio/object-util");
855
920
  function parsable() {
856
921
  return (target, propertyKey, descriptor) => {
857
922
  if (!(propertyKey in target)) {
@@ -866,32 +931,16 @@ function parsable() {
866
931
  return descriptor;
867
932
  };
868
933
  }
869
- var Types = {
870
- Any: SchemaAny,
871
- Array: SchemaArray,
872
- Tuple: SchemaTuple,
873
- Boolean: SchemaBoolean,
874
- Date: SchemaDate,
875
- Enum: SchemaEnum,
876
- Literal: SchemaLiteral,
877
- Nullable: SchemaNullable,
878
- Object: SchemaObject,
879
- Record: SchemaRecord,
880
- String: SchemaString,
881
- Union: SchemaUnion,
882
- Intersection: SchemaIntersection,
883
- Default: SchemaDefault,
884
- Undefined: SchemaUndefined,
885
- Void: SchemaVoid,
886
- Null: SchemaNull,
887
- Nullish: SchemaNullish
888
- };
889
934
  var _Schema = class _Schema extends SchemaObject {
890
935
  static register(module2) {
891
936
  this.registeredModules.push(module2);
892
937
  }
893
938
  static getModule(name) {
894
- return this.registeredModules.find((it) => it.name === name);
939
+ const module2 = this.registeredModules.find((it) => it.id === name);
940
+ if (!module2) {
941
+ console.log("Couldn't find module", name);
942
+ }
943
+ return module2 != null ? module2 : SchemaAny;
895
944
  }
896
945
  static any() {
897
946
  return new SchemaAny();
@@ -913,8 +962,8 @@ var _Schema = class _Schema extends SchemaObject {
913
962
  * @param input the literal value (note: append `as const` else the typing won't work correctly)
914
963
  * @returns
915
964
  */
916
- static literal(input) {
917
- return new SchemaLiteral(input);
965
+ static literal(...inputs) {
966
+ return new SchemaLiteral(...inputs);
918
967
  }
919
968
  static nullable(...inputs) {
920
969
  return new SchemaNullable(...inputs);
@@ -963,25 +1012,35 @@ var _Schema = class _Schema extends SchemaObject {
963
1012
  }
964
1013
  static fromJSON(json) {
965
1014
  var _a, _b, _c, _d, _e, _f;
966
- const fn = this.getModule(json.i);
1015
+ const fn = this.getModule(json._i);
967
1016
  if (!fn) {
968
- throw new Error(`Schema cannot parse ${json.i}`);
1017
+ throw new Error(`Schema cannot parse ${json._i}`);
969
1018
  }
970
- const item = new fn(...(_b = (_a = json.c) == null ? void 0 : _a.map((it) => this.isSchemaJSON(it) ? _Schema.fromJSON(it) : it)) != null ? _b : []);
1019
+ const item = new fn(...(_b = (_a = json.c) == null ? void 0 : _a.map((it) => this.deepParseSchemaJSON(it))) != null ? _b : []);
971
1020
  for (const validation of (_c = json.f) != null ? _c : []) {
972
1021
  if (!(validation.n in item)) {
973
1022
  throw new Error("validation not available in Schema Item");
974
1023
  }
975
- item[validation.n](...(_e = (_d = validation.a) == null ? void 0 : _d.map((it) => _Schema.isSchemaJSON(it) ? _Schema.fromJSON(it) : it)) != null ? _e : []);
1024
+ item[validation.n](...(_e = (_d = validation.a) == null ? void 0 : _d.map((it) => this.deepParseSchemaJSON(it))) != null ? _e : []);
976
1025
  }
977
1026
  item.attrs(...(_f = json.a) != null ? _f : []);
978
1027
  return item;
979
1028
  }
1029
+ static deepParseSchemaJSON(item) {
1030
+ if (this.isSchemaJSON(item)) {
1031
+ return _Schema.fromJSON(item);
1032
+ } else if (Array.isArray(item)) {
1033
+ return item.map((it) => this.deepParseSchemaJSON(it));
1034
+ } else if ((0, import_object_util6.isObject)(item)) {
1035
+ return (0, import_object_util6.objectRemap)(item, (value, key) => ({ value: this.deepParseSchemaJSON(value), key }));
1036
+ }
1037
+ return item;
1038
+ }
980
1039
  static isSchemaJSON(data) {
981
1040
  if (typeof data !== "object" || data === null) {
982
1041
  return false;
983
1042
  }
984
- if (!("i" in data)) {
1043
+ if (!("_i" in data)) {
985
1044
  return false;
986
1045
  }
987
1046
  return true;
@@ -1028,7 +1087,10 @@ _Schema.registeredModules = [
1028
1087
  SchemaUndefined,
1029
1088
  SchemaVoid,
1030
1089
  SchemaNull,
1031
- SchemaNullish
1090
+ SchemaNullish,
1091
+ SchemaFile,
1092
+ SchemaAny,
1093
+ SchemaNumber
1032
1094
  ];
1033
1095
  var Schema = _Schema;
1034
1096
  var s = Schema;
@@ -1055,7 +1117,6 @@ var s = Schema;
1055
1117
  SchemaUndefined,
1056
1118
  SchemaUnion,
1057
1119
  SchemaVoid,
1058
- Types,
1059
1120
  isNull,
1060
1121
  parsable,
1061
1122
  parseForm,
package/dist/Schema.mjs CHANGED
@@ -13,7 +13,7 @@ var __decorateClass = (decorators, target, key, kind) => {
13
13
  import { objectClone, objectGet, objectLoop, objectSet as objectSet2 } from "@dzeio/object-util";
14
14
 
15
15
  // src/SchemaItem.ts
16
- import { isObject, objectClean, objectSet } from "@dzeio/object-util";
16
+ import { isObject, objectClean, objectRemap, objectSet } from "@dzeio/object-util";
17
17
  var _SchemaItem = class _SchemaItem {
18
18
  constructor(items) {
19
19
  // standard Schema V1 spec
@@ -129,7 +129,7 @@ var _SchemaItem = class _SchemaItem {
129
129
  if (!this.isOfType(input)) {
130
130
  return {
131
131
  valid: false,
132
- errors: [{ message: "invalid type" }]
132
+ errors: [{ message: this.invalidError }]
133
133
  };
134
134
  }
135
135
  const validationErrors = [];
@@ -161,14 +161,24 @@ var _SchemaItem = class _SchemaItem {
161
161
  toJSON() {
162
162
  var _a;
163
163
  const res = {
164
- i: this.constructor.name,
164
+ _i: this.constructor.id,
165
165
  a: this.attributes.length > 0 ? this.attributes : void 0,
166
- c: (_a = this.items) == null ? void 0 : _a.map((it) => it instanceof _SchemaItem ? it.toJSON() : it),
166
+ c: (_a = this.items) == null ? void 0 : _a.map((it) => this.deepSerializeItem(it)),
167
167
  f: this.savedCalls.map((it) => it.args ? { n: it.name, a: Array.from(it.args) } : { n: it.name })
168
168
  };
169
169
  objectClean(res, { deep: false });
170
170
  return res;
171
171
  }
172
+ deepSerializeItem(item) {
173
+ if (item instanceof _SchemaItem) {
174
+ return item.toJSON();
175
+ } else if (Array.isArray(item)) {
176
+ return item.map((it) => this.deepSerializeItem(it));
177
+ } else if (isObject(item)) {
178
+ return objectRemap(item, (value, key) => ({ value: this.deepSerializeItem(value), key }));
179
+ }
180
+ return item;
181
+ }
172
182
  addValidation(fn, error) {
173
183
  this.validations.push(typeof fn === "function" ? { fn, error } : fn);
174
184
  return this;
@@ -232,6 +242,10 @@ var SchemaArray = class extends SchemaItem {
232
242
  this.postProcess.push((input) => input.filter((it, idx) => input.indexOf(it) === idx));
233
243
  return this;
234
244
  }
245
+ clean() {
246
+ this.postProcess.push((input) => input.filter((it) => !isNull(it)));
247
+ return this;
248
+ }
235
249
  split(separator = ",") {
236
250
  this.addPreProcess((it) => typeof it === "string" ? it.split(separator) : it);
237
251
  return this;
@@ -246,9 +260,13 @@ var SchemaArray = class extends SchemaItem {
246
260
  return Array.isArray(input) ? input.map((entry, index) => ({ item: this.values, value: entry, path: index.toString() })) : [];
247
261
  }
248
262
  };
263
+ SchemaArray.id = "array";
249
264
  __decorateClass([
250
265
  parsable()
251
266
  ], SchemaArray.prototype, "unique", 1);
267
+ __decorateClass([
268
+ parsable()
269
+ ], SchemaArray.prototype, "clean", 1);
252
270
  __decorateClass([
253
271
  parsable()
254
272
  ], SchemaArray.prototype, "split", 1);
@@ -274,6 +292,7 @@ var SchemaBoolean = class extends SchemaItem {
274
292
  return typeof input === "boolean";
275
293
  }
276
294
  };
295
+ SchemaBoolean.id = "boolean";
277
296
  __decorateClass([
278
297
  parsable()
279
298
  ], SchemaBoolean.prototype, "parseString", 1);
@@ -288,6 +307,14 @@ var SchemaNullable = class extends SchemaItem {
288
307
  this.addPreProcess((it) => !it ? void 0 : it);
289
308
  return this;
290
309
  }
310
+ emptyAsNull() {
311
+ this.addPreProcess((it) => it === "" ? void 0 : it);
312
+ return this;
313
+ }
314
+ emptyFileAsNull() {
315
+ this.addPreProcess((it) => it instanceof File && it.size === 0 ? void 0 : it);
316
+ return this;
317
+ }
291
318
  unwrap() {
292
319
  return this.child;
293
320
  }
@@ -304,9 +331,16 @@ var SchemaNullable = class extends SchemaItem {
304
331
  return super.parseSubItems(input, options);
305
332
  }
306
333
  };
334
+ SchemaNullable.id = "nullable";
307
335
  __decorateClass([
308
336
  parsable()
309
337
  ], SchemaNullable.prototype, "falsyAsNull", 1);
338
+ __decorateClass([
339
+ parsable()
340
+ ], SchemaNullable.prototype, "emptyAsNull", 1);
341
+ __decorateClass([
342
+ parsable()
343
+ ], SchemaNullable.prototype, "emptyFileAsNull", 1);
310
344
 
311
345
  // src/items/object.ts
312
346
  import { isObject as isObject2, objectFind, objectMap } from "@dzeio/object-util";
@@ -314,7 +348,6 @@ var SchemaObject = class extends SchemaItem {
314
348
  constructor(model) {
315
349
  super([model]);
316
350
  this.model = model;
317
- this.id = "object";
318
351
  }
319
352
  isOfType(input) {
320
353
  return isObject2(input) && !objectFind(this.model, (item, key) => !item.isOfType(input[key]));
@@ -323,6 +356,7 @@ var SchemaObject = class extends SchemaItem {
323
356
  return isObject2(input) ? objectMap(this.model, (schema, key) => ({ item: schema, value: input[key], path: key.toString() })) : [];
324
357
  }
325
358
  };
359
+ SchemaObject.id = "object";
326
360
 
327
361
  // src/helpers.ts
328
362
  function isNull(value) {
@@ -333,7 +367,8 @@ function parseQuery(schema, query, opts) {
333
367
  for (const [key, value] of query) {
334
368
  const keys = key.split(".").map((it) => /^\d+$/g.test(it) ? Number.parseInt(it, 10) : it);
335
369
  const schemaItem = getSchemaItemAtPath(schema, keys);
336
- const finalValue = schemaItem instanceof SchemaArray ? query.getAll(key) : value;
370
+ const allValues = query.getAll(key);
371
+ const finalValue = schemaItem && schemaItem.parse(allValues).valid ? allValues : value;
337
372
  objectSet2(record, keys, finalValue);
338
373
  }
339
374
  return schema.parse(record, opts);
@@ -343,7 +378,8 @@ function parseFormData(schema, data, opts) {
343
378
  for (const [key, value] of data) {
344
379
  const keys = key.split(".").map((it) => /^\d+$/g.test(it) ? Number.parseInt(it, 10) : it);
345
380
  const schemaItem = getSchemaItemAtPath(schema, keys);
346
- const finalValue = schemaItem instanceof SchemaArray ? data.getAll(key) : value;
381
+ const allValues = data.getAll(key);
382
+ const finalValue = schemaItem && schemaItem.parse(allValues).valid ? allValues : value;
347
383
  objectSet2(record, keys, finalValue);
348
384
  }
349
385
  const handleBoolean = (value, keys) => {
@@ -405,6 +441,7 @@ var SchemaAny = class extends SchemaItem {
405
441
  return true;
406
442
  }
407
443
  };
444
+ SchemaAny.id = "any";
408
445
 
409
446
  // src/items/date.ts
410
447
  var SchemaDate = class extends SchemaItem {
@@ -448,6 +485,7 @@ var SchemaDate = class extends SchemaItem {
448
485
  return input instanceof Date;
449
486
  }
450
487
  };
488
+ SchemaDate.id = "date";
451
489
  __decorateClass([
452
490
  parsable()
453
491
  ], SchemaDate.prototype, "parseString", 1);
@@ -486,6 +524,7 @@ var SchemaRecord = class extends SchemaItem {
486
524
  return result;
487
525
  }
488
526
  };
527
+ SchemaRecord.id = "record";
489
528
 
490
529
  // src/items/enum.ts
491
530
  var SchemaEnum = class extends SchemaItem {
@@ -506,18 +545,20 @@ var SchemaEnum = class extends SchemaItem {
506
545
  return typeof input === this.type;
507
546
  }
508
547
  };
548
+ SchemaEnum.id = "enum";
509
549
 
510
550
  // src/items/literal.ts
511
551
  var SchemaLiteral = class extends SchemaItem {
512
- constructor(value) {
513
- super([value]);
514
- this.value = value;
515
- this.validations.push({ fn: (it) => it === this.value });
552
+ constructor(...values) {
553
+ super(values);
554
+ this.values = values;
555
+ this.validations.push({ fn: (it) => this.values.includes(it) });
516
556
  }
517
557
  isOfType(input) {
518
- return typeof input === typeof this.value;
558
+ return this.values.some((it) => typeof input === typeof it);
519
559
  }
520
560
  };
561
+ SchemaLiteral.id = "literal";
521
562
 
522
563
  // src/items/number.ts
523
564
  var SchemaNumber = class extends SchemaItem {
@@ -571,6 +612,7 @@ var SchemaNumber = class extends SchemaItem {
571
612
  return this.lte(...params);
572
613
  }
573
614
  };
615
+ SchemaNumber.id = "number";
574
616
  __decorateClass([
575
617
  parsable()
576
618
  ], SchemaNumber.prototype, "lte", 1);
@@ -630,6 +672,15 @@ var SchemaString = class extends SchemaItem {
630
672
  });
631
673
  return this;
632
674
  }
675
+ email(message) {
676
+ this.addValidation({
677
+ fn(input) {
678
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input);
679
+ },
680
+ error: message
681
+ });
682
+ return this;
683
+ }
633
684
  minLength(value, message) {
634
685
  return this.min(value, message);
635
686
  }
@@ -640,6 +691,7 @@ var SchemaString = class extends SchemaItem {
640
691
  return typeof input === "string";
641
692
  }
642
693
  };
694
+ SchemaString.id = "string";
643
695
  __decorateClass([
644
696
  parsable()
645
697
  ], SchemaString.prototype, "min", 1);
@@ -655,6 +707,9 @@ __decorateClass([
655
707
  __decorateClass([
656
708
  parsable()
657
709
  ], SchemaString.prototype, "regex", 1);
710
+ __decorateClass([
711
+ parsable()
712
+ ], SchemaString.prototype, "email", 1);
658
713
 
659
714
  // src/items/union.ts
660
715
  var SchemaUnion = class extends SchemaItem {
@@ -678,6 +733,7 @@ var SchemaUnion = class extends SchemaItem {
678
733
  return result;
679
734
  }
680
735
  };
736
+ SchemaUnion.id = "union";
681
737
 
682
738
  // src/items/intersection.ts
683
739
  import { isObject as isObject4 } from "@dzeio/object-util";
@@ -706,6 +762,7 @@ var SchemaIntersection = class extends SchemaItem {
706
762
  return result;
707
763
  }
708
764
  };
765
+ SchemaIntersection.id = "intersection";
709
766
 
710
767
  // src/items/default.ts
711
768
  var SchemaDefault = class extends SchemaItem {
@@ -725,6 +782,7 @@ var SchemaDefault = class extends SchemaItem {
725
782
  return [{ item: this.child, value: isNull(input) || !this.strict && !input ? this.defaultVal : input, path: void 0 }];
726
783
  }
727
784
  };
785
+ SchemaDefault.id = "default";
728
786
 
729
787
  // src/items/file.ts
730
788
  var SchemaFile = class extends SchemaItem {
@@ -744,6 +802,7 @@ var SchemaFile = class extends SchemaItem {
744
802
  return input instanceof File;
745
803
  }
746
804
  };
805
+ SchemaFile.id = "file";
747
806
  __decorateClass([
748
807
  parsable()
749
808
  ], SchemaFile.prototype, "extension", 1);
@@ -772,6 +831,7 @@ var SchemaTuple = class extends SchemaItem {
772
831
  return Array.isArray(input) ? this.children.map((entry, index) => ({ value: input[index], item: entry, path: index.toString() })) : [];
773
832
  }
774
833
  };
834
+ SchemaTuple.id = "tuple";
775
835
 
776
836
  // src/items/nullish.ts
777
837
  var SchemaUndefined = class extends SchemaItem {
@@ -779,28 +839,34 @@ var SchemaUndefined = class extends SchemaItem {
779
839
  return typeof input === "undefined";
780
840
  }
781
841
  };
842
+ SchemaUndefined.id = "undefined";
782
843
  var SchemaNull = class extends SchemaItem {
783
844
  isOfType(input) {
784
845
  return input === null;
785
846
  }
786
847
  };
848
+ SchemaNull.id = "null";
787
849
  var SchemaVoid = class extends SchemaItem {
788
850
  isOfType(input) {
789
851
  return typeof input === "undefined";
790
852
  }
791
853
  };
854
+ SchemaVoid.id = "void";
792
855
  var SchemaNullish = class extends SchemaItem {
793
856
  isOfType(input) {
794
857
  return isNull(input);
795
858
  }
796
859
  };
860
+ SchemaNullish.id = "nullish";
797
861
  var SchemaNever = class extends SchemaItem {
798
862
  isOfType(_input) {
799
863
  return false;
800
864
  }
801
865
  };
866
+ SchemaNever.id = "never";
802
867
 
803
868
  // src/Schema.ts
869
+ import { isObject as isObject5, objectRemap as objectRemap2 } from "@dzeio/object-util";
804
870
  function parsable() {
805
871
  return (target, propertyKey, descriptor) => {
806
872
  if (!(propertyKey in target)) {
@@ -815,32 +881,16 @@ function parsable() {
815
881
  return descriptor;
816
882
  };
817
883
  }
818
- var Types = {
819
- Any: SchemaAny,
820
- Array: SchemaArray,
821
- Tuple: SchemaTuple,
822
- Boolean: SchemaBoolean,
823
- Date: SchemaDate,
824
- Enum: SchemaEnum,
825
- Literal: SchemaLiteral,
826
- Nullable: SchemaNullable,
827
- Object: SchemaObject,
828
- Record: SchemaRecord,
829
- String: SchemaString,
830
- Union: SchemaUnion,
831
- Intersection: SchemaIntersection,
832
- Default: SchemaDefault,
833
- Undefined: SchemaUndefined,
834
- Void: SchemaVoid,
835
- Null: SchemaNull,
836
- Nullish: SchemaNullish
837
- };
838
884
  var _Schema = class _Schema extends SchemaObject {
839
885
  static register(module) {
840
886
  this.registeredModules.push(module);
841
887
  }
842
888
  static getModule(name) {
843
- return this.registeredModules.find((it) => it.name === name);
889
+ const module = this.registeredModules.find((it) => it.id === name);
890
+ if (!module) {
891
+ console.log("Couldn't find module", name);
892
+ }
893
+ return module != null ? module : SchemaAny;
844
894
  }
845
895
  static any() {
846
896
  return new SchemaAny();
@@ -862,8 +912,8 @@ var _Schema = class _Schema extends SchemaObject {
862
912
  * @param input the literal value (note: append `as const` else the typing won't work correctly)
863
913
  * @returns
864
914
  */
865
- static literal(input) {
866
- return new SchemaLiteral(input);
915
+ static literal(...inputs) {
916
+ return new SchemaLiteral(...inputs);
867
917
  }
868
918
  static nullable(...inputs) {
869
919
  return new SchemaNullable(...inputs);
@@ -912,25 +962,35 @@ var _Schema = class _Schema extends SchemaObject {
912
962
  }
913
963
  static fromJSON(json) {
914
964
  var _a, _b, _c, _d, _e, _f;
915
- const fn = this.getModule(json.i);
965
+ const fn = this.getModule(json._i);
916
966
  if (!fn) {
917
- throw new Error(`Schema cannot parse ${json.i}`);
967
+ throw new Error(`Schema cannot parse ${json._i}`);
918
968
  }
919
- const item = new fn(...(_b = (_a = json.c) == null ? void 0 : _a.map((it) => this.isSchemaJSON(it) ? _Schema.fromJSON(it) : it)) != null ? _b : []);
969
+ const item = new fn(...(_b = (_a = json.c) == null ? void 0 : _a.map((it) => this.deepParseSchemaJSON(it))) != null ? _b : []);
920
970
  for (const validation of (_c = json.f) != null ? _c : []) {
921
971
  if (!(validation.n in item)) {
922
972
  throw new Error("validation not available in Schema Item");
923
973
  }
924
- item[validation.n](...(_e = (_d = validation.a) == null ? void 0 : _d.map((it) => _Schema.isSchemaJSON(it) ? _Schema.fromJSON(it) : it)) != null ? _e : []);
974
+ item[validation.n](...(_e = (_d = validation.a) == null ? void 0 : _d.map((it) => this.deepParseSchemaJSON(it))) != null ? _e : []);
925
975
  }
926
976
  item.attrs(...(_f = json.a) != null ? _f : []);
927
977
  return item;
928
978
  }
979
+ static deepParseSchemaJSON(item) {
980
+ if (this.isSchemaJSON(item)) {
981
+ return _Schema.fromJSON(item);
982
+ } else if (Array.isArray(item)) {
983
+ return item.map((it) => this.deepParseSchemaJSON(it));
984
+ } else if (isObject5(item)) {
985
+ return objectRemap2(item, (value, key) => ({ value: this.deepParseSchemaJSON(value), key }));
986
+ }
987
+ return item;
988
+ }
929
989
  static isSchemaJSON(data) {
930
990
  if (typeof data !== "object" || data === null) {
931
991
  return false;
932
992
  }
933
- if (!("i" in data)) {
993
+ if (!("_i" in data)) {
934
994
  return false;
935
995
  }
936
996
  return true;
@@ -977,7 +1037,10 @@ _Schema.registeredModules = [
977
1037
  SchemaUndefined,
978
1038
  SchemaVoid,
979
1039
  SchemaNull,
980
- SchemaNullish
1040
+ SchemaNullish,
1041
+ SchemaFile,
1042
+ SchemaAny,
1043
+ SchemaNumber
981
1044
  ];
982
1045
  var Schema = _Schema;
983
1046
  var s = Schema;
@@ -1003,7 +1066,6 @@ export {
1003
1066
  SchemaUndefined,
1004
1067
  SchemaUnion,
1005
1068
  SchemaVoid,
1006
- Types,
1007
1069
  Schema as default,
1008
1070
  isNull,
1009
1071
  parsable,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dzeio/schema",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "dependencies": {
5
5
  "@dzeio/object-util": "^1.9.2"
6
6
  },