@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.
Files changed (150) hide show
  1. package/README.md +2 -2
  2. package/build/compile/code.mjs +1 -2
  3. package/build/compile/validator.mjs +5 -1
  4. package/build/format/iri.mjs +16 -9
  5. package/build/guard/emit.mjs +2 -2
  6. package/build/guard/guard.d.mts +7 -5
  7. package/build/guard/guard.mjs +14 -9
  8. package/build/guard/index.mjs +6 -0
  9. package/build/guard/unicode/unicode.d.mts +6 -0
  10. package/build/guard/unicode/unicode.mjs +35 -0
  11. package/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
  12. package/build/schema/build.mjs +4 -5
  13. package/build/schema/check.mjs +1 -1
  14. package/build/schema/engine/_context.d.mts +5 -1
  15. package/build/schema/engine/_context.mjs +16 -3
  16. package/build/schema/engine/_functions.d.mts +2 -2
  17. package/build/schema/engine/_functions.mjs +1 -1
  18. package/build/schema/engine/_pathing.d.mts +1 -0
  19. package/build/schema/engine/_pathing.mjs +11 -0
  20. package/build/schema/engine/_reducer.d.mts +3 -3
  21. package/build/schema/engine/_refine.d.mts +5 -5
  22. package/build/schema/engine/_refine.mjs +14 -9
  23. package/build/schema/engine/_stack.d.mts +34 -20
  24. package/build/schema/engine/_stack.mjs +143 -202
  25. package/build/schema/engine/additionalItems.d.mts +4 -4
  26. package/build/schema/engine/additionalProperties.d.mts +8 -8
  27. package/build/schema/engine/additionalProperties.mjs +12 -15
  28. package/build/schema/engine/allOf.d.mts +4 -4
  29. package/build/schema/engine/allOf.mjs +1 -1
  30. package/build/schema/engine/anyOf.d.mts +4 -4
  31. package/build/schema/engine/anyOf.mjs +4 -9
  32. package/build/schema/engine/boolean.d.mts +4 -4
  33. package/build/schema/engine/boolean.mjs +2 -6
  34. package/build/schema/engine/const.d.mts +4 -4
  35. package/build/schema/engine/const.mjs +2 -6
  36. package/build/schema/engine/contains.d.mts +4 -4
  37. package/build/schema/engine/contains.mjs +2 -6
  38. package/build/schema/engine/dependencies.d.mts +4 -4
  39. package/build/schema/engine/dependencies.mjs +5 -7
  40. package/build/schema/engine/dependentRequired.d.mts +4 -4
  41. package/build/schema/engine/dependentRequired.mjs +2 -6
  42. package/build/schema/engine/dependentSchemas.d.mts +4 -4
  43. package/build/schema/engine/dependentSchemas.mjs +2 -1
  44. package/build/schema/engine/dynamicRef.d.mts +4 -4
  45. package/build/schema/engine/dynamicRef.mjs +12 -8
  46. package/build/schema/engine/enum.d.mts +4 -4
  47. package/build/schema/engine/enum.mjs +2 -6
  48. package/build/schema/engine/exclusiveMaximum.d.mts +4 -4
  49. package/build/schema/engine/exclusiveMaximum.mjs +2 -6
  50. package/build/schema/engine/exclusiveMinimum.d.mts +4 -4
  51. package/build/schema/engine/exclusiveMinimum.mjs +2 -6
  52. package/build/schema/engine/format.d.mts +4 -4
  53. package/build/schema/engine/format.mjs +11 -8
  54. package/build/schema/engine/if.d.mts +4 -4
  55. package/build/schema/engine/if.mjs +5 -13
  56. package/build/schema/engine/items.d.mts +4 -4
  57. package/build/schema/engine/items.mjs +1 -1
  58. package/build/schema/engine/maxContains.d.mts +4 -4
  59. package/build/schema/engine/maxContains.mjs +2 -6
  60. package/build/schema/engine/maxItems.d.mts +4 -4
  61. package/build/schema/engine/maxItems.mjs +2 -6
  62. package/build/schema/engine/maxLength.d.mts +4 -4
  63. package/build/schema/engine/maxLength.mjs +2 -6
  64. package/build/schema/engine/maxProperties.d.mts +4 -4
  65. package/build/schema/engine/maxProperties.mjs +2 -6
  66. package/build/schema/engine/maximum.d.mts +4 -4
  67. package/build/schema/engine/maximum.mjs +2 -6
  68. package/build/schema/engine/minContains.d.mts +4 -4
  69. package/build/schema/engine/minContains.mjs +2 -6
  70. package/build/schema/engine/minItems.d.mts +5 -5
  71. package/build/schema/engine/minItems.mjs +2 -6
  72. package/build/schema/engine/minLength.d.mts +4 -4
  73. package/build/schema/engine/minLength.mjs +2 -6
  74. package/build/schema/engine/minProperties.d.mts +4 -4
  75. package/build/schema/engine/minProperties.mjs +2 -6
  76. package/build/schema/engine/minimum.d.mts +4 -4
  77. package/build/schema/engine/minimum.mjs +2 -6
  78. package/build/schema/engine/multipleOf.d.mts +4 -4
  79. package/build/schema/engine/multipleOf.mjs +2 -6
  80. package/build/schema/engine/not.d.mts +4 -4
  81. package/build/schema/engine/not.mjs +4 -8
  82. package/build/schema/engine/oneOf.d.mts +4 -4
  83. package/build/schema/engine/oneOf.mjs +5 -10
  84. package/build/schema/engine/pattern.d.mts +4 -4
  85. package/build/schema/engine/pattern.mjs +3 -7
  86. package/build/schema/engine/patternProperties.d.mts +4 -4
  87. package/build/schema/engine/patternProperties.mjs +4 -3
  88. package/build/schema/engine/prefixItems.d.mts +4 -4
  89. package/build/schema/engine/prefixItems.mjs +1 -1
  90. package/build/schema/engine/properties.d.mts +4 -4
  91. package/build/schema/engine/properties.mjs +4 -3
  92. package/build/schema/engine/propertyNames.d.mts +4 -4
  93. package/build/schema/engine/propertyNames.mjs +5 -8
  94. package/build/schema/engine/recursiveRef.d.mts +4 -4
  95. package/build/schema/engine/recursiveRef.mjs +12 -8
  96. package/build/schema/engine/ref.d.mts +4 -4
  97. package/build/schema/engine/ref.mjs +18 -14
  98. package/build/schema/engine/required.d.mts +4 -4
  99. package/build/schema/engine/required.mjs +2 -6
  100. package/build/schema/engine/schema.d.mts +7 -7
  101. package/build/schema/engine/schema.mjs +136 -138
  102. package/build/schema/engine/type.d.mts +4 -4
  103. package/build/schema/engine/type.mjs +2 -6
  104. package/build/schema/engine/unevaluatedItems.d.mts +4 -4
  105. package/build/schema/engine/unevaluatedItems.mjs +3 -7
  106. package/build/schema/engine/unevaluatedProperties.d.mts +4 -4
  107. package/build/schema/engine/unevaluatedProperties.mjs +3 -7
  108. package/build/schema/engine/uniqueItems.d.mts +4 -4
  109. package/build/schema/engine/uniqueItems.mjs +2 -6
  110. package/build/schema/errors.mjs +1 -1
  111. package/build/schema/intern/intern.d.mts +6 -9
  112. package/build/schema/intern/intern.mjs +90 -56
  113. package/build/schema/meta/draft_2019_09.d.mts +2 -0
  114. package/build/schema/meta/draft_2019_09.mjs +288 -0
  115. package/build/schema/meta/draft_2020_12.d.mts +2 -0
  116. package/build/schema/meta/draft_2020_12.mjs +300 -0
  117. package/build/schema/meta/draft_3.d.mts +2 -0
  118. package/build/schema/meta/draft_3.mjs +143 -0
  119. package/build/schema/meta/draft_4.d.mts +2 -0
  120. package/build/schema/meta/draft_4.mjs +149 -0
  121. package/build/schema/meta/draft_6.d.mts +2 -0
  122. package/build/schema/meta/draft_6.mjs +155 -0
  123. package/build/schema/meta/draft_7.d.mts +2 -0
  124. package/build/schema/meta/draft_7.mjs +172 -0
  125. package/build/schema/meta/index.d.mts +2 -0
  126. package/build/schema/meta/index.mjs +2 -0
  127. package/build/schema/meta/meta.d.mts +9 -0
  128. package/build/schema/meta/meta.mjs +15 -0
  129. package/build/schema/meta/schema.d.mts +6 -0
  130. package/build/schema/meta/schema.mjs +1 -0
  131. package/build/schema/parse.mjs +3 -0
  132. package/build/schema/pointer/pointer.d.mts +1 -6
  133. package/build/schema/pointer/pointer.mjs +47 -64
  134. package/build/schema/resolve/resolve.d.mts +6 -32
  135. package/build/schema/resolve/resolve.mjs +231 -227
  136. package/build/schema/schema.d.mts +1 -0
  137. package/build/schema/schema.mjs +1 -0
  138. package/build/system/settings/internal.d.mts +2 -0
  139. package/build/system/settings/internal.mjs +20 -0
  140. package/build/system/settings/settings.d.mts +11 -0
  141. package/build/system/settings/settings.mjs +14 -0
  142. package/build/type/extends/inference.d.mts +1 -1
  143. package/build/type/extends/inference.mjs +15 -2
  144. package/build/type/extends/tuple.d.mts +2 -1
  145. package/build/type/extends/tuple.mjs +21 -1
  146. package/build/value/parse/parse.mjs +10 -4
  147. package/changes.json +1 -1
  148. package/package.json +3 -3
  149. package/readme.md +52 -84
  150. /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
- export const DefaultBase = 'https://json-schema.org';
4
+ import * as Stack from '../engine/_stack.mjs';
6
5
  // ------------------------------------------------------------------
7
- // Find: FindDynamicAnchor
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 FindDynamicAnchor(schema, name) {
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 = FindDynamicAnchor(schema[key], name);
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 = Schema.IsSchemaObject(schema) && Schema.IsId(schema) ? new URL(schema.$id, base.href) : base;
54
+ const nextBase = RelativeBase(schema, base);
37
55
  if (Guard.IsArray(schema)) {
38
56
  for (const item of schema) {
39
- const result = FindBase(item, nextBase, target);
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 = FindBase(schema[key], nextBase, target);
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: MatchId
55
- // ------------------------------------------------------------------
56
- function MatchId(schema, base, ref) {
57
- // ref is a bare fragment naming this schema's $id directly
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('#') ? MatchHash(schema, ref) : schema;
98
+ return ref.hash.startsWith('#') ? MatchWithHash(schema, ref) : schema;
64
99
  return undefined;
65
100
  }
66
- // ------------------------------------------------------------------
67
- // Match: MatchAnchor
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
- // Match: MatchDynamicAnchor
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
- // Match: MatchHash
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
- const result = Pointer.Get(schema, fragment);
95
- return result;
119
+ return MatchWithId(schema, base, ref) ??
120
+ MatchWithAnchor(schema, base, ref) ??
121
+ MatchWithDynamicAnchor(schema, base, ref) ??
122
+ MatchWithHash(schema, ref);
96
123
  }
97
- // ------------------------------------------------------------------
98
- // Match: Match
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 = FromValue(item, base, ref);
128
+ const match = Match(item, base, ref);
124
129
  return !Guard.IsUndefined(match) ? match : result;
125
130
  }, undefined);
126
131
  }
127
- // ------------------------------------------------------------------
128
- // FromObject
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 (SkipProperty(key))
136
+ if (Guard.IsEqual(key, 'const') || Guard.IsEqual(key, 'enum'))
136
137
  return result;
137
- const match = FromValue(schema[key], base, ref);
138
+ const match = Match(schema[key], base, ref);
138
139
  return !Guard.IsUndefined(match) ? match : result;
139
140
  }, undefined);
140
141
  }
141
- // ------------------------------------------------------------------
142
- // FromValue
143
- // ------------------------------------------------------------------
144
- function FromValue(schema, base, ref) {
145
- const nextBase = Schema.IsSchemaObject(schema) && Schema.IsId(schema) ? new URL(schema.$id, base.href) : base;
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
- export function Resource(context, schema, base, ref) {
167
- const result = Ref(context, schema, base, ref, false);
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
- // CanonicalHref
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 style schemas (no $schema keyword) treat a nested $id as an
206
- // in-place base URI change rather than a new resource boundary. A
207
- // local ('#...') ref that lands somewhere with a different base than
208
- // the current reference base needs a frame so later anchor/pointer
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 LegacyRetrievedResource(root, lexicalSchema, referenceBase, ref, schema) {
167
+ function FindDeferredResourceLegacy(stack, ref, schema) {
212
168
  if (!ref.$ref.startsWith('#'))
213
169
  return undefined;
214
- if (Guard.HasPropertyKey(root, '$schema'))
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
- // RetrievedResource: RemoteRetrievedResource
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
- // RetrievedResource
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
- // ResolvedResource: FindResolvedResource
188
+ // FindResolvedResource
247
189
  //
248
- // The ref crossed into a different resource but landed on a schema
249
- // that doesn't itself carry that resource's $id (e.g. a pointer into
250
- // the middle of a remote document). The enclosing resource still
251
- // needs to be entered so lexical/base lookups behave as if traversal
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(context, root, referenceBase, canonical, schema, ids) {
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 { target: schema, resource };
201
+ return { resource };
261
202
  }
262
203
  // ------------------------------------------------------------------
263
- // Ref
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
- export function Ref(remotes, schema, base, ref, applySchemaId = true) {
266
- const initialBase = new URL(base || '.', DefaultBase);
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
- // DynamicRef
273
- // ------------------------------------------------------------------
274
- export function DynamicRef(context, root, base, schema, dynamicRef, dynamicAnchors) {
275
- const initialBase = new URL(base || '.', DefaultBase);
276
- const fragmentRoot = dynamicRef.$dynamicRef.startsWith('#') ? schema : root;
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
- if (!Schema.IsSchemaObject(fragmentTarget) || !Schema.IsDynamicAnchor(fragmentTarget))
288
- return fragmentTarget;
289
- const fragment = new URL(dynamicRef.$dynamicRef, initialBase).hash;
290
- if (fragment.startsWith('#/'))
291
- return fragmentTarget;
292
- const anchorTarget = dynamicAnchors.find((anchor) => Guard.IsEqual(anchor.$dynamicAnchor, fragmentTarget.$dynamicAnchor));
293
- return anchorTarget ?? fragmentTarget;
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
- // ResolveRef
234
+ // RefNextStack
297
235
  //
298
- // Resolves the schema a $ref points to, and describes whether that
299
- // crossing implies a "retrieved resource" frame or entering a
300
- // resource the target doesn't itself carry the $id for. The caller
301
- // decides whether and how to record these.
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
- export function ResolveRef(stackframe, ref) {
304
- const source = stackframe.inRetrievedFrame ? stackframe.lexicalSchema : stackframe.root;
305
- const refRoot = ref.$ref.startsWith('#') ? stackframe.lexicalSchema : source;
306
- const schema = Ref(stackframe.context, refRoot, stackframe.referenceBase, ref.$ref, false);
307
- if (!schema || !Schema.IsSchemaObject(schema))
308
- return { schema };
309
- const canonical = new URL(ref.$ref, stackframe.referenceBase).href.split('#')[0];
310
- const isRemote = !Guard.IsEqual(canonical, stackframe.resourceBase);
311
- const retrievedResource = FindRetrievedResource(stackframe, ref, schema, canonical, isRemote);
312
- const resolvedResource = isRemote ? FindResolvedResource(stackframe.context, stackframe.root, stackframe.referenceBase, canonical, schema, stackframe.ids) : undefined;
313
- return { schema, retrievedResource, resolvedResource };
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
- // ResolveRecursiveRef
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 ResolveRecursiveRef(stackframe, recursiveRef) {
319
- const refRoot = Schema.IsRecursiveAnchorTrue(stackframe.lexicalSchema) ? stackframe.recursiveAnchors[0] : stackframe.lexicalSchema;
320
- return Ref(stackframe.context, refRoot, stackframe.lexicalBase, recursiveRef.$recursiveRef, false);
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
- // ResolveDynamicRef
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
- export function ResolveDynamicRef(stackframe, dynamicRef) {
326
- return DynamicRef(stackframe.context, stackframe.root, stackframe.lexicalBase, stackframe.lexicalSchema, dynamicRef, stackframe.dynamicAnchors);
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
  }
@@ -1,5 +1,6 @@
1
1
  export * from './engine/index.mjs';
2
2
  export * from './intern/index.mjs';
3
+ export * from './meta/index.mjs';
3
4
  export * from './pointer/index.mjs';
4
5
  export * from './resolve/index.mjs';
5
6
  export * from './static/index.mjs';
@@ -1,5 +1,6 @@
1
1
  export * from './engine/index.mjs';
2
2
  export * from './intern/index.mjs';
3
+ export * from './meta/index.mjs';
3
4
  export * from './pointer/index.mjs';
4
5
  export * from './resolve/index.mjs';
5
6
  export * from './static/index.mjs';
@@ -0,0 +1,2 @@
1
+ export declare function EnableParseErrors(): void;
2
+ export declare function DisableParseErrors(): void;
@@ -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