typebox 1.1.15 → 1.1.17

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.
@@ -0,0 +1,2 @@
1
+ export declare function IsIdnLabel(value: string): boolean;
2
+ export declare function IsLabel(value: string): boolean;
@@ -0,0 +1,216 @@
1
+ import * as Puny from './_puny.mjs';
2
+ // ------------------------------------------------------------------
3
+ // Unicode General Category Helper (RFC 5892)
4
+ // ------------------------------------------------------------------
5
+ function IsNonspacingMark(cp) {
6
+ return /\p{Mn}/u.test(String.fromCodePoint(cp));
7
+ }
8
+ function IsSpacingCombiningMark(cp) {
9
+ return /\p{Mc}/u.test(String.fromCodePoint(cp));
10
+ }
11
+ function IsEnclosingMark(cp) {
12
+ return /\p{Me}/u.test(String.fromCodePoint(cp));
13
+ }
14
+ function IsCombiningMark(cp) {
15
+ return IsNonspacingMark(cp) || IsSpacingCombiningMark(cp) || IsEnclosingMark(cp);
16
+ }
17
+ // ------------------------------------------------------------------
18
+ // RFC 5892 §2.6 DISALLOWED exceptions
19
+ //
20
+ // https://tools.ietf.org/html/rfc5892#section-2.6
21
+ // ------------------------------------------------------------------
22
+ const RFC5892_DISALLOWED = new Set([
23
+ 0x0640, // ARABIC TATWEEL
24
+ 0x07fa, // NKO LAJANYALAN
25
+ 0x302e, // HANGUL SINGLE DOT TONE MARK
26
+ 0x302f, // HANGUL DOUBLE DOT TONE MARK
27
+ 0x3031, // VERTICAL KANA REPEAT MARK
28
+ 0x3032, // VERTICAL KANA REPEAT WITH VOICED ITERATION MARK
29
+ 0x3033, // VERTICAL KANA REPEAT MARK UPPER HALF
30
+ 0x3034, // VERTICAL KANA REPEAT WITH VOICED ITERATION MARK UPPER HALF
31
+ 0x3035, // VERTICAL KANA REPEAT MARK LOWER HALF
32
+ 0x303b // VERTICAL IDEOGRAPHIC ITERATION MARK
33
+ ]);
34
+ // ------------------------------------------------------------------
35
+ // A set of Virama (halant) code points used to validate CONTEXTJ
36
+ // rules (RFC 5892 Appendix A.1). These characters allow a subsequent
37
+ // Zero Width Joiner (U+200D) to be valid in a label.
38
+ // ------------------------------------------------------------------
39
+ const VIRAMA_CPS = new Set([
40
+ 0x094d,
41
+ 0x09cd,
42
+ 0x0a4d,
43
+ 0x0acd,
44
+ 0x0b4d,
45
+ 0x0bcd,
46
+ 0x0c4d,
47
+ 0x0ccd,
48
+ 0x0d3b,
49
+ 0x0d3c,
50
+ 0x0d4d,
51
+ 0x0dca,
52
+ 0x1b44,
53
+ 0x1baa,
54
+ 0x1bab,
55
+ 0xa9c0,
56
+ 0x11046,
57
+ 0x1107f,
58
+ 0x110b9,
59
+ 0x11133,
60
+ 0x11134,
61
+ 0x111c0,
62
+ 0x11235,
63
+ 0x1134d,
64
+ 0x11442,
65
+ 0x114c2,
66
+ 0x115bf,
67
+ 0x1163f,
68
+ 0x116b6,
69
+ 0x11c3f,
70
+ 0x11d44,
71
+ 0x11d45
72
+ ]);
73
+ // ------------------------------------------------------------------
74
+ // Guards for CONTEXTO rules (RFC 5892 Appendix A)
75
+ // ------------------------------------------------------------------
76
+ function IsGreek(cp) {
77
+ return /\p{Script=Greek}/u.test(String.fromCodePoint(cp));
78
+ }
79
+ function IsHebrew(cp) {
80
+ return /\p{Script=Hebrew}/u.test(String.fromCodePoint(cp));
81
+ }
82
+ function IsHiragana(cp) {
83
+ return /\p{Script=Hiragana}/u.test(String.fromCodePoint(cp));
84
+ }
85
+ function IsKatakana(cp) {
86
+ return /\p{Script=Katakana}/u.test(String.fromCodePoint(cp));
87
+ }
88
+ function IsHan(cp) {
89
+ return /\p{Script=Han}/u.test(String.fromCodePoint(cp));
90
+ }
91
+ function IsArabicIndicDigit(cp) {
92
+ return cp >= 0x0660 && cp <= 0x0669;
93
+ }
94
+ function IsExtendedArabicIndicDigit(cp) {
95
+ return cp >= 0x06f0 && cp <= 0x06f9;
96
+ }
97
+ function IsVirama(cp) {
98
+ return VIRAMA_CPS.has(cp);
99
+ }
100
+ // ------------------------------------------------------------------
101
+ // IsUnicodeLabel
102
+ // ------------------------------------------------------------------
103
+ function IsUnicodeLabel(value) {
104
+ if (value.length === 0)
105
+ return false;
106
+ // Use spread to handle surrogate pairs and provide O(1) neighbor access
107
+ const cps = [...value].map((c) => c.codePointAt(0));
108
+ const len = cps.length;
109
+ // RFC 5891 §4.2.3.2: Hyphen rules
110
+ if (cps[0] === 0x2d || cps[len - 1] === 0x2d)
111
+ return false;
112
+ if (len >= 4 && cps[2] === 0x2d && cps[3] === 0x2d)
113
+ return false;
114
+ // RFC 5891 §4.2.3.2 - Must not begin with a combining mark
115
+ if (IsCombiningMark(cps[0]))
116
+ return false;
117
+ let hasJapanese = false;
118
+ let hasArabicIndic = false;
119
+ let hasExtendedArabicIndic = false;
120
+ for (let i = 0; i < len; i++) {
121
+ const cp = cps[i];
122
+ // 1. DISALLOWED exceptions
123
+ if (RFC5892_DISALLOWED.has(cp))
124
+ return false;
125
+ // 2. Collect Flags
126
+ if (IsHiragana(cp) || IsKatakana(cp) || IsHan(cp))
127
+ hasJapanese = true;
128
+ if (IsArabicIndicDigit(cp))
129
+ hasArabicIndic = true;
130
+ if (IsExtendedArabicIndicDigit(cp))
131
+ hasExtendedArabicIndic = true;
132
+ // 3. CONTEXTO / CONTEXTJ Neighbor Rules
133
+ const prev = cps[i - 1], next = cps[i + 1];
134
+ switch (cp) {
135
+ case 0x00b7:
136
+ if (prev !== 0x006c || next !== 0x006c)
137
+ return false;
138
+ break; // MIDDLE DOT (Catalan)
139
+ case 0x0375:
140
+ if (next === undefined || !IsGreek(next))
141
+ return false;
142
+ break; // Greek KERAIA
143
+ case 0x05f3:
144
+ case 0x05f4:
145
+ if (prev === undefined || !IsHebrew(prev))
146
+ return false;
147
+ break; // Hebrew GERESH
148
+ case 0x200d:
149
+ if (prev === undefined || !IsVirama(prev))
150
+ return false;
151
+ break; // ZWJ
152
+ case 0x30fb: /* Checked at end via hasJapanese */
153
+ break; // KATAKANA MIDDLE DOT
154
+ }
155
+ }
156
+ // 4. Global Context Validations (Post-loop)
157
+ // RFC 5892 Appendix A.7 - Katakana Middle Dot requirement
158
+ if (value.includes('\u30fb') && !hasJapanese)
159
+ return false;
160
+ // RFC 5892 Appendix A.8/A.9 - Mixing Arabic Digits
161
+ if (hasArabicIndic && hasExtendedArabicIndic)
162
+ return false;
163
+ return true;
164
+ }
165
+ // ------------------------------------------------------------------
166
+ // IsAsciiLabel
167
+ // ------------------------------------------------------------------
168
+ function IsAsciiLabel(value) {
169
+ // Must not start or end with a hyphen
170
+ if (value.charCodeAt(0) === 45 || value.charCodeAt(value.length - 1) === 45)
171
+ return false;
172
+ // RFC 5891 §4.2.3.1 : "--" at positions 3-4 is reserved for A-labels only
173
+ if (value.length >= 4 && value.charCodeAt(2) === 45 && value.charCodeAt(3) === 45)
174
+ return false;
175
+ // All characters must be alphanumeric or hyphen
176
+ for (let i = 0; i < value.length; i++) {
177
+ const ch = value.charCodeAt(i);
178
+ if (!((ch >= 97 && ch <= 122) || // a-z
179
+ (ch >= 65 && ch <= 90) || // A-Z
180
+ (ch >= 48 && ch <= 57) || // 0-9
181
+ ch === 45 // '-'
182
+ ))
183
+ return false;
184
+ }
185
+ return true;
186
+ }
187
+ // ------------------------------------------------------------------
188
+ // IsPunyLabel
189
+ // ------------------------------------------------------------------
190
+ function IsPuny(value) {
191
+ return value.toLowerCase().startsWith('xn--');
192
+ }
193
+ function IsPunyLabel(value) {
194
+ try {
195
+ return IsUnicodeLabel(Puny.Decode(value.slice(4)));
196
+ }
197
+ catch {
198
+ return false; // invalid punycode encoding
199
+ }
200
+ }
201
+ // ------------------------------------------------------------------
202
+ // IsIdnLabel
203
+ // ------------------------------------------------------------------
204
+ export function IsIdnLabel(value) {
205
+ if (value.length === 0 || value.length > 63)
206
+ return false;
207
+ return IsPuny(value) ? IsPunyLabel(value) : IsUnicodeLabel(value);
208
+ }
209
+ // ------------------------------------------------------------------
210
+ // IsLabel
211
+ // ------------------------------------------------------------------
212
+ export function IsLabel(value) {
213
+ if (value.length === 0 || value.length > 63)
214
+ return false;
215
+ return IsPuny(value) ? IsPunyLabel(value) : IsAsciiLabel(value);
216
+ }
@@ -0,0 +1 @@
1
+ export declare function Decode(value: string): string;
@@ -0,0 +1,74 @@
1
+ // ------------------------------------------------------------------
2
+ // PunyCode (RFC 3492)
3
+ // ------------------------------------------------------------------
4
+ const PUNYCODE_BASE = 36;
5
+ const PUNYCODE_TMIN = 1;
6
+ const PUNYCODE_TMAX = 26;
7
+ const PUNYCODE_SKEW = 38;
8
+ const PUNYCODE_DAMP = 700;
9
+ const PUNYCODE_INITIAL_BIAS = 72;
10
+ const PUNYCODE_INITIAL_N = 128;
11
+ // ------------------------------------------------------------------
12
+ // Adapt
13
+ // ------------------------------------------------------------------
14
+ function Adapt(delta, numPoints, firstTime) {
15
+ delta = firstTime ? Math.floor(delta / PUNYCODE_DAMP) : delta >> 1;
16
+ delta += Math.floor(delta / numPoints);
17
+ let k = 0;
18
+ while (delta > (((PUNYCODE_BASE - PUNYCODE_TMIN) * PUNYCODE_TMAX) >> 1)) {
19
+ delta = Math.floor(delta / (PUNYCODE_BASE - PUNYCODE_TMIN));
20
+ k += PUNYCODE_BASE;
21
+ }
22
+ return k + Math.floor(((PUNYCODE_BASE - PUNYCODE_TMIN + 1) * delta) / (delta + PUNYCODE_SKEW));
23
+ }
24
+ // ------------------------------------------------------------------
25
+ // Decode
26
+ // ------------------------------------------------------------------
27
+ export function Decode(value) {
28
+ const output = [];
29
+ let n = PUNYCODE_INITIAL_N;
30
+ let i = 0;
31
+ let bias = PUNYCODE_INITIAL_BIAS;
32
+ const delimIdx = value.lastIndexOf('-');
33
+ if (delimIdx > 0) {
34
+ for (let j = 0; j < delimIdx; j++) {
35
+ const cp = value.charCodeAt(j);
36
+ if (cp >= 128)
37
+ throw new Error('Invalid punycode: non-basic before delimiter');
38
+ output.push(cp);
39
+ }
40
+ }
41
+ let inIdx = delimIdx < 0 ? 0 : delimIdx + 1;
42
+ while (inIdx < value.length) {
43
+ const oldi = i;
44
+ let w = 1;
45
+ let k = PUNYCODE_BASE;
46
+ while (true) {
47
+ if (inIdx >= value.length)
48
+ throw new Error('Invalid punycode: unexpected end of input');
49
+ const ch = value.charCodeAt(inIdx++);
50
+ let digit;
51
+ if (ch >= 0x61 && ch <= 0x7a)
52
+ digit = ch - 0x61; // a-z => 0-25
53
+ else if (ch >= 0x30 && ch <= 0x39)
54
+ digit = ch - 0x30 + 26; // 0-9 => 26-35
55
+ else if (ch >= 0x41 && ch <= 0x5a)
56
+ digit = ch - 0x41; // A-Z => 0-25
57
+ else
58
+ throw new Error('Invalid punycode: bad digit character');
59
+ i += digit * w;
60
+ const t = k <= bias ? PUNYCODE_TMIN : k >= bias + PUNYCODE_TMAX ? PUNYCODE_TMAX : k - bias;
61
+ if (digit < t)
62
+ break;
63
+ w *= PUNYCODE_BASE - t;
64
+ k += PUNYCODE_BASE;
65
+ }
66
+ const outLen = output.length + 1;
67
+ bias = Adapt(i - oldi, outLen, oldi === 0);
68
+ n += Math.floor(i / outLen);
69
+ i %= outLen;
70
+ output.splice(i, 0, n);
71
+ i++;
72
+ }
73
+ return globalThis.String.fromCodePoint(...output);
74
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Returns true if the value is a Duration string
3
- * @source ajv-formats
2
+ * Returns true if the value is a valid ISO-8601 duration.
3
+ * @specification https://tools.ietf.org/html/rfc3339
4
4
  */
5
5
  export declare function IsDuration(value: string): boolean;
@@ -1,7 +1,7 @@
1
- const Duration = /^P(?!$)((\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?|(\d+W)?)$/;
1
+ const Duration = /^P((\d+Y(\d+M(\d+D)?)?|\d+M(\d+D)?|\d+D)(T(\d+H(\d+M(\d+S)?)?|\d+M(\d+S)?|\d+S))?|T(\d+H(\d+M(\d+S)?)?|\d+M(\d+S)?|\d+S)|\d+W)$/;
2
2
  /**
3
- * Returns true if the value is a Duration string
4
- * @source ajv-formats
3
+ * Returns true if the value is a valid ISO-8601 duration.
4
+ * @specification https://tools.ietf.org/html/rfc3339
5
5
  */
6
6
  export function IsDuration(value) {
7
7
  return Duration.test(value);
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Returns true if the value matches RFC 1123 hostname syntax.
2
+ * Returns true if the value is a valid hostname.
3
3
  * @specification https://tools.ietf.org/html/rfc1123
4
+ * @specification https://tools.ietf.org/html/rfc5891
5
+ * @specification https://tools.ietf.org/html/rfc5892
4
6
  */
5
7
  export declare function IsHostname(value: string): boolean;
@@ -1,34 +1,18 @@
1
+ import * as Idna from './_idna.mjs';
1
2
  /**
2
- * Returns true if the value matches RFC 1123 hostname syntax.
3
+ * Returns true if the value is a valid hostname.
3
4
  * @specification https://tools.ietf.org/html/rfc1123
5
+ * @specification https://tools.ietf.org/html/rfc5891
6
+ * @specification https://tools.ietf.org/html/rfc5892
4
7
  */
5
8
  export function IsHostname(value) {
6
- if (value.length > 253 || value.length === 0)
9
+ if (value.length === 0 || value.length > 253)
7
10
  return false;
8
- let start = 0;
9
- let prev = 0;
10
- for (let i = 0; i < value.length; i++) {
11
- const ch = value.charCodeAt(i);
12
- if (ch === 46) { // '.'
13
- // trailing dot is valid e.g. "example.com." but not "."
14
- if (i === value.length - 1 && start < i)
15
- break;
16
- const len = i - start;
17
- if (len === 0 || len > 63 || value.charCodeAt(start) === 45 || prev === 45)
18
- return false;
19
- start = i + 1;
20
- }
21
- else if (!((ch >= 97 && ch <= 122) || // a-z
22
- (ch >= 65 && ch <= 90) || // A-Z
23
- (ch >= 48 && ch <= 57) || // 0-9
24
- ch === 45 // '-'
25
- )) {
11
+ if (value.charCodeAt(value.length - 1) === 46)
12
+ return false;
13
+ for (const label of value.split('.')) {
14
+ if (!Idna.IsLabel(label))
26
15
  return false;
27
- }
28
- prev = ch;
29
16
  }
30
- const length = value.length - start;
31
- const first = value.charCodeAt(start);
32
- const last = value.charCodeAt(value.length - 1);
33
- return length > 0 && length <= 63 && first !== 45 && last !== 45;
17
+ return true;
34
18
  }
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Returns true if the value is an IDN Hostname
3
- * @specification Json Schema 2020-12
2
+ * Returns true if the value is a valid internationalized (IDN) hostname.
3
+ * @specification https://tools.ietf.org/html/rfc3490
4
+ * @specification https://tools.ietf.org/html/rfc5891
5
+ * @specification https://tools.ietf.org/html/rfc5892
4
6
  */
5
7
  export declare function IsIdnHostname(value: string): boolean;
@@ -1,118 +1,18 @@
1
- function IsValidAdjacentForKatakanaMiddleDot(cp) {
2
- return ((cp >= 0x3040 && cp <= 0x309F) || // Hiragana
3
- (cp >= 0x30A0 && cp <= 0x30FF && cp !== 0x30FB) || // Katakana (excluding U+30FB)
4
- (cp >= 0x4E00 && cp <= 0x9FFF) // Han (CJK Unified Ideographs)
5
- );
6
- }
1
+ import { IsIdnLabel } from './_idna.mjs';
7
2
  /**
8
- * Returns true if the value is an IDN Hostname
9
- * @specification Json Schema 2020-12
3
+ * Returns true if the value is a valid internationalized (IDN) hostname.
4
+ * @specification https://tools.ietf.org/html/rfc3490
5
+ * @specification https://tools.ietf.org/html/rfc5891
6
+ * @specification https://tools.ietf.org/html/rfc5892
10
7
  */
11
8
  export function IsIdnHostname(value) {
12
9
  if (value.length === 0 || value.includes(' '))
13
10
  return false;
14
- // Normalize (NFC) and replace allowed separators with a dot
15
- // Allowed label separators per RFC3490: U+002E, U+3002, U+FF0E, U+FF61
16
- const normalized = value.normalize('NFC').replace(/[\u002E\u3002\uFF0E\uFF61]/g, '.');
17
- if (normalized.length > 253)
11
+ const canonical = value.normalize('NFC').replace(/[\u002E\u3002\uFF0E\uFF61]/g, '.');
12
+ if (canonical.length > 253)
18
13
  return false;
19
- const labels = normalized.split('.');
20
- for (const label of labels) {
21
- if (label.length === 0 || label.length > 63)
22
- return false;
23
- // Labels must not begin or end with a hyphen
24
- if (label.charCodeAt(0) === 45 || label.charCodeAt(label.length - 1) === 45)
25
- return false;
26
- // A-label (punycode) checks
27
- if ((label.charCodeAt(0) === 120 || label.charCodeAt(0) === 88) && // 'x' or 'X'
28
- (label.charCodeAt(1) === 110 || label.charCodeAt(1) === 78) && // 'n' or 'N'
29
- label.charCodeAt(2) === 45 && // '-'
30
- label.charCodeAt(3) === 45 // '-'
31
- ) {
32
- const punycodePart = label.slice(4);
33
- if (punycodePart.length < 2 || punycodePart.includes('---'))
34
- return false;
35
- continue;
36
- }
37
- // U-label checks
38
- let hasArabicIndic = false;
39
- let hasExtendedArabicIndic = false;
40
- for (let i = 0; i < label.length; i++) {
41
- // deno-coverage-ignore
42
- const cp = label.codePointAt(i) ?? 0;
43
- // Disallowed code points
44
- if (cp === 0x302E || cp === 0x302F ||
45
- cp === 0x3031 || cp === 0x3032 || cp === 0x3033 || cp === 0x3034 || cp === 0x3035 ||
46
- cp === 0x303B || cp === 0x0640 || cp === 0x07FA)
47
- return false;
48
- // Disallow labels starting with certain combining marks
49
- if (i === 0 && (cp === 0x0903 || cp === 0x0300 || cp === 0x0488))
50
- return false;
51
- // MIDDLE DOT (U+00B7) must be flanked by 'l' or 'L'
52
- if (cp === 0x00B7) {
53
- if (i === 0 || i === label.length - 1)
54
- return false;
55
- // deno-coverage-ignore
56
- const prev = label.codePointAt(i - 1) ?? 0;
57
- // deno-coverage-ignore
58
- const next = label.codePointAt(i + 1) ?? 0;
59
- if ((prev !== 108 && prev !== 76) || (next !== 108 && next !== 76))
60
- return false;
61
- }
62
- // KATAKANA MIDDLE DOT (U+30FB) | U+30FB is below U+FFFF so stride is always 1
63
- if (cp === 0x30FB) {
64
- if (label.length === 1)
65
- return false;
66
- if (i === 0) {
67
- // deno-coverage-ignore
68
- const next = label.codePointAt(i + 1) ?? 0;
69
- if (!IsValidAdjacentForKatakanaMiddleDot(next))
70
- return false;
71
- }
72
- else {
73
- // deno-coverage-ignore
74
- const prev = label.codePointAt(i - 1) ?? 0;
75
- // deno-coverage-ignore
76
- const next = label.codePointAt(i + 1) ?? 0;
77
- if (!IsValidAdjacentForKatakanaMiddleDot(prev) || !IsValidAdjacentForKatakanaMiddleDot(next))
78
- return false;
79
- }
80
- }
81
- // Greek KERAIA (U+0375) | U+0375 is below U+FFFF so stride is always 1
82
- if (cp === 0x0375) {
83
- if (i === label.length - 1)
84
- return false;
85
- // deno-coverage-ignore
86
- const next = label.codePointAt(i + 1) ?? 0;
87
- if (next < 0x0370 || next > 0x03FF)
88
- return false;
89
- }
90
- // Hebrew GERESH (U+05F3) and GERSHAYIM (U+05F4)
91
- if (cp === 0x05F3 || cp === 0x05F4) {
92
- if (i === 0)
93
- return false;
94
- // deno-coverage-ignore
95
- const prev = label.codePointAt(i - 1) ?? 0;
96
- if (prev < 0x05D0 || prev > 0x05EA)
97
- return false;
98
- }
99
- // ZERO WIDTH JOINER (U+200D)
100
- if (cp === 0x200D) {
101
- if (i === 0)
102
- return false;
103
- // deno-coverage-ignore
104
- const prev = label.codePointAt(i - 1) ?? 0;
105
- if (prev !== 0x094D)
106
- return false;
107
- }
108
- // Arabic-Indic digits
109
- if (cp >= 0x0660 && cp <= 0x0669)
110
- hasArabicIndic = true;
111
- // Extended Arabic-Indic digits
112
- if (cp >= 0x06F0 && cp <= 0x06F9)
113
- hasExtendedArabicIndic = true;
114
- }
115
- if (hasArabicIndic && hasExtendedArabicIndic)
14
+ for (const label of canonical.split('.')) {
15
+ if (!IsIdnLabel(label))
116
16
  return false;
117
17
  }
118
18
  return true;
@@ -1,6 +1,5 @@
1
1
  /**
2
- * Returns true if the value is a uri reference
3
- * @specification
4
- * @source ajv-formats
2
+ * Returns true if the value is a valid URI Reference.
3
+ * @specification https://tools.ietf.org/html/rfc3986
5
4
  */
6
5
  export declare function IsUriReference(value: string): boolean;
@@ -1,8 +1,7 @@
1
- const UriReference = /^(?:(?:[a-z][a-z0-9+\-.]*:)?\/?\/)?(?:[^\\\s#][^\s#]*)?(?:#[^\\\s]*)?$/i;
1
+ const UriReference = /^(?!.*[^\x00-\x7F])(?!.*\\)(?:(?:[a-z][a-z0-9+\-.]*:)?(?:\/\/[^\s[\]{}<>^`|]*)?|[^\s[\]{}<>^`|]*)(?:\?[^\s[\]{}<>^`|]*)?(?:#[^\s[\]{}<>^`|]*)?$/i;
2
2
  /**
3
- * Returns true if the value is a uri reference
4
- * @specification
5
- * @source ajv-formats
3
+ * Returns true if the value is a valid URI Reference.
4
+ * @specification https://tools.ietf.org/html/rfc3986
6
5
  */
7
6
  export function IsUriReference(value) {
8
7
  return UriReference.test(value);
@@ -1,9 +1,5 @@
1
1
  /** Returns the number of grapheme clusters in a string */
2
2
  export declare function GraphemeCount(value: string): number;
3
- /** Checks if a string has at least a minimum number of grapheme clusters */
4
- export declare function IsMinLength(value: string, minLength: number): boolean;
5
- /** Checks if a string has at most a maximum number of grapheme clusters */
6
- export declare function IsMaxLength(value: string, maxLength: number): boolean;
7
3
  /** Fast check for minimum grapheme length, falls back to full check if needed */
8
4
  export declare function IsMinLengthFast(value: string, minLength: number): boolean;
9
5
  /** Fast check for maximum grapheme length, falls back to full check if needed */
@@ -94,9 +94,15 @@ export function GraphemeCount(value) {
94
94
  // IsMinLength
95
95
  // --------------------------------------------------------------------------
96
96
  /** Checks if a string has at least a minimum number of grapheme clusters */
97
- export function IsMinLength(value, minLength) {
97
+ function IsMinLength(value, minLength) {
98
+ // ----------------------------------------------------------------
99
+ // Inaccessible via public interface (review)
100
+ //
101
+ // deno-coverage-ignore-start
102
+ // ----------------------------------------------------------------
98
103
  if (minLength === 0)
99
104
  return true; // 0-length
105
+ // deno-coverage-ignore-stop
100
106
  let count = 0;
101
107
  let index = 0;
102
108
  while (index < value.length) {
@@ -111,7 +117,7 @@ export function IsMinLength(value, minLength) {
111
117
  // IsMaxLength
112
118
  // --------------------------------------------------------------------------
113
119
  /** Checks if a string has at most a maximum number of grapheme clusters */
114
- export function IsMaxLength(value, maxLength) {
120
+ function IsMaxLength(value, maxLength) {
115
121
  let count = 0;
116
122
  let index = 0;
117
123
  while (index < value.length) {
@@ -4,14 +4,17 @@ export declare class BuildContext {
4
4
  private readonly hasUnevaluated;
5
5
  constructor(hasUnevaluated: boolean);
6
6
  UseUnevaluated(): boolean;
7
+ Push(): string;
8
+ Pop(): string;
7
9
  AddIndex(index: string): string;
8
10
  AddKey(key: string): string;
9
11
  Merge(results: string): string;
10
12
  }
11
13
  export declare class CheckContext {
12
- private readonly indices;
13
- private readonly keys;
14
+ private readonly stack;
14
15
  constructor();
16
+ Push(): true;
17
+ Pop(): true;
15
18
  AddIndex(index: number): true;
16
19
  AddKey(key: string): true;
17
20
  GetIndices(): Set<number>;
@@ -30,6 +30,18 @@ export class BuildContext {
30
30
  UseUnevaluated() {
31
31
  return this.hasUnevaluated;
32
32
  }
33
+ // ----------------------------------------------------------------
34
+ // Stack
35
+ // ----------------------------------------------------------------
36
+ Push() {
37
+ return E.Call(E.Member('context', 'Push'), []);
38
+ }
39
+ Pop() {
40
+ return E.Call(E.Member('context', 'Pop'), []);
41
+ }
42
+ // ----------------------------------------------------------------
43
+ // Top
44
+ // ----------------------------------------------------------------
33
45
  AddIndex(index) {
34
46
  return E.Call(E.Member('context', 'AddIndex'), [index]);
35
47
  }
@@ -45,27 +57,46 @@ export class BuildContext {
45
57
  // ------------------------------------------------------------------
46
58
  export class CheckContext {
47
59
  constructor() {
48
- this.indices = new Set();
49
- this.keys = new Set();
60
+ const indices = new Set();
61
+ const keys = new Set();
62
+ this.stack = [{ indices, keys }];
63
+ }
64
+ // ----------------------------------------------------------------
65
+ // Stack
66
+ // ----------------------------------------------------------------
67
+ Push() {
68
+ const indices = new Set();
69
+ const keys = new Set();
70
+ this.stack.push({ indices, keys });
71
+ return true;
72
+ }
73
+ Pop() {
74
+ this.stack.pop();
75
+ return true;
50
76
  }
77
+ // ----------------------------------------------------------------
78
+ // Top
79
+ // ----------------------------------------------------------------
51
80
  AddIndex(index) {
52
- this.indices.add(index);
81
+ this.GetIndices().add(index);
53
82
  return true;
54
83
  }
55
84
  AddKey(key) {
56
- this.keys.add(key);
85
+ this.GetKeys().add(key);
57
86
  return true;
58
87
  }
59
88
  GetIndices() {
60
- return this.indices;
89
+ const top = this.stack[this.stack.length - 1];
90
+ return top.indices;
61
91
  }
62
92
  GetKeys() {
63
- return this.keys;
93
+ const top = this.stack[this.stack.length - 1];
94
+ return top.keys;
64
95
  }
65
96
  Merge(results) {
66
97
  for (const context of results) {
67
- context.indices.forEach(value => this.indices.add(value));
68
- context.keys.forEach(value => this.keys.add(value));
98
+ context.GetIndices().forEach(value => this.GetIndices().add(value));
99
+ context.GetKeys().forEach(value => this.GetKeys().add(value));
69
100
  }
70
101
  return true;
71
102
  }
@@ -1,9 +1,7 @@
1
1
  export interface TExternal {
2
- /** The name of the variable that holds external variables in generated code */
3
- identifier: string;
4
- /** An array of external variables */
2
+ identifier: 'External';
5
3
  variables: unknown[];
6
4
  }
7
- export declare function ResetExternal(): void;
8
5
  export declare function CreateVariable(value: unknown): string;
6
+ export declare function ResetExternal(): void;
9
7
  export declare function GetExternal(): TExternal;
@@ -1,34 +1,25 @@
1
1
  // deno-fmt-ignore-file
2
- const identifier = 'external_';
3
- let resetCount = 0;
4
2
  const state = {
5
- identifier: `${identifier}${resetCount}`,
3
+ identifier: 'External',
6
4
  variables: []
7
5
  };
8
6
  // ------------------------------------------------------------------
9
- // ResetExternals
10
- //
11
- // Each reset results in a new external group identifier. This is done
12
- // to prevent variable name overlap when generating and evaluating
13
- // multiple types in the same scope.
14
- //
15
- // ------------------------------------------------------------------
16
- export function ResetExternal() {
17
- state.identifier = `${identifier}${resetCount}`;
18
- state.variables = [];
19
- resetCount += 1;
20
- }
21
- // ------------------------------------------------------------------
22
7
  // CreateVariable
23
8
  // ------------------------------------------------------------------
24
9
  export function CreateVariable(value) {
25
- const call = `${state.identifier}[${state.variables.length}]`;
10
+ const call = `External[${state.variables.length}]`;
26
11
  state.variables.push(value);
27
12
  return call;
28
13
  }
29
14
  // ------------------------------------------------------------------
15
+ // ResetExternal
16
+ // ------------------------------------------------------------------
17
+ export function ResetExternal() {
18
+ state.variables = [];
19
+ }
20
+ // ------------------------------------------------------------------
30
21
  // GetExternals
31
22
  // ------------------------------------------------------------------
32
23
  export function GetExternal() {
33
- return state;
24
+ return { ...state };
34
25
  }
@@ -2,7 +2,7 @@
2
2
  import * as Schema from '../types/index.mjs';
3
3
  import { Unique } from './_unique.mjs';
4
4
  import { Guard as G, EmitGuard as E } from '../../guard/index.mjs';
5
- import { BuildSchema, CheckSchema, ErrorSchema } from './schema.mjs';
5
+ import { BuildSchemaPushStack, CheckSchemaPushStack, ErrorSchemaPushStack } from './schema.mjs';
6
6
  // ------------------------------------------------------------------
7
7
  // Valid
8
8
  // ------------------------------------------------------------------
@@ -16,7 +16,7 @@ export function BuildAdditionalItems(stack, context, schema, value) {
16
16
  if (!IsValid(schema))
17
17
  return E.Constant(true);
18
18
  const [item, index] = [Unique(), Unique()];
19
- const isSchema = BuildSchema(stack, context, schema.additionalItems, item);
19
+ const isSchema = BuildSchemaPushStack(stack, context, schema.additionalItems, item);
20
20
  const isLength = E.IsLessThan(index, E.Constant(schema.items.length));
21
21
  const addIndex = context.AddIndex(index);
22
22
  const guarded = context.UseUnevaluated() ? E.Or(isLength, E.And(isSchema, addIndex)) : E.Or(isLength, isSchema);
@@ -30,7 +30,7 @@ export function CheckAdditionalItems(stack, context, schema, value) {
30
30
  return true;
31
31
  const isAdditionalItems = value.every((item, index) => {
32
32
  return G.IsLessThan(index, schema.items.length)
33
- || (CheckSchema(stack, context, schema.additionalItems, item) && context.AddIndex(index));
33
+ || (CheckSchemaPushStack(stack, context, schema.additionalItems, item) && context.AddIndex(index));
34
34
  });
35
35
  return isAdditionalItems;
36
36
  }
@@ -44,7 +44,7 @@ export function ErrorAdditionalItems(stack, context, schemaPath, instancePath, s
44
44
  const nextSchemaPath = `${schemaPath}/additionalItems`;
45
45
  const nextInstancePath = `${instancePath}/${index}`;
46
46
  return G.IsLessThan(index, schema.items.length) ||
47
- (ErrorSchema(stack, context, nextSchemaPath, nextInstancePath, schema.additionalItems, item) && context.AddIndex(index));
47
+ (ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema.additionalItems, item) && context.AddIndex(index));
48
48
  });
49
49
  return isAdditionalItems;
50
50
  }
@@ -4,7 +4,7 @@ import * as V from './_externals.mjs';
4
4
  import { Unique } from './_unique.mjs';
5
5
  import { AccumulatedErrorContext } from './_context.mjs';
6
6
  import { EmitGuard as E, Guard as G } from '../../guard/index.mjs';
7
- import { BuildSchema, CheckSchema, ErrorSchema } from './schema.mjs';
7
+ import { BuildSchemaPushStack, CheckSchemaPushStack, ErrorSchemaPushStack } from './schema.mjs';
8
8
  // ------------------------------------------------------------------
9
9
  // Common: GetPropertiesPattern
10
10
  //
@@ -59,7 +59,7 @@ export function BuildAdditionalPropertiesFast(context, schema, value) {
59
59
  export function BuildAdditionalPropertiesStandard(stack, context, schema, value) {
60
60
  const [key, _index] = [Unique(), Unique()];
61
61
  const regexp = V.CreateVariable(new RegExp(GetPropertiesPattern(schema)));
62
- const isSchema = BuildSchema(stack, context, schema.additionalProperties, `${value}[${key}]`);
62
+ const isSchema = BuildSchemaPushStack(stack, context, schema.additionalProperties, `${value}[${key}]`);
63
63
  const isKey = E.Call(E.Member(regexp, 'test'), [key]);
64
64
  const addKey = context.AddKey(key);
65
65
  const guarded = context.UseUnevaluated() ? E.Or(isKey, E.And(isSchema, addKey)) : E.Or(isKey, isSchema);
@@ -81,7 +81,7 @@ export function CheckAdditionalProperties(stack, context, schema, value) {
81
81
  const regexp = new RegExp(GetPropertiesPattern(schema));
82
82
  const isAdditionalProperties = G.Every(G.Keys(value), 0, (key, _index) => {
83
83
  return regexp.test(key) ||
84
- (CheckSchema(stack, context, schema.additionalProperties, value[key]) && context.AddKey(key));
84
+ (CheckSchemaPushStack(stack, context, schema.additionalProperties, value[key]) && context.AddKey(key));
85
85
  });
86
86
  return isAdditionalProperties;
87
87
  }
@@ -96,7 +96,7 @@ export function ErrorAdditionalProperties(stack, context, schemaPath, instancePa
96
96
  const nextInstancePath = `${instancePath}/${key}`;
97
97
  const nextContext = new AccumulatedErrorContext();
98
98
  const isAdditionalProperty = regexp.test(key) ||
99
- (ErrorSchema(stack, nextContext, nextSchemaPath, nextInstancePath, schema.additionalProperties, value[key]) && context.AddKey(key));
99
+ (ErrorSchemaPushStack(stack, nextContext, nextSchemaPath, nextInstancePath, schema.additionalProperties, value[key]) && context.AddKey(key));
100
100
  if (!isAdditionalProperty)
101
101
  additionalProperties.push(key);
102
102
  return isAdditionalProperty;
@@ -1,14 +1,14 @@
1
1
  // deno-fmt-ignore-file
2
2
  import * as Schema from '../types/index.mjs';
3
3
  import { Guard as G, EmitGuard as E } from '../../guard/index.mjs';
4
- import { BuildSchema, CheckSchema, ErrorSchema } from './schema.mjs';
4
+ import { BuildSchemaPushStack, CheckSchemaPushStack, ErrorSchemaPushStack } from './schema.mjs';
5
5
  // ------------------------------------------------------------------
6
6
  // ItemsSized
7
7
  // ------------------------------------------------------------------
8
8
  function BuildItemsSized(stack, context, schema, value) {
9
9
  return E.ReduceAnd(schema.items.map((schema, index) => {
10
10
  const isLength = E.IsLessEqualThan(E.Member(value, 'length'), E.Constant(index));
11
- const isSchema = BuildSchema(stack, context, schema, `${value}[${index}]`);
11
+ const isSchema = BuildSchemaPushStack(stack, context, schema, `${value}[${index}]`);
12
12
  const addIndex = context.AddIndex(E.Constant(index));
13
13
  const guarded = context.UseUnevaluated() ? E.And(isSchema, addIndex) : isSchema;
14
14
  return E.Or(isLength, guarded);
@@ -17,7 +17,7 @@ function BuildItemsSized(stack, context, schema, value) {
17
17
  function CheckItemsSized(stack, context, schema, value) {
18
18
  return G.Every(schema.items, 0, (schema, index) => {
19
19
  return G.IsLessEqualThan(value.length, index)
20
- || (CheckSchema(stack, context, schema, value[index]) && context.AddIndex(index));
20
+ || (CheckSchemaPushStack(stack, context, schema, value[index]) && context.AddIndex(index));
21
21
  });
22
22
  }
23
23
  function ErrorItemsSized(stack, context, schemaPath, instancePath, schema, value) {
@@ -25,7 +25,7 @@ function ErrorItemsSized(stack, context, schemaPath, instancePath, schema, value
25
25
  const nextSchemaPath = `${schemaPath}/items/${index}`;
26
26
  const nextInstancePath = `${instancePath}/${index}`;
27
27
  return G.IsLessEqualThan(value.length, index)
28
- || (ErrorSchema(stack, context, nextSchemaPath, nextInstancePath, schema, value[index]) && context.AddIndex(index));
28
+ || (ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema, value[index]) && context.AddIndex(index));
29
29
  });
30
30
  }
31
31
  // ------------------------------------------------------------------
@@ -33,7 +33,7 @@ function ErrorItemsSized(stack, context, schemaPath, instancePath, schema, value
33
33
  // ------------------------------------------------------------------
34
34
  function BuildItemsUnsized(stack, context, schema, value) {
35
35
  const offset = Schema.IsPrefixItems(schema) ? schema.prefixItems.length : 0;
36
- const isSchema = BuildSchema(stack, context, schema.items, 'element');
36
+ const isSchema = BuildSchemaPushStack(stack, context, schema.items, 'element');
37
37
  const addIndex = context.AddIndex('index');
38
38
  const guarded = context.UseUnevaluated() ? E.And(isSchema, addIndex) : isSchema;
39
39
  return E.Every(value, E.Constant(offset), ['element', 'index'], guarded);
@@ -41,7 +41,7 @@ function BuildItemsUnsized(stack, context, schema, value) {
41
41
  function CheckItemsUnsized(stack, context, schema, value) {
42
42
  const offset = Schema.IsPrefixItems(schema) ? schema.prefixItems.length : 0;
43
43
  return G.Every(value, offset, (element, index) => {
44
- return CheckSchema(stack, context, schema.items, element)
44
+ return CheckSchemaPushStack(stack, context, schema.items, element)
45
45
  && context.AddIndex(index);
46
46
  });
47
47
  }
@@ -50,7 +50,7 @@ function ErrorItemsUnsized(stack, context, schemaPath, instancePath, schema, val
50
50
  return G.EveryAll(value, offset, (element, index) => {
51
51
  const nextSchemaPath = `${schemaPath}/items`;
52
52
  const nextInstancePath = `${instancePath}/${index}`;
53
- return ErrorSchema(stack, context, nextSchemaPath, nextInstancePath, schema.items, element)
53
+ return ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema.items, element)
54
54
  && context.AddIndex(index);
55
55
  });
56
56
  }
@@ -2,7 +2,7 @@
2
2
  import * as Externals from './_externals.mjs';
3
3
  import { Unique } from './_unique.mjs';
4
4
  import { Guard as G, EmitGuard as E } from '../../guard/index.mjs';
5
- import { BuildSchema, CheckSchema, ErrorSchema } from './schema.mjs';
5
+ import { BuildSchemaPushStack, CheckSchemaPushStack, ErrorSchemaPushStack } from './schema.mjs';
6
6
  // ------------------------------------------------------------------
7
7
  // Build
8
8
  // ------------------------------------------------------------------
@@ -11,7 +11,7 @@ export function BuildPatternProperties(stack, context, schema, value) {
11
11
  const [key, prop] = [Unique(), Unique()];
12
12
  const regexp = Externals.CreateVariable(new RegExp(pattern, 'u'));
13
13
  const notKey = E.Not(E.Call(E.Member(regexp, 'test'), [key]));
14
- const isSchema = BuildSchema(stack, context, schema, prop);
14
+ const isSchema = BuildSchemaPushStack(stack, context, schema, prop);
15
15
  const addKey = context.AddKey(key);
16
16
  const guarded = context.UseUnevaluated() ? E.Or(notKey, E.And(isSchema, addKey)) : E.Or(notKey, isSchema);
17
17
  return E.Every(E.Entries(value), E.Constant(0), [`[${key}, ${prop}]`, '_'], guarded);
@@ -24,7 +24,7 @@ export function CheckPatternProperties(stack, context, schema, value) {
24
24
  return G.Every(G.Entries(schema.patternProperties), 0, ([pattern, schema]) => {
25
25
  const regexp = new RegExp(pattern, 'u');
26
26
  return G.Every(G.Entries(value), 0, ([key, prop]) => {
27
- return !regexp.test(key) || CheckSchema(stack, context, schema, prop) && context.AddKey(key);
27
+ return !regexp.test(key) || CheckSchemaPushStack(stack, context, schema, prop) && context.AddKey(key);
28
28
  });
29
29
  });
30
30
  }
@@ -38,7 +38,7 @@ export function ErrorPatternProperties(stack, context, schemaPath, instancePath,
38
38
  return G.EveryAll(G.Entries(value), 0, ([key, value]) => {
39
39
  const nextInstancePath = `${instancePath}/${key}`;
40
40
  const notKey = !regexp.test(key);
41
- return notKey || ErrorSchema(stack, context, nextSchemaPath, nextInstancePath, schema, value) && context.AddKey(key);
41
+ return notKey || ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema, value) && context.AddKey(key);
42
42
  });
43
43
  });
44
44
  }
@@ -1,13 +1,13 @@
1
1
  // deno-fmt-ignore-file
2
2
  import { Guard as G, EmitGuard as E } from '../../guard/index.mjs';
3
- import { BuildSchema, CheckSchema, ErrorSchema } from './schema.mjs';
3
+ import { BuildSchemaPushStack, CheckSchemaPushStack, ErrorSchemaPushStack } from './schema.mjs';
4
4
  // ------------------------------------------------------------------
5
5
  // Build
6
6
  // ------------------------------------------------------------------
7
7
  export function BuildPrefixItems(stack, context, schema, value) {
8
8
  return E.ReduceAnd(schema.prefixItems.map((schema, index) => {
9
9
  const isLength = E.IsLessEqualThan(E.Member(value, 'length'), E.Constant(index));
10
- const isSchema = BuildSchema(stack, context, schema, `${value}[${index}]`);
10
+ const isSchema = BuildSchemaPushStack(stack, context, schema, `${value}[${index}]`);
11
11
  const addIndex = context.AddIndex(E.Constant(index));
12
12
  const guarded = context.UseUnevaluated() ? E.And(isSchema, addIndex) : isSchema;
13
13
  return E.Or(isLength, guarded);
@@ -19,7 +19,7 @@ export function BuildPrefixItems(stack, context, schema, value) {
19
19
  export function CheckPrefixItems(stack, context, schema, value) {
20
20
  return G.IsEqual(value.length, 0) || G.Every(schema.prefixItems, 0, (schema, index) => {
21
21
  return G.IsLessEqualThan(value.length, index)
22
- || (CheckSchema(stack, context, schema, value[index]) && context.AddIndex(index));
22
+ || (CheckSchemaPushStack(stack, context, schema, value[index]) && context.AddIndex(index));
23
23
  });
24
24
  }
25
25
  // ------------------------------------------------------------------
@@ -30,6 +30,6 @@ export function ErrorPrefixItems(stack, context, schemaPath, instancePath, schem
30
30
  const nextSchemaPath = `${schemaPath}/prefixItems/${index}`;
31
31
  const nextInstancePath = `${instancePath}/${index}`;
32
32
  return G.IsLessEqualThan(value.length, index)
33
- || (ErrorSchema(stack, context, nextSchemaPath, nextInstancePath, schema, value[index]) && context.AddIndex(index));
33
+ || (ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema, value[index]) && context.AddIndex(index));
34
34
  });
35
35
  }
@@ -1,7 +1,7 @@
1
1
  // deno-fmt-ignore-file
2
2
  import * as Schema from '../types/index.mjs';
3
3
  import { Guard as G, EmitGuard as E } from '../../guard/index.mjs';
4
- import { BuildSchema, CheckSchema, ErrorSchema } from './schema.mjs';
4
+ import { BuildSchemaPushStack, CheckSchemaPushStack, ErrorSchemaPushStack } from './schema.mjs';
5
5
  import { InexactOptionalCheck, InexactOptionalBuild, IsExactOptional } from './_exact_optional.mjs';
6
6
  // ------------------------------------------------------------------
7
7
  // Build
@@ -10,7 +10,7 @@ export function BuildProperties(stack, context, schema, value) {
10
10
  const required = Schema.IsRequired(schema) ? schema.required : [];
11
11
  const everyKey = G.Entries(schema.properties).map(([key, schema]) => {
12
12
  const notKey = E.Not(E.HasPropertyKey(value, E.Constant(key)));
13
- const isSchema = BuildSchema(stack, context, schema, E.Member(value, key));
13
+ const isSchema = BuildSchemaPushStack(stack, context, schema, E.Member(value, key));
14
14
  const addKey = context.AddKey(E.Constant(key));
15
15
  const guarded = context.UseUnevaluated() ? E.And(isSchema, addKey) : isSchema;
16
16
  // --------------------------------------------------------------
@@ -50,7 +50,7 @@ export function BuildProperties(stack, context, schema, value) {
50
50
  export function CheckProperties(stack, context, schema, value) {
51
51
  const required = Schema.IsRequired(schema) ? schema.required : [];
52
52
  const isProperties = G.Every(G.Entries(schema.properties), 0, ([key, schema]) => {
53
- const isProperty = !G.HasPropertyKey(value, key) || (CheckSchema(stack, context, schema, value[key]) && context.AddKey(key));
53
+ const isProperty = !G.HasPropertyKey(value, key) || (CheckSchemaPushStack(stack, context, schema, value[key]) && context.AddKey(key));
54
54
  return IsExactOptional(required, key)
55
55
  ? isProperty
56
56
  : InexactOptionalCheck(value, key) || isProperty;
@@ -66,7 +66,7 @@ export function ErrorProperties(stack, context, schemaPath, instancePath, schema
66
66
  const nextSchemaPath = `${schemaPath}/properties/${key}`;
67
67
  const nextInstancePath = `${instancePath}/${key}`;
68
68
  // Defer error generation for IsExactOptional
69
- const isProperty = () => (!G.HasPropertyKey(value, key) || (ErrorSchema(stack, context, nextSchemaPath, nextInstancePath, schema, value[key]) && context.AddKey(key)));
69
+ const isProperty = () => (!G.HasPropertyKey(value, key) || (ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema, value[key]) && context.AddKey(key)));
70
70
  return IsExactOptional(required, key)
71
71
  ? isProperty()
72
72
  : InexactOptionalCheck(value, key) || isProperty();
@@ -1,6 +1,9 @@
1
1
  import * as Schema from '../types/index.mjs';
2
2
  import { Stack } from './_stack.mjs';
3
3
  import { BuildContext, CheckContext, ErrorContext } from './_context.mjs';
4
+ export declare function BuildSchemaPushStack(stack: Stack, context: BuildContext, schema: Schema.XSchema, value: string): string;
4
5
  export declare function BuildSchema(stack: Stack, context: BuildContext, schema: Schema.XSchema, value: string): string;
6
+ export declare function CheckSchemaPushStack(stack: Stack, context: CheckContext, schema: Schema.XSchema, value: unknown): boolean;
5
7
  export declare function CheckSchema(stack: Stack, context: CheckContext, schema: Schema.XSchema, value: unknown): boolean;
8
+ export declare function ErrorSchemaPushStack(stack: Stack, context: ErrorContext, schemaPath: string, instancePath: string, schema: Schema.XSchema, value: unknown): boolean;
6
9
  export declare function ErrorSchema(stack: Stack, context: ErrorContext, schemaPath: string, instancePath: string, schema: Schema.XSchema, value: unknown): boolean;
@@ -117,6 +117,11 @@ function HasNumberKeywords(schema) {
117
117
  // ----------------------------------------------------------------
118
118
  // Build
119
119
  // ----------------------------------------------------------------
120
+ export function BuildSchemaPushStack(stack, context, schema, value) {
121
+ return context.UseUnevaluated()
122
+ ? E.And(E.And(context.Push(), BuildSchema(stack, context, schema, value)), context.Pop())
123
+ : BuildSchema(stack, context, schema, value);
124
+ }
120
125
  export function BuildSchema(stack, context, schema, value) {
121
126
  stack.Push(schema);
122
127
  const conditions = [];
@@ -237,6 +242,9 @@ export function BuildSchema(stack, context, schema, value) {
237
242
  // ----------------------------------------------------------------
238
243
  // Check
239
244
  // ----------------------------------------------------------------
245
+ export function CheckSchemaPushStack(stack, context, schema, value) {
246
+ return (context.Push() && CheckSchema(stack, context, schema, value)) && context.Pop();
247
+ }
240
248
  export function CheckSchema(stack, context, schema, value) {
241
249
  stack.Push(schema);
242
250
  const result = Schema.IsBooleanSchema(schema) ? CheckBooleanSchema(stack, context, schema, value) : ((!Schema.IsType(schema) || CheckType(stack, context, schema, value)) &&
@@ -287,6 +295,9 @@ export function CheckSchema(stack, context, schema, value) {
287
295
  // ----------------------------------------------------------------
288
296
  // Error
289
297
  // ----------------------------------------------------------------
298
+ export function ErrorSchemaPushStack(stack, context, schemaPath, instancePath, schema, value) {
299
+ return (context.Push() && ErrorSchema(stack, context, schemaPath, instancePath, schema, value)) && context.Pop();
300
+ }
290
301
  export function ErrorSchema(stack, context, schemaPath, instancePath, schema, value) {
291
302
  stack.Push(schema);
292
303
  const result = (Schema.IsBooleanSchema(schema)) ? ErrorBooleanSchema(stack, context, schemaPath, instancePath, schema, value) : (!!(+(!Schema.IsType(schema) || ErrorType(stack, context, schemaPath, instancePath, schema, value)) &
@@ -155,30 +155,7 @@ export interface TNumberOptions extends TSchemaOptions {
155
155
  export type TFormat = 'date-time' | 'date' | 'duration' | 'email' | 'hostname' | 'idn-email' | 'idn-hostname' | 'ipv4' | 'ipv6' | 'iri-reference' | 'iri' | 'json-pointer-uri-fragment' | 'json-pointer' | 'json-string' | 'regex' | 'relative-json-pointer' | 'time' | 'uri-reference' | 'uri-template' | 'uri' | 'url' | 'uuid' | ({} & string);
156
156
  export interface TStringOptions extends TSchemaOptions {
157
157
  /**
158
- * Specifies the expected string format.
159
- *
160
- * Common values include:
161
- * - `base64` – Base64-encoded string.
162
- * - `date-time` – [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date-time format.
163
- * - `date` – [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date (YYYY-MM-DD).
164
- * - `duration` – [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) duration format.
165
- * - `email` – RFC 5321/5322 compliant email address.
166
- * - `hostname` – RFC 1034/1035 compliant host name.
167
- * - `idn-email` – Internationalized email address.
168
- * - `idn-hostname` – Internationalized host name.
169
- * - `ipv4` – IPv4 address.
170
- * - `ipv6` – IPv6 address.
171
- * - `iri` / `iri-reference` – Internationalized Resource Identifier.
172
- * - `json-pointer` / `json-pointer-uri-fragment` – JSON Pointer format.
173
- * - `json-string` – String containing valid JSON.
174
- * - `regex` – Regular expression syntax.
175
- * - `relative-json-pointer` – Relative JSON Pointer format.
176
- * - `time` – [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) time (HH:MM:SS).
177
- * - `uri-reference` / `uri-template` – URI reference or template.
178
- * - `url` – Web URL format.
179
- * - `uuid` – RFC 4122 UUID string.
180
- *
181
- * May also be a custom format string.
158
+ * Specifies the expected string format. May also be a custom format string.
182
159
  */
183
160
  format?: TFormat;
184
161
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "typebox",
3
3
  "description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
4
- "version": "1.1.15",
4
+ "version": "1.1.17",
5
5
  "keywords": [
6
6
  "typescript",
7
7
  "jsonschema"