@oscarpalmer/jhunal 0.3.0 → 0.4.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/README.md +2 -0
- package/dist/helpers.cjs +24 -3
- package/dist/helpers.js +24 -3
- package/dist/is.cjs +19 -0
- package/dist/is.js +14 -0
- package/dist/schematic.cjs +5 -3
- package/dist/schematic.js +5 -3
- package/dist/validation/schema.validation.cjs +54 -0
- package/dist/validation/schema.validation.js +49 -0
- package/dist/validation/type.validation.cjs +33 -0
- package/dist/validation/type.validation.js +29 -0
- package/dist/validation/value.validation.cjs +35 -0
- package/dist/validation/value.validation.js +31 -0
- package/package.json +1 -1
- package/src/helpers.ts +33 -5
- package/src/index.ts +1 -1
- package/src/is.ts +22 -0
- package/src/model.ts +84 -43
- package/src/schematic.ts +14 -10
- package/src/validation/schema.validation.ts +63 -0
- package/src/validation/type.validation.ts +34 -0
- package/src/validation/value.validation.ts +46 -0
- package/types/helpers.d.cts +26 -1
- package/types/helpers.d.ts +2 -2
- package/types/index.d.cts +25 -14
- package/types/index.d.ts +1 -1
- package/types/is.d.cts +15 -0
- package/types/is.d.ts +3 -0
- package/types/model.d.cts +27 -12
- package/types/model.d.ts +27 -11
- package/types/schematic.d.cts +25 -14
- package/types/schematic.d.ts +4 -4
- package/types/validation/schema.validation.d.cts +55 -0
- package/types/validation/schema.validation.d.ts +3 -0
- package/types/validation/type.validation.d.cts +43 -0
- package/types/validation/type.validation.d.ts +2 -0
- package/types/validation/value.validation.d.cts +43 -0
- package/types/validation/value.validation.d.ts +2 -0
- package/dist/validation.cjs +0 -89
- package/dist/validation.js +0 -84
- package/src/validation.ts +0 -109
- package/types/validation.d.cts +0 -28
- package/types/validation.d.ts +0 -3
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Jhunal
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@oscarpalmer/jhunal) [](https://github.com/oscarpalmer/jhunal/actions/workflows/test.yml)
|
|
4
|
+
|
|
3
5
|
> Jhunal, sage God of Runes,
|
|
4
6
|
> Flies free beneath the glistening moons.
|
|
5
7
|
> A night owl who's so droll,
|
package/dist/helpers.cjs
CHANGED
|
@@ -2,19 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
4
|
|
|
5
|
+
const is = require('./is.cjs');
|
|
6
|
+
const validation_schema_validation = require('./validation/schema.validation.cjs');
|
|
7
|
+
|
|
5
8
|
function getTypes(value) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
const returned = [];
|
|
10
|
+
const values = Array.isArray(value) ? value : [value];
|
|
11
|
+
const { length } = values;
|
|
12
|
+
for (let index = 0; index < length; index += 1) {
|
|
13
|
+
const type = values[index];
|
|
14
|
+
switch (true) {
|
|
15
|
+
case is.isSchematic(type):
|
|
16
|
+
returned.push(type);
|
|
17
|
+
break;
|
|
18
|
+
case (typeof type === "string" && types.has(type)):
|
|
19
|
+
returned.push(type);
|
|
20
|
+
break;
|
|
21
|
+
case (typeof type === "object" && type !== null): {
|
|
22
|
+
returned.push(validation_schema_validation.validateSchema(type));
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return returned;
|
|
9
28
|
}
|
|
10
29
|
const types = /* @__PURE__ */ new Set([
|
|
11
30
|
"array",
|
|
12
31
|
"bigint",
|
|
13
32
|
"boolean",
|
|
14
33
|
"date",
|
|
34
|
+
"date-like",
|
|
15
35
|
"function",
|
|
16
36
|
"null",
|
|
17
37
|
"number",
|
|
38
|
+
"numerical",
|
|
18
39
|
"object",
|
|
19
40
|
"string",
|
|
20
41
|
"symbol",
|
package/dist/helpers.js
CHANGED
|
@@ -1,16 +1,37 @@
|
|
|
1
|
+
import { isSchematic } from './is.js';
|
|
2
|
+
import { validateSchema } from './validation/schema.validation.js';
|
|
3
|
+
|
|
1
4
|
function getTypes(value) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
+
const returned = [];
|
|
6
|
+
const values = Array.isArray(value) ? value : [value];
|
|
7
|
+
const { length } = values;
|
|
8
|
+
for (let index = 0; index < length; index += 1) {
|
|
9
|
+
const type = values[index];
|
|
10
|
+
switch (true) {
|
|
11
|
+
case isSchematic(type):
|
|
12
|
+
returned.push(type);
|
|
13
|
+
break;
|
|
14
|
+
case (typeof type === "string" && types.has(type)):
|
|
15
|
+
returned.push(type);
|
|
16
|
+
break;
|
|
17
|
+
case (typeof type === "object" && type !== null): {
|
|
18
|
+
returned.push(validateSchema(type));
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return returned;
|
|
5
24
|
}
|
|
6
25
|
const types = /* @__PURE__ */ new Set([
|
|
7
26
|
"array",
|
|
8
27
|
"bigint",
|
|
9
28
|
"boolean",
|
|
10
29
|
"date",
|
|
30
|
+
"date-like",
|
|
11
31
|
"function",
|
|
12
32
|
"null",
|
|
13
33
|
"number",
|
|
34
|
+
"numerical",
|
|
14
35
|
"object",
|
|
15
36
|
"string",
|
|
16
37
|
"symbol",
|
package/dist/is.cjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
|
|
5
|
+
function isDateLike(value) {
|
|
6
|
+
if (value instanceof Date) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
if (typeof value === "number") {
|
|
10
|
+
return value >= -864e13 && value <= 864e13;
|
|
11
|
+
}
|
|
12
|
+
return typeof value === "string" && !Number.isNaN(Date.parse(value));
|
|
13
|
+
}
|
|
14
|
+
function isSchematic(value) {
|
|
15
|
+
return typeof value === "object" && value !== null && "$schematic" in value && value.$schematic === true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
exports.isDateLike = isDateLike;
|
|
19
|
+
exports.isSchematic = isSchematic;
|
package/dist/is.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
function isDateLike(value) {
|
|
2
|
+
if (value instanceof Date) {
|
|
3
|
+
return true;
|
|
4
|
+
}
|
|
5
|
+
if (typeof value === "number") {
|
|
6
|
+
return value >= -864e13 && value <= 864e13;
|
|
7
|
+
}
|
|
8
|
+
return typeof value === "string" && !Number.isNaN(Date.parse(value));
|
|
9
|
+
}
|
|
10
|
+
function isSchematic(value) {
|
|
11
|
+
return typeof value === "object" && value !== null && "$schematic" in value && value.$schematic === true;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { isDateLike, isSchematic };
|
package/dist/schematic.cjs
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const validation_schema_validation = require('./validation/schema.validation.cjs');
|
|
6
|
+
const validation_value_validation = require('./validation/value.validation.cjs');
|
|
6
7
|
|
|
7
8
|
function schematic(schema) {
|
|
8
|
-
const validated =
|
|
9
|
+
const validated = validation_schema_validation.validateSchema(schema);
|
|
9
10
|
const canValidate = validated.length > 0;
|
|
10
11
|
return Object.freeze({
|
|
11
|
-
|
|
12
|
+
$schematic: true,
|
|
13
|
+
is: (value) => canValidate && validation_value_validation.validateValue(validated, value)
|
|
12
14
|
});
|
|
13
15
|
}
|
|
14
16
|
|
package/dist/schematic.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { validateSchema } from './validation/schema.validation.js';
|
|
2
|
+
import { validateValue } from './validation/value.validation.js';
|
|
2
3
|
|
|
3
4
|
function schematic(schema) {
|
|
4
|
-
const validated =
|
|
5
|
+
const validated = validateSchema(schema);
|
|
5
6
|
const canValidate = validated.length > 0;
|
|
6
7
|
return Object.freeze({
|
|
7
|
-
|
|
8
|
+
$schematic: true,
|
|
9
|
+
is: (value) => canValidate && validateValue(validated, value)
|
|
8
10
|
});
|
|
9
11
|
}
|
|
10
12
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
|
|
5
|
+
const helpers = require('../helpers.cjs');
|
|
6
|
+
|
|
7
|
+
function validateSchema(schema) {
|
|
8
|
+
if (validatedSchemas.has(schema)) {
|
|
9
|
+
return validatedSchemas.get(schema);
|
|
10
|
+
}
|
|
11
|
+
const validated = {
|
|
12
|
+
keys: [],
|
|
13
|
+
length: 0,
|
|
14
|
+
properties: {}
|
|
15
|
+
};
|
|
16
|
+
if (typeof schema !== "object" || schema === null) {
|
|
17
|
+
return validated;
|
|
18
|
+
}
|
|
19
|
+
const keys = Object.keys(schema);
|
|
20
|
+
const { length } = keys;
|
|
21
|
+
for (let index = 0; index < length; index += 1) {
|
|
22
|
+
const key = keys[index];
|
|
23
|
+
const value = schema[key];
|
|
24
|
+
let required = true;
|
|
25
|
+
let types;
|
|
26
|
+
if (Array.isArray(value)) {
|
|
27
|
+
types = helpers.getTypes(value);
|
|
28
|
+
} else if (typeof value === "object" && value !== null) {
|
|
29
|
+
if (typeof value.required === "boolean") {
|
|
30
|
+
required = value.required;
|
|
31
|
+
}
|
|
32
|
+
types = helpers.getTypes(value.type);
|
|
33
|
+
} else {
|
|
34
|
+
types = helpers.getTypes(value);
|
|
35
|
+
}
|
|
36
|
+
if (types.length > 0) {
|
|
37
|
+
if (!required && !types.includes("undefined")) {
|
|
38
|
+
types.push("undefined");
|
|
39
|
+
}
|
|
40
|
+
validated.keys.push(key);
|
|
41
|
+
validated.properties[key] = {
|
|
42
|
+
required,
|
|
43
|
+
types
|
|
44
|
+
};
|
|
45
|
+
validated.length += 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
validatedSchemas.set(schema, validated);
|
|
49
|
+
return validated;
|
|
50
|
+
}
|
|
51
|
+
const validatedSchemas = /* @__PURE__ */ new WeakMap();
|
|
52
|
+
|
|
53
|
+
exports.validateSchema = validateSchema;
|
|
54
|
+
exports.validatedSchemas = validatedSchemas;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { getTypes } from '../helpers.js';
|
|
2
|
+
|
|
3
|
+
function validateSchema(schema) {
|
|
4
|
+
if (validatedSchemas.has(schema)) {
|
|
5
|
+
return validatedSchemas.get(schema);
|
|
6
|
+
}
|
|
7
|
+
const validated = {
|
|
8
|
+
keys: [],
|
|
9
|
+
length: 0,
|
|
10
|
+
properties: {}
|
|
11
|
+
};
|
|
12
|
+
if (typeof schema !== "object" || schema === null) {
|
|
13
|
+
return validated;
|
|
14
|
+
}
|
|
15
|
+
const keys = Object.keys(schema);
|
|
16
|
+
const { length } = keys;
|
|
17
|
+
for (let index = 0; index < length; index += 1) {
|
|
18
|
+
const key = keys[index];
|
|
19
|
+
const value = schema[key];
|
|
20
|
+
let required = true;
|
|
21
|
+
let types;
|
|
22
|
+
if (Array.isArray(value)) {
|
|
23
|
+
types = getTypes(value);
|
|
24
|
+
} else if (typeof value === "object" && value !== null) {
|
|
25
|
+
if (typeof value.required === "boolean") {
|
|
26
|
+
required = value.required;
|
|
27
|
+
}
|
|
28
|
+
types = getTypes(value.type);
|
|
29
|
+
} else {
|
|
30
|
+
types = getTypes(value);
|
|
31
|
+
}
|
|
32
|
+
if (types.length > 0) {
|
|
33
|
+
if (!required && !types.includes("undefined")) {
|
|
34
|
+
types.push("undefined");
|
|
35
|
+
}
|
|
36
|
+
validated.keys.push(key);
|
|
37
|
+
validated.properties[key] = {
|
|
38
|
+
required,
|
|
39
|
+
types
|
|
40
|
+
};
|
|
41
|
+
validated.length += 1;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
validatedSchemas.set(schema, validated);
|
|
45
|
+
return validated;
|
|
46
|
+
}
|
|
47
|
+
const validatedSchemas = /* @__PURE__ */ new WeakMap();
|
|
48
|
+
|
|
49
|
+
export { validateSchema, validatedSchemas };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
|
|
5
|
+
const is = require('../is.cjs');
|
|
6
|
+
const validation_value_validation = require('./value.validation.cjs');
|
|
7
|
+
|
|
8
|
+
function validateType(type, value) {
|
|
9
|
+
if (typeof type === "string") {
|
|
10
|
+
return validators[type](value);
|
|
11
|
+
}
|
|
12
|
+
if (is.isSchematic(type)) {
|
|
13
|
+
return type.is(value);
|
|
14
|
+
}
|
|
15
|
+
return validation_value_validation.validateValue(type, value);
|
|
16
|
+
}
|
|
17
|
+
const validators = {
|
|
18
|
+
array: Array.isArray,
|
|
19
|
+
bigint: (value) => typeof value === "bigint",
|
|
20
|
+
boolean: (value) => typeof value === "boolean",
|
|
21
|
+
date: (value) => value instanceof Date,
|
|
22
|
+
"date-like": is.isDateLike,
|
|
23
|
+
function: (value) => typeof value === "function",
|
|
24
|
+
null: (value) => value === null,
|
|
25
|
+
number: (value) => typeof value === "number",
|
|
26
|
+
numerical: (value) => validators.bigint(value) || validators.number(value),
|
|
27
|
+
object: (value) => typeof value === "object" && value !== null,
|
|
28
|
+
string: (value) => typeof value === "string",
|
|
29
|
+
symbol: (value) => typeof value === "symbol",
|
|
30
|
+
undefined: (value) => value === void 0
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
exports.validateType = validateType;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { isDateLike, isSchematic } from '../is.js';
|
|
2
|
+
import { validateValue } from './value.validation.js';
|
|
3
|
+
|
|
4
|
+
function validateType(type, value) {
|
|
5
|
+
if (typeof type === "string") {
|
|
6
|
+
return validators[type](value);
|
|
7
|
+
}
|
|
8
|
+
if (isSchematic(type)) {
|
|
9
|
+
return type.is(value);
|
|
10
|
+
}
|
|
11
|
+
return validateValue(type, value);
|
|
12
|
+
}
|
|
13
|
+
const validators = {
|
|
14
|
+
array: Array.isArray,
|
|
15
|
+
bigint: (value) => typeof value === "bigint",
|
|
16
|
+
boolean: (value) => typeof value === "boolean",
|
|
17
|
+
date: (value) => value instanceof Date,
|
|
18
|
+
"date-like": isDateLike,
|
|
19
|
+
function: (value) => typeof value === "function",
|
|
20
|
+
null: (value) => value === null,
|
|
21
|
+
number: (value) => typeof value === "number",
|
|
22
|
+
numerical: (value) => validators.bigint(value) || validators.number(value),
|
|
23
|
+
object: (value) => typeof value === "object" && value !== null,
|
|
24
|
+
string: (value) => typeof value === "string",
|
|
25
|
+
symbol: (value) => typeof value === "symbol",
|
|
26
|
+
undefined: (value) => value === void 0
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export { validateType };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
|
|
5
|
+
const validation_type_validation = require('./type.validation.cjs');
|
|
6
|
+
|
|
7
|
+
function validateValue(validated, obj) {
|
|
8
|
+
if (typeof obj !== "object" || obj === null) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
outer: for (let keyIndex = 0; keyIndex < validated.length; keyIndex += 1) {
|
|
12
|
+
const key = validated.keys[keyIndex];
|
|
13
|
+
const property = validated.properties[key];
|
|
14
|
+
const value = obj[key];
|
|
15
|
+
if (value === void 0 && property.required && !property.types.includes("undefined")) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
const typesLength = property.types.length;
|
|
19
|
+
if (typesLength === 1) {
|
|
20
|
+
if (!validation_type_validation.validateType(property.types[0], value)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
|
|
26
|
+
if (validation_type_validation.validateType(property.types[typeIndex], value)) {
|
|
27
|
+
continue outer;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
exports.validateValue = validateValue;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { validateType } from './type.validation.js';
|
|
2
|
+
|
|
3
|
+
function validateValue(validated, obj) {
|
|
4
|
+
if (typeof obj !== "object" || obj === null) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
outer: for (let keyIndex = 0; keyIndex < validated.length; keyIndex += 1) {
|
|
8
|
+
const key = validated.keys[keyIndex];
|
|
9
|
+
const property = validated.properties[key];
|
|
10
|
+
const value = obj[key];
|
|
11
|
+
if (value === void 0 && property.required && !property.types.includes("undefined")) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
const typesLength = property.types.length;
|
|
15
|
+
if (typesLength === 1) {
|
|
16
|
+
if (!validateType(property.types[0], value)) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
|
|
22
|
+
if (validateType(property.types[typeIndex], value)) {
|
|
23
|
+
continue outer;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { validateValue };
|
package/package.json
CHANGED
package/src/helpers.ts
CHANGED
|
@@ -1,9 +1,35 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {isSchematic} from './is';
|
|
2
|
+
import type {ValidatedPropertyType, Values} from './model';
|
|
3
|
+
import {validateSchema} from './validation/schema.validation';
|
|
2
4
|
|
|
3
|
-
export function getTypes(value: unknown):
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export function getTypes(value: unknown): ValidatedPropertyType[] {
|
|
6
|
+
const returned: ValidatedPropertyType[] = [];
|
|
7
|
+
const values = Array.isArray(value) ? value : [value];
|
|
8
|
+
const {length} = values;
|
|
9
|
+
|
|
10
|
+
for (let index = 0; index < length; index += 1) {
|
|
11
|
+
const type = values[index];
|
|
12
|
+
|
|
13
|
+
switch (true) {
|
|
14
|
+
case isSchematic(type):
|
|
15
|
+
returned.push(type);
|
|
16
|
+
break;
|
|
17
|
+
|
|
18
|
+
case typeof type === 'string' && types.has(type as never):
|
|
19
|
+
returned.push(type as never);
|
|
20
|
+
break;
|
|
21
|
+
|
|
22
|
+
case typeof type === 'object' && type !== null: {
|
|
23
|
+
returned.push(validateSchema(type));
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
default:
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return returned;
|
|
7
33
|
}
|
|
8
34
|
|
|
9
35
|
const types = new Set<keyof Values>([
|
|
@@ -11,9 +37,11 @@ const types = new Set<keyof Values>([
|
|
|
11
37
|
'bigint',
|
|
12
38
|
'boolean',
|
|
13
39
|
'date',
|
|
40
|
+
'date-like',
|
|
14
41
|
'function',
|
|
15
42
|
'null',
|
|
16
43
|
'number',
|
|
44
|
+
'numerical',
|
|
17
45
|
'object',
|
|
18
46
|
'string',
|
|
19
47
|
'symbol',
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type {Schema, Schematic} from './model';
|
|
1
|
+
export type {Schema, Schematic, TypedSchema} from './model';
|
|
2
2
|
export * from './schematic';
|
package/src/is.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type {Schematic} from './model';
|
|
2
|
+
|
|
3
|
+
export function isDateLike(value: unknown): value is Date {
|
|
4
|
+
if (value instanceof Date) {
|
|
5
|
+
return true;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (typeof value === 'number') {
|
|
9
|
+
return value >= -8_640e12 && value <= 8_640e12;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return typeof value === 'string' && !Number.isNaN(Date.parse(value));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function isSchematic(value: unknown): value is Schematic<never> {
|
|
16
|
+
return (
|
|
17
|
+
typeof value === 'object' &&
|
|
18
|
+
value !== null &&
|
|
19
|
+
'$schematic' in value &&
|
|
20
|
+
value.$schematic === true
|
|
21
|
+
);
|
|
22
|
+
}
|
package/src/model.ts
CHANGED
|
@@ -5,39 +5,63 @@ import type {
|
|
|
5
5
|
UnionToTuple,
|
|
6
6
|
} from 'type-fest';
|
|
7
7
|
|
|
8
|
+
export type AutoInferExclude = 'date-like' | 'numerical';
|
|
9
|
+
|
|
8
10
|
export type GetKey<Value> = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
[Key in Exclude<ValueKey, AutoInferExclude>]: Value extends Values[Key]
|
|
12
|
+
? Key
|
|
13
|
+
: never;
|
|
14
|
+
}[Exclude<ValueKey, AutoInferExclude>] extends infer SpecificKey
|
|
15
|
+
? SpecificKey extends never
|
|
16
|
+
? {
|
|
17
|
+
[Key in AutoInferExclude]: Value extends Values[Key] ? Key : never;
|
|
18
|
+
}[AutoInferExclude]
|
|
19
|
+
: SpecificKey
|
|
20
|
+
: never;
|
|
11
21
|
|
|
12
|
-
export type GetTypes<Value extends unknown[]> = Value extends [infer
|
|
13
|
-
?
|
|
22
|
+
export type GetTypes<Value extends unknown[]> = Value extends [infer Type]
|
|
23
|
+
? Type
|
|
14
24
|
: Value;
|
|
15
25
|
|
|
16
26
|
export type GetType<Value> = GetTypes<UnionToTuple<GetKey<Value>>>;
|
|
17
27
|
|
|
18
28
|
export type InferProperty<Value> = Value extends Property
|
|
19
|
-
? Value['type']
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
? InferPropertyType<Value['type']>
|
|
30
|
+
: never;
|
|
31
|
+
|
|
32
|
+
type InferPropertyType<Value> = Value extends (infer Type)[]
|
|
33
|
+
? InferPropertyTypeValue<Type>[]
|
|
34
|
+
: InferPropertyTypeValue<Value>;
|
|
35
|
+
|
|
36
|
+
type InferPropertyTypeValue<Value> = Value extends PropertyType
|
|
37
|
+
? Value extends Schema
|
|
38
|
+
? Inferred<Value>
|
|
39
|
+
: Value extends Schematic<infer Model>
|
|
40
|
+
? Model
|
|
41
|
+
: Value extends ValueKey
|
|
42
|
+
? Values[Value]
|
|
43
|
+
: Value extends (infer NestedElementType)[]
|
|
44
|
+
? InferPropertyTypeValue<NestedElementType>[]
|
|
45
|
+
: Value
|
|
24
46
|
: never;
|
|
25
47
|
|
|
26
|
-
export type InferValue<Value> = Value extends
|
|
48
|
+
export type InferValue<Value> = Value extends ValueKey
|
|
27
49
|
? Values[Value]
|
|
28
|
-
: Value extends
|
|
50
|
+
: Value extends ValueKey[]
|
|
29
51
|
? Values[Value[number]]
|
|
30
52
|
: never;
|
|
31
53
|
|
|
32
|
-
export type Inferred<Model extends Schema> =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
54
|
+
export type Inferred<Model extends Schema> = Simplify<
|
|
55
|
+
{
|
|
56
|
+
[Key in InferredRequiredProperties<Model>]: Model[Key] extends Property
|
|
57
|
+
? InferProperty<Model[Key]>
|
|
58
|
+
: InferValue<Model[Key]>;
|
|
59
|
+
} & {
|
|
60
|
+
[Key in InferredOptionalProperties<Model>]?: Model[Key] extends Property
|
|
61
|
+
? InferProperty<Model[Key]>
|
|
62
|
+
: never;
|
|
63
|
+
}
|
|
64
|
+
>;
|
|
41
65
|
|
|
42
66
|
export type InferredOptionalProperties<Model extends Schema> = {
|
|
43
67
|
[Key in keyof Model]: Model[Key] extends Property
|
|
@@ -61,9 +85,11 @@ export type OptionalProperty<Type> = {
|
|
|
61
85
|
};
|
|
62
86
|
|
|
63
87
|
export type Property = {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
};
|
|
88
|
+
required?: boolean;
|
|
89
|
+
type: PropertyType | PropertyType[];
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
type PropertyType = Schema | Schematic<unknown> | ValueKey;
|
|
67
93
|
|
|
68
94
|
export type RequiredProperty<Type> = {
|
|
69
95
|
required: true;
|
|
@@ -73,7 +99,9 @@ export type RequiredProperty<Type> = {
|
|
|
73
99
|
/**
|
|
74
100
|
* A schema for validating objects
|
|
75
101
|
*/
|
|
76
|
-
export type Schema =
|
|
102
|
+
export type Schema = {
|
|
103
|
+
[key: string]: Property | ValueKey | ValueKey[];
|
|
104
|
+
};
|
|
77
105
|
|
|
78
106
|
/**
|
|
79
107
|
* A schematic for validating objects
|
|
@@ -101,27 +129,40 @@ export type TypedSchema<Model extends Typed> = Simplify<
|
|
|
101
129
|
>;
|
|
102
130
|
|
|
103
131
|
export type ValidatedProperty = {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
};
|
|
132
|
+
required: boolean;
|
|
133
|
+
types: ValidatedPropertyType[];
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export type ValidatedPropertyType =
|
|
137
|
+
| Schematic<unknown>
|
|
138
|
+
| ValidatedSchema
|
|
139
|
+
| ValueKey;
|
|
107
140
|
|
|
108
141
|
export type ValidatedSchema = {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
142
|
+
keys: string[];
|
|
143
|
+
length: number;
|
|
144
|
+
properties: ValidatedSchemaProperties;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
type ValidatedSchemaProperties = {
|
|
148
|
+
[key: string]: ValidatedProperty;
|
|
112
149
|
};
|
|
113
150
|
|
|
151
|
+
export type ValueKey = keyof Values;
|
|
152
|
+
|
|
114
153
|
export type Values = {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
154
|
+
array: unknown[];
|
|
155
|
+
bigint: bigint;
|
|
156
|
+
boolean: boolean;
|
|
157
|
+
date: Date;
|
|
158
|
+
'date-like': number | string | Date;
|
|
159
|
+
// biome-ignore lint/complexity/noBannedTypes: it's the most basic value type, so I think it's ok
|
|
160
|
+
function: Function;
|
|
161
|
+
null: null;
|
|
162
|
+
number: number;
|
|
163
|
+
numerical: bigint | number;
|
|
164
|
+
object: object;
|
|
165
|
+
string: string;
|
|
166
|
+
symbol: symbol;
|
|
167
|
+
undefined: undefined;
|
|
168
|
+
};
|