@astrale-os/kernel-dsl 1.0.0-beta.15 → 1.0.0-beta.17
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/builder/class/authoring.js +3 -2
- package/dist/v1/builder/class/input.d.ts +45 -14
- package/dist/v1/builder/index.d.ts +2 -1
- package/dist/v1/builder/lowering/class.d.ts +8 -0
- package/dist/v1/builder/lowering/class.js +40 -16
- package/dist/v1/builder/lowering/schema/compile.js +3 -3
- package/dist/v1/builder/policy/authoring.js +97 -88
- package/dist/v1/bundle/model.js +1 -1
- package/dist/v1/compiled/admission/accept.js +1 -7
- package/dist/v1/compiled/admission/semantics/class.js +2 -3
- package/dist/v1/compiled/admission/semantics/policy/parity.js +25 -13
- package/dist/v1/compiled/admission/semantics/policy/typing.js +2 -2
- package/dist/v1/compiled/admission/wire/class.js +23 -18
- package/dist/v1/compiled/admission/wire/policy.d.ts +4 -3
- package/dist/v1/compiled/admission/wire/policy.js +8 -7
- package/dist/v1/compiled/loader/load.js +1 -1
- package/dist/v1/domain/create.js +1 -1
- package/dist/v1/domain/model/input.d.ts +2 -1
- package/dist/v1/domain/projection/classes.js +1 -1
- package/dist/v1/domain/validation/create.d.ts +2 -1
- package/dist/v1/domain/validation/create.js +1 -1
- package/dist/v1/index.d.ts +1 -1
- package/dist/v1/language/.spec/schemas/draft-2020-12.schema.json +462 -0
- package/dist/v1/language/callable/resolved.d.ts +11 -2
- package/dist/v1/language/class/model/class.d.ts +17 -5
- package/dist/v1/language/freeze.d.ts +5 -0
- package/dist/v1/{schema/canonical → language}/freeze.js +4 -0
- package/dist/v1/language/policy/analysis/typing.d.ts +5 -2
- package/dist/v1/language/policy/analysis/typing.js +158 -42
- package/dist/v1/language/policy/model/policy.d.ts +44 -4
- package/dist/v1/language/policy/model/policy.js +14 -0
- package/dist/v1/language/policy/normalization/normalize.d.ts +6 -6
- package/dist/v1/language/policy/normalization/normalize.js +5 -5
- package/dist/v1/language/validation/rule.d.ts +22 -6
- package/dist/v1/language/validation/rule.js +4 -15
- package/dist/v1/language/value/evaluate/program.d.ts +2 -1
- package/dist/v1/language/value/evaluate/program.js +2 -2
- package/dist/v1/language/value/evaluate/validate.d.ts +2 -2
- package/dist/v1/language/value/evaluate/validate.js +2 -2
- package/dist/v1/language/value/ordering.d.ts +5 -0
- package/dist/v1/language/value/ordering.js +14 -0
- package/dist/v1/language/value/profile/json.validate.d.ts +3 -1
- package/dist/v1/language/value/profile/json.validate.js +3 -2
- package/dist/v1/language/value/reference/closure.js +3 -4
- package/dist/v1/language/value/reference/registry.index.d.ts +2 -0
- package/dist/v1/language/value/reference/registry.index.js +31 -15
- package/dist/v1/schema/.spec/schemas/domain-schema.schema.json +210 -27
- package/dist/v1/schema/admission/callable.js +1 -1
- package/dist/v1/schema/canonical/revision.js +4 -4
- package/dist/v1/schema/compatibility/comparators/callables.js +1 -1
- package/dist/v1/schema/compatibility/comparators/classes.js +4 -4
- package/dist/v1/schema/compatibility/comparators/members.js +1 -1
- package/dist/v1/schema/compatibility/comparators/values.js +2 -2
- package/dist/v1/schema/compatibility/report.js +1 -1
- package/dist/v1/schema/compatibility/versioning/index.js +1 -1
- package/dist/v1/schema/model/schema.js +1 -1
- package/dist/v1/schema/normalization/domain.js +9 -8
- package/dist/v1/schema/resolution/domain.js +1 -1
- package/dist/v1/schema/resolution/origins.js +3 -2
- package/dist/v1/schema/rule.d.ts +8 -14
- package/dist/v1/schema/rule.js +14 -2
- package/dist/v1/schema/validation/class.d.ts +6 -2
- package/dist/v1/schema/validation/class.js +20 -25
- package/dist/v1/schema/validation/domain.js +1 -1
- package/dist/v1/schema/validation/domain.json-schema.d.ts +2 -2
- package/dist/v1/schema/validation/domain.json-schema.js +20 -6
- package/dist/v1/schema/validation/domain.structure.d.ts +4765 -1005
- package/dist/v1/schema/validation/domain.structure.js +21 -9
- package/dist/v1/schema/validation/json.json-schema.d.ts +18 -2
- package/dist/v1/schema/validation/json.json-schema.js +14 -4
- package/dist/v1/schema/validation/policy/budgets.d.ts +1 -1
- package/dist/v1/schema/validation/policy/budgets.js +4 -4
- package/dist/v1/schema/validation/policy/context.d.ts +1 -2
- package/dist/v1/schema/validation/policy/context.js +2 -7
- package/dist/v1/schema/validation/policy/uses.d.ts +10 -2
- package/dist/v1/schema/validation/policy/uses.js +26 -13
- package/dist/v1/schema/validation/policy/validate.js +2 -3
- package/dist/v1/schema/validation/value-api.d.ts +2 -0
- package/dist/v1/schema/validation/value-api.js +2 -0
- package/dist/v1/schema/validation/value.json-schema.d.ts +7 -9
- package/dist/v1/schema/validation/value.json-schema.js +38 -27
- package/package.json +2 -1
- package/dist/v1/schema/canonical/domain.d.ts +0 -3
- package/dist/v1/schema/canonical/domain.digest.d.ts +0 -3
- package/dist/v1/schema/canonical/domain.digest.js +0 -5
- package/dist/v1/schema/canonical/domain.js +0 -5
- package/dist/v1/schema/canonical/freeze.d.ts +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CLASS_OPERATIONS } from '../../language/policy/model/policy.js';
|
|
1
2
|
import { assertKnownKeys } from '../schema/diagnostic.js';
|
|
2
3
|
import { authoringValue } from '../schema/handle.js';
|
|
3
4
|
const classInputs = new WeakMap();
|
|
@@ -28,7 +29,7 @@ export function nodeClass(config) {
|
|
|
28
29
|
'unique',
|
|
29
30
|
]);
|
|
30
31
|
if (admitted.policies !== undefined)
|
|
31
|
-
assertKnownKeys(admitted.policies,
|
|
32
|
+
assertKnownKeys(admitted.policies, CLASS_OPERATIONS);
|
|
32
33
|
const value = authoringValue('definition', {
|
|
33
34
|
kind: 'node',
|
|
34
35
|
});
|
|
@@ -125,7 +126,7 @@ function validateIncidentEndpointInput(value) {
|
|
|
125
126
|
/** Check the nested Edge Class options; the caller has checked the option keys themselves. */
|
|
126
127
|
function validateEdgeClassOptions(value, constraints) {
|
|
127
128
|
if (value.policies !== undefined)
|
|
128
|
-
assertKnownKeys(value.policies,
|
|
129
|
+
assertKnownKeys(value.policies, CLASS_OPERATIONS);
|
|
129
130
|
if (value.constraints !== undefined)
|
|
130
131
|
assertKnownKeys(value.constraints, constraints);
|
|
131
132
|
}
|
|
@@ -3,7 +3,7 @@ import type { Inheritance } from '../../language/class/model/class.js';
|
|
|
3
3
|
import type { MediaType } from '../../language/class/model/data.js';
|
|
4
4
|
import type { EdgeCount, EdgeLifetime } from '../../language/class/model/edge.js';
|
|
5
5
|
import type { ResolvedClass } from '../../language/class/resolved.js';
|
|
6
|
-
import type { ClassRuleChecks, ClassRuleObject } from '../../language/policy/model/policy.js';
|
|
6
|
+
import type { ClassRuleChecks, ClassRuleObject, CreateRuleChecks, CreateRuleObject, EdgeRuleChecks } from '../../language/policy/model/policy.js';
|
|
7
7
|
import type { Method, PolicyCheckContext } from '../callable/authoring.js';
|
|
8
8
|
import type { Policy } from '../policy/authoring.js';
|
|
9
9
|
import type { Lazy } from '../schema/lazy.js';
|
|
@@ -37,26 +37,57 @@ export interface IncidentEndpointInput {
|
|
|
37
37
|
/** What deleting a Node at this endpoint does to the Edge; derived when omitted. */
|
|
38
38
|
readonly onDelete?: EdgeLifetime;
|
|
39
39
|
}
|
|
40
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* One Class slot: a local Policy, or its constant value. An omitted observation admits every
|
|
42
|
+
* caller, as `true` does; an omitted write admits only the owning Domain, as `false` does.
|
|
43
|
+
*/
|
|
41
44
|
export type ClassPolicyInput = Lazy<Policy> | boolean;
|
|
42
|
-
/** Local observation Policies of a Class. */
|
|
43
|
-
export interface ClassPoliciesInput {
|
|
44
|
-
readonly read?: ClassPolicyInput;
|
|
45
|
-
readonly traverse?: ClassPolicyInput;
|
|
46
|
-
}
|
|
47
45
|
/**
|
|
48
|
-
* Policy checks deciding one Node Class
|
|
49
|
-
* exact member, the same Node for every
|
|
46
|
+
* Policy checks deciding one Node Class slot. `self` is the observed or written Node; `ref` names
|
|
47
|
+
* one exact member, the same Node for every candidate.
|
|
50
48
|
*/
|
|
51
49
|
export interface ClassRuleContext extends PolicyCheckContext<ClassRuleObject> {
|
|
52
50
|
}
|
|
53
51
|
export type ClassRuleBuilder = (context: ClassRuleContext) => ClassRuleChecks;
|
|
54
|
-
/** One Node Class
|
|
52
|
+
/** One Node Class slot: a local Policy, a constant value, or Policy checks. */
|
|
55
53
|
export type NodeClassPolicyInput = ClassPolicyInput | ClassRuleBuilder;
|
|
56
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Policy checks deciding the creation of a Node. The Node is not yet, so it has no `self`: `ref`
|
|
56
|
+
* names each object, one exact member.
|
|
57
|
+
*/
|
|
58
|
+
export interface CreateRuleContext extends Omit<PolicyCheckContext<CreateRuleObject>, 'self'> {
|
|
59
|
+
}
|
|
60
|
+
export type CreateRuleBuilder = (context: CreateRuleContext) => CreateRuleChecks;
|
|
61
|
+
/**
|
|
62
|
+
* The Node Class create slot: a constant value, or Policy checks over members. A Policy alone
|
|
63
|
+
* would have no object there.
|
|
64
|
+
*/
|
|
65
|
+
export type NodeClassCreatePolicyInput = boolean | CreateRuleBuilder;
|
|
66
|
+
/** Local Policies of a Node Class. */
|
|
57
67
|
export interface NodeClassPoliciesInput {
|
|
58
68
|
readonly read?: NodeClassPolicyInput;
|
|
59
69
|
readonly traverse?: NodeClassPolicyInput;
|
|
70
|
+
readonly create?: NodeClassCreatePolicyInput;
|
|
71
|
+
readonly update?: NodeClassPolicyInput;
|
|
72
|
+
readonly delete?: NodeClassPolicyInput;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Policy checks deciding one Edge Class slot. `self` is the observed or written Edge, checked by a
|
|
76
|
+
* Policy whose `source` and `target` are its endpoints; `ref` names one exact member, the same Node
|
|
77
|
+
* for every candidate.
|
|
78
|
+
*/
|
|
79
|
+
export interface EdgeRuleContext extends PolicyCheckContext<ClassRuleObject> {
|
|
80
|
+
}
|
|
81
|
+
export type EdgeRuleBuilder = (context: EdgeRuleContext) => EdgeRuleChecks;
|
|
82
|
+
/** One Edge Class slot: a local Policy, a constant value, or Policy checks. */
|
|
83
|
+
export type EdgeClassPolicyInput = ClassPolicyInput | EdgeRuleBuilder;
|
|
84
|
+
/** Local Policies of an Edge Class. */
|
|
85
|
+
export interface EdgeClassPoliciesInput {
|
|
86
|
+
readonly read?: EdgeClassPolicyInput;
|
|
87
|
+
readonly traverse?: EdgeClassPolicyInput;
|
|
88
|
+
readonly create?: EdgeClassPolicyInput;
|
|
89
|
+
readonly update?: EdgeClassPolicyInput;
|
|
90
|
+
readonly delete?: EdgeClassPolicyInput;
|
|
60
91
|
}
|
|
61
92
|
/** Authored Node Class. */
|
|
62
93
|
export interface NodeClassInput {
|
|
@@ -69,7 +100,7 @@ export interface NodeClassInput {
|
|
|
69
100
|
readonly data?: MediaType;
|
|
70
101
|
readonly methods?: Readonly<Record<string, Method>>;
|
|
71
102
|
readonly icon?: string;
|
|
72
|
-
/** Local
|
|
103
|
+
/** Local Policies; inherited by no descendant and forbidden on abstract Classes. */
|
|
73
104
|
readonly policies?: NodeClassPoliciesInput;
|
|
74
105
|
/**
|
|
75
106
|
* The tuples no two Nodes of this Class and of its active concrete descendants share while every
|
|
@@ -90,8 +121,8 @@ export interface EdgeClassOptions {
|
|
|
90
121
|
readonly description?: string;
|
|
91
122
|
readonly extends?: readonly EdgeClassReferenceInput[];
|
|
92
123
|
readonly properties?: PropertyRecordInput;
|
|
93
|
-
/** Local
|
|
94
|
-
readonly policies?:
|
|
124
|
+
/** Local Policies; inherited by no descendant and forbidden on abstract Classes. */
|
|
125
|
+
readonly policies?: EdgeClassPoliciesInput;
|
|
95
126
|
readonly constraints?: {
|
|
96
127
|
readonly noSelf?: true;
|
|
97
128
|
readonly acyclic?: true;
|
|
@@ -15,7 +15,8 @@ export type { BuilderDiagnostic as Diagnostic, BuilderDiagnosticCode as Diagnost
|
|
|
15
15
|
export type { CallableInputBase, CallableInput, BinaryInputAuthoring, CallableOutputInput, CallableProjection, CallablePolicyBuilder, CallablePolicyContext, PolicyCheckContext, BinaryOutput, Function, FunctionInput, Method, MethodInput, PolicyObjectInput, StreamOutput, } from './callable/authoring.js';
|
|
16
16
|
export type { CoreEdge, CoreEndpoint, CoreInput, CoreNode } from './core/authoring.js';
|
|
17
17
|
export type { Class, DirectedEdgeClass, EdgeClass, NodeClass, UndirectedEdgeClass, } from './class/handle.js';
|
|
18
|
-
export type { ClassReferenceInput as ClassReference, ClassRuleBuilder, ClassRuleContext, DirectedEdgeInput, DirectedSourceInput, DirectedTargetInput, EdgeClassCommon, EdgeClassInput, EdgeClassReferenceInput as EdgeClassReference, EdgeUniqueFieldInput, EdgeUniqueTupleInput, IncidentEndpointInput, NodeClassInput, NodeClassPoliciesInput, NodeClassPolicyInput, NodeClassReferenceInput as NodeClassReference, NodeUniqueTupleInput, UndirectedEdgeInput, } from './class/input.js';
|
|
18
|
+
export type { ClassReferenceInput as ClassReference, ClassRuleBuilder, ClassRuleContext, CreateRuleBuilder, CreateRuleContext, DirectedEdgeInput, DirectedSourceInput, DirectedTargetInput, EdgeClassCommon, EdgeClassInput, EdgeClassPoliciesInput, EdgeClassPolicyInput, EdgeClassReferenceInput as EdgeClassReference, EdgeRuleBuilder, EdgeRuleContext, EdgeUniqueFieldInput, EdgeUniqueTupleInput, IncidentEndpointInput, NodeClassCreatePolicyInput, NodeClassInput, NodeClassPoliciesInput, NodeClassPolicyInput, NodeClassReferenceInput as NodeClassReference, NodeUniqueTupleInput, UndirectedEdgeInput, } from './class/input.js';
|
|
19
|
+
export type { ClassRuleChecks, CreateRuleChecks, EdgeRuleChecks, } from '../language/policy/model/policy.js';
|
|
19
20
|
export type { AuthoredPropertyProjection, AuthoredMethodProjection, ClassIdentityProjection, ClassOwnerProjection, ClassReferenceProjection, } from './class/projection.js';
|
|
20
21
|
export type { PathAuthoring } from './value/path.js';
|
|
21
22
|
export type { Lazy } from './schema/lazy.js';
|
|
@@ -13,13 +13,21 @@ export declare class V1DefinitionCompiler {
|
|
|
13
13
|
compileClass(value: Class, name: string, pointer: string): ClassDefinition;
|
|
14
14
|
private nodeClass;
|
|
15
15
|
private edgeClass;
|
|
16
|
+
/**
|
|
17
|
+
* An omitted observation, like `true`, lowers to the absent slot a Schema reads as every caller
|
|
18
|
+
* (A18 defers X1). A write slot has the converse spelling: `false` and an omitted slot lower to
|
|
19
|
+
* the absent slot, owner only.
|
|
20
|
+
*/
|
|
16
21
|
private classPolicies;
|
|
17
22
|
/**
|
|
18
23
|
* A lazy Policy ignores the context it is called with; a rule builder returns Policy checks. Both
|
|
19
24
|
* are functions, so the result tells them apart.
|
|
20
25
|
*/
|
|
21
26
|
private classPolicy;
|
|
27
|
+
/** A Node create rule checks members only: the Node it creates is not yet. */
|
|
28
|
+
private createRule;
|
|
22
29
|
private classRuleContext;
|
|
30
|
+
private createRuleContext;
|
|
23
31
|
private endpointBase;
|
|
24
32
|
private directedSource;
|
|
25
33
|
private directedTarget;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { compareDefinitionRefs } from '../../addressing/ordering.js';
|
|
2
2
|
import { isMethodExecutable } from '../../language/callable/executable.js';
|
|
3
|
-
import { isClassRuleChecks } from '../../language/policy/model/policy.js';
|
|
3
|
+
import { CLASS_OPERATIONS, isClassObservation, isClassRuleChecks, } from '../../language/policy/model/policy.js';
|
|
4
4
|
import { normalizeClassRule } from '../../language/policy/normalization/normalize.js';
|
|
5
5
|
import { callableConfiguration } from '../callable/authoring.js';
|
|
6
6
|
import { classConfiguration } from '../class/authoring.js';
|
|
@@ -88,43 +88,57 @@ export class V1DefinitionCompiler {
|
|
|
88
88
|
extends: this.parents(input.extends, 'edge', `${pointer}/extends`),
|
|
89
89
|
properties: facet,
|
|
90
90
|
...contract,
|
|
91
|
-
// classPolicy refuses Policy checks on an Edge Class, so only Class Policies remain.
|
|
92
91
|
policies: this.classPolicies(input, 'edge', `${pointer}/policies`),
|
|
93
92
|
};
|
|
94
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* An omitted observation, like `true`, lowers to the absent slot a Schema reads as every caller
|
|
96
|
+
* (A18 defers X1). A write slot has the converse spelling: `false` and an omitted slot lower to
|
|
97
|
+
* the absent slot, owner only.
|
|
98
|
+
*/
|
|
95
99
|
classPolicies(input, kind, pointer) {
|
|
96
100
|
const slot = (operation) => {
|
|
97
101
|
const value = input.policies?.[operation];
|
|
102
|
+
const observation = isClassObservation(operation);
|
|
98
103
|
if (value === undefined)
|
|
99
104
|
return undefined;
|
|
100
105
|
if (typeof value !== 'boolean')
|
|
101
|
-
return this.classPolicy(value, kind, `${pointer}/${operation}`);
|
|
102
|
-
//
|
|
106
|
+
return this.classPolicy(value, kind, operation, `${pointer}/${operation}`);
|
|
107
|
+
// A constant on an abstract Class would otherwise lower to nothing and pass unnoticed.
|
|
103
108
|
if (input.abstract === true) {
|
|
104
|
-
fail('BUILDER_ABSTRACT_POLICY', `${pointer}/${operation}`, 'Abstract Classes cannot declare
|
|
109
|
+
fail('BUILDER_ABSTRACT_POLICY', `${pointer}/${operation}`, 'Abstract Classes cannot declare Class Policies.');
|
|
105
110
|
}
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const traverse = slot('traverse');
|
|
111
|
-
return {
|
|
112
|
-
...(read === undefined ? {} : { read }),
|
|
113
|
-
...(traverse === undefined ? {} : { traverse }),
|
|
111
|
+
// Each slot spells only the constant its absence does not mean.
|
|
112
|
+
if (observation)
|
|
113
|
+
return value ? undefined : false;
|
|
114
|
+
return value ? true : undefined;
|
|
114
115
|
};
|
|
116
|
+
return Object.fromEntries(CLASS_OPERATIONS.flatMap((operation) => {
|
|
117
|
+
const policy = slot(operation);
|
|
118
|
+
return policy === undefined ? [] : [[operation, policy]];
|
|
119
|
+
}));
|
|
115
120
|
}
|
|
116
121
|
/**
|
|
117
122
|
* A lazy Policy ignores the context it is called with; a rule builder returns Policy checks. Both
|
|
118
123
|
* are functions, so the result tells them apart.
|
|
119
124
|
*/
|
|
120
|
-
classPolicy(value, kind, pointer) {
|
|
125
|
+
classPolicy(value, kind, operation, pointer) {
|
|
126
|
+
if (kind === 'node' && operation === 'create')
|
|
127
|
+
return this.createRule(value, pointer);
|
|
121
128
|
if (typeof value !== 'function')
|
|
122
129
|
return this.policies.ref(value, pointer);
|
|
123
130
|
const result = value(this.classRuleContext(pointer));
|
|
124
131
|
if (!isClassRuleResult(result))
|
|
125
132
|
return this.policies.ref(result, pointer);
|
|
126
|
-
|
|
127
|
-
|
|
133
|
+
return normalizeClassRule(result);
|
|
134
|
+
}
|
|
135
|
+
/** A Node create rule checks members only: the Node it creates is not yet. */
|
|
136
|
+
createRule(value, pointer) {
|
|
137
|
+
const result = typeof value === 'function'
|
|
138
|
+
? value(this.createRuleContext(pointer))
|
|
139
|
+
: undefined;
|
|
140
|
+
if (!isClassRuleResult(result)) {
|
|
141
|
+
fail('BUILDER_POLICY', pointer, 'A Node create rule checks Policies of ref(...) members: a Policy alone has no object there.');
|
|
128
142
|
}
|
|
129
143
|
return normalizeClassRule(result);
|
|
130
144
|
}
|
|
@@ -135,6 +149,16 @@ export class V1DefinitionCompiler {
|
|
|
135
149
|
fail('BUILDER_POLICY_INPUT', pointer, 'A Class rule checks self or one ref(...) member.');
|
|
136
150
|
});
|
|
137
151
|
}
|
|
152
|
+
createRuleContext(pointer) {
|
|
153
|
+
return policyCheckContext(this.context, pointer, (object) => {
|
|
154
|
+
if (object?.kind === 'ref')
|
|
155
|
+
return object;
|
|
156
|
+
if (object?.kind === 'self') {
|
|
157
|
+
fail('BUILDER_POLICY', pointer, 'A Node create rule has no self: the Node is not yet.');
|
|
158
|
+
}
|
|
159
|
+
fail('BUILDER_POLICY_INPUT', pointer, 'A Node create rule checks one ref(...) member.');
|
|
160
|
+
});
|
|
161
|
+
}
|
|
138
162
|
endpointBase(value, pointer) {
|
|
139
163
|
return {
|
|
140
164
|
role: value.as,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { deepFreeze } from '../../../language/freeze.js';
|
|
1
2
|
import { acceptDomainSchema } from '../../../schema/admission/accept.js';
|
|
2
|
-
import { canonicalizeDomainSchema } from '../../../schema/canonical/domain.js';
|
|
3
|
-
import { deepFreeze } from '../../../schema/canonical/freeze.js';
|
|
4
3
|
import { MemoryDomainSchemaLookup } from '../../../schema/dependency/lookup.js';
|
|
4
|
+
import { normalizeDomainSchema } from '../../../schema/normalization/domain.js';
|
|
5
5
|
import { lookupEntriesForDependencies } from '../../../schema/resolution/closure.js';
|
|
6
6
|
import { parseDomainSchemaStructure } from '../../../schema/validation/domain.structure.js';
|
|
7
7
|
import { assertKnownKeys, escapeToken } from '../../schema/diagnostic.js';
|
|
@@ -90,7 +90,7 @@ function assembleDomainSchema(origin, input, lookup) {
|
|
|
90
90
|
dependencies: context.dependencies(),
|
|
91
91
|
};
|
|
92
92
|
const structured = parseDomainSchemaStructure(candidate);
|
|
93
|
-
const canonical = parseDomainSchemaStructure(
|
|
93
|
+
const canonical = parseDomainSchemaStructure(normalizeDomainSchema(structured));
|
|
94
94
|
return deepFreeze(canonical);
|
|
95
95
|
}
|
|
96
96
|
function mapRecord(record, map) {
|
|
@@ -21,97 +21,24 @@ function createPolicy(input) {
|
|
|
21
21
|
declarations.set(value, input);
|
|
22
22
|
return value;
|
|
23
23
|
}
|
|
24
|
-
export const policy = Object.freeze(Object.assign(createPolicy, {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
24
|
+
export const policy = Object.freeze(Object.assign(createPolicy, { allOf: composer('allOf'), anyOf: composer('anyOf') }));
|
|
25
|
+
function composer(operator) {
|
|
26
|
+
return (first, ...rest) => createPolicy(composition(operator, first === undefined ? [] : [first, ...rest]));
|
|
27
|
+
}
|
|
28
28
|
export function createPatternContext(options) {
|
|
29
|
-
|
|
30
|
-
const subject = Object.freeze({ kind: 'subject' });
|
|
31
|
-
const object = Object.freeze({ kind: 'object' });
|
|
32
|
-
const source = Object.freeze({ kind: 'source' });
|
|
33
|
-
const target = Object.freeze({ kind: 'target' });
|
|
34
|
-
const classRef = (value) => options.resolveEdgeClass(value, `${options.pointer}/match/class`);
|
|
29
|
+
const nextVariable = variableIds();
|
|
35
30
|
const context = {
|
|
36
31
|
ref: (member) => ({
|
|
37
32
|
kind: 'ref',
|
|
38
33
|
ref: options.resolveObject(member, `${options.pointer}/match/ref`),
|
|
39
34
|
}),
|
|
40
35
|
sameNode: (left, right) => ({ sameNode: { left, right } }),
|
|
41
|
-
subject,
|
|
42
|
-
object,
|
|
43
|
-
source,
|
|
44
|
-
target,
|
|
45
|
-
edge: ((
|
|
46
|
-
|
|
47
|
-
if (ends === undefined) {
|
|
48
|
-
if (typeof first === 'function' || first.kind === 'edge') {
|
|
49
|
-
fail('BUILDER_POLICY', pointer, 'edge(classValue, ends) names both ends by their roles.');
|
|
50
|
-
}
|
|
51
|
-
const input = first;
|
|
52
|
-
assertKnownKeys(input, ['source', 'class', 'target', 'repeat']);
|
|
53
|
-
if (input.repeat !== undefined)
|
|
54
|
-
assertKnownKeys(input.repeat, ['min', 'max']);
|
|
55
|
-
return edgePattern(input.source, classRef(input.class), input.target, input.repeat);
|
|
56
|
-
}
|
|
57
|
-
const ref = classRef(first);
|
|
58
|
-
const [sourceRole, targetRole] = options.edgeRoles(ref);
|
|
59
|
-
if (typeof ends !== 'object' || ends === null) {
|
|
60
|
-
fail('BUILDER_POLICY', pointer, 'edge(classValue, ends) names both ends by their roles.');
|
|
61
|
-
}
|
|
62
|
-
assertKnownKeys(ends, [sourceRole, targetRole], pointer);
|
|
63
|
-
for (const role of [sourceRole, targetRole]) {
|
|
64
|
-
if (!Object.hasOwn(ends, role)) {
|
|
65
|
-
fail('BUILDER_POLICY', `${pointer}/${escapeToken(role)}`, `edge(...) names both ends of ${ref.origin}:class.${ref.name}: "${sourceRole}" and "${targetRole}".`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
if (edgeOptions !== undefined)
|
|
69
|
-
assertKnownKeys(edgeOptions, ['repeat'], pointer);
|
|
70
|
-
if (edgeOptions?.repeat !== undefined) {
|
|
71
|
-
assertKnownKeys(edgeOptions.repeat, ['min', 'max'], `${pointer}/repeat`);
|
|
72
|
-
}
|
|
73
|
-
return edgePattern(ends[sourceRole], ref, ends[targetRole], edgeOptions?.repeat);
|
|
74
|
-
}),
|
|
75
|
-
exists(build) {
|
|
76
|
-
const nodes = [];
|
|
77
|
-
const bind = (selector, definition) => {
|
|
78
|
-
const variable = Object.freeze({ kind: 'variable', id: nextVariable++ });
|
|
79
|
-
if (selector === 'any') {
|
|
80
|
-
nodes.push({ variable, selector: Object.freeze({ kind: 'any' }) });
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
const classRef = options.resolveNodeClass(definition, `${options.pointer}/match/exists/nodes`);
|
|
84
|
-
nodes.push(selector === 'exact'
|
|
85
|
-
? { variable, class: classRef }
|
|
86
|
-
: { variable, selector: Object.freeze({ kind: 'satisfies', class: classRef }) });
|
|
87
|
-
}
|
|
88
|
-
return variable;
|
|
89
|
-
};
|
|
90
|
-
const node = function (...args) {
|
|
91
|
-
if (args.length > 1 || (args.length === 1 && args[0] === undefined)) {
|
|
92
|
-
fail('BUILDER_POLICY', `${options.pointer}/match/exists/nodes`, 'node(...) accepts either no arguments or one Node Class.');
|
|
93
|
-
}
|
|
94
|
-
return args.length === 0
|
|
95
|
-
? bind('any')
|
|
96
|
-
: bind('satisfies', args[0]);
|
|
97
|
-
};
|
|
98
|
-
Object.defineProperty(node, 'exact', {
|
|
99
|
-
enumerable: true,
|
|
100
|
-
value(definition) {
|
|
101
|
-
if (arguments.length !== 1 || definition === undefined) {
|
|
102
|
-
fail('BUILDER_POLICY', `${options.pointer}/match/exists/nodes`, 'node.exact(...) requires exactly one Node Class.');
|
|
103
|
-
}
|
|
104
|
-
return bind('exact', definition);
|
|
105
|
-
},
|
|
106
|
-
});
|
|
107
|
-
Object.freeze(node);
|
|
108
|
-
const where = build({ node });
|
|
109
|
-
const [first, ...rest] = nodes;
|
|
110
|
-
if (first === undefined) {
|
|
111
|
-
fail('BUILDER_POLICY_EMPTY_EXISTS', `${options.pointer}/match/exists/nodes`, 'exists(...) must declare at least one variable Node.');
|
|
112
|
-
}
|
|
113
|
-
return { exists: { nodes: [first, ...rest], where } };
|
|
114
|
-
},
|
|
36
|
+
subject: Object.freeze({ kind: 'subject' }),
|
|
37
|
+
object: Object.freeze({ kind: 'object' }),
|
|
38
|
+
source: Object.freeze({ kind: 'source' }),
|
|
39
|
+
target: Object.freeze({ kind: 'target' }),
|
|
40
|
+
edge: (...args) => edge(options, args),
|
|
41
|
+
exists: (build) => exists(options, nextVariable, build),
|
|
115
42
|
allOf(...expressions) {
|
|
116
43
|
nonEmpty(expressions, `${options.pointer}/match/allOf`);
|
|
117
44
|
return { allOf: expressions };
|
|
@@ -123,6 +50,50 @@ export function createPatternContext(options) {
|
|
|
123
50
|
};
|
|
124
51
|
return Object.freeze(context);
|
|
125
52
|
}
|
|
53
|
+
/** Variable ids, unique across every `exists(...)` of one pattern. */
|
|
54
|
+
function variableIds() {
|
|
55
|
+
let next = 0;
|
|
56
|
+
return () => next++;
|
|
57
|
+
}
|
|
58
|
+
function edge(options, args) {
|
|
59
|
+
const pointer = `${options.pointer}/match/edge`;
|
|
60
|
+
if (args[1] === undefined)
|
|
61
|
+
return legacyEdge(options, args[0], pointer);
|
|
62
|
+
const [classValue, ends, edgeOptions] = args;
|
|
63
|
+
const ref = options.resolveEdgeClass(classValue, `${options.pointer}/match/class`);
|
|
64
|
+
const [sourceRole, targetRole] = options.edgeRoles(ref);
|
|
65
|
+
if (typeof ends !== 'object' || ends === null) {
|
|
66
|
+
fail('BUILDER_POLICY', pointer, 'edge(classValue, ends) names both ends by their roles.');
|
|
67
|
+
}
|
|
68
|
+
assertKnownKeys(ends, [sourceRole, targetRole], pointer);
|
|
69
|
+
const missing = `edge(...) names both ends of ${ref.origin}:class.${ref.name}: "${sourceRole}" and "${targetRole}".`;
|
|
70
|
+
const sourceTerm = endTerm(ends, sourceRole, pointer, missing);
|
|
71
|
+
const targetTerm = endTerm(ends, targetRole, pointer, missing);
|
|
72
|
+
if (edgeOptions !== undefined)
|
|
73
|
+
assertKnownKeys(edgeOptions, ['repeat'], pointer);
|
|
74
|
+
if (edgeOptions?.repeat !== undefined) {
|
|
75
|
+
assertKnownKeys(edgeOptions.repeat, ['min', 'max'], `${pointer}/repeat`);
|
|
76
|
+
}
|
|
77
|
+
return edgePattern(sourceTerm, ref, targetTerm, edgeOptions?.repeat);
|
|
78
|
+
}
|
|
79
|
+
function legacyEdge(options, input, pointer) {
|
|
80
|
+
// Typed callers cannot pass an Edge Class without ends; untyped ones can, and `kind` is read
|
|
81
|
+
// without `in` so a primitive still reaches `assertKnownKeys`.
|
|
82
|
+
if (typeof input === 'function' || input.kind === 'edge') {
|
|
83
|
+
fail('BUILDER_POLICY', pointer, 'edge(classValue, ends) names both ends by their roles.');
|
|
84
|
+
}
|
|
85
|
+
assertKnownKeys(input, ['source', 'class', 'target', 'repeat']);
|
|
86
|
+
if (input.repeat !== undefined)
|
|
87
|
+
assertKnownKeys(input.repeat, ['min', 'max']);
|
|
88
|
+
const ref = options.resolveEdgeClass(input.class, `${options.pointer}/match/class`);
|
|
89
|
+
return edgePattern(input.source, ref, input.target, input.repeat);
|
|
90
|
+
}
|
|
91
|
+
/** The term of one role. An own key holding `undefined` passes through, as it always has. */
|
|
92
|
+
function endTerm(ends, role, pointer, missing) {
|
|
93
|
+
if (!Object.hasOwn(ends, role))
|
|
94
|
+
fail('BUILDER_POLICY', `${pointer}/${escapeToken(role)}`, missing);
|
|
95
|
+
return ends[role];
|
|
96
|
+
}
|
|
126
97
|
/** One Edge pattern, whichever form named its ends. */
|
|
127
98
|
function edgePattern(source, classRef, target, repeat) {
|
|
128
99
|
return {
|
|
@@ -132,12 +103,50 @@ function edgePattern(source, classRef, target, repeat) {
|
|
|
132
103
|
...(repeat === undefined ? {} : { repeat: { ...repeat } }),
|
|
133
104
|
};
|
|
134
105
|
}
|
|
106
|
+
function exists(options, nextVariable, build) {
|
|
107
|
+
const pointer = `${options.pointer}/match/exists/nodes`;
|
|
108
|
+
const nodes = [];
|
|
109
|
+
const bind = (selector) => {
|
|
110
|
+
const variable = Object.freeze({ kind: 'variable', id: nextVariable() });
|
|
111
|
+
nodes.push(nodeVariable(options, variable, selector, pointer));
|
|
112
|
+
return variable;
|
|
113
|
+
};
|
|
114
|
+
const where = build({ node: nodeBinder(bind, pointer) });
|
|
115
|
+
const [first, ...rest] = nodes;
|
|
116
|
+
if (first === undefined) {
|
|
117
|
+
fail('BUILDER_POLICY_EMPTY_EXISTS', pointer, 'exists(...) must declare at least one variable Node.');
|
|
118
|
+
}
|
|
119
|
+
return { exists: { nodes: [first, ...rest], where } };
|
|
120
|
+
}
|
|
121
|
+
function nodeVariable(options, variable, selector, pointer) {
|
|
122
|
+
if (selector.kind === 'any')
|
|
123
|
+
return { variable, selector: Object.freeze({ kind: 'any' }) };
|
|
124
|
+
const classRef = options.resolveNodeClass(selector.definition, pointer);
|
|
125
|
+
if (selector.kind === 'exact')
|
|
126
|
+
return { variable, class: classRef };
|
|
127
|
+
return { variable, selector: Object.freeze({ kind: 'satisfies', class: classRef }) };
|
|
128
|
+
}
|
|
129
|
+
function nodeBinder(bind, pointer) {
|
|
130
|
+
function node(...args) {
|
|
131
|
+
const definition = args[0];
|
|
132
|
+
if (args.length > 1 || (args.length === 1 && definition === undefined)) {
|
|
133
|
+
fail('BUILDER_POLICY', pointer, 'node(...) accepts either no arguments or one Node Class.');
|
|
134
|
+
}
|
|
135
|
+
return definition === undefined
|
|
136
|
+
? bind({ kind: 'any' })
|
|
137
|
+
: bind({ kind: 'satisfies', definition });
|
|
138
|
+
}
|
|
139
|
+
function exact(definition) {
|
|
140
|
+
if (arguments.length !== 1 || definition === undefined) {
|
|
141
|
+
fail('BUILDER_POLICY', pointer, 'node.exact(...) requires exactly one Node Class.');
|
|
142
|
+
}
|
|
143
|
+
return bind({ kind: 'exact', definition });
|
|
144
|
+
}
|
|
145
|
+
return Object.freeze(Object.assign(node, { exact }));
|
|
146
|
+
}
|
|
135
147
|
function composition(operator, policies) {
|
|
136
148
|
nonEmpty(policies, `/${operator}`);
|
|
137
|
-
const value = {
|
|
138
|
-
operator,
|
|
139
|
-
policies: [...policies],
|
|
140
|
-
};
|
|
149
|
+
const value = { operator, policies: [...policies] };
|
|
141
150
|
compositions.add(value);
|
|
142
151
|
return value;
|
|
143
152
|
}
|
package/dist/v1/bundle/model.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { deepFreeze } from '../
|
|
1
|
+
import { deepFreeze } from '../language/freeze.js';
|
|
2
2
|
export const DOMAIN_BUNDLE_FORMAT = 'astrale.dsl.bundle';
|
|
3
3
|
export const DOMAIN_BUNDLE_VERSION = 'v1';
|
|
4
4
|
export function asDomainSchemaBundle(root, closure) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { accept as acceptPortable } from '@astrale-os/kernel-dsl/value';
|
|
2
|
+
import { deepFreeze } from '../../language/freeze.js';
|
|
2
3
|
import { limits } from '../../language/limits.js';
|
|
3
4
|
import {} from '../model/schema.js';
|
|
4
5
|
import { validateClosure } from './closure.js';
|
|
@@ -69,10 +70,3 @@ export function acceptCompiledSchema(input) {
|
|
|
69
70
|
validateCompiledSemantics(candidate);
|
|
70
71
|
return deepFreeze(candidate);
|
|
71
72
|
}
|
|
72
|
-
function deepFreeze(input) {
|
|
73
|
-
if (input === null || typeof input !== 'object' || Object.isFrozen(input))
|
|
74
|
-
return input;
|
|
75
|
-
for (const value of Object.values(input))
|
|
76
|
-
deepFreeze(value);
|
|
77
|
-
return Object.freeze(input);
|
|
78
|
-
}
|
|
@@ -90,9 +90,8 @@ function programKey(entry, value) {
|
|
|
90
90
|
/** Check automatic Properties, immutability and abstract Class obligations. */
|
|
91
91
|
export function validateClassFacets(context) {
|
|
92
92
|
for (const located of context.classes.values()) {
|
|
93
|
-
if (located.value.abstract &&
|
|
94
|
-
(located.
|
|
95
|
-
fail(`${located.pointer}/policies`, 'Abstract Classes cannot declare observation Policies.');
|
|
93
|
+
if (located.value.abstract && Object.keys(located.value.policies).length > 0) {
|
|
94
|
+
fail(`${located.pointer}/policies`, 'Abstract Classes cannot declare Class Policies.');
|
|
96
95
|
}
|
|
97
96
|
for (const [index, property] of located.value.properties.entries()) {
|
|
98
97
|
const path = `${located.pointer}/properties/${index}`;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {} from '../../../../addressing/index.js';
|
|
1
|
+
import { Key } from '../../../../addressing/index.js';
|
|
2
2
|
import { branchesOf, targetMode, isConnected, } from '../../../../language/policy/analysis/branches.js';
|
|
3
3
|
import { exceededLimits, measureChecks, policyMeasurer, } from '../../../../language/policy/analysis/budgets.js';
|
|
4
4
|
import { neverAdmittedClasses, } from '../../../../language/policy/analysis/checks.js';
|
|
5
5
|
import {} from '../../../../language/policy/analysis/typing.js';
|
|
6
|
-
import { checksNameTheCaller, isClassRuleChecks, } from '../../../../language/policy/model/policy.js';
|
|
6
|
+
import { CLASS_OPERATIONS, checksNameTheCaller, isClassRuleChecks, } from '../../../../language/policy/model/policy.js';
|
|
7
7
|
import { normalizePolicyExpression } from '../../../../language/policy/normalization/normalize.js';
|
|
8
8
|
import {} from '../../../model/schema.js';
|
|
9
9
|
import { fail } from '../../diagnostic.js';
|
|
10
|
-
import { isCompiledEdge } from '../context.js';
|
|
10
|
+
import { isCompiledEdge, } from '../context.js';
|
|
11
11
|
import { callableObjectContracts } from './contracts.js';
|
|
12
12
|
import { compiledPolicyTyping } from './typing.js';
|
|
13
13
|
/** Check Policy typing and expansion budgets against the entry’s own closure. */
|
|
@@ -46,26 +46,25 @@ export function validatePolicyParity(context, entry, entryIndex, policies, origi
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
for (const [classIndex, definition] of entry.definitions.classes.entries()) {
|
|
49
|
-
|
|
49
|
+
const edge = isCompiledEdge(definition) ? definition : undefined;
|
|
50
|
+
for (const operation of CLASS_OPERATIONS) {
|
|
50
51
|
const policy = definition.policies[operation];
|
|
51
52
|
if (typeof policy !== 'object')
|
|
52
53
|
continue;
|
|
53
54
|
const path = `/closure/${entryIndex}/definitions/classes/${classIndex}/policies/${operation}`;
|
|
54
55
|
if (isClassRuleChecks(policy)) {
|
|
55
|
-
// The wire admits rules only
|
|
56
|
-
validatePolicyChecks(context, typing, entry, policy, -1, definition.ref, path, 'class');
|
|
56
|
+
// The wire admits rules only over `self` and `ref` objects, and `ref` alone to create a Node.
|
|
57
|
+
validatePolicyChecks(context, typing, entry, policy, -1, definition.ref, path, 'class', edge);
|
|
57
58
|
continue;
|
|
58
59
|
}
|
|
59
|
-
const label = operation
|
|
60
|
+
const label = `${operation[0].toUpperCase()}${operation.slice(1)}`;
|
|
60
61
|
if (definition.kind === 'node') {
|
|
61
62
|
if (!typing.policyAccepts(policy.name, { kind: 'exact', ref: definition.ref })) {
|
|
62
63
|
fail(path, `${label} Policy is incompatible with its protected Node Class.`);
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
|
-
else if (
|
|
66
|
-
|
|
67
|
-
fail(path, `${label} Policy is incompatible with an accepted Edge endpoint pair.`);
|
|
68
|
-
}
|
|
66
|
+
else if (edge !== undefined && !typing.policyAcceptsEdgeClass(policy.name, edge)) {
|
|
67
|
+
fail(path, `${label} Policy is incompatible with an accepted Edge endpoint pair.`);
|
|
69
68
|
}
|
|
70
69
|
}
|
|
71
70
|
if (definition.kind === 'node') {
|
|
@@ -90,7 +89,7 @@ const SITE = {
|
|
|
90
89
|
callable: { checks: 'Callable Policy checks', objects: 'the callable object contract' },
|
|
91
90
|
class: { checks: 'Class rule checks', objects: 'the Class rule object contract' },
|
|
92
91
|
};
|
|
93
|
-
function validatePolicyChecks(context, typing, entry, expression, input, receiver, path, site) {
|
|
92
|
+
function validatePolicyChecks(context, typing, entry, expression, input, receiver, path, site, edge) {
|
|
94
93
|
if (!checksNameTheCaller(expression)) {
|
|
95
94
|
fail(path, `${SITE[site].checks} must check a Policy on every branch: sameNode alone names no caller.`);
|
|
96
95
|
}
|
|
@@ -99,13 +98,26 @@ function validatePolicyChecks(context, typing, entry, expression, input, receive
|
|
|
99
98
|
}
|
|
100
99
|
const leaves = new Map();
|
|
101
100
|
const visit = (value, pointer) => {
|
|
102
|
-
if ('sameNode' in value)
|
|
101
|
+
if ('sameNode' in value) {
|
|
102
|
+
// `self` is an Edge in an Edge Class rule, and sameNode compares Nodes.
|
|
103
|
+
if (edge !== undefined &&
|
|
104
|
+
(value.sameNode.left.kind === 'self' || value.sameNode.right.kind === 'self'))
|
|
105
|
+
fail(pointer, 'sameNode compares Nodes: self is an Edge here.');
|
|
103
106
|
return;
|
|
107
|
+
}
|
|
104
108
|
if (!('check' in value)) {
|
|
105
109
|
const children = 'allOf' in value ? value.allOf : value.anyOf;
|
|
106
110
|
children.forEach((child, index) => visit(child, `${pointer}/${index}`));
|
|
107
111
|
return;
|
|
108
112
|
}
|
|
113
|
+
if (edge !== undefined && value.object.kind === 'self') {
|
|
114
|
+
// An Edge is checked as an Edge Class Policy is: over every concrete endpoint pair.
|
|
115
|
+
if (!typing.policyAcceptsEdgeClass(value.check.name, edge))
|
|
116
|
+
fail(pointer, 'Named Policy is incompatible with an accepted Edge endpoint pair.');
|
|
117
|
+
const name = Key.of(edge.ref);
|
|
118
|
+
leaves.set(value, { accepted: [name], admitted: new Set([name]) });
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
109
121
|
const contracts = callableObjectContracts(context, entry, input, receiver, value.object);
|
|
110
122
|
if (contracts === undefined)
|
|
111
123
|
return;
|
|
@@ -2,7 +2,7 @@ import { Key } from '../../../../addressing/index.js';
|
|
|
2
2
|
import { PolicyTyping } from '../../../../language/policy/analysis/typing.js';
|
|
3
3
|
import {} from '../../../../language/policy/model/policy.js';
|
|
4
4
|
import {} from '../../../model/schema.js';
|
|
5
|
-
import {
|
|
5
|
+
import { isCompiledEdge } from '../context.js';
|
|
6
6
|
import { referenceContract } from './contracts.js';
|
|
7
7
|
/** Types one entry's Policies against the Node Classes of its own closure, as source admission. */
|
|
8
8
|
export function compiledPolicyTyping(context, entry, normalized, origins) {
|
|
@@ -14,7 +14,7 @@ export function compiledPolicyTyping(context, entry, normalized, origins) {
|
|
|
14
14
|
allNodeClasses: nodeClasses.map((value) => value.ref),
|
|
15
15
|
concreteNodeClasses: nodeClasses.filter((value) => !value.abstract).map((value) => value.ref),
|
|
16
16
|
isLocalPolicy: (ref) => ref.origin === entry.origin && ref.kind === 'policy',
|
|
17
|
-
|
|
17
|
+
resolveClass: (ref) => context.classes.get(Key.of(ref))?.value,
|
|
18
18
|
edgeDeclaration: (ref) => {
|
|
19
19
|
const value = context.classes.get(Key.of(ref))?.value;
|
|
20
20
|
return value !== undefined && isCompiledEdge(value) ? value : undefined;
|