typebox 1.3.11 → 1.3.13

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 (91) hide show
  1. package/build/format/date.d.mts +1 -1
  2. package/build/format/date.mjs +1 -1
  3. package/build/format/date_time.d.mts +2 -2
  4. package/build/format/date_time.mjs +3 -3
  5. package/build/format/email.d.mts +1 -1
  6. package/build/format/email.mjs +2 -2
  7. package/build/format/hostname.mjs +2 -10
  8. package/build/format/idn_email.d.mts +1 -1
  9. package/build/format/idn_email.mjs +3 -3
  10. package/build/format/idn_hostname.d.mts +1 -0
  11. package/build/format/idn_hostname.mjs +3 -11
  12. package/build/format/idna/format/bidi.d.mts +3 -0
  13. package/build/format/idna/format/bidi.mjs +98 -0
  14. package/build/format/idna/format/puny.d.mts +3 -0
  15. package/build/format/idna/format/puny.mjs +144 -0
  16. package/build/format/idna/hostname.d.mts +1 -0
  17. package/build/format/idna/hostname.mjs +16 -0
  18. package/build/format/idna/idn-hostname.d.mts +1 -0
  19. package/build/format/idna/idn-hostname.mjs +23 -0
  20. package/build/format/idna/index.d.mts +2 -0
  21. package/build/format/idna/index.mjs +2 -0
  22. package/build/format/idna/label/ascii.d.mts +1 -0
  23. package/build/format/idna/label/ascii.mjs +9 -0
  24. package/build/format/idna/label/puny.d.mts +1 -0
  25. package/build/format/idna/label/puny.mjs +28 -0
  26. package/build/format/idna/label/unicode.d.mts +1 -0
  27. package/build/format/idna/label/unicode.mjs +106 -0
  28. package/build/format/idna/pattern/pattern.d.mts +30 -0
  29. package/build/format/idna/pattern/pattern.mjs +70 -0
  30. package/build/format/ipv4.d.mts +0 -1
  31. package/build/format/ipv4.mjs +2 -32
  32. package/build/format/ipv6.mjs +2 -61
  33. package/build/format/iri.d.mts +1 -1
  34. package/build/format/iri.mjs +2 -8
  35. package/build/format/iri_reference.d.mts +2 -2
  36. package/build/format/iri_reference.mjs +9 -55
  37. package/build/format/regex.d.mts +1 -2
  38. package/build/format/regex.mjs +2 -6
  39. package/build/format/time.d.mts +2 -2
  40. package/build/format/time.mjs +19 -14
  41. package/build/format/uri.mjs +2 -129
  42. package/build/format/uri_template.d.mts +0 -1
  43. package/build/format/uri_template.mjs +1 -2
  44. package/build/format/url.d.mts +2 -2
  45. package/build/format/url.mjs +3 -4
  46. package/build/guard/guard.mjs +2 -2
  47. package/build/guard/string.d.mts +2 -2
  48. package/build/guard/string.mjs +7 -7
  49. package/build/schema/engine/_regexp.d.mts +2 -0
  50. package/build/schema/engine/_regexp.mjs +4 -0
  51. package/build/schema/engine/_stack.mjs +1 -1
  52. package/build/schema/engine/additionalProperties.mjs +4 -3
  53. package/build/schema/engine/pattern.mjs +3 -2
  54. package/build/schema/engine/patternProperties.mjs +4 -3
  55. package/build/schema/engine/schema.mjs +13 -4
  56. package/build/schema/resolve/ref.d.mts +1 -0
  57. package/build/schema/resolve/ref.mjs +13 -3
  58. package/build/schema/types/index.d.mts +0 -2
  59. package/build/schema/types/index.mjs +0 -2
  60. package/build/system/memory/clone.mjs +1 -1
  61. package/build/system/memory/discard.mjs +2 -1
  62. package/build/type/engine/evaluate/broaden.d.mts +5 -5
  63. package/build/type/engine/evaluate/broaden.mjs +20 -26
  64. package/build/type/engine/evaluate/compare.d.mts +6 -10
  65. package/build/type/engine/evaluate/compare.mjs +9 -13
  66. package/build/type/engine/evaluate/composite.d.mts +7 -4
  67. package/build/type/engine/evaluate/composite.mjs +12 -19
  68. package/build/type/engine/evaluate/distribute.d.mts +4 -20
  69. package/build/type/engine/evaluate/distribute.mjs +8 -20
  70. package/build/type/engine/evaluate/evaluate.d.mts +4 -4
  71. package/build/type/engine/evaluate/evaluate.mjs +11 -8
  72. package/build/type/engine/evaluate/flatten.d.mts +1 -1
  73. package/build/type/engine/evaluate/flatten.mjs +3 -4
  74. package/build/type/engine/evaluate/narrow.d.mts +17 -2
  75. package/build/type/engine/evaluate/narrow.mjs +26 -6
  76. package/build/type/engine/exclude/operation.mjs +3 -4
  77. package/build/type/engine/extract/operation.d.mts +1 -1
  78. package/build/type/engine/extract/operation.mjs +3 -4
  79. package/build/type/engine/priority/priority.d.mts +2 -2
  80. package/build/type/engine/priority/priority.mjs +3 -4
  81. package/build/type/script/parser.mjs +8 -1
  82. package/package.json +1 -1
  83. package/readme.md +3 -4
  84. package/build/format/_idna.d.mts +0 -2
  85. package/build/format/_idna.mjs +0 -246
  86. package/build/format/_puny.d.mts +0 -1
  87. package/build/format/_puny.mjs +0 -77
  88. package/build/schema/types/contentEncoding.d.mts +0 -9
  89. package/build/schema/types/contentEncoding.mjs +0 -13
  90. package/build/schema/types/contentMediaType.d.mts +0 -9
  91. package/build/schema/types/contentMediaType.mjs +0 -13
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Returns true if the value is a ISO8601 Date component string
3
- * @source ajv-formats
3
+ * @description https://datatracker.ietf.org/doc/html/rfc3339
4
4
  * @example `2020-12-12`
5
5
  */
6
6
  export declare function IsDate(value: string): boolean;
@@ -5,7 +5,7 @@ function IsLeapYear(year) {
5
5
  }
6
6
  /**
7
7
  * Returns true if the value is a ISO8601 Date component string
8
- * @source ajv-formats
8
+ * @description https://datatracker.ietf.org/doc/html/rfc3339
9
9
  * @example `2020-12-12`
10
10
  */
11
11
  export function IsDate(value) {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Returns true if the value is a ISO8601 DateTime string
3
- * @source ajv-formats
3
+ * @specification https://datatracker.ietf.org/doc/html/rfc3339
4
4
  * @example `2020-12-12T20:20:40+00:00`
5
5
  */
6
- export declare function IsDateTime(value: string, strictTimeZone?: boolean): boolean;
6
+ export declare function IsDateTime(value: string): boolean;
@@ -2,10 +2,10 @@ import { IsDate } from './date.mjs';
2
2
  import { IsTime } from './time.mjs';
3
3
  /**
4
4
  * Returns true if the value is a ISO8601 DateTime string
5
- * @source ajv-formats
5
+ * @specification https://datatracker.ietf.org/doc/html/rfc3339
6
6
  * @example `2020-12-12T20:20:40+00:00`
7
7
  */
8
- export function IsDateTime(value, strictTimeZone = true) {
8
+ export function IsDateTime(value) {
9
9
  const dateTime = value.split(/T/i);
10
- return dateTime.length === 2 && IsDate(dateTime[0]) && IsTime(dateTime[1], strictTimeZone);
10
+ return dateTime.length === 2 && IsDate(dateTime[0]) && IsTime(dateTime[1]);
11
11
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * Returns true if the value is an Email
3
- * @specification ajv-formats
3
+ * @specification https://datatracker.ietf.org/doc/html/rfc5322
4
4
  */
5
5
  export declare function IsEmail(value: string): boolean;
@@ -1,7 +1,7 @@
1
- const Email = /^(?!.*\.\.)[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i;
1
+ const Email = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[^"\\]|\\.)*")@(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*|\[(?:IPv6:[a-f0-9:]+|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})\])$/i;
2
2
  /**
3
3
  * Returns true if the value is an Email
4
- * @specification ajv-formats
4
+ * @specification https://datatracker.ietf.org/doc/html/rfc5322
5
5
  */
6
6
  export function IsEmail(value) {
7
7
  return Email.test(value);
@@ -1,4 +1,4 @@
1
- import * as Idna from './_idna.mjs';
1
+ import * as Idna from './idna/index.mjs';
2
2
  /**
3
3
  * Returns true if the value is a valid hostname.
4
4
  * @specification https://tools.ietf.org/html/rfc1123
@@ -6,13 +6,5 @@ import * as Idna from './_idna.mjs';
6
6
  * @specification https://tools.ietf.org/html/rfc5892
7
7
  */
8
8
  export function IsHostname(value) {
9
- if (value.length === 0 || value.length > 253)
10
- return false;
11
- if (value.charCodeAt(value.length - 1) === 46)
12
- return false;
13
- for (const label of value.split('.')) {
14
- if (!Idna.IsLabel(label))
15
- return false;
16
- }
17
- return true;
9
+ return Idna.IsHostname(value);
18
10
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * Returns true if the value is an IdnEmail
3
- * @specification ajv-formats (unicode-extension)
3
+ * @specification https://datatracker.ietf.org/doc/html/rfc4952
4
4
  */
5
5
  export declare function IsIdnEmail(value: string): boolean;
@@ -1,8 +1,8 @@
1
- const IdnEmail = /^(?!.*\.\.)[\p{L}\p{N}!#$%&'*+/=?^_`{|}~-]+(?:\.[\p{L}\p{N}!#$%&'*+/=?^_`{|}~-]+)*@[\p{L}\p{N}](?:[\p{L}\p{N}-]{0,61}[\p{L}\p{N}])?(?:\.[\p{L}\p{N}](?:[\p{L}\p{N}-]{0,61}[\p{L}\p{N}])?)*$/iu;
1
+ const IdnEmail = /^(?:[A-Za-z0-9!#$%&'*+\/=?^_`{|}~\u{0080}-\u{10FFFF}-]+(?:\.[A-Za-z0-9!#$%&'*+\/=?^_`{|}~\u{0080}-\u{10FFFF}-]+)*|"(?:[^"\\]|\\.)*")@[\p{L}\p{N}](?:[\p{L}\p{N}-]{0,62})(?<!-)(?:\.[\p{L}\p{N}](?:[\p{L}\p{N}-]{0,62})(?<!-))*$/iu;
2
2
  /**
3
3
  * Returns true if the value is an IdnEmail
4
- * @specification ajv-formats (unicode-extension)
4
+ * @specification https://datatracker.ietf.org/doc/html/rfc4952
5
5
  */
6
6
  export function IsIdnEmail(value) {
7
- return IdnEmail.test(value);
7
+ return IdnEmail.test(value.normalize('NFC'));
8
8
  }
@@ -3,5 +3,6 @@
3
3
  * @specification https://tools.ietf.org/html/rfc3490
4
4
  * @specification https://tools.ietf.org/html/rfc5891
5
5
  * @specification https://tools.ietf.org/html/rfc5892
6
+ * @specification https://tools.ietf.org/html/rfc5893
6
7
  */
7
8
  export declare function IsIdnHostname(value: string): boolean;
@@ -1,19 +1,11 @@
1
- import { IsIdnLabel } from './_idna.mjs';
1
+ import * as Idna from './idna/index.mjs';
2
2
  /**
3
3
  * Returns true if the value is a valid internationalized (IDN) hostname.
4
4
  * @specification https://tools.ietf.org/html/rfc3490
5
5
  * @specification https://tools.ietf.org/html/rfc5891
6
6
  * @specification https://tools.ietf.org/html/rfc5892
7
+ * @specification https://tools.ietf.org/html/rfc5893
7
8
  */
8
9
  export function IsIdnHostname(value) {
9
- if (value.length === 0 || value.includes(' '))
10
- return false;
11
- const canonical = value.normalize('NFC').replace(/[\u002E\u3002\uFF0E\uFF61]/g, '.');
12
- if (canonical.length > 253)
13
- return false;
14
- for (const label of canonical.split('.')) {
15
- if (!IsIdnLabel(label))
16
- return false;
17
- }
18
- return true;
10
+ return Idna.IsIdnHostname(value);
19
11
  }
@@ -0,0 +1,3 @@
1
+ export declare function HasBidiChars(value: string): boolean;
2
+ export declare function HasRightToLeftCharacters(value: string): boolean;
3
+ export declare function SatisfiesBidiRule(value: string): boolean;
@@ -0,0 +1,98 @@
1
+ // deno-fmt-ignore-file
2
+ import * as FormatPuny from './puny.mjs';
3
+ import * as Pattern from '../pattern/pattern.mjs';
4
+ // ------------------------------------------------------------------
5
+ // LOCAL REGEX: Allowed Bidi classes per direction (RFC 5893)
6
+ // ------------------------------------------------------------------
7
+ const RE_RTL_ALLOWED = /^(?:R|AL|AN|EN|ES|CS|ET|ON|BN|NSM)$/;
8
+ const RE_LTR_ALLOWED = /^(?:L|EN|ES|CS|ET|ON|BN|NSM)$/;
9
+ const RE_RTL_CLASSES = /^(?:R|AL|AN)$/;
10
+ // ------------------------------------------------------------------
11
+ // HasBidiChars
12
+ //
13
+ // Decodes a punycode label to its Unicode form (if it is one) and
14
+ // checks whether the result is an RTL label per RFC 5893 §1.4.
15
+ // ------------------------------------------------------------------
16
+ export function HasBidiChars(value) {
17
+ if (FormatPuny.IsAcePrefixed(value)) {
18
+ try {
19
+ return HasRightToLeftCharacters(FormatPuny.Decode(value.slice(4).toLowerCase()));
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ return HasRightToLeftCharacters(value);
26
+ }
27
+ // ------------------------------------------------------------------
28
+ // GetBidiClass
29
+ // ------------------------------------------------------------------
30
+ function GetBidiClass(codePoint) {
31
+ const char = String.fromCodePoint(codePoint);
32
+ return (Pattern.RE_EUROPEAN_NUMBER.test(char) ? 'EN' :
33
+ Pattern.RE_ARABIC_INDIC_DIGIT.test(char) ? 'AN' :
34
+ // Pattern.RE_EUROPEAN_SEPARATOR.test(char) ? 'ES' : // (no-spec-coverage)
35
+ // Pattern.RE_COMMON_SEPARATOR.test(char) ? 'CS' : // (no-spec-coverage)
36
+ Pattern.RE_MARK_NONSPACING.test(char) ? 'NSM' :
37
+ Pattern.RE_SCRIPT_HEBREW.test(char) ? 'R' :
38
+ Pattern.RE_SCRIPT_ARABIC_LETTER.test(char) ? 'AL' :
39
+ Pattern.RE_LETTER.test(char) ? 'L' :
40
+ 'ON');
41
+ }
42
+ // ------------------------------------------------------------------
43
+ // HasRightToLeftCharacters
44
+ //
45
+ // Per RFC 5893 §1.4: "An RTL label is a label that contains at least
46
+ // one character of type R, AL, or AN." Used to determine whether a
47
+ // domain name is a "Bidi domain name" (RFC 5893 §1.4), in which case
48
+ // the Bidi Rule applies to every label in the domain.
49
+ // ------------------------------------------------------------------
50
+ export function HasRightToLeftCharacters(value) {
51
+ for (const ch of value)
52
+ if (RE_RTL_CLASSES.test(GetBidiClass(ch.codePointAt(0))))
53
+ return true;
54
+ return false;
55
+ }
56
+ // ------------------------------------------------------------------
57
+ // SatisfiesBidiRule
58
+ // ------------------------------------------------------------------
59
+ export function SatisfiesBidiRule(value) {
60
+ let isRtl = false;
61
+ let allowed = RE_LTR_ALLOWED;
62
+ let sawEN = false;
63
+ let sawAN = false;
64
+ let isFirst = true;
65
+ // let lastClass: string | null = null // (no-spec-coverage)
66
+ for (const ch of value) {
67
+ const bidiClass = GetBidiClass(ch.codePointAt(0));
68
+ if (isFirst) {
69
+ // 1. The first character must be a character with Bidi property L, R, or AL.
70
+ if (bidiClass !== 'L' && bidiClass !== 'R' && bidiClass !== 'AL')
71
+ return false;
72
+ isRtl = bidiClass === 'R' || bidiClass === 'AL';
73
+ allowed = isRtl ? RE_RTL_ALLOWED : RE_LTR_ALLOWED;
74
+ isFirst = false;
75
+ }
76
+ // 2 / 5. Only characters in the allowed set for this direction may appear.
77
+ if (!allowed.test(bidiClass))
78
+ return false;
79
+ if (bidiClass === 'EN')
80
+ sawEN = true;
81
+ else if (bidiClass === 'AN')
82
+ sawAN = true;
83
+ // if (bidiClass !== 'NSM') lastClass = bidiClass // (no-spec-coverage)
84
+ }
85
+ if (isRtl && sawEN && sawAN)
86
+ return false; // spec coverage path
87
+ // (no-spec-coverage)
88
+ // if (isRtl) {
89
+ // // 3. The end of the label must be R, AL, EN, or AN (ignoring trailing NSM).
90
+ // // if (lastClass !== 'R' && lastClass !== 'AL' && lastClass !== 'EN' && lastClass !== 'AN') return false
91
+ // // 4. If an EN is present, no AN may be present, and vice versa.
92
+ // if (sawEN && sawAN) return false
93
+ // } else {
94
+ // // 6. The end of the label must be L or EN (ignoring trailing NSM).
95
+ // // if (lastClass !== 'L' && lastClass !== 'EN') return false
96
+ // }
97
+ return true;
98
+ }
@@ -0,0 +1,3 @@
1
+ export declare function IsAcePrefixed(value: string): boolean;
2
+ export declare function Decode(value: string): string;
3
+ export declare function Encode(input: string): string;
@@ -0,0 +1,144 @@
1
+ import * as Pattern from '../pattern/pattern.mjs';
2
+ // ------------------------------------------------------------------
3
+ // PunyCode (RFC 3492)
4
+ // ------------------------------------------------------------------
5
+ const PUNYCODE_BASE = 36;
6
+ const PUNYCODE_TMIN = 1;
7
+ const PUNYCODE_TMAX = 26;
8
+ const PUNYCODE_SKEW = 38;
9
+ const PUNYCODE_DAMP = 700;
10
+ const PUNYCODE_INITIAL_BIAS = 72;
11
+ const PUNYCODE_INITIAL_N = 128;
12
+ // ------------------------------------------------------------------
13
+ // ThrowDontCare
14
+ // ------------------------------------------------------------------
15
+ function ThrowDontCare() {
16
+ throw null;
17
+ }
18
+ // ------------------------------------------------------------------
19
+ // IsAcePrefixed
20
+ // ------------------------------------------------------------------
21
+ export function IsAcePrefixed(value) {
22
+ return value.toLowerCase().startsWith('xn--');
23
+ }
24
+ // ------------------------------------------------------------------
25
+ // Adapt
26
+ // ------------------------------------------------------------------
27
+ function Adapt(delta, numPoints, firstTime) {
28
+ delta = firstTime ? Math.floor(delta / PUNYCODE_DAMP) : delta >> 1;
29
+ delta += Math.floor(delta / numPoints);
30
+ let k = 0;
31
+ while (delta > (((PUNYCODE_BASE - PUNYCODE_TMIN) * PUNYCODE_TMAX) >> 1)) {
32
+ delta = Math.floor(delta / (PUNYCODE_BASE - PUNYCODE_TMIN));
33
+ k += PUNYCODE_BASE;
34
+ }
35
+ return k + Math.floor(((PUNYCODE_BASE - PUNYCODE_TMIN + 1) * delta) / (delta + PUNYCODE_SKEW));
36
+ }
37
+ // ------------------------------------------------------------------
38
+ // Decode
39
+ // ------------------------------------------------------------------
40
+ export function Decode(value) {
41
+ const output = [];
42
+ let n = PUNYCODE_INITIAL_N;
43
+ let i = 0;
44
+ let bias = PUNYCODE_INITIAL_BIAS;
45
+ const delimIdx = value.lastIndexOf('-');
46
+ if (delimIdx > 0) {
47
+ for (let j = 0; j < delimIdx; j++) {
48
+ const cp = value.charCodeAt(j);
49
+ if (cp >= 128)
50
+ ThrowDontCare(); // throw new Error('Invalid punycode: non-basic before delimiter')
51
+ output.push(cp);
52
+ }
53
+ }
54
+ let inIdx = delimIdx < 0 ? 0 : delimIdx + 1;
55
+ while (inIdx < value.length) {
56
+ const oldi = i;
57
+ let w = 1;
58
+ let k = PUNYCODE_BASE;
59
+ while (true) {
60
+ if (inIdx >= value.length)
61
+ ThrowDontCare(); // throw new Error('Invalid punycode: unexpected end of input')
62
+ const ch = value.charCodeAt(inIdx++);
63
+ let digit;
64
+ if (ch >= 0x61 && ch <= 0x7a)
65
+ digit = ch - 0x61; // a-z => 0-25
66
+ else if (ch >= 0x30 && ch <= 0x39)
67
+ digit = ch - 0x30 + 26; // 0-9 => 26-35
68
+ // else if (ch >= 0x41 && ch <= 0x5a) digit = ch - 0x41 // A-Z => 0-25 // (no-spec-coverage)
69
+ else
70
+ ThrowDontCare(); // throw new Error('Invalid punycode: bad digit character')
71
+ i += digit * w;
72
+ const t = k <= bias ? PUNYCODE_TMIN : k >= bias + PUNYCODE_TMAX ? PUNYCODE_TMAX : k - bias;
73
+ if (digit < t)
74
+ break;
75
+ w *= PUNYCODE_BASE - t;
76
+ k += PUNYCODE_BASE;
77
+ }
78
+ const outLen = output.length + 1;
79
+ bias = Adapt(i - oldi, outLen, oldi === 0);
80
+ n += Math.floor(i / outLen);
81
+ i %= outLen;
82
+ output.splice(i, 0, n);
83
+ i++;
84
+ }
85
+ return String.fromCodePoint(...output);
86
+ }
87
+ // ------------------------------------------------------------------
88
+ // DigitToChar
89
+ // ------------------------------------------------------------------
90
+ function DigitToChar(digit) {
91
+ return digit < 26 ? String.fromCharCode(digit + 0x61) : String.fromCharCode(digit - 26 + 0x30);
92
+ }
93
+ // ------------------------------------------------------------------
94
+ // Encode
95
+ //
96
+ // Encodes a Unicode string into its Punycode payload (the part that
97
+ // follows the 'xn--' ACE prefix). Used to compute the true A-label
98
+ // length of a U-label, since the 63-octet label length limit (RFC
99
+ // 5891 §4.2.4) applies to the encoded form, not the code point count.
100
+ // ------------------------------------------------------------------
101
+ const RE_REPLACE_NON_ASCII = new RegExp(Pattern.RE_NON_ASCII.source, 'gu');
102
+ export function Encode(input) {
103
+ // Extract basic ASCII characters and set initial output array state
104
+ const basic = input.replace(RE_REPLACE_NON_ASCII, '');
105
+ const basicLength = basic.length;
106
+ const result = basicLength > 0 ? [basic, '-'] : [];
107
+ // Extract unicode codepoints
108
+ const codePoints = Array.from(input, (char) => char.codePointAt(0));
109
+ let n = PUNYCODE_INITIAL_N;
110
+ let delta = 0;
111
+ let bias = PUNYCODE_INITIAL_BIAS;
112
+ let handledCPCount = basicLength;
113
+ while (handledCPCount < codePoints.length) {
114
+ let m = Infinity;
115
+ for (const cp of codePoints) {
116
+ if (cp >= n && cp < m)
117
+ m = cp;
118
+ }
119
+ delta += (m - n) * (handledCPCount + 1);
120
+ n = m;
121
+ for (const cp of codePoints) {
122
+ if (cp < n)
123
+ delta++;
124
+ if (cp === n) {
125
+ let q = delta;
126
+ for (let k = PUNYCODE_BASE;; k += PUNYCODE_BASE) {
127
+ const t = k <= bias ? PUNYCODE_TMIN : k >= bias + PUNYCODE_TMAX ? PUNYCODE_TMAX : k - bias;
128
+ if (q < t)
129
+ break;
130
+ const digit = t + ((q - t) % (PUNYCODE_BASE - t));
131
+ result.push(DigitToChar(digit));
132
+ q = Math.floor((q - t) / (PUNYCODE_BASE - t));
133
+ }
134
+ result.push(DigitToChar(q));
135
+ bias = Adapt(delta, handledCPCount + 1, handledCPCount === basicLength);
136
+ delta = 0;
137
+ handledCPCount++;
138
+ }
139
+ }
140
+ delta++;
141
+ n++;
142
+ }
143
+ return result.join('');
144
+ }
@@ -0,0 +1 @@
1
+ export declare function IsHostname(value: string): boolean;
@@ -0,0 +1,16 @@
1
+ import * as LabelAscii from './label/ascii.mjs';
2
+ import * as LabelPuny from './label/puny.mjs';
3
+ function IsValidLabelLength(value) {
4
+ return value.length > 0 && value.length <= 63;
5
+ }
6
+ function IsLabel(value) {
7
+ return IsValidLabelLength(value) && (LabelPuny.IsPunyLabel(value) ||
8
+ LabelAscii.IsAsciiLabel(value));
9
+ }
10
+ export function IsHostname(value) {
11
+ if (value.length === 0 || value.length > 253)
12
+ return false;
13
+ if (value.charCodeAt(value.length - 1) === 46)
14
+ return false;
15
+ return value.split('.').every((label) => IsLabel(label));
16
+ }
@@ -0,0 +1 @@
1
+ export declare function IsIdnHostname(value: string): boolean;
@@ -0,0 +1,23 @@
1
+ import * as FormatBidi from './format/bidi.mjs';
2
+ import * as LabelUnicode from './label/unicode.mjs';
3
+ import * as LabelPuny from './label/puny.mjs';
4
+ function IsValidLabelLength(value) {
5
+ return value.length > 0 && value.length <= 63;
6
+ }
7
+ function IsLabel(value) {
8
+ return IsValidLabelLength(value) && (LabelPuny.IsPunyLabel(value) ||
9
+ LabelUnicode.IsUnicodeLabel(value));
10
+ }
11
+ function NormalizeHostname(value) {
12
+ return value.normalize('NFC').replace(/[\u002E\u3002\uFF0E\uFF61]/g, '.');
13
+ }
14
+ export function IsIdnHostname(value) {
15
+ if (value.length === 0 || value.includes(' '))
16
+ return false;
17
+ const normalized = NormalizeHostname(value);
18
+ if (normalized.length > 253)
19
+ return false;
20
+ const labels = normalized.split('.');
21
+ const hasBidiChars = labels.some((label) => FormatBidi.HasBidiChars(label));
22
+ return labels.every((label) => IsLabel(label) && (!hasBidiChars || FormatBidi.SatisfiesBidiRule(label)));
23
+ }
@@ -0,0 +1,2 @@
1
+ export * from './hostname.mjs';
2
+ export * from './idn-hostname.mjs';
@@ -0,0 +1,2 @@
1
+ export * from './hostname.mjs';
2
+ export * from './idn-hostname.mjs';
@@ -0,0 +1 @@
1
+ export declare function IsAsciiLabel(value: string): boolean;
@@ -0,0 +1,9 @@
1
+ import * as Pattern from '../pattern/pattern.mjs';
2
+ // -------------------------------------------------------------------
3
+ // Validates an ASCII LDH label per RFC 5891 §4.2.3.1
4
+ // -------------------------------------------------------------------
5
+ export function IsAsciiLabel(value) {
6
+ return (Pattern.RE_RULE_HYPHEN_PLACEMENT.test(value) &&
7
+ Pattern.RE_RULE_NOT_RESERVED_ACE.test(value) &&
8
+ Pattern.RE_ASCII_LDH.test(value));
9
+ }
@@ -0,0 +1 @@
1
+ export declare function IsPunyLabel(value: string): boolean;
@@ -0,0 +1,28 @@
1
+ import * as FormatPuny from '../format/puny.mjs';
2
+ import * as LabelUnicode from './unicode.mjs';
3
+ import * as Pattern from '../pattern/pattern.mjs';
4
+ // ------------------------------------------------------------------
5
+ // IsPunyLabel
6
+ // ------------------------------------------------------------------
7
+ export function IsPunyLabel(value) {
8
+ if (!FormatPuny.IsAcePrefixed(value))
9
+ return false;
10
+ try {
11
+ const body = value.slice(4).toLowerCase();
12
+ // A payload consisting of only a hyphen, or starting with the delimiter
13
+ // (like "-9uc"), has 0 basic ASCII characters preceding it and is malformed.
14
+ if (body.lastIndexOf('-') === 0)
15
+ return false;
16
+ const decoded = FormatPuny.Decode(body);
17
+ // RFC 5890 §2.3.2.1 - a U-label must contain at least one non-ASCII
18
+ // character. Code-unit level check: any non-ASCII codepoint has at least
19
+ // one UTF-16 unit >= 0x80 (surrogate halves included), so no need to
20
+ // decode codepoints or allocate a character array to answer this.
21
+ if (!Pattern.RE_NON_ASCII.test(decoded))
22
+ return false;
23
+ return LabelUnicode.IsUnicodeLabel(decoded);
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
@@ -0,0 +1 @@
1
+ export declare function IsUnicodeLabel(value: string): boolean;
@@ -0,0 +1,106 @@
1
+ import * as Pattern from '../pattern/pattern.mjs';
2
+ import * as FormatBidi from '../format/bidi.mjs';
3
+ import * as FormatPuny from '../format/puny.mjs';
4
+ // ------------------------------------------------------------------
5
+ // ExceedsMaxALabelLength
6
+ //
7
+ // RFC 5890 §2.3.2.1: an A-label (the ACE-encoded form of a label,
8
+ // "xn--" + punycode) must not exceed 63 octets. Only labels
9
+ // containing non-ASCII characters need checking - a pure-ASCII label
10
+ // has no "xn--" prefix and is used as-is, so its punycode-encoded
11
+ // length is irrelevant. The ASCII check is a cheap short-circuit that
12
+ // avoids running the punycode encoder on labels that don't need it.
13
+ // ------------------------------------------------------------------
14
+ function ExceedsMaxALabelLength(value) {
15
+ return Pattern.RE_NON_ASCII.test(value) && FormatPuny.Encode(value).length + 4 > 63;
16
+ }
17
+ // ------------------------------------------------------------------
18
+ // HasInvalidHyphens
19
+ //
20
+ // RFC 5891 §4.2.3.2: label must not start or end with a hyphen, and
21
+ // must not have hyphens in the 3rd and 4th codepoint positions (the
22
+ // ACE prefix reservation, e.g. "xn--"). Operates on `chars` (the
23
+ // per-codepoint string array) rather than raw string indices so
24
+ // supplementary-plane characters earlier in the label don't throw
25
+ // off the codepoint-position count.
26
+ // ------------------------------------------------------------------
27
+ function HasInvalidHyphens(chars) {
28
+ if (chars[0] === '-' || chars[chars.length - 1] === '-')
29
+ return true;
30
+ return chars.slice(2).join('').startsWith('--');
31
+ }
32
+ // ------------------------------------------------------------------
33
+ // IsUnicodeLabel
34
+ // ------------------------------------------------------------------
35
+ export function IsUnicodeLabel(value) {
36
+ // RFC 5890 §2.3.2.1: Ensure Max Length
37
+ if (ExceedsMaxALabelLength(value))
38
+ return false;
39
+ // RFC 5893 - Bidi Rule (applies whenever this label itself is RTL)
40
+ if (FormatBidi.HasRightToLeftCharacters(value) && !FormatBidi.SatisfiesBidiRule(value))
41
+ return false;
42
+ const chars = [...value];
43
+ const codePoints = chars.map((c) => c.codePointAt(0));
44
+ const length = codePoints.length;
45
+ // RFC 5891 §4.2.3.2: Hyphen rules
46
+ if (HasInvalidHyphens(chars))
47
+ return false;
48
+ // RFC 5891 §4.2.3.2 - Must not begin with a combining mark
49
+ if (Pattern.RE_COMBINING_MARK.test(chars[0]))
50
+ return false;
51
+ let hasJapanese = false;
52
+ // let hasArabicIndic = false // (no-spec-coverage)
53
+ // let hasExtendedArabicIndic = false // (no-spec-coverage)
54
+ for (let i = 0; i < length; i++) {
55
+ const codePoint = codePoints[i];
56
+ const char = chars[i];
57
+ // 1. DISALLOWED exceptions
58
+ if (Pattern.RE_RFC5892_DISALLOWED.test(char))
59
+ return false;
60
+ // 1b. General category (PVALID) enforcement
61
+ if (!Pattern.RE_PERMITTED_CATEGORY.test(char))
62
+ return false;
63
+ // 2. Collect Flags
64
+ if (Pattern.RE_SCRIPT_JAPANESE.test(char))
65
+ hasJapanese = true;
66
+ // if (Pattern.RE_ARABIC_INDIC_DIGIT.test(char)) hasArabicIndic = true // (no-spec-coverage)
67
+ // if (Pattern.RE_EXT_ARABIC_INDIC_DIGIT.test(char)) hasExtendedArabicIndic = true // (no-spec-coverage)
68
+ // 3. CONTEXTO / CONTEXTJ Neighbor Rules
69
+ const prev = codePoints[i - 1], next = codePoints[i + 1];
70
+ switch (codePoint) {
71
+ case 0x00b7:
72
+ if (prev !== 0x006c || next !== 0x006c)
73
+ return false;
74
+ break; // MIDDLE DOT (Catalan)
75
+ case 0x0375:
76
+ if (!next || !Pattern.RE_SCRIPT_GREEK.test(chars[i + 1]))
77
+ return false;
78
+ break; // Greek KERAIA
79
+ case 0x05f3:
80
+ case 0x05f4:
81
+ if (!prev || !Pattern.RE_SCRIPT_HEBREW.test(chars[i - 1]))
82
+ return false;
83
+ break; // Hebrew GERESH
84
+ case 0x200c: // ZWNJ - RFC 5892 Appendix A.1
85
+ // Note: Full validation requires a Unicode joining type table. We reject
86
+ // only when preceded by ASCII (U+0000-U+007F), which can never satisfy
87
+ // the Virama or cursive-joining rules.
88
+ if (!prev || (prev < 0x0080 && !Pattern.RE_VIRAMA.test(chars[i - 1])))
89
+ return false;
90
+ break;
91
+ case 0x200d: // ZWJ: RFC 5892 Appendix A.2
92
+ if (!prev || !Pattern.RE_VIRAMA.test(chars[i - 1]))
93
+ return false;
94
+ break;
95
+ case 0x30fb: // Checked at end via hasJapanese
96
+ break; // KATAKANA MIDDLE DOT
97
+ }
98
+ }
99
+ // 4. Global Context Validations (Post-loop)
100
+ // RFC 5892 Appendix A.7 - Katakana Middle Dot requirement
101
+ if (value.includes('\u30fb') && !hasJapanese)
102
+ return false;
103
+ // RFC 5892 Appendix A.8/A.9 - Mixing Arabic Digits
104
+ // if (hasArabicIndic && hasExtendedArabicIndic) return false // (no-spec-coverage)
105
+ return true;
106
+ }
@@ -0,0 +1,30 @@
1
+ export declare const RE_RULE_HYPHEN_PLACEMENT: RegExp;
2
+ export declare const RE_RULE_NOT_RESERVED_ACE: RegExp;
3
+ export declare const RE_ASCII_LDH: RegExp;
4
+ export declare const RE_ASCII: RegExp;
5
+ export declare const RE_NON_ASCII: RegExp;
6
+ export declare const RE_HIGH_SURROGATE: RegExp;
7
+ export declare const RE_REGIONAL_INDICATOR: RegExp;
8
+ export declare const RE_VARIATION_SELECTOR: RegExp;
9
+ export declare const RE_ZERO_WIDTH_JOINER: RegExp;
10
+ export declare const RE_ASCII_DIGIT: RegExp;
11
+ export declare const RE_ARABIC_INDIC_DIGIT: RegExp;
12
+ export declare const RE_EXT_ARABIC_INDIC_DIGIT: RegExp;
13
+ export declare const RE_COMMON_SEPARATOR: RegExp;
14
+ export declare const RE_EUROPEAN_SEPARATOR: RegExp;
15
+ export declare const RE_MARK_NONSPACING: RegExp;
16
+ export declare const RE_MARK_SPACING_COMBINING: RegExp;
17
+ export declare const RE_MARK_ENCLOSING: RegExp;
18
+ export declare const RE_COMBINING_MARK: RegExp;
19
+ export declare const RE_LETTER: RegExp;
20
+ export declare const RE_NUMBER_DECIMAL: RegExp;
21
+ export declare const RE_SCRIPT_GREEK: RegExp;
22
+ export declare const RE_SCRIPT_HEBREW: RegExp;
23
+ export declare const RE_SCRIPT_JAPANESE: RegExp;
24
+ export declare const RE_SCRIPT_ARABIC_LETTER: RegExp;
25
+ export declare const RE_VIRAMA: RegExp;
26
+ export declare const RE_RFC5892_DISALLOWED: RegExp;
27
+ export declare const RE_CONTEXTO_EXCEPTIONS: RegExp;
28
+ export declare const RE_PVALID_EXCEPTIONS: RegExp;
29
+ export declare const RE_EUROPEAN_NUMBER: RegExp;
30
+ export declare const RE_PERMITTED_CATEGORY: RegExp;