@astrale-os/kernel-dsl 1.0.0-beta.12 → 1.0.0-beta.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/dist/v1/addressing/definition-ref.js +21 -37
  2. package/dist/v1/addressing/ordering.d.ts +2 -0
  3. package/dist/v1/addressing/ordering.js +4 -0
  4. package/dist/v1/addressing/patterns.d.ts +0 -1
  5. package/dist/v1/addressing/patterns.js +0 -5
  6. package/dist/v1/builder/class/authoring.js +5 -28
  7. package/dist/v1/builder/lowering/schema/context.js +2 -4
  8. package/dist/v1/builder/lowering/value/path.js +2 -4
  9. package/dist/v1/builder/lowering/value/zod.js +1 -3
  10. package/dist/v1/builder/schema/define.d.ts +0 -1
  11. package/dist/v1/builder/schema/diagnostic.d.ts +2 -1
  12. package/dist/v1/builder/schema/diagnostic.js +5 -10
  13. package/dist/v1/builder/schema/projection.d.ts +1 -1
  14. package/dist/v1/builder/value/full-match.d.ts +0 -1
  15. package/dist/v1/builder/value/full-match.js +0 -1
  16. package/dist/v1/bundle/codec.js +2 -4
  17. package/dist/v1/bundle/diagnostic.js +3 -7
  18. package/dist/v1/bundle/structure.js +2 -4
  19. package/dist/v1/compiled/admission/diagnostic.d.ts +1 -1
  20. package/dist/v1/compiled/admission/diagnostic.js +1 -3
  21. package/dist/v1/compiled/admission/revision.d.ts +9 -1
  22. package/dist/v1/compiled/admission/revision.js +6 -3
  23. package/dist/v1/compiled/admission/semantics/class.d.ts +4 -1
  24. package/dist/v1/compiled/admission/semantics/class.js +4 -8
  25. package/dist/v1/compiled/admission/semantics/core.d.ts +1 -24
  26. package/dist/v1/compiled/admission/semantics/core.js +54 -34
  27. package/dist/v1/compiled/admission/semantics/edge.d.ts +2 -4
  28. package/dist/v1/compiled/admission/semantics/edge.js +6 -65
  29. package/dist/v1/compiled/admission/semantics/policy/callable.js +0 -2
  30. package/dist/v1/compiled/admission/semantics/policy/contracts.d.ts +5 -20
  31. package/dist/v1/compiled/admission/semantics/policy/contracts.js +8 -21
  32. package/dist/v1/compiled/admission/semantics/policy/parity.js +13 -22
  33. package/dist/v1/compiled/admission/semantics/policy/pattern.d.ts +4 -1
  34. package/dist/v1/compiled/admission/semantics/policy/pattern.js +4 -16
  35. package/dist/v1/compiled/admission/semantics/policy/typing.d.ts +2 -24
  36. package/dist/v1/compiled/admission/semantics/policy/typing.js +19 -201
  37. package/dist/v1/compiled/compiler/compile.js +6 -8
  38. package/dist/v1/compiled/diagnostic.js +2 -3
  39. package/dist/v1/compiled/loader/load.d.ts +3 -2
  40. package/dist/v1/compiled/loader/load.js +10 -44
  41. package/dist/v1/domain/create.js +3 -5
  42. package/dist/v1/domain/namespace/member-collection.js +4 -6
  43. package/dist/v1/domain/validation/create.d.ts +0 -1
  44. package/dist/v1/domain/validation/create.js +0 -35
  45. package/dist/v1/language/class/inheritance.d.ts +18 -0
  46. package/dist/v1/language/class/inheritance.js +73 -0
  47. package/dist/v1/language/class/property-values.js +2 -4
  48. package/dist/v1/language/core/facts.d.ts +72 -0
  49. package/dist/v1/language/core/facts.js +95 -0
  50. package/dist/v1/language/policy/analysis/branches.d.ts +8 -0
  51. package/dist/v1/language/policy/analysis/branches.js +2 -1
  52. package/dist/v1/language/policy/analysis/budgets.d.ts +13 -1
  53. package/dist/v1/language/policy/analysis/budgets.js +104 -0
  54. package/dist/v1/language/policy/analysis/typing.d.ts +48 -0
  55. package/dist/v1/language/policy/analysis/typing.js +338 -0
  56. package/dist/v1/language/validation/diagnostic.d.ts +14 -0
  57. package/dist/v1/language/validation/diagnostic.js +21 -0
  58. package/dist/v1/language/value/compile/fields.js +4 -8
  59. package/dist/v1/language/value/profile/rules.js +5 -7
  60. package/dist/v1/language/value/profile/validate.js +1 -10
  61. package/dist/v1/language/value/reference/recursion.js +2 -22
  62. package/dist/v1/language/value/syntax/pointer.d.ts +2 -0
  63. package/dist/v1/language/value/syntax/pointer.js +5 -2
  64. package/dist/v1/language/value/syntax/walk.d.ts +2 -0
  65. package/dist/v1/language/value/syntax/walk.js +19 -20
  66. package/dist/v1/schema/compatibility/diff.js +2 -4
  67. package/dist/v1/schema/compatibility/meaning/footprint.js +16 -50
  68. package/dist/v1/schema/compatibility/structure/requirements.js +26 -58
  69. package/dist/v1/schema/compatibility/walk.d.ts +17 -0
  70. package/dist/v1/schema/compatibility/walk.js +41 -0
  71. package/dist/v1/schema/diagnostic.js +3 -11
  72. package/dist/v1/schema/resolution/context.js +3 -5
  73. package/dist/v1/schema/validation/callable.js +3 -5
  74. package/dist/v1/schema/validation/class.js +10 -52
  75. package/dist/v1/schema/validation/core.js +65 -199
  76. package/dist/v1/schema/validation/domain.js +1 -10
  77. package/dist/v1/schema/validation/domain.structure.js +2 -4
  78. package/dist/v1/schema/validation/policy/budgets.js +5 -112
  79. package/dist/v1/schema/validation/policy/context.d.ts +5 -3
  80. package/dist/v1/schema/validation/policy/context.js +5 -3
  81. package/dist/v1/schema/validation/policy/objects.d.ts +1 -1
  82. package/dist/v1/schema/validation/policy/objects.js +6 -14
  83. package/dist/v1/schema/validation/policy/references.js +5 -6
  84. package/dist/v1/schema/validation/policy/typing.d.ts +3 -18
  85. package/dist/v1/schema/validation/policy/typing.js +22 -356
  86. package/dist/v1/schema/validation/policy/uses.d.ts +1 -1
  87. package/dist/v1/schema/validation/policy/uses.js +9 -22
  88. package/dist/v1/schema/validation/policy/validate.js +3 -2
  89. package/dist/v1/schema/validation/value-api.js +2 -2
  90. package/dist/v1/schema/validation/value.js +5 -7
  91. package/dist/v1/schema/validation/view.js +4 -8
  92. package/package.json +1 -1
  93. package/dist/v1/compiled/admission/semantics/cardinality.d.ts +0 -5
  94. package/dist/v1/compiled/admission/semantics/cardinality.js +0 -128
  95. package/dist/v1/compiled/admission/semantics/policy/equality.d.ts +0 -8
  96. package/dist/v1/compiled/admission/semantics/policy/equality.js +0 -27
  97. package/dist/v1/compiled/admission/semantics/policy/measure.d.ts +0 -9
  98. package/dist/v1/compiled/admission/semantics/policy/measure.js +0 -81
  99. package/dist/v1/compiled/admission/semantics/policy/variants.d.ts +0 -10
  100. package/dist/v1/compiled/admission/semantics/policy/variants.js +0 -65
  101. package/dist/v1/language/class/index.d.ts +0 -8
  102. package/dist/v1/language/class/index.js +0 -1
  103. package/dist/v1/language/core/index.d.ts +0 -2
  104. package/dist/v1/language/core/index.js +0 -1
  105. package/dist/v1/language/value/index.d.ts +0 -11
  106. package/dist/v1/language/value/index.js +0 -8
@@ -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,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
- class UnionFind {
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 { PolicyCheckExpression } from '../model/policy.js';
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
+ }