@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
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { Static, TSchema } from "typebox";
|
|
2
|
-
import type { ParseResult } from "../parse/types/parse.interface.js";
|
|
2
|
+
import type { Issue, ParseResult } from "../parse/types/parse.interface.js";
|
|
3
3
|
import { State } from "../symbols/state.js";
|
|
4
4
|
import { PropertyStates } from "./enums/property-states.js";
|
|
5
5
|
import type { IDefineProperty } from "./types/define-property.interface.js";
|
|
6
6
|
import type { IPropertyType } from "./types/property-type.interface.js";
|
|
7
|
+
/**
|
|
8
|
+
* Adds to `issues` those of the value a pipeline has just rejected, each
|
|
9
|
+
* under `path`, where the value is. An issue of the value itself has `path`
|
|
10
|
+
* as it is, not a copy.
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export declare function takeRejectionIssues(path: readonly (string | number)[], issues: Issue[]): void;
|
|
7
14
|
/** How a property handles its value; `Value` is the value of its schema, as in `ISchema`. */
|
|
8
15
|
export declare abstract class AbstractDefineProperty<SchemaType extends TSchema, Value = Static<SchemaType>> implements IDefineProperty<SchemaType, Value> {
|
|
9
16
|
[State]: PropertyStates;
|
|
@@ -27,9 +34,13 @@ export declare abstract class AbstractDefineProperty<SchemaType extends TSchema,
|
|
|
27
34
|
protected afterHandle(value: Value): Value;
|
|
28
35
|
/** The value, or `MISMATCH` when the schema rejects it. */
|
|
29
36
|
protected handle(value: Value): Value;
|
|
30
|
-
/** `attempt`, with the error of any step as a
|
|
37
|
+
/** `attempt`, with the error of any step as a rejection. */
|
|
31
38
|
private attemptWithoutThrowing;
|
|
32
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Runs the pipeline, updating the state: the handled value, or `REJECTED`
|
|
41
|
+
* with the reason in `rejection`. A handler that is not declared is not
|
|
42
|
+
* run, and neither is the shape check that protects it.
|
|
43
|
+
*/
|
|
33
44
|
private attempt;
|
|
34
45
|
/**
|
|
35
46
|
* Runs a handler: an `Exception` it throws goes up as it is, any other
|
|
@@ -38,11 +49,28 @@ export declare abstract class AbstractDefineProperty<SchemaType extends TSchema,
|
|
|
38
49
|
private runHandler;
|
|
39
50
|
/** The `InvalidPropertyValue` of an error that is not an `Exception`, as its cause. */
|
|
40
51
|
private invalidValue;
|
|
41
|
-
/**
|
|
52
|
+
/** Rejects the value with an `exception` that a step threw. */
|
|
42
53
|
private raise;
|
|
43
54
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
55
|
+
* Rejects `value`, which the schema rejects, with its errors, found once
|
|
56
|
+
* and kept for the details of the exception too.
|
|
46
57
|
*/
|
|
47
58
|
private mismatch;
|
|
48
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Tells that the definitions of `prototype` are as `propertyOf` declares them.
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
64
|
+
export declare function declarePipeline(prototype: object): void;
|
|
65
|
+
/**
|
|
66
|
+
* `definition.parse` without its result object: a function giving the handled
|
|
67
|
+
* value, or `REJECTED`, with the issues for `takeRejectionIssues` to take.
|
|
68
|
+
* `undefined` when `definition` has a `parse` of its own, which must be
|
|
69
|
+
* called instead.
|
|
70
|
+
*
|
|
71
|
+
* For a definition declared by `propertyOf`, the function is the pipeline of
|
|
72
|
+
* `attempt` with what never changes read once: which steps there are, the
|
|
73
|
+
* schema, and no state, which nobody can read.
|
|
74
|
+
* @internal
|
|
75
|
+
*/
|
|
76
|
+
export declare function parserOf(definition: AbstractDefineProperty<TSchema>): ((value: unknown) => unknown) | undefined;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { Exception } from "../exception/exception.js";
|
|
2
|
+
import { LazyIssue, REJECTED } from "../parse/issue.js";
|
|
3
|
+
import {
|
|
4
|
+
checksOfSchema,
|
|
5
|
+
describeError,
|
|
6
|
+
errorsOfSchema
|
|
7
|
+
} from "../schema/schema.js";
|
|
8
|
+
import { State } from "../symbols/state.js";
|
|
9
|
+
import { PropertyStates } from "./enums/property-states.js";
|
|
10
|
+
import { InvalidPropertyValue, PropertyRequired } from "./exceptions.js";
|
|
11
|
+
const MISMATCH = Symbol("mismatch");
|
|
12
|
+
|
|
13
|
+
class Failure {
|
|
14
|
+
source;
|
|
15
|
+
raised;
|
|
16
|
+
errors;
|
|
17
|
+
cause;
|
|
18
|
+
constructor(source, raised, errors) {
|
|
19
|
+
this.source = source;
|
|
20
|
+
this.raised = raised;
|
|
21
|
+
this.errors = errors;
|
|
22
|
+
this.cause = raised;
|
|
23
|
+
}
|
|
24
|
+
exception() {
|
|
25
|
+
if (this.cause === undefined) {
|
|
26
|
+
const { source, errors } = this;
|
|
27
|
+
this.cause = errors ? new InvalidPropertyValue({
|
|
28
|
+
source,
|
|
29
|
+
details: { errors: errors.map(describeError) }
|
|
30
|
+
}) : new PropertyRequired({ source });
|
|
31
|
+
}
|
|
32
|
+
return this.cause;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
let rejection;
|
|
36
|
+
function reject(failure) {
|
|
37
|
+
rejection = failure;
|
|
38
|
+
return REJECTED;
|
|
39
|
+
}
|
|
40
|
+
function segmentsOf(pointer) {
|
|
41
|
+
return pointer.slice(1).split("/").map((segment) => {
|
|
42
|
+
const key = segment.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
43
|
+
return /^(0|[1-9]\d*)$/.test(key) ? Number(key) : key;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function issueOf(failure, message, path, code) {
|
|
47
|
+
return new LazyIssue(message, path, code, failure.source, failure);
|
|
48
|
+
}
|
|
49
|
+
export function takeRejectionIssues(path, issues) {
|
|
50
|
+
const failure = rejection;
|
|
51
|
+
rejection = undefined;
|
|
52
|
+
const { raised, errors, source } = failure;
|
|
53
|
+
if (raised) {
|
|
54
|
+
issues.push({
|
|
55
|
+
message: raised.message,
|
|
56
|
+
path,
|
|
57
|
+
code: "invalid_value",
|
|
58
|
+
source,
|
|
59
|
+
cause: raised
|
|
60
|
+
});
|
|
61
|
+
} else if (!errors) {
|
|
62
|
+
issues.push(issueOf(failure, "is required", path, "required"));
|
|
63
|
+
} else if (errors.length === 0) {
|
|
64
|
+
issues.push(issueOf(failure, "is invalid", path, "invalid_value"));
|
|
65
|
+
} else {
|
|
66
|
+
for (const { message, instancePath } of errors) {
|
|
67
|
+
issues.push(issueOf(failure, message, instancePath === "" ? path : [...path, ...segmentsOf(instancePath)], "invalid_value"));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export class AbstractDefineProperty {
|
|
73
|
+
[State] = PropertyStates.Declared;
|
|
74
|
+
make(value) {
|
|
75
|
+
const handled = this.attempt(value);
|
|
76
|
+
if (handled !== REJECTED)
|
|
77
|
+
return handled;
|
|
78
|
+
const failure = rejection;
|
|
79
|
+
rejection = undefined;
|
|
80
|
+
throw failure.exception();
|
|
81
|
+
}
|
|
82
|
+
parse(value) {
|
|
83
|
+
const handled = this.attemptWithoutThrowing(value);
|
|
84
|
+
if (handled !== REJECTED)
|
|
85
|
+
return { value: handled };
|
|
86
|
+
const issues = [];
|
|
87
|
+
takeRejectionIssues([], issues);
|
|
88
|
+
return { issues };
|
|
89
|
+
}
|
|
90
|
+
preHandle(value) {
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
afterHandle(value) {
|
|
94
|
+
return value;
|
|
95
|
+
}
|
|
96
|
+
handle(value) {
|
|
97
|
+
return this.type.schema.match(value) ? value : MISMATCH;
|
|
98
|
+
}
|
|
99
|
+
attemptWithoutThrowing(value) {
|
|
100
|
+
try {
|
|
101
|
+
return this.attempt(value);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
return this.raise(error instanceof Exception ? error : this.invalidValue(error));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
attempt(value) {
|
|
107
|
+
const { name, optional, schema } = this.type;
|
|
108
|
+
this[State] = PropertyStates.Declared;
|
|
109
|
+
if (value === undefined) {
|
|
110
|
+
if (!optional)
|
|
111
|
+
return reject(new Failure(name, undefined, undefined));
|
|
112
|
+
this[State] = PropertyStates.Done;
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
const preHandles = this.preHandle !== PASS.preHandle;
|
|
116
|
+
const handles = this.handle !== PASS.handle;
|
|
117
|
+
if ((preHandles || handles) && !schema.matchShape(value)) {
|
|
118
|
+
return this.mismatch(value);
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
if (preHandles) {
|
|
122
|
+
this[State] = PropertyStates.PreHandling;
|
|
123
|
+
value = this.runHandler(this.preHandle, value);
|
|
124
|
+
}
|
|
125
|
+
this[State] = PropertyStates.Handling;
|
|
126
|
+
if (handles) {
|
|
127
|
+
const handled = this.handle(value);
|
|
128
|
+
if (handled === MISMATCH)
|
|
129
|
+
return this.mismatch(value);
|
|
130
|
+
value = handled;
|
|
131
|
+
} else if (!schema.match(value)) {
|
|
132
|
+
if (!preHandles && !schema.matchShape(value)) {
|
|
133
|
+
this[State] = PropertyStates.Declared;
|
|
134
|
+
}
|
|
135
|
+
return this.mismatch(value);
|
|
136
|
+
}
|
|
137
|
+
if (this.afterHandle !== PASS.afterHandle) {
|
|
138
|
+
this[State] = PropertyStates.AfterHandling;
|
|
139
|
+
value = this.runHandler(this.afterHandle, value);
|
|
140
|
+
}
|
|
141
|
+
} catch (error) {
|
|
142
|
+
if (error instanceof Exception)
|
|
143
|
+
return this.raise(error);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
this[State] = PropertyStates.Done;
|
|
147
|
+
return value;
|
|
148
|
+
}
|
|
149
|
+
runHandler(handler, value) {
|
|
150
|
+
try {
|
|
151
|
+
return handler.call(this, value);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (error instanceof Exception)
|
|
154
|
+
throw error;
|
|
155
|
+
throw this.invalidValue(error);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
invalidValue(error) {
|
|
159
|
+
return new InvalidPropertyValue({
|
|
160
|
+
source: this.type.name,
|
|
161
|
+
details: {
|
|
162
|
+
errors: [error instanceof Error ? error.message : String(error)]
|
|
163
|
+
},
|
|
164
|
+
cause: error
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
raise(exception) {
|
|
168
|
+
return reject(new Failure(this.type.name, exception, undefined));
|
|
169
|
+
}
|
|
170
|
+
mismatch(value) {
|
|
171
|
+
const { name, schema } = this.type;
|
|
172
|
+
return reject(new Failure(name, undefined, errorsOfSchema(schema, value)));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const PASS = AbstractDefineProperty.prototype;
|
|
176
|
+
const declared = new WeakSet;
|
|
177
|
+
export function declarePipeline(prototype) {
|
|
178
|
+
declared.add(prototype);
|
|
179
|
+
}
|
|
180
|
+
export function parserOf(definition) {
|
|
181
|
+
const pipeline = definition;
|
|
182
|
+
if (pipeline.parse !== AbstractDefineProperty.prototype.parse) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (!declared.has(Object.getPrototypeOf(definition)) || pipeline.handle !== PASS.handle || Object.hasOwn(definition, "preHandle") || Object.hasOwn(definition, "afterHandle")) {
|
|
186
|
+
return (value) => pipeline.attemptWithoutThrowing(value);
|
|
187
|
+
}
|
|
188
|
+
const { name, optional, schema } = pipeline.type;
|
|
189
|
+
const { match, matchShape } = checksOfSchema(schema);
|
|
190
|
+
const preHandle = pipeline.preHandle === PASS.preHandle ? undefined : pipeline.preHandle;
|
|
191
|
+
const afterHandle = pipeline.afterHandle === PASS.afterHandle ? undefined : pipeline.afterHandle;
|
|
192
|
+
return (value) => {
|
|
193
|
+
if (value === undefined) {
|
|
194
|
+
return optional ? value : reject(new Failure(name, undefined, undefined));
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
if (preHandle !== undefined) {
|
|
198
|
+
if (!matchShape(value))
|
|
199
|
+
return pipeline.mismatch(value);
|
|
200
|
+
value = preHandle.call(pipeline, value);
|
|
201
|
+
}
|
|
202
|
+
if (!match(value))
|
|
203
|
+
return pipeline.mismatch(value);
|
|
204
|
+
return afterHandle === undefined ? value : afterHandle.call(pipeline, value);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
return pipeline.raise(error instanceof Exception ? error : pipeline.invalidValue(error));
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export var PropertyStates;
|
|
2
|
+
((PropertyStates) => {
|
|
3
|
+
PropertyStates[PropertyStates["Declared"] = 0] = "Declared";
|
|
4
|
+
PropertyStates[PropertyStates["PreHandling"] = 1] = "PreHandling";
|
|
5
|
+
PropertyStates[PropertyStates["Handling"] = 2] = "Handling";
|
|
6
|
+
PropertyStates[PropertyStates["AfterHandling"] = 3] = "AfterHandling";
|
|
7
|
+
PropertyStates[PropertyStates["Done"] = 4] = "Done";
|
|
8
|
+
})(PropertyStates ||= {});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ExceptionLayers } from "../exception/enums/exception-layers.js";
|
|
2
|
+
import { exceptionOf } from "../exception/exception.js";
|
|
3
|
+
export const PropertyRequired = exceptionOf({
|
|
4
|
+
layer: ExceptionLayers.Property,
|
|
5
|
+
name: "PropertyRequired",
|
|
6
|
+
message: (_, source) => `Property "${source}" is required.`
|
|
7
|
+
});
|
|
8
|
+
export const InvalidPropertyValue = exceptionOf({
|
|
9
|
+
layer: ExceptionLayers.Property,
|
|
10
|
+
name: "InvalidPropertyValue",
|
|
11
|
+
message: ({ errors }, source) => `Invalid value for property "${source}": ${errors.join("; ")}`
|
|
12
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { fieldOf } from "../blueprint/callable.js";
|
|
2
|
+
import { isProperty } from "./is-property.js";
|
|
3
|
+
export const PropertyInput = Symbol("propertyInput");
|
|
4
|
+
export function propertyInputOf(field) {
|
|
5
|
+
const property = fieldOf(field);
|
|
6
|
+
if (!isProperty(property))
|
|
7
|
+
return;
|
|
8
|
+
const declared = property[PropertyInput];
|
|
9
|
+
return typeof declared === "object" && declared !== null && isProperty(declared.accepts) && typeof declared.convert === "function" ? declared : undefined;
|
|
10
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const lineages = new WeakMap;
|
|
2
|
+
export function recordPropertyLineage(Property, lineage) {
|
|
3
|
+
if (!lineages.has(Property))
|
|
4
|
+
lineages.set(Property, lineage);
|
|
5
|
+
}
|
|
6
|
+
export function propertyLineageOf(Property) {
|
|
7
|
+
return typeof Property === "function" ? lineages.get(Property) : undefined;
|
|
8
|
+
}
|
|
@@ -53,5 +53,32 @@ export interface PropertyClass<SchemaType extends TSchema, Value = Static<Schema
|
|
|
53
53
|
with<Self extends AnyPropertyConstructor>(this: Self, options: PropertyOptions<SchemaType, Value>): Self;
|
|
54
54
|
demo<Self extends AbstractProperty<any>>(this: new (value: never) => Self): Self;
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Declares a property: a class that holds one value, run through
|
|
58
|
+
* `preHandle`, the validation against the TypeBox `schema` and
|
|
59
|
+
* `afterHandle`. `optional`, `sensitive` and `unique` flag it for the
|
|
60
|
+
* blueprints and records that hold it, and `default` is its `demo()` value.
|
|
61
|
+
* Extend the class to add behavior, or narrow it with `.with(options)`. A
|
|
62
|
+
* value its schema rejects makes the constructor throw
|
|
63
|
+
* {@link InvalidPropertyValue}, and `undefined` for a required one
|
|
64
|
+
* {@link PropertyRequired}.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* import { propertyOf } from "@afora/core";
|
|
69
|
+
* import { Type } from "typebox";
|
|
70
|
+
*
|
|
71
|
+
* const Name = propertyOf({
|
|
72
|
+
* name: "name",
|
|
73
|
+
* schema: Type.String({ minLength: 3 }),
|
|
74
|
+
* preHandle: (value) => value.trim(),
|
|
75
|
+
* default: "Jane", // used by Name.demo()
|
|
76
|
+
* });
|
|
77
|
+
*
|
|
78
|
+
* new Name(" Alice ").value; // "Alice"
|
|
79
|
+
* Name.demo().value; // "Jane"
|
|
80
|
+
* // new Name("a") throws InvalidPropertyValue
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
56
83
|
export declare function propertyOf<SchemaType extends TSchema, Optional extends boolean = false, const Unique extends boolean = false, const Sensitive extends boolean = false>({ name, schema, optional, sensitive, unique, default: _default, preHandle: onPreHandle, afterHandle: onAfterHandle, }: PropertyOfArgs<SchemaType, Optional, Unique, Sensitive>): PropertyClass<SchemaValueType<SchemaType, Optional>, Static<SchemaType>> & UniqueMark<Unique> & SensitiveMark<Sensitive>;
|
|
57
84
|
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { schemaOf } from "../schema/schema.js";
|
|
3
|
+
import { Demo } from "../symbols/demo.js";
|
|
4
|
+
import { AbstractProperty } from "./abstract-property.js";
|
|
5
|
+
import { AbstractDefineProperty, declarePipeline } from "./define-property.js";
|
|
6
|
+
export function propertyOf({
|
|
7
|
+
name,
|
|
8
|
+
schema,
|
|
9
|
+
optional,
|
|
10
|
+
sensitive = false,
|
|
11
|
+
unique = false,
|
|
12
|
+
default: _default,
|
|
13
|
+
preHandle: onPreHandle,
|
|
14
|
+
afterHandle: onAfterHandle
|
|
15
|
+
}) {
|
|
16
|
+
const valueSchema = optional ? Type.Optional(schema) : schema;
|
|
17
|
+
const SchemaConstructor = schemaOf(name, valueSchema);
|
|
18
|
+
const type = {
|
|
19
|
+
[Demo]: _default,
|
|
20
|
+
name,
|
|
21
|
+
schema: new SchemaConstructor,
|
|
22
|
+
optional: optional ?? false,
|
|
23
|
+
sensitive,
|
|
24
|
+
unique
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
class DefineProperty extends AbstractDefineProperty {
|
|
28
|
+
get type() {
|
|
29
|
+
return type;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const steps = DefineProperty.prototype;
|
|
33
|
+
if (onPreHandle)
|
|
34
|
+
steps.preHandle = (value) => onPreHandle(value);
|
|
35
|
+
if (onAfterHandle)
|
|
36
|
+
steps.afterHandle = (value) => onAfterHandle(value);
|
|
37
|
+
declarePipeline(DefineProperty.prototype);
|
|
38
|
+
|
|
39
|
+
class Property extends AbstractProperty {
|
|
40
|
+
static type = type;
|
|
41
|
+
createDefinition() {
|
|
42
|
+
return new DefineProperty;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return Property;
|
|
46
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { rawTypeOf, schemaOf } from "../schema/schema.js";
|
|
2
|
+
import { Demo } from "../symbols/demo.js";
|
|
3
|
+
import { recordPropertyLineage } from "./lineage.js";
|
|
4
|
+
const METADATA_KEYS = [
|
|
5
|
+
"title",
|
|
6
|
+
"description",
|
|
7
|
+
"examples",
|
|
8
|
+
"deprecated",
|
|
9
|
+
"readOnly",
|
|
10
|
+
"writeOnly"
|
|
11
|
+
];
|
|
12
|
+
const LOWER_BOUNDS = {
|
|
13
|
+
min: ["minimum", "minLength"],
|
|
14
|
+
exclusiveMin: ["exclusiveMinimum"]
|
|
15
|
+
};
|
|
16
|
+
const UPPER_BOUNDS = {
|
|
17
|
+
max: ["maximum", "maxLength"],
|
|
18
|
+
exclusiveMax: ["exclusiveMaximum"]
|
|
19
|
+
};
|
|
20
|
+
export function derivePropertyOf(Property, type) {
|
|
21
|
+
const Base = Property;
|
|
22
|
+
|
|
23
|
+
class Derived extends Base {
|
|
24
|
+
static type = type;
|
|
25
|
+
createDefinition() {
|
|
26
|
+
const definition = super.createDefinition();
|
|
27
|
+
Object.defineProperty(definition, "type", {
|
|
28
|
+
value: type,
|
|
29
|
+
configurable: true
|
|
30
|
+
});
|
|
31
|
+
return definition;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
Object.defineProperty(Derived, "name", { value: Property.name });
|
|
35
|
+
return Derived;
|
|
36
|
+
}
|
|
37
|
+
function copyOf(schema) {
|
|
38
|
+
return Object.defineProperties({}, Object.getOwnPropertyDescriptors(schema));
|
|
39
|
+
}
|
|
40
|
+
function addAllOf(schema, constraint) {
|
|
41
|
+
schema.allOf = [...schema.allOf ?? [], constraint];
|
|
42
|
+
}
|
|
43
|
+
function refinedSchemaOf(base, options) {
|
|
44
|
+
const schema = copyOf(base);
|
|
45
|
+
const keyword = (keys) => keys.length === 1 || schema.type !== "string" ? keys[0] : keys[1];
|
|
46
|
+
for (const key of METADATA_KEYS) {
|
|
47
|
+
if (options[key] !== undefined)
|
|
48
|
+
schema[key] = options[key];
|
|
49
|
+
}
|
|
50
|
+
for (const [option, keys] of Object.entries(LOWER_BOUNDS)) {
|
|
51
|
+
const value = options[option];
|
|
52
|
+
if (value === undefined)
|
|
53
|
+
continue;
|
|
54
|
+
const name = keyword(keys);
|
|
55
|
+
const current = schema[name];
|
|
56
|
+
schema[name] = current === undefined ? value : Math.max(current, value);
|
|
57
|
+
}
|
|
58
|
+
for (const [option, keys] of Object.entries(UPPER_BOUNDS)) {
|
|
59
|
+
const value = options[option];
|
|
60
|
+
if (value === undefined)
|
|
61
|
+
continue;
|
|
62
|
+
const name = keyword(keys);
|
|
63
|
+
const current = schema[name];
|
|
64
|
+
schema[name] = current === undefined ? value : Math.min(current, value);
|
|
65
|
+
}
|
|
66
|
+
if (options.multipleOf !== undefined) {
|
|
67
|
+
if (schema.multipleOf === undefined)
|
|
68
|
+
schema.multipleOf = options.multipleOf;
|
|
69
|
+
else
|
|
70
|
+
addAllOf(schema, { multipleOf: options.multipleOf });
|
|
71
|
+
}
|
|
72
|
+
if (options.pattern !== undefined) {
|
|
73
|
+
const pattern = options.pattern instanceof RegExp ? options.pattern.source : options.pattern;
|
|
74
|
+
if (schema.pattern === undefined)
|
|
75
|
+
schema.pattern = pattern;
|
|
76
|
+
else
|
|
77
|
+
addAllOf(schema, { pattern });
|
|
78
|
+
}
|
|
79
|
+
return schema;
|
|
80
|
+
}
|
|
81
|
+
export function refinePropertyOf(Property, options) {
|
|
82
|
+
const base = Property.type;
|
|
83
|
+
const settings = options;
|
|
84
|
+
const schema = refinedSchemaOf(rawTypeOf(base.schema), settings);
|
|
85
|
+
const SchemaConstructor = schemaOf(base.name, schema);
|
|
86
|
+
const examples = settings.examples;
|
|
87
|
+
const type = {
|
|
88
|
+
...base,
|
|
89
|
+
[Demo]: settings.default ?? examples?.[0] ?? base[Demo],
|
|
90
|
+
schema: new SchemaConstructor,
|
|
91
|
+
...settings.fill !== undefined && { fill: settings.fill },
|
|
92
|
+
...typeof settings.renamedFrom === "string" && {
|
|
93
|
+
renamedFrom: settings.renamedFrom
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const Refined = derivePropertyOf(Property, type);
|
|
97
|
+
recordPropertyLineage(Refined, {
|
|
98
|
+
kind: "refined",
|
|
99
|
+
base: Property,
|
|
100
|
+
options: Object.freeze({ ...settings })
|
|
101
|
+
});
|
|
102
|
+
return Refined;
|
|
103
|
+
}
|
|
@@ -14,6 +14,16 @@ export interface PropertyMetadata<Value> {
|
|
|
14
14
|
readonly writeOnly?: boolean;
|
|
15
15
|
/** The demo value, as `default` in `propertyOf`; it is not written to the schema. */
|
|
16
16
|
readonly default?: Value;
|
|
17
|
+
/**
|
|
18
|
+
* The value a repository gives the key when a stored row lacks it, on read
|
|
19
|
+
* and in a backfill (`app.migrate`); unlike `default`, it fills real data.
|
|
20
|
+
*/
|
|
21
|
+
readonly fill?: Value;
|
|
22
|
+
/**
|
|
23
|
+
* The key that held the value in rows stored before the key was renamed:
|
|
24
|
+
* a repository moves it on read and in a backfill.
|
|
25
|
+
*/
|
|
26
|
+
readonly renamedFrom?: string;
|
|
17
27
|
}
|
|
18
28
|
/**
|
|
19
29
|
* Bounds of a number. They only narrow the property: a bound looser than one
|
|
@@ -15,6 +15,10 @@ export interface IPropertyType<SchemaType extends TSchema, Value = Static<Schema
|
|
|
15
15
|
readonly sensitive?: boolean;
|
|
16
16
|
/** Whether a record lists a key holding it in `options.unique`, for repositories to enforce. */
|
|
17
17
|
readonly unique?: boolean;
|
|
18
|
+
/** `fill` of `.with()`: the value given to the key when a stored row lacks it. */
|
|
19
|
+
readonly fill?: Value;
|
|
20
|
+
/** `renamedFrom` of `.with()`: the key that held the value in older rows. */
|
|
21
|
+
readonly renamedFrom?: string;
|
|
18
22
|
}
|
|
19
23
|
/**
|
|
20
24
|
* The type of a property declared `unique`, as `Slug`, so that the keys
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { BlueprintField, BlueprintInput, BlueprintValue, IBlueprint, IBlueprintCollection } from "../blueprint/types/blueprint.interface.js";
|
|
2
|
+
import { type Complete } from "../parse/parse.js";
|
|
2
3
|
import type { ParseResult } from "../parse/types/parse.interface.js";
|
|
3
4
|
import type { StandardSchemaV1 } from "../standard/standard-schema.js";
|
|
4
5
|
import { Meta } from "../symbols/meta.js";
|
|
@@ -15,6 +16,13 @@ interface RecordDeclaration<Properties extends IBlueprintCollection> {
|
|
|
15
16
|
export declare const RESERVED_RECORD_KEYS: readonly string[];
|
|
16
17
|
/** Makes each of `keys` a member of the records of `prototype`, e.g. `user.name`. */
|
|
17
18
|
export declare function exposeRecordKeys(prototype: object, keys: readonly string[]): void;
|
|
19
|
+
/**
|
|
20
|
+
* Tells the record whose constructor runs next that the values of `keys` are
|
|
21
|
+
* valid as they are. For a class that makes values for its own record on the
|
|
22
|
+
* way to `super()`, as an entity does of its id.
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
export declare function vouchFor(keys: readonly string[], complete?: Complete): void;
|
|
18
26
|
/** How `recordDataOf` stores the records a record holds. */
|
|
19
27
|
export interface RecordDataOptions {
|
|
20
28
|
/**
|