@astrale-os/kernel-dsl 1.0.0-beta.13 → 1.0.0-beta.14
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/key.js +2 -1
- package/dist/v1/addressing/patterns.d.ts +1 -0
- package/dist/v1/addressing/patterns.js +2 -1
- package/dist/v1/builder/class/property.d.ts +3 -9
- package/dist/v1/builder/class/property.js +1 -0
- package/dist/v1/builder/lowering/class.js +5 -1
- package/dist/v1/builder/lowering/policy.js +1 -0
- package/dist/v1/builder/policy/authoring.js +3 -2
- package/dist/v1/bundle/codec.js +2 -2
- package/dist/v1/bundle/diagnostic.d.ts +2 -0
- package/dist/v1/bundle/diagnostic.js +6 -0
- package/dist/v1/bundle/structure.js +2 -2
- package/dist/v1/domain/validation/create.d.ts +4 -1
- package/dist/v1/domain/validation/create.js +21 -34
- package/dist/v1/language/.spec/schemas/value-schema.schema.json +22 -0
- package/dist/v1/language/class/model/class.d.ts +4 -4
- package/dist/v1/language/class/model/edge.d.ts +2 -2
- package/dist/v1/language/class/model/property.d.ts +16 -7
- package/dist/v1/language/definition/metadata.d.ts +5 -0
- package/dist/v1/language/definition/metadata.js +7 -0
- package/dist/v1/language/policy/model/policy.d.ts +5 -5
- package/dist/v1/language/policy/normalization/normalize.js +17 -16
- package/dist/v1/language/validation/diagnostic.d.ts +1 -1
- package/dist/v1/language/validation/rule.d.ts +26 -0
- package/dist/v1/language/validation/rule.js +116 -0
- package/dist/v1/language/value/profile/meta-schema.compiled.js +4 -1
- package/dist/v1/language/value/profile/rules.js +13 -37
- package/dist/v1/language/value/profile/vocabulary.d.ts +35 -2
- package/dist/v1/language/value/profile/vocabulary.js +52 -5
- package/dist/v1/language/value/reference/registry.index.js +2 -1
- package/dist/v1/language/value/syntax/keywords.d.ts +3 -3
- package/dist/v1/language/value/syntax/keywords.js +4 -20
- package/dist/v1/language/value/syntax/node-path/validate.js +2 -3
- package/dist/v1/schema/.spec/schemas/domain-schema.schema.json +2336 -0
- package/dist/v1/schema/analysis/class.js +33 -15
- package/dist/v1/schema/compatibility/api.d.ts +1 -1
- package/dist/v1/schema/compatibility/coordinate.js +3 -3
- package/dist/v1/schema/compatibility/model.d.ts +5 -0
- package/dist/v1/schema/diagnostic.d.ts +17 -3
- package/dist/v1/schema/diagnostic.js +11 -0
- package/dist/v1/schema/index.d.ts +3 -1
- package/dist/v1/schema/index.js +1 -0
- package/dist/v1/schema/model/schema.d.ts +19 -1
- package/dist/v1/schema/normalization/domain.js +1 -0
- package/dist/v1/schema/resolution/closure.js +2 -1
- package/dist/v1/schema/resolution/context.js +3 -1
- package/dist/v1/schema/rule.d.ts +29 -0
- package/dist/v1/schema/rule.js +415 -0
- package/dist/v1/schema/validation/callable.d.ts +4 -1
- package/dist/v1/schema/validation/callable.js +10 -1
- package/dist/v1/schema/validation/class.js +36 -44
- package/dist/v1/schema/validation/core.js +3 -3
- package/dist/v1/schema/validation/domain.json-schema.d.ts +15 -0
- package/dist/v1/schema/validation/domain.json-schema.js +183 -0
- package/dist/v1/schema/validation/domain.structure.d.ts +4018 -0
- package/dist/v1/schema/validation/domain.structure.js +341 -151
- package/dist/v1/schema/validation/json.json-schema.d.ts +24 -0
- package/dist/v1/schema/validation/json.json-schema.js +36 -0
- package/dist/v1/schema/validation/policy/references.js +5 -21
- package/dist/v1/schema/validation/policy/uses.js +0 -3
- package/dist/v1/schema/validation/value-api.d.ts +12 -1
- package/dist/v1/schema/validation/value-api.js +10 -1
- package/dist/v1/schema/validation/value.js +3 -3
- package/dist/v1/schema/validation/value.json-schema.d.ts +51 -0
- package/dist/v1/schema/validation/value.json-schema.js +126 -0
- package/package.json +3 -1
|
@@ -3,39 +3,48 @@ import { Key, PropertyKey } from '../../addressing/index.js';
|
|
|
3
3
|
import { definitionRefIndex } from '../../addressing/ordering.js';
|
|
4
4
|
import { composeMethods } from '../../language/callable/composition.js';
|
|
5
5
|
import { canonicalizeValueSchema } from '../../language/value/profile/canonicalize.js';
|
|
6
|
+
import { escapePointerToken } from '../../language/value/syntax/pointer.js';
|
|
6
7
|
import { diagnostic } from '../diagnostic.js';
|
|
7
8
|
const formatDefinitionRef = Key.of;
|
|
8
9
|
export function analyzeDefinitions(environment) {
|
|
9
10
|
const diagnostics = [];
|
|
10
11
|
const result = new Map();
|
|
11
12
|
const visiting = new Set();
|
|
13
|
+
// A dependency was accepted against this same exact closure: a rule breaks here only at a Class
|
|
14
|
+
// of the candidate, or on an incomplete closure, which the dependency diagnostics report. An
|
|
15
|
+
// unresolved parent is reported where the candidate names it, by Class validation.
|
|
16
|
+
const reporter = (owner) => (code, at, message, ref) => {
|
|
17
|
+
if (owner.origin !== environment.candidate.origin)
|
|
18
|
+
return;
|
|
19
|
+
const pointer = `/classes/${escapePointerToken(owner.name)}${at}`;
|
|
20
|
+
diagnostics.push(diagnostic(code, pointer, message, ref));
|
|
21
|
+
};
|
|
12
22
|
const analyze = (ref) => {
|
|
13
23
|
const key = definitionRefIndex(ref);
|
|
14
24
|
const cached = result.get(key);
|
|
15
25
|
if (cached !== undefined)
|
|
16
26
|
return cached;
|
|
17
|
-
if (visiting.has(key)) {
|
|
18
|
-
diagnostics.push(diagnostic('DV_CLASS_ACYCLIC', '', `Inheritance cycle reaches ${formatDefinitionRef(ref)}.`, formatDefinitionRef(ref)));
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
|
21
27
|
const resolved = environment.resolveAny(ref);
|
|
22
28
|
if (resolved === undefined)
|
|
23
29
|
return undefined;
|
|
24
30
|
visiting.add(key);
|
|
31
|
+
const report = reporter(ref);
|
|
25
32
|
const declaration = resolved.declaration;
|
|
26
33
|
const parents = declaration.extends;
|
|
27
|
-
const parentAnalyses = parents.flatMap((parent) => {
|
|
34
|
+
const parentAnalyses = parents.flatMap((parent, index) => {
|
|
28
35
|
const target = environment.resolveAny(parent);
|
|
29
|
-
if (target
|
|
30
|
-
|
|
36
|
+
if (target?.ref.kind !== 'class')
|
|
37
|
+
return [];
|
|
38
|
+
if (visiting.has(definitionRefIndex(target.ref))) {
|
|
39
|
+
report('DV_CLASS_ACYCLIC', `/extends/${index}`, `Inheritance cycle reaches ${formatDefinitionRef(parent)}.`, formatDefinitionRef(parent));
|
|
31
40
|
return [];
|
|
32
41
|
}
|
|
33
|
-
const analysis =
|
|
42
|
+
const analysis = analyze(target.ref);
|
|
34
43
|
return analysis === undefined ? [] : [analysis];
|
|
35
44
|
});
|
|
36
45
|
const properties = mergeFields(parentAnalyses.map((parent) => parent.properties), ownFields(ref, declaration));
|
|
37
|
-
const data = mergeData(ref, declaration, parentAnalyses,
|
|
38
|
-
const methods = mergeMethods(ref, declaration, parentAnalyses,
|
|
46
|
+
const data = mergeData(ref, declaration, parentAnalyses, report);
|
|
47
|
+
const methods = mergeMethods(ref, declaration, parentAnalyses, report);
|
|
39
48
|
const analysis = {
|
|
40
49
|
ref,
|
|
41
50
|
declaration,
|
|
@@ -82,7 +91,7 @@ function mergeFields(inherited, own) {
|
|
|
82
91
|
}
|
|
83
92
|
return result;
|
|
84
93
|
}
|
|
85
|
-
function mergeData(owner, declaration, parents,
|
|
94
|
+
function mergeData(owner, declaration, parents, report) {
|
|
86
95
|
let effective;
|
|
87
96
|
for (const parent of parents) {
|
|
88
97
|
if (parent.data === undefined)
|
|
@@ -92,14 +101,15 @@ function mergeData(owner, declaration, parents, diagnostics) {
|
|
|
92
101
|
continue;
|
|
93
102
|
}
|
|
94
103
|
if (effective.identity !== parent.data.identity) {
|
|
95
|
-
|
|
104
|
+
const index = declaration.extends.findIndex((ref) => definitionRefIndex(ref) === definitionRefIndex(parent.ref));
|
|
105
|
+
report('DV_DATA_COMPOSITION', `/extends/${index}`, `Data has distinct declaring owners ${formatDefinitionRef(effective.owner)} and ${formatDefinitionRef(parent.data.owner)}.`);
|
|
96
106
|
}
|
|
97
107
|
}
|
|
98
108
|
const own = 'data' in declaration ? declaration.data : undefined;
|
|
99
109
|
if (own === undefined)
|
|
100
110
|
return effective;
|
|
101
111
|
if (effective !== undefined) {
|
|
102
|
-
|
|
112
|
+
report('DV_DATA_COMPOSITION', '/data', `Data redeclares the inherited contract from ${formatDefinitionRef(effective.owner)}.`);
|
|
103
113
|
}
|
|
104
114
|
return {
|
|
105
115
|
identity: `${definitionRefIndex(owner)}\u0000data`,
|
|
@@ -107,12 +117,20 @@ function mergeData(owner, declaration, parents, diagnostics) {
|
|
|
107
117
|
declaration: own,
|
|
108
118
|
};
|
|
109
119
|
}
|
|
110
|
-
function mergeMethods(owner, declaration, parents,
|
|
120
|
+
function mergeMethods(owner, declaration, parents, report) {
|
|
111
121
|
const own = new Map(Object.entries('methods' in declaration ? declaration.methods : {}).map(([name, method]) => [
|
|
112
122
|
name,
|
|
113
123
|
{ key: `${Key.of(owner)}.method.${name}`, owner, name, declaration: method },
|
|
114
124
|
]));
|
|
115
|
-
return composeMethods(parents, own, declaration.abstract, (left, right) => sameMethodSignature(left.declaration, right.declaration),
|
|
125
|
+
return composeMethods(parents, own, declaration.abstract, (left, right) => sameMethodSignature(left.declaration, right.declaration),
|
|
126
|
+
// A changed signature is the local Method's; an ambiguous or missing one needs a local Method.
|
|
127
|
+
(message, issue) => {
|
|
128
|
+
const local = issue.kind === 'signature'
|
|
129
|
+
? [...own.values()].find(({ key }) => key === issue.local)
|
|
130
|
+
: undefined;
|
|
131
|
+
const at = local === undefined ? '/methods' : `/methods/${escapePointerToken(local.name)}`;
|
|
132
|
+
report('DV_METHOD_COMPOSITION', at, message, Key.of(owner));
|
|
133
|
+
});
|
|
116
134
|
}
|
|
117
135
|
/** The exact signature required by abstract Method composition. */
|
|
118
136
|
export function sameMethodSignature(left, right) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { compare, compareMeaning, compareStructure } from './compare.js';
|
|
2
2
|
export { closedParents } from './extension.js';
|
|
3
3
|
export { requiredBump } from './versioning/index.js';
|
|
4
|
-
export type { Analysis, Assessment, Bump, Comparison, ComparisonEntry, ComparisonEvidence, ComparisonRequest, ComparisonScope, Facet, Fingerprint, MeaningComparison, Observation, RequiredBump, SchemaIdentity, StructureComparison, Subject, Usage, VersionChange, } from './model.js';
|
|
4
|
+
export type { Analysis, Assessment, Bump, Comparison, ComparisonEntry, ComparisonEvidence, ComparisonRequest, ComparisonScope, DiagnosticCode, Facet, Fingerprint, MeaningComparison, Observation, RequiredBump, SchemaIdentity, StructureComparison, Subject, Usage, VersionChange, } from './model.js';
|
|
@@ -20,10 +20,10 @@ export function keyForDefinitionRef(ref) {
|
|
|
20
20
|
/** Interpret one canonical V1 Key as a Definition or a Class member location. */
|
|
21
21
|
export function keyReference(key) {
|
|
22
22
|
const semantic = key.slice(key.indexOf(':') + 1);
|
|
23
|
+
// A Core slug may hold `.`: the name of a Core key is the whole rest of its coordinate.
|
|
24
|
+
if (semantic.startsWith('core.'))
|
|
25
|
+
return { kind: 'core', name: semantic.slice('core.'.length) };
|
|
23
26
|
const parts = semantic.split('.');
|
|
24
|
-
if (parts[0] === 'core' && parts.length === 2) {
|
|
25
|
-
return { kind: 'core', name: parts[1] };
|
|
26
|
-
}
|
|
27
27
|
if (parts.length === 2) {
|
|
28
28
|
return { kind: parts[0], name: parts[1] };
|
|
29
29
|
}
|
|
@@ -4,6 +4,11 @@ import type { DomainSchema } from '../model/schema.js';
|
|
|
4
4
|
import type { ReferenceSite } from '../resolution/origins.js';
|
|
5
5
|
import type { MeaningDifference } from './diff.js';
|
|
6
6
|
export type Fingerprint = `sha256:${string}`;
|
|
7
|
+
/**
|
|
8
|
+
* The codes a comparison request is refused with: the request, not a Schema, is invalid. A
|
|
9
|
+
* `schema.Error` carries them beside the codes of a refused Schema document.
|
|
10
|
+
*/
|
|
11
|
+
export type DiagnosticCode = 'DM_CAPABILITY_INVALID' | 'DM_DEPENDENCY_CONTEXT_INVALID' | 'DM_DEPENDENCY_NOT_RETAINED' | 'DM_MEMBER_ORIGIN_MISMATCH' | 'DM_MEMBER_ROOT_INVALID';
|
|
7
12
|
/** Inputs carry accepted schemas; a dependency's source is always its retained exact context. */
|
|
8
13
|
export interface ComparisonRequest {
|
|
9
14
|
readonly scope: {
|
|
@@ -1,11 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import type { DiagnosticCode as LanguageDiagnosticCode } from '../language/validation/diagnostic.js';
|
|
2
|
+
import type { Diagnostic as LanguageDiagnostic } from '../language/validation/diagnostic.js';
|
|
3
|
+
import type { DiagnosticCode as CompatibilityDiagnosticCode } from './compatibility/model.js';
|
|
4
|
+
/** The codes a Schema document is refused with, one per rule of `RULES`. */
|
|
5
|
+
export type SchemaDiagnosticCode = 'DV_ACCEPTANCE_CONTEXT' | 'DV_CALLABLE_ADMISSION' | 'DV_CALLABLE_AUTH' | 'DV_CALLABLE_IO' | 'DV_CLASS_ABSTRACT' | 'DV_CLASS_ACYCLIC' | 'DV_CLASS_INHERITANCE' | 'DV_CLASS_KIND' | 'DV_CORE_EDGE_CLASS' | 'DV_CORE_EDGE_CONSTRAINTS' | 'DV_CORE_EDGE_KEY' | 'DV_CORE_EDGE_PROPERTIES' | 'DV_CORE_EDGE_UNIQUE' | 'DV_CORE_NODE_CLASS' | 'DV_CORE_NODE_PROPERTIES' | 'DV_CORE_NODE_UNIQUE' | '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_FOREIGN_MINIMUM' | 'DV_EDGE_LIFETIME' | 'DV_EDGE_ROLE' | 'DV_EDGE_UNIQUE' | 'DV_ENTRYPOINT' | 'DV_JSON_VALUE' | 'DV_METHOD_ABSTRACT' | 'DV_METHOD_COMPOSITION' | 'DV_NODE_UNIQUE' | 'DV_PROPERTY_AUTO' | '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_BINARY_INPUT' | 'STRUCTURE_CALLABLE_POLICY_AUTH' | 'STRUCTURE_DEPENDENCY_ALIAS' | 'STRUCTURE_DOMAIN_NAME' | 'STRUCTURE_DUPLICATE_ITEM' | 'STRUCTURE_EDGE_BLOB' | 'STRUCTURE_EDGE_ORIENTATION' | 'STRUCTURE_FORMAT' | 'STRUCTURE_KEY' | 'STRUCTURE_MAXIMUM' | 'STRUCTURE_MINIMUM' | 'STRUCTURE_PROPERTY_KEY' | 'STRUCTURE_PROTO_KEY' | 'STRUCTURE_REQUIRED' | 'STRUCTURE_STATE_TRANSITIONS' | 'STRUCTURE_TYPE' | 'STRUCTURE_UNION' | 'STRUCTURE_UNKNOWN_FIELD' | 'STRUCTURE_VALUE' | 'UNSUPPORTED_DOCUMENT_FORMAT' | 'UNSUPPORTED_DSL_VERSION';
|
|
6
|
+
/**
|
|
7
|
+
* A Schema refuses a document with its own codes, and a comparison request with the
|
|
8
|
+
* compatibility codes. `pointer` names the position the refused rule applies to, in the document
|
|
9
|
+
* or in the request; it is empty, the root, only when text does not parse or the document is not
|
|
10
|
+
* an object.
|
|
11
|
+
*/
|
|
12
|
+
export interface SchemaDiagnostic<out Code extends SchemaDiagnosticCode | CompatibilityDiagnosticCode = SchemaDiagnosticCode | CompatibilityDiagnosticCode> {
|
|
3
13
|
readonly code: Code;
|
|
4
14
|
readonly pointer: string;
|
|
5
15
|
readonly message: string;
|
|
6
16
|
readonly ref?: string;
|
|
17
|
+
/** The code of the value-language refusal the diagnostic carries; its message is the message. */
|
|
18
|
+
readonly valueCode?: LanguageDiagnosticCode;
|
|
7
19
|
}
|
|
8
|
-
export declare function diagnostic<const Code extends SchemaDiagnosticCode>(code: Code, pointer: string, message: string, ref?: string): SchemaDiagnostic<Code>;
|
|
20
|
+
export declare function diagnostic<const Code extends SchemaDiagnosticCode | CompatibilityDiagnosticCode>(code: Code, pointer: string, message: string, ref?: string): SchemaDiagnostic<Code>;
|
|
21
|
+
/** A Schema diagnostic carrying one value-language refusal, at its position and with its code. */
|
|
22
|
+
export declare function valueDiagnostic<const Code extends SchemaDiagnosticCode>(code: Code, refusal: LanguageDiagnostic): SchemaDiagnostic<Code>;
|
|
9
23
|
export declare class SchemaError extends Error {
|
|
10
24
|
readonly diagnostics: readonly SchemaDiagnostic[];
|
|
11
25
|
constructor(diagnostics: readonly SchemaDiagnostic[]);
|
|
@@ -2,6 +2,17 @@ import { formatDiagnostics, orderDiagnostics } from '../language/validation/diag
|
|
|
2
2
|
export function diagnostic(code, pointer, message, ref) {
|
|
3
3
|
return Object.freeze({ code, pointer, message, ...(ref === undefined ? {} : { ref }) });
|
|
4
4
|
}
|
|
5
|
+
/** A Schema diagnostic carrying one value-language refusal, at its position and with its code. */
|
|
6
|
+
export function valueDiagnostic(code, refusal) {
|
|
7
|
+
const { pointer, message, ref } = refusal;
|
|
8
|
+
return Object.freeze({
|
|
9
|
+
code,
|
|
10
|
+
pointer,
|
|
11
|
+
message,
|
|
12
|
+
...(ref === undefined ? {} : { ref }),
|
|
13
|
+
valueCode: refusal.code,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
5
16
|
export class SchemaError extends Error {
|
|
6
17
|
diagnostics;
|
|
7
18
|
constructor(diagnostics) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Admit, encode, inspect, and semantically resolve canonical V1 DomainSchemas. */
|
|
2
2
|
import type { SourceDomain } from '../domain/index.js';
|
|
3
3
|
import type { DomainSchema } from './model/schema.js';
|
|
4
|
-
export type { DomainSchema, DomainSchemaIR, DomainOfSchema as DomainOf } from './model/schema.js';
|
|
4
|
+
export type { DomainSchema, DomainSchemaIR, DomainSchemaDocument as Document, DomainOfSchema as DomainOf, } from './model/schema.js';
|
|
5
5
|
export type ResolvedDomainOf<Schema extends DomainSchema> = SourceDomain<Schema>;
|
|
6
6
|
export interface Resolve {
|
|
7
7
|
<const Schema extends DomainSchema>(schema: Schema): ResolvedDomainOf<Schema>;
|
|
@@ -20,6 +20,8 @@ export { compile, load } from '../compiled/index.js';
|
|
|
20
20
|
export type { CompiledSchema, DomainOfCompiled } from '../compiled/index.js';
|
|
21
21
|
export { SchemaError as Error } from './diagnostic.js';
|
|
22
22
|
export type { SchemaDiagnostic as Diagnostic } from './diagnostic.js';
|
|
23
|
+
export { RULES } from './rule.js';
|
|
24
|
+
export type { SchemaRule as Rule, SchemaRuleStage as RuleStage } from './rule.js';
|
|
23
25
|
export type { DomainSchemaLookup as Lookup } from './dependency/lookup.js';
|
|
24
26
|
export type { DomainSchemaHeader as Header } from './codec/header.js';
|
|
25
27
|
export type { DomainDependency } from '../addressing/index.js';
|
package/dist/v1/schema/index.js
CHANGED
|
@@ -10,5 +10,6 @@ export { header } from './codec/header.js';
|
|
|
10
10
|
export { DOMAIN_FORMAT as FORMAT, DOMAIN_VERSION as VERSION } from './model/format.js';
|
|
11
11
|
export { compile, load } from '../compiled/index.js';
|
|
12
12
|
export { SchemaError as Error } from './diagnostic.js';
|
|
13
|
+
export { RULES } from './rule.js';
|
|
13
14
|
/** The versioned value-schema grammar embedded in declarations. */
|
|
14
15
|
export * as values from './validation/value-api.js';
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Value as JsonValue } from '@astrale-os/kernel-dsl/value';
|
|
2
|
+
import type { Key, Revision } from '../../addressing/index.js';
|
|
2
3
|
import type { DomainDependencyMap, ViewRef } from '../../addressing/index.js';
|
|
3
4
|
import type { Domain, DomainOfSource, DomainSource } from '../../domain/model/domain.js';
|
|
4
5
|
import type { FunctionDefinition } from '../../language/callable/model/callable.js';
|
|
5
6
|
import type { ClassDefinition } from '../../language/class/model/class.js';
|
|
7
|
+
import type { PropertyValues } from '../../language/class/property-values.js';
|
|
6
8
|
import type { CoreContent } from '../../language/core/model/core.js';
|
|
7
9
|
import type { PolicyDefinition } from '../../language/policy/model/policy.js';
|
|
8
10
|
import type { ViewDefinition } from '../../language/view/model/view.js';
|
|
@@ -21,6 +23,22 @@ export interface DomainSchemaIR {
|
|
|
21
23
|
readonly views: Readonly<Record<string, ViewDefinition>>;
|
|
22
24
|
readonly core: CoreContent;
|
|
23
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* The JSON document of a Domain schema, as tools write and exchange it: `DomainSchemaIR` without
|
|
28
|
+
* its in-process proofs. The structure the Kernel enforces has this type, which the build checks
|
|
29
|
+
* (`validation/domain.structure.typecheck.ts`), and the published JSON Schema describes it.
|
|
30
|
+
*/
|
|
31
|
+
export type DomainSchemaDocument = DocumentOf<DomainSchemaIR>;
|
|
32
|
+
/**
|
|
33
|
+
* The JSON document a model type describes. A `Revision` and `PropertyValues` are in-process
|
|
34
|
+
* proofs: the document carries them as plain text and plain values.
|
|
35
|
+
*/
|
|
36
|
+
export type DocumentOf<Model> = [JsonValue] extends [Model] ? Model : DocumentOfEach<Model>;
|
|
37
|
+
type DocumentOfEach<Model> = Model extends Revision ? string : Model extends PropertyValues ? {
|
|
38
|
+
readonly [Key in keyof Model as Key extends string ? Key : never]: DocumentOf<Model[Key]>;
|
|
39
|
+
} : Model extends string | number | boolean | null | undefined ? Model : {
|
|
40
|
+
readonly [Key in keyof Model]: DocumentOf<Model[Key]>;
|
|
41
|
+
};
|
|
24
42
|
declare const DOMAIN_SCHEMA_BRAND: unique symbol;
|
|
25
43
|
/**
|
|
26
44
|
* Accepted canonical schema carrying its exact resolved Domain projection.
|
|
@@ -20,8 +20,9 @@ export function requireDomainClosure(schema) {
|
|
|
20
20
|
const closure = knownDomainClosure(schema);
|
|
21
21
|
if (closure !== undefined)
|
|
22
22
|
return closure;
|
|
23
|
+
// What the value lacks is the exact closure of its dependencies, retained only by acceptance.
|
|
23
24
|
throw new SchemaError([
|
|
24
|
-
diagnostic('DV_ACCEPTANCE_CONTEXT', '', `DomainSchema ${schema.origin} has no retained acceptance context; accept it again against its exact lookup.`),
|
|
25
|
+
diagnostic('DV_ACCEPTANCE_CONTEXT', '/dependencies', `DomainSchema ${schema.origin} has no retained acceptance context; accept it again against its exact lookup.`),
|
|
25
26
|
]);
|
|
26
27
|
}
|
|
27
28
|
export function lookupForDomainClosure(schema) {
|
|
@@ -147,10 +147,12 @@ function loadDependencyClosure(candidate, dependencies, lookup, diagnostics) {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
function validateDependencyUse(candidate, directOrigins, diagnostics) {
|
|
150
|
+
// Each reference that cannot resolve is reported where it is written; the dependency it lacks
|
|
151
|
+
// belongs in the dependency map.
|
|
150
152
|
const used = collectUsedForeignOrigins(candidate);
|
|
151
153
|
for (const origin of used) {
|
|
152
154
|
if (!directOrigins.has(origin)) {
|
|
153
|
-
diagnostics.push(diagnostic('DV_DEPENDENCY_DIRECT', '', `Foreign origin ${origin} is referenced without an exact direct dependency.`));
|
|
155
|
+
diagnostics.push(diagnostic('DV_DEPENDENCY_DIRECT', '/dependencies', `Foreign origin ${origin} is referenced without an exact direct dependency.`));
|
|
154
156
|
}
|
|
155
157
|
}
|
|
156
158
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { SchemaDiagnosticCode } from './diagnostic.js';
|
|
2
|
+
/**
|
|
3
|
+
* What a rule reads to decide. `structure`: the shape of the document alone. `rule`: the whole
|
|
4
|
+
* document. `context`: the document and its environment, so one document can be accepted in one
|
|
5
|
+
* environment and refused in another. The environment is what the lookup serves for the pinned
|
|
6
|
+
* dependencies, their accepted Schemas or their absence, and, for a Schema already accepted, the
|
|
7
|
+
* closure its acceptance retained.
|
|
8
|
+
*/
|
|
9
|
+
export type SchemaRuleStage = 'structure' | 'rule' | 'context';
|
|
10
|
+
/** The rule one Schema diagnostic code reports. */
|
|
11
|
+
export interface SchemaRule {
|
|
12
|
+
readonly stage: SchemaRuleStage;
|
|
13
|
+
/**
|
|
14
|
+
* The positions the rule constrains, which its diagnostics point at: JSON Pointer templates in
|
|
15
|
+
* which a `{name}` token stands for one token of the kind it names and a final `{/path*}` for any
|
|
16
|
+
* further tokens. `{endpoint}` is `source`, `target`, `0` or `1`; `{count}` is `outgoing`,
|
|
17
|
+
* `incoming` or `incident`; `{operation}` is `read` or `traverse`; `{key}` is a Property key.
|
|
18
|
+
*/
|
|
19
|
+
readonly positions: readonly [string, ...string[]];
|
|
20
|
+
/** The rule, in one plain sentence. */
|
|
21
|
+
readonly statement: string;
|
|
22
|
+
/** What the feature the rule guards enforces on data or on calls, where it enforces something. */
|
|
23
|
+
readonly enforces?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Every Schema diagnostic code with the rule it reports. A code added to the DSL does not compile
|
|
27
|
+
* until it is described here.
|
|
28
|
+
*/
|
|
29
|
+
export declare const RULES: Readonly<Record<SchemaDiagnosticCode, SchemaRule>>;
|