@astrale-os/kernel-dsl 0.2.0-beta.8 → 1.0.0-beta.1
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 +5 -4
- package/dist/v1/addressing/method-key.js +3 -2
- package/dist/v1/addressing/patterns.d.ts +0 -5
- package/dist/v1/addressing/patterns.js +5 -5
- package/dist/v1/builder/callable/authoring.d.ts +87 -41
- package/dist/v1/builder/callable/authoring.js +29 -14
- package/dist/v1/builder/class/authoring.d.ts +311 -36
- package/dist/v1/builder/class/authoring.js +3 -4
- package/dist/v1/builder/class/property.d.ts +16 -8
- package/dist/v1/builder/class/property.js +21 -5
- package/dist/v1/builder/core/authoring.d.ts +28 -13
- package/dist/v1/builder/core/authoring.js +22 -2
- package/dist/v1/builder/index.d.ts +9 -8
- package/dist/v1/builder/index.js +2 -2
- package/dist/v1/builder/lowering/callable.d.ts +3 -1
- package/dist/v1/builder/lowering/callable.js +43 -51
- package/dist/v1/builder/lowering/class.d.ts +7 -0
- package/dist/v1/builder/lowering/class.js +79 -29
- package/dist/v1/builder/lowering/core.d.ts +3 -2
- package/dist/v1/builder/lowering/core.js +9 -6
- package/dist/v1/builder/lowering/policy.d.ts +8 -1
- package/dist/v1/builder/lowering/policy.js +35 -0
- package/dist/v1/builder/lowering/schema/capture.js +9 -4
- package/dist/v1/builder/lowering/schema/compile.d.ts +2 -2
- package/dist/v1/builder/lowering/schema/compile.js +15 -2
- package/dist/v1/builder/lowering/schema/context.d.ts +11 -8
- package/dist/v1/builder/lowering/schema/context.js +59 -29
- package/dist/v1/builder/lowering/schema/ownership.d.ts +3 -3
- package/dist/v1/builder/lowering/schema/ownership.js +2 -1
- package/dist/v1/builder/lowering/value/compile.js +14 -4
- package/dist/v1/builder/lowering/value/zod.d.ts +7 -6
- package/dist/v1/builder/lowering/value/zod.js +16 -7
- package/dist/v1/builder/lowering/view.d.ts +4 -3
- package/dist/v1/builder/lowering/view.js +2 -14
- package/dist/v1/builder/policy/authoring.d.ts +23 -6
- package/dist/v1/builder/policy/authoring.js +35 -8
- package/dist/v1/builder/schema/define.d.ts +8 -5
- package/dist/v1/builder/schema/diagnostic.d.ts +1 -1
- package/dist/v1/builder/schema/handle.d.ts +2 -1
- package/dist/v1/builder/schema/input.d.ts +9 -1
- package/dist/v1/builder/schema/projection/callable.d.ts +51 -0
- package/dist/v1/builder/schema/projection/callable.js +1 -0
- package/dist/v1/builder/schema/projection/class.d.ts +89 -0
- package/dist/v1/builder/schema/projection/class.js +1 -0
- package/dist/v1/builder/schema/projection/core-input.d.ts +32 -0
- package/dist/v1/builder/schema/projection/core-input.js +1 -0
- package/dist/v1/builder/schema/projection/domain.d.ts +59 -0
- package/dist/v1/builder/schema/projection/domain.js +1 -0
- package/dist/v1/builder/schema/projection/identity.d.ts +39 -0
- package/dist/v1/builder/schema/projection/identity.js +1 -0
- package/dist/v1/builder/schema/projection/model.d.ts +59 -0
- package/dist/v1/builder/schema/projection/model.js +1 -0
- package/dist/v1/builder/schema/projection/property.d.ts +32 -0
- package/dist/v1/builder/schema/projection/property.js +1 -0
- package/dist/v1/builder/schema/projection/resolved-class.d.ts +76 -0
- package/dist/v1/builder/schema/projection/resolved-class.js +1 -0
- package/dist/v1/builder/schema/projection.d.ts +4 -258
- package/dist/v1/builder/value/full-match.js +6 -3
- package/dist/v1/builder/value/path.d.ts +2 -2
- package/dist/v1/builder/value/path.js +2 -2
- package/dist/v1/builder/view/authoring.d.ts +6 -14
- package/dist/v1/builder/view/authoring.js +13 -5
- package/dist/v1/bundle/structure.d.ts +2 -1
- package/dist/v1/compiled/admission/accept.d.ts +1 -1
- package/dist/v1/compiled/admission/accept.js +11 -814
- package/dist/v1/compiled/admission/closure.d.ts +3 -0
- package/dist/v1/compiled/admission/closure.js +173 -0
- package/dist/v1/compiled/admission/diagnostic.d.ts +7 -0
- package/dist/v1/compiled/admission/diagnostic.js +13 -0
- package/dist/v1/compiled/admission/revision.js +9 -1
- package/dist/v1/compiled/admission/semantics/cardinality.d.ts +5 -0
- package/dist/v1/compiled/admission/semantics/cardinality.js +113 -0
- package/dist/v1/compiled/admission/semantics/class.d.ts +5 -0
- package/dist/v1/compiled/admission/semantics/class.js +125 -0
- package/dist/v1/compiled/admission/semantics/context.d.ts +60 -0
- package/dist/v1/compiled/admission/semantics/context.js +81 -0
- package/dist/v1/compiled/admission/semantics/core.d.ts +35 -0
- package/dist/v1/compiled/admission/semantics/core.js +123 -0
- package/dist/v1/compiled/admission/semantics/edge.d.ts +8 -0
- package/dist/v1/compiled/admission/semantics/edge.js +89 -0
- package/dist/v1/compiled/admission/semantics/policy/admit.d.ts +4 -0
- package/dist/v1/compiled/admission/semantics/policy/admit.js +63 -0
- package/dist/v1/compiled/admission/semantics/policy/callable.d.ts +5 -0
- package/dist/v1/compiled/admission/semantics/policy/callable.js +72 -0
- package/dist/v1/compiled/admission/semantics/policy/contracts.d.ts +24 -0
- package/dist/v1/compiled/admission/semantics/policy/contracts.js +45 -0
- package/dist/v1/compiled/admission/semantics/policy/equality.d.ts +8 -0
- package/dist/v1/compiled/admission/semantics/policy/equality.js +27 -0
- package/dist/v1/compiled/admission/semantics/policy/measure.d.ts +9 -0
- package/dist/v1/compiled/admission/semantics/policy/measure.js +81 -0
- package/dist/v1/compiled/admission/semantics/policy/parity.d.ts +4 -0
- package/dist/v1/compiled/admission/semantics/policy/parity.js +138 -0
- package/dist/v1/compiled/admission/semantics/policy/pattern.d.ts +8 -0
- package/dist/v1/compiled/admission/semantics/policy/pattern.js +78 -0
- package/dist/v1/compiled/admission/semantics/policy/typing.d.ts +28 -0
- package/dist/v1/compiled/admission/semantics/policy/typing.js +206 -0
- package/dist/v1/compiled/admission/semantics/policy/variants.d.ts +10 -0
- package/dist/v1/compiled/admission/semantics/policy/variants.js +65 -0
- package/dist/v1/compiled/admission/semantics.d.ts +1 -1
- package/dist/v1/compiled/admission/semantics.js +8 -1078
- package/dist/v1/compiled/admission/wire/callable.d.ts +6 -0
- package/dist/v1/compiled/admission/wire/callable.js +90 -0
- package/dist/v1/compiled/admission/wire/class.d.ts +4 -0
- package/dist/v1/compiled/admission/wire/class.js +133 -0
- package/dist/v1/compiled/admission/wire/core.d.ts +5 -0
- package/dist/v1/compiled/admission/wire/core.js +32 -0
- package/dist/v1/compiled/admission/wire/dependency.d.ts +14 -0
- package/dist/v1/compiled/admission/wire/dependency.js +43 -0
- package/dist/v1/compiled/admission/wire/entry.d.ts +5 -0
- package/dist/v1/compiled/admission/wire/entry.js +100 -0
- package/dist/v1/compiled/admission/wire/pattern.d.ts +12 -0
- package/dist/v1/compiled/admission/wire/pattern.js +111 -0
- package/dist/v1/compiled/admission/wire/policy.d.ts +10 -0
- package/dist/v1/compiled/admission/wire/policy.js +189 -0
- package/dist/v1/compiled/admission/wire/program.d.ts +4 -0
- package/dist/v1/compiled/admission/wire/program.js +52 -0
- package/dist/v1/compiled/admission/wire/property.d.ts +4 -0
- package/dist/v1/compiled/admission/wire/property.js +74 -0
- package/dist/v1/compiled/admission/wire/reference.d.ts +8 -0
- package/dist/v1/compiled/admission/wire/reference.js +33 -0
- package/dist/v1/compiled/admission/wire/value.d.ts +29 -0
- package/dist/v1/compiled/admission/wire/value.js +98 -0
- package/dist/v1/compiled/admission/wire/view.d.ts +3 -0
- package/dist/v1/compiled/admission/wire/view.js +17 -0
- package/dist/v1/compiled/compiler/compile.js +43 -11
- package/dist/v1/compiled/generated.d.ts +10 -0
- package/dist/v1/compiled/generated.js +15 -0
- package/dist/v1/compiled/loader/load.d.ts +5 -0
- package/dist/v1/compiled/loader/load.js +18 -4
- package/dist/v1/compiled/model/schema.d.ts +16 -7
- package/dist/v1/domain/create.js +18 -28
- package/dist/v1/domain/model/domain.d.ts +0 -1
- package/dist/v1/domain/model/input.d.ts +3 -0
- package/dist/v1/domain/projection/classes.js +13 -41
- package/dist/v1/domain/validation/create.d.ts +2 -0
- package/dist/v1/domain/validation/create.js +12 -0
- package/dist/v1/index.d.ts +5 -2
- package/dist/v1/index.js +3 -1
- package/dist/v1/language/callable/composition.d.ts +27 -0
- package/dist/v1/language/callable/composition.js +52 -0
- package/dist/v1/language/callable/executable.d.ts +6 -0
- package/dist/v1/language/callable/executable.js +4 -0
- package/dist/v1/language/callable/model/callable.d.ts +34 -9
- package/dist/v1/language/callable/model/callable.js +3 -1
- package/dist/v1/language/callable/resolved.d.ts +23 -8
- package/dist/v1/language/class/facets.d.ts +5 -2
- package/dist/v1/language/class/inheritance.d.ts +12 -0
- package/dist/v1/language/class/inheritance.js +25 -0
- package/dist/v1/language/class/lifetime.d.ts +17 -0
- package/dist/v1/language/class/lifetime.js +26 -0
- package/dist/v1/language/class/model/class.d.ts +8 -4
- package/dist/v1/language/class/model/property.d.ts +4 -2
- package/dist/v1/language/class/property-values.js +5 -2
- package/dist/v1/language/class/resolved.d.ts +25 -15
- package/dist/v1/language/core/model/core.d.ts +7 -1
- package/dist/v1/language/core/resolved.d.ts +6 -2
- package/dist/v1/language/definition/metadata.d.ts +8 -0
- package/dist/v1/language/definition/metadata.js +12 -0
- package/dist/v1/language/index.d.ts +9 -0
- package/dist/v1/language/index.js +6 -0
- package/dist/v1/language/policy/analysis/branches.d.ts +4 -3
- package/dist/v1/language/policy/analysis/branches.js +54 -12
- package/dist/v1/language/policy/analysis/budgets.js +1 -1
- package/dist/v1/language/policy/analysis/checks.d.ts +28 -0
- package/dist/v1/language/policy/analysis/checks.js +80 -0
- package/dist/v1/language/policy/index.d.ts +1 -0
- package/dist/v1/language/policy/index.js +1 -0
- package/dist/v1/language/policy/model/policy.d.ts +71 -5
- package/dist/v1/language/policy/model/policy.js +52 -1
- package/dist/v1/language/policy/normalization/normalize.d.ts +12 -1
- package/dist/v1/language/policy/normalization/normalize.js +178 -44
- package/dist/v1/language/state/index.d.ts +3 -0
- package/dist/v1/language/state/index.js +1 -0
- package/dist/v1/language/state/machine.d.ts +28 -0
- package/dist/v1/language/state/machine.js +40 -0
- package/dist/v1/language/state/topology.d.ts +14 -0
- package/dist/v1/language/state/topology.js +69 -0
- package/dist/v1/language/value/compile/fields.d.ts +1 -1
- package/dist/v1/language/value/compile/load.d.ts +4 -2
- package/dist/v1/language/value/compile/load.js +22 -1
- package/dist/v1/language/value/compile/model.d.ts +16 -1
- package/dist/v1/language/value/evaluate/assertions.d.ts +2 -0
- package/dist/v1/language/value/evaluate/assertions.js +13 -0
- package/dist/v1/language/value/evaluate/evaluator.js +111 -28
- package/dist/v1/language/value/evaluate/preparation.d.ts +10 -1
- package/dist/v1/language/value/evaluate/preparation.js +17 -26
- package/dist/v1/language/value/evaluate/program.js +1 -1
- package/dist/v1/language/value/evaluate/validate.d.ts +6 -2
- package/dist/v1/language/value/evaluate/validate.js +18 -11
- package/dist/v1/language/value/inclusion/includes.d.ts +9 -0
- package/dist/v1/language/value/inclusion/includes.js +777 -0
- package/dist/v1/language/value/model/blob.d.ts +31 -0
- package/dist/v1/language/value/model/blob.js +90 -0
- package/dist/v1/language/value/model/instant.d.ts +0 -2
- package/dist/v1/language/value/model/instant.js +1 -1
- package/dist/v1/language/value/model/schema.d.ts +2 -1
- package/dist/v1/language/value/model/schema.js +1 -5
- package/dist/v1/language/value/ordering.d.ts +2 -0
- package/dist/v1/language/value/ordering.js +4 -8
- package/dist/v1/language/value/profile/json.validate.js +1 -1
- package/dist/v1/language/value/profile/rules.js +48 -12
- package/dist/v1/language/value/reference/registry.d.ts +2 -1
- package/dist/v1/language/value/regexp/ast.js +3 -64
- package/dist/v1/language/value/regexp/compile.d.ts +32 -3
- package/dist/v1/language/value/regexp/compile.js +117 -21
- package/dist/v1/language/value/regexp/matcher.d.ts +6 -3
- package/dist/v1/language/value/regexp/matcher.js +185 -28
- package/dist/v1/language/value/regexp/syntax.d.ts +12 -1
- package/dist/v1/language/value/regexp/syntax.js +14 -2
- package/dist/v1/language/value/regexp/unicode.d.ts +32 -0
- package/dist/v1/language/value/regexp/unicode.js +139 -0
- package/dist/v1/language/value/syntax/full-match.js +8 -5
- package/dist/v1/language/value/syntax/node-path/validate.js +4 -6
- package/dist/v1/language/view/model/view.d.ts +2 -4
- package/dist/v1/language/view/resolved.d.ts +2 -2
- package/dist/v1/schema/analysis/class.d.ts +36 -6
- package/dist/v1/schema/analysis/class.js +31 -66
- package/dist/v1/schema/canonical/revision.d.ts +2 -1
- package/dist/v1/schema/canonical/revision.js +4 -1
- package/dist/v1/schema/compatibility/api.d.ts +3 -0
- package/dist/v1/schema/compatibility/api.js +2 -0
- package/dist/v1/schema/compatibility/comparators/callables.d.ts +39 -0
- package/dist/v1/schema/compatibility/comparators/callables.js +101 -0
- package/dist/v1/schema/compatibility/comparators/classes.d.ts +47 -0
- package/dist/v1/schema/compatibility/comparators/classes.js +160 -0
- package/dist/v1/schema/compatibility/comparators/index.d.ts +12 -0
- package/dist/v1/schema/compatibility/comparators/index.js +53 -0
- package/dist/v1/schema/compatibility/comparators/members.d.ts +4 -0
- package/dist/v1/schema/compatibility/comparators/members.js +49 -0
- package/dist/v1/schema/compatibility/comparators/values.d.ts +5 -0
- package/dist/v1/schema/compatibility/comparators/values.js +37 -0
- package/dist/v1/schema/compatibility/compare.d.ts +5 -0
- package/dist/v1/schema/compatibility/compare.js +23 -0
- package/dist/v1/schema/compatibility/context.d.ts +19 -0
- package/dist/v1/schema/compatibility/context.js +49 -0
- package/dist/v1/schema/compatibility/coordinate.d.ts +40 -0
- package/dist/v1/schema/compatibility/coordinate.js +38 -0
- package/dist/v1/schema/compatibility/diff.d.ts +12 -0
- package/dist/v1/schema/compatibility/diff.js +39 -0
- package/dist/v1/schema/compatibility/evidence.d.ts +16 -0
- package/dist/v1/schema/compatibility/evidence.js +62 -0
- package/dist/v1/schema/compatibility/fields.d.ts +194 -0
- package/dist/v1/schema/compatibility/fields.js +94 -0
- package/dist/v1/schema/compatibility/index.d.ts +6 -0
- package/dist/v1/schema/compatibility/index.js +3 -0
- package/dist/v1/schema/compatibility/meaning/footprint.d.ts +7 -0
- package/dist/v1/schema/compatibility/meaning/footprint.js +59 -0
- package/dist/v1/schema/compatibility/meaning/index.d.ts +3 -0
- package/dist/v1/schema/compatibility/meaning/index.js +16 -0
- package/dist/v1/schema/compatibility/model.d.ts +131 -0
- package/dist/v1/schema/compatibility/model.js +1 -0
- package/dist/v1/schema/compatibility/references.d.ts +38 -0
- package/dist/v1/schema/compatibility/references.js +149 -0
- package/dist/v1/schema/compatibility/report.d.ts +27 -0
- package/dist/v1/schema/compatibility/report.js +100 -0
- package/dist/v1/schema/compatibility/scope.d.ts +36 -0
- package/dist/v1/schema/compatibility/scope.js +110 -0
- package/dist/v1/schema/compatibility/structure/index.d.ts +3 -0
- package/dist/v1/schema/compatibility/structure/index.js +40 -0
- package/dist/v1/schema/compatibility/structure/inheritance.d.ts +7 -0
- package/dist/v1/schema/compatibility/structure/inheritance.js +68 -0
- package/dist/v1/schema/compatibility/structure/requirements.d.ts +7 -0
- package/dist/v1/schema/compatibility/structure/requirements.js +97 -0
- package/dist/v1/schema/compatibility/subjects.d.ts +39 -0
- package/dist/v1/schema/compatibility/subjects.js +143 -0
- package/dist/v1/schema/compatibility/versioning/index.d.ts +8 -0
- package/dist/v1/schema/compatibility/versioning/index.js +50 -0
- package/dist/v1/schema/compatibility/versioning/members.d.ts +12 -0
- package/dist/v1/schema/compatibility/versioning/members.js +47 -0
- package/dist/v1/schema/compatibility/versioning/surface.d.ts +11 -0
- package/dist/v1/schema/compatibility/versioning/surface.js +61 -0
- package/dist/v1/schema/diagnostic.d.ts +1 -1
- package/dist/v1/schema/fingerprint.d.ts +2 -0
- package/dist/v1/schema/fingerprint.js +1 -0
- package/dist/v1/schema/index.d.ts +4 -3
- package/dist/v1/schema/index.js +2 -1
- package/dist/v1/schema/model/schema.d.ts +8 -11
- package/dist/v1/schema/normalization/domain.js +57 -13
- package/dist/v1/schema/resolution/definition.index.d.ts +1 -2
- package/dist/v1/schema/resolution/definition.index.js +0 -3
- package/dist/v1/schema/resolution/domain.d.ts +4 -1
- package/dist/v1/schema/resolution/domain.js +26 -18
- package/dist/v1/schema/resolution/origins.d.ts +28 -5
- package/dist/v1/schema/resolution/origins.js +68 -31
- package/dist/v1/schema/validation/callable.d.ts +4 -0
- package/dist/v1/schema/validation/callable.js +39 -0
- package/dist/v1/schema/validation/class.d.ts +10 -0
- package/dist/v1/schema/validation/class.js +79 -60
- package/dist/v1/schema/validation/core.js +83 -55
- package/dist/v1/schema/validation/domain.d.ts +2 -1
- package/dist/v1/schema/validation/domain.js +2 -0
- package/dist/v1/schema/validation/domain.structure.d.ts +0 -2
- package/dist/v1/schema/validation/domain.structure.js +214 -171
- package/dist/v1/schema/validation/policy/budgets.js +36 -6
- package/dist/v1/schema/validation/policy/context.js +5 -16
- package/dist/v1/schema/validation/policy/objects.d.ts +4 -0
- package/dist/v1/schema/validation/policy/objects.js +71 -0
- package/dist/v1/schema/validation/policy/references.js +16 -4
- package/dist/v1/schema/validation/policy/typing.d.ts +2 -0
- package/dist/v1/schema/validation/policy/typing.js +55 -7
- package/dist/v1/schema/validation/policy/uses.js +73 -99
- package/dist/v1/schema/validation/value-api.d.ts +2 -0
- package/dist/v1/schema/validation/value-api.js +1 -0
- package/dist/v1/schema/validation/value.js +7 -1
- package/dist/v1/schema/validation/view.js +14 -9
- package/dist/value/accept.d.ts +9 -0
- package/dist/value/accept.js +106 -7
- package/dist/value/canonical.d.ts +3 -0
- package/dist/value/canonical.js +22 -6
- package/dist/value/immutable.optimization.d.ts +15 -0
- package/dist/value/immutable.optimization.js +34 -0
- package/dist/value/index.d.ts +1 -1
- package/dist/value/index.js +1 -1
- package/dist/value/json.d.ts +1 -1
- package/dist/value/json.js +1 -1
- package/dist/value/limits.d.ts +1 -1
- package/dist/value/unicode.d.ts +4 -1
- package/dist/value/unicode.js +28 -0
- package/package.json +20 -5
- package/dist/v1/schema/compatibility/meaning.d.ts +0 -29
- package/dist/v1/schema/compatibility/meaning.js +0 -605
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { compareDefinitionRefs, definitionRefIndex } from '../../addressing/ordering.js';
|
|
2
|
+
import { isBinaryInput } from '../../language/callable/model/callable.js';
|
|
3
|
+
import { isClassRuleChecks, policyVariableClass } from '../../language/policy/model/policy.js';
|
|
2
4
|
import { isValueObject as isJsonObject } from '../../language/value/model/object.js';
|
|
3
5
|
import { walkSchema } from '../../language/value/syntax/walk.js';
|
|
4
6
|
/** Collect only semantic refs, never strings or objects embedded as JSON data. */
|
|
@@ -11,7 +13,8 @@ export function collectUsedForeignOrigins(schema) {
|
|
|
11
13
|
export function collectDomainDefinitionRefs(schema) {
|
|
12
14
|
const result = new Map();
|
|
13
15
|
const add = (ref) => {
|
|
14
|
-
|
|
16
|
+
const definition = ref.kind === 'method' ? ref.owner : ref;
|
|
17
|
+
result.set(definitionRefIndex(definition), definition);
|
|
15
18
|
};
|
|
16
19
|
for (const declaration of Object.values(schema.classes)) {
|
|
17
20
|
collectClassRefs(declaration, add);
|
|
@@ -22,51 +25,66 @@ export function collectDomainDefinitionRefs(schema) {
|
|
|
22
25
|
for (const declaration of Object.values(schema.policies)) {
|
|
23
26
|
collectPolicyDefinitionRefs(declaration, add);
|
|
24
27
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
collectCoreRefs(schema, add);
|
|
29
|
+
return Object.freeze([...result.values()].sort(compareDefinitionRefs));
|
|
30
|
+
}
|
|
31
|
+
export function collectCoreRefs(schema, add) {
|
|
29
32
|
for (const node of Object.values(schema.core.nodes))
|
|
30
|
-
add(node.class);
|
|
33
|
+
add(node.class, 'core');
|
|
31
34
|
for (const edge of schema.core.edges) {
|
|
32
|
-
add(edge.class);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
add(edge.class, 'core');
|
|
36
|
+
for (const endpoint of [edge.source, edge.target]) {
|
|
37
|
+
const ref = coreEndpointDefinitionRef(endpoint);
|
|
38
|
+
// An endpoint names the Definition without instantiating it, exactly like an accepts contract.
|
|
39
|
+
if (ref !== undefined)
|
|
40
|
+
add(ref, 'endpoint');
|
|
41
|
+
}
|
|
37
42
|
}
|
|
38
|
-
|
|
43
|
+
}
|
|
44
|
+
/** The owning Domain addresses no Definition, and a Method is addressed through its owner Class. */
|
|
45
|
+
export function coreEndpointDefinitionRef(endpoint) {
|
|
46
|
+
if (endpoint.kind === 'domain')
|
|
47
|
+
return undefined;
|
|
48
|
+
return endpoint.kind === 'method' ? endpoint.owner : endpoint;
|
|
39
49
|
}
|
|
40
50
|
export function collectClassRefs(declaration, add) {
|
|
41
|
-
declaration.extends.forEach(add);
|
|
51
|
+
declaration.extends.forEach((ref) => add(ref, 'extends'));
|
|
42
52
|
Object.values(declaration.properties).forEach((property) => collectValueDefinitionRefs(property.schema, add));
|
|
53
|
+
collectClassPolicyRefs(declaration, add);
|
|
43
54
|
if (declaration.kind === 'edge') {
|
|
44
55
|
collectEndpointRefs(declaration, add);
|
|
45
|
-
if (declaration.policies.traverse !== undefined)
|
|
46
|
-
add(declaration.policies.traverse);
|
|
47
56
|
return;
|
|
48
57
|
}
|
|
49
58
|
Object.values(declaration.methods).forEach((method) => collectCallableRefs(method, add));
|
|
50
|
-
if (declaration.policies.read !== undefined)
|
|
51
|
-
add(declaration.policies.read);
|
|
52
|
-
if (declaration.policies.traverse !== undefined)
|
|
53
|
-
add(declaration.policies.traverse);
|
|
54
59
|
}
|
|
55
|
-
function
|
|
60
|
+
export function collectClassPolicyRefs(declaration, add) {
|
|
61
|
+
for (const policy of [declaration.policies.read, declaration.policies.traverse]) {
|
|
62
|
+
if (isClassRuleChecks(policy))
|
|
63
|
+
collectPolicyCheckRefs(policy, add);
|
|
64
|
+
else if (typeof policy === 'object')
|
|
65
|
+
add(policy, 'policy');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function collectEndpointRefs(declaration, add) {
|
|
56
69
|
const endpoints = declaration.orientation === 'directed'
|
|
57
70
|
? [declaration.endpoints.source, declaration.endpoints.target]
|
|
58
71
|
: declaration.endpoints;
|
|
59
|
-
endpoints[0].accepts.forEach(add);
|
|
60
|
-
endpoints[1].accepts.forEach(add);
|
|
72
|
+
endpoints[0].accepts.forEach((ref) => add(ref, 'endpoint'));
|
|
73
|
+
endpoints[1].accepts.forEach((ref) => add(ref, 'endpoint'));
|
|
61
74
|
}
|
|
62
75
|
export function collectCallableRefs(declaration, add) {
|
|
63
|
-
|
|
76
|
+
collectCallableContractRefs(declaration, add);
|
|
77
|
+
if (typeof declaration.policy === 'object') {
|
|
78
|
+
collectPolicyCheckRefs(declaration.policy, add);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** References inside the contract a caller compiles against: the input and output value schemas. */
|
|
82
|
+
export function collectCallableContractRefs(declaration, add) {
|
|
83
|
+
collectValueDefinitionRefs(isBinaryInput(declaration.input) ? declaration.input.metadata : declaration.input, add);
|
|
64
84
|
if (declaration.output.mode === 'value')
|
|
65
85
|
collectValueDefinitionRefs(declaration.output.schema, add);
|
|
66
86
|
if (declaration.output.mode === 'stream')
|
|
67
87
|
collectValueDefinitionRefs(declaration.output.item, add);
|
|
68
|
-
if (declaration.policy !== undefined)
|
|
69
|
-
collectPolicyCheckRefs(declaration.policy, add);
|
|
70
88
|
}
|
|
71
89
|
export function collectPolicyDefinitionRefs(declaration, add) {
|
|
72
90
|
collectPolicyExpressionRefs(declaration.expression, add);
|
|
@@ -77,15 +95,28 @@ function collectPolicyExpressionRefs(expression, add) {
|
|
|
77
95
|
return;
|
|
78
96
|
}
|
|
79
97
|
const refs = 'allOf' in expression ? expression.allOf : expression.anyOf;
|
|
80
|
-
refs.forEach(add);
|
|
98
|
+
refs.forEach((ref) => add(ref, 'policy'));
|
|
81
99
|
}
|
|
82
100
|
function collectPolicyPatternRefs(expression, add) {
|
|
101
|
+
if ('sameNode' in expression) {
|
|
102
|
+
for (const term of [expression.sameNode.left, expression.sameNode.right])
|
|
103
|
+
if (term.kind === 'ref')
|
|
104
|
+
add(term.ref, 'policy');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
83
107
|
if ('source' in expression) {
|
|
84
|
-
|
|
108
|
+
for (const term of [expression.source, expression.target])
|
|
109
|
+
if (term.kind === 'ref')
|
|
110
|
+
add(term.ref, 'policy');
|
|
111
|
+
add(expression.class, 'pattern');
|
|
85
112
|
return;
|
|
86
113
|
}
|
|
87
114
|
if ('exists' in expression) {
|
|
88
|
-
expression.exists.nodes.forEach((node) =>
|
|
115
|
+
expression.exists.nodes.forEach((node) => {
|
|
116
|
+
const ref = policyVariableClass(node);
|
|
117
|
+
if (ref !== undefined)
|
|
118
|
+
add(ref, 'policy');
|
|
119
|
+
});
|
|
89
120
|
collectPolicyPatternRefs(expression.exists.where, add);
|
|
90
121
|
return;
|
|
91
122
|
}
|
|
@@ -93,10 +124,16 @@ function collectPolicyPatternRefs(expression, add) {
|
|
|
93
124
|
children.forEach((child) => collectPolicyPatternRefs(child, add));
|
|
94
125
|
}
|
|
95
126
|
function collectPolicyCheckRefs(expression, add) {
|
|
127
|
+
if ('sameNode' in expression) {
|
|
128
|
+
for (const term of [expression.sameNode.left, expression.sameNode.right])
|
|
129
|
+
if (term.kind === 'ref')
|
|
130
|
+
add(term.ref, 'policy');
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
96
133
|
if ('check' in expression) {
|
|
97
|
-
add(expression.check);
|
|
134
|
+
add(expression.check, 'policy');
|
|
98
135
|
if (expression.object.kind === 'ref')
|
|
99
|
-
add(expression.object.ref);
|
|
136
|
+
add(expression.object.ref, 'policy');
|
|
100
137
|
return;
|
|
101
138
|
}
|
|
102
139
|
const children = 'allOf' in expression ? expression.allOf : expression.anyOf;
|
|
@@ -114,7 +151,7 @@ export function collectValueDefinitionRefs(schema, add) {
|
|
|
114
151
|
typeof candidate.origin === 'string' &&
|
|
115
152
|
typeof candidate.kind === 'string' &&
|
|
116
153
|
typeof candidate.name === 'string') {
|
|
117
|
-
add(candidate);
|
|
154
|
+
add(candidate, 'value');
|
|
118
155
|
}
|
|
119
156
|
}
|
|
120
157
|
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SchemaDiagnostic } from '../diagnostic.js';
|
|
2
|
+
import type { DomainSchemaIR } from '../model/schema.js';
|
|
3
|
+
/** Validate the execution modifier of every local Function and Node Method. */
|
|
4
|
+
export declare function validateCallables(schema: DomainSchemaIR): readonly SchemaDiagnostic[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { isBinaryInput } from '../../language/callable/model/callable.js';
|
|
2
|
+
import { diagnostic } from '../diagnostic.js';
|
|
3
|
+
/** Validate the execution modifier of every local Function and Node Method. */
|
|
4
|
+
export function validateCallables(schema) {
|
|
5
|
+
const diagnostics = [];
|
|
6
|
+
for (const [name, declaration] of Object.entries(schema.functions)) {
|
|
7
|
+
validateExecution(declaration, `/functions/${escapePointer(name)}`, diagnostics);
|
|
8
|
+
}
|
|
9
|
+
for (const [name, declaration] of Object.entries(schema.classes)) {
|
|
10
|
+
if (declaration.kind !== 'node')
|
|
11
|
+
continue;
|
|
12
|
+
for (const [method, value] of Object.entries(declaration.methods)) {
|
|
13
|
+
const pointer = `/classes/${escapePointer(name)}/methods/${escapePointer(method)}`;
|
|
14
|
+
validateExecution(value, pointer, diagnostics);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return Object.freeze(diagnostics);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* An Execution records its initiating caller and its admitted input, from which the run is
|
|
21
|
+
* resubmitted, and retains one portable outcome. A durable callable therefore needs a known caller,
|
|
22
|
+
* a value input and a replayable value output.
|
|
23
|
+
*/
|
|
24
|
+
function validateExecution(declaration, pointer, diagnostics) {
|
|
25
|
+
if (declaration.execution?.durable !== true)
|
|
26
|
+
return;
|
|
27
|
+
if (declaration.auth === 'anonymous') {
|
|
28
|
+
diagnostics.push(diagnostic('DV_CALLABLE_AUTH', `${pointer}/auth`, 'A durable callable requires authenticated or authorized auth.'));
|
|
29
|
+
}
|
|
30
|
+
if (isBinaryInput(declaration.input)) {
|
|
31
|
+
diagnostics.push(diagnostic('DV_CALLABLE_IO', `${pointer}/input/mode`, 'A durable callable requires a value input.'));
|
|
32
|
+
}
|
|
33
|
+
if (declaration.output.mode !== 'value') {
|
|
34
|
+
diagnostics.push(diagnostic('DV_CALLABLE_IO', `${pointer}/output/mode`, 'A durable callable requires a value output.'));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function escapePointer(value) {
|
|
38
|
+
return value.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
39
|
+
}
|
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
import type { ClassRef } from '../../addressing/index.js';
|
|
2
|
+
import type { ClassDefinition } from '../../language/class/model/class.js';
|
|
1
3
|
import type { DefinitionAnalysisResult } from '../analysis/class.js';
|
|
2
4
|
import type { SchemaDiagnostic } from '../diagnostic.js';
|
|
3
5
|
import type { DomainResolutionContext } from '../resolution/context.js';
|
|
4
6
|
/** Validate the semantic contracts owned by Class declarations. */
|
|
5
7
|
export declare function validateDefinitions(environment: DomainResolutionContext, analysis: DefinitionAnalysisResult): readonly SchemaDiagnostic[];
|
|
8
|
+
/** Whether `child` safely refines its parent Edge contract `parent`. */
|
|
9
|
+
export declare function edgeContractRefines(environment: DomainResolutionContext, child: Extract<ClassDefinition, {
|
|
10
|
+
readonly kind: 'edge';
|
|
11
|
+
}>, parent: Extract<ClassDefinition, {
|
|
12
|
+
readonly kind: 'edge';
|
|
13
|
+
}>): boolean;
|
|
14
|
+
/** Whether `candidate` is, or is a Node Class extending, one of `accepts`. */
|
|
15
|
+
export declare function classSatisfies(environment: DomainResolutionContext, candidate: ClassRef, accepts: readonly ClassRef[]): boolean;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { Key } from '../../addressing/key.js';
|
|
2
2
|
import { definitionRefIndex } from '../../addressing/ordering.js';
|
|
3
|
+
import { isMethodExecutable } from '../../language/callable/executable.js';
|
|
4
|
+
import { classSatisfies as satisfiesClass, isGraphRoot } from '../../language/class/inheritance.js';
|
|
5
|
+
import { admitStateTopology } from '../../language/state/topology.js';
|
|
6
|
+
import { isBlobValueSchema } from '../../language/value/model/blob.js';
|
|
3
7
|
import { classifyOrdering } from '../../language/value/ordering.js';
|
|
4
8
|
import { diagnostic } from '../diagnostic.js';
|
|
5
9
|
import { createValueSchemaRegistry } from '../resolution/value.registry.js';
|
|
@@ -14,6 +18,10 @@ export function validateDefinitions(environment, analysis) {
|
|
|
14
18
|
if (!sameRef(declaration.ref, ref)) {
|
|
15
19
|
diagnostics.push(diagnostic('DV_REF_RESOLVES', `${pointer}/ref`, `Class ref must be exactly ${formatDefinitionRef(ref)}.`, formatDefinitionRef(declaration.ref)));
|
|
16
20
|
}
|
|
21
|
+
if (declaration.abstract &&
|
|
22
|
+
(declaration.policies.read !== undefined || declaration.policies.traverse !== undefined)) {
|
|
23
|
+
diagnostics.push(diagnostic('DV_CLASS_ABSTRACT', `${pointer}/policies`, 'Abstract Classes cannot declare observation Policies.'));
|
|
24
|
+
}
|
|
17
25
|
validateFacet(environment, declaration, pointer, diagnostics);
|
|
18
26
|
validateParents(environment, ref, declaration.kind, declaration.extends, diagnostics);
|
|
19
27
|
if (declaration.kind === 'edge') {
|
|
@@ -26,22 +34,60 @@ export function validateDefinitions(environment, analysis) {
|
|
|
26
34
|
function validateFacet(environment, declaration, pointer, diagnostics) {
|
|
27
35
|
const valueRegistry = createValueSchemaRegistry(environment);
|
|
28
36
|
for (const [name, property] of Object.entries(declaration.properties)) {
|
|
37
|
+
const propertyPointer = `${pointer}/properties/${escapePointer(name)}`;
|
|
38
|
+
if (isBlobValueSchema(property.schema) &&
|
|
39
|
+
(declaration.kind !== 'node' || property.auto !== undefined || property.state !== undefined)) {
|
|
40
|
+
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
|
+
}
|
|
42
|
+
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
|
+
try {
|
|
47
|
+
const topology = admitStateTopology(property.state);
|
|
48
|
+
const expected = Object.keys(topology.transitions).sort();
|
|
49
|
+
const schema = property.schema;
|
|
50
|
+
const schemaMatches = schema !== null &&
|
|
51
|
+
typeof schema === 'object' &&
|
|
52
|
+
!Array.isArray(schema) &&
|
|
53
|
+
Object.keys(schema).length === 2 &&
|
|
54
|
+
schema.type === 'string' &&
|
|
55
|
+
Array.isArray(schema.enum) &&
|
|
56
|
+
schema.enum.length === expected.length &&
|
|
57
|
+
[...schema.enum].sort().every((state, index) => state === expected[index]);
|
|
58
|
+
if (!property.required || property.auto !== undefined || !schemaMatches) {
|
|
59
|
+
diagnostics.push(diagnostic('DV_PROPERTY_STATE', `${propertyPointer}/state`, 'A State Property is required, non-automatic, and has exactly its declared states.'));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
diagnostics.push(diagnostic('DV_PROPERTY_STATE', `${propertyPointer}/state`, error instanceof Error ? error.message : 'Invalid State topology.'));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (property.immutable !== undefined) {
|
|
67
|
+
const immutablePointer = `${propertyPointer}/immutable`;
|
|
68
|
+
if (property.auto !== undefined || property.state !== undefined) {
|
|
69
|
+
diagnostics.push(diagnostic('DV_PROPERTY_IMMUTABLE', immutablePointer, 'An immutable Property is neither automatic nor a State Property.'));
|
|
70
|
+
}
|
|
71
|
+
if (property.immutable === 'once' && property.required) {
|
|
72
|
+
diagnostics.push(diagnostic('DV_PROPERTY_IMMUTABLE', immutablePointer, 'A required immutable Property is written at creation: declare it create, not once.'));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
29
75
|
if (property.auto === undefined)
|
|
30
76
|
continue;
|
|
31
|
-
const
|
|
77
|
+
const autoPointer = `${propertyPointer}/auto`;
|
|
32
78
|
if (property.required && !property.auto.on.includes('create')) {
|
|
33
|
-
diagnostics.push(diagnostic('DV_PROPERTY_AUTO', `${
|
|
79
|
+
diagnostics.push(diagnostic('DV_PROPERTY_AUTO', `${autoPointer}/on`, 'A required auto Property must run on create.'));
|
|
34
80
|
}
|
|
35
81
|
if (property.auto.set === 'instant' &&
|
|
36
82
|
classifyOrdering(property.schema, valueRegistry) !== 'instant') {
|
|
37
|
-
diagnostics.push(diagnostic('DV_PROPERTY_AUTO', `${
|
|
83
|
+
diagnostics.push(diagnostic('DV_PROPERTY_AUTO', `${autoPointer}/set`, 'The instant setter requires an Instant value schema.'));
|
|
38
84
|
}
|
|
39
85
|
}
|
|
40
86
|
if (declaration.kind !== 'node')
|
|
41
87
|
return;
|
|
42
88
|
for (const [name, method] of Object.entries(declaration.methods)) {
|
|
43
89
|
const methodPointer = `${pointer}/methods/${escapePointer(name)}`;
|
|
44
|
-
if (method
|
|
90
|
+
if (!isMethodExecutable(declaration, method) && method.policy !== undefined) {
|
|
45
91
|
diagnostics.push(diagnostic('DV_METHOD_ABSTRACT', `${methodPointer}/policy`, 'Abstract Methods cannot have a Policy.'));
|
|
46
92
|
}
|
|
47
93
|
}
|
|
@@ -66,19 +112,24 @@ function validateEdgeContract(environment, owner, declaration, diagnostics) {
|
|
|
66
112
|
if (endpoints[0].role === endpoints[1].role) {
|
|
67
113
|
diagnostics.push(diagnostic('DV_EDGE_ROLE', '', `${formatDefinitionRef(owner)} has equal endpoint roles.`));
|
|
68
114
|
}
|
|
69
|
-
|
|
70
|
-
|
|
115
|
+
const counts = declaration.orientation === 'directed'
|
|
116
|
+
? [declaration.endpoints.source.outgoing, declaration.endpoints.target.incoming]
|
|
117
|
+
: [declaration.endpoints[0].incident, declaration.endpoints[1].incident];
|
|
118
|
+
validateEndpoint(environment, owner, endpoints[0], counts[0], declaration.orientation === 'directed' ? 'source' : 'first endpoint', diagnostics);
|
|
119
|
+
validateEndpoint(environment, owner, endpoints[1], counts[1], declaration.orientation === 'directed' ? 'target' : 'second endpoint', diagnostics);
|
|
71
120
|
if (declaration.orientation === 'undirected') {
|
|
72
|
-
if (!sameIncidentEndpointContract(declaration.endpoints[0], declaration.endpoints[1]) &&
|
|
73
|
-
undirectedEndpointsOverlap(environment, declaration.endpoints)) {
|
|
74
|
-
diagnostics.push(diagnostic('DV_EDGE_UNDIRECTED', '', `${formatDefinitionRef(owner)} has unequal undirected endpoint contracts whose accepted Node families overlap.`));
|
|
75
|
-
}
|
|
76
121
|
if (declaration.constraints.acyclic === true) {
|
|
77
122
|
diagnostics.push(diagnostic('DV_EDGE_CONSTRAINT', '', 'acyclic is valid only for directed Edge contracts.'));
|
|
78
123
|
}
|
|
79
124
|
}
|
|
80
125
|
}
|
|
81
|
-
function validateEndpoint(environment, owner, endpoint, side, diagnostics) {
|
|
126
|
+
function validateEndpoint(environment, owner, endpoint, count, side, diagnostics) {
|
|
127
|
+
// An Edge Class binds only the Nodes of its Domain and its dependents: it cannot oblige the
|
|
128
|
+
// Nodes of a Class another Domain owns to carry its Edges.
|
|
129
|
+
const foreign = endpoint.accepts.find((ref) => ref.origin !== owner.origin);
|
|
130
|
+
if (foreign !== undefined && (count === '1' || count === '1..*')) {
|
|
131
|
+
diagnostics.push(diagnostic('DV_EDGE_FOREIGN_MINIMUM', '', `${formatDefinitionRef(owner)} ${side} accepts ${formatDefinitionRef(foreign)} of another Domain and cannot require ${count} Edges.`));
|
|
132
|
+
}
|
|
82
133
|
const seen = new Set();
|
|
83
134
|
for (const ref of endpoint.accepts) {
|
|
84
135
|
const key = definitionRefIndex(ref);
|
|
@@ -113,7 +164,10 @@ function validateEdgeClassComposition(environment, diagnostics) {
|
|
|
113
164
|
}
|
|
114
165
|
}
|
|
115
166
|
}
|
|
116
|
-
|
|
167
|
+
/** Whether `child` safely refines its parent Edge contract `parent`. */
|
|
168
|
+
export function edgeContractRefines(environment, child, parent) {
|
|
169
|
+
if (isGraphRoot(parent))
|
|
170
|
+
return true;
|
|
117
171
|
if (child.orientation !== parent.orientation)
|
|
118
172
|
return false;
|
|
119
173
|
if (parent.constraints.noSelf === true && child.constraints.noSelf !== true)
|
|
@@ -130,7 +184,10 @@ function edgeContractRefines(environment, child, parent) {
|
|
|
130
184
|
return false;
|
|
131
185
|
const refines = (childIndex, parentIndex) => endpointRefines(environment, child.endpoints[childIndex], parent.endpoints[parentIndex]) &&
|
|
132
186
|
countRefines(child.endpoints[childIndex].incident, parent.endpoints[parentIndex].incident);
|
|
133
|
-
|
|
187
|
+
const direct = refines(0, 0) && refines(1, 1);
|
|
188
|
+
if (direct)
|
|
189
|
+
return true;
|
|
190
|
+
return refines(0, 1) && refines(1, 0);
|
|
134
191
|
}
|
|
135
192
|
function endpointRefines(environment, child, parent) {
|
|
136
193
|
return child.accepts.every((accepted) => classSatisfies(environment, accepted, parent.accepts));
|
|
@@ -146,56 +203,18 @@ function countRefines(child, parent) {
|
|
|
146
203
|
const [parentMinimum, parentMaximum] = bounds[parent];
|
|
147
204
|
return childMinimum >= parentMinimum && childMaximum <= parentMaximum;
|
|
148
205
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return false;
|
|
152
|
-
const a = [...left.accepts].map(definitionRefIndex).sort();
|
|
153
|
-
const b = [...right.accepts].map(definitionRefIndex).sort();
|
|
154
|
-
return a.length === b.length && a.every((value, index) => value === b[index]);
|
|
155
|
-
}
|
|
156
|
-
function undirectedEndpointsOverlap(environment, endpoints) {
|
|
157
|
-
for (const resolved of environment.definitions.values()) {
|
|
158
|
-
if (resolved.ref.kind !== 'class' ||
|
|
159
|
-
resolved.declaration.kind !== 'node' ||
|
|
160
|
-
resolved.declaration.abstract) {
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
const candidate = resolved.ref;
|
|
164
|
-
if (classSatisfies(environment, candidate, endpoints[0].accepts) &&
|
|
165
|
-
classSatisfies(environment, candidate, endpoints[1].accepts)) {
|
|
166
|
-
return true;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
function classSatisfies(environment, candidate, accepts) {
|
|
206
|
+
/** Whether `candidate` is, or is a Node Class extending, one of `accepts`. */
|
|
207
|
+
export function classSatisfies(environment, candidate, accepts) {
|
|
172
208
|
if (accepts.some((ref) => definitionRefIndex(ref) === definitionRefIndex(candidate)))
|
|
173
209
|
return true;
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
resolved.declaration.kind !== 'node') {
|
|
210
|
+
const resolve = (ref) => environment.resolveAny(ref)?.declaration;
|
|
211
|
+
const actual = resolve(candidate);
|
|
212
|
+
if (actual?.kind !== 'node')
|
|
178
213
|
return false;
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const accepted = new Set(accepts.map(definitionRefIndex));
|
|
184
|
-
for (const parent of parents) {
|
|
185
|
-
const key = definitionRefIndex(parent);
|
|
186
|
-
if (accepted.has(key))
|
|
187
|
-
return true;
|
|
188
|
-
if (visited.has(key))
|
|
189
|
-
continue;
|
|
190
|
-
visited.add(key);
|
|
191
|
-
const resolved = environment.resolveAny(parent);
|
|
192
|
-
if (resolved !== undefined &&
|
|
193
|
-
resolved.ref.kind === 'class' &&
|
|
194
|
-
extendsAny(environment, resolved.declaration.extends, accepts, visited)) {
|
|
195
|
-
return true;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
return false;
|
|
214
|
+
return accepts.some((ref) => {
|
|
215
|
+
const required = resolve(ref);
|
|
216
|
+
return required !== undefined && satisfiesClass(actual, required, resolve);
|
|
217
|
+
});
|
|
199
218
|
}
|
|
200
219
|
function localRef(origin, name) {
|
|
201
220
|
return { origin, kind: 'class', name };
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Key } from '../../addressing/key.js';
|
|
2
2
|
import { compareUnicode, definitionRefIndex } from '../../addressing/ordering.js';
|
|
3
|
+
import { isMethodExecutable } from '../../language/callable/executable.js';
|
|
4
|
+
import { policyObjectKey, policyObjectOrigin, projectedMemberClass, } from '../../language/policy/model/policy.js';
|
|
3
5
|
import { validateJsonInstance } from '../../language/value/evaluate/validate.js';
|
|
4
6
|
import { diagnostic } from '../diagnostic.js';
|
|
7
|
+
import { classSatisfies } from './class.js';
|
|
5
8
|
const formatDefinitionRef = Key.of;
|
|
6
9
|
export function validateCore(environment, analysis, registry) {
|
|
7
10
|
const diagnostics = [];
|
|
@@ -42,8 +45,8 @@ function resolveCoreEdges(environment, analysis, registry, nodesByRef, diagnosti
|
|
|
42
45
|
const edges = [];
|
|
43
46
|
for (const [index, edge] of environment.candidate.core.edges.entries()) {
|
|
44
47
|
const pointer = `/core/edges/${index}`;
|
|
45
|
-
const source = resolveCoreEndpoint(edge.source, `${pointer}/source`, nodesByRef, diagnostics);
|
|
46
|
-
const target = resolveCoreEndpoint(edge.target, `${pointer}/target`, nodesByRef, diagnostics);
|
|
48
|
+
const source = resolveCoreEndpoint(environment, edge.source, `${pointer}/source`, nodesByRef, diagnostics);
|
|
49
|
+
const target = resolveCoreEndpoint(environment, edge.target, `${pointer}/target`, nodesByRef, diagnostics);
|
|
47
50
|
const resolved = environment.resolve(edge.class);
|
|
48
51
|
if (edge.class.origin !== environment.candidate.origin ||
|
|
49
52
|
resolved === undefined ||
|
|
@@ -75,14 +78,37 @@ function resolveCoreEdges(environment, analysis, registry, nodesByRef, diagnosti
|
|
|
75
78
|
}
|
|
76
79
|
return edges;
|
|
77
80
|
}
|
|
78
|
-
function resolveCoreEndpoint(ref, pointer, nodesByRef, diagnostics) {
|
|
81
|
+
function resolveCoreEndpoint(environment, ref, pointer, nodesByRef, diagnostics) {
|
|
79
82
|
if (ref.kind === 'domain')
|
|
80
83
|
return { kind: 'domain', ref, key: 'domain' };
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
diagnostics.push(diagnostic('DV_CORE_REF', pointer, `Core endpoint ${
|
|
84
|
+
const undeclared = () => {
|
|
85
|
+
const key = policyObjectKey(ref);
|
|
86
|
+
diagnostics.push(diagnostic('DV_CORE_REF', pointer, `Core endpoint ${key} does not name a declared local Definition.`, key));
|
|
87
|
+
return undefined;
|
|
88
|
+
};
|
|
89
|
+
if (policyObjectOrigin(ref) !== environment.candidate.origin)
|
|
90
|
+
return undeclared();
|
|
91
|
+
if (ref.kind === 'core')
|
|
92
|
+
return nodesByRef.get(definitionRefIndex(ref)) ?? undeclared();
|
|
93
|
+
if (!declaresProjectedMember(environment, ref))
|
|
94
|
+
return undeclared();
|
|
95
|
+
return { kind: 'member', key: policyObjectKey(ref), classRef: projectedMemberClass(ref) };
|
|
96
|
+
}
|
|
97
|
+
/** Only a projected declaration can carry a Core fact; an abstract Method is never projected. */
|
|
98
|
+
function declaresProjectedMember(environment, ref) {
|
|
99
|
+
const candidate = environment.candidate;
|
|
100
|
+
if (ref.kind === 'method') {
|
|
101
|
+
const owner = candidate.classes[ref.owner.name];
|
|
102
|
+
const method = owner?.kind === 'node' ? owner.methods[ref.name] : undefined;
|
|
103
|
+
return method !== undefined && isMethodExecutable(owner, method);
|
|
84
104
|
}
|
|
85
|
-
|
|
105
|
+
if (ref.kind === 'class')
|
|
106
|
+
return Object.hasOwn(candidate.classes, ref.name);
|
|
107
|
+
if (ref.kind === 'function')
|
|
108
|
+
return Object.hasOwn(candidate.functions, ref.name);
|
|
109
|
+
if (ref.kind === 'policy')
|
|
110
|
+
return Object.hasOwn(candidate.policies, ref.name);
|
|
111
|
+
return Object.hasOwn(candidate.views, ref.name);
|
|
86
112
|
}
|
|
87
113
|
function endpointSatisfies(environment, endpoint, accepts) {
|
|
88
114
|
// The owning Domain is a graph-projection identity, not a Definition declared by this DSL.
|
|
@@ -92,9 +118,11 @@ function endpointSatisfies(environment, endpoint, accepts) {
|
|
|
92
118
|
function validateCreationProperties(definition, properties, registry, code, pointer, diagnostics) {
|
|
93
119
|
const schema = {
|
|
94
120
|
type: 'object',
|
|
95
|
-
properties: Object.fromEntries([...definition.properties]
|
|
121
|
+
properties: Object.fromEntries([...definition.properties]
|
|
122
|
+
.filter(([, field]) => field.auto === undefined)
|
|
123
|
+
.map(([name, field]) => [name, field.schema])),
|
|
96
124
|
required: [...definition.properties]
|
|
97
|
-
.filter(([, field]) => field.required)
|
|
125
|
+
.filter(([, field]) => field.required && field.auto === undefined)
|
|
98
126
|
.map(([name]) => name)
|
|
99
127
|
.sort(compareUnicode),
|
|
100
128
|
additionalProperties: false,
|
|
@@ -155,41 +183,68 @@ function validateCoreEdgeSet(environment, edges, nodesByRef, diagnostics) {
|
|
|
155
183
|
}
|
|
156
184
|
}
|
|
157
185
|
function validateCardinality(environment, declaration, edges, nodesByRef, diagnostics) {
|
|
186
|
+
const subjects = cardinalitySubjects(edges, nodesByRef);
|
|
158
187
|
if (declaration.orientation === 'undirected') {
|
|
159
188
|
const [first, second] = declaration.endpoints;
|
|
160
|
-
for (const
|
|
161
|
-
const matchesFirst = classSatisfies(environment,
|
|
162
|
-
const matchesSecond = classSatisfies(environment,
|
|
189
|
+
for (const subject of subjects) {
|
|
190
|
+
const matchesFirst = classSatisfies(environment, subject.classRef, first.accepts);
|
|
191
|
+
const matchesSecond = classSatisfies(environment, subject.classRef, second.accepts);
|
|
163
192
|
if (!matchesFirst && !matchesSecond)
|
|
164
193
|
continue;
|
|
165
|
-
const degree = edges.filter((edge) => edge.source.key ===
|
|
194
|
+
const degree = edges.filter((edge) => edge.source.key === subject.key || edge.target.key === subject.key).length;
|
|
166
195
|
if (matchesFirst)
|
|
167
|
-
|
|
196
|
+
checkBound(first, first.incident, degree, subject, diagnostics);
|
|
168
197
|
if (matchesSecond && !sameIncidentEndpointContract(first, second)) {
|
|
169
|
-
|
|
198
|
+
checkBound(second, second.incident, degree, subject, diagnostics);
|
|
170
199
|
}
|
|
171
200
|
}
|
|
172
201
|
return;
|
|
173
202
|
}
|
|
174
|
-
for (const
|
|
175
|
-
if (classSatisfies(environment,
|
|
176
|
-
const degree = edges.filter((edge) => edge.source.key ===
|
|
177
|
-
checkBound(declaration.endpoints.source, declaration.endpoints.source.outgoing, degree,
|
|
203
|
+
for (const subject of subjects) {
|
|
204
|
+
if (classSatisfies(environment, subject.classRef, declaration.endpoints.source.accepts)) {
|
|
205
|
+
const degree = edges.filter((edge) => edge.source.key === subject.key).length;
|
|
206
|
+
checkBound(declaration.endpoints.source, declaration.endpoints.source.outgoing, degree, subject, diagnostics);
|
|
178
207
|
}
|
|
179
|
-
if (classSatisfies(environment,
|
|
180
|
-
const degree = edges.filter((edge) => edge.target.key ===
|
|
181
|
-
checkBound(declaration.endpoints.target, declaration.endpoints.target.incoming, degree,
|
|
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, {
|
|
223
|
+
key: node.key,
|
|
224
|
+
classRef: node.classRef,
|
|
225
|
+
pointer: `/core/nodes/${escapePointer(node.slug)}`,
|
|
226
|
+
minimum: true,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
for (const edge of edges) {
|
|
230
|
+
for (const endpoint of [edge.source, edge.target]) {
|
|
231
|
+
if (endpoint.kind !== 'member' || subjects.has(endpoint.key))
|
|
232
|
+
continue;
|
|
233
|
+
subjects.set(endpoint.key, {
|
|
234
|
+
key: endpoint.key,
|
|
235
|
+
classRef: endpoint.classRef,
|
|
236
|
+
pointer: edge.pointer,
|
|
237
|
+
minimum: false,
|
|
238
|
+
});
|
|
182
239
|
}
|
|
183
240
|
}
|
|
241
|
+
return Object.freeze([...subjects.values()]);
|
|
184
242
|
}
|
|
185
|
-
function checkBound(endpoint, count, degree,
|
|
243
|
+
function checkBound(endpoint, count, degree, subject, diagnostics) {
|
|
186
244
|
const [minimum, maximum] = countBounds(count);
|
|
187
|
-
if (degree
|
|
245
|
+
if (degree <= maximum && (degree >= minimum || !subject.minimum))
|
|
188
246
|
return;
|
|
189
|
-
diagnostics.push(diagnostic('DV_CORE_EDGE_CONSTRAINTS',
|
|
190
|
-
}
|
|
191
|
-
function checkIncidentBound(endpoint, degree, node, diagnostics) {
|
|
192
|
-
checkBound(endpoint, endpoint.incident, degree, node, diagnostics);
|
|
247
|
+
diagnostics.push(diagnostic('DV_CORE_EDGE_CONSTRAINTS', subject.pointer, `Core degree ${degree} violates ${endpoint.role} Edge count ${count}.`));
|
|
193
248
|
}
|
|
194
249
|
function sameIncidentEndpointContract(left, right) {
|
|
195
250
|
return (left.incident === right.incident &&
|
|
@@ -232,33 +287,6 @@ function hasDirectedCycle(edges) {
|
|
|
232
287
|
};
|
|
233
288
|
return [...outgoing.keys()].some(visit);
|
|
234
289
|
}
|
|
235
|
-
function classSatisfies(environment, classRef, accepts) {
|
|
236
|
-
if (accepts.some((ref) => definitionRefIndex(ref) === definitionRefIndex(classRef)))
|
|
237
|
-
return true;
|
|
238
|
-
const resolved = environment.resolveAny(classRef);
|
|
239
|
-
if (resolved === undefined || resolved.ref.kind !== 'class' || resolved.kind !== 'node') {
|
|
240
|
-
return false;
|
|
241
|
-
}
|
|
242
|
-
return classExtendsAny(environment, resolved.declaration.extends, accepts, new Set());
|
|
243
|
-
}
|
|
244
|
-
function classExtendsAny(environment, parents, accepts, visited) {
|
|
245
|
-
const accepted = new Set(accepts.map(definitionRefIndex));
|
|
246
|
-
for (const parent of parents) {
|
|
247
|
-
const key = definitionRefIndex(parent);
|
|
248
|
-
if (accepted.has(key))
|
|
249
|
-
return true;
|
|
250
|
-
if (visited.has(key))
|
|
251
|
-
continue;
|
|
252
|
-
visited.add(key);
|
|
253
|
-
const resolved = environment.resolveAny(parent);
|
|
254
|
-
if (resolved !== undefined &&
|
|
255
|
-
resolved.ref.kind === 'class' &&
|
|
256
|
-
classExtendsAny(environment, resolved.declaration.extends, accepts, visited)) {
|
|
257
|
-
return true;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
return false;
|
|
261
|
-
}
|
|
262
290
|
function escapePointer(value) {
|
|
263
291
|
return value.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
264
292
|
}
|
|
@@ -3,9 +3,10 @@ import type { DomainSchemaLookup } from '../dependency/lookup.js';
|
|
|
3
3
|
import type { SchemaDiagnostic } from '../diagnostic.js';
|
|
4
4
|
import type { DomainSchemaIR } from '../model/schema.js';
|
|
5
5
|
import type { DomainResolutionContext } from '../resolution/context.js';
|
|
6
|
-
|
|
6
|
+
interface DomainSchemaValidation {
|
|
7
7
|
readonly context: DomainResolutionContext;
|
|
8
8
|
readonly analysis: DefinitionAnalysisResult;
|
|
9
9
|
readonly diagnostics: readonly SchemaDiagnostic[];
|
|
10
10
|
}
|
|
11
11
|
export declare function validateDomainSchemaSemantics(schema: DomainSchemaIR, lookup: DomainSchemaLookup): DomainSchemaValidation;
|
|
12
|
+
export {};
|