@oscarpalmer/jhunal 0.26.0 → 0.27.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/constants.d.mts +15 -7
- package/dist/constants.mjs +15 -6
- package/dist/handler/base.handler.d.mts +6 -0
- package/dist/{validator/base.validator.mjs → handler/base.handler.mjs} +5 -5
- package/dist/handler/function.handler.d.mts +6 -0
- package/dist/handler/function.handler.mjs +9 -0
- package/dist/handler/object.handler.d.mts +7 -0
- package/dist/handler/object.handler.mjs +130 -0
- package/dist/handler/schema.handler.d.mts +7 -0
- package/dist/handler/schema.handler.mjs +16 -0
- package/dist/handler/type.handler.d.mts +9 -0
- package/dist/handler/type.handler.mjs +71 -0
- package/dist/handler/validator.handler.d.mts +10 -0
- package/dist/handler/validator.handler.mjs +34 -0
- package/dist/handler/value.handler.d.mts +14 -0
- package/dist/handler/value.handler.mjs +98 -0
- package/dist/helpers/message.helper.d.mts +9 -7
- package/dist/helpers/message.helper.mjs +34 -16
- package/dist/helpers/misc.helper.d.mts +13 -6
- package/dist/helpers/misc.helper.mjs +12 -4
- package/dist/helpers/report.helper.d.mts +23 -0
- package/dist/helpers/report.helper.mjs +19 -0
- package/dist/helpers/result.helper.d.mts +7 -0
- package/dist/helpers/result.helper.mjs +17 -0
- package/dist/index.d.mts +170 -71
- package/dist/index.mjs +354 -215
- package/dist/models/infer.model.d.mts +11 -8
- package/dist/models/misc.model.d.mts +8 -8
- package/dist/models/schematic.plain.model.d.mts +10 -9
- package/dist/models/schematic.typed.model.d.mts +1 -1
- package/dist/models/transform.model.d.mts +2 -2
- package/dist/models/validation.model.d.mts +56 -25
- package/dist/models/validation.model.mjs +11 -2
- package/dist/schema.d.mts +32 -32
- package/dist/schema.mjs +11 -19
- package/dist/validator.d.mts +83 -0
- package/dist/validator.mjs +25 -0
- package/package.json +2 -2
- package/src/constants.ts +30 -8
- package/src/{validator/base.validator.ts → handler/base.handler.ts} +6 -6
- package/src/handler/function.handler.ts +9 -0
- package/src/handler/object.handler.ts +245 -0
- package/src/handler/schema.handler.ts +25 -0
- package/src/handler/type.handler.ts +160 -0
- package/src/handler/validator.handler.ts +49 -0
- package/src/handler/value.handler.ts +202 -0
- package/src/helpers/message.helper.ts +72 -30
- package/src/helpers/misc.helper.ts +23 -6
- package/src/helpers/report.helper.ts +72 -0
- package/src/helpers/result.helper.ts +33 -0
- package/src/index.ts +1 -0
- package/src/models/infer.model.ts +31 -13
- package/src/models/misc.model.ts +9 -9
- package/src/models/schematic.plain.model.ts +12 -9
- package/src/models/schematic.typed.model.ts +3 -3
- package/src/models/transform.model.ts +2 -2
- package/src/models/validation.model.ts +75 -37
- package/src/schema.ts +42 -70
- package/src/validator.ts +135 -0
- package/dist/validator/base.validator.d.mts +0 -6
- package/dist/validator/function.validator.d.mts +0 -6
- package/dist/validator/function.validator.mjs +0 -9
- package/dist/validator/named.handler.d.mts +0 -6
- package/dist/validator/named.handler.mjs +0 -23
- package/dist/validator/named.validator.d.mts +0 -7
- package/dist/validator/named.validator.mjs +0 -38
- package/dist/validator/object.validator.d.mts +0 -7
- package/dist/validator/object.validator.mjs +0 -207
- package/dist/validator/schema.validator.d.mts +0 -7
- package/dist/validator/schema.validator.mjs +0 -16
- package/src/validator/function.validator.ts +0 -9
- package/src/validator/named.handler.ts +0 -65
- package/src/validator/named.validator.ts +0 -61
- package/src/validator/object.validator.ts +0 -426
- package/src/validator/schema.validator.ts +0 -25
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { PROPERTY_VALIDATOR } from "./constants.mjs";
|
|
2
|
+
import { getValidatorHandler } from "./handler/validator.handler.mjs";
|
|
3
|
+
import { isResult } from "./helpers/result.helper.mjs";
|
|
4
|
+
//#region src/validator.ts
|
|
5
|
+
var Validator = class {
|
|
6
|
+
#handler;
|
|
7
|
+
constructor(handler, types) {
|
|
8
|
+
Object.defineProperty(this, PROPERTY_VALIDATOR, { value: true });
|
|
9
|
+
this.#handler = handler;
|
|
10
|
+
validatorHandlers.set(this, handler);
|
|
11
|
+
validatorTypes.set(this, types);
|
|
12
|
+
}
|
|
13
|
+
is(value, options) {
|
|
14
|
+
return isResult(this.#handler, value, options);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function validator(value, validators) {
|
|
18
|
+
if (value instanceof Validator) return value;
|
|
19
|
+
const { handler, types } = getValidatorHandler(value, validators);
|
|
20
|
+
return new Validator(handler, types);
|
|
21
|
+
}
|
|
22
|
+
const validatorHandlers = /* @__PURE__ */ new WeakMap();
|
|
23
|
+
const validatorTypes = /* @__PURE__ */ new WeakMap();
|
|
24
|
+
//#endregion
|
|
25
|
+
export { Validator, validator, validatorHandlers, validatorTypes };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oscarpalmer/jhunal",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Flies free beneath the glistening moons…",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"schema",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@oscarpalmer/atoms": "^0.170"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@types/node": "^25.
|
|
44
|
+
"@types/node": "^25.6",
|
|
45
45
|
"@vitest/coverage-istanbul": "^4.1",
|
|
46
46
|
"jsdom": "^29.0",
|
|
47
47
|
"tsdown": "^0.21",
|
package/src/constants.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {ValueType} from './models/misc.model';
|
|
2
2
|
import type {ReportingType} from './models/validation.model';
|
|
3
3
|
|
|
4
4
|
// #region Grammar
|
|
@@ -31,6 +31,8 @@ export const NAME_ERROR_SCHEMATIC = 'SchematicError';
|
|
|
31
31
|
|
|
32
32
|
export const NAME_ERROR_VALIDATION = 'ValidationError';
|
|
33
33
|
|
|
34
|
+
export const NAME_ERROR_VALIDATOR = 'ValidatorError';
|
|
35
|
+
|
|
34
36
|
// #endregion
|
|
35
37
|
|
|
36
38
|
// #region Properties
|
|
@@ -43,22 +45,29 @@ export const PROPERTY_SCHEMA = '$schema';
|
|
|
43
45
|
|
|
44
46
|
export const PROPERTY_TYPE = '$type';
|
|
45
47
|
|
|
48
|
+
export const PROPERTY_VALIDATOR = '$validator';
|
|
49
|
+
|
|
46
50
|
export const PROPERTY_VALIDATORS = '$validators';
|
|
47
51
|
|
|
48
52
|
// #endregion
|
|
49
53
|
|
|
50
|
-
// #region
|
|
54
|
+
// #region Value validation
|
|
51
55
|
|
|
52
56
|
export const VALIDATION_MESSAGE_INVALID_INPUT = 'Expected an object as input but received <>';
|
|
53
57
|
|
|
54
58
|
export const VALIDATION_MESSAGE_INVALID_REQUIRED = "Expected <> for required property '<>'";
|
|
55
59
|
|
|
56
|
-
export const
|
|
60
|
+
export const VALIDATION_MESSAGE_INVALID_PROPERTY_TYPE = "Expected <> for '<>' but received <>";
|
|
57
61
|
|
|
58
|
-
export const
|
|
62
|
+
export const VALIDATION_MESSAGE_INVALID_PROPERTY_VALIDATOR =
|
|
59
63
|
"Value does not satisfy validator for '<>' and type '<>'";
|
|
60
64
|
|
|
61
|
-
export const
|
|
65
|
+
export const VALIDATION_MESSAGE_INVALID_VALIDATOR_SUFFIX = ' at index <>';
|
|
66
|
+
|
|
67
|
+
export const VALIDATION_MESSAGE_INVALID_VALUE_TYPE = 'Expected <> but received <>';
|
|
68
|
+
|
|
69
|
+
export const VALIDATION_MESSAGE_INVALID_VALUE_VALIDATOR =
|
|
70
|
+
"Value does not satisfy validator for type '<>'";
|
|
62
71
|
|
|
63
72
|
export const VALIDATION_MESSAGE_UNKNOWN_KEYS = 'Found keys that are not defined in the schema: <>';
|
|
64
73
|
|
|
@@ -72,12 +81,15 @@ export const REPORTING_FIRST: ReportingType = 'first';
|
|
|
72
81
|
|
|
73
82
|
export const REPORTING_NONE: ReportingType = 'none';
|
|
74
83
|
|
|
84
|
+
export const REPORTING_RESULT: ReportingType = 'result';
|
|
85
|
+
|
|
75
86
|
export const REPORTING_THROW: ReportingType = 'throw';
|
|
76
87
|
|
|
77
88
|
export const REPORTING_TYPES = new Set<ReportingType>([
|
|
78
89
|
REPORTING_ALL,
|
|
79
90
|
REPORTING_FIRST,
|
|
80
91
|
REPORTING_NONE,
|
|
92
|
+
REPORTING_RESULT,
|
|
81
93
|
REPORTING_THROW,
|
|
82
94
|
]);
|
|
83
95
|
|
|
@@ -136,7 +148,7 @@ export const TYPE_OBJECT = 'object';
|
|
|
136
148
|
|
|
137
149
|
export const TYPE_UNDEFINED = 'undefined';
|
|
138
150
|
|
|
139
|
-
export const VALIDATABLE_TYPES = new Set<
|
|
151
|
+
export const VALIDATABLE_TYPES = new Set<ValueType>([
|
|
140
152
|
TYPE_ARRAY,
|
|
141
153
|
'bigint',
|
|
142
154
|
'boolean',
|
|
@@ -148,9 +160,9 @@ export const VALIDATABLE_TYPES = new Set<ValueName>([
|
|
|
148
160
|
'symbol',
|
|
149
161
|
]);
|
|
150
162
|
|
|
151
|
-
export const
|
|
163
|
+
export const TYPES_ALL = new Set<ValueType>([...VALIDATABLE_TYPES, TYPE_NULL, TYPE_UNDEFINED]);
|
|
152
164
|
|
|
153
|
-
export const
|
|
165
|
+
export const TYPES_PREFIXED: Record<ValueType, string> = {
|
|
154
166
|
[TYPE_ARRAY]: `an ${TYPE_ARRAY}`,
|
|
155
167
|
bigint: `a bigint`,
|
|
156
168
|
boolean: `a boolean`,
|
|
@@ -165,3 +177,13 @@ export const PREFIXED_TYPES: Record<ValueName, string> = {
|
|
|
165
177
|
};
|
|
166
178
|
|
|
167
179
|
// #endregion
|
|
180
|
+
|
|
181
|
+
// #region Validator validation
|
|
182
|
+
|
|
183
|
+
export const VALIDATOR_MESSAGE_INVALID_PROPERTY_NULLABLE =
|
|
184
|
+
"Validator must not be 'null' or 'undefined'";
|
|
185
|
+
|
|
186
|
+
export const VALIDATOR_MESSAGE_INVALID_PROPERTY_TYPE = 'Validator must be of a valid type';
|
|
187
|
+
|
|
188
|
+
export const VALIDATOR_MESSAGE_INVALID_VALIDATOR =
|
|
189
|
+
'Validator must be a function or an array of functions';
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {ValidationHandler, PropertyValidation} from '../models/validation.model';
|
|
2
2
|
|
|
3
|
-
export function
|
|
4
|
-
const {length} =
|
|
3
|
+
export function getBaseHandler(handlers: ValidationHandler[]): ValidationHandler {
|
|
4
|
+
const {length} = handlers;
|
|
5
5
|
|
|
6
6
|
return (input, parameters, get) => {
|
|
7
|
-
const allInformation:
|
|
7
|
+
const allInformation: PropertyValidation[] = [];
|
|
8
8
|
|
|
9
9
|
for (let index = 0; index < length; index += 1) {
|
|
10
10
|
const previousInformation = parameters.information;
|
|
11
11
|
|
|
12
|
-
const nextInformation:
|
|
12
|
+
const nextInformation: PropertyValidation[] = [];
|
|
13
13
|
|
|
14
14
|
parameters.information = nextInformation;
|
|
15
15
|
|
|
16
|
-
const result =
|
|
16
|
+
const result = handlers[index](input, parameters, get);
|
|
17
17
|
|
|
18
18
|
parameters.information = previousInformation;
|
|
19
19
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import {isConstructor} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import {instanceOf} from '../helpers/misc.helper';
|
|
3
|
+
import type {ValidationHandler} from '../models/validation.model';
|
|
4
|
+
|
|
5
|
+
export function getFunctionHandler(fn: Function): ValidationHandler {
|
|
6
|
+
const handler = isConstructor(fn) ? instanceOf(fn) : fn;
|
|
7
|
+
|
|
8
|
+
return input => (handler(input) ? true : []);
|
|
9
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import {isPlainObject} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import type {PlainObject} from '@oscarpalmer/atoms/models';
|
|
3
|
+
import {clone} from '@oscarpalmer/atoms/value/clone';
|
|
4
|
+
import {
|
|
5
|
+
PROPERTY_DEFAULT,
|
|
6
|
+
PROPERTY_REQUIRED,
|
|
7
|
+
PROPERTY_TYPE,
|
|
8
|
+
PROPERTY_VALIDATORS,
|
|
9
|
+
SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY,
|
|
10
|
+
} from '../constants';
|
|
11
|
+
import {
|
|
12
|
+
getDisallowedMessage,
|
|
13
|
+
getInputPropertyMissingMessage,
|
|
14
|
+
getInputPropertyTypeMessage,
|
|
15
|
+
getInputTypeMessage,
|
|
16
|
+
getUnknownKeysMessage,
|
|
17
|
+
} from '../helpers/message.helper';
|
|
18
|
+
import {report} from '../helpers/report.helper';
|
|
19
|
+
import {
|
|
20
|
+
SchematicError,
|
|
21
|
+
ValidationError,
|
|
22
|
+
type PropertyValidation,
|
|
23
|
+
type PropertyValidationKey,
|
|
24
|
+
type ValidationHandler,
|
|
25
|
+
type ValidationHandlerItem,
|
|
26
|
+
} from '../models/validation.model';
|
|
27
|
+
import {getValueHandler} from './value.handler';
|
|
28
|
+
|
|
29
|
+
function getDisallowedProperty(obj: PlainObject): string | undefined {
|
|
30
|
+
if (PROPERTY_DEFAULT in obj) {
|
|
31
|
+
return PROPERTY_DEFAULT;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (PROPERTY_REQUIRED in obj) {
|
|
35
|
+
return PROPERTY_REQUIRED;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (PROPERTY_TYPE in obj) {
|
|
39
|
+
return PROPERTY_TYPE;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (PROPERTY_VALIDATORS in obj) {
|
|
43
|
+
return PROPERTY_VALIDATORS;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function getObjectHandler(
|
|
48
|
+
original: PlainObject,
|
|
49
|
+
origin?: PropertyValidationKey,
|
|
50
|
+
fromType?: boolean,
|
|
51
|
+
): ValidationHandler {
|
|
52
|
+
const keys = Object.keys(original);
|
|
53
|
+
const keysLength = keys.length;
|
|
54
|
+
|
|
55
|
+
if (keysLength === 0) {
|
|
56
|
+
throw new SchematicError(SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (fromType ?? false) {
|
|
60
|
+
const property = getDisallowedProperty(original);
|
|
61
|
+
|
|
62
|
+
if (property != null) {
|
|
63
|
+
throw new SchematicError(getDisallowedMessage(origin!.full, property));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const set = new Set<string>();
|
|
68
|
+
|
|
69
|
+
const items: ValidationHandlerItem[] = [];
|
|
70
|
+
|
|
71
|
+
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
72
|
+
const key = keys[keyIndex];
|
|
73
|
+
|
|
74
|
+
const {
|
|
75
|
+
defaults,
|
|
76
|
+
handler,
|
|
77
|
+
key: fullKey,
|
|
78
|
+
required,
|
|
79
|
+
types,
|
|
80
|
+
} = getValueHandler(
|
|
81
|
+
{
|
|
82
|
+
value: original[key],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
key,
|
|
86
|
+
origin,
|
|
87
|
+
},
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
items.push({
|
|
91
|
+
defaults,
|
|
92
|
+
handler,
|
|
93
|
+
required,
|
|
94
|
+
types,
|
|
95
|
+
key: fullKey,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
set.add(key);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const validatorsLength = items.length;
|
|
102
|
+
|
|
103
|
+
return (input, parameters, get) => {
|
|
104
|
+
if (!isPlainObject(input)) {
|
|
105
|
+
return origin == null
|
|
106
|
+
? report(
|
|
107
|
+
{
|
|
108
|
+
message: {
|
|
109
|
+
arguments: [input],
|
|
110
|
+
callback: getInputTypeMessage,
|
|
111
|
+
},
|
|
112
|
+
original: parameters,
|
|
113
|
+
value: input,
|
|
114
|
+
},
|
|
115
|
+
true,
|
|
116
|
+
)
|
|
117
|
+
: [];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (parameters.strict) {
|
|
121
|
+
const inputKeys = Object.keys(input);
|
|
122
|
+
const unknownKeys = inputKeys.filter(key => !set.has(key));
|
|
123
|
+
|
|
124
|
+
if (unknownKeys.length > 0) {
|
|
125
|
+
const information: PropertyValidation = {
|
|
126
|
+
key: origin,
|
|
127
|
+
message: getUnknownKeysMessage(unknownKeys),
|
|
128
|
+
value: input,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
if (parameters.reporting.throw) {
|
|
132
|
+
throw new ValidationError([information]);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
parameters.information?.push(information);
|
|
136
|
+
|
|
137
|
+
return [information];
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const getAndClone = get && parameters.clone;
|
|
142
|
+
|
|
143
|
+
const allInformation: PropertyValidation[] = [];
|
|
144
|
+
const output: PlainObject = {};
|
|
145
|
+
|
|
146
|
+
for (let validatorIndex = 0; validatorIndex < validatorsLength; validatorIndex += 1) {
|
|
147
|
+
const {defaults, handler, key, required, types} = items[validatorIndex];
|
|
148
|
+
|
|
149
|
+
const value = (input as PlainObject)[key.short];
|
|
150
|
+
|
|
151
|
+
if (value === undefined) {
|
|
152
|
+
if (required) {
|
|
153
|
+
if (get && defaults != null) {
|
|
154
|
+
const defaultValue = clone(defaults.value);
|
|
155
|
+
|
|
156
|
+
if (parameters.clone) {
|
|
157
|
+
output[key.short] = defaultValue;
|
|
158
|
+
} else {
|
|
159
|
+
input[key.short] = defaultValue;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (parameters.reporting.none) {
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const reported = report({
|
|
170
|
+
key,
|
|
171
|
+
value,
|
|
172
|
+
information: {
|
|
173
|
+
all: allInformation,
|
|
174
|
+
},
|
|
175
|
+
message: {
|
|
176
|
+
arguments: [key.full, types],
|
|
177
|
+
callback: getInputPropertyMissingMessage,
|
|
178
|
+
},
|
|
179
|
+
original: parameters,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
if (reported == null) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return reported;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const previousOutput = parameters.output;
|
|
193
|
+
|
|
194
|
+
parameters.key = key.full;
|
|
195
|
+
parameters.output = output;
|
|
196
|
+
|
|
197
|
+
const result = handler(value, parameters, get);
|
|
198
|
+
|
|
199
|
+
parameters.output = previousOutput;
|
|
200
|
+
|
|
201
|
+
if (result === true) {
|
|
202
|
+
if (getAndClone && !isPlainObject(value)) {
|
|
203
|
+
output[key.short] = clone(value);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (parameters.reporting.none) {
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const reported = report({
|
|
214
|
+
key,
|
|
215
|
+
value,
|
|
216
|
+
extract: false,
|
|
217
|
+
information: {
|
|
218
|
+
all: allInformation,
|
|
219
|
+
existing: typeof result !== 'boolean' && result.length > 0 ? result : undefined,
|
|
220
|
+
},
|
|
221
|
+
message: {
|
|
222
|
+
arguments: [key.full, types, value],
|
|
223
|
+
callback: getInputPropertyTypeMessage,
|
|
224
|
+
},
|
|
225
|
+
original: parameters,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
if (reported == null) {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return reported;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (getAndClone) {
|
|
236
|
+
if (origin == null) {
|
|
237
|
+
parameters.output = output;
|
|
238
|
+
} else {
|
|
239
|
+
parameters.output[origin.short] = output;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return allInformation.length === 0 ? true : allInformation;
|
|
244
|
+
};
|
|
245
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {isPlainObject} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import type {ValidationHandler} from '../models/validation.model';
|
|
3
|
+
import {Schema, schemaHandlers} from '../schema';
|
|
4
|
+
|
|
5
|
+
export function getSchemaHandler(schematic: Schema<unknown>): ValidationHandler {
|
|
6
|
+
const handler = schemaHandlers.get(schematic)!;
|
|
7
|
+
|
|
8
|
+
return (input, parameters, get) => {
|
|
9
|
+
let result: ReturnType<ValidationHandler>;
|
|
10
|
+
|
|
11
|
+
if (isPlainObject(input)) {
|
|
12
|
+
result = handler(input, parameters, get);
|
|
13
|
+
} else {
|
|
14
|
+
result = [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (result === true) {
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
parameters.information?.push(...result);
|
|
22
|
+
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
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
|
+
TYPES_ALL,
|
|
10
|
+
VALIDATOR_MESSAGE_INVALID_VALIDATOR,
|
|
11
|
+
} from '../constants';
|
|
12
|
+
import {
|
|
13
|
+
getInputPropertyValidatorMessage,
|
|
14
|
+
getInputValueValidatorMessage,
|
|
15
|
+
} from '../helpers/message.helper';
|
|
16
|
+
import type {ValueType} from '../models/misc.model';
|
|
17
|
+
import {
|
|
18
|
+
type PropertyValidation,
|
|
19
|
+
type PropertyValidationKey,
|
|
20
|
+
type TypeValidators,
|
|
21
|
+
type ValidationHandler,
|
|
22
|
+
type ValidationHandlerType,
|
|
23
|
+
type Validators,
|
|
24
|
+
SchematicError,
|
|
25
|
+
ValidatorError,
|
|
26
|
+
} from '../models/validation.model';
|
|
27
|
+
|
|
28
|
+
export function getTypeHandler(
|
|
29
|
+
type: ValueType,
|
|
30
|
+
validators: Validators,
|
|
31
|
+
key?: PropertyValidationKey,
|
|
32
|
+
): ValidationHandler {
|
|
33
|
+
const validator = typeValidators[type];
|
|
34
|
+
|
|
35
|
+
const typedValidators = validators[type] ?? [];
|
|
36
|
+
const {length} = typedValidators;
|
|
37
|
+
|
|
38
|
+
return (input, parameters) => {
|
|
39
|
+
if (!validator(input)) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for (let index = 0; index < length; index += 1) {
|
|
44
|
+
const validator = typedValidators[index];
|
|
45
|
+
|
|
46
|
+
if (validator(input) === true) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const information: PropertyValidation = {
|
|
51
|
+
validator,
|
|
52
|
+
message:
|
|
53
|
+
key == null
|
|
54
|
+
? getInputValueValidatorMessage(type, index, length)
|
|
55
|
+
: getInputPropertyValidatorMessage(key.full, type, index, length),
|
|
56
|
+
value: input,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
if (key != null) {
|
|
60
|
+
information.key = key;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
parameters.information?.push(information);
|
|
64
|
+
|
|
65
|
+
return parameters.reporting.none ? [] : [information];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return true;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function getTypeValidators(types: ValidationHandlerType[], original: unknown): Validators {
|
|
73
|
+
const values = types.filter(type => TYPES_ALL.has(type as ValueType)) as ValueType[];
|
|
74
|
+
const {length} = values;
|
|
75
|
+
|
|
76
|
+
const validators: Validators = {};
|
|
77
|
+
|
|
78
|
+
if (original == null || length === 0) {
|
|
79
|
+
return validators;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (typeof original === 'function' || Array.isArray(original)) {
|
|
83
|
+
if (length > 1) {
|
|
84
|
+
throw new ValidatorError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return getValidators({[values[0]]: original}, true);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return getValidators(original, true);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function getValidators(original: unknown, allowed: boolean, prefix?: string): Validators {
|
|
94
|
+
const validators: Validators = {};
|
|
95
|
+
|
|
96
|
+
if (original == null) {
|
|
97
|
+
return validators;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!allowed) {
|
|
101
|
+
throw new SchematicError(
|
|
102
|
+
SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace(
|
|
103
|
+
TEMPLATE_PATTERN,
|
|
104
|
+
prefix!,
|
|
105
|
+
).replace(TEMPLATE_PATTERN, PROPERTY_VALIDATORS),
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!isPlainObject(original)) {
|
|
110
|
+
throw new SchematicError(SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const keys = Object.keys(original);
|
|
114
|
+
const {length} = keys;
|
|
115
|
+
|
|
116
|
+
for (let index = 0; index < length; index += 1) {
|
|
117
|
+
const key = keys[index];
|
|
118
|
+
|
|
119
|
+
if (!TYPES_ALL.has(key as never)) {
|
|
120
|
+
throw new SchematicError(
|
|
121
|
+
SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY.replace(TEMPLATE_PATTERN, key),
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const value = original[key];
|
|
126
|
+
|
|
127
|
+
validators[key as ValueType] = (Array.isArray(value) ? value : [value]).map(item => {
|
|
128
|
+
if (typeof item !== 'function') {
|
|
129
|
+
if (prefix == null) {
|
|
130
|
+
throw new ValidatorError(VALIDATOR_MESSAGE_INVALID_VALIDATOR);
|
|
131
|
+
} else {
|
|
132
|
+
throw new SchematicError(
|
|
133
|
+
SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE.replace(TEMPLATE_PATTERN, key).replace(
|
|
134
|
+
TEMPLATE_PATTERN,
|
|
135
|
+
prefix,
|
|
136
|
+
),
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return item;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return validators;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const typeValidators: TypeValidators = {
|
|
149
|
+
array: Array.isArray,
|
|
150
|
+
bigint: value => typeof value === 'bigint',
|
|
151
|
+
boolean: value => typeof value === 'boolean',
|
|
152
|
+
date: value => value instanceof Date,
|
|
153
|
+
function: value => typeof value === 'function',
|
|
154
|
+
null: value => value === null,
|
|
155
|
+
number: value => typeof value === 'number',
|
|
156
|
+
object: value => typeof value === 'object' && value !== null,
|
|
157
|
+
string: value => typeof value === 'string',
|
|
158
|
+
symbol: value => typeof value === 'symbol',
|
|
159
|
+
undefined: value => value === undefined,
|
|
160
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {getInputValueTypeMessage} from '../helpers/message.helper';
|
|
2
|
+
import {report} from '../helpers/report.helper';
|
|
3
|
+
import type {ValidationHandler, ValidationHandlerType} from '../models/validation.model';
|
|
4
|
+
import {getValueHandler} from './value.handler';
|
|
5
|
+
|
|
6
|
+
type ValidatorHandler = {
|
|
7
|
+
handler: ValidationHandler;
|
|
8
|
+
types: ValidationHandlerType[];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function getValidatorHandler(value: unknown, validators?: unknown): ValidatorHandler {
|
|
12
|
+
const {handler, types} = getValueHandler({
|
|
13
|
+
validators,
|
|
14
|
+
value,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const validator: ValidationHandler = (input, parameters, get) => {
|
|
18
|
+
const result = handler(input, parameters, get);
|
|
19
|
+
|
|
20
|
+
if (result === true) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (parameters.key != null) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const reported = report({
|
|
29
|
+
value: input,
|
|
30
|
+
extract: false,
|
|
31
|
+
information: {
|
|
32
|
+
all: parameters.information ?? [],
|
|
33
|
+
existing: result.length > 0 ? result : undefined,
|
|
34
|
+
},
|
|
35
|
+
message: {
|
|
36
|
+
arguments: [types, input],
|
|
37
|
+
callback: getInputValueTypeMessage,
|
|
38
|
+
},
|
|
39
|
+
original: parameters,
|
|
40
|
+
})!;
|
|
41
|
+
|
|
42
|
+
return reported;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
types,
|
|
47
|
+
handler: validator,
|
|
48
|
+
};
|
|
49
|
+
}
|