@astrale-os/kernel-dsl 1.0.0-beta.2 → 1.0.0-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/v1/addressing/class-key.js +3 -3
- package/dist/v1/addressing/definition-ref.js +21 -37
- package/dist/v1/addressing/domain-dependency.d.ts +0 -6
- package/dist/v1/addressing/domain-dependency.js +1 -6
- package/dist/v1/addressing/key.d.ts +4 -1
- package/dist/v1/addressing/key.js +23 -3
- package/dist/v1/addressing/ordering.d.ts +2 -0
- package/dist/v1/addressing/ordering.js +4 -0
- package/dist/v1/addressing/patterns.d.ts +1 -1
- package/dist/v1/addressing/patterns.js +2 -6
- package/dist/v1/builder/callable/authoring.d.ts +11 -5
- package/dist/v1/builder/callable/authoring.js +2 -0
- package/dist/v1/builder/class/authoring.d.ts +94 -224
- package/dist/v1/builder/class/authoring.js +31 -33
- package/dist/v1/builder/class/handle.d.ts +27 -0
- package/dist/v1/builder/class/handle.js +1 -0
- package/dist/v1/builder/class/input.d.ts +159 -0
- package/dist/v1/builder/class/projection.d.ts +129 -0
- package/dist/v1/builder/class/projection.js +1 -0
- package/dist/v1/builder/class/property.d.ts +3 -9
- package/dist/v1/builder/class/property.js +1 -0
- package/dist/v1/builder/core/authoring.d.ts +1 -1
- package/dist/v1/builder/index.d.ts +5 -2
- package/dist/v1/builder/lowering/callable.js +1 -0
- package/dist/v1/builder/lowering/class.d.ts +9 -1
- package/dist/v1/builder/lowering/class.js +62 -17
- package/dist/v1/builder/lowering/policy.js +2 -0
- package/dist/v1/builder/lowering/property-keys.d.ts +27 -0
- package/dist/v1/builder/lowering/property-keys.js +108 -0
- package/dist/v1/builder/lowering/schema/compile.js +11 -6
- package/dist/v1/builder/lowering/schema/context.d.ts +9 -1
- package/dist/v1/builder/lowering/schema/context.js +36 -4
- package/dist/v1/builder/lowering/schema/lifetime.d.ts +11 -0
- package/dist/v1/builder/lowering/schema/lifetime.js +55 -0
- package/dist/v1/builder/lowering/value/path.d.ts +1 -1
- package/dist/v1/builder/lowering/value/path.js +2 -4
- package/dist/v1/builder/lowering/value/zod.js +1 -3
- package/dist/v1/builder/policy/authoring.d.ts +85 -5
- package/dist/v1/builder/policy/authoring.js +107 -68
- package/dist/v1/builder/schema/define.d.ts +0 -1
- package/dist/v1/builder/schema/diagnostic.d.ts +3 -2
- package/dist/v1/builder/schema/diagnostic.js +5 -10
- package/dist/v1/builder/schema/input.d.ts +1 -1
- package/dist/v1/builder/schema/projection/callable.d.ts +7 -5
- package/dist/v1/builder/schema/projection/class.d.ts +118 -15
- package/dist/v1/builder/schema/projection/core-input.d.ts +2 -1
- package/dist/v1/builder/schema/projection/identity.d.ts +2 -1
- package/dist/v1/builder/schema/projection/model.d.ts +4 -2
- package/dist/v1/builder/schema/projection/property.d.ts +1 -1
- package/dist/v1/builder/schema/projection/resolved-class.d.ts +2 -1
- package/dist/v1/builder/schema/projection.d.ts +1 -1
- package/dist/v1/builder/value/full-match.d.ts +0 -1
- package/dist/v1/builder/value/full-match.js +0 -1
- package/dist/v1/builder/value/path-metadata.d.ts +1 -1
- package/dist/v1/builder/value/path.d.ts +1 -1
- package/dist/v1/bundle/codec.js +11 -13
- package/dist/v1/bundle/diagnostic.d.ts +2 -0
- package/dist/v1/bundle/diagnostic.js +9 -7
- package/dist/v1/bundle/model.js +1 -1
- package/dist/v1/bundle/structure.js +4 -6
- package/dist/v1/compiled/admission/accept.js +4 -10
- package/dist/v1/compiled/admission/closure.js +2 -2
- package/dist/v1/compiled/admission/diagnostic.d.ts +1 -1
- package/dist/v1/compiled/admission/diagnostic.js +1 -3
- package/dist/v1/compiled/admission/revision.d.ts +9 -1
- package/dist/v1/compiled/admission/revision.js +6 -3
- package/dist/v1/compiled/admission/semantics/class.d.ts +4 -1
- package/dist/v1/compiled/admission/semantics/class.js +37 -12
- package/dist/v1/compiled/admission/semantics/core.d.ts +1 -24
- package/dist/v1/compiled/admission/semantics/core.js +56 -24
- package/dist/v1/compiled/admission/semantics/edge.d.ts +2 -4
- package/dist/v1/compiled/admission/semantics/edge.js +6 -65
- package/dist/v1/compiled/admission/semantics/policy/callable.js +0 -2
- package/dist/v1/compiled/admission/semantics/policy/contracts.d.ts +5 -20
- package/dist/v1/compiled/admission/semantics/policy/contracts.js +8 -21
- package/dist/v1/compiled/admission/semantics/policy/parity.js +40 -43
- package/dist/v1/compiled/admission/semantics/policy/pattern.d.ts +4 -1
- package/dist/v1/compiled/admission/semantics/policy/pattern.js +4 -16
- package/dist/v1/compiled/admission/semantics/policy/typing.d.ts +2 -24
- package/dist/v1/compiled/admission/semantics/policy/typing.js +19 -201
- package/dist/v1/compiled/admission/wire/callable.js +11 -1
- package/dist/v1/compiled/admission/wire/class.js +73 -21
- package/dist/v1/compiled/admission/wire/policy.d.ts +4 -3
- package/dist/v1/compiled/admission/wire/policy.js +8 -7
- package/dist/v1/compiled/compiler/compile.js +8 -8
- package/dist/v1/compiled/diagnostic.js +2 -3
- package/dist/v1/compiled/loader/load.d.ts +3 -2
- package/dist/v1/compiled/loader/load.js +11 -45
- package/dist/v1/domain/create.js +5 -6
- package/dist/v1/domain/model/domain.d.ts +2 -7
- package/dist/v1/domain/model/input.d.ts +2 -1
- package/dist/v1/domain/namespace/member-collection.js +4 -6
- package/dist/v1/domain/projection/classes.js +4 -1
- package/dist/v1/domain/validation/create.d.ts +6 -3
- package/dist/v1/domain/validation/create.js +21 -69
- package/dist/v1/index.d.ts +2 -1
- package/dist/v1/language/.spec/schemas/draft-2020-12.schema.json +462 -0
- package/dist/v1/language/.spec/schemas/value-schema.schema.json +22 -0
- package/dist/v1/language/callable/admission.d.ts +15 -0
- package/dist/v1/language/callable/admission.js +43 -0
- package/dist/v1/language/callable/model/callable.d.ts +10 -0
- package/dist/v1/language/callable/resolved.d.ts +16 -3
- package/dist/v1/language/class/inheritance.d.ts +36 -5
- package/dist/v1/language/class/inheritance.js +87 -1
- package/dist/v1/language/class/lifetime.d.ts +50 -11
- package/dist/v1/language/class/lifetime.js +89 -20
- package/dist/v1/language/class/model/class.d.ts +45 -9
- package/dist/v1/language/class/model/edge.d.ts +31 -2
- package/dist/v1/language/class/model/property.d.ts +16 -7
- package/dist/v1/language/class/property-values.js +2 -4
- package/dist/v1/language/class/unique.d.ts +143 -0
- package/dist/v1/language/class/unique.js +264 -0
- package/dist/v1/language/core/facts.d.ts +85 -0
- package/dist/v1/language/core/facts.js +116 -0
- package/dist/v1/language/definition/metadata.d.ts +5 -0
- package/dist/v1/language/definition/metadata.js +7 -0
- package/dist/v1/language/freeze.d.ts +5 -0
- package/dist/v1/{schema/canonical → language}/freeze.js +4 -0
- package/dist/v1/language/index.d.ts +7 -2
- package/dist/v1/language/index.js +5 -1
- package/dist/v1/language/limits.d.ts +64 -0
- package/dist/v1/language/limits.js +60 -0
- package/dist/v1/language/policy/analysis/branches.d.ts +8 -0
- package/dist/v1/language/policy/analysis/branches.js +2 -1
- package/dist/v1/language/policy/analysis/budgets.d.ts +45 -12
- package/dist/v1/language/policy/analysis/budgets.js +133 -19
- package/dist/v1/language/policy/analysis/checks.js +3 -2
- package/dist/v1/language/policy/analysis/typing.d.ts +51 -0
- package/dist/v1/language/policy/analysis/typing.js +455 -0
- package/dist/v1/language/policy/model/policy.d.ts +49 -9
- package/dist/v1/language/policy/model/policy.js +14 -0
- package/dist/v1/language/policy/normalization/normalize.d.ts +6 -6
- package/dist/v1/language/policy/normalization/normalize.js +22 -21
- package/dist/v1/language/validation/diagnostic.d.ts +15 -1
- package/dist/v1/language/validation/diagnostic.js +21 -0
- package/dist/v1/language/validation/rule.d.ts +45 -0
- package/dist/v1/language/validation/rule.js +109 -0
- package/dist/v1/language/value/compile/fields.js +4 -8
- package/dist/v1/language/value/evaluate/program.d.ts +2 -1
- package/dist/v1/language/value/evaluate/program.js +2 -2
- package/dist/v1/language/value/evaluate/validate.d.ts +2 -2
- package/dist/v1/language/value/evaluate/validate.js +6 -2
- package/dist/v1/language/value/evaluate/validity.optimization.d.ts +14 -0
- package/dist/v1/language/value/evaluate/validity.optimization.js +342 -0
- package/dist/v1/language/value/inclusion/arrays.d.ts +3 -0
- package/dist/v1/language/value/inclusion/arrays.js +85 -0
- package/dist/v1/language/value/inclusion/assertions.d.ts +18 -0
- package/dist/v1/language/value/inclusion/assertions.js +29 -0
- package/dist/v1/language/value/inclusion/combinators.d.ts +3 -0
- package/dist/v1/language/value/inclusion/combinators.js +67 -0
- package/dist/v1/language/value/inclusion/equivalence.d.ts +4 -0
- package/dist/v1/language/value/inclusion/equivalence.js +74 -0
- package/dist/v1/language/value/inclusion/evidence.d.ts +34 -0
- package/dist/v1/language/value/inclusion/evidence.js +138 -0
- package/dist/v1/language/value/inclusion/includes.d.ts +17 -0
- package/dist/v1/language/value/inclusion/includes.js +25 -719
- package/dist/v1/language/value/inclusion/keywords.d.ts +5 -0
- package/dist/v1/language/value/inclusion/keywords.js +31 -0
- package/dist/v1/language/value/inclusion/kinds.d.ts +17 -0
- package/dist/v1/language/value/inclusion/kinds.js +57 -0
- package/dist/v1/language/value/inclusion/location.d.ts +24 -0
- package/dist/v1/language/value/inclusion/location.js +63 -0
- package/dist/v1/language/value/inclusion/numbers.d.ts +3 -0
- package/dist/v1/language/value/inclusion/numbers.js +41 -0
- package/dist/v1/language/value/inclusion/objects.d.ts +3 -0
- package/dist/v1/language/value/inclusion/objects.js +190 -0
- package/dist/v1/language/value/inclusion/strings.d.ts +3 -0
- package/dist/v1/language/value/inclusion/strings.js +29 -0
- package/dist/v1/language/value/inclusion/types.d.ts +3 -0
- package/dist/v1/language/value/inclusion/types.js +11 -0
- package/dist/v1/language/value/ordering.d.ts +14 -0
- package/dist/v1/language/value/ordering.js +86 -9
- package/dist/v1/language/value/profile/canonicalize.js +6 -5
- package/dist/v1/language/value/profile/json.validate.d.ts +3 -1
- package/dist/v1/language/value/profile/json.validate.js +3 -2
- package/dist/v1/language/value/profile/meta-schema.compiled.js +4 -1
- package/dist/v1/language/value/profile/rules.js +17 -43
- package/dist/v1/language/value/profile/validate.js +1 -10
- package/dist/v1/language/value/profile/vocabulary.d.ts +35 -2
- package/dist/v1/language/value/profile/vocabulary.js +52 -5
- package/dist/v1/language/value/reference/closure.js +3 -4
- package/dist/v1/language/value/reference/recursion.js +2 -22
- package/dist/v1/language/value/reference/registry.index.d.ts +2 -0
- package/dist/v1/language/value/reference/registry.index.js +33 -16
- package/dist/v1/language/value/regexp/ast.js +6 -7
- package/dist/v1/language/value/regexp/compile.d.ts +5 -11
- package/dist/v1/language/value/regexp/compile.js +14 -12
- package/dist/v1/language/value/regexp/syntax.js +3 -2
- package/dist/v1/language/value/syntax/keywords.d.ts +3 -3
- package/dist/v1/language/value/syntax/keywords.js +4 -20
- package/dist/v1/language/value/syntax/node-path/validate.js +2 -3
- package/dist/v1/language/value/syntax/pointer.d.ts +2 -0
- package/dist/v1/language/value/syntax/pointer.js +5 -2
- package/dist/v1/language/value/syntax/walk.d.ts +2 -0
- package/dist/v1/language/value/syntax/walk.js +19 -20
- package/dist/v1/schema/.spec/schemas/domain-schema.schema.json +2519 -0
- package/dist/v1/schema/admission/accept.js +3 -14
- package/dist/v1/schema/admission/callable.d.ts +21 -0
- package/dist/v1/schema/admission/callable.js +96 -0
- package/dist/v1/schema/analysis/class.js +33 -15
- package/dist/v1/schema/canonical/revision.js +4 -4
- package/dist/v1/schema/compatibility/api.d.ts +2 -1
- package/dist/v1/schema/compatibility/api.js +1 -0
- package/dist/v1/schema/compatibility/comparators/callables.js +1 -1
- package/dist/v1/schema/compatibility/comparators/classes.d.ts +9 -4
- package/dist/v1/schema/compatibility/comparators/classes.js +29 -8
- package/dist/v1/schema/compatibility/comparators/index.d.ts +1 -1
- package/dist/v1/schema/compatibility/comparators/members.js +1 -1
- package/dist/v1/schema/compatibility/comparators/values.js +2 -2
- package/dist/v1/schema/compatibility/coordinate.js +3 -3
- package/dist/v1/schema/compatibility/diff.js +2 -4
- package/dist/v1/schema/compatibility/extension.d.ts +11 -0
- package/dist/v1/schema/compatibility/extension.js +22 -0
- package/dist/v1/schema/compatibility/fields.d.ts +20 -4
- package/dist/v1/schema/compatibility/fields.js +13 -3
- package/dist/v1/schema/compatibility/meaning/footprint.js +16 -50
- package/dist/v1/schema/compatibility/model.d.ts +17 -5
- package/dist/v1/schema/compatibility/report.js +1 -1
- package/dist/v1/schema/compatibility/scope.d.ts +2 -0
- package/dist/v1/schema/compatibility/scope.js +4 -1
- package/dist/v1/schema/compatibility/structure/index.js +6 -4
- package/dist/v1/schema/compatibility/structure/requirements.js +57 -58
- package/dist/v1/schema/compatibility/versioning/index.js +1 -1
- package/dist/v1/schema/compatibility/versioning/surface.d.ts +1 -1
- package/dist/v1/schema/compatibility/versioning/surface.js +30 -2
- package/dist/v1/schema/compatibility/walk.d.ts +17 -0
- package/dist/v1/schema/compatibility/walk.js +41 -0
- package/dist/v1/schema/diagnostic.d.ts +17 -3
- package/dist/v1/schema/diagnostic.js +14 -11
- package/dist/v1/schema/index.d.ts +10 -1
- package/dist/v1/schema/index.js +4 -0
- package/dist/v1/schema/model/schema.d.ts +20 -1
- package/dist/v1/schema/model/schema.js +1 -1
- package/dist/v1/schema/normalization/domain.d.ts +2 -0
- package/dist/v1/schema/normalization/domain.js +29 -9
- package/dist/v1/schema/resolution/closure.js +2 -1
- package/dist/v1/schema/resolution/context.js +13 -13
- package/dist/v1/schema/resolution/domain.d.ts +5 -0
- package/dist/v1/schema/resolution/domain.js +2 -2
- package/dist/v1/schema/resolution/origins.js +3 -2
- package/dist/v1/schema/rule.d.ts +26 -0
- package/dist/v1/schema/rule.js +440 -0
- package/dist/v1/schema/validation/callable.d.ts +35 -2
- package/dist/v1/schema/validation/callable.js +65 -9
- package/dist/v1/schema/validation/class.d.ts +6 -2
- package/dist/v1/schema/validation/class.js +127 -104
- package/dist/v1/schema/validation/core.js +90 -168
- package/dist/v1/schema/validation/domain.js +4 -13
- package/dist/v1/schema/validation/domain.json-schema.d.ts +15 -0
- package/dist/v1/schema/validation/domain.json-schema.js +197 -0
- package/dist/v1/schema/validation/domain.route.d.ts +6 -1
- package/dist/v1/schema/validation/domain.route.js +18 -0
- package/dist/v1/schema/validation/domain.structure.d.ts +7780 -0
- package/dist/v1/schema/validation/domain.structure.js +398 -147
- package/dist/v1/schema/validation/json.json-schema.d.ts +40 -0
- package/dist/v1/schema/validation/json.json-schema.js +46 -0
- package/dist/v1/schema/validation/policy/budgets.d.ts +33 -2
- package/dist/v1/schema/validation/policy/budgets.js +87 -121
- package/dist/v1/schema/validation/policy/context.d.ts +6 -5
- package/dist/v1/schema/validation/policy/context.js +7 -10
- package/dist/v1/schema/validation/policy/objects.d.ts +1 -1
- package/dist/v1/schema/validation/policy/objects.js +6 -14
- package/dist/v1/schema/validation/policy/references.js +11 -27
- package/dist/v1/schema/validation/policy/typing.d.ts +3 -18
- package/dist/v1/schema/validation/policy/typing.js +22 -356
- package/dist/v1/schema/validation/policy/uses.d.ts +40 -3
- package/dist/v1/schema/validation/policy/uses.js +66 -89
- package/dist/v1/schema/validation/policy/validate.js +5 -5
- package/dist/v1/schema/validation/value-api.d.ts +22 -0
- package/dist/v1/schema/validation/value-api.js +34 -1
- package/dist/v1/schema/validation/value.d.ts +3 -0
- package/dist/v1/schema/validation/value.js +9 -17
- package/dist/v1/schema/validation/value.json-schema.d.ts +49 -0
- package/dist/v1/schema/validation/value.json-schema.js +137 -0
- package/dist/v1/schema/validation/view.js +4 -8
- package/dist/value/canonical.d.ts +6 -0
- package/dist/value/canonical.js +36 -0
- package/dist/value/decode.d.ts +7 -0
- package/dist/value/decode.js +159 -9
- package/dist/value/index.d.ts +1 -1
- package/dist/value/json.d.ts +2 -2
- package/dist/value/json.js +2 -2
- package/dist/value/types.d.ts +6 -0
- package/dist/value/unicode.d.ts +2 -1
- package/dist/value/unicode.js +2 -0
- package/package.json +8 -1
- package/dist/v1/builder/lowering/core-properties.d.ts +0 -10
- package/dist/v1/builder/lowering/core-properties.js +0 -76
- package/dist/v1/compiled/admission/semantics/cardinality.d.ts +0 -5
- package/dist/v1/compiled/admission/semantics/cardinality.js +0 -113
- package/dist/v1/compiled/admission/semantics/policy/equality.d.ts +0 -8
- package/dist/v1/compiled/admission/semantics/policy/equality.js +0 -27
- package/dist/v1/compiled/admission/semantics/policy/measure.d.ts +0 -9
- package/dist/v1/compiled/admission/semantics/policy/measure.js +0 -81
- package/dist/v1/compiled/admission/semantics/policy/variants.d.ts +0 -10
- package/dist/v1/compiled/admission/semantics/policy/variants.js +0 -65
- package/dist/v1/language/class/index.d.ts +0 -8
- package/dist/v1/language/class/index.js +0 -1
- package/dist/v1/language/core/index.d.ts +0 -2
- package/dist/v1/language/value/index.d.ts +0 -11
- package/dist/v1/language/value/index.js +0 -8
- package/dist/v1/schema/canonical/domain.d.ts +0 -3
- package/dist/v1/schema/canonical/domain.digest.d.ts +0 -3
- package/dist/v1/schema/canonical/domain.digest.js +0 -5
- package/dist/v1/schema/canonical/domain.js +0 -5
- package/dist/v1/schema/canonical/freeze.d.ts +0 -1
- /package/dist/v1/{language/core/index.js → builder/class/input.js} +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
/** The origin of the Kernel, whose Schema every Domain depends on. */
|
|
2
|
+
export const KERNEL_ORIGIN = 'kernel.astrale.ai';
|
|
1
3
|
/** Kernel graph roots are intrinsic supertypes, not authored structural Edge contracts. */
|
|
2
4
|
export function isGraphRoot(value) {
|
|
3
|
-
return (value.ref.origin ===
|
|
5
|
+
return (value.ref.origin === KERNEL_ORIGIN &&
|
|
4
6
|
value.ref.name === (value.kind === 'node' ? 'Node' : 'Edge'));
|
|
5
7
|
}
|
|
6
8
|
/** Same-kind satisfaction includes the intrinsic root and the declared parent closure. */
|
|
@@ -23,3 +25,87 @@ export function classSatisfies(candidate, required, resolve) {
|
|
|
23
25
|
};
|
|
24
26
|
return visit(candidate);
|
|
25
27
|
}
|
|
28
|
+
/** The inheritance a Class declares, `'internal'` when it declares none. */
|
|
29
|
+
export function inheritanceOf(declaration) {
|
|
30
|
+
return declaration.inheritance ?? 'internal';
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Whether a Class of another Domain may extend this Class: only an `'open'` one admits it. Its own
|
|
34
|
+
* Domain may extend any Class that is not `'final'`.
|
|
35
|
+
*/
|
|
36
|
+
export function admitsForeignSubclass(declaration) {
|
|
37
|
+
return inheritanceOf(declaration) === 'open';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Whether `child` safely refines its parent Edge contract `parent`: same orientation, at least the
|
|
41
|
+
* parent's constraints, and endpoints whose accepted Classes `satisfies` one the paired parent
|
|
42
|
+
* endpoint accepts, within its count. Undirected endpoints may pair in either order.
|
|
43
|
+
*/
|
|
44
|
+
export function edgeContractRefines(child, parent, satisfies) {
|
|
45
|
+
if (isGraphRoot(parent))
|
|
46
|
+
return true;
|
|
47
|
+
if (child.orientation !== parent.orientation)
|
|
48
|
+
return false;
|
|
49
|
+
if (parent.constraints.noSelf === true && child.constraints.noSelf !== true)
|
|
50
|
+
return false;
|
|
51
|
+
if (parent.constraints.acyclic === true && child.constraints.acyclic !== true)
|
|
52
|
+
return false;
|
|
53
|
+
const endpointRefines = (childEndpoint, parentEndpoint) => childEndpoint.accepts.every((accepted) => satisfies(accepted, parentEndpoint.accepts));
|
|
54
|
+
if (child.orientation === 'directed' && parent.orientation === 'directed') {
|
|
55
|
+
return (endpointRefines(child.endpoints.source, parent.endpoints.source) &&
|
|
56
|
+
countRefines(child.endpoints.source.outgoing, parent.endpoints.source.outgoing) &&
|
|
57
|
+
endpointRefines(child.endpoints.target, parent.endpoints.target) &&
|
|
58
|
+
countRefines(child.endpoints.target.incoming, parent.endpoints.target.incoming));
|
|
59
|
+
}
|
|
60
|
+
if (child.orientation !== 'undirected' || parent.orientation !== 'undirected')
|
|
61
|
+
return false;
|
|
62
|
+
const refines = (childIndex, parentIndex) => endpointRefines(child.endpoints[childIndex], parent.endpoints[parentIndex]) &&
|
|
63
|
+
countRefines(child.endpoints[childIndex].incident, parent.endpoints[parentIndex].incident);
|
|
64
|
+
const direct = refines(0, 0) && refines(1, 1);
|
|
65
|
+
if (direct)
|
|
66
|
+
return true;
|
|
67
|
+
return refines(0, 1) && refines(1, 0);
|
|
68
|
+
}
|
|
69
|
+
function countRefines(child, parent) {
|
|
70
|
+
const [childMinimum, childMaximum] = countBounds(child);
|
|
71
|
+
const [parentMinimum, parentMaximum] = countBounds(parent);
|
|
72
|
+
return childMinimum >= parentMinimum && childMaximum <= parentMaximum;
|
|
73
|
+
}
|
|
74
|
+
/** Interpret an Edge count as inclusive degree bounds. */
|
|
75
|
+
export function countBounds(value) {
|
|
76
|
+
switch (value) {
|
|
77
|
+
case '0..*':
|
|
78
|
+
return [0, Number.POSITIVE_INFINITY];
|
|
79
|
+
case '1..*':
|
|
80
|
+
return [1, Number.POSITIVE_INFINITY];
|
|
81
|
+
case '0..1':
|
|
82
|
+
return [0, 1];
|
|
83
|
+
case '1':
|
|
84
|
+
return [1, 1];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/** Whether Edges of one Class, read from source to target, close a cycle (`acyclic` forbids it). */
|
|
88
|
+
export function hasDirectedCycle(edges) {
|
|
89
|
+
const outgoing = new Map();
|
|
90
|
+
for (const edge of edges) {
|
|
91
|
+
const targets = outgoing.get(edge.source.key) ?? [];
|
|
92
|
+
targets.push(edge.target.key);
|
|
93
|
+
outgoing.set(edge.source.key, targets);
|
|
94
|
+
}
|
|
95
|
+
const visiting = new Set();
|
|
96
|
+
const visited = new Set();
|
|
97
|
+
const visit = (key) => {
|
|
98
|
+
if (visiting.has(key))
|
|
99
|
+
return true;
|
|
100
|
+
if (visited.has(key))
|
|
101
|
+
return false;
|
|
102
|
+
visiting.add(key);
|
|
103
|
+
for (const target of outgoing.get(key) ?? [])
|
|
104
|
+
if (visit(target))
|
|
105
|
+
return true;
|
|
106
|
+
visiting.delete(key);
|
|
107
|
+
visited.add(key);
|
|
108
|
+
return false;
|
|
109
|
+
};
|
|
110
|
+
return [...outgoing.keys()].some(visit);
|
|
111
|
+
}
|
|
@@ -1,17 +1,56 @@
|
|
|
1
1
|
import type { ClassRef } from '../../addressing/index.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ClassDefinition, EdgeClassDefinition } from './model/class.js';
|
|
3
|
+
import type { EdgeContract, EdgeCount, EdgeEndpointBase, EdgeLifetime } from './model/edge.js';
|
|
4
|
+
export type { EdgeLifetime } from './model/edge.js';
|
|
5
|
+
/** The Classes lifetimes read: those of an Edge Class's Domain and of its dependency closure. */
|
|
6
|
+
export interface LifetimeScope {
|
|
7
|
+
/**
|
|
8
|
+
* Whether a Node of another Domain may be of the Class: it is `'open'`, or a Class of its own
|
|
9
|
+
* Domain that extends it is.
|
|
10
|
+
*/
|
|
11
|
+
readonly extendable: (ref: ClassRef) => boolean;
|
|
12
|
+
}
|
|
13
|
+
/** The lifetime scope of `classes`. */
|
|
14
|
+
export declare function lifetimeScope(classes: Iterable<ClassDefinition>): LifetimeScope;
|
|
15
|
+
/** One endpoint of an Edge contract and how many Edges of the Class each Node in it has. */
|
|
16
|
+
export interface ContractEndpoint {
|
|
17
|
+
readonly endpoint: EdgeEndpointBase;
|
|
18
|
+
readonly count: EdgeCount;
|
|
19
|
+
}
|
|
20
|
+
/** The endpoints of an Edge contract in order: source then target, or the two incident ones. */
|
|
21
|
+
export declare function contractEndpoints(contract: EdgeContract): readonly [ContractEndpoint, ContractEndpoint];
|
|
3
22
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
23
|
+
* Whether an endpoint of an Edge Class of `origin` can hold a Node of another Domain: it accepts a
|
|
24
|
+
* Class `origin` does not own, or one another Domain may extend. The Kernel's own relations are the
|
|
25
|
+
* exception: every Domain depends on the Kernel and extends its roots, so its relations bind every
|
|
26
|
+
* Node and keep the lifetimes they have as closed Classes, however open the Kernel's Classes are.
|
|
6
27
|
*/
|
|
7
|
-
export
|
|
28
|
+
export declare function reachesAnotherDomain(origin: ClassRef['origin'], endpoint: EdgeEndpointBase, scope: LifetimeScope): boolean;
|
|
8
29
|
/**
|
|
9
|
-
* The lifetime of each endpoint of
|
|
10
|
-
*
|
|
30
|
+
* The lifetime of each endpoint of `edge`, in endpoint order: the one it declares, else the derived
|
|
31
|
+
* one.
|
|
11
32
|
*
|
|
12
|
-
* An Edge Class binds only the Nodes of its own Domain and of the Domains that depend on it
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* detaching
|
|
33
|
+
* An Edge Class binds only the Nodes of its own Domain and of the Domains that depend on it, and a
|
|
34
|
+
* Domain blocks only the deletion of its own Nodes. An endpoint that can hold a Node of another
|
|
35
|
+
* Domain therefore detaches, unless an endpoint of the Class declares a minimum count that
|
|
36
|
+
* detaching could break (`requiredEndpoint`). Every other endpoint restricts.
|
|
16
37
|
*/
|
|
17
|
-
export declare function edgeLifetimes(
|
|
38
|
+
export declare function edgeLifetimes(edge: EdgeClassDefinition, scope: LifetimeScope): readonly [EdgeLifetime, EdgeLifetime];
|
|
39
|
+
/** One breach of the lifetime laws at one endpoint of an Edge Class: its index and why. */
|
|
40
|
+
export interface LifetimeBreach {
|
|
41
|
+
readonly index: 0 | 1;
|
|
42
|
+
readonly reason: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The breaches of the lifetime laws (LANGUAGE-EDGE-LIFETIME) by the lifetimes `edge` declares: an
|
|
46
|
+
* endpoint that can hold a Node of another Domain never restricts, and none detaches in a Class
|
|
47
|
+
* with an endpoint that requires an Edge (`requiredEndpoint`). A derived lifetime breaks neither.
|
|
48
|
+
*/
|
|
49
|
+
export declare function lifetimeBreaches(edge: EdgeClassDefinition, scope: LifetimeScope): readonly LifetimeBreach[];
|
|
50
|
+
/**
|
|
51
|
+
* The first endpoint of an Edge Class that requires an Edge, if one does, with its index. Detaching
|
|
52
|
+
* there could leave a Node below its count, so an endpoint of such a Class never detaches.
|
|
53
|
+
*/
|
|
54
|
+
export declare function requiredEndpoint(edge: EdgeContract): (ContractEndpoint & {
|
|
55
|
+
readonly index: 0 | 1;
|
|
56
|
+
}) | undefined;
|
|
@@ -1,26 +1,95 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import { definitionRefIndex } from '../../addressing/ordering.js';
|
|
2
|
+
import { KERNEL_ORIGIN } from './inheritance.js';
|
|
3
|
+
/** The lifetime scope of `classes`. */
|
|
4
|
+
export function lifetimeScope(classes) {
|
|
5
|
+
const declarations = new Map();
|
|
6
|
+
for (const declaration of classes)
|
|
7
|
+
declarations.set(definitionRefIndex(declaration.ref), declaration);
|
|
8
|
+
const extendable = new Set();
|
|
9
|
+
const open = (ref) => {
|
|
10
|
+
const key = definitionRefIndex(ref);
|
|
11
|
+
if (extendable.has(key))
|
|
12
|
+
return;
|
|
13
|
+
extendable.add(key);
|
|
14
|
+
for (const parent of declarations.get(key)?.extends ?? [])
|
|
15
|
+
if (parent.origin === ref.origin)
|
|
16
|
+
open(parent);
|
|
17
|
+
};
|
|
18
|
+
for (const declaration of declarations.values())
|
|
19
|
+
if (declaration.kind === 'node' && declaration.inheritance === 'open')
|
|
20
|
+
open(declaration.ref);
|
|
21
|
+
return Object.freeze({
|
|
22
|
+
extendable: (ref) => extendable.has(definitionRefIndex(ref)),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/** The endpoints of an Edge contract in order: source then target, or the two incident ones. */
|
|
26
|
+
export function contractEndpoints(contract) {
|
|
27
|
+
return contract.orientation === 'directed'
|
|
12
28
|
? [
|
|
13
|
-
|
|
14
|
-
|
|
29
|
+
{ endpoint: contract.endpoints.source, count: contract.endpoints.source.outgoing },
|
|
30
|
+
{ endpoint: contract.endpoints.target, count: contract.endpoints.target.incoming },
|
|
15
31
|
]
|
|
16
32
|
: [
|
|
17
|
-
|
|
18
|
-
|
|
33
|
+
{ endpoint: contract.endpoints[0], count: contract.endpoints[0].incident },
|
|
34
|
+
{ endpoint: contract.endpoints[1], count: contract.endpoints[1].incident },
|
|
19
35
|
];
|
|
20
|
-
const required = endpoints.some(([, count]) => minimum(count) > 0);
|
|
21
|
-
const lifetime = ([accepts]) => !required && accepts.some((ref) => ref.origin !== origin) ? 'detach' : 'restrict';
|
|
22
|
-
return Object.freeze([lifetime(endpoints[0]), lifetime(endpoints[1])]);
|
|
23
36
|
}
|
|
24
|
-
|
|
25
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Whether an endpoint of an Edge Class of `origin` can hold a Node of another Domain: it accepts a
|
|
39
|
+
* Class `origin` does not own, or one another Domain may extend. The Kernel's own relations are the
|
|
40
|
+
* exception: every Domain depends on the Kernel and extends its roots, so its relations bind every
|
|
41
|
+
* Node and keep the lifetimes they have as closed Classes, however open the Kernel's Classes are.
|
|
42
|
+
*/
|
|
43
|
+
export function reachesAnotherDomain(origin, endpoint, scope) {
|
|
44
|
+
return endpoint.accepts.some((ref) => ref.origin !== origin || (origin !== KERNEL_ORIGIN && scope.extendable(ref)));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The lifetime of each endpoint of `edge`, in endpoint order: the one it declares, else the derived
|
|
48
|
+
* one.
|
|
49
|
+
*
|
|
50
|
+
* An Edge Class binds only the Nodes of its own Domain and of the Domains that depend on it, and a
|
|
51
|
+
* Domain blocks only the deletion of its own Nodes. An endpoint that can hold a Node of another
|
|
52
|
+
* Domain therefore detaches, unless an endpoint of the Class declares a minimum count that
|
|
53
|
+
* detaching could break (`requiredEndpoint`). Every other endpoint restricts.
|
|
54
|
+
*/
|
|
55
|
+
export function edgeLifetimes(edge, scope) {
|
|
56
|
+
const required = requiredEndpoint(edge) !== undefined;
|
|
57
|
+
const [head, tail] = contractEndpoints(edge).map(({ endpoint }) => endpoint.onDelete ??
|
|
58
|
+
(!required && reachesAnotherDomain(edge.ref.origin, endpoint, scope) ? 'detach' : 'restrict'));
|
|
59
|
+
return Object.freeze([head, tail]);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The breaches of the lifetime laws (LANGUAGE-EDGE-LIFETIME) by the lifetimes `edge` declares: an
|
|
63
|
+
* endpoint that can hold a Node of another Domain never restricts, and none detaches in a Class
|
|
64
|
+
* with an endpoint that requires an Edge (`requiredEndpoint`). A derived lifetime breaks neither.
|
|
65
|
+
*/
|
|
66
|
+
export function lifetimeBreaches(edge, scope) {
|
|
67
|
+
const required = requiredEndpoint(edge)?.count;
|
|
68
|
+
return Object.freeze(contractEndpoints(edge).flatMap(({ endpoint }, index) => {
|
|
69
|
+
const at = index;
|
|
70
|
+
if (endpoint.onDelete === 'restrict' &&
|
|
71
|
+
reachesAnotherDomain(edge.ref.origin, endpoint, scope))
|
|
72
|
+
return [
|
|
73
|
+
{
|
|
74
|
+
index: at,
|
|
75
|
+
reason: 'can hold Nodes of another Domain and cannot restrict their deletion.',
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
if (endpoint.onDelete === 'detach' && required !== undefined)
|
|
79
|
+
return [
|
|
80
|
+
{
|
|
81
|
+
index: at,
|
|
82
|
+
reason: `cannot detach: an endpoint of the Class requires ${required} Edges.`,
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
return [];
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The first endpoint of an Edge Class that requires an Edge, if one does, with its index. Detaching
|
|
90
|
+
* there could leave a Node below its count, so an endpoint of such a Class never detaches.
|
|
91
|
+
*/
|
|
92
|
+
export function requiredEndpoint(edge) {
|
|
93
|
+
const index = contractEndpoints(edge).findIndex(({ count }) => count === '1' || count === '1..*');
|
|
94
|
+
return index === -1 ? undefined : { ...contractEndpoints(edge)[index], index: index };
|
|
26
95
|
}
|
|
@@ -1,32 +1,68 @@
|
|
|
1
|
-
import type { ClassRef, DefinitionBase } from '../../../addressing/index.js';
|
|
1
|
+
import type { ClassRef, DefinitionBase, PropertyKey } from '../../../addressing/index.js';
|
|
2
2
|
import type { MethodRecord } from '../../callable/model/callable.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { EdgeClassPolicy, EdgeClassWritePolicy, NodeClassCreatePolicy, NodeClassPolicy, NodeClassWritePolicy } from '../../policy/model/policy.js';
|
|
4
4
|
import type { DataFacet } from './data.js';
|
|
5
5
|
import type { EdgeContract } from './edge.js';
|
|
6
|
-
import type { PropertyFacet } from './property.js';
|
|
6
|
+
import type { EdgePropertyDefinition, NodePropertyDefinition, PropertyFacet } from './property.js';
|
|
7
7
|
export type ClassKind = 'node' | 'edge';
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Which Classes may extend a Class: `'open'`, those of its Domain and of every Domain that depends
|
|
10
|
+
* on that Domain; `'internal'`, those of its Domain only; `'final'`, none.
|
|
11
|
+
*/
|
|
12
|
+
export type Inheritance = 'open' | 'internal' | 'final';
|
|
13
|
+
/**
|
|
14
|
+
* An absent observation rule admits every caller; a delegation is still scoped by its ceiling. An
|
|
15
|
+
* absent write rule admits only the Domain that declares the Class.
|
|
16
|
+
*/
|
|
9
17
|
export interface NodeClassPolicies {
|
|
10
18
|
readonly read?: NodeClassPolicy;
|
|
11
19
|
readonly traverse?: NodeClassPolicy;
|
|
20
|
+
readonly create?: NodeClassCreatePolicy;
|
|
21
|
+
readonly update?: NodeClassWritePolicy;
|
|
22
|
+
readonly delete?: NodeClassWritePolicy;
|
|
12
23
|
}
|
|
13
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* An absent observation rule admits every caller; a delegation is still scoped by its ceiling. An
|
|
26
|
+
* absent write rule admits only the Domain that declares the Class.
|
|
27
|
+
*/
|
|
14
28
|
export interface EdgeClassPolicies {
|
|
15
|
-
readonly read?:
|
|
16
|
-
readonly traverse?:
|
|
29
|
+
readonly read?: EdgeClassPolicy;
|
|
30
|
+
readonly traverse?: EdgeClassPolicy;
|
|
31
|
+
readonly create?: EdgeClassWritePolicy;
|
|
32
|
+
readonly update?: EdgeClassWritePolicy;
|
|
33
|
+
readonly delete?: EdgeClassWritePolicy;
|
|
17
34
|
}
|
|
18
|
-
|
|
35
|
+
/**
|
|
36
|
+
* The Properties one key of a Node Class names, own or inherited, which no two Nodes of the Classes
|
|
37
|
+
* it covers share while each of them is present: distinct, by key in code-point order.
|
|
38
|
+
*/
|
|
39
|
+
export type NodeUniqueTuple = readonly [PropertyKey, ...PropertyKey[]];
|
|
40
|
+
/**
|
|
41
|
+
* The form of a Node key tuple: its fields are Properties, whatever their keys and number. A
|
|
42
|
+
* backend announces it to enforce Node keys, so a tuple is never ignored where it is not.
|
|
43
|
+
*/
|
|
44
|
+
export type NodeUniqueForm = readonly ['property'];
|
|
45
|
+
export interface NodeClassDefinition extends DefinitionBase<ClassRef>, PropertyFacet<NodePropertyDefinition>, DataFacet {
|
|
19
46
|
readonly kind: 'node';
|
|
20
47
|
readonly abstract: boolean;
|
|
48
|
+
/** Absent when `'internal'`, the default, so a Class that keeps the default keeps its revision. */
|
|
49
|
+
readonly inheritance?: Exclude<Inheritance, 'internal'>;
|
|
21
50
|
readonly description?: string;
|
|
22
51
|
readonly extends: readonly ClassRef[];
|
|
23
52
|
readonly methods: MethodRecord;
|
|
24
53
|
readonly icon?: string;
|
|
25
54
|
readonly policies: NodeClassPolicies;
|
|
55
|
+
/**
|
|
56
|
+
* The tuples no two Nodes of this Class and of its active concrete descendants share while every
|
|
57
|
+
* Property is present; absent, none. A descendant is covered without declaring them again.
|
|
58
|
+
*/
|
|
59
|
+
readonly unique?: readonly [NodeUniqueTuple, ...NodeUniqueTuple[]];
|
|
26
60
|
}
|
|
27
|
-
export type EdgeClassDefinition = DefinitionBase<ClassRef> & PropertyFacet & EdgeContract & {
|
|
61
|
+
export type EdgeClassDefinition = DefinitionBase<ClassRef> & PropertyFacet<EdgePropertyDefinition> & EdgeContract & {
|
|
28
62
|
readonly kind: 'edge';
|
|
29
63
|
readonly abstract: boolean;
|
|
64
|
+
/** Absent when `'internal'`, the default, so a Class that keeps the default keeps its revision. */
|
|
65
|
+
readonly inheritance?: Exclude<Inheritance, 'internal'>;
|
|
30
66
|
readonly description?: string;
|
|
31
67
|
readonly extends: readonly ClassRef[];
|
|
32
68
|
readonly policies: EdgeClassPolicies;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import type { ClassRef } from '../../../addressing/index.js';
|
|
1
|
+
import type { ClassRef, PropertyKey } from '../../../addressing/index.js';
|
|
2
2
|
export type EdgeCount = '0..*' | '1..*' | '0..1' | '1';
|
|
3
3
|
export type EdgeOrientation = 'directed' | 'undirected';
|
|
4
|
+
/**
|
|
5
|
+
* What deleting the Node at one endpoint does to an Edge: `restrict` requires the transition to
|
|
6
|
+
* delete the Edge explicitly; `detach` deletes the Edge with the Node.
|
|
7
|
+
*/
|
|
8
|
+
export type EdgeLifetime = 'restrict' | 'detach';
|
|
4
9
|
export interface EdgeEndpointBase {
|
|
5
10
|
readonly role: string;
|
|
6
|
-
readonly accepts: readonly ClassRef[];
|
|
11
|
+
readonly accepts: readonly [ClassRef, ...ClassRef[]];
|
|
12
|
+
/** Declared only when authored; otherwise derived (`edgeLifetimes`). */
|
|
13
|
+
readonly onDelete?: EdgeLifetime;
|
|
7
14
|
}
|
|
8
15
|
export interface DirectedSourceEndpoint extends EdgeEndpointBase {
|
|
9
16
|
readonly outgoing: EdgeCount;
|
|
@@ -22,6 +29,22 @@ export interface UndirectedEdgeConstraints {
|
|
|
22
29
|
readonly noSelf?: true;
|
|
23
30
|
readonly acyclic?: never;
|
|
24
31
|
}
|
|
32
|
+
/** A field a key tuple names: an endpoint of the Edge, its slug, or one of its Properties. */
|
|
33
|
+
export type EdgeUniqueField = 'source' | 'target' | 'slug' | {
|
|
34
|
+
readonly property: PropertyKey;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* The fields one key of a directed Edge Class names, which no two Edges of the Classes it covers
|
|
38
|
+
* share while each of them is present: distinct, in canonical order (`compareEdgeUniqueFields`).
|
|
39
|
+
*/
|
|
40
|
+
export type EdgeUniqueTuple = readonly [EdgeUniqueField, ...EdgeUniqueField[]];
|
|
41
|
+
/** The kind of a key field: an endpoint, the slug, or a Property whatever its key. */
|
|
42
|
+
export type EdgeUniqueFieldKind = 'source' | 'target' | 'slug' | 'property';
|
|
43
|
+
/**
|
|
44
|
+
* The form of a key tuple: the kinds of its fields, each once, in canonical order. A backend
|
|
45
|
+
* announces the forms it enforces, so a tuple of a form it does not announce is never ignored.
|
|
46
|
+
*/
|
|
47
|
+
export type EdgeUniqueForm = readonly [EdgeUniqueFieldKind, ...EdgeUniqueFieldKind[]];
|
|
25
48
|
export interface DirectedEdgeContract {
|
|
26
49
|
readonly orientation: 'directed';
|
|
27
50
|
readonly endpoints: {
|
|
@@ -29,10 +52,16 @@ export interface DirectedEdgeContract {
|
|
|
29
52
|
readonly target: DirectedTargetEndpoint;
|
|
30
53
|
};
|
|
31
54
|
readonly constraints: DirectedEdgeConstraints;
|
|
55
|
+
/**
|
|
56
|
+
* The tuples no two Edges of this Class and of its active concrete descendants share. Absent
|
|
57
|
+
* when the Class declares none, so a Class without one keeps its revision; never empty.
|
|
58
|
+
*/
|
|
59
|
+
readonly unique?: readonly [EdgeUniqueTuple, ...EdgeUniqueTuple[]];
|
|
32
60
|
}
|
|
33
61
|
export interface UndirectedEdgeContract {
|
|
34
62
|
readonly orientation: 'undirected';
|
|
35
63
|
readonly endpoints: readonly [IncidentEndpoint, IncidentEndpoint];
|
|
36
64
|
readonly constraints: UndirectedEdgeConstraints;
|
|
65
|
+
readonly unique?: never;
|
|
37
66
|
}
|
|
38
67
|
export type EdgeContract = DirectedEdgeContract | UndirectedEdgeContract;
|
|
@@ -1,20 +1,29 @@
|
|
|
1
|
+
import type { StateTopology } from '../../state/index.js';
|
|
2
|
+
import type { JsonSchema } from '../../value/model/schema.js';
|
|
1
3
|
export type AutoEvent = 'create' | 'update';
|
|
2
4
|
export type AutoSet = 'instant';
|
|
3
5
|
/** `create`: written only by node or edge creation. `once`: written while absent, never unset. */
|
|
4
6
|
export type PropertyImmutability = 'create' | 'once';
|
|
5
7
|
export interface PropertyAuto {
|
|
6
|
-
readonly on: readonly AutoEvent[];
|
|
8
|
+
readonly on: readonly [AutoEvent, ...AutoEvent[]];
|
|
7
9
|
readonly set: AutoSet;
|
|
8
10
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
/** A Property of a Node Class, which may be a State Property. */
|
|
12
|
+
export interface NodePropertyDefinition {
|
|
13
|
+
readonly schema: JsonSchema;
|
|
11
14
|
readonly required: boolean;
|
|
12
15
|
readonly auto?: PropertyAuto;
|
|
13
16
|
readonly immutable?: PropertyImmutability;
|
|
14
17
|
readonly description?: string;
|
|
15
|
-
readonly state?:
|
|
18
|
+
readonly state?: StateTopology;
|
|
16
19
|
}
|
|
17
|
-
|
|
18
|
-
export interface
|
|
19
|
-
readonly
|
|
20
|
+
/** A Property of an Edge Class: an Edge has no State Property. */
|
|
21
|
+
export interface EdgePropertyDefinition extends Omit<NodePropertyDefinition, 'state'> {
|
|
22
|
+
readonly state?: never;
|
|
23
|
+
}
|
|
24
|
+
/** A Property of a Class of either kind. */
|
|
25
|
+
export type PropertyDefinition = NodePropertyDefinition | EdgePropertyDefinition;
|
|
26
|
+
export type PropertyRecord<Definition extends PropertyDefinition = PropertyDefinition> = Readonly<Record<string, Definition>>;
|
|
27
|
+
export interface PropertyFacet<Definition extends PropertyDefinition = PropertyDefinition> {
|
|
28
|
+
readonly properties: PropertyRecord<Definition>;
|
|
20
29
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { acceptPropertyRoot } from '../../../value/accept.js';
|
|
2
2
|
import { isImmutableSnapshot } from '../../../value/immutable.optimization.js';
|
|
3
3
|
import { PropertyKey as admitPropertyKey } from '../../addressing/index.js';
|
|
4
|
+
import { compareCodeUnits } from '../../addressing/ordering.js';
|
|
4
5
|
export function acceptPropertyValues(input, pointer = '') {
|
|
5
6
|
const admitted = acceptPropertyRoot(input);
|
|
6
7
|
if (admitted === null || typeof admitted !== 'object' || Array.isArray(admitted)) {
|
|
@@ -10,7 +11,7 @@ export function acceptPropertyValues(input, pointer = '') {
|
|
|
10
11
|
}
|
|
11
12
|
export function createPropertyValues(entries) {
|
|
12
13
|
const output = Object.create(null);
|
|
13
|
-
for (const [key, value] of [...entries].sort(([left], [right]) =>
|
|
14
|
+
for (const [key, value] of [...entries].sort(([left], [right]) => compareCodeUnits(left, right))) {
|
|
14
15
|
Object.defineProperty(output, key, { enumerable: true, value: freeze(value) });
|
|
15
16
|
}
|
|
16
17
|
return Object.freeze(output);
|
|
@@ -28,6 +29,3 @@ function freeze(value) {
|
|
|
28
29
|
freeze(member);
|
|
29
30
|
return Object.freeze(value);
|
|
30
31
|
}
|
|
31
|
-
function compare(left, right) {
|
|
32
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
33
|
-
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import type { Value as PortableValue } from '@astrale-os/kernel-dsl/value';
|
|
2
|
+
import type { ClassRef } from '../../addressing/index.js';
|
|
3
|
+
import type { OrderingKind } from '../value/ordering.js';
|
|
4
|
+
import type { ClassAncestry } from './inheritance.js';
|
|
5
|
+
import type { NodeUniqueForm, NodeUniqueTuple } from './model/class.js';
|
|
6
|
+
import type { EdgeUniqueField, EdgeUniqueForm, EdgeUniqueTuple } from './model/edge.js';
|
|
7
|
+
import { ClassKey } from '../../addressing/class-key.js';
|
|
8
|
+
/**
|
|
9
|
+
* Every form a key tuple may take, in canonical order: each nonempty set of field kinds. A Property
|
|
10
|
+
* kind stands for one Property or more, whatever their keys.
|
|
11
|
+
*/
|
|
12
|
+
export declare const EDGE_UNIQUE_FORMS: readonly EdgeUniqueForm[];
|
|
13
|
+
/** The one form a Node key tuple takes: its fields are Properties, whatever their keys. */
|
|
14
|
+
export declare const NODE_UNIQUE_FORMS: readonly NodeUniqueForm[];
|
|
15
|
+
/**
|
|
16
|
+
* The forms of key tuples a backend enforces, by the kind of the Classes they constrain: a Node key
|
|
17
|
+
* reads Node Properties and an Edge key the fields of an Edge, so announcing one says nothing of
|
|
18
|
+
* the other.
|
|
19
|
+
*/
|
|
20
|
+
export interface UniqueForms {
|
|
21
|
+
readonly edge: readonly EdgeUniqueForm[];
|
|
22
|
+
readonly node: readonly NodeUniqueForm[];
|
|
23
|
+
}
|
|
24
|
+
/** Every form of every kind, which a backend enforcing any key tuple announces. */
|
|
25
|
+
export declare const UNIQUE_FORMS: UniqueForms;
|
|
26
|
+
/** No form of either kind: a backend that announces none enforces no key tuple. */
|
|
27
|
+
export declare const NO_UNIQUE_FORMS: UniqueForms;
|
|
28
|
+
/** The fields of an Edge a key tuple reads; the slug is absent from an Edge without one. */
|
|
29
|
+
export interface EdgeUniqueFacts {
|
|
30
|
+
readonly source: string;
|
|
31
|
+
readonly target: string;
|
|
32
|
+
readonly slug?: string;
|
|
33
|
+
/** Its Property values by key; a Property it lacks is absent. */
|
|
34
|
+
readonly props: Readonly<Record<string, PortableValue>>;
|
|
35
|
+
}
|
|
36
|
+
/** The Properties of a Node a key tuple reads by key; a Property it lacks is absent. */
|
|
37
|
+
export interface NodeUniqueFacts {
|
|
38
|
+
readonly props: Readonly<Record<string, PortableValue>>;
|
|
39
|
+
}
|
|
40
|
+
/** The canonical order of fields: source, target, slug, then Properties by key. */
|
|
41
|
+
export declare function compareEdgeUniqueFields(left: EdgeUniqueField, right: EdgeUniqueField): number;
|
|
42
|
+
/** The canonical order of tuples: field by field, a tuple before every tuple it prefixes. */
|
|
43
|
+
export declare const compareEdgeUniqueTuples: (left: EdgeUniqueTuple, right: EdgeUniqueTuple) => number;
|
|
44
|
+
/**
|
|
45
|
+
* The tuple `value` spells, detached, or undefined when it spells none: a nonempty list of fields,
|
|
46
|
+
* distinct and in canonical order, so one set of fields has one spelling.
|
|
47
|
+
*/
|
|
48
|
+
export declare function edgeUniqueTuple(value: unknown): EdgeUniqueTuple | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* The tuple the endpoints and slug `named` holds spell, in canonical order, or undefined when it
|
|
51
|
+
* holds none: the key a selector names an Edge by. A selector names no Property.
|
|
52
|
+
*/
|
|
53
|
+
export declare function namedEdgeUniqueTuple(named: {
|
|
54
|
+
readonly source?: unknown;
|
|
55
|
+
readonly target?: unknown;
|
|
56
|
+
readonly slug?: unknown;
|
|
57
|
+
}): EdgeUniqueTuple | undefined;
|
|
58
|
+
/** The canonical order of Node tuples: Property by Property, a tuple before every one it prefixes. */
|
|
59
|
+
export declare const compareNodeUniqueTuples: (left: NodeUniqueTuple, right: NodeUniqueTuple) => number;
|
|
60
|
+
/**
|
|
61
|
+
* The Node tuple `value` spells, detached, or undefined when it spells none: a nonempty list of
|
|
62
|
+
* Property keys, distinct and in code-point order, so one set of Properties has one spelling.
|
|
63
|
+
*/
|
|
64
|
+
export declare function nodeUniqueTuple(value: unknown): NodeUniqueTuple | undefined;
|
|
65
|
+
/** The form of `NODE_UNIQUE_FORMS` that `value` spells, or undefined when it spells none. */
|
|
66
|
+
export declare function nodeUniqueForm(value: unknown): NodeUniqueForm | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* Whether a backend announcing `forms` for Nodes enforces the Node tuple `value` spells: every
|
|
69
|
+
* Node tuple has the one Node form. False when `value` spells no tuple.
|
|
70
|
+
*/
|
|
71
|
+
export declare function enforcesNodeUniqueTuple(forms: readonly NodeUniqueForm[], value: unknown): boolean;
|
|
72
|
+
/** The form of `tuple`: the kinds of its fields, each once. */
|
|
73
|
+
export declare function edgeUniqueFormOf(tuple: EdgeUniqueTuple): EdgeUniqueForm;
|
|
74
|
+
/** The form of `EDGE_UNIQUE_FORMS` that `value` spells, or undefined when it spells none. */
|
|
75
|
+
export declare function edgeUniqueForm(value: unknown): EdgeUniqueForm | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Whether a backend announcing `forms` enforces the tuple `value` spells: its form is one of them.
|
|
78
|
+
* False when `value` spells no tuple, so a tuple is never taken as enforced by mistake.
|
|
79
|
+
*/
|
|
80
|
+
export declare function enforcesEdgeUniqueTuple(forms: readonly EdgeUniqueForm[], value: unknown): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Whether a Property may be a key field (D-S1): a single-kind scalar by its ordering facet, a
|
|
83
|
+
* string, number, boolean or instant, that no automatic program writes.
|
|
84
|
+
*/
|
|
85
|
+
export declare function keyableProperty(ordering: OrderingKind | undefined, auto: unknown): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* The values of the fields of `tuple` on `edge`, in order, or undefined when one of them is absent,
|
|
88
|
+
* so that an Edge without a slug or without a Property never collides.
|
|
89
|
+
*/
|
|
90
|
+
export declare function edgeUniqueValues(tuple: EdgeUniqueTuple, edge: EdgeUniqueFacts): readonly PortableValue[] | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* The value `edge` takes under `tuple`, the canonical JSON of the values of its fields, or
|
|
93
|
+
* undefined when one of them is absent: two distinct Edges of the Classes a tuple covers collide
|
|
94
|
+
* exactly when they take one value. Endpoints compare by NodeId, slugs by exact text and
|
|
95
|
+
* Properties by canonical Value.
|
|
96
|
+
*/
|
|
97
|
+
export declare function edgeUniqueValue(tuple: EdgeUniqueTuple, edge: EdgeUniqueFacts): string | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* The values of the Properties of `tuple` on `node`, in order, or undefined when one of them is
|
|
100
|
+
* absent, so that a Node without one of them never collides, like NULL in an SQL UNIQUE.
|
|
101
|
+
*/
|
|
102
|
+
export declare function nodeUniqueValues(tuple: NodeUniqueTuple, node: NodeUniqueFacts): readonly PortableValue[] | undefined;
|
|
103
|
+
/**
|
|
104
|
+
* The value `node` takes under `tuple`, the canonical JSON of the values of its Properties, or
|
|
105
|
+
* undefined when one of them is absent: two distinct Nodes of the Classes a tuple covers collide
|
|
106
|
+
* exactly when they take one value. Properties compare by canonical Value, nothing normalized.
|
|
107
|
+
*/
|
|
108
|
+
export declare function nodeUniqueValue(tuple: NodeUniqueTuple, node: NodeUniqueFacts): string | undefined;
|
|
109
|
+
/** A Class with the key tuples it declares, an Edge Class or a Node Class. */
|
|
110
|
+
type KeyedClass = ClassAncestry & {
|
|
111
|
+
readonly unique?: readonly (EdgeUniqueTuple | NodeUniqueTuple)[];
|
|
112
|
+
};
|
|
113
|
+
/** A key tuple together with the Class declaring it, whose descendants it covers. */
|
|
114
|
+
export interface DeclaredEdgeUniqueTuple {
|
|
115
|
+
readonly class: ClassKey;
|
|
116
|
+
readonly fields: EdgeUniqueTuple;
|
|
117
|
+
}
|
|
118
|
+
/** A Node key tuple together with the Class declaring it, whose descendants it covers. */
|
|
119
|
+
export interface DeclaredNodeUniqueTuple {
|
|
120
|
+
readonly class: ClassKey;
|
|
121
|
+
readonly fields: NodeUniqueTuple;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* The tuples covering `candidate`: those it and each of its ancestors declare, each with the Class
|
|
125
|
+
* declaring it, ancestors found by `resolve`. A descendant never restates them.
|
|
126
|
+
*/
|
|
127
|
+
export declare function coveringEdgeUniqueTuples<Declaration extends KeyedClass>(candidate: Declaration, resolve: (ref: ClassRef) => Declaration | undefined): readonly DeclaredEdgeUniqueTuple[];
|
|
128
|
+
/**
|
|
129
|
+
* The Node tuples covering `candidate`: those it and each of its ancestors declare, each with the
|
|
130
|
+
* Class declaring it, ancestors found by `resolve`. A descendant never restates them.
|
|
131
|
+
*/
|
|
132
|
+
export declare function coveringNodeUniqueTuples<Declaration extends KeyedClass>(candidate: Declaration, resolve: (ref: ClassRef) => Declaration | undefined): readonly DeclaredNodeUniqueTuple[];
|
|
133
|
+
/**
|
|
134
|
+
* The keys `edge` holds: its value under each tuple of `tuples`, tagged by the Class declaring the
|
|
135
|
+
* tuple, so two Edges collide exactly when they hold one key.
|
|
136
|
+
*/
|
|
137
|
+
export declare function edgeUniqueKeys(tuples: readonly DeclaredEdgeUniqueTuple[], edge: EdgeUniqueFacts): readonly string[];
|
|
138
|
+
/**
|
|
139
|
+
* The keys `node` holds: its value under each tuple of `tuples`, tagged by the Class declaring the
|
|
140
|
+
* tuple, so two Nodes collide exactly when they hold one key.
|
|
141
|
+
*/
|
|
142
|
+
export declare function nodeUniqueKeys(tuples: readonly DeclaredNodeUniqueTuple[], node: NodeUniqueFacts): readonly string[];
|
|
143
|
+
export {};
|