@astrale-os/kernel-dsl 1.0.0-beta.13 → 1.0.0-beta.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/v1/addressing/domain-dependency.d.ts +0 -6
- package/dist/v1/addressing/domain-dependency.js +1 -6
- package/dist/v1/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/authoring.d.ts +43 -0
- package/dist/v1/builder/class/property.d.ts +3 -9
- package/dist/v1/builder/class/property.js +1 -0
- package/dist/v1/builder/index.d.ts +1 -1
- package/dist/v1/builder/lowering/class.js +5 -1
- package/dist/v1/builder/lowering/policy.js +2 -0
- package/dist/v1/builder/lowering/schema/context.d.ts +5 -0
- package/dist/v1/builder/lowering/schema/context.js +22 -0
- package/dist/v1/builder/policy/authoring.d.ts +84 -4
- package/dist/v1/builder/policy/authoring.js +44 -14
- package/dist/v1/builder/schema/projection/class.d.ts +116 -14
- package/dist/v1/bundle/codec.js +9 -9
- 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/compiled/admission/accept.js +3 -3
- package/dist/v1/compiled/admission/closure.js +2 -2
- package/dist/v1/compiled/admission/semantics/core.js +3 -7
- package/dist/v1/compiled/admission/semantics/policy/parity.js +3 -10
- package/dist/v1/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/core/facts.d.ts +17 -4
- package/dist/v1/language/core/facts.js +26 -5
- package/dist/v1/language/definition/metadata.d.ts +5 -0
- package/dist/v1/language/definition/metadata.js +7 -0
- package/dist/v1/language/limits.d.ts +64 -0
- package/dist/v1/language/limits.js +60 -0
- package/dist/v1/language/policy/analysis/budgets.d.ts +39 -18
- package/dist/v1/language/policy/analysis/budgets.js +30 -20
- package/dist/v1/language/policy/analysis/checks.js +3 -2
- package/dist/v1/language/policy/analysis/typing.js +4 -3
- 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 +29 -0
- package/dist/v1/language/validation/rule.js +120 -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/regexp/ast.js +6 -7
- package/dist/v1/language/value/regexp/compile.d.ts +5 -11
- package/dist/v1/language/value/regexp/compile.js +14 -12
- package/dist/v1/language/value/regexp/syntax.js +3 -2
- package/dist/v1/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/admission/accept.js +3 -14
- package/dist/v1/schema/admission/callable.d.ts +21 -0
- package/dist/v1/schema/admission/callable.js +96 -0
- package/dist/v1/schema/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 +10 -1
- package/dist/v1/schema/index.js +4 -0
- package/dist/v1/schema/model/schema.d.ts +19 -1
- package/dist/v1/schema/normalization/domain.d.ts +2 -0
- package/dist/v1/schema/normalization/domain.js +2 -1
- package/dist/v1/schema/resolution/closure.js +2 -1
- package/dist/v1/schema/resolution/context.js +10 -8
- package/dist/v1/schema/resolution/domain.d.ts +5 -0
- package/dist/v1/schema/resolution/domain.js +1 -1
- package/dist/v1/schema/rule.d.ts +32 -0
- package/dist/v1/schema/rule.js +428 -0
- package/dist/v1/schema/validation/callable.d.ts +35 -2
- package/dist/v1/schema/validation/callable.js +51 -8
- package/dist/v1/schema/validation/class.js +36 -44
- package/dist/v1/schema/validation/core.js +19 -13
- package/dist/v1/schema/validation/domain.js +2 -2
- 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.route.d.ts +6 -1
- package/dist/v1/schema/validation/domain.route.js +18 -0
- package/dist/v1/schema/validation/domain.structure.d.ts +4020 -0
- package/dist/v1/schema/validation/domain.structure.js +359 -153
- 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/budgets.d.ts +33 -2
- package/dist/v1/schema/validation/policy/budgets.js +89 -16
- package/dist/v1/schema/validation/policy/references.js +6 -21
- package/dist/v1/schema/validation/policy/uses.d.ts +29 -0
- package/dist/v1/schema/validation/policy/uses.js +28 -51
- 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.d.ts +3 -0
- package/dist/v1/schema/validation/value.js +6 -12
- 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
|
@@ -1,22 +1,11 @@
|
|
|
1
|
-
import { accept as acceptJsonValue, BoundaryError as JsonBoundaryError, } from '@astrale-os/kernel-dsl/value';
|
|
2
1
|
import { canonicalDomainSchemaAfterValidation } from '../canonical/revision.js';
|
|
3
2
|
import { emptyDomainSchemaLookup } from '../dependency/lookup.js';
|
|
4
|
-
import { SchemaError
|
|
3
|
+
import { SchemaError } from '../diagnostic.js';
|
|
5
4
|
import { rememberDomainClosure } from '../resolution/closure.js';
|
|
6
5
|
import { validateDomainSchemaSemantics } from '../validation/domain.js';
|
|
7
|
-
import {
|
|
6
|
+
import { structureDomainSchema } from '../validation/domain.route.js';
|
|
8
7
|
export function acceptDomainSchema(input, lookup = emptyDomainSchemaLookup()) {
|
|
9
|
-
|
|
10
|
-
try {
|
|
11
|
-
admitted = acceptJsonValue(input);
|
|
12
|
-
}
|
|
13
|
-
catch (error) {
|
|
14
|
-
if (error instanceof JsonBoundaryError) {
|
|
15
|
-
throw new SchemaError([diagnostic('DV_JSON_VALUE', error.pointer, error.message)]);
|
|
16
|
-
}
|
|
17
|
-
throw error;
|
|
18
|
-
}
|
|
19
|
-
const structured = routeDomainSchema(admitted);
|
|
8
|
+
const structured = structureDomainSchema(input);
|
|
20
9
|
const validation = validateDomainSchemaSemantics(structured, lookup);
|
|
21
10
|
if (validation.diagnostics.length > 0)
|
|
22
11
|
throw new SchemaError(validation.diagnostics);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ClassRef } from '../../addressing/index.js';
|
|
2
|
+
import type { CallableValidation } from '../../domain/validation/create.js';
|
|
3
|
+
import type { CallableDefinition } from '../../language/callable/model/callable.js';
|
|
4
|
+
import type { DomainSchema } from '../model/schema.js';
|
|
5
|
+
/** One admitted callable contract and the validators of its exact owner environment. */
|
|
6
|
+
export interface AcceptedCallable extends CallableValidation {
|
|
7
|
+
readonly definition: CallableDefinition;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Accept one callable contract in the exact environment of its owner Domain, by the one validation
|
|
11
|
+
* every contract passes wherever it is declared (`validateContract`, `validateContractPolicy`,
|
|
12
|
+
* `validateCheckBudget`): the structure of a Function declaration without `ref`, its value schemas
|
|
13
|
+
* against the owner registry, its execution modifier and admission age, and its Policy with the
|
|
14
|
+
* budget of its checks. `receiver` is the owner Node Class whose Node receives the call and which
|
|
15
|
+
* the Policy names `self`: the Class of a Function instance, whose Node carries the contract, or
|
|
16
|
+
* the owner of an instance Method. Without it, as at a Function declaration, the Policy names none.
|
|
17
|
+
* Returns the canonical definition and its validators.
|
|
18
|
+
*/
|
|
19
|
+
export declare function acceptCallable(input: unknown, owner: DomainSchema, options?: {
|
|
20
|
+
readonly receiver?: ClassRef;
|
|
21
|
+
}): AcceptedCallable;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { accept as acceptJsonValue, BoundaryError as JsonBoundaryError, } from '@astrale-os/kernel-dsl/value';
|
|
2
|
+
import { definitionRefIndex } from '../../addressing/ordering.js';
|
|
3
|
+
import { isBinaryInput } from '../../language/callable/model/callable.js';
|
|
4
|
+
import { measureChecks } from '../../language/policy/analysis/budgets.js';
|
|
5
|
+
import { PolicyTyping } from '../../language/policy/analysis/typing.js';
|
|
6
|
+
import { normalizePolicyChecks } from '../../language/policy/normalization/normalize.js';
|
|
7
|
+
import {} from '../../language/value/evaluate/preparation.js';
|
|
8
|
+
import { analyzeDefinitions } from '../analysis/class.js';
|
|
9
|
+
import { deepFreeze } from '../canonical/freeze.js';
|
|
10
|
+
import { SchemaError, diagnostic } from '../diagnostic.js';
|
|
11
|
+
import { canonicalizeCallable } from '../normalization/domain.js';
|
|
12
|
+
import { lookupForDomainClosure } from '../resolution/closure.js';
|
|
13
|
+
import { buildDomainResolutionContext } from '../resolution/context.js';
|
|
14
|
+
import { callableValidation } from '../resolution/domain.js';
|
|
15
|
+
import { createDomainValueSchemaRegistry } from '../resolution/value.registry.js';
|
|
16
|
+
import { validateContract } from '../validation/callable.js';
|
|
17
|
+
import { parseCallableContract } from '../validation/domain.structure.js';
|
|
18
|
+
import { validateCheckBudget } from '../validation/policy/budgets.js';
|
|
19
|
+
import { PolicyValidationContext } from '../validation/policy/context.js';
|
|
20
|
+
import { validatePolicyReferences } from '../validation/policy/references.js';
|
|
21
|
+
import { validateContractPolicy } from '../validation/policy/uses.js';
|
|
22
|
+
// An accepted DomainSchema is immutable and retains its closure, so its environment is reusable.
|
|
23
|
+
const environments = new WeakMap();
|
|
24
|
+
/**
|
|
25
|
+
* Accept one callable contract in the exact environment of its owner Domain, by the one validation
|
|
26
|
+
* every contract passes wherever it is declared (`validateContract`, `validateContractPolicy`,
|
|
27
|
+
* `validateCheckBudget`): the structure of a Function declaration without `ref`, its value schemas
|
|
28
|
+
* against the owner registry, its execution modifier and admission age, and its Policy with the
|
|
29
|
+
* budget of its checks. `receiver` is the owner Node Class whose Node receives the call and which
|
|
30
|
+
* the Policy names `self`: the Class of a Function instance, whose Node carries the contract, or
|
|
31
|
+
* the owner of an instance Method. Without it, as at a Function declaration, the Policy names none.
|
|
32
|
+
* Returns the canonical definition and its validators.
|
|
33
|
+
*/
|
|
34
|
+
export function acceptCallable(input, owner, options = {}) {
|
|
35
|
+
let value;
|
|
36
|
+
try {
|
|
37
|
+
value = acceptJsonValue(input);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error instanceof JsonBoundaryError) {
|
|
41
|
+
throw new SchemaError([diagnostic('DV_JSON_VALUE', error.pointer, error.message)]);
|
|
42
|
+
}
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
const callable = parseCallableContract(value);
|
|
46
|
+
const environment = ownerEnvironment(owner);
|
|
47
|
+
const { receiver } = options;
|
|
48
|
+
if (receiver !== undefined) {
|
|
49
|
+
const resolved = environment.resolution.resolve(receiver);
|
|
50
|
+
if (resolved === undefined ||
|
|
51
|
+
resolved.ref.kind !== 'class' ||
|
|
52
|
+
resolved.kind !== 'node' ||
|
|
53
|
+
definitionRefIndex(resolved.ref) !== definitionRefIndex(receiver) ||
|
|
54
|
+
receiver.origin !== owner.origin) {
|
|
55
|
+
throw new SchemaError([
|
|
56
|
+
diagnostic('DV_REF_RESOLVES', '', 'A receiver must be a Node Class of the owner Domain.'),
|
|
57
|
+
]);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const issues = [];
|
|
61
|
+
validateContract(callable, '', environment.registry, issues);
|
|
62
|
+
if (typeof callable.policy === 'object') {
|
|
63
|
+
const policies = new PolicyValidationContext(environment.resolution, environment.analysis);
|
|
64
|
+
// Normalizes the owner's named Policies, which the Policy's checks are typed against.
|
|
65
|
+
validatePolicyReferences(policies);
|
|
66
|
+
validateContractPolicy(policies, new PolicyTyping(policies), callable, '', receiver);
|
|
67
|
+
// A document measures its own check trees (`validatePolicyBudgets`); this one is in none.
|
|
68
|
+
validateCheckBudget(policies, '/policy', measureChecks(normalizePolicyChecks(callable.policy)));
|
|
69
|
+
issues.push(...policies.diagnostics);
|
|
70
|
+
}
|
|
71
|
+
if (issues.length > 0)
|
|
72
|
+
throw new SchemaError(issues);
|
|
73
|
+
const definition = deepFreeze(canonicalizeCallable(callable));
|
|
74
|
+
const validation = callableValidation(isBinaryInput(definition.input) ? definition.input.metadata : definition.input, definition.output.mode === 'binary'
|
|
75
|
+
? undefined
|
|
76
|
+
: definition.output.mode === 'value'
|
|
77
|
+
? definition.output.schema
|
|
78
|
+
: definition.output.item, environment.registry,
|
|
79
|
+
// Patterns live with these validators: carried contracts never grow a process-wide pool.
|
|
80
|
+
new Map());
|
|
81
|
+
return Object.freeze({ ...validation, definition });
|
|
82
|
+
}
|
|
83
|
+
function ownerEnvironment(owner) {
|
|
84
|
+
const cached = environments.get(owner);
|
|
85
|
+
if (cached !== undefined)
|
|
86
|
+
return cached;
|
|
87
|
+
const lookup = lookupForDomainClosure(owner);
|
|
88
|
+
const resolution = buildDomainResolutionContext(owner, lookup);
|
|
89
|
+
const environment = Object.freeze({
|
|
90
|
+
resolution,
|
|
91
|
+
analysis: analyzeDefinitions(resolution),
|
|
92
|
+
registry: createDomainValueSchemaRegistry(owner, lookup),
|
|
93
|
+
});
|
|
94
|
+
environments.set(owner, environment);
|
|
95
|
+
return environment;
|
|
96
|
+
}
|
|
@@ -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>;
|
|
@@ -9,6 +9,8 @@ export interface Resolve {
|
|
|
9
9
|
export declare const resolve: Resolve;
|
|
10
10
|
export type { SchemaDiagnosticCode as DiagnosticCode } from './diagnostic.js';
|
|
11
11
|
export { acceptDomainSchema as accept } from './admission/accept.js';
|
|
12
|
+
export { acceptCallable } from './admission/callable.js';
|
|
13
|
+
export type { AcceptedCallable } from './admission/callable.js';
|
|
12
14
|
export { decodeDomainSchema as decode, encodeDomainSchema as encode, serializeDomainSchema as serialize, } from './codec/schema.js';
|
|
13
15
|
export { revisionOfDomainSchema as revision } from './canonical/revision.js';
|
|
14
16
|
export { ANNOTATION_KEYWORDS, FIELD_ROLES, callableFingerprint } from './compatibility/index.js';
|
|
@@ -20,6 +22,13 @@ export { compile, load } from '../compiled/index.js';
|
|
|
20
22
|
export type { CompiledSchema, DomainOfCompiled } from '../compiled/index.js';
|
|
21
23
|
export { SchemaError as Error } from './diagnostic.js';
|
|
22
24
|
export type { SchemaDiagnostic as Diagnostic } from './diagnostic.js';
|
|
25
|
+
export { RULES } from './rule.js';
|
|
26
|
+
export type { SchemaRule as Rule, SchemaRuleStage as RuleStage } from './rule.js';
|
|
27
|
+
export { limits } from '../language/limits.js';
|
|
28
|
+
export type { LimitKey } from '../language/limits.js';
|
|
29
|
+
export { measurePolicies } from './validation/policy/budgets.js';
|
|
30
|
+
export type { PolicyMeasures } from './validation/policy/budgets.js';
|
|
31
|
+
export type { CheckMeasure, PolicyMeasure } from '../language/policy/analysis/budgets.js';
|
|
23
32
|
export type { DomainSchemaLookup as Lookup } from './dependency/lookup.js';
|
|
24
33
|
export type { DomainSchemaHeader as Header } from './codec/header.js';
|
|
25
34
|
export type { DomainDependency } from '../addressing/index.js';
|
package/dist/v1/schema/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { resolve as resolveDomainSchema } from './resolution/domain.js';
|
|
3
3
|
export const resolve = resolveDomainSchema;
|
|
4
4
|
export { acceptDomainSchema as accept } from './admission/accept.js';
|
|
5
|
+
export { acceptCallable } from './admission/callable.js';
|
|
5
6
|
export { decodeDomainSchema as decode, encodeDomainSchema as encode, serializeDomainSchema as serialize, } from './codec/schema.js';
|
|
6
7
|
export { revisionOfDomainSchema as revision } from './canonical/revision.js';
|
|
7
8
|
export { ANNOTATION_KEYWORDS, FIELD_ROLES, callableFingerprint } from './compatibility/index.js';
|
|
@@ -10,5 +11,8 @@ export { header } from './codec/header.js';
|
|
|
10
11
|
export { DOMAIN_FORMAT as FORMAT, DOMAIN_VERSION as VERSION } from './model/format.js';
|
|
11
12
|
export { compile, load } from '../compiled/index.js';
|
|
12
13
|
export { SchemaError as Error } from './diagnostic.js';
|
|
14
|
+
export { RULES } from './rule.js';
|
|
15
|
+
export { limits } from '../language/limits.js';
|
|
16
|
+
export { measurePolicies } from './validation/policy/budgets.js';
|
|
13
17
|
/** The versioned value-schema grammar embedded in declarations. */
|
|
14
18
|
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.
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
import type { CallableDefinition } from '../../language/callable/model/callable.js';
|
|
1
2
|
import type { DomainSchemaIR } from '../model/schema.js';
|
|
2
3
|
export declare function normalizeDomainSchema(schema: DomainSchemaIR): DomainSchemaIR;
|
|
4
|
+
export declare function canonicalizeCallable(value: CallableDefinition): CallableDefinition;
|
|
@@ -118,7 +118,7 @@ function canonicalizeFunction(value) {
|
|
|
118
118
|
...canonicalizeCallable(value),
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
|
-
function canonicalizeCallable(value) {
|
|
121
|
+
export function canonicalizeCallable(value) {
|
|
122
122
|
const base = {
|
|
123
123
|
...withDescription(value),
|
|
124
124
|
input: isBinaryInput(value.input)
|
|
@@ -172,6 +172,7 @@ function canonicalizeProperty(value) {
|
|
|
172
172
|
? {}
|
|
173
173
|
: {
|
|
174
174
|
auto: {
|
|
175
|
+
// The distinct events of a non-empty list are a non-empty list.
|
|
175
176
|
on: [...new Set(value.auto.on)].sort(compareUnicode),
|
|
176
177
|
set: value.auto.set,
|
|
177
178
|
},
|
|
@@ -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) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { dependencyLimits } from '../../addressing/domain-dependency.js';
|
|
2
1
|
import { definitionRefIndex } from '../../addressing/ordering.js';
|
|
3
2
|
import { DOMAIN_REVISION_PATTERN } from '../../addressing/patterns.js';
|
|
3
|
+
import { limits } from '../../language/limits.js';
|
|
4
4
|
import { escapePointerToken } from '../../language/value/syntax/pointer.js';
|
|
5
5
|
import { revisionOfDomainSchema } from '../canonical/revision.js';
|
|
6
6
|
import { diagnostic } from '../diagnostic.js';
|
|
@@ -11,8 +11,8 @@ export function buildDomainResolutionContext(candidate, lookup) {
|
|
|
11
11
|
const dependencies = new Map();
|
|
12
12
|
const definitions = new Map();
|
|
13
13
|
const directOrigins = new Set();
|
|
14
|
-
if (Object.keys(candidate.dependencies).length >
|
|
15
|
-
diagnostics.push(diagnostic('DV_DEPENDENCY_LIMITS', '/dependencies', `A Domain may declare at most ${
|
|
14
|
+
if (Object.keys(candidate.dependencies).length > limits.dependency.direct) {
|
|
15
|
+
diagnostics.push(diagnostic('DV_DEPENDENCY_LIMITS', '/dependencies', `A Domain may declare at most ${limits.dependency.direct} direct dependency aliases.`));
|
|
16
16
|
}
|
|
17
17
|
for (const [alias, dependency] of Object.entries(candidate.dependencies)) {
|
|
18
18
|
const pointer = `/dependencies/${escapePointerToken(alias)}`;
|
|
@@ -121,16 +121,16 @@ function loadDependencyClosure(candidate, dependencies, lookup, diagnostics) {
|
|
|
121
121
|
continue;
|
|
122
122
|
}
|
|
123
123
|
dependencies.set(nested.origin, nested);
|
|
124
|
-
if (dependencies.size + 1 >
|
|
124
|
+
if (dependencies.size + 1 > limits.dependency.closure) {
|
|
125
125
|
if (!closureLimitReported) {
|
|
126
|
-
diagnostics.push(diagnostic('DV_DEPENDENCY_LIMITS', '/dependencies', `A dependency closure may contain at most ${
|
|
126
|
+
diagnostics.push(diagnostic('DV_DEPENDENCY_LIMITS', '/dependencies', `A dependency closure may contain at most ${limits.dependency.closure} Domains.`));
|
|
127
127
|
closureLimitReported = true;
|
|
128
128
|
}
|
|
129
129
|
continue;
|
|
130
130
|
}
|
|
131
131
|
const depth = frame.depth + 1;
|
|
132
|
-
if (depth >
|
|
133
|
-
diagnostics.push(diagnostic('DV_DEPENDENCY_LIMITS', pointer, `Dependency depth ${depth} exceeds the maximum ${
|
|
132
|
+
if (depth > limits.dependency.depth) {
|
|
133
|
+
diagnostics.push(diagnostic('DV_DEPENDENCY_LIMITS', pointer, `Dependency depth ${depth} exceeds the maximum ${limits.dependency.depth}.`));
|
|
134
134
|
continue;
|
|
135
135
|
}
|
|
136
136
|
const key = `${dependency.origin}\u0000${dependency.revision}`;
|
|
@@ -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
|
}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { SourceDomain } from '../../domain/model/domain.js';
|
|
2
|
+
import type { CallableValidation } from '../../domain/validation/create.js';
|
|
3
|
+
import type { JsonSchema } from '../../language/value/model/schema.js';
|
|
4
|
+
import type { ValueSchemaRegistry } from '../../language/value/reference/registry.js';
|
|
2
5
|
import type { DomainSchema } from '../model/schema.js';
|
|
6
|
+
import { type PatternPool } from '../../language/value/evaluate/preparation.js';
|
|
3
7
|
/**
|
|
4
8
|
* Resolve one accepted Schema through its exact retained source closure. Acceptance validated it
|
|
5
9
|
* against that closure, which is the only way a Schema retains one, so it is not validated again.
|
|
6
10
|
*/
|
|
7
11
|
export declare function resolve<const S extends DomainSchema>(schema: S): SourceDomain<S>;
|
|
12
|
+
export declare function callableValidation(input: JsonSchema, output: JsonSchema | undefined, registry: ValueSchemaRegistry, patterns: PatternPool): CallableValidation;
|
|
@@ -88,7 +88,7 @@ function sourceValidation(closure, registries) {
|
|
|
88
88
|
}
|
|
89
89
|
return createDomainValidation(properties, callables);
|
|
90
90
|
}
|
|
91
|
-
function callableValidation(input, output, registry, patterns) {
|
|
91
|
+
export function callableValidation(input, output, registry, patterns) {
|
|
92
92
|
const prepared = prepareValueSchema(input, registry, '', patterns);
|
|
93
93
|
if (!prepared.compiled) {
|
|
94
94
|
throw new TypeError(`Accepted callable input cannot be prepared: ${prepared.message}`);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { SchemaDiagnosticCode } from './diagnostic.js';
|
|
2
|
+
import { type LimitKey } from '../language/limits.js';
|
|
3
|
+
/**
|
|
4
|
+
* What a rule reads to decide. `structure`: the shape of the document alone. `rule`: the whole
|
|
5
|
+
* document. `context`: the document and its environment, so one document can be accepted in one
|
|
6
|
+
* environment and refused in another. The environment is what the lookup serves for the pinned
|
|
7
|
+
* dependencies, their accepted Schemas or their absence, and, for a Schema already accepted, the
|
|
8
|
+
* closure its acceptance retained.
|
|
9
|
+
*/
|
|
10
|
+
export type SchemaRuleStage = 'structure' | 'rule' | 'context';
|
|
11
|
+
/** The rule one Schema diagnostic code reports. */
|
|
12
|
+
export interface SchemaRule {
|
|
13
|
+
readonly stage: SchemaRuleStage;
|
|
14
|
+
/**
|
|
15
|
+
* The positions the rule constrains, which its diagnostics point at: JSON Pointer templates in
|
|
16
|
+
* which a `{name}` token stands for one token of the kind it names and a final `{/path*}` for any
|
|
17
|
+
* further tokens. `{endpoint}` is `source`, `target`, `0` or `1`; `{count}` is `outgoing`,
|
|
18
|
+
* `incoming` or `incident`; `{operation}` is `read` or `traverse`; `{key}` is a Property key.
|
|
19
|
+
*/
|
|
20
|
+
readonly positions: readonly [string, ...string[]];
|
|
21
|
+
/** The rule, in one plain sentence. */
|
|
22
|
+
readonly statement: string;
|
|
23
|
+
/** What the feature the rule guards enforces on data or on calls, where it enforces something. */
|
|
24
|
+
readonly enforces?: string;
|
|
25
|
+
/** The limits of `limits` the rule enforces, by key, where it enforces some. */
|
|
26
|
+
readonly limits?: readonly [LimitKey, ...LimitKey[]];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Every Schema diagnostic code with the rule it reports. A code added to the DSL does not compile
|
|
30
|
+
* until it is described here.
|
|
31
|
+
*/
|
|
32
|
+
export declare const RULES: Readonly<Record<SchemaDiagnosticCode, SchemaRule>>;
|