@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
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { assertionsHold } from './assertions.js';
|
|
2
|
+
import { equivalent } from './equivalence.js';
|
|
3
|
+
import { evidenceOf } from './evidence.js';
|
|
4
|
+
import { isTop } from './keywords.js';
|
|
5
|
+
import { accepts, at, childrenOf, schemaOf } from './location.js';
|
|
6
6
|
/**
|
|
7
7
|
* Whether `outer` admits every value `inner` admits, under the one V1 evaluator.
|
|
8
8
|
*
|
|
@@ -13,60 +13,13 @@ import { appendPointer } from '../syntax/pointer.js';
|
|
|
13
13
|
export function valueProgramIncludes(outer, inner) {
|
|
14
14
|
return new Inclusion().includes(at(outer, outer.root), at(inner, inner.root));
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const OBJECT = 4;
|
|
19
|
-
const ARRAY = 8;
|
|
20
|
-
const STRING = 16;
|
|
21
|
-
const INTEGER = 32;
|
|
22
|
-
const FRACTION = 64;
|
|
23
|
-
const NUMBER = INTEGER | FRACTION;
|
|
24
|
-
const ANY = NULL | BOOLEAN | OBJECT | ARRAY | STRING | NUMBER;
|
|
25
|
-
/** Keywords the evaluator never asserts. */
|
|
26
|
-
const INERT = new Set([
|
|
27
|
-
'$anchor',
|
|
28
|
-
'$comment',
|
|
29
|
-
'$defs',
|
|
30
|
-
'$id',
|
|
31
|
-
'$schema',
|
|
32
|
-
'contentEncoding',
|
|
33
|
-
'contentMediaType',
|
|
34
|
-
'contentSchema',
|
|
35
|
-
'default',
|
|
36
|
-
'deprecated',
|
|
37
|
-
'description',
|
|
38
|
-
'examples',
|
|
39
|
-
'format',
|
|
40
|
-
'readOnly',
|
|
41
|
-
'title',
|
|
42
|
-
'writeOnly',
|
|
43
|
-
'x-astrale-path',
|
|
44
|
-
]);
|
|
45
|
-
/** Keywords whose subschemas the equivalence check compares positionally. */
|
|
46
|
-
const SUBSCHEMA_KEYWORDS = new Set([
|
|
47
|
-
'additionalProperties',
|
|
48
|
-
'allOf',
|
|
49
|
-
'anyOf',
|
|
50
|
-
'contains',
|
|
51
|
-
'dependentSchemas',
|
|
52
|
-
'else',
|
|
53
|
-
'if',
|
|
54
|
-
'items',
|
|
55
|
-
'not',
|
|
56
|
-
'oneOf',
|
|
57
|
-
'patternProperties',
|
|
58
|
-
'prefixItems',
|
|
59
|
-
'properties',
|
|
60
|
-
'propertyNames',
|
|
61
|
-
'then',
|
|
62
|
-
'unevaluatedItems',
|
|
63
|
-
'unevaluatedProperties',
|
|
64
|
-
]);
|
|
65
|
-
class Inclusion {
|
|
16
|
+
/** One inclusion question: the decided pairs, the pairs being decided and the evidence cache. */
|
|
17
|
+
export class Inclusion {
|
|
66
18
|
programs = new Map();
|
|
67
19
|
decided = new Map();
|
|
68
20
|
pending = new Set();
|
|
69
21
|
evidenceByAt = new Map();
|
|
22
|
+
/** Whether `outer` admits every value `inner` admits; a cyclic premise proves nothing. */
|
|
70
23
|
includes(outer, inner) {
|
|
71
24
|
const key = this.pair(outer, inner);
|
|
72
25
|
const known = this.decided.get(key);
|
|
@@ -85,19 +38,33 @@ class Inclusion {
|
|
|
85
38
|
this.pending.delete(key);
|
|
86
39
|
}
|
|
87
40
|
}
|
|
41
|
+
/** The evidence of one location, computed once per question. */
|
|
42
|
+
evidence(location) {
|
|
43
|
+
const key = this.location(location);
|
|
44
|
+
const cached = this.evidenceByAt.get(key);
|
|
45
|
+
if (cached !== undefined)
|
|
46
|
+
return cached;
|
|
47
|
+
const result = evidenceOf(location);
|
|
48
|
+
this.evidenceByAt.set(key, result);
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
/** A key identifying an ordered pair of locations within this question. */
|
|
52
|
+
pair(outer, inner) {
|
|
53
|
+
return `${this.location(outer)}|${this.location(inner)}`;
|
|
54
|
+
}
|
|
88
55
|
decide(outer, inner) {
|
|
89
56
|
const schema = schemaOf(outer);
|
|
90
57
|
if (isTop(schema))
|
|
91
58
|
return true;
|
|
92
59
|
const evidence = this.evidence(inner);
|
|
93
60
|
if (evidence.values !== undefined) {
|
|
94
|
-
return evidence.values.every((value) => !
|
|
61
|
+
return evidence.values.every((value) => !accepts(inner, value) || accepts(outer, value));
|
|
95
62
|
}
|
|
96
63
|
if (schema === false)
|
|
97
64
|
return false;
|
|
98
|
-
if (
|
|
65
|
+
if (equivalent(this, outer, inner))
|
|
99
66
|
return true;
|
|
100
|
-
if (schema !== true &&
|
|
67
|
+
if (schema !== true && assertionsHold(this, outer, schema, inner, evidence))
|
|
101
68
|
return true;
|
|
102
69
|
// A disjunction admits each value through one branch, and each branch alone is weaker.
|
|
103
70
|
return evidence.conjuncts.some((conjunct) => ['anyOf', 'oneOf'].some((keyword) => {
|
|
@@ -105,535 +72,6 @@ class Inclusion {
|
|
|
105
72
|
return branches.length > 0 && branches.every((branch) => this.includes(outer, branch));
|
|
106
73
|
}));
|
|
107
74
|
}
|
|
108
|
-
assertionsHold(outer, schema, inner, evidence) {
|
|
109
|
-
// Annotation-dependent keywords are decided only by equivalence.
|
|
110
|
-
if (Object.hasOwn(schema, 'unevaluatedProperties'))
|
|
111
|
-
return false;
|
|
112
|
-
if (Object.hasOwn(schema, 'unevaluatedItems'))
|
|
113
|
-
return false;
|
|
114
|
-
return Object.keys(schema).every((keyword) => this.assertionHolds(keyword, outer, schema, inner, evidence));
|
|
115
|
-
}
|
|
116
|
-
assertionHolds(keyword, outer, schema, inner, evidence) {
|
|
117
|
-
const value = schema[keyword];
|
|
118
|
-
switch (keyword) {
|
|
119
|
-
case '$ref': {
|
|
120
|
-
const target = referenceOf(outer);
|
|
121
|
-
return target !== undefined && this.includes(target, inner);
|
|
122
|
-
}
|
|
123
|
-
case 'allOf':
|
|
124
|
-
return childrenOf(outer, keyword).every((branch) => this.includes(branch, inner));
|
|
125
|
-
case 'anyOf':
|
|
126
|
-
return childrenOf(outer, keyword).some((branch) => this.includes(branch, inner));
|
|
127
|
-
case 'oneOf':
|
|
128
|
-
return false;
|
|
129
|
-
case 'not': {
|
|
130
|
-
const negated = childOf(outer, keyword);
|
|
131
|
-
return negated !== undefined && this.excludes(negated, evidence);
|
|
132
|
-
}
|
|
133
|
-
case 'if':
|
|
134
|
-
case 'then':
|
|
135
|
-
case 'else':
|
|
136
|
-
return this.conditionalHolds(outer, inner, evidence);
|
|
137
|
-
case 'type':
|
|
138
|
-
return (evidence.kinds & ~typeMask(value)) === 0;
|
|
139
|
-
case 'const':
|
|
140
|
-
case 'enum':
|
|
141
|
-
return false;
|
|
142
|
-
case 'x-astrale-value-kind':
|
|
143
|
-
return typeof value === 'string' && evidence.valueKinds.has(value);
|
|
144
|
-
case 'maximum':
|
|
145
|
-
return (typeof value !== 'number' ||
|
|
146
|
-
!has(evidence, NUMBER) ||
|
|
147
|
-
(evidence.upper !== undefined && evidence.upper.value <= value));
|
|
148
|
-
case 'exclusiveMaximum':
|
|
149
|
-
return (typeof value !== 'number' ||
|
|
150
|
-
!has(evidence, NUMBER) ||
|
|
151
|
-
(evidence.upper !== undefined &&
|
|
152
|
-
(evidence.upper.value < value ||
|
|
153
|
-
(evidence.upper.exclusive && evidence.upper.value <= value))));
|
|
154
|
-
case 'minimum':
|
|
155
|
-
return (typeof value !== 'number' ||
|
|
156
|
-
!has(evidence, NUMBER) ||
|
|
157
|
-
(evidence.lower !== undefined && evidence.lower.value >= value));
|
|
158
|
-
case 'exclusiveMinimum':
|
|
159
|
-
return (typeof value !== 'number' ||
|
|
160
|
-
!has(evidence, NUMBER) ||
|
|
161
|
-
(evidence.lower !== undefined &&
|
|
162
|
-
(evidence.lower.value > value ||
|
|
163
|
-
(evidence.lower.exclusive && evidence.lower.value >= value))));
|
|
164
|
-
case 'multipleOf':
|
|
165
|
-
return (typeof value !== 'number' ||
|
|
166
|
-
!has(evidence, NUMBER) ||
|
|
167
|
-
evidence.multipleOf.some((divisor) => isMultipleOf(divisor, value)) ||
|
|
168
|
-
(!has(evidence, FRACTION) && isMultipleOf(1, value)));
|
|
169
|
-
case 'maxLength':
|
|
170
|
-
return (typeof value !== 'number' ||
|
|
171
|
-
!has(evidence, STRING) ||
|
|
172
|
-
(evidence.maxLength !== undefined && evidence.maxLength <= value));
|
|
173
|
-
case 'minLength':
|
|
174
|
-
return (typeof value !== 'number' ||
|
|
175
|
-
!has(evidence, STRING) ||
|
|
176
|
-
value <= 0 ||
|
|
177
|
-
evidence.minLength >= value);
|
|
178
|
-
case 'pattern':
|
|
179
|
-
return (typeof value !== 'string' ||
|
|
180
|
-
!has(evidence, STRING) ||
|
|
181
|
-
evidence.patterns.has(value) ||
|
|
182
|
-
evidence.fullMatches.has(value));
|
|
183
|
-
case 'fullMatch':
|
|
184
|
-
return (typeof value !== 'string' || !has(evidence, STRING) || evidence.fullMatches.has(value));
|
|
185
|
-
case 'maxItems':
|
|
186
|
-
return (typeof value !== 'number' ||
|
|
187
|
-
!has(evidence, ARRAY) ||
|
|
188
|
-
(evidence.maxItems !== undefined && evidence.maxItems <= value));
|
|
189
|
-
case 'minItems':
|
|
190
|
-
return (typeof value !== 'number' ||
|
|
191
|
-
!has(evidence, ARRAY) ||
|
|
192
|
-
value <= 0 ||
|
|
193
|
-
evidence.minItems >= value);
|
|
194
|
-
case 'uniqueItems':
|
|
195
|
-
return (value !== true ||
|
|
196
|
-
!has(evidence, ARRAY) ||
|
|
197
|
-
evidence.uniqueItems ||
|
|
198
|
-
(evidence.maxItems !== undefined && evidence.maxItems <= 1));
|
|
199
|
-
case 'prefixItems':
|
|
200
|
-
case 'items':
|
|
201
|
-
return this.itemsHold(outer, schema, evidence);
|
|
202
|
-
case 'contains':
|
|
203
|
-
case 'minContains':
|
|
204
|
-
case 'maxContains':
|
|
205
|
-
return this.containsHolds(outer, schema, evidence);
|
|
206
|
-
case 'maxProperties':
|
|
207
|
-
return (typeof value !== 'number' ||
|
|
208
|
-
!has(evidence, OBJECT) ||
|
|
209
|
-
(evidence.maxProperties !== undefined && evidence.maxProperties <= value) ||
|
|
210
|
-
evidence.conjuncts.some((conjunct) => {
|
|
211
|
-
const names = this.closedNames(conjunct);
|
|
212
|
-
return names !== undefined && names.length <= value;
|
|
213
|
-
}));
|
|
214
|
-
case 'minProperties':
|
|
215
|
-
return (typeof value !== 'number' ||
|
|
216
|
-
!has(evidence, OBJECT) ||
|
|
217
|
-
value <= 0 ||
|
|
218
|
-
evidence.minProperties >= value ||
|
|
219
|
-
evidence.required.size >= value);
|
|
220
|
-
case 'required':
|
|
221
|
-
return (!Array.isArray(value) ||
|
|
222
|
-
!has(evidence, OBJECT) ||
|
|
223
|
-
value.every((name) => typeof name !== 'string' || evidence.required.has(name)));
|
|
224
|
-
case 'dependentRequired':
|
|
225
|
-
return (!isJsonObject(value) ||
|
|
226
|
-
!has(evidence, OBJECT) ||
|
|
227
|
-
Object.entries(value).every(([name, dependencies]) => !Array.isArray(dependencies) ||
|
|
228
|
-
this.forbids(evidence, name) ||
|
|
229
|
-
dependencies.every((dependency) => typeof dependency !== 'string' ||
|
|
230
|
-
evidence.required.has(dependency) ||
|
|
231
|
-
evidence.dependentRequired.get(name)?.has(dependency) === true)));
|
|
232
|
-
case 'properties':
|
|
233
|
-
return (!isJsonObject(value) ||
|
|
234
|
-
!has(evidence, OBJECT) ||
|
|
235
|
-
Object.keys(value).every((name) => {
|
|
236
|
-
const member = childOf(outer, keyword, name);
|
|
237
|
-
return (member === undefined ||
|
|
238
|
-
isTop(schemaOf(member)) ||
|
|
239
|
-
this.memberConstraints(evidence, name).some((constraint) => this.includes(member, constraint)));
|
|
240
|
-
}));
|
|
241
|
-
case 'patternProperties':
|
|
242
|
-
return (!isJsonObject(value) ||
|
|
243
|
-
!has(evidence, OBJECT) ||
|
|
244
|
-
Object.keys(value).every((pattern) => {
|
|
245
|
-
const member = childOf(outer, keyword, pattern);
|
|
246
|
-
if (member === undefined || isTop(schemaOf(member)))
|
|
247
|
-
return true;
|
|
248
|
-
return evidence.conjuncts.some((conjunct) => {
|
|
249
|
-
const same = childOf(conjunct, keyword, pattern);
|
|
250
|
-
if (same !== undefined && this.includes(member, same))
|
|
251
|
-
return true;
|
|
252
|
-
return this.coversNames(conjunct, member, (name) => matches(outer, pattern, name));
|
|
253
|
-
});
|
|
254
|
-
}));
|
|
255
|
-
case 'additionalProperties':
|
|
256
|
-
return this.additionalHolds(outer, schema, evidence);
|
|
257
|
-
case 'propertyNames': {
|
|
258
|
-
const names = childOf(outer, keyword);
|
|
259
|
-
if (names === undefined || isTop(schemaOf(names)) || !has(evidence, OBJECT))
|
|
260
|
-
return true;
|
|
261
|
-
return evidence.conjuncts.some((conjunct) => {
|
|
262
|
-
const own = childOf(conjunct, keyword);
|
|
263
|
-
if (own !== undefined && this.includes(names, own))
|
|
264
|
-
return true;
|
|
265
|
-
const closed = this.closedNames(conjunct);
|
|
266
|
-
return closed !== undefined && closed.every((name) => this.accepts(names, name));
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
case 'dependentSchemas':
|
|
270
|
-
return (!isJsonObject(value) ||
|
|
271
|
-
!has(evidence, OBJECT) ||
|
|
272
|
-
Object.keys(value).every((name) => {
|
|
273
|
-
const dependent = childOf(outer, keyword, name);
|
|
274
|
-
if (dependent === undefined || isTop(schemaOf(dependent)))
|
|
275
|
-
return true;
|
|
276
|
-
if (this.forbids(evidence, name))
|
|
277
|
-
return true;
|
|
278
|
-
if (evidence.conjuncts.some((conjunct) => this.includes(dependent, conjunct))) {
|
|
279
|
-
return true;
|
|
280
|
-
}
|
|
281
|
-
return evidence.conjuncts.some((conjunct) => {
|
|
282
|
-
const own = childOf(conjunct, keyword, name);
|
|
283
|
-
return own !== undefined && this.includes(dependent, own);
|
|
284
|
-
});
|
|
285
|
-
}));
|
|
286
|
-
default:
|
|
287
|
-
return INERT.has(keyword);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
/** Whether no value admitted by `evidence` satisfies `negated`. */
|
|
291
|
-
excludes(negated, evidence) {
|
|
292
|
-
if ((this.evidence(negated).kinds & evidence.kinds) === 0)
|
|
293
|
-
return true;
|
|
294
|
-
return evidence.conjuncts.some((conjunct) => {
|
|
295
|
-
const own = childOf(conjunct, 'not');
|
|
296
|
-
return own !== undefined && this.includes(own, negated);
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
conditionalHolds(outer, inner, evidence) {
|
|
300
|
-
const condition = childOf(outer, 'if');
|
|
301
|
-
if (condition === undefined)
|
|
302
|
-
return true;
|
|
303
|
-
const then = childOf(outer, 'then');
|
|
304
|
-
const otherwise = childOf(outer, 'else');
|
|
305
|
-
const thenHolds = (fallback) => then === undefined ||
|
|
306
|
-
this.includes(then, inner) ||
|
|
307
|
-
(fallback !== undefined && this.includes(then, fallback));
|
|
308
|
-
const elseHolds = (fallback) => otherwise === undefined ||
|
|
309
|
-
this.includes(otherwise, inner) ||
|
|
310
|
-
(fallback !== undefined && this.includes(otherwise, fallback));
|
|
311
|
-
if (thenHolds() && elseHolds())
|
|
312
|
-
return true;
|
|
313
|
-
for (const conjunct of evidence.conjuncts) {
|
|
314
|
-
const own = childOf(conjunct, 'if');
|
|
315
|
-
if (own === undefined || !this.equivalent(own, condition))
|
|
316
|
-
continue;
|
|
317
|
-
if (thenHolds(childOf(conjunct, 'then')) && elseHolds(childOf(conjunct, 'else')))
|
|
318
|
-
return true;
|
|
319
|
-
}
|
|
320
|
-
if (this.includes(condition, inner))
|
|
321
|
-
return thenHolds();
|
|
322
|
-
if (this.excludes(condition, evidence))
|
|
323
|
-
return elseHolds();
|
|
324
|
-
return false;
|
|
325
|
-
}
|
|
326
|
-
itemsHold(outer, schema, evidence) {
|
|
327
|
-
if (!has(evidence, ARRAY))
|
|
328
|
-
return true;
|
|
329
|
-
const prefix = childrenOf(outer, 'prefixItems');
|
|
330
|
-
const rest = Object.hasOwn(schema, 'items') ? childOf(outer, 'items') : undefined;
|
|
331
|
-
const width = Math.max(prefix.length, ...evidence.conjuncts.map((conjunct) => childrenOf(conjunct, 'prefixItems').length));
|
|
332
|
-
// Every index at or beyond `width` meets `items` on both sides.
|
|
333
|
-
for (let index = 0; index <= width; index++) {
|
|
334
|
-
const required = index < prefix.length ? prefix[index] : rest;
|
|
335
|
-
if (required === undefined || isTop(schemaOf(required)))
|
|
336
|
-
continue;
|
|
337
|
-
if (evidence.maxItems !== undefined && evidence.maxItems <= index)
|
|
338
|
-
continue;
|
|
339
|
-
const admitted = evidence.conjuncts.flatMap((conjunct) => {
|
|
340
|
-
const own = childrenOf(conjunct, 'prefixItems');
|
|
341
|
-
if (index < own.length)
|
|
342
|
-
return [own[index]];
|
|
343
|
-
const items = childOf(conjunct, 'items');
|
|
344
|
-
return items === undefined ? [] : [items];
|
|
345
|
-
});
|
|
346
|
-
if (!admitted.some((constraint) => this.includes(required, constraint)))
|
|
347
|
-
return false;
|
|
348
|
-
}
|
|
349
|
-
return true;
|
|
350
|
-
}
|
|
351
|
-
containsHolds(outer, schema, evidence) {
|
|
352
|
-
const contains = childOf(outer, 'contains');
|
|
353
|
-
if (contains === undefined || !has(evidence, ARRAY))
|
|
354
|
-
return true;
|
|
355
|
-
const minimum = typeof schema.minContains === 'number' ? schema.minContains : 1;
|
|
356
|
-
const maximum = typeof schema.maxContains === 'number' ? schema.maxContains : Number.POSITIVE_INFINITY;
|
|
357
|
-
const ownContains = evidence.conjuncts.flatMap((conjunct) => {
|
|
358
|
-
const own = childOf(conjunct, 'contains');
|
|
359
|
-
if (own === undefined)
|
|
360
|
-
return [];
|
|
361
|
-
const conjunctSchema = schemaOf(conjunct);
|
|
362
|
-
return [
|
|
363
|
-
{
|
|
364
|
-
at: own,
|
|
365
|
-
minimum: typeof conjunctSchema.minContains === 'number' ? conjunctSchema.minContains : 1,
|
|
366
|
-
maximum: typeof conjunctSchema.maxContains === 'number'
|
|
367
|
-
? conjunctSchema.maxContains
|
|
368
|
-
: Number.POSITIVE_INFINITY,
|
|
369
|
-
},
|
|
370
|
-
];
|
|
371
|
-
});
|
|
372
|
-
// Every inner match is an outer match, so outer counts at least as many.
|
|
373
|
-
const atLeast = minimum <= 0 ||
|
|
374
|
-
ownContains.some((own) => own.minimum >= minimum && this.includes(contains, own.at));
|
|
375
|
-
// Every outer match is an inner match, so outer counts at most as many.
|
|
376
|
-
const atMost = maximum === Number.POSITIVE_INFINITY ||
|
|
377
|
-
(evidence.maxItems !== undefined && evidence.maxItems <= maximum) ||
|
|
378
|
-
ownContains.some((own) => own.maximum <= maximum && this.includes(own.at, contains));
|
|
379
|
-
return atLeast && atMost;
|
|
380
|
-
}
|
|
381
|
-
additionalHolds(outer, schema, evidence) {
|
|
382
|
-
const additional = childOf(outer, 'additionalProperties');
|
|
383
|
-
if (additional === undefined || isTop(schemaOf(additional)) || !has(evidence, OBJECT)) {
|
|
384
|
-
return true;
|
|
385
|
-
}
|
|
386
|
-
const declared = isJsonObject(schema.properties) ? schema.properties : {};
|
|
387
|
-
const patterns = isJsonObject(schema.patternProperties)
|
|
388
|
-
? Object.keys(schema.patternProperties)
|
|
389
|
-
: [];
|
|
390
|
-
const isAdditional = (name) => !Object.hasOwn(declared, name) && !patterns.some((pattern) => matches(outer, pattern, name));
|
|
391
|
-
return evidence.conjuncts.some((conjunct) => this.coversNames(conjunct, additional, isAdditional, patterns));
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* Whether every property of a `conjunct`-admitted object whose name is `relevant` satisfies
|
|
395
|
-
* `required`. Names matching a pattern in `settled` are never relevant.
|
|
396
|
-
*/
|
|
397
|
-
coversNames(conjunct, required, relevant, settled = []) {
|
|
398
|
-
const schema = schemaOf(conjunct);
|
|
399
|
-
if (!isJsonObject(schema))
|
|
400
|
-
return false;
|
|
401
|
-
const rest = childOf(conjunct, 'additionalProperties');
|
|
402
|
-
if (rest === undefined || !this.includes(required, rest))
|
|
403
|
-
return false;
|
|
404
|
-
const declared = isJsonObject(schema.properties) ? Object.keys(schema.properties) : [];
|
|
405
|
-
const patterns = isJsonObject(schema.patternProperties)
|
|
406
|
-
? Object.keys(schema.patternProperties)
|
|
407
|
-
: [];
|
|
408
|
-
return (declared.every((name) => {
|
|
409
|
-
if (!relevant(name))
|
|
410
|
-
return true;
|
|
411
|
-
const member = childOf(conjunct, 'properties', name);
|
|
412
|
-
return member !== undefined && this.includes(required, member);
|
|
413
|
-
}) &&
|
|
414
|
-
patterns.every((pattern) => {
|
|
415
|
-
if (settled.includes(pattern))
|
|
416
|
-
return true;
|
|
417
|
-
const member = childOf(conjunct, 'patternProperties', pattern);
|
|
418
|
-
return member !== undefined && this.includes(required, member);
|
|
419
|
-
}));
|
|
420
|
-
}
|
|
421
|
-
/** Locations one conjunct applies to the value of property `name`. */
|
|
422
|
-
memberConstraints(evidence, name) {
|
|
423
|
-
return evidence.conjuncts.flatMap((conjunct) => {
|
|
424
|
-
const schema = schemaOf(conjunct);
|
|
425
|
-
if (!isJsonObject(schema))
|
|
426
|
-
return [];
|
|
427
|
-
const constraints = [];
|
|
428
|
-
const declared = isJsonObject(schema.properties) && Object.hasOwn(schema.properties, name);
|
|
429
|
-
if (declared) {
|
|
430
|
-
const member = childOf(conjunct, 'properties', name);
|
|
431
|
-
if (member !== undefined)
|
|
432
|
-
constraints.push(member);
|
|
433
|
-
}
|
|
434
|
-
let matched = false;
|
|
435
|
-
if (isJsonObject(schema.patternProperties)) {
|
|
436
|
-
for (const pattern of Object.keys(schema.patternProperties)) {
|
|
437
|
-
if (!matches(conjunct, pattern, name))
|
|
438
|
-
continue;
|
|
439
|
-
matched = true;
|
|
440
|
-
const member = childOf(conjunct, 'patternProperties', pattern);
|
|
441
|
-
if (member !== undefined)
|
|
442
|
-
constraints.push(member);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
if (!declared && !matched) {
|
|
446
|
-
const rest = childOf(conjunct, 'additionalProperties');
|
|
447
|
-
if (rest !== undefined)
|
|
448
|
-
constraints.push(rest);
|
|
449
|
-
}
|
|
450
|
-
return constraints;
|
|
451
|
-
});
|
|
452
|
-
}
|
|
453
|
-
/** Whether an admitted object never has property `name`. */
|
|
454
|
-
forbids(evidence, name) {
|
|
455
|
-
return this.memberConstraints(evidence, name).some((constraint) => this.evidence(constraint).kinds === 0);
|
|
456
|
-
}
|
|
457
|
-
/** The complete property-name set of a closed object conjunct, when it is one. */
|
|
458
|
-
closedNames(conjunct) {
|
|
459
|
-
const schema = schemaOf(conjunct);
|
|
460
|
-
if (!isJsonObject(schema))
|
|
461
|
-
return undefined;
|
|
462
|
-
if (isJsonObject(schema.patternProperties) && Object.keys(schema.patternProperties).length > 0)
|
|
463
|
-
return undefined;
|
|
464
|
-
const rest = childOf(conjunct, 'additionalProperties');
|
|
465
|
-
if (rest === undefined || this.evidence(rest).kinds !== 0)
|
|
466
|
-
return undefined;
|
|
467
|
-
return isJsonObject(schema.properties) ? Object.keys(schema.properties) : [];
|
|
468
|
-
}
|
|
469
|
-
/** Whether the two locations are bisimilar: equal assertions over paired subschemas. */
|
|
470
|
-
equivalent(left, right) {
|
|
471
|
-
const pending = [[left, right]];
|
|
472
|
-
const seen = new Set();
|
|
473
|
-
while (pending.length > 0) {
|
|
474
|
-
const [first, second] = pending.pop();
|
|
475
|
-
const key = this.pair(first, second);
|
|
476
|
-
if (seen.has(key))
|
|
477
|
-
continue;
|
|
478
|
-
seen.add(key);
|
|
479
|
-
const a = schemaOf(first);
|
|
480
|
-
const b = schemaOf(second);
|
|
481
|
-
if (typeof a === 'boolean' || typeof b === 'boolean') {
|
|
482
|
-
if (a !== b)
|
|
483
|
-
return false;
|
|
484
|
-
continue;
|
|
485
|
-
}
|
|
486
|
-
const assertions = assertionKeys(a);
|
|
487
|
-
if (assertions.length !== assertionKeys(b).length)
|
|
488
|
-
return false;
|
|
489
|
-
for (const keyword of assertions) {
|
|
490
|
-
if (!Object.hasOwn(b, keyword) || !jsonEqual(a[keyword], b[keyword]))
|
|
491
|
-
return false;
|
|
492
|
-
}
|
|
493
|
-
const firstChildren = subschemaChildren(first);
|
|
494
|
-
const secondChildren = subschemaChildren(second);
|
|
495
|
-
if (firstChildren.size !== secondChildren.size)
|
|
496
|
-
return false;
|
|
497
|
-
for (const [path, index] of firstChildren) {
|
|
498
|
-
const other = secondChildren.get(path);
|
|
499
|
-
if (other === undefined)
|
|
500
|
-
return false;
|
|
501
|
-
pending.push([at(first.program, index), at(second.program, other)]);
|
|
502
|
-
}
|
|
503
|
-
const firstReference = referenceOf(first);
|
|
504
|
-
const secondReference = referenceOf(second);
|
|
505
|
-
if ((firstReference === undefined) !== (secondReference === undefined))
|
|
506
|
-
return false;
|
|
507
|
-
if (firstReference !== undefined)
|
|
508
|
-
pending.push([firstReference, secondReference]);
|
|
509
|
-
}
|
|
510
|
-
return true;
|
|
511
|
-
}
|
|
512
|
-
evidence(location) {
|
|
513
|
-
const key = this.location(location);
|
|
514
|
-
const cached = this.evidenceByAt.get(key);
|
|
515
|
-
if (cached !== undefined)
|
|
516
|
-
return cached;
|
|
517
|
-
const conjuncts = conjunctsOf(location);
|
|
518
|
-
let kinds = ANY;
|
|
519
|
-
let values;
|
|
520
|
-
let upper;
|
|
521
|
-
let lower;
|
|
522
|
-
const multipleOf = [];
|
|
523
|
-
let maxLength;
|
|
524
|
-
let minLength = 0;
|
|
525
|
-
const patterns = new Set();
|
|
526
|
-
const fullMatches = new Set();
|
|
527
|
-
let maxItems;
|
|
528
|
-
let minItems = 0;
|
|
529
|
-
let uniqueItems = false;
|
|
530
|
-
let maxProperties;
|
|
531
|
-
let minProperties = 0;
|
|
532
|
-
const required = new Set();
|
|
533
|
-
const dependentRequired = new Map();
|
|
534
|
-
const valueKinds = new Set();
|
|
535
|
-
const narrow = (candidates) => {
|
|
536
|
-
values =
|
|
537
|
-
values === undefined
|
|
538
|
-
? [...candidates]
|
|
539
|
-
: values.filter((value) => candidates.some((candidate) => jsonEqual(value, candidate)));
|
|
540
|
-
};
|
|
541
|
-
for (const conjunct of conjuncts) {
|
|
542
|
-
const schema = schemaOf(conjunct);
|
|
543
|
-
if (schema === false)
|
|
544
|
-
kinds = 0;
|
|
545
|
-
if (!isJsonObject(schema))
|
|
546
|
-
continue;
|
|
547
|
-
kinds &= typeMask(schema.type);
|
|
548
|
-
if (Object.hasOwn(schema, 'const')) {
|
|
549
|
-
narrow([schema.const]);
|
|
550
|
-
kinds &= kindOf(schema.const);
|
|
551
|
-
}
|
|
552
|
-
if (Array.isArray(schema.enum)) {
|
|
553
|
-
narrow(schema.enum);
|
|
554
|
-
kinds &= schema.enum.reduce((mask, value) => mask | kindOf(value), 0);
|
|
555
|
-
}
|
|
556
|
-
const valueKind = schema['x-astrale-value-kind'];
|
|
557
|
-
if (typeof valueKind === 'string') {
|
|
558
|
-
valueKinds.add(valueKind);
|
|
559
|
-
if (valueKind === 'instant')
|
|
560
|
-
kinds &= STRING;
|
|
561
|
-
if (valueKind === 'blob')
|
|
562
|
-
kinds &= OBJECT;
|
|
563
|
-
}
|
|
564
|
-
upper = tighter(upper, schema.maximum, false, (a, b) => a < b);
|
|
565
|
-
upper = tighter(upper, schema.exclusiveMaximum, true, (a, b) => a < b);
|
|
566
|
-
lower = tighter(lower, schema.minimum, false, (a, b) => a > b);
|
|
567
|
-
lower = tighter(lower, schema.exclusiveMinimum, true, (a, b) => a > b);
|
|
568
|
-
if (typeof schema.multipleOf === 'number')
|
|
569
|
-
multipleOf.push(schema.multipleOf);
|
|
570
|
-
if (typeof schema.maxLength === 'number')
|
|
571
|
-
maxLength = min(maxLength, schema.maxLength);
|
|
572
|
-
if (typeof schema.minLength === 'number')
|
|
573
|
-
minLength = Math.max(minLength, schema.minLength);
|
|
574
|
-
if (typeof schema.pattern === 'string')
|
|
575
|
-
patterns.add(schema.pattern);
|
|
576
|
-
if (typeof schema.fullMatch === 'string')
|
|
577
|
-
fullMatches.add(schema.fullMatch);
|
|
578
|
-
if (typeof schema.maxItems === 'number')
|
|
579
|
-
maxItems = min(maxItems, schema.maxItems);
|
|
580
|
-
if (typeof schema.minItems === 'number')
|
|
581
|
-
minItems = Math.max(minItems, schema.minItems);
|
|
582
|
-
if (schema.uniqueItems === true)
|
|
583
|
-
uniqueItems = true;
|
|
584
|
-
if (typeof schema.maxProperties === 'number') {
|
|
585
|
-
maxProperties = min(maxProperties, schema.maxProperties);
|
|
586
|
-
}
|
|
587
|
-
if (typeof schema.minProperties === 'number') {
|
|
588
|
-
minProperties = Math.max(minProperties, schema.minProperties);
|
|
589
|
-
}
|
|
590
|
-
if (Array.isArray(schema.required)) {
|
|
591
|
-
for (const name of schema.required)
|
|
592
|
-
if (typeof name === 'string')
|
|
593
|
-
required.add(name);
|
|
594
|
-
}
|
|
595
|
-
if (isJsonObject(schema.dependentRequired)) {
|
|
596
|
-
for (const [name, dependencies] of Object.entries(schema.dependentRequired)) {
|
|
597
|
-
if (!Array.isArray(dependencies))
|
|
598
|
-
continue;
|
|
599
|
-
const known = dependentRequired.get(name) ?? new Set();
|
|
600
|
-
for (const dependency of dependencies) {
|
|
601
|
-
if (typeof dependency === 'string')
|
|
602
|
-
known.add(dependency);
|
|
603
|
-
}
|
|
604
|
-
dependentRequired.set(name, known);
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
const finite = values === undefined
|
|
609
|
-
? finiteKinds(kinds)
|
|
610
|
-
: values.filter((value) => (kindOf(value) & kinds) !== 0);
|
|
611
|
-
const result = Object.freeze({
|
|
612
|
-
conjuncts,
|
|
613
|
-
kinds,
|
|
614
|
-
...(finite === undefined ? {} : { values: finite }),
|
|
615
|
-
...(upper === undefined ? {} : { upper }),
|
|
616
|
-
...(lower === undefined ? {} : { lower }),
|
|
617
|
-
multipleOf,
|
|
618
|
-
...(maxLength === undefined ? {} : { maxLength }),
|
|
619
|
-
minLength,
|
|
620
|
-
patterns,
|
|
621
|
-
fullMatches,
|
|
622
|
-
...(maxItems === undefined ? {} : { maxItems }),
|
|
623
|
-
minItems,
|
|
624
|
-
uniqueItems,
|
|
625
|
-
...(maxProperties === undefined ? {} : { maxProperties }),
|
|
626
|
-
minProperties,
|
|
627
|
-
required,
|
|
628
|
-
dependentRequired,
|
|
629
|
-
valueKinds,
|
|
630
|
-
});
|
|
631
|
-
this.evidenceByAt.set(key, result);
|
|
632
|
-
return result;
|
|
633
|
-
}
|
|
634
|
-
accepts(location, value) {
|
|
635
|
-
return evaluateInstance(loadValueProgram(location.program, location.index), value).valid;
|
|
636
|
-
}
|
|
637
75
|
location(value) {
|
|
638
76
|
let id = this.programs.get(value.program);
|
|
639
77
|
if (id === undefined) {
|
|
@@ -642,136 +80,4 @@ class Inclusion {
|
|
|
642
80
|
}
|
|
643
81
|
return `${id}:${value.index}`;
|
|
644
82
|
}
|
|
645
|
-
pair(outer, inner) {
|
|
646
|
-
return `${this.location(outer)}|${this.location(inner)}`;
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
function at(program, index) {
|
|
650
|
-
return { program, index };
|
|
651
|
-
}
|
|
652
|
-
function schemaOf(location) {
|
|
653
|
-
const node = location.program.nodes[location.index];
|
|
654
|
-
if (node === undefined)
|
|
655
|
-
throw new TypeError('Value program location is absent.');
|
|
656
|
-
return node.schema;
|
|
657
|
-
}
|
|
658
|
-
function childOf(location, keyword, member) {
|
|
659
|
-
const base = appendPointer('', keyword);
|
|
660
|
-
const key = (member === undefined ? base : appendPointer(base, member)).slice(1);
|
|
661
|
-
const index = location.program.nodes[location.index]?.children[key];
|
|
662
|
-
return index === undefined ? undefined : at(location.program, index);
|
|
663
|
-
}
|
|
664
|
-
function childrenOf(location, keyword) {
|
|
665
|
-
const schema = schemaOf(location);
|
|
666
|
-
if (!isJsonObject(schema) || !Array.isArray(schema[keyword]))
|
|
667
|
-
return [];
|
|
668
|
-
return schema[keyword].flatMap((_, index) => {
|
|
669
|
-
const child = childOf(location, keyword, index);
|
|
670
|
-
return child === undefined ? [] : [child];
|
|
671
|
-
});
|
|
672
|
-
}
|
|
673
|
-
function referenceOf(location) {
|
|
674
|
-
const index = location.program.nodes[location.index]?.reference;
|
|
675
|
-
return index === undefined ? undefined : at(location.program, index);
|
|
676
|
-
}
|
|
677
|
-
/** The location with its `$ref` targets and `allOf` branches; admission makes this acyclic. */
|
|
678
|
-
function conjunctsOf(location) {
|
|
679
|
-
const seen = new Set();
|
|
680
|
-
const conjuncts = [];
|
|
681
|
-
const visit = (current) => {
|
|
682
|
-
if (seen.has(current.index))
|
|
683
|
-
return;
|
|
684
|
-
seen.add(current.index);
|
|
685
|
-
conjuncts.push(current);
|
|
686
|
-
const reference = referenceOf(current);
|
|
687
|
-
if (reference !== undefined)
|
|
688
|
-
visit(reference);
|
|
689
|
-
for (const branch of childrenOf(current, 'allOf'))
|
|
690
|
-
visit(branch);
|
|
691
|
-
};
|
|
692
|
-
visit(location);
|
|
693
|
-
return conjuncts;
|
|
694
|
-
}
|
|
695
|
-
function matches(location, pattern, name) {
|
|
696
|
-
return loadValueProgram(location.program).matcher(pattern).test(name);
|
|
697
|
-
}
|
|
698
|
-
/** Whether a schema asserts nothing. */
|
|
699
|
-
function isTop(schema) {
|
|
700
|
-
if (schema === true)
|
|
701
|
-
return true;
|
|
702
|
-
if (schema === false)
|
|
703
|
-
return false;
|
|
704
|
-
return Object.keys(schema).every((keyword) => INERT.has(keyword) ||
|
|
705
|
-
((keyword === 'then' || keyword === 'else') && !Object.hasOwn(schema, 'if')) ||
|
|
706
|
-
((keyword === 'minContains' || keyword === 'maxContains') &&
|
|
707
|
-
!Object.hasOwn(schema, 'contains')));
|
|
708
|
-
}
|
|
709
|
-
function assertionKeys(schema) {
|
|
710
|
-
return Object.keys(schema).filter((keyword) => !INERT.has(keyword) && !SUBSCHEMA_KEYWORDS.has(keyword) && keyword !== '$ref');
|
|
711
|
-
}
|
|
712
|
-
/** Subschema children keyed by their keyword path, without `$defs` or inert annotations. */
|
|
713
|
-
function subschemaChildren(location) {
|
|
714
|
-
const children = location.program.nodes[location.index]?.children ?? {};
|
|
715
|
-
return new Map(Object.entries(children).filter(([path]) => SUBSCHEMA_KEYWORDS.has(path.split('/', 1)[0].replaceAll('~1', '/').replaceAll('~0', '~'))));
|
|
716
|
-
}
|
|
717
|
-
function has(evidence, kinds) {
|
|
718
|
-
return (evidence.kinds & kinds) !== 0;
|
|
719
|
-
}
|
|
720
|
-
function typeMask(type) {
|
|
721
|
-
if (type === undefined)
|
|
722
|
-
return ANY;
|
|
723
|
-
const names = typeof type === 'string' ? [type] : Array.isArray(type) ? type : [];
|
|
724
|
-
return names.reduce((mask, name) => {
|
|
725
|
-
switch (name) {
|
|
726
|
-
case 'null':
|
|
727
|
-
return mask | NULL;
|
|
728
|
-
case 'boolean':
|
|
729
|
-
return mask | BOOLEAN;
|
|
730
|
-
case 'object':
|
|
731
|
-
return mask | OBJECT;
|
|
732
|
-
case 'array':
|
|
733
|
-
return mask | ARRAY;
|
|
734
|
-
case 'string':
|
|
735
|
-
return mask | STRING;
|
|
736
|
-
case 'integer':
|
|
737
|
-
return mask | INTEGER;
|
|
738
|
-
case 'number':
|
|
739
|
-
return mask | NUMBER;
|
|
740
|
-
default:
|
|
741
|
-
return mask;
|
|
742
|
-
}
|
|
743
|
-
}, 0);
|
|
744
|
-
}
|
|
745
|
-
function kindOf(value) {
|
|
746
|
-
if (value === null)
|
|
747
|
-
return NULL;
|
|
748
|
-
if (typeof value === 'boolean')
|
|
749
|
-
return BOOLEAN;
|
|
750
|
-
if (typeof value === 'string')
|
|
751
|
-
return STRING;
|
|
752
|
-
if (typeof value === 'number')
|
|
753
|
-
return Number.isInteger(value) ? INTEGER : FRACTION;
|
|
754
|
-
return Array.isArray(value) ? ARRAY : OBJECT;
|
|
755
|
-
}
|
|
756
|
-
/** The finite value set of a kind mask made only of null and booleans. */
|
|
757
|
-
function finiteKinds(kinds) {
|
|
758
|
-
if ((kinds & ~(NULL | BOOLEAN)) !== 0)
|
|
759
|
-
return undefined;
|
|
760
|
-
return [
|
|
761
|
-
...((kinds & NULL) !== 0 ? [null] : []),
|
|
762
|
-
...((kinds & BOOLEAN) !== 0 ? [true, false] : []),
|
|
763
|
-
];
|
|
764
|
-
}
|
|
765
|
-
function tighter(current, value, exclusive, stricter) {
|
|
766
|
-
if (typeof value !== 'number')
|
|
767
|
-
return current;
|
|
768
|
-
if (current === undefined ||
|
|
769
|
-
stricter(value, current.value) ||
|
|
770
|
-
(value === current.value && exclusive)) {
|
|
771
|
-
return { value, exclusive };
|
|
772
|
-
}
|
|
773
|
-
return current;
|
|
774
|
-
}
|
|
775
|
-
function min(current, value) {
|
|
776
|
-
return current === undefined ? value : Math.min(current, value);
|
|
777
83
|
}
|