typebox 1.3.10 → 1.3.12

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 (70) 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 +6 -6
  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 +14 -11
  61. package/build/system/memory/discard.mjs +5 -5
  62. package/package.json +1 -1
  63. package/build/format/_idna.d.mts +0 -2
  64. package/build/format/_idna.mjs +0 -246
  65. package/build/format/_puny.d.mts +0 -1
  66. package/build/format/_puny.mjs +0 -77
  67. package/build/schema/types/contentEncoding.d.mts +0 -9
  68. package/build/schema/types/contentEncoding.mjs +0 -13
  69. package/build/schema/types/contentMediaType.d.mts +0 -9
  70. package/build/schema/types/contentMediaType.mjs +0 -13
@@ -3,6 +3,7 @@ import * as S from '../types/index.mjs';
3
3
  import * as V from './_externals.mjs';
4
4
  import { Unique } from './_unique.mjs';
5
5
  import { AccumulatedErrorContext } from './_context.mjs';
6
+ import { UnicodeRegExp } from './_regexp.mjs';
6
7
  import { EmitGuard as E, Guard as G } from '../../guard/index.mjs';
7
8
  import { BuildSchemaPushStack, CheckSchemaPushStack, ErrorSchemaPushStack } from './schema.mjs';
8
9
  // ------------------------------------------------------------------
@@ -58,7 +59,7 @@ export function BuildAdditionalPropertiesFast(_context, schema, value) {
58
59
  // ------------------------------------------------------------------
59
60
  export function BuildAdditionalPropertiesStandard(stack, context, schema, value) {
60
61
  const [key, _index] = [Unique(), Unique()];
61
- const regexp = V.CreateVariable(new RegExp(GetPropertiesPattern(schema)));
62
+ const regexp = V.CreateVariable(UnicodeRegExp(GetPropertiesPattern(schema)));
62
63
  const isSchema = BuildSchemaPushStack(stack, context, schema.additionalProperties, `${value}[${key}]`);
63
64
  const isKey = E.Call(E.Member(regexp, 'test'), [key]);
64
65
  const addKey = context.AddKey(key);
@@ -78,7 +79,7 @@ export function BuildAdditionalProperties(stack, context, schema, value) {
78
79
  // Check
79
80
  // ------------------------------------------------------------------
80
81
  export function CheckAdditionalProperties(stack, context, schema, value) {
81
- const regexp = new RegExp(GetPropertiesPattern(schema));
82
+ const regexp = UnicodeRegExp(GetPropertiesPattern(schema));
82
83
  const isAdditionalProperties = G.Every(G.Keys(value), 0, (key, _index) => {
83
84
  return regexp.test(key) ||
84
85
  (CheckSchemaPushStack(stack, context, schema.additionalProperties, value[key]) && context.AddKey(key));
@@ -89,7 +90,7 @@ export function CheckAdditionalProperties(stack, context, schema, value) {
89
90
  // Error
90
91
  // ------------------------------------------------------------------
91
92
  export function ErrorAdditionalProperties(stack, context, schemaPath, instancePath, schema, value) {
92
- const regexp = new RegExp(GetPropertiesPattern(schema));
93
+ const regexp = UnicodeRegExp(GetPropertiesPattern(schema));
93
94
  const additionalProperties = [];
94
95
  const isAdditionalProperties = G.EveryAll(G.Keys(value), 0, (key, _index) => {
95
96
  const nextSchemaPath = `${schemaPath}/additionalProperties`;
@@ -1,18 +1,19 @@
1
1
  // deno-fmt-ignore-file
2
2
  import * as Externals from './_externals.mjs';
3
3
  import { Guard as G, EmitGuard as E } from '../../guard/index.mjs';
4
+ import { UnicodeRegExp } from './_regexp.mjs';
4
5
  // ------------------------------------------------------------------
5
6
  // Build
6
7
  // ------------------------------------------------------------------
7
8
  export function BuildPattern(_stack, _context, schema, value) {
8
- const regexp = Externals.CreateVariable(G.IsString(schema.pattern) ? new RegExp(schema.pattern, 'u') : schema.pattern);
9
+ const regexp = Externals.CreateVariable(G.IsString(schema.pattern) ? UnicodeRegExp(schema.pattern) : schema.pattern);
9
10
  return E.Call(E.Member(regexp, 'test'), [value]);
10
11
  }
11
12
  // ------------------------------------------------------------------
12
13
  // Check
13
14
  // ------------------------------------------------------------------
14
15
  export function CheckPattern(_stack, _context, schema, value) {
15
- const regexp = G.IsString(schema.pattern) ? new RegExp(schema.pattern, 'u') : schema.pattern;
16
+ const regexp = G.IsString(schema.pattern) ? UnicodeRegExp(schema.pattern) : schema.pattern;
16
17
  return regexp.test(value);
17
18
  }
18
19
  // ------------------------------------------------------------------
@@ -1,6 +1,7 @@
1
1
  // deno-fmt-ignore-file
2
2
  import * as Externals from './_externals.mjs';
3
3
  import { Unique } from './_unique.mjs';
4
+ import { UnicodeRegExp } from './_regexp.mjs';
4
5
  import { Guard as G, EmitGuard as E } from '../../guard/index.mjs';
5
6
  import { BuildSchemaPushStack, CheckSchemaPushStack, ErrorSchemaPushStack } from './schema.mjs';
6
7
  // ------------------------------------------------------------------
@@ -9,7 +10,7 @@ import { BuildSchemaPushStack, CheckSchemaPushStack, ErrorSchemaPushStack } from
9
10
  export function BuildPatternProperties(stack, context, schema, value) {
10
11
  return E.ReduceAnd(G.Entries(schema.patternProperties).map(([pattern, schema]) => {
11
12
  const [key, prop] = [Unique(), Unique()];
12
- const regexp = Externals.CreateVariable(new RegExp(pattern, 'u'));
13
+ const regexp = Externals.CreateVariable(UnicodeRegExp(pattern));
13
14
  const notKey = E.Not(E.Call(E.Member(regexp, 'test'), [key]));
14
15
  const isSchema = BuildSchemaPushStack(stack, context, schema, prop);
15
16
  const addKey = context.AddKey(key);
@@ -22,7 +23,7 @@ export function BuildPatternProperties(stack, context, schema, value) {
22
23
  // ------------------------------------------------------------------
23
24
  export function CheckPatternProperties(stack, context, schema, value) {
24
25
  return G.Every(G.Entries(schema.patternProperties), 0, ([pattern, schema]) => {
25
- const regexp = new RegExp(pattern, 'u');
26
+ const regexp = UnicodeRegExp(pattern);
26
27
  return G.Every(G.Entries(value), 0, ([key, prop]) => {
27
28
  return !regexp.test(key) || CheckSchemaPushStack(stack, context, schema, prop) && context.AddKey(key);
28
29
  });
@@ -34,7 +35,7 @@ export function CheckPatternProperties(stack, context, schema, value) {
34
35
  export function ErrorPatternProperties(stack, context, schemaPath, instancePath, schema, value) {
35
36
  return G.EveryAll(G.Entries(schema.patternProperties), 0, ([pattern, schema]) => {
36
37
  const nextSchemaPath = `${schemaPath}/patternProperties/${pattern}`;
37
- const regexp = new RegExp(pattern, 'u');
38
+ const regexp = UnicodeRegExp(pattern);
38
39
  return G.EveryAll(G.Entries(value), 0, ([key, value]) => {
39
40
  const nextInstancePath = `${instancePath}/${key}`;
40
41
  const notKey = !regexp.test(key);
@@ -45,12 +45,21 @@ import { BuildUnevaluatedItems, CheckUnevaluatedItems, ErrorUnevaluatedItems } f
45
45
  import { BuildUnevaluatedProperties, CheckUnevaluatedProperties, ErrorUnevaluatedProperties } from './unevaluatedProperties.mjs';
46
46
  import { BuildUniqueItems, CheckUniqueItems, ErrorUniqueItems } from './uniqueItems.mjs';
47
47
  // ----------------------------------------------------------------
48
- // HasTypeName
48
+ // HasTypeName (Optimization)
49
+ //
50
+ // We only consider a schema as having a type name when the schema
51
+ // has a single type string, or when every element in the type
52
+ // array is the same. For a type array, we must treat multi-variant
53
+ // types as unions and therefore can NOT use an optimized forward
54
+ // type check.
55
+ //
49
56
  // ----------------------------------------------------------------
50
57
  function HasTypeName(schema, typename) {
51
- return Schema.IsType(schema) &&
52
- (G.IsArray(schema.type) && G.IsGreaterThan(schema.type.length, 0) && G.Every(schema.type, 0, type => G.IsEqual(type, typename)) ||
53
- G.IsEqual(schema.type, typename));
58
+ return (Schema.IsType(schema) &&
59
+ ((G.IsArray(schema.type) &&
60
+ G.IsGreaterThan(schema.type.length, 0) &&
61
+ G.Every(schema.type, 0, type => G.IsEqual(type, typename))) ||
62
+ G.IsEqual(schema.type, typename)));
54
63
  }
55
64
  // ----------------------------------------------------------------
56
65
  // HasObject
@@ -1,3 +1,4 @@
1
1
  import * as Schema from '../types/index.mjs';
2
+ export declare const DefaultBase: URL;
2
3
  export declare function Ref(schema: Schema.XSchemaObject, ref: string): Schema.XSchema | undefined;
3
4
  export declare function DynamicRef(root: Schema.XSchemaObject, base: Schema.XSchemaObject, dynamicRef: Schema.XDynamicRef, dynamicAnchors: Schema.XDynamicAnchor[]): Schema.XSchema | undefined;
@@ -3,6 +3,10 @@ import { Guard } from '../../guard/index.mjs';
3
3
  import { Pointer } from '../pointer/index.mjs';
4
4
  import * as Schema from '../types/index.mjs';
5
5
  // ------------------------------------------------------------------
6
+ // DefaultBase
7
+ // ------------------------------------------------------------------
8
+ export const DefaultBase = new URL('https://json-schema.org');
9
+ // ------------------------------------------------------------------
6
10
  // Match: Id
7
11
  // ------------------------------------------------------------------
8
12
  function MatchId(schema, base, ref) {
@@ -83,8 +87,15 @@ function FromArray(schema, base, ref) {
83
87
  // ------------------------------------------------------------------
84
88
  // FromObject
85
89
  // ------------------------------------------------------------------
90
+ function SkipProperty(key) {
91
+ // these are explicit data encoded in a schema, they should not
92
+ // be considered valid targets used for de-referencing.
93
+ return Guard.IsEqual(key, 'const') || Guard.IsEqual(key, 'enum');
94
+ }
86
95
  function FromObject(schema, base, ref) {
87
96
  return Guard.Keys(schema).reduce((result, key) => {
97
+ if (SkipProperty(key))
98
+ return result;
88
99
  const match = FromValue(schema[key], base, ref);
89
100
  return !Guard.IsUndefined(match) ? match : result;
90
101
  }, undefined);
@@ -111,8 +122,7 @@ function FromValue(schema, base, ref) {
111
122
  // Ref
112
123
  // ------------------------------------------------------------------
113
124
  export function Ref(schema, ref) {
114
- const defaultBase = new URL('http://unknown/');
115
- const initialBase = Schema.IsId(schema) ? new URL(schema.$id, defaultBase.href) : defaultBase;
125
+ const initialBase = Schema.IsId(schema) ? new URL(schema.$id, DefaultBase.href) : DefaultBase;
116
126
  const initialRef = new URL(ref, initialBase.href);
117
127
  return FromValue(schema, initialBase, initialRef);
118
128
  }
@@ -134,7 +144,7 @@ export function DynamicRef(root, base, dynamicRef, dynamicAnchors) {
134
144
  // Extract the fragment portion of the reference. According to the test suite,
135
145
  // only plain fragment names (e.g., "#foo") trigger the dynamic scope; JSON
136
146
  // Pointer fragments (e.g., "#/definitions/foo") bypass dynamic resolution.
137
- const fragment = new URL(dynamicRef.$dynamicRef, 'http://unknown/').hash;
147
+ const fragment = new URL(dynamicRef.$dynamicRef, DefaultBase).hash;
138
148
  if (fragment.startsWith('#/'))
139
149
  return fragmentTarget;
140
150
  // Search the live dynamic anchor stack for a schema whose $dynamicAnchor matches the
@@ -6,8 +6,6 @@ export * from './anchor.mjs';
6
6
  export * from './anyOf.mjs';
7
7
  export * from './const.mjs';
8
8
  export * from './contains.mjs';
9
- export * from './contentEncoding.mjs';
10
- export * from './contentMediaType.mjs';
11
9
  export * from './default.mjs';
12
10
  export * from './defs.mjs';
13
11
  export * from './dependencies.mjs';
@@ -12,8 +12,6 @@ export * from './anchor.mjs';
12
12
  export * from './anyOf.mjs';
13
13
  export * from './const.mjs';
14
14
  export * from './contains.mjs';
15
- export * from './contentEncoding.mjs';
16
- export * from './contentMediaType.mjs';
17
15
  export * from './default.mjs';
18
16
  export * from './defs.mjs';
19
17
  export * from './dependencies.mjs';
@@ -13,24 +13,27 @@ function FromClassInstance(value) {
13
13
  return value; // atomic
14
14
  }
15
15
  // ------------------------------------------------------------------
16
- // TypeObject
16
+ // SchemaObject
17
17
  //
18
- // Types have non-enumerable properties that MUST be preserved on Clone.
19
- // The following is the optimal path for TypeBox types.
18
+ // Schema objects have non-enumerable properties that MUST be preserved
19
+ // on Clone. The following is the optimal path these objects.
20
20
  // ------------------------------------------------------------------
21
- function IsTypeObject(value) {
21
+ function IsSchemaObject(value) {
22
22
  return (Guard.HasPropertyKey(value, '~kind') ||
23
23
  Guard.HasPropertyKey(value, '~unsafe'));
24
24
  }
25
- function FromTypeObject(value) {
25
+ function FromSchemaObject(value) {
26
26
  const result = {};
27
- const descriptors = Object.getOwnPropertyDescriptors(value);
28
- for (const key of Object.keys(descriptors)) {
27
+ for (const key of Object.getOwnPropertyNames(value)) {
29
28
  if (Guard.IsUnsafePropertyKey(key))
30
29
  continue; // (ignore: prototype-pollution)
31
- const descriptor = descriptors[key];
32
- if (Guard.HasPropertyKey(descriptor, 'value')) {
33
- Object.defineProperty(result, key, { ...descriptor, value: FromValue(descriptor.value) });
30
+ const descriptor = Object.getOwnPropertyDescriptor(value, key); // safe-name!
31
+ descriptor.value = FromValue(descriptor.value);
32
+ if (Guard.IsEqual(descriptor.enumerable, true)) {
33
+ result[key] = descriptor.value;
34
+ }
35
+ else {
36
+ Object.defineProperty(result, key, descriptor);
34
37
  }
35
38
  }
36
39
  return result;
@@ -55,7 +58,7 @@ function FromPlainObject(value) {
55
58
  // ------------------------------------------------------------------
56
59
  function FromObject(value) {
57
60
  return (Guard.IsClassInstance(value) ? FromClassInstance(value) :
58
- IsTypeObject(value) ? FromTypeObject(value) :
61
+ IsSchemaObject(value) ? FromSchemaObject(value) :
59
62
  FromPlainObject(value));
60
63
  }
61
64
  // ------------------------------------------------------------------
@@ -6,12 +6,12 @@ import { Clone } from './clone.mjs';
6
6
  export function Discard(value, propertyKeys) {
7
7
  Metrics.discard += 1;
8
8
  const result = {};
9
- const descriptors = Object.getOwnPropertyDescriptors(Clone(value));
10
- const keysToDiscard = new Set(propertyKeys);
11
- for (const key of Object.keys(descriptors)) {
12
- if (keysToDiscard.has(key))
9
+ for (const key of Object.getOwnPropertyNames(value)) {
10
+ if (propertyKeys.includes(key))
13
11
  continue;
14
- Object.defineProperty(result, key, descriptors[key]);
12
+ const descriptor = Object.getOwnPropertyDescriptor(value, key); // safe-name!
13
+ descriptor.value = Clone(descriptor.value);
14
+ Object.defineProperty(result, key, descriptor);
15
15
  }
16
16
  return result;
17
17
  }
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.3.10",
4
+ "version": "1.3.12",
5
5
  "keywords": [
6
6
  "typescript",
7
7
  "jsonschema"
@@ -1,2 +0,0 @@
1
- export declare function IsIdnLabel(value: string): boolean;
2
- export declare function IsLabel(value: string): boolean;
@@ -1,246 +0,0 @@
1
- import { Unreachable } from '../system/unreachable/index.mjs';
2
- import * as Puny from './_puny.mjs';
3
- // ------------------------------------------------------------------
4
- // Unicode General Category Helper (RFC 5892)
5
- // ------------------------------------------------------------------
6
- function IsNonspacingMark(cp) {
7
- return /\p{Mn}/u.test(String.fromCodePoint(cp));
8
- }
9
- function IsSpacingCombiningMark(cp) {
10
- return /\p{Mc}/u.test(String.fromCodePoint(cp));
11
- }
12
- function IsEnclosingMark(cp) {
13
- return /\p{Me}/u.test(String.fromCodePoint(cp));
14
- }
15
- function IsCombiningMark(cp) {
16
- return IsNonspacingMark(cp) || IsSpacingCombiningMark(cp) || IsEnclosingMark(cp);
17
- }
18
- // ------------------------------------------------------------------
19
- // RFC 5892 §2.6 DISALLOWED exceptions
20
- //
21
- // https://tools.ietf.org/html/rfc5892#section-2.6
22
- // ------------------------------------------------------------------
23
- const RFC5892_DISALLOWED = new Set([
24
- 0x0640, // ARABIC TATWEEL
25
- 0x07fa, // NKO LAJANYALAN
26
- 0x302e, // HANGUL SINGLE DOT TONE MARK
27
- 0x302f, // HANGUL DOUBLE DOT TONE MARK
28
- 0x3031, // VERTICAL KANA REPEAT MARK
29
- 0x3032, // VERTICAL KANA REPEAT WITH VOICED ITERATION MARK
30
- 0x3033, // VERTICAL KANA REPEAT MARK UPPER HALF
31
- 0x3034, // VERTICAL KANA REPEAT WITH VOICED ITERATION MARK UPPER HALF
32
- 0x3035, // VERTICAL KANA REPEAT MARK LOWER HALF
33
- 0x303b // VERTICAL IDEOGRAPHIC ITERATION MARK
34
- ]);
35
- // ------------------------------------------------------------------
36
- // A set of Virama (halant) code points used to validate CONTEXTJ
37
- // rules (RFC 5892 Appendix A.1). These characters allow a subsequent
38
- // Zero Width Non-Joiner (U+200C) or Zero Width Joiner (U+200D) to
39
- // be valid in a label.
40
- // ------------------------------------------------------------------
41
- const VIRAMA_CPS = new Set([
42
- 0x094d,
43
- 0x09cd,
44
- 0x0a4d,
45
- 0x0acd,
46
- 0x0b4d,
47
- 0x0bcd,
48
- 0x0c4d,
49
- 0x0ccd,
50
- 0x0d3b,
51
- 0x0d3c,
52
- 0x0d4d,
53
- 0x0dca,
54
- 0x1b44,
55
- 0x1baa,
56
- 0x1bab,
57
- 0xa9c0,
58
- 0x11046,
59
- 0x1107f,
60
- 0x110b9,
61
- 0x11133,
62
- 0x11134,
63
- 0x111c0,
64
- 0x11235,
65
- 0x1134d,
66
- 0x11442,
67
- 0x114c2,
68
- 0x115bf,
69
- 0x1163f,
70
- 0x116b6,
71
- 0x11c3f,
72
- 0x11d44,
73
- 0x11d45
74
- ]);
75
- // ------------------------------------------------------------------
76
- // Guards for CONTEXTO rules (RFC 5892 Appendix A)
77
- // ------------------------------------------------------------------
78
- function IsGreek(cp) {
79
- return /\p{Script=Greek}/u.test(String.fromCodePoint(cp));
80
- }
81
- function IsHebrew(cp) {
82
- return /\p{Script=Hebrew}/u.test(String.fromCodePoint(cp));
83
- }
84
- function IsHiragana(cp) {
85
- return /\p{Script=Hiragana}/u.test(String.fromCodePoint(cp));
86
- }
87
- function IsKatakana(cp) {
88
- return /\p{Script=Katakana}/u.test(String.fromCodePoint(cp));
89
- }
90
- function IsHan(cp) {
91
- return /\p{Script=Han}/u.test(String.fromCodePoint(cp));
92
- }
93
- function IsArabicIndicDigit(cp) {
94
- return cp >= 0x0660 && cp <= 0x0669;
95
- }
96
- function IsExtendedArabicIndicDigit(cp) {
97
- return cp >= 0x06f0 && cp <= 0x06f9;
98
- }
99
- function IsVirama(cp) {
100
- return VIRAMA_CPS.has(cp);
101
- }
102
- // ------------------------------------------------------------------
103
- // IsUnicodeLabel
104
- // ------------------------------------------------------------------
105
- function IsUnicodeLabel(value) {
106
- // deno-coverage-ignore-start - unable to reach via format guards
107
- if (value.length === 0)
108
- return Unreachable(); // false
109
- // deno-coverage-ignore-stop
110
- // Use spread to handle surrogate pairs and provide O(1) neighbor access
111
- const cps = [...value].map((c) => c.codePointAt(0));
112
- const len = cps.length;
113
- // RFC 5891 §4.2.3.2: Hyphen rules
114
- if (cps[0] === 0x2d || cps[len - 1] === 0x2d)
115
- return false;
116
- if (len >= 4 && cps[2] === 0x2d && cps[3] === 0x2d)
117
- return false;
118
- // RFC 5891 §4.2.3.2 - Must not begin with a combining mark
119
- if (IsCombiningMark(cps[0]))
120
- return false;
121
- let hasJapanese = false;
122
- let hasArabicIndic = false;
123
- let hasExtendedArabicIndic = false;
124
- for (let i = 0; i < len; i++) {
125
- const cp = cps[i];
126
- // 1. DISALLOWED exceptions
127
- if (RFC5892_DISALLOWED.has(cp))
128
- return false;
129
- // 2. Collect Flags
130
- if (IsHiragana(cp) || IsKatakana(cp) || IsHan(cp))
131
- hasJapanese = true;
132
- if (IsArabicIndicDigit(cp))
133
- hasArabicIndic = true;
134
- if (IsExtendedArabicIndicDigit(cp))
135
- hasExtendedArabicIndic = true;
136
- // 3. CONTEXTO / CONTEXTJ Neighbor Rules
137
- const prev = cps[i - 1], next = cps[i + 1];
138
- switch (cp) {
139
- case 0x00b7:
140
- if (prev !== 0x006c || next !== 0x006c)
141
- return false;
142
- break; // MIDDLE DOT (Catalan)
143
- case 0x0375:
144
- if (next === undefined || !IsGreek(next))
145
- return false;
146
- break; // Greek KERAIA
147
- case 0x05f3:
148
- case 0x05f4:
149
- if (prev === undefined || !IsHebrew(prev))
150
- return false;
151
- break; // Hebrew GERESH
152
- case 0x200c: // ZWNJ - RFC 5892 Appendix A.1
153
- // Note: Full validation requires a Unicode joining type table. We reject
154
- // only when preceded by ASCII (U+0000-U+007F), which can never satisfy
155
- // the Virama or cursive-joining rules.
156
- if (prev === undefined || (prev < 0x0080 && !IsVirama(prev)))
157
- return false;
158
- break;
159
- case 0x200d: // ZWJ - RFC 5892 Appendix A.2
160
- if (prev === undefined || !IsVirama(prev))
161
- return false;
162
- break;
163
- case 0x30fb: /* Checked at end via hasJapanese */
164
- break; // KATAKANA MIDDLE DOT
165
- }
166
- }
167
- // 4. Global Context Validations (Post-loop)
168
- // RFC 5892 Appendix A.7 - Katakana Middle Dot requirement
169
- if (value.includes('\u30fb') && !hasJapanese)
170
- return false;
171
- // RFC 5892 Appendix A.8/A.9 - Mixing Arabic Digits
172
- if (hasArabicIndic && hasExtendedArabicIndic)
173
- return false;
174
- return true;
175
- }
176
- // ------------------------------------------------------------------
177
- // IsAsciiLabel
178
- // ------------------------------------------------------------------
179
- function IsAsciiLabel(value) {
180
- // Must not start or end with a hyphen
181
- if (value.charCodeAt(0) === 45 || value.charCodeAt(value.length - 1) === 45)
182
- return false;
183
- // RFC 5891 §4.2.3.1 : "--" at positions 3-4 is reserved for A-labels only
184
- if (value.length >= 4 && value.charCodeAt(2) === 45 && value.charCodeAt(3) === 45)
185
- return false;
186
- // All characters must be alphanumeric or hyphen
187
- for (let i = 0; i < value.length; i++) {
188
- const ch = value.charCodeAt(i);
189
- if (!((ch >= 97 && ch <= 122) || // a-z
190
- (ch >= 65 && ch <= 90) || // A-Z
191
- (ch >= 48 && ch <= 57) || // 0-9
192
- ch === 45 // '-'
193
- ))
194
- return false;
195
- }
196
- return true;
197
- }
198
- // ------------------------------------------------------------------
199
- // IsPunyLabel
200
- // ------------------------------------------------------------------
201
- function IsPuny(value) {
202
- return value.toLowerCase().startsWith('xn--');
203
- }
204
- function IsPunyLabel(value) {
205
- try {
206
- const payload = value.slice(4).toLowerCase();
207
- // 1. Structural Validation (RFC 3492 syntax)
208
- //
209
- // If the payload contains a hyphen, it MUST be a delimiter separating basic
210
- // ASCII characters from the variable-length integers. A payload consisting
211
- // of ONLY a hyphen or starting with multiple hyphens without basic ASCII
212
- // characters (like "-9uc") is fundamentally malformed.
213
- //
214
- const lastHyphen = payload.lastIndexOf('-');
215
- if (lastHyphen === 0) {
216
- // Catches "-9uc" right here because the delimiter is at index 0, meaning 0
217
- // basic ASCII characters preceded it, which is non-canonical.
218
- return false;
219
- }
220
- // 2. Decode the payload
221
- const decoded = Puny.Decode(payload);
222
- if (!decoded)
223
- return false;
224
- // 3. Validate the output rules against RFC 5892
225
- return IsUnicodeLabel(decoded);
226
- }
227
- catch {
228
- return false;
229
- }
230
- }
231
- // ------------------------------------------------------------------
232
- // IsIdnLabel
233
- // ------------------------------------------------------------------
234
- export function IsIdnLabel(value) {
235
- if (value.length === 0 || value.length > 63)
236
- return false;
237
- return IsPuny(value) ? IsPunyLabel(value) : IsUnicodeLabel(value);
238
- }
239
- // ------------------------------------------------------------------
240
- // IsLabel
241
- // ------------------------------------------------------------------
242
- export function IsLabel(value) {
243
- if (value.length === 0 || value.length > 63)
244
- return false;
245
- return IsPuny(value) ? IsPunyLabel(value) : IsAsciiLabel(value);
246
- }
@@ -1 +0,0 @@
1
- export declare function Decode(value: string): string;
@@ -1,77 +0,0 @@
1
- import { Unreachable } from '../system/unreachable/index.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
- // Adapt
14
- // ------------------------------------------------------------------
15
- function Adapt(delta, numPoints, firstTime) {
16
- delta = firstTime ? Math.floor(delta / PUNYCODE_DAMP) : delta >> 1;
17
- delta += Math.floor(delta / numPoints);
18
- let k = 0;
19
- while (delta > (((PUNYCODE_BASE - PUNYCODE_TMIN) * PUNYCODE_TMAX) >> 1)) {
20
- delta = Math.floor(delta / (PUNYCODE_BASE - PUNYCODE_TMIN));
21
- k += PUNYCODE_BASE;
22
- }
23
- return k + Math.floor(((PUNYCODE_BASE - PUNYCODE_TMIN + 1) * delta) / (delta + PUNYCODE_SKEW));
24
- }
25
- // ------------------------------------------------------------------
26
- // Decode
27
- // ------------------------------------------------------------------
28
- export function Decode(value) {
29
- const output = [];
30
- let n = PUNYCODE_INITIAL_N;
31
- let i = 0;
32
- let bias = PUNYCODE_INITIAL_BIAS;
33
- const delimIdx = value.lastIndexOf('-');
34
- if (delimIdx > 0) {
35
- for (let j = 0; j < delimIdx; j++) {
36
- const cp = value.charCodeAt(j);
37
- if (cp >= 128)
38
- throw new Error('Invalid punycode: non-basic before delimiter');
39
- output.push(cp);
40
- }
41
- }
42
- let inIdx = delimIdx < 0 ? 0 : delimIdx + 1;
43
- while (inIdx < value.length) {
44
- const oldi = i;
45
- let w = 1;
46
- let k = PUNYCODE_BASE;
47
- while (true) {
48
- if (inIdx >= value.length)
49
- throw new Error('Invalid punycode: unexpected end of input');
50
- const ch = value.charCodeAt(inIdx++);
51
- let digit;
52
- if (ch >= 0x61 && ch <= 0x7a)
53
- digit = ch - 0x61; // a-z => 0-25
54
- else if (ch >= 0x30 && ch <= 0x39)
55
- digit = ch - 0x30 + 26; // 0-9 => 26-35
56
- // deno-coverage-ignore-start - _idna.ts maps input to lowercase, so we can't reach here
57
- else if (ch >= 0x41 && ch <= 0x5a)
58
- Unreachable(); // digit = ch - 0x41 // A-Z => 0-25
59
- // deno-coverage-ignore-stop
60
- else
61
- throw new Error('Invalid punycode: bad digit character');
62
- i += digit * w;
63
- const t = k <= bias ? PUNYCODE_TMIN : k >= bias + PUNYCODE_TMAX ? PUNYCODE_TMAX : k - bias;
64
- if (digit < t)
65
- break;
66
- w *= PUNYCODE_BASE - t;
67
- k += PUNYCODE_BASE;
68
- }
69
- const outLen = output.length + 1;
70
- bias = Adapt(i - oldi, outLen, oldi === 0);
71
- n += Math.floor(i / outLen);
72
- i %= outLen;
73
- output.splice(i, 0, n);
74
- i++;
75
- }
76
- return globalThis.String.fromCodePoint(...output);
77
- }
@@ -1,9 +0,0 @@
1
- import { type XSchemaObject } from './schema.mjs';
2
- export interface XContentEncoding<ContentEncoding extends string = string> {
3
- contentEncoding: ContentEncoding;
4
- }
5
- /**
6
- * Returns true if the schema contains a valid contentEncoding property
7
- * @specification Json Schema 7
8
- */
9
- export declare function IsContentEncoding(schema: XSchemaObject): schema is XContentEncoding;
@@ -1,13 +0,0 @@
1
- // deno-fmt-ignore-file
2
- import { Guard } from '../../guard/index.mjs';
3
- // ------------------------------------------------------------------
4
- // Guard
5
- // ------------------------------------------------------------------
6
- /**
7
- * Returns true if the schema contains a valid contentEncoding property
8
- * @specification Json Schema 7
9
- */
10
- export function IsContentEncoding(schema) {
11
- return Guard.HasPropertyKey(schema, 'contentEncoding')
12
- && Guard.IsString(schema.contentEncoding);
13
- }
@@ -1,9 +0,0 @@
1
- import { type XSchemaObject } from './schema.mjs';
2
- export interface XContentMediaType<ContentMediaType extends string = string> {
3
- contentMediaType: ContentMediaType;
4
- }
5
- /**
6
- * Returns true if the schema contains a valid contentMediaType property
7
- * @specification Json Schema 7
8
- */
9
- export declare function IsContentMediaType(schema: XSchemaObject): schema is XContentMediaType;
@@ -1,13 +0,0 @@
1
- // deno-fmt-ignore-file
2
- import { Guard } from '../../guard/index.mjs';
3
- // ------------------------------------------------------------------
4
- // Guard
5
- // ------------------------------------------------------------------
6
- /**
7
- * Returns true if the schema contains a valid contentMediaType property
8
- * @specification Json Schema 7
9
- */
10
- export function IsContentMediaType(schema) {
11
- return Guard.HasPropertyKey(schema, 'contentMediaType')
12
- && Guard.IsString(schema.contentMediaType);
13
- }