@oscarpalmer/jhunal 0.23.0 → 0.25.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.
Files changed (40) hide show
  1. package/dist/constants.d.mts +8 -5
  2. package/dist/constants.mjs +20 -23
  3. package/dist/helpers/message.helper.d.mts +11 -5
  4. package/dist/helpers/message.helper.mjs +31 -9
  5. package/dist/helpers/misc.helper.d.mts +4 -4
  6. package/dist/helpers/misc.helper.mjs +4 -4
  7. package/dist/index.d.mts +66 -78
  8. package/dist/index.mjs +100 -62
  9. package/dist/models/infer.model.d.mts +21 -21
  10. package/dist/models/misc.model.d.mts +3 -3
  11. package/dist/models/{schema.plain.model.d.mts → schematic.plain.model.d.mts} +20 -18
  12. package/dist/models/{schema.typed.model.d.mts → schematic.typed.model.d.mts} +10 -24
  13. package/dist/models/transform.model.d.mts +6 -6
  14. package/dist/models/validation.model.d.mts +13 -3
  15. package/dist/{schematic.d.mts → schema.d.mts} +18 -18
  16. package/dist/{schematic.mjs → schema.mjs} +12 -12
  17. package/dist/validator/named.handler.d.mts +1 -1
  18. package/dist/validator/named.handler.mjs +3 -2
  19. package/dist/validator/named.validator.mjs +2 -3
  20. package/dist/validator/object.validator.mjs +40 -22
  21. package/dist/validator/schematic.validator.d.mts +3 -3
  22. package/dist/validator/schematic.validator.mjs +4 -4
  23. package/package.json +1 -1
  24. package/src/constants.ts +24 -28
  25. package/src/helpers/message.helper.ts +74 -9
  26. package/src/helpers/misc.helper.ts +9 -10
  27. package/src/index.ts +4 -4
  28. package/src/models/infer.model.ts +26 -28
  29. package/src/models/misc.model.ts +3 -3
  30. package/src/models/{schema.plain.model.ts → schematic.plain.model.ts} +22 -20
  31. package/src/models/{schema.typed.model.ts → schematic.typed.model.ts} +10 -28
  32. package/src/models/transform.model.ts +6 -6
  33. package/src/models/validation.model.ts +14 -2
  34. package/src/{schematic.ts → schema.ts} +23 -23
  35. package/src/validator/named.handler.ts +16 -1
  36. package/src/validator/named.validator.ts +3 -4
  37. package/src/validator/object.validator.ts +81 -55
  38. package/src/validator/schematic.validator.ts +3 -3
  39. /package/dist/models/{schema.plain.model.mjs → schematic.plain.model.mjs} +0 -0
  40. /package/dist/models/{schema.typed.model.mjs → schematic.typed.model.mjs} +0 -0
package/dist/index.mjs CHANGED
@@ -10,8 +10,9 @@ const CONJUNCTION_AND_COMMA = ", and ";
10
10
  const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
11
11
  const NAME_ERROR_SCHEMATIC = "SchematicError";
12
12
  const NAME_ERROR_VALIDATION = "ValidationError";
13
+ const PROPERTY_DEFAULT = "$default";
13
14
  const PROPERTY_REQUIRED = "$required";
14
- const PROPERTY_SCHEMATIC = "$schematic";
15
+ const PROPERTY_SCHEMA = "$schema";
15
16
  const PROPERTY_TYPE = "$type";
16
17
  const PROPERTY_VALIDATORS = "$validators";
17
18
  const VALIDATION_MESSAGE_INVALID_INPUT = "Expected an object as input but received <>";
@@ -29,8 +30,10 @@ const REPORTING_TYPES = new Set([
29
30
  REPORTING_NONE,
30
31
  REPORTING_THROW
31
32
  ]);
33
+ const SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_REQUIRED = "'<>' has a default value but is not required";
34
+ const SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_TYPE = "Expected default value for property '<>' to be <>";
32
35
  const SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY = "Schema must have at least one property";
33
- const SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED = "'<>.<>' property is not allowed for schemas in $type";
36
+ const SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED = "'<>.<>' property is not allowed for plain schemas";
34
37
  const SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE = "'<>' property must not be 'null' or 'undefined'";
35
38
  const SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED = "'<>.$required' property must be a boolean";
36
39
  const SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE = "'<>' property must be of a valid type";
@@ -39,42 +42,36 @@ const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY = "Validator '<>' does not exist";
39
42
  const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE = "Validators must be an object";
40
43
  const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE = "Validator '<>' must be a function or an array of functions";
41
44
  const TYPE_ARRAY = "array";
42
- const TYPE_BIGINT = "bigint";
43
- const TYPE_BOOLEAN = "boolean";
44
- const TYPE_DATE = "date";
45
45
  const TYPE_FUNCTION = "function";
46
46
  const TYPE_FUNCTION_RESULT = "a validated value";
47
47
  const TYPE_NULL = "null";
48
- const TYPE_NUMBER = "number";
49
48
  const TYPE_OBJECT = "object";
50
- const TYPE_STRING = "string";
51
- const TYPE_SYMBOL = "symbol";
52
49
  const TYPE_UNDEFINED = "undefined";
53
50
  const TYPE_ALL = new Set([
54
51
  ...new Set([
55
52
  TYPE_ARRAY,
56
- TYPE_BIGINT,
57
- TYPE_BOOLEAN,
58
- TYPE_DATE,
53
+ "bigint",
54
+ "boolean",
55
+ "date",
59
56
  TYPE_FUNCTION,
60
- TYPE_NUMBER,
57
+ "number",
61
58
  TYPE_OBJECT,
62
- TYPE_STRING,
63
- TYPE_SYMBOL
59
+ "string",
60
+ "symbol"
64
61
  ]),
65
62
  TYPE_NULL,
66
63
  TYPE_UNDEFINED
67
64
  ]);
68
65
  const PREFIXED_TYPES = {
69
66
  [TYPE_ARRAY]: `an ${TYPE_ARRAY}`,
70
- [TYPE_BIGINT]: `a ${TYPE_BIGINT}`,
71
- [TYPE_BOOLEAN]: `a ${TYPE_BOOLEAN}`,
72
- [TYPE_DATE]: `a ${TYPE_DATE}`,
67
+ bigint: `a bigint`,
68
+ boolean: `a boolean`,
69
+ date: `a date`,
73
70
  [TYPE_FUNCTION]: `a ${TYPE_FUNCTION}`,
74
71
  [TYPE_NULL]: TYPE_NULL,
75
- [TYPE_NUMBER]: `a ${TYPE_NUMBER}`,
76
- [TYPE_STRING]: `a ${TYPE_STRING}`,
77
- [TYPE_SYMBOL]: `a ${TYPE_SYMBOL}`,
72
+ number: `a number`,
73
+ string: `a string`,
74
+ symbol: `a symbol`,
78
75
  [TYPE_OBJECT]: `an ${TYPE_OBJECT}`,
79
76
  [TYPE_UNDEFINED]: TYPE_UNDEFINED
80
77
  };
@@ -84,7 +81,7 @@ function getParameters(input) {
84
81
  if (typeof input === "boolean") return {
85
82
  clone: true,
86
83
  output: {},
87
- reporting: getReporting(REPORTING_NONE),
84
+ reporting: getReporting(),
88
85
  strict: input
89
86
  };
90
87
  if (REPORTING_TYPES.has(input)) return {
@@ -128,8 +125,8 @@ function instanceOf(constructor) {
128
125
  * @param value Value to check
129
126
  * @returns `true` if the value is a schematic, `false` otherwise
130
127
  */
131
- function isSchematic(value) {
132
- return typeof value === "object" && value !== null && "$schematic" in value && value["$schematic"] === true;
128
+ function isSchema(value) {
129
+ return typeof value === "object" && value !== null && "$schema" in value && value["$schema"] === true;
133
130
  }
134
131
  //#endregion
135
132
  //#region src/models/validation.model.ts
@@ -154,26 +151,45 @@ var ValidationError = class extends Error {
154
151
  };
155
152
  //#endregion
156
153
  //#region src/helpers/message.helper.ts
157
- function getInvalidInputMessage(actual) {
154
+ function getDefaultRequiredMessage(key) {
155
+ return SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_REQUIRED.replace("<>", key);
156
+ }
157
+ function getDefaultTypeMessage(key, types) {
158
+ let message = SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_TYPE.replace("<>", key);
159
+ message = message.replace("<>", renderTypes(types));
160
+ return message;
161
+ }
162
+ function getDisallowedMessage(key, property) {
163
+ let message = SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", key);
164
+ message = message.replace("<>", property);
165
+ return message;
166
+ }
167
+ function getInputTypeMessage(actual) {
158
168
  return VALIDATION_MESSAGE_INVALID_INPUT.replace("<>", getValueType(actual));
159
169
  }
160
- function getInvalidMissingMessage(key, types) {
170
+ function getInputPropertyMissingMessage(key, types) {
161
171
  let message = VALIDATION_MESSAGE_INVALID_REQUIRED.replace("<>", renderTypes(types));
162
172
  message = message.replace("<>", key);
163
173
  return message;
164
174
  }
165
- function getInvalidTypeMessage(key, types, actual) {
175
+ function getInputPropertyTypeMessage(key, types, actual) {
166
176
  let message = VALIDATION_MESSAGE_INVALID_TYPE.replace("<>", renderTypes(types));
167
177
  message = message.replace("<>", key);
168
178
  message = message.replace("<>", getValueType(actual));
169
179
  return message;
170
180
  }
171
- function getInvalidValidatorMessage(key, type, index, length) {
181
+ function getInputPropertyValidatorMessage(key, type, index, length) {
172
182
  let message = VALIDATION_MESSAGE_INVALID_VALUE.replace("<>", key);
173
183
  message = message.replace("<>", type);
174
184
  if (length > 1) message += VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX.replace("<>", String(index));
175
185
  return message;
176
186
  }
187
+ function getSchematicPropertyNullableMessage(key) {
188
+ return SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", key);
189
+ }
190
+ function getSchematicPropertyTypeMessage(key) {
191
+ return SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", key);
192
+ }
177
193
  function getPropertyType(type) {
178
194
  switch (true) {
179
195
  case typeof type === "function": return isConstructor(type) ? type.name : TYPE_FUNCTION_RESULT;
@@ -181,9 +197,6 @@ function getPropertyType(type) {
181
197
  default: return PREFIXED_TYPES[TYPE_OBJECT];
182
198
  }
183
199
  }
184
- function getUnknownKeysMessage(keys) {
185
- return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace("<>", renderKeys(keys));
186
- }
187
200
  function getValueType(value) {
188
201
  const valueType = typeof value;
189
202
  switch (true) {
@@ -219,6 +232,12 @@ function renderTypes(types) {
219
232
  }
220
233
  return renderParts(parts, CONJUNCTION_OR, CONJUNCTION_OR_COMMA);
221
234
  }
235
+ function getRequiredMessage(key) {
236
+ return SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace("<>", key);
237
+ }
238
+ function getUnknownKeysMessage(keys) {
239
+ return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace("<>", renderKeys(keys));
240
+ }
222
241
  //#endregion
223
242
  //#region src/validator/base.validator.ts
224
243
  function getBaseValidator(validators) {
@@ -245,9 +264,10 @@ function getFunctionValidator(fn) {
245
264
  }
246
265
  //#endregion
247
266
  //#region src/validator/named.handler.ts
248
- function getNamedHandlers(original, prefix) {
267
+ function getNamedHandlers(original, prefix, allowed) {
249
268
  const handlers = {};
250
269
  if (original == null) return handlers;
270
+ if (!allowed) throw new TypeError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", prefix).replace("<>", PROPERTY_VALIDATORS));
251
271
  if (!isPlainObject(original)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
252
272
  const keys = Object.keys(original);
253
273
  const { length } = keys;
@@ -276,7 +296,7 @@ function getNamedValidator(key, name, handlers) {
276
296
  const information = {
277
297
  key,
278
298
  validator,
279
- message: getInvalidValidatorMessage(key.full, name, index, length),
299
+ message: getInputPropertyValidatorMessage(key.full, name, index, length),
280
300
  value: input
281
301
  };
282
302
  parameters.information?.push(information);
@@ -300,8 +320,8 @@ const namedValidators = {
300
320
  };
301
321
  //#endregion
302
322
  //#region src/validator/schematic.validator.ts
303
- function getSchematicValidator(schematic) {
304
- const validator = schematicValidator.get(schematic);
323
+ function getSchemaValidator(schematic) {
324
+ const validator = schemaValidators.get(schematic);
305
325
  return (input, parameters, get) => {
306
326
  let result;
307
327
  if (isPlainObject(input)) result = validator(input, parameters, get);
@@ -313,7 +333,13 @@ function getSchematicValidator(schematic) {
313
333
  }
314
334
  //#endregion
315
335
  //#region src/validator/object.validator.ts
336
+ function getDefaults(obj, key, allowed) {
337
+ if (!("$default" in obj)) return;
338
+ if (!allowed) throw new SchematicError(getDisallowedMessage(key, PROPERTY_DEFAULT));
339
+ return { value: obj[PROPERTY_DEFAULT] };
340
+ }
316
341
  function getDisallowedProperty(obj) {
342
+ if ("$default" in obj) return PROPERTY_DEFAULT;
317
343
  if ("$required" in obj) return PROPERTY_REQUIRED;
318
344
  if ("$type" in obj) return PROPERTY_TYPE;
319
345
  if ("$validators" in obj) return PROPERTY_VALIDATORS;
@@ -324,14 +350,14 @@ function getObjectValidator(original, origin, fromType) {
324
350
  if (keysLength === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY);
325
351
  if (fromType ?? false) {
326
352
  const property = getDisallowedProperty(original);
327
- if (property != null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", origin.full).replace("<>", property));
353
+ if (property != null) throw new SchematicError(getDisallowedMessage(origin.full, property));
328
354
  }
329
355
  const set = /* @__PURE__ */ new Set();
330
356
  const items = [];
331
357
  for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
332
358
  const key = keys[keyIndex];
333
359
  const value = original[key];
334
- if (value == null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", join([origin?.full, key], ".")));
360
+ if (value == null) throw new SchematicError(getSchematicPropertyNullableMessage(join([origin?.full, key], ".")));
335
361
  const prefixedKey = origin == null ? key : join([origin.full, key], ".");
336
362
  const fullKey = {
337
363
  full: prefixedKey,
@@ -340,16 +366,18 @@ function getObjectValidator(original, origin, fromType) {
340
366
  let handlers = {};
341
367
  let required = true;
342
368
  let typed = false;
369
+ let defaults;
343
370
  let types;
344
371
  const validators = [];
345
372
  if (isPlainObject(value)) {
346
373
  typed = PROPERTY_TYPE in value;
347
374
  const type = typed ? value[PROPERTY_TYPE] : value;
348
- handlers = getNamedHandlers(value[PROPERTY_VALIDATORS], prefixedKey);
349
- required = getRequired(key, value) ?? required;
375
+ defaults = getDefaults(value, prefixedKey, typed);
376
+ handlers = getNamedHandlers(value[PROPERTY_VALIDATORS], prefixedKey, typed);
377
+ required = getRequired(value, prefixedKey, typed) ?? required;
350
378
  types = Array.isArray(type) ? type : [type];
351
379
  } else types = Array.isArray(value) ? value : [value];
352
- if (types.length === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", prefixedKey).replace("<>", String(value)));
380
+ if (types.length === 0) throw new SchematicError(getSchematicPropertyTypeMessage(prefixedKey));
353
381
  const typesLength = types.length;
354
382
  for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
355
383
  const type = types[typeIndex];
@@ -361,23 +389,28 @@ function getObjectValidator(original, origin, fromType) {
361
389
  case isPlainObject(type):
362
390
  validator = getObjectValidator(type, fullKey, typed);
363
391
  break;
364
- case isSchematic(type):
365
- validator = getSchematicValidator(type);
392
+ case isSchema(type):
393
+ validator = getSchemaValidator(type);
366
394
  break;
367
395
  case TYPE_ALL.has(type):
368
396
  validator = getNamedValidator(fullKey, type, handlers);
369
397
  break;
370
- default: throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", prefixedKey).replace("<>", String(type)));
398
+ default: throw new SchematicError(getSchematicPropertyTypeMessage(prefixedKey));
371
399
  }
372
400
  validators.push(validator);
373
401
  }
374
- set.add(key);
402
+ required = required && !types.includes("undefined");
403
+ if (defaults != null && !required) throw new SchematicError(getDefaultRequiredMessage(prefixedKey));
404
+ const validator = getBaseValidator(validators);
405
+ if (defaults != null && Array.isArray(validator(defaults.value, getParameters(), false))) throw new SchematicError(getDefaultTypeMessage(prefixedKey, types));
375
406
  items.push({
407
+ defaults,
408
+ required,
376
409
  types,
377
- key: fullKey,
378
- required: required && !types.includes("undefined"),
379
- validator: getBaseValidator(validators)
410
+ validator,
411
+ key: fullKey
380
412
  });
413
+ set.add(key);
381
414
  }
382
415
  const validatorsLength = items.length;
383
416
  return (input, parameters, get) => {
@@ -389,7 +422,7 @@ function getObjectValidator(original, origin, fromType) {
389
422
  short: ""
390
423
  },
391
424
  value: input,
392
- message: getInvalidInputMessage(input)
425
+ message: getInputTypeMessage(input)
393
426
  };
394
427
  if (parameters.reporting.throw) throw new ValidationError([information]);
395
428
  parameters.information?.push(information);
@@ -414,15 +447,19 @@ function getObjectValidator(original, origin, fromType) {
414
447
  const allInformation = [];
415
448
  const output = {};
416
449
  for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
417
- const { key, required, types, validator } = items[validatorIndex];
450
+ const { defaults, key, required, types, validator } = items[validatorIndex];
418
451
  const value = input[key.short];
419
452
  if (value === void 0) {
420
453
  if (required) {
454
+ if (get && defaults != null) {
455
+ output[key.short] = clone(defaults.value);
456
+ continue;
457
+ }
421
458
  if (parameters.reporting.none) return [];
422
459
  const information = {
423
460
  key,
424
461
  value,
425
- message: getInvalidMissingMessage(key.full, types)
462
+ message: getInputPropertyMissingMessage(key.full, types)
426
463
  };
427
464
  if (parameters.reporting.throw) throw new ValidationError([information]);
428
465
  parameters.information?.push(information);
@@ -446,7 +483,7 @@ function getObjectValidator(original, origin, fromType) {
446
483
  const information = typeof result !== "boolean" && result.length > 0 ? result : [{
447
484
  key,
448
485
  value,
449
- message: getInvalidTypeMessage(key.full, types, value)
486
+ message: getInputPropertyTypeMessage(key.full, types, value)
450
487
  }];
451
488
  if (parameters.reporting.throw) throw new ValidationError(information);
452
489
  if (parameters.reporting.all) {
@@ -460,22 +497,23 @@ function getObjectValidator(original, origin, fromType) {
460
497
  return allInformation.length === 0 ? true : allInformation;
461
498
  };
462
499
  }
463
- function getRequired(key, obj) {
500
+ function getRequired(obj, key, allowed) {
464
501
  if (!("$required" in obj)) return;
465
- if (typeof obj["$required"] !== "boolean") throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace("<>", key));
502
+ if (!allowed) throw new SchematicError(getDisallowedMessage(key, PROPERTY_REQUIRED));
503
+ if (typeof obj["$required"] !== "boolean") throw new SchematicError(getRequiredMessage(key));
466
504
  return obj[PROPERTY_REQUIRED];
467
505
  }
468
506
  //#endregion
469
- //#region src/schematic.ts
507
+ //#region src/schema.ts
470
508
  /**
471
- * A schematic for validating objects
509
+ * A schema for validating objects
472
510
  */
473
- var Schematic = class {
511
+ var Schema = class {
474
512
  #validator;
475
513
  constructor(validator) {
476
- Object.defineProperty(this, PROPERTY_SCHEMATIC, { value: true });
514
+ Object.defineProperty(this, PROPERTY_SCHEMA, { value: true });
477
515
  this.#validator = validator;
478
- schematicValidator.set(this, validator);
516
+ schemaValidators.set(this, validator);
479
517
  }
480
518
  get(value, options) {
481
519
  const parameters = getParameters(options);
@@ -492,11 +530,11 @@ var Schematic = class {
492
530
  return error(parameters.reporting.all ? result : result[0]);
493
531
  }
494
532
  };
495
- function schematic(schema) {
496
- if (isSchematic(schema)) return schema;
533
+ function schema(schema) {
534
+ if (isSchema(schema)) return schema;
497
535
  if (!isPlainObject(schema)) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE);
498
- return new Schematic(getObjectValidator(schema));
536
+ return new Schema(getObjectValidator(schema));
499
537
  }
500
- const schematicValidator = /* @__PURE__ */ new WeakMap();
538
+ const schemaValidators = /* @__PURE__ */ new WeakMap();
501
539
  //#endregion
502
- export { SchematicError, ValidationError, instanceOf, isSchematic, schematic };
540
+ export { SchematicError, ValidationError, instanceOf, isSchema, schema };
@@ -1,35 +1,35 @@
1
- import { Schematic } from "../schematic.mjs";
2
- import { PlainSchema, Schema, SchemaProperty } from "./schema.plain.model.mjs";
1
+ import { Schema } from "../schema.mjs";
2
+ import { PlainSchematic, Schematic, SchematicProperty } from "./schematic.plain.model.mjs";
3
3
  import { IsOptionalProperty, ValueName, Values } from "./misc.model.mjs";
4
4
  import { Constructor, Simplify } from "@oscarpalmer/atoms/models";
5
5
 
6
6
  //#region src/models/infer.model.d.ts
7
7
  /**
8
- * Infers the TypeScript type from a {@link Schema} definition
8
+ * Infers the TypeScript type from a {@link Schematic} definition
9
9
  *
10
- * @template Model Schema to infer types from
10
+ * @template Model Schematic to infer types from
11
11
  *
12
12
  * @example
13
13
  * ```ts
14
- * const userSchema = {
14
+ * const userSchematic = {
15
15
  * name: 'string',
16
16
  * age: 'number',
17
17
  * address: { $required: false, $type: 'string' },
18
- * } satisfies Schema;
18
+ * } satisfies Schematic;
19
19
  *
20
- * type User = Infer<typeof userSchema>;
20
+ * type User = Infer<typeof userSchematic>;
21
21
  * // { name: string; age: number; address?: string }
22
22
  * ```
23
23
  */
24
- type Infer<Model extends Schema> = Simplify<{ [Key in InferRequiredKeys<Model>]: InferSchemaEntry<Model[Key]> } & { [Key in InferOptionalKeys<Model>]?: InferSchemaEntry<Model[Key]> }>;
24
+ type Infer<Model extends Schematic> = Simplify<{ [Key in InferRequiredKeys<Model>]: InferSchemaEntry<Model[Key]> } & { [Key in InferOptionalKeys<Model>]?: InferSchemaEntry<Model[Key]> }>;
25
25
  /**
26
- * Extracts keys from a {@link Schema} whose entries are optional _(i.e., `$required` is `false`)_
26
+ * Extracts keys from a {@link Schematic} whose entries are optional _(i.e., `$required` is `false`)_
27
27
  *
28
- * @template Model - {@link Schema} to extract optional keys from
28
+ * @template Model - {@link Schematic} to extract optional keys from
29
29
  */
30
- type InferOptionalKeys<Model extends Schema> = keyof { [Key in keyof Model as IsOptionalProperty<Model[Key]> extends true ? Key : never]: never };
30
+ type InferOptionalKeys<Model extends Schematic> = keyof { [Key in keyof Model as IsOptionalProperty<Model[Key]> extends true ? Key : never]: never };
31
31
  /**
32
- * Infers the TypeScript type from a {@link SchemaProperty}'s `$type` field
32
+ * Infers the TypeScript type from a {@link SchematicProperty}'s `$type` field
33
33
  *
34
34
  * @template Value `$type` value _(single or array)_
35
35
  */
@@ -37,30 +37,30 @@ type InferPropertyType<Value> = Value extends (infer Item)[] ? InferPropertyValu
37
37
  /**
38
38
  * Maps a single `$type` definition to its TypeScript equivalent
39
39
  *
40
- * Resolves, in order: {@link Constructor} instances, {@link Schematic} models, {@link ValueName} strings, and nested {@link PlainSchema} objects
40
+ * Resolves, in order: {@link Constructor}s, {@link Schema} instances, {@link ValueName} values, and nested {@link PlainSchematic} objects
41
41
  *
42
42
  * @template Value single type definition
43
43
  */
44
- type InferPropertyValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends Schematic<infer Model> ? Model : Value extends ValueName ? Values[Value & ValueName] : Value extends Schema ? Infer<Value> : never;
44
+ type InferPropertyValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends Schema<infer Model> ? Model : Value extends ValueName ? Values[Value & ValueName] : Value extends PlainSchematic ? Infer<Value> : never;
45
45
  /**
46
- * Extracts keys from a {@link Schema} whose entries are required _(i.e., `$required` is not `false`)_
46
+ * Extracts keys from a {@link Schematic} whose entries are required _(i.e., `$required` is not `false`)_
47
47
  *
48
- * @template Model Schema to extract required keys from
48
+ * @template Model Schematic to extract required keys from
49
49
  */
50
- type InferRequiredKeys<Model extends Schema> = keyof { [Key in keyof Model as IsOptionalProperty<Model[Key]> extends true ? never : Key]: never };
50
+ type InferRequiredKeys<Model extends Schematic> = keyof { [Key in keyof Model as IsOptionalProperty<Model[Key]> extends true ? never : Key]: never };
51
51
  /**
52
- * Infers the TypeScript type from a top-level {@link Schema} entry
52
+ * Infers the TypeScript type from a top-level {@link Schematic} entry
53
53
  *
54
- * @template Value Schema entry value _(single or array)_
54
+ * @template Value Schematic entry value _(single or array)_
55
55
  */
56
56
  type InferSchemaEntry<Value> = Value extends (infer Item)[] ? InferSchemaEntryValue<Item> : InferSchemaEntryValue<Value>;
57
57
  /**
58
58
  * Maps a single top-level schema entry to its TypeScript type
59
59
  *
60
- * Resolves, in order: {@link Constructor} instances, {@link Schematic} models, {@link SchemaProperty} objects, {@link PlainSchema} objects, and {@link ValueName} strings
60
+ * Resolves, in order: {@link Constructor}s, {@link Schema} instances, {@link SchemaProperty} objects, {@link PlainSchematic} objects, and {@link ValueName} values
61
61
  *
62
62
  * @template Value single schema entry
63
63
  */
64
- type InferSchemaEntryValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends Schematic<infer Model> ? Model : Value extends SchemaProperty ? InferPropertyType<Value['$type']> : Value extends PlainSchema ? Infer<Value & Schema> : Value extends ValueName ? Values[Value & ValueName] : Value extends Schema ? Infer<Value> : never;
64
+ type InferSchemaEntryValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends Schema<infer Model> ? Model : Value extends SchematicProperty ? InferPropertyType<Value['$type']> : Value extends PlainSchematic ? Infer<Value & Schematic> : Value extends ValueName ? Values[Value & ValueName] : never;
65
65
  //#endregion
66
66
  export { Infer, InferOptionalKeys, InferPropertyType, InferPropertyValue, InferRequiredKeys, InferSchemaEntry, InferSchemaEntryValue };
@@ -1,4 +1,4 @@
1
- import { SchemaProperty } from "./schema.plain.model.mjs";
1
+ import { SchematicProperty } from "./schematic.plain.model.mjs";
2
2
 
3
3
  //#region src/models/misc.model.d.ts
4
4
  /**
@@ -29,11 +29,11 @@ type ExtractValueNames<Value> = Value extends ValueName ? Value : Value extends
29
29
  /**
30
30
  * Determines whether a schema entry is optional
31
31
  *
32
- * Returns `true` if the entry is a {@link SchemaProperty} with `$required` set to `false`; otherwise returns `false`
32
+ * Returns `true` if the entry is a {@link SchematicProperty} with `$required` set to `false`; otherwise returns `false`
33
33
  *
34
34
  * @template Value Schema entry to check
35
35
  */
36
- type IsOptionalProperty<Value> = Value extends SchemaProperty ? Value['$required'] extends false ? true : false : false;
36
+ type IsOptionalProperty<Value> = Value extends SchematicProperty ? Value['$required'] extends false ? true : false : false;
37
37
  /**
38
38
  * Extracts the last member from a union type by leveraging contravariance of function parameter types
39
39
  *
@@ -1,43 +1,44 @@
1
- import { Schematic } from "../schematic.mjs";
1
+ import { Schema } from "../schema.mjs";
2
2
  import { ExtractValueNames, ValueName, Values } from "./misc.model.mjs";
3
3
  import { Constructor } from "@oscarpalmer/atoms/models";
4
4
 
5
- //#region src/models/schema.plain.model.d.ts
5
+ //#region src/models/schematic.plain.model.d.ts
6
6
  /**
7
- * A generic schema allowing nested schemas, {@link SchemaEntry} values, or arrays of {@link SchemaEntry} as values
7
+ * A generic schematic allowing nested schematics, {@link SchematicEntry} values, or arrays of {@link SchematicEntry} as values
8
8
  */
9
- type PlainSchema = {
10
- [key: string]: PlainSchema | SchemaEntry | SchemaEntry[] | undefined;
9
+ type PlainSchematic = {
10
+ [key: string]: PlainSchematic | SchematicEntry | SchematicEntry[] | undefined;
11
11
  } & {
12
+ $default?: never;
12
13
  $required?: never;
13
14
  $type?: never;
14
15
  $validators?: never;
15
16
  };
16
17
  /**
17
- * A schema for validating objects
18
+ * A schematic for validating objects
18
19
  *
19
20
  * @example
20
21
  * ```ts
21
- * const schema: Schema = {
22
+ * const schematic = {
22
23
  * name: 'string',
23
24
  * age: 'number',
24
25
  * tags: ['string', 'number'],
25
- * };
26
+ * } satisfies Schematic;
26
27
  * ```
27
28
  */
28
- type Schema = PlainSchema;
29
+ type Schematic = PlainSchematic;
29
30
  /**
30
- * A union of all valid types for a single schema entry
31
+ * A union of all valid types for a single schematic entry
31
32
  *
32
- * Can be a {@link Constructor}, {@link PlainSchema}, {@link SchemaProperty}, {@link Schematic}, {@link ValueName} string, or a custom validator function
33
+ * Can be a {@link Constructor}, {@link PlainSchematic}, {@link SchematicProperty}, {@link Schema}, {@link ValueName}, or a custom validator function
33
34
  */
34
- type SchemaEntry = Constructor | PlainSchema | SchemaProperty | Schematic<unknown> | ValueName | ((value: unknown) => boolean);
35
+ type SchematicEntry = Constructor | PlainSchematic | Schema<unknown> | SchematicProperty | ValueName | ((value: unknown) => boolean);
35
36
  /**
36
37
  * A property definition with explicit type(s), an optional requirement flag, and optional validators
37
38
  *
38
39
  * @example
39
40
  * ```ts
40
- * const prop: SchemaProperty = {
41
+ * const prop: SchematicProperty = {
41
42
  * $required: false,
42
43
  * $type: ['string', 'number'],
43
44
  * $validators: {
@@ -47,7 +48,8 @@ type SchemaEntry = Constructor | PlainSchema | SchemaProperty | Schematic<unknow
47
48
  * };
48
49
  * ```
49
50
  */
50
- type SchemaProperty = {
51
+ type SchematicProperty = {
52
+ $default?: unknown;
51
53
  /**
52
54
  * Whether the property is required _(defaults to `true`)_
53
55
  */
@@ -62,11 +64,11 @@ type SchemaProperty = {
62
64
  $validators?: PropertyValidators<SchemaPropertyType | SchemaPropertyType[]>;
63
65
  };
64
66
  /**
65
- * A union of valid types for a {@link SchemaProperty}'s `$type` field
67
+ * A union of valid types for a {@link SchematicProperty}'s `$type` field
66
68
  *
67
- * Can be a {@link Constructor}, {@link PlainSchema}, {@link Schematic}, {@link ValueName} string, or a custom validator function
69
+ * Can be a {@link Constructor}, {@link PlainSchematic}, {@link Schema}, {@link ValueName} string, or a custom validator function
68
70
  */
69
- type SchemaPropertyType = Constructor | PlainSchema | Schematic<unknown> | ValueName | ((value: unknown) => boolean);
71
+ type SchemaPropertyType = Constructor | PlainSchematic | Schema<unknown> | ValueName | ((value: unknown) => boolean);
70
72
  /**
71
73
  * A map of optional validator functions keyed by {@link ValueName}, used to add custom validation to {@link SchemaProperty} definitions
72
74
  *
@@ -83,4 +85,4 @@ type SchemaPropertyType = Constructor | PlainSchema | Schematic<unknown> | Value
83
85
  */
84
86
  type PropertyValidators<Value> = { [Key in ExtractValueNames<Value>]?: ((value: Values[Key]) => boolean) | Array<(value: Values[Key]) => boolean> };
85
87
  //#endregion
86
- export { PlainSchema, PropertyValidators, Schema, SchemaEntry, SchemaProperty, SchemaPropertyType };
88
+ export { PlainSchematic, PropertyValidators, SchemaPropertyType, Schematic, SchematicEntry, SchematicProperty };
@@ -1,12 +1,12 @@
1
1
  import { ToSchemaPropertyType, ToSchemaType } from "./transform.model.mjs";
2
- import { Schematic } from "../schematic.mjs";
3
- import { PropertyValidators } from "./schema.plain.model.mjs";
2
+ import { Schema } from "../schema.mjs";
3
+ import { PropertyValidators } from "./schematic.plain.model.mjs";
4
4
  import { OptionalKeys, RequiredKeys } from "./misc.model.mjs";
5
5
  import { PlainObject, Simplify } from "@oscarpalmer/atoms/models";
6
6
 
7
- //#region src/models/schema.typed.model.d.ts
7
+ //#region src/models/schematic.typed.model.d.ts
8
8
  /**
9
- * A typed optional property definition generated by {@link TypedSchema} for optional keys, with `$required` set to `false` and excludes `undefined` from the type
9
+ * A typed optional property definition generated by {@link TypedSchematic} for optional keys, with `$required` set to `false` and excludes `undefined` from the type
10
10
  *
11
11
  * @template Value Property's type _(including `undefined`)_
12
12
  *
@@ -18,12 +18,13 @@ import { PlainObject, Simplify } from "@oscarpalmer/atoms/models";
18
18
  * ```
19
19
  */
20
20
  type TypedPropertyOptional<Value> = {
21
+ $default?: never;
21
22
  $required: false;
22
23
  $type: ToSchemaPropertyType<Exclude<Value, undefined>>;
23
24
  $validators?: PropertyValidators<ToSchemaPropertyType<Exclude<Value, undefined>>>;
24
25
  };
25
26
  /**
26
- * A typed required property definition generated by {@link TypedSchema} for required keys, with `$required` defaulting to `true`
27
+ * A typed required property definition generated by {@link TypedSchematic} for required keys, with `$required` defaulting to `true`
27
28
  *
28
29
  * @template Value Property's type
29
30
  *
@@ -35,6 +36,7 @@ type TypedPropertyOptional<Value> = {
35
36
  * ```
36
37
  */
37
38
  type TypedPropertyRequired<Value> = {
39
+ $default?: unknown;
38
40
  $required?: true;
39
41
  $type: ToSchemaPropertyType<Value>;
40
42
  $validators?: PropertyValidators<ToSchemaPropertyType<Value>>;
@@ -42,7 +44,7 @@ type TypedPropertyRequired<Value> = {
42
44
  /**
43
45
  * Creates a schema type constrained to match a TypeScript type
44
46
  *
45
- * Required keys map to {@link ToSchemaType} or {@link TypedPropertyRequired}; plain object values may also use {@link Schematic}. Optional keys map to {@link TypedPropertyOptional} or, for plain objects, {@link TypedSchemaOptional}
47
+ * Required keys map to {@link ToSchemaType} or {@link TypedPropertyRequired}; plain object values may also use {@link Schema}
46
48
  *
47
49
  * @template Model Object type to generate a schema for
48
50
  *
@@ -57,22 +59,6 @@ type TypedPropertyRequired<Value> = {
57
59
  * };
58
60
  * ```
59
61
  */
60
- type TypedSchema<Model extends PlainObject> = Simplify<{ [Key in RequiredKeys<Model>]: Model[Key] extends PlainObject ? TypedSchemaRequired<Model[Key]> | Schematic<Model[Key]> : ToSchemaType<Model[Key]> | TypedPropertyRequired<Model[Key]> } & { [Key in OptionalKeys<Model>]: Exclude<Model[Key], undefined> extends PlainObject ? TypedSchemaOptional<Exclude<Model[Key], undefined>> | Schematic<Exclude<Model[Key], undefined>> : TypedPropertyOptional<Model[Key]> }>;
61
- /**
62
- * A {@link TypedSchema} variant for optional nested objects, with `$required` fixed to `false`
63
- *
64
- * @template Model Nested object type
65
- */
66
- type TypedSchemaOptional<Model extends PlainObject> = {
67
- $required: false;
68
- } & TypedSchema<Model>;
69
- /**
70
- * A {@link TypedSchema} variant for required nested objects, with `$required` defaulting to `true`
71
- *
72
- * @template Model Nested object type
73
- */
74
- type TypedSchemaRequired<Model extends PlainObject> = {
75
- $required?: true;
76
- } & TypedSchema<Model>;
62
+ type TypedSchematic<Model extends PlainObject> = Simplify<{ [Key in RequiredKeys<Model>]: Model[Key] extends PlainObject ? Schema<Model[Key]> : ToSchemaType<Model[Key]> | TypedPropertyRequired<Model[Key]> } & { [Key in OptionalKeys<Model>]: Exclude<Model[Key], undefined> extends PlainObject ? Schema<Exclude<Model[Key], undefined>> : TypedPropertyOptional<Model[Key]> }>;
77
63
  //#endregion
78
- export { TypedPropertyOptional, TypedPropertyRequired, TypedSchema };
64
+ export { TypedPropertyOptional, TypedPropertyRequired, TypedSchematic };