@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
@@ -1,5 +1,5 @@
1
- import { TypedSchema } from "./schema.typed.model.mjs";
2
- import { Schematic } from "../schematic.mjs";
1
+ import { TypedSchematic } from "./schematic.typed.model.mjs";
2
+ import { Schema } from "../schema.mjs";
3
3
  import { DeduplicateTuple, UnionToTuple, UnwrapSingle, Values } from "./misc.model.mjs";
4
4
  import { PlainObject } from "@oscarpalmer/atoms/models";
5
5
 
@@ -25,11 +25,11 @@ type ToSchemaPropertyType<Value> = UnwrapSingle<DeduplicateTuple<MapToSchemaProp
25
25
  /**
26
26
  * Converts a single type to its schema property equivalent
27
27
  *
28
- * Plain objects become {@link TypedSchema}; primitives go through {@link ToValueType}
28
+ * Plain objects become {@link TypedSchematic}; primitives go through {@link ToValueType}
29
29
  *
30
30
  * @template Value Type to convert
31
31
  */
32
- type ToSchemaPropertyTypeEach<Value> = Value extends PlainObject ? TypedSchema<Value> : ToValueType<Value>;
32
+ type ToSchemaPropertyTypeEach<Value> = Value extends PlainObject ? TypedSchematic<Value> : ToValueType<Value>;
33
33
  /**
34
34
  * Converts a TypeScript type to its {@link ValueName} representation, suitable for use as a top-level schema entry
35
35
  *
@@ -39,7 +39,7 @@ type ToSchemaType<Value> = UnwrapSingle<DeduplicateTuple<MapToValueTypes<UnionTo
39
39
  /**
40
40
  * Maps a type to its {@link ValueName} string equivalent
41
41
  *
42
- * Resolves {@link Schematic} types as-is, then performs a reverse-lookup against {@link Values} _(excluding `'object'`)_ to find a matching key. If no match is found, `object` types resolve to `'object'` or a type-guard function, and all other unrecognised types resolve to a type-guard function
42
+ * Resolves {@link Schema} types as-is, then performs a reverse-lookup against {@link Values} _(excluding `'object'`)_ to find a matching key. If no match is found, `object` types resolve to `'object'` or a type-guard function, and all other unrecognised types resolve to a type-guard function
43
43
  *
44
44
  * @template Value Type to map
45
45
  *
@@ -50,6 +50,6 @@ type ToSchemaType<Value> = UnwrapSingle<DeduplicateTuple<MapToValueTypes<UnionTo
50
50
  * // ToValueType<Date> => 'date'
51
51
  * ```
52
52
  */
53
- type ToValueType<Value> = Value extends Schematic<any> ? Value : { [Key in keyof Omit<Values, 'object'>]: Value extends Values[Key] ? Key : never }[keyof Omit<Values, 'object'>] extends infer Match ? [Match] extends [never] ? Value extends object ? 'object' | ((value: unknown) => value is Value) : (value: unknown) => value is Value : Match : never;
53
+ type ToValueType<Value> = Value extends Schema<any> ? Value : { [Key in keyof Omit<Values, 'object'>]: Value extends Values[Key] ? Key : never }[keyof Omit<Values, 'object'>] extends infer Match ? [Match] extends [never] ? Value extends object ? 'object' | ((value: unknown) => value is Value) : (value: unknown) => value is Value : Match : never;
54
54
  //#endregion
55
55
  export { MapToSchemaPropertyTypes, MapToValueTypes, ToSchemaPropertyType, ToSchemaPropertyTypeEach, ToSchemaType, ToValueType };
@@ -1,4 +1,4 @@
1
- import { Schematic } from "../schematic.mjs";
1
+ import { Schema } from "../schema.mjs";
2
2
  import { ValueName } from "./misc.model.mjs";
3
3
  import { GenericCallback, PlainObject } from "@oscarpalmer/atoms/models";
4
4
 
@@ -70,6 +70,16 @@ type GetOptions<Errors extends ReportingType> = BaseOptions<Errors> & {
70
70
  */
71
71
  type IsOptions<Errors extends ReportingType> = BaseOptions<Errors>;
72
72
  type Validator = (input: unknown, parameters: ValidatorParameters, get: boolean) => true | ValidationInformation[];
73
+ type ValidatorDefaults = {
74
+ value: unknown;
75
+ };
76
+ type ValidatorItem = {
77
+ defaults: ValidatorDefaults | undefined;
78
+ key: ValidationInformationKey;
79
+ required: boolean;
80
+ types: ValidatorType[];
81
+ validator: Validator;
82
+ };
73
83
  type ValidatorParameters = {
74
84
  clone: boolean;
75
85
  information?: ValidationInformation[];
@@ -77,6 +87,6 @@ type ValidatorParameters = {
77
87
  reporting: ReportingInformation;
78
88
  strict: boolean;
79
89
  };
80
- type ValidatorType = Function | PlainObject | Schematic<unknown> | ValueName;
90
+ type ValidatorType = Function | PlainObject | Schema<unknown> | ValueName;
81
91
  //#endregion
82
- export { GetOptions, IsOptions, NamedValidatorHandlers, NamedValidators, ReportingInformation, ReportingType, SchematicError, ValidationError, ValidationInformation, ValidationInformationKey, Validator, ValidatorParameters, ValidatorType };
92
+ export { GetOptions, IsOptions, NamedValidatorHandlers, NamedValidators, ReportingInformation, ReportingType, SchematicError, ValidationError, ValidationInformation, ValidationInformationKey, Validator, ValidatorDefaults, ValidatorItem, ValidatorParameters, ValidatorType };
@@ -1,17 +1,17 @@
1
1
  import { Infer } from "./models/infer.model.mjs";
2
- import { TypedSchema } from "./models/schema.typed.model.mjs";
2
+ import { TypedSchematic } from "./models/schematic.typed.model.mjs";
3
3
  import { GetOptions, IsOptions, ValidationInformation, Validator } from "./models/validation.model.mjs";
4
- import { Schema } from "./models/schema.plain.model.mjs";
4
+ import { Schematic } from "./models/schematic.plain.model.mjs";
5
5
  import { PlainObject } from "@oscarpalmer/atoms/models";
6
6
  import { Result } from "@oscarpalmer/atoms/result/models";
7
7
 
8
- //#region src/schematic.d.ts
8
+ //#region src/schema.d.ts
9
9
  /**
10
- * A schematic for validating objects
10
+ * A schema for validating objects
11
11
  */
12
- declare class Schematic<Model> {
12
+ declare class Schema<Model> {
13
13
  #private;
14
- private readonly $schematic;
14
+ private readonly $schema;
15
15
  constructor(validator: Validator);
16
16
  /**
17
17
  * Parse a value according to the schema
@@ -159,21 +159,21 @@ declare class Schematic<Model> {
159
159
  is(value: unknown, strict?: true): value is Model;
160
160
  }
161
161
  /**
162
- * Create a schematic from a schema
162
+ * Create a schema from a schematic
163
163
  * @template Model Schema type
164
- * @param schema Schema to create the schematic from
165
- * @throws Throws {@link SchematicError} if the schema can not be converted into a schematic
166
- * @returns A schematic for the given schema
164
+ * @param schema Schematic to create the schema from
165
+ * @throws Throws {@link SchematicError} if the schematic can not be converted into a schema
166
+ * @returns A schema for the given schematic
167
167
  */
168
- declare function schematic<Model extends Schema>(schema: Model): Schematic<Infer<Model>>;
168
+ declare function schema<Model extends Schematic>(schema: Model): Schema<Infer<Model>>;
169
169
  /**
170
- * Create a schematic from a typed schema
170
+ * Create a schema from a typed schematic
171
171
  * @template Model Existing type
172
- * @param schema Typed schema to create the schematic from
173
- * @throws Throws {@link SchematicError} if the schema can not be converted into a schematic
174
- * @returns A schematic for the given typed schema
172
+ * @param schema Typed schematic to create the schema from
173
+ * @throws Throws {@link SchematicError} if the schematic can not be converted into a schema
174
+ * @returns A schema for the given typed schematic
175
175
  */
176
- declare function schematic<Model extends PlainObject>(schema: TypedSchema<Model>): Schematic<Model>;
177
- declare const schematicValidator: WeakMap<Schematic<unknown>, Validator>;
176
+ declare function schema<Model extends PlainObject>(schema: TypedSchematic<Model>): Schema<Model>;
177
+ declare const schemaValidators: WeakMap<Schema<unknown>, Validator>;
178
178
  //#endregion
179
- export { Schematic, schematic, schematicValidator };
179
+ export { Schema, schema, schemaValidators };
@@ -1,19 +1,19 @@
1
- import { PROPERTY_SCHEMATIC, SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE } from "./constants.mjs";
2
- import { getParameters, isSchematic } from "./helpers/misc.helper.mjs";
1
+ import { PROPERTY_SCHEMA, SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE } from "./constants.mjs";
2
+ import { getParameters, isSchema } from "./helpers/misc.helper.mjs";
3
3
  import { SchematicError } from "./models/validation.model.mjs";
4
4
  import { getObjectValidator } from "./validator/object.validator.mjs";
5
5
  import { isPlainObject } from "@oscarpalmer/atoms/is";
6
6
  import { error, ok } from "@oscarpalmer/atoms/result/misc";
7
- //#region src/schematic.ts
7
+ //#region src/schema.ts
8
8
  /**
9
- * A schematic for validating objects
9
+ * A schema for validating objects
10
10
  */
11
- var Schematic = class {
11
+ var Schema = class {
12
12
  #validator;
13
13
  constructor(validator) {
14
- Object.defineProperty(this, PROPERTY_SCHEMATIC, { value: true });
14
+ Object.defineProperty(this, PROPERTY_SCHEMA, { value: true });
15
15
  this.#validator = validator;
16
- schematicValidator.set(this, validator);
16
+ schemaValidators.set(this, validator);
17
17
  }
18
18
  get(value, options) {
19
19
  const parameters = getParameters(options);
@@ -30,11 +30,11 @@ var Schematic = class {
30
30
  return error(parameters.reporting.all ? result : result[0]);
31
31
  }
32
32
  };
33
- function schematic(schema) {
34
- if (isSchematic(schema)) return schema;
33
+ function schema(schema) {
34
+ if (isSchema(schema)) return schema;
35
35
  if (!isPlainObject(schema)) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE);
36
- return new Schematic(getObjectValidator(schema));
36
+ return new Schema(getObjectValidator(schema));
37
37
  }
38
- const schematicValidator = /* @__PURE__ */ new WeakMap();
38
+ const schemaValidators = /* @__PURE__ */ new WeakMap();
39
39
  //#endregion
40
- export { Schematic, schematic, schematicValidator };
40
+ export { Schema, schema, schemaValidators };
@@ -1,6 +1,6 @@
1
1
  import { NamedValidatorHandlers } from "../models/validation.model.mjs";
2
2
 
3
3
  //#region src/validator/named.handler.d.ts
4
- declare function getNamedHandlers(original: unknown, prefix: string): NamedValidatorHandlers;
4
+ declare function getNamedHandlers(original: unknown, prefix: string, allowed: boolean): NamedValidatorHandlers;
5
5
  //#endregion
6
6
  export { getNamedHandlers };
@@ -1,9 +1,10 @@
1
- import { SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE, TYPE_ALL } from "../constants.mjs";
1
+ import { PROPERTY_VALIDATORS, SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE, SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE, TYPE_ALL } from "../constants.mjs";
2
2
  import { isPlainObject } from "@oscarpalmer/atoms/is";
3
3
  //#region src/validator/named.handler.ts
4
- function getNamedHandlers(original, prefix) {
4
+ function getNamedHandlers(original, prefix, allowed) {
5
5
  const handlers = {};
6
6
  if (original == null) return handlers;
7
+ if (!allowed) throw new TypeError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", prefix).replace("<>", PROPERTY_VALIDATORS));
7
8
  if (!isPlainObject(original)) throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
8
9
  const keys = Object.keys(original);
9
10
  const { length } = keys;
@@ -1,5 +1,4 @@
1
- import "../constants.mjs";
2
- import { getInvalidValidatorMessage } from "../helpers/message.helper.mjs";
1
+ import { getInputPropertyValidatorMessage } from "../helpers/message.helper.mjs";
3
2
  //#region src/validator/named.validator.ts
4
3
  function getNamedValidator(key, name, handlers) {
5
4
  const validator = namedValidators[name];
@@ -13,7 +12,7 @@ function getNamedValidator(key, name, handlers) {
13
12
  const information = {
14
13
  key,
15
14
  validator,
16
- message: getInvalidValidatorMessage(key.full, name, index, length),
15
+ message: getInputPropertyValidatorMessage(key.full, name, index, length),
17
16
  value: input
18
17
  };
19
18
  parameters.information?.push(information);
@@ -1,17 +1,23 @@
1
- import { PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY, SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED, SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE, SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED, SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE, TYPE_ALL } from "../constants.mjs";
2
- import { isSchematic } from "../helpers/misc.helper.mjs";
1
+ import { PROPERTY_DEFAULT, PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY, TYPE_ALL } from "../constants.mjs";
2
+ import { getParameters, isSchema } from "../helpers/misc.helper.mjs";
3
3
  import { SchematicError, ValidationError } from "../models/validation.model.mjs";
4
- import { getInvalidInputMessage, getInvalidMissingMessage, getInvalidTypeMessage, getUnknownKeysMessage } from "../helpers/message.helper.mjs";
4
+ import { getDefaultRequiredMessage, getDefaultTypeMessage, getDisallowedMessage, getInputPropertyMissingMessage, getInputPropertyTypeMessage, getInputTypeMessage, getRequiredMessage, getSchematicPropertyNullableMessage, getSchematicPropertyTypeMessage, getUnknownKeysMessage } from "../helpers/message.helper.mjs";
5
5
  import { getBaseValidator } from "./base.validator.mjs";
6
6
  import { getFunctionValidator } from "./function.validator.mjs";
7
7
  import { getNamedHandlers } from "./named.handler.mjs";
8
8
  import { getNamedValidator } from "./named.validator.mjs";
9
- import { getSchematicValidator } from "./schematic.validator.mjs";
9
+ import { getSchemaValidator } from "./schematic.validator.mjs";
10
10
  import { isPlainObject } from "@oscarpalmer/atoms/is";
11
11
  import { join } from "@oscarpalmer/atoms/string";
12
12
  import { clone } from "@oscarpalmer/atoms/value/clone";
13
13
  //#region src/validator/object.validator.ts
14
+ function getDefaults(obj, key, allowed) {
15
+ if (!("$default" in obj)) return;
16
+ if (!allowed) throw new SchematicError(getDisallowedMessage(key, PROPERTY_DEFAULT));
17
+ return { value: obj[PROPERTY_DEFAULT] };
18
+ }
14
19
  function getDisallowedProperty(obj) {
20
+ if ("$default" in obj) return PROPERTY_DEFAULT;
15
21
  if ("$required" in obj) return PROPERTY_REQUIRED;
16
22
  if ("$type" in obj) return PROPERTY_TYPE;
17
23
  if ("$validators" in obj) return PROPERTY_VALIDATORS;
@@ -22,14 +28,14 @@ function getObjectValidator(original, origin, fromType) {
22
28
  if (keysLength === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY);
23
29
  if (fromType ?? false) {
24
30
  const property = getDisallowedProperty(original);
25
- if (property != null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace("<>", origin.full).replace("<>", property));
31
+ if (property != null) throw new SchematicError(getDisallowedMessage(origin.full, property));
26
32
  }
27
33
  const set = /* @__PURE__ */ new Set();
28
34
  const items = [];
29
35
  for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
30
36
  const key = keys[keyIndex];
31
37
  const value = original[key];
32
- if (value == null) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace("<>", join([origin?.full, key], ".")));
38
+ if (value == null) throw new SchematicError(getSchematicPropertyNullableMessage(join([origin?.full, key], ".")));
33
39
  const prefixedKey = origin == null ? key : join([origin.full, key], ".");
34
40
  const fullKey = {
35
41
  full: prefixedKey,
@@ -38,16 +44,18 @@ function getObjectValidator(original, origin, fromType) {
38
44
  let handlers = {};
39
45
  let required = true;
40
46
  let typed = false;
47
+ let defaults;
41
48
  let types;
42
49
  const validators = [];
43
50
  if (isPlainObject(value)) {
44
51
  typed = PROPERTY_TYPE in value;
45
52
  const type = typed ? value[PROPERTY_TYPE] : value;
46
- handlers = getNamedHandlers(value[PROPERTY_VALIDATORS], prefixedKey);
47
- required = getRequired(key, value) ?? required;
53
+ defaults = getDefaults(value, prefixedKey, typed);
54
+ handlers = getNamedHandlers(value[PROPERTY_VALIDATORS], prefixedKey, typed);
55
+ required = getRequired(value, prefixedKey, typed) ?? required;
48
56
  types = Array.isArray(type) ? type : [type];
49
57
  } else types = Array.isArray(value) ? value : [value];
50
- if (types.length === 0) throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", prefixedKey).replace("<>", String(value)));
58
+ if (types.length === 0) throw new SchematicError(getSchematicPropertyTypeMessage(prefixedKey));
51
59
  const typesLength = types.length;
52
60
  for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
53
61
  const type = types[typeIndex];
@@ -59,23 +67,28 @@ function getObjectValidator(original, origin, fromType) {
59
67
  case isPlainObject(type):
60
68
  validator = getObjectValidator(type, fullKey, typed);
61
69
  break;
62
- case isSchematic(type):
63
- validator = getSchematicValidator(type);
70
+ case isSchema(type):
71
+ validator = getSchemaValidator(type);
64
72
  break;
65
73
  case TYPE_ALL.has(type):
66
74
  validator = getNamedValidator(fullKey, type, handlers);
67
75
  break;
68
- default: throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace("<>", prefixedKey).replace("<>", String(type)));
76
+ default: throw new SchematicError(getSchematicPropertyTypeMessage(prefixedKey));
69
77
  }
70
78
  validators.push(validator);
71
79
  }
72
- set.add(key);
80
+ required = required && !types.includes("undefined");
81
+ if (defaults != null && !required) throw new SchematicError(getDefaultRequiredMessage(prefixedKey));
82
+ const validator = getBaseValidator(validators);
83
+ if (defaults != null && Array.isArray(validator(defaults.value, getParameters(), false))) throw new SchematicError(getDefaultTypeMessage(prefixedKey, types));
73
84
  items.push({
85
+ defaults,
86
+ required,
74
87
  types,
75
- key: fullKey,
76
- required: required && !types.includes("undefined"),
77
- validator: getBaseValidator(validators)
88
+ validator,
89
+ key: fullKey
78
90
  });
91
+ set.add(key);
79
92
  }
80
93
  const validatorsLength = items.length;
81
94
  return (input, parameters, get) => {
@@ -87,7 +100,7 @@ function getObjectValidator(original, origin, fromType) {
87
100
  short: ""
88
101
  },
89
102
  value: input,
90
- message: getInvalidInputMessage(input)
103
+ message: getInputTypeMessage(input)
91
104
  };
92
105
  if (parameters.reporting.throw) throw new ValidationError([information]);
93
106
  parameters.information?.push(information);
@@ -112,15 +125,19 @@ function getObjectValidator(original, origin, fromType) {
112
125
  const allInformation = [];
113
126
  const output = {};
114
127
  for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
115
- const { key, required, types, validator } = items[validatorIndex];
128
+ const { defaults, key, required, types, validator } = items[validatorIndex];
116
129
  const value = input[key.short];
117
130
  if (value === void 0) {
118
131
  if (required) {
132
+ if (get && defaults != null) {
133
+ output[key.short] = clone(defaults.value);
134
+ continue;
135
+ }
119
136
  if (parameters.reporting.none) return [];
120
137
  const information = {
121
138
  key,
122
139
  value,
123
- message: getInvalidMissingMessage(key.full, types)
140
+ message: getInputPropertyMissingMessage(key.full, types)
124
141
  };
125
142
  if (parameters.reporting.throw) throw new ValidationError([information]);
126
143
  parameters.information?.push(information);
@@ -144,7 +161,7 @@ function getObjectValidator(original, origin, fromType) {
144
161
  const information = typeof result !== "boolean" && result.length > 0 ? result : [{
145
162
  key,
146
163
  value,
147
- message: getInvalidTypeMessage(key.full, types, value)
164
+ message: getInputPropertyTypeMessage(key.full, types, value)
148
165
  }];
149
166
  if (parameters.reporting.throw) throw new ValidationError(information);
150
167
  if (parameters.reporting.all) {
@@ -158,9 +175,10 @@ function getObjectValidator(original, origin, fromType) {
158
175
  return allInformation.length === 0 ? true : allInformation;
159
176
  };
160
177
  }
161
- function getRequired(key, obj) {
178
+ function getRequired(obj, key, allowed) {
162
179
  if (!("$required" in obj)) return;
163
- if (typeof obj["$required"] !== "boolean") throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace("<>", key));
180
+ if (!allowed) throw new SchematicError(getDisallowedMessage(key, PROPERTY_REQUIRED));
181
+ if (typeof obj["$required"] !== "boolean") throw new SchematicError(getRequiredMessage(key));
164
182
  return obj[PROPERTY_REQUIRED];
165
183
  }
166
184
  //#endregion
@@ -1,7 +1,7 @@
1
1
  import { Validator } from "../models/validation.model.mjs";
2
- import { Schematic } from "../schematic.mjs";
2
+ import { Schema } from "../schema.mjs";
3
3
 
4
4
  //#region src/validator/schematic.validator.d.ts
5
- declare function getSchematicValidator(schematic: Schematic<unknown>): Validator;
5
+ declare function getSchemaValidator(schematic: Schema<unknown>): Validator;
6
6
  //#endregion
7
- export { getSchematicValidator };
7
+ export { getSchemaValidator };
@@ -1,8 +1,8 @@
1
- import { schematicValidator } from "../schematic.mjs";
1
+ import { schemaValidators } from "../schema.mjs";
2
2
  import { isPlainObject } from "@oscarpalmer/atoms/is";
3
3
  //#region src/validator/schematic.validator.ts
4
- function getSchematicValidator(schematic) {
5
- const validator = schematicValidator.get(schematic);
4
+ function getSchemaValidator(schematic) {
5
+ const validator = schemaValidators.get(schematic);
6
6
  return (input, parameters, get) => {
7
7
  let result;
8
8
  if (isPlainObject(input)) result = validator(input, parameters, get);
@@ -13,4 +13,4 @@ function getSchematicValidator(schematic) {
13
13
  };
14
14
  }
15
15
  //#endregion
16
- export { getSchematicValidator };
16
+ export { getSchemaValidator };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oscarpalmer/jhunal",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "description": "Flies free beneath the glistening moons…",
5
5
  "keywords": [
6
6
  "schema",
package/src/constants.ts CHANGED
@@ -23,9 +23,9 @@ export const MESSAGE_CONSTRUCTOR = 'Expected a constructor function';
23
23
 
24
24
  // #region Names
25
25
 
26
- export const NAME_SCHEMATIC = 'Schematic';
26
+ export const NAME_SCHEMA = 'Schema';
27
27
 
28
- export const NAME_SCHEMATIC_PREFIXED = 'a Schematic';
28
+ export const NAME_SCHEMA_PREFIXED = 'a Schema';
29
29
 
30
30
  export const NAME_ERROR_SCHEMATIC = 'SchematicError';
31
31
 
@@ -35,9 +35,11 @@ export const NAME_ERROR_VALIDATION = 'ValidationError';
35
35
 
36
36
  // #region Properties
37
37
 
38
+ export const PROPERTY_DEFAULT = '$default';
39
+
38
40
  export const PROPERTY_REQUIRED = '$required';
39
41
 
40
- export const PROPERTY_SCHEMATIC = '$schematic';
42
+ export const PROPERTY_SCHEMA = '$schema';
41
43
 
42
44
  export const PROPERTY_TYPE = '$type';
43
45
 
@@ -83,10 +85,16 @@ export const REPORTING_TYPES = new Set<ReportingType>([
83
85
 
84
86
  // #region Schematic validation
85
87
 
88
+ export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_REQUIRED =
89
+ "'<>' has a default value but is not required";
90
+
91
+ export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_TYPE =
92
+ "Expected default value for property '<>' to be <>";
93
+
86
94
  export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY = 'Schema must have at least one property';
87
95
 
88
96
  export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED =
89
- "'<>.<>' property is not allowed for schemas in $type";
97
+ "'<>.<>' property is not allowed for plain schemas";
90
98
 
91
99
  export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE =
92
100
  "'<>' property must not be 'null' or 'undefined'";
@@ -118,52 +126,40 @@ export const TEMPLATE_PATTERN = '<>';
118
126
 
119
127
  export const TYPE_ARRAY = 'array';
120
128
 
121
- const TYPE_BIGINT = 'bigint';
122
-
123
- const TYPE_BOOLEAN = 'boolean';
124
-
125
- const TYPE_DATE = 'date';
126
-
127
129
  export const TYPE_FUNCTION = 'function';
128
130
 
129
131
  export const TYPE_FUNCTION_RESULT = 'a validated value';
130
132
 
131
133
  export const TYPE_NULL = 'null';
132
134
 
133
- const TYPE_NUMBER = 'number';
134
-
135
135
  export const TYPE_OBJECT = 'object';
136
136
 
137
- const TYPE_STRING = 'string';
138
-
139
- const TYPE_SYMBOL = 'symbol';
140
-
141
137
  export const TYPE_UNDEFINED = 'undefined';
142
138
 
143
139
  export const VALIDATABLE_TYPES = new Set<ValueName>([
144
140
  TYPE_ARRAY,
145
- TYPE_BIGINT,
146
- TYPE_BOOLEAN,
147
- TYPE_DATE,
141
+ 'bigint',
142
+ 'boolean',
143
+ 'date',
148
144
  TYPE_FUNCTION,
149
- TYPE_NUMBER,
145
+ 'number',
150
146
  TYPE_OBJECT,
151
- TYPE_STRING,
152
- TYPE_SYMBOL,
147
+ 'string',
148
+ 'symbol',
153
149
  ]);
154
150
 
155
151
  export const TYPE_ALL = new Set<ValueName>([...VALIDATABLE_TYPES, TYPE_NULL, TYPE_UNDEFINED]);
156
152
 
157
153
  export const PREFIXED_TYPES: Record<ValueName, string> = {
158
154
  [TYPE_ARRAY]: `an ${TYPE_ARRAY}`,
159
- [TYPE_BIGINT]: `a ${TYPE_BIGINT}`,
160
- [TYPE_BOOLEAN]: `a ${TYPE_BOOLEAN}`,
161
- [TYPE_DATE]: `a ${TYPE_DATE}`,
155
+ bigint: `a bigint`,
156
+ boolean: `a boolean`,
157
+ date: `a date`,
162
158
  [TYPE_FUNCTION]: `a ${TYPE_FUNCTION}`,
163
159
  [TYPE_NULL]: TYPE_NULL,
164
- [TYPE_NUMBER]: `a ${TYPE_NUMBER}`,
165
- [TYPE_STRING]: `a ${TYPE_STRING}`,
166
- [TYPE_SYMBOL]: `a ${TYPE_SYMBOL}`,
160
+ number: `a number`,
161
+ string: `a string`,
162
+ symbol: `a symbol`,
167
163
  [TYPE_OBJECT]: `an ${TYPE_OBJECT}`,
168
164
  [TYPE_UNDEFINED]: TYPE_UNDEFINED,
169
165
  };
@@ -6,10 +6,15 @@ import {
6
6
  CONJUNCTION_OR,
7
7
  CONJUNCTION_OR_COMMA,
8
8
  PREFIXED_TYPES,
9
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_REQUIRED,
10
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_TYPE,
11
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED,
12
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE,
13
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED,
14
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE,
9
15
  TEMPLATE_PATTERN,
10
16
  TYPE_ALL,
11
17
  TYPE_ARRAY,
12
- TYPE_FUNCTION,
13
18
  TYPE_FUNCTION_RESULT,
14
19
  TYPE_NULL,
15
20
  TYPE_OBJECT,
@@ -23,11 +28,41 @@ import {
23
28
  import type {ValueName} from '../models/misc.model';
24
29
  import type {ValidatorType} from '../models/validation.model';
25
30
 
26
- export function getInvalidInputMessage(actual: unknown): string {
31
+ // #region Defaults
32
+
33
+ export function getDefaultRequiredMessage(key: string): string {
34
+ return SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_REQUIRED.replace(TEMPLATE_PATTERN, key);
35
+ }
36
+
37
+ export function getDefaultTypeMessage(key: string, types: ValidatorType[]): string {
38
+ let message = SCHEMATIC_MESSAGE_SCHEMA_INVALID_DEFAULT_TYPE.replace(TEMPLATE_PATTERN, key);
39
+
40
+ message = message.replace(TEMPLATE_PATTERN, renderTypes(types));
41
+
42
+ return message;
43
+ }
44
+
45
+ // #endregion
46
+
47
+ // #region Disallowed
48
+
49
+ export function getDisallowedMessage(key: string, property: string): string {
50
+ let message = SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace(TEMPLATE_PATTERN, key);
51
+
52
+ message = message.replace(TEMPLATE_PATTERN, property);
53
+
54
+ return message;
55
+ }
56
+
57
+ // #endregion
58
+
59
+ // #region Input
60
+
61
+ export function getInputTypeMessage(actual: unknown): string {
27
62
  return VALIDATION_MESSAGE_INVALID_INPUT.replace(TEMPLATE_PATTERN, getValueType(actual));
28
63
  }
29
64
 
30
- export function getInvalidMissingMessage(key: string, types: ValidatorType[]): string {
65
+ export function getInputPropertyMissingMessage(key: string, types: ValidatorType[]): string {
31
66
  let message = VALIDATION_MESSAGE_INVALID_REQUIRED.replace(TEMPLATE_PATTERN, renderTypes(types));
32
67
 
33
68
  message = message.replace(TEMPLATE_PATTERN, key);
@@ -35,7 +70,7 @@ export function getInvalidMissingMessage(key: string, types: ValidatorType[]): s
35
70
  return message;
36
71
  }
37
72
 
38
- export function getInvalidTypeMessage(
73
+ export function getInputPropertyTypeMessage(
39
74
  key: string,
40
75
  types: ValidatorType[],
41
76
  actual: unknown,
@@ -48,7 +83,7 @@ export function getInvalidTypeMessage(
48
83
  return message;
49
84
  }
50
85
 
51
- export function getInvalidValidatorMessage(
86
+ export function getInputPropertyValidatorMessage(
52
87
  key: string,
53
88
  type: ValueName,
54
89
  index: number,
@@ -65,6 +100,22 @@ export function getInvalidValidatorMessage(
65
100
  return message;
66
101
  }
67
102
 
103
+ // #endregion
104
+
105
+ // #region Schematic
106
+
107
+ export function getSchematicPropertyNullableMessage(key: string): string {
108
+ return SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE.replace(TEMPLATE_PATTERN, key);
109
+ }
110
+
111
+ export function getSchematicPropertyTypeMessage(key: string): string {
112
+ return SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE.replace(TEMPLATE_PATTERN, key);
113
+ }
114
+
115
+ // #endregion
116
+
117
+ // #region Misc.
118
+
68
119
  function getPropertyType(type: ValidatorType): string {
69
120
  switch (true) {
70
121
  case typeof type === 'function':
@@ -78,10 +129,6 @@ function getPropertyType(type: ValidatorType): string {
78
129
  }
79
130
  }
80
131
 
81
- export function getUnknownKeysMessage(keys: string[]): string {
82
- return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace(TEMPLATE_PATTERN, renderKeys(keys));
83
- }
84
-
85
132
  function getValueType(value: unknown): string {
86
133
  const valueType = typeof value;
87
134
 
@@ -150,3 +197,21 @@ function renderTypes(types: ValidatorType[]): string {
150
197
 
151
198
  return renderParts(parts, CONJUNCTION_OR, CONJUNCTION_OR_COMMA);
152
199
  }
200
+
201
+ // #endregion
202
+
203
+ // #region Required
204
+
205
+ export function getRequiredMessage(key: string): string {
206
+ return SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace(TEMPLATE_PATTERN, key);
207
+ }
208
+
209
+ // #endregion
210
+
211
+ // #region Strictness
212
+
213
+ export function getUnknownKeysMessage(keys: string[]): string {
214
+ return VALIDATION_MESSAGE_UNKNOWN_KEYS.replace(TEMPLATE_PATTERN, renderKeys(keys));
215
+ }
216
+
217
+ // #endregion