@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
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { core as zodCore } from 'zod';
|
|
2
|
+
type JsonSchema = zodCore.JSONSchema.JSONSchema;
|
|
3
|
+
/**
|
|
4
|
+
* The check that a document is portable JSON, which `schema.decode` and `schema.accept` make first.
|
|
5
|
+
* JSON Schema reads a parsed value and compares numbers by their value: it states that no string or
|
|
6
|
+
* member name holds U+0000, and cannot state negative zero, a lone surrogate, a UTF-8 size, a
|
|
7
|
+
* nesting depth without one definition per level, a count of members, or what the text was.
|
|
8
|
+
*/
|
|
9
|
+
export declare const jsonValueRules: {
|
|
10
|
+
readonly 'portable-json': {
|
|
11
|
+
readonly code: 'DV_JSON_VALUE';
|
|
12
|
+
readonly statement: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export type JsonValueRule = keyof typeof jsonValueRules;
|
|
16
|
+
/**
|
|
17
|
+
* Portable JSON in JSON Schema: `root` constrains the whole document, and `definitions` holds every
|
|
18
|
+
* value it reaches and every string. The named check leaves `x-astrale-rule` on `portable-json`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function jsonValueJsonSchema(): {
|
|
21
|
+
readonly root: JsonSchema;
|
|
22
|
+
readonly definitions: Readonly<Record<string, JsonSchema>>;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { RULES } from '../rule.js';
|
|
2
|
+
/**
|
|
3
|
+
* The check that a document is portable JSON, which `schema.decode` and `schema.accept` make first.
|
|
4
|
+
* JSON Schema reads a parsed value and compares numbers by their value: it states that no string or
|
|
5
|
+
* member name holds U+0000, and cannot state negative zero, a lone surrogate, a UTF-8 size, a
|
|
6
|
+
* nesting depth without one definition per level, a count of members, or what the text was.
|
|
7
|
+
*/
|
|
8
|
+
export const jsonValueRules = {
|
|
9
|
+
'portable-json': { code: 'DV_JSON_VALUE', statement: RULES.DV_JSON_VALUE.statement },
|
|
10
|
+
};
|
|
11
|
+
const VALUE = '#/$defs/portable-json';
|
|
12
|
+
const TEXT = '#/$defs/portable-string';
|
|
13
|
+
/**
|
|
14
|
+
* Portable JSON in JSON Schema: `root` constrains the whole document, and `definitions` holds every
|
|
15
|
+
* value it reaches and every string. The named check leaves `x-astrale-rule` on `portable-json`.
|
|
16
|
+
*/
|
|
17
|
+
export function jsonValueJsonSchema() {
|
|
18
|
+
return {
|
|
19
|
+
root: { $ref: VALUE },
|
|
20
|
+
definitions: {
|
|
21
|
+
'portable-json': {
|
|
22
|
+
anyOf: [
|
|
23
|
+
{ type: 'null' },
|
|
24
|
+
{ type: 'boolean' },
|
|
25
|
+
{ type: 'number' },
|
|
26
|
+
{ $ref: TEXT },
|
|
27
|
+
{ type: 'array', items: { $ref: VALUE } },
|
|
28
|
+
{ type: 'object', propertyNames: { $ref: TEXT }, additionalProperties: { $ref: VALUE } },
|
|
29
|
+
],
|
|
30
|
+
'x-astrale-rule': 'portable-json',
|
|
31
|
+
},
|
|
32
|
+
// The pattern is the character itself, which every regular-expression dialect reads.
|
|
33
|
+
'portable-string': { type: 'string', not: { pattern: '\u0000' } },
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { escapePointer } from './context.js';
|
|
1
|
+
import { BRANCH_OVERFLOW, MAX_BRANCHES, MAX_CHECK_DEPTH, MAX_CHECK_LEAVES, MAX_DOMAINS, MAX_EDGES, MAX_PATTERN_DEPTH, MAX_REPEAT, MAX_VARIABLES, measureChecks, policyMeasurer, } from '../../../language/policy/analysis/budgets.js';
|
|
2
|
+
import { escapePointerToken } from '../../../language/value/syntax/pointer.js';
|
|
4
3
|
export { BRANCH_OVERFLOW, MAX_BRANCHES, MAX_CHECK_DEPTH, MAX_CHECK_LEAVES, MAX_DOMAINS, MAX_EDGES, MAX_PATTERN_DEPTH, MAX_REPEAT, MAX_VARIABLES, measureChecks, };
|
|
5
4
|
export function validatePolicyBudgets(context) {
|
|
6
|
-
|
|
7
|
-
// path that reaches it (the only path-sensitive outcome, the back-edge `undefined`, already holds
|
|
8
|
-
// for every node on or reaching a composition cycle, regardless of entry), so caching the
|
|
9
|
-
// completed result by node identity turns path enumeration over the composition DAG into work
|
|
10
|
-
// linear in the number of nodes while preserving the exact measure and PL_BUDGET decision.
|
|
11
|
-
const measures = new Map();
|
|
5
|
+
const measurePolicy = policyMeasurer(context.environment.candidate.origin, context.normalized, (ref) => context.isLocalPolicy(ref));
|
|
12
6
|
for (const name of Object.keys(context.environment.candidate.policies)) {
|
|
13
|
-
const measure = measurePolicy(
|
|
7
|
+
const measure = measurePolicy(name);
|
|
14
8
|
if (measure === undefined)
|
|
15
9
|
continue;
|
|
16
|
-
const pointer = `/policies/${
|
|
10
|
+
const pointer = `/policies/${escapePointerToken(name)}`;
|
|
17
11
|
if (measure.depth > MAX_PATTERN_DEPTH) {
|
|
18
12
|
context.add('PL_BUDGET', pointer, `Expanded Pattern depth ${measure.depth} exceeds ${MAX_PATTERN_DEPTH}.`);
|
|
19
13
|
}
|
|
@@ -29,104 +23,3 @@ export function validatePolicyBudgets(context) {
|
|
|
29
23
|
}
|
|
30
24
|
}
|
|
31
25
|
}
|
|
32
|
-
function measurePolicy(context, name, visiting, measures) {
|
|
33
|
-
if (visiting.has(name))
|
|
34
|
-
return undefined;
|
|
35
|
-
if (measures.has(name))
|
|
36
|
-
return measures.get(name);
|
|
37
|
-
const declaration = context.normalized.get(name);
|
|
38
|
-
if (declaration === undefined)
|
|
39
|
-
return undefined;
|
|
40
|
-
const nested = new Set(visiting);
|
|
41
|
-
nested.add(name);
|
|
42
|
-
const measure = measureDeclaration(context, declaration, nested, measures);
|
|
43
|
-
measures.set(name, measure);
|
|
44
|
-
return measure;
|
|
45
|
-
}
|
|
46
|
-
function measureDeclaration(context, declaration, nested, measures) {
|
|
47
|
-
if ('match' in declaration) {
|
|
48
|
-
return measurePattern(declaration.match, context.environment.candidate.origin);
|
|
49
|
-
}
|
|
50
|
-
const refs = 'allOf' in declaration ? declaration.allOf : declaration.anyOf;
|
|
51
|
-
const children = refs.flatMap((ref) => {
|
|
52
|
-
if (!context.isLocalPolicy(ref))
|
|
53
|
-
return [];
|
|
54
|
-
const value = measurePolicy(context, ref.name, nested, measures);
|
|
55
|
-
return value === undefined ? [] : [value];
|
|
56
|
-
});
|
|
57
|
-
if (children.length !== refs.length || children.length === 0)
|
|
58
|
-
return undefined;
|
|
59
|
-
return combineMeasures('allOf' in declaration ? 'allOf' : 'anyOf', children);
|
|
60
|
-
}
|
|
61
|
-
function measurePattern(pattern, ownOrigin) {
|
|
62
|
-
if ('sameNode' in pattern)
|
|
63
|
-
return {
|
|
64
|
-
depth: 1,
|
|
65
|
-
edgeCounts: [1],
|
|
66
|
-
domains: new Set([
|
|
67
|
-
ownOrigin,
|
|
68
|
-
...[pattern.sameNode.left, pattern.sameNode.right].flatMap((term) => term.kind === 'ref' ? [policyObjectOrigin(term.ref)] : []),
|
|
69
|
-
]),
|
|
70
|
-
};
|
|
71
|
-
if (isEdge(pattern)) {
|
|
72
|
-
return {
|
|
73
|
-
depth: 1,
|
|
74
|
-
edgeCounts: [1],
|
|
75
|
-
domains: new Set([
|
|
76
|
-
ownOrigin,
|
|
77
|
-
pattern.class.origin,
|
|
78
|
-
...[pattern.source, pattern.target].flatMap((term) => term.kind === 'ref' ? [policyObjectOrigin(term.ref)] : []),
|
|
79
|
-
]),
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
if ('exists' in pattern) {
|
|
83
|
-
const child = measurePattern(pattern.exists.where, ownOrigin);
|
|
84
|
-
return {
|
|
85
|
-
depth: child.depth + 1,
|
|
86
|
-
edgeCounts: child.edgeCounts,
|
|
87
|
-
domains: new Set([
|
|
88
|
-
...child.domains,
|
|
89
|
-
...pattern.exists.nodes.flatMap((node) => {
|
|
90
|
-
const ref = policyVariableClass(node);
|
|
91
|
-
return ref === undefined ? [] : [ref.origin];
|
|
92
|
-
}),
|
|
93
|
-
]),
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
const { key, values } = patternOperands(pattern);
|
|
97
|
-
return combineMeasures(key, values.map((child) => measurePattern(child, ownOrigin)));
|
|
98
|
-
}
|
|
99
|
-
function combineMeasures(key, children) {
|
|
100
|
-
const depth = 1 + Math.max(0, ...children.map((child) => child.depth));
|
|
101
|
-
const domains = new Set(children.flatMap((child) => [...child.domains]));
|
|
102
|
-
if (key === 'anyOf') {
|
|
103
|
-
return {
|
|
104
|
-
depth,
|
|
105
|
-
edgeCounts: children.flatMap((child) => child.edgeCounts).slice(0, BRANCH_OVERFLOW),
|
|
106
|
-
domains,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
let edgeCounts = [0];
|
|
110
|
-
for (const child of children) {
|
|
111
|
-
const next = [];
|
|
112
|
-
for (const left of edgeCounts) {
|
|
113
|
-
for (const right of child.edgeCounts) {
|
|
114
|
-
next.push(left + right);
|
|
115
|
-
if (next.length >= BRANCH_OVERFLOW)
|
|
116
|
-
break;
|
|
117
|
-
}
|
|
118
|
-
if (next.length >= BRANCH_OVERFLOW)
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
edgeCounts = next;
|
|
122
|
-
}
|
|
123
|
-
return { depth, edgeCounts, domains };
|
|
124
|
-
}
|
|
125
|
-
function patternOperands(value) {
|
|
126
|
-
return 'allOf' in value
|
|
127
|
-
? { key: 'allOf', values: value.allOf }
|
|
128
|
-
: { key: 'anyOf', values: value.anyOf };
|
|
129
|
-
}
|
|
130
|
-
function isEdge(value) {
|
|
131
|
-
return 'source' in value;
|
|
132
|
-
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { ClassDefinition } from '../../../language/class/model/class.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ObjectContract, PolicyTypingScope } from '../../../language/policy/analysis/typing.js';
|
|
3
|
+
import type { PolicyExpression, PolicyObjectRef } from '../../../language/policy/model/policy.js';
|
|
3
4
|
import type { DefinitionAnalysisResult } from '../../analysis/class.js';
|
|
4
5
|
import type { SchemaDiagnostic, SchemaDiagnosticCode } from '../../diagnostic.js';
|
|
5
6
|
import type { DomainResolutionContext } from '../../resolution/context.js';
|
|
6
7
|
import type { IndexedClassDefinition } from '../../resolution/definition.index.js';
|
|
7
8
|
import { type ClassRef, type PolicyRef } from '../../../addressing/index.js';
|
|
8
|
-
export declare class PolicyValidationContext {
|
|
9
|
+
export declare class PolicyValidationContext implements PolicyTypingScope {
|
|
9
10
|
#private;
|
|
10
11
|
readonly environment: DomainResolutionContext;
|
|
11
12
|
readonly analysis: DefinitionAnalysisResult;
|
|
@@ -23,6 +24,7 @@ export declare class PolicyValidationContext {
|
|
|
23
24
|
}> | undefined;
|
|
24
25
|
/** Return true when candidate is the required Class or a same-kind descendant. */
|
|
25
26
|
classExtends(candidate: ClassRef, required: ClassRef): boolean;
|
|
27
|
+
/** The contract a Policy pattern reference types, reporting an invalid one under `/policies`. */
|
|
28
|
+
referenceContract(ref: PolicyObjectRef): ObjectContract | undefined;
|
|
26
29
|
add(code: SchemaDiagnosticCode, pointer: string, message: string, ref?: string): void;
|
|
27
30
|
}
|
|
28
|
-
export declare function escapePointer(value: string): string;
|
|
@@ -2,6 +2,7 @@ import { Key } from '../../../addressing/index.js';
|
|
|
2
2
|
import { definitionRefIndex } from '../../../addressing/ordering.js';
|
|
3
3
|
import { classSatisfies } from '../../../language/class/inheritance.js';
|
|
4
4
|
import { diagnostic } from '../../diagnostic.js';
|
|
5
|
+
import { referenceContracts } from './objects.js';
|
|
5
6
|
const formatDefinitionRef = Key.of;
|
|
6
7
|
export class PolicyValidationContext {
|
|
7
8
|
environment;
|
|
@@ -69,10 +70,11 @@ export class PolicyValidationContext {
|
|
|
69
70
|
const target = resolve(required);
|
|
70
71
|
return actual !== undefined && target !== undefined && classSatisfies(actual, target, resolve);
|
|
71
72
|
}
|
|
73
|
+
/** The contract a Policy pattern reference types, reporting an invalid one under `/policies`. */
|
|
74
|
+
referenceContract(ref) {
|
|
75
|
+
return referenceContracts(this, ref, '/policies')?.[0];
|
|
76
|
+
}
|
|
72
77
|
add(code, pointer, message, ref) {
|
|
73
78
|
this.diagnostics.push(diagnostic(code, pointer, message, ref));
|
|
74
79
|
}
|
|
75
80
|
}
|
|
76
|
-
export function escapePointer(value) {
|
|
77
|
-
return value.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
78
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { PolicyObjectRef } from '../../../language/index.js';
|
|
2
|
+
import type { ObjectContract } from '../../../language/policy/analysis/typing.js';
|
|
2
3
|
import type { PolicyValidationContext } from './context.js';
|
|
3
|
-
import type { ObjectContract } from './typing.js';
|
|
4
4
|
export declare function referenceContracts(validation: PolicyValidationContext, ref: PolicyObjectRef, pointer: string): readonly ObjectContract[] | undefined;
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { definitionRefIndex } from '../../../addressing/ordering.js';
|
|
2
2
|
import { isMethodExecutable } from '../../../language/callable/executable.js';
|
|
3
|
-
import { policyObjectKey, policyObjectOrigin } from '../../../language/index.js';
|
|
4
|
-
const KERNEL_ORIGIN = 'kernel.astrale.ai';
|
|
5
|
-
const PROJECTION_CLASS = nodeClassRef('Class');
|
|
6
|
-
const PROJECTION_FUNCTION = nodeClassRef('Function');
|
|
7
|
-
const PROJECTION_POLICY = nodeClassRef('Policy');
|
|
8
|
-
const PROJECTION_VIEW = nodeClassRef('View');
|
|
3
|
+
import { policyObjectKey, policyObjectOrigin, projectedMemberClass, } from '../../../language/index.js';
|
|
9
4
|
export function referenceContracts(validation, ref, pointer) {
|
|
10
5
|
const candidate = validation.environment.candidate;
|
|
11
6
|
const local = policyObjectOrigin(ref) === candidate.origin;
|
|
@@ -21,7 +16,7 @@ export function referenceContracts(validation, ref, pointer) {
|
|
|
21
16
|
case 'class': {
|
|
22
17
|
const resolved = validation.environment.resolve(ref);
|
|
23
18
|
return resolved?.ref.kind === ref.kind
|
|
24
|
-
? [{ kind: 'exact', ref:
|
|
19
|
+
? [{ kind: 'exact', ref: projectedMemberClass(ref) }]
|
|
25
20
|
: invalidPolicyObjectRef(validation, ref, pointer);
|
|
26
21
|
}
|
|
27
22
|
case 'method': {
|
|
@@ -29,20 +24,20 @@ export function referenceContracts(validation, ref, pointer) {
|
|
|
29
24
|
const method = declaringClass?.kind === 'node' ? declaringClass.methods[ref.name] : undefined;
|
|
30
25
|
return method === undefined || !isMethodExecutable(declaringClass, method)
|
|
31
26
|
? invalidPolicyObjectRef(validation, ref, pointer)
|
|
32
|
-
: [{ kind: 'exact', ref:
|
|
27
|
+
: [{ kind: 'exact', ref: projectedMemberClass(ref) }];
|
|
33
28
|
}
|
|
34
29
|
case 'function':
|
|
35
30
|
return owner.functions[ref.name] === undefined
|
|
36
31
|
? invalidPolicyObjectRef(validation, ref, pointer)
|
|
37
|
-
: [{ kind: 'exact', ref:
|
|
32
|
+
: [{ kind: 'exact', ref: projectedMemberClass(ref) }];
|
|
38
33
|
case 'policy':
|
|
39
34
|
return owner.policies[ref.name] === undefined
|
|
40
35
|
? invalidPolicyObjectRef(validation, ref, pointer)
|
|
41
|
-
: [{ kind: 'exact', ref:
|
|
36
|
+
: [{ kind: 'exact', ref: projectedMemberClass(ref) }];
|
|
42
37
|
case 'view':
|
|
43
38
|
return owner.views[ref.name] === undefined
|
|
44
39
|
? invalidPolicyObjectRef(validation, ref, pointer)
|
|
45
|
-
: [{ kind: 'exact', ref:
|
|
40
|
+
: [{ kind: 'exact', ref: projectedMemberClass(ref) }];
|
|
46
41
|
case 'core': {
|
|
47
42
|
const node = owner.core.nodes[ref.name];
|
|
48
43
|
if (node === undefined)
|
|
@@ -66,6 +61,3 @@ function invalidPolicyObjectRef(validation, ref, pointer) {
|
|
|
66
61
|
validation.add('PL_REF', `${pointer}/ref`, `${policyObjectKey(ref)} is not an exact local or direct-dependency projected Policy object.`, policyObjectKey(ref));
|
|
67
62
|
return undefined;
|
|
68
63
|
}
|
|
69
|
-
function nodeClassRef(name) {
|
|
70
|
-
return { origin: KERNEL_ORIGIN, kind: 'class', name };
|
|
71
|
-
}
|
|
@@ -1,24 +1,22 @@
|
|
|
1
|
+
import { equalDefinitionRefs } from '../../../addressing/definition-ref.js';
|
|
1
2
|
import { branchesOf, isConnected, targetMode } from '../../../language/policy/analysis/branches.js';
|
|
2
3
|
import { policyVariableClass } from '../../../language/policy/model/policy.js';
|
|
3
4
|
import { normalizePolicyExpression, normalizePolicyPattern, } from '../../../language/policy/normalization/normalize.js';
|
|
4
|
-
import {
|
|
5
|
-
import { escapePointer } from './context.js';
|
|
5
|
+
import { escapePointerToken } from '../../../language/value/syntax/pointer.js';
|
|
6
6
|
import { referenceContracts } from './objects.js';
|
|
7
7
|
export function validatePolicyReferences(context) {
|
|
8
8
|
for (const [name, declaration] of Object.entries(context.environment.candidate.policies)) {
|
|
9
|
-
const pointer = `/policies/${
|
|
9
|
+
const pointer = `/policies/${escapePointerToken(name)}`;
|
|
10
10
|
const expected = { origin: context.environment.candidate.origin, kind: 'policy', name };
|
|
11
|
-
if (declaration.ref
|
|
12
|
-
declaration.ref.kind !== expected.kind ||
|
|
13
|
-
declaration.ref.name !== expected.name) {
|
|
11
|
+
if (!equalDefinitionRefs(declaration.ref, expected)) {
|
|
14
12
|
context.add('DV_REF_RESOLVES', `${pointer}/ref`, `Policy ref must be exactly ${expected.origin}:policy.${expected.name}.`);
|
|
15
13
|
}
|
|
16
14
|
const expression = declaration.expression;
|
|
17
15
|
context.normalized.set(name, normalizePolicyExpression(expression));
|
|
18
16
|
if ('match' in expression)
|
|
19
|
-
validateMatch(context, name, expression.match, pointer);
|
|
17
|
+
validateMatch(context, name, expression.match, `${pointer}/expression`);
|
|
20
18
|
else
|
|
21
|
-
validateComposition(context, expression, pointer);
|
|
19
|
+
validateComposition(context, expression, `${pointer}/expression`);
|
|
22
20
|
}
|
|
23
21
|
validateCycles(context);
|
|
24
22
|
}
|
|
@@ -54,22 +52,13 @@ function validatePatternNode(context, pattern, pointer, scope, declarations, use
|
|
|
54
52
|
context.resolveEdge(pattern.class, `${pointer}/class`);
|
|
55
53
|
validateTerm(context, pattern.source, `${pointer}/source`, scope, uses);
|
|
56
54
|
validateTerm(context, pattern.target, `${pointer}/target`, scope, uses);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
!Number.isInteger(max) ||
|
|
61
|
-
min < 0 ||
|
|
62
|
-
max < min ||
|
|
63
|
-
max > MAX_REPEAT) {
|
|
64
|
-
context.add('PL_REPEAT', `${pointer}/repeat`, `Repeat requires integral bounds 0 <= min <= max <= ${MAX_REPEAT}.`);
|
|
65
|
-
}
|
|
55
|
+
// The structure bounds each to an integer from 0 to MAX_REPEAT; only their order is left.
|
|
56
|
+
if (pattern.repeat !== undefined && pattern.repeat.max < pattern.repeat.min) {
|
|
57
|
+
context.add('PL_REPEAT', `${pointer}/repeat`, 'Repeat requires min <= max.');
|
|
66
58
|
}
|
|
67
59
|
return;
|
|
68
60
|
}
|
|
69
61
|
if ('exists' in pattern) {
|
|
70
|
-
if (pattern.exists.nodes.length > MAX_VARIABLES) {
|
|
71
|
-
context.add('PL_BUDGET', `${pointer}/exists/nodes`, `An exists expression declares ${pattern.exists.nodes.length} variables; the maximum is ${MAX_VARIABLES}.`);
|
|
72
|
-
}
|
|
73
62
|
const nested = new Set(scope);
|
|
74
63
|
for (const [index, node] of pattern.exists.nodes.entries()) {
|
|
75
64
|
const id = node.variable.id;
|
|
@@ -93,9 +82,6 @@ function validatePatternNode(context, pattern, pointer, scope, declarations, use
|
|
|
93
82
|
return;
|
|
94
83
|
}
|
|
95
84
|
const { key, values } = patternOperands(pattern);
|
|
96
|
-
if (values.length === 0) {
|
|
97
|
-
context.add('PL_COMPOSITION', `${pointer}/${key}`, `${key} must be non-empty.`);
|
|
98
|
-
}
|
|
99
85
|
values.forEach((child, index) => validatePatternNode(context, child, `${pointer}/${key}/${index}`, scope, declarations, uses));
|
|
100
86
|
}
|
|
101
87
|
function validateTerm(context, term, pointer, scope, uses) {
|
|
@@ -113,9 +99,6 @@ function validateTerm(context, term, pointer, scope, uses) {
|
|
|
113
99
|
function validateComposition(context, declaration, pointer) {
|
|
114
100
|
const key = 'allOf' in declaration ? 'allOf' : 'anyOf';
|
|
115
101
|
const refs = 'allOf' in declaration ? declaration.allOf : declaration.anyOf;
|
|
116
|
-
if (refs.length === 0) {
|
|
117
|
-
context.add('PL_COMPOSITION', `${pointer}/${key}`, `${key} must be non-empty.`);
|
|
118
|
-
}
|
|
119
102
|
refs.forEach((ref, index) => context.resolvePolicy(ref, `${pointer}/${key}/${index}`));
|
|
120
103
|
}
|
|
121
104
|
function validateCycles(context) {
|
|
@@ -123,7 +106,7 @@ function validateCycles(context) {
|
|
|
123
106
|
const visited = new Set();
|
|
124
107
|
const visit = (name, stack) => {
|
|
125
108
|
if (visiting.has(name)) {
|
|
126
|
-
context.add('PL_COMPOSITION', `/policies/${
|
|
109
|
+
context.add('PL_COMPOSITION', `/policies/${escapePointerToken(name)}`, `Named Policy composition cycle: ${[...stack, name].join(' -> ')}.`);
|
|
127
110
|
return;
|
|
128
111
|
}
|
|
129
112
|
if (visited.has(name))
|
|
@@ -1,21 +1,6 @@
|
|
|
1
1
|
import type { ClassRef } from '../../../addressing/index.js';
|
|
2
|
+
import type { ObjectContract, PolicyTyping } from '../../../language/policy/analysis/typing.js';
|
|
2
3
|
import type { PolicyValidationContext } from './context.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} | {
|
|
6
|
-
readonly kind: 'exact';
|
|
7
|
-
readonly ref: ClassRef;
|
|
8
|
-
};
|
|
9
|
-
export declare class PolicyTyping {
|
|
10
|
-
#private;
|
|
11
|
-
readonly context: PolicyValidationContext;
|
|
12
|
-
constructor(context: PolicyValidationContext);
|
|
13
|
-
validatePolicies(): void;
|
|
14
|
-
policyAccepts(name: string, object: ObjectContract): boolean;
|
|
15
|
-
/** Whether each normalized branch of the Policy is typed for an object of this contract. */
|
|
16
|
-
policyBranchTyping(name: string, object: ObjectContract): readonly boolean[] | undefined;
|
|
17
|
-
policyAcceptsEdge(name: string, source: ObjectContract, target: ObjectContract): boolean;
|
|
18
|
-
concreteEndpointClasses(accepts: readonly ClassRef[]): readonly ClassRef[];
|
|
19
|
-
endpointsOverlap(left: readonly ClassRef[], right: readonly ClassRef[]): boolean;
|
|
20
|
-
}
|
|
4
|
+
/** Type every expanded branch of each named Policy at its own default use. */
|
|
5
|
+
export declare function validatePolicyTyping(context: PolicyValidationContext, typing: PolicyTyping): void;
|
|
21
6
|
export declare function contractOfNodeDefinition(ref: ClassRef): ObjectContract;
|