@oscarpalmer/jhunal 0.10.0 → 0.12.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 +20 -6
- package/dist/index.js +3 -2
- package/dist/is.js +4 -4
- package/dist/jhunal.full.js +136 -118
- package/dist/models.js +8 -0
- package/dist/schematic.js +13 -12
- package/dist/validation/property.validation.js +96 -0
- package/dist/validation/value.validation.js +28 -30
- package/package.json +1 -1
- package/src/constants.ts +29 -6
- package/src/index.ts +2 -2
- package/src/is.ts +3 -3
- package/src/models.ts +72 -41
- package/src/schematic.ts +25 -15
- package/src/validation/property.validation.ts +190 -0
- package/src/validation/value.validation.ts +45 -53
- package/types/constants.d.ts +14 -3
- package/types/index.d.ts +2 -2
- package/types/is.d.ts +1 -1
- package/types/models.d.ts +26 -20
- package/types/schematic.d.ts +2 -3
- package/types/validation/property.validation.d.ts +3 -0
- package/types/validation/value.validation.d.ts +2 -3
- package/dist/node_modules/@oscarpalmer/atoms/dist/internal/array/compact.js +0 -12
- package/dist/node_modules/@oscarpalmer/atoms/dist/internal/is.js +0 -20
- package/dist/node_modules/@oscarpalmer/atoms/dist/internal/string.js +0 -24
- package/dist/node_modules/@oscarpalmer/atoms/dist/value/smush.js +0 -36
- package/dist/validation/schema.validation.js +0 -92
- package/src/validation/schema.validation.ts +0 -192
- package/types/validation/schema.validation.d.ts +0 -2
package/types/constants.d.ts
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const EXPRESSION_HAS_NUMBER: RegExp;
|
|
1
|
+
export declare const ERROR_NAME = "SchematicError";
|
|
3
2
|
export declare const EXPRESSION_INDEX: RegExp;
|
|
3
|
+
export declare const EXPRESSION_KEY_PREFIX: RegExp;
|
|
4
|
+
export declare const EXPRESSION_KEY_VALUE: RegExp;
|
|
4
5
|
export declare const EXPRESSION_PROPERTY: RegExp;
|
|
6
|
+
export declare const MESSAGE_CONSTRUCTOR = "Expected a constructor function";
|
|
7
|
+
export declare const MESSAGE_SCHEMA_INVALID_EMPTY = "Schema must have at least one property";
|
|
8
|
+
export declare const MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED = "'<>.$required' property must be a boolean";
|
|
9
|
+
export declare const MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE = "'<>' property must be of a valid type";
|
|
10
|
+
export declare const MESSAGE_SCHEMA_INVALID_TYPE = "Schema must be an object";
|
|
11
|
+
export declare const MESSAGE_VALIDATOR_INVALID_KEY = "Validator '<>' does not exist";
|
|
12
|
+
export declare const MESSAGE_VALIDATOR_INVALID_TYPE = "Validators must be an object";
|
|
13
|
+
export declare const MESSAGE_VALIDATOR_INVALID_VALUE = "Validator '<>' must be a function or an array of functions";
|
|
5
14
|
export declare const PROPERTY_REQUIRED = "$required";
|
|
6
15
|
export declare const PROPERTY_TYPE = "$type";
|
|
7
16
|
export declare const PROPERTY_VALIDATORS = "$validators";
|
|
8
17
|
export declare const SCHEMATIC_NAME = "$schematic";
|
|
18
|
+
export declare const TEMPLATE_PATTERN = "<>";
|
|
9
19
|
export declare const TYPE_OBJECT = "object";
|
|
10
20
|
export declare const TYPE_UNDEFINED = "undefined";
|
|
11
|
-
export declare const
|
|
21
|
+
export declare const VALIDATABLE_TYPES: Set<keyof import("./models").Values>;
|
|
22
|
+
export declare const TYPE_ALL: Set<keyof import("./models").Values>;
|
package/types/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type
|
|
1
|
+
export { instanceOf } from './is';
|
|
2
|
+
export { SchematicError, type Schema, type TypedSchema } from './models';
|
|
3
3
|
export { schematic, type Schematic } from './schematic';
|
package/types/is.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Constructor } from './models';
|
|
2
2
|
import type { Schematic } from './schematic';
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function instanceOf<Instance>(constructor: Constructor<Instance>): (value: unknown) => value is Instance;
|
|
4
4
|
export declare function isSchematic(value: unknown): value is Schematic<never>;
|
package/types/models.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PlainObject, Simplify } from '@oscarpalmer/atoms/models';
|
|
1
|
+
import type { GenericCallback, PlainObject, Simplify } from '@oscarpalmer/atoms/models';
|
|
2
2
|
import type { Schematic } from './schematic';
|
|
3
3
|
export type Constructor<Instance = any> = new (...args: any[]) => Instance;
|
|
4
4
|
type DeduplicateTuple<Value extends unknown[], Seen extends unknown[] = []> = Value extends [
|
|
@@ -23,8 +23,12 @@ type InferRequiredKeys<Model extends Schema> = keyof {
|
|
|
23
23
|
[Key in keyof Model as IsOptionalProperty<Model[Key]> extends true ? never : Key]: never;
|
|
24
24
|
};
|
|
25
25
|
type InferSchemaEntry<Value> = Value extends (infer Item)[] ? InferSchemaEntryValue<Item> : InferSchemaEntryValue<Value>;
|
|
26
|
-
type InferSchemaEntryValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends Schematic<infer Model> ? Model : Value extends SchemaProperty ? InferPropertyType<Value['$type']> : Value extends ValueName ? Values[Value & ValueName] : Value extends Schema ? Infer<Value> : never;
|
|
27
|
-
type IsOptionalProperty<Value> = Value extends SchemaProperty ? Value['$required'] extends false ? true : false :
|
|
26
|
+
type InferSchemaEntryValue<Value> = Value extends Constructor<infer Instance> ? Instance : Value extends Schematic<infer Model> ? Model : Value extends SchemaProperty ? InferPropertyType<Value['$type']> : Value extends NestedSchema ? Infer<Omit<Value, '$required'>> : Value extends ValueName ? Values[Value & ValueName] : Value extends Schema ? Infer<Value> : never;
|
|
27
|
+
type IsOptionalProperty<Value> = Value extends SchemaProperty ? Value['$required'] extends false ? true : false : Value extends {
|
|
28
|
+
$required?: boolean;
|
|
29
|
+
} ? Value extends {
|
|
30
|
+
$required: false;
|
|
31
|
+
} ? true : false : false;
|
|
28
32
|
type LastOfUnion<Value> = UnionToIntersection<Value extends unknown ? () => Value : never> extends () => infer Item ? Item : never;
|
|
29
33
|
type MapToValueTypes<Value extends unknown[]> = Value extends [infer Head, ...infer Tail] ? [ToValueType<Head>, ...MapToValueTypes<Tail>] : [];
|
|
30
34
|
type MapToSchemaPropertyTypes<Value extends unknown[]> = Value extends [infer Head, ...infer Tail] ? [ToSchemaPropertyTypeEach<Head>, ...MapToSchemaPropertyTypes<Tail>] : [];
|
|
@@ -33,7 +37,8 @@ type MapToSchemaPropertyTypes<Value extends unknown[]> = Value extends [infer He
|
|
|
33
37
|
*/
|
|
34
38
|
export type NestedSchema = {
|
|
35
39
|
$required?: boolean;
|
|
36
|
-
|
|
40
|
+
[key: string]: any;
|
|
41
|
+
};
|
|
37
42
|
type OptionalKeys<Value> = {
|
|
38
43
|
[Key in keyof Value]-?: {} extends Pick<Value, Key> ? Key : never;
|
|
39
44
|
}[keyof Value];
|
|
@@ -45,9 +50,9 @@ type RequiredKeys<Value> = Exclude<keyof Value, OptionalKeys<Value>>;
|
|
|
45
50
|
* A schema for validating objects
|
|
46
51
|
*/
|
|
47
52
|
export type Schema = SchemaIndex;
|
|
48
|
-
type SchemaEntry = Constructor |
|
|
53
|
+
type SchemaEntry = Constructor | Schema | SchemaProperty | Schematic<unknown> | ValueName | ((value: unknown) => boolean);
|
|
49
54
|
interface SchemaIndex {
|
|
50
|
-
[key: string]: SchemaEntry | SchemaEntry[];
|
|
55
|
+
[key: string]: NestedSchema | SchemaEntry | SchemaEntry[];
|
|
51
56
|
}
|
|
52
57
|
/**
|
|
53
58
|
* A property definition with explicit type(s) and optional requirement flag
|
|
@@ -57,11 +62,14 @@ export type SchemaProperty = {
|
|
|
57
62
|
$type: SchemaPropertyType | SchemaPropertyType[];
|
|
58
63
|
$validators?: PropertyValidators<SchemaPropertyType | SchemaPropertyType[]>;
|
|
59
64
|
};
|
|
60
|
-
type SchemaPropertyType = Constructor | Schema | Schematic<unknown> | ValueName;
|
|
65
|
+
type SchemaPropertyType = Constructor | Schema | Schematic<unknown> | ValueName | ((value: unknown) => boolean);
|
|
66
|
+
export declare class SchematicError extends Error {
|
|
67
|
+
constructor(message: string);
|
|
68
|
+
}
|
|
61
69
|
type ToSchemaPropertyType<Value> = UnwrapSingle<DeduplicateTuple<MapToSchemaPropertyTypes<UnionToTuple<Value>>>>;
|
|
62
|
-
type ToSchemaPropertyTypeEach<Value> = Value extends PlainObject ? TypedSchema<Value> : ToValueType<Value>;
|
|
70
|
+
type ToSchemaPropertyTypeEach<Value> = Value extends NestedSchema ? Omit<Value, '$required'> : Value extends PlainObject ? TypedSchema<Value> : ToValueType<Value>;
|
|
63
71
|
type ToSchemaType<Value> = UnwrapSingle<DeduplicateTuple<MapToValueTypes<UnionToTuple<Value>>>>;
|
|
64
|
-
type ToValueType<Value> = Value extends unknown[] ? 'array' : Value extends bigint ? 'bigint' : Value extends boolean ? 'boolean' : Value extends Date ? 'date' : Value extends Function ? 'function' : Value extends null ? 'null' : Value extends number ? 'number' : Value extends object ? 'object' | ((value: unknown) => value is Value) : Value extends string ? 'string' : Value extends symbol ? 'symbol' : Value extends undefined ? 'undefined' : (value: unknown) => value is Value;
|
|
72
|
+
type ToValueType<Value> = Value extends unknown[] ? 'array' : Value extends bigint ? 'bigint' : Value extends boolean ? 'boolean' : Value extends Date ? 'date' : Value extends Schematic<any> ? Value : Value extends Function ? 'function' : Value extends null ? 'null' : Value extends number ? 'number' : Value extends object ? 'object' | ((value: unknown) => value is Value) : Value extends string ? 'string' : Value extends symbol ? 'symbol' : Value extends undefined ? 'undefined' : (value: unknown) => value is Value;
|
|
65
73
|
type TuplePermutations<Tuple extends unknown[], Elput extends unknown[] = []> = Tuple['length'] extends 0 ? Elput : {
|
|
66
74
|
[Key in keyof Tuple]: TuplePermutations<TupleRemoveAt<Tuple, Key & `${number}`>, [
|
|
67
75
|
...Elput,
|
|
@@ -101,9 +109,9 @@ export type TypedPropertyRequired<Value> = {
|
|
|
101
109
|
* Create a schema type constrained to match a TypeScript type
|
|
102
110
|
*/
|
|
103
111
|
export type TypedSchema<Model extends PlainObject> = Simplify<{
|
|
104
|
-
[Key in RequiredKeys<Model>]: Model[Key] extends PlainObject ? TypedSchemaRequired<Model[Key]> : ToSchemaType<Model[Key]> | TypedPropertyRequired<Model[Key]>;
|
|
112
|
+
[Key in RequiredKeys<Model>]: Model[Key] extends PlainObject ? TypedSchemaRequired<Model[Key]> | Schematic<Model[Key]> : ToSchemaType<Model[Key]> | TypedPropertyRequired<Model[Key]>;
|
|
105
113
|
} & {
|
|
106
|
-
[Key in OptionalKeys<Model>]: Exclude<Model[Key], undefined> extends PlainObject ? TypedSchemaOptional<Exclude<Model[Key], undefined>> : TypedPropertyOptional<Model[Key]>;
|
|
114
|
+
[Key in OptionalKeys<Model>]: Exclude<Model[Key], undefined> extends PlainObject ? TypedSchemaOptional<Exclude<Model[Key], undefined>> | Schematic<Exclude<Model[Key], undefined>> : TypedPropertyOptional<Model[Key]>;
|
|
107
115
|
}>;
|
|
108
116
|
type TypedSchemaOptional<Model extends PlainObject> = {
|
|
109
117
|
$required: false;
|
|
@@ -115,22 +123,20 @@ type UnionToIntersection<Value> = (Value extends unknown ? (value: Value) => voi
|
|
|
115
123
|
type UnionToTuple<Value, Items extends unknown[] = []> = [Value] extends [never] ? Items : UnionToTuple<Exclude<Value, LastOfUnion<Value>>, [LastOfUnion<Value>, ...Items]>;
|
|
116
124
|
type UnwrapSingle<Value extends unknown[]> = Value extends [infer Only] ? Only : Value['length'] extends 1 | 2 | 3 | 4 | 5 ? TuplePermutations<Value> : Value;
|
|
117
125
|
export type ValidatedProperty = {
|
|
126
|
+
key: ValidatedPropertyKey;
|
|
118
127
|
required: boolean;
|
|
119
128
|
types: ValidatedPropertyType[];
|
|
120
129
|
validators: ValidatedPropertyValidators;
|
|
121
130
|
};
|
|
122
|
-
export type
|
|
131
|
+
export type ValidatedPropertyKey = {
|
|
132
|
+
full: string;
|
|
133
|
+
prefix: string | undefined;
|
|
134
|
+
value: string;
|
|
135
|
+
};
|
|
136
|
+
export type ValidatedPropertyType = GenericCallback | Schematic<unknown> | ValueName;
|
|
123
137
|
export type ValidatedPropertyValidators = {
|
|
124
138
|
[Key in ValueName]?: Array<(value: unknown) => boolean>;
|
|
125
139
|
};
|
|
126
|
-
export type ValidatedSchema = {
|
|
127
|
-
enabled: boolean;
|
|
128
|
-
keys: {
|
|
129
|
-
array: string[];
|
|
130
|
-
set: Set<string>;
|
|
131
|
-
};
|
|
132
|
-
properties: Record<string, ValidatedProperty>;
|
|
133
|
-
};
|
|
134
140
|
/**
|
|
135
141
|
* Valid type name strings
|
|
136
142
|
*/
|
package/types/schematic.d.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import type { PlainObject } from '@oscarpalmer/atoms/models';
|
|
2
|
-
import type
|
|
2
|
+
import { type Infer, type Schema, type TypedSchema, type ValidatedProperty } from './models';
|
|
3
3
|
/**
|
|
4
4
|
* A schematic for validating objects
|
|
5
5
|
*/
|
|
6
6
|
export declare class Schematic<Model> {
|
|
7
7
|
#private;
|
|
8
8
|
private readonly $schematic;
|
|
9
|
-
|
|
10
|
-
constructor(schema: Model);
|
|
9
|
+
constructor(properties: ValidatedProperty[]);
|
|
11
10
|
/**
|
|
12
11
|
* Does the value match the schema?
|
|
13
12
|
*/
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import type { ValidatedProperty
|
|
2
|
-
export declare function
|
|
3
|
-
export declare function validateValue(validated: ValidatedSchema, obj: unknown): boolean;
|
|
1
|
+
import type { ValidatedProperty } from '../models';
|
|
2
|
+
export declare function validateObject(obj: unknown, properties: ValidatedProperty[]): boolean;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
function compact(array, strict) {
|
|
2
|
-
if (!Array.isArray(array)) return [];
|
|
3
|
-
if (strict === true) return array.filter(Boolean);
|
|
4
|
-
const { length } = array;
|
|
5
|
-
const compacted = [];
|
|
6
|
-
for (let index = 0; index < length; index += 1) {
|
|
7
|
-
const item = array[index];
|
|
8
|
-
if (item != null) compacted.push(item);
|
|
9
|
-
}
|
|
10
|
-
return compacted;
|
|
11
|
-
}
|
|
12
|
-
export { compact };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Is the value an array or a record?
|
|
3
|
-
* @param value Value to check
|
|
4
|
-
* @returns `true` if the value is an array or a record, otherwise `false`
|
|
5
|
-
*/
|
|
6
|
-
function isArrayOrPlainObject(value) {
|
|
7
|
-
return Array.isArray(value) || isPlainObject(value);
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Is the value a plain object?
|
|
11
|
-
* @param value Value to check
|
|
12
|
-
* @returns `true` if the value is a plain object, otherwise `false`
|
|
13
|
-
*/
|
|
14
|
-
function isPlainObject(value) {
|
|
15
|
-
if (value === null || typeof value !== "object") return false;
|
|
16
|
-
if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
|
|
17
|
-
const prototype = Object.getPrototypeOf(value);
|
|
18
|
-
return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
|
|
19
|
-
}
|
|
20
|
-
export { isArrayOrPlainObject };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { compact } from "./array/compact.js";
|
|
2
|
-
/**
|
|
3
|
-
* Get the string value from any value
|
|
4
|
-
* @param value Original value
|
|
5
|
-
* @returns String representation of the value
|
|
6
|
-
*/
|
|
7
|
-
function getString(value) {
|
|
8
|
-
if (typeof value === "string") return value;
|
|
9
|
-
if (value == null) return "";
|
|
10
|
-
if (typeof value === "function") return getString(value());
|
|
11
|
-
if (typeof value !== "object") return String(value);
|
|
12
|
-
const asString = String(value.valueOf?.() ?? value);
|
|
13
|
-
return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Join an array of values into a string
|
|
17
|
-
* @param value Array of values
|
|
18
|
-
* @param delimiter Delimiter to use between values
|
|
19
|
-
* @returns Joined string
|
|
20
|
-
*/
|
|
21
|
-
function join(value, delimiter) {
|
|
22
|
-
return compact(value).map(getString).join(typeof delimiter === "string" ? delimiter : "");
|
|
23
|
-
}
|
|
24
|
-
export { join };
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { isArrayOrPlainObject } from "../internal/is.js";
|
|
2
|
-
import { join } from "../internal/string.js";
|
|
3
|
-
function flattenObject(value, depth, smushed, prefix) {
|
|
4
|
-
if (depth >= MAX_DEPTH) return {};
|
|
5
|
-
if (smushed.has(value)) return smushed.get(value);
|
|
6
|
-
const keys = Object.keys(value);
|
|
7
|
-
const { length } = keys;
|
|
8
|
-
const flattened = {};
|
|
9
|
-
for (let index = 0; index < length; index += 1) {
|
|
10
|
-
const key = keys[index];
|
|
11
|
-
const val = value[key];
|
|
12
|
-
if (isArrayOrPlainObject(val)) {
|
|
13
|
-
const prefixedKey = join([prefix, key], ".");
|
|
14
|
-
flattened[prefixedKey] = Array.isArray(val) ? [...val] : { ...val };
|
|
15
|
-
const nested = flattenObject(val, depth + 1, smushed, prefixedKey);
|
|
16
|
-
const nestedKeys = Object.keys(nested);
|
|
17
|
-
const nestedLength = nestedKeys.length;
|
|
18
|
-
for (let nestedIndex = 0; nestedIndex < nestedLength; nestedIndex += 1) {
|
|
19
|
-
const nestedKey = nestedKeys[nestedIndex];
|
|
20
|
-
flattened[nestedKey] = nested[nestedKey];
|
|
21
|
-
}
|
|
22
|
-
} else flattened[join([prefix, key], ".")] = val;
|
|
23
|
-
}
|
|
24
|
-
smushed.set(value, flattened);
|
|
25
|
-
return flattened;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Smush an object into a flat object that uses dot notation keys
|
|
29
|
-
* @param value Object to smush
|
|
30
|
-
* @returns Smushed object with dot notation keys
|
|
31
|
-
*/
|
|
32
|
-
function smush(value) {
|
|
33
|
-
return typeof value === "object" && value !== null ? flattenObject(value, 0, /* @__PURE__ */ new WeakMap()) : {};
|
|
34
|
-
}
|
|
35
|
-
var MAX_DEPTH = 100;
|
|
36
|
-
export { smush };
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { EXPRESSION_HAS_NUMBER, EXPRESSION_INDEX, EXPRESSION_PROPERTY, PROPERTY_REQUIRED, PROPERTY_TYPE, PROPERTY_VALIDATORS, TYPE_ALL, TYPE_OBJECT, TYPE_UNDEFINED } from "../constants.js";
|
|
2
|
-
import { isInstance, isSchematic } from "../is.js";
|
|
3
|
-
import { smush } from "../node_modules/@oscarpalmer/atoms/dist/value/smush.js";
|
|
4
|
-
import { isConstructor } from "@oscarpalmer/atoms/is";
|
|
5
|
-
function addPropertyType(to, key, values, validators, required) {
|
|
6
|
-
if (to.keys.set.has(key)) {
|
|
7
|
-
const property = to.properties[key];
|
|
8
|
-
for (const type of values) if (!property.types.includes(type)) property.types.push(type);
|
|
9
|
-
} else {
|
|
10
|
-
to.keys.array.push(key);
|
|
11
|
-
to.keys.set.add(key);
|
|
12
|
-
to.properties[key] = {
|
|
13
|
-
required,
|
|
14
|
-
types: values,
|
|
15
|
-
validators: {}
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
if (!required && !to.properties[key].types.includes("undefined")) to.properties[key].types.push(TYPE_UNDEFINED);
|
|
19
|
-
to.properties[key].validators = validators;
|
|
20
|
-
}
|
|
21
|
-
function getSchema(schema) {
|
|
22
|
-
const validated = {
|
|
23
|
-
enabled: false,
|
|
24
|
-
keys: {
|
|
25
|
-
array: [],
|
|
26
|
-
set: /* @__PURE__ */ new Set()
|
|
27
|
-
},
|
|
28
|
-
properties: {}
|
|
29
|
-
};
|
|
30
|
-
return typeof schema === "object" && schema !== null ? getValidatedSchema(schema, validated) : validated;
|
|
31
|
-
}
|
|
32
|
-
function getTypes(value, validated, prefix) {
|
|
33
|
-
const propertyTypes = [];
|
|
34
|
-
const values = Array.isArray(value) ? value : [value];
|
|
35
|
-
const { length } = values;
|
|
36
|
-
for (let index = 0; index < length; index += 1) {
|
|
37
|
-
const type = values[index];
|
|
38
|
-
const typeOfType = typeof type;
|
|
39
|
-
if (isSchematic(type) || typeOfType === "string" && TYPE_ALL.has(type)) {
|
|
40
|
-
propertyTypes.push(type);
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
if (typeOfType === "function") {
|
|
44
|
-
propertyTypes.push(isConstructor(type) ? isInstance(type) : type);
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
if (typeOfType !== "object" || type === null) continue;
|
|
48
|
-
if ("$type" in type) {
|
|
49
|
-
propertyTypes.push(...getTypes(type[PROPERTY_TYPE], validated, prefix));
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
addPropertyType(validated, prefix, [TYPE_OBJECT], {}, type[PROPERTY_REQUIRED] !== false);
|
|
53
|
-
propertyTypes.push(TYPE_OBJECT);
|
|
54
|
-
getValidatedSchema(type, validated, prefix);
|
|
55
|
-
}
|
|
56
|
-
return propertyTypes;
|
|
57
|
-
}
|
|
58
|
-
function getValidatedSchema(schema, validated, prefix) {
|
|
59
|
-
const smushed = smush(schema);
|
|
60
|
-
const keys = Object.keys(smushed);
|
|
61
|
-
const { length } = keys;
|
|
62
|
-
const arrayKeys = /* @__PURE__ */ new Set();
|
|
63
|
-
const noPrefix = prefix == null;
|
|
64
|
-
prefix = noPrefix ? "" : `${prefix}.`;
|
|
65
|
-
for (let index = 0; index < length; index += 1) {
|
|
66
|
-
const key = keys[index];
|
|
67
|
-
const value = smushed[key];
|
|
68
|
-
if (Array.isArray(value)) arrayKeys.add(key);
|
|
69
|
-
if (EXPRESSION_PROPERTY.test(key)) continue;
|
|
70
|
-
if (EXPRESSION_HAS_NUMBER.test(key) && arrayKeys.has(key.replace(EXPRESSION_INDEX, ""))) continue;
|
|
71
|
-
let required = true;
|
|
72
|
-
let validators = {};
|
|
73
|
-
const isObject = typeof value === "object" && value !== null;
|
|
74
|
-
if (isObject && "$required" in value) required = typeof value["$required"] === "boolean" ? value[PROPERTY_REQUIRED] : true;
|
|
75
|
-
if (isObject && "$validators" in value) validators = getValidators(value[PROPERTY_VALIDATORS]);
|
|
76
|
-
const prefixedKey = `${prefix}${key}`;
|
|
77
|
-
const types = getTypes(value, validated, prefixedKey);
|
|
78
|
-
if (types.length > 0) addPropertyType(validated, prefixedKey, types, validators, required);
|
|
79
|
-
}
|
|
80
|
-
if (noPrefix) validated.keys.array.sort();
|
|
81
|
-
return validated;
|
|
82
|
-
}
|
|
83
|
-
function getValidators(original) {
|
|
84
|
-
const validators = {};
|
|
85
|
-
if (typeof original !== "object" || original === null) return validators;
|
|
86
|
-
for (const type of TYPE_ALL) {
|
|
87
|
-
const value = original[type];
|
|
88
|
-
validators[type] = (Array.isArray(value) ? value : [value]).filter((validator) => typeof validator === "function");
|
|
89
|
-
}
|
|
90
|
-
return validators;
|
|
91
|
-
}
|
|
92
|
-
export { getSchema };
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import {isConstructor} from '@oscarpalmer/atoms/is';
|
|
2
|
-
import type {PlainObject} from '@oscarpalmer/atoms/models';
|
|
3
|
-
import {smush} from '@oscarpalmer/atoms/value/misc';
|
|
4
|
-
import {
|
|
5
|
-
EXPRESSION_HAS_NUMBER,
|
|
6
|
-
EXPRESSION_INDEX,
|
|
7
|
-
EXPRESSION_PROPERTY,
|
|
8
|
-
PROPERTY_REQUIRED,
|
|
9
|
-
PROPERTY_TYPE,
|
|
10
|
-
PROPERTY_VALIDATORS,
|
|
11
|
-
TYPE_ALL,
|
|
12
|
-
TYPE_OBJECT,
|
|
13
|
-
TYPE_UNDEFINED,
|
|
14
|
-
} from '../constants';
|
|
15
|
-
import {isInstance, isSchematic} from '../is';
|
|
16
|
-
import type {
|
|
17
|
-
Schema,
|
|
18
|
-
ValidatedPropertyType,
|
|
19
|
-
ValidatedPropertyValidators,
|
|
20
|
-
ValidatedSchema,
|
|
21
|
-
} from '../models';
|
|
22
|
-
|
|
23
|
-
function addPropertyType(
|
|
24
|
-
to: ValidatedSchema,
|
|
25
|
-
key: string,
|
|
26
|
-
values: ValidatedPropertyType[],
|
|
27
|
-
validators: ValidatedPropertyValidators,
|
|
28
|
-
required: boolean,
|
|
29
|
-
): void {
|
|
30
|
-
if (to.keys.set.has(key)) {
|
|
31
|
-
const property = to.properties[key];
|
|
32
|
-
|
|
33
|
-
for (const type of values) {
|
|
34
|
-
if (!property.types.includes(type)) {
|
|
35
|
-
property.types.push(type);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
} else {
|
|
39
|
-
to.keys.array.push(key);
|
|
40
|
-
to.keys.set.add(key);
|
|
41
|
-
|
|
42
|
-
to.properties[key] = {
|
|
43
|
-
required,
|
|
44
|
-
types: values,
|
|
45
|
-
validators: {},
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (!required && !to.properties[key].types.includes(TYPE_UNDEFINED)) {
|
|
50
|
-
to.properties[key].types.push(TYPE_UNDEFINED);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
to.properties[key].validators = validators;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function getSchema(schema: unknown): ValidatedSchema {
|
|
57
|
-
const validated: ValidatedSchema = {
|
|
58
|
-
enabled: false,
|
|
59
|
-
keys: {
|
|
60
|
-
array: [],
|
|
61
|
-
set: new Set<string>(),
|
|
62
|
-
},
|
|
63
|
-
properties: {},
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
return typeof schema === 'object' && schema !== null
|
|
67
|
-
? getValidatedSchema(schema as Schema, validated)
|
|
68
|
-
: validated;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function getTypes(
|
|
72
|
-
value: unknown,
|
|
73
|
-
validated: ValidatedSchema,
|
|
74
|
-
prefix: string,
|
|
75
|
-
): ValidatedPropertyType[] {
|
|
76
|
-
const propertyTypes: ValidatedPropertyType[] = [];
|
|
77
|
-
|
|
78
|
-
const values = Array.isArray(value) ? value : [value];
|
|
79
|
-
const {length} = values;
|
|
80
|
-
|
|
81
|
-
for (let index = 0; index < length; index += 1) {
|
|
82
|
-
const type = values[index];
|
|
83
|
-
const typeOfType = typeof type;
|
|
84
|
-
|
|
85
|
-
if (isSchematic(type) || (typeOfType === 'string' && TYPE_ALL.has(type as never))) {
|
|
86
|
-
propertyTypes.push(type as never);
|
|
87
|
-
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (typeOfType === 'function') {
|
|
92
|
-
propertyTypes.push(isConstructor(type) ? isInstance(type) : type);
|
|
93
|
-
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (typeOfType !== 'object' || type === null) {
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (PROPERTY_TYPE in type) {
|
|
102
|
-
propertyTypes.push(...getTypes(type[PROPERTY_TYPE], validated, prefix));
|
|
103
|
-
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
addPropertyType(validated, prefix, [TYPE_OBJECT], {}, type[PROPERTY_REQUIRED] !== false);
|
|
108
|
-
|
|
109
|
-
propertyTypes.push(TYPE_OBJECT);
|
|
110
|
-
|
|
111
|
-
getValidatedSchema(type as Schema, validated, prefix);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return propertyTypes;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function getValidatedSchema(
|
|
118
|
-
schema: Schema,
|
|
119
|
-
validated: ValidatedSchema,
|
|
120
|
-
prefix?: string,
|
|
121
|
-
): ValidatedSchema {
|
|
122
|
-
const smushed = smush(schema as PlainObject);
|
|
123
|
-
const keys = Object.keys(smushed);
|
|
124
|
-
const {length} = keys;
|
|
125
|
-
|
|
126
|
-
const arrayKeys = new Set<string>();
|
|
127
|
-
const noPrefix = prefix == null;
|
|
128
|
-
|
|
129
|
-
prefix = noPrefix ? '' : `${prefix}.`;
|
|
130
|
-
|
|
131
|
-
for (let index = 0; index < length; index += 1) {
|
|
132
|
-
const key = keys[index];
|
|
133
|
-
const value = smushed[key];
|
|
134
|
-
|
|
135
|
-
if (Array.isArray(value)) {
|
|
136
|
-
arrayKeys.add(key);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (EXPRESSION_PROPERTY.test(key)) {
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (EXPRESSION_HAS_NUMBER.test(key) && arrayKeys.has(key.replace(EXPRESSION_INDEX, ''))) {
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
let required = true;
|
|
148
|
-
let validators: ValidatedPropertyValidators = {};
|
|
149
|
-
|
|
150
|
-
const isObject = typeof value === 'object' && value !== null;
|
|
151
|
-
|
|
152
|
-
if (isObject && PROPERTY_REQUIRED in value) {
|
|
153
|
-
required = typeof value[PROPERTY_REQUIRED] === 'boolean' ? value[PROPERTY_REQUIRED] : true;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (isObject && PROPERTY_VALIDATORS in value) {
|
|
157
|
-
validators = getValidators(value[PROPERTY_VALIDATORS]);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const prefixedKey = `${prefix}${key}`;
|
|
161
|
-
|
|
162
|
-
const types = getTypes(value, validated, prefixedKey);
|
|
163
|
-
|
|
164
|
-
if (types.length > 0) {
|
|
165
|
-
addPropertyType(validated, prefixedKey, types, validators, required);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (noPrefix) {
|
|
170
|
-
validated.keys.array.sort();
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return validated;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function getValidators(original: unknown): ValidatedPropertyValidators {
|
|
177
|
-
const validators: ValidatedPropertyValidators = {};
|
|
178
|
-
|
|
179
|
-
if (typeof original !== 'object' || original === null) {
|
|
180
|
-
return validators;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
for (const type of TYPE_ALL) {
|
|
184
|
-
const value = (original as PlainObject)[type];
|
|
185
|
-
|
|
186
|
-
validators[type] = (Array.isArray(value) ? value : [value]).filter(
|
|
187
|
-
validator => typeof validator === 'function',
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return validators;
|
|
192
|
-
}
|