@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,48 +1,63 @@
|
|
|
1
|
+
import { equalDefinitionRefs } from '../../addressing/definition-ref.js';
|
|
1
2
|
import { Key } from '../../addressing/key.js';
|
|
2
3
|
import { definitionRefIndex } from '../../addressing/ordering.js';
|
|
3
4
|
import { isMethodExecutable } from '../../language/callable/executable.js';
|
|
4
|
-
import { classSatisfies as satisfiesClass,
|
|
5
|
+
import { classSatisfies as satisfiesClass, edgeContractRefines as refinesEdgeContract, } from '../../language/class/inheritance.js';
|
|
6
|
+
import { lifetimeBreaches, lifetimeScope } from '../../language/class/lifetime.js';
|
|
7
|
+
import { keyableProperty } from '../../language/class/unique.js';
|
|
5
8
|
import { admitStateTopology } from '../../language/state/topology.js';
|
|
6
9
|
import { isBlobValueSchema } from '../../language/value/model/blob.js';
|
|
7
10
|
import { classifyOrdering } from '../../language/value/ordering.js';
|
|
11
|
+
import { escapePointerToken } from '../../language/value/syntax/pointer.js';
|
|
8
12
|
import { diagnostic } from '../diagnostic.js';
|
|
9
|
-
import {
|
|
13
|
+
import { createDomainValueSchemaRegistry } from '../resolution/value.registry.js';
|
|
10
14
|
const formatDefinitionRef = Key.of;
|
|
11
|
-
/**
|
|
12
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Validate the semantic contracts owned by Class declarations. `registry` is the candidate's value
|
|
17
|
+
* registry; each dependency's is built at most once, so the Classes share them.
|
|
18
|
+
*/
|
|
19
|
+
export function validateDefinitions(environment, analysis, registry) {
|
|
13
20
|
const diagnostics = [...analysis.diagnostics];
|
|
14
21
|
const schema = environment.candidate;
|
|
22
|
+
let scope;
|
|
23
|
+
const registries = new Map([[schema.origin, registry]]);
|
|
24
|
+
const registryOf = (origin) => {
|
|
25
|
+
if (!registries.has(origin)) {
|
|
26
|
+
const dependency = environment.dependencies.get(origin);
|
|
27
|
+
registries.set(origin, dependency === undefined ? undefined : createDomainValueSchemaRegistry(dependency));
|
|
28
|
+
}
|
|
29
|
+
return registries.get(origin);
|
|
30
|
+
};
|
|
15
31
|
for (const [name, declaration] of Object.entries(schema.classes)) {
|
|
16
|
-
const ref =
|
|
17
|
-
const pointer = `/classes/${
|
|
18
|
-
if (!
|
|
32
|
+
const ref = { origin: schema.origin, kind: 'class', name };
|
|
33
|
+
const pointer = `/classes/${escapePointerToken(name)}`;
|
|
34
|
+
if (!equalDefinitionRefs(declaration.ref, ref)) {
|
|
19
35
|
diagnostics.push(diagnostic('DV_REF_RESOLVES', `${pointer}/ref`, `Class ref must be exactly ${formatDefinitionRef(ref)}.`, formatDefinitionRef(declaration.ref)));
|
|
20
36
|
}
|
|
21
|
-
if (declaration.abstract &&
|
|
22
|
-
(
|
|
23
|
-
diagnostics.push(diagnostic('DV_CLASS_ABSTRACT', `${pointer}/policies`, 'Abstract Classes cannot declare observation Policies.'));
|
|
37
|
+
if (declaration.abstract && Object.keys(declaration.policies).length > 0) {
|
|
38
|
+
diagnostics.push(diagnostic('DV_CLASS_ABSTRACT', `${pointer}/policies`, 'Abstract Classes cannot declare Class Policies.'));
|
|
24
39
|
}
|
|
25
|
-
validateFacet(
|
|
40
|
+
validateFacet(registry, declaration, pointer, diagnostics);
|
|
26
41
|
validateParents(environment, ref, declaration.kind, declaration.extends, diagnostics);
|
|
27
42
|
if (declaration.kind === 'edge') {
|
|
28
|
-
validateEdgeContract(environment, ref, declaration, diagnostics);
|
|
43
|
+
validateEdgeContract(environment, ref, declaration, pointer, diagnostics);
|
|
44
|
+
scope ??= lifetimeScope([...environment.definitions.values()].map(({ declaration }) => declaration));
|
|
45
|
+
validateEdgeLifetimes(scope, ref, declaration, pointer, diagnostics);
|
|
46
|
+
validateEdgeClassComposition(environment, ref, declaration, pointer, diagnostics);
|
|
29
47
|
}
|
|
48
|
+
validateUniqueProperties(registryOf, analysis, ref, declaration, pointer, diagnostics);
|
|
30
49
|
}
|
|
31
|
-
validateEdgeClassComposition(environment, diagnostics);
|
|
32
50
|
return Object.freeze(diagnostics);
|
|
33
51
|
}
|
|
34
|
-
function validateFacet(
|
|
35
|
-
const valueRegistry = createValueSchemaRegistry(environment);
|
|
52
|
+
function validateFacet(valueRegistry, declaration, pointer, diagnostics) {
|
|
36
53
|
for (const [name, property] of Object.entries(declaration.properties)) {
|
|
37
|
-
const propertyPointer = `${pointer}/properties/${
|
|
54
|
+
const propertyPointer = `${pointer}/properties/${escapePointerToken(name)}`;
|
|
55
|
+
// The structure refuses a blob on an Edge Property and a State Property on an Edge Class.
|
|
38
56
|
if (isBlobValueSchema(property.schema) &&
|
|
39
|
-
(
|
|
57
|
+
(property.auto !== undefined || property.state !== undefined)) {
|
|
40
58
|
diagnostics.push(diagnostic('DV_VALUE_SCHEMA', `${propertyPointer}/schema/x-astrale-value-kind`, 'Blob values are allowed only on non-automatic, non-state Node properties.'));
|
|
41
59
|
}
|
|
42
60
|
if (property.state !== undefined) {
|
|
43
|
-
if (declaration.kind !== 'node') {
|
|
44
|
-
diagnostics.push(diagnostic('DV_PROPERTY_STATE', `${propertyPointer}/state`, 'A State Property may be declared only on a Node Class.'));
|
|
45
|
-
}
|
|
46
61
|
try {
|
|
47
62
|
const topology = admitStateTopology(property.state);
|
|
48
63
|
const expected = Object.keys(topology.transitions).sort();
|
|
@@ -86,16 +101,22 @@ function validateFacet(environment, declaration, pointer, diagnostics) {
|
|
|
86
101
|
if (declaration.kind !== 'node')
|
|
87
102
|
return;
|
|
88
103
|
for (const [name, method] of Object.entries(declaration.methods)) {
|
|
89
|
-
const methodPointer = `${pointer}/methods/${
|
|
90
|
-
if (
|
|
104
|
+
const methodPointer = `${pointer}/methods/${escapePointerToken(name)}`;
|
|
105
|
+
if (isMethodExecutable(declaration, method))
|
|
106
|
+
continue;
|
|
107
|
+
if (method.policy !== undefined) {
|
|
91
108
|
diagnostics.push(diagnostic('DV_METHOD_ABSTRACT', `${methodPointer}/policy`, 'Abstract Methods cannot have a Policy.'));
|
|
92
109
|
}
|
|
110
|
+
// An admission age qualifies the admission of an executable declaration, like its Policy.
|
|
111
|
+
if (method.admission !== undefined) {
|
|
112
|
+
diagnostics.push(diagnostic('DV_METHOD_ABSTRACT', `${methodPointer}/admission`, 'Abstract Methods cannot have an admission age.'));
|
|
113
|
+
}
|
|
93
114
|
}
|
|
94
115
|
}
|
|
95
116
|
function validateParents(environment, owner, ownerKind, parents, diagnostics) {
|
|
96
117
|
for (const [index, parent] of parents.entries()) {
|
|
97
118
|
const target = environment.resolve(parent);
|
|
98
|
-
const pointer = `/classes/${
|
|
119
|
+
const pointer = `/classes/${escapePointerToken(owner.name)}/extends/${index}`;
|
|
99
120
|
if (target === undefined) {
|
|
100
121
|
diagnostics.push(diagnostic('DV_REF_RESOLVES', pointer, `Parent ${formatDefinitionRef(parent)} does not resolve exactly.`, formatDefinitionRef(parent)));
|
|
101
122
|
continue;
|
|
@@ -103,105 +124,116 @@ function validateParents(environment, owner, ownerKind, parents, diagnostics) {
|
|
|
103
124
|
if (target.ref.kind !== 'class' || target.declaration.kind !== ownerKind) {
|
|
104
125
|
diagnostics.push(diagnostic('DV_CLASS_KIND', pointer, `${formatDefinitionRef(owner)} cannot extend different-kind Class ${formatDefinitionRef(parent)}.`, formatDefinitionRef(parent)));
|
|
105
126
|
}
|
|
127
|
+
else if (target.declaration.inheritance === 'final') {
|
|
128
|
+
diagnostics.push(diagnostic('DV_CLASS_INHERITANCE', pointer, `${formatDefinitionRef(owner)} cannot extend final Class ${formatDefinitionRef(parent)}.`, formatDefinitionRef(parent)));
|
|
129
|
+
}
|
|
106
130
|
}
|
|
107
131
|
}
|
|
108
|
-
function validateEdgeContract(environment, owner, declaration, diagnostics) {
|
|
109
|
-
const
|
|
132
|
+
function validateEdgeContract(environment, owner, declaration, pointer, diagnostics) {
|
|
133
|
+
const directed = declaration.orientation === 'directed';
|
|
134
|
+
const endpoints = directed
|
|
110
135
|
? [declaration.endpoints.source, declaration.endpoints.target]
|
|
111
136
|
: declaration.endpoints;
|
|
137
|
+
const keys = directed ? ['source', 'target'] : ['0', '1'];
|
|
112
138
|
if (endpoints[0].role === endpoints[1].role) {
|
|
113
|
-
diagnostics.push(diagnostic('DV_EDGE_ROLE',
|
|
139
|
+
diagnostics.push(diagnostic('DV_EDGE_ROLE', `${pointer}/endpoints/${keys[1]}/role`, `${formatDefinitionRef(owner)} has equal endpoint roles.`));
|
|
114
140
|
}
|
|
115
|
-
const counts =
|
|
116
|
-
? [
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
141
|
+
const counts = directed
|
|
142
|
+
? [
|
|
143
|
+
['outgoing', declaration.endpoints.source.outgoing],
|
|
144
|
+
['incoming', declaration.endpoints.target.incoming],
|
|
145
|
+
]
|
|
146
|
+
: [
|
|
147
|
+
['incident', declaration.endpoints[0].incident],
|
|
148
|
+
['incident', declaration.endpoints[1].incident],
|
|
149
|
+
];
|
|
150
|
+
validateEndpoint(environment, owner, endpoints[0], counts[0], directed ? 'source' : 'first endpoint', `${pointer}/endpoints/${keys[0]}`, diagnostics);
|
|
151
|
+
validateEndpoint(environment, owner, endpoints[1], counts[1], directed ? 'target' : 'second endpoint', `${pointer}/endpoints/${keys[1]}`, diagnostics);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Each Property a key tuple names is one of the Class's own or inherited Properties, and keyable:
|
|
155
|
+
* a single-kind scalar by its ordering facet that no automatic program writes (D-S1). Properties
|
|
156
|
+
* inherit without redefinition, so the key reads one meaning on every descendant it covers. A Node
|
|
157
|
+
* tuple names Properties only; an Edge tuple names them as `{ property }` beside its other fields.
|
|
158
|
+
*/
|
|
159
|
+
function validateUniqueProperties(registryOf, analysis, owner, declaration, pointer, diagnostics) {
|
|
160
|
+
if (declaration.kind === 'edge' && declaration.orientation !== 'directed')
|
|
161
|
+
return;
|
|
162
|
+
if (declaration.unique === undefined)
|
|
163
|
+
return;
|
|
164
|
+
const properties = analysis.definitions.get(definitionRefIndex(owner))?.properties;
|
|
165
|
+
if (properties === undefined)
|
|
166
|
+
return;
|
|
167
|
+
const code = declaration.kind === 'node' ? 'DV_NODE_UNIQUE' : 'DV_EDGE_UNIQUE';
|
|
168
|
+
const check = (key, at) => {
|
|
169
|
+
const property = properties.get(key);
|
|
170
|
+
if (property === undefined) {
|
|
171
|
+
diagnostics.push(diagnostic(code, at, `${key} is not a Property of the Class.`));
|
|
172
|
+
return;
|
|
123
173
|
}
|
|
174
|
+
const registry = registryOf(property.owner.origin);
|
|
175
|
+
const ordering = registry === undefined ? undefined : classifyOrdering(property.schema, registry);
|
|
176
|
+
if (!keyableProperty(ordering, property.auto)) {
|
|
177
|
+
diagnostics.push(diagnostic(code, at, 'A key Property is a string, number, boolean or instant that no automatic program writes.'));
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
if (declaration.kind === 'node') {
|
|
181
|
+
declaration.unique.forEach((tuple, t) => tuple.forEach((key, f) => check(key, `${pointer}/unique/${t}/${f}`)));
|
|
182
|
+
return;
|
|
124
183
|
}
|
|
184
|
+
declaration.unique.forEach((tuple, t) => tuple.forEach((field, f) => {
|
|
185
|
+
if (typeof field !== 'string')
|
|
186
|
+
check(field.property, `${pointer}/unique/${t}/${f}/property`);
|
|
187
|
+
}));
|
|
125
188
|
}
|
|
126
|
-
|
|
189
|
+
// The structure refuses a repeated accepted Class before semantics: `accepts` is a set.
|
|
190
|
+
function validateEndpoint(environment, owner, endpoint, [countField, count], side, pointer, diagnostics) {
|
|
127
191
|
// An Edge Class binds only the Nodes of its Domain and its dependents: it cannot oblige the
|
|
128
192
|
// Nodes of a Class another Domain owns to carry its Edges.
|
|
129
193
|
const foreign = endpoint.accepts.find((ref) => ref.origin !== owner.origin);
|
|
130
194
|
if (foreign !== undefined && (count === '1' || count === '1..*')) {
|
|
131
|
-
diagnostics.push(diagnostic('DV_EDGE_FOREIGN_MINIMUM',
|
|
195
|
+
diagnostics.push(diagnostic('DV_EDGE_FOREIGN_MINIMUM', `${pointer}/${countField}`, `${formatDefinitionRef(owner)} ${side} accepts ${formatDefinitionRef(foreign)} of another Domain and cannot require ${count} Edges.`));
|
|
132
196
|
}
|
|
133
|
-
const
|
|
134
|
-
for (const ref of endpoint.accepts) {
|
|
135
|
-
const key = definitionRefIndex(ref);
|
|
136
|
-
if (seen.has(key)) {
|
|
137
|
-
diagnostics.push(diagnostic('DV_EDGE_ACCEPTS', '', `${formatDefinitionRef(owner)} ${side} repeats ${formatDefinitionRef(ref)}.`));
|
|
138
|
-
}
|
|
139
|
-
seen.add(key);
|
|
197
|
+
for (const [index, ref] of endpoint.accepts.entries()) {
|
|
140
198
|
const resolved = environment.resolve(ref);
|
|
141
199
|
if (resolved === undefined ||
|
|
142
200
|
resolved.ref.kind !== 'class' ||
|
|
143
201
|
resolved.declaration.kind !== 'node') {
|
|
144
|
-
diagnostics.push(diagnostic('DV_EDGE_ACCEPTS',
|
|
202
|
+
diagnostics.push(diagnostic('DV_EDGE_ACCEPTS', `${pointer}/accepts/${index}`, `${formatDefinitionRef(owner)} ${side} ref ${formatDefinitionRef(ref)} does not resolve to a Node Class.`));
|
|
145
203
|
}
|
|
146
204
|
}
|
|
147
205
|
}
|
|
148
|
-
/**
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
206
|
+
/**
|
|
207
|
+
* The lifetime laws over the lifetimes a Schema declares. What an endpoint derives where it
|
|
208
|
+
* declares nothing is never refused here: a stored Registry decoded again keeps it.
|
|
209
|
+
*/
|
|
210
|
+
function validateEdgeLifetimes(scope, owner, declaration, pointer, diagnostics) {
|
|
211
|
+
const sides = declaration.orientation === 'directed'
|
|
212
|
+
? ['source', 'target']
|
|
213
|
+
: ['first endpoint', 'second endpoint'];
|
|
214
|
+
const keys = declaration.orientation === 'directed' ? ['source', 'target'] : ['0', '1'];
|
|
215
|
+
for (const { index, reason } of lifetimeBreaches(declaration, scope)) {
|
|
216
|
+
diagnostics.push(diagnostic('DV_EDGE_LIFETIME', `${pointer}/endpoints/${keys[index]}/onDelete`, `${formatDefinitionRef(owner)} ${sides[index]} ${reason}`));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Edge inheritance is refinement, not a second interface composition mechanism. A dependency
|
|
221
|
+
* Edge Class was judged against this same exact closure when it was accepted.
|
|
222
|
+
*/
|
|
223
|
+
function validateEdgeClassComposition(environment, owner, child, pointer, diagnostics) {
|
|
224
|
+
for (const [index, parentRef] of child.extends.entries()) {
|
|
225
|
+
const parent = environment.resolveAny(parentRef);
|
|
226
|
+
if (parent === undefined || parent.ref.kind !== 'class' || parent.declaration.kind !== 'edge') {
|
|
152
227
|
continue;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (parent === undefined ||
|
|
157
|
-
parent.ref.kind !== 'class' ||
|
|
158
|
-
parent.declaration.kind !== 'edge') {
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
if (!edgeContractRefines(environment, child, parent.declaration)) {
|
|
162
|
-
diagnostics.push(diagnostic('DV_EDGE_CLASS_COMPOSITION', '', `${formatDefinitionRef(resolved.ref)} does not safely refine ${formatDefinitionRef(parentRef)}.`));
|
|
163
|
-
}
|
|
228
|
+
}
|
|
229
|
+
if (!edgeContractRefines(environment, child, parent.declaration)) {
|
|
230
|
+
diagnostics.push(diagnostic('DV_EDGE_CLASS_COMPOSITION', `${pointer}/extends/${index}`, `${formatDefinitionRef(owner)} does not safely refine ${formatDefinitionRef(parentRef)}.`));
|
|
164
231
|
}
|
|
165
232
|
}
|
|
166
233
|
}
|
|
167
234
|
/** Whether `child` safely refines its parent Edge contract `parent`. */
|
|
168
235
|
export function edgeContractRefines(environment, child, parent) {
|
|
169
|
-
|
|
170
|
-
return true;
|
|
171
|
-
if (child.orientation !== parent.orientation)
|
|
172
|
-
return false;
|
|
173
|
-
if (parent.constraints.noSelf === true && child.constraints.noSelf !== true)
|
|
174
|
-
return false;
|
|
175
|
-
if (parent.constraints.acyclic === true && child.constraints.acyclic !== true)
|
|
176
|
-
return false;
|
|
177
|
-
if (child.orientation === 'directed' && parent.orientation === 'directed') {
|
|
178
|
-
return (endpointRefines(environment, child.endpoints.source, parent.endpoints.source) &&
|
|
179
|
-
countRefines(child.endpoints.source.outgoing, parent.endpoints.source.outgoing) &&
|
|
180
|
-
endpointRefines(environment, child.endpoints.target, parent.endpoints.target) &&
|
|
181
|
-
countRefines(child.endpoints.target.incoming, parent.endpoints.target.incoming));
|
|
182
|
-
}
|
|
183
|
-
if (child.orientation !== 'undirected' || parent.orientation !== 'undirected')
|
|
184
|
-
return false;
|
|
185
|
-
const refines = (childIndex, parentIndex) => endpointRefines(environment, child.endpoints[childIndex], parent.endpoints[parentIndex]) &&
|
|
186
|
-
countRefines(child.endpoints[childIndex].incident, parent.endpoints[parentIndex].incident);
|
|
187
|
-
const direct = refines(0, 0) && refines(1, 1);
|
|
188
|
-
if (direct)
|
|
189
|
-
return true;
|
|
190
|
-
return refines(0, 1) && refines(1, 0);
|
|
191
|
-
}
|
|
192
|
-
function endpointRefines(environment, child, parent) {
|
|
193
|
-
return child.accepts.every((accepted) => classSatisfies(environment, accepted, parent.accepts));
|
|
194
|
-
}
|
|
195
|
-
function countRefines(child, parent) {
|
|
196
|
-
const bounds = {
|
|
197
|
-
'0..*': [0, Number.POSITIVE_INFINITY],
|
|
198
|
-
'1..*': [1, Number.POSITIVE_INFINITY],
|
|
199
|
-
'0..1': [0, 1],
|
|
200
|
-
'1': [1, 1],
|
|
201
|
-
};
|
|
202
|
-
const [childMinimum, childMaximum] = bounds[child];
|
|
203
|
-
const [parentMinimum, parentMaximum] = bounds[parent];
|
|
204
|
-
return childMinimum >= parentMinimum && childMaximum <= parentMaximum;
|
|
236
|
+
return refinesEdgeContract(child, parent, (candidate, accepts) => classSatisfies(environment, candidate, accepts));
|
|
205
237
|
}
|
|
206
238
|
/** Whether `candidate` is, or is a Node Class extending, one of `accepts`. */
|
|
207
239
|
export function classSatisfies(environment, candidate, accepts) {
|
|
@@ -216,12 +248,3 @@ export function classSatisfies(environment, candidate, accepts) {
|
|
|
216
248
|
return required !== undefined && satisfiesClass(actual, required, resolve);
|
|
217
249
|
});
|
|
218
250
|
}
|
|
219
|
-
function localRef(origin, name) {
|
|
220
|
-
return { origin, kind: 'class', name };
|
|
221
|
-
}
|
|
222
|
-
function sameRef(left, right) {
|
|
223
|
-
return left.origin === right.origin && left.kind === right.kind && left.name === right.name;
|
|
224
|
-
}
|
|
225
|
-
function escapePointer(value) {
|
|
226
|
-
return value.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
227
|
-
}
|
|
@@ -1,26 +1,44 @@
|
|
|
1
|
+
import { equalDefinitionRefs } from '../../addressing/definition-ref.js';
|
|
1
2
|
import { Key } from '../../addressing/key.js';
|
|
2
3
|
import { compareUnicode, definitionRefIndex } from '../../addressing/ordering.js';
|
|
3
4
|
import { isMethodExecutable } from '../../language/callable/executable.js';
|
|
5
|
+
import { coveringEdgeUniqueTuples, coveringNodeUniqueTuples, edgeUniqueKeys, nodeUniqueKeys, } from '../../language/class/unique.js';
|
|
6
|
+
import { checkCoreEdgeSet, checkHeldKeys, coreEndpointsSatisfy, DOMAIN_ENDPOINT_CLASS, } from '../../language/core/facts.js';
|
|
4
7
|
import { policyObjectKey, policyObjectOrigin, projectedMemberClass, } from '../../language/policy/model/policy.js';
|
|
5
8
|
import { validateJsonInstance } from '../../language/value/evaluate/validate.js';
|
|
6
|
-
import {
|
|
9
|
+
import { escapePointerToken } from '../../language/value/syntax/pointer.js';
|
|
10
|
+
import { diagnostic, valueDiagnostic } from '../diagnostic.js';
|
|
7
11
|
import { classSatisfies } from './class.js';
|
|
8
12
|
const formatDefinitionRef = Key.of;
|
|
9
13
|
export function validateCore(environment, analysis, registry) {
|
|
10
14
|
const diagnostics = [];
|
|
11
15
|
const nodesByRef = resolveCoreNodes(environment, analysis, registry, diagnostics);
|
|
12
16
|
const edges = resolveCoreEdges(environment, analysis, registry, nodesByRef, diagnostics);
|
|
17
|
+
validateCoreNodeKeys(environment, nodesByRef, diagnostics);
|
|
13
18
|
validateCoreEdgeSet(environment, edges, nodesByRef, diagnostics);
|
|
14
19
|
return Object.freeze(diagnostics);
|
|
15
20
|
}
|
|
21
|
+
/** No two Core Nodes hold one key under a tuple covering their Classes, whichever declares it. */
|
|
22
|
+
function validateCoreNodeKeys(environment, nodesByRef, diagnostics) {
|
|
23
|
+
const resolve = (ref) => environment.resolveAny(ref)?.declaration;
|
|
24
|
+
checkHeldKeys(nodesByRef.values(), (node) => {
|
|
25
|
+
const declaration = resolve(node.classRef);
|
|
26
|
+
if (declaration === undefined)
|
|
27
|
+
return [];
|
|
28
|
+
return nodeUniqueKeys(coveringNodeUniqueTuples(declaration, resolve), {
|
|
29
|
+
props: environment.candidate.core.nodes[node.slug].properties,
|
|
30
|
+
});
|
|
31
|
+
}, (node, previous) => diagnostics.push(diagnostic('DV_CORE_NODE_UNIQUE', nodePointer(node), `Core Node holds a key the Core Node at ${nodePointer(previous)} holds.`)));
|
|
32
|
+
}
|
|
33
|
+
function nodePointer(node) {
|
|
34
|
+
return `/core/nodes/${escapePointerToken(node.slug)}`;
|
|
35
|
+
}
|
|
16
36
|
function resolveCoreNodes(environment, analysis, registry, diagnostics) {
|
|
17
37
|
const nodes = new Map();
|
|
18
38
|
for (const [slug, node] of Object.entries(environment.candidate.core.nodes)) {
|
|
19
|
-
const pointer = `/core/nodes/${
|
|
39
|
+
const pointer = `/core/nodes/${escapePointerToken(slug)}`;
|
|
20
40
|
const ref = { origin: environment.candidate.origin, kind: 'core', name: slug };
|
|
21
|
-
if (node.ref
|
|
22
|
-
node.ref.kind !== ref.kind ||
|
|
23
|
-
node.ref.name !== ref.name) {
|
|
41
|
+
if (!equalDefinitionRefs(node.ref, ref)) {
|
|
24
42
|
diagnostics.push(diagnostic('DV_REF_RESOLVES', `${pointer}/ref`, `Core ref must be exactly ${formatDefinitionRef(ref)}.`, formatDefinitionRef(node.ref)));
|
|
25
43
|
}
|
|
26
44
|
const resolved = environment.resolve(node.class);
|
|
@@ -63,15 +81,11 @@ function resolveCoreEdges(environment, analysis, registry, nodesByRef, diagnosti
|
|
|
63
81
|
const declaration = resolved.declaration;
|
|
64
82
|
if (source === undefined || target === undefined)
|
|
65
83
|
continue;
|
|
66
|
-
const endpointsSatisfy = declaration
|
|
67
|
-
? endpointSatisfies(environment, source, declaration.endpoints.source.accepts) &&
|
|
68
|
-
endpointSatisfies(environment, target, declaration.endpoints.target.accepts)
|
|
69
|
-
: (endpointSatisfies(environment, source, declaration.endpoints[0].accepts) &&
|
|
70
|
-
endpointSatisfies(environment, target, declaration.endpoints[1].accepts)) ||
|
|
71
|
-
(endpointSatisfies(environment, source, declaration.endpoints[1].accepts) &&
|
|
72
|
-
endpointSatisfies(environment, target, declaration.endpoints[0].accepts));
|
|
84
|
+
const endpointsSatisfy = coreEndpointsSatisfy(declaration, source, target, (endpoint, accepts) => endpointSatisfies(environment, endpoint, accepts));
|
|
73
85
|
if (!endpointsSatisfy) {
|
|
74
|
-
diagnostics.push(diagnostic('DV_CORE_EDGE_CLASS', pointer, `Core Edge endpoints do not satisfy ${formatDefinitionRef(edge.class)}
|
|
86
|
+
diagnostics.push(diagnostic('DV_CORE_EDGE_CLASS', pointer, `Core Edge endpoints do not satisfy ${formatDefinitionRef(edge.class)}.${source.kind === 'domain' || target.kind === 'domain'
|
|
87
|
+
? ` The owning Domain is a ${formatDefinitionRef(DOMAIN_ENDPOINT_CLASS)} Node: the endpoint that names it must accept that Class or one it extends.`
|
|
88
|
+
: ''}`, formatDefinitionRef(edge.class)));
|
|
75
89
|
continue;
|
|
76
90
|
}
|
|
77
91
|
edges.push({ source, target, declaration, value: edge, pointer });
|
|
@@ -80,7 +94,7 @@ function resolveCoreEdges(environment, analysis, registry, nodesByRef, diagnosti
|
|
|
80
94
|
}
|
|
81
95
|
function resolveCoreEndpoint(environment, ref, pointer, nodesByRef, diagnostics) {
|
|
82
96
|
if (ref.kind === 'domain')
|
|
83
|
-
return { kind: 'domain', ref, key: 'domain' };
|
|
97
|
+
return { kind: 'domain', ref, key: 'domain', classRef: DOMAIN_ENDPOINT_CLASS };
|
|
84
98
|
const undeclared = () => {
|
|
85
99
|
const key = policyObjectKey(ref);
|
|
86
100
|
diagnostics.push(diagnostic('DV_CORE_REF', pointer, `Core endpoint ${key} does not name a declared local Definition.`, key));
|
|
@@ -110,10 +124,14 @@ function declaresProjectedMember(environment, ref) {
|
|
|
110
124
|
return Object.hasOwn(candidate.policies, ref.name);
|
|
111
125
|
return Object.hasOwn(candidate.views, ref.name);
|
|
112
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* A Core Node is admitted by its own authored Class, a projected member by the Kernel declaration
|
|
129
|
+
* Class it projects as, and the owning Domain by the Kernel `Domain` Class of its Node: the write
|
|
130
|
+
* that projects the Edge binds exactly that Node, so an Edge Class that does not accept it can
|
|
131
|
+
* never be installed (DV-CORE-EDGE-CLASS).
|
|
132
|
+
*/
|
|
113
133
|
function endpointSatisfies(environment, endpoint, accepts) {
|
|
114
|
-
|
|
115
|
-
// Its concrete Class contract is therefore admitted by the projection compiler.
|
|
116
|
-
return endpoint.kind === 'domain' || classSatisfies(environment, endpoint.classRef, accepts);
|
|
134
|
+
return classSatisfies(environment, endpoint.classRef, accepts);
|
|
117
135
|
}
|
|
118
136
|
function validateCreationProperties(definition, properties, registry, code, pointer, diagnostics) {
|
|
119
137
|
const schema = {
|
|
@@ -127,166 +145,70 @@ function validateCreationProperties(definition, properties, registry, code, poin
|
|
|
127
145
|
.sort(compareUnicode),
|
|
128
146
|
additionalProperties: false,
|
|
129
147
|
};
|
|
130
|
-
for (const
|
|
131
|
-
diagnostics.push(
|
|
148
|
+
for (const refusal of validateJsonInstance(schema, properties, registry, pointer)) {
|
|
149
|
+
diagnostics.push(valueDiagnostic(code, refusal));
|
|
132
150
|
}
|
|
133
151
|
}
|
|
134
152
|
function validateCoreEdgeSet(environment, edges, nodesByRef, diagnostics) {
|
|
135
|
-
const
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
for (const edge of edges) {
|
|
155
|
-
const classKey = definitionRefIndex(edge.value.class);
|
|
156
|
-
const [source, target] = edge.declaration.orientation === 'undirected' &&
|
|
157
|
-
compareUnicode(edge.source.key, edge.target.key) > 0
|
|
158
|
-
? [edge.target.key, edge.source.key]
|
|
159
|
-
: [edge.source.key, edge.target.key];
|
|
160
|
-
const key = `${classKey}\u0000${source}\u0000${target}`;
|
|
161
|
-
const previous = seen.get(key);
|
|
162
|
-
if (previous !== undefined) {
|
|
163
|
-
diagnostics.push(diagnostic('DV_CORE_EDGE_KEY', edge.pointer, `Core Edge duplicates the normalized EdgeKey declared at ${previous}.`));
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
seen.set(key, edge.pointer);
|
|
167
|
-
}
|
|
168
|
-
const slice = edgeSlices.get(classKey) ?? {
|
|
169
|
-
declaration: edge.declaration,
|
|
170
|
-
edges: [],
|
|
171
|
-
};
|
|
172
|
-
slice.edges.push(edge);
|
|
173
|
-
edgeSlices.set(classKey, slice);
|
|
174
|
-
if (edge.declaration.constraints.noSelf === true && edge.source.key === edge.target.key) {
|
|
175
|
-
diagnostics.push(diagnostic('DV_CORE_EDGE_CONSTRAINTS', edge.pointer, 'Core Edge violates noSelf.'));
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
for (const { declaration, edges: classEdges } of edgeSlices.values()) {
|
|
179
|
-
if (declaration.constraints.acyclic === true && hasDirectedCycle(classEdges)) {
|
|
180
|
-
diagnostics.push(diagnostic('DV_CORE_EDGE_CONSTRAINTS', '/core/edges', 'Core Edge set violates exact-Class acyclicity.'));
|
|
181
|
-
}
|
|
182
|
-
validateCardinality(environment, declaration, classEdges, nodesByRef, diagnostics);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
function validateCardinality(environment, declaration, edges, nodesByRef, diagnostics) {
|
|
186
|
-
const subjects = cardinalitySubjects(edges, nodesByRef);
|
|
187
|
-
if (declaration.orientation === 'undirected') {
|
|
188
|
-
const [first, second] = declaration.endpoints;
|
|
189
|
-
for (const subject of subjects) {
|
|
190
|
-
const matchesFirst = classSatisfies(environment, subject.classRef, first.accepts);
|
|
191
|
-
const matchesSecond = classSatisfies(environment, subject.classRef, second.accepts);
|
|
192
|
-
if (!matchesFirst && !matchesSecond)
|
|
193
|
-
continue;
|
|
194
|
-
const degree = edges.filter((edge) => edge.source.key === subject.key || edge.target.key === subject.key).length;
|
|
195
|
-
if (matchesFirst)
|
|
196
|
-
checkBound(first, first.incident, degree, subject, diagnostics);
|
|
197
|
-
if (matchesSecond && !sameIncidentEndpointContract(first, second)) {
|
|
198
|
-
checkBound(second, second.incident, degree, subject, diagnostics);
|
|
153
|
+
const { candidate } = environment;
|
|
154
|
+
const resolve = (ref) => environment.resolveAny(ref)?.declaration;
|
|
155
|
+
checkCoreEdgeSet({
|
|
156
|
+
edges: edges.map((edge) => ({
|
|
157
|
+
edge,
|
|
158
|
+
class: definitionRefIndex(edge.value.class),
|
|
159
|
+
contract: edge.declaration,
|
|
160
|
+
source: factEndpoint(edge.source, edge.pointer),
|
|
161
|
+
target: factEndpoint(edge.target, edge.pointer),
|
|
162
|
+
})),
|
|
163
|
+
classes: Object.entries(candidate.classes).flatMap(([name, declaration]) => {
|
|
164
|
+
if (declaration.kind !== 'edge')
|
|
165
|
+
return [];
|
|
166
|
+
const ref = { origin: candidate.origin, kind: 'class', name };
|
|
167
|
+
const resolved = environment.resolve(ref);
|
|
168
|
+
if (resolved === undefined || resolved.ref.kind !== 'class' || resolved.kind !== 'edge') {
|
|
169
|
+
return [];
|
|
199
170
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const degree = edges.filter((edge) => edge.source.key === subject.key).length;
|
|
206
|
-
checkBound(declaration.endpoints.source, declaration.endpoints.source.outgoing, degree, subject, diagnostics);
|
|
207
|
-
}
|
|
208
|
-
if (classSatisfies(environment, subject.classRef, declaration.endpoints.target.accepts)) {
|
|
209
|
-
const degree = edges.filter((edge) => edge.target.key === subject.key).length;
|
|
210
|
-
checkBound(declaration.endpoints.target, declaration.endpoints.target.incoming, degree, subject, diagnostics);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Every declared Core Node proves its own complete degree, so both bounds hold. A Definition
|
|
216
|
-
* endpoint is only named by the Edges that reach it: the Domain may also create ordinary Edges of
|
|
217
|
-
* the same Class against it, so a minimum is unprovable here and only the maximum is enforced.
|
|
218
|
-
*/
|
|
219
|
-
function cardinalitySubjects(edges, nodesByRef) {
|
|
220
|
-
const subjects = new Map();
|
|
221
|
-
for (const node of nodesByRef.values()) {
|
|
222
|
-
subjects.set(node.key, {
|
|
171
|
+
return [
|
|
172
|
+
{ key: definitionRefIndex(ref), contract: resolved.declaration },
|
|
173
|
+
];
|
|
174
|
+
}),
|
|
175
|
+
nodes: [...nodesByRef.values()].map((node) => ({
|
|
223
176
|
key: node.key,
|
|
224
|
-
|
|
225
|
-
pointer:
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
177
|
+
class: node.classRef,
|
|
178
|
+
pointer: nodePointer(node),
|
|
179
|
+
})),
|
|
180
|
+
satisfies: (ref, accepts) => classSatisfies(environment, ref, accepts),
|
|
181
|
+
keys: ({ edge }) => edgeUniqueKeys(coveringEdgeUniqueTuples(edge.declaration, resolve), {
|
|
182
|
+
source: edge.source.key,
|
|
183
|
+
target: edge.target.key,
|
|
184
|
+
props: edge.value.properties,
|
|
185
|
+
}),
|
|
186
|
+
sameIncident: sameIncidentEndpointContract,
|
|
187
|
+
report: (issue) => diagnostics.push(coreEdgeDiagnostic(issue)),
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/** A projected member's degree, and the owning Domain's, is reported at the Edge that names it. */
|
|
191
|
+
function factEndpoint(endpoint, pointer) {
|
|
192
|
+
return endpoint.kind === 'core'
|
|
193
|
+
? endpoint
|
|
194
|
+
: { key: endpoint.key, member: { class: endpoint.classRef, pointer } };
|
|
242
195
|
}
|
|
243
|
-
function
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
196
|
+
function coreEdgeDiagnostic(issue) {
|
|
197
|
+
switch (issue.kind) {
|
|
198
|
+
case 'identity':
|
|
199
|
+
return diagnostic('DV_CORE_EDGE_KEY', issue.edge.pointer, `Core Edge duplicates the normalized EdgeKey declared at ${issue.previous.pointer}.`);
|
|
200
|
+
case 'no-self':
|
|
201
|
+
return diagnostic('DV_CORE_EDGE_CONSTRAINTS', issue.edge.pointer, 'Core Edge violates noSelf.');
|
|
202
|
+
case 'key':
|
|
203
|
+
return diagnostic('DV_CORE_EDGE_UNIQUE', issue.edge.pointer, `Core Edge holds a key the Core Edge at ${issue.previous.pointer} holds.`);
|
|
204
|
+
case 'acyclic':
|
|
205
|
+
return diagnostic('DV_CORE_EDGE_CONSTRAINTS', '/core/edges', 'Core Edge set violates exact-Class acyclicity.');
|
|
206
|
+
case 'degree':
|
|
207
|
+
return diagnostic('DV_CORE_EDGE_CONSTRAINTS', issue.pointer, `Core degree ${issue.degree} violates ${issue.endpoint.role} Edge count ${issue.count}.`);
|
|
208
|
+
}
|
|
248
209
|
}
|
|
249
210
|
function sameIncidentEndpointContract(left, right) {
|
|
250
211
|
return (left.incident === right.incident &&
|
|
251
212
|
left.accepts.length === right.accepts.length &&
|
|
252
213
|
left.accepts.every((ref, index) => definitionRefIndex(ref) === definitionRefIndex(right.accepts[index])));
|
|
253
214
|
}
|
|
254
|
-
function countBounds(value) {
|
|
255
|
-
switch (value) {
|
|
256
|
-
case '0..*':
|
|
257
|
-
return [0, Number.POSITIVE_INFINITY];
|
|
258
|
-
case '1..*':
|
|
259
|
-
return [1, Number.POSITIVE_INFINITY];
|
|
260
|
-
case '0..1':
|
|
261
|
-
return [0, 1];
|
|
262
|
-
case '1':
|
|
263
|
-
return [1, 1];
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
function hasDirectedCycle(edges) {
|
|
267
|
-
const outgoing = new Map();
|
|
268
|
-
for (const edge of edges) {
|
|
269
|
-
const targets = outgoing.get(edge.source.key) ?? [];
|
|
270
|
-
targets.push(edge.target.key);
|
|
271
|
-
outgoing.set(edge.source.key, targets);
|
|
272
|
-
}
|
|
273
|
-
const visiting = new Set();
|
|
274
|
-
const visited = new Set();
|
|
275
|
-
const visit = (key) => {
|
|
276
|
-
if (visiting.has(key))
|
|
277
|
-
return true;
|
|
278
|
-
if (visited.has(key))
|
|
279
|
-
return false;
|
|
280
|
-
visiting.add(key);
|
|
281
|
-
for (const target of outgoing.get(key) ?? [])
|
|
282
|
-
if (visit(target))
|
|
283
|
-
return true;
|
|
284
|
-
visiting.delete(key);
|
|
285
|
-
visited.add(key);
|
|
286
|
-
return false;
|
|
287
|
-
};
|
|
288
|
-
return [...outgoing.keys()].some(visit);
|
|
289
|
-
}
|
|
290
|
-
function escapePointer(value) {
|
|
291
|
-
return value.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
292
|
-
}
|