@astrale-os/kernel-dsl 1.0.0-beta.12 → 1.0.0-beta.13
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/definition-ref.js +21 -37
- package/dist/v1/addressing/ordering.d.ts +2 -0
- package/dist/v1/addressing/ordering.js +4 -0
- package/dist/v1/addressing/patterns.d.ts +0 -1
- package/dist/v1/addressing/patterns.js +0 -5
- package/dist/v1/builder/class/authoring.js +5 -28
- package/dist/v1/builder/lowering/schema/context.js +2 -4
- package/dist/v1/builder/lowering/value/path.js +2 -4
- package/dist/v1/builder/lowering/value/zod.js +1 -3
- package/dist/v1/builder/schema/define.d.ts +0 -1
- package/dist/v1/builder/schema/diagnostic.d.ts +2 -1
- package/dist/v1/builder/schema/diagnostic.js +5 -10
- 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/bundle/codec.js +2 -4
- package/dist/v1/bundle/diagnostic.js +3 -7
- package/dist/v1/bundle/structure.js +2 -4
- 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 +4 -8
- package/dist/v1/compiled/admission/semantics/core.d.ts +1 -24
- package/dist/v1/compiled/admission/semantics/core.js +54 -34
- 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 +13 -22
- 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/compiler/compile.js +6 -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 +10 -44
- package/dist/v1/domain/create.js +3 -5
- package/dist/v1/domain/namespace/member-collection.js +4 -6
- package/dist/v1/domain/validation/create.d.ts +0 -1
- package/dist/v1/domain/validation/create.js +0 -35
- package/dist/v1/language/class/inheritance.d.ts +18 -0
- package/dist/v1/language/class/inheritance.js +73 -0
- package/dist/v1/language/class/property-values.js +2 -4
- package/dist/v1/language/core/facts.d.ts +72 -0
- package/dist/v1/language/core/facts.js +95 -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 +13 -1
- package/dist/v1/language/policy/analysis/budgets.js +104 -0
- package/dist/v1/language/policy/analysis/typing.d.ts +48 -0
- package/dist/v1/language/policy/analysis/typing.js +338 -0
- package/dist/v1/language/validation/diagnostic.d.ts +14 -0
- package/dist/v1/language/validation/diagnostic.js +21 -0
- package/dist/v1/language/value/compile/fields.js +4 -8
- package/dist/v1/language/value/profile/rules.js +5 -7
- package/dist/v1/language/value/profile/validate.js +1 -10
- package/dist/v1/language/value/reference/recursion.js +2 -22
- 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/compatibility/diff.js +2 -4
- package/dist/v1/schema/compatibility/meaning/footprint.js +16 -50
- package/dist/v1/schema/compatibility/structure/requirements.js +26 -58
- package/dist/v1/schema/compatibility/walk.d.ts +17 -0
- package/dist/v1/schema/compatibility/walk.js +41 -0
- package/dist/v1/schema/diagnostic.js +3 -11
- package/dist/v1/schema/resolution/context.js +3 -5
- package/dist/v1/schema/validation/callable.js +3 -5
- package/dist/v1/schema/validation/class.js +10 -52
- package/dist/v1/schema/validation/core.js +65 -199
- package/dist/v1/schema/validation/domain.js +1 -10
- package/dist/v1/schema/validation/domain.structure.js +2 -4
- package/dist/v1/schema/validation/policy/budgets.js +5 -112
- package/dist/v1/schema/validation/policy/context.d.ts +5 -3
- package/dist/v1/schema/validation/policy/context.js +5 -3
- 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 +5 -6
- 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 +1 -1
- package/dist/v1/schema/validation/policy/uses.js +9 -22
- package/dist/v1/schema/validation/policy/validate.js +3 -2
- package/dist/v1/schema/validation/value-api.js +2 -2
- package/dist/v1/schema/validation/value.js +5 -7
- package/dist/v1/schema/validation/view.js +4 -8
- package/package.json +1 -1
- package/dist/v1/compiled/admission/semantics/cardinality.d.ts +0 -5
- package/dist/v1/compiled/admission/semantics/cardinality.js +0 -128
- 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/core/index.js +0 -1
- package/dist/v1/language/value/index.d.ts +0 -11
- package/dist/v1/language/value/index.js +0 -8
|
@@ -1,59 +1,25 @@
|
|
|
1
|
-
import { Key } from '../../../addressing/index.js';
|
|
2
|
-
import { compareAddedProperties, compareLostProperties } from '../comparators/classes.js';
|
|
3
|
-
import { compareFacet } from '../comparators/index.js';
|
|
4
|
-
import { contextInvalid } from '../context.js';
|
|
5
1
|
import { callableReferences, classReferences, inherits, memberReferences, valueReferences, } from '../references.js';
|
|
2
|
+
import { walkReferences } from '../walk.js';
|
|
6
3
|
/** Meaning follows complete callable contracts through the exact authored reference closure. */
|
|
7
4
|
export function compareFootprint({ context, report, }) {
|
|
8
|
-
|
|
9
|
-
const visited = new Set();
|
|
10
|
-
for (const reference of queue) {
|
|
11
|
-
report.note(reference);
|
|
12
|
-
const { coordinate, usage } = reference;
|
|
13
|
-
const visit = `${coordinate.key}:${usage.relation}`;
|
|
14
|
-
if (visited.has(visit))
|
|
15
|
-
continue;
|
|
16
|
-
visited.add(visit);
|
|
17
|
-
const pair = context.pair(coordinate);
|
|
18
|
-
const subject = pair.source;
|
|
19
|
-
if (subject === undefined)
|
|
20
|
-
throw contextInvalid(`Retained acceptance context has no meaning for ${coordinate.key}.`, coordinate.key);
|
|
21
|
-
let facet;
|
|
5
|
+
walkReferences({ context, report }, (subject, { usage }, reach) => {
|
|
22
6
|
switch (subject.kind) {
|
|
23
|
-
case 'class':
|
|
24
|
-
|
|
25
|
-
queue.push(...classReferences(subject, false));
|
|
7
|
+
case 'class':
|
|
8
|
+
reach(...classReferences(subject, false));
|
|
26
9
|
if (inherits(usage))
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
10
|
+
reach(...classReferences(subject, true));
|
|
11
|
+
return inherits(usage) ? 'class.inherit' : 'class.reference';
|
|
30
12
|
case 'property':
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
break;
|
|
13
|
+
reach(...valueReferences(subject));
|
|
14
|
+
return 'property';
|
|
34
15
|
case 'method':
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
: subject.coordinate.ref.kind;
|
|
43
|
-
queue.push(...memberReferences(subject));
|
|
44
|
-
}
|
|
16
|
+
reach(...callableReferences(subject));
|
|
17
|
+
return 'method.signature';
|
|
18
|
+
case 'member':
|
|
19
|
+
reach(...memberReferences(subject));
|
|
20
|
+
return subject.coordinate.ref.kind === 'function'
|
|
21
|
+
? 'function.signature'
|
|
22
|
+
: subject.coordinate.ref.kind;
|
|
45
23
|
}
|
|
46
|
-
|
|
47
|
-
continue;
|
|
48
|
-
report.record({
|
|
49
|
-
pair,
|
|
50
|
-
facet,
|
|
51
|
-
...compareFacet({ context, pair, facet }),
|
|
52
|
-
requirement: { kind: facet },
|
|
53
|
-
});
|
|
54
|
-
if (facet === 'class.inherit')
|
|
55
|
-
compareAddedProperties({ context, pair, report });
|
|
56
|
-
if (subject.kind === 'class')
|
|
57
|
-
compareLostProperties({ pair, report });
|
|
58
|
-
}
|
|
24
|
+
});
|
|
59
25
|
}
|
|
@@ -1,79 +1,47 @@
|
|
|
1
|
-
import { Key } from '../../../addressing/index.js';
|
|
2
1
|
import { inheritanceOf } from '../../../language/class/inheritance.js';
|
|
3
|
-
import {
|
|
2
|
+
import { inheritanceMeaning } from '../comparators/classes.js';
|
|
4
3
|
import { compareFacet } from '../comparators/index.js';
|
|
5
4
|
import { fingerprintMeaning } from '../comparators/values.js';
|
|
6
5
|
import { contextInvalid } from '../context.js';
|
|
7
6
|
import { methodCoordinate } from '../coordinate.js';
|
|
8
7
|
import { closedParents } from '../extension.js';
|
|
9
8
|
import { callableReferences, classReferences, inherits, memberReferences, usageOf, valueReferences, } from '../references.js';
|
|
9
|
+
import { walkReferences } from '../walk.js';
|
|
10
10
|
/** Structure follows data and abstract obligations; concrete IO never expands its requirements. */
|
|
11
11
|
export function compareRequirements({ context, report, }) {
|
|
12
|
-
|
|
13
|
-
const visited = new Set();
|
|
14
|
-
for (const reference of queue) {
|
|
15
|
-
report.note(reference);
|
|
16
|
-
const { coordinate, usage } = reference;
|
|
17
|
-
const visit = `${coordinate.key}:${usage.relation}`;
|
|
18
|
-
if (visited.has(visit))
|
|
19
|
-
continue;
|
|
20
|
-
visited.add(visit);
|
|
21
|
-
const pair = context.pair(coordinate);
|
|
22
|
-
const subject = pair.source;
|
|
23
|
-
if (subject === undefined)
|
|
24
|
-
throw contextInvalid(`Retained acceptance context has no meaning for ${coordinate.key}.`, coordinate.key);
|
|
25
|
-
let facet;
|
|
12
|
+
walkReferences({ context, report }, (subject, { coordinate, usage }, reach) => {
|
|
26
13
|
switch (subject.kind) {
|
|
27
|
-
case 'class':
|
|
28
|
-
|
|
29
|
-
queue.push(...classReferences(subject, false));
|
|
14
|
+
case 'class':
|
|
15
|
+
reach(...classReferences(subject, false));
|
|
30
16
|
if (inherits(usage)) {
|
|
31
|
-
|
|
17
|
+
reach(...classReferences(subject, true));
|
|
32
18
|
for (const method of subject.analysis.requirements.values())
|
|
33
|
-
|
|
19
|
+
reach({
|
|
34
20
|
coordinate: methodCoordinate(method.owner, method.name),
|
|
35
21
|
usage: usageOf(subject.schema, 'abstract', coordinate.key),
|
|
36
22
|
});
|
|
37
23
|
}
|
|
38
|
-
|
|
39
|
-
}
|
|
24
|
+
return inherits(usage) ? 'class.inherit' : 'class.reference';
|
|
40
25
|
case 'property':
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
? 'function.existence'
|
|
54
|
-
: subject.coordinate.ref.kind;
|
|
55
|
-
if (facet !== 'function.existence')
|
|
56
|
-
queue.push(...memberReferences(subject));
|
|
57
|
-
}
|
|
26
|
+
reach(...valueReferences(subject));
|
|
27
|
+
return 'property';
|
|
28
|
+
case 'method':
|
|
29
|
+
if (usage.relation !== 'abstract')
|
|
30
|
+
return 'method.existence';
|
|
31
|
+
reach(...callableReferences(subject));
|
|
32
|
+
return 'method.inheritance';
|
|
33
|
+
case 'member':
|
|
34
|
+
if (subject.coordinate.ref.kind === 'function')
|
|
35
|
+
return 'function.existence';
|
|
36
|
+
reach(...memberReferences(subject));
|
|
37
|
+
return subject.coordinate.ref.kind;
|
|
58
38
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
usage.relation === 'capability';
|
|
66
|
-
report.record({
|
|
67
|
-
pair,
|
|
68
|
-
facet,
|
|
69
|
-
...compareFacet({ context, pair, facet }),
|
|
70
|
-
...(required ? { requirement: { kind: facet } } : {}),
|
|
71
|
-
});
|
|
72
|
-
if (facet === 'class.inherit')
|
|
73
|
-
compareAddedProperties({ context, pair, report });
|
|
74
|
-
if (subject.kind === 'class')
|
|
75
|
-
compareLostProperties({ pair, report });
|
|
76
|
-
}
|
|
39
|
+
},
|
|
40
|
+
// Class membership does not establish an invocation dependency. Explicit member selection,
|
|
41
|
+
// a Method the dependent declares as a capability, and inherited abstract obligations do.
|
|
42
|
+
(facet, usage) => facet !== 'method.existence' ||
|
|
43
|
+
usage.relation === 'selection' ||
|
|
44
|
+
usage.relation === 'capability');
|
|
77
45
|
compareReliance({ context, report });
|
|
78
46
|
compareExtension({ context, report });
|
|
79
47
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Usage } from './model.js';
|
|
2
|
+
import type { Reference } from './references.js';
|
|
3
|
+
import type { Report } from './report.js';
|
|
4
|
+
import type { ComparisonContext } from './scope.js';
|
|
5
|
+
import type { ResolvedSubject } from './subjects.js';
|
|
6
|
+
import { compareFacet } from './comparators/index.js';
|
|
7
|
+
type WalkedFacet = Parameters<typeof compareFacet>[0]['facet'];
|
|
8
|
+
/**
|
|
9
|
+
* Follow the reference closure from the roots once per coordinate and usage relation. `expand`
|
|
10
|
+
* names the facet a reached subject is compared under and `reach`es what it references; a subject
|
|
11
|
+
* of the compared origin is then recorded, as a requirement when `required` says so.
|
|
12
|
+
*/
|
|
13
|
+
export declare function walkReferences({ context, report }: {
|
|
14
|
+
readonly context: ComparisonContext;
|
|
15
|
+
readonly report: Report;
|
|
16
|
+
}, expand: (subject: ResolvedSubject, reference: Reference, reach: (...references: readonly Reference[]) => void) => WalkedFacet, required?: (facet: WalkedFacet, usage: Usage) => boolean): void;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Key } from '../../addressing/index.js';
|
|
2
|
+
import { compareAddedProperties, compareLostProperties } from './comparators/classes.js';
|
|
3
|
+
import { compareFacet } from './comparators/index.js';
|
|
4
|
+
import { contextInvalid } from './context.js';
|
|
5
|
+
/**
|
|
6
|
+
* Follow the reference closure from the roots once per coordinate and usage relation. `expand`
|
|
7
|
+
* names the facet a reached subject is compared under and `reach`es what it references; a subject
|
|
8
|
+
* of the compared origin is then recorded, as a requirement when `required` says so.
|
|
9
|
+
*/
|
|
10
|
+
export function walkReferences({ context, report }, expand, required = () => true) {
|
|
11
|
+
const queue = [...context.roots];
|
|
12
|
+
const reach = (...references) => {
|
|
13
|
+
queue.push(...references);
|
|
14
|
+
};
|
|
15
|
+
const visited = new Set();
|
|
16
|
+
for (const reference of queue) {
|
|
17
|
+
report.note(reference);
|
|
18
|
+
const { coordinate, usage } = reference;
|
|
19
|
+
const visit = `${coordinate.key}:${usage.relation}`;
|
|
20
|
+
if (visited.has(visit))
|
|
21
|
+
continue;
|
|
22
|
+
visited.add(visit);
|
|
23
|
+
const pair = context.pair(coordinate);
|
|
24
|
+
const subject = pair.source;
|
|
25
|
+
if (subject === undefined)
|
|
26
|
+
throw contextInvalid(`Retained acceptance context has no meaning for ${coordinate.key}.`, coordinate.key);
|
|
27
|
+
const facet = expand(subject, reference, reach);
|
|
28
|
+
if (Key.origin(coordinate.key) !== context.source.origin)
|
|
29
|
+
continue;
|
|
30
|
+
report.record({
|
|
31
|
+
pair,
|
|
32
|
+
facet,
|
|
33
|
+
...compareFacet({ context, pair, facet }),
|
|
34
|
+
...(required(facet, usage) ? { requirement: { kind: facet } } : {}),
|
|
35
|
+
});
|
|
36
|
+
if (facet === 'class.inherit')
|
|
37
|
+
compareAddedProperties({ context, pair, report });
|
|
38
|
+
if (subject.kind === 'class')
|
|
39
|
+
compareLostProperties({ pair, report });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -1,21 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { formatDiagnostics, orderDiagnostics } from '../language/validation/diagnostic.js';
|
|
2
2
|
export function diagnostic(code, pointer, message, ref) {
|
|
3
3
|
return Object.freeze({ code, pointer, message, ...(ref === undefined ? {} : { ref }) });
|
|
4
4
|
}
|
|
5
5
|
export class SchemaError extends Error {
|
|
6
6
|
diagnostics;
|
|
7
7
|
constructor(diagnostics) {
|
|
8
|
-
const ordered =
|
|
9
|
-
super(ordered
|
|
8
|
+
const ordered = orderDiagnostics(diagnostics);
|
|
9
|
+
super(formatDiagnostics(ordered));
|
|
10
10
|
this.name = 'SchemaError';
|
|
11
11
|
this.diagnostics = Object.freeze(ordered);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
-
function compareDiagnostic(left, right) {
|
|
15
|
-
return (compareUnicode(left.pointer, right.pointer) ||
|
|
16
|
-
compareUnicode(left.code, right.code) ||
|
|
17
|
-
compareUnicode(left.message, right.message));
|
|
18
|
-
}
|
|
19
|
-
function formatDiagnostic(value) {
|
|
20
|
-
return `${value.pointer || '/'} [${value.code}] ${value.message}`;
|
|
21
|
-
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { dependencyLimits } from '../../addressing/domain-dependency.js';
|
|
2
2
|
import { definitionRefIndex } from '../../addressing/ordering.js';
|
|
3
3
|
import { DOMAIN_REVISION_PATTERN } from '../../addressing/patterns.js';
|
|
4
|
+
import { escapePointerToken } from '../../language/value/syntax/pointer.js';
|
|
4
5
|
import { revisionOfDomainSchema } from '../canonical/revision.js';
|
|
5
6
|
import { diagnostic } from '../diagnostic.js';
|
|
6
7
|
import { indexSchemaDefinitions } from './definition.index.js';
|
|
@@ -14,7 +15,7 @@ export function buildDomainResolutionContext(candidate, lookup) {
|
|
|
14
15
|
diagnostics.push(diagnostic('DV_DEPENDENCY_LIMITS', '/dependencies', `A Domain may declare at most ${dependencyLimits.direct} direct dependency aliases.`));
|
|
15
16
|
}
|
|
16
17
|
for (const [alias, dependency] of Object.entries(candidate.dependencies)) {
|
|
17
|
-
const pointer = `/dependencies/${
|
|
18
|
+
const pointer = `/dependencies/${escapePointerToken(alias)}`;
|
|
18
19
|
if (!DOMAIN_REVISION_PATTERN.test(dependency.revision))
|
|
19
20
|
continue;
|
|
20
21
|
if (dependency.origin === candidate.origin) {
|
|
@@ -94,7 +95,7 @@ function loadDependencyClosure(candidate, dependencies, lookup, diagnostics) {
|
|
|
94
95
|
continue;
|
|
95
96
|
}
|
|
96
97
|
const [alias, dependency] = edge;
|
|
97
|
-
const pointer = frames.length === 1 ? `/dependencies/${
|
|
98
|
+
const pointer = frames.length === 1 ? `/dependencies/${escapePointerToken(alias)}` : '/dependencies';
|
|
98
99
|
if (activeOrigins.has(dependency.origin)) {
|
|
99
100
|
diagnostics.push(diagnostic('DV_DEPENDENCY_ACYCLIC', pointer, `Dependency cycle reaches ${dependency.origin}.`));
|
|
100
101
|
continue;
|
|
@@ -153,6 +154,3 @@ function validateDependencyUse(candidate, directOrigins, diagnostics) {
|
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
}
|
|
156
|
-
function escapeToken(value) {
|
|
157
|
-
return value.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
158
|
-
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { isAdmissionMaxAge, MAXIMUM_ADMISSION_AGE_SECONDS, } from '../../language/callable/admission.js';
|
|
2
2
|
import { isBinaryInput } from '../../language/callable/model/callable.js';
|
|
3
|
+
import { escapePointerToken } from '../../language/value/syntax/pointer.js';
|
|
3
4
|
import { diagnostic } from '../diagnostic.js';
|
|
4
5
|
/** Validate the execution modifier and admission age of every local Function and Node Method. */
|
|
5
6
|
export function validateCallables(schema) {
|
|
6
7
|
const diagnostics = [];
|
|
7
8
|
for (const [name, declaration] of Object.entries(schema.functions)) {
|
|
8
|
-
const pointer = `/functions/${
|
|
9
|
+
const pointer = `/functions/${escapePointerToken(name)}`;
|
|
9
10
|
validateExecution(declaration, pointer, diagnostics);
|
|
10
11
|
validateAdmission(declaration, pointer, diagnostics);
|
|
11
12
|
}
|
|
@@ -13,7 +14,7 @@ export function validateCallables(schema) {
|
|
|
13
14
|
if (declaration.kind !== 'node')
|
|
14
15
|
continue;
|
|
15
16
|
for (const [method, value] of Object.entries(declaration.methods)) {
|
|
16
|
-
const pointer = `/classes/${
|
|
17
|
+
const pointer = `/classes/${escapePointerToken(name)}/methods/${escapePointerToken(method)}`;
|
|
17
18
|
validateExecution(value, pointer, diagnostics);
|
|
18
19
|
validateAdmission(value, pointer, diagnostics);
|
|
19
20
|
}
|
|
@@ -49,6 +50,3 @@ function validateExecution(declaration, pointer, diagnostics) {
|
|
|
49
50
|
diagnostics.push(diagnostic('DV_CALLABLE_IO', `${pointer}/output/mode`, 'A durable callable requires a value output.'));
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
|
-
function escapePointer(value) {
|
|
53
|
-
return value.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
54
|
-
}
|
|
@@ -1,12 +1,14 @@
|
|
|
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';
|
|
5
6
|
import { lifetimeBreaches, lifetimeScope } from '../../language/class/lifetime.js';
|
|
6
7
|
import { keyableProperty } from '../../language/class/unique.js';
|
|
7
8
|
import { admitStateTopology } from '../../language/state/topology.js';
|
|
8
9
|
import { isBlobValueSchema } from '../../language/value/model/blob.js';
|
|
9
10
|
import { classifyOrdering } from '../../language/value/ordering.js';
|
|
11
|
+
import { escapePointerToken } from '../../language/value/syntax/pointer.js';
|
|
10
12
|
import { diagnostic } from '../diagnostic.js';
|
|
11
13
|
import { createDomainValueSchemaRegistry, createValueSchemaRegistry, } from '../resolution/value.registry.js';
|
|
12
14
|
const formatDefinitionRef = Key.of;
|
|
@@ -16,9 +18,9 @@ export function validateDefinitions(environment, analysis) {
|
|
|
16
18
|
const schema = environment.candidate;
|
|
17
19
|
let scope;
|
|
18
20
|
for (const [name, declaration] of Object.entries(schema.classes)) {
|
|
19
|
-
const ref =
|
|
20
|
-
const pointer = `/classes/${
|
|
21
|
-
if (!
|
|
21
|
+
const ref = { origin: schema.origin, kind: 'class', name };
|
|
22
|
+
const pointer = `/classes/${escapePointerToken(name)}`;
|
|
23
|
+
if (!equalDefinitionRefs(declaration.ref, ref)) {
|
|
22
24
|
diagnostics.push(diagnostic('DV_REF_RESOLVES', `${pointer}/ref`, `Class ref must be exactly ${formatDefinitionRef(ref)}.`, formatDefinitionRef(declaration.ref)));
|
|
23
25
|
}
|
|
24
26
|
if (declaration.abstract &&
|
|
@@ -40,7 +42,7 @@ export function validateDefinitions(environment, analysis) {
|
|
|
40
42
|
function validateFacet(environment, declaration, pointer, diagnostics) {
|
|
41
43
|
const valueRegistry = createValueSchemaRegistry(environment);
|
|
42
44
|
for (const [name, property] of Object.entries(declaration.properties)) {
|
|
43
|
-
const propertyPointer = `${pointer}/properties/${
|
|
45
|
+
const propertyPointer = `${pointer}/properties/${escapePointerToken(name)}`;
|
|
44
46
|
if (isBlobValueSchema(property.schema) &&
|
|
45
47
|
(declaration.kind !== 'node' || property.auto !== undefined || property.state !== undefined)) {
|
|
46
48
|
diagnostics.push(diagnostic('DV_VALUE_SCHEMA', `${propertyPointer}/schema/x-astrale-value-kind`, 'Blob values are allowed only on non-automatic, non-state Node properties.'));
|
|
@@ -92,7 +94,7 @@ function validateFacet(environment, declaration, pointer, diagnostics) {
|
|
|
92
94
|
if (declaration.kind !== 'node')
|
|
93
95
|
return;
|
|
94
96
|
for (const [name, method] of Object.entries(declaration.methods)) {
|
|
95
|
-
const methodPointer = `${pointer}/methods/${
|
|
97
|
+
const methodPointer = `${pointer}/methods/${escapePointerToken(name)}`;
|
|
96
98
|
if (isMethodExecutable(declaration, method))
|
|
97
99
|
continue;
|
|
98
100
|
if (method.policy !== undefined) {
|
|
@@ -107,7 +109,7 @@ function validateFacet(environment, declaration, pointer, diagnostics) {
|
|
|
107
109
|
function validateParents(environment, owner, ownerKind, parents, diagnostics) {
|
|
108
110
|
for (const [index, parent] of parents.entries()) {
|
|
109
111
|
const target = environment.resolve(parent);
|
|
110
|
-
const pointer = `/classes/${
|
|
112
|
+
const pointer = `/classes/${escapePointerToken(owner.name)}/extends/${index}`;
|
|
111
113
|
if (target === undefined) {
|
|
112
114
|
diagnostics.push(diagnostic('DV_REF_RESOLVES', pointer, `Parent ${formatDefinitionRef(parent)} does not resolve exactly.`, formatDefinitionRef(parent)));
|
|
113
115
|
continue;
|
|
@@ -244,42 +246,7 @@ function validateEdgeClassComposition(environment, diagnostics) {
|
|
|
244
246
|
}
|
|
245
247
|
/** Whether `child` safely refines its parent Edge contract `parent`. */
|
|
246
248
|
export function edgeContractRefines(environment, child, parent) {
|
|
247
|
-
|
|
248
|
-
return true;
|
|
249
|
-
if (child.orientation !== parent.orientation)
|
|
250
|
-
return false;
|
|
251
|
-
if (parent.constraints.noSelf === true && child.constraints.noSelf !== true)
|
|
252
|
-
return false;
|
|
253
|
-
if (parent.constraints.acyclic === true && child.constraints.acyclic !== true)
|
|
254
|
-
return false;
|
|
255
|
-
if (child.orientation === 'directed' && parent.orientation === 'directed') {
|
|
256
|
-
return (endpointRefines(environment, child.endpoints.source, parent.endpoints.source) &&
|
|
257
|
-
countRefines(child.endpoints.source.outgoing, parent.endpoints.source.outgoing) &&
|
|
258
|
-
endpointRefines(environment, child.endpoints.target, parent.endpoints.target) &&
|
|
259
|
-
countRefines(child.endpoints.target.incoming, parent.endpoints.target.incoming));
|
|
260
|
-
}
|
|
261
|
-
if (child.orientation !== 'undirected' || parent.orientation !== 'undirected')
|
|
262
|
-
return false;
|
|
263
|
-
const refines = (childIndex, parentIndex) => endpointRefines(environment, child.endpoints[childIndex], parent.endpoints[parentIndex]) &&
|
|
264
|
-
countRefines(child.endpoints[childIndex].incident, parent.endpoints[parentIndex].incident);
|
|
265
|
-
const direct = refines(0, 0) && refines(1, 1);
|
|
266
|
-
if (direct)
|
|
267
|
-
return true;
|
|
268
|
-
return refines(0, 1) && refines(1, 0);
|
|
269
|
-
}
|
|
270
|
-
function endpointRefines(environment, child, parent) {
|
|
271
|
-
return child.accepts.every((accepted) => classSatisfies(environment, accepted, parent.accepts));
|
|
272
|
-
}
|
|
273
|
-
function countRefines(child, parent) {
|
|
274
|
-
const bounds = {
|
|
275
|
-
'0..*': [0, Number.POSITIVE_INFINITY],
|
|
276
|
-
'1..*': [1, Number.POSITIVE_INFINITY],
|
|
277
|
-
'0..1': [0, 1],
|
|
278
|
-
'1': [1, 1],
|
|
279
|
-
};
|
|
280
|
-
const [childMinimum, childMaximum] = bounds[child];
|
|
281
|
-
const [parentMinimum, parentMaximum] = bounds[parent];
|
|
282
|
-
return childMinimum >= parentMinimum && childMaximum <= parentMaximum;
|
|
249
|
+
return refinesEdgeContract(child, parent, (candidate, accepts) => classSatisfies(environment, candidate, accepts));
|
|
283
250
|
}
|
|
284
251
|
/** Whether `candidate` is, or is a Node Class extending, one of `accepts`. */
|
|
285
252
|
export function classSatisfies(environment, candidate, accepts) {
|
|
@@ -294,12 +261,3 @@ export function classSatisfies(environment, candidate, accepts) {
|
|
|
294
261
|
return required !== undefined && satisfiesClass(actual, required, resolve);
|
|
295
262
|
});
|
|
296
263
|
}
|
|
297
|
-
function localRef(origin, name) {
|
|
298
|
-
return { origin, kind: 'class', name };
|
|
299
|
-
}
|
|
300
|
-
function sameRef(left, right) {
|
|
301
|
-
return left.origin === right.origin && left.kind === right.kind && left.name === right.name;
|
|
302
|
-
}
|
|
303
|
-
function escapePointer(value) {
|
|
304
|
-
return value.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
305
|
-
}
|