@astrale-os/kernel-dsl 1.0.0-beta.2 → 1.0.0-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/v1/addressing/class-key.js +3 -3
- package/dist/v1/addressing/definition-ref.js +21 -37
- package/dist/v1/addressing/domain-dependency.d.ts +0 -6
- package/dist/v1/addressing/domain-dependency.js +1 -6
- package/dist/v1/addressing/key.d.ts +4 -1
- package/dist/v1/addressing/key.js +23 -3
- package/dist/v1/addressing/ordering.d.ts +2 -0
- package/dist/v1/addressing/ordering.js +4 -0
- package/dist/v1/addressing/patterns.d.ts +1 -1
- package/dist/v1/addressing/patterns.js +2 -6
- package/dist/v1/builder/callable/authoring.d.ts +11 -5
- package/dist/v1/builder/callable/authoring.js +2 -0
- package/dist/v1/builder/class/authoring.d.ts +94 -224
- package/dist/v1/builder/class/authoring.js +31 -33
- package/dist/v1/builder/class/handle.d.ts +27 -0
- package/dist/v1/builder/class/handle.js +1 -0
- package/dist/v1/builder/class/input.d.ts +159 -0
- package/dist/v1/builder/class/projection.d.ts +129 -0
- package/dist/v1/builder/class/projection.js +1 -0
- package/dist/v1/builder/class/property.d.ts +3 -9
- package/dist/v1/builder/class/property.js +1 -0
- package/dist/v1/builder/core/authoring.d.ts +1 -1
- package/dist/v1/builder/index.d.ts +5 -2
- package/dist/v1/builder/lowering/callable.js +1 -0
- package/dist/v1/builder/lowering/class.d.ts +9 -1
- package/dist/v1/builder/lowering/class.js +62 -17
- package/dist/v1/builder/lowering/policy.js +2 -0
- package/dist/v1/builder/lowering/property-keys.d.ts +27 -0
- package/dist/v1/builder/lowering/property-keys.js +108 -0
- package/dist/v1/builder/lowering/schema/compile.js +11 -6
- package/dist/v1/builder/lowering/schema/context.d.ts +9 -1
- package/dist/v1/builder/lowering/schema/context.js +36 -4
- package/dist/v1/builder/lowering/schema/lifetime.d.ts +11 -0
- package/dist/v1/builder/lowering/schema/lifetime.js +55 -0
- package/dist/v1/builder/lowering/value/path.d.ts +1 -1
- package/dist/v1/builder/lowering/value/path.js +2 -4
- package/dist/v1/builder/lowering/value/zod.js +1 -3
- package/dist/v1/builder/policy/authoring.d.ts +85 -5
- package/dist/v1/builder/policy/authoring.js +107 -68
- package/dist/v1/builder/schema/define.d.ts +0 -1
- package/dist/v1/builder/schema/diagnostic.d.ts +3 -2
- package/dist/v1/builder/schema/diagnostic.js +5 -10
- package/dist/v1/builder/schema/input.d.ts +1 -1
- package/dist/v1/builder/schema/projection/callable.d.ts +7 -5
- package/dist/v1/builder/schema/projection/class.d.ts +118 -15
- package/dist/v1/builder/schema/projection/core-input.d.ts +2 -1
- package/dist/v1/builder/schema/projection/identity.d.ts +2 -1
- package/dist/v1/builder/schema/projection/model.d.ts +4 -2
- package/dist/v1/builder/schema/projection/property.d.ts +1 -1
- package/dist/v1/builder/schema/projection/resolved-class.d.ts +2 -1
- package/dist/v1/builder/schema/projection.d.ts +1 -1
- package/dist/v1/builder/value/full-match.d.ts +0 -1
- package/dist/v1/builder/value/full-match.js +0 -1
- package/dist/v1/builder/value/path-metadata.d.ts +1 -1
- package/dist/v1/builder/value/path.d.ts +1 -1
- package/dist/v1/bundle/codec.js +11 -13
- package/dist/v1/bundle/diagnostic.d.ts +2 -0
- package/dist/v1/bundle/diagnostic.js +9 -7
- package/dist/v1/bundle/model.js +1 -1
- package/dist/v1/bundle/structure.js +4 -6
- package/dist/v1/compiled/admission/accept.js +4 -10
- package/dist/v1/compiled/admission/closure.js +2 -2
- package/dist/v1/compiled/admission/diagnostic.d.ts +1 -1
- package/dist/v1/compiled/admission/diagnostic.js +1 -3
- package/dist/v1/compiled/admission/revision.d.ts +9 -1
- package/dist/v1/compiled/admission/revision.js +6 -3
- package/dist/v1/compiled/admission/semantics/class.d.ts +4 -1
- package/dist/v1/compiled/admission/semantics/class.js +37 -12
- package/dist/v1/compiled/admission/semantics/core.d.ts +1 -24
- package/dist/v1/compiled/admission/semantics/core.js +56 -24
- package/dist/v1/compiled/admission/semantics/edge.d.ts +2 -4
- package/dist/v1/compiled/admission/semantics/edge.js +6 -65
- package/dist/v1/compiled/admission/semantics/policy/callable.js +0 -2
- package/dist/v1/compiled/admission/semantics/policy/contracts.d.ts +5 -20
- package/dist/v1/compiled/admission/semantics/policy/contracts.js +8 -21
- package/dist/v1/compiled/admission/semantics/policy/parity.js +40 -43
- package/dist/v1/compiled/admission/semantics/policy/pattern.d.ts +4 -1
- package/dist/v1/compiled/admission/semantics/policy/pattern.js +4 -16
- package/dist/v1/compiled/admission/semantics/policy/typing.d.ts +2 -24
- package/dist/v1/compiled/admission/semantics/policy/typing.js +19 -201
- package/dist/v1/compiled/admission/wire/callable.js +11 -1
- package/dist/v1/compiled/admission/wire/class.js +73 -21
- package/dist/v1/compiled/admission/wire/policy.d.ts +4 -3
- package/dist/v1/compiled/admission/wire/policy.js +8 -7
- package/dist/v1/compiled/compiler/compile.js +8 -8
- package/dist/v1/compiled/diagnostic.js +2 -3
- package/dist/v1/compiled/loader/load.d.ts +3 -2
- package/dist/v1/compiled/loader/load.js +11 -45
- package/dist/v1/domain/create.js +5 -6
- package/dist/v1/domain/model/domain.d.ts +2 -7
- package/dist/v1/domain/model/input.d.ts +2 -1
- package/dist/v1/domain/namespace/member-collection.js +4 -6
- package/dist/v1/domain/projection/classes.js +4 -1
- package/dist/v1/domain/validation/create.d.ts +6 -3
- package/dist/v1/domain/validation/create.js +21 -69
- package/dist/v1/index.d.ts +2 -1
- package/dist/v1/language/.spec/schemas/draft-2020-12.schema.json +462 -0
- package/dist/v1/language/.spec/schemas/value-schema.schema.json +22 -0
- package/dist/v1/language/callable/admission.d.ts +15 -0
- package/dist/v1/language/callable/admission.js +43 -0
- package/dist/v1/language/callable/model/callable.d.ts +10 -0
- package/dist/v1/language/callable/resolved.d.ts +16 -3
- package/dist/v1/language/class/inheritance.d.ts +36 -5
- package/dist/v1/language/class/inheritance.js +87 -1
- package/dist/v1/language/class/lifetime.d.ts +50 -11
- package/dist/v1/language/class/lifetime.js +89 -20
- package/dist/v1/language/class/model/class.d.ts +45 -9
- package/dist/v1/language/class/model/edge.d.ts +31 -2
- package/dist/v1/language/class/model/property.d.ts +16 -7
- package/dist/v1/language/class/property-values.js +2 -4
- package/dist/v1/language/class/unique.d.ts +143 -0
- package/dist/v1/language/class/unique.js +264 -0
- package/dist/v1/language/core/facts.d.ts +85 -0
- package/dist/v1/language/core/facts.js +116 -0
- package/dist/v1/language/definition/metadata.d.ts +5 -0
- package/dist/v1/language/definition/metadata.js +7 -0
- package/dist/v1/language/freeze.d.ts +5 -0
- package/dist/v1/{schema/canonical → language}/freeze.js +4 -0
- package/dist/v1/language/index.d.ts +7 -2
- package/dist/v1/language/index.js +5 -1
- package/dist/v1/language/limits.d.ts +64 -0
- package/dist/v1/language/limits.js +60 -0
- package/dist/v1/language/policy/analysis/branches.d.ts +8 -0
- package/dist/v1/language/policy/analysis/branches.js +2 -1
- package/dist/v1/language/policy/analysis/budgets.d.ts +45 -12
- package/dist/v1/language/policy/analysis/budgets.js +133 -19
- package/dist/v1/language/policy/analysis/checks.js +3 -2
- package/dist/v1/language/policy/analysis/typing.d.ts +51 -0
- package/dist/v1/language/policy/analysis/typing.js +455 -0
- package/dist/v1/language/policy/model/policy.d.ts +49 -9
- package/dist/v1/language/policy/model/policy.js +14 -0
- package/dist/v1/language/policy/normalization/normalize.d.ts +6 -6
- package/dist/v1/language/policy/normalization/normalize.js +22 -21
- package/dist/v1/language/validation/diagnostic.d.ts +15 -1
- package/dist/v1/language/validation/diagnostic.js +21 -0
- package/dist/v1/language/validation/rule.d.ts +45 -0
- package/dist/v1/language/validation/rule.js +109 -0
- package/dist/v1/language/value/compile/fields.js +4 -8
- package/dist/v1/language/value/evaluate/program.d.ts +2 -1
- package/dist/v1/language/value/evaluate/program.js +2 -2
- package/dist/v1/language/value/evaluate/validate.d.ts +2 -2
- package/dist/v1/language/value/evaluate/validate.js +6 -2
- package/dist/v1/language/value/evaluate/validity.optimization.d.ts +14 -0
- package/dist/v1/language/value/evaluate/validity.optimization.js +342 -0
- package/dist/v1/language/value/inclusion/arrays.d.ts +3 -0
- package/dist/v1/language/value/inclusion/arrays.js +85 -0
- package/dist/v1/language/value/inclusion/assertions.d.ts +18 -0
- package/dist/v1/language/value/inclusion/assertions.js +29 -0
- package/dist/v1/language/value/inclusion/combinators.d.ts +3 -0
- package/dist/v1/language/value/inclusion/combinators.js +67 -0
- package/dist/v1/language/value/inclusion/equivalence.d.ts +4 -0
- package/dist/v1/language/value/inclusion/equivalence.js +74 -0
- package/dist/v1/language/value/inclusion/evidence.d.ts +34 -0
- package/dist/v1/language/value/inclusion/evidence.js +138 -0
- package/dist/v1/language/value/inclusion/includes.d.ts +17 -0
- package/dist/v1/language/value/inclusion/includes.js +25 -719
- package/dist/v1/language/value/inclusion/keywords.d.ts +5 -0
- package/dist/v1/language/value/inclusion/keywords.js +31 -0
- package/dist/v1/language/value/inclusion/kinds.d.ts +17 -0
- package/dist/v1/language/value/inclusion/kinds.js +57 -0
- package/dist/v1/language/value/inclusion/location.d.ts +24 -0
- package/dist/v1/language/value/inclusion/location.js +63 -0
- package/dist/v1/language/value/inclusion/numbers.d.ts +3 -0
- package/dist/v1/language/value/inclusion/numbers.js +41 -0
- package/dist/v1/language/value/inclusion/objects.d.ts +3 -0
- package/dist/v1/language/value/inclusion/objects.js +190 -0
- package/dist/v1/language/value/inclusion/strings.d.ts +3 -0
- package/dist/v1/language/value/inclusion/strings.js +29 -0
- package/dist/v1/language/value/inclusion/types.d.ts +3 -0
- package/dist/v1/language/value/inclusion/types.js +11 -0
- package/dist/v1/language/value/ordering.d.ts +14 -0
- package/dist/v1/language/value/ordering.js +86 -9
- package/dist/v1/language/value/profile/canonicalize.js +6 -5
- package/dist/v1/language/value/profile/json.validate.d.ts +3 -1
- package/dist/v1/language/value/profile/json.validate.js +3 -2
- package/dist/v1/language/value/profile/meta-schema.compiled.js +4 -1
- package/dist/v1/language/value/profile/rules.js +17 -43
- package/dist/v1/language/value/profile/validate.js +1 -10
- 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/closure.js +3 -4
- package/dist/v1/language/value/reference/recursion.js +2 -22
- package/dist/v1/language/value/reference/registry.index.d.ts +2 -0
- package/dist/v1/language/value/reference/registry.index.js +33 -16
- 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/language/value/syntax/pointer.d.ts +2 -0
- package/dist/v1/language/value/syntax/pointer.js +5 -2
- package/dist/v1/language/value/syntax/walk.d.ts +2 -0
- package/dist/v1/language/value/syntax/walk.js +19 -20
- package/dist/v1/schema/.spec/schemas/domain-schema.schema.json +2519 -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/canonical/revision.js +4 -4
- package/dist/v1/schema/compatibility/api.d.ts +2 -1
- package/dist/v1/schema/compatibility/api.js +1 -0
- package/dist/v1/schema/compatibility/comparators/callables.js +1 -1
- package/dist/v1/schema/compatibility/comparators/classes.d.ts +9 -4
- package/dist/v1/schema/compatibility/comparators/classes.js +29 -8
- package/dist/v1/schema/compatibility/comparators/index.d.ts +1 -1
- package/dist/v1/schema/compatibility/comparators/members.js +1 -1
- package/dist/v1/schema/compatibility/comparators/values.js +2 -2
- package/dist/v1/schema/compatibility/coordinate.js +3 -3
- package/dist/v1/schema/compatibility/diff.js +2 -4
- package/dist/v1/schema/compatibility/extension.d.ts +11 -0
- package/dist/v1/schema/compatibility/extension.js +22 -0
- package/dist/v1/schema/compatibility/fields.d.ts +20 -4
- package/dist/v1/schema/compatibility/fields.js +13 -3
- package/dist/v1/schema/compatibility/meaning/footprint.js +16 -50
- package/dist/v1/schema/compatibility/model.d.ts +17 -5
- package/dist/v1/schema/compatibility/report.js +1 -1
- package/dist/v1/schema/compatibility/scope.d.ts +2 -0
- package/dist/v1/schema/compatibility/scope.js +4 -1
- package/dist/v1/schema/compatibility/structure/index.js +6 -4
- package/dist/v1/schema/compatibility/structure/requirements.js +57 -58
- package/dist/v1/schema/compatibility/versioning/index.js +1 -1
- package/dist/v1/schema/compatibility/versioning/surface.d.ts +1 -1
- package/dist/v1/schema/compatibility/versioning/surface.js +30 -2
- package/dist/v1/schema/compatibility/walk.d.ts +17 -0
- package/dist/v1/schema/compatibility/walk.js +41 -0
- package/dist/v1/schema/diagnostic.d.ts +17 -3
- package/dist/v1/schema/diagnostic.js +14 -11
- 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 +20 -1
- package/dist/v1/schema/model/schema.js +1 -1
- package/dist/v1/schema/normalization/domain.d.ts +2 -0
- package/dist/v1/schema/normalization/domain.js +29 -9
- package/dist/v1/schema/resolution/closure.js +2 -1
- package/dist/v1/schema/resolution/context.js +13 -13
- package/dist/v1/schema/resolution/domain.d.ts +5 -0
- package/dist/v1/schema/resolution/domain.js +2 -2
- package/dist/v1/schema/resolution/origins.js +3 -2
- package/dist/v1/schema/rule.d.ts +26 -0
- package/dist/v1/schema/rule.js +440 -0
- package/dist/v1/schema/validation/callable.d.ts +35 -2
- package/dist/v1/schema/validation/callable.js +65 -9
- package/dist/v1/schema/validation/class.d.ts +6 -2
- package/dist/v1/schema/validation/class.js +127 -104
- package/dist/v1/schema/validation/core.js +90 -168
- package/dist/v1/schema/validation/domain.js +4 -13
- package/dist/v1/schema/validation/domain.json-schema.d.ts +15 -0
- package/dist/v1/schema/validation/domain.json-schema.js +197 -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 +7780 -0
- package/dist/v1/schema/validation/domain.structure.js +398 -147
- package/dist/v1/schema/validation/json.json-schema.d.ts +40 -0
- package/dist/v1/schema/validation/json.json-schema.js +46 -0
- package/dist/v1/schema/validation/policy/budgets.d.ts +33 -2
- package/dist/v1/schema/validation/policy/budgets.js +87 -121
- package/dist/v1/schema/validation/policy/context.d.ts +6 -5
- package/dist/v1/schema/validation/policy/context.js +7 -10
- package/dist/v1/schema/validation/policy/objects.d.ts +1 -1
- package/dist/v1/schema/validation/policy/objects.js +6 -14
- package/dist/v1/schema/validation/policy/references.js +11 -27
- package/dist/v1/schema/validation/policy/typing.d.ts +3 -18
- package/dist/v1/schema/validation/policy/typing.js +22 -356
- package/dist/v1/schema/validation/policy/uses.d.ts +40 -3
- package/dist/v1/schema/validation/policy/uses.js +66 -89
- package/dist/v1/schema/validation/policy/validate.js +5 -5
- package/dist/v1/schema/validation/value-api.d.ts +22 -0
- package/dist/v1/schema/validation/value-api.js +34 -1
- package/dist/v1/schema/validation/value.d.ts +3 -0
- package/dist/v1/schema/validation/value.js +9 -17
- package/dist/v1/schema/validation/value.json-schema.d.ts +49 -0
- package/dist/v1/schema/validation/value.json-schema.js +137 -0
- package/dist/v1/schema/validation/view.js +4 -8
- package/dist/value/canonical.d.ts +6 -0
- package/dist/value/canonical.js +36 -0
- package/dist/value/decode.d.ts +7 -0
- package/dist/value/decode.js +159 -9
- package/dist/value/index.d.ts +1 -1
- package/dist/value/json.d.ts +2 -2
- package/dist/value/json.js +2 -2
- package/dist/value/types.d.ts +6 -0
- package/dist/value/unicode.d.ts +2 -1
- package/dist/value/unicode.js +2 -0
- package/package.json +8 -1
- package/dist/v1/builder/lowering/core-properties.d.ts +0 -10
- package/dist/v1/builder/lowering/core-properties.js +0 -76
- package/dist/v1/compiled/admission/semantics/cardinality.d.ts +0 -5
- package/dist/v1/compiled/admission/semantics/cardinality.js +0 -113
- package/dist/v1/compiled/admission/semantics/policy/equality.d.ts +0 -8
- package/dist/v1/compiled/admission/semantics/policy/equality.js +0 -27
- package/dist/v1/compiled/admission/semantics/policy/measure.d.ts +0 -9
- package/dist/v1/compiled/admission/semantics/policy/measure.js +0 -81
- package/dist/v1/compiled/admission/semantics/policy/variants.d.ts +0 -10
- package/dist/v1/compiled/admission/semantics/policy/variants.js +0 -65
- package/dist/v1/language/class/index.d.ts +0 -8
- package/dist/v1/language/class/index.js +0 -1
- package/dist/v1/language/core/index.d.ts +0 -2
- package/dist/v1/language/value/index.d.ts +0 -11
- package/dist/v1/language/value/index.js +0 -8
- package/dist/v1/schema/canonical/domain.d.ts +0 -3
- package/dist/v1/schema/canonical/domain.digest.d.ts +0 -3
- package/dist/v1/schema/canonical/domain.digest.js +0 -5
- package/dist/v1/schema/canonical/domain.js +0 -5
- package/dist/v1/schema/canonical/freeze.d.ts +0 -1
- /package/dist/v1/{language/core/index.js → builder/class/input.js} +0 -0
|
@@ -7,10 +7,11 @@ const TYPE_RANK = new Map(TYPE_ORDER.map((name, index) => [name, index]));
|
|
|
7
7
|
const encoder = new TextEncoder();
|
|
8
8
|
/** Canonicalizes syntax without rewriting the schema's algebra. Validate first. */
|
|
9
9
|
export function canonicalizeValueSchema(schema, context, registry) {
|
|
10
|
+
void context;
|
|
10
11
|
void registry;
|
|
11
|
-
return canonicalizeSchema(schema, true
|
|
12
|
+
return canonicalizeSchema(schema, true);
|
|
12
13
|
}
|
|
13
|
-
function canonicalizeSchema(schema, root
|
|
14
|
+
function canonicalizeSchema(schema, root) {
|
|
14
15
|
if (typeof schema === 'boolean')
|
|
15
16
|
return schema;
|
|
16
17
|
const result = {};
|
|
@@ -39,17 +40,17 @@ function canonicalizeSchema(schema, root, context) {
|
|
|
39
40
|
result[keyword] = canonicalizePathAnnotation(value);
|
|
40
41
|
}
|
|
41
42
|
else if (SCHEMA_SINGLE_KEYWORDS.has(keyword) && isJsonSchema(value)) {
|
|
42
|
-
result[keyword] = canonicalizeSchema(value, false
|
|
43
|
+
result[keyword] = canonicalizeSchema(value, false);
|
|
43
44
|
}
|
|
44
45
|
else if (SCHEMA_ARRAY_KEYWORDS.has(keyword) && Array.isArray(value)) {
|
|
45
|
-
result[keyword] = value.map((entry) => isJsonSchema(entry) ? canonicalizeSchema(entry, false
|
|
46
|
+
result[keyword] = value.map((entry) => isJsonSchema(entry) ? canonicalizeSchema(entry, false) : canonicalizeJson(entry));
|
|
46
47
|
}
|
|
47
48
|
else if (SCHEMA_MAP_KEYWORDS.has(keyword) && isJsonObject(value)) {
|
|
48
49
|
const schemas = {};
|
|
49
50
|
for (const name of Object.keys(value).sort()) {
|
|
50
51
|
const entry = value[name];
|
|
51
52
|
schemas[name] = isJsonSchema(entry)
|
|
52
|
-
? canonicalizeSchema(entry, false
|
|
53
|
+
? canonicalizeSchema(entry, false)
|
|
53
54
|
: canonicalizeJson(entry);
|
|
54
55
|
}
|
|
55
56
|
result[keyword] = schemas;
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
import { type Options } from '@astrale-os/kernel-dsl/value';
|
|
1
2
|
import type { Diagnostic } from '../../validation/diagnostic.js';
|
|
2
|
-
|
|
3
|
+
/** Whether `value` is a portable JSON Value, within the portable limits `options` overrides. */
|
|
4
|
+
export declare function validateCanonicalJsonDomain(value: unknown, pointer: string, options?: Options): readonly Diagnostic[];
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { acceptForRead as acceptJsonValue, BoundaryError as JsonBoundaryError, } from '@astrale-os/kernel-dsl/value';
|
|
2
2
|
import { diagnostic } from '../../validation/diagnostic.js';
|
|
3
|
-
|
|
3
|
+
/** Whether `value` is a portable JSON Value, within the portable limits `options` overrides. */
|
|
4
|
+
export function validateCanonicalJsonDomain(value, pointer, options) {
|
|
4
5
|
try {
|
|
5
|
-
acceptJsonValue(value);
|
|
6
|
+
acceptJsonValue(value, options);
|
|
6
7
|
return [];
|
|
7
8
|
}
|
|
8
9
|
catch (error) {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"use strict";
|
|
5
5
|
export const validate = validate20;
|
|
6
6
|
export default validate20;
|
|
7
|
-
const schema31 = { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://schemas.astrale.ai/dsl/v1/value-schema", "$vocabulary": {}, "allOf": [{ "$ref": "https://json-schema.org/draft/2020-12/schema" }], "properties": { "fullMatch": { "type": "string" }, "x-astrale-path": { "type": "object" } } };
|
|
7
|
+
const schema31 = { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://schemas.astrale.ai/dsl/v1/value-schema", "$dynamicAnchor": "meta", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true, "https://json-schema.org/draft/2020-12/vocab/applicator": true, "https://json-schema.org/draft/2020-12/vocab/unevaluated": true, "https://json-schema.org/draft/2020-12/vocab/validation": true, "https://json-schema.org/draft/2020-12/vocab/meta-data": true, "https://json-schema.org/draft/2020-12/vocab/format-annotation": true, "https://json-schema.org/draft/2020-12/vocab/content": true, "https://schemas.astrale.ai/dsl/v1/value-schema/vocabulary": true }, "title": "Astrale V1 value schema", "$comment": "The meta-schema of the V1 value-schema dialect: Draft 2020-12 and the required Astrale vocabulary (fullMatch, x-astrale-path, x-astrale-value-kind). Its $dynamicAnchor extends Draft 2020-12 at every subschema, not only the root. The rules of the profile beyond it are published as schema.values.RULES.", "allOf": [{ "$ref": "https://json-schema.org/draft/2020-12/schema" }], "properties": { "fullMatch": { "type": "string" }, "x-astrale-path": { "type": "object" } } };
|
|
8
8
|
const schema0 = { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://json-schema.org/draft/2020-12/schema", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true, "https://json-schema.org/draft/2020-12/vocab/applicator": true, "https://json-schema.org/draft/2020-12/vocab/unevaluated": true, "https://json-schema.org/draft/2020-12/vocab/validation": true, "https://json-schema.org/draft/2020-12/vocab/meta-data": true, "https://json-schema.org/draft/2020-12/vocab/format-annotation": true, "https://json-schema.org/draft/2020-12/vocab/content": true }, "$dynamicAnchor": "meta", "title": "Core and Validation specifications meta-schema", "allOf": [{ "$ref": "meta/core" }, { "$ref": "meta/applicator" }, { "$ref": "meta/unevaluated" }, { "$ref": "meta/validation" }, { "$ref": "meta/meta-data" }, { "$ref": "meta/format-annotation" }, { "$ref": "meta/content" }], "type": ["object", "boolean"], "$comment": "This meta-schema also defines keywords that have appeared in previous drafts in order to prevent incompatible extensions as they remain in common use.", "properties": { "definitions": { "$comment": "\"definitions\" has been replaced by \"$defs\".", "type": "object", "additionalProperties": { "$dynamicRef": "#meta" }, "deprecated": true, "default": {} }, "dependencies": { "$comment": "\"dependencies\" has been split and replaced by \"dependentSchemas\" and \"dependentRequired\" in order to serve their differing semantics.", "type": "object", "additionalProperties": { "anyOf": [{ "$dynamicRef": "#meta" }, { "$ref": "meta/validation#/$defs/stringArray" }] }, "deprecated": true, "default": {} }, "$recursiveAnchor": { "$comment": "\"$recursiveAnchor\" has been replaced by \"$dynamicAnchor\".", "$ref": "meta/core#/$defs/anchorString", "deprecated": true }, "$recursiveRef": { "$comment": "\"$recursiveRef\" has been replaced by \"$dynamicRef\".", "$ref": "meta/core#/$defs/uriReferenceString", "deprecated": true } } };
|
|
9
9
|
const schema23 = { "type": "array", "items": { "type": "string" }, "uniqueItems": true, "default": [] };
|
|
10
10
|
const schema5 = { "type": "string", "pattern": "^[A-Za-z_][-A-Za-z0-9._]*$" };
|
|
@@ -2042,6 +2042,9 @@ function validate20(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
2042
2042
|
if (evaluated0.dynamicItems) {
|
|
2043
2043
|
evaluated0.items = undefined;
|
|
2044
2044
|
}
|
|
2045
|
+
if (!dynamicAnchors.meta) {
|
|
2046
|
+
dynamicAnchors.meta = validate20;
|
|
2047
|
+
}
|
|
2045
2048
|
if (!(validate0(data, { instancePath, parentData, parentDataProperty, rootData, dynamicAnchors }))) {
|
|
2046
2049
|
vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);
|
|
2047
2050
|
errors = vErrors.length;
|
|
@@ -4,8 +4,11 @@ import { blob, BLOB_VALUE_KIND } from '../model/blob.js';
|
|
|
4
4
|
import { isValueObject as isJsonObject } from '../model/object.js';
|
|
5
5
|
import { VALUE_SCHEMA_DIALECT } from '../model/schema.js';
|
|
6
6
|
import { refuseIRegexp, stateBudgetMessage } from '../regexp/syntax.js';
|
|
7
|
+
import { escapePointerToken } from '../syntax/pointer.js';
|
|
7
8
|
import { walkSchema } from '../syntax/walk.js';
|
|
8
|
-
import {
|
|
9
|
+
import { FORBIDDEN_KEYWORDS, VALUE_KEYWORDS } from './vocabulary.js';
|
|
10
|
+
const KEYWORDS = new Set(VALUE_KEYWORDS);
|
|
11
|
+
const FORBIDDEN = new Set(FORBIDDEN_KEYWORDS);
|
|
9
12
|
export function validateSchemaProfile(schema, context, pointer) {
|
|
10
13
|
const diagnostics = [];
|
|
11
14
|
walkSchema(schema, (location) => {
|
|
@@ -13,11 +16,11 @@ export function validateSchemaProfile(schema, context, pointer) {
|
|
|
13
16
|
return;
|
|
14
17
|
const currentPointer = `${pointer}${location.pointer}`;
|
|
15
18
|
for (const keyword of Object.keys(location.schema)) {
|
|
16
|
-
if (!
|
|
17
|
-
diagnostics.push(diagnostic('VS_KEYWORD_CLOSED', `${currentPointer}/${
|
|
19
|
+
if (!KEYWORDS.has(keyword)) {
|
|
20
|
+
diagnostics.push(diagnostic('VS_KEYWORD_CLOSED', `${currentPointer}/${escapePointerToken(keyword)}`, `Keyword ${keyword} is outside the closed V1 Draft 2020-12 vocabulary.`));
|
|
18
21
|
}
|
|
19
|
-
if (
|
|
20
|
-
diagnostics.push(diagnostic('VS_DYNAMIC_FORBIDDEN', `${currentPointer}/${
|
|
22
|
+
if (FORBIDDEN.has(keyword)) {
|
|
23
|
+
diagnostics.push(diagnostic('VS_DYNAMIC_FORBIDDEN', `${currentPointer}/${escapePointerToken(keyword)}`, `Keyword ${keyword} is forbidden by V1.`));
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
if (Object.hasOwn(location.schema, '$schema')) {
|
|
@@ -28,7 +31,11 @@ export function validateSchemaProfile(schema, context, pointer) {
|
|
|
28
31
|
if (Object.hasOwn(location.schema, '$id')) {
|
|
29
32
|
diagnostics.push(diagnostic('VS_RESOURCE_ID', `${currentPointer}/$id`, '$id is forbidden in an embedded V1 value schema.'));
|
|
30
33
|
}
|
|
31
|
-
|
|
34
|
+
// The dialect refuses a repeated type, required or dependentRequired entry; it lets an enum
|
|
35
|
+
// repeat a value.
|
|
36
|
+
if (Array.isArray(location.schema.enum)) {
|
|
37
|
+
rejectCanonicalDuplicates(location.schema.enum, `${currentPointer}/enum`, diagnostics);
|
|
38
|
+
}
|
|
32
39
|
validateValueKind(location.schema, context, location.depth, currentPointer, diagnostics);
|
|
33
40
|
validateRegexes(location.schema, currentPointer, diagnostics);
|
|
34
41
|
});
|
|
@@ -73,28 +80,8 @@ function isCanonicalBlobSchema(input) {
|
|
|
73
80
|
function isString(input) {
|
|
74
81
|
return typeof input === 'string';
|
|
75
82
|
}
|
|
76
|
-
|
|
77
|
-
if (Array.isArray(schema.type)) {
|
|
78
|
-
rejectPrimitiveDuplicates(schema.type, `${pointer}/type`, 'type', diagnostics);
|
|
79
|
-
}
|
|
80
|
-
if (Array.isArray(schema.required)) {
|
|
81
|
-
rejectPrimitiveDuplicates(schema.required, `${pointer}/required`, 'required', diagnostics);
|
|
82
|
-
}
|
|
83
|
-
if (Array.isArray(schema.enum)) {
|
|
84
|
-
rejectCanonicalDuplicates(schema.enum, `${pointer}/enum`, 'enum', diagnostics);
|
|
85
|
-
}
|
|
86
|
-
if (isJsonObject(schema.dependentRequired)) {
|
|
87
|
-
for (const [name, dependencies] of Object.entries(schema.dependentRequired)) {
|
|
88
|
-
if (Array.isArray(dependencies)) {
|
|
89
|
-
rejectPrimitiveDuplicates(dependencies, `${pointer}/dependentRequired/${escapeToken(name)}`, 'dependentRequired', diagnostics);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
83
|
+
/** The dialect refuses a fullMatch that is not a string, at every location. */
|
|
94
84
|
function validateRegexes(schema, pointer, diagnostics) {
|
|
95
|
-
if (Object.hasOwn(schema, 'fullMatch') && typeof schema.fullMatch !== 'string') {
|
|
96
|
-
diagnostics.push(diagnostic('VS_META_SCHEMA', `${pointer}/fullMatch`, 'fullMatch must be an I-Regexp source string.'));
|
|
97
|
-
}
|
|
98
85
|
if (typeof schema.fullMatch === 'string') {
|
|
99
86
|
portableRegex(schema.fullMatch, `${pointer}/fullMatch`, 'fullMatch', 'fullMatch must satisfy the complete RFC 9485 I-Regexp syntax.', diagnostics);
|
|
100
87
|
}
|
|
@@ -103,7 +90,7 @@ function validateRegexes(schema, pointer, diagnostics) {
|
|
|
103
90
|
}
|
|
104
91
|
if (isJsonObject(schema.patternProperties)) {
|
|
105
92
|
for (const pattern of Object.keys(schema.patternProperties)) {
|
|
106
|
-
portableRegex(pattern, `${pointer}/patternProperties/${
|
|
93
|
+
portableRegex(pattern, `${pointer}/patternProperties/${escapePointerToken(pattern)}`, 'A patternProperties key', 'patternProperties keys must satisfy RFC 9485 I-Regexp syntax.', diagnostics);
|
|
107
94
|
}
|
|
108
95
|
}
|
|
109
96
|
}
|
|
@@ -113,17 +100,7 @@ function portableRegex(source, pointer, subject, syntax, diagnostics) {
|
|
|
113
100
|
return;
|
|
114
101
|
diagnostics.push(diagnostic('VS_REGEX_PORTABLE', pointer, refusal === 'syntax' ? syntax : stateBudgetMessage(subject)));
|
|
115
102
|
}
|
|
116
|
-
function
|
|
117
|
-
const seen = new Set();
|
|
118
|
-
for (const value of values) {
|
|
119
|
-
if (seen.has(value)) {
|
|
120
|
-
diagnostics.push(diagnostic('VS_META_SCHEMA', pointer, `${name} is a duplicate-free semantic set.`));
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
seen.add(value);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
function rejectCanonicalDuplicates(values, pointer, name, diagnostics) {
|
|
103
|
+
function rejectCanonicalDuplicates(values, pointer, diagnostics) {
|
|
127
104
|
const seen = new Set();
|
|
128
105
|
for (const value of values) {
|
|
129
106
|
let key;
|
|
@@ -134,12 +111,9 @@ function rejectCanonicalDuplicates(values, pointer, name, diagnostics) {
|
|
|
134
111
|
continue;
|
|
135
112
|
}
|
|
136
113
|
if (seen.has(key)) {
|
|
137
|
-
diagnostics.push(diagnostic('VS_META_SCHEMA', pointer,
|
|
114
|
+
diagnostics.push(diagnostic('VS_META_SCHEMA', pointer, 'enum rejects canonically equal duplicates.'));
|
|
138
115
|
return;
|
|
139
116
|
}
|
|
140
117
|
seen.add(key);
|
|
141
118
|
}
|
|
142
119
|
}
|
|
143
|
-
function escapeToken(value) {
|
|
144
|
-
return value.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
145
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { orderAndDeduplicate } from '../../validation/diagnostic.js';
|
|
2
2
|
import { collectResourceClosure } from '../reference/closure.js';
|
|
3
3
|
import { validateProductiveRecursion } from '../reference/recursion.js';
|
|
4
4
|
import { hasNodeDefinition, indexRegistry } from '../reference/registry.index.js';
|
|
@@ -28,12 +28,3 @@ export function validateValueSchema(schema, context, registry, pointer = '') {
|
|
|
28
28
|
diagnostics.push(...validateProductiveRecursion(closure.resources, closure.resolutions));
|
|
29
29
|
return orderAndDeduplicate(diagnostics);
|
|
30
30
|
}
|
|
31
|
-
function orderAndDeduplicate(diagnostics) {
|
|
32
|
-
const unique = new Map();
|
|
33
|
-
for (const value of diagnostics) {
|
|
34
|
-
unique.set(`${value.pointer}\u0000${value.code}\u0000${value.ref ?? ''}\u0000${value.message}`, value);
|
|
35
|
-
}
|
|
36
|
-
return [...unique.values()].sort((left, right) => compareUnicode(left.pointer, right.pointer) ||
|
|
37
|
-
compareUnicode(left.code, right.code) ||
|
|
38
|
-
compareUnicode(left.message, right.message));
|
|
39
|
-
}
|
|
@@ -1,2 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
declare const keywords: readonly ['$anchor', '$comment', '$defs', '$dynamicAnchor', '$dynamicRef', '$id', '$ref', '$schema', '$vocabulary', 'additionalProperties', 'allOf', 'anyOf', 'const', 'contains', 'contentEncoding', 'contentMediaType', 'contentSchema', 'default', 'dependentRequired', 'dependentSchemas', 'deprecated', 'description', 'else', 'enum', 'examples', 'exclusiveMaximum', 'exclusiveMinimum', 'format', 'fullMatch', 'if', 'items', 'maxContains', 'maxItems', 'maxLength', 'maxProperties', 'maximum', 'minContains', 'minItems', 'minLength', 'minProperties', 'minimum', 'multipleOf', 'not', 'oneOf', 'pattern', 'patternProperties', 'prefixItems', 'properties', 'propertyNames', 'readOnly', 'required', 'then', 'title', 'type', 'unevaluatedItems', 'unevaluatedProperties', 'uniqueItems', 'writeOnly', 'x-astrale-path', 'x-astrale-value-kind'];
|
|
2
|
+
export type ValueKeyword = (typeof keywords)[number];
|
|
3
|
+
/**
|
|
4
|
+
* The closed V1 vocabulary: every keyword a value schema may name, the Astrale profile's included
|
|
5
|
+
* (`fullMatch`, `x-astrale-path`, `x-astrale-value-kind`). Any other keyword is refused
|
|
6
|
+
* (`VS_KEYWORD_CLOSED`). Other rules restrict some of these: the forbidden keywords never appear,
|
|
7
|
+
* `$id` never, `$schema` only at the root. Frozen and Unicode-ordered.
|
|
8
|
+
*/
|
|
9
|
+
export declare const VALUE_KEYWORDS: readonly ValueKeyword[];
|
|
10
|
+
/** The keywords of the vocabulary refused wherever they appear (`VS_DYNAMIC_FORBIDDEN`). */
|
|
11
|
+
export declare const FORBIDDEN_KEYWORDS: readonly ValueKeyword[];
|
|
12
|
+
/**
|
|
13
|
+
* The keywords whose value holds subschemas, by its shape: one schema, an array of schemas, or an
|
|
14
|
+
* object of named schemas. A value schema's locations are its root and the subschemas these hold.
|
|
15
|
+
*/
|
|
16
|
+
export declare const SUBSCHEMA_KEYWORDS: {
|
|
17
|
+
readonly single: readonly ValueKeyword[];
|
|
18
|
+
readonly array: readonly ValueKeyword[];
|
|
19
|
+
readonly map: readonly ValueKeyword[];
|
|
20
|
+
};
|
|
21
|
+
/** A value kind a schema declares with `x-astrale-value-kind`, because no JSON type gives it. */
|
|
22
|
+
export interface DeclaredValueKind {
|
|
23
|
+
/** The JSON type of its values, which the schema states beside the declaration. */
|
|
24
|
+
readonly type: 'string' | 'object';
|
|
25
|
+
/**
|
|
26
|
+
* Where a schema may declare it: at any location of any value schema, or only as the whole
|
|
27
|
+
* schema of a Node Property that is neither automatic nor a State Property.
|
|
28
|
+
*/
|
|
29
|
+
readonly placement: 'any' | 'node-property';
|
|
30
|
+
/** The kind, in one plain sentence. */
|
|
31
|
+
readonly statement: string;
|
|
32
|
+
}
|
|
33
|
+
/** The value kinds `x-astrale-value-kind` declares; it admits no other value. */
|
|
34
|
+
export declare const DECLARED_VALUE_KINDS: Readonly<Record<'instant' | 'blob', DeclaredValueKind>>;
|
|
35
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
const keywords = [
|
|
2
2
|
'$anchor',
|
|
3
3
|
'$comment',
|
|
4
4
|
'$defs',
|
|
@@ -31,15 +31,15 @@ export const STANDARD_SCHEMA_KEYWORDS = new Set([
|
|
|
31
31
|
'if',
|
|
32
32
|
'items',
|
|
33
33
|
'maxContains',
|
|
34
|
-
'maximum',
|
|
35
34
|
'maxItems',
|
|
36
35
|
'maxLength',
|
|
37
36
|
'maxProperties',
|
|
37
|
+
'maximum',
|
|
38
38
|
'minContains',
|
|
39
|
-
'minimum',
|
|
40
39
|
'minItems',
|
|
41
40
|
'minLength',
|
|
42
41
|
'minProperties',
|
|
42
|
+
'minimum',
|
|
43
43
|
'multipleOf',
|
|
44
44
|
'not',
|
|
45
45
|
'oneOf',
|
|
@@ -59,10 +59,57 @@ export const STANDARD_SCHEMA_KEYWORDS = new Set([
|
|
|
59
59
|
'writeOnly',
|
|
60
60
|
'x-astrale-path',
|
|
61
61
|
'x-astrale-value-kind',
|
|
62
|
-
]
|
|
63
|
-
|
|
62
|
+
];
|
|
63
|
+
/**
|
|
64
|
+
* The closed V1 vocabulary: every keyword a value schema may name, the Astrale profile's included
|
|
65
|
+
* (`fullMatch`, `x-astrale-path`, `x-astrale-value-kind`). Any other keyword is refused
|
|
66
|
+
* (`VS_KEYWORD_CLOSED`). Other rules restrict some of these: the forbidden keywords never appear,
|
|
67
|
+
* `$id` never, `$schema` only at the root. Frozen and Unicode-ordered.
|
|
68
|
+
*/
|
|
69
|
+
export const VALUE_KEYWORDS = Object.freeze(keywords);
|
|
70
|
+
/** The keywords of the vocabulary refused wherever they appear (`VS_DYNAMIC_FORBIDDEN`). */
|
|
71
|
+
export const FORBIDDEN_KEYWORDS = Object.freeze([
|
|
64
72
|
'$anchor',
|
|
65
73
|
'$dynamicAnchor',
|
|
66
74
|
'$dynamicRef',
|
|
67
75
|
'$vocabulary',
|
|
68
76
|
]);
|
|
77
|
+
/**
|
|
78
|
+
* The keywords whose value holds subschemas, by its shape: one schema, an array of schemas, or an
|
|
79
|
+
* object of named schemas. A value schema's locations are its root and the subschemas these hold.
|
|
80
|
+
*/
|
|
81
|
+
export const SUBSCHEMA_KEYWORDS = Object.freeze({
|
|
82
|
+
single: Object.freeze([
|
|
83
|
+
'additionalProperties',
|
|
84
|
+
'contains',
|
|
85
|
+
'contentSchema',
|
|
86
|
+
'else',
|
|
87
|
+
'if',
|
|
88
|
+
'items',
|
|
89
|
+
'not',
|
|
90
|
+
'propertyNames',
|
|
91
|
+
'then',
|
|
92
|
+
'unevaluatedItems',
|
|
93
|
+
'unevaluatedProperties',
|
|
94
|
+
]),
|
|
95
|
+
array: Object.freeze(['allOf', 'anyOf', 'oneOf', 'prefixItems']),
|
|
96
|
+
map: Object.freeze([
|
|
97
|
+
'$defs',
|
|
98
|
+
'dependentSchemas',
|
|
99
|
+
'patternProperties',
|
|
100
|
+
'properties',
|
|
101
|
+
]),
|
|
102
|
+
});
|
|
103
|
+
/** The value kinds `x-astrale-value-kind` declares; it admits no other value. */
|
|
104
|
+
export const DECLARED_VALUE_KINDS = Object.freeze({
|
|
105
|
+
instant: Object.freeze({
|
|
106
|
+
type: 'string',
|
|
107
|
+
placement: 'any',
|
|
108
|
+
statement: 'A UTC instant written YYYY-MM-DDTHH:mm:ss.sssZ, in the years 0000 to 9999, whose text order is its chronological order.',
|
|
109
|
+
}),
|
|
110
|
+
blob: Object.freeze({
|
|
111
|
+
type: 'object',
|
|
112
|
+
placement: 'node-property',
|
|
113
|
+
statement: 'The Ref of stored contents, its digest, media type and size: the schema is exactly a values.blob output, and the Property is written with an upload receipt.',
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
@@ -36,10 +36,9 @@ export function collectResourceClosure(schema, context, index, pointer) {
|
|
|
36
36
|
const target = result.resolved.resource;
|
|
37
37
|
if (resources.has(target.key))
|
|
38
38
|
return;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
};
|
|
39
|
+
// The graph NodePath resource is no part of the schema: what it holds is reported at the
|
|
40
|
+
// $ref that names it.
|
|
41
|
+
const registered = { ...target, diagnosticPointer: refPointer };
|
|
43
42
|
resources.set(target.key, registered);
|
|
44
43
|
queue.push(registered);
|
|
45
44
|
});
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { diagnostic } from '../../validation/diagnostic.js';
|
|
2
2
|
import { isValueObject as isJsonObject } from '../model/object.js';
|
|
3
|
-
import { SCHEMA_ARRAY_KEYWORDS, SCHEMA_MAP_KEYWORDS, SCHEMA_SINGLE_KEYWORDS, } from '../syntax/keywords.js';
|
|
4
3
|
import { appendPointer } from '../syntax/pointer.js';
|
|
5
|
-
import {
|
|
4
|
+
import { forEachSubschema, walkSchema } from '../syntax/walk.js';
|
|
6
5
|
import { locationKey } from './closure.js';
|
|
7
6
|
export const CONSUMING_SCHEMA_KEYWORDS = new Set([
|
|
8
7
|
'additionalProperties',
|
|
@@ -43,26 +42,7 @@ export function validateProductiveRecursion(resources, resolutions) {
|
|
|
43
42
|
for (const [keyword, value] of Object.entries(location.schema)) {
|
|
44
43
|
if (!NON_CONSUMING_SCHEMA_KEYWORDS.has(keyword))
|
|
45
44
|
continue;
|
|
46
|
-
|
|
47
|
-
if (SCHEMA_SINGLE_KEYWORDS.has(keyword) && isJsonSchema(value)) {
|
|
48
|
-
outgoing.add(locationKey(resource.key, keywordPointer));
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
if (SCHEMA_ARRAY_KEYWORDS.has(keyword) && Array.isArray(value)) {
|
|
52
|
-
value.forEach((entry, index) => {
|
|
53
|
-
if (isJsonSchema(entry)) {
|
|
54
|
-
outgoing.add(locationKey(resource.key, appendPointer(keywordPointer, index)));
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
if (SCHEMA_MAP_KEYWORDS.has(keyword) && isJsonObject(value)) {
|
|
60
|
-
for (const [name, entry] of Object.entries(value)) {
|
|
61
|
-
if (isJsonSchema(entry)) {
|
|
62
|
-
outgoing.add(locationKey(resource.key, appendPointer(keywordPointer, name)));
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
45
|
+
forEachSubschema(keyword, value, appendPointer(location.pointer, keyword), (_, at) => outgoing.add(locationKey(resource.key, at)));
|
|
66
46
|
}
|
|
67
47
|
});
|
|
68
48
|
}
|
|
@@ -5,6 +5,8 @@ export interface RegistryIndex {
|
|
|
5
5
|
readonly registry: ValueSchemaRegistry;
|
|
6
6
|
readonly domains: ReadonlyMap<string, ValueSchemaDomainRegistry>;
|
|
7
7
|
readonly dependenciesByOwner: ReadonlyMap<string, ReadonlyMap<string, string>>;
|
|
8
|
+
/** The `definitionRefIndex` of each Node Definition its own Domain lists. */
|
|
9
|
+
readonly nodeDefinitions: ReadonlySet<string>;
|
|
8
10
|
}
|
|
9
11
|
export declare function indexRegistry(registry: ValueSchemaRegistry, pointer: string): {
|
|
10
12
|
readonly index: RegistryIndex;
|
|
@@ -4,11 +4,21 @@ import { diagnostic } from '../../validation/diagnostic.js';
|
|
|
4
4
|
import { isValueObject as isJsonObject } from '../model/object.js';
|
|
5
5
|
import { JSON_SCHEMA_DIALECT } from '../model/schema.js';
|
|
6
6
|
import { GRAPH_NODE_PATH_SCHEMA_ID } from '../syntax/node-path/schema.js';
|
|
7
|
+
// A registry is an immutable value, and every value schema of a Domain is validated against the
|
|
8
|
+
// same one: an index that admitted it without a diagnostic is reused, so the closure is indexed
|
|
9
|
+
// once per registry rather than once per value schema.
|
|
10
|
+
const admittedIndexes = new WeakMap();
|
|
7
11
|
export function indexRegistry(registry, pointer) {
|
|
12
|
+
const admitted = admittedIndexes.get(registry);
|
|
13
|
+
if (admitted !== undefined)
|
|
14
|
+
return { index: admitted, diagnostics: [] };
|
|
8
15
|
const diagnostics = [];
|
|
9
16
|
const domains = new Map();
|
|
10
17
|
domains.set(registry.current.origin, registry.current);
|
|
11
|
-
|
|
18
|
+
// The registry is the closure the Kernel builds for the schema at `pointer`, not a document: a
|
|
19
|
+
// fault of one of its entries is a fault of the closure that schema is checked with, reported
|
|
20
|
+
// there, the entry named in the message.
|
|
21
|
+
validateDomainRegistry(registry.current, 'current', false, pointer, diagnostics);
|
|
12
22
|
const dependencies = [
|
|
13
23
|
...registry.directDependencies.map((domain) => ({ domain, lane: 'directDependencies' })),
|
|
14
24
|
...registry.transitiveDependencies.map((domain) => ({
|
|
@@ -17,10 +27,9 @@ export function indexRegistry(registry, pointer) {
|
|
|
17
27
|
})),
|
|
18
28
|
];
|
|
19
29
|
dependencies.forEach(({ domain, lane }, index) => {
|
|
20
|
-
|
|
21
|
-
validateDomainRegistry(domain, domainPointer, true, diagnostics);
|
|
30
|
+
validateDomainRegistry(domain, `${lane}/${index}`, true, pointer, diagnostics);
|
|
22
31
|
if (domain.origin === registry.current.origin || domains.has(domain.origin)) {
|
|
23
|
-
diagnostics.push(diagnostic('VS_REFERENCE_RESOLUTION',
|
|
32
|
+
diagnostics.push(diagnostic('VS_REFERENCE_RESOLUTION', pointer, `Registry origin ${domain.origin} is duplicated in the exact closure, at ${lane}/${index}.`));
|
|
24
33
|
return;
|
|
25
34
|
}
|
|
26
35
|
domains.set(domain.origin, domain);
|
|
@@ -31,36 +40,44 @@ export function indexRegistry(registry, pointer) {
|
|
|
31
40
|
dependenciesByOwner.set(domain.origin, pins);
|
|
32
41
|
for (const dependency of domain.dependencies) {
|
|
33
42
|
const target = domains.get(dependency.origin);
|
|
43
|
+
// The schema at `pointer` cannot be judged without the closure it may reference.
|
|
34
44
|
if (target === undefined || target.revision !== dependency.revision) {
|
|
35
|
-
diagnostics.push(diagnostic('VS_REFERENCE_RESOLUTION',
|
|
45
|
+
diagnostics.push(diagnostic('VS_REFERENCE_RESOLUTION', pointer, `Registry closure is missing exact ${dependency.origin}@${dependency.revision} required by ${domain.origin}.`));
|
|
36
46
|
}
|
|
37
47
|
}
|
|
38
48
|
}
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
const nodeDefinitions = new Set();
|
|
50
|
+
for (const domain of domains.values()) {
|
|
51
|
+
for (const ref of domain.nodeDefinitions) {
|
|
52
|
+
if (ref.origin === domain.origin)
|
|
53
|
+
nodeDefinitions.add(definitionRefIndex(ref));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
validateGraphNodePathResource(registry.graphNodePath, pointer, diagnostics);
|
|
57
|
+
const index = { registry, domains, dependenciesByOwner, nodeDefinitions };
|
|
58
|
+
if (diagnostics.length === 0)
|
|
59
|
+
admittedIndexes.set(registry, index);
|
|
60
|
+
return { index, diagnostics };
|
|
41
61
|
}
|
|
42
62
|
export function isOriginVisibleFrom(index, ownerOrigin, targetOrigin) {
|
|
43
63
|
return (ownerOrigin === targetOrigin ||
|
|
44
64
|
index.dependenciesByOwner.get(ownerOrigin)?.has(targetOrigin) === true);
|
|
45
65
|
}
|
|
46
66
|
export function hasNodeDefinition(index, ref, ownerOrigin) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return (index.domains
|
|
50
|
-
.get(ref.origin)
|
|
51
|
-
?.nodeDefinitions.some((candidate) => definitionRefIndex(candidate) === definitionRefIndex(ref)) === true);
|
|
67
|
+
return (isOriginVisibleFrom(index, ownerOrigin, ref.origin) &&
|
|
68
|
+
index.nodeDefinitions.has(definitionRefIndex(ref)));
|
|
52
69
|
}
|
|
53
|
-
function validateDomainRegistry(domain,
|
|
70
|
+
function validateDomainRegistry(domain, entry, revisionRequired, pointer, diagnostics) {
|
|
54
71
|
if (!DOMAIN_ORIGIN_PATTERN.test(domain.origin)) {
|
|
55
|
-
diagnostics.push(diagnostic('VS_REFERENCE_RESOLUTION',
|
|
72
|
+
diagnostics.push(diagnostic('VS_REFERENCE_RESOLUTION', pointer, `Registry origin is invalid, at ${entry}.`));
|
|
56
73
|
}
|
|
57
74
|
if ((revisionRequired && domain.revision === undefined) ||
|
|
58
75
|
(domain.revision !== undefined && !DOMAIN_REVISION_PATTERN.test(domain.revision))) {
|
|
59
|
-
diagnostics.push(diagnostic('VS_REFERENCE_RESOLUTION',
|
|
76
|
+
diagnostics.push(diagnostic('VS_REFERENCE_RESOLUTION', pointer, `A dependency-closure registry entry requires its exact sha256 revision, at ${entry}.`));
|
|
60
77
|
}
|
|
61
78
|
for (const ref of domain.nodeDefinitions) {
|
|
62
79
|
if (ref.origin !== domain.origin) {
|
|
63
|
-
diagnostics.push(diagnostic('VS_REFERENCE_RESOLUTION',
|
|
80
|
+
diagnostics.push(diagnostic('VS_REFERENCE_RESOLUTION', pointer, `A registry domain can list only its own Node Definitions, at ${entry}.`));
|
|
64
81
|
}
|
|
65
82
|
}
|
|
66
83
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import { limits } from '../../limits.js';
|
|
1
2
|
import { categoryRanges, complement, mergeRanges } from './unicode.js';
|
|
2
3
|
const CATEGORY = /^(?:L[lmotu]?|M[cen]?|N[dlo]?|P[cdefios]?|Z[lps]?|S[ckmo]?|C[cfno]?)$/u;
|
|
3
|
-
const
|
|
4
|
-
const MAX_NESTING = 32;
|
|
5
|
-
const MAX_REPEAT = 1000;
|
|
4
|
+
const { maxCodePoints, maxNesting, maxRepeat } = limits.regexp;
|
|
6
5
|
const DOT_RANGES = [
|
|
7
6
|
[0, 9],
|
|
8
7
|
[11, 12],
|
|
@@ -14,7 +13,7 @@ export function parseIRegexp(source) {
|
|
|
14
13
|
if (!isUnicodeScalarString(source) || source === '[^]')
|
|
15
14
|
return undefined;
|
|
16
15
|
const characters = Array.from(source);
|
|
17
|
-
if (characters.length >
|
|
16
|
+
if (characters.length > maxCodePoints)
|
|
18
17
|
return undefined;
|
|
19
18
|
const parser = new Parser(characters);
|
|
20
19
|
const expression = parser.expression(undefined, 0);
|
|
@@ -30,7 +29,7 @@ class Parser {
|
|
|
30
29
|
return this.index === this.characters.length;
|
|
31
30
|
}
|
|
32
31
|
expression(stop, depth) {
|
|
33
|
-
if (depth >
|
|
32
|
+
if (depth > maxNesting)
|
|
34
33
|
return undefined;
|
|
35
34
|
const alternatives = [];
|
|
36
35
|
const first = this.sequence(stop, depth);
|
|
@@ -112,14 +111,14 @@ class Parser {
|
|
|
112
111
|
quantifier() {
|
|
113
112
|
this.index++;
|
|
114
113
|
const minimum = this.integer();
|
|
115
|
-
if (minimum === undefined || minimum >
|
|
114
|
+
if (minimum === undefined || minimum > maxRepeat)
|
|
116
115
|
return undefined;
|
|
117
116
|
let maximum = minimum;
|
|
118
117
|
if (this.peek() === ',') {
|
|
119
118
|
this.index++;
|
|
120
119
|
maximum = this.integer();
|
|
121
120
|
}
|
|
122
|
-
if ((maximum !== undefined && (maximum >
|
|
121
|
+
if ((maximum !== undefined && (maximum > maxRepeat || maximum < minimum)) ||
|
|
123
122
|
this.peek() !== '}') {
|
|
124
123
|
return undefined;
|
|
125
124
|
}
|
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
import type { Pattern, RunPattern } from '../compile/model.js';
|
|
2
2
|
import type { Expression } from './ast.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* counted-run form never expands, so it is not subject to this budget.
|
|
8
|
-
*/
|
|
9
|
-
export declare const MAX_STATES = 10000;
|
|
10
|
-
/**
|
|
11
|
-
* Thrown when an I-Regexp source compiles to a machine of more than `MAX_STATES` states. A short
|
|
12
|
-
* branching source such as `(a{0,1000}){0,60}b` would unroll to ~120k states and cost seconds per
|
|
13
|
-
* validated value (P1-I-01); it is refused before any state is built.
|
|
4
|
+
* Thrown when an I-Regexp source compiles to a machine of more than `limits.regexp.maxStates`
|
|
5
|
+
* states. A short branching source such as `(a{0,1000}){0,60}b` would unroll to ~120k states and
|
|
6
|
+
* cost seconds per validated value (P1-I-01); it is refused before any state is built.
|
|
14
7
|
*/
|
|
15
8
|
export declare class PatternComplexityError extends RangeError {
|
|
16
9
|
readonly limit: number;
|
|
@@ -20,7 +13,8 @@ export declare class PatternComplexityError extends RangeError {
|
|
|
20
13
|
export declare function compilePattern(source: string): Pattern | RunPattern;
|
|
21
14
|
/**
|
|
22
15
|
* Whether a parsed I-Regexp compiles within the state budget: as counted runs, which never expand,
|
|
23
|
-
* or as a machine of at most `
|
|
16
|
+
* or as a machine of at most `limits.regexp.maxStates` states, counted from the AST before anything
|
|
17
|
+
* is built.
|
|
24
18
|
*/
|
|
25
19
|
export declare function withinStateBudget(expression: Expression): boolean;
|
|
26
20
|
/**
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
+
import { limits } from '../../limits.js';
|
|
1
2
|
import { parseIRegexp } from './ast.js';
|
|
2
3
|
/**
|
|
3
|
-
* The most states the machine of one I-Regexp may have
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The most states the machine of one I-Regexp may have, an implementation limit as RFC 9485 §8
|
|
5
|
+
* allows. Counted repetitions are expanded copy by copy, so the parser's bounds on length, nesting
|
|
6
|
+
* and counts alone admit machines of billions of states. The counted-run form never expands, so it
|
|
7
|
+
* is not subject to this budget.
|
|
7
8
|
*/
|
|
8
|
-
|
|
9
|
+
const { maxStates } = limits.regexp;
|
|
9
10
|
/**
|
|
10
|
-
* Thrown when an I-Regexp source compiles to a machine of more than `
|
|
11
|
-
* branching source such as `(a{0,1000}){0,60}b` would unroll to ~120k states and
|
|
12
|
-
* validated value (P1-I-01); it is refused before any state is built.
|
|
11
|
+
* Thrown when an I-Regexp source compiles to a machine of more than `limits.regexp.maxStates`
|
|
12
|
+
* states. A short branching source such as `(a{0,1000}){0,60}b` would unroll to ~120k states and
|
|
13
|
+
* cost seconds per validated value (P1-I-01); it is refused before any state is built.
|
|
13
14
|
*/
|
|
14
15
|
export class PatternComplexityError extends RangeError {
|
|
15
16
|
limit;
|
|
16
|
-
constructor(limit =
|
|
17
|
+
constructor(limit = maxStates) {
|
|
17
18
|
super(`Cannot compile an I-Regexp machine of more than ${limit} states.`);
|
|
18
19
|
this.limit = limit;
|
|
19
20
|
this.name = 'PatternComplexityError';
|
|
@@ -27,7 +28,7 @@ export function compilePattern(source) {
|
|
|
27
28
|
const runs = scalarRuns(expression);
|
|
28
29
|
if (runs !== undefined)
|
|
29
30
|
return Object.freeze({ source, runs });
|
|
30
|
-
if (states(expression) >
|
|
31
|
+
if (states(expression) > maxStates)
|
|
31
32
|
throw new PatternComplexityError();
|
|
32
33
|
const builder = new Builder();
|
|
33
34
|
const fragment = builder.expression(expression);
|
|
@@ -40,10 +41,11 @@ export function compilePattern(source) {
|
|
|
40
41
|
}
|
|
41
42
|
/**
|
|
42
43
|
* Whether a parsed I-Regexp compiles within the state budget: as counted runs, which never expand,
|
|
43
|
-
* or as a machine of at most `
|
|
44
|
+
* or as a machine of at most `limits.regexp.maxStates` states, counted from the AST before anything
|
|
45
|
+
* is built.
|
|
44
46
|
*/
|
|
45
47
|
export function withinStateBudget(expression) {
|
|
46
|
-
return scalarRuns(expression) !== undefined || states(expression) <=
|
|
48
|
+
return scalarRuns(expression) !== undefined || states(expression) <= maxStates;
|
|
47
49
|
}
|
|
48
50
|
/**
|
|
49
51
|
* The number of states `Builder` builds for an expression, computed from the AST alone: `states`
|