@astrale-os/kernel-dsl 1.0.0-beta.14 → 1.0.0-beta.16
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/domain-dependency.d.ts +0 -6
- package/dist/v1/addressing/domain-dependency.js +1 -6
- package/dist/v1/builder/class/authoring.d.ts +43 -0
- package/dist/v1/builder/index.d.ts +1 -1
- package/dist/v1/builder/lowering/policy.js +1 -0
- package/dist/v1/builder/lowering/schema/context.d.ts +5 -0
- package/dist/v1/builder/lowering/schema/context.js +22 -0
- package/dist/v1/builder/policy/authoring.d.ts +84 -4
- package/dist/v1/builder/policy/authoring.js +41 -12
- package/dist/v1/builder/schema/projection/class.d.ts +116 -14
- package/dist/v1/bundle/codec.js +7 -7
- package/dist/v1/compiled/admission/accept.js +3 -3
- package/dist/v1/compiled/admission/closure.js +2 -2
- package/dist/v1/compiled/admission/semantics/core.js +3 -7
- package/dist/v1/compiled/admission/semantics/policy/parity.js +3 -10
- package/dist/v1/compiled/admission/semantics/policy/typing.js +2 -2
- package/dist/v1/language/.spec/schemas/draft-2020-12.schema.json +462 -0
- package/dist/v1/language/core/facts.d.ts +17 -4
- package/dist/v1/language/core/facts.js +26 -5
- package/dist/v1/language/limits.d.ts +64 -0
- package/dist/v1/language/limits.js +60 -0
- package/dist/v1/language/policy/analysis/budgets.d.ts +39 -18
- package/dist/v1/language/policy/analysis/budgets.js +30 -20
- package/dist/v1/language/policy/analysis/checks.js +3 -2
- package/dist/v1/language/policy/analysis/typing.d.ts +4 -2
- package/dist/v1/language/policy/analysis/typing.js +136 -14
- package/dist/v1/language/validation/rule.d.ts +9 -0
- package/dist/v1/language/validation/rule.js +9 -7
- package/dist/v1/language/value/ordering.d.ts +5 -0
- package/dist/v1/language/value/ordering.js +14 -0
- package/dist/v1/language/value/reference/closure.js +3 -4
- package/dist/v1/language/value/reference/registry.index.d.ts +2 -0
- package/dist/v1/language/value/reference/registry.index.js +31 -15
- package/dist/v1/language/value/regexp/ast.js +6 -7
- package/dist/v1/language/value/regexp/compile.d.ts +5 -11
- package/dist/v1/language/value/regexp/compile.js +14 -12
- package/dist/v1/language/value/regexp/syntax.js +3 -2
- package/dist/v1/schema/.spec/schemas/domain-schema.schema.json +30 -2
- package/dist/v1/schema/admission/accept.js +3 -14
- package/dist/v1/schema/admission/callable.d.ts +21 -0
- package/dist/v1/schema/admission/callable.js +96 -0
- package/dist/v1/schema/index.d.ts +7 -0
- package/dist/v1/schema/index.js +3 -0
- package/dist/v1/schema/normalization/domain.d.ts +2 -0
- package/dist/v1/schema/normalization/domain.js +1 -1
- package/dist/v1/schema/resolution/context.js +7 -7
- package/dist/v1/schema/resolution/domain.d.ts +5 -0
- package/dist/v1/schema/resolution/domain.js +1 -1
- package/dist/v1/schema/rule.d.ts +9 -0
- package/dist/v1/schema/rule.js +29 -4
- package/dist/v1/schema/validation/callable.d.ts +33 -3
- package/dist/v1/schema/validation/callable.js +49 -15
- package/dist/v1/schema/validation/class.d.ts +6 -2
- package/dist/v1/schema/validation/class.js +18 -22
- package/dist/v1/schema/validation/core.js +16 -10
- package/dist/v1/schema/validation/domain.js +3 -3
- package/dist/v1/schema/validation/domain.route.d.ts +6 -1
- package/dist/v1/schema/validation/domain.route.js +18 -0
- package/dist/v1/schema/validation/domain.structure.d.ts +28 -26
- package/dist/v1/schema/validation/domain.structure.js +22 -6
- package/dist/v1/schema/validation/policy/budgets.d.ts +33 -2
- package/dist/v1/schema/validation/policy/budgets.js +89 -16
- package/dist/v1/schema/validation/policy/context.d.ts +1 -2
- package/dist/v1/schema/validation/policy/context.js +2 -7
- package/dist/v1/schema/validation/policy/references.js +2 -1
- package/dist/v1/schema/validation/policy/uses.d.ts +29 -0
- package/dist/v1/schema/validation/policy/uses.js +28 -48
- package/dist/v1/schema/validation/value-api.d.ts +2 -0
- package/dist/v1/schema/validation/value-api.js +2 -0
- package/dist/v1/schema/validation/value.d.ts +3 -0
- package/dist/v1/schema/validation/value.js +3 -9
- package/dist/v1/schema/validation/value.json-schema.d.ts +3 -3
- package/dist/v1/schema/validation/value.json-schema.js +22 -4
- package/package.json +2 -1
|
@@ -10,9 +10,3 @@ export type DomainDependency = JsonObject & {
|
|
|
10
10
|
export type DependencyAlias = string;
|
|
11
11
|
/** Exact direct dependency pins keyed by their authored aliases. */
|
|
12
12
|
export type DomainDependencyMap = Readonly<Record<DependencyAlias, DomainDependency>>;
|
|
13
|
-
/** Representation-neutral admission budgets shared by source and compiled closures. */
|
|
14
|
-
export declare const dependencyLimits: Readonly<{
|
|
15
|
-
direct: 32;
|
|
16
|
-
closure: 256;
|
|
17
|
-
depth: 32;
|
|
18
|
-
}>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Value as PortableValue } from '@astrale-os/kernel-dsl/value';
|
|
2
2
|
import type { z } from 'zod';
|
|
3
|
+
import type { ClassRef } from '../../addressing/index.js';
|
|
3
4
|
import type { ResolvedClass, ResolvedProperty } from '../../language/class/resolved.js';
|
|
4
5
|
import type { StateTopologyOf } from '../../language/state/topology.js';
|
|
5
6
|
import type { BlobReceipt, BlobRef, BlobSchema } from '../../language/value/model/blob.js';
|
|
@@ -82,6 +83,44 @@ type ClassDepthOfInput<Input> = Input extends {
|
|
|
82
83
|
} ? Parents extends readonly [] ? 0 : Increment<ClassDepthOf<Parents[number]>> : 0;
|
|
83
84
|
type CompactReference<Value> = Value extends () => infer Resolved ? () => CompactReference<Resolved> : Value extends ResolvedClass ? ClassProjectionOfResolved<Value> : Value extends Class ? ClassReferenceProjectionOf<Value> : Value;
|
|
84
85
|
type CompactReferences<Values extends readonly unknown[]> = Values extends readonly [] ? readonly [] : Values extends readonly [infer Value, ...infer Rest] ? readonly [CompactReference<Value>, ...CompactReferences<Rest>] : readonly CompactReference<Values[number]>[];
|
|
86
|
+
/**
|
|
87
|
+
* A Class an endpoint accepts, as its projection keeps it: the exact ref of a resolved Class, the
|
|
88
|
+
* mark of an authored one, which the Schema names, or the ref as given. A lazy reference stays lazy.
|
|
89
|
+
*/
|
|
90
|
+
type CompactAccepted<Value> = Value extends () => infer Resolved ? () => CompactAccepted<Resolved> : Value extends ResolvedClass ? ExactClassRefOf<Value> : Value extends NodeClass<infer Config> ? AcceptedClassMark<Config> : Value;
|
|
91
|
+
/**
|
|
92
|
+
* What tells an authored Node Class from the other Classes of its Schema in an endpoint's type:
|
|
93
|
+
* its abstractness, its depth and the names of its effective members. Names alone keep the Edge
|
|
94
|
+
* handle small enough to print in a declaration file; Classes alike in all of these are the same
|
|
95
|
+
* accepted Class to the types, never to the Schema. `schema/projection/class.ts` names the Classes
|
|
96
|
+
* of a Schema and of its direct dependencies that bear the mark, since either may own the handle.
|
|
97
|
+
*/
|
|
98
|
+
type AcceptedClassMark<Config> = {
|
|
99
|
+
readonly kind: 'node';
|
|
100
|
+
readonly abstract: Config extends {
|
|
101
|
+
readonly abstract: infer Abstract;
|
|
102
|
+
} ? Abstract : never;
|
|
103
|
+
readonly depth: Config extends {
|
|
104
|
+
readonly depth: infer Depth;
|
|
105
|
+
} ? Depth : never;
|
|
106
|
+
readonly properties: Config extends {
|
|
107
|
+
readonly effectiveProperties: infer Properties;
|
|
108
|
+
} ? Properties extends {
|
|
109
|
+
readonly name: infer Name;
|
|
110
|
+
} ? Name : never : never;
|
|
111
|
+
readonly methods: Config extends {
|
|
112
|
+
readonly effectiveInstanceMethods: infer Instance;
|
|
113
|
+
readonly effectiveStaticMethods: infer Static;
|
|
114
|
+
} ? Instance | Static extends infer Method ? Method extends {
|
|
115
|
+
readonly name: infer Name;
|
|
116
|
+
} ? Name : never : never : never;
|
|
117
|
+
};
|
|
118
|
+
/** The ref of a resolved Class, exact while its key is. */
|
|
119
|
+
type ExactClassRefOf<Value extends ResolvedClass> = Value['key'] extends `${infer Origin}:class.${infer Name}` ? string extends Origin ? ClassRef : string extends Name ? ClassRef : ClassRef<Name> & {
|
|
120
|
+
readonly origin: Origin;
|
|
121
|
+
} : ClassRef;
|
|
122
|
+
/** The Classes one endpoint accepts, in any order: the runtime list is canonically sorted. */
|
|
123
|
+
type CompactAccepts<Values> = Values extends readonly (infer Value)[] ? readonly CompactAccepted<Value>[] : readonly never[];
|
|
85
124
|
type CompactParentsOf<Input> = Input extends {
|
|
86
125
|
readonly extends?: infer Values extends readonly unknown[];
|
|
87
126
|
} ? 'extends' extends keyof Input ? CompactReferences<Values> : readonly [] : readonly [];
|
|
@@ -114,10 +153,12 @@ type CompactDirectedInput<Input extends Omit<DirectedEdgeInput, 'orientation'>>
|
|
|
114
153
|
} ? NonNullable<Value> : never : never>;
|
|
115
154
|
readonly source: {
|
|
116
155
|
readonly as: Input['source']['as'];
|
|
156
|
+
readonly accepts: CompactAccepts<Input['source']['accepts']>;
|
|
117
157
|
readonly outgoing: Input['source']['outgoing'];
|
|
118
158
|
};
|
|
119
159
|
readonly target: {
|
|
120
160
|
readonly as: Input['target']['as'];
|
|
161
|
+
readonly accepts: CompactAccepts<Input['target']['accepts']>;
|
|
121
162
|
readonly incoming: Input['target']['incoming'];
|
|
122
163
|
};
|
|
123
164
|
readonly constraints: Input extends {
|
|
@@ -137,10 +178,12 @@ type CompactUndirectedInput<Input extends Omit<UndirectedEdgeInput, 'orientation
|
|
|
137
178
|
readonly endpoints: readonly [
|
|
138
179
|
{
|
|
139
180
|
readonly as: Input['endpoints'][0]['as'];
|
|
181
|
+
readonly accepts: CompactAccepts<Input['endpoints'][0]['accepts']>;
|
|
140
182
|
readonly incident: Input['endpoints'][0]['incident'];
|
|
141
183
|
},
|
|
142
184
|
{
|
|
143
185
|
readonly as: Input['endpoints'][1]['as'];
|
|
186
|
+
readonly accepts: CompactAccepts<Input['endpoints'][1]['accepts']>;
|
|
144
187
|
readonly incident: Input['endpoints'][1]['incident'];
|
|
145
188
|
}
|
|
146
189
|
];
|
|
@@ -19,7 +19,7 @@ export type { ClassReferenceInput as ClassReference, ClassRuleBuilder, ClassRule
|
|
|
19
19
|
export type { AuthoredPropertyProjection, AuthoredMethodProjection, ClassIdentityProjection, ClassOwnerProjection, ClassReferenceProjection, } from './class/projection.js';
|
|
20
20
|
export type { PathAuthoring } from './value/path.js';
|
|
21
21
|
export type { Lazy } from './schema/lazy.js';
|
|
22
|
-
export type { MatchPolicyInput, Policy, PolicyBuilder as PolicyFactory, PolicyEdgeInput, PolicyExistsContext, PolicyInput, PolicyNodeBinder, PolicyPatternContext, } from './policy/authoring.js';
|
|
22
|
+
export type { EdgeRolesOf, MatchPolicyInput, Policy, PolicyBuilder as PolicyFactory, PolicyEdgeClassInput, PolicyEdgeEnds, PolicyEdgeInput, PolicyEdgeOptions, PolicyEdgeRepeat, PolicyExistsContext, PolicyInput, PolicyNodeBinder, PolicyPatternContext, } from './policy/authoring.js';
|
|
23
23
|
export type { AutoOptions, AutoProperty, Property, PropertyFieldInput as PropertyField, PropertyOptions, ValueSchemaInput, } from './class/property.js';
|
|
24
24
|
export type { CorePropertyInput } from './schema/projection.js';
|
|
25
25
|
export type { ClassProjection, FunctionProjection, MethodProjection, PropertyProjection, } from './schema/projection.js';
|
|
@@ -24,6 +24,7 @@ export class V1PolicyCompiler {
|
|
|
24
24
|
const match = input.match(createPatternContext({
|
|
25
25
|
resolveObject: (member, refPointer) => this.context.resolvePolicyObject(member, refPointer),
|
|
26
26
|
resolveEdgeClass: (definition, refPointer) => this.context.resolveEdgeClass(definition, refPointer),
|
|
27
|
+
edgeRoles: (ref) => this.context.edgeRoles(ref),
|
|
27
28
|
resolveNodeClass: (definition, refPointer) => this.context.resolveNodeClass(definition, refPointer),
|
|
28
29
|
pointer,
|
|
29
30
|
}));
|
|
@@ -34,6 +34,11 @@ export declare class BuilderContext {
|
|
|
34
34
|
resolveParent(input: ClassReferenceInput, kind: ClassKind, pointer: string): ClassRef;
|
|
35
35
|
resolveNodeClass(input: ClassReferenceInput, pointer: string): ClassRef;
|
|
36
36
|
resolveEdgeClass(input: ClassReferenceInput, pointer: string): ClassRef;
|
|
37
|
+
/**
|
|
38
|
+
* The roles of a resolved Edge Class's source and target, or of an undirected Class's two
|
|
39
|
+
* endpoints in their stored order, which is the authored one.
|
|
40
|
+
*/
|
|
41
|
+
edgeRoles(ref: ClassRef): readonly [source: string, target: string];
|
|
37
42
|
resolvePolicy(input: Lazy<unknown>, pointer: string): PolicyRef;
|
|
38
43
|
resolvePolicyObject(input: PolicyObjectInput | PolicyObjectRef, pointer: string): PolicyObjectRef;
|
|
39
44
|
/** A Core fact belongs to the Domain that declares it, so a dependency endpoint never resolves. */
|
|
@@ -8,6 +8,7 @@ import { escapePointerToken } from '../../../language/value/syntax/pointer.js';
|
|
|
8
8
|
import { revisionOfDomainSchema } from '../../../schema/canonical/revision.js';
|
|
9
9
|
import { requireDomainClosure } from '../../../schema/resolution/closure.js';
|
|
10
10
|
import { collectUsedForeignOrigins } from '../../../schema/resolution/origins.js';
|
|
11
|
+
import { classConfiguration } from '../../class/authoring.js';
|
|
11
12
|
import { fail } from '../../schema/diagnostic.js';
|
|
12
13
|
import { resolveLazy } from '../../schema/lazy.js';
|
|
13
14
|
import { OwnershipCapture } from './ownership.js';
|
|
@@ -16,6 +17,7 @@ export class BuilderContext {
|
|
|
16
17
|
ownership = new OwnershipCapture();
|
|
17
18
|
localDefinitions = new Map();
|
|
18
19
|
localClassKinds = new Map();
|
|
20
|
+
#localClasses = new Map();
|
|
19
21
|
policies = new Map();
|
|
20
22
|
policyObjects = new Map();
|
|
21
23
|
policyObjectRefs = new Set();
|
|
@@ -49,6 +51,7 @@ export class BuilderContext {
|
|
|
49
51
|
}
|
|
50
52
|
this.localDefinitions.set(key, ref);
|
|
51
53
|
this.localClassKinds.set(key, value.kind);
|
|
54
|
+
this.#localClasses.set(key, value);
|
|
52
55
|
this.ownership.captureDefinition(value, ref, pointer);
|
|
53
56
|
this.capturePolicyObject(value, ref);
|
|
54
57
|
}
|
|
@@ -109,6 +112,25 @@ export class BuilderContext {
|
|
|
109
112
|
resolveEdgeClass(input, pointer) {
|
|
110
113
|
return this.resolveClass(input, 'edge', pointer);
|
|
111
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* The roles of a resolved Edge Class's source and target, or of an undirected Class's two
|
|
117
|
+
* endpoints in their stored order, which is the authored one.
|
|
118
|
+
*/
|
|
119
|
+
edgeRoles(ref) {
|
|
120
|
+
if (ref.origin === this.origin) {
|
|
121
|
+
const value = this.#localClasses.get(definitionRefIndex(ref));
|
|
122
|
+
if (value.orientation === 'directed') {
|
|
123
|
+
const input = classConfiguration(value);
|
|
124
|
+
return [input.source.as, input.target.as];
|
|
125
|
+
}
|
|
126
|
+
const input = classConfiguration(value);
|
|
127
|
+
return [input.endpoints[0].as, input.endpoints[1].as];
|
|
128
|
+
}
|
|
129
|
+
const definition = this.#dependencies.get(ref.origin).schema.classes[ref.name];
|
|
130
|
+
return definition.orientation === 'directed'
|
|
131
|
+
? [definition.endpoints.source.role, definition.endpoints.target.role]
|
|
132
|
+
: [definition.endpoints[0].role, definition.endpoints[1].role];
|
|
133
|
+
}
|
|
112
134
|
resolvePolicy(input, pointer) {
|
|
113
135
|
const value = resolveLazy(input, pointer);
|
|
114
136
|
if (typeof value !== 'object' || value === null) {
|
|
@@ -1,18 +1,79 @@
|
|
|
1
1
|
import type { ClassRef } from '../../addressing/index.js';
|
|
2
|
+
import type { ResolvedClass } from '../../language/class/resolved.js';
|
|
2
3
|
import type { PolicyCheckExpression, PolicyPatternExpression, PolicyPatternTerm as CanonicalPolicyPatternTerm, PolicyObjectRef } from '../../language/policy/model/policy.js';
|
|
3
4
|
import type { PolicyObjectInput } from '../callable/authoring.js';
|
|
5
|
+
import type { DirectedEdgeClass, EdgeClass, UndirectedEdgeClass } from '../class/handle.js';
|
|
4
6
|
import type { EdgeClassReferenceInput, NodeClassReferenceInput } from '../class/input.js';
|
|
5
7
|
import type { AuthoringValue } from '../schema/handle.js';
|
|
6
8
|
import type { Lazy } from '../schema/lazy.js';
|
|
9
|
+
import type { ResolveLazy } from '../schema/projection/identity.js';
|
|
10
|
+
/**
|
|
11
|
+
* @deprecated Name the ends by their roles: `edge(classValue, { [role]: term }, { repeat })`
|
|
12
|
+
* lowers to this same pattern.
|
|
13
|
+
*/
|
|
7
14
|
export interface PolicyEdgeInput {
|
|
8
15
|
readonly source: CanonicalPolicyPatternTerm;
|
|
9
16
|
readonly class: EdgeClassReferenceInput;
|
|
10
17
|
readonly target: CanonicalPolicyPatternTerm;
|
|
11
|
-
readonly repeat?:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
readonly repeat?: PolicyEdgeRepeat;
|
|
19
|
+
}
|
|
20
|
+
/** How many Edges of the Class a path between the two terms crosses, both bounds included. */
|
|
21
|
+
export interface PolicyEdgeRepeat {
|
|
22
|
+
readonly min: number;
|
|
23
|
+
readonly max: number;
|
|
24
|
+
}
|
|
25
|
+
export interface PolicyEdgeOptions {
|
|
26
|
+
readonly repeat?: PolicyEdgeRepeat;
|
|
15
27
|
}
|
|
28
|
+
/** An Edge Class whose ends a Policy names by role: authored, resolved, or either lazily. */
|
|
29
|
+
export type PolicyEdgeClassInput = Lazy<EdgeClass | ResolvedClass<'edge'>>;
|
|
30
|
+
/**
|
|
31
|
+
* The roles of an Edge Class's two ends, as literal types: the `as` of an authored Class's ends,
|
|
32
|
+
* the `role` of a resolved Class's, read through a lazy reference.
|
|
33
|
+
*/
|
|
34
|
+
export type EdgeRolesOf<Value> = ResolveLazy<Value> extends infer Resolved ? Resolved extends DirectedEdgeClass<infer Config> ? Config extends {
|
|
35
|
+
readonly source: {
|
|
36
|
+
readonly as: infer Source;
|
|
37
|
+
};
|
|
38
|
+
readonly target: {
|
|
39
|
+
readonly as: infer Target;
|
|
40
|
+
};
|
|
41
|
+
} ? Source | Target : never : Resolved extends UndirectedEdgeClass<infer Config> ? Config extends {
|
|
42
|
+
readonly endpoints: readonly [
|
|
43
|
+
{
|
|
44
|
+
readonly as: infer First;
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
readonly as: infer Second;
|
|
48
|
+
}
|
|
49
|
+
];
|
|
50
|
+
} ? First | Second : never : Resolved extends {
|
|
51
|
+
readonly kind: 'edge';
|
|
52
|
+
readonly definition: {
|
|
53
|
+
readonly endpoints: infer Endpoints;
|
|
54
|
+
};
|
|
55
|
+
} ? Endpoints extends {
|
|
56
|
+
readonly source: {
|
|
57
|
+
readonly role: infer Source;
|
|
58
|
+
};
|
|
59
|
+
readonly target: {
|
|
60
|
+
readonly role: infer Target;
|
|
61
|
+
};
|
|
62
|
+
} ? Source | Target : Endpoints extends readonly [
|
|
63
|
+
{
|
|
64
|
+
readonly role: infer First;
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
readonly role: infer Second;
|
|
68
|
+
}
|
|
69
|
+
] ? First | Second : never : never : never;
|
|
70
|
+
/**
|
|
71
|
+
* The two ends of an Edge, keyed by exactly the Class's two roles, both required. A Class whose
|
|
72
|
+
* roles the types do not know names no ends.
|
|
73
|
+
*/
|
|
74
|
+
export type PolicyEdgeEnds<Value> = [EdgeRolesOf<Value>] extends [never] ? never : string extends EdgeRolesOf<Value> ? never : {
|
|
75
|
+
readonly [Role in EdgeRolesOf<Value> & string]: CanonicalPolicyPatternTerm;
|
|
76
|
+
};
|
|
16
77
|
export interface PolicyNodeBinder {
|
|
17
78
|
(): CanonicalPolicyPatternTerm;
|
|
18
79
|
(definition: NodeClassReferenceInput): CanonicalPolicyPatternTerm;
|
|
@@ -36,6 +97,23 @@ export interface PolicyPatternContext {
|
|
|
36
97
|
readonly object: CanonicalPolicyPatternTerm;
|
|
37
98
|
readonly source: CanonicalPolicyPatternTerm;
|
|
38
99
|
readonly target: CanonicalPolicyPatternTerm;
|
|
100
|
+
/**
|
|
101
|
+
* An Edge of `classValue` between two terms, each keyed by the role of its end: `{ [role]: term }`,
|
|
102
|
+
* the source's role written first by convention. It lowers to the pattern whose source is the
|
|
103
|
+
* term of the source's role and whose target is the term of the target's role. For an undirected
|
|
104
|
+
* Class, the first endpoint's role lowers to the source, and the roles only order the two terms:
|
|
105
|
+
* the pattern still matches an Edge between the two Nodes whichever end each Node holds.
|
|
106
|
+
*
|
|
107
|
+
* ```ts
|
|
108
|
+
* edge(project_owned_by, { owner: subject, project })
|
|
109
|
+
* edge(() => subtask_of, { child: a, parent: b }, { repeat: { min: 1, max: 3 } })
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
edge<ClassValue extends PolicyEdgeClassInput>(classValue: ClassValue, ends: PolicyEdgeEnds<ClassValue>, options?: PolicyEdgeOptions): PolicyPatternExpression;
|
|
113
|
+
/**
|
|
114
|
+
* @deprecated Name the ends by their roles: `edge(classValue, { [role]: term }, { repeat })`
|
|
115
|
+
* lowers to this same pattern.
|
|
116
|
+
*/
|
|
39
117
|
edge(input: PolicyEdgeInput): PolicyPatternExpression;
|
|
40
118
|
exists(build: (context: PolicyExistsContext) => PolicyPatternExpression): PolicyPatternExpression;
|
|
41
119
|
allOf(first: PolicyPatternExpression, ...rest: readonly PolicyPatternExpression[]): PolicyPatternExpression;
|
|
@@ -63,6 +141,8 @@ export declare const policy: PolicyBuilder;
|
|
|
63
141
|
export declare function createPatternContext(options: {
|
|
64
142
|
readonly resolveObject: (value: PolicyObjectInput, pointer: string) => PolicyObjectRef;
|
|
65
143
|
readonly resolveEdgeClass: (value: EdgeClassReferenceInput, pointer: string) => ClassRef;
|
|
144
|
+
/** The roles of an Edge Class's source and target, or of an undirected Class's two endpoints. */
|
|
145
|
+
readonly edgeRoles: (ref: ClassRef) => readonly [source: string, target: string];
|
|
66
146
|
readonly resolveNodeClass: (value: NodeClassReferenceInput, pointer: string) => ClassRef;
|
|
67
147
|
readonly pointer: string;
|
|
68
148
|
}): PolicyPatternContext;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assertKnownKeys, fail } from '../schema/diagnostic.js';
|
|
1
|
+
import { assertKnownKeys, escapeToken, fail } from '../schema/diagnostic.js';
|
|
2
2
|
import { authoringValue } from '../schema/handle.js';
|
|
3
3
|
const declarations = new WeakMap();
|
|
4
4
|
const compositions = new WeakSet();
|
|
@@ -31,6 +31,7 @@ export function createPatternContext(options) {
|
|
|
31
31
|
const object = Object.freeze({ kind: 'object' });
|
|
32
32
|
const source = Object.freeze({ kind: 'source' });
|
|
33
33
|
const target = Object.freeze({ kind: 'target' });
|
|
34
|
+
const classRef = (value) => options.resolveEdgeClass(value, `${options.pointer}/match/class`);
|
|
34
35
|
const context = {
|
|
35
36
|
ref: (member) => ({
|
|
36
37
|
kind: 'ref',
|
|
@@ -41,17 +42,36 @@ export function createPatternContext(options) {
|
|
|
41
42
|
object,
|
|
42
43
|
source,
|
|
43
44
|
target,
|
|
44
|
-
edge(
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
45
|
+
edge: ((first, ends, edgeOptions) => {
|
|
46
|
+
const pointer = `${options.pointer}/match/edge`;
|
|
47
|
+
if (ends === undefined) {
|
|
48
|
+
if (typeof first === 'function' || first.kind === 'edge') {
|
|
49
|
+
fail('BUILDER_POLICY', pointer, 'edge(classValue, ends) names both ends by their roles.');
|
|
50
|
+
}
|
|
51
|
+
const input = first;
|
|
52
|
+
assertKnownKeys(input, ['source', 'class', 'target', 'repeat']);
|
|
53
|
+
if (input.repeat !== undefined)
|
|
54
|
+
assertKnownKeys(input.repeat, ['min', 'max']);
|
|
55
|
+
return edgePattern(input.source, classRef(input.class), input.target, input.repeat);
|
|
56
|
+
}
|
|
57
|
+
const ref = classRef(first);
|
|
58
|
+
const [sourceRole, targetRole] = options.edgeRoles(ref);
|
|
59
|
+
if (typeof ends !== 'object' || ends === null) {
|
|
60
|
+
fail('BUILDER_POLICY', pointer, 'edge(classValue, ends) names both ends by their roles.');
|
|
61
|
+
}
|
|
62
|
+
assertKnownKeys(ends, [sourceRole, targetRole], pointer);
|
|
63
|
+
for (const role of [sourceRole, targetRole]) {
|
|
64
|
+
if (!Object.hasOwn(ends, role)) {
|
|
65
|
+
fail('BUILDER_POLICY', `${pointer}/${escapeToken(role)}`, `edge(...) names both ends of ${ref.origin}:class.${ref.name}: "${sourceRole}" and "${targetRole}".`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (edgeOptions !== undefined)
|
|
69
|
+
assertKnownKeys(edgeOptions, ['repeat'], pointer);
|
|
70
|
+
if (edgeOptions?.repeat !== undefined) {
|
|
71
|
+
assertKnownKeys(edgeOptions.repeat, ['min', 'max'], `${pointer}/repeat`);
|
|
72
|
+
}
|
|
73
|
+
return edgePattern(ends[sourceRole], ref, ends[targetRole], edgeOptions?.repeat);
|
|
74
|
+
}),
|
|
55
75
|
exists(build) {
|
|
56
76
|
const nodes = [];
|
|
57
77
|
const bind = (selector, definition) => {
|
|
@@ -103,6 +123,15 @@ export function createPatternContext(options) {
|
|
|
103
123
|
};
|
|
104
124
|
return Object.freeze(context);
|
|
105
125
|
}
|
|
126
|
+
/** One Edge pattern, whichever form named its ends. */
|
|
127
|
+
function edgePattern(source, classRef, target, repeat) {
|
|
128
|
+
return {
|
|
129
|
+
source,
|
|
130
|
+
class: classRef,
|
|
131
|
+
target,
|
|
132
|
+
...(repeat === undefined ? {} : { repeat: { ...repeat } }),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
106
135
|
function composition(operator, policies) {
|
|
107
136
|
nonEmpty(policies, `/${operator}`);
|
|
108
137
|
const value = {
|
|
@@ -1,13 +1,119 @@
|
|
|
1
1
|
import type * as language from '../../../language/index.js';
|
|
2
|
+
import type { DomainSchema, DomainOfSchema } from '../../../schema/model/schema.js';
|
|
2
3
|
import type { NodeClass, DirectedEdgeClass, UndirectedEdgeClass, Class, ProjectionOfClass } from '../../class/handle.js';
|
|
3
4
|
import type { ClassReferenceProjection } from '../../class/projection.js';
|
|
4
5
|
import type { DomainSchemaInput } from '../input.js';
|
|
5
6
|
import type { OwnInstanceMethodProjectionsOf, OwnStaticMethodProjectionsOf } from './callable.js';
|
|
6
|
-
import type { AbstractOf, ConstraintsOf, ResolveLazy, LocalNameOfReference, ClassesInputOf, LocalNameOf } from './identity.js';
|
|
7
|
+
import type { AbstractOf, ConstraintsOf, ResolveLazy, LocalNameOfReference, ClassesInputOf, LocalNameOf, RecordField } from './identity.js';
|
|
7
8
|
import type { ClassProjection } from './model.js';
|
|
8
9
|
import type { EffectivePropertyProjectionsOf, OwnPropertyProjectionsOf } from './property.js';
|
|
9
10
|
import type { ClassProjectionOfResolved, ExactClass } from './resolved-class.js';
|
|
10
|
-
|
|
11
|
+
/**
|
|
12
|
+
* A Class an endpoint accepts as the Schema names it: an authored Class by the ref of every Class
|
|
13
|
+
* that bears its mark, else the ref it carries.
|
|
14
|
+
*/
|
|
15
|
+
type AcceptedRefOf<Origin extends string, Reference, Root extends DomainSchemaInput> = Reference extends unknown ? ResolveLazy<Reference> extends infer Resolved ? Resolved extends {
|
|
16
|
+
readonly kind: 'node';
|
|
17
|
+
} ? MarkedClassRefOf<Origin, Resolved, Root> : Resolved extends {
|
|
18
|
+
readonly origin: infer RefOrigin extends string;
|
|
19
|
+
readonly kind: 'class';
|
|
20
|
+
readonly name: infer RefName extends string;
|
|
21
|
+
} ? language.ClassRef<RefName> & {
|
|
22
|
+
readonly origin: RefOrigin;
|
|
23
|
+
} : language.ClassRef : never : never;
|
|
24
|
+
/** The mark the class authoring module gives an accepted Node Class (`AcceptedClassMark`). */
|
|
25
|
+
type ClassMarkOf<Value> = Value extends NodeClass<infer Config> ? {
|
|
26
|
+
readonly kind: 'node';
|
|
27
|
+
readonly abstract: Config extends {
|
|
28
|
+
readonly abstract: infer Abstract;
|
|
29
|
+
} ? Abstract : never;
|
|
30
|
+
readonly depth: Config extends {
|
|
31
|
+
readonly depth: infer Depth;
|
|
32
|
+
} ? Depth : never;
|
|
33
|
+
readonly properties: Config extends {
|
|
34
|
+
readonly effectiveProperties: infer Properties;
|
|
35
|
+
} ? Properties extends {
|
|
36
|
+
readonly name: infer Name;
|
|
37
|
+
} ? Name : never : never;
|
|
38
|
+
readonly methods: Config extends {
|
|
39
|
+
readonly effectiveInstanceMethods: infer Instance;
|
|
40
|
+
readonly effectiveStaticMethods: infer Static;
|
|
41
|
+
} ? Instance | Static extends infer Method ? Method extends {
|
|
42
|
+
readonly name: infer Name;
|
|
43
|
+
} ? Name : never : never : never;
|
|
44
|
+
} : never;
|
|
45
|
+
type Same<Left, Right> = [Left] extends [Right] ? ([Right] extends [Left] ? true : false) : false;
|
|
46
|
+
/** Every local Class name whose mark is the accepted mark. */
|
|
47
|
+
type LocalNameOfMark<Root extends DomainSchemaInput, Mark> = {
|
|
48
|
+
[Name in keyof ClassesInputOf<Root>]: Same<ClassMarkOf<ClassesInputOf<Root>[Name]>, Mark> extends true ? Name : never;
|
|
49
|
+
}[keyof ClassesInputOf<Root>];
|
|
50
|
+
/**
|
|
51
|
+
* Every Class an authored handle bearing the mark may be: the builder resolves the handle of a
|
|
52
|
+
* Class of the Schema or of a direct dependency, so either may bear it. The ref stays broad when no
|
|
53
|
+
* Class bears it or a dependency's Classes are not named in the types.
|
|
54
|
+
*/
|
|
55
|
+
type MarkedClassRefOf<Origin extends string, Mark, Root extends DomainSchemaInput> = LocalClassRefOf<Origin, LocalNameOfMark<Root, Mark>> | DependencyClassRefOfMark<Root, Mark> extends infer Refs ? [Refs] extends [never] ? language.ClassRef : Refs : never;
|
|
56
|
+
type LocalClassRefOf<Origin extends string, Name> = Name extends string ? language.ClassRef<Name> & {
|
|
57
|
+
readonly origin: Origin;
|
|
58
|
+
} : never;
|
|
59
|
+
/** The names of the members of a resolved collection. */
|
|
60
|
+
type MemberNamesOf<Collection> = Collection extends {
|
|
61
|
+
readonly byKey: infer ByKey;
|
|
62
|
+
} ? ByKey[keyof ByKey] extends infer Member ? Member extends {
|
|
63
|
+
readonly name: infer Name;
|
|
64
|
+
} ? Name : never : never : never;
|
|
65
|
+
/**
|
|
66
|
+
* A dependency Class may bear a mark when it agrees with it in abstractness and the names of its
|
|
67
|
+
* effective Properties, and its own Methods are among the mark's. Its resolved type keeps neither
|
|
68
|
+
* its depth nor the abstract Methods it inherits, so neither is compared.
|
|
69
|
+
*/
|
|
70
|
+
type ResolvedBearsMark<Value, Mark> = Value extends {
|
|
71
|
+
readonly kind: 'node';
|
|
72
|
+
readonly definition: {
|
|
73
|
+
readonly abstract: infer Abstract;
|
|
74
|
+
};
|
|
75
|
+
readonly properties: infer Properties;
|
|
76
|
+
readonly methods: infer Methods;
|
|
77
|
+
readonly static: {
|
|
78
|
+
readonly methods: infer StaticMethods;
|
|
79
|
+
};
|
|
80
|
+
} ? Mark extends {
|
|
81
|
+
readonly abstract: infer MarkAbstract;
|
|
82
|
+
readonly properties: infer MarkProperties;
|
|
83
|
+
readonly methods: infer MarkMethods;
|
|
84
|
+
} ? Same<{
|
|
85
|
+
readonly abstract: Abstract;
|
|
86
|
+
readonly properties: MemberNamesOf<Properties>;
|
|
87
|
+
}, {
|
|
88
|
+
readonly abstract: MarkAbstract;
|
|
89
|
+
readonly properties: MarkProperties;
|
|
90
|
+
}> extends true ? [MemberNamesOf<Methods> | MemberNamesOf<StaticMethods>] extends [MarkMethods] ? true : false : false : false : false;
|
|
91
|
+
/** Every Node Class of a direct dependency that may bear the mark. */
|
|
92
|
+
type DependencyClassRefOfMark<Root extends DomainSchemaInput, Mark> = {
|
|
93
|
+
[Alias in keyof RecordField<Root, 'dependencies'>]: RecordField<Root, 'dependencies'>[Alias] extends infer Schema extends DomainSchema ? DomainOfSchema<Schema>['classes'] extends infer Classes ? string extends keyof Classes ? language.ClassRef : {
|
|
94
|
+
[Name in keyof Classes]: ResolvedBearsMark<Classes[Name], Mark> extends true ? Classes[Name] extends {
|
|
95
|
+
readonly ref: {
|
|
96
|
+
readonly origin: infer RefOrigin extends string;
|
|
97
|
+
readonly name: infer RefName extends string;
|
|
98
|
+
};
|
|
99
|
+
} ? language.ClassRef<RefName> & {
|
|
100
|
+
readonly origin: RefOrigin;
|
|
101
|
+
} : never : never;
|
|
102
|
+
}[keyof Classes] : never : never;
|
|
103
|
+
}[keyof RecordField<Root, 'dependencies'>];
|
|
104
|
+
/** Every Class an endpoint accepts, in any order: the runtime list is canonically sorted. */
|
|
105
|
+
type AcceptedRefsOf<Origin extends string, Accepts, Root extends DomainSchemaInput> = Accepts extends readonly (infer Reference)[] ? readonly [AcceptedRefOf<Origin, Reference, Root>, ...AcceptedRefOf<Origin, Reference, Root>[]] : readonly [language.ClassRef, ...language.ClassRef[]];
|
|
106
|
+
/** One endpoint as the Schema stores it: its role and its exact accepted Classes. */
|
|
107
|
+
type ProjectedEndpoint<Origin extends string, Endpoint, Root extends DomainSchemaInput> = Endpoint extends {
|
|
108
|
+
readonly as: infer Role;
|
|
109
|
+
readonly accepts: infer Accepts;
|
|
110
|
+
} ? {
|
|
111
|
+
readonly role: Role;
|
|
112
|
+
readonly accepts: AcceptedRefsOf<Origin, Accepts, Root>;
|
|
113
|
+
readonly onDelete?: language.EdgeLifetime;
|
|
114
|
+
} : never;
|
|
115
|
+
type EdgeDefinitionFields = 'ref' | 'kind' | 'abstract' | 'orientation' | 'endpoints' | 'constraints';
|
|
116
|
+
type ProjectedClassDefinition<Origin extends string, Name extends string, Value, Root extends DomainSchemaInput> = Value extends NodeClass<infer Config> ? language.NodeClassDefinition & {
|
|
11
117
|
readonly ref: language.ClassRef<Name> & {
|
|
12
118
|
readonly origin: Origin;
|
|
13
119
|
};
|
|
@@ -22,7 +128,7 @@ type ProjectedClassDefinition<Origin extends string, Name extends string, Value>
|
|
|
22
128
|
readonly as: string;
|
|
23
129
|
readonly incoming: language.EdgeCount;
|
|
24
130
|
};
|
|
25
|
-
} ? language.
|
|
131
|
+
} ? Omit<language.DirectedEdgeDefinition, EdgeDefinitionFields> & {
|
|
26
132
|
readonly ref: language.ClassRef<Name> & {
|
|
27
133
|
readonly origin: Origin;
|
|
28
134
|
};
|
|
@@ -30,12 +136,10 @@ type ProjectedClassDefinition<Origin extends string, Name extends string, Value>
|
|
|
30
136
|
readonly abstract: AbstractOf<Input>;
|
|
31
137
|
readonly orientation: 'directed';
|
|
32
138
|
readonly endpoints: {
|
|
33
|
-
readonly source:
|
|
34
|
-
readonly role: Source['as'];
|
|
139
|
+
readonly source: ProjectedEndpoint<Origin, Source, Root> & {
|
|
35
140
|
readonly outgoing: Source['outgoing'];
|
|
36
141
|
};
|
|
37
|
-
readonly target:
|
|
38
|
-
readonly role: Target['as'];
|
|
142
|
+
readonly target: ProjectedEndpoint<Origin, Target, Root> & {
|
|
39
143
|
readonly incoming: Target['incoming'];
|
|
40
144
|
};
|
|
41
145
|
};
|
|
@@ -51,7 +155,7 @@ type ProjectedClassDefinition<Origin extends string, Name extends string, Value>
|
|
|
51
155
|
readonly incident: language.EdgeCount;
|
|
52
156
|
}
|
|
53
157
|
];
|
|
54
|
-
} ? language.
|
|
158
|
+
} ? Omit<language.UndirectedEdgeDefinition, EdgeDefinitionFields> & {
|
|
55
159
|
readonly ref: language.ClassRef<Name> & {
|
|
56
160
|
readonly origin: Origin;
|
|
57
161
|
};
|
|
@@ -59,12 +163,10 @@ type ProjectedClassDefinition<Origin extends string, Name extends string, Value>
|
|
|
59
163
|
readonly abstract: AbstractOf<Input>;
|
|
60
164
|
readonly orientation: 'undirected';
|
|
61
165
|
readonly endpoints: readonly [
|
|
62
|
-
|
|
63
|
-
readonly role: First['as'];
|
|
166
|
+
ProjectedEndpoint<Origin, First, Root> & {
|
|
64
167
|
readonly incident: First['incident'];
|
|
65
168
|
},
|
|
66
|
-
|
|
67
|
-
readonly role: Second['as'];
|
|
169
|
+
ProjectedEndpoint<Origin, Second, Root> & {
|
|
68
170
|
readonly incident: Second['incident'];
|
|
69
171
|
}
|
|
70
172
|
];
|
|
@@ -82,9 +184,9 @@ type ParentClassProjectionTuple<Origin extends string, Parents extends readonly
|
|
|
82
184
|
type ShallowClassProjectionOfAuthoring<Origin extends string, Name extends string, Value, Root extends DomainSchemaInput> = ClassProjectionWithParents<Origin, Name, Value, Root, readonly language.AnyResolvedClass[]>;
|
|
83
185
|
/** Project each authored Class independently before computing its parent tuple. */
|
|
84
186
|
export type ClassProjectionOfAuthoring<Origin extends string, Name extends string, Value, Root extends DomainSchemaInput, Seen = Value> = Value extends Class ? ClassProjectionWithParents<Origin, Name, Value, Root, ParentClassProjectionTuple<Origin, ParentInputsOfConfig<ProjectionOfClass<Extract<Value, Class>>>, Root, Seen>> : never;
|
|
85
|
-
type ClassProjectionWithParents<Origin extends string, Name extends string, Value, Root extends DomainSchemaInput, Parents extends readonly unknown[]> = Value extends NodeClass<infer _Config> ? ClassProjection<'node', Extract<ProjectedClassDefinition<Origin, Name, Value>, language.NodeClassDefinition>, language.ClassRef<Name> & {
|
|
187
|
+
type ClassProjectionWithParents<Origin extends string, Name extends string, Value, Root extends DomainSchemaInput, Parents extends readonly unknown[]> = Value extends NodeClass<infer _Config> ? ClassProjection<'node', Extract<ProjectedClassDefinition<Origin, Name, Value, Root>, language.NodeClassDefinition>, language.ClassRef<Name> & {
|
|
86
188
|
readonly origin: Origin;
|
|
87
|
-
}, language.DefinitionKey<Origin, 'class', Name>, Parents, EffectivePropertyProjectionsOf<Origin, Name, Value, Root>, OwnInstanceMethodProjectionsOf<Origin, Name, Value>, OwnStaticMethodProjectionsOf<Origin, Name, Value>, OwnPropertyProjectionsOf<Origin, Name, Value>, OwnInstanceMethodProjectionsOf<Origin, Name, Value>, OwnStaticMethodProjectionsOf<Origin, Name, Value>> : Value extends DirectedEdgeClass | UndirectedEdgeClass ? ClassProjection<'edge', Extract<ProjectedClassDefinition<Origin, Name, Value>, language.EdgeClassDefinition>, language.ClassRef<Name> & {
|
|
189
|
+
}, language.DefinitionKey<Origin, 'class', Name>, Parents, EffectivePropertyProjectionsOf<Origin, Name, Value, Root>, OwnInstanceMethodProjectionsOf<Origin, Name, Value>, OwnStaticMethodProjectionsOf<Origin, Name, Value>, OwnPropertyProjectionsOf<Origin, Name, Value>, OwnInstanceMethodProjectionsOf<Origin, Name, Value>, OwnStaticMethodProjectionsOf<Origin, Name, Value>> : Value extends DirectedEdgeClass | UndirectedEdgeClass ? ClassProjection<'edge', Extract<ProjectedClassDefinition<Origin, Name, Value, Root>, language.EdgeClassDefinition>, language.ClassRef<Name> & {
|
|
88
190
|
readonly origin: Origin;
|
|
89
191
|
}, language.DefinitionKey<Origin, 'class', Name>, Parents, EffectivePropertyProjectionsOf<Origin, Name, Value, Root>, never, never, OwnPropertyProjectionsOf<Origin, Name, Value>, never, never> : never;
|
|
90
192
|
export {};
|
package/dist/v1/bundle/codec.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { accept as acceptJsonValue, BoundaryError as JsonBoundaryError, json, } from '@astrale-os/kernel-dsl/value';
|
|
2
|
-
import { dependencyLimits } from '../addressing/domain-dependency.js';
|
|
3
2
|
import { compareUnicode } from '../addressing/ordering.js';
|
|
3
|
+
import { limits } from '../language/limits.js';
|
|
4
4
|
import { escapePointerToken } from '../language/value/syntax/pointer.js';
|
|
5
5
|
import { acceptDomainSchema } from '../schema/admission/accept.js';
|
|
6
6
|
import { canonicalDomainSchemaAfterValidation } from '../schema/canonical/revision.js';
|
|
@@ -46,12 +46,12 @@ function acceptBundleValue(input) {
|
|
|
46
46
|
const closure = structure.closure.map((schema, index) => candidate(schema, `/closure/${index}`));
|
|
47
47
|
const diagnostics = [];
|
|
48
48
|
const candidates = new Map();
|
|
49
|
-
if (closure.length + 1 >
|
|
50
|
-
diagnostics.push(diagnostic('DV_DEPENDENCY_LIMITS', '/closure', `A dependency closure may contain at most ${
|
|
49
|
+
if (closure.length + 1 > limits.dependency.closure) {
|
|
50
|
+
diagnostics.push(diagnostic('DV_DEPENDENCY_LIMITS', '/closure', `A dependency closure may contain at most ${limits.dependency.closure} Domains.`));
|
|
51
51
|
}
|
|
52
52
|
for (const entry of [root, ...closure]) {
|
|
53
|
-
if (Object.keys(entry.schema.dependencies).length >
|
|
54
|
-
diagnostics.push(diagnostic('DV_DEPENDENCY_LIMITS', `${entry.pointer}/dependencies`, `A Domain may declare at most ${
|
|
53
|
+
if (Object.keys(entry.schema.dependencies).length > limits.dependency.direct) {
|
|
54
|
+
diagnostics.push(diagnostic('DV_DEPENDENCY_LIMITS', `${entry.pointer}/dependencies`, `A Domain may declare at most ${limits.dependency.direct} direct dependency aliases.`));
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
for (const entry of closure) {
|
|
@@ -128,8 +128,8 @@ function collectReachable(current, root, candidates, reachable, active, revision
|
|
|
128
128
|
return;
|
|
129
129
|
}
|
|
130
130
|
active.add(current.key);
|
|
131
|
-
if (depth >
|
|
132
|
-
diagnostics.push(diagnostic('DV_DEPENDENCY_LIMITS', current.pointer, `Dependency depth ${depth} exceeds the maximum ${
|
|
131
|
+
if (depth > limits.dependency.depth) {
|
|
132
|
+
diagnostics.push(diagnostic('DV_DEPENDENCY_LIMITS', current.pointer, `Dependency depth ${depth} exceeds the maximum ${limits.dependency.depth}.`));
|
|
133
133
|
active.delete(current.key);
|
|
134
134
|
return;
|
|
135
135
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { accept as acceptPortable } from '@astrale-os/kernel-dsl/value';
|
|
2
|
-
import {
|
|
2
|
+
import { limits } from '../../language/limits.js';
|
|
3
3
|
import {} from '../model/schema.js';
|
|
4
4
|
import { validateClosure } from './closure.js';
|
|
5
5
|
import { invalid, pointer } from './diagnostic.js';
|
|
@@ -20,7 +20,7 @@ export function acceptCompiledSchema(input) {
|
|
|
20
20
|
const rootPin = dependency(root.root, 'root', '/root');
|
|
21
21
|
const machines = new Map();
|
|
22
22
|
const closure = array(root.closure, 'closure', '/closure').map((value, index) => entry(value, index, `/closure/${index}`, machines));
|
|
23
|
-
if (closure.length >
|
|
23
|
+
if (closure.length > limits.dependency.closure) {
|
|
24
24
|
invalid('dependency closure limit', 'COMPILED_DEPENDENCY_LIMITS', '/closure');
|
|
25
25
|
}
|
|
26
26
|
const closureOrigins = new Set();
|
|
@@ -34,7 +34,7 @@ export function acceptCompiledSchema(input) {
|
|
|
34
34
|
if (rootEntry?.revision !== rootPin.revision)
|
|
35
35
|
invalid('root pin', undefined, '/root');
|
|
36
36
|
for (const [entryIndex, owner] of closure.entries()) {
|
|
37
|
-
if (Object.keys(owner.dependencies).length >
|
|
37
|
+
if (Object.keys(owner.dependencies).length > limits.dependency.direct) {
|
|
38
38
|
invalid('direct dependency limit', 'COMPILED_DEPENDENCY_LIMITS', `/closure/${entryIndex}/dependencies`);
|
|
39
39
|
}
|
|
40
40
|
for (const [alias, pin] of Object.entries(owner.dependencies)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {} from '@astrale-os/kernel-dsl/value';
|
|
2
|
-
import { dependencyLimits } from '../../addressing/domain-dependency.js';
|
|
3
2
|
import { Key, isDefinitionRef } from '../../addressing/index.js';
|
|
4
3
|
import {} from '../../language/class/model/edge.js';
|
|
4
|
+
import { limits } from '../../language/limits.js';
|
|
5
5
|
import {} from '../model/schema.js';
|
|
6
6
|
import { invalid, pointer } from './diagnostic.js';
|
|
7
7
|
/** Require closed direct references, acyclic inheritance and concrete Core Classes. */
|
|
@@ -128,7 +128,7 @@ function validateDependencyCycles(candidate) {
|
|
|
128
128
|
const visited = new Set();
|
|
129
129
|
const frames = [];
|
|
130
130
|
const push = (origin, depth) => {
|
|
131
|
-
if (depth >
|
|
131
|
+
if (depth > limits.dependency.depth) {
|
|
132
132
|
invalid('dependency depth limit', 'COMPILED_DEPENDENCY_LIMITS', `/closure/${byOrigin.get(origin)?.index ?? 0}/dependencies`);
|
|
133
133
|
}
|
|
134
134
|
active.add(origin);
|