@depup/typebox 1.3.27-depup.0 → 1.3.34-depup.0
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/README.md +2 -2
- package/build/compile/code.mjs +1 -2
- package/build/compile/validator.mjs +5 -1
- package/build/format/iri.mjs +16 -9
- package/build/guard/emit.mjs +2 -2
- package/build/guard/guard.d.mts +7 -5
- package/build/guard/guard.mjs +14 -9
- package/build/guard/index.mjs +6 -0
- package/build/guard/unicode/unicode.d.mts +6 -0
- package/build/guard/unicode/unicode.mjs +35 -0
- package/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
- package/build/schema/build.mjs +4 -5
- package/build/schema/check.mjs +1 -1
- package/build/schema/engine/_context.d.mts +5 -1
- package/build/schema/engine/_context.mjs +16 -3
- package/build/schema/engine/_functions.d.mts +2 -2
- package/build/schema/engine/_functions.mjs +1 -1
- package/build/schema/engine/_pathing.d.mts +1 -0
- package/build/schema/engine/_pathing.mjs +11 -0
- package/build/schema/engine/_reducer.d.mts +3 -3
- package/build/schema/engine/_refine.d.mts +5 -5
- package/build/schema/engine/_refine.mjs +14 -9
- package/build/schema/engine/_stack.d.mts +34 -20
- package/build/schema/engine/_stack.mjs +143 -202
- package/build/schema/engine/additionalItems.d.mts +4 -4
- package/build/schema/engine/additionalProperties.d.mts +8 -8
- package/build/schema/engine/additionalProperties.mjs +12 -15
- package/build/schema/engine/allOf.d.mts +4 -4
- package/build/schema/engine/allOf.mjs +1 -1
- package/build/schema/engine/anyOf.d.mts +4 -4
- package/build/schema/engine/anyOf.mjs +4 -9
- package/build/schema/engine/boolean.d.mts +4 -4
- package/build/schema/engine/boolean.mjs +2 -6
- package/build/schema/engine/const.d.mts +4 -4
- package/build/schema/engine/const.mjs +2 -6
- package/build/schema/engine/contains.d.mts +4 -4
- package/build/schema/engine/contains.mjs +2 -6
- package/build/schema/engine/dependencies.d.mts +4 -4
- package/build/schema/engine/dependencies.mjs +5 -7
- package/build/schema/engine/dependentRequired.d.mts +4 -4
- package/build/schema/engine/dependentRequired.mjs +2 -6
- package/build/schema/engine/dependentSchemas.d.mts +4 -4
- package/build/schema/engine/dependentSchemas.mjs +2 -1
- package/build/schema/engine/dynamicRef.d.mts +4 -4
- package/build/schema/engine/dynamicRef.mjs +12 -8
- package/build/schema/engine/enum.d.mts +4 -4
- package/build/schema/engine/enum.mjs +2 -6
- package/build/schema/engine/exclusiveMaximum.d.mts +4 -4
- package/build/schema/engine/exclusiveMaximum.mjs +2 -6
- package/build/schema/engine/exclusiveMinimum.d.mts +4 -4
- package/build/schema/engine/exclusiveMinimum.mjs +2 -6
- package/build/schema/engine/format.d.mts +4 -4
- package/build/schema/engine/format.mjs +11 -8
- package/build/schema/engine/if.d.mts +4 -4
- package/build/schema/engine/if.mjs +5 -13
- package/build/schema/engine/items.d.mts +4 -4
- package/build/schema/engine/items.mjs +1 -1
- package/build/schema/engine/maxContains.d.mts +4 -4
- package/build/schema/engine/maxContains.mjs +2 -6
- package/build/schema/engine/maxItems.d.mts +4 -4
- package/build/schema/engine/maxItems.mjs +2 -6
- package/build/schema/engine/maxLength.d.mts +4 -4
- package/build/schema/engine/maxLength.mjs +2 -6
- package/build/schema/engine/maxProperties.d.mts +4 -4
- package/build/schema/engine/maxProperties.mjs +2 -6
- package/build/schema/engine/maximum.d.mts +4 -4
- package/build/schema/engine/maximum.mjs +2 -6
- package/build/schema/engine/minContains.d.mts +4 -4
- package/build/schema/engine/minContains.mjs +2 -6
- package/build/schema/engine/minItems.d.mts +5 -5
- package/build/schema/engine/minItems.mjs +2 -6
- package/build/schema/engine/minLength.d.mts +4 -4
- package/build/schema/engine/minLength.mjs +2 -6
- package/build/schema/engine/minProperties.d.mts +4 -4
- package/build/schema/engine/minProperties.mjs +2 -6
- package/build/schema/engine/minimum.d.mts +4 -4
- package/build/schema/engine/minimum.mjs +2 -6
- package/build/schema/engine/multipleOf.d.mts +4 -4
- package/build/schema/engine/multipleOf.mjs +2 -6
- package/build/schema/engine/not.d.mts +4 -4
- package/build/schema/engine/not.mjs +4 -8
- package/build/schema/engine/oneOf.d.mts +4 -4
- package/build/schema/engine/oneOf.mjs +5 -10
- package/build/schema/engine/pattern.d.mts +4 -4
- package/build/schema/engine/pattern.mjs +3 -7
- package/build/schema/engine/patternProperties.d.mts +4 -4
- package/build/schema/engine/patternProperties.mjs +4 -3
- package/build/schema/engine/prefixItems.d.mts +4 -4
- package/build/schema/engine/prefixItems.mjs +1 -1
- package/build/schema/engine/properties.d.mts +4 -4
- package/build/schema/engine/properties.mjs +4 -3
- package/build/schema/engine/propertyNames.d.mts +4 -4
- package/build/schema/engine/propertyNames.mjs +5 -8
- package/build/schema/engine/recursiveRef.d.mts +4 -4
- package/build/schema/engine/recursiveRef.mjs +12 -8
- package/build/schema/engine/ref.d.mts +4 -4
- package/build/schema/engine/ref.mjs +18 -14
- package/build/schema/engine/required.d.mts +4 -4
- package/build/schema/engine/required.mjs +2 -6
- package/build/schema/engine/schema.d.mts +7 -7
- package/build/schema/engine/schema.mjs +136 -138
- package/build/schema/engine/type.d.mts +4 -4
- package/build/schema/engine/type.mjs +2 -6
- package/build/schema/engine/unevaluatedItems.d.mts +4 -4
- package/build/schema/engine/unevaluatedItems.mjs +3 -7
- package/build/schema/engine/unevaluatedProperties.d.mts +4 -4
- package/build/schema/engine/unevaluatedProperties.mjs +3 -7
- package/build/schema/engine/uniqueItems.d.mts +4 -4
- package/build/schema/engine/uniqueItems.mjs +2 -6
- package/build/schema/errors.mjs +1 -1
- package/build/schema/intern/intern.d.mts +6 -9
- package/build/schema/intern/intern.mjs +90 -56
- package/build/schema/meta/draft_2019_09.d.mts +2 -0
- package/build/schema/meta/draft_2019_09.mjs +288 -0
- package/build/schema/meta/draft_2020_12.d.mts +2 -0
- package/build/schema/meta/draft_2020_12.mjs +300 -0
- package/build/schema/meta/draft_3.d.mts +2 -0
- package/build/schema/meta/draft_3.mjs +143 -0
- package/build/schema/meta/draft_4.d.mts +2 -0
- package/build/schema/meta/draft_4.mjs +149 -0
- package/build/schema/meta/draft_6.d.mts +2 -0
- package/build/schema/meta/draft_6.mjs +155 -0
- package/build/schema/meta/draft_7.d.mts +2 -0
- package/build/schema/meta/draft_7.mjs +172 -0
- package/build/schema/meta/index.d.mts +2 -0
- package/build/schema/meta/index.mjs +2 -0
- package/build/schema/meta/meta.d.mts +9 -0
- package/build/schema/meta/meta.mjs +15 -0
- package/build/schema/meta/schema.d.mts +6 -0
- package/build/schema/meta/schema.mjs +1 -0
- package/build/schema/parse.mjs +3 -0
- package/build/schema/pointer/pointer.d.mts +1 -6
- package/build/schema/pointer/pointer.mjs +47 -64
- package/build/schema/resolve/resolve.d.mts +6 -32
- package/build/schema/resolve/resolve.mjs +231 -227
- package/build/schema/schema.d.mts +1 -0
- package/build/schema/schema.mjs +1 -0
- package/build/system/settings/internal.d.mts +2 -0
- package/build/system/settings/internal.mjs +20 -0
- package/build/system/settings/settings.d.mts +11 -0
- package/build/system/settings/settings.mjs +14 -0
- package/build/type/extends/inference.d.mts +1 -1
- package/build/type/extends/inference.mjs +15 -2
- package/build/type/extends/tuple.d.mts +2 -1
- package/build/type/extends/tuple.mjs +21 -1
- package/build/value/parse/parse.mjs +10 -4
- package/changes.json +1 -1
- package/package.json +3 -3
- package/readme.md +52 -84
- /package/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
|
@@ -1,49 +1,67 @@
|
|
|
1
|
-
// deno-fmt-ignore-file
|
|
2
1
|
import { Guard } from '../../guard/index.mjs';
|
|
3
2
|
import { Pointer } from '../pointer/index.mjs';
|
|
4
3
|
import * as Schema from '../types/index.mjs';
|
|
5
|
-
|
|
4
|
+
import * as Stack from '../engine/_stack.mjs';
|
|
6
5
|
// ------------------------------------------------------------------
|
|
7
|
-
//
|
|
6
|
+
// Helpers
|
|
7
|
+
//
|
|
8
|
+
// Utilities to compute schema base URIs, normalize absolute URLs,
|
|
9
|
+
// strip URL fragments for canonical hrefs, find target base URIs,
|
|
10
|
+
// resolve $ref root schemas, and identify JSON pointers vs anchors.
|
|
11
|
+
// ------------------------------------------------------------------
|
|
12
|
+
function RelativeBase(schema, base) {
|
|
13
|
+
return Schema.IsSchemaObject(schema) && Schema.IsId(schema) ? Stack.NextUri(schema.$id, base.href) : base;
|
|
14
|
+
}
|
|
15
|
+
function AbsoluteBase(base) {
|
|
16
|
+
return Stack.NextUri(base, Stack.DefaultUri);
|
|
17
|
+
}
|
|
18
|
+
function CanonicalHref(url) {
|
|
19
|
+
return url.href.split('#')[0];
|
|
20
|
+
}
|
|
21
|
+
function Base(schema, base, target) {
|
|
22
|
+
return SearchBase(schema, AbsoluteBase(base), target);
|
|
23
|
+
}
|
|
24
|
+
function RefRoot(stack, ref) {
|
|
25
|
+
return (ref.$ref.startsWith('#') || stack.enteredResource) ? stack.lexicalSchema : stack.schema;
|
|
26
|
+
}
|
|
27
|
+
function IsPointerFragment(fragment) {
|
|
28
|
+
return fragment.startsWith('#/');
|
|
29
|
+
}
|
|
30
|
+
// ------------------------------------------------------------------
|
|
31
|
+
// Search
|
|
32
|
+
//
|
|
33
|
+
// Recursive tree walks that locate things by identity, not URL.
|
|
34
|
+
// SearchDynamicAnchor finds a node with a matching $dynamicAnchor.
|
|
35
|
+
// SearchBase finds a specific target schema (by reference) and
|
|
36
|
+
// returns its base URI, tracking $id rebasing as it descends.
|
|
8
37
|
// ------------------------------------------------------------------
|
|
9
|
-
function
|
|
38
|
+
function SearchDynamicAnchor(schema, name) {
|
|
10
39
|
if (Guard.IsObject(schema) && Schema.IsDynamicAnchor(schema) && Guard.IsEqual(schema.$dynamicAnchor, name)) {
|
|
11
40
|
return schema;
|
|
12
41
|
}
|
|
13
42
|
if (Guard.IsObject(schema)) {
|
|
14
43
|
for (const key of Guard.Keys(schema)) {
|
|
15
|
-
const result =
|
|
44
|
+
const result = SearchDynamicAnchor(schema[key], name);
|
|
16
45
|
if (result)
|
|
17
46
|
return result;
|
|
18
47
|
}
|
|
19
48
|
}
|
|
20
|
-
// (no-coverage) - is it even possible to search for an anchor
|
|
21
|
-
// with embedded logical schema like allOf, anyOf, etc?
|
|
22
|
-
// if (Guard.IsArray(schema)) { // (no-coverage)
|
|
23
|
-
// for (const item of schema) {
|
|
24
|
-
// const result = FindDynamicAnchor(item, name)
|
|
25
|
-
// if (result) return result
|
|
26
|
-
// }
|
|
27
|
-
// }
|
|
28
49
|
return undefined;
|
|
29
50
|
}
|
|
30
|
-
|
|
31
|
-
// Find: FindBase
|
|
32
|
-
// ------------------------------------------------------------------
|
|
33
|
-
function FindBase(schema, base, target) {
|
|
51
|
+
function SearchBase(schema, base, target) {
|
|
34
52
|
if (Guard.IsEqual(schema, target))
|
|
35
53
|
return base.href;
|
|
36
|
-
const nextBase =
|
|
54
|
+
const nextBase = RelativeBase(schema, base);
|
|
37
55
|
if (Guard.IsArray(schema)) {
|
|
38
56
|
for (const item of schema) {
|
|
39
|
-
const result =
|
|
57
|
+
const result = SearchBase(item, nextBase, target);
|
|
40
58
|
if (!Guard.IsUndefined(result))
|
|
41
59
|
return result;
|
|
42
60
|
}
|
|
43
61
|
}
|
|
44
62
|
else if (Guard.IsObject(schema)) {
|
|
45
63
|
for (const key of Guard.Keys(schema)) {
|
|
46
|
-
const result =
|
|
64
|
+
const result = SearchBase(schema[key], nextBase, target);
|
|
47
65
|
if (!Guard.IsUndefined(result))
|
|
48
66
|
return result;
|
|
49
67
|
}
|
|
@@ -51,277 +69,263 @@ function FindBase(schema, base, target) {
|
|
|
51
69
|
return undefined;
|
|
52
70
|
}
|
|
53
71
|
// ------------------------------------------------------------------
|
|
54
|
-
// Match
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
72
|
+
// Match
|
|
73
|
+
//
|
|
74
|
+
// Tests whether a schema node is what a reference URL points to.
|
|
75
|
+
// MatchSchemaObject checks a single node in order: $id, $anchor,
|
|
76
|
+
// $dynamicAnchor, then JSON pointer/hash. MatchFromArray,
|
|
77
|
+
// MatchFromObject, and Match recurse through the tree to try every
|
|
78
|
+
// node, skipping const and enum since their values are user data,
|
|
79
|
+
// not schema.
|
|
80
|
+
// ------------------------------------------------------------------
|
|
81
|
+
function MatchWithHash(schema, ref) {
|
|
82
|
+
if (ref.href.endsWith('#'))
|
|
83
|
+
return schema;
|
|
84
|
+
if (!ref.hash.startsWith('#'))
|
|
85
|
+
return undefined;
|
|
86
|
+
const fragment = decodeURIComponent(ref.hash.slice(1));
|
|
87
|
+
if (!fragment.startsWith('/'))
|
|
88
|
+
return undefined;
|
|
89
|
+
return Pointer.Get(schema, fragment);
|
|
90
|
+
}
|
|
91
|
+
function MatchWithId(schema, base, ref) {
|
|
92
|
+
if (!Schema.IsId(schema))
|
|
93
|
+
return undefined;
|
|
58
94
|
if (Guard.IsEqual(schema.$id, ref.hash))
|
|
59
95
|
return schema;
|
|
60
96
|
const absoluteRef = new URL(ref.href, base.href);
|
|
61
|
-
// ref shares this $id's document, so resolve the fragment within it
|
|
62
97
|
if (Guard.IsEqual(base.pathname, absoluteRef.pathname))
|
|
63
|
-
return ref.hash.startsWith('#') ?
|
|
98
|
+
return ref.hash.startsWith('#') ? MatchWithHash(schema, ref) : schema;
|
|
64
99
|
return undefined;
|
|
65
100
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
function MatchAnchor(schema, base, ref) {
|
|
101
|
+
function MatchWithAnchor(schema, base, ref) {
|
|
102
|
+
if (!Schema.IsAnchor(schema))
|
|
103
|
+
return undefined;
|
|
70
104
|
const absoluteAnchor = new URL(`#${schema.$anchor}`, base.href);
|
|
71
105
|
const absoluteRef = new URL(ref.href, base.href);
|
|
72
106
|
return Guard.IsEqual(absoluteAnchor.href, absoluteRef.href) ? schema : undefined;
|
|
73
107
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
function MatchDynamicAnchor(schema, base, ref) {
|
|
108
|
+
function MatchWithDynamicAnchor(schema, base, ref) {
|
|
109
|
+
if (!Schema.IsDynamicAnchor(schema))
|
|
110
|
+
return undefined;
|
|
78
111
|
const absoluteAnchor = new URL(`#${schema.$dynamicAnchor}`, base.href);
|
|
79
112
|
const absoluteRef = new URL(ref.href, base.href);
|
|
80
113
|
const isMatch = Guard.IsEqual(absoluteAnchor.href, absoluteRef.href);
|
|
81
114
|
return isMatch ? schema : undefined;
|
|
82
115
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
// ------------------------------------------------------------------
|
|
86
|
-
function MatchHash(schema, ref) {
|
|
87
|
-
if (ref.href.endsWith('#'))
|
|
88
|
-
return schema;
|
|
89
|
-
if (!ref.hash.startsWith('#'))
|
|
90
|
-
return undefined;
|
|
91
|
-
const fragment = decodeURIComponent(ref.hash.slice(1));
|
|
92
|
-
if (!fragment.startsWith('/'))
|
|
116
|
+
function MatchSchemaObject(schema, base, ref) {
|
|
117
|
+
if (!Schema.IsSchemaObject(schema))
|
|
93
118
|
return undefined;
|
|
94
|
-
|
|
95
|
-
|
|
119
|
+
return MatchWithId(schema, base, ref) ??
|
|
120
|
+
MatchWithAnchor(schema, base, ref) ??
|
|
121
|
+
MatchWithDynamicAnchor(schema, base, ref) ??
|
|
122
|
+
MatchWithHash(schema, ref);
|
|
96
123
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
function Match(schema, base, ref) {
|
|
101
|
-
if (Schema.IsId(schema)) {
|
|
102
|
-
const result = MatchId(schema, base, ref);
|
|
103
|
-
if (!Guard.IsUndefined(result))
|
|
104
|
-
return result;
|
|
105
|
-
}
|
|
106
|
-
if (Schema.IsAnchor(schema)) {
|
|
107
|
-
const result = MatchAnchor(schema, base, ref);
|
|
108
|
-
if (!Guard.IsUndefined(result))
|
|
109
|
-
return result;
|
|
110
|
-
}
|
|
111
|
-
if (Schema.IsDynamicAnchor(schema)) {
|
|
112
|
-
const result = MatchDynamicAnchor(schema, base, ref);
|
|
113
|
-
if (!Guard.IsUndefined(result))
|
|
114
|
-
return result;
|
|
115
|
-
}
|
|
116
|
-
return MatchHash(schema, ref);
|
|
117
|
-
}
|
|
118
|
-
// ------------------------------------------------------------------
|
|
119
|
-
// FromArray
|
|
120
|
-
// ------------------------------------------------------------------
|
|
121
|
-
function FromArray(schema, base, ref) {
|
|
124
|
+
function MatchFromArray(schema, base, ref) {
|
|
125
|
+
if (!Guard.IsArray(schema))
|
|
126
|
+
return undefined;
|
|
122
127
|
return schema.reduce((result, item) => {
|
|
123
|
-
const match =
|
|
128
|
+
const match = Match(item, base, ref);
|
|
124
129
|
return !Guard.IsUndefined(match) ? match : result;
|
|
125
130
|
}, undefined);
|
|
126
131
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
function SkipProperty(key) {
|
|
131
|
-
return Guard.IsEqual(key, 'const') || Guard.IsEqual(key, 'enum');
|
|
132
|
-
}
|
|
133
|
-
function FromObject(schema, base, ref) {
|
|
132
|
+
function MatchFromObject(schema, base, ref) {
|
|
133
|
+
if (!Guard.IsObject(schema))
|
|
134
|
+
return undefined;
|
|
134
135
|
return Guard.Keys(schema).reduce((result, key) => {
|
|
135
|
-
if (
|
|
136
|
+
if (Guard.IsEqual(key, 'const') || Guard.IsEqual(key, 'enum'))
|
|
136
137
|
return result;
|
|
137
|
-
const match =
|
|
138
|
+
const match = Match(schema[key], base, ref);
|
|
138
139
|
return !Guard.IsUndefined(match) ? match : result;
|
|
139
140
|
}, undefined);
|
|
140
141
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (Schema.IsSchemaObject(schema)) {
|
|
147
|
-
const result = Match(schema, nextBase, ref);
|
|
148
|
-
if (!Guard.IsUndefined(result))
|
|
149
|
-
return result;
|
|
150
|
-
}
|
|
151
|
-
if (Guard.IsArray(schema))
|
|
152
|
-
return FromArray(schema, nextBase, ref);
|
|
153
|
-
if (Guard.IsObject(schema))
|
|
154
|
-
return FromObject(schema, nextBase, ref);
|
|
155
|
-
return undefined;
|
|
156
|
-
}
|
|
157
|
-
// ------------------------------------------------------------------
|
|
158
|
-
// Base
|
|
159
|
-
// ------------------------------------------------------------------
|
|
160
|
-
export function Base(schema, base, target) {
|
|
161
|
-
return FindBase(schema, new URL(base || '.', DefaultBase), target);
|
|
142
|
+
function Match(schema, base, ref) {
|
|
143
|
+
const relativeBase = RelativeBase(schema, base);
|
|
144
|
+
return MatchSchemaObject(schema, relativeBase, ref) ??
|
|
145
|
+
MatchFromArray(schema, relativeBase, ref) ??
|
|
146
|
+
MatchFromObject(schema, relativeBase, ref);
|
|
162
147
|
}
|
|
163
148
|
// ------------------------------------------------------------------
|
|
164
149
|
// Resource
|
|
150
|
+
//
|
|
151
|
+
// Wraps RefInternal to check whether the resolved schema is itself
|
|
152
|
+
// a resource root (carries its own $id). Used by FindResolvedResource
|
|
153
|
+
// to tell a boundary hit from a landing inside a resource.
|
|
165
154
|
// ------------------------------------------------------------------
|
|
166
|
-
|
|
167
|
-
const result =
|
|
155
|
+
function Resource(context, schema, base, ref) {
|
|
156
|
+
const result = RefInternal(context, schema, base, ref);
|
|
168
157
|
return Schema.IsSchemaObject(result) && Schema.IsId(result) ? result : undefined;
|
|
169
158
|
}
|
|
170
159
|
// ------------------------------------------------------------------
|
|
171
|
-
//
|
|
172
|
-
// ------------------------------------------------------------------
|
|
173
|
-
function CanonicalHref(url) {
|
|
174
|
-
return url.href.split('#')[0];
|
|
175
|
-
}
|
|
176
|
-
// ------------------------------------------------------------------
|
|
177
|
-
// Ref: RefRemote (Phase 1)
|
|
178
|
-
// ------------------------------------------------------------------
|
|
179
|
-
function RefContext(context, ref) {
|
|
180
|
-
return Guard.HasPropertyKey(context, ref) ? context[ref] : undefined;
|
|
181
|
-
}
|
|
182
|
-
// ------------------------------------------------------------------
|
|
183
|
-
// Ref: RefRemote (Phase 2)
|
|
184
|
-
// ------------------------------------------------------------------
|
|
185
|
-
function RefLocal(schema, base, ref) {
|
|
186
|
-
return FromValue(schema, base, ref);
|
|
187
|
-
}
|
|
188
|
-
// ------------------------------------------------------------------
|
|
189
|
-
// Ref: RefRemote (Phase 3)
|
|
190
|
-
// ------------------------------------------------------------------
|
|
191
|
-
function RefRemote(context, base, ref) {
|
|
192
|
-
const canonicalHref = CanonicalHref(ref);
|
|
193
|
-
if (Guard.IsEqual(canonicalHref, CanonicalHref(base)))
|
|
194
|
-
return undefined;
|
|
195
|
-
if (!Guard.HasPropertyKey(context, canonicalHref))
|
|
196
|
-
return undefined;
|
|
197
|
-
const remoteSchema = context[canonicalHref];
|
|
198
|
-
const remoteBase = (Schema.IsSchemaObject(remoteSchema) && Schema.IsId(remoteSchema)) ? new URL(remoteSchema.$id, canonicalHref) : new URL(canonicalHref);
|
|
199
|
-
const result = Guard.IsEqual(ref.hash, '') ? remoteSchema : FromValue(remoteSchema, remoteBase, ref);
|
|
200
|
-
return result;
|
|
201
|
-
}
|
|
202
|
-
// ------------------------------------------------------------------
|
|
203
|
-
// RetrievedResource: LegacyRetrievedResource
|
|
160
|
+
// FindDeferredResource
|
|
204
161
|
//
|
|
205
|
-
// Draft-4
|
|
206
|
-
// in-place base
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
// resolution is computed against the right base.
|
|
162
|
+
// Legacy Draft-4 schemas (no $schema keyword) treat a nested $id as
|
|
163
|
+
// an in-place base change, not a new resource. A local ('#...') ref
|
|
164
|
+
// landing at a different base than the current one needs a stack
|
|
165
|
+
// entry so later lookups use the right base.
|
|
210
166
|
// ------------------------------------------------------------------
|
|
211
|
-
function
|
|
167
|
+
function FindDeferredResourceLegacy(stack, ref, schema) {
|
|
212
168
|
if (!ref.$ref.startsWith('#'))
|
|
213
169
|
return undefined;
|
|
214
|
-
if (Guard.HasPropertyKey(
|
|
170
|
+
if (!Schema.IsSchemaObject(stack.schema) || Guard.HasPropertyKey(stack.schema, '$schema'))
|
|
215
171
|
return undefined;
|
|
216
|
-
const targetBase = Base(lexicalSchema, referenceBase, schema);
|
|
217
|
-
if (Guard.IsUndefined(targetBase) || Guard.IsEqual(targetBase, referenceBase))
|
|
172
|
+
const targetBase = Base(stack.lexicalSchema, stack.referenceBase, schema);
|
|
173
|
+
if (Guard.IsUndefined(targetBase) || Guard.IsEqual(targetBase, stack.referenceBase))
|
|
218
174
|
return undefined;
|
|
219
|
-
return { target: schema, base: targetBase, root: lexicalSchema };
|
|
175
|
+
return { target: schema, base: targetBase, root: /* safe-object-root */ stack.lexicalSchema };
|
|
220
176
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
//
|
|
224
|
-
// The ref's canonical URL names a document already loaded into
|
|
225
|
-
// context. That document becomes the frame's root going forward.
|
|
226
|
-
// ------------------------------------------------------------------
|
|
227
|
-
function RemoteRetrievedResource(context, canonical, schema) {
|
|
228
|
-
const remoteRoot = context[canonical];
|
|
177
|
+
function FindDeferredResourceModern(stack, canonical, schema) {
|
|
178
|
+
const remoteRoot = stack.context[canonical];
|
|
229
179
|
if (!Schema.IsSchemaObject(remoteRoot))
|
|
230
180
|
return undefined;
|
|
231
181
|
return { target: schema, base: canonical, root: remoteRoot };
|
|
232
182
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
// A genuinely remote document frame always wins over a same-document
|
|
237
|
-
// legacy one: only one frame is ever entered per ref.
|
|
238
|
-
// ------------------------------------------------------------------
|
|
239
|
-
function FindRetrievedResource(stackframe, ref, schema, canonical, isRemote) {
|
|
240
|
-
const remote = isRemote ? RemoteRetrievedResource(stackframe.context, canonical, schema) : undefined;
|
|
241
|
-
if (!Guard.IsUndefined(remote))
|
|
242
|
-
return remote;
|
|
243
|
-
return LegacyRetrievedResource(stackframe.root, stackframe.lexicalSchema, stackframe.referenceBase, ref, schema);
|
|
183
|
+
function FindDeferredResource(stack, ref, schema, canonical, isRemote) {
|
|
184
|
+
const remote = isRemote ? FindDeferredResourceModern(stack, canonical, schema) : undefined;
|
|
185
|
+
return Guard.IsUndefined(remote) ? FindDeferredResourceLegacy(stack, ref, schema) : remote;
|
|
244
186
|
}
|
|
245
187
|
// ------------------------------------------------------------------
|
|
246
|
-
//
|
|
188
|
+
// FindResolvedResource
|
|
247
189
|
//
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
// had walked in from its top.
|
|
190
|
+
// Handles a ref that crossed into a different resource but landed
|
|
191
|
+
// on a schema without that resource's $id (e.g. a pointer into the
|
|
192
|
+
// middle of a remote document). Enters the enclosing resource so
|
|
193
|
+
// lexical/base lookups behave as if traversal walked in from its top.
|
|
253
194
|
// ------------------------------------------------------------------
|
|
254
|
-
function FindResolvedResource(
|
|
195
|
+
function FindResolvedResource(stack, canonical, schema) {
|
|
255
196
|
if (Schema.IsId(schema))
|
|
256
197
|
return undefined;
|
|
257
|
-
const resource = Resource(context, root, referenceBase, canonical);
|
|
258
|
-
if (!resource || ids.includes(resource))
|
|
198
|
+
const resource = Resource(stack.context, /* safe-object-root */ stack.schema, stack.referenceBase, canonical);
|
|
199
|
+
if (!resource || stack.ids.includes(resource))
|
|
259
200
|
return undefined;
|
|
260
|
-
return {
|
|
201
|
+
return { resource };
|
|
261
202
|
}
|
|
262
203
|
// ------------------------------------------------------------------
|
|
263
|
-
//
|
|
204
|
+
// RefInternal
|
|
205
|
+
//
|
|
206
|
+
// Shared lookup used by Ref, RecursiveRef, and DynamicRef. Tries,
|
|
207
|
+
// in order: exact match in the pre-registered context, then a local
|
|
208
|
+
// search within the given schema, then a search in a remote
|
|
209
|
+
// document. Returns just the schema; caller-specific bookkeeping
|
|
210
|
+
// (deferred/resolved resources) happens one level up.
|
|
264
211
|
// ------------------------------------------------------------------
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const resolvedBase = applySchemaId && Schema.IsId(schema) ? new URL(schema.$id, initialBase) : initialBase;
|
|
268
|
-
const initialRef = new URL(ref, resolvedBase.href);
|
|
269
|
-
return RefContext(remotes, ref) ?? RefLocal(schema, resolvedBase, initialRef) ?? RefRemote(remotes, resolvedBase, initialRef);
|
|
212
|
+
function RefInternalWithContext(context, ref) {
|
|
213
|
+
return Guard.HasPropertyKey(context, ref) ? context[ref] : undefined;
|
|
270
214
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
const fragmentTarget = Ref(context, fragmentRoot, base, dynamicRef.$dynamicRef, false);
|
|
278
|
-
if (Guard.IsUndefined(fragmentTarget)) {
|
|
279
|
-
const fragment = new URL(dynamicRef.$dynamicRef, initialBase).hash;
|
|
280
|
-
if (!fragment.startsWith('#/') && fragment.startsWith('#')) {
|
|
281
|
-
const name = decodeURIComponent(fragment.slice(1));
|
|
282
|
-
const anchorTarget = dynamicAnchors.find((anchor) => Guard.IsEqual(anchor.$dynamicAnchor, name)) ?? FindDynamicAnchor(root, name);
|
|
283
|
-
return anchorTarget;
|
|
284
|
-
}
|
|
215
|
+
function RefInternalWithLocal(schema, base, ref) {
|
|
216
|
+
return Match(schema, base, ref);
|
|
217
|
+
}
|
|
218
|
+
function RefInternalWithRemote(context, base, ref) {
|
|
219
|
+
const canonicalHref = CanonicalHref(ref);
|
|
220
|
+
if (!Guard.HasPropertyKey(context, canonicalHref) || Guard.IsEqual(canonicalHref, CanonicalHref(base)))
|
|
285
221
|
return undefined;
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
const
|
|
293
|
-
return
|
|
222
|
+
const remoteSchema = context[canonicalHref];
|
|
223
|
+
const remoteBase = RelativeBase(remoteSchema, new URL(canonicalHref));
|
|
224
|
+
return Guard.IsEqual(ref.hash, '') ? remoteSchema : Match(remoteSchema, remoteBase, ref);
|
|
225
|
+
}
|
|
226
|
+
function RefInternal(context, schema, base, ref) {
|
|
227
|
+
const absoluteBase = AbsoluteBase(base);
|
|
228
|
+
const target = Stack.NextUri(ref, absoluteBase.href);
|
|
229
|
+
return RefInternalWithContext(context, ref) ??
|
|
230
|
+
RefInternalWithLocal(schema, absoluteBase, target) ??
|
|
231
|
+
RefInternalWithRemote(context, absoluteBase, target);
|
|
294
232
|
}
|
|
295
233
|
// ------------------------------------------------------------------
|
|
296
|
-
//
|
|
234
|
+
// RefNextStack
|
|
297
235
|
//
|
|
298
|
-
//
|
|
299
|
-
//
|
|
300
|
-
//
|
|
301
|
-
//
|
|
236
|
+
// Computes the next stack state from any deferred or resolved
|
|
237
|
+
// resource found while following a $ref, carrying existing stack
|
|
238
|
+
// state forward rather than rebuilding it.
|
|
239
|
+
// ------------------------------------------------------------------
|
|
240
|
+
function RefNextStackDeferred(stack, deferredResource) {
|
|
241
|
+
if (!deferredResource)
|
|
242
|
+
return stack;
|
|
243
|
+
const resourceEntries = new Map(stack.resourceEntries);
|
|
244
|
+
resourceEntries.set(deferredResource.target, { base: deferredResource.base, root: deferredResource.root });
|
|
245
|
+
return { ...stack, resourceEntries };
|
|
246
|
+
}
|
|
247
|
+
function RefNextStackResolved(stack, resolvedResource) {
|
|
248
|
+
return resolvedResource ? Stack.NextStack(stack, resolvedResource.resource) : stack;
|
|
249
|
+
}
|
|
250
|
+
function RefNextStack(stack, pendingResource, deferredResource, resolvedResource) {
|
|
251
|
+
const withDeferred = RefNextStackDeferred({ ...stack, pendingResource }, deferredResource);
|
|
252
|
+
const withResolved = RefNextStackResolved(withDeferred, resolvedResource);
|
|
253
|
+
return withResolved;
|
|
254
|
+
}
|
|
302
255
|
// ------------------------------------------------------------------
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const
|
|
313
|
-
|
|
256
|
+
// RefResult
|
|
257
|
+
//
|
|
258
|
+
// Builds the final XRefResult. RefResultFound gets the canonical
|
|
259
|
+
// URL, checks if it's remote from the current resource, and looks
|
|
260
|
+
// for a deferred or resolved resource crossing accordingly.
|
|
261
|
+
// RefResultNotFound just advances pendingResource if a schema was
|
|
262
|
+
// found without crossing into a resource.
|
|
263
|
+
// ------------------------------------------------------------------
|
|
264
|
+
function RefResultFound(stack, ref, schema) {
|
|
265
|
+
const canonical = CanonicalHref(Stack.NextUri(ref.$ref, stack.referenceBase));
|
|
266
|
+
const isRemote = !Guard.IsEqual(canonical, stack.resourceBase);
|
|
267
|
+
const deferredResource = FindDeferredResource(stack, ref, schema, canonical, isRemote);
|
|
268
|
+
const resolvedResource = isRemote ? FindResolvedResource(stack, canonical, schema) : undefined;
|
|
269
|
+
return { schema, stack: RefNextStack(stack, true, deferredResource, resolvedResource) };
|
|
270
|
+
}
|
|
271
|
+
function RefResultNotFound(stack, schema) {
|
|
272
|
+
return { schema, stack: RefNextStack(stack, !Guard.IsUndefined(schema)) };
|
|
314
273
|
}
|
|
315
274
|
// ------------------------------------------------------------------
|
|
316
|
-
//
|
|
275
|
+
// Ref
|
|
276
|
+
//
|
|
277
|
+
// Picks the root to resolve against, and returns a XRefResult
|
|
278
|
+
// containing the resolved schema and the next stack state for
|
|
279
|
+
// subsequent evaluation.
|
|
317
280
|
// ------------------------------------------------------------------
|
|
318
|
-
export function
|
|
319
|
-
const
|
|
320
|
-
return
|
|
281
|
+
export function Ref(stack, ref) {
|
|
282
|
+
const schema = RefInternal(stack.context, RefRoot(stack, ref), stack.referenceBase, ref.$ref);
|
|
283
|
+
return Schema.IsSchemaObject(schema) ? RefResultFound(stack, ref, schema) : RefResultNotFound(stack, schema);
|
|
321
284
|
}
|
|
322
285
|
// ------------------------------------------------------------------
|
|
323
|
-
//
|
|
286
|
+
// RecursiveRef: Draft 2019-09
|
|
287
|
+
//
|
|
288
|
+
// If a $recursiveAnchor is active in scope, it's used as the root
|
|
289
|
+
// instead of the lexical schema, letting the ref bind to the
|
|
290
|
+
// outermost applicable schema rather than the innermost.
|
|
291
|
+
// ------------------------------------------------------------------
|
|
292
|
+
function IsRecursiveAnchorInScope(stack) {
|
|
293
|
+
return Schema.IsSchemaObject(stack.lexicalSchema) && Schema.IsRecursiveAnchorTrue(stack.lexicalSchema);
|
|
294
|
+
}
|
|
295
|
+
export function RecursiveRef(stack, recursiveRef) {
|
|
296
|
+
const schema = IsRecursiveAnchorInScope(stack) ? stack.recursiveAnchor : stack.lexicalSchema;
|
|
297
|
+
return RefInternal(stack.context, schema, stack.lexicalBase, recursiveRef.$recursiveRef);
|
|
298
|
+
}
|
|
324
299
|
// ------------------------------------------------------------------
|
|
325
|
-
|
|
326
|
-
|
|
300
|
+
// DynamicRef: Draft 2020-12
|
|
301
|
+
//
|
|
302
|
+
// FindScopedDynamicAnchor checks anchors tracked on the stack first,
|
|
303
|
+
// then falls back to a full tree search. If RefInternal finds a target
|
|
304
|
+
// directly, DynamicRefWhenFound only continues the scoped search when
|
|
305
|
+
// that target itself has a $dynamicAnchor. If RefInternal finds nothing,
|
|
306
|
+
// DynamicRefWhenNotFound goes straight to a scoped anchor search
|
|
307
|
+
// by name.
|
|
308
|
+
// ------------------------------------------------------------------
|
|
309
|
+
function DynamicRefFragment(stack, dynamicRef) {
|
|
310
|
+
return Stack.NextUri(dynamicRef.$dynamicRef, AbsoluteBase(stack.lexicalBase).href).hash;
|
|
311
|
+
}
|
|
312
|
+
function FindScopedDynamicAnchor(stack, name) {
|
|
313
|
+
return stack.dynamicAnchors.find((anchor) => Guard.IsEqual(anchor.$dynamicAnchor, name)) ?? SearchDynamicAnchor(stack.schema, name);
|
|
314
|
+
}
|
|
315
|
+
function DynamicRefWhenFound(stack, dynamicRef, fragmentTarget) {
|
|
316
|
+
if (!Schema.IsSchemaObject(fragmentTarget) || !Schema.IsDynamicAnchor(fragmentTarget))
|
|
317
|
+
return fragmentTarget;
|
|
318
|
+
const fragment = DynamicRefFragment(stack, dynamicRef);
|
|
319
|
+
return IsPointerFragment(fragment) ? fragmentTarget : FindScopedDynamicAnchor(stack, fragmentTarget.$dynamicAnchor);
|
|
320
|
+
}
|
|
321
|
+
function DynamicRefWhenNotFound(stack, dynamicRef) {
|
|
322
|
+
const fragment = DynamicRefFragment(stack, dynamicRef);
|
|
323
|
+
// (review): We never observe this condition, but should be able to reach here in coverage.
|
|
324
|
+
// if (IsPointerFragment(fragment) || !fragment.startsWith('#')) return undefined
|
|
325
|
+
return FindScopedDynamicAnchor(stack, decodeURIComponent(fragment.slice(1)));
|
|
326
|
+
}
|
|
327
|
+
export function DynamicRef(stack, dynamicRef) {
|
|
328
|
+
const fragmentRoot = dynamicRef.$dynamicRef.startsWith('#') ? stack.lexicalSchema : stack.schema;
|
|
329
|
+
const fragmentTarget = RefInternal(stack.context, fragmentRoot, stack.lexicalBase, dynamicRef.$dynamicRef);
|
|
330
|
+
return Guard.IsUndefined(fragmentTarget) ? DynamicRefWhenNotFound(stack, dynamicRef) : DynamicRefWhenFound(stack, dynamicRef, fragmentTarget);
|
|
327
331
|
}
|
package/build/schema/schema.mjs
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Get } from './settings.mjs';
|
|
2
|
+
// ------------------------------------------------------------------
|
|
3
|
+
// TempMaxErrors
|
|
4
|
+
// ------------------------------------------------------------------
|
|
5
|
+
let TempMaxErrors = 0;
|
|
6
|
+
// ------------------------------------------------------------------
|
|
7
|
+
// [Internal] EnableParseErrors
|
|
8
|
+
// ------------------------------------------------------------------
|
|
9
|
+
export function EnableParseErrors() {
|
|
10
|
+
const settings = Get();
|
|
11
|
+
TempMaxErrors = settings.maxErrors;
|
|
12
|
+
settings.maxErrors = settings.maxParseErrors;
|
|
13
|
+
}
|
|
14
|
+
// ------------------------------------------------------------------
|
|
15
|
+
// [Internal] DisableParseErrors
|
|
16
|
+
// ------------------------------------------------------------------
|
|
17
|
+
export function DisableParseErrors() {
|
|
18
|
+
const settings = Get();
|
|
19
|
+
settings.maxErrors = TempMaxErrors;
|
|
20
|
+
}
|
|
@@ -16,6 +16,17 @@ export interface TSettings {
|
|
|
16
16
|
* @default 8
|
|
17
17
|
*/
|
|
18
18
|
maxErrors: number;
|
|
19
|
+
/**
|
|
20
|
+
* Specifies the maximum number of errors to gather for failed Parse operations. TypeBox will
|
|
21
|
+
* automatically run an error-gathering pass on failed Parses to attach diagnostics to the
|
|
22
|
+
* thrown exception. This setting controls the number of errors gathered in that pass. Higher
|
|
23
|
+
* values will reduce throughput on failure cases, so a maximum of 4 is recommended if more
|
|
24
|
+
* errors are needed. The default setting of 1 will terminate on the first error, while a
|
|
25
|
+
* setting of 0 will skip error gathering entirely.
|
|
26
|
+
*
|
|
27
|
+
* @default 1
|
|
28
|
+
*/
|
|
29
|
+
maxParseErrors: number;
|
|
19
30
|
/**
|
|
20
31
|
* Specifies the maximum number of instantiations allowed within a top-level generic instantiation
|
|
21
32
|
* context. This setting can be used to bound generic calls to a fixed count, which can be useful if
|