@astrale-os/kernel-dsl 0.2.0-beta.37 → 0.2.0-beta.39

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.
Files changed (102) hide show
  1. package/dist/v1/builder/core/authoring.d.ts +7 -2
  2. package/dist/v1/builder/lowering/schema/context.d.ts +9 -4
  3. package/dist/v1/builder/lowering/schema/context.js +20 -20
  4. package/dist/v1/builder/policy/authoring.d.ts +6 -6
  5. package/dist/v1/builder/policy/authoring.js +3 -1
  6. package/dist/v1/compiled/admission/accept.js +97 -18
  7. package/dist/v1/compiled/admission/semantics.js +77 -24
  8. package/dist/v1/compiled/compiler/compile.js +23 -7
  9. package/dist/v1/compiled/loader/load.d.ts +11 -2
  10. package/dist/v1/compiled/loader/load.js +4 -1
  11. package/dist/v1/compiled/model/schema.d.ts +5 -4
  12. package/dist/v1/domain/create.js +17 -9
  13. package/dist/v1/index.d.ts +1 -1
  14. package/dist/v1/language/callable/composition.d.ts +13 -1
  15. package/dist/v1/language/callable/composition.js +13 -3
  16. package/dist/v1/language/core/model/core.d.ts +7 -1
  17. package/dist/v1/language/core/resolved.d.ts +6 -2
  18. package/dist/v1/language/index.d.ts +1 -1
  19. package/dist/v1/language/index.js +1 -1
  20. package/dist/v1/language/policy/index.d.ts +1 -1
  21. package/dist/v1/language/policy/index.js +1 -1
  22. package/dist/v1/language/policy/model/policy.d.ts +1 -0
  23. package/dist/v1/language/policy/model/policy.js +17 -0
  24. package/dist/v1/language/value/compile/fields.d.ts +1 -1
  25. package/dist/v1/language/value/compile/load.d.ts +4 -2
  26. package/dist/v1/language/value/compile/load.js +22 -1
  27. package/dist/v1/language/value/compile/model.d.ts +16 -1
  28. package/dist/v1/language/value/evaluate/assertions.d.ts +2 -0
  29. package/dist/v1/language/value/evaluate/assertions.js +13 -0
  30. package/dist/v1/language/value/evaluate/evaluator.js +78 -17
  31. package/dist/v1/language/value/evaluate/preparation.d.ts +10 -1
  32. package/dist/v1/language/value/evaluate/preparation.js +17 -26
  33. package/dist/v1/language/value/evaluate/program.js +1 -1
  34. package/dist/v1/language/value/evaluate/validate.d.ts +6 -2
  35. package/dist/v1/language/value/evaluate/validate.js +18 -11
  36. package/dist/v1/language/value/ordering.d.ts +2 -0
  37. package/dist/v1/language/value/ordering.js +4 -8
  38. package/dist/v1/language/value/regexp/compile.d.ts +3 -3
  39. package/dist/v1/language/value/regexp/compile.js +56 -11
  40. package/dist/v1/language/value/regexp/matcher.d.ts +3 -3
  41. package/dist/v1/language/value/regexp/matcher.js +75 -3
  42. package/dist/v1/schema/analysis/class.d.ts +21 -0
  43. package/dist/v1/schema/analysis/class.js +18 -9
  44. package/dist/v1/schema/compatibility/api.d.ts +2 -0
  45. package/dist/v1/schema/compatibility/api.js +1 -0
  46. package/dist/v1/schema/compatibility/comparators/callables.d.ts +28 -0
  47. package/dist/v1/schema/compatibility/comparators/callables.js +77 -0
  48. package/dist/v1/schema/compatibility/comparators/classes.d.ts +28 -0
  49. package/dist/v1/schema/compatibility/comparators/classes.js +96 -0
  50. package/dist/v1/schema/compatibility/comparators/index.d.ts +12 -0
  51. package/dist/v1/schema/compatibility/comparators/index.js +41 -0
  52. package/dist/v1/schema/compatibility/comparators/members.d.ts +4 -0
  53. package/dist/v1/schema/compatibility/comparators/members.js +49 -0
  54. package/dist/v1/schema/compatibility/comparators/values.d.ts +5 -0
  55. package/dist/v1/schema/compatibility/comparators/values.js +37 -0
  56. package/dist/v1/schema/compatibility/compare.d.ts +5 -57
  57. package/dist/v1/schema/compatibility/compare.js +19 -162
  58. package/dist/v1/schema/compatibility/coordinate.d.ts +2 -7
  59. package/dist/v1/schema/compatibility/coordinate.js +2 -6
  60. package/dist/v1/schema/compatibility/evidence.d.ts +5 -0
  61. package/dist/v1/schema/compatibility/evidence.js +51 -0
  62. package/dist/v1/schema/compatibility/fields.d.ts +6 -0
  63. package/dist/v1/schema/compatibility/fields.js +5 -0
  64. package/dist/v1/schema/compatibility/index.d.ts +5 -4
  65. package/dist/v1/schema/compatibility/index.js +3 -2
  66. package/dist/v1/schema/compatibility/legacy/index.d.ts +58 -0
  67. package/dist/v1/schema/compatibility/legacy/index.js +145 -0
  68. package/dist/v1/schema/compatibility/meaning/footprint.d.ts +7 -0
  69. package/dist/v1/schema/compatibility/meaning/footprint.js +57 -0
  70. package/dist/v1/schema/compatibility/meaning/index.d.ts +3 -0
  71. package/dist/v1/schema/compatibility/meaning/index.js +14 -0
  72. package/dist/v1/schema/compatibility/model.d.ts +96 -0
  73. package/dist/v1/schema/compatibility/model.js +1 -0
  74. package/dist/v1/schema/compatibility/references.d.ts +30 -0
  75. package/dist/v1/schema/compatibility/references.js +122 -0
  76. package/dist/v1/schema/compatibility/report.d.ts +26 -0
  77. package/dist/v1/schema/compatibility/report.js +100 -0
  78. package/dist/v1/schema/compatibility/scope.d.ts +27 -0
  79. package/dist/v1/schema/compatibility/scope.js +78 -0
  80. package/dist/v1/schema/compatibility/structure/index.d.ts +3 -0
  81. package/dist/v1/schema/compatibility/structure/index.js +16 -0
  82. package/dist/v1/schema/compatibility/structure/inheritance.d.ts +7 -0
  83. package/dist/v1/schema/compatibility/structure/inheritance.js +68 -0
  84. package/dist/v1/schema/compatibility/structure/requirements.d.ts +7 -0
  85. package/dist/v1/schema/compatibility/structure/requirements.js +70 -0
  86. package/dist/v1/schema/compatibility/subjects.d.ts +34 -0
  87. package/dist/v1/schema/compatibility/subjects.js +86 -0
  88. package/dist/v1/schema/fingerprint.d.ts +2 -2
  89. package/dist/v1/schema/fingerprint.js +1 -1
  90. package/dist/v1/schema/index.d.ts +3 -0
  91. package/dist/v1/schema/index.js +2 -0
  92. package/dist/v1/schema/normalization/domain.js +15 -1
  93. package/dist/v1/schema/resolution/domain.js +17 -10
  94. package/dist/v1/schema/resolution/origins.d.ts +3 -0
  95. package/dist/v1/schema/resolution/origins.js +12 -4
  96. package/dist/v1/schema/validation/core.js +78 -26
  97. package/dist/v1/schema/validation/domain.structure.js +7 -2
  98. package/package.json +2 -2
  99. package/dist/v1/schema/compatibility/footprint.d.ts +0 -25
  100. package/dist/v1/schema/compatibility/footprint.js +0 -263
  101. package/dist/v1/schema/compatibility/meaning.d.ts +0 -44
  102. package/dist/v1/schema/compatibility/meaning.js +0 -234
@@ -1,6 +1,7 @@
1
1
  import type { DefinitionRef } from '../../addressing/index.js';
2
2
  import type { FunctionDefinition, MethodDefinition } from '../../language/callable/model/callable.js';
3
3
  import type { ClassDefinition } from '../../language/class/model/class.js';
4
+ import type { CoreEndpointRef } from '../../language/core/model/core.js';
4
5
  import type { PolicyDefinition } from '../../language/policy/model/policy.js';
5
6
  import type { JsonSchema } from '../../language/value/model/schema.js';
6
7
  import type { DomainSchemaIR } from '../model/schema.js';
@@ -15,6 +16,8 @@ export declare function collectUsedForeignOrigins(schema: DomainSchemaIR): Reado
15
16
  /** Complete structured references in one schema, in canonical order. */
16
17
  export declare function collectDomainDefinitionRefs(schema: DomainSchemaIR): readonly DefinitionRef[];
17
18
  export declare function collectCoreRefs(schema: DomainSchemaIR, add: ReferenceCollector): void;
19
+ /** The owning Domain addresses no Definition, and a Method is addressed through its owner Class. */
20
+ export declare function coreEndpointDefinitionRef(endpoint: CoreEndpointRef): DefinitionRef | undefined;
18
21
  export declare function collectClassRefs(declaration: ClassDefinition, add: ReferenceCollector): void;
19
22
  export declare function collectClassPolicyRefs(declaration: ClassDefinition, add: ReferenceCollector): void;
20
23
  export declare function collectEndpointRefs(declaration: Extract<ClassDefinition, {
@@ -36,12 +36,20 @@ export function collectCoreRefs(schema, add) {
36
36
  add(node.class, 'core');
37
37
  for (const edge of schema.core.edges) {
38
38
  add(edge.class, 'core');
39
- if (edge.source.kind !== 'domain')
40
- add(edge.source, 'core');
41
- if (edge.target.kind !== 'domain')
42
- add(edge.target, 'core');
39
+ for (const endpoint of [edge.source, edge.target]) {
40
+ const ref = coreEndpointDefinitionRef(endpoint);
41
+ // An endpoint names the Definition without instantiating it, exactly like an accepts contract.
42
+ if (ref !== undefined)
43
+ add(ref, 'endpoint');
44
+ }
43
45
  }
44
46
  }
47
+ /** The owning Domain addresses no Definition, and a Method is addressed through its owner Class. */
48
+ export function coreEndpointDefinitionRef(endpoint) {
49
+ if (endpoint.kind === 'domain')
50
+ return undefined;
51
+ return endpoint.kind === 'method' ? endpoint.owner : endpoint;
52
+ }
45
53
  export function collectClassRefs(declaration, add) {
46
54
  declaration.extends.forEach((ref) => add(ref, 'extends'));
47
55
  Object.values(declaration.properties).forEach((property) => collectValueDefinitionRefs(property.schema, add));
@@ -1,5 +1,7 @@
1
1
  import { Key } from '../../addressing/key.js';
2
2
  import { compareUnicode, definitionRefIndex } from '../../addressing/ordering.js';
3
+ import { isMethodExecutable } from '../../language/callable/executable.js';
4
+ import { policyObjectKey, policyObjectOrigin, projectedMemberClass, } from '../../language/policy/model/policy.js';
3
5
  import { validateJsonInstance } from '../../language/value/evaluate/validate.js';
4
6
  import { diagnostic } from '../diagnostic.js';
5
7
  const formatDefinitionRef = Key.of;
@@ -42,8 +44,8 @@ function resolveCoreEdges(environment, analysis, registry, nodesByRef, diagnosti
42
44
  const edges = [];
43
45
  for (const [index, edge] of environment.candidate.core.edges.entries()) {
44
46
  const pointer = `/core/edges/${index}`;
45
- const source = resolveCoreEndpoint(edge.source, `${pointer}/source`, nodesByRef, diagnostics);
46
- const target = resolveCoreEndpoint(edge.target, `${pointer}/target`, nodesByRef, diagnostics);
47
+ const source = resolveCoreEndpoint(environment, edge.source, `${pointer}/source`, nodesByRef, diagnostics);
48
+ const target = resolveCoreEndpoint(environment, edge.target, `${pointer}/target`, nodesByRef, diagnostics);
47
49
  const resolved = environment.resolve(edge.class);
48
50
  if (edge.class.origin !== environment.candidate.origin ||
49
51
  resolved === undefined ||
@@ -75,14 +77,37 @@ function resolveCoreEdges(environment, analysis, registry, nodesByRef, diagnosti
75
77
  }
76
78
  return edges;
77
79
  }
78
- function resolveCoreEndpoint(ref, pointer, nodesByRef, diagnostics) {
80
+ function resolveCoreEndpoint(environment, ref, pointer, nodesByRef, diagnostics) {
79
81
  if (ref.kind === 'domain')
80
82
  return { kind: 'domain', ref, key: 'domain' };
81
- const node = nodesByRef.get(definitionRefIndex(ref));
82
- if (node === undefined) {
83
- diagnostics.push(diagnostic('DV_CORE_REF', pointer, `Core endpoint ${formatDefinitionRef(ref)} does not name a declared local Core Node.`, formatDefinitionRef(ref)));
83
+ const undeclared = () => {
84
+ const key = policyObjectKey(ref);
85
+ diagnostics.push(diagnostic('DV_CORE_REF', pointer, `Core endpoint ${key} does not name a declared local Definition.`, key));
86
+ return undefined;
87
+ };
88
+ if (policyObjectOrigin(ref) !== environment.candidate.origin)
89
+ return undeclared();
90
+ if (ref.kind === 'core')
91
+ return nodesByRef.get(definitionRefIndex(ref)) ?? undeclared();
92
+ if (!declaresProjectedMember(environment, ref))
93
+ return undeclared();
94
+ return { kind: 'member', key: policyObjectKey(ref), classRef: projectedMemberClass(ref) };
95
+ }
96
+ /** Only a projected declaration can carry a Core fact; an abstract Method is never projected. */
97
+ function declaresProjectedMember(environment, ref) {
98
+ const candidate = environment.candidate;
99
+ if (ref.kind === 'method') {
100
+ const owner = candidate.classes[ref.owner.name];
101
+ const method = owner?.kind === 'node' ? owner.methods[ref.name] : undefined;
102
+ return method !== undefined && isMethodExecutable(owner, method);
84
103
  }
85
- return node;
104
+ if (ref.kind === 'class')
105
+ return Object.hasOwn(candidate.classes, ref.name);
106
+ if (ref.kind === 'function')
107
+ return Object.hasOwn(candidate.functions, ref.name);
108
+ if (ref.kind === 'policy')
109
+ return Object.hasOwn(candidate.policies, ref.name);
110
+ return Object.hasOwn(candidate.views, ref.name);
86
111
  }
87
112
  function endpointSatisfies(environment, endpoint, accepts) {
88
113
  // The owning Domain is a graph-projection identity, not a Definition declared by this DSL.
@@ -157,41 +182,68 @@ function validateCoreEdgeSet(environment, edges, nodesByRef, diagnostics) {
157
182
  }
158
183
  }
159
184
  function validateCardinality(environment, declaration, edges, nodesByRef, diagnostics) {
185
+ const subjects = cardinalitySubjects(edges, nodesByRef);
160
186
  if (declaration.orientation === 'undirected') {
161
187
  const [first, second] = declaration.endpoints;
162
- for (const node of nodesByRef.values()) {
163
- const matchesFirst = classSatisfies(environment, node.classRef, first.accepts);
164
- const matchesSecond = classSatisfies(environment, node.classRef, second.accepts);
188
+ for (const subject of subjects) {
189
+ const matchesFirst = classSatisfies(environment, subject.classRef, first.accepts);
190
+ const matchesSecond = classSatisfies(environment, subject.classRef, second.accepts);
165
191
  if (!matchesFirst && !matchesSecond)
166
192
  continue;
167
- const degree = edges.filter((edge) => edge.source.key === node.key || edge.target.key === node.key).length;
193
+ const degree = edges.filter((edge) => edge.source.key === subject.key || edge.target.key === subject.key).length;
168
194
  if (matchesFirst)
169
- checkIncidentBound(first, degree, node, diagnostics);
195
+ checkBound(first, first.incident, degree, subject, diagnostics);
170
196
  if (matchesSecond && !sameIncidentEndpointContract(first, second)) {
171
- checkIncidentBound(second, degree, node, diagnostics);
197
+ checkBound(second, second.incident, degree, subject, diagnostics);
172
198
  }
173
199
  }
174
200
  return;
175
201
  }
176
- for (const node of nodesByRef.values()) {
177
- if (classSatisfies(environment, node.classRef, declaration.endpoints.source.accepts)) {
178
- const degree = edges.filter((edge) => edge.source.key === node.key).length;
179
- checkBound(declaration.endpoints.source, declaration.endpoints.source.outgoing, degree, node, diagnostics);
202
+ for (const subject of subjects) {
203
+ if (classSatisfies(environment, subject.classRef, declaration.endpoints.source.accepts)) {
204
+ const degree = edges.filter((edge) => edge.source.key === subject.key).length;
205
+ checkBound(declaration.endpoints.source, declaration.endpoints.source.outgoing, degree, subject, diagnostics);
180
206
  }
181
- if (classSatisfies(environment, node.classRef, declaration.endpoints.target.accepts)) {
182
- const degree = edges.filter((edge) => edge.target.key === node.key).length;
183
- checkBound(declaration.endpoints.target, declaration.endpoints.target.incoming, degree, node, diagnostics);
207
+ if (classSatisfies(environment, subject.classRef, declaration.endpoints.target.accepts)) {
208
+ const degree = edges.filter((edge) => edge.target.key === subject.key).length;
209
+ checkBound(declaration.endpoints.target, declaration.endpoints.target.incoming, degree, subject, diagnostics);
210
+ }
211
+ }
212
+ }
213
+ /**
214
+ * Every declared Core Node proves its own complete degree, so both bounds hold. A Definition
215
+ * endpoint is only named by the Edges that reach it: the Domain may also create ordinary Edges of
216
+ * the same Class against it, so a minimum is unprovable here and only the maximum is enforced.
217
+ */
218
+ function cardinalitySubjects(edges, nodesByRef) {
219
+ const subjects = new Map();
220
+ for (const node of nodesByRef.values()) {
221
+ subjects.set(node.key, {
222
+ key: node.key,
223
+ classRef: node.classRef,
224
+ pointer: `/core/nodes/${escapePointer(node.slug)}`,
225
+ minimum: true,
226
+ });
227
+ }
228
+ for (const edge of edges) {
229
+ for (const endpoint of [edge.source, edge.target]) {
230
+ if (endpoint.kind !== 'member' || subjects.has(endpoint.key))
231
+ continue;
232
+ subjects.set(endpoint.key, {
233
+ key: endpoint.key,
234
+ classRef: endpoint.classRef,
235
+ pointer: edge.pointer,
236
+ minimum: false,
237
+ });
184
238
  }
185
239
  }
240
+ return Object.freeze([...subjects.values()]);
186
241
  }
187
- function checkBound(endpoint, count, degree, node, diagnostics) {
242
+ function checkBound(endpoint, count, degree, subject, diagnostics) {
188
243
  const [minimum, maximum] = countBounds(count);
189
- if (degree >= minimum && degree <= maximum)
244
+ if (degree <= maximum && (degree >= minimum || !subject.minimum))
190
245
  return;
191
- diagnostics.push(diagnostic('DV_CORE_EDGE_CONSTRAINTS', `/core/nodes/${escapePointer(node.slug)}`, `Core degree ${degree} violates ${endpoint.role} Edge count ${count}.`));
192
- }
193
- function checkIncidentBound(endpoint, degree, node, diagnostics) {
194
- checkBound(endpoint, endpoint.incident, degree, node, diagnostics);
246
+ diagnostics.push(diagnostic('DV_CORE_EDGE_CONSTRAINTS', subject.pointer, `Core degree ${degree} violates ${endpoint.role} Edge count ${count}.`));
195
247
  }
196
248
  function sameIncidentEndpointContract(left, right) {
197
249
  return (left.incident === right.incident &&
@@ -61,14 +61,19 @@ const coreRefSchema = strictObject({
61
61
  name: coreSlugSchema,
62
62
  });
63
63
  const domainRefSchema = strictObject({ kind: literal('domain') });
64
- const coreEndpointRefSchema = discriminatedUnion('kind', [coreRefSchema, domainRefSchema]);
65
- const policyObjectRefSchema = discriminatedUnion('kind', [
64
+ /** Every Definition whose installed projection resolves through one exact member Path. */
65
+ const projectedMemberRefOptions = [
66
66
  strictObject({ kind: literal('method'), owner: classRefSchema, name: memberNameSchema }),
67
67
  classRefSchema,
68
68
  functionRefSchema,
69
69
  policyRefSchema,
70
70
  viewRefSchema,
71
71
  coreRefSchema,
72
+ ];
73
+ const policyObjectRefSchema = discriminatedUnion('kind', projectedMemberRefOptions);
74
+ const coreEndpointRefSchema = discriminatedUnion('kind', [
75
+ ...projectedMemberRefOptions,
76
+ domainRefSchema,
72
77
  ]);
73
78
  const edgeEndpointBaseShape = {
74
79
  role: memberNameSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/kernel-dsl",
3
- "version": "0.2.0-beta.37",
3
+ "version": "0.2.0-beta.39",
4
4
  "description": "Astrale Kernel DSL - Schema authoring, inference, and IR serialization",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -99,7 +99,7 @@
99
99
  "ajv": "^8.20.0",
100
100
  "re2js": "2.8.6",
101
101
  "typescript": "~6.0.3",
102
- "vitest": "^4.1.10",
102
+ "vitest": "^5.0.1",
103
103
  "yaml": "2.9.0"
104
104
  },
105
105
  "scripts": {
@@ -1,25 +0,0 @@
1
- import type { Value as JsonValue } from '@astrale-os/kernel-dsl/value';
2
- import type { Key as SemanticKey } from '../../addressing/index.js';
3
- import type { DomainSchema } from '../model/schema.js';
4
- import type { Context } from './context.js';
5
- import type { Coordinate } from './coordinate.js';
6
- import type { DependencyMeaningLevel } from './fields.js';
7
- import type { ClassRequirement, MeaningFingerprint } from './meaning.js';
8
- /** One footprint coordinate with the meaning the dependent was authored against. */
9
- export interface SourceMeaning {
10
- readonly coordinate: Coordinate;
11
- readonly meaning: JsonValue;
12
- readonly fingerprint: MeaningFingerprint;
13
- readonly requirement?: ClassRequirement;
14
- }
15
- /** Every dependency Definition the dependent's own declarations name, at its strongest usage. */
16
- export declare function collectSchemaRoots(owner: DomainSchema): readonly Coordinate[];
17
- /**
18
- * The transitive footprint: from the roots, every Class, Property, Method, Function, Policy, View
19
- * and Core coordinate of the selected origin that the dependent's meaning reaches. A Class carries
20
- * its strongest usage level; only inheritance traverses ancestors and Edge endpoint contracts, and
21
- * a reached callable contributes its contract references but never its Policy check.
22
- */
23
- export declare function collectReachableMeanings(roots: readonly Coordinate[], selectedOrigin: string, context: Context): ReadonlyMap<SemanticKey, SourceMeaning>;
24
- /** Resolve one caller-supplied Key of the source into an exact coordinate that exists there. */
25
- export declare function coordinateForKey(context: Context, source: DomainSchema, input: SemanticKey, index: number, level?: DependencyMeaningLevel): Coordinate;
@@ -1,263 +0,0 @@
1
- import { Key } from '../../addressing/index.js';
2
- import { compareUnicode, definitionRefIndex } from '../../addressing/ordering.js';
3
- import { SchemaError, diagnostic } from '../diagnostic.js';
4
- import { collectCallableContractRefs, collectCallableRefs, collectClassPolicyRefs, collectClassRefs, collectCoreRefs, collectEndpointRefs, collectPolicyDefinitionRefs, collectValueDefinitionRefs, } from '../resolution/origins.js';
5
- import { contextInvalid, effectiveDefinition, effectiveMethod, requireOwner } from './context.js';
6
- import { classCoordinate, keyReference, levelOf, memberCoordinate, methodCoordinate, propertyCoordinate, } from './coordinate.js';
7
- import { classMeaning, fingerprintMeaning, meaningForCoordinate, memberMeaning, methodMeaning, propertyMeaning, } from './meaning.js';
8
- /** Every dependency Definition the dependent's own declarations name, at its strongest usage. */
9
- export function collectSchemaRoots(owner) {
10
- const classes = new Map();
11
- const members = new Map();
12
- const add = (ref, site) => {
13
- if (ref.kind === 'class') {
14
- const index = definitionRefIndex(ref);
15
- const level = levelOf(site);
16
- const previous = classes.get(index);
17
- if (previous === undefined || (previous.level === 'reference' && level === 'inherit')) {
18
- classes.set(index, classCoordinate(ref, level));
19
- }
20
- return;
21
- }
22
- members.set(definitionRefIndex(ref), memberCoordinate(ref));
23
- };
24
- for (const declaration of Object.values(owner.classes))
25
- collectClassRefs(declaration, add);
26
- for (const declaration of Object.values(owner.functions))
27
- collectCallableRefs(declaration, add);
28
- for (const declaration of Object.values(owner.policies)) {
29
- collectPolicyDefinitionRefs(declaration, add);
30
- }
31
- for (const declaration of Object.values(owner.views)) {
32
- if (declaration.target.kind === 'definition') {
33
- declaration.target.definitions.forEach((ref) => add(ref, 'view'));
34
- }
35
- }
36
- collectCoreRefs(owner, add);
37
- return [...classes.values(), ...members.values()].sort((left, right) => compareUnicode(left.key, right.key));
38
- }
39
- /**
40
- * The transitive footprint: from the roots, every Class, Property, Method, Function, Policy, View
41
- * and Core coordinate of the selected origin that the dependent's meaning reaches. A Class carries
42
- * its strongest usage level; only inheritance traverses ancestors and Edge endpoint contracts, and
43
- * a reached callable contributes its contract references but never its Policy check.
44
- */
45
- export function collectReachableMeanings(roots, selectedOrigin, context) {
46
- const meanings = new Map();
47
- const classLevels = new Map();
48
- const visitedMembers = new Set();
49
- const pendingClasses = [];
50
- const pendingMembers = [];
51
- const push = (ref, site) => {
52
- if (ref.kind === 'class')
53
- pendingClasses.push(classCoordinate(ref, levelOf(site)));
54
- else
55
- pendingMembers.push(memberCoordinate(ref));
56
- };
57
- for (const coordinate of roots) {
58
- if (coordinate.kind === 'class') {
59
- pendingClasses.push(coordinate);
60
- continue;
61
- }
62
- if (coordinate.kind === 'member') {
63
- pendingMembers.push(coordinate);
64
- continue;
65
- }
66
- const meaning = meaningForCoordinate(context, coordinate);
67
- if (meaning === undefined) {
68
- throw new SchemaError([
69
- diagnostic('DM_MEMBER_ROOT_INVALID', '/roots', `Member comparison root ${coordinate.key} does not exist in its source context.`, coordinate.key),
70
- ]);
71
- }
72
- retainMeaning(meanings, selectedOrigin, coordinate, meaning);
73
- collectCoordinateSemanticRefs(context, coordinate, push);
74
- }
75
- const visitClass = (coordinate) => {
76
- const index = definitionRefIndex(coordinate.ref);
77
- const previous = classLevels.get(index);
78
- if (previous === 'inherit' || previous === coordinate.level)
79
- return;
80
- classLevels.set(index, coordinate.level);
81
- const owner = requireOwner(context, coordinate.ref, coordinate.key);
82
- const declaration = owner.classes[coordinate.ref.name];
83
- const analysis = effectiveDefinition(context, owner, coordinate.ref);
84
- const resolved = classMeaning(context, coordinate);
85
- if (declaration === undefined || analysis === undefined || resolved === undefined) {
86
- throw contextInvalid(`Retained acceptance context has no meaning for ${coordinate.key}.`, coordinate.key);
87
- }
88
- retainMeaning(meanings, selectedOrigin, coordinate, resolved.meaning, resolved.requirement);
89
- if (previous === undefined) {
90
- // The surface is level-independent: every effective Property and Method the dependent may
91
- // read or call, with the Definitions their contracts and policies name.
92
- for (const field of analysis.properties.values()) {
93
- retainMeaning(meanings, selectedOrigin, propertyCoordinate(field.owner, field.name), propertyMeaning(field));
94
- collectValueDefinitionRefs(field.schema, push);
95
- }
96
- for (const method of analysis.methods.values()) {
97
- retainMeaning(meanings, selectedOrigin, methodCoordinate(method.owner, method.name), methodMeaning(method));
98
- collectCallableContractRefs(method.declaration, push);
99
- }
100
- collectClassPolicyRefs(declaration, push);
101
- }
102
- if (coordinate.level === 'inherit') {
103
- // Only inheritance takes on the ancestry and, for an Edge, the endpoint contract.
104
- declaration.extends.forEach((parent) => push(parent, 'extends'));
105
- if (declaration.kind === 'edge')
106
- collectEndpointRefs(declaration, push);
107
- }
108
- };
109
- const visitMember = (coordinate) => {
110
- const index = definitionRefIndex(coordinate.ref);
111
- if (visitedMembers.has(index))
112
- return;
113
- visitedMembers.add(index);
114
- const owner = requireOwner(context, coordinate.ref, coordinate.key);
115
- const meaning = memberMeaning(owner, coordinate.ref);
116
- if (meaning === undefined) {
117
- throw contextInvalid(`Retained acceptance context has no meaning for ${coordinate.key}.`, coordinate.key);
118
- }
119
- retainMeaning(meanings, selectedOrigin, coordinate, meaning);
120
- collectMemberSemanticRefs(owner, coordinate.ref, push);
121
- };
122
- let classIndex = 0;
123
- let memberIndex = 0;
124
- while (classIndex < pendingClasses.length || memberIndex < pendingMembers.length) {
125
- if (classIndex < pendingClasses.length)
126
- visitClass(pendingClasses[classIndex++]);
127
- else
128
- visitMember(pendingMembers[memberIndex++]);
129
- }
130
- return meanings;
131
- }
132
- /** Resolve one caller-supplied Key of the source into an exact coordinate that exists there. */
133
- export function coordinateForKey(context, source, input, index, level = 'reference') {
134
- let key;
135
- try {
136
- key = Key(input);
137
- }
138
- catch {
139
- return invalidMemberRoot(input, index, 'is not a canonical semantic Key');
140
- }
141
- if (Key.origin(key) !== source.origin) {
142
- return invalidMemberRoot(key, index, `belongs to ${Key.origin(key)}, not source ${source.origin}`);
143
- }
144
- const reference = keyReference(key);
145
- let coordinate;
146
- if (reference.member !== undefined && reference.ownerName !== undefined) {
147
- if (source.classes[reference.ownerName] === undefined) {
148
- return invalidMemberRoot(key, index, 'has no exact owning Definition');
149
- }
150
- const owner = { origin: source.origin, kind: 'class', name: reference.ownerName };
151
- coordinate =
152
- reference.member === 'property'
153
- ? propertyCoordinate(owner, reference.name)
154
- : methodCoordinate(owner, reference.name);
155
- }
156
- else if (reference.kind === 'class') {
157
- if (source.classes[reference.name] === undefined) {
158
- return invalidMemberRoot(key, index, 'does not exist in the source');
159
- }
160
- // A Class root takes the caller's level; compareMemberMeaning passes none and compares the
161
- // surface at reference level without inferring an inheritance contract.
162
- coordinate = classCoordinate({ origin: source.origin, kind: 'class', name: reference.name }, level);
163
- }
164
- else {
165
- coordinate = memberCoordinate({
166
- origin: source.origin,
167
- kind: reference.kind,
168
- name: reference.name,
169
- });
170
- }
171
- if (meaningForCoordinate(context, coordinate) === undefined) {
172
- return invalidMemberRoot(key, index, 'does not exist in the source');
173
- }
174
- return coordinate;
175
- }
176
- function collectCoordinateSemanticRefs(context, coordinate, add) {
177
- const owner = context.schemas.get(coordinate.owner.origin);
178
- const analysis = owner === undefined ? undefined : effectiveDefinition(context, owner, coordinate.owner);
179
- if (analysis === undefined)
180
- return;
181
- if (coordinate.kind === 'property') {
182
- const field = analysis.properties.get(coordinate.key);
183
- if (field !== undefined)
184
- collectValueDefinitionRefs(field.schema, add);
185
- return;
186
- }
187
- const method = effectiveMethod(analysis, coordinate.key);
188
- if (method !== undefined)
189
- collectCallableContractRefs(method.declaration, add);
190
- }
191
- function collectMemberSemanticRefs(owner, ref, add) {
192
- switch (ref.kind) {
193
- case 'function': {
194
- const declaration = owner.functions[ref.name];
195
- if (declaration !== undefined)
196
- collectCallableRefs(declaration, add);
197
- return;
198
- }
199
- case 'policy': {
200
- const declaration = owner.policies[ref.name];
201
- if (declaration !== undefined)
202
- collectPolicyDefinitionRefs(declaration, add);
203
- return;
204
- }
205
- case 'view': {
206
- const declaration = owner.views[ref.name];
207
- if (declaration?.target.kind === 'definition') {
208
- declaration.target.definitions.forEach((definition) => add(definition, 'view'));
209
- }
210
- return;
211
- }
212
- case 'core': {
213
- // The dependency instantiates its own Core; the dependent only refers to it.
214
- const node = owner.core.nodes[ref.name];
215
- if (node === undefined)
216
- return;
217
- add(node.class);
218
- for (const edge of owner.core.edges) {
219
- const incident = (edge.source.kind === 'core' && edge.source.name === ref.name) ||
220
- (edge.target.kind === 'core' && edge.target.name === ref.name);
221
- if (!incident)
222
- continue;
223
- add(edge.class);
224
- if (edge.source.kind !== 'domain')
225
- add(edge.source);
226
- if (edge.target.kind !== 'domain')
227
- add(edge.target);
228
- }
229
- }
230
- }
231
- }
232
- function retainMeaning(meanings, selectedOrigin, coordinate, meaning, requirement) {
233
- if (Key.origin(coordinate.key) !== selectedOrigin)
234
- return;
235
- const fingerprint = fingerprintMeaning(meaning);
236
- const previous = meanings.get(coordinate.key);
237
- if (previous !== undefined) {
238
- const upgraded = previous.coordinate.kind === 'class' &&
239
- coordinate.kind === 'class' &&
240
- previous.coordinate.level !== coordinate.level;
241
- if (upgraded) {
242
- // A stronger requirement replaces the weaker one for the same Class.
243
- if (coordinate.level === 'reference')
244
- return;
245
- }
246
- else if (previous.fingerprint !== fingerprint) {
247
- throw new SchemaError([
248
- diagnostic('DM_MEANING_INCONSISTENT', '', `Semantic coordinate ${coordinate.key} produced inconsistent effective meaning.`, coordinate.key),
249
- ]);
250
- }
251
- }
252
- meanings.set(coordinate.key, Object.freeze({
253
- coordinate,
254
- meaning,
255
- fingerprint,
256
- ...(requirement === undefined ? {} : { requirement }),
257
- }));
258
- }
259
- function invalidMemberRoot(key, index, reason) {
260
- throw new SchemaError([
261
- diagnostic('DM_MEMBER_ROOT_INVALID', `/roots/${index}`, `Key ${JSON.stringify(key)} ${reason}.`, typeof key === 'string' ? key : undefined),
262
- ]);
263
- }
@@ -1,44 +0,0 @@
1
- import type { Value as JsonValue } from '@astrale-os/kernel-dsl/value';
2
- import type { Key as SemanticKey, PropertyKey as SemanticPropertyKey } from '../../addressing/index.js';
3
- import type { ResolvedFunction, ResolvedMethod } from '../../language/callable/resolved.js';
4
- import type { JsonSchema } from '../../language/value/model/schema.js';
5
- import type { EffectiveField, EffectiveMethod } from '../analysis/class.js';
6
- import type { DomainSchema } from '../model/schema.js';
7
- import type { Context } from './context.js';
8
- import type { ClassCoordinate, Coordinate, MemberRef } from './coordinate.js';
9
- export type MeaningFingerprint = `sha256:${string}`;
10
- /** What the source Class projects onto the target before comparing an inherited Class. */
11
- export interface ClassRequirement {
12
- readonly ancestors: readonly SemanticKey[];
13
- readonly properties: ReadonlySet<SemanticPropertyKey>;
14
- }
15
- /**
16
- * The meaning of one coordinate is a portable value built from the fields `fields.ts` classifies
17
- * as counting at the coordinate's usage level; `__tests__/fields.test.ts` proves the two agree.
18
- * Comparison works on these values, so every difference can name its exact path.
19
- */
20
- export declare function meaningForCoordinate(context: Context, coordinate: Coordinate, requirement?: ClassRequirement): JsonValue | undefined;
21
- /**
22
- * A reference needs the Class to exist with its kind, abstractness and orientation; inheritance
23
- * additionally takes on the source ancestors, class policies, data contract and, for an Edge, the
24
- * endpoint and constraint contracts. A target projected onto a source requirement keeps only the
25
- * ancestors the source named, so a superset satisfies it while a removal changes it.
26
- */
27
- export declare function classMeaning(context: Context, coordinate: ClassCoordinate, onto?: ClassRequirement): {
28
- readonly meaning: JsonValue;
29
- readonly requirement: ClassRequirement;
30
- } | undefined;
31
- export declare function memberMeaning(owner: DomainSchema, ref: MemberRef): JsonValue | undefined;
32
- export declare function propertyMeaning(field: EffectiveField): JsonValue;
33
- export declare function methodMeaning(method: EffectiveMethod): JsonValue;
34
- /**
35
- * Fingerprint the contract a caller compiles against, independently of its Domain revision: the
36
- * exact key, the owner, dispatch and abstractness of a Method, and the semantic input and output
37
- * contracts; authorization is excluded (DM-CALLABLE-FINGERPRINT). A static consumer pins this
38
- * instead of a Domain revision, so a dependency release that leaves the callable contract untouched
39
- * keeps every bound invocation valid.
40
- */
41
- export declare function callableFingerprint(callable: ResolvedFunction | ResolvedMethod): MeaningFingerprint;
42
- /** Drop annotation keywords wherever a schema keyword nests a schema; never inside data. */
43
- export declare function semanticValueSchema(value: JsonSchema): JsonSchema;
44
- export declare function fingerprintMeaning(value: unknown): MeaningFingerprint;