@oscarpalmer/jhunal 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -461,7 +461,7 @@ declare class Schema<Model> {
461
461
  * @param options Validation options
462
462
  * @returns Deeply cloned value, or `undefined` if it's invalid
463
463
  */
464
- get(value: unknown, options: GetOptions<'none'>): Model | undefined;
464
+ get(value: unknown, options: Partial<GetOptions<'none'>>): Model | undefined;
465
465
  /**
466
466
  * Parse a value according to the schema
467
467
  *
@@ -533,7 +533,7 @@ declare class Schema<Model> {
533
533
  * @param options Validation options
534
534
  * @returns `true` if the value matches the schema, otherwise `false`
535
535
  */
536
- is(value: unknown, options: IsOptions<'none'>): value is Model;
536
+ is(value: unknown, options: Partial<IsOptions<'none'>>): value is Model;
537
537
  /**
538
538
  * Does the value match the schema?
539
539
  *
package/dist/index.mjs CHANGED
@@ -319,7 +319,7 @@ const namedValidators = {
319
319
  undefined: (value) => value === void 0
320
320
  };
321
321
  //#endregion
322
- //#region src/validator/schematic.validator.ts
322
+ //#region src/validator/schema.validator.ts
323
323
  function getSchemaValidator(schematic) {
324
324
  const validator = schemaValidators.get(schematic);
325
325
  return (input, parameters, get) => {
@@ -357,8 +357,8 @@ function getObjectValidator(original, origin, fromType) {
357
357
  for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
358
358
  const key = keys[keyIndex];
359
359
  const value = original[key];
360
- if (value == null) throw new SchematicError(getSchematicPropertyNullableMessage(join([origin?.full, key], ".")));
361
360
  const prefixedKey = origin == null ? key : join([origin.full, key], ".");
361
+ if (value == null) throw new SchematicError(getSchematicPropertyNullableMessage(prefixedKey));
362
362
  const fullKey = {
363
363
  full: prefixedKey,
364
364
  short: key
@@ -414,20 +414,18 @@ function getObjectValidator(original, origin, fromType) {
414
414
  }
415
415
  const validatorsLength = items.length;
416
416
  return (input, parameters, get) => {
417
- if (!isPlainObject(input)) {
418
- if (origin != null) return [];
419
- const information = {
420
- key: {
421
- full: "",
422
- short: ""
423
- },
424
- value: input,
425
- message: getInputTypeMessage(input)
426
- };
427
- if (parameters.reporting.throw) throw new ValidationError([information]);
428
- parameters.information?.push(information);
429
- return [information];
430
- }
417
+ if (!isPlainObject(input)) return origin == null ? report({
418
+ key: {
419
+ full: "",
420
+ short: ""
421
+ },
422
+ message: {
423
+ arguments: [input],
424
+ callback: getInputTypeMessage
425
+ },
426
+ original: parameters,
427
+ value: input
428
+ }, true) : [];
431
429
  if (parameters.strict) {
432
430
  const unknownKeys = Object.keys(input).filter((key) => !set.has(key));
433
431
  if (unknownKeys.length > 0) {
@@ -444,6 +442,7 @@ function getObjectValidator(original, origin, fromType) {
444
442
  return [information];
445
443
  }
446
444
  }
445
+ const getAndClone = get && parameters.clone;
447
446
  const allInformation = [];
448
447
  const output = {};
449
448
  for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
@@ -452,22 +451,24 @@ function getObjectValidator(original, origin, fromType) {
452
451
  if (value === void 0) {
453
452
  if (required) {
454
453
  if (get && defaults != null) {
455
- output[key.short] = clone(defaults.value);
454
+ const defaultValue = clone(defaults.value);
455
+ if (parameters.clone) output[key.short] = defaultValue;
456
+ else input[key.short] = defaultValue;
456
457
  continue;
457
458
  }
458
459
  if (parameters.reporting.none) return [];
459
- const information = {
460
+ const reported = report({
460
461
  key,
461
462
  value,
462
- message: getInputPropertyMissingMessage(key.full, types)
463
- };
464
- if (parameters.reporting.throw) throw new ValidationError([information]);
465
- parameters.information?.push(information);
466
- if (parameters.reporting.all) {
467
- allInformation.push(information);
468
- continue;
469
- }
470
- return [information];
463
+ information: { all: allInformation },
464
+ message: {
465
+ arguments: [key.full, types],
466
+ callback: getInputPropertyMissingMessage
467
+ },
468
+ original: parameters
469
+ });
470
+ if (reported == null) continue;
471
+ return reported;
471
472
  }
472
473
  continue;
473
474
  }
@@ -476,23 +477,32 @@ function getObjectValidator(original, origin, fromType) {
476
477
  const result = validator(value, parameters, get);
477
478
  parameters.output = previousOutput;
478
479
  if (result === true) {
479
- if (get && !isPlainObject(value)) output[key.short] = parameters.clone ? clone(value) : value;
480
+ if (getAndClone && !isPlainObject(value)) output[key.short] = clone(value);
480
481
  continue;
481
482
  }
482
483
  if (parameters.reporting.none) return [];
483
- const information = typeof result !== "boolean" && result.length > 0 ? result : [{
484
+ const reported = report({
484
485
  key,
485
486
  value,
486
- message: getInputPropertyTypeMessage(key.full, types, value)
487
- }];
488
- if (parameters.reporting.throw) throw new ValidationError(information);
489
- if (parameters.reporting.all) {
490
- allInformation.push(...information);
491
- continue;
492
- }
493
- return information;
487
+ extract: false,
488
+ information: {
489
+ all: allInformation,
490
+ existing: typeof result !== "boolean" && result.length > 0 ? result : void 0
491
+ },
492
+ message: {
493
+ arguments: [
494
+ key.full,
495
+ types,
496
+ value
497
+ ],
498
+ callback: getInputPropertyTypeMessage
499
+ },
500
+ original: parameters
501
+ });
502
+ if (reported == null) continue;
503
+ return reported;
494
504
  }
495
- if (get) if (origin == null) parameters.output = output;
505
+ if (getAndClone) if (origin == null) parameters.output = output;
496
506
  else parameters.output[origin.short] = output;
497
507
  return allInformation.length === 0 ? true : allInformation;
498
508
  };
@@ -503,6 +513,18 @@ function getRequired(obj, key, allowed) {
503
513
  if (typeof obj["$required"] !== "boolean") throw new SchematicError(getRequiredMessage(key));
504
514
  return obj[PROPERTY_REQUIRED];
505
515
  }
516
+ function report(parameters, getReports) {
517
+ const { information, message, original } = parameters;
518
+ const reported = information?.existing ?? [{
519
+ key: parameters.key,
520
+ value: parameters.value,
521
+ message: message.callback(...message.arguments)
522
+ }];
523
+ if (original.reporting.throw) throw new ValidationError(reported);
524
+ information?.all.push(...reported);
525
+ if (parameters.extract ?? true) original.information?.push(...reported);
526
+ if ((getReports ?? false) || !original.reporting.all) return reported;
527
+ }
506
528
  //#endregion
507
529
  //#region src/schema.ts
508
530
  /**
@@ -518,7 +540,7 @@ var Schema = class {
518
540
  get(value, options) {
519
541
  const parameters = getParameters(options);
520
542
  const result = this.#validator(value, parameters, true);
521
- if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.output : ok(parameters.output);
543
+ if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.clone ? parameters.output : value : ok(parameters.clone ? parameters.output : value);
522
544
  if (parameters.reporting.none) return;
523
545
  return error(parameters.reporting.all ? result : result[0]);
524
546
  }
package/dist/schema.d.mts CHANGED
@@ -75,7 +75,7 @@ declare class Schema<Model> {
75
75
  * @param options Validation options
76
76
  * @returns Deeply cloned value, or `undefined` if it's invalid
77
77
  */
78
- get(value: unknown, options: GetOptions<'none'>): Model | undefined;
78
+ get(value: unknown, options: Partial<GetOptions<'none'>>): Model | undefined;
79
79
  /**
80
80
  * Parse a value according to the schema
81
81
  *
@@ -147,7 +147,7 @@ declare class Schema<Model> {
147
147
  * @param options Validation options
148
148
  * @returns `true` if the value matches the schema, otherwise `false`
149
149
  */
150
- is(value: unknown, options: IsOptions<'none'>): value is Model;
150
+ is(value: unknown, options: Partial<IsOptions<'none'>>): value is Model;
151
151
  /**
152
152
  * Does the value match the schema?
153
153
  *
package/dist/schema.mjs CHANGED
@@ -18,7 +18,7 @@ var Schema = class {
18
18
  get(value, options) {
19
19
  const parameters = getParameters(options);
20
20
  const result = this.#validator(value, parameters, true);
21
- if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.output : ok(parameters.output);
21
+ if (result === true) return parameters.reporting.none || parameters.reporting.throw ? parameters.clone ? parameters.output : value : ok(parameters.clone ? parameters.output : value);
22
22
  if (parameters.reporting.none) return;
23
23
  return error(parameters.reporting.all ? result : result[0]);
24
24
  }
@@ -6,7 +6,7 @@ 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 { getSchemaValidator } from "./schematic.validator.mjs";
9
+ import { getSchemaValidator } from "./schema.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";
@@ -35,8 +35,8 @@ function getObjectValidator(original, origin, fromType) {
35
35
  for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
36
36
  const key = keys[keyIndex];
37
37
  const value = original[key];
38
- if (value == null) throw new SchematicError(getSchematicPropertyNullableMessage(join([origin?.full, key], ".")));
39
38
  const prefixedKey = origin == null ? key : join([origin.full, key], ".");
39
+ if (value == null) throw new SchematicError(getSchematicPropertyNullableMessage(prefixedKey));
40
40
  const fullKey = {
41
41
  full: prefixedKey,
42
42
  short: key
@@ -92,20 +92,18 @@ function getObjectValidator(original, origin, fromType) {
92
92
  }
93
93
  const validatorsLength = items.length;
94
94
  return (input, parameters, get) => {
95
- if (!isPlainObject(input)) {
96
- if (origin != null) return [];
97
- const information = {
98
- key: {
99
- full: "",
100
- short: ""
101
- },
102
- value: input,
103
- message: getInputTypeMessage(input)
104
- };
105
- if (parameters.reporting.throw) throw new ValidationError([information]);
106
- parameters.information?.push(information);
107
- return [information];
108
- }
95
+ if (!isPlainObject(input)) return origin == null ? report({
96
+ key: {
97
+ full: "",
98
+ short: ""
99
+ },
100
+ message: {
101
+ arguments: [input],
102
+ callback: getInputTypeMessage
103
+ },
104
+ original: parameters,
105
+ value: input
106
+ }, true) : [];
109
107
  if (parameters.strict) {
110
108
  const unknownKeys = Object.keys(input).filter((key) => !set.has(key));
111
109
  if (unknownKeys.length > 0) {
@@ -122,6 +120,7 @@ function getObjectValidator(original, origin, fromType) {
122
120
  return [information];
123
121
  }
124
122
  }
123
+ const getAndClone = get && parameters.clone;
125
124
  const allInformation = [];
126
125
  const output = {};
127
126
  for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
@@ -130,22 +129,24 @@ function getObjectValidator(original, origin, fromType) {
130
129
  if (value === void 0) {
131
130
  if (required) {
132
131
  if (get && defaults != null) {
133
- output[key.short] = clone(defaults.value);
132
+ const defaultValue = clone(defaults.value);
133
+ if (parameters.clone) output[key.short] = defaultValue;
134
+ else input[key.short] = defaultValue;
134
135
  continue;
135
136
  }
136
137
  if (parameters.reporting.none) return [];
137
- const information = {
138
+ const reported = report({
138
139
  key,
139
140
  value,
140
- message: getInputPropertyMissingMessage(key.full, types)
141
- };
142
- if (parameters.reporting.throw) throw new ValidationError([information]);
143
- parameters.information?.push(information);
144
- if (parameters.reporting.all) {
145
- allInformation.push(information);
146
- continue;
147
- }
148
- return [information];
141
+ information: { all: allInformation },
142
+ message: {
143
+ arguments: [key.full, types],
144
+ callback: getInputPropertyMissingMessage
145
+ },
146
+ original: parameters
147
+ });
148
+ if (reported == null) continue;
149
+ return reported;
149
150
  }
150
151
  continue;
151
152
  }
@@ -154,23 +155,32 @@ function getObjectValidator(original, origin, fromType) {
154
155
  const result = validator(value, parameters, get);
155
156
  parameters.output = previousOutput;
156
157
  if (result === true) {
157
- if (get && !isPlainObject(value)) output[key.short] = parameters.clone ? clone(value) : value;
158
+ if (getAndClone && !isPlainObject(value)) output[key.short] = clone(value);
158
159
  continue;
159
160
  }
160
161
  if (parameters.reporting.none) return [];
161
- const information = typeof result !== "boolean" && result.length > 0 ? result : [{
162
+ const reported = report({
162
163
  key,
163
164
  value,
164
- message: getInputPropertyTypeMessage(key.full, types, value)
165
- }];
166
- if (parameters.reporting.throw) throw new ValidationError(information);
167
- if (parameters.reporting.all) {
168
- allInformation.push(...information);
169
- continue;
170
- }
171
- return information;
165
+ extract: false,
166
+ information: {
167
+ all: allInformation,
168
+ existing: typeof result !== "boolean" && result.length > 0 ? result : void 0
169
+ },
170
+ message: {
171
+ arguments: [
172
+ key.full,
173
+ types,
174
+ value
175
+ ],
176
+ callback: getInputPropertyTypeMessage
177
+ },
178
+ original: parameters
179
+ });
180
+ if (reported == null) continue;
181
+ return reported;
172
182
  }
173
- if (get) if (origin == null) parameters.output = output;
183
+ if (getAndClone) if (origin == null) parameters.output = output;
174
184
  else parameters.output[origin.short] = output;
175
185
  return allInformation.length === 0 ? true : allInformation;
176
186
  };
@@ -181,5 +191,17 @@ function getRequired(obj, key, allowed) {
181
191
  if (typeof obj["$required"] !== "boolean") throw new SchematicError(getRequiredMessage(key));
182
192
  return obj[PROPERTY_REQUIRED];
183
193
  }
194
+ function report(parameters, getReports) {
195
+ const { information, message, original } = parameters;
196
+ const reported = information?.existing ?? [{
197
+ key: parameters.key,
198
+ value: parameters.value,
199
+ message: message.callback(...message.arguments)
200
+ }];
201
+ if (original.reporting.throw) throw new ValidationError(reported);
202
+ information?.all.push(...reported);
203
+ if (parameters.extract ?? true) original.information?.push(...reported);
204
+ if ((getReports ?? false) || !original.reporting.all) return reported;
205
+ }
184
206
  //#endregion
185
207
  export { getObjectValidator };
@@ -1,7 +1,7 @@
1
1
  import { Validator } from "../models/validation.model.mjs";
2
2
  import { Schema } from "../schema.mjs";
3
3
 
4
- //#region src/validator/schematic.validator.d.ts
4
+ //#region src/validator/schema.validator.d.ts
5
5
  declare function getSchemaValidator(schematic: Schema<unknown>): Validator;
6
6
  //#endregion
7
7
  export { getSchemaValidator };
@@ -1,6 +1,6 @@
1
1
  import { schemaValidators } from "../schema.mjs";
2
2
  import { isPlainObject } from "@oscarpalmer/atoms/is";
3
- //#region src/validator/schematic.validator.ts
3
+ //#region src/validator/schema.validator.ts
4
4
  function getSchemaValidator(schematic) {
5
5
  const validator = schemaValidators.get(schematic);
6
6
  return (input, parameters, get) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oscarpalmer/jhunal",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "Flies free beneath the glistening moons…",
5
5
  "keywords": [
6
6
  "schema",
package/src/schema.ts CHANGED
@@ -102,7 +102,7 @@ export class Schema<Model> {
102
102
  * @param options Validation options
103
103
  * @returns Deeply cloned value, or `undefined` if it's invalid
104
104
  */
105
- get(value: unknown, options: GetOptions<'none'>): Model | undefined;
105
+ get(value: unknown, options: Partial<GetOptions<'none'>>): Model | undefined;
106
106
 
107
107
  /**
108
108
  * Parse a value according to the schema
@@ -121,8 +121,10 @@ export class Schema<Model> {
121
121
 
122
122
  if (result === true) {
123
123
  return parameters.reporting.none || parameters.reporting.throw
124
- ? parameters.output
125
- : ok(parameters.output);
124
+ ? parameters.clone
125
+ ? parameters.output
126
+ : value
127
+ : ok(parameters.clone ? parameters.output : value);
126
128
  }
127
129
 
128
130
  if (parameters.reporting.none) {
@@ -200,7 +202,7 @@ export class Schema<Model> {
200
202
  * @param options Validation options
201
203
  * @returns `true` if the value matches the schema, otherwise `false`
202
204
  */
203
- is(value: unknown, options: IsOptions<'none'>): value is Model;
205
+ is(value: unknown, options: Partial<IsOptions<'none'>>): value is Model;
204
206
 
205
207
  /**
206
208
  * Does the value match the schema?
@@ -34,13 +34,33 @@ import {
34
34
  type Validator,
35
35
  type ValidatorDefaults,
36
36
  type ValidatorItem,
37
+ type ValidatorParameters,
37
38
  type ValidatorType,
38
39
  } from '../models/validation.model';
39
40
  import {getBaseValidator} from './base.validator';
40
41
  import {getFunctionValidator} from './function.validator';
41
42
  import {getNamedHandlers} from './named.handler';
42
43
  import {getNamedValidator} from './named.validator';
43
- import {getSchemaValidator} from './schematic.validator';
44
+ import {getSchemaValidator} from './schema.validator';
45
+
46
+ type ReportParameters<Callback extends (...args: any[]) => string> = {
47
+ extract?: boolean;
48
+ information?: ReportParametersInformation;
49
+ key: ValidationInformationKey;
50
+ message: ReportParametersMessage<Callback>;
51
+ original: ValidatorParameters;
52
+ value: unknown;
53
+ };
54
+
55
+ type ReportParametersMessage<Callback extends (...args: any[]) => string> = {
56
+ arguments: Parameters<Callback>;
57
+ callback: Callback;
58
+ };
59
+
60
+ type ReportParametersInformation = {
61
+ all: ValidationInformation[];
62
+ existing?: ValidationInformation[];
63
+ };
44
64
 
45
65
  function getDefaults(
46
66
  obj: PlainObject,
@@ -106,12 +126,12 @@ export function getObjectValidator(
106
126
  const key = keys[keyIndex];
107
127
  const value = original[key];
108
128
 
129
+ const prefixedKey = origin == null ? key : join([origin.full, key], '.');
130
+
109
131
  if (value == null) {
110
- throw new SchematicError(getSchematicPropertyNullableMessage(join([origin?.full, key], '.')));
132
+ throw new SchematicError(getSchematicPropertyNullableMessage(prefixedKey));
111
133
  }
112
134
 
113
- const prefixedKey = origin == null ? key : join([origin.full, key], '.');
114
-
115
135
  const fullKey: ValidationInformationKey = {
116
136
  full: prefixedKey,
117
137
  short: key,
@@ -203,26 +223,23 @@ export function getObjectValidator(
203
223
 
204
224
  return (input, parameters, get) => {
205
225
  if (!isPlainObject(input)) {
206
- if (origin != null) {
207
- return [];
208
- }
209
-
210
- const information: ValidationInformation = {
211
- key: {
212
- full: '',
213
- short: '',
214
- },
215
- value: input,
216
- message: getInputTypeMessage(input),
217
- };
218
-
219
- if (parameters.reporting.throw) {
220
- throw new ValidationError([information]);
221
- }
222
-
223
- parameters.information?.push(information);
224
-
225
- return [information];
226
+ return origin == null
227
+ ? report(
228
+ {
229
+ key: {
230
+ full: '',
231
+ short: '',
232
+ },
233
+ message: {
234
+ arguments: [input],
235
+ callback: getInputTypeMessage,
236
+ },
237
+ original: parameters,
238
+ value: input,
239
+ },
240
+ true,
241
+ )
242
+ : [];
226
243
  }
227
244
 
228
245
  if (parameters.strict) {
@@ -249,6 +266,8 @@ export function getObjectValidator(
249
266
  }
250
267
  }
251
268
 
269
+ const getAndClone = get && parameters.clone;
270
+
252
271
  const allInformation: ValidationInformation[] = [];
253
272
  const output: PlainObject = {};
254
273
 
@@ -260,7 +279,13 @@ export function getObjectValidator(
260
279
  if (value === undefined) {
261
280
  if (required) {
262
281
  if (get && defaults != null) {
263
- output[key.short] = clone(defaults.value);
282
+ const defaultValue = clone(defaults.value);
283
+
284
+ if (parameters.clone) {
285
+ output[key.short] = defaultValue;
286
+ } else {
287
+ input[key.short] = defaultValue;
288
+ }
264
289
 
265
290
  continue;
266
291
  }
@@ -269,25 +294,24 @@ export function getObjectValidator(
269
294
  return [];
270
295
  }
271
296
 
272
- const information: ValidationInformation = {
297
+ const reported = report({
273
298
  key,
274
299
  value,
275
- message: getInputPropertyMissingMessage(key.full, types),
276
- };
277
-
278
- if (parameters.reporting.throw) {
279
- throw new ValidationError([information]);
280
- }
281
-
282
- parameters.information?.push(information);
283
-
284
- if (parameters.reporting.all) {
285
- allInformation.push(information);
286
-
300
+ information: {
301
+ all: allInformation,
302
+ },
303
+ message: {
304
+ arguments: [key.full, types],
305
+ callback: getInputPropertyMissingMessage,
306
+ },
307
+ original: parameters,
308
+ });
309
+
310
+ if (reported == null) {
287
311
  continue;
288
312
  }
289
313
 
290
- return [information];
314
+ return reported;
291
315
  }
292
316
 
293
317
  continue;
@@ -302,8 +326,8 @@ export function getObjectValidator(
302
326
  parameters.output = previousOutput;
303
327
 
304
328
  if (result === true) {
305
- if (get && !isPlainObject(value)) {
306
- output[key.short] = parameters.clone ? clone(value) : value;
329
+ if (getAndClone && !isPlainObject(value)) {
330
+ output[key.short] = clone(value);
307
331
  }
308
332
 
309
333
  continue;
@@ -313,31 +337,29 @@ export function getObjectValidator(
313
337
  return [];
314
338
  }
315
339
 
316
- const information: ValidationInformation[] =
317
- typeof result !== 'boolean' && result.length > 0
318
- ? result
319
- : [
320
- {
321
- key,
322
- value,
323
- message: getInputPropertyTypeMessage(key.full, types, value),
324
- },
325
- ];
326
-
327
- if (parameters.reporting.throw) {
328
- throw new ValidationError(information);
329
- }
330
-
331
- if (parameters.reporting.all) {
332
- allInformation.push(...information);
340
+ const reported = report({
341
+ key,
342
+ value,
343
+ extract: false,
344
+ information: {
345
+ all: allInformation,
346
+ existing: typeof result !== 'boolean' && result.length > 0 ? result : undefined,
347
+ },
348
+ message: {
349
+ arguments: [key.full, types, value],
350
+ callback: getInputPropertyTypeMessage,
351
+ },
352
+ original: parameters,
353
+ });
333
354
 
355
+ if (reported == null) {
334
356
  continue;
335
357
  }
336
358
 
337
- return information;
359
+ return reported;
338
360
  }
339
361
 
340
- if (get) {
362
+ if (getAndClone) {
341
363
  if (origin == null) {
342
364
  parameters.output = output;
343
365
  } else {
@@ -364,3 +386,41 @@ function getRequired(obj: PlainObject, key: string, allowed: boolean): boolean |
364
386
 
365
387
  return obj[PROPERTY_REQUIRED];
366
388
  }
389
+
390
+ function report<Callback extends (...args: any[]) => string>(
391
+ parameters: ReportParameters<Callback>,
392
+ getReports: true,
393
+ ): ValidationInformation[];
394
+
395
+ function report<Callback extends (...args: any[]) => string>(
396
+ parameters: ReportParameters<Callback>,
397
+ ): ValidationInformation[] | undefined;
398
+
399
+ function report<Callback extends (...args: any[]) => string>(
400
+ parameters: ReportParameters<Callback>,
401
+ getReports?: boolean,
402
+ ): ValidationInformation[] | undefined {
403
+ const {information, message, original} = parameters;
404
+
405
+ const reported: ValidationInformation[] = information?.existing ?? [
406
+ {
407
+ key: parameters.key,
408
+ value: parameters.value,
409
+ message: message.callback(...message.arguments),
410
+ },
411
+ ];
412
+
413
+ if (original.reporting.throw) {
414
+ throw new ValidationError(reported);
415
+ }
416
+
417
+ information?.all.push(...reported);
418
+
419
+ if (parameters.extract ?? true) {
420
+ original.information?.push(...reported);
421
+ }
422
+
423
+ if ((getReports ?? false) || !original.reporting.all) {
424
+ return reported;
425
+ }
426
+ }