@@ -34,23 +34,13 @@ class IdnaException implements Exception {
3434 String toString () => 'IdnaException: $message ' ;
3535}
3636
37- /// The Punycode codec instance used for encoding/decoding.
38- const _punycodeCodec = PunycodeCodec ();
39-
4037/// Encodes a domain name to its ASCII-compatible (Punycode) form.
4138///
4239/// This function:
43- /// 1. Splits the domain into labels (parts between dots)
44- /// 2. Normalizes each label to NFC (Normalization Form Canonical Composition)
45- /// 3. Performs case folding (converts to lowercase)
46- /// 4. Applies Punycode encoding with 'xn--' prefix for non-ASCII labels
47- /// 5. Validates label lengths (≤63 characters)
40+ /// 1. Normalizes the domain to NFC
41+ /// 2. Applies IDNA encoding using [domainToAscii]
4842///
49- /// Throws [IdnaException] if:
50- /// - A label exceeds 63 characters after encoding
51- /// - The domain exceeds 253 characters
52- /// - A label is empty
53- /// - The Punycode encoding fails
43+ /// Throws [IdnaException] if encoding or validation fails.
5444///
5545/// Example:
5646/// ```dart
@@ -63,68 +53,21 @@ String idnaEncode(String domain) {
6353 return domain;
6454 }
6555
66- final labels = domain.split ('.' );
67- final encodedLabels = < String > [];
68-
69- for (final label in labels) {
70- final encoded = _encodeLabel (label);
71- encodedLabels.add (encoded);
72- }
73-
74- final result = encodedLabels.join ('.' );
75-
76- // Validate total domain length
77- if (result.length > maxDomainLength) {
78- throw IdnaException ('Encoded domain exceeds maximum length of $maxDomainLength characters: '
79- '${result .length } characters' );
80- }
81-
82- return result;
83- }
84-
85- /// Encodes a single domain label using IDNA rules.
86- String _encodeLabel (String label) {
87- if (label.isEmpty) {
88- // Empty labels can occur with trailing dots (e.g., "example.com.")
89- // Return as-is to preserve the structure
90- return label;
91- }
92-
93- // 1. Normalize to NFC (Normalization Form Canonical Composition)
94- // This ensures that characters like 'ü' (U+00FC) and 'u' + '̈' (U+0308)
95- // are treated identically.
96- String normalized = unorm.nfc (label);
56+ // Normalize to NFC (Normalization Form Canonical Composition)
57+ // punycoder expects input to be normalized.
58+ final normalized = unorm.nfc (domain);
9759
98- // 2. Case folding: convert to lowercase
99- // Domain names are case-insensitive per DNS specifications.
100- normalized = normalized.toLowerCase ();
101-
102- // 3. Encode using PunycodeCodec
103- // The codec automatically:
104- // - Returns unchanged if already ASCII
105- // - Adds 'xn--' prefix for non-ASCII labels
10660 try {
107- final encoded = _punycodeCodec.encode (normalized);
108-
109- // 4. Validate encoded label length
110- if (encoded.length > maxLabelLength) {
111- throw IdnaException ('Encoded label exceeds maximum length of $maxLabelLength characters: '
112- '"$encoded " (${encoded .length } characters)' );
113- }
114-
115- return encoded;
116- } catch (e) {
117- if (e is IdnaException ) rethrow ;
118- throw IdnaException ('Failed to encode label "$label ": $e ' );
61+ // Use domainToAscii which handles splitting, lowercase, prefix and validation
62+ return domainToAscii (normalized);
63+ } on FormatException catch (e) {
64+ throw IdnaException (e.message);
11965 }
12066}
12167
12268/// Decodes a Punycode-encoded domain name back to Unicode.
12369///
124- /// This function:
125- /// 1. Splits the domain into labels
126- /// 2. Detects 'xn--' prefixed labels and decodes them
127- /// 3. Returns the decoded Unicode domain
70+ /// This function uses [domainToUnicode] to handle 'xn--' prefixed labels.
12871///
12972/// Throws [IdnaException] if Punycode decoding fails.
13073///
@@ -137,28 +80,10 @@ String idnaDecode(String domain) {
13780 return domain;
13881 }
13982
140- final labels = domain.split ('.' );
141- final decodedLabels = < String > [];
142-
143- for (final label in labels) {
144- final decoded = _decodeLabel (label);
145- decodedLabels.add (decoded);
146- }
147-
148- return decodedLabels.join ('.' );
149- }
150-
151- /// Decodes a single Punycode label.
152- String _decodeLabel (String label) {
153- if (label.isEmpty) {
154- return label;
155- }
156-
157- // PunycodeCodec.decode handles 'xn--' prefixed labels automatically
15883 try {
159- return _punycodeCodec. decode (label );
160- } catch (e) {
161- throw IdnaException ('Failed to decode Punycode label "$ label ": $ e ' );
84+ return domainToUnicode (domain );
85+ } on FormatException catch (e) {
86+ throw IdnaException (e.message );
16287 }
16388}
16489
0 commit comments