@astrale-os/kernel-dsl 0.2.0-beta.28 → 0.2.0-beta.29
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.
|
@@ -43,6 +43,7 @@ export interface NodeClassInput {
|
|
|
43
43
|
readonly data?: MediaType;
|
|
44
44
|
readonly methods?: Readonly<Record<string, Method>>;
|
|
45
45
|
readonly icon?: string;
|
|
46
|
+
/** Local observation Policies; inherited by no descendant and forbidden on abstract Classes. */
|
|
46
47
|
readonly policies?: {
|
|
47
48
|
readonly read?: Lazy<Policy>;
|
|
48
49
|
readonly traverse?: Lazy<Policy>;
|
|
@@ -53,6 +54,7 @@ export interface EdgeClassOptions {
|
|
|
53
54
|
readonly description?: string;
|
|
54
55
|
readonly extends?: readonly EdgeClassReferenceInput[];
|
|
55
56
|
readonly properties?: PropertyRecordInput;
|
|
57
|
+
/** Local observation Policies; inherited by no descendant and forbidden on abstract Classes. */
|
|
56
58
|
readonly policies?: {
|
|
57
59
|
readonly read?: Lazy<Policy>;
|
|
58
60
|
readonly traverse?: Lazy<Policy>;
|
|
@@ -178,6 +178,10 @@ function policyKey(value) {
|
|
|
178
178
|
}
|
|
179
179
|
function validateClassFacets(context) {
|
|
180
180
|
for (const located of context.classes.values()) {
|
|
181
|
+
if (located.value.abstract &&
|
|
182
|
+
(located.value.policies.read !== undefined || located.value.policies.traverse !== undefined)) {
|
|
183
|
+
fail(`${located.pointer}/policies`, 'Abstract Classes cannot declare observation Policies.');
|
|
184
|
+
}
|
|
181
185
|
for (const [index, property] of located.value.properties.entries()) {
|
|
182
186
|
const path = `${located.pointer}/properties/${index}`;
|
|
183
187
|
if (property.auto !== undefined) {
|
|
@@ -252,26 +256,7 @@ function edgeRefines(context, child, parent) {
|
|
|
252
256
|
const direct = refine(0, 0) && refine(1, 1);
|
|
253
257
|
if (direct)
|
|
254
258
|
return true;
|
|
255
|
-
|
|
256
|
-
return reverse && !hasEffectiveEdgePolicy(context, parent, new Set());
|
|
257
|
-
}
|
|
258
|
-
function hasEffectiveEdgePolicy(context, declaration, visited) {
|
|
259
|
-
if (declaration.policies.read !== undefined || declaration.policies.traverse !== undefined) {
|
|
260
|
-
return true;
|
|
261
|
-
}
|
|
262
|
-
for (const parentRef of declaration.extends) {
|
|
263
|
-
const key = Key.of(parentRef);
|
|
264
|
-
if (visited.has(key))
|
|
265
|
-
continue;
|
|
266
|
-
visited.add(key);
|
|
267
|
-
const parent = context.classes.get(key)?.value;
|
|
268
|
-
if (parent !== undefined &&
|
|
269
|
-
isCompiledEdge(parent) &&
|
|
270
|
-
hasEffectiveEdgePolicy(context, parent, visited)) {
|
|
271
|
-
return true;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
return false;
|
|
259
|
+
return refine(0, 1) && refine(1, 0);
|
|
275
260
|
}
|
|
276
261
|
function endpointRefines(context, child, parent) {
|
|
277
262
|
return child.accepts.every((accepted) => classSatisfiesAny(context, accepted, parent.accepts));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Key, MethodKey as MethodKeyValue, PropertyKey as PropertyKeyValue, } from '../../addressing/index.js';
|
|
2
2
|
import { acceptPropertyValues } from '../../language/class/property-values.js';
|
|
3
3
|
import { appendPointer } from '../../language/value/syntax/pointer.js';
|
|
4
4
|
import { createMethodCollection, createPropertyCollection } from '../namespace/member-collection.js';
|
|
@@ -24,16 +24,6 @@ export function createClasses(definitions, validation) {
|
|
|
24
24
|
throw new TypeError(`Class ${key} extends a Class of another graph kind.`);
|
|
25
25
|
}
|
|
26
26
|
const shell = {};
|
|
27
|
-
const policies = Object.freeze({
|
|
28
|
-
read: Object.freeze(uniquePolicyRefs([
|
|
29
|
-
...parents.flatMap((parent) => [...parent.policies.read]),
|
|
30
|
-
...(definition.policies.read === undefined ? [] : [definition.policies.read]),
|
|
31
|
-
])),
|
|
32
|
-
traverse: Object.freeze(uniquePolicyRefs([
|
|
33
|
-
...parents.flatMap((parent) => [...parent.policies.traverse]),
|
|
34
|
-
...(definition.policies.traverse === undefined ? [] : [definition.policies.traverse]),
|
|
35
|
-
])),
|
|
36
|
-
});
|
|
37
27
|
const effectiveProperties = new Map();
|
|
38
28
|
const effectiveMethods = new Map();
|
|
39
29
|
let inheritedData;
|
|
@@ -102,7 +92,7 @@ export function createClasses(definitions, validation) {
|
|
|
102
92
|
abstract: definition.abstract,
|
|
103
93
|
definition,
|
|
104
94
|
extends: Object.freeze(parents),
|
|
105
|
-
policies,
|
|
95
|
+
policies: definition.policies,
|
|
106
96
|
data: definition.kind === 'node' ? (ownData ?? inheritedData) : undefined,
|
|
107
97
|
properties: createPropertyCollection(effectiveProperties.values()),
|
|
108
98
|
methods: createMethodCollection(instanceMethods),
|
|
@@ -110,7 +100,6 @@ export function createClasses(definitions, validation) {
|
|
|
110
100
|
self: Object.freeze({
|
|
111
101
|
data: definition.kind === 'node' ? ownData : undefined,
|
|
112
102
|
properties: createPropertyCollection(ownProperties),
|
|
113
|
-
policies: definition.policies,
|
|
114
103
|
methods: createMethodCollection(ownInstanceMethods),
|
|
115
104
|
static: Object.freeze({ methods: createMethodCollection(ownStaticMethods) }),
|
|
116
105
|
}),
|
|
@@ -138,12 +127,6 @@ export function createClasses(definitions, validation) {
|
|
|
138
127
|
resolve(definition.ref);
|
|
139
128
|
return resolved;
|
|
140
129
|
}
|
|
141
|
-
function uniquePolicyRefs(values) {
|
|
142
|
-
const result = new Map();
|
|
143
|
-
for (const value of values)
|
|
144
|
-
result.set(Key.of(value), value);
|
|
145
|
-
return [...result.values()].sort((left, right) => compareUnicode(Key.of(left), Key.of(right)));
|
|
146
|
-
}
|
|
147
130
|
function validateProperties(abstract, properties, input) {
|
|
148
131
|
if (abstract) {
|
|
149
132
|
return [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Value as PortableValue } from '@astrale-os/kernel-dsl/value';
|
|
2
|
-
import type { ClassRef, DefinitionKey, Key,
|
|
2
|
+
import type { ClassRef, DefinitionKey, Key, PropertyKey } from '../../addressing/index.js';
|
|
3
3
|
import type { ResolvedMethodCollection } from '../callable/resolved.js';
|
|
4
4
|
import type { StateTopology } from '../state/index.js';
|
|
5
5
|
import type { Diagnostic } from '../validation/diagnostic.js';
|
|
@@ -25,11 +25,6 @@ export interface ResolvedData {
|
|
|
25
25
|
readonly owner: ResolvedClass<'node'>;
|
|
26
26
|
readonly definition: DataDefinition;
|
|
27
27
|
}
|
|
28
|
-
export interface ResolvedClassPolicies {
|
|
29
|
-
/** Effective read Policies for this Node or Edge Class. */
|
|
30
|
-
readonly read: readonly PolicyRef[];
|
|
31
|
-
readonly traverse: readonly PolicyRef[];
|
|
32
|
-
}
|
|
33
28
|
export type ResolvedPropertyCollection<ByKey extends Readonly<Record<PropertyKey, ResolvedProperty<unknown>>> = Readonly<Record<PropertyKey, ResolvedProperty<unknown>>>, ByName extends Readonly<Record<string, ResolvedProperty<unknown>>> = Readonly<Record<never, never>>> = Readonly<ByName> & Iterable<ByKey[keyof ByKey]> & {
|
|
34
29
|
readonly byKey: ByKey;
|
|
35
30
|
get<Key extends keyof ByKey>(key: Key): ByKey[Key];
|
|
@@ -47,8 +42,8 @@ export interface ResolvedClass<Kind extends ClassKind = ClassKind, Properties ex
|
|
|
47
42
|
readonly abstract: boolean;
|
|
48
43
|
readonly definition: Definition;
|
|
49
44
|
readonly extends: Parents & readonly ResolvedClass<Kind>[];
|
|
50
|
-
/**
|
|
51
|
-
readonly policies:
|
|
45
|
+
/** Local observation Policies; Class inheritance never contributes an attachment. */
|
|
46
|
+
readonly policies: Definition['policies'];
|
|
52
47
|
readonly data: Kind extends 'node' ? ResolvedData | undefined : undefined;
|
|
53
48
|
readonly properties: Properties;
|
|
54
49
|
readonly methods: Kind extends 'node' ? InstanceMethods : ResolvedMethodCollection<Record<never, never>>;
|
|
@@ -58,8 +53,6 @@ export interface ResolvedClass<Kind extends ClassKind = ClassKind, Properties ex
|
|
|
58
53
|
readonly self: {
|
|
59
54
|
readonly data: Kind extends 'node' ? ResolvedData | undefined : undefined;
|
|
60
55
|
readonly properties: SelfProperties;
|
|
61
|
-
/** Policies declared by this exact Class only. */
|
|
62
|
-
readonly policies: Definition['policies'];
|
|
63
56
|
readonly methods: Kind extends 'node' ? SelfInstanceMethods : ResolvedMethodCollection<Record<never, never>>;
|
|
64
57
|
readonly static: {
|
|
65
58
|
readonly methods: Kind extends 'node' ? SelfStaticMethods : ResolvedMethodCollection<Record<never, never>>;
|
|
@@ -15,6 +15,10 @@ export function validateDefinitions(environment, analysis) {
|
|
|
15
15
|
if (!sameRef(declaration.ref, ref)) {
|
|
16
16
|
diagnostics.push(diagnostic('DV_REF_RESOLVES', `${pointer}/ref`, `Class ref must be exactly ${formatDefinitionRef(ref)}.`, formatDefinitionRef(declaration.ref)));
|
|
17
17
|
}
|
|
18
|
+
if (declaration.abstract &&
|
|
19
|
+
(declaration.policies.read !== undefined || declaration.policies.traverse !== undefined)) {
|
|
20
|
+
diagnostics.push(diagnostic('DV_CLASS_ABSTRACT', `${pointer}/policies`, 'Abstract Classes cannot declare observation Policies.'));
|
|
21
|
+
}
|
|
18
22
|
validateFacet(environment, declaration, pointer, diagnostics);
|
|
19
23
|
validateParents(environment, ref, declaration.kind, declaration.extends, diagnostics);
|
|
20
24
|
if (declaration.kind === 'edge') {
|
|
@@ -159,27 +163,7 @@ function edgeContractRefines(environment, child, parent) {
|
|
|
159
163
|
const direct = refines(0, 0) && refines(1, 1);
|
|
160
164
|
if (direct)
|
|
161
165
|
return true;
|
|
162
|
-
|
|
163
|
-
return reverse && !hasEffectiveEdgePolicy(environment, parent, new Set());
|
|
164
|
-
}
|
|
165
|
-
function hasEffectiveEdgePolicy(environment, declaration, visited) {
|
|
166
|
-
if (declaration.policies.read !== undefined || declaration.policies.traverse !== undefined) {
|
|
167
|
-
return true;
|
|
168
|
-
}
|
|
169
|
-
for (const parentRef of declaration.extends) {
|
|
170
|
-
const key = definitionRefIndex(parentRef);
|
|
171
|
-
if (visited.has(key))
|
|
172
|
-
continue;
|
|
173
|
-
visited.add(key);
|
|
174
|
-
const parent = environment.resolveAny(parentRef);
|
|
175
|
-
if (parent !== undefined &&
|
|
176
|
-
parent.ref.kind === 'class' &&
|
|
177
|
-
parent.declaration.kind === 'edge' &&
|
|
178
|
-
hasEffectiveEdgePolicy(environment, parent.declaration, visited)) {
|
|
179
|
-
return true;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return false;
|
|
166
|
+
return refines(0, 1) && refines(1, 0);
|
|
183
167
|
}
|
|
184
168
|
function endpointRefines(environment, child, parent) {
|
|
185
169
|
return child.accepts.every((accepted) => classSatisfies(environment, accepted, parent.accepts));
|