@astrale-os/kernel-dsl 0.2.0-beta.47 → 0.2.0-beta.49
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/patterns.d.ts +0 -5
- package/dist/v1/addressing/patterns.js +5 -5
- package/dist/v1/builder/callable/authoring.d.ts +1 -1
- package/dist/v1/builder/class/authoring.d.ts +0 -12
- package/dist/v1/builder/class/property.d.ts +1 -1
- package/dist/v1/builder/index.d.ts +1 -1
- package/dist/v1/builder/lowering/callable.d.ts +2 -1
- package/dist/v1/builder/lowering/core.d.ts +3 -2
- package/dist/v1/builder/lowering/schema/compile.js +14 -1
- package/dist/v1/builder/lowering/value/zod.d.ts +3 -2
- package/dist/v1/builder/lowering/view.d.ts +2 -1
- package/dist/v1/builder/schema/define.d.ts +4 -2
- package/dist/v1/builder/schema/handle.d.ts +2 -1
- package/dist/v1/builder/schema/input.d.ts +8 -0
- package/dist/v1/builder/schema/projection/callable.d.ts +51 -0
- package/dist/v1/builder/schema/projection/callable.js +1 -0
- package/dist/v1/builder/schema/projection/class.d.ts +89 -0
- package/dist/v1/builder/schema/projection/class.js +1 -0
- package/dist/v1/builder/schema/projection/core-input.d.ts +32 -0
- package/dist/v1/builder/schema/projection/core-input.js +1 -0
- package/dist/v1/builder/schema/projection/domain.d.ts +59 -0
- package/dist/v1/builder/schema/projection/domain.js +1 -0
- package/dist/v1/builder/schema/projection/identity.d.ts +39 -0
- package/dist/v1/builder/schema/projection/identity.js +1 -0
- package/dist/v1/builder/schema/projection/model.d.ts +59 -0
- package/dist/v1/builder/schema/projection/model.js +1 -0
- package/dist/v1/builder/schema/projection/property.d.ts +32 -0
- package/dist/v1/builder/schema/projection/property.js +1 -0
- package/dist/v1/builder/schema/projection/resolved-class.d.ts +76 -0
- package/dist/v1/builder/schema/projection/resolved-class.js +1 -0
- package/dist/v1/builder/schema/projection.d.ts +4 -375
- package/dist/v1/bundle/structure.d.ts +2 -1
- package/dist/v1/compiled/admission/accept.d.ts +1 -1
- package/dist/v1/compiled/admission/accept.js +7 -1005
- package/dist/v1/compiled/admission/closure.d.ts +3 -0
- package/dist/v1/compiled/admission/closure.js +173 -0
- package/dist/v1/compiled/admission/diagnostic.d.ts +7 -0
- package/dist/v1/compiled/admission/diagnostic.js +13 -0
- package/dist/v1/compiled/admission/revision.js +2 -0
- package/dist/v1/compiled/admission/semantics/cardinality.d.ts +5 -0
- package/dist/v1/compiled/admission/semantics/cardinality.js +113 -0
- package/dist/v1/compiled/admission/semantics/class.d.ts +5 -0
- package/dist/v1/compiled/admission/semantics/class.js +125 -0
- package/dist/v1/compiled/admission/semantics/context.d.ts +60 -0
- package/dist/v1/compiled/admission/semantics/context.js +81 -0
- package/dist/v1/compiled/admission/semantics/core.d.ts +35 -0
- package/dist/v1/compiled/admission/semantics/core.js +123 -0
- package/dist/v1/compiled/admission/semantics/edge.d.ts +8 -0
- package/dist/v1/compiled/admission/semantics/edge.js +89 -0
- package/dist/v1/compiled/admission/semantics/policy/admit.d.ts +4 -0
- package/dist/v1/compiled/admission/semantics/policy/admit.js +57 -0
- package/dist/v1/compiled/admission/semantics/policy/callable.d.ts +5 -0
- package/dist/v1/compiled/admission/semantics/policy/callable.js +72 -0
- package/dist/v1/compiled/admission/semantics/policy/contracts.d.ts +24 -0
- package/dist/v1/compiled/admission/semantics/policy/contracts.js +45 -0
- package/dist/v1/compiled/admission/semantics/policy/equality.d.ts +8 -0
- package/dist/v1/compiled/admission/semantics/policy/equality.js +27 -0
- package/dist/v1/compiled/admission/semantics/policy/measure.d.ts +9 -0
- package/dist/v1/compiled/admission/semantics/policy/measure.js +81 -0
- package/dist/v1/compiled/admission/semantics/policy/parity.d.ts +4 -0
- package/dist/v1/compiled/admission/semantics/policy/parity.js +126 -0
- package/dist/v1/compiled/admission/semantics/policy/pattern.d.ts +8 -0
- package/dist/v1/compiled/admission/semantics/policy/pattern.js +78 -0
- package/dist/v1/compiled/admission/semantics/policy/typing.d.ts +28 -0
- package/dist/v1/compiled/admission/semantics/policy/typing.js +206 -0
- package/dist/v1/compiled/admission/semantics/policy/variants.d.ts +10 -0
- package/dist/v1/compiled/admission/semantics/policy/variants.js +65 -0
- package/dist/v1/compiled/admission/semantics.d.ts +1 -1
- package/dist/v1/compiled/admission/semantics.js +8 -1222
- package/dist/v1/compiled/admission/wire/callable.d.ts +6 -0
- package/dist/v1/compiled/admission/wire/callable.js +90 -0
- package/dist/v1/compiled/admission/wire/class.d.ts +4 -0
- package/dist/v1/compiled/admission/wire/class.js +117 -0
- package/dist/v1/compiled/admission/wire/core.d.ts +5 -0
- package/dist/v1/compiled/admission/wire/core.js +32 -0
- package/dist/v1/compiled/admission/wire/dependency.d.ts +14 -0
- package/dist/v1/compiled/admission/wire/dependency.js +43 -0
- package/dist/v1/compiled/admission/wire/entry.d.ts +5 -0
- package/dist/v1/compiled/admission/wire/entry.js +100 -0
- package/dist/v1/compiled/admission/wire/pattern.d.ts +12 -0
- package/dist/v1/compiled/admission/wire/pattern.js +111 -0
- package/dist/v1/compiled/admission/wire/policy.d.ts +5 -0
- package/dist/v1/compiled/admission/wire/policy.js +168 -0
- package/dist/v1/compiled/admission/wire/program.d.ts +4 -0
- package/dist/v1/compiled/admission/wire/program.js +52 -0
- package/dist/v1/compiled/admission/wire/property.d.ts +4 -0
- package/dist/v1/compiled/admission/wire/property.js +74 -0
- package/dist/v1/compiled/admission/wire/reference.d.ts +8 -0
- package/dist/v1/compiled/admission/wire/reference.js +33 -0
- package/dist/v1/compiled/admission/wire/value.d.ts +29 -0
- package/dist/v1/compiled/admission/wire/value.js +98 -0
- package/dist/v1/compiled/admission/wire/view.d.ts +3 -0
- package/dist/v1/compiled/admission/wire/view.js +17 -0
- package/dist/v1/compiled/compiler/compile.js +2 -0
- package/dist/v1/compiled/model/schema.d.ts +5 -1
- package/dist/v1/domain/projection/classes.js +2 -9
- package/dist/v1/index.d.ts +1 -1
- package/dist/v1/language/class/inheritance.d.ts +12 -0
- package/dist/v1/language/class/inheritance.js +25 -0
- package/dist/v1/language/class/resolved.d.ts +5 -1
- package/dist/v1/language/definition/metadata.d.ts +8 -0
- package/dist/v1/language/definition/metadata.js +12 -0
- package/dist/v1/language/value/model/blob.d.ts +0 -2
- package/dist/v1/language/value/model/blob.js +2 -2
- package/dist/v1/language/value/model/instant.d.ts +0 -2
- package/dist/v1/language/value/model/instant.js +1 -1
- package/dist/v1/language/value/model/schema.d.ts +2 -1
- package/dist/v1/language/value/model/schema.js +1 -5
- package/dist/v1/language/value/reference/registry.d.ts +2 -1
- package/dist/v1/language/value/regexp/syntax.d.ts +2 -1
- package/dist/v1/language/view/model/view.d.ts +2 -10
- package/dist/v1/schema/analysis/class.d.ts +2 -1
- package/dist/v1/schema/canonical/revision.d.ts +2 -1
- package/dist/v1/schema/compatibility/comparators/classes.d.ts +2 -1
- package/dist/v1/schema/compatibility/coordinate.d.ts +2 -1
- package/dist/v1/schema/compatibility/references.js +1 -10
- package/dist/v1/schema/compatibility/report.d.ts +2 -1
- package/dist/v1/schema/compatibility/scope.d.ts +0 -4
- package/dist/v1/schema/compatibility/scope.js +1 -1
- package/dist/v1/schema/diagnostic.d.ts +1 -1
- package/dist/v1/schema/model/schema.d.ts +5 -1
- package/dist/v1/schema/normalization/domain.js +11 -6
- package/dist/v1/schema/resolution/definition.index.d.ts +1 -2
- package/dist/v1/schema/resolution/definition.index.js +0 -3
- package/dist/v1/schema/resolution/origins.d.ts +1 -1
- package/dist/v1/schema/resolution/origins.js +0 -5
- package/dist/v1/schema/validation/class.js +10 -50
- package/dist/v1/schema/validation/core.js +1 -27
- package/dist/v1/schema/validation/domain.d.ts +2 -1
- package/dist/v1/schema/validation/domain.structure.d.ts +0 -2
- package/dist/v1/schema/validation/domain.structure.js +8 -8
- package/dist/v1/schema/validation/policy/context.js +5 -16
- package/dist/v1/schema/validation/view.js +14 -9
- package/dist/value/accept.d.ts +1 -1
- package/dist/value/accept.js +32 -6
- package/dist/value/canonical.js +10 -2
- package/dist/value/immutable.optimization.d.ts +4 -1
- package/dist/value/immutable.optimization.js +8 -2
- package/dist/value/limits.d.ts +1 -1
- package/dist/value/unicode.d.ts +3 -0
- package/dist/value/unicode.js +27 -0
- package/package.json +1 -1
|
@@ -10,3 +10,11 @@ export declare const icon: Readonly<{
|
|
|
10
10
|
readonly minLength: 1;
|
|
11
11
|
readonly maxLength: 8000;
|
|
12
12
|
}>;
|
|
13
|
+
/** Exact V1 bound for the required human-facing display name a new Domain revision declares. */
|
|
14
|
+
export declare const name: Readonly<{
|
|
15
|
+
readonly type: 'string';
|
|
16
|
+
readonly minLength: 1;
|
|
17
|
+
readonly maxLength: 100;
|
|
18
|
+
}>;
|
|
19
|
+
/** The common source and compiled grammar for a name displayed exactly as authored. */
|
|
20
|
+
export declare function isDomainNameText(value: string): boolean;
|
|
@@ -10,3 +10,15 @@ export const icon = Object.freeze({
|
|
|
10
10
|
minLength: 1,
|
|
11
11
|
maxLength: 8000,
|
|
12
12
|
});
|
|
13
|
+
/** Exact V1 bound for the required human-facing display name a new Domain revision declares. */
|
|
14
|
+
export const name = Object.freeze({
|
|
15
|
+
type: 'string',
|
|
16
|
+
minLength: 1,
|
|
17
|
+
maxLength: 100,
|
|
18
|
+
});
|
|
19
|
+
// oxlint-disable-next-line no-control-regex
|
|
20
|
+
const DOMAIN_NAME_CONTROL = /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/u;
|
|
21
|
+
/** The common source and compiled grammar for a name displayed exactly as authored. */
|
|
22
|
+
export function isDomainNameText(value) {
|
|
23
|
+
return value.trim() === value && !DOMAIN_NAME_CONTROL.test(value);
|
|
24
|
+
}
|
|
@@ -21,8 +21,6 @@ export interface BlobOptions {
|
|
|
21
21
|
readonly mediaTypes?: readonly string[];
|
|
22
22
|
}
|
|
23
23
|
export declare const BLOB_VALUE_KIND: 'blob';
|
|
24
|
-
export declare const BLOB_DIGEST_PATTERN = "sha256:[0-9a-f]{64}";
|
|
25
|
-
export declare const BLOB_MEDIA_TYPE_PATTERN = "[a-z0-9!#$%&'*+.^_`|~-]+/[a-z0-9!#$%&'*+.^_`|~-]+(;[a-z0-9!#$%&'*+.^_`|~-]+=[!#$%&'*+.^_`|~0-9A-Za-z-]+)*";
|
|
26
24
|
/** Build the one canonical V1 schema shape for a blob-valued Node property. */
|
|
27
25
|
export declare function blob(options: BlobOptions): BlobSchema;
|
|
28
26
|
/** Marker recognition on an already admitted V1 value schema. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const BLOB_VALUE_KIND = 'blob';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
const BLOB_DIGEST_PATTERN = 'sha256:[0-9a-f]{64}';
|
|
3
|
+
const BLOB_MEDIA_TYPE_PATTERN = "[a-z0-9!#$%&'*+.^_`|~-]+/[a-z0-9!#$%&'*+.^_`|~-]+(;[a-z0-9!#$%&'*+.^_`|~-]+=[!#$%&'*+.^_`|~0-9A-Za-z-]+)*";
|
|
4
4
|
const TOKEN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/u;
|
|
5
5
|
const DIGEST = /^sha256:[0-9a-f]{64}$/u;
|
|
6
6
|
/** Build the one canonical V1 schema shape for a blob-valued Node property. */
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
/** Exact portable UTC millisecond Instant used by the V1 value-schema dialect. */
|
|
2
|
-
/** Canonical value-language annotation for an Instant string. */
|
|
3
|
-
export declare const INSTANT_VALUE_KIND: 'instant';
|
|
4
2
|
export declare const instant: Readonly<{
|
|
5
3
|
readonly type: 'string';
|
|
6
4
|
readonly 'x-astrale-value-kind': 'instant';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Exact portable UTC millisecond Instant used by the V1 value-schema dialect. */
|
|
2
2
|
/** Canonical value-language annotation for an Instant string. */
|
|
3
|
-
|
|
3
|
+
const INSTANT_VALUE_KIND = 'instant';
|
|
4
4
|
export const instant = Object.freeze({
|
|
5
5
|
type: 'string',
|
|
6
6
|
'x-astrale-value-kind': INSTANT_VALUE_KIND,
|
|
@@ -21,5 +21,6 @@ export interface PathAnnotation {
|
|
|
21
21
|
readonly cardinality: 'one';
|
|
22
22
|
readonly accepts: readonly ClassRef[];
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
declare const VALUE_SCHEMA_CONTEXTS: readonly ['property-facet', 'callable-input', 'callable-output'];
|
|
25
25
|
export type ValueSchemaContext = (typeof VALUE_SCHEMA_CONTEXTS)[number];
|
|
26
|
+
export {};
|
|
@@ -4,8 +4,4 @@ export const JSON_SCHEMA_DIALECT = 'https://json-schema.org/draft/2020-12/schema
|
|
|
4
4
|
export const VALUE_SCHEMA_DIALECT = 'https://schemas.astrale.ai/dsl/v1/value-schema';
|
|
5
5
|
/** Required vocabulary carried by the V1 value-schema dialect. */
|
|
6
6
|
export const VALUE_SCHEMA_VOCABULARY = 'https://schemas.astrale.ai/dsl/v1/value-schema/vocabulary';
|
|
7
|
-
|
|
8
|
-
'property-facet',
|
|
9
|
-
'callable-input',
|
|
10
|
-
'callable-output',
|
|
11
|
-
];
|
|
7
|
+
const VALUE_SCHEMA_CONTEXTS = ['property-facet', 'callable-input', 'callable-output'];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClassRef } from '../../../addressing/index.js';
|
|
2
2
|
import type { JsonSchema } from '../model/schema.js';
|
|
3
|
-
|
|
3
|
+
interface ValueSchemaDependency {
|
|
4
4
|
readonly origin: string;
|
|
5
5
|
readonly revision: `sha256:${string}`;
|
|
6
6
|
}
|
|
@@ -22,3 +22,4 @@ export interface ValueSchemaRegistry {
|
|
|
22
22
|
readonly transitiveDependencies: readonly ValueSchemaDomainRegistry[];
|
|
23
23
|
readonly graphNodePath: JsonSchema;
|
|
24
24
|
}
|
|
25
|
+
export {};
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
* parser's bounds on length, nesting and counts; `states` when its machine would exceed the state
|
|
4
4
|
* budget.
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
type IRegexpRefusal = 'syntax' | 'states';
|
|
7
7
|
/** The refusal of one source, through the same AST and state count as compilation. */
|
|
8
8
|
export declare function refuseIRegexp(source: string): IRegexpRefusal | undefined;
|
|
9
9
|
/** Complete RFC 9485 syntax admission, within the implementation limits RFC 9485 §8 allows. */
|
|
10
10
|
export declare function isIRegexp(source: string): boolean;
|
|
11
11
|
/** The authoring explanation of a `states` refusal of `subject` (`pattern`, `fullMatch`, ...). */
|
|
12
12
|
export declare function stateBudgetMessage(subject: string): string;
|
|
13
|
+
export {};
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
/**
|
|
3
|
-
* Document target of one View. Every View targets its owning Domain: authoring and compilation
|
|
4
|
-
* only produce `{ kind: 'domain' }`. The `definition` member is the legacy Class target of earlier
|
|
5
|
-
* V1 documents; admission still accepts it so already-persisted documents keep their exact revision
|
|
6
|
-
* and recover, but it carries no meaning and Runtime installation refuses it for a new revision.
|
|
7
|
-
*/
|
|
1
|
+
import type { DefinitionBase, ViewRef } from '../../../addressing/index.js';
|
|
2
|
+
/** Every View targets its owning Domain. */
|
|
8
3
|
export type ViewTarget = {
|
|
9
4
|
readonly kind: 'domain';
|
|
10
|
-
} | {
|
|
11
|
-
readonly kind: 'definition';
|
|
12
|
-
readonly definitions: readonly [ClassRef, ...ClassRef[]];
|
|
13
5
|
};
|
|
14
6
|
export interface ViewDefinition extends DefinitionBase<ViewRef> {
|
|
15
7
|
readonly description?: string;
|
|
@@ -25,7 +25,7 @@ export interface EffectiveMethod {
|
|
|
25
25
|
readonly name: string;
|
|
26
26
|
readonly declaration: MethodDefinition;
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
interface EffectiveData {
|
|
29
29
|
readonly identity: string;
|
|
30
30
|
readonly owner: ClassRef;
|
|
31
31
|
readonly declaration: DataDefinition;
|
|
@@ -68,3 +68,4 @@ export declare function methodSignature(value: MethodDefinition): {
|
|
|
68
68
|
durable: boolean;
|
|
69
69
|
} | undefined;
|
|
70
70
|
};
|
|
71
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Revision } from '../../addressing/index.js';
|
|
2
2
|
import { type DomainSchema, type DomainSchemaIR } from '../model/schema.js';
|
|
3
|
-
|
|
3
|
+
interface CanonicalDomainSchema {
|
|
4
4
|
readonly schema: DomainSchema;
|
|
5
5
|
readonly bytes: Uint8Array;
|
|
6
6
|
readonly revision: Revision;
|
|
@@ -9,3 +9,4 @@ export declare function canonicalDomainSchema(value: DomainSchema): CanonicalDom
|
|
|
9
9
|
/** Internal acceptance seam. The caller must establish whole-Domain validity first. */
|
|
10
10
|
export declare function canonicalDomainSchemaAfterValidation(value: DomainSchemaIR): CanonicalDomainSchema;
|
|
11
11
|
export declare function revisionOfDomainSchema(schema: DomainSchema): Revision;
|
|
12
|
+
export {};
|
|
@@ -6,7 +6,7 @@ import type { ClassCoordinate } from '../coordinate.js';
|
|
|
6
6
|
import type { DependencyMeaningLevel } from '../fields.js';
|
|
7
7
|
import type { Report } from '../report.js';
|
|
8
8
|
import type { ComparisonContext, SubjectPair } from '../scope.js';
|
|
9
|
-
|
|
9
|
+
interface ClassRequirement {
|
|
10
10
|
readonly ancestors: readonly SemanticKey[];
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
@@ -44,3 +44,4 @@ export declare function compareAddedProperties({ context, pair, report, }: {
|
|
|
44
44
|
readonly pair: SubjectPair;
|
|
45
45
|
readonly report: Report;
|
|
46
46
|
}): void;
|
|
47
|
+
export {};
|
|
@@ -29,7 +29,7 @@ export declare function memberCoordinate(ref: MemberRef): MemberCoordinate;
|
|
|
29
29
|
export declare function propertyCoordinate(owner: ClassRef, name: string): PropertyCoordinate;
|
|
30
30
|
export declare function methodCoordinate(owner: ClassRef, name: string): MethodCoordinate;
|
|
31
31
|
export declare function keyForDefinitionRef(ref: DefinitionRef): SemanticKey;
|
|
32
|
-
|
|
32
|
+
interface ParsedKeyReference {
|
|
33
33
|
readonly kind: Definition.Kind;
|
|
34
34
|
readonly name: string;
|
|
35
35
|
readonly member?: 'property' | 'method';
|
|
@@ -37,3 +37,4 @@ export interface ParsedKeyReference {
|
|
|
37
37
|
}
|
|
38
38
|
/** Interpret one canonical V1 Key as a Definition or a Class member location. */
|
|
39
39
|
export declare function keyReference(key: SemanticKey): ParsedKeyReference;
|
|
40
|
+
export {};
|
|
@@ -46,11 +46,6 @@ export function rootReferences(schema) {
|
|
|
46
46
|
collectCallableRefs(declaration, collector(schema, result, keyForDefinitionRef(declaration.ref)));
|
|
47
47
|
for (const declaration of Object.values(schema.policies))
|
|
48
48
|
collectPolicyDefinitionRefs(declaration, collector(schema, result, keyForDefinitionRef(declaration.ref)));
|
|
49
|
-
for (const declaration of Object.values(schema.views))
|
|
50
|
-
if (declaration.target.kind === 'definition') {
|
|
51
|
-
const add = collector(schema, result, keyForDefinitionRef(declaration.ref));
|
|
52
|
-
declaration.target.definitions.forEach((ref) => add(ref, 'view'));
|
|
53
|
-
}
|
|
54
49
|
collectCoreRefs(schema, collector(schema, result));
|
|
55
50
|
return result;
|
|
56
51
|
}
|
|
@@ -127,12 +122,8 @@ export function memberReferences(subject) {
|
|
|
127
122
|
case 'policy':
|
|
128
123
|
collectPolicyDefinitionRefs(schema.policies[ref.name], add);
|
|
129
124
|
break;
|
|
130
|
-
case 'view':
|
|
131
|
-
const view = schema.views[ref.name];
|
|
132
|
-
if (view.target.kind === 'definition')
|
|
133
|
-
view.target.definitions.forEach((ref) => add(ref, 'view'));
|
|
125
|
+
case 'view':
|
|
134
126
|
break;
|
|
135
|
-
}
|
|
136
127
|
case 'core': {
|
|
137
128
|
add(schema.core.nodes[ref.name].class, 'endpoint');
|
|
138
129
|
for (const edge of schema.core.edges) {
|
|
@@ -2,7 +2,7 @@ import type { Value } from '@astrale-os/kernel-dsl/value';
|
|
|
2
2
|
import type { Assessment, ComparisonEntry, Facet } from './model.js';
|
|
3
3
|
import type { Reference } from './references.js';
|
|
4
4
|
import type { SubjectPair } from './scope.js';
|
|
5
|
-
|
|
5
|
+
interface ComparisonFact {
|
|
6
6
|
readonly pair: SubjectPair;
|
|
7
7
|
readonly facet: Facet;
|
|
8
8
|
readonly before?: Value;
|
|
@@ -24,3 +24,4 @@ export declare function createReport(): {
|
|
|
24
24
|
export type Report = ReturnType<typeof createReport>;
|
|
25
25
|
/** Full comparison merges facts; it never reclassifies the two analyses' conclusions. */
|
|
26
26
|
export declare function mergeEntries(...groups: readonly (readonly ComparisonEntry[])[]): readonly ComparisonEntry[];
|
|
27
|
+
export {};
|
|
@@ -34,7 +34,3 @@ export declare function prepare(request: ComparisonRequest): ComparisonContext;
|
|
|
34
34
|
* of a version that may declare none.
|
|
35
35
|
*/
|
|
36
36
|
export declare function selectMembers(source: DomainSchema, target: DomainSchema, keys: readonly Key[]): ComparisonContext;
|
|
37
|
-
export declare function retainedContext(dependent: DomainSchema, origin: Key.Origin, path: '/target/origin' | '/origin'): {
|
|
38
|
-
source: DomainSchema;
|
|
39
|
-
context: Context;
|
|
40
|
-
};
|
|
@@ -99,7 +99,7 @@ function comparisonContext({ kind, source, target, dependent, before, roots, cap
|
|
|
99
99
|
},
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
|
-
|
|
102
|
+
function retainedContext(dependent, origin, path) {
|
|
103
103
|
resolve(dependent);
|
|
104
104
|
const source = (knownDomainClosure(dependent) ?? []).find((entry) => entry.schema.origin === origin)?.schema;
|
|
105
105
|
if (source === undefined)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type SchemaDiagnosticCode = 'DM_CAPABILITY_INVALID' | 'DM_MEMBER_ROOT_INVALID' | 'DM_DEPENDENCY_CONTEXT_INVALID' | 'DM_DEPENDENCY_NOT_RETAINED' | 'DM_MEANING_INCONSISTENT' | 'DM_MEMBER_ORIGIN_MISMATCH' | 'DV_ACCEPTANCE_CONTEXT' | 'DV_CALLABLE_AUTH' | 'DV_CALLABLE_IO' | 'DV_CALLABLE_POLICY_AUTH' | 'DV_CLASS_ABSTRACT' | 'DV_CLASS_ACYCLIC' | 'DV_CLASS_KIND' | 'DV_CORE_EDGE_CLASS' | 'DV_CORE_EDGE_CONSTRAINTS' | 'DV_CORE_EDGE_KEY' | 'DV_CORE_EDGE_PROPERTIES' | 'DV_CORE_NODE_CLASS' | 'DV_CORE_NODE_PROPERTIES' | 'DV_CORE_REF' | 'DV_DATA_COMPOSITION' | 'DV_DEPENDENCY_ACYCLIC' | 'DV_DEPENDENCY_DIRECT' | 'DV_DEPENDENCY_EXACT' | 'DV_DEPENDENCY_LIMITS' | 'DV_DEPENDENCY_REVISION_COHERENCE' | 'DV_DEPENDENCY_UNIQUE' | 'DV_EDGE_ACCEPTS' | 'DV_EDGE_CLASS_COMPOSITION' | 'DV_EDGE_CONSTRAINT' | 'DV_EDGE_ROLE' | 'DV_EDGE_UNDIRECTED' | 'DV_JSON_VALUE' | 'DV_METHOD_ABSTRACT' | 'DV_METHOD_COMPOSITION' | 'DV_PROPERTY_AUTO' | 'DV_PROPERTY_COMPOSITION' | 'DV_PROPERTY_IMMUTABLE' | 'DV_PROPERTY_STATE' | 'DV_REF_RESOLVES' | 'DV_VALUE_SCHEMA' | '
|
|
1
|
+
export type SchemaDiagnosticCode = 'DM_CAPABILITY_INVALID' | 'DM_MEMBER_ROOT_INVALID' | 'DM_DEPENDENCY_CONTEXT_INVALID' | 'DM_DEPENDENCY_NOT_RETAINED' | 'DM_MEANING_INCONSISTENT' | 'DM_MEMBER_ORIGIN_MISMATCH' | 'DV_ACCEPTANCE_CONTEXT' | 'DV_CALLABLE_AUTH' | 'DV_CALLABLE_IO' | 'DV_CALLABLE_POLICY_AUTH' | 'DV_CLASS_ABSTRACT' | 'DV_CLASS_ACYCLIC' | 'DV_CLASS_KIND' | 'DV_CORE_EDGE_CLASS' | 'DV_CORE_EDGE_CONSTRAINTS' | 'DV_CORE_EDGE_KEY' | 'DV_CORE_EDGE_PROPERTIES' | 'DV_CORE_NODE_CLASS' | 'DV_CORE_NODE_PROPERTIES' | 'DV_CORE_REF' | 'DV_DATA_COMPOSITION' | 'DV_DEPENDENCY_ACYCLIC' | 'DV_DEPENDENCY_DIRECT' | 'DV_DEPENDENCY_EXACT' | 'DV_DEPENDENCY_LIMITS' | 'DV_DEPENDENCY_REVISION_COHERENCE' | 'DV_DEPENDENCY_UNIQUE' | 'DV_EDGE_ACCEPTS' | 'DV_EDGE_CLASS_COMPOSITION' | 'DV_EDGE_CONSTRAINT' | 'DV_EDGE_ROLE' | 'DV_EDGE_UNDIRECTED' | 'DV_ENTRYPOINT' | 'DV_JSON_VALUE' | 'DV_METHOD_ABSTRACT' | 'DV_METHOD_COMPOSITION' | 'DV_PROPERTY_AUTO' | 'DV_PROPERTY_COMPOSITION' | 'DV_PROPERTY_IMMUTABLE' | 'DV_PROPERTY_STATE' | 'DV_REF_RESOLVES' | 'DV_VALUE_SCHEMA' | 'PL_BUDGET' | 'PL_COMPOSITION' | 'PL_CONNECTIVITY' | 'PL_REF' | 'PL_REPEAT' | 'PL_TARGET' | 'PL_TYPING' | 'PL_USE' | 'PL_VARIABLE_SCOPE' | 'STRUCTURE_ABSTRACT_POLICY' | 'STRUCTURE_CALLABLE_POLICY_AUTH' | 'STRUCTURE_DUPLICATE_ITEM' | 'STRUCTURE_EDGE_ORIENTATION' | 'STRUCTURE_FORMAT' | 'STRUCTURE_INVALID' | 'STRUCTURE_KEY' | 'STRUCTURE_MAXIMUM' | 'STRUCTURE_MINIMUM' | 'STRUCTURE_MULTIPLE' | 'STRUCTURE_REQUIRED' | 'STRUCTURE_TYPE' | 'STRUCTURE_UNION' | 'STRUCTURE_UNKNOWN_FIELD' | 'STRUCTURE_VALUE' | 'UNSUPPORTED_DOCUMENT_FORMAT' | 'UNSUPPORTED_DSL_VERSION';
|
|
2
2
|
export interface SchemaDiagnostic<out Code extends SchemaDiagnosticCode = SchemaDiagnosticCode> {
|
|
3
3
|
readonly code: Code;
|
|
4
4
|
readonly pointer: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Key } from '../../addressing/index.js';
|
|
2
|
-
import type { DomainDependencyMap } from '../../addressing/index.js';
|
|
2
|
+
import type { DomainDependencyMap, ViewRef } from '../../addressing/index.js';
|
|
3
3
|
import type { Domain, DomainOfSource, DomainSource } from '../../domain/model/domain.js';
|
|
4
4
|
import type { FunctionDefinition } from '../../language/callable/model/callable.js';
|
|
5
5
|
import type { ClassDefinition } from '../../language/class/model/class.js';
|
|
@@ -10,6 +10,10 @@ export interface DomainSchemaIR {
|
|
|
10
10
|
readonly format: 'astrale.dsl';
|
|
11
11
|
readonly version: 'v1';
|
|
12
12
|
readonly origin: Key.Origin;
|
|
13
|
+
/** Human-facing display name of the Domain, projected as its Domain Node `name`. */
|
|
14
|
+
readonly name: string;
|
|
15
|
+
/** The one View this Domain opens by default, projected as its `entrypoint` Edge. */
|
|
16
|
+
readonly entrypoint?: ViewRef;
|
|
13
17
|
readonly dependencies: DomainDependencyMap;
|
|
14
18
|
readonly classes: Readonly<Record<string, ClassDefinition>>;
|
|
15
19
|
readonly functions: Readonly<Record<string, FunctionDefinition>>;
|
|
@@ -13,6 +13,16 @@ export function normalizeDomainSchema(schema) {
|
|
|
13
13
|
format: 'astrale.dsl',
|
|
14
14
|
version: 'v1',
|
|
15
15
|
origin: schema.origin,
|
|
16
|
+
name: schema.name,
|
|
17
|
+
...(schema.entrypoint === undefined
|
|
18
|
+
? {}
|
|
19
|
+
: {
|
|
20
|
+
entrypoint: {
|
|
21
|
+
origin: schema.entrypoint.origin,
|
|
22
|
+
kind: 'view',
|
|
23
|
+
name: schema.entrypoint.name,
|
|
24
|
+
},
|
|
25
|
+
}),
|
|
16
26
|
dependencies: mapRecord(schema.dependencies, (dependency) => ({ ...dependency })),
|
|
17
27
|
classes,
|
|
18
28
|
functions: mapRecord(schema.functions, canonicalizeFunction),
|
|
@@ -42,12 +52,7 @@ function canonicalizeView(value) {
|
|
|
42
52
|
return {
|
|
43
53
|
ref: value.ref,
|
|
44
54
|
...withDescription(value),
|
|
45
|
-
target:
|
|
46
|
-
? { kind: 'domain' }
|
|
47
|
-
: {
|
|
48
|
-
kind: 'definition',
|
|
49
|
-
definitions: [...value.target.definitions].sort(compareDefinitionRefs),
|
|
50
|
-
},
|
|
55
|
+
target: { kind: 'domain' },
|
|
51
56
|
};
|
|
52
57
|
}
|
|
53
58
|
function canonicalizeClass(value) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClassRef
|
|
1
|
+
import type { ClassRef } from '../../addressing/index.js';
|
|
2
2
|
import type { ClassDefinition } from '../../language/class/model/class.js';
|
|
3
3
|
import type { DomainSchemaIR } from '../model/schema.js';
|
|
4
4
|
/** One exact Class declaration resolved within the retained Domain closure. */
|
|
@@ -18,4 +18,3 @@ export type IndexedClassDefinition = {
|
|
|
18
18
|
}>;
|
|
19
19
|
};
|
|
20
20
|
export declare function indexSchemaDefinitions(schema: DomainSchemaIR): ReadonlyMap<string, IndexedClassDefinition>;
|
|
21
|
-
export declare function resolveIndexedReference(indexes: ReadonlyMap<string, IndexedClassDefinition>, ref: DefinitionRef): IndexedClassDefinition | undefined;
|
|
@@ -10,7 +10,7 @@ import type { DomainSchemaIR } from '../model/schema.js';
|
|
|
10
10
|
* instantiates the Definition; every other site only refers to it. `pattern` is the Edge Class a
|
|
11
11
|
* Policy pattern matches, whose orientation and accepted endpoint Classes Policy typing reads.
|
|
12
12
|
*/
|
|
13
|
-
export type ReferenceSite = 'extends' | 'endpoint' | 'value' | 'policy' | 'pattern' | '
|
|
13
|
+
export type ReferenceSite = 'extends' | 'endpoint' | 'value' | 'policy' | 'pattern' | 'core';
|
|
14
14
|
/**
|
|
15
15
|
* What a site names: a Definition, or the Class-owned Method a Policy object term names. A Policy
|
|
16
16
|
* keeps the Method itself, since it resolves that Method's own executable declaration; a collector
|
|
@@ -25,11 +25,6 @@ export function collectDomainDefinitionRefs(schema) {
|
|
|
25
25
|
for (const declaration of Object.values(schema.policies)) {
|
|
26
26
|
collectPolicyDefinitionRefs(declaration, add);
|
|
27
27
|
}
|
|
28
|
-
for (const declaration of Object.values(schema.views)) {
|
|
29
|
-
if (declaration.target.kind === 'definition') {
|
|
30
|
-
declaration.target.definitions.forEach((ref) => add(ref, 'view'));
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
28
|
collectCoreRefs(schema, add);
|
|
34
29
|
return Object.freeze([...result.values()].sort(compareDefinitionRefs));
|
|
35
30
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Key } from '../../addressing/key.js';
|
|
2
2
|
import { definitionRefIndex } from '../../addressing/ordering.js';
|
|
3
3
|
import { isMethodExecutable } from '../../language/callable/executable.js';
|
|
4
|
+
import { classSatisfies as satisfiesClass, isGraphRoot } from '../../language/class/inheritance.js';
|
|
4
5
|
import { admitStateTopology } from '../../language/state/topology.js';
|
|
5
6
|
import { isBlobValueSchema } from '../../language/value/model/blob.js';
|
|
6
7
|
import { classifyOrdering } from '../../language/value/ordering.js';
|
|
@@ -114,10 +115,6 @@ function validateEdgeContract(environment, owner, declaration, diagnostics) {
|
|
|
114
115
|
validateEndpoint(environment, owner, endpoints[0], declaration.orientation === 'directed' ? 'source' : 'first endpoint', diagnostics);
|
|
115
116
|
validateEndpoint(environment, owner, endpoints[1], declaration.orientation === 'directed' ? 'target' : 'second endpoint', diagnostics);
|
|
116
117
|
if (declaration.orientation === 'undirected') {
|
|
117
|
-
if (!sameIncidentEndpointContract(declaration.endpoints[0], declaration.endpoints[1]) &&
|
|
118
|
-
undirectedEndpointsOverlap(environment, declaration.endpoints)) {
|
|
119
|
-
diagnostics.push(diagnostic('DV_EDGE_UNDIRECTED', '', `${formatDefinitionRef(owner)} has unequal undirected endpoint contracts whose accepted Node families overlap.`));
|
|
120
|
-
}
|
|
121
118
|
if (declaration.constraints.acyclic === true) {
|
|
122
119
|
diagnostics.push(diagnostic('DV_EDGE_CONSTRAINT', '', 'acyclic is valid only for directed Edge contracts.'));
|
|
123
120
|
}
|
|
@@ -160,6 +157,8 @@ function validateEdgeClassComposition(environment, diagnostics) {
|
|
|
160
157
|
}
|
|
161
158
|
/** Whether `child` safely refines its parent Edge contract `parent`. */
|
|
162
159
|
export function edgeContractRefines(environment, child, parent) {
|
|
160
|
+
if (isGraphRoot(parent))
|
|
161
|
+
return true;
|
|
163
162
|
if (child.orientation !== parent.orientation)
|
|
164
163
|
return false;
|
|
165
164
|
if (parent.constraints.noSelf === true && child.constraints.noSelf !== true)
|
|
@@ -195,57 +194,18 @@ function countRefines(child, parent) {
|
|
|
195
194
|
const [parentMinimum, parentMaximum] = bounds[parent];
|
|
196
195
|
return childMinimum >= parentMinimum && childMaximum <= parentMaximum;
|
|
197
196
|
}
|
|
198
|
-
function sameIncidentEndpointContract(left, right) {
|
|
199
|
-
if (left.incident !== right.incident)
|
|
200
|
-
return false;
|
|
201
|
-
const a = [...left.accepts].map(definitionRefIndex).sort();
|
|
202
|
-
const b = [...right.accepts].map(definitionRefIndex).sort();
|
|
203
|
-
return a.length === b.length && a.every((value, index) => value === b[index]);
|
|
204
|
-
}
|
|
205
|
-
function undirectedEndpointsOverlap(environment, endpoints) {
|
|
206
|
-
for (const resolved of environment.definitions.values()) {
|
|
207
|
-
if (resolved.ref.kind !== 'class' ||
|
|
208
|
-
resolved.declaration.kind !== 'node' ||
|
|
209
|
-
resolved.declaration.abstract) {
|
|
210
|
-
continue;
|
|
211
|
-
}
|
|
212
|
-
const candidate = resolved.ref;
|
|
213
|
-
if (classSatisfies(environment, candidate, endpoints[0].accepts) &&
|
|
214
|
-
classSatisfies(environment, candidate, endpoints[1].accepts)) {
|
|
215
|
-
return true;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return false;
|
|
219
|
-
}
|
|
220
197
|
/** Whether `candidate` is, or is a Node Class extending, one of `accepts`. */
|
|
221
198
|
export function classSatisfies(environment, candidate, accepts) {
|
|
222
199
|
if (accepts.some((ref) => definitionRefIndex(ref) === definitionRefIndex(candidate)))
|
|
223
200
|
return true;
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
resolved.declaration.kind !== 'node') {
|
|
201
|
+
const resolve = (ref) => environment.resolveAny(ref)?.declaration;
|
|
202
|
+
const actual = resolve(candidate);
|
|
203
|
+
if (actual?.kind !== 'node')
|
|
228
204
|
return false;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const accepted = new Set(accepts.map(definitionRefIndex));
|
|
234
|
-
for (const parent of parents) {
|
|
235
|
-
const key = definitionRefIndex(parent);
|
|
236
|
-
if (accepted.has(key))
|
|
237
|
-
return true;
|
|
238
|
-
if (visited.has(key))
|
|
239
|
-
continue;
|
|
240
|
-
visited.add(key);
|
|
241
|
-
const resolved = environment.resolveAny(parent);
|
|
242
|
-
if (resolved !== undefined &&
|
|
243
|
-
resolved.ref.kind === 'class' &&
|
|
244
|
-
extendsAny(environment, resolved.declaration.extends, accepts, visited)) {
|
|
245
|
-
return true;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
return false;
|
|
205
|
+
return accepts.some((ref) => {
|
|
206
|
+
const required = resolve(ref);
|
|
207
|
+
return required !== undefined && satisfiesClass(actual, required, resolve);
|
|
208
|
+
});
|
|
249
209
|
}
|
|
250
210
|
function localRef(origin, name) {
|
|
251
211
|
return { origin, kind: 'class', name };
|
|
@@ -4,6 +4,7 @@ import { isMethodExecutable } from '../../language/callable/executable.js';
|
|
|
4
4
|
import { policyObjectKey, policyObjectOrigin, projectedMemberClass, } from '../../language/policy/model/policy.js';
|
|
5
5
|
import { validateJsonInstance } from '../../language/value/evaluate/validate.js';
|
|
6
6
|
import { diagnostic } from '../diagnostic.js';
|
|
7
|
+
import { classSatisfies } from './class.js';
|
|
7
8
|
const formatDefinitionRef = Key.of;
|
|
8
9
|
export function validateCore(environment, analysis, registry) {
|
|
9
10
|
const diagnostics = [];
|
|
@@ -286,33 +287,6 @@ function hasDirectedCycle(edges) {
|
|
|
286
287
|
};
|
|
287
288
|
return [...outgoing.keys()].some(visit);
|
|
288
289
|
}
|
|
289
|
-
function classSatisfies(environment, classRef, accepts) {
|
|
290
|
-
if (accepts.some((ref) => definitionRefIndex(ref) === definitionRefIndex(classRef)))
|
|
291
|
-
return true;
|
|
292
|
-
const resolved = environment.resolveAny(classRef);
|
|
293
|
-
if (resolved === undefined || resolved.ref.kind !== 'class' || resolved.kind !== 'node') {
|
|
294
|
-
return false;
|
|
295
|
-
}
|
|
296
|
-
return classExtendsAny(environment, resolved.declaration.extends, accepts, new Set());
|
|
297
|
-
}
|
|
298
|
-
function classExtendsAny(environment, parents, accepts, visited) {
|
|
299
|
-
const accepted = new Set(accepts.map(definitionRefIndex));
|
|
300
|
-
for (const parent of parents) {
|
|
301
|
-
const key = definitionRefIndex(parent);
|
|
302
|
-
if (accepted.has(key))
|
|
303
|
-
return true;
|
|
304
|
-
if (visited.has(key))
|
|
305
|
-
continue;
|
|
306
|
-
visited.add(key);
|
|
307
|
-
const resolved = environment.resolveAny(parent);
|
|
308
|
-
if (resolved !== undefined &&
|
|
309
|
-
resolved.ref.kind === 'class' &&
|
|
310
|
-
classExtendsAny(environment, resolved.declaration.extends, accepts, visited)) {
|
|
311
|
-
return true;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
return false;
|
|
315
|
-
}
|
|
316
290
|
function escapePointer(value) {
|
|
317
291
|
return value.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
318
292
|
}
|
|
@@ -3,9 +3,10 @@ import type { DomainSchemaLookup } from '../dependency/lookup.js';
|
|
|
3
3
|
import type { SchemaDiagnostic } from '../diagnostic.js';
|
|
4
4
|
import type { DomainSchemaIR } from '../model/schema.js';
|
|
5
5
|
import type { DomainResolutionContext } from '../resolution/context.js';
|
|
6
|
-
|
|
6
|
+
interface DomainSchemaValidation {
|
|
7
7
|
readonly context: DomainResolutionContext;
|
|
8
8
|
readonly analysis: DefinitionAnalysisResult;
|
|
9
9
|
readonly diagnostics: readonly SchemaDiagnostic[];
|
|
10
10
|
}
|
|
11
11
|
export declare function validateDomainSchemaSemantics(schema: DomainSchemaIR, lookup: DomainSchemaLookup): DomainSchemaValidation;
|
|
12
|
+
export {};
|
|
@@ -17,6 +17,10 @@ const descriptionSchema = string()
|
|
|
17
17
|
.min(metadata.description.minLength)
|
|
18
18
|
.max(metadata.description.maxLength);
|
|
19
19
|
const iconSchema = string().min(metadata.icon.minLength).max(metadata.icon.maxLength);
|
|
20
|
+
const domainNameSchema = string()
|
|
21
|
+
.min(metadata.name.minLength)
|
|
22
|
+
.max(metadata.name.maxLength)
|
|
23
|
+
.refine(metadata.isDomainNameText, 'Expected one trimmed line of text.');
|
|
20
24
|
const jsonValueSchema = lazy(() => union([
|
|
21
25
|
nullSchema(),
|
|
22
26
|
boolean(),
|
|
@@ -292,13 +296,7 @@ const policyDefinitionSchema = strictObject({
|
|
|
292
296
|
expression: policyExpressionSchema,
|
|
293
297
|
description: descriptionSchema.optional(),
|
|
294
298
|
});
|
|
295
|
-
const viewTargetSchema =
|
|
296
|
-
strictObject({ kind: literal('domain') }),
|
|
297
|
-
strictObject({
|
|
298
|
-
kind: literal('definition'),
|
|
299
|
-
definitions: uniqueArray(classRefSchema).min(1),
|
|
300
|
-
}),
|
|
301
|
-
]);
|
|
299
|
+
const viewTargetSchema = strictObject({ kind: literal('domain') });
|
|
302
300
|
const viewDefinitionSchema = strictObject({
|
|
303
301
|
ref: viewRefSchema,
|
|
304
302
|
description: descriptionSchema.optional(),
|
|
@@ -323,6 +321,8 @@ const structuralSchema = strictObject({
|
|
|
323
321
|
format: literal(DOMAIN_FORMAT),
|
|
324
322
|
version: literal(DOMAIN_VERSION),
|
|
325
323
|
origin: originSchema,
|
|
324
|
+
name: domainNameSchema,
|
|
325
|
+
entrypoint: viewRefSchema.optional(),
|
|
326
326
|
dependencies: record(dependencyAliasSchema, domainDependencySchema),
|
|
327
327
|
classes: record(memberNameSchema, classDeclarationSchema),
|
|
328
328
|
functions: record(memberNameSchema, functionDefinitionSchema),
|
|
@@ -330,7 +330,7 @@ const structuralSchema = strictObject({
|
|
|
330
330
|
views: record(memberNameSchema, viewDefinitionSchema),
|
|
331
331
|
core: coreSchema,
|
|
332
332
|
});
|
|
333
|
-
|
|
333
|
+
const domainSchemaStructuralSchema = structuralSchema;
|
|
334
334
|
export function parseDomainSchemaStructure(input) {
|
|
335
335
|
const result = domainSchemaStructuralSchema.safeParse(input);
|
|
336
336
|
if (result.success)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Key } from '../../../addressing/index.js';
|
|
2
2
|
import { definitionRefIndex } from '../../../addressing/ordering.js';
|
|
3
|
+
import { classSatisfies } from '../../../language/class/inheritance.js';
|
|
3
4
|
import { diagnostic } from '../../diagnostic.js';
|
|
4
5
|
const formatDefinitionRef = Key.of;
|
|
5
6
|
export class PolicyValidationContext {
|
|
@@ -63,22 +64,10 @@ export class PolicyValidationContext {
|
|
|
63
64
|
}
|
|
64
65
|
/** Return true when candidate is the required Class or a same-kind descendant. */
|
|
65
66
|
classExtends(candidate, required) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
const key = definitionRefIndex(ref);
|
|
71
|
-
if (key === definitionRefIndex(required))
|
|
72
|
-
return true;
|
|
73
|
-
if (visited.has(key))
|
|
74
|
-
return false;
|
|
75
|
-
visited.add(key);
|
|
76
|
-
const resolved = this.environment.resolveAny(ref);
|
|
77
|
-
if (resolved === undefined || resolved.ref.kind !== 'class')
|
|
78
|
-
return false;
|
|
79
|
-
return resolved.declaration.extends.some(visit);
|
|
80
|
-
};
|
|
81
|
-
return visit(candidate);
|
|
67
|
+
const resolve = (ref) => this.environment.resolveAny(ref)?.declaration;
|
|
68
|
+
const actual = resolve(candidate);
|
|
69
|
+
const target = resolve(required);
|
|
70
|
+
return actual !== undefined && target !== undefined && classSatisfies(actual, target, resolve);
|
|
82
71
|
}
|
|
83
72
|
add(code, pointer, message, ref) {
|
|
84
73
|
this.diagnostics.push(diagnostic(code, pointer, message, ref));
|
|
@@ -9,21 +9,26 @@ export function validateViews(environment) {
|
|
|
9
9
|
if (!sameRef(view.ref, ref)) {
|
|
10
10
|
diagnostics.push(diagnostic('DV_REF_RESOLVES', `${pointer}/ref`, `View ref must be exactly ${formatDefinitionRef(ref)}.`, formatDefinitionRef(view.ref)));
|
|
11
11
|
}
|
|
12
|
-
if (view.target.kind === 'definition') {
|
|
13
|
-
view.target.definitions.forEach((ref, index) => validateDefinitionTarget(environment, ref, `${pointer}/target/definitions/${index}`, diagnostics));
|
|
14
|
-
}
|
|
15
12
|
}
|
|
13
|
+
validateEntrypoint(environment, diagnostics);
|
|
16
14
|
return Object.freeze(diagnostics);
|
|
17
15
|
}
|
|
16
|
+
/** The entrypoint names one View this Domain declares for itself. */
|
|
17
|
+
function validateEntrypoint(environment, diagnostics) {
|
|
18
|
+
const { entrypoint, origin, views } = environment.candidate;
|
|
19
|
+
if (entrypoint === undefined)
|
|
20
|
+
return;
|
|
21
|
+
// An own member only: a name such as `constructor` must not resolve on the prototype.
|
|
22
|
+
const view = entrypoint.origin === origin && Object.hasOwn(views, entrypoint.name)
|
|
23
|
+
? views[entrypoint.name]
|
|
24
|
+
: undefined;
|
|
25
|
+
if (view === undefined) {
|
|
26
|
+
diagnostics.push(diagnostic('DV_ENTRYPOINT', '/entrypoint', `Entrypoint ${formatDefinitionRef(entrypoint)} is not a Domain-targeted View of ${origin}.`, formatDefinitionRef(entrypoint)));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
18
29
|
function sameRef(left, right) {
|
|
19
30
|
return left.origin === right.origin && left.kind === right.kind && left.name === right.name;
|
|
20
31
|
}
|
|
21
|
-
function validateDefinitionTarget(environment, ref, pointer, diagnostics) {
|
|
22
|
-
const target = environment.resolve(ref);
|
|
23
|
-
if (target === undefined || target.ref.kind !== 'class' || target.kind !== 'node') {
|
|
24
|
-
diagnostics.push(diagnostic('DV_VIEW_TARGET', pointer, `Definition target ${formatDefinitionRef(ref)} does not resolve to a Node Class.`, formatDefinitionRef(ref)));
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
32
|
function escapePointer(value) {
|
|
28
33
|
return value.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
29
34
|
}
|