@afora/core 0.0.8 → 0.0.11
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 +149 -23
- package/dist/adapters.d.ts +25 -0
- package/dist/adapters.js +32 -0
- package/dist/core/application/application.d.ts +30 -0
- package/dist/core/application/application.js +1291 -0
- package/dist/core/application/exceptions.d.ts +17 -0
- package/dist/core/application/exceptions.js +85 -0
- package/dist/core/application/migrate.d.ts +19 -0
- package/dist/core/application/migrate.js +67 -0
- package/dist/core/application/providers.js +108 -0
- package/dist/core/application/registry.js +23 -0
- package/dist/core/application/schema.d.ts +30 -0
- package/dist/core/application/schema.js +398 -0
- package/dist/core/application/start.js +162 -0
- package/dist/core/application/types/application.interface.d.ts +60 -3
- package/dist/core/auth/jwt.d.ts +30 -0
- package/dist/core/auth/jwt.js +200 -0
- package/dist/core/auth/types/jwt.interface.d.ts +74 -0
- package/dist/core/blueprint/blueprint-plugin.js +7 -0
- package/dist/core/blueprint/blueprint.js +146 -0
- package/dist/core/blueprint/callable.js +13 -0
- package/dist/core/blueprint/exceptions.d.ts +5 -0
- package/dist/core/blueprint/exceptions.js +20 -0
- package/dist/core/blueprint/is-blueprint.js +4 -0
- package/dist/core/blueprint/list.js +19 -0
- package/dist/core/blueprint/optional.d.ts +3 -1
- package/dist/core/blueprint/optional.js +69 -0
- package/dist/core/blueprint/record-field.js +14 -0
- package/dist/core/blueprint/slice.js +127 -0
- package/dist/core/blueprint/types/blueprint.interface.d.ts +95 -5
- package/dist/core/blueprint/variant.d.ts +32 -0
- package/dist/core/blueprint/variant.js +72 -0
- package/dist/core/command/command.js +428 -0
- package/dist/core/command/exceptions.js +30 -0
- package/dist/core/command/types/command.interface.d.ts +10 -1
- package/dist/core/entity/abstract-entity.d.ts +24 -0
- package/dist/core/entity/abstract-entity.js +181 -0
- package/dist/core/entity/entity.d.ts +1 -1
- package/dist/core/entity/entity.js +209 -0
- package/dist/core/entity/event.d.ts +39 -0
- package/dist/core/entity/event.js +80 -0
- package/dist/core/entity/exceptions.d.ts +9 -0
- package/dist/core/entity/exceptions.js +27 -0
- package/dist/core/entity/trust.d.ts +24 -0
- package/dist/core/entity/trust.js +7 -0
- package/dist/core/entity/types/entity.interface.d.ts +30 -0
- package/dist/core/entity/version.js +13 -0
- package/dist/core/environment/environment.d.ts +26 -3
- package/dist/core/environment/environment.js +71 -0
- package/dist/core/event-policy/event-policy.js +76 -0
- package/dist/core/event-policy/exceptions.js +12 -0
- package/dist/core/event-policy/publish.js +98 -0
- package/dist/core/event-policy/publishers.js +18 -0
- package/dist/core/event-policy/types/event-policy.interface.d.ts +8 -2
- package/dist/core/exception/enums/exception-layers.js +15 -0
- package/dist/core/exception/exception.d.ts +15 -0
- package/dist/core/exception/exception.js +128 -0
- package/dist/core/exception/exported.js +49 -0
- package/dist/core/exception/guard.d.ts +20 -1
- package/dist/core/exception/guard.js +16 -0
- package/dist/core/exception/types/exception.interface.d.ts +13 -0
- package/dist/core/json.js +19 -0
- package/dist/core/logger/exceptions.js +7 -0
- package/dist/core/logger/logger.d.ts +14 -1
- package/dist/core/logger/logger.js +178 -0
- package/dist/core/openapi/exceptions.js +7 -0
- package/dist/core/openapi/openapi.js +132 -0
- package/dist/core/openapi/types/openapi.interface.d.ts +7 -1
- package/dist/core/output/access.d.ts +16 -0
- package/dist/core/output/access.js +66 -0
- package/dist/core/output/coerce.js +38 -0
- package/dist/core/output/exceptions.d.ts +16 -0
- package/dist/core/output/exceptions.js +22 -0
- package/dist/core/output/http.d.ts +36 -0
- package/dist/core/output/http.js +351 -0
- package/dist/core/output/openapi-sink.d.ts +33 -4
- package/dist/core/output/openapi-sink.js +571 -0
- package/dist/core/output/output.js +192 -0
- package/dist/core/output/problem.js +30 -0
- package/dist/core/output/select.js +28 -0
- package/dist/core/output/stage.d.ts +7 -2
- package/dist/core/output/stage.js +111 -0
- package/dist/core/output/status.d.ts +1 -1
- package/dist/core/output/status.js +52 -0
- package/dist/core/output/types/http.interface.d.ts +134 -0
- package/dist/core/output/types/output.interface.d.ts +49 -5
- package/dist/core/parse/issue.d.ts +28 -3
- package/dist/core/parse/issue.js +31 -0
- package/dist/core/parse/parse.d.ts +16 -0
- package/dist/core/parse/parse.js +323 -0
- package/dist/core/parse/strip.js +48 -0
- package/dist/core/property/abstract-property.d.ts +9 -0
- package/dist/core/property/abstract-property.js +37 -0
- package/dist/core/property/define-property.d.ts +34 -6
- package/dist/core/property/define-property.js +209 -0
- package/dist/core/property/enums/property-states.js +8 -0
- package/dist/core/property/exceptions.js +12 -0
- package/dist/core/property/input.js +10 -0
- package/dist/core/property/is-property.js +3 -0
- package/dist/core/property/lineage.js +8 -0
- package/dist/core/property/property.d.ts +27 -0
- package/dist/core/property/property.js +46 -0
- package/dist/core/property/refine.js +103 -0
- package/dist/core/property/types/property-options.interface.d.ts +10 -0
- package/dist/core/property/types/property-type.interface.d.ts +4 -0
- package/dist/core/record/abstract-record.d.ts +8 -0
- package/dist/core/record/abstract-record.js +307 -0
- package/dist/core/record/exceptions.js +49 -0
- package/dist/core/record/marks.js +7 -0
- package/dist/core/record/mask.js +60 -0
- package/dist/core/record/name.js +23 -0
- package/dist/core/record/plugin-catalog.js +115 -0
- package/dist/core/record/plugin.js +198 -0
- package/dist/core/record/record.js +117 -0
- package/dist/core/record/types/record.interface.d.ts +17 -1
- package/dist/core/repository/cursor.js +83 -0
- package/dist/core/repository/exceptions.d.ts +13 -0
- package/dist/core/repository/exceptions.js +72 -0
- package/dist/core/repository/in-memory.d.ts +2 -2
- package/dist/core/repository/in-memory.js +196 -0
- package/dist/core/repository/migrate.d.ts +20 -0
- package/dist/core/repository/migrate.js +254 -0
- package/dist/core/repository/plan.js +27 -0
- package/dist/core/repository/provider.js +29 -0
- package/dist/core/repository/query.js +153 -0
- package/dist/core/repository/references.js +196 -0
- package/dist/core/repository/repository.d.ts +22 -2
- package/dist/core/repository/repository.js +720 -0
- package/dist/core/repository/state.d.ts +2 -0
- package/dist/core/repository/state.js +138 -0
- package/dist/core/repository/types/query.interface.d.ts +13 -0
- package/dist/core/repository/types/repository.interface.d.ts +50 -5
- package/dist/core/repository/types/schema.interface.d.ts +132 -0
- package/dist/core/repository/upcast.d.ts +64 -0
- package/dist/core/repository/upcast.js +179 -0
- package/dist/core/schema/schema.d.ts +37 -0
- package/dist/core/schema/schema.js +542 -0
- package/dist/core/standard/standard-schema.js +1 -0
- package/dist/core/standard/standard.js +23 -0
- package/dist/core/symbols/demo.d.ts +4 -0
- package/dist/core/symbols/demo.js +1 -0
- package/dist/core/symbols/kind.d.ts +1 -1
- package/dist/core/symbols/kind.js +1 -0
- package/dist/core/symbols/meta.js +1 -0
- package/dist/core/symbols/state.d.ts +5 -0
- package/dist/core/symbols/state.js +1 -0
- package/dist/core/tracing/exceptions.d.ts +4 -0
- package/dist/core/tracing/exceptions.js +7 -0
- package/dist/core/tracing/tracing.d.ts +72 -0
- package/dist/core/tracing/tracing.js +101 -0
- package/dist/core/use-case/access.d.ts +12 -0
- package/dist/core/use-case/access.js +56 -0
- package/dist/core/use-case/decorators.d.ts +40 -0
- package/dist/core/use-case/decorators.js +65 -0
- package/dist/core/use-case/exceptions.d.ts +5 -1
- package/dist/core/use-case/exceptions.js +48 -0
- package/dist/core/use-case/plugin-catalog.js +68 -0
- package/dist/core/use-case/plugin.js +133 -0
- package/dist/core/use-case/route.d.ts +18 -0
- package/dist/core/use-case/route.js +200 -0
- package/dist/core/use-case/scope.d.ts +5 -0
- package/dist/core/use-case/scope.js +4 -0
- package/dist/core/use-case/steps/describe.d.ts +5 -1
- package/dist/core/use-case/steps/describe.js +24 -0
- package/dist/core/use-case/steps/references.js +105 -0
- package/dist/core/use-case/steps/run.js +139 -0
- package/dist/core/use-case/steps/types/check.interface.d.ts +233 -0
- package/dist/core/use-case/steps/types/steps.interface.d.ts +8 -1
- package/dist/core/use-case/steps/validate.js +368 -0
- package/dist/core/use-case/target.js +100 -0
- package/dist/core/use-case/types/access.interface.d.ts +39 -0
- package/dist/core/use-case/types/route.interface.d.ts +86 -0
- package/dist/core/use-case/use-case.d.ts +127 -2
- package/dist/core/use-case/use-case.js +493 -0
- package/dist/experimental.d.ts +18 -1
- package/dist/experimental.js +18 -123
- package/dist/index.d.ts +49 -51
- package/dist/index.js +213 -443
- package/dist/std/blueprint-plugin.js +42 -0
- package/dist/std/blueprint.d.ts +21 -0
- package/dist/std/blueprint.js +3 -0
- package/dist/std/command.js +3 -0
- package/dist/std/entity.d.ts +20 -1
- package/dist/std/entity.js +30 -0
- package/dist/std/event-policies.js +3 -0
- package/dist/std/properties/contact.d.ts +3 -0
- package/dist/std/properties/contact.js +29 -0
- package/dist/std/properties/enum.js +26 -0
- package/dist/std/properties/exceptions.js +14 -0
- package/dist/std/properties/headless.js +45 -0
- package/dist/std/properties/identity.js +28 -0
- package/dist/std/properties/json.js +161 -0
- package/dist/std/properties/password.d.ts +0 -2
- package/dist/std/properties/password.js +79 -0
- package/dist/std/properties/primitives.d.ts +4 -0
- package/dist/std/properties/primitives.js +28 -0
- package/dist/std/properties/time.js +55 -0
- package/dist/std/record-plugins.d.ts +2 -2
- package/dist/std/record-plugins.js +73 -0
- package/dist/std/record.d.ts +20 -1
- package/dist/std/record.js +3 -0
- package/dist/std/resource.d.ts +31 -0
- package/dist/std/resource.js +39 -0
- package/dist/std/runtime.d.ts +6 -0
- package/dist/std/runtime.js +193 -0
- package/dist/std/stages.js +4 -0
- package/dist/std/use-cases/auth.d.ts +5 -1
- package/dist/std/use-cases/auth.js +193 -0
- package/dist/std/use-cases/crud.js +261 -0
- package/dist/std/use-cases/index.d.ts +1 -1
- package/dist/std/use-cases/index.js +12 -0
- package/dist/std/use-cases/lifecycle.js +97 -0
- package/dist/std/use-cases/shared.d.ts +2 -2
- package/dist/std/use-cases/shared.js +232 -0
- package/dist/std/use-cases/types.d.ts +102 -2
- package/dist/std/use-cases/types.js +0 -0
- package/dist/testing/http-provider-contract.d.ts +32 -0
- package/dist/testing/http-provider-contract.js +344 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +3 -944
- package/dist/testing/memory-publisher.js +12 -0
- package/dist/testing/provider-contract.d.ts +26 -1
- package/dist/testing/provider-contract.js +1071 -0
- package/package.json +23 -3
- package/dist/index-qxfkyd6k.js +0 -1721
- package/dist/index-t5qwtyj5.js +0 -8194
|
@@ -5,6 +5,43 @@ export declare function describeError(error: {
|
|
|
5
5
|
instancePath: string;
|
|
6
6
|
message: string;
|
|
7
7
|
}): string;
|
|
8
|
+
/** One TypeBox error, as `Errors` gives it. */
|
|
9
|
+
export interface SchemaError {
|
|
10
|
+
readonly keyword: string;
|
|
11
|
+
readonly schemaPath: string;
|
|
12
|
+
readonly instancePath: string;
|
|
13
|
+
readonly params: object;
|
|
14
|
+
readonly message: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The errors of `value`, which `schema` rejects. For every schema but one
|
|
18
|
+
* they are what `schema.type.Errors(value)` gives: same errors, same order,
|
|
19
|
+
* same messages. The one is a discriminated union given an object, told by
|
|
20
|
+
* the variant its key names (see `errorsOfVariant`). TypeBox is only asked
|
|
21
|
+
* about a schema with a keyword that has no explanation here (`explainerOf`).
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
export declare function errorsOfSchema(schema: ISchema<TSchema>, value: unknown): readonly SchemaError[];
|
|
25
|
+
/** The two checks of a schema, as functions. */
|
|
26
|
+
export interface SchemaChecks {
|
|
27
|
+
match(value: unknown): boolean;
|
|
28
|
+
matchShape(value: unknown): boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* `schema.match` and `schema.matchShape`, compiled now, for who checks many
|
|
32
|
+
* values with one schema; those of a schema not made by `schemaOf` call it.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
export declare function checksOfSchema(schema: ISchema<TSchema>): SchemaChecks;
|
|
36
|
+
/**
|
|
37
|
+
* The TypeBox schema of `schema`, as it was given, without compiling it:
|
|
38
|
+
* `schema.type.Type()` gives the same schema but compiles it first, which is
|
|
39
|
+
* most of the time spent at import when only the schema is read (the
|
|
40
|
+
* meta-schema of `ctx.schema` alone takes milliseconds). A schema not made
|
|
41
|
+
* by `schemaOf` is asked through `type`.
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
export declare function rawTypeOf<SchemaType extends TSchema>(schema: ISchema<SchemaType>): SchemaType;
|
|
8
45
|
/** A schema class declared with `schemaOf`. */
|
|
9
46
|
export interface SchemaClass<SchemaType extends TSchema> {
|
|
10
47
|
new (type?: SchemaType): ISchema<SchemaType>;
|
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
import Compile from "typebox/compile";
|
|
2
|
+
import { Locale, Settings } from "typebox/system";
|
|
3
|
+
const KEPT_KEYWORDS = new Set([
|
|
4
|
+
"type",
|
|
5
|
+
"required",
|
|
6
|
+
"$ref",
|
|
7
|
+
"$id",
|
|
8
|
+
"$anchor",
|
|
9
|
+
"$dynamicRef",
|
|
10
|
+
"$dynamicAnchor"
|
|
11
|
+
]);
|
|
12
|
+
const SCHEMA_KEYWORDS = new Set([
|
|
13
|
+
"additionalProperties",
|
|
14
|
+
"items",
|
|
15
|
+
"additionalItems",
|
|
16
|
+
"prefixItems",
|
|
17
|
+
"anyOf",
|
|
18
|
+
"oneOf",
|
|
19
|
+
"allOf",
|
|
20
|
+
"contains",
|
|
21
|
+
"propertyNames"
|
|
22
|
+
]);
|
|
23
|
+
const SCHEMA_MAP_KEYWORDS = new Set([
|
|
24
|
+
"properties",
|
|
25
|
+
"patternProperties",
|
|
26
|
+
"dependentSchemas",
|
|
27
|
+
"$defs",
|
|
28
|
+
"definitions"
|
|
29
|
+
]);
|
|
30
|
+
const JSON_TYPES = new Set([
|
|
31
|
+
"null",
|
|
32
|
+
"array",
|
|
33
|
+
"string",
|
|
34
|
+
"number",
|
|
35
|
+
"boolean",
|
|
36
|
+
"object"
|
|
37
|
+
]);
|
|
38
|
+
function typeOfValue(value) {
|
|
39
|
+
const type = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
40
|
+
return JSON_TYPES.has(type) ? type : undefined;
|
|
41
|
+
}
|
|
42
|
+
function shapeOf(schema) {
|
|
43
|
+
if (Array.isArray(schema))
|
|
44
|
+
return schema.map(shapeOf);
|
|
45
|
+
if (typeof schema !== "object" || schema === null)
|
|
46
|
+
return schema;
|
|
47
|
+
const shape = {};
|
|
48
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
49
|
+
if (KEPT_KEYWORDS.has(key))
|
|
50
|
+
shape[key] = value;
|
|
51
|
+
else if (SCHEMA_KEYWORDS.has(key))
|
|
52
|
+
shape[key] = shapeOf(value);
|
|
53
|
+
else if (SCHEMA_MAP_KEYWORDS.has(key)) {
|
|
54
|
+
shape[key] = Object.fromEntries(Object.entries(value).map(([name, item]) => [
|
|
55
|
+
name,
|
|
56
|
+
shapeOf(item)
|
|
57
|
+
]));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!("type" in shape)) {
|
|
61
|
+
const values = "const" in schema ? [schema.const] : schema.enum;
|
|
62
|
+
if (Array.isArray(values)) {
|
|
63
|
+
const types = values.map(typeOfValue);
|
|
64
|
+
if (types.every((type) => type !== undefined)) {
|
|
65
|
+
shape.type = [...new Set(types)];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return shape;
|
|
70
|
+
}
|
|
71
|
+
export function describeError(error) {
|
|
72
|
+
return `${error.instancePath || "/"}: ${error.message}`;
|
|
73
|
+
}
|
|
74
|
+
const INERT_KEYWORDS = new Set([
|
|
75
|
+
"~kind",
|
|
76
|
+
"~optional",
|
|
77
|
+
"~readonly",
|
|
78
|
+
"~unsafe",
|
|
79
|
+
"title",
|
|
80
|
+
"description",
|
|
81
|
+
"default",
|
|
82
|
+
"examples",
|
|
83
|
+
"deprecated",
|
|
84
|
+
"readOnly",
|
|
85
|
+
"writeOnly",
|
|
86
|
+
"$comment"
|
|
87
|
+
]);
|
|
88
|
+
const isNumeric = (value) => typeof value === "number" || typeof value === "bigint";
|
|
89
|
+
const LEAF_KEYWORDS = [
|
|
90
|
+
[
|
|
91
|
+
"type",
|
|
92
|
+
(value) => typeof value === "string" || Array.isArray(value) && value.every((item) => typeof item === "string"),
|
|
93
|
+
(type) => ({ type })
|
|
94
|
+
],
|
|
95
|
+
["minLength", (value) => typeof value === "number", (limit) => ({ limit })],
|
|
96
|
+
["maxLength", (value) => typeof value === "number", (limit) => ({ limit })],
|
|
97
|
+
["format", (value) => typeof value === "string", (format) => ({ format })],
|
|
98
|
+
["pattern", (value) => typeof value === "string", (pattern) => ({ pattern })],
|
|
99
|
+
["exclusiveMinimum", isNumeric, (limit) => ({ comparison: ">", limit })],
|
|
100
|
+
["exclusiveMaximum", isNumeric, (limit) => ({ comparison: "<", limit })],
|
|
101
|
+
["minimum", isNumeric, (limit) => ({ comparison: ">=", limit })],
|
|
102
|
+
["maximum", isNumeric, (limit) => ({ comparison: "<=", limit })],
|
|
103
|
+
["multipleOf", isNumeric, (multipleOf) => ({ multipleOf })],
|
|
104
|
+
["const", () => true, (allowedValue) => ({ allowedValue })],
|
|
105
|
+
["enum", Array.isArray, (allowedValues) => ({ allowedValues })]
|
|
106
|
+
];
|
|
107
|
+
const LEAF_KEYWORD_NAMES = new Set(LEAF_KEYWORDS.map(([keyword]) => keyword));
|
|
108
|
+
function leafChecksOf(schema) {
|
|
109
|
+
if (typeof schema !== "object" || schema === null)
|
|
110
|
+
return;
|
|
111
|
+
for (const key of Reflect.ownKeys(schema)) {
|
|
112
|
+
if (!LEAF_KEYWORD_NAMES.has(key) && !INERT_KEYWORDS.has(key)) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const checks = [];
|
|
117
|
+
for (const [keyword, reads, params] of LEAF_KEYWORDS) {
|
|
118
|
+
if (!Object.hasOwn(schema, keyword))
|
|
119
|
+
continue;
|
|
120
|
+
const value = schema[keyword];
|
|
121
|
+
if (!reads(value))
|
|
122
|
+
return;
|
|
123
|
+
const validator = Compile({ [keyword]: value });
|
|
124
|
+
checks.push({
|
|
125
|
+
keyword,
|
|
126
|
+
params: params(value),
|
|
127
|
+
check: (candidate) => validator.Check(candidate)
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return checks;
|
|
131
|
+
}
|
|
132
|
+
const leafChecks = new WeakMap;
|
|
133
|
+
function addError(sink, keyword, schemaPath, instancePath, params) {
|
|
134
|
+
if (sink.errors.length < sink.max) {
|
|
135
|
+
const error = { keyword, schemaPath, instancePath, params };
|
|
136
|
+
sink.errors.push({ ...error, message: sink.locale(error) });
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
const segmentOf = (key) => key.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
141
|
+
const hasKey = (value, key) => key === "__proto__" || key === "constructor" || key === "prototype" ? Object.hasOwn(value, key) : (key in value);
|
|
142
|
+
const STRUCTURE_KEYWORDS = new Set([
|
|
143
|
+
"required",
|
|
144
|
+
"properties",
|
|
145
|
+
"additionalProperties",
|
|
146
|
+
"items",
|
|
147
|
+
"minItems",
|
|
148
|
+
"maxItems",
|
|
149
|
+
"anyOf"
|
|
150
|
+
]);
|
|
151
|
+
function explainerOf(schema) {
|
|
152
|
+
if (!isRecord(schema))
|
|
153
|
+
return;
|
|
154
|
+
for (const key of Reflect.ownKeys(schema)) {
|
|
155
|
+
if (!LEAF_KEYWORD_NAMES.has(key) && !INERT_KEYWORDS.has(key) && !STRUCTURE_KEYWORDS.has(key)) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
let type;
|
|
160
|
+
const leaves = [];
|
|
161
|
+
for (const [keyword, reads, params] of LEAF_KEYWORDS) {
|
|
162
|
+
if (!Object.hasOwn(schema, keyword))
|
|
163
|
+
continue;
|
|
164
|
+
const value = schema[keyword];
|
|
165
|
+
if (!reads(value))
|
|
166
|
+
return;
|
|
167
|
+
const validator = Compile({ [keyword]: value });
|
|
168
|
+
const leaf = {
|
|
169
|
+
keyword,
|
|
170
|
+
params: params(value),
|
|
171
|
+
check: (candidate) => validator.Check(candidate)
|
|
172
|
+
};
|
|
173
|
+
if (keyword === "type")
|
|
174
|
+
type = leaf;
|
|
175
|
+
else
|
|
176
|
+
leaves.push(leaf);
|
|
177
|
+
}
|
|
178
|
+
let required;
|
|
179
|
+
if (Object.hasOwn(schema, "required")) {
|
|
180
|
+
const value = schema.required;
|
|
181
|
+
if (!Array.isArray(value))
|
|
182
|
+
return;
|
|
183
|
+
if (!value.every((key) => typeof key === "string"))
|
|
184
|
+
return;
|
|
185
|
+
required = value;
|
|
186
|
+
}
|
|
187
|
+
let properties;
|
|
188
|
+
if (Object.hasOwn(schema, "properties")) {
|
|
189
|
+
if (!isRecord(schema.properties))
|
|
190
|
+
return;
|
|
191
|
+
const list = [];
|
|
192
|
+
for (const [key, property] of Object.entries(schema.properties)) {
|
|
193
|
+
const explain = explainerOf(property);
|
|
194
|
+
if (!explain)
|
|
195
|
+
return;
|
|
196
|
+
list.push({
|
|
197
|
+
key,
|
|
198
|
+
segment: segmentOf(key),
|
|
199
|
+
required: required?.includes(key) ?? false,
|
|
200
|
+
explain
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
properties = list;
|
|
204
|
+
}
|
|
205
|
+
let declared;
|
|
206
|
+
if (Object.hasOwn(schema, "additionalProperties")) {
|
|
207
|
+
if (schema.additionalProperties !== false)
|
|
208
|
+
return;
|
|
209
|
+
declared = new Set(properties?.map(({ key }) => key));
|
|
210
|
+
}
|
|
211
|
+
let items;
|
|
212
|
+
if (Object.hasOwn(schema, "items")) {
|
|
213
|
+
items = explainerOf(schema.items);
|
|
214
|
+
if (!items)
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const limits = [];
|
|
218
|
+
for (const keyword of ["minItems", "maxItems"]) {
|
|
219
|
+
if (!Object.hasOwn(schema, keyword))
|
|
220
|
+
continue;
|
|
221
|
+
const limit = schema[keyword];
|
|
222
|
+
if (typeof limit !== "number")
|
|
223
|
+
return;
|
|
224
|
+
const validator = Compile({ [keyword]: limit });
|
|
225
|
+
limits.push({
|
|
226
|
+
keyword,
|
|
227
|
+
params: { limit },
|
|
228
|
+
check: (candidate) => validator.Check(candidate)
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
let anyOf;
|
|
232
|
+
if (Object.hasOwn(schema, "anyOf")) {
|
|
233
|
+
if (!Array.isArray(schema.anyOf))
|
|
234
|
+
return;
|
|
235
|
+
const list = [];
|
|
236
|
+
for (const option of schema.anyOf) {
|
|
237
|
+
const explain = explainerOf(option);
|
|
238
|
+
if (!explain)
|
|
239
|
+
return;
|
|
240
|
+
list.push(explain);
|
|
241
|
+
}
|
|
242
|
+
anyOf = list;
|
|
243
|
+
}
|
|
244
|
+
return (value, schemaPath, instancePath, sink) => {
|
|
245
|
+
if (sink.errors.length >= sink.max)
|
|
246
|
+
return false;
|
|
247
|
+
let accepted = true;
|
|
248
|
+
if (type && !type.check(value)) {
|
|
249
|
+
accepted = addError(sink, "type", schemaPath, instancePath, type.params);
|
|
250
|
+
}
|
|
251
|
+
if (isRecord(value)) {
|
|
252
|
+
if (required) {
|
|
253
|
+
const missing = required.filter((key) => !hasKey(value, key));
|
|
254
|
+
if (missing.length > 0) {
|
|
255
|
+
accepted = addError(sink, "required", schemaPath, instancePath, {
|
|
256
|
+
requiredProperties: missing
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (declared) {
|
|
261
|
+
const undeclared = [];
|
|
262
|
+
for (const key of Object.getOwnPropertyNames(value)) {
|
|
263
|
+
if (declared.has(key))
|
|
264
|
+
continue;
|
|
265
|
+
undeclared.push(key);
|
|
266
|
+
addError(sink, "boolean", `${schemaPath}/additionalProperties`, `${instancePath}/${segmentOf(key)}`, {});
|
|
267
|
+
}
|
|
268
|
+
if (undeclared.length > 0) {
|
|
269
|
+
accepted = addError(sink, "additionalProperties", schemaPath, instancePath, { additionalProperties: undeclared });
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (properties) {
|
|
273
|
+
for (const property of properties) {
|
|
274
|
+
const { key } = property;
|
|
275
|
+
if (!property.required && !sink.exact && value[key] === undefined) {
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
if (!hasKey(value, key))
|
|
279
|
+
continue;
|
|
280
|
+
const explained = property.explain(value[key], `${schemaPath}/properties/${property.segment}`, `${instancePath}/${property.segment}`, sink);
|
|
281
|
+
if (!explained)
|
|
282
|
+
accepted = false;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (Array.isArray(value)) {
|
|
287
|
+
if (items) {
|
|
288
|
+
const explain = items;
|
|
289
|
+
value.forEach((item, index) => {
|
|
290
|
+
const explained = explain(item, `${schemaPath}/items`, `${instancePath}/${index}`, sink);
|
|
291
|
+
if (!explained)
|
|
292
|
+
accepted = false;
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
for (const limit of limits) {
|
|
296
|
+
if (limit.check(value))
|
|
297
|
+
continue;
|
|
298
|
+
accepted = addError(sink, limit.keyword, schemaPath, instancePath, limit.params);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
for (const leaf of leaves) {
|
|
302
|
+
if (leaf.check(value))
|
|
303
|
+
continue;
|
|
304
|
+
accepted = addError(sink, leaf.keyword, schemaPath, instancePath, leaf.params);
|
|
305
|
+
}
|
|
306
|
+
if (anyOf) {
|
|
307
|
+
const failed = [];
|
|
308
|
+
let matched = false;
|
|
309
|
+
for (const [index, explain] of anyOf.entries()) {
|
|
310
|
+
const own = { ...sink, errors: [] };
|
|
311
|
+
const explained = explain(value, `${schemaPath}/anyOf/${index}`, instancePath, own);
|
|
312
|
+
if (explained)
|
|
313
|
+
matched = true;
|
|
314
|
+
else
|
|
315
|
+
failed.push(own.errors);
|
|
316
|
+
}
|
|
317
|
+
if (!matched) {
|
|
318
|
+
for (const errors of failed) {
|
|
319
|
+
for (const error of errors) {
|
|
320
|
+
if (sink.errors.length < sink.max)
|
|
321
|
+
sink.errors.push(error);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
accepted = addError(sink, "anyOf", schemaPath, instancePath, {});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return accepted;
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
const explainers = new WeakMap;
|
|
331
|
+
function sinkOf() {
|
|
332
|
+
const settings = Settings.Get();
|
|
333
|
+
const locale = Locale.Get();
|
|
334
|
+
if (typeof settings?.maxErrors !== "number" || typeof locale !== "function") {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
errors: [],
|
|
339
|
+
max: settings.maxErrors,
|
|
340
|
+
locale,
|
|
341
|
+
exact: settings.exactOptionalPropertyTypes === true
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
345
|
+
function literalOf(variant, key) {
|
|
346
|
+
if (!isRecord(variant) || variant.type !== "object")
|
|
347
|
+
return;
|
|
348
|
+
const { properties, required } = variant;
|
|
349
|
+
if (!isRecord(properties) || !Array.isArray(required))
|
|
350
|
+
return;
|
|
351
|
+
if (!required.includes(key) || !Object.hasOwn(properties, key)) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
const property = properties[key];
|
|
355
|
+
if (!isRecord(property) || !Object.hasOwn(property, "const"))
|
|
356
|
+
return;
|
|
357
|
+
const value = property.const;
|
|
358
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? { value } : undefined;
|
|
359
|
+
}
|
|
360
|
+
function discriminatedUnionOf(schema) {
|
|
361
|
+
if (!isRecord(schema) || !Array.isArray(schema.anyOf))
|
|
362
|
+
return;
|
|
363
|
+
for (const key of Reflect.ownKeys(schema)) {
|
|
364
|
+
if (key !== "anyOf" && !INERT_KEYWORDS.has(key))
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const options = schema.anyOf;
|
|
368
|
+
const [first] = options;
|
|
369
|
+
if (options.length < 2 || !isRecord(first) || !isRecord(first.properties)) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
for (const key of Object.keys(first.properties)) {
|
|
373
|
+
const variants = new Map;
|
|
374
|
+
for (const [index, option] of options.entries()) {
|
|
375
|
+
const literal = literalOf(option, key);
|
|
376
|
+
if (!literal || variants.has(literal.value))
|
|
377
|
+
break;
|
|
378
|
+
let validator;
|
|
379
|
+
variants.set(literal.value, {
|
|
380
|
+
index,
|
|
381
|
+
explain: explainerOf(option),
|
|
382
|
+
Errors: (value) => {
|
|
383
|
+
validator ??= Compile(option);
|
|
384
|
+
return validator.Errors(value);
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
if (variants.size !== options.length)
|
|
389
|
+
continue;
|
|
390
|
+
return {
|
|
391
|
+
key,
|
|
392
|
+
segment: segmentOf(key),
|
|
393
|
+
allowedValues: [...variants.keys()],
|
|
394
|
+
variants
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
const discriminatedUnions = new WeakMap;
|
|
400
|
+
function errorsOfVariant(union, value) {
|
|
401
|
+
const variant = union.variants.get(value[union.key]);
|
|
402
|
+
if (variant) {
|
|
403
|
+
const at = `#/anyOf/${variant.index}`;
|
|
404
|
+
const sink = variant.explain && sinkOf();
|
|
405
|
+
if (variant.explain && sink) {
|
|
406
|
+
variant.explain(value, at, "", sink);
|
|
407
|
+
return sink.errors.length > 0 ? sink.errors : undefined;
|
|
408
|
+
}
|
|
409
|
+
const errors = variant.Errors(value);
|
|
410
|
+
if (errors.length === 0)
|
|
411
|
+
return;
|
|
412
|
+
return errors.map((error) => ({
|
|
413
|
+
...error,
|
|
414
|
+
schemaPath: at + error.schemaPath.slice(1)
|
|
415
|
+
}));
|
|
416
|
+
}
|
|
417
|
+
const maxErrors = Settings.Get().maxErrors;
|
|
418
|
+
const locale = Locale.Get();
|
|
419
|
+
if (typeof maxErrors !== "number" || typeof locale !== "function") {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
if (maxErrors < 1)
|
|
423
|
+
return [];
|
|
424
|
+
const error = {
|
|
425
|
+
keyword: "enum",
|
|
426
|
+
schemaPath: "#/anyOf",
|
|
427
|
+
instancePath: `/${union.segment}`,
|
|
428
|
+
params: { allowedValues: union.allowedValues }
|
|
429
|
+
};
|
|
430
|
+
return [{ ...error, message: locale(error) }];
|
|
431
|
+
}
|
|
432
|
+
export function errorsOfSchema(schema, value) {
|
|
433
|
+
let checks = leafChecks.get(schema);
|
|
434
|
+
if (checks === undefined) {
|
|
435
|
+
checks = leafChecksOf(rawTypeOf(schema)) ?? null;
|
|
436
|
+
leafChecks.set(schema, checks);
|
|
437
|
+
}
|
|
438
|
+
const maxErrors = Settings.Get().maxErrors;
|
|
439
|
+
const locale = Locale.Get();
|
|
440
|
+
if (checks !== null && typeof maxErrors === "number" && typeof locale === "function") {
|
|
441
|
+
const errors = [];
|
|
442
|
+
for (const { keyword, params, check } of checks) {
|
|
443
|
+
if (errors.length >= maxErrors)
|
|
444
|
+
break;
|
|
445
|
+
if (check(value))
|
|
446
|
+
continue;
|
|
447
|
+
const error = { keyword, schemaPath: "#", instancePath: "", params };
|
|
448
|
+
errors.push({ ...error, message: locale(error) });
|
|
449
|
+
}
|
|
450
|
+
if (errors.length > 0)
|
|
451
|
+
return errors;
|
|
452
|
+
}
|
|
453
|
+
if (checks === null && isRecord(value)) {
|
|
454
|
+
let union = discriminatedUnions.get(schema);
|
|
455
|
+
if (union === undefined) {
|
|
456
|
+
union = discriminatedUnionOf(rawTypeOf(schema)) ?? null;
|
|
457
|
+
discriminatedUnions.set(schema, union);
|
|
458
|
+
}
|
|
459
|
+
const errors = union && errorsOfVariant(union, value);
|
|
460
|
+
if (errors)
|
|
461
|
+
return errors;
|
|
462
|
+
}
|
|
463
|
+
if (checks === null) {
|
|
464
|
+
let explain = explainers.get(schema);
|
|
465
|
+
if (explain === undefined) {
|
|
466
|
+
explain = explainerOf(rawTypeOf(schema)) ?? null;
|
|
467
|
+
explainers.set(schema, explain);
|
|
468
|
+
}
|
|
469
|
+
const sink = explain && sinkOf();
|
|
470
|
+
if (explain && sink) {
|
|
471
|
+
explain(value, "#", "", sink);
|
|
472
|
+
if (sink.errors.length > 0)
|
|
473
|
+
return sink.errors;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return schema.type.Errors(value);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
class AbstractSchema {
|
|
480
|
+
_type;
|
|
481
|
+
validator;
|
|
482
|
+
shapeValidator;
|
|
483
|
+
constructor(_type) {
|
|
484
|
+
this._type = _type;
|
|
485
|
+
}
|
|
486
|
+
match(value) {
|
|
487
|
+
return this.type.Check(value);
|
|
488
|
+
}
|
|
489
|
+
matchShape(value) {
|
|
490
|
+
this.shapeValidator ??= Compile(shapeOf(this._type));
|
|
491
|
+
return this.shapeValidator.Check(value);
|
|
492
|
+
}
|
|
493
|
+
checks() {
|
|
494
|
+
const validator = this.type;
|
|
495
|
+
const shape = shapeOf(this._type);
|
|
496
|
+
if (shape.type === "string" && Object.keys(shape).length === 1) {
|
|
497
|
+
return {
|
|
498
|
+
match: (value) => validator.Check(value),
|
|
499
|
+
matchShape: (value) => typeof value === "string"
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
return {
|
|
503
|
+
match: (value) => validator.Check(value),
|
|
504
|
+
matchShape: (value) => this.matchShape(value)
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
errors(value) {
|
|
508
|
+
return this.type.Errors(value).map(describeError);
|
|
509
|
+
}
|
|
510
|
+
toString() {
|
|
511
|
+
return JSON.stringify(this._type);
|
|
512
|
+
}
|
|
513
|
+
get type() {
|
|
514
|
+
this.validator ??= Compile(this._type);
|
|
515
|
+
return this.validator;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
export function checksOfSchema(schema) {
|
|
519
|
+
return schema instanceof AbstractSchema ? schema.checks() : {
|
|
520
|
+
match: (value) => schema.match(value),
|
|
521
|
+
matchShape: (value) => schema.matchShape(value)
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
export function rawTypeOf(schema) {
|
|
525
|
+
return schema instanceof AbstractSchema ? schema._type : schema.type.Type();
|
|
526
|
+
}
|
|
527
|
+
export function schemaOf(name, schema) {
|
|
528
|
+
|
|
529
|
+
class Schema extends AbstractSchema {
|
|
530
|
+
constructor(type = schema) {
|
|
531
|
+
super(type);
|
|
532
|
+
}
|
|
533
|
+
static fromString(value) {
|
|
534
|
+
return new Schema(JSON.parse(value));
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
Object.defineProperty(Schema, "name", { value: name });
|
|
538
|
+
Object.defineProperty(Schema, Symbol.for("nodejs.util.inspect.custom"), {
|
|
539
|
+
value: () => `@afora::schema:${name}`
|
|
540
|
+
});
|
|
541
|
+
return Schema;
|
|
542
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const STANDARD_VENDOR = "afora";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { STANDARD_VENDOR } from "./standard-schema.js";
|
|
2
|
+
function standardOf(parse) {
|
|
3
|
+
return Object.freeze({
|
|
4
|
+
version: 1,
|
|
5
|
+
vendor: STANDARD_VENDOR,
|
|
6
|
+
validate: parse
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
export function withStandard(target, parse) {
|
|
10
|
+
return Object.defineProperty(target, "~standard", {
|
|
11
|
+
value: standardOf(parse),
|
|
12
|
+
enumerable: false
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
const cache = new WeakMap;
|
|
16
|
+
export function standardOfClass(Class) {
|
|
17
|
+
let standard = cache.get(Class);
|
|
18
|
+
if (!standard) {
|
|
19
|
+
standard = standardOf((value) => Class.safeParse(value));
|
|
20
|
+
cache.set(Class, standard);
|
|
21
|
+
}
|
|
22
|
+
return standard;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const Demo = Symbol("demo");
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/** Brands blueprints, lists and records, so none is told apart by its shape. */
|
|
1
|
+
/** Brands blueprints, lists, variants and records, so none is told apart by its shape. */
|
|
2
2
|
export declare const Kind: unique symbol;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const Kind = Symbol("kind");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const Meta = Symbol("meta");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const State = Symbol("state");
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ExceptionLayers } from "../exception/enums/exception-layers.js";
|
|
2
|
+
import { exceptionOf } from "../exception/exception.js";
|
|
3
|
+
export const InvalidTraceDeclaration = exceptionOf({
|
|
4
|
+
layer: ExceptionLayers.Application,
|
|
5
|
+
name: "InvalidTraceDeclaration",
|
|
6
|
+
message: ({ reason }) => reason
|
|
7
|
+
});
|