@astrale-os/kernel-dsl 1.0.0-beta.11 → 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/callable/authoring.d.ts +1 -1
- package/dist/v1/builder/class/authoring.d.ts +6 -256
- package/dist/v1/builder/class/authoring.js +5 -28
- 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 +129 -0
- package/dist/v1/builder/class/projection.d.ts +129 -0
- package/dist/v1/builder/class/projection.js +1 -0
- package/dist/v1/builder/core/authoring.d.ts +1 -1
- package/dist/v1/builder/index.d.ts +3 -1
- package/dist/v1/builder/lowering/class.d.ts +1 -1
- package/dist/v1/builder/lowering/schema/context.d.ts +2 -1
- package/dist/v1/builder/lowering/schema/context.js +2 -4
- 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 +1 -1
- 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/input.d.ts +1 -1
- package/dist/v1/builder/schema/projection/class.d.ts +2 -1
- 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/property.d.ts +1 -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 +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/index.d.ts +1 -0
- package/dist/v1/language/index.js +1 -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 +15 -1
- package/dist/v1/language/validation/diagnostic.js +21 -0
- package/dist/v1/language/value/compile/fields.js +4 -8
- 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 +9 -0
- package/dist/v1/language/value/ordering.js +72 -9
- 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.d.ts +9 -0
- package/dist/v1/schema/validation/value-api.js +23 -1
- package/dist/v1/schema/validation/value.js +5 -7
- package/dist/v1/schema/validation/view.js +4 -8
- package/dist/value/canonical.d.ts +3 -2
- package/dist/value/canonical.js +30 -6
- 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 +1 -1
- package/dist/value/json.js +1 -1
- 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 +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/value/index.d.ts +0 -11
- package/dist/v1/language/value/index.js +0 -8
- /package/dist/v1/{language/core/index.js → builder/class/input.js} +0 -0
|
@@ -1,206 +1,24 @@
|
|
|
1
1
|
import { Key } from '../../../../addressing/index.js';
|
|
2
|
-
import {
|
|
3
|
-
import { branchesOf, branchProduct, capBranches, targetMode, termKey, } from '../../../../language/policy/analysis/branches.js';
|
|
2
|
+
import { PolicyTyping } from '../../../../language/policy/analysis/typing.js';
|
|
4
3
|
import {} from '../../../../language/policy/model/policy.js';
|
|
5
4
|
import {} from '../../../model/schema.js';
|
|
6
|
-
import { classSatisfiesAny } from '../context.js';
|
|
7
|
-
import {
|
|
8
|
-
import { CompiledUnionFind } from './equality.js';
|
|
9
|
-
import { compiledEdgeAlternatives } from './variants.js';
|
|
5
|
+
import { classSatisfiesAny, isCompiledEdge } from '../context.js';
|
|
6
|
+
import { referenceContract } from './contracts.js';
|
|
10
7
|
/** Types one entry's Policies against the Node Classes of its own closure, as source admission. */
|
|
11
|
-
export
|
|
12
|
-
context
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
expandedBranches(name, visiting, namespace) {
|
|
28
|
-
if (visiting.has(name))
|
|
29
|
-
return undefined;
|
|
30
|
-
const declaration = this.normalized.get(name);
|
|
31
|
-
if (declaration === undefined)
|
|
32
|
-
return undefined;
|
|
33
|
-
if ('match' in declaration)
|
|
34
|
-
return branchesOf(declaration.match, namespace);
|
|
35
|
-
const nested = new Set(visiting);
|
|
36
|
-
nested.add(name);
|
|
37
|
-
const refs = 'allOf' in declaration ? declaration.allOf : declaration.anyOf;
|
|
38
|
-
const children = [];
|
|
39
|
-
for (const [index, ref] of refs.entries()) {
|
|
40
|
-
if (ref.origin !== this.entry.origin || ref.kind !== 'policy')
|
|
41
|
-
return undefined;
|
|
42
|
-
const expanded = this.expandedBranches(ref.name, nested, `${namespace}/${index}:${ref.name}`);
|
|
43
|
-
if (expanded === undefined)
|
|
44
|
-
return undefined;
|
|
45
|
-
children.push(expanded);
|
|
46
|
-
}
|
|
47
|
-
return 'allOf' in declaration ? branchProduct(children) : capBranches(children.flat());
|
|
48
|
-
}
|
|
49
|
-
policyAccepts(name, object) {
|
|
50
|
-
return this.policyBranchTyping(name, object)?.every(Boolean) ?? false;
|
|
51
|
-
}
|
|
52
|
-
policyBranchTyping(name, object) {
|
|
53
|
-
const branches = this.expandedBranches(name, new Set(), `$use:${name}`);
|
|
54
|
-
return branches?.map((branch) => this.branchIsTyped(branch, { kind: 'object', object }));
|
|
55
|
-
}
|
|
56
|
-
policyAcceptsEdge(name, source, target) {
|
|
57
|
-
const branches = this.expandedBranches(name, new Set(), `$edge-use:${name}`);
|
|
58
|
-
return (branches !== undefined &&
|
|
59
|
-
branches.every((branch) => this.branchIsTyped(branch, { kind: 'edge', source, target })));
|
|
60
|
-
}
|
|
61
|
-
concreteEndpointClasses(accepts) {
|
|
62
|
-
return this.concreteNodeClasses.filter((candidate) => classSatisfiesAny(this.context, candidate, accepts));
|
|
63
|
-
}
|
|
64
|
-
endpointsOverlap(left, right) {
|
|
65
|
-
const seed = [{ kind: 'open', requirements: [] }];
|
|
66
|
-
return this.applyEndpoint(this.applyEndpoint(seed, left), right).length > 0;
|
|
67
|
-
}
|
|
68
|
-
branchIsTyped(branch, use) {
|
|
69
|
-
if (targetMode(branch) !== use.kind)
|
|
70
|
-
return false;
|
|
71
|
-
return compiledEdgeAlternatives(branch.edges, this).some((variants) => this.constraintsSatisfiable(branch, variants, use));
|
|
72
|
-
}
|
|
73
|
-
constraintsSatisfiable(branch, variants, use) {
|
|
74
|
-
const terms = new Set(use.kind === 'object' ? ['subject', 'object'] : ['subject', 'source', 'target']);
|
|
75
|
-
for (const key of branch.variables.keys())
|
|
76
|
-
terms.add(key);
|
|
77
|
-
for (const key of branch.terms.keys())
|
|
78
|
-
terms.add(key);
|
|
79
|
-
for (const edge of branch.edges) {
|
|
80
|
-
terms.add(termKey(edge.pattern.source, edge.namespace));
|
|
81
|
-
terms.add(termKey(edge.pattern.target, edge.namespace));
|
|
82
|
-
}
|
|
83
|
-
const union = new CompiledUnionFind(terms);
|
|
84
|
-
for (const [left, right] of branch.equalities)
|
|
85
|
-
union.join(left, right);
|
|
86
|
-
for (const variant of variants)
|
|
87
|
-
for (const [left, right] of variant.equalities)
|
|
88
|
-
union.join(left, right);
|
|
89
|
-
const constraints = new Map();
|
|
90
|
-
for (const variant of variants) {
|
|
91
|
-
for (const [term, accepts] of variant.constraints) {
|
|
92
|
-
const root = union.find(term);
|
|
93
|
-
const values = constraints.get(root) ?? [];
|
|
94
|
-
values.push(accepts);
|
|
95
|
-
constraints.set(root, values);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
const groups = new Map();
|
|
99
|
-
for (const term of terms) {
|
|
100
|
-
const root = union.find(term);
|
|
101
|
-
const values = groups.get(root) ?? [];
|
|
102
|
-
values.push(term);
|
|
103
|
-
groups.set(root, values);
|
|
104
|
-
}
|
|
105
|
-
for (const [root, members] of groups) {
|
|
106
|
-
let candidates = [{ kind: 'open', requirements: [] }];
|
|
107
|
-
for (const member of members) {
|
|
108
|
-
candidates = this.applyInitial(candidates, member, branch, use);
|
|
109
|
-
if (candidates.length === 0)
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
for (const endpoint of constraints.get(root) ?? []) {
|
|
113
|
-
candidates = this.applyEndpoint(candidates, endpoint);
|
|
114
|
-
if (candidates.length === 0)
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
return true;
|
|
119
|
-
}
|
|
120
|
-
applyInitial(candidates, term, branch, use) {
|
|
121
|
-
if (term === 'subject')
|
|
122
|
-
return this.applyAnyNodeClass(candidates);
|
|
123
|
-
const contract = compiledTargetContract(term, use);
|
|
124
|
-
if (contract !== undefined) {
|
|
125
|
-
return contract.kind === 'exact'
|
|
126
|
-
? this.applyExact(candidates, contract.ref)
|
|
127
|
-
: uniqueCompiledCandidates(this.allNodeClasses.flatMap((ref) => this.applyExact(candidates, ref)));
|
|
128
|
-
}
|
|
129
|
-
const referenced = branch.terms.get(term);
|
|
130
|
-
if (referenced?.kind === 'ref') {
|
|
131
|
-
const contract = callableObjectContracts(this.context, this.entry, 0, undefined, referenced)?.[0];
|
|
132
|
-
return contract?.kind === 'exact' ? this.applyExact(candidates, contract.ref) : [];
|
|
133
|
-
}
|
|
134
|
-
const selector = branch.variables.get(term);
|
|
135
|
-
if (selector === undefined)
|
|
136
|
-
return [];
|
|
137
|
-
if (selector.kind === 'exact')
|
|
138
|
-
return this.applyExact(candidates, selector.class);
|
|
139
|
-
if (selector.kind === 'any')
|
|
140
|
-
return candidates;
|
|
141
|
-
return this.applyRequirement(candidates, selector.class);
|
|
142
|
-
}
|
|
143
|
-
applyExact(candidates, exact) {
|
|
144
|
-
return uniqueCompiledCandidates(candidates.flatMap((candidate) => {
|
|
145
|
-
if (candidate.kind === 'exact')
|
|
146
|
-
return Key.of(candidate.ref) === Key.of(exact) ? [candidate] : [];
|
|
147
|
-
return candidate.requirements.every((required) => classSatisfiesAny(this.context, exact, [required]))
|
|
148
|
-
? [{ kind: 'exact', ref: exact }]
|
|
149
|
-
: [];
|
|
150
|
-
}));
|
|
151
|
-
}
|
|
152
|
-
applyAnyNodeClass(candidates) {
|
|
153
|
-
return uniqueCompiledCandidates(candidates.flatMap((candidate) => candidate.kind === 'exact'
|
|
154
|
-
? [candidate]
|
|
155
|
-
: this.allNodeClasses
|
|
156
|
-
.filter((ref) => candidate.requirements.every((required) => classSatisfiesAny(this.context, ref, [required])))
|
|
157
|
-
.map((ref) => ({ kind: 'exact', ref }))));
|
|
158
|
-
}
|
|
159
|
-
applyRequirement(candidates, required) {
|
|
160
|
-
const result = [];
|
|
161
|
-
for (const candidate of candidates) {
|
|
162
|
-
if (candidate.kind === 'exact') {
|
|
163
|
-
if (classSatisfiesAny(this.context, candidate.ref, [required]))
|
|
164
|
-
result.push(candidate);
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
result.push({
|
|
168
|
-
kind: 'open',
|
|
169
|
-
requirements: uniqueClassRefs([...candidate.requirements, required]),
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return uniqueCompiledCandidates(result);
|
|
174
|
-
}
|
|
175
|
-
applyEndpoint(candidates, accepts) {
|
|
176
|
-
const result = [];
|
|
177
|
-
for (const candidate of candidates) {
|
|
178
|
-
if (candidate.kind === 'exact') {
|
|
179
|
-
if (classSatisfiesAny(this.context, candidate.ref, accepts))
|
|
180
|
-
result.push(candidate);
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
for (const accept of accepts) {
|
|
184
|
-
result.push({
|
|
185
|
-
kind: 'open',
|
|
186
|
-
requirements: uniqueClassRefs([...candidate.requirements, accept]),
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return uniqueCompiledCandidates(result);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
function uniqueCompiledCandidates(values) {
|
|
195
|
-
const result = new Map();
|
|
196
|
-
for (const value of values) {
|
|
197
|
-
const key = value.kind === 'exact'
|
|
198
|
-
? `exact:${Key.of(value.ref)}`
|
|
199
|
-
: `open:${value.requirements.map(Key.of).sort(compareUnicode).join('|')}`;
|
|
200
|
-
result.set(key, value);
|
|
201
|
-
}
|
|
202
|
-
return [...result.values()];
|
|
203
|
-
}
|
|
204
|
-
function uniqueClassRefs(values) {
|
|
205
|
-
return [...new Map(values.map((value) => [Key.of(value), value])).values()];
|
|
8
|
+
export function compiledPolicyTyping(context, entry, normalized, origins) {
|
|
9
|
+
const nodeClasses = [...context.classes.values()]
|
|
10
|
+
.map(({ value }) => value)
|
|
11
|
+
.filter((value) => value.kind === 'node' && origins.has(value.ref.origin));
|
|
12
|
+
return new PolicyTyping({
|
|
13
|
+
normalized,
|
|
14
|
+
allNodeClasses: nodeClasses.map((value) => value.ref),
|
|
15
|
+
concreteNodeClasses: nodeClasses.filter((value) => !value.abstract).map((value) => value.ref),
|
|
16
|
+
isLocalPolicy: (ref) => ref.origin === entry.origin && ref.kind === 'policy',
|
|
17
|
+
classExtends: (candidate, required) => classSatisfiesAny(context, candidate, [required]),
|
|
18
|
+
edgeDeclaration: (ref) => {
|
|
19
|
+
const value = context.classes.get(Key.of(ref))?.value;
|
|
20
|
+
return value !== undefined && isCompiledEdge(value) ? value : undefined;
|
|
21
|
+
},
|
|
22
|
+
referenceContract: (ref) => referenceContract(context, ref),
|
|
23
|
+
});
|
|
206
24
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { compareCodeUnits } from '../../addressing/ordering.js';
|
|
1
2
|
import { isBinaryInput } from '../../language/callable/model/callable.js';
|
|
2
3
|
import { inputFieldNodes } from '../../language/value/compile/fields.js';
|
|
3
4
|
import { prepareValueSchema } from '../../language/value/evaluate/preparation.js';
|
|
@@ -13,7 +14,7 @@ export function compile(schema) {
|
|
|
13
14
|
...requireDomainClosure(schema).map(({ schema: dependency }) => dependency),
|
|
14
15
|
]
|
|
15
16
|
.filter((value, index, all) => all.findIndex(({ origin }) => origin === value.origin) === index)
|
|
16
|
-
.sort((left, right) =>
|
|
17
|
+
.sort((left, right) => compareCodeUnits(left.origin, right.origin));
|
|
17
18
|
const closure = Object.freeze(sources.map((source) => compileEntry(source, lookup)));
|
|
18
19
|
return Object.freeze({
|
|
19
20
|
format: 'astrale.dsl.compiled-schema',
|
|
@@ -46,7 +47,7 @@ function compileEntry(schema, lookup) {
|
|
|
46
47
|
};
|
|
47
48
|
const add = (contract, pointer) => addProgram(prepare(contract, pointer).program());
|
|
48
49
|
const properties = (definition, pointer) => Object.entries(definition.properties)
|
|
49
|
-
.sort(([left], [right]) =>
|
|
50
|
+
.sort(([left], [right]) => compareCodeUnits(left, right))
|
|
50
51
|
.map(([name, property]) => {
|
|
51
52
|
const prepared = prepare(property.schema, `${pointer}/properties/${name}/schema`);
|
|
52
53
|
const ordering = classifyPreparedOrdering(prepared);
|
|
@@ -68,7 +69,7 @@ function compileEntry(schema, lookup) {
|
|
|
68
69
|
value: add(value.mode === 'value' ? value.schema : value.item, pointer),
|
|
69
70
|
};
|
|
70
71
|
const classes = Object.values(schema.classes)
|
|
71
|
-
.sort((left, right) =>
|
|
72
|
+
.sort((left, right) => compareCodeUnits(left.ref.name, right.ref.name))
|
|
72
73
|
.map((definition) => {
|
|
73
74
|
const pointer = `/classes/${definition.ref.name}`;
|
|
74
75
|
if (definition.kind === 'edge') {
|
|
@@ -77,7 +78,7 @@ function compileEntry(schema, lookup) {
|
|
|
77
78
|
}
|
|
78
79
|
const { properties: _, methods: __, ...rest } = definition;
|
|
79
80
|
const methods = Object.entries(definition.methods)
|
|
80
|
-
.sort(([left], [right]) =>
|
|
81
|
+
.sort(([left], [right]) => compareCodeUnits(left, right))
|
|
81
82
|
.map(([name, method]) => {
|
|
82
83
|
const input = add(method.input, `${pointer}/methods/${name}/input`);
|
|
83
84
|
const fields = inputFieldNodes(values[input]);
|
|
@@ -98,7 +99,7 @@ function compileEntry(schema, lookup) {
|
|
|
98
99
|
return { ...rest, properties: properties(definition, pointer), methods };
|
|
99
100
|
});
|
|
100
101
|
const functions = Object.values(schema.functions)
|
|
101
|
-
.sort((left, right) =>
|
|
102
|
+
.sort((left, right) => compareCodeUnits(left.ref.name, right.ref.name))
|
|
102
103
|
.map((definition) => {
|
|
103
104
|
const binary = isBinaryInput(definition.input);
|
|
104
105
|
const inputIndex = add(binary ? definition.input.metadata : definition.input, binary
|
|
@@ -142,6 +143,3 @@ function compileEntry(schema, lookup) {
|
|
|
142
143
|
patterns: Object.freeze([...patternIndices.keys()]),
|
|
143
144
|
});
|
|
144
145
|
}
|
|
145
|
-
function compare(left, right) {
|
|
146
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
147
|
-
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import { formatDiagnostics } from '../language/validation/diagnostic.js';
|
|
1
2
|
export class CompiledSchemaError extends Error {
|
|
2
3
|
diagnostics;
|
|
3
4
|
constructor(diagnostics, options) {
|
|
4
|
-
super(diagnostics
|
|
5
|
-
.map(({ code, pointer, message }) => `${pointer || '/'} [${code}] ${message}`)
|
|
6
|
-
.join('\n'), options);
|
|
5
|
+
super(formatDiagnostics(diagnostics), options);
|
|
7
6
|
this.name = 'CompiledSchemaError';
|
|
8
7
|
this.diagnostics = Object.freeze([...diagnostics]);
|
|
9
8
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import type { Domain } from '../../domain/model/domain.js';
|
|
1
2
|
import type { CompiledSchema, DomainOfCompiled } from '../model/schema.js';
|
|
2
3
|
/** Load admitted compiled data through the one resolved Domain constructor. */
|
|
3
4
|
export declare function load<const Input extends CompiledSchema>(input: Input): DomainOfCompiled<Input>;
|
|
4
|
-
export declare function load(input: unknown):
|
|
5
|
+
export declare function load(input: unknown): Domain;
|
|
5
6
|
/**
|
|
6
7
|
* Realize compiled material whose exact embedded bytes were already proven by generated build code.
|
|
7
8
|
* External bytes and caller-provided values must continue through {@link load}.
|
|
8
9
|
*/
|
|
9
|
-
export declare function realize(compiled: CompiledSchema):
|
|
10
|
+
export declare function realize(compiled: CompiledSchema): Domain;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Key, MethodKey, PropertyKey as PropertyKeyValue } from '../../addressing/index.js';
|
|
2
2
|
import { compareUnicode } from '../../addressing/ordering.js';
|
|
3
3
|
import { createDomain } from '../../domain/create.js';
|
|
4
|
-
import {
|
|
4
|
+
import { createDomainValidation, unknownInputField } from '../../domain/validation/create.js';
|
|
5
5
|
import { bindValueProgram } from '../../language/value/compile/load.js';
|
|
6
6
|
import { validateValueProgram } from '../../language/value/evaluate/program.js';
|
|
7
7
|
import { acceptCompiledSchema } from '../admission/accept.js';
|
|
8
|
+
import { schemaOf, sourceFunction, sourceMethod } from '../admission/revision.js';
|
|
8
9
|
export function load(input) {
|
|
9
10
|
return realize(acceptCompiledSchema(input));
|
|
10
11
|
}
|
|
@@ -14,13 +15,14 @@ export function load(input) {
|
|
|
14
15
|
*/
|
|
15
16
|
export function realize(compiled) {
|
|
16
17
|
const entries = new Map(compiled.closure.map((entry) => [entry.origin, loadEntry(entry)]));
|
|
18
|
+
const loaded = [...entries.values()];
|
|
17
19
|
const root = entries.get(compiled.root.origin);
|
|
18
20
|
if (root === undefined || root.entry.revision !== compiled.root.revision) {
|
|
19
21
|
throw new TypeError('Compiled root is absent or has the wrong revision.');
|
|
20
22
|
}
|
|
21
23
|
return createDomain({
|
|
22
24
|
root: compiled.root,
|
|
23
|
-
entries: Object.freeze(
|
|
25
|
+
entries: Object.freeze(loaded
|
|
24
26
|
.map(({ entry, definitions }) => Object.freeze({
|
|
25
27
|
origin: entry.origin,
|
|
26
28
|
revision: entry.revision,
|
|
@@ -29,7 +31,8 @@ export function realize(compiled) {
|
|
|
29
31
|
coreEdges: entry.facts.core,
|
|
30
32
|
}))
|
|
31
33
|
.sort((left, right) => compareUnicode(left.origin, right.origin))),
|
|
32
|
-
|
|
34
|
+
// Closure admission refuses a duplicate Definition, so no two entries share a key.
|
|
35
|
+
validation: createDomainValidation(new Map(loaded.flatMap(({ properties }) => [...properties])), new Map(loaded.flatMap(({ callables }) => [...callables]))),
|
|
33
36
|
});
|
|
34
37
|
}
|
|
35
38
|
function loadEntry(entry) {
|
|
@@ -52,13 +55,13 @@ function loadEntry(entry) {
|
|
|
52
55
|
const methods = Object.fromEntries(compiled.methods.map((method) => {
|
|
53
56
|
const key = MethodKey.of(compiled.ref, method.name);
|
|
54
57
|
callablePrograms.set(key, callableProgram(method));
|
|
55
|
-
return [method.name,
|
|
58
|
+
return [method.name, Object.freeze(sourceMethod(entry, method))];
|
|
56
59
|
}));
|
|
57
60
|
return Object.freeze({ ...definition, properties, methods });
|
|
58
61
|
});
|
|
59
62
|
const functions = entry.definitions.functions.map((compiled) => {
|
|
60
63
|
callablePrograms.set(Key.of(compiled.ref), callableProgram(compiled));
|
|
61
|
-
return
|
|
64
|
+
return Object.freeze(sourceFunction(entry, compiled));
|
|
62
65
|
});
|
|
63
66
|
return {
|
|
64
67
|
entry,
|
|
@@ -69,46 +72,9 @@ function loadEntry(entry) {
|
|
|
69
72
|
...entry.definitions.views,
|
|
70
73
|
...entry.definitions.core,
|
|
71
74
|
]),
|
|
72
|
-
|
|
75
|
+
...programValidation(entry.values.map((value) => bindValueProgram(value, entry.patterns)), propertyPrograms, propertyOrdering, callablePrograms),
|
|
73
76
|
};
|
|
74
77
|
}
|
|
75
|
-
function loadMethod(entry, value) {
|
|
76
|
-
const { name: _, input, fields: __, output, ...definition } = value;
|
|
77
|
-
return Object.freeze({
|
|
78
|
-
...definition,
|
|
79
|
-
input: schemaOf(entry, input),
|
|
80
|
-
output: loadOutput(entry, output),
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
function loadFunction(entry, value) {
|
|
84
|
-
const { input, fields: _, output, ...definition } = value;
|
|
85
|
-
return Object.freeze({
|
|
86
|
-
...definition,
|
|
87
|
-
input: typeof input === 'number'
|
|
88
|
-
? schemaOf(entry, input)
|
|
89
|
-
: {
|
|
90
|
-
mode: 'binary',
|
|
91
|
-
metadata: schemaOf(entry, input.metadata),
|
|
92
|
-
maximumBytes: input.maximumBytes,
|
|
93
|
-
},
|
|
94
|
-
output: loadOutput(entry, output),
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
function loadOutput(entry, output) {
|
|
98
|
-
if (output.mode === 'binary')
|
|
99
|
-
return output;
|
|
100
|
-
const schema = schemaOf(entry, output.value);
|
|
101
|
-
return output.mode === 'value'
|
|
102
|
-
? { mode: 'value', schema }
|
|
103
|
-
: { mode: 'stream', item: schema };
|
|
104
|
-
}
|
|
105
|
-
function schemaOf(entry, index) {
|
|
106
|
-
const program = entry.values[index];
|
|
107
|
-
const root = program?.nodes[program.root];
|
|
108
|
-
if (root === undefined)
|
|
109
|
-
throw new TypeError(`Compiled Value program ${index} is absent.`);
|
|
110
|
-
return root.schema;
|
|
111
|
-
}
|
|
112
78
|
function callableProgram(value) {
|
|
113
79
|
return {
|
|
114
80
|
input: typeof value.input === 'number' ? value.input : value.input.metadata,
|
|
@@ -151,5 +117,5 @@ function programValidation(programs, properties, propertyOrdering, callables) {
|
|
|
151
117
|
validateOutput: (value) => output === undefined ? [] : validateValueProgram(output, value),
|
|
152
118
|
}));
|
|
153
119
|
}
|
|
154
|
-
return
|
|
120
|
+
return { properties: propertyValidation, callables: callableValidation };
|
|
155
121
|
}
|
package/dist/v1/domain/create.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Key, MethodKey } from '../addressing/index.js';
|
|
2
|
+
import { compareCodeUnits } from '../addressing/ordering.js';
|
|
2
3
|
import { frozenRecord } from './namespace/member-collection.js';
|
|
3
4
|
import { createClasses } from './projection/classes.js';
|
|
4
5
|
const admittedDomains = new WeakSet();
|
|
@@ -43,7 +44,7 @@ export function createDomain(input) {
|
|
|
43
44
|
const visibleOrigins = new Set(visibleEntries.map(({ origin }) => origin));
|
|
44
45
|
const local = [...definitionsByKey.values()]
|
|
45
46
|
.filter(({ ref }) => ref.origin === entry.origin)
|
|
46
|
-
.sort((left, right) =>
|
|
47
|
+
.sort((left, right) => compareCodeUnits(left.key, right.key));
|
|
47
48
|
const classes = namespace(local, 'class');
|
|
48
49
|
const functions = namespace(local, 'function');
|
|
49
50
|
const policies = namespace(local, 'policy');
|
|
@@ -86,7 +87,7 @@ export function createDomain(input) {
|
|
|
86
87
|
revision: entry.revision,
|
|
87
88
|
closure: Object.freeze(visibleEntries
|
|
88
89
|
.map(({ origin, revision }) => Object.freeze({ origin, revision }))
|
|
89
|
-
.sort((left, right) =>
|
|
90
|
+
.sort((left, right) => compareCodeUnits(left.origin, right.origin))),
|
|
90
91
|
dependencies,
|
|
91
92
|
classes,
|
|
92
93
|
functions,
|
|
@@ -250,6 +251,3 @@ function isViewDefinition(value) {
|
|
|
250
251
|
function isCoreDefinition(value) {
|
|
251
252
|
return value.ref.kind === 'core';
|
|
252
253
|
}
|
|
253
|
-
function compare(left, right) {
|
|
254
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
255
|
-
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { PropertyKey as PropertyKeyValue } from '../../addressing/index.js';
|
|
2
|
+
import { compareCodeUnits } from '../../addressing/ordering.js';
|
|
2
3
|
import { createPropertyValues } from '../../language/class/property-values.js';
|
|
3
4
|
const PROPERTY_OPERATIONS = new Set(['byKey', 'get', 'from']);
|
|
4
5
|
const METHOD_OPERATIONS = new Set(['byKey', 'get']);
|
|
5
6
|
export function createPropertyCollection(values) {
|
|
6
|
-
const ordered = [...values].sort((left, right) =>
|
|
7
|
+
const ordered = [...values].sort((left, right) => compareCodeUnits(left.key, right.key));
|
|
7
8
|
const byKey = frozenRecord(ordered.map((value) => [value.key, value]));
|
|
8
9
|
const named = uniqueNames(ordered);
|
|
9
10
|
const collection = {
|
|
@@ -39,7 +40,7 @@ export function createPropertyCollection(values) {
|
|
|
39
40
|
return Object.freeze(collection);
|
|
40
41
|
}
|
|
41
42
|
export function createMethodCollection(values) {
|
|
42
|
-
const ordered = [...values].sort((left, right) =>
|
|
43
|
+
const ordered = [...values].sort((left, right) => compareCodeUnits(left.key, right.key));
|
|
43
44
|
const byKey = frozenRecord(ordered.map((value) => [value.key, value]));
|
|
44
45
|
const named = uniqueNames(ordered);
|
|
45
46
|
const collection = {
|
|
@@ -71,11 +72,8 @@ function installShortcuts(target, named, reserved) {
|
|
|
71
72
|
}
|
|
72
73
|
export function frozenRecord(entries) {
|
|
73
74
|
const output = Object.create(null);
|
|
74
|
-
for (const [key, value] of [...entries].sort(([left], [right]) =>
|
|
75
|
+
for (const [key, value] of [...entries].sort(([left], [right]) => compareCodeUnits(left, right))) {
|
|
75
76
|
Object.defineProperty(output, key, { enumerable: true, value });
|
|
76
77
|
}
|
|
77
78
|
return Object.freeze(output);
|
|
78
79
|
}
|
|
79
|
-
function compare(left, right) {
|
|
80
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
81
|
-
}
|
|
@@ -16,5 +16,4 @@ export interface CallableValidation {
|
|
|
16
16
|
}
|
|
17
17
|
/** Build the one Domain-level router shared by source resolution and compiled loading. */
|
|
18
18
|
export declare function createDomainValidation(properties: ReadonlyMap<PropertyKey, PropertyValidation>, callables: ReadonlyMap<Key.Callable, CallableValidation>): DomainValidation;
|
|
19
|
-
export declare function combineDomainValidation(values: readonly DomainValidation[]): DomainValidation;
|
|
20
19
|
export declare function unknownInputField(field: string): readonly Diagnostic[];
|
|
@@ -32,41 +32,6 @@ export function createDomainValidation(properties, callables) {
|
|
|
32
32
|
};
|
|
33
33
|
return Object.freeze(validation);
|
|
34
34
|
}
|
|
35
|
-
export function combineDomainValidation(values) {
|
|
36
|
-
const validation = {
|
|
37
|
-
propertyExists: (key) => values.some((value) => value.propertyExists(key)),
|
|
38
|
-
property(key, input) {
|
|
39
|
-
const owner = values.find((value) => value.propertyExists(key));
|
|
40
|
-
return owner === undefined ? unknownTarget('Property', key) : owner.property(key, input);
|
|
41
|
-
},
|
|
42
|
-
propertyProgram(key) {
|
|
43
|
-
const owner = values.find((value) => value.propertyExists(key));
|
|
44
|
-
if (owner === undefined)
|
|
45
|
-
throw new TypeError(`Property ${key} is absent.`);
|
|
46
|
-
return owner.propertyProgram(key);
|
|
47
|
-
},
|
|
48
|
-
propertyOrdering: (key) => values.find((value) => value.propertyExists(key))?.propertyOrdering(key),
|
|
49
|
-
callableExists: (key) => values.some((value) => value.callableExists(key)),
|
|
50
|
-
callableInput(key, input) {
|
|
51
|
-
const owner = values.find((value) => value.callableExists(key));
|
|
52
|
-
return owner === undefined ? unknownTarget('Callable', key) : owner.callableInput(key, input);
|
|
53
|
-
},
|
|
54
|
-
callableFields: (key) => values.find((value) => value.callableExists(key))?.callableFields(key),
|
|
55
|
-
callableInputField(key, field, input) {
|
|
56
|
-
const owner = values.find((value) => value.callableExists(key));
|
|
57
|
-
return owner === undefined
|
|
58
|
-
? unknownTarget('Callable', key)
|
|
59
|
-
: owner.callableInputField(key, field, input);
|
|
60
|
-
},
|
|
61
|
-
callableOutput(key, output) {
|
|
62
|
-
const owner = values.find((value) => value.callableExists(key));
|
|
63
|
-
return owner === undefined
|
|
64
|
-
? unknownTarget('Callable', key)
|
|
65
|
-
: owner.callableOutput(key, output);
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
return Object.freeze(validation);
|
|
69
|
-
}
|
|
70
35
|
export function unknownInputField(field) {
|
|
71
36
|
return [
|
|
72
37
|
Object.freeze({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ClassRef } from '../../addressing/index.js';
|
|
2
2
|
import type { ClassKind, Inheritance } from './model/class.js';
|
|
3
|
+
import type { EdgeContract, EdgeCount } from './model/edge.js';
|
|
3
4
|
/** A Class as satisfaction reads it, shared by source, compiled and resolved Class admission. */
|
|
4
5
|
export interface ClassAncestry {
|
|
5
6
|
readonly ref: ClassRef;
|
|
@@ -23,3 +24,20 @@ export declare function inheritanceOf(declaration: {
|
|
|
23
24
|
export declare function admitsForeignSubclass(declaration: {
|
|
24
25
|
readonly inheritance?: Inheritance;
|
|
25
26
|
}): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Whether `child` safely refines its parent Edge contract `parent`: same orientation, at least the
|
|
29
|
+
* parent's constraints, and endpoints whose accepted Classes `satisfies` one the paired parent
|
|
30
|
+
* endpoint accepts, within its count. Undirected endpoints may pair in either order.
|
|
31
|
+
*/
|
|
32
|
+
export declare function edgeContractRefines(child: EdgeContract, parent: EdgeContract & Pick<ClassAncestry, 'ref' | 'kind'>, satisfies: (candidate: ClassRef, accepts: readonly ClassRef[]) => boolean): boolean;
|
|
33
|
+
/** Interpret an Edge count as inclusive degree bounds. */
|
|
34
|
+
export declare function countBounds(value: EdgeCount): readonly [number, number];
|
|
35
|
+
/** Whether Edges of one Class, read from source to target, close a cycle (`acyclic` forbids it). */
|
|
36
|
+
export declare function hasDirectedCycle(edges: readonly {
|
|
37
|
+
readonly source: {
|
|
38
|
+
readonly key: string;
|
|
39
|
+
};
|
|
40
|
+
readonly target: {
|
|
41
|
+
readonly key: string;
|
|
42
|
+
};
|
|
43
|
+
}[]): boolean;
|
|
@@ -36,3 +36,76 @@ export function inheritanceOf(declaration) {
|
|
|
36
36
|
export function admitsForeignSubclass(declaration) {
|
|
37
37
|
return inheritanceOf(declaration) === 'open';
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Whether `child` safely refines its parent Edge contract `parent`: same orientation, at least the
|
|
41
|
+
* parent's constraints, and endpoints whose accepted Classes `satisfies` one the paired parent
|
|
42
|
+
* endpoint accepts, within its count. Undirected endpoints may pair in either order.
|
|
43
|
+
*/
|
|
44
|
+
export function edgeContractRefines(child, parent, satisfies) {
|
|
45
|
+
if (isGraphRoot(parent))
|
|
46
|
+
return true;
|
|
47
|
+
if (child.orientation !== parent.orientation)
|
|
48
|
+
return false;
|
|
49
|
+
if (parent.constraints.noSelf === true && child.constraints.noSelf !== true)
|
|
50
|
+
return false;
|
|
51
|
+
if (parent.constraints.acyclic === true && child.constraints.acyclic !== true)
|
|
52
|
+
return false;
|
|
53
|
+
const endpointRefines = (childEndpoint, parentEndpoint) => childEndpoint.accepts.every((accepted) => satisfies(accepted, parentEndpoint.accepts));
|
|
54
|
+
if (child.orientation === 'directed' && parent.orientation === 'directed') {
|
|
55
|
+
return (endpointRefines(child.endpoints.source, parent.endpoints.source) &&
|
|
56
|
+
countRefines(child.endpoints.source.outgoing, parent.endpoints.source.outgoing) &&
|
|
57
|
+
endpointRefines(child.endpoints.target, parent.endpoints.target) &&
|
|
58
|
+
countRefines(child.endpoints.target.incoming, parent.endpoints.target.incoming));
|
|
59
|
+
}
|
|
60
|
+
if (child.orientation !== 'undirected' || parent.orientation !== 'undirected')
|
|
61
|
+
return false;
|
|
62
|
+
const refines = (childIndex, parentIndex) => endpointRefines(child.endpoints[childIndex], parent.endpoints[parentIndex]) &&
|
|
63
|
+
countRefines(child.endpoints[childIndex].incident, parent.endpoints[parentIndex].incident);
|
|
64
|
+
const direct = refines(0, 0) && refines(1, 1);
|
|
65
|
+
if (direct)
|
|
66
|
+
return true;
|
|
67
|
+
return refines(0, 1) && refines(1, 0);
|
|
68
|
+
}
|
|
69
|
+
function countRefines(child, parent) {
|
|
70
|
+
const [childMinimum, childMaximum] = countBounds(child);
|
|
71
|
+
const [parentMinimum, parentMaximum] = countBounds(parent);
|
|
72
|
+
return childMinimum >= parentMinimum && childMaximum <= parentMaximum;
|
|
73
|
+
}
|
|
74
|
+
/** Interpret an Edge count as inclusive degree bounds. */
|
|
75
|
+
export function countBounds(value) {
|
|
76
|
+
switch (value) {
|
|
77
|
+
case '0..*':
|
|
78
|
+
return [0, Number.POSITIVE_INFINITY];
|
|
79
|
+
case '1..*':
|
|
80
|
+
return [1, Number.POSITIVE_INFINITY];
|
|
81
|
+
case '0..1':
|
|
82
|
+
return [0, 1];
|
|
83
|
+
case '1':
|
|
84
|
+
return [1, 1];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/** Whether Edges of one Class, read from source to target, close a cycle (`acyclic` forbids it). */
|
|
88
|
+
export function hasDirectedCycle(edges) {
|
|
89
|
+
const outgoing = new Map();
|
|
90
|
+
for (const edge of edges) {
|
|
91
|
+
const targets = outgoing.get(edge.source.key) ?? [];
|
|
92
|
+
targets.push(edge.target.key);
|
|
93
|
+
outgoing.set(edge.source.key, targets);
|
|
94
|
+
}
|
|
95
|
+
const visiting = new Set();
|
|
96
|
+
const visited = new Set();
|
|
97
|
+
const visit = (key) => {
|
|
98
|
+
if (visiting.has(key))
|
|
99
|
+
return true;
|
|
100
|
+
if (visited.has(key))
|
|
101
|
+
return false;
|
|
102
|
+
visiting.add(key);
|
|
103
|
+
for (const target of outgoing.get(key) ?? [])
|
|
104
|
+
if (visit(target))
|
|
105
|
+
return true;
|
|
106
|
+
visiting.delete(key);
|
|
107
|
+
visited.add(key);
|
|
108
|
+
return false;
|
|
109
|
+
};
|
|
110
|
+
return [...outgoing.keys()].some(visit);
|
|
111
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { acceptPropertyRoot } from '../../../value/accept.js';
|
|
2
2
|
import { isImmutableSnapshot } from '../../../value/immutable.optimization.js';
|
|
3
3
|
import { PropertyKey as admitPropertyKey } from '../../addressing/index.js';
|
|
4
|
+
import { compareCodeUnits } from '../../addressing/ordering.js';
|
|
4
5
|
export function acceptPropertyValues(input, pointer = '') {
|
|
5
6
|
const admitted = acceptPropertyRoot(input);
|
|
6
7
|
if (admitted === null || typeof admitted !== 'object' || Array.isArray(admitted)) {
|
|
@@ -10,7 +11,7 @@ export function acceptPropertyValues(input, pointer = '') {
|
|
|
10
11
|
}
|
|
11
12
|
export function createPropertyValues(entries) {
|
|
12
13
|
const output = Object.create(null);
|
|
13
|
-
for (const [key, value] of [...entries].sort(([left], [right]) =>
|
|
14
|
+
for (const [key, value] of [...entries].sort(([left], [right]) => compareCodeUnits(left, right))) {
|
|
14
15
|
Object.defineProperty(output, key, { enumerable: true, value: freeze(value) });
|
|
15
16
|
}
|
|
16
17
|
return Object.freeze(output);
|
|
@@ -28,6 +29,3 @@ function freeze(value) {
|
|
|
28
29
|
freeze(member);
|
|
29
30
|
return Object.freeze(value);
|
|
30
31
|
}
|
|
31
|
-
function compare(left, right) {
|
|
32
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
33
|
-
}
|