@astrale-os/kernel-dsl 1.0.0-beta.16 → 1.0.0-beta.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/v1/builder/class/authoring.js +3 -2
- package/dist/v1/builder/class/input.d.ts +45 -14
- package/dist/v1/builder/index.d.ts +2 -1
- package/dist/v1/builder/lowering/class.d.ts +8 -0
- package/dist/v1/builder/lowering/class.js +40 -16
- package/dist/v1/builder/lowering/schema/compile.js +3 -3
- package/dist/v1/builder/policy/authoring.js +97 -88
- package/dist/v1/bundle/model.js +1 -1
- package/dist/v1/compiled/admission/accept.js +1 -7
- package/dist/v1/compiled/admission/semantics/class.js +2 -3
- package/dist/v1/compiled/admission/semantics/policy/parity.js +25 -13
- package/dist/v1/compiled/admission/wire/class.js +23 -18
- package/dist/v1/compiled/admission/wire/policy.d.ts +4 -3
- package/dist/v1/compiled/admission/wire/policy.js +8 -7
- package/dist/v1/compiled/loader/load.js +1 -1
- package/dist/v1/domain/create.js +1 -1
- package/dist/v1/domain/model/input.d.ts +2 -1
- package/dist/v1/domain/projection/classes.js +1 -1
- package/dist/v1/domain/validation/create.d.ts +2 -1
- package/dist/v1/domain/validation/create.js +1 -1
- package/dist/v1/index.d.ts +1 -1
- package/dist/v1/language/callable/resolved.d.ts +11 -2
- package/dist/v1/language/class/model/class.d.ts +17 -5
- package/dist/v1/language/freeze.d.ts +5 -0
- package/dist/v1/{schema/canonical → language}/freeze.js +4 -0
- package/dist/v1/language/policy/analysis/typing.d.ts +1 -0
- package/dist/v1/language/policy/analysis/typing.js +74 -79
- package/dist/v1/language/policy/model/policy.d.ts +44 -4
- package/dist/v1/language/policy/model/policy.js +14 -0
- package/dist/v1/language/policy/normalization/normalize.d.ts +6 -6
- package/dist/v1/language/policy/normalization/normalize.js +5 -5
- package/dist/v1/language/validation/rule.d.ts +18 -8
- package/dist/v1/language/validation/rule.js +2 -11
- package/dist/v1/language/value/evaluate/program.d.ts +2 -1
- package/dist/v1/language/value/evaluate/program.js +2 -2
- package/dist/v1/language/value/evaluate/validate.d.ts +2 -2
- package/dist/v1/language/value/evaluate/validate.js +2 -2
- package/dist/v1/language/value/profile/json.validate.d.ts +3 -1
- package/dist/v1/language/value/profile/json.validate.js +3 -2
- package/dist/v1/schema/.spec/schemas/domain-schema.schema.json +180 -25
- package/dist/v1/schema/admission/callable.js +1 -1
- package/dist/v1/schema/canonical/revision.js +4 -4
- package/dist/v1/schema/compatibility/comparators/callables.js +1 -1
- package/dist/v1/schema/compatibility/comparators/classes.js +4 -4
- package/dist/v1/schema/compatibility/comparators/members.js +1 -1
- package/dist/v1/schema/compatibility/comparators/values.js +2 -2
- package/dist/v1/schema/compatibility/report.js +1 -1
- package/dist/v1/schema/compatibility/versioning/index.js +1 -1
- package/dist/v1/schema/model/schema.js +1 -1
- package/dist/v1/schema/normalization/domain.js +9 -8
- package/dist/v1/schema/resolution/domain.js +1 -1
- package/dist/v1/schema/resolution/origins.js +3 -2
- package/dist/v1/schema/rule.d.ts +8 -20
- package/dist/v1/schema/rule.js +1 -1
- package/dist/v1/schema/validation/class.js +2 -3
- package/dist/v1/schema/validation/domain.json-schema.d.ts +2 -2
- package/dist/v1/schema/validation/domain.json-schema.js +20 -6
- package/dist/v1/schema/validation/domain.structure.d.ts +4765 -1005
- package/dist/v1/schema/validation/domain.structure.js +21 -9
- package/dist/v1/schema/validation/json.json-schema.d.ts +18 -2
- package/dist/v1/schema/validation/json.json-schema.js +14 -4
- package/dist/v1/schema/validation/policy/budgets.d.ts +1 -1
- package/dist/v1/schema/validation/policy/budgets.js +4 -4
- package/dist/v1/schema/validation/policy/uses.d.ts +10 -2
- package/dist/v1/schema/validation/policy/uses.js +26 -13
- package/dist/v1/schema/validation/policy/validate.js +2 -3
- package/dist/v1/schema/validation/value.json-schema.d.ts +4 -6
- package/dist/v1/schema/validation/value.json-schema.js +18 -25
- package/package.json +1 -1
- package/dist/v1/schema/canonical/domain.d.ts +0 -3
- package/dist/v1/schema/canonical/domain.digest.d.ts +0 -3
- package/dist/v1/schema/canonical/domain.digest.js +0 -5
- package/dist/v1/schema/canonical/domain.js +0 -5
- package/dist/v1/schema/canonical/freeze.d.ts +0 -1
|
@@ -277,7 +277,7 @@ const policyCheckObjectSchema = discriminatedUnion('kind', [
|
|
|
277
277
|
}),
|
|
278
278
|
refObjectSchema,
|
|
279
279
|
]).register(documentJsonSchema, { id: 'policy-check-object' });
|
|
280
|
-
/** A
|
|
280
|
+
/** A Class rule checks the observed or written instance or one exact member: it has no input. */
|
|
281
281
|
const classRuleObjectSchema = discriminatedUnion('kind', [
|
|
282
282
|
selfObjectSchema,
|
|
283
283
|
refObjectSchema,
|
|
@@ -294,6 +294,8 @@ function policyChecksSchema(objectSchema, id) {
|
|
|
294
294
|
}
|
|
295
295
|
const policyCheckExpressionSchema = policyChecksSchema(policyCheckObjectSchema, 'policy-check-expr');
|
|
296
296
|
const classRuleChecksSchema = policyChecksSchema(classRuleObjectSchema, 'class-rule-check-expr');
|
|
297
|
+
/** A Node create rule has no Node to check yet: its objects are exact members only. */
|
|
298
|
+
const createRuleChecksSchema = policyChecksSchema(refObjectSchema, 'create-rule-check-expr');
|
|
297
299
|
const callableOutputSchema = discriminatedUnion('mode', [
|
|
298
300
|
strictObject({
|
|
299
301
|
mode: literal('value'),
|
|
@@ -353,17 +355,27 @@ const methodDeclarationSchema = strictObject({
|
|
|
353
355
|
const methodRecordSchema = record(memberNameSchema, methodDeclarationSchema).register(documentJsonSchema, {
|
|
354
356
|
id: 'method-record',
|
|
355
357
|
});
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
358
|
+
// Each slot spells one constant: the other one is what its absence already means.
|
|
359
|
+
const observationPolicySchema = union([
|
|
360
|
+
literal(false),
|
|
361
|
+
policyRefSchema,
|
|
362
|
+
classRuleChecksSchema,
|
|
363
|
+
]).register(documentJsonSchema, { id: 'observation-policy' });
|
|
364
|
+
const writePolicySchema = union([literal(true), policyRefSchema, classRuleChecksSchema]).register(documentJsonSchema, { id: 'write-policy' });
|
|
365
|
+
const createPolicySchema = union([literal(true), createRuleChecksSchema]).register(documentJsonSchema, { id: 'create-policy' });
|
|
360
366
|
const nodeClassPoliciesSchema = strictObject({
|
|
361
|
-
read:
|
|
362
|
-
traverse:
|
|
367
|
+
read: observationPolicySchema.optional(),
|
|
368
|
+
traverse: observationPolicySchema.optional(),
|
|
369
|
+
create: createPolicySchema.optional(),
|
|
370
|
+
update: writePolicySchema.optional(),
|
|
371
|
+
delete: writePolicySchema.optional(),
|
|
363
372
|
});
|
|
364
373
|
const edgeClassPoliciesSchema = strictObject({
|
|
365
|
-
read:
|
|
366
|
-
traverse:
|
|
374
|
+
read: observationPolicySchema.optional(),
|
|
375
|
+
traverse: observationPolicySchema.optional(),
|
|
376
|
+
create: writePolicySchema.optional(),
|
|
377
|
+
update: writePolicySchema.optional(),
|
|
378
|
+
delete: writePolicySchema.optional(),
|
|
367
379
|
});
|
|
368
380
|
// The default `'internal'` is the absence of the field: one spelling per meaning, one revision.
|
|
369
381
|
const inheritanceSchema = enumeration(['open', 'final']);
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
import type { core as zodCore } from 'zod';
|
|
2
|
-
type
|
|
2
|
+
import type { DiagnosticCode as ValueDiagnosticCode } from '../../language/validation/diagnostic.js';
|
|
3
|
+
import type { SchemaDiagnosticCode } from '../diagnostic.js';
|
|
4
|
+
/** A JSON Schema of the published document, or a part of one. */
|
|
5
|
+
export type JsonSchema = zodCore.JSONSchema.JSONSchema;
|
|
6
|
+
/**
|
|
7
|
+
* A check JSON Schema cannot state, which the published document names: the code the Kernel
|
|
8
|
+
* reports, with its value code for a check on value schemas, and the rule in one plain sentence.
|
|
9
|
+
*/
|
|
10
|
+
export interface NamedRuleEntry {
|
|
11
|
+
readonly code: SchemaDiagnosticCode;
|
|
12
|
+
readonly valueCode?: ValueDiagnosticCode;
|
|
13
|
+
readonly statement: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* `schema` with the `x-astrale-rule` marker naming the checks of `Rule` it leaves to the Kernel.
|
|
17
|
+
* `Rule` is given at each call, so that a name outside it does not compile.
|
|
18
|
+
*/
|
|
19
|
+
export declare function named<Rule extends string = never>(schema: JsonSchema, ...rules: [NoInfer<Rule>, ...NoInfer<Rule>[]]): JsonSchema;
|
|
3
20
|
/**
|
|
4
21
|
* The check that a document is portable JSON, which `schema.decode` and `schema.accept` make first.
|
|
5
22
|
* JSON Schema reads a parsed value and compares numbers by their value: it states that no string or
|
|
@@ -21,4 +38,3 @@ export declare function jsonValueJsonSchema(): {
|
|
|
21
38
|
readonly root: JsonSchema;
|
|
22
39
|
readonly definitions: Readonly<Record<string, JsonSchema>>;
|
|
23
40
|
};
|
|
24
|
-
export {};
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { RULES } from '../rule.js';
|
|
2
|
+
/**
|
|
3
|
+
* `schema` with the `x-astrale-rule` marker naming the checks of `Rule` it leaves to the Kernel.
|
|
4
|
+
* `Rule` is given at each call, so that a name outside it does not compile.
|
|
5
|
+
*/
|
|
6
|
+
export function named(schema, ...rules) {
|
|
7
|
+
return { ...schema, 'x-astrale-rule': rules };
|
|
8
|
+
}
|
|
2
9
|
/**
|
|
3
10
|
* The check that a document is portable JSON, which `schema.decode` and `schema.accept` make first.
|
|
4
11
|
* JSON Schema reads a parsed value and compares numbers by their value: it states that no string or
|
|
@@ -18,17 +25,20 @@ export function jsonValueJsonSchema() {
|
|
|
18
25
|
return {
|
|
19
26
|
root: { $ref: VALUE },
|
|
20
27
|
definitions: {
|
|
21
|
-
'portable-json': {
|
|
28
|
+
'portable-json': named({
|
|
22
29
|
anyOf: [
|
|
23
30
|
{ type: 'null' },
|
|
24
31
|
{ type: 'boolean' },
|
|
25
32
|
{ type: 'number' },
|
|
26
33
|
{ $ref: TEXT },
|
|
27
34
|
{ type: 'array', items: { $ref: VALUE } },
|
|
28
|
-
{
|
|
35
|
+
{
|
|
36
|
+
type: 'object',
|
|
37
|
+
propertyNames: { $ref: TEXT },
|
|
38
|
+
additionalProperties: { $ref: VALUE },
|
|
39
|
+
},
|
|
29
40
|
],
|
|
30
|
-
|
|
31
|
-
},
|
|
41
|
+
}, 'portable-json'),
|
|
32
42
|
// The pattern is the character itself, which every regular-expression dialect reads.
|
|
33
43
|
'portable-string': { type: 'string', not: { pattern: '\u0000' } },
|
|
34
44
|
},
|
|
@@ -13,7 +13,7 @@ export interface PolicyMeasures {
|
|
|
13
13
|
readonly unmeasured: readonly string[];
|
|
14
14
|
/**
|
|
15
15
|
* Each check tree by the JSON Pointer of its position: the Policy of a Function or a Method, or
|
|
16
|
-
* the
|
|
16
|
+
* the rule of a Class slot.
|
|
17
17
|
*/
|
|
18
18
|
readonly checks: Readonly<Record<string, CheckMeasure>>;
|
|
19
19
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { deepFreeze } from '../../../language/freeze.js';
|
|
1
2
|
import { limits } from '../../../language/limits.js';
|
|
2
3
|
import { exceededLimits, measureChecks, policyMeasurer, } from '../../../language/policy/analysis/budgets.js';
|
|
3
|
-
import { isClassRuleChecks } from '../../../language/policy/model/policy.js';
|
|
4
|
+
import { CLASS_OPERATIONS, isClassRuleChecks } from '../../../language/policy/model/policy.js';
|
|
4
5
|
import { normalizePolicyChecks, normalizePolicyExpression, } from '../../../language/policy/normalization/normalize.js';
|
|
5
6
|
import { escapePointerToken } from '../../../language/value/syntax/pointer.js';
|
|
6
|
-
import { deepFreeze } from '../../canonical/freeze.js';
|
|
7
7
|
import { structureDomainSchema } from '../domain.route.js';
|
|
8
8
|
import { SITE } from './uses.js';
|
|
9
9
|
/**
|
|
@@ -55,7 +55,7 @@ export function validateCheckBudget(context, pointer, measure) {
|
|
|
55
55
|
if (exceededLimits(measure).length === 0)
|
|
56
56
|
return;
|
|
57
57
|
const { checkDepth, checkBranches, checkLeaves } = limits.policy;
|
|
58
|
-
// A callable holds its checks at `policy`; a
|
|
58
|
+
// A callable holds its checks at `policy`; a Class rule at `policies/{operation}`.
|
|
59
59
|
const site = SITE[pointer.endsWith('/policy') ? 'callable' : 'class'];
|
|
60
60
|
context.add('PL_BUDGET', pointer, `${site.checks} require depth <= ${checkDepth}, branches <= ${checkBranches}, and leaves <= ${checkLeaves}; got ${measure.checkDepth}, ${measure.checkBranches}, ${measure.checkLeaves}.`);
|
|
61
61
|
}
|
|
@@ -76,7 +76,7 @@ function normalizedPolicies(schema) {
|
|
|
76
76
|
function* checkTrees(schema) {
|
|
77
77
|
for (const [name, declaration] of Object.entries(schema.classes)) {
|
|
78
78
|
const owner = `/classes/${escapePointerToken(name)}`;
|
|
79
|
-
for (const operation of
|
|
79
|
+
for (const operation of CLASS_OPERATIONS) {
|
|
80
80
|
const rule = declaration.policies[operation];
|
|
81
81
|
if (typeof rule === 'object' && isClassRuleChecks(rule)) {
|
|
82
82
|
yield [`${owner}/policies/${operation}`, rule];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CallableDefinition } from '../../../language/callable/model/callable.js';
|
|
2
|
+
import type { EdgeContract } from '../../../language/class/model/edge.js';
|
|
2
3
|
import type { PolicyTyping } from '../../../language/policy/analysis/typing.js';
|
|
3
4
|
import type { PolicyCheckExpression } from '../../../language/policy/model/policy.js';
|
|
4
5
|
import type { JsonSchema } from '../../../language/value/model/schema.js';
|
|
@@ -10,6 +11,13 @@ interface CheckContext {
|
|
|
10
11
|
readonly input: JsonSchema;
|
|
11
12
|
/** The Node Class that receives the call, which the checks name `self`; none, and none is named. */
|
|
12
13
|
readonly receiver?: ClassRef;
|
|
14
|
+
/** In an Edge Class rule, the Edge `self` names, in place of a receiver. */
|
|
15
|
+
readonly edge?: EdgeUse;
|
|
16
|
+
}
|
|
17
|
+
/** One Edge Class, whose declaration fixes the concrete Node Classes of its endpoints. */
|
|
18
|
+
interface EdgeUse {
|
|
19
|
+
readonly ref: ClassRef;
|
|
20
|
+
readonly declaration: EdgeContract;
|
|
13
21
|
}
|
|
14
22
|
/** How a refusal names the checks of each site and the contract of their objects. */
|
|
15
23
|
export declare const SITE: {
|
|
@@ -22,8 +30,8 @@ export declare const SITE: {
|
|
|
22
30
|
readonly objects: 'the Class rule object contract';
|
|
23
31
|
};
|
|
24
32
|
};
|
|
25
|
-
|
|
26
|
-
export declare function
|
|
33
|
+
/** Type every Class slot: its Policy against the instance it decides, or its Policy checks. */
|
|
34
|
+
export declare function validateClassUses(context: PolicyValidationContext, typing: PolicyTyping): void;
|
|
27
35
|
export declare function validateCallableUses(context: PolicyValidationContext, typing: PolicyTyping): void;
|
|
28
36
|
/**
|
|
29
37
|
* Validate the Policy of one callable contract written at `pointer`, wherever it is declared:
|
|
@@ -2,7 +2,7 @@ import { Key } from '../../../addressing/index.js';
|
|
|
2
2
|
import { definitionRefIndex } from '../../../addressing/ordering.js';
|
|
3
3
|
import { isBinaryInput } from '../../../language/callable/model/callable.js';
|
|
4
4
|
import { neverAdmittedClasses, } from '../../../language/policy/analysis/checks.js';
|
|
5
|
-
import { checksNameTheCaller, isClassRuleChecks } from '../../../language/policy/model/policy.js';
|
|
5
|
+
import { CLASS_OPERATIONS, checksNameTheCaller, isClassRuleChecks, } from '../../../language/policy/model/policy.js';
|
|
6
6
|
import { normalizePolicyChecks } from '../../../language/policy/normalization/normalize.js';
|
|
7
7
|
import { GRAPH_NODE_PATH_SCHEMA_ID } from '../../../language/value/syntax/node-path/schema.js';
|
|
8
8
|
import { escapePointerToken } from '../../../language/value/syntax/pointer.js';
|
|
@@ -15,11 +15,10 @@ export const SITE = {
|
|
|
15
15
|
callable: { checks: 'Callable checks', objects: 'the callable object contract' },
|
|
16
16
|
class: { checks: 'Class rule checks', objects: 'the Class rule object contract' },
|
|
17
17
|
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
validateClassPolicyUses(context, typing, 'traverse');
|
|
18
|
+
/** Type every Class slot: its Policy against the instance it decides, or its Policy checks. */
|
|
19
|
+
export function validateClassUses(context, typing) {
|
|
20
|
+
for (const operation of CLASS_OPERATIONS)
|
|
21
|
+
validateClassPolicyUses(context, typing, operation);
|
|
23
22
|
}
|
|
24
23
|
function validateClassPolicyUses(context, typing, operation) {
|
|
25
24
|
for (const [name, declaration] of Object.entries(context.environment.candidate.classes)) {
|
|
@@ -27,23 +26,23 @@ function validateClassPolicyUses(context, typing, operation) {
|
|
|
27
26
|
if (typeof ref !== 'object')
|
|
28
27
|
continue;
|
|
29
28
|
const pointer = `/classes/${escapePointerToken(name)}/policies/${operation}`;
|
|
29
|
+
const self = { origin: context.environment.candidate.origin, kind: 'class', name };
|
|
30
30
|
if (isClassRuleChecks(ref)) {
|
|
31
|
-
// Structure admits
|
|
31
|
+
// Structure admits `self` everywhere but in a Node create rule: there is no Node yet.
|
|
32
32
|
validateChecks(context, typing, ref, {
|
|
33
33
|
site: 'class',
|
|
34
34
|
pointer,
|
|
35
35
|
input: {},
|
|
36
|
-
|
|
36
|
+
...(declaration.kind === 'node'
|
|
37
|
+
? { receiver: self }
|
|
38
|
+
: { edge: { ref: self, declaration } }),
|
|
37
39
|
});
|
|
38
40
|
continue;
|
|
39
41
|
}
|
|
40
42
|
if (!context.resolvePolicy(ref, pointer))
|
|
41
43
|
continue;
|
|
42
44
|
if (declaration.kind === 'node') {
|
|
43
|
-
const object = {
|
|
44
|
-
kind: 'exact',
|
|
45
|
-
ref: { origin: context.environment.candidate.origin, kind: 'class', name },
|
|
46
|
-
};
|
|
45
|
+
const object = { kind: 'exact', ref: self };
|
|
47
46
|
if (typing.policyAccepts(ref.name, object))
|
|
48
47
|
continue;
|
|
49
48
|
context.add('PL_USE', pointer, `${formatDefinitionRef(ref)} is not valid for every normalized branch of ${operation} Node Class ${name}.`, formatDefinitionRef(ref));
|
|
@@ -98,7 +97,11 @@ function visitChecks(validation, typing, expression, context, pointer, leaves) {
|
|
|
98
97
|
if ('sameNode' in expression) {
|
|
99
98
|
for (const [side, object] of Object.entries(expression.sameNode)) {
|
|
100
99
|
const objectPointer = `${pointer}/sameNode/${side}`;
|
|
101
|
-
if (object.kind === 'self')
|
|
100
|
+
if (object.kind === 'self' && context.edge !== undefined) {
|
|
101
|
+
// `self` is an Edge there, and sameNode compares Nodes.
|
|
102
|
+
validation.add('PL_USE', objectPointer, 'sameNode compares Nodes: self is an Edge here.');
|
|
103
|
+
}
|
|
104
|
+
else if (object.kind === 'self')
|
|
102
105
|
selfContracts(validation, context, objectPointer);
|
|
103
106
|
else if (object.kind === 'input')
|
|
104
107
|
inputContracts(validation, context, object.field, objectPointer);
|
|
@@ -110,6 +113,16 @@ function visitChecks(validation, typing, expression, context, pointer, leaves) {
|
|
|
110
113
|
if ('check' in expression) {
|
|
111
114
|
if (!validation.resolvePolicy(expression.check, `${pointer}/check`))
|
|
112
115
|
return;
|
|
116
|
+
if (expression.object.kind === 'self' && context.edge !== undefined) {
|
|
117
|
+
// An Edge is checked as an Edge Class Policy is: over every concrete endpoint pair.
|
|
118
|
+
if (!typing.policyAcceptsEdgeClass(expression.check.name, context.edge.declaration)) {
|
|
119
|
+
validation.add('PL_USE', pointer, `${formatDefinitionRef(expression.check)} is not valid for every concrete source/target pair of Edge Class ${context.edge.ref.name}.`, formatDefinitionRef(expression.check));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const edge = formatDefinitionRef(context.edge.ref);
|
|
123
|
+
leaves.set(expression, { accepted: [edge], admitted: new Set([edge]) });
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
113
126
|
const objectPointer = `${pointer}/object`;
|
|
114
127
|
const contracts = expression.object.kind === 'self'
|
|
115
128
|
? selfContracts(validation, context, objectPointer)
|
|
@@ -3,7 +3,7 @@ import { validatePolicyBudgets } from './budgets.js';
|
|
|
3
3
|
import { PolicyValidationContext } from './context.js';
|
|
4
4
|
import { validatePolicyReferences } from './references.js';
|
|
5
5
|
import { validatePolicyTyping } from './typing.js';
|
|
6
|
-
import { validateCallableUses,
|
|
6
|
+
import { validateCallableUses, validateClassUses } from './uses.js';
|
|
7
7
|
/**
|
|
8
8
|
* Validates the closed V1 Policy language after structural parsing.
|
|
9
9
|
*
|
|
@@ -17,8 +17,7 @@ export function validatePolicies(environment, analysis) {
|
|
|
17
17
|
validatePolicyBudgets(context);
|
|
18
18
|
const typing = new PolicyTyping(context);
|
|
19
19
|
validatePolicyTyping(context, typing);
|
|
20
|
-
|
|
21
|
-
validateTraverseUses(context, typing);
|
|
20
|
+
validateClassUses(context, typing);
|
|
22
21
|
validateCallableUses(context, typing);
|
|
23
22
|
return Object.freeze(context.diagnostics);
|
|
24
23
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
type JsonSchema = zodCore.JSONSchema.JSONSchema;
|
|
1
|
+
import { type JsonSchema } from './json.json-schema.js';
|
|
3
2
|
/**
|
|
4
3
|
* The checks on value schemas JSON Schema cannot state, which the published document names with
|
|
5
4
|
* the positions it constrains. The Kernel reports each as `DV_VALUE_SCHEMA`, with its value code.
|
|
@@ -18,12 +17,12 @@ export declare const valueSchemaRules: {
|
|
|
18
17
|
readonly 'value-recursion': {
|
|
19
18
|
readonly code: 'DV_VALUE_SCHEMA';
|
|
20
19
|
readonly valueCode: 'VS_RECURSION_PRODUCTIVE';
|
|
21
|
-
readonly statement:
|
|
20
|
+
readonly statement: string;
|
|
22
21
|
};
|
|
23
22
|
readonly 'value-reference-form': {
|
|
24
23
|
readonly code: 'DV_VALUE_SCHEMA';
|
|
25
24
|
readonly valueCode: 'VS_REFERENCE_FORM';
|
|
26
|
-
readonly statement:
|
|
25
|
+
readonly statement: string;
|
|
27
26
|
};
|
|
28
27
|
readonly 'value-reference-resolution': {
|
|
29
28
|
readonly code: 'DV_VALUE_SCHEMA';
|
|
@@ -33,7 +32,7 @@ export declare const valueSchemaRules: {
|
|
|
33
32
|
readonly 'value-regexp': {
|
|
34
33
|
readonly code: 'DV_VALUE_SCHEMA';
|
|
35
34
|
readonly valueCode: 'VS_REGEX_PORTABLE';
|
|
36
|
-
readonly statement:
|
|
35
|
+
readonly statement: string;
|
|
37
36
|
};
|
|
38
37
|
};
|
|
39
38
|
export type ValueSchemaRule = keyof typeof valueSchemaRules;
|
|
@@ -48,4 +47,3 @@ export declare function valueSchemaJsonSchema(): {
|
|
|
48
47
|
readonly definitions: Readonly<Record<string, JsonSchema>>;
|
|
49
48
|
readonly nodeProperty: JsonSchema;
|
|
50
49
|
};
|
|
51
|
-
export {};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { VALUE_RULES } from '../../language/validation/rule.js';
|
|
1
2
|
import { VALUE_SCHEMA_DIALECT } from '../../language/value/model/schema.js';
|
|
2
3
|
import { FORBIDDEN_KEYWORDS, SUBSCHEMA_KEYWORDS, VALUE_KEYWORDS, } from '../../language/value/profile/vocabulary.js';
|
|
4
|
+
import { named } from './json.json-schema.js';
|
|
3
5
|
/**
|
|
4
6
|
* The checks on value schemas JSON Schema cannot state, which the published document names with
|
|
5
7
|
* the positions it constrains. The Kernel reports each as `DV_VALUE_SCHEMA`, with its value code.
|
|
@@ -19,12 +21,12 @@ export const valueSchemaRules = {
|
|
|
19
21
|
'value-recursion': {
|
|
20
22
|
code: 'DV_VALUE_SCHEMA',
|
|
21
23
|
valueCode: 'VS_RECURSION_PRODUCTIVE',
|
|
22
|
-
statement:
|
|
24
|
+
statement: VALUE_RULES.VS_RECURSION_PRODUCTIVE.statement,
|
|
23
25
|
},
|
|
24
26
|
'value-reference-form': {
|
|
25
27
|
code: 'DV_VALUE_SCHEMA',
|
|
26
28
|
valueCode: 'VS_REFERENCE_FORM',
|
|
27
|
-
statement:
|
|
29
|
+
statement: VALUE_RULES.VS_REFERENCE_FORM.statement,
|
|
28
30
|
},
|
|
29
31
|
'value-reference-resolution': {
|
|
30
32
|
code: 'DV_VALUE_SCHEMA',
|
|
@@ -34,7 +36,7 @@ export const valueSchemaRules = {
|
|
|
34
36
|
'value-regexp': {
|
|
35
37
|
code: 'DV_VALUE_SCHEMA',
|
|
36
38
|
valueCode: 'VS_REGEX_PORTABLE',
|
|
37
|
-
statement:
|
|
39
|
+
statement: VALUE_RULES.VS_REGEX_PORTABLE.statement,
|
|
38
40
|
},
|
|
39
41
|
};
|
|
40
42
|
const KIND = 'x-astrale-value-kind';
|
|
@@ -55,10 +57,7 @@ export function valueSchemaJsonSchema() {
|
|
|
55
57
|
objectOrBoolean({
|
|
56
58
|
properties: {
|
|
57
59
|
$schema: { const: VALUE_SCHEMA_DIALECT },
|
|
58
|
-
[KIND]: {
|
|
59
|
-
enum: ['instant', 'blob'],
|
|
60
|
-
'x-astrale-rule': 'value-blob',
|
|
61
|
-
},
|
|
60
|
+
[KIND]: named({ enum: ['instant', 'blob'] }, 'value-blob'),
|
|
62
61
|
},
|
|
63
62
|
}),
|
|
64
63
|
],
|
|
@@ -70,31 +69,25 @@ export function valueSchemaJsonSchema() {
|
|
|
70
69
|
},
|
|
71
70
|
properties: {
|
|
72
71
|
$id: false,
|
|
73
|
-
$ref: {
|
|
74
|
-
type: 'string',
|
|
75
|
-
'x-astrale-rule': [
|
|
76
|
-
'value-recursion',
|
|
77
|
-
'value-reference-form',
|
|
78
|
-
'value-reference-resolution',
|
|
79
|
-
],
|
|
80
|
-
},
|
|
72
|
+
$ref: named({ type: 'string' }, 'value-recursion', 'value-reference-form', 'value-reference-resolution'),
|
|
81
73
|
enum: { type: 'array', uniqueItems: true },
|
|
82
|
-
fullMatch: { type: 'string', '
|
|
83
|
-
pattern: { type: 'string', '
|
|
84
|
-
'x-astrale-path': { $ref: PATH, '
|
|
74
|
+
fullMatch: named({ type: 'string' }, 'value-regexp'),
|
|
75
|
+
pattern: named({ type: 'string' }, 'value-regexp'),
|
|
76
|
+
'x-astrale-path': named({ $ref: PATH }, 'value-path'),
|
|
85
77
|
...Object.fromEntries(SUBSCHEMA_KEYWORDS.single.map((keyword) => [keyword, { $ref: SUBSCHEMA }])),
|
|
86
78
|
...Object.fromEntries(SUBSCHEMA_KEYWORDS.array.map((keyword) => [
|
|
87
79
|
keyword,
|
|
88
80
|
{ type: 'array', items: { $ref: SUBSCHEMA } },
|
|
89
81
|
])),
|
|
90
|
-
...Object.fromEntries(SUBSCHEMA_KEYWORDS.map.map((keyword) =>
|
|
91
|
-
|
|
92
|
-
{
|
|
82
|
+
...Object.fromEntries(SUBSCHEMA_KEYWORDS.map.map((keyword) => {
|
|
83
|
+
const members = {
|
|
93
84
|
type: 'object',
|
|
94
85
|
additionalProperties: { $ref: SUBSCHEMA },
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
86
|
+
};
|
|
87
|
+
if (keyword !== 'patternProperties')
|
|
88
|
+
return [keyword, members];
|
|
89
|
+
return [keyword, named(members, 'value-regexp')];
|
|
90
|
+
})),
|
|
98
91
|
},
|
|
99
92
|
// An instant is a string.
|
|
100
93
|
if: { required: [KIND], properties: { [KIND]: { const: 'instant' } } },
|
|
@@ -111,7 +104,7 @@ export function valueSchemaJsonSchema() {
|
|
|
111
104
|
type: 'array',
|
|
112
105
|
minItems: 1,
|
|
113
106
|
uniqueItems: true,
|
|
114
|
-
items: { $ref: '#/$defs/class-ref', '
|
|
107
|
+
items: named({ $ref: '#/$defs/class-ref' }, 'value-reference-resolution'),
|
|
115
108
|
},
|
|
116
109
|
},
|
|
117
110
|
required: ['target', 'cardinality', 'accepts'],
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function deepFreeze<T>(value: T): Readonly<T>;
|