@astrale-os/kernel-dsl 0.2.0-beta.45 → 0.2.0-beta.47
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/class-key.js +5 -4
- package/dist/v1/addressing/method-key.js +3 -2
- package/dist/v1/builder/class/property.d.ts +3 -1
- package/dist/v1/builder/class/property.js +9 -1
- package/dist/v1/builder/lowering/schema/compile.js +1 -1
- package/dist/v1/builder/lowering/value/compile.js +3 -0
- package/dist/v1/builder/lowering/value/zod.js +11 -2
- package/dist/v1/builder/lowering/view.d.ts +2 -2
- package/dist/v1/builder/lowering/view.js +2 -14
- package/dist/v1/builder/schema/diagnostic.d.ts +1 -1
- package/dist/v1/builder/value/full-match.js +6 -3
- package/dist/v1/builder/view/authoring.d.ts +3 -7
- package/dist/v1/builder/view/authoring.js +5 -2
- package/dist/v1/compiled/admission/accept.js +31 -6
- package/dist/v1/compiled/admission/semantics.js +49 -16
- package/dist/v1/compiled/compiler/compile.js +1 -0
- package/dist/v1/compiled/loader/load.js +1 -0
- package/dist/v1/domain/create.js +0 -19
- package/dist/v1/domain/model/domain.d.ts +0 -1
- package/dist/v1/domain/model/input.d.ts +3 -0
- package/dist/v1/domain/projection/classes.js +1 -0
- package/dist/v1/domain/validation/create.d.ts +2 -0
- package/dist/v1/domain/validation/create.js +12 -0
- package/dist/v1/language/class/model/property.d.ts +3 -0
- package/dist/v1/language/class/resolved.d.ts +3 -0
- package/dist/v1/language/index.d.ts +2 -0
- package/dist/v1/language/index.js +1 -0
- package/dist/v1/language/policy/normalization/normalize.d.ts +4 -0
- package/dist/v1/language/policy/normalization/normalize.js +51 -13
- package/dist/v1/language/value/inclusion/includes.d.ts +9 -0
- package/dist/v1/language/value/inclusion/includes.js +777 -0
- package/dist/v1/language/value/profile/rules.js +11 -32
- package/dist/v1/language/value/regexp/ast.js +3 -64
- package/dist/v1/language/value/regexp/compile.d.ts +25 -2
- package/dist/v1/language/value/regexp/compile.js +48 -12
- package/dist/v1/language/value/regexp/syntax.d.ts +11 -1
- package/dist/v1/language/value/regexp/syntax.js +14 -2
- package/dist/v1/language/value/regexp/unicode.d.ts +32 -0
- package/dist/v1/language/value/regexp/unicode.js +139 -0
- package/dist/v1/language/value/syntax/full-match.js +6 -3
- package/dist/v1/language/view/model/view.d.ts +6 -0
- package/dist/v1/language/view/resolved.d.ts +2 -2
- package/dist/v1/schema/analysis/class.d.ts +2 -1
- package/dist/v1/schema/analysis/class.js +1 -0
- package/dist/v1/schema/compatibility/comparators/callables.d.ts +7 -0
- package/dist/v1/schema/compatibility/comparators/callables.js +13 -0
- package/dist/v1/schema/compatibility/comparators/classes.d.ts +18 -0
- package/dist/v1/schema/compatibility/comparators/classes.js +54 -0
- package/dist/v1/schema/compatibility/comparators/index.d.ts +1 -1
- package/dist/v1/schema/compatibility/comparators/index.js +14 -2
- package/dist/v1/schema/compatibility/context.d.ts +6 -2
- package/dist/v1/schema/compatibility/context.js +12 -6
- package/dist/v1/schema/compatibility/evidence.d.ts +8 -1
- package/dist/v1/schema/compatibility/evidence.js +10 -1
- package/dist/v1/schema/compatibility/fields.d.ts +2 -0
- package/dist/v1/schema/compatibility/fields.js +1 -0
- package/dist/v1/schema/compatibility/meaning/footprint.js +3 -1
- package/dist/v1/schema/compatibility/meaning/index.js +4 -2
- package/dist/v1/schema/compatibility/model.d.ts +11 -6
- package/dist/v1/schema/compatibility/references.d.ts +8 -1
- package/dist/v1/schema/compatibility/references.js +39 -6
- package/dist/v1/schema/compatibility/scope.d.ts +5 -0
- package/dist/v1/schema/compatibility/scope.js +5 -2
- package/dist/v1/schema/compatibility/structure/index.js +21 -2
- package/dist/v1/schema/compatibility/structure/requirements.js +26 -1
- package/dist/v1/schema/compatibility/subjects.js +20 -2
- package/dist/v1/schema/diagnostic.d.ts +1 -1
- package/dist/v1/schema/normalization/domain.js +1 -0
- package/dist/v1/schema/resolution/domain.d.ts +4 -1
- package/dist/v1/schema/resolution/domain.js +7 -7
- package/dist/v1/schema/resolution/origins.d.ts +11 -4
- package/dist/v1/schema/resolution/origins.js +7 -8
- package/dist/v1/schema/validation/class.d.ts +10 -0
- package/dist/v1/schema/validation/class.js +13 -2
- package/dist/v1/schema/validation/domain.structure.js +1 -0
- package/package.json +1 -1
|
@@ -49,6 +49,30 @@ export function classMeaning(context, coordinate, level, onto) {
|
|
|
49
49
|
};
|
|
50
50
|
return { meaning: deepFreeze(meaning), requirement };
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* What a Policy pattern reads of an Edge it matches: its orientation and the Classes each endpoint
|
|
54
|
+
* accepts, without cardinalities or roles. Undirected endpoints form an unordered pair.
|
|
55
|
+
*/
|
|
56
|
+
export function edgeEndpoints(context, coordinate) {
|
|
57
|
+
const declaration = context.schemas.get(coordinate.ref.origin)?.classes[coordinate.ref.name];
|
|
58
|
+
if (declaration?.kind !== 'edge')
|
|
59
|
+
return undefined;
|
|
60
|
+
const accepts = ({ accepts: refs }) => refs.map(keyForDefinitionRef).sort(compareUnicode);
|
|
61
|
+
return deepFreeze(declaration.orientation === 'directed'
|
|
62
|
+
? {
|
|
63
|
+
coordinate: 'class',
|
|
64
|
+
orientation: 'directed',
|
|
65
|
+
source: accepts(declaration.endpoints.source),
|
|
66
|
+
target: accepts(declaration.endpoints.target),
|
|
67
|
+
}
|
|
68
|
+
: {
|
|
69
|
+
coordinate: 'class',
|
|
70
|
+
orientation: 'undirected',
|
|
71
|
+
endpoints: declaration.endpoints
|
|
72
|
+
.map(accepts)
|
|
73
|
+
.sort((left, right) => compareUnicode(left.join('\n'), right.join('\n'))),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
52
76
|
export function propertyMeaning(field) {
|
|
53
77
|
return deepFreeze({
|
|
54
78
|
coordinate: 'property',
|
|
@@ -75,6 +99,36 @@ function ancestorKeys(context, ref) {
|
|
|
75
99
|
visit(ref);
|
|
76
100
|
return [...seen].sort(compareUnicode);
|
|
77
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* A Class a dependent references or inherits keeps every effective Property it had, whichever
|
|
104
|
+
* ancestor declares it. Each Property is compared on its owner, which still declares it when the
|
|
105
|
+
* Class stops extending that owner, and is not compared at all when another origin owns it: only the
|
|
106
|
+
* Class's own identity set shows those losses. Every loss is recorded, a Property its owner removed
|
|
107
|
+
* included, and only a loss is: a comparison that keeps every identity keeps its facts and evidence
|
|
108
|
+
* bytes, and an added ancestor or Property obliges nothing. The target is projected onto the source
|
|
109
|
+
* identities, as inherited ancestry is, so the differences name the lost Properties.
|
|
110
|
+
*/
|
|
111
|
+
export function compareLostProperties({ pair, report, }) {
|
|
112
|
+
if (pair.source?.kind !== 'class' || pair.target?.kind !== 'class')
|
|
113
|
+
return;
|
|
114
|
+
const kept = pair.target.analysis.properties;
|
|
115
|
+
const identities = [...pair.source.analysis.properties.keys()].sort(compareUnicode);
|
|
116
|
+
if (identities.every((identity) => kept.has(identity)))
|
|
117
|
+
return;
|
|
118
|
+
report.record({
|
|
119
|
+
pair,
|
|
120
|
+
facet: 'class.properties',
|
|
121
|
+
before: propertyIdentities(identities),
|
|
122
|
+
after: propertyIdentities(identities.filter((identity) => kept.has(identity))),
|
|
123
|
+
requirement: { kind: 'class.properties' },
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function propertyIdentities(identities) {
|
|
127
|
+
return deepFreeze({
|
|
128
|
+
coordinate: 'class',
|
|
129
|
+
properties: Object.fromEntries(identities.map((identity) => [identity, true])),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
78
132
|
/** Newly required data is an obligation even though it was absent from the source footprint. */
|
|
79
133
|
export function compareAddedProperties({ context, pair, report, }) {
|
|
80
134
|
if (pair.source?.kind !== 'class' || pair.target?.kind !== 'class')
|
|
@@ -5,7 +5,7 @@ import type { ComparisonContext, SubjectPair } from '../scope.js';
|
|
|
5
5
|
export declare function compareFacet({ context, pair, facet, }: {
|
|
6
6
|
readonly context: ComparisonContext;
|
|
7
7
|
readonly pair: SubjectPair;
|
|
8
|
-
readonly facet: Exclude<Facet, 'class.composition' | 'property.required'>;
|
|
8
|
+
readonly facet: Exclude<Facet, 'class.composition' | 'class.properties' | 'property.required'>;
|
|
9
9
|
}): {
|
|
10
10
|
readonly before?: Value;
|
|
11
11
|
readonly after?: Value;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { methodInheritance, functionSignature, functionExistence, methodSignature, methodExistence, } from './callables.js';
|
|
2
|
-
import { classMeaning, propertyMeaning } from './classes.js';
|
|
1
|
+
import { methodInheritance, functionSignature, functionExistence, methodObject, methodSignature, methodExistence, } from './callables.js';
|
|
2
|
+
import { classMeaning, edgeEndpoints, propertyMeaning } from './classes.js';
|
|
3
3
|
import { memberMeaning } from './members.js';
|
|
4
4
|
/** Shared facet comparisons know declarations, never installation or an analysis mode. */
|
|
5
5
|
export function compareFacet({ context, pair, facet, }) {
|
|
@@ -11,6 +11,14 @@ export function compareFacet({ context, pair, facet, }) {
|
|
|
11
11
|
const after = classMeaning(context.after, pair.coordinate, level, before?.requirement);
|
|
12
12
|
return { before: before?.meaning, after: after?.meaning };
|
|
13
13
|
}
|
|
14
|
+
if (facet === 'class.endpoints') {
|
|
15
|
+
if (pair.coordinate.kind !== 'class')
|
|
16
|
+
throw new TypeError('Class facet requires a Class coordinate.');
|
|
17
|
+
return {
|
|
18
|
+
before: edgeEndpoints(context.before, pair.coordinate),
|
|
19
|
+
after: edgeEndpoints(context.after, pair.coordinate),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
14
22
|
const value = (subject) => {
|
|
15
23
|
if (subject === undefined)
|
|
16
24
|
return undefined;
|
|
@@ -19,6 +27,10 @@ export function compareFacet({ context, pair, facet, }) {
|
|
|
19
27
|
return subject.kind === 'property' ? propertyMeaning(subject.field) : undefined;
|
|
20
28
|
case 'method.existence':
|
|
21
29
|
return subject.kind === 'method' ? methodExistence(subject.method) : undefined;
|
|
30
|
+
case 'method.object':
|
|
31
|
+
return subject.kind === 'method'
|
|
32
|
+
? methodObject(subject.method, subject.schema.classes[subject.method.owner.name])
|
|
33
|
+
: undefined;
|
|
22
34
|
case 'method.signature':
|
|
23
35
|
return subject.kind === 'method' ? methodSignature(subject.method) : undefined;
|
|
24
36
|
case 'method.inheritance':
|
|
@@ -2,11 +2,15 @@ import type { ClassRef, DefinitionRef, Key as SemanticKey } from '../../addressi
|
|
|
2
2
|
import type { DefinitionAnalysis, EffectiveMethod } from '../analysis/class.js';
|
|
3
3
|
import type { DomainSchema } from '../model/schema.js';
|
|
4
4
|
import { SchemaError } from '../diagnostic.js';
|
|
5
|
-
/** One accepted root with its exact closure and a memoized
|
|
5
|
+
/** One accepted root with its exact closure and a memoized Definition analysis per owner. */
|
|
6
6
|
export interface Context {
|
|
7
7
|
readonly schemas: ReadonlyMap<string, DomainSchema>;
|
|
8
|
-
analysis(owner: DomainSchema): ReadonlyMap<string, DefinitionAnalysis
|
|
8
|
+
analysis(owner: DomainSchema): ReadonlyMap<string, DefinitionAnalysis>;
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Every owner passed acceptance against the closure it retains, which is the only way a schema
|
|
12
|
+
* gets one, so its analysis is derived without validating it again.
|
|
13
|
+
*/
|
|
10
14
|
export declare function contextOf(root: DomainSchema): Context;
|
|
11
15
|
export declare function effectiveDefinition(context: Context, owner: DomainSchema, ref: ClassRef): DefinitionAnalysis | undefined;
|
|
12
16
|
/** Effective Methods are keyed by name; a coordinate names one by its exact Method Key. */
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { MethodKey } from '../../addressing/index.js';
|
|
2
2
|
import { definitionRefIndex } from '../../addressing/ordering.js';
|
|
3
|
+
import { analyzeDefinitions } from '../analysis/class.js';
|
|
3
4
|
import { SchemaError, diagnostic } from '../diagnostic.js';
|
|
4
5
|
import { knownDomainClosure, lookupForDomainClosure } from '../resolution/closure.js';
|
|
5
|
-
import {
|
|
6
|
+
import { buildDomainResolutionContext } from '../resolution/context.js';
|
|
7
|
+
/**
|
|
8
|
+
* Every owner passed acceptance against the closure it retains, which is the only way a schema
|
|
9
|
+
* gets one, so its analysis is derived without validating it again.
|
|
10
|
+
*/
|
|
6
11
|
export function contextOf(root) {
|
|
7
12
|
const schemas = new Map([
|
|
8
13
|
[root.origin, root],
|
|
@@ -12,16 +17,17 @@ export function contextOf(root) {
|
|
|
12
17
|
return {
|
|
13
18
|
schemas,
|
|
14
19
|
analysis(owner) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
let definitions = analyses.get(owner);
|
|
21
|
+
if (definitions === undefined) {
|
|
22
|
+
definitions = analyzeDefinitions(buildDomainResolutionContext(owner, lookupForDomainClosure(owner))).definitions;
|
|
23
|
+
analyses.set(owner, definitions);
|
|
18
24
|
}
|
|
19
|
-
return
|
|
25
|
+
return definitions;
|
|
20
26
|
},
|
|
21
27
|
};
|
|
22
28
|
}
|
|
23
29
|
export function effectiveDefinition(context, owner, ref) {
|
|
24
|
-
return context.analysis(owner)
|
|
30
|
+
return context.analysis(owner).get(definitionRefIndex(ref));
|
|
25
31
|
}
|
|
26
32
|
/** Effective Methods are keyed by name; a coordinate names one by its exact Method Key. */
|
|
27
33
|
export function effectiveMethod(analysis, key) {
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { Analysis, ComparisonEvidence } from './model.js';
|
|
2
2
|
/**
|
|
3
3
|
* Only semantic facts and decisions are durable; provenance and diagnostic prose are not. Each
|
|
4
|
-
* analysis names the
|
|
4
|
+
* analysis names the oldest requirement policy that yields its facts: a version applies exactly when
|
|
5
|
+
* a fact it introduced is recorded, so a comparison without one keeps the earlier version's bytes.
|
|
5
6
|
*/
|
|
6
7
|
export declare function evidenceOf({ kind, version, scope, entries, assessments, }: Omit<Analysis, 'evidence'> & {
|
|
7
8
|
readonly kind: ComparisonEvidence['kind'];
|
|
8
9
|
readonly version: ComparisonEvidence['version'];
|
|
9
10
|
}): ComparisonEvidence;
|
|
11
|
+
/**
|
|
12
|
+
* Whether a referenced or inherited Class lost an effective Property. The fact is recorded only on a
|
|
13
|
+
* loss, so the evidence version that introduced it applies exactly when it is present
|
|
14
|
+
* (DM-CLASS-PROPERTIES).
|
|
15
|
+
*/
|
|
16
|
+
export declare function losesProperties({ entries }: Pick<Analysis, 'entries'>): boolean;
|
|
@@ -2,7 +2,8 @@ import { compareUnicode } from '../../addressing/ordering.js';
|
|
|
2
2
|
import { fingerprintMeaning } from './comparators/values.js';
|
|
3
3
|
/**
|
|
4
4
|
* Only semantic facts and decisions are durable; provenance and diagnostic prose are not. Each
|
|
5
|
-
* analysis names the
|
|
5
|
+
* analysis names the oldest requirement policy that yields its facts: a version applies exactly when
|
|
6
|
+
* a fact it introduced is recorded, so a comparison without one keeps the earlier version's bytes.
|
|
6
7
|
*/
|
|
7
8
|
export function evidenceOf({ kind, version, scope, entries, assessments, }) {
|
|
8
9
|
return Object.freeze({
|
|
@@ -38,6 +39,14 @@ export function evidenceOf({ kind, version, scope, entries, assessments, }) {
|
|
|
38
39
|
}),
|
|
39
40
|
});
|
|
40
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Whether a referenced or inherited Class lost an effective Property. The fact is recorded only on a
|
|
44
|
+
* loss, so the evidence version that introduced it applies exactly when it is present
|
|
45
|
+
* (DM-CLASS-PROPERTIES).
|
|
46
|
+
*/
|
|
47
|
+
export function losesProperties({ entries }) {
|
|
48
|
+
return entries.some(({ observations }) => observations.some(({ facet }) => facet === 'class.properties'));
|
|
49
|
+
}
|
|
41
50
|
/** Version-1 evidence keeps its original tags independently of public facet names. */
|
|
42
51
|
function evidenceFacet(facet) {
|
|
43
52
|
switch (facet) {
|
|
@@ -43,6 +43,7 @@ export declare const PROPERTY_FIELDS: Readonly<{
|
|
|
43
43
|
schema: "always";
|
|
44
44
|
required: "always";
|
|
45
45
|
auto: "always";
|
|
46
|
+
immutable: "always";
|
|
46
47
|
state: "always";
|
|
47
48
|
description: Readonly<{
|
|
48
49
|
excluded: 'annotation';
|
|
@@ -132,6 +133,7 @@ export declare const FIELD_ROLES: Readonly<{
|
|
|
132
133
|
schema: "always";
|
|
133
134
|
required: "always";
|
|
134
135
|
auto: "always";
|
|
136
|
+
immutable: "always";
|
|
135
137
|
state: "always";
|
|
136
138
|
description: Readonly<{
|
|
137
139
|
excluded: 'annotation';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Key } from '../../../addressing/index.js';
|
|
2
|
-
import { compareAddedProperties } from '../comparators/classes.js';
|
|
2
|
+
import { compareAddedProperties, compareLostProperties } from '../comparators/classes.js';
|
|
3
3
|
import { compareFacet } from '../comparators/index.js';
|
|
4
4
|
import { contextInvalid } from '../context.js';
|
|
5
5
|
import { callableReferences, classReferences, inherits, memberReferences, valueReferences, } from '../references.js';
|
|
@@ -53,5 +53,7 @@ export function compareFootprint({ context, report, }) {
|
|
|
53
53
|
});
|
|
54
54
|
if (facet === 'class.inherit')
|
|
55
55
|
compareAddedProperties({ context, pair, report });
|
|
56
|
+
if (subject.kind === 'class')
|
|
57
|
+
compareLostProperties({ pair, report });
|
|
56
58
|
}
|
|
57
59
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { evidenceOf } from '../evidence.js';
|
|
1
|
+
import { evidenceOf, losesProperties } from '../evidence.js';
|
|
2
2
|
import { createReport } from '../report.js';
|
|
3
3
|
import { compareFootprint } from './footprint.js';
|
|
4
4
|
export function analyzeMeaning(context) {
|
|
@@ -9,6 +9,8 @@ export function analyzeMeaning(context) {
|
|
|
9
9
|
kind: 'meaning',
|
|
10
10
|
...result,
|
|
11
11
|
equivalent: result.assessments.every(({ satisfied }) => satisfied),
|
|
12
|
-
|
|
12
|
+
// Version 2 adds a referenced or inherited Class that lost an effective Property; without it,
|
|
13
|
+
// version 1.
|
|
14
|
+
evidence: evidenceOf({ kind: 'meaning', version: losesProperties(result) ? 2 : 1, ...result }),
|
|
13
15
|
});
|
|
14
16
|
}
|
|
@@ -46,7 +46,7 @@ export interface Usage {
|
|
|
46
46
|
readonly key?: Key;
|
|
47
47
|
readonly relation: ReferenceSite | 'member' | 'abstract' | 'selection' | 'capability';
|
|
48
48
|
}
|
|
49
|
-
export type Facet = 'class.reference' | 'class.inherit' | 'class.composition' | 'property' | 'property.required' | 'method.existence' | 'method.inheritance' | 'method.signature' | 'function.existence' | 'function.signature' | 'policy' | 'view' | 'core';
|
|
49
|
+
export type Facet = 'class.reference' | 'class.inherit' | 'class.composition' | 'class.properties' | 'class.endpoints' | 'property' | 'property.required' | 'method.existence' | 'method.object' | 'method.inheritance' | 'method.signature' | 'function.existence' | 'function.signature' | 'policy' | 'view' | 'core';
|
|
50
50
|
/** A fact about a compared facet, including unchanged facets. No admission decision is implied. */
|
|
51
51
|
export interface Observation {
|
|
52
52
|
readonly id: string;
|
|
@@ -74,14 +74,19 @@ export interface Assessment {
|
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
76
|
* Evidence is a semantic projection; presentation/provenance never enters its digest. Versions are
|
|
77
|
-
* per kind
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
77
|
+
* per kind, and a comparison names the oldest policy that yields its facts. Meaning is version 1.
|
|
78
|
+
* Structure is version 2, or version 3 when declared capabilities are among its roots, so a
|
|
79
|
+
* comparison without them keeps the version-2 bytes. Capability Keys join the root Key set of both
|
|
80
|
+
* digests: one that is not already a root changes the meaning fingerprint, never its version, and
|
|
81
|
+
* meaning evidence never records whether capabilities were declared. A referenced or inherited Class
|
|
82
|
+
* that loses an effective Property (`class.properties`) raises structure to version 4 and meaning to
|
|
83
|
+
* version 2, and structure is version 4 too when it records that a dependent Policy lost what it
|
|
84
|
+
* relies on (`method.object`, `class.endpoints`). Those facts are recorded only on such a loss, so
|
|
85
|
+
* every other comparison, every compatible one included, keeps its bytes.
|
|
81
86
|
*/
|
|
82
87
|
export interface ComparisonEvidence {
|
|
83
88
|
readonly kind: 'structure' | 'meaning';
|
|
84
|
-
readonly version: 1 | 2 | 3;
|
|
89
|
+
readonly version: 1 | 2 | 3 | 4;
|
|
85
90
|
readonly fingerprint: Fingerprint;
|
|
86
91
|
}
|
|
87
92
|
export interface Analysis {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { Key } from '../../addressing/index.js';
|
|
2
1
|
import type { DomainSchema } from '../model/schema.js';
|
|
3
2
|
import type { Coordinate } from './coordinate.js';
|
|
4
3
|
import type { Usage } from './model.js';
|
|
5
4
|
import type { ResolvedSubject } from './subjects.js';
|
|
5
|
+
import { Key } from '../../addressing/index.js';
|
|
6
6
|
export interface Reference {
|
|
7
7
|
readonly coordinate: Coordinate;
|
|
8
8
|
readonly usage: Usage;
|
|
@@ -14,6 +14,13 @@ export declare function schemaIdentity(schema: DomainSchema): Readonly<{
|
|
|
14
14
|
export declare function usageOf(schema: DomainSchema, relation: Usage['relation'], key?: Key): Usage;
|
|
15
15
|
/** References keep their declaring member and relation; no strongest-usage collapse happens here. */
|
|
16
16
|
export declare function rootReferences(schema: DomainSchema): readonly Reference[];
|
|
17
|
+
/**
|
|
18
|
+
* What the dependent's own Policies rely on in one origin beyond naming a Definition: each Method a
|
|
19
|
+
* Policy object term names, which the Policy resolves as its owner's own executable declaration, and
|
|
20
|
+
* each Edge Class a Policy pattern matches, whose orientation and accepted endpoint Classes Policy
|
|
21
|
+
* typing reads. Policies the dependent reaches in a dependency are that dependency's own.
|
|
22
|
+
*/
|
|
23
|
+
export declare function policyReliance(schema: DomainSchema, origin: Key.Origin): readonly Reference[];
|
|
17
24
|
/** Existing DSL collectors own reference syntax. These functions attach comparison provenance. */
|
|
18
25
|
export declare function valueReferences(subject: Extract<ResolvedSubject, {
|
|
19
26
|
kind: 'property';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Key } from '../../addressing/index.js';
|
|
1
2
|
import { revisionOfDomainSchema } from '../canonical/revision.js';
|
|
2
3
|
import { collectCallableContractRefs, collectCallableRefs, collectClassPolicyRefs, collectCoreRefs, collectEndpointRefs, collectPolicyDefinitionRefs, collectValueDefinitionRefs, coreEndpointDefinitionRef, } from '../resolution/origins.js';
|
|
3
4
|
import { classCoordinate, keyForDefinitionRef, memberCoordinate, methodCoordinate, propertyCoordinate, } from './coordinate.js';
|
|
@@ -11,13 +12,17 @@ export function usageOf(schema, relation, key) {
|
|
|
11
12
|
...(key === undefined ? {} : { key }),
|
|
12
13
|
});
|
|
13
14
|
}
|
|
15
|
+
/** A Method a Policy names stays a reference to its owner Class; `policyReliance` keeps the Method. */
|
|
14
16
|
function collector(schema, result, key) {
|
|
15
|
-
return (ref, relation) =>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
:
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
return (ref, relation) => {
|
|
18
|
+
const definition = ref.kind === 'method' ? ref.owner : ref;
|
|
19
|
+
result.push({
|
|
20
|
+
coordinate: definition.kind === 'class'
|
|
21
|
+
? classCoordinate(definition)
|
|
22
|
+
: memberCoordinate(definition),
|
|
23
|
+
usage: usageOf(schema, relation, key),
|
|
24
|
+
});
|
|
25
|
+
};
|
|
21
26
|
}
|
|
22
27
|
/** References keep their declaring member and relation; no strongest-usage collapse happens here. */
|
|
23
28
|
export function rootReferences(schema) {
|
|
@@ -49,6 +54,34 @@ export function rootReferences(schema) {
|
|
|
49
54
|
collectCoreRefs(schema, collector(schema, result));
|
|
50
55
|
return result;
|
|
51
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* What the dependent's own Policies rely on in one origin beyond naming a Definition: each Method a
|
|
59
|
+
* Policy object term names, which the Policy resolves as its owner's own executable declaration, and
|
|
60
|
+
* each Edge Class a Policy pattern matches, whose orientation and accepted endpoint Classes Policy
|
|
61
|
+
* typing reads. Policies the dependent reaches in a dependency are that dependency's own.
|
|
62
|
+
*/
|
|
63
|
+
export function policyReliance(schema, origin) {
|
|
64
|
+
const result = new Map();
|
|
65
|
+
const collect = (key) => (ref, site) => {
|
|
66
|
+
const coordinate = ref.kind === 'method'
|
|
67
|
+
? methodCoordinate(ref.owner, ref.name)
|
|
68
|
+
: site === 'pattern'
|
|
69
|
+
? classCoordinate(ref)
|
|
70
|
+
: undefined;
|
|
71
|
+
if (coordinate === undefined || Key.origin(coordinate.key) !== origin)
|
|
72
|
+
return;
|
|
73
|
+
result.set(`${coordinate.key}:${site}`, { coordinate, usage: usageOf(schema, site, key) });
|
|
74
|
+
};
|
|
75
|
+
for (const declaration of Object.values(schema.classes))
|
|
76
|
+
if (declaration.kind === 'node')
|
|
77
|
+
for (const [name, method] of Object.entries(declaration.methods))
|
|
78
|
+
collectCallableRefs(method, collect(methodCoordinate(declaration.ref, name).key));
|
|
79
|
+
for (const declaration of Object.values(schema.functions))
|
|
80
|
+
collectCallableRefs(declaration, collect(keyForDefinitionRef(declaration.ref)));
|
|
81
|
+
for (const declaration of Object.values(schema.policies))
|
|
82
|
+
collectPolicyDefinitionRefs(declaration, collect(keyForDefinitionRef(declaration.ref)));
|
|
83
|
+
return [...result.values()];
|
|
84
|
+
}
|
|
52
85
|
/** Existing DSL collectors own reference syntax. These functions attach comparison provenance. */
|
|
53
86
|
export function valueReferences(subject) {
|
|
54
87
|
const result = [];
|
|
@@ -20,6 +20,11 @@ export interface ComparisonContext {
|
|
|
20
20
|
readonly roots: readonly Reference[];
|
|
21
21
|
/** Roots the dependent declares as capabilities on the compared origin; also in `roots`. */
|
|
22
22
|
readonly capabilities: readonly Reference[];
|
|
23
|
+
/**
|
|
24
|
+
* What the dependent's own Policies rely on in the compared origin (`policyReliance`). Not roots:
|
|
25
|
+
* structure records them only when they fail, so a compatible comparison keeps its bytes.
|
|
26
|
+
*/
|
|
27
|
+
readonly reliance: readonly Reference[];
|
|
23
28
|
pair(coordinate: Coordinate): SubjectPair;
|
|
24
29
|
}
|
|
25
30
|
export declare function prepare(request: ComparisonRequest): ComparisonContext;
|
|
@@ -3,7 +3,7 @@ import { SchemaError, diagnostic } from '../diagnostic.js';
|
|
|
3
3
|
import { knownDomainClosure } from '../resolution/closure.js';
|
|
4
4
|
import { resolve } from '../resolution/domain.js';
|
|
5
5
|
import { contextOf } from './context.js';
|
|
6
|
-
import { rootReferences, schemaIdentity, usageOf } from './references.js';
|
|
6
|
+
import { policyReliance, rootReferences, schemaIdentity, usageOf } from './references.js';
|
|
7
7
|
import { capabilityCoordinates, coordinateForKey, resolveSubject } from './subjects.js';
|
|
8
8
|
export function prepare(request) {
|
|
9
9
|
const { scope, target } = request;
|
|
@@ -41,6 +41,7 @@ export function prepare(request) {
|
|
|
41
41
|
before,
|
|
42
42
|
roots: [...rootReferences(dependent), ...capabilities],
|
|
43
43
|
capabilities,
|
|
44
|
+
reliance: policyReliance(dependent, source.origin),
|
|
44
45
|
});
|
|
45
46
|
}
|
|
46
47
|
/**
|
|
@@ -61,9 +62,10 @@ export function selectMembers(source, target, keys) {
|
|
|
61
62
|
usage: usageOf(source, 'selection', key),
|
|
62
63
|
})),
|
|
63
64
|
capabilities: [],
|
|
65
|
+
reliance: [],
|
|
64
66
|
});
|
|
65
67
|
}
|
|
66
|
-
function comparisonContext({ kind, source, target, dependent, before, roots, capabilities, }) {
|
|
68
|
+
function comparisonContext({ kind, source, target, dependent, before, roots, capabilities, reliance, }) {
|
|
67
69
|
resolve(target);
|
|
68
70
|
const after = contextOf(target);
|
|
69
71
|
const pairs = new Map();
|
|
@@ -75,6 +77,7 @@ function comparisonContext({ kind, source, target, dependent, before, roots, cap
|
|
|
75
77
|
after,
|
|
76
78
|
roots,
|
|
77
79
|
capabilities,
|
|
80
|
+
reliance,
|
|
78
81
|
scope: Object.freeze({
|
|
79
82
|
kind,
|
|
80
83
|
source: schemaIdentity(source),
|
|
@@ -11,11 +11,30 @@ export function analyzeStructure(context) {
|
|
|
11
11
|
kind: 'structure',
|
|
12
12
|
...result,
|
|
13
13
|
compatible: result.assessments.every(({ satisfied }) => satisfied),
|
|
14
|
-
//
|
|
14
|
+
// Each version adds one requirement policy and applies only when its fact is present: 3 a
|
|
15
|
+
// declared capability root, 4 a lost effective Property of a reached Class or a failed Policy
|
|
16
|
+
// reliance, facts recorded only when they fail. Without one, evidence keeps its version-2 bytes.
|
|
15
17
|
evidence: evidenceOf({
|
|
16
18
|
kind: 'structure',
|
|
17
|
-
version:
|
|
19
|
+
version: recordsFailureOnlyFact(result.assessments)
|
|
20
|
+
? 4
|
|
21
|
+
: context.capabilities.length > 0
|
|
22
|
+
? 3
|
|
23
|
+
: 2,
|
|
18
24
|
...result,
|
|
19
25
|
}),
|
|
20
26
|
});
|
|
21
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* The facts structure records only when they fail: a referenced or inherited Class that lost an
|
|
30
|
+
* effective Property, and what a dependent Policy relies on (a Method object, a matched Edge's
|
|
31
|
+
* endpoints).
|
|
32
|
+
*/
|
|
33
|
+
const FAILURE_ONLY_FACETS = new Set([
|
|
34
|
+
'class.properties',
|
|
35
|
+
'method.object',
|
|
36
|
+
'class.endpoints',
|
|
37
|
+
]);
|
|
38
|
+
function recordsFailureOnlyFact(assessments) {
|
|
39
|
+
return assessments.some(({ requirement }) => FAILURE_ONLY_FACETS.has(requirement.kind));
|
|
40
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Key } from '../../../addressing/index.js';
|
|
2
|
-
import { compareAddedProperties } from '../comparators/classes.js';
|
|
2
|
+
import { compareAddedProperties, compareLostProperties } from '../comparators/classes.js';
|
|
3
3
|
import { compareFacet } from '../comparators/index.js';
|
|
4
|
+
import { fingerprintMeaning } from '../comparators/values.js';
|
|
4
5
|
import { contextInvalid } from '../context.js';
|
|
5
6
|
import { methodCoordinate } from '../coordinate.js';
|
|
6
7
|
import { callableReferences, classReferences, inherits, memberReferences, usageOf, valueReferences, } from '../references.js';
|
|
@@ -68,5 +69,29 @@ export function compareRequirements({ context, report, }) {
|
|
|
68
69
|
});
|
|
69
70
|
if (facet === 'class.inherit')
|
|
70
71
|
compareAddedProperties({ context, pair, report });
|
|
72
|
+
if (subject.kind === 'class')
|
|
73
|
+
compareLostProperties({ pair, report });
|
|
74
|
+
}
|
|
75
|
+
compareReliance({ context, report });
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* What a dependent Policy relies on is recorded only when it fails: a Method it names that is gone
|
|
79
|
+
* or no longer executable by its owner, or an Edge it matches whose orientation or accepted endpoint
|
|
80
|
+
* Classes changed. A held reliance adds no fact, so a compatible comparison keeps its evidence bytes
|
|
81
|
+
* and no coordinate minted from it moves; a failed one is a refusal, from which none is minted.
|
|
82
|
+
*/
|
|
83
|
+
function compareReliance({ context, report, }) {
|
|
84
|
+
for (const reference of context.reliance) {
|
|
85
|
+
const pair = context.pair(reference.coordinate);
|
|
86
|
+
if (pair.source === undefined)
|
|
87
|
+
throw contextInvalid(`Retained acceptance context has no meaning for ${reference.coordinate.key}.`, reference.coordinate.key);
|
|
88
|
+
const facet = reference.coordinate.kind === 'method' ? 'method.object' : 'class.endpoints';
|
|
89
|
+
const { before, after } = compareFacet({ context, pair, facet });
|
|
90
|
+
if (before !== undefined &&
|
|
91
|
+
after !== undefined &&
|
|
92
|
+
fingerprintMeaning(before) === fingerprintMeaning(after))
|
|
93
|
+
continue;
|
|
94
|
+
report.note(reference);
|
|
95
|
+
report.record({ pair, facet, before, after, requirement: { kind: facet } });
|
|
71
96
|
}
|
|
72
97
|
}
|
|
@@ -115,11 +115,29 @@ function capabilityCoordinate(source, key) {
|
|
|
115
115
|
}
|
|
116
116
|
function invalidCapability(key, index, reason) {
|
|
117
117
|
throw new SchemaError([
|
|
118
|
-
diagnostic('DM_CAPABILITY_INVALID', `/capabilities/${index}`, `Capability ${
|
|
118
|
+
diagnostic('DM_CAPABILITY_INVALID', `/capabilities/${index}`, `Capability ${shown(key)} ${reason}.`, typeof key === 'string' ? key : undefined),
|
|
119
119
|
]);
|
|
120
120
|
}
|
|
121
121
|
function invalidMemberRoot(key, index, reason) {
|
|
122
122
|
throw new SchemaError([
|
|
123
|
-
diagnostic('DM_MEMBER_ROOT_INVALID', `/roots/${index}`, `Key ${
|
|
123
|
+
diagnostic('DM_MEMBER_ROOT_INVALID', `/roots/${index}`, `Key ${shown(key)} ${reason}.`, typeof key === 'string' ? key : undefined),
|
|
124
124
|
]);
|
|
125
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* A caller-supplied item as diagnostic text. Formatting never throws, so the caller always gets the
|
|
128
|
+
* diagnostic: a bigint is shown as its literal, and another item JSON cannot encode, such as a cyclic
|
|
129
|
+
* object, is named by its type.
|
|
130
|
+
*/
|
|
131
|
+
function shown(item) {
|
|
132
|
+
if (typeof item === 'bigint')
|
|
133
|
+
return `${item}n`;
|
|
134
|
+
try {
|
|
135
|
+
const text = JSON.stringify(item);
|
|
136
|
+
if (text !== undefined)
|
|
137
|
+
return text;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// Not encodable as JSON: named by its type below.
|
|
141
|
+
}
|
|
142
|
+
return `<${typeof item}>`;
|
|
143
|
+
}
|
|
@@ -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_STATE' | 'DV_REF_RESOLVES' | 'DV_VALUE_SCHEMA' | 'DV_VIEW_TARGET' | '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';
|
|
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' | 'DV_VIEW_TARGET' | '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;
|
|
@@ -142,6 +142,7 @@ function canonicalizeProperty(value) {
|
|
|
142
142
|
set: value.auto.set,
|
|
143
143
|
},
|
|
144
144
|
}),
|
|
145
|
+
...(value.immutable === undefined ? {} : { immutable: value.immutable }),
|
|
145
146
|
...(value.description === undefined ? {} : { description: value.description }),
|
|
146
147
|
...(value.state === undefined
|
|
147
148
|
? {}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { SourceDomain } from '../../domain/model/domain.js';
|
|
2
2
|
import type { DomainSchema } from '../model/schema.js';
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Resolve one accepted Schema through its exact retained source closure. Acceptance validated it
|
|
5
|
+
* against that closure, which is the only way a Schema retains one, so it is not validated again.
|
|
6
|
+
*/
|
|
4
7
|
export declare function resolve<const S extends DomainSchema>(schema: S): SourceDomain<S>;
|
|
@@ -9,12 +9,14 @@ import { validateValueProgram } from '../../language/value/evaluate/program.js';
|
|
|
9
9
|
import { validateJsonInstance, validatePreparedInstance, } from '../../language/value/evaluate/validate.js';
|
|
10
10
|
import { classifyPreparedOrdering } from '../../language/value/ordering.js';
|
|
11
11
|
import { revisionOfDomainSchema } from '../canonical/revision.js';
|
|
12
|
-
import { SchemaError } from '../diagnostic.js';
|
|
13
|
-
import { validateDomainSchemaSemantics } from '../validation/domain.js';
|
|
14
12
|
import { lookupForDomainClosure } from './closure.js';
|
|
13
|
+
import { buildDomainResolutionContext } from './context.js';
|
|
15
14
|
import { createDomainValueSchemaRegistry } from './value.registry.js';
|
|
16
15
|
const resolvedSchemas = new WeakMap();
|
|
17
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Resolve one accepted Schema through its exact retained source closure. Acceptance validated it
|
|
18
|
+
* against that closure, which is the only way a Schema retains one, so it is not validated again.
|
|
19
|
+
*/
|
|
18
20
|
export function resolve(schema) {
|
|
19
21
|
const cached = resolvedSchemas.get(schema);
|
|
20
22
|
if (cached !== undefined)
|
|
@@ -24,10 +26,7 @@ export function resolve(schema) {
|
|
|
24
26
|
return resolved;
|
|
25
27
|
}
|
|
26
28
|
function resolveWithLookup(schema, lookup) {
|
|
27
|
-
const
|
|
28
|
-
if (validation.diagnostics.length > 0)
|
|
29
|
-
throw new SchemaError(validation.diagnostics);
|
|
30
|
-
const closure = [schema, ...validation.context.dependencies.values()];
|
|
29
|
+
const closure = [schema, ...buildDomainResolutionContext(schema, lookup).dependencies.values()];
|
|
31
30
|
const registries = new Map(closure.map((owner) => [owner.origin, createDomainValueSchemaRegistry(owner, lookup)]));
|
|
32
31
|
const input = {
|
|
33
32
|
root: Object.freeze({
|
|
@@ -66,6 +65,7 @@ function sourceValidation(closure, registries) {
|
|
|
66
65
|
properties.set(PropertyKey.of(definition.ref, name), Object.freeze({
|
|
67
66
|
ordering: classifyPreparedOrdering(prepared.value),
|
|
68
67
|
validate: (input) => validatePreparedInstance(prepared.value, input),
|
|
68
|
+
program: () => prepared.value.program(),
|
|
69
69
|
}));
|
|
70
70
|
}
|
|
71
71
|
if (definition.kind !== 'node')
|