@astrale-os/kernel-dsl 1.0.0-beta.12 → 1.0.0-beta.14
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/key.js +2 -1
- package/dist/v1/addressing/ordering.d.ts +2 -0
- package/dist/v1/addressing/ordering.js +4 -0
- package/dist/v1/addressing/patterns.d.ts +1 -1
- package/dist/v1/addressing/patterns.js +2 -6
- package/dist/v1/builder/class/authoring.js +5 -28
- package/dist/v1/builder/class/property.d.ts +3 -9
- package/dist/v1/builder/class/property.js +1 -0
- package/dist/v1/builder/lowering/class.js +5 -1
- package/dist/v1/builder/lowering/policy.js +1 -0
- package/dist/v1/builder/lowering/schema/context.js +2 -4
- package/dist/v1/builder/lowering/value/path.js +2 -4
- package/dist/v1/builder/lowering/value/zod.js +1 -3
- package/dist/v1/builder/policy/authoring.js +3 -2
- package/dist/v1/builder/schema/define.d.ts +0 -1
- package/dist/v1/builder/schema/diagnostic.d.ts +2 -1
- package/dist/v1/builder/schema/diagnostic.js +5 -10
- package/dist/v1/builder/schema/projection.d.ts +1 -1
- package/dist/v1/builder/value/full-match.d.ts +0 -1
- package/dist/v1/builder/value/full-match.js +0 -1
- package/dist/v1/bundle/codec.js +4 -6
- package/dist/v1/bundle/diagnostic.d.ts +2 -0
- package/dist/v1/bundle/diagnostic.js +9 -7
- package/dist/v1/bundle/structure.js +4 -6
- 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 +4 -2
- package/dist/v1/domain/validation/create.js +21 -69
- package/dist/v1/language/.spec/schemas/value-schema.schema.json +22 -0
- package/dist/v1/language/class/inheritance.d.ts +18 -0
- package/dist/v1/language/class/inheritance.js +73 -0
- package/dist/v1/language/class/model/class.d.ts +4 -4
- package/dist/v1/language/class/model/edge.d.ts +2 -2
- package/dist/v1/language/class/model/property.d.ts +16 -7
- 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/definition/metadata.d.ts +5 -0
- package/dist/v1/language/definition/metadata.js +7 -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/policy/model/policy.d.ts +5 -5
- package/dist/v1/language/policy/normalization/normalize.js +17 -16
- package/dist/v1/language/validation/diagnostic.d.ts +15 -1
- package/dist/v1/language/validation/diagnostic.js +21 -0
- package/dist/v1/language/validation/rule.d.ts +26 -0
- package/dist/v1/language/validation/rule.js +116 -0
- package/dist/v1/language/value/compile/fields.js +4 -8
- package/dist/v1/language/value/profile/meta-schema.compiled.js +4 -1
- package/dist/v1/language/value/profile/rules.js +17 -43
- package/dist/v1/language/value/profile/validate.js +1 -10
- package/dist/v1/language/value/profile/vocabulary.d.ts +35 -2
- package/dist/v1/language/value/profile/vocabulary.js +52 -5
- package/dist/v1/language/value/reference/recursion.js +2 -22
- package/dist/v1/language/value/reference/registry.index.js +2 -1
- package/dist/v1/language/value/syntax/keywords.d.ts +3 -3
- package/dist/v1/language/value/syntax/keywords.js +4 -20
- package/dist/v1/language/value/syntax/node-path/validate.js +2 -3
- 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/.spec/schemas/domain-schema.schema.json +2336 -0
- package/dist/v1/schema/analysis/class.js +33 -15
- package/dist/v1/schema/compatibility/api.d.ts +1 -1
- package/dist/v1/schema/compatibility/coordinate.js +3 -3
- package/dist/v1/schema/compatibility/diff.js +2 -4
- package/dist/v1/schema/compatibility/meaning/footprint.js +16 -50
- package/dist/v1/schema/compatibility/model.d.ts +5 -0
- 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.d.ts +17 -3
- package/dist/v1/schema/diagnostic.js +14 -11
- package/dist/v1/schema/index.d.ts +3 -1
- package/dist/v1/schema/index.js +1 -0
- package/dist/v1/schema/model/schema.d.ts +19 -1
- package/dist/v1/schema/normalization/domain.js +1 -0
- package/dist/v1/schema/resolution/closure.js +2 -1
- package/dist/v1/schema/resolution/context.js +6 -6
- package/dist/v1/schema/rule.d.ts +29 -0
- package/dist/v1/schema/rule.js +415 -0
- package/dist/v1/schema/validation/callable.d.ts +4 -1
- package/dist/v1/schema/validation/callable.js +13 -6
- package/dist/v1/schema/validation/class.js +46 -96
- package/dist/v1/schema/validation/core.js +68 -202
- package/dist/v1/schema/validation/domain.js +1 -10
- package/dist/v1/schema/validation/domain.json-schema.d.ts +15 -0
- package/dist/v1/schema/validation/domain.json-schema.js +183 -0
- package/dist/v1/schema/validation/domain.structure.d.ts +4018 -0
- package/dist/v1/schema/validation/domain.structure.js +343 -155
- package/dist/v1/schema/validation/json.json-schema.d.ts +24 -0
- package/dist/v1/schema/validation/json.json-schema.js +36 -0
- 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 +10 -27
- 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 -25
- package/dist/v1/schema/validation/policy/validate.js +3 -2
- package/dist/v1/schema/validation/value-api.d.ts +12 -1
- package/dist/v1/schema/validation/value-api.js +12 -3
- package/dist/v1/schema/validation/value.js +8 -10
- package/dist/v1/schema/validation/value.json-schema.d.ts +51 -0
- package/dist/v1/schema/validation/value.json-schema.js +126 -0
- package/dist/v1/schema/validation/view.js +4 -8
- package/package.json +3 -1
- package/dist/v1/compiled/admission/semantics/cardinality.d.ts +0 -5
- package/dist/v1/compiled/admission/semantics/cardinality.js +0 -128
- package/dist/v1/compiled/admission/semantics/policy/equality.d.ts +0 -8
- package/dist/v1/compiled/admission/semantics/policy/equality.js +0 -27
- package/dist/v1/compiled/admission/semantics/policy/measure.d.ts +0 -9
- package/dist/v1/compiled/admission/semantics/policy/measure.js +0 -81
- package/dist/v1/compiled/admission/semantics/policy/variants.d.ts +0 -10
- package/dist/v1/compiled/admission/semantics/policy/variants.js +0 -65
- package/dist/v1/language/class/index.d.ts +0 -8
- package/dist/v1/language/class/index.js +0 -1
- package/dist/v1/language/core/index.d.ts +0 -2
- package/dist/v1/language/core/index.js +0 -1
- package/dist/v1/language/value/index.d.ts +0 -11
- package/dist/v1/language/value/index.js +0 -8
|
@@ -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
|
+
}
|
|
@@ -3,7 +3,7 @@ import type { MethodRecord } from '../../callable/model/callable.js';
|
|
|
3
3
|
import type { ClassPolicy, NodeClassPolicy } from '../../policy/model/policy.js';
|
|
4
4
|
import type { DataFacet } from './data.js';
|
|
5
5
|
import type { EdgeContract } from './edge.js';
|
|
6
|
-
import type { PropertyFacet } from './property.js';
|
|
6
|
+
import type { EdgePropertyDefinition, NodePropertyDefinition, PropertyFacet } from './property.js';
|
|
7
7
|
export type ClassKind = 'node' | 'edge';
|
|
8
8
|
/**
|
|
9
9
|
* Which Classes may extend a Class: `'open'`, those of its Domain and of every Domain that depends
|
|
@@ -30,7 +30,7 @@ export type NodeUniqueTuple = readonly [PropertyKey, ...PropertyKey[]];
|
|
|
30
30
|
* backend announces it to enforce Node keys, so a tuple is never ignored where it is not.
|
|
31
31
|
*/
|
|
32
32
|
export type NodeUniqueForm = readonly ['property'];
|
|
33
|
-
export interface NodeClassDefinition extends DefinitionBase<ClassRef>, PropertyFacet
|
|
33
|
+
export interface NodeClassDefinition extends DefinitionBase<ClassRef>, PropertyFacet<NodePropertyDefinition>, DataFacet {
|
|
34
34
|
readonly kind: 'node';
|
|
35
35
|
readonly abstract: boolean;
|
|
36
36
|
/** Absent when `'internal'`, the default, so a Class that keeps the default keeps its revision. */
|
|
@@ -44,9 +44,9 @@ export interface NodeClassDefinition extends DefinitionBase<ClassRef>, PropertyF
|
|
|
44
44
|
* The tuples no two Nodes of this Class and of its active concrete descendants share while every
|
|
45
45
|
* Property is present; absent, none. A descendant is covered without declaring them again.
|
|
46
46
|
*/
|
|
47
|
-
readonly unique?: readonly NodeUniqueTuple[];
|
|
47
|
+
readonly unique?: readonly [NodeUniqueTuple, ...NodeUniqueTuple[]];
|
|
48
48
|
}
|
|
49
|
-
export type EdgeClassDefinition = DefinitionBase<ClassRef> & PropertyFacet & EdgeContract & {
|
|
49
|
+
export type EdgeClassDefinition = DefinitionBase<ClassRef> & PropertyFacet<EdgePropertyDefinition> & EdgeContract & {
|
|
50
50
|
readonly kind: 'edge';
|
|
51
51
|
readonly abstract: boolean;
|
|
52
52
|
/** Absent when `'internal'`, the default, so a Class that keeps the default keeps its revision. */
|
|
@@ -8,7 +8,7 @@ export type EdgeOrientation = 'directed' | 'undirected';
|
|
|
8
8
|
export type EdgeLifetime = 'restrict' | 'detach';
|
|
9
9
|
export interface EdgeEndpointBase {
|
|
10
10
|
readonly role: string;
|
|
11
|
-
readonly accepts: readonly ClassRef[];
|
|
11
|
+
readonly accepts: readonly [ClassRef, ...ClassRef[]];
|
|
12
12
|
/** Declared only when authored; otherwise derived (`edgeLifetimes`). */
|
|
13
13
|
readonly onDelete?: EdgeLifetime;
|
|
14
14
|
}
|
|
@@ -56,7 +56,7 @@ export interface DirectedEdgeContract {
|
|
|
56
56
|
* The tuples no two Edges of this Class and of its active concrete descendants share. Absent
|
|
57
57
|
* when the Class declares none, so a Class without one keeps its revision; never empty.
|
|
58
58
|
*/
|
|
59
|
-
readonly unique?: readonly EdgeUniqueTuple[];
|
|
59
|
+
readonly unique?: readonly [EdgeUniqueTuple, ...EdgeUniqueTuple[]];
|
|
60
60
|
}
|
|
61
61
|
export interface UndirectedEdgeContract {
|
|
62
62
|
readonly orientation: 'undirected';
|
|
@@ -1,20 +1,29 @@
|
|
|
1
|
+
import type { StateTopology } from '../../state/index.js';
|
|
2
|
+
import type { JsonSchema } from '../../value/model/schema.js';
|
|
1
3
|
export type AutoEvent = 'create' | 'update';
|
|
2
4
|
export type AutoSet = 'instant';
|
|
3
5
|
/** `create`: written only by node or edge creation. `once`: written while absent, never unset. */
|
|
4
6
|
export type PropertyImmutability = 'create' | 'once';
|
|
5
7
|
export interface PropertyAuto {
|
|
6
|
-
readonly on: readonly AutoEvent[];
|
|
8
|
+
readonly on: readonly [AutoEvent, ...AutoEvent[]];
|
|
7
9
|
readonly set: AutoSet;
|
|
8
10
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
/** A Property of a Node Class, which may be a State Property. */
|
|
12
|
+
export interface NodePropertyDefinition {
|
|
13
|
+
readonly schema: JsonSchema;
|
|
11
14
|
readonly required: boolean;
|
|
12
15
|
readonly auto?: PropertyAuto;
|
|
13
16
|
readonly immutable?: PropertyImmutability;
|
|
14
17
|
readonly description?: string;
|
|
15
|
-
readonly state?:
|
|
18
|
+
readonly state?: StateTopology;
|
|
16
19
|
}
|
|
17
|
-
|
|
18
|
-
export interface
|
|
19
|
-
readonly
|
|
20
|
+
/** A Property of an Edge Class: an Edge has no State Property. */
|
|
21
|
+
export interface EdgePropertyDefinition extends Omit<NodePropertyDefinition, 'state'> {
|
|
22
|
+
readonly state?: never;
|
|
23
|
+
}
|
|
24
|
+
/** A Property of a Class of either kind. */
|
|
25
|
+
export type PropertyDefinition = NodePropertyDefinition | EdgePropertyDefinition;
|
|
26
|
+
export type PropertyRecord<Definition extends PropertyDefinition = PropertyDefinition> = Readonly<Record<string, Definition>>;
|
|
27
|
+
export interface PropertyFacet<Definition extends PropertyDefinition = PropertyDefinition> {
|
|
28
|
+
readonly properties: PropertyRecord<Definition>;
|
|
20
29
|
}
|
|
@@ -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
|
-
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { ClassRef } from '../../addressing/index.js';
|
|
2
|
+
import type { EdgeContract, EdgeCount, EdgeEndpointBase, IncidentEndpoint } from '../class/model/edge.js';
|
|
3
|
+
/** One endpoint of a Core Edge: a Core Node, a projected member or the owning Domain. */
|
|
4
|
+
export interface CoreFactEndpoint {
|
|
5
|
+
readonly key: string;
|
|
6
|
+
/** Set on a projected member: its Kernel Class, and where a breach of its degree is reported. */
|
|
7
|
+
readonly member?: {
|
|
8
|
+
readonly class: ClassRef;
|
|
9
|
+
readonly pointer: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/** One Core Edge whose endpoints satisfy its exact Class. */
|
|
13
|
+
export interface CoreFactEdge<Edge> {
|
|
14
|
+
readonly edge: Edge;
|
|
15
|
+
/** The exact Class's key, as `CoreEdgeSet.classes` names it. */
|
|
16
|
+
readonly class: string;
|
|
17
|
+
readonly contract: EdgeContract;
|
|
18
|
+
readonly source: CoreFactEndpoint;
|
|
19
|
+
readonly target: CoreFactEndpoint;
|
|
20
|
+
}
|
|
21
|
+
/** One declared Core Node. It proves its own complete degree, so both bounds hold. */
|
|
22
|
+
export interface CoreDegreeSubject {
|
|
23
|
+
readonly key: string;
|
|
24
|
+
readonly class: ClassRef;
|
|
25
|
+
readonly pointer: string;
|
|
26
|
+
}
|
|
27
|
+
export interface CoreEdgeSet<Edge> {
|
|
28
|
+
readonly edges: readonly CoreFactEdge<Edge>[];
|
|
29
|
+
/** The local exact Edge Classes, in the order their slices are checked. */
|
|
30
|
+
readonly classes: readonly {
|
|
31
|
+
readonly key: string;
|
|
32
|
+
readonly contract: EdgeContract;
|
|
33
|
+
}[];
|
|
34
|
+
readonly nodes: readonly CoreDegreeSubject[];
|
|
35
|
+
readonly satisfies: (ref: ClassRef, accepts: readonly ClassRef[]) => boolean;
|
|
36
|
+
/** The keys an Edge holds under the tuples covering its Class. */
|
|
37
|
+
readonly keys: (edge: CoreFactEdge<Edge>) => readonly string[];
|
|
38
|
+
/** Whether an undirected Edge's two endpoints state one contract, counted once. */
|
|
39
|
+
readonly sameIncident: (left: IncidentEndpoint, right: IncidentEndpoint) => boolean;
|
|
40
|
+
readonly report: (issue: CoreEdgeIssue<Edge>) => void;
|
|
41
|
+
}
|
|
42
|
+
export type CoreEdgeIssue<Edge> = {
|
|
43
|
+
readonly kind: 'identity';
|
|
44
|
+
readonly edge: Edge;
|
|
45
|
+
readonly previous: Edge;
|
|
46
|
+
} | {
|
|
47
|
+
readonly kind: 'no-self';
|
|
48
|
+
readonly edge: Edge;
|
|
49
|
+
} | {
|
|
50
|
+
readonly kind: 'key';
|
|
51
|
+
readonly edge: Edge;
|
|
52
|
+
readonly previous: Edge;
|
|
53
|
+
} | {
|
|
54
|
+
readonly kind: 'acyclic';
|
|
55
|
+
readonly class: string;
|
|
56
|
+
} | {
|
|
57
|
+
readonly kind: 'degree';
|
|
58
|
+
readonly pointer: string;
|
|
59
|
+
readonly endpoint: EdgeEndpointBase;
|
|
60
|
+
readonly count: EdgeCount;
|
|
61
|
+
readonly degree: number;
|
|
62
|
+
};
|
|
63
|
+
/** Whether the endpoints satisfy the contract: in order when directed, in either order when not. */
|
|
64
|
+
export declare function coreEndpointsSatisfy<Endpoint>(contract: EdgeContract, source: Endpoint, target: Endpoint, satisfies: (endpoint: Endpoint, accepts: readonly ClassRef[]) => boolean): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Report each fact that holds a key an earlier fact holds, with the first holder of that key. Core
|
|
67
|
+
* facts have no slug, so only tuples of endpoints and Properties bind them (DV-NODE-UNIQUE,
|
|
68
|
+
* DV-EDGE-UNIQUE); Activation checks them against stored data.
|
|
69
|
+
*/
|
|
70
|
+
export declare function checkHeldKeys<Fact>(facts: Iterable<Fact>, keys: (fact: Fact) => readonly string[], report: (fact: Fact, previous: Fact) => void): void;
|
|
71
|
+
/** Check normalized Edge identity, noSelf, keys, exact-Class acyclicity and Core degrees. */
|
|
72
|
+
export declare function checkCoreEdgeSet<Edge>(set: CoreEdgeSet<Edge>): void;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { compareUnicode } from '../../addressing/ordering.js';
|
|
2
|
+
import { countBounds, hasDirectedCycle } from '../class/inheritance.js';
|
|
3
|
+
/** Whether the endpoints satisfy the contract: in order when directed, in either order when not. */
|
|
4
|
+
export function coreEndpointsSatisfy(contract, source, target, satisfies) {
|
|
5
|
+
if (contract.orientation === 'directed') {
|
|
6
|
+
const { endpoints } = contract;
|
|
7
|
+
return (satisfies(source, endpoints.source.accepts) && satisfies(target, endpoints.target.accepts));
|
|
8
|
+
}
|
|
9
|
+
const [first, second] = contract.endpoints;
|
|
10
|
+
return ((satisfies(source, first.accepts) && satisfies(target, second.accepts)) ||
|
|
11
|
+
(satisfies(source, second.accepts) && satisfies(target, first.accepts)));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Report each fact that holds a key an earlier fact holds, with the first holder of that key. Core
|
|
15
|
+
* facts have no slug, so only tuples of endpoints and Properties bind them (DV-NODE-UNIQUE,
|
|
16
|
+
* DV-EDGE-UNIQUE); Activation checks them against stored data.
|
|
17
|
+
*/
|
|
18
|
+
export function checkHeldKeys(facts, keys, report) {
|
|
19
|
+
const holders = new Map();
|
|
20
|
+
for (const fact of facts) {
|
|
21
|
+
const held = keys(fact);
|
|
22
|
+
const holder = held.find((key) => holders.has(key));
|
|
23
|
+
if (holder !== undefined)
|
|
24
|
+
report(fact, holders.get(holder));
|
|
25
|
+
for (const key of held)
|
|
26
|
+
if (!holders.has(key))
|
|
27
|
+
holders.set(key, fact);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Check normalized Edge identity, noSelf, keys, exact-Class acyclicity and Core degrees. */
|
|
31
|
+
export function checkCoreEdgeSet(set) {
|
|
32
|
+
const identities = new Map();
|
|
33
|
+
const slices = new Map(set.classes.map(({ key }) => [key, []]));
|
|
34
|
+
for (const fact of set.edges) {
|
|
35
|
+
const [source, target] = fact.contract.orientation === 'undirected' &&
|
|
36
|
+
compareUnicode(fact.source.key, fact.target.key) > 0
|
|
37
|
+
? [fact.target.key, fact.source.key]
|
|
38
|
+
: [fact.source.key, fact.target.key];
|
|
39
|
+
const identity = `${fact.class}\u0000${source}\u0000${target}`;
|
|
40
|
+
const previous = identities.get(identity);
|
|
41
|
+
if (previous !== undefined)
|
|
42
|
+
set.report({ kind: 'identity', edge: fact.edge, previous });
|
|
43
|
+
else
|
|
44
|
+
identities.set(identity, fact.edge);
|
|
45
|
+
slices.get(fact.class)?.push(fact);
|
|
46
|
+
if (fact.contract.constraints.noSelf === true && fact.source.key === fact.target.key)
|
|
47
|
+
set.report({ kind: 'no-self', edge: fact.edge });
|
|
48
|
+
}
|
|
49
|
+
checkHeldKeys(set.edges, set.keys, (fact, previous) => set.report({ kind: 'key', edge: fact.edge, previous: previous.edge }));
|
|
50
|
+
for (const { key, contract } of set.classes) {
|
|
51
|
+
const slice = slices.get(key);
|
|
52
|
+
if (contract.constraints.acyclic === true && hasDirectedCycle(slice))
|
|
53
|
+
set.report({ kind: 'acyclic', class: key });
|
|
54
|
+
checkDegrees(set, contract, slice);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function checkDegrees(set, contract, slice) {
|
|
58
|
+
for (const subject of degreeSubjects(set.nodes, slice)) {
|
|
59
|
+
const check = (endpoint, count, degree) => {
|
|
60
|
+
const [minimum, maximum] = countBounds(count);
|
|
61
|
+
if (degree > maximum || (degree < minimum && subject.minimum))
|
|
62
|
+
set.report({ kind: 'degree', pointer: subject.pointer, endpoint, count, degree });
|
|
63
|
+
};
|
|
64
|
+
if (contract.orientation === 'directed') {
|
|
65
|
+
const { source, target } = contract.endpoints;
|
|
66
|
+
if (set.satisfies(subject.class, source.accepts))
|
|
67
|
+
check(source, source.outgoing, slice.filter((edge) => edge.source.key === subject.key).length);
|
|
68
|
+
if (set.satisfies(subject.class, target.accepts))
|
|
69
|
+
check(target, target.incoming, slice.filter((edge) => edge.target.key === subject.key).length);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const [first, second] = contract.endpoints;
|
|
73
|
+
const degree = slice.filter((edge) => edge.source.key === subject.key || edge.target.key === subject.key).length;
|
|
74
|
+
if (set.satisfies(subject.class, first.accepts))
|
|
75
|
+
check(first, first.incident, degree);
|
|
76
|
+
if (!set.sameIncident(first, second) && set.satisfies(subject.class, second.accepts))
|
|
77
|
+
check(second, second.incident, degree);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Every declared Core Node proves its own complete degree, so both bounds hold. A projected member
|
|
82
|
+
* is only named by the Edges that reach it: the Domain may also create ordinary Edges of the same
|
|
83
|
+
* Class against it, so a minimum is unprovable here and only the maximum is enforced.
|
|
84
|
+
*/
|
|
85
|
+
function degreeSubjects(nodes, slice) {
|
|
86
|
+
const subjects = new Map(nodes.map((node) => [node.key, { ...node, minimum: true }]));
|
|
87
|
+
for (const edge of slice) {
|
|
88
|
+
for (const { key, member } of [edge.source, edge.target]) {
|
|
89
|
+
if (member === undefined || subjects.has(key))
|
|
90
|
+
continue;
|
|
91
|
+
subjects.set(key, { key, class: member.class, pointer: member.pointer, minimum: false });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return subjects.values();
|
|
95
|
+
}
|
|
@@ -18,3 +18,8 @@ export declare const name: Readonly<{
|
|
|
18
18
|
}>;
|
|
19
19
|
/** The common source and compiled grammar for a name displayed exactly as authored. */
|
|
20
20
|
export declare function isDomainNameText(value: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The same grammar as a portable pattern: no control character, and neither first nor last a
|
|
23
|
+
* character `trim` removes, spelled out since `\s` differs between regular expression engines.
|
|
24
|
+
*/
|
|
25
|
+
export declare const DOMAIN_NAME_TEXT_PATTERN: RegExp;
|
|
@@ -22,3 +22,10 @@ const DOMAIN_NAME_CONTROL = /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/u;
|
|
|
22
22
|
export function isDomainNameText(value) {
|
|
23
23
|
return value.trim() === value && !DOMAIN_NAME_CONTROL.test(value);
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* The same grammar as a portable pattern: no control character, and neither first nor last a
|
|
27
|
+
* character `trim` removes, spelled out since `\s` differs between regular expression engines.
|
|
28
|
+
*/
|
|
29
|
+
export const DOMAIN_NAME_TEXT_PATTERN =
|
|
30
|
+
// oxlint-disable-next-line no-control-regex
|
|
31
|
+
/^(?:[^\u0000-\u001f\u007f-\u009f\u0020\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff](?:[^\u0000-\u001f\u007f-\u009f\u2028\u2029]*[^\u0000-\u001f\u007f-\u009f\u0020\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff])?)?$/u;
|
|
@@ -18,3 +18,11 @@ export declare function capBranches(values: readonly PatternBranch[]): readonly
|
|
|
18
18
|
export declare function isConnected(branch: PatternBranch): boolean;
|
|
19
19
|
export declare function targetMode(branch: PatternBranch): PolicyTargetMode | undefined;
|
|
20
20
|
export declare function termKey(term: PolicyPatternTerm, namespace: string): string;
|
|
21
|
+
/** Disjoint sets of term keys, merged by the equalities of one Policy branch. */
|
|
22
|
+
export declare class UnionFind {
|
|
23
|
+
#private;
|
|
24
|
+
constructor(values: Iterable<string>);
|
|
25
|
+
add(value: string): void;
|
|
26
|
+
find(value: string): string;
|
|
27
|
+
join(left: string, right: string): void;
|
|
28
|
+
}
|
|
@@ -146,7 +146,8 @@ function collectVariableClasses(pattern, namespace) {
|
|
|
146
146
|
function variableKey(namespace, id) {
|
|
147
147
|
return `variable:${namespace}:${id}`;
|
|
148
148
|
}
|
|
149
|
-
|
|
149
|
+
/** Disjoint sets of term keys, merged by the equalities of one Policy branch. */
|
|
150
|
+
export class UnionFind {
|
|
150
151
|
#parents = new Map();
|
|
151
152
|
constructor(values) {
|
|
152
153
|
for (const value of values)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PolicyRef } from '../../../addressing/index.js';
|
|
2
|
+
import type { PolicyCheckExpression, PolicyExpression } from '../model/policy.js';
|
|
2
3
|
export declare const MAX_PATTERN_DEPTH = 4;
|
|
3
4
|
export declare const MAX_BRANCHES = 8;
|
|
4
5
|
export declare const MAX_VARIABLES = 4;
|
|
@@ -8,6 +9,17 @@ export declare const MAX_DOMAINS = 4;
|
|
|
8
9
|
export declare const MAX_CHECK_DEPTH = 4;
|
|
9
10
|
export declare const MAX_CHECK_LEAVES = 8;
|
|
10
11
|
export declare const BRANCH_OVERFLOW: number;
|
|
12
|
+
export interface PatternMeasure {
|
|
13
|
+
readonly depth: number;
|
|
14
|
+
readonly edgeCounts: readonly number[];
|
|
15
|
+
readonly domains: ReadonlySet<string>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Measure named Policies by their expanded branches, depth and referenced Domains. A Policy has no
|
|
19
|
+
* measure when it is not normalized, when its expansion reaches itself, or when a composition names
|
|
20
|
+
* a Policy `isLocal` refuses or one without a measure.
|
|
21
|
+
*/
|
|
22
|
+
export declare function policyMeasurer(origin: string, normalized: ReadonlyMap<string, PolicyExpression>, isLocal: (ref: PolicyRef) => boolean): (name: string) => PatternMeasure | undefined;
|
|
11
23
|
export interface CheckMeasure {
|
|
12
24
|
readonly depth: number;
|
|
13
25
|
readonly branches: number;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { policyObjectOrigin, policyVariableClass } from '../model/policy.js';
|
|
1
2
|
export const MAX_PATTERN_DEPTH = 4;
|
|
2
3
|
export const MAX_BRANCHES = 8;
|
|
3
4
|
export const MAX_VARIABLES = 4;
|
|
@@ -7,6 +8,109 @@ export const MAX_DOMAINS = 4;
|
|
|
7
8
|
export const MAX_CHECK_DEPTH = 4;
|
|
8
9
|
export const MAX_CHECK_LEAVES = 8;
|
|
9
10
|
export const BRANCH_OVERFLOW = MAX_BRANCHES + 1;
|
|
11
|
+
/**
|
|
12
|
+
* Measure named Policies by their expanded branches, depth and referenced Domains. A Policy has no
|
|
13
|
+
* measure when it is not normalized, when its expansion reaches itself, or when a composition names
|
|
14
|
+
* a Policy `isLocal` refuses or one without a measure.
|
|
15
|
+
*/
|
|
16
|
+
export function policyMeasurer(origin, normalized, isLocal) {
|
|
17
|
+
// Measure every distinct composition node once. A node's expanded measure is independent of the
|
|
18
|
+
// path that reaches it (the only path-sensitive outcome, the back-edge `undefined`, already holds
|
|
19
|
+
// for every node on or reaching a composition cycle, regardless of entry), so caching the
|
|
20
|
+
// completed result by node identity turns path enumeration over the composition DAG into work
|
|
21
|
+
// linear in the number of nodes while preserving the exact measure.
|
|
22
|
+
const measures = new Map();
|
|
23
|
+
const measurePolicy = (name, visiting) => {
|
|
24
|
+
if (visiting.has(name))
|
|
25
|
+
return undefined;
|
|
26
|
+
if (measures.has(name))
|
|
27
|
+
return measures.get(name);
|
|
28
|
+
const declaration = normalized.get(name);
|
|
29
|
+
if (declaration === undefined)
|
|
30
|
+
return undefined;
|
|
31
|
+
const nested = new Set(visiting);
|
|
32
|
+
nested.add(name);
|
|
33
|
+
const measure = measureDeclaration(declaration, nested);
|
|
34
|
+
measures.set(name, measure);
|
|
35
|
+
return measure;
|
|
36
|
+
};
|
|
37
|
+
const measureDeclaration = (declaration, nested) => {
|
|
38
|
+
if ('match' in declaration)
|
|
39
|
+
return measurePattern(declaration.match, origin);
|
|
40
|
+
const refs = 'allOf' in declaration ? declaration.allOf : declaration.anyOf;
|
|
41
|
+
const children = refs.flatMap((ref) => {
|
|
42
|
+
if (!isLocal(ref))
|
|
43
|
+
return [];
|
|
44
|
+
const value = measurePolicy(ref.name, nested);
|
|
45
|
+
return value === undefined ? [] : [value];
|
|
46
|
+
});
|
|
47
|
+
if (children.length !== refs.length || children.length === 0)
|
|
48
|
+
return undefined;
|
|
49
|
+
return combineMeasures('allOf' in declaration ? 'allOf' : 'anyOf', children);
|
|
50
|
+
};
|
|
51
|
+
return (name) => measurePolicy(name, new Set());
|
|
52
|
+
}
|
|
53
|
+
function measurePattern(pattern, origin) {
|
|
54
|
+
if ('sameNode' in pattern)
|
|
55
|
+
return {
|
|
56
|
+
depth: 1,
|
|
57
|
+
edgeCounts: [1],
|
|
58
|
+
domains: new Set([
|
|
59
|
+
origin,
|
|
60
|
+
...[pattern.sameNode.left, pattern.sameNode.right].flatMap((term) => term.kind === 'ref' ? [policyObjectOrigin(term.ref)] : []),
|
|
61
|
+
]),
|
|
62
|
+
};
|
|
63
|
+
if ('source' in pattern)
|
|
64
|
+
return {
|
|
65
|
+
depth: 1,
|
|
66
|
+
edgeCounts: [1],
|
|
67
|
+
domains: new Set([
|
|
68
|
+
origin,
|
|
69
|
+
pattern.class.origin,
|
|
70
|
+
...[pattern.source, pattern.target].flatMap((term) => term.kind === 'ref' ? [policyObjectOrigin(term.ref)] : []),
|
|
71
|
+
]),
|
|
72
|
+
};
|
|
73
|
+
if ('exists' in pattern) {
|
|
74
|
+
const child = measurePattern(pattern.exists.where, origin);
|
|
75
|
+
return {
|
|
76
|
+
depth: child.depth + 1,
|
|
77
|
+
edgeCounts: child.edgeCounts,
|
|
78
|
+
domains: new Set([
|
|
79
|
+
...child.domains,
|
|
80
|
+
...pattern.exists.nodes.flatMap((node) => {
|
|
81
|
+
const ref = policyVariableClass(node);
|
|
82
|
+
return ref === undefined ? [] : [ref.origin];
|
|
83
|
+
}),
|
|
84
|
+
]),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return combineMeasures('allOf' in pattern ? 'allOf' : 'anyOf', ('allOf' in pattern ? pattern.allOf : pattern.anyOf).map((child) => measurePattern(child, origin)));
|
|
88
|
+
}
|
|
89
|
+
function combineMeasures(kind, children) {
|
|
90
|
+
const depth = 1 + Math.max(0, ...children.map((child) => child.depth));
|
|
91
|
+
const domains = new Set(children.flatMap((child) => [...child.domains]));
|
|
92
|
+
if (kind === 'anyOf')
|
|
93
|
+
return {
|
|
94
|
+
depth,
|
|
95
|
+
edgeCounts: children.flatMap((child) => child.edgeCounts).slice(0, BRANCH_OVERFLOW),
|
|
96
|
+
domains,
|
|
97
|
+
};
|
|
98
|
+
let edgeCounts = [0];
|
|
99
|
+
for (const child of children) {
|
|
100
|
+
const next = [];
|
|
101
|
+
for (const left of edgeCounts) {
|
|
102
|
+
for (const right of child.edgeCounts) {
|
|
103
|
+
next.push(left + right);
|
|
104
|
+
if (next.length >= BRANCH_OVERFLOW)
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
if (next.length >= BRANCH_OVERFLOW)
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
edgeCounts = next;
|
|
111
|
+
}
|
|
112
|
+
return { depth, edgeCounts, domains };
|
|
113
|
+
}
|
|
10
114
|
export function measureChecks(expression) {
|
|
11
115
|
if ('check' in expression || 'sameNode' in expression)
|
|
12
116
|
return { depth: 1, branches: 1, leaves: 1 };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ClassRef, PolicyRef } from '../../../addressing/index.js';
|
|
2
|
+
import type { EdgeContract } from '../../class/model/edge.js';
|
|
3
|
+
import type { PolicyExpression, PolicyObjectRef } from '../model/policy.js';
|
|
4
|
+
import type { CheckLeafClasses } from './checks.js';
|
|
5
|
+
import { type PatternBranch } from './branches.js';
|
|
6
|
+
export type ObjectContract = {
|
|
7
|
+
readonly kind: 'default';
|
|
8
|
+
} | {
|
|
9
|
+
readonly kind: 'exact';
|
|
10
|
+
readonly ref: ClassRef;
|
|
11
|
+
};
|
|
12
|
+
export type PolicyUseContract = {
|
|
13
|
+
readonly kind: 'object';
|
|
14
|
+
readonly object: ObjectContract;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: 'edge';
|
|
17
|
+
readonly source: ObjectContract;
|
|
18
|
+
readonly target: ObjectContract;
|
|
19
|
+
};
|
|
20
|
+
/** What Policy typing reads of the closure it types against: source or compiled admission. */
|
|
21
|
+
export interface PolicyTypingScope {
|
|
22
|
+
readonly normalized: ReadonlyMap<string, PolicyExpression>;
|
|
23
|
+
readonly allNodeClasses: readonly ClassRef[];
|
|
24
|
+
readonly concreteNodeClasses: readonly ClassRef[];
|
|
25
|
+
isLocalPolicy(ref: PolicyRef): boolean;
|
|
26
|
+
/** Whether `candidate` is the `required` Class or a same-kind descendant. */
|
|
27
|
+
classExtends(candidate: ClassRef, required: ClassRef): boolean;
|
|
28
|
+
edgeDeclaration(ref: ClassRef): EdgeContract | undefined;
|
|
29
|
+
/** The contract of a Node a Policy pattern references, `undefined` when it has none. */
|
|
30
|
+
referenceContract(ref: PolicyObjectRef): ObjectContract | undefined;
|
|
31
|
+
}
|
|
32
|
+
export declare class PolicyTyping {
|
|
33
|
+
#private;
|
|
34
|
+
readonly scope: PolicyTypingScope;
|
|
35
|
+
constructor(scope: PolicyTypingScope);
|
|
36
|
+
/** The normalized branches of a named Policy, `undefined` when it does not expand. */
|
|
37
|
+
expandedBranches(name: string, namespace: string): readonly PatternBranch[] | undefined;
|
|
38
|
+
policyAccepts(name: string, object: ObjectContract): boolean;
|
|
39
|
+
/** Whether the Policy accepts every concrete source and target pair the Edge Class accepts. */
|
|
40
|
+
policyAcceptsEdgeClass(name: string, declaration: EdgeContract): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* How a check of the Policy types against each contract of its object, `undefined` when the
|
|
43
|
+
* Policy does not expand or one of its branches is typed for no contract.
|
|
44
|
+
*/
|
|
45
|
+
checkLeafClasses(name: string, contracts: readonly ObjectContract[]): CheckLeafClasses | undefined;
|
|
46
|
+
endpointsOverlap(left: readonly ClassRef[], right: readonly ClassRef[]): boolean;
|
|
47
|
+
branchIsTyped(branch: PatternBranch, use: PolicyUseContract): boolean;
|
|
48
|
+
}
|