@oscarpalmer/jhunal 0.22.0 → 0.24.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 (46) hide show
  1. package/dist/constants.d.mts +11 -4
  2. package/dist/constants.mjs +27 -8
  3. package/dist/helpers/message.helper.d.mts +17 -0
  4. package/dist/helpers/message.helper.mjs +92 -0
  5. package/dist/helpers/misc.helper.d.mts +22 -0
  6. package/dist/helpers/misc.helper.mjs +56 -0
  7. package/dist/index.d.mts +309 -292
  8. package/dist/index.mjs +237 -166
  9. package/dist/models/schema.plain.model.d.mts +2 -0
  10. package/dist/models/schema.typed.model.d.mts +3 -17
  11. package/dist/models/validation.model.d.mts +28 -7
  12. package/dist/schematic.d.mts +25 -7
  13. package/dist/schematic.mjs +6 -4
  14. package/dist/validator/base.validator.d.mts +6 -0
  15. package/dist/validator/base.validator.mjs +19 -0
  16. package/dist/validator/function.validator.d.mts +6 -0
  17. package/dist/validator/function.validator.mjs +9 -0
  18. package/dist/validator/named.handler.d.mts +6 -0
  19. package/dist/validator/named.handler.mjs +23 -0
  20. package/dist/validator/named.validator.d.mts +7 -0
  21. package/dist/validator/named.validator.mjs +38 -0
  22. package/dist/validator/object.validator.d.mts +7 -0
  23. package/dist/validator/object.validator.mjs +185 -0
  24. package/dist/validator/schematic.validator.d.mts +7 -0
  25. package/dist/validator/schematic.validator.mjs +16 -0
  26. package/package.json +1 -1
  27. package/src/constants.ts +34 -6
  28. package/src/helpers/message.helper.ts +217 -0
  29. package/src/helpers/misc.helper.ts +92 -0
  30. package/src/index.ts +3 -3
  31. package/src/models/schema.plain.model.ts +2 -0
  32. package/src/models/schema.typed.model.ts +4 -22
  33. package/src/models/validation.model.ts +31 -6
  34. package/src/schematic.ts +43 -16
  35. package/src/validator/base.validator.ts +31 -0
  36. package/src/validator/function.validator.ts +9 -0
  37. package/src/validator/named.handler.ts +65 -0
  38. package/src/validator/named.validator.ts +61 -0
  39. package/src/validator/object.validator.ts +366 -0
  40. package/src/validator/schematic.validator.ts +25 -0
  41. package/dist/helpers.d.mts +0 -28
  42. package/dist/helpers.mjs +0 -120
  43. package/dist/validation.d.mts +0 -7
  44. package/dist/validation.mjs +0 -245
  45. package/src/helpers.ts +0 -249
  46. package/src/validation.ts +0 -498
@@ -0,0 +1,217 @@
1
+ import {isConstructor, isPlainObject} from '@oscarpalmer/atoms/is';
2
+ import {
3
+ COMMA,
4
+ CONJUNCTION_AND,
5
+ CONJUNCTION_AND_COMMA,
6
+ CONJUNCTION_OR,
7
+ CONJUNCTION_OR_COMMA,
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,
15
+ TEMPLATE_PATTERN,
16
+ TYPE_ALL,
17
+ TYPE_ARRAY,
18
+ TYPE_FUNCTION_RESULT,
19
+ TYPE_NULL,
20
+ TYPE_OBJECT,
21
+ VALIDATION_MESSAGE_INVALID_INPUT,
22
+ VALIDATION_MESSAGE_INVALID_REQUIRED,
23
+ VALIDATION_MESSAGE_INVALID_TYPE,
24
+ VALIDATION_MESSAGE_INVALID_VALUE,
25
+ VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX,
26
+ VALIDATION_MESSAGE_UNKNOWN_KEYS,
27
+ } from '../constants';
28
+ import type {ValueName} from '../models/misc.model';
29
+ import type {ValidatorType} from '../models/validation.model';
30
+
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 {
62
+ return VALIDATION_MESSAGE_INVALID_INPUT.replace(TEMPLATE_PATTERN, getValueType(actual));
63
+ }
64
+
65
+ export function getInputPropertyMissingMessage(key: string, types: ValidatorType[]): string {
66
+ let message = VALIDATION_MESSAGE_INVALID_REQUIRED.replace(TEMPLATE_PATTERN, renderTypes(types));
67
+
68
+ message = message.replace(TEMPLATE_PATTERN, key);
69
+
70
+ return message;
71
+ }
72
+
73
+ export function getInputPropertyTypeMessage(
74
+ key: string,
75
+ types: ValidatorType[],
76
+ actual: unknown,
77
+ ): string {
78
+ let message = VALIDATION_MESSAGE_INVALID_TYPE.replace(TEMPLATE_PATTERN, renderTypes(types));
79
+
80
+ message = message.replace(TEMPLATE_PATTERN, key);
81
+ message = message.replace(TEMPLATE_PATTERN, getValueType(actual));
82
+
83
+ return message;
84
+ }
85
+
86
+ export function getInputPropertyValidatorMessage(
87
+ key: string,
88
+ type: ValueName,
89
+ index: number,
90
+ length: number,
91
+ ): string {
92
+ let message = VALIDATION_MESSAGE_INVALID_VALUE.replace(TEMPLATE_PATTERN, key);
93
+
94
+ message = message.replace(TEMPLATE_PATTERN, type);
95
+
96
+ if (length > 1) {
97
+ message += VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX.replace(TEMPLATE_PATTERN, String(index));
98
+ }
99
+
100
+ return message;
101
+ }
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
+
119
+ function getPropertyType(type: ValidatorType): string {
120
+ switch (true) {
121
+ case typeof type === 'function':
122
+ return isConstructor(type) ? type.name : TYPE_FUNCTION_RESULT;
123
+
124
+ case TYPE_ALL.has(type as ValueName):
125
+ return PREFIXED_TYPES[type as ValueName];
126
+
127
+ default:
128
+ return PREFIXED_TYPES[TYPE_OBJECT];
129
+ }
130
+ }
131
+
132
+ function getValueType(value: unknown): string {
133
+ const valueType = typeof value;
134
+
135
+ switch (true) {
136
+ case value === null:
137
+ return TYPE_NULL;
138
+
139
+ case Array.isArray(value):
140
+ return PREFIXED_TYPES[TYPE_ARRAY];
141
+
142
+ case isPlainObject(value):
143
+ return PREFIXED_TYPES[TYPE_OBJECT];
144
+
145
+ case valueType !== TYPE_OBJECT:
146
+ return PREFIXED_TYPES[valueType as ValueName];
147
+
148
+ default:
149
+ return (value as object).constructor.name;
150
+ }
151
+ }
152
+
153
+ function renderKeys(keys: string[]): string {
154
+ return renderParts(
155
+ keys.map(key => `'${key}'`),
156
+ CONJUNCTION_AND,
157
+ CONJUNCTION_AND_COMMA,
158
+ );
159
+ }
160
+
161
+ function renderParts(parts: string[], delimiterShort: string, delimiterLong: string): string {
162
+ const {length} = parts;
163
+
164
+ if (length === 1) {
165
+ return parts[0];
166
+ }
167
+
168
+ let rendered = '';
169
+
170
+ for (let index = 0; index < length; index += 1) {
171
+ rendered += parts[index];
172
+
173
+ if (index < length - 2) {
174
+ rendered += COMMA;
175
+ } else if (index === length - 2) {
176
+ rendered += parts.length > 2 ? delimiterLong : delimiterShort;
177
+ }
178
+ }
179
+
180
+ return rendered;
181
+ }
182
+
183
+ function renderTypes(types: ValidatorType[]): string {
184
+ const unique = new Set<string>();
185
+ const parts: string[] = [];
186
+
187
+ for (let index = 0; index < types.length; index += 1) {
188
+ const rendered = getPropertyType(types[index]);
189
+
190
+ if (unique.has(rendered)) {
191
+ continue;
192
+ }
193
+
194
+ unique.add(rendered);
195
+ parts.push(rendered);
196
+ }
197
+
198
+ return renderParts(parts, CONJUNCTION_OR, CONJUNCTION_OR_COMMA);
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
@@ -0,0 +1,92 @@
1
+ import {isConstructor, isPlainObject} from '@oscarpalmer/atoms/is';
2
+ import type {Constructor} from '@oscarpalmer/atoms/models';
3
+ import {
4
+ MESSAGE_CONSTRUCTOR,
5
+ PROPERTY_SCHEMATIC,
6
+ REPORTING_ALL,
7
+ REPORTING_FIRST,
8
+ REPORTING_NONE,
9
+ REPORTING_THROW,
10
+ REPORTING_TYPES,
11
+ } from '../constants';
12
+ import type {
13
+ ReportingInformation,
14
+ ReportingType,
15
+ ValidatorParameters,
16
+ } from '../models/validation.model';
17
+ import type {Schematic} from '../schematic';
18
+
19
+ export function getParameters(input?: unknown): ValidatorParameters {
20
+ if (typeof input === 'boolean') {
21
+ return {
22
+ clone: true,
23
+ output: {},
24
+ reporting: getReporting(),
25
+ strict: input,
26
+ };
27
+ }
28
+
29
+ if (REPORTING_TYPES.has(input as ReportingType)) {
30
+ return {
31
+ clone: true,
32
+ output: {},
33
+ reporting: getReporting(input as ReportingType),
34
+ strict: false,
35
+ };
36
+ }
37
+
38
+ const options = isPlainObject(input) ? input : {};
39
+
40
+ return {
41
+ clone: typeof options.clone === 'boolean' ? options.clone : true,
42
+ output: {},
43
+ reporting: getReporting(options.errors),
44
+ strict: typeof options.strict === 'boolean' ? options.strict : false,
45
+ };
46
+ }
47
+
48
+ export function getReporting(value?: unknown): ReportingInformation {
49
+ const type = REPORTING_TYPES.has(value as ReportingType)
50
+ ? (value as ReportingType)
51
+ : REPORTING_NONE;
52
+
53
+ return {
54
+ type,
55
+ [REPORTING_ALL]: type === REPORTING_ALL,
56
+ [REPORTING_FIRST]: type === REPORTING_FIRST,
57
+ [REPORTING_NONE]: type === REPORTING_NONE,
58
+ [REPORTING_THROW]: type === REPORTING_THROW,
59
+ } as ReportingInformation;
60
+ }
61
+
62
+ /**
63
+ * Creates a validator function for a given constructor
64
+ * @param constructor - Constructor to check against
65
+ * @throws Will throw a `TypeError` if the provided argument is not a valid constructor
66
+ * @returns Validator function that checks if a value is an instance of the constructor
67
+ */
68
+ export function instanceOf<Instance>(
69
+ constructor: Constructor<Instance>,
70
+ ): (value: unknown) => value is Instance {
71
+ if (!isConstructor(constructor)) {
72
+ throw new TypeError(MESSAGE_CONSTRUCTOR);
73
+ }
74
+
75
+ return (value: unknown): value is Instance => {
76
+ return value instanceof constructor;
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Is the value a schematic?
82
+ * @param value Value to check
83
+ * @returns `true` if the value is a schematic, `false` otherwise
84
+ */
85
+ export function isSchematic(value: unknown): value is Schematic<never> {
86
+ return (
87
+ typeof value === 'object' &&
88
+ value !== null &&
89
+ PROPERTY_SCHEMATIC in value &&
90
+ value[PROPERTY_SCHEMATIC] === true
91
+ );
92
+ }
package/src/index.ts CHANGED
@@ -1,10 +1,10 @@
1
- export {instanceOf, isSchematic} from './helpers';
1
+ export {instanceOf, isSchematic} from './helpers/misc.helper';
2
2
  export type {Schema} from './models/schema.plain.model';
3
3
  export type {TypedSchema} from './models/schema.typed.model';
4
4
  export {
5
5
  SchematicError,
6
6
  ValidationError,
7
- type ValidationInformation,
8
- type ValidationOptions,
7
+ type GetOptions,
8
+ type IsOptions,
9
9
  } from './models/validation.model';
10
10
  export {schematic, type Schematic} from './schematic';
@@ -8,6 +8,7 @@ import type {ExtractValueNames, ValueName, Values} from './misc.model';
8
8
  export type PlainSchema = {
9
9
  [key: string]: PlainSchema | SchemaEntry | SchemaEntry[] | undefined;
10
10
  } & {
11
+ $default?: never;
11
12
  $required?: never;
12
13
  $type?: never;
13
14
  $validators?: never;
@@ -56,6 +57,7 @@ export type SchemaEntry =
56
57
  * ```
57
58
  */
58
59
  export type SchemaProperty = {
60
+ $default?: unknown;
59
61
  /**
60
62
  * Whether the property is required _(defaults to `true`)_
61
63
  */
@@ -17,6 +17,7 @@ import type {ToSchemaPropertyType, ToSchemaType} from './transform.model';
17
17
  * ```
18
18
  */
19
19
  export type TypedPropertyOptional<Value> = {
20
+ $default?: never;
20
21
  $required: false;
21
22
  $type: ToSchemaPropertyType<Exclude<Value, undefined>>;
22
23
  $validators?: PropertyValidators<ToSchemaPropertyType<Exclude<Value, undefined>>>;
@@ -35,6 +36,7 @@ export type TypedPropertyOptional<Value> = {
35
36
  * ```
36
37
  */
37
38
  export type TypedPropertyRequired<Value> = {
39
+ $default?: unknown;
38
40
  $required?: true;
39
41
  $type: ToSchemaPropertyType<Value>;
40
42
  $validators?: PropertyValidators<ToSchemaPropertyType<Value>>;
@@ -61,31 +63,11 @@ export type TypedPropertyRequired<Value> = {
61
63
  export type TypedSchema<Model extends PlainObject> = Simplify<
62
64
  {
63
65
  [Key in RequiredKeys<Model>]: Model[Key] extends PlainObject
64
- ? TypedSchemaRequired<Model[Key]> | Schematic<Model[Key]>
66
+ ? Schematic<Model[Key]>
65
67
  : ToSchemaType<Model[Key]> | TypedPropertyRequired<Model[Key]>;
66
68
  } & {
67
69
  [Key in OptionalKeys<Model>]: Exclude<Model[Key], undefined> extends PlainObject
68
- ?
69
- | TypedSchemaOptional<Exclude<Model[Key], undefined>>
70
- | Schematic<Exclude<Model[Key], undefined>>
70
+ ? Schematic<Exclude<Model[Key], undefined>>
71
71
  : TypedPropertyOptional<Model[Key]>;
72
72
  }
73
73
  >;
74
-
75
- /**
76
- * A {@link TypedSchema} variant for optional nested objects, with `$required` fixed to `false`
77
- *
78
- * @template Model Nested object type
79
- */
80
- type TypedSchemaOptional<Model extends PlainObject> = {
81
- $required: false;
82
- } & TypedSchema<Model>;
83
-
84
- /**
85
- * A {@link TypedSchema} variant for required nested objects, with `$required` defaulting to `true`
86
- *
87
- * @template Model Nested object type
88
- */
89
- type TypedSchemaRequired<Model extends PlainObject> = {
90
- $required?: true;
91
- } & TypedSchema<Model>;
@@ -91,20 +91,32 @@ export type ValidationInformationKey = {
91
91
 
92
92
  // #region Options
93
93
 
94
- /**
95
- * Options for validation
96
- */
97
- export type ValidationOptions<Errors extends ReportingType> = {
94
+ type BaseOptions<Errors extends ReportingType> = {
98
95
  /**
99
96
  * How should validation failures be reported; see {@link ReportingType} _(defaults to `'none'`)_
100
97
  */
101
- errors?: Errors;
98
+ errors: Errors;
102
99
  /**
103
100
  * Validate if unknown keys are present in the object? _(defaults to `false`)_
104
101
  */
105
102
  strict?: boolean;
106
103
  };
107
104
 
105
+ /**
106
+ * Options for validating and getting a value from an input
107
+ */
108
+ export type GetOptions<Errors extends ReportingType> = BaseOptions<Errors> & {
109
+ /**
110
+ * Get a deeply cloned version of the input? _(defaults to `true`)_
111
+ */
112
+ clone?: boolean;
113
+ };
114
+
115
+ /**
116
+ * Options for validation an input value
117
+ */
118
+ export type IsOptions<Errors extends ReportingType> = BaseOptions<Errors>;
119
+
108
120
  // #endregion
109
121
 
110
122
  // #region Validator
@@ -113,9 +125,22 @@ export type Validator = (
113
125
  input: unknown,
114
126
  parameters: ValidatorParameters,
115
127
  get: boolean,
116
- ) => boolean | ValidationInformation[];
128
+ ) => true | ValidationInformation[];
129
+
130
+ export type ValidatorDefaults = {
131
+ value: unknown;
132
+ };
133
+
134
+ export type ValidatorItem = {
135
+ defaults: ValidatorDefaults | undefined;
136
+ key: ValidationInformationKey;
137
+ required: boolean;
138
+ types: ValidatorType[];
139
+ validator: Validator;
140
+ };
117
141
 
118
142
  export type ValidatorParameters = {
143
+ clone: boolean;
119
144
  information?: ValidationInformation[];
120
145
  output: PlainObject;
121
146
  reporting: ReportingInformation;
package/src/schematic.ts CHANGED
@@ -3,17 +3,18 @@ import type {PlainObject} from '@oscarpalmer/atoms/models';
3
3
  import {error, ok} from '@oscarpalmer/atoms/result/misc';
4
4
  import type {Result} from '@oscarpalmer/atoms/result/models';
5
5
  import {PROPERTY_SCHEMATIC, SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE} from './constants';
6
- import {getParameters, isSchematic} from './helpers';
6
+ import {getParameters, isSchematic} from './helpers/misc.helper';
7
7
  import type {Infer} from './models/infer.model';
8
8
  import type {Schema} from './models/schema.plain.model';
9
9
  import type {TypedSchema} from './models/schema.typed.model';
10
10
  import {
11
11
  SchematicError,
12
+ type GetOptions,
13
+ type IsOptions,
12
14
  type ValidationInformation,
13
- type ValidationOptions,
14
15
  type Validator,
15
16
  } from './models/validation.model';
16
- import {getObjectValidator} from './validation';
17
+ import {getObjectValidator} from './validator/object.validator';
17
18
 
18
19
  /**
19
20
  * A schematic for validating objects
@@ -41,7 +42,7 @@ export class Schematic<Model> {
41
42
  * @param options Validation options
42
43
  * @returns Deeply cloned version of the value if it matches the schema, otherwise throws an error
43
44
  */
44
- get(value: unknown, options: ValidationOptions<'throw'>): Model;
45
+ get(value: unknown, options: GetOptions<'throw'>): Model;
45
46
 
46
47
  /**
47
48
  * Parse a value according to the schema
@@ -61,7 +62,7 @@ export class Schematic<Model> {
61
62
  * @param options Validation options
62
63
  * @returns Result holding deeply cloned value or all validation information
63
64
  */
64
- get(value: unknown, options: ValidationOptions<'all'>): Result<Model, ValidationInformation[]>;
65
+ get(value: unknown, options: GetOptions<'all'>): Result<Model, ValidationInformation[]>;
65
66
 
66
67
  /**
67
68
  * Parse a value according to the schema
@@ -81,7 +82,7 @@ export class Schematic<Model> {
81
82
  * @param options Validation options
82
83
  * @returns Result holding deeply cloned value or all validation information
83
84
  */
84
- get(value: unknown, options: ValidationOptions<'first'>): Result<Model, ValidationInformation>;
85
+ get(value: unknown, options: GetOptions<'first'>): Result<Model, ValidationInformation>;
85
86
 
86
87
  /**
87
88
  * Parse a value according to the schema
@@ -93,6 +94,16 @@ export class Schematic<Model> {
93
94
  */
94
95
  get(value: unknown, errors: 'first'): Result<Model, ValidationInformation>;
95
96
 
97
+ /**
98
+ * Parse a value according to the schema
99
+ *
100
+ * Returns a deeply cloned version of the value or `undefined` if the value does not match the schema
101
+ * @param value Value to parse
102
+ * @param options Validation options
103
+ * @returns Deeply cloned value, or `undefined` if it's invalid
104
+ */
105
+ get(value: unknown, options: GetOptions<'none'>): Model | undefined;
106
+
96
107
  /**
97
108
  * Parse a value according to the schema
98
109
  *
@@ -108,14 +119,16 @@ export class Schematic<Model> {
108
119
 
109
120
  const result = this.#validator(value, parameters, true);
110
121
 
111
- if (typeof result === 'boolean') {
112
- return parameters.reporting.none
113
- ? result
114
- ? parameters.output
115
- : undefined
122
+ if (result === true) {
123
+ return parameters.reporting.none || parameters.reporting.throw
124
+ ? parameters.output
116
125
  : ok(parameters.output);
117
126
  }
118
127
 
128
+ if (parameters.reporting.none) {
129
+ return;
130
+ }
131
+
119
132
  return error(parameters.reporting.all ? result : result[0]);
120
133
  }
121
134
 
@@ -127,7 +140,7 @@ export class Schematic<Model> {
127
140
  * @param options Validation options
128
141
  * @returns `true` if the value matches the schema, otherwise throws an error
129
142
  */
130
- is(value: unknown, options: ValidationOptions<'throw'>): asserts value is Model;
143
+ is(value: unknown, options: IsOptions<'throw'>): asserts value is Model;
131
144
 
132
145
  /**
133
146
  * Does the value match the schema?
@@ -147,7 +160,7 @@ export class Schematic<Model> {
147
160
  * @param options Validation options
148
161
  * @returns Result holding `true` or all validation information
149
162
  */
150
- is(value: unknown, options: ValidationOptions<'all'>): Result<true, ValidationInformation[]>;
163
+ is(value: unknown, options: IsOptions<'all'>): Result<true, ValidationInformation[]>;
151
164
 
152
165
  /**
153
166
  * Does the value match the schema?
@@ -167,7 +180,7 @@ export class Schematic<Model> {
167
180
  * @param options Validation options
168
181
  * @returns `true` if the value matches the schema, otherwise `false`
169
182
  */
170
- is(value: unknown, options: ValidationOptions<'first'>): Result<true, ValidationInformation>;
183
+ is(value: unknown, options: IsOptions<'first'>): Result<true, ValidationInformation>;
171
184
 
172
185
  /**
173
186
  * Does the value match the schema?
@@ -179,6 +192,16 @@ export class Schematic<Model> {
179
192
  */
180
193
  is(value: unknown, errors: 'first'): Result<true, ValidationInformation>;
181
194
 
195
+ /**
196
+ * Does the value match the schema?
197
+ *
198
+ * Will validate that the value matches the schema and return `true` or `false`, without any validation information for validation failures
199
+ * @param value Value to validate
200
+ * @param options Validation options
201
+ * @returns `true` if the value matches the schema, otherwise `false`
202
+ */
203
+ is(value: unknown, options: IsOptions<'none'>): value is Model;
204
+
182
205
  /**
183
206
  * Does the value match the schema?
184
207
  *
@@ -194,8 +217,12 @@ export class Schematic<Model> {
194
217
 
195
218
  const result = this.#validator(value, parameters, false);
196
219
 
197
- if (typeof result === 'boolean') {
198
- return parameters.reporting.none ? result : ok(result);
220
+ if (result === true) {
221
+ return parameters.reporting.none || parameters.reporting.throw ? result : ok(result);
222
+ }
223
+
224
+ if (parameters.reporting.none) {
225
+ return false;
199
226
  }
200
227
 
201
228
  return error(parameters.reporting.all ? result : result[0]);
@@ -0,0 +1,31 @@
1
+ import type {ValidationInformation, Validator} from '../models/validation.model';
2
+
3
+ export function getBaseValidator(validators: Validator[]): Validator {
4
+ const {length} = validators;
5
+
6
+ return (input, parameters, get) => {
7
+ const allInformation: ValidationInformation[] = [];
8
+
9
+ for (let index = 0; index < length; index += 1) {
10
+ const previousInformation = parameters.information;
11
+
12
+ const nextInformation: ValidationInformation[] = [];
13
+
14
+ parameters.information = nextInformation;
15
+
16
+ const result = validators[index](input, parameters, get);
17
+
18
+ parameters.information = previousInformation;
19
+
20
+ if (result === true) {
21
+ return true;
22
+ }
23
+
24
+ parameters.information?.push(...result);
25
+
26
+ allInformation.push(...result);
27
+ }
28
+
29
+ return allInformation;
30
+ };
31
+ }
@@ -0,0 +1,9 @@
1
+ import {isConstructor} from '@oscarpalmer/atoms/is';
2
+ import {instanceOf} from '../helpers/misc.helper';
3
+ import type {Validator} from '../models/validation.model';
4
+
5
+ export function getFunctionValidator(fn: Function): Validator {
6
+ const validator = isConstructor(fn) ? instanceOf(fn) : fn;
7
+
8
+ return input => (validator(input) ? true : []);
9
+ }
@@ -0,0 +1,65 @@
1
+ import {isPlainObject} from '@oscarpalmer/atoms/is';
2
+ import {
3
+ PROPERTY_VALIDATORS,
4
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED,
5
+ SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY,
6
+ SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE,
7
+ SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE,
8
+ TEMPLATE_PATTERN,
9
+ TYPE_ALL,
10
+ } from '../constants';
11
+ import type {ValueName} from '../models/misc.model';
12
+ import type {NamedValidatorHandlers} from '../models/validation.model';
13
+
14
+ export function getNamedHandlers(
15
+ original: unknown,
16
+ prefix: string,
17
+ allowed: boolean,
18
+ ): NamedValidatorHandlers {
19
+ const handlers: NamedValidatorHandlers = {};
20
+
21
+ if (original == null) {
22
+ return handlers;
23
+ }
24
+
25
+ if (!allowed) {
26
+ throw new TypeError(
27
+ SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace(
28
+ TEMPLATE_PATTERN,
29
+ prefix,
30
+ ).replace(TEMPLATE_PATTERN, PROPERTY_VALIDATORS),
31
+ );
32
+ }
33
+
34
+ if (!isPlainObject(original)) {
35
+ throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
36
+ }
37
+
38
+ const keys = Object.keys(original);
39
+ const {length} = keys;
40
+
41
+ for (let index = 0; index < length; index += 1) {
42
+ const key = keys[index];
43
+
44
+ if (!TYPE_ALL.has(key as never)) {
45
+ throw new TypeError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace(TEMPLATE_PATTERN, key));
46
+ }
47
+
48
+ const value = original[key];
49
+
50
+ handlers[key as ValueName] = (Array.isArray(value) ? value : [value]).map(item => {
51
+ if (typeof item !== 'function') {
52
+ throw new TypeError(
53
+ SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace(TEMPLATE_PATTERN, key).replace(
54
+ TEMPLATE_PATTERN,
55
+ prefix,
56
+ ),
57
+ );
58
+ }
59
+
60
+ return item;
61
+ });
62
+ }
63
+
64
+ return handlers;
65
+ }