@oscarpalmer/jhunal 0.13.0 → 0.14.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.js +5 -6
- package/dist/jhunal.full.js +20 -11
- package/dist/validation/property.validation.js +17 -9
- package/package.json +1 -1
- package/src/constants.ts +7 -9
- package/src/models.ts +6 -2
- package/src/validation/property.validation.ts +37 -14
- package/types/constants.d.ts +4 -5
- package/types/models.d.ts +5 -2
- package/types/validation/property.validation.d.ts +1 -1
package/dist/constants.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
const ERROR_NAME = "SchematicError";
|
|
2
|
-
const EXPRESSION_INDEX = /\.\d+$/;
|
|
3
|
-
const EXPRESSION_KEY_PREFIX = /\.\w+$/;
|
|
4
|
-
const EXPRESSION_KEY_VALUE = /^.*\.(\w+)$/;
|
|
5
2
|
const EXPRESSION_PROPERTY = /(^|\.)\$(required|type|validators)(\.|$)/;
|
|
6
3
|
const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
|
|
7
4
|
const MESSAGE_SCHEMA_INVALID_EMPTY = "Schema must have at least one property";
|
|
8
|
-
const
|
|
9
|
-
const
|
|
5
|
+
const MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED = "'<key>.<property>' property is not allowed for schemas in $type";
|
|
6
|
+
const MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED = "'<>.$required' property must be a boolean";
|
|
10
7
|
const MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE = "'<>' property must be of a valid type";
|
|
11
8
|
const MESSAGE_SCHEMA_INVALID_TYPE = "Schema must be an object";
|
|
12
9
|
const MESSAGE_VALIDATOR_INVALID_KEY = "Validator '<>' does not exist";
|
|
@@ -17,6 +14,8 @@ const PROPERTY_TYPE = "$type";
|
|
|
17
14
|
const PROPERTY_VALIDATORS = "$validators";
|
|
18
15
|
const SCHEMATIC_NAME = "$schematic";
|
|
19
16
|
const TEMPLATE_PATTERN = "<>";
|
|
17
|
+
const TEMPLATE_PATTERN_KEY = "<key>";
|
|
18
|
+
const TEMPLATE_PATTERN_PROPERTY = "<property>";
|
|
20
19
|
const TYPE_OBJECT = "object";
|
|
21
20
|
const TYPE_UNDEFINED = "undefined";
|
|
22
21
|
const VALIDATABLE_TYPES = new Set([
|
|
@@ -35,4 +34,4 @@ const TYPE_ALL = new Set([
|
|
|
35
34
|
"null",
|
|
36
35
|
TYPE_UNDEFINED
|
|
37
36
|
]);
|
|
38
|
-
export { ERROR_NAME,
|
|
37
|
+
export { ERROR_NAME, EXPRESSION_PROPERTY, MESSAGE_CONSTRUCTOR, MESSAGE_SCHEMA_INVALID_EMPTY, MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED, MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED, MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE, MESSAGE_SCHEMA_INVALID_TYPE, MESSAGE_VALIDATOR_INVALID_KEY, MESSAGE_VALIDATOR_INVALID_TYPE, MESSAGE_VALIDATOR_INVALID_VALUE, PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, SCHEMATIC_NAME, TEMPLATE_PATTERN, TEMPLATE_PATTERN_KEY, TEMPLATE_PATTERN_PROPERTY, TYPE_ALL, TYPE_OBJECT, TYPE_UNDEFINED, VALIDATABLE_TYPES };
|
package/dist/jhunal.full.js
CHANGED
|
@@ -51,12 +51,11 @@ function join(value, delimiter) {
|
|
|
51
51
|
return compact(value).map(getString).join(typeof delimiter === "string" ? delimiter : "");
|
|
52
52
|
}
|
|
53
53
|
const ERROR_NAME = "SchematicError";
|
|
54
|
-
const EXPRESSION_INDEX = /\.\d+$/;
|
|
55
54
|
const EXPRESSION_PROPERTY = /(^|\.)\$(required|type|validators)(\.|$)/;
|
|
56
55
|
const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
|
|
57
56
|
const MESSAGE_SCHEMA_INVALID_EMPTY = "Schema must have at least one property";
|
|
58
|
-
const
|
|
59
|
-
const
|
|
57
|
+
const MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED = "'<key>.<property>' property is not allowed for schemas in $type";
|
|
58
|
+
const MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED = "'<>.$required' property must be a boolean";
|
|
60
59
|
const MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE = "'<>' property must be of a valid type";
|
|
61
60
|
const MESSAGE_SCHEMA_INVALID_TYPE = "Schema must be an object";
|
|
62
61
|
const MESSAGE_VALIDATOR_INVALID_KEY = "Validator '<>' does not exist";
|
|
@@ -67,6 +66,8 @@ const PROPERTY_TYPE = "$type";
|
|
|
67
66
|
const PROPERTY_VALIDATORS = "$validators";
|
|
68
67
|
const SCHEMATIC_NAME = "$schematic";
|
|
69
68
|
const TEMPLATE_PATTERN = "<>";
|
|
69
|
+
const TEMPLATE_PATTERN_KEY = "<key>";
|
|
70
|
+
const TEMPLATE_PATTERN_PROPERTY = "<property>";
|
|
70
71
|
const TYPE_OBJECT = "object";
|
|
71
72
|
const TYPE_UNDEFINED = "undefined";
|
|
72
73
|
const VALIDATABLE_TYPES = new Set([
|
|
@@ -100,15 +101,23 @@ var SchematicError = class extends Error {
|
|
|
100
101
|
this.name = ERROR_NAME;
|
|
101
102
|
}
|
|
102
103
|
};
|
|
103
|
-
function
|
|
104
|
+
function getDisallowedProperty(obj) {
|
|
105
|
+
if (PROPERTY_REQUIRED in obj) return PROPERTY_REQUIRED;
|
|
106
|
+
if (PROPERTY_TYPE in obj) return PROPERTY_TYPE;
|
|
107
|
+
if (PROPERTY_VALIDATORS in obj) return PROPERTY_VALIDATORS;
|
|
108
|
+
}
|
|
109
|
+
function getProperties(original, prefix, fromType) {
|
|
104
110
|
if (Object.keys(original).length === 0) throw new SchematicError(MESSAGE_SCHEMA_INVALID_EMPTY);
|
|
105
|
-
if (
|
|
111
|
+
if (fromType ?? false) {
|
|
112
|
+
const property = getDisallowedProperty(original);
|
|
113
|
+
if (property != null) throw new SchematicError(MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace(TEMPLATE_PATTERN_KEY, prefix).replace(TEMPLATE_PATTERN_PROPERTY, property));
|
|
114
|
+
}
|
|
106
115
|
const keys = Object.keys(original);
|
|
107
116
|
const keysLength = keys.length;
|
|
108
117
|
const properties = [];
|
|
109
118
|
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
110
119
|
const key = keys[keyIndex];
|
|
111
|
-
if (
|
|
120
|
+
if (EXPRESSION_PROPERTY.test(key)) continue;
|
|
112
121
|
const value = original[key];
|
|
113
122
|
const types = [];
|
|
114
123
|
let required = true;
|
|
@@ -116,8 +125,8 @@ function getProperties(original, prefix, fromTypes) {
|
|
|
116
125
|
if (isPlainObject(value)) {
|
|
117
126
|
required = getRequired(key, value) ?? required;
|
|
118
127
|
validators = getValidators(value[PROPERTY_VALIDATORS]);
|
|
119
|
-
if (PROPERTY_TYPE in value) types.push(
|
|
120
|
-
else types.push(
|
|
128
|
+
if (PROPERTY_TYPE in value) types.push(TYPE_OBJECT, ...getTypes(key, value[PROPERTY_TYPE], prefix, true));
|
|
129
|
+
else types.push(TYPE_OBJECT, ...getTypes(key, value, prefix));
|
|
121
130
|
} else types.push(...getTypes(key, value, prefix));
|
|
122
131
|
if (!required && !types.includes(TYPE_UNDEFINED)) types.push(TYPE_UNDEFINED);
|
|
123
132
|
properties.push({
|
|
@@ -131,10 +140,10 @@ function getProperties(original, prefix, fromTypes) {
|
|
|
131
140
|
}
|
|
132
141
|
function getRequired(key, obj) {
|
|
133
142
|
if (!(PROPERTY_REQUIRED in obj)) return;
|
|
134
|
-
if (typeof obj[PROPERTY_REQUIRED] !== "boolean") throw new SchematicError(
|
|
143
|
+
if (typeof obj[PROPERTY_REQUIRED] !== "boolean") throw new SchematicError(MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace(TEMPLATE_PATTERN, key));
|
|
135
144
|
return obj[PROPERTY_REQUIRED];
|
|
136
145
|
}
|
|
137
|
-
function getTypes(key, original, prefix,
|
|
146
|
+
function getTypes(key, original, prefix, fromType) {
|
|
138
147
|
const array = Array.isArray(original) ? original : [original];
|
|
139
148
|
const { length } = array;
|
|
140
149
|
const types = [];
|
|
@@ -145,7 +154,7 @@ function getTypes(key, original, prefix, fromTypes) {
|
|
|
145
154
|
types.push(isConstructor(value) ? instanceOf(value) : value);
|
|
146
155
|
break;
|
|
147
156
|
case isPlainObject(value):
|
|
148
|
-
types.push(...getProperties(value, join([prefix, key], "."),
|
|
157
|
+
types.push(...getProperties(value, join([prefix, key], "."), fromType));
|
|
149
158
|
break;
|
|
150
159
|
case isSchematic(value):
|
|
151
160
|
types.push(value);
|
|
@@ -1,17 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EXPRESSION_PROPERTY, MESSAGE_SCHEMA_INVALID_EMPTY, MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED, MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED, MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE, MESSAGE_VALIDATOR_INVALID_KEY, MESSAGE_VALIDATOR_INVALID_TYPE, MESSAGE_VALIDATOR_INVALID_VALUE, PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, TEMPLATE_PATTERN_KEY, TEMPLATE_PATTERN_PROPERTY, TYPE_ALL, TYPE_OBJECT, TYPE_UNDEFINED, VALIDATABLE_TYPES } from "../constants.js";
|
|
2
2
|
import { instanceOf, isSchematic } from "../helpers.js";
|
|
3
3
|
import { SchematicError } from "../models.js";
|
|
4
4
|
import { join } from "../node_modules/@oscarpalmer/atoms/dist/internal/string.js";
|
|
5
5
|
import { isConstructor, isPlainObject } from "@oscarpalmer/atoms/is";
|
|
6
|
-
function
|
|
6
|
+
function getDisallowedProperty(obj) {
|
|
7
|
+
if ("$required" in obj) return PROPERTY_REQUIRED;
|
|
8
|
+
if ("$type" in obj) return PROPERTY_TYPE;
|
|
9
|
+
if ("$validators" in obj) return PROPERTY_VALIDATORS;
|
|
10
|
+
}
|
|
11
|
+
function getProperties(original, prefix, fromType) {
|
|
7
12
|
if (Object.keys(original).length === 0) throw new SchematicError(MESSAGE_SCHEMA_INVALID_EMPTY);
|
|
8
|
-
if (
|
|
13
|
+
if (fromType ?? false) {
|
|
14
|
+
const property = getDisallowedProperty(original);
|
|
15
|
+
if (property != null) throw new SchematicError(MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace(TEMPLATE_PATTERN_KEY, prefix).replace(TEMPLATE_PATTERN_PROPERTY, property));
|
|
16
|
+
}
|
|
9
17
|
const keys = Object.keys(original);
|
|
10
18
|
const keysLength = keys.length;
|
|
11
19
|
const properties = [];
|
|
12
20
|
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
13
21
|
const key = keys[keyIndex];
|
|
14
|
-
if (
|
|
22
|
+
if (EXPRESSION_PROPERTY.test(key)) continue;
|
|
15
23
|
const value = original[key];
|
|
16
24
|
const types = [];
|
|
17
25
|
let required = true;
|
|
@@ -19,8 +27,8 @@ function getProperties(original, prefix, fromTypes) {
|
|
|
19
27
|
if (isPlainObject(value)) {
|
|
20
28
|
required = getRequired(key, value) ?? required;
|
|
21
29
|
validators = getValidators(value[PROPERTY_VALIDATORS]);
|
|
22
|
-
if ("$type" in value) types.push(
|
|
23
|
-
else types.push(
|
|
30
|
+
if ("$type" in value) types.push(TYPE_OBJECT, ...getTypes(key, value[PROPERTY_TYPE], prefix, true));
|
|
31
|
+
else types.push(TYPE_OBJECT, ...getTypes(key, value, prefix));
|
|
24
32
|
} else types.push(...getTypes(key, value, prefix));
|
|
25
33
|
if (!required && !types.includes("undefined")) types.push(TYPE_UNDEFINED);
|
|
26
34
|
properties.push({
|
|
@@ -34,10 +42,10 @@ function getProperties(original, prefix, fromTypes) {
|
|
|
34
42
|
}
|
|
35
43
|
function getRequired(key, obj) {
|
|
36
44
|
if (!("$required" in obj)) return;
|
|
37
|
-
if (typeof obj["$required"] !== "boolean") throw new SchematicError(
|
|
45
|
+
if (typeof obj["$required"] !== "boolean") throw new SchematicError(MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace("<>", key));
|
|
38
46
|
return obj[PROPERTY_REQUIRED];
|
|
39
47
|
}
|
|
40
|
-
function getTypes(key, original, prefix,
|
|
48
|
+
function getTypes(key, original, prefix, fromType) {
|
|
41
49
|
const array = Array.isArray(original) ? original : [original];
|
|
42
50
|
const { length } = array;
|
|
43
51
|
const types = [];
|
|
@@ -48,7 +56,7 @@ function getTypes(key, original, prefix, fromTypes) {
|
|
|
48
56
|
types.push(isConstructor(value) ? instanceOf(value) : value);
|
|
49
57
|
break;
|
|
50
58
|
case isPlainObject(value):
|
|
51
|
-
types.push(...getProperties(value, join([prefix, key], "."),
|
|
59
|
+
types.push(...getProperties(value, join([prefix, key], "."), fromType));
|
|
52
60
|
break;
|
|
53
61
|
case isSchematic(value):
|
|
54
62
|
types.push(value);
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -2,22 +2,16 @@ import type {ValueName} from './models';
|
|
|
2
2
|
|
|
3
3
|
export const ERROR_NAME = 'SchematicError';
|
|
4
4
|
|
|
5
|
-
export const EXPRESSION_INDEX = /\.\d+$/;
|
|
6
|
-
|
|
7
|
-
export const EXPRESSION_KEY_PREFIX = /\.\w+$/;
|
|
8
|
-
|
|
9
|
-
export const EXPRESSION_KEY_VALUE = /^.*\.(\w+)$/;
|
|
10
|
-
|
|
11
5
|
export const EXPRESSION_PROPERTY = /(^|\.)\$(required|type|validators)(\.|$)/;
|
|
12
6
|
|
|
13
7
|
export const MESSAGE_CONSTRUCTOR = 'Expected a constructor function';
|
|
14
8
|
|
|
15
9
|
export const MESSAGE_SCHEMA_INVALID_EMPTY = 'Schema must have at least one property';
|
|
16
10
|
|
|
17
|
-
export const
|
|
18
|
-
"'
|
|
11
|
+
export const MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED =
|
|
12
|
+
"'<key>.<property>' property is not allowed for schemas in $type";
|
|
19
13
|
|
|
20
|
-
export const
|
|
14
|
+
export const MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED =
|
|
21
15
|
"'<>.$required' property must be a boolean";
|
|
22
16
|
|
|
23
17
|
export const MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE = "'<>' property must be of a valid type";
|
|
@@ -41,6 +35,10 @@ export const SCHEMATIC_NAME = '$schematic';
|
|
|
41
35
|
|
|
42
36
|
export const TEMPLATE_PATTERN = '<>';
|
|
43
37
|
|
|
38
|
+
export const TEMPLATE_PATTERN_KEY = '<key>';
|
|
39
|
+
|
|
40
|
+
export const TEMPLATE_PATTERN_PROPERTY = '<property>';
|
|
41
|
+
|
|
44
42
|
export const TYPE_OBJECT = 'object';
|
|
45
43
|
|
|
46
44
|
export const TYPE_UNDEFINED = 'undefined';
|
package/src/models.ts
CHANGED
|
@@ -109,6 +109,10 @@ type OptionalKeys<Value> = {
|
|
|
109
109
|
[Key in keyof Value]-?: {} extends Pick<Value, Key> ? Key : never;
|
|
110
110
|
}[keyof Value];
|
|
111
111
|
|
|
112
|
+
type PlainSchema = {
|
|
113
|
+
[key: string]: NestedSchema | SchemaEntry | SchemaEntry[];
|
|
114
|
+
};
|
|
115
|
+
|
|
112
116
|
type PropertyValidators<Value> = {
|
|
113
117
|
[Key in ExtractValueNames<Value>]?:
|
|
114
118
|
| ((value: Values[Key]) => boolean)
|
|
@@ -135,7 +139,7 @@ interface SchemaIndex {
|
|
|
135
139
|
}
|
|
136
140
|
|
|
137
141
|
/**
|
|
138
|
-
* A property definition with explicit type(s)
|
|
142
|
+
* A property definition with explicit type(s), optional requirement flag, and optional validators
|
|
139
143
|
*/
|
|
140
144
|
export type SchemaProperty = {
|
|
141
145
|
$required?: boolean;
|
|
@@ -145,7 +149,7 @@ export type SchemaProperty = {
|
|
|
145
149
|
|
|
146
150
|
type SchemaPropertyType =
|
|
147
151
|
| Constructor
|
|
148
|
-
|
|
|
152
|
+
| PlainSchema
|
|
149
153
|
| Schematic<unknown>
|
|
150
154
|
| ValueName
|
|
151
155
|
| ((value: unknown) => boolean);
|
|
@@ -2,11 +2,10 @@ import {isConstructor, isPlainObject} from '@oscarpalmer/atoms/is';
|
|
|
2
2
|
import type {PlainObject} from '@oscarpalmer/atoms/models';
|
|
3
3
|
import {join} from '@oscarpalmer/atoms/string/misc';
|
|
4
4
|
import {
|
|
5
|
-
EXPRESSION_INDEX,
|
|
6
5
|
EXPRESSION_PROPERTY,
|
|
7
6
|
MESSAGE_SCHEMA_INVALID_EMPTY,
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED,
|
|
8
|
+
MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED,
|
|
10
9
|
MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE,
|
|
11
10
|
MESSAGE_VALIDATOR_INVALID_KEY,
|
|
12
11
|
MESSAGE_VALIDATOR_INVALID_TYPE,
|
|
@@ -15,7 +14,10 @@ import {
|
|
|
15
14
|
PROPERTY_TYPE,
|
|
16
15
|
PROPERTY_VALIDATORS,
|
|
17
16
|
TEMPLATE_PATTERN,
|
|
17
|
+
TEMPLATE_PATTERN_KEY,
|
|
18
|
+
TEMPLATE_PATTERN_PROPERTY,
|
|
18
19
|
TYPE_ALL,
|
|
20
|
+
TYPE_OBJECT,
|
|
19
21
|
TYPE_UNDEFINED,
|
|
20
22
|
VALIDATABLE_TYPES,
|
|
21
23
|
} from '../constants';
|
|
@@ -28,19 +30,40 @@ import {
|
|
|
28
30
|
type ValueName,
|
|
29
31
|
} from '../models';
|
|
30
32
|
|
|
33
|
+
function getDisallowedProperty(obj: PlainObject): string | undefined {
|
|
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
|
+
|
|
31
47
|
export function getProperties(
|
|
32
48
|
original: PlainObject,
|
|
33
49
|
prefix?: string,
|
|
34
|
-
|
|
50
|
+
fromType?: boolean,
|
|
35
51
|
): ValidatedProperty[] {
|
|
36
52
|
if (Object.keys(original).length === 0) {
|
|
37
53
|
throw new SchematicError(MESSAGE_SCHEMA_INVALID_EMPTY);
|
|
38
54
|
}
|
|
39
55
|
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
)
|
|
56
|
+
if (fromType ?? false) {
|
|
57
|
+
const property = getDisallowedProperty(original);
|
|
58
|
+
|
|
59
|
+
if (property != null) {
|
|
60
|
+
throw new SchematicError(
|
|
61
|
+
MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED.replace(TEMPLATE_PATTERN_KEY, prefix!).replace(
|
|
62
|
+
TEMPLATE_PATTERN_PROPERTY,
|
|
63
|
+
property,
|
|
64
|
+
),
|
|
65
|
+
);
|
|
66
|
+
}
|
|
44
67
|
}
|
|
45
68
|
|
|
46
69
|
const keys = Object.keys(original);
|
|
@@ -51,7 +74,7 @@ export function getProperties(
|
|
|
51
74
|
for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
|
|
52
75
|
const key = keys[keyIndex];
|
|
53
76
|
|
|
54
|
-
if (
|
|
77
|
+
if (EXPRESSION_PROPERTY.test(key)) {
|
|
55
78
|
continue;
|
|
56
79
|
}
|
|
57
80
|
|
|
@@ -67,9 +90,9 @@ export function getProperties(
|
|
|
67
90
|
validators = getValidators(value[PROPERTY_VALIDATORS]);
|
|
68
91
|
|
|
69
92
|
if (PROPERTY_TYPE in value) {
|
|
70
|
-
types.push(
|
|
93
|
+
types.push(TYPE_OBJECT, ...getTypes(key, value[PROPERTY_TYPE], prefix, true));
|
|
71
94
|
} else {
|
|
72
|
-
types.push(
|
|
95
|
+
types.push(TYPE_OBJECT, ...getTypes(key, value, prefix));
|
|
73
96
|
}
|
|
74
97
|
} else {
|
|
75
98
|
types.push(...getTypes(key, value, prefix));
|
|
@@ -97,7 +120,7 @@ function getRequired(key: string, obj: PlainObject): boolean | undefined {
|
|
|
97
120
|
|
|
98
121
|
if (typeof obj[PROPERTY_REQUIRED] !== 'boolean') {
|
|
99
122
|
throw new SchematicError(
|
|
100
|
-
|
|
123
|
+
MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED.replace(TEMPLATE_PATTERN, key),
|
|
101
124
|
);
|
|
102
125
|
}
|
|
103
126
|
|
|
@@ -108,7 +131,7 @@ function getTypes(
|
|
|
108
131
|
key: string,
|
|
109
132
|
original: unknown,
|
|
110
133
|
prefix?: string,
|
|
111
|
-
|
|
134
|
+
fromType?: boolean,
|
|
112
135
|
): ValidatedPropertyType[] {
|
|
113
136
|
const array = Array.isArray(original) ? original : [original];
|
|
114
137
|
const {length} = array;
|
|
@@ -124,7 +147,7 @@ function getTypes(
|
|
|
124
147
|
break;
|
|
125
148
|
|
|
126
149
|
case isPlainObject(value):
|
|
127
|
-
types.push(...getProperties(value, join([prefix, key], '.'),
|
|
150
|
+
types.push(...getProperties(value, join([prefix, key], '.'), fromType));
|
|
128
151
|
break;
|
|
129
152
|
|
|
130
153
|
case isSchematic(value):
|
package/types/constants.d.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
export declare const ERROR_NAME = "SchematicError";
|
|
2
|
-
export declare const EXPRESSION_INDEX: RegExp;
|
|
3
|
-
export declare const EXPRESSION_KEY_PREFIX: RegExp;
|
|
4
|
-
export declare const EXPRESSION_KEY_VALUE: RegExp;
|
|
5
2
|
export declare const EXPRESSION_PROPERTY: RegExp;
|
|
6
3
|
export declare const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
|
|
7
4
|
export declare const MESSAGE_SCHEMA_INVALID_EMPTY = "Schema must have at least one property";
|
|
8
|
-
export declare const
|
|
9
|
-
export declare const
|
|
5
|
+
export declare const MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED = "'<key>.<property>' property is not allowed for schemas in $type";
|
|
6
|
+
export declare const MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED = "'<>.$required' property must be a boolean";
|
|
10
7
|
export declare const MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE = "'<>' property must be of a valid type";
|
|
11
8
|
export declare const MESSAGE_SCHEMA_INVALID_TYPE = "Schema must be an object";
|
|
12
9
|
export declare const MESSAGE_VALIDATOR_INVALID_KEY = "Validator '<>' does not exist";
|
|
@@ -17,6 +14,8 @@ export declare const PROPERTY_TYPE = "$type";
|
|
|
17
14
|
export declare const PROPERTY_VALIDATORS = "$validators";
|
|
18
15
|
export declare const SCHEMATIC_NAME = "$schematic";
|
|
19
16
|
export declare const TEMPLATE_PATTERN = "<>";
|
|
17
|
+
export declare const TEMPLATE_PATTERN_KEY = "<key>";
|
|
18
|
+
export declare const TEMPLATE_PATTERN_PROPERTY = "<property>";
|
|
20
19
|
export declare const TYPE_OBJECT = "object";
|
|
21
20
|
export declare const TYPE_UNDEFINED = "undefined";
|
|
22
21
|
export declare const VALIDATABLE_TYPES: Set<keyof import("./models").Values>;
|
package/types/models.d.ts
CHANGED
|
@@ -42,6 +42,9 @@ export type NestedSchema = {
|
|
|
42
42
|
type OptionalKeys<Value> = {
|
|
43
43
|
[Key in keyof Value]-?: {} extends Pick<Value, Key> ? Key : never;
|
|
44
44
|
}[keyof Value];
|
|
45
|
+
type PlainSchema = {
|
|
46
|
+
[key: string]: NestedSchema | SchemaEntry | SchemaEntry[];
|
|
47
|
+
};
|
|
45
48
|
type PropertyValidators<Value> = {
|
|
46
49
|
[Key in ExtractValueNames<Value>]?: ((value: Values[Key]) => boolean) | Array<(value: Values[Key]) => boolean>;
|
|
47
50
|
};
|
|
@@ -55,14 +58,14 @@ interface SchemaIndex {
|
|
|
55
58
|
[key: string]: NestedSchema | SchemaEntry | SchemaEntry[];
|
|
56
59
|
}
|
|
57
60
|
/**
|
|
58
|
-
* A property definition with explicit type(s)
|
|
61
|
+
* A property definition with explicit type(s), optional requirement flag, and optional validators
|
|
59
62
|
*/
|
|
60
63
|
export type SchemaProperty = {
|
|
61
64
|
$required?: boolean;
|
|
62
65
|
$type: SchemaPropertyType | SchemaPropertyType[];
|
|
63
66
|
$validators?: PropertyValidators<SchemaPropertyType | SchemaPropertyType[]>;
|
|
64
67
|
};
|
|
65
|
-
type SchemaPropertyType = Constructor |
|
|
68
|
+
type SchemaPropertyType = Constructor | PlainSchema | Schematic<unknown> | ValueName | ((value: unknown) => boolean);
|
|
66
69
|
export declare class SchematicError extends Error {
|
|
67
70
|
constructor(message: string);
|
|
68
71
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { PlainObject } from '@oscarpalmer/atoms/models';
|
|
2
2
|
import { type ValidatedProperty } from '../models';
|
|
3
|
-
export declare function getProperties(original: PlainObject, prefix?: string,
|
|
3
|
+
export declare function getProperties(original: PlainObject, prefix?: string, fromType?: boolean): ValidatedProperty[];
|