2 // based on https://github.com/bestiejs/punycode.js/blob/master/punycode.js
3 var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
10 var initialN = 128; // 0x80
11 var delimiter = '-'; // '\x2D'
12 var regexNonASCII = /[^\0-\u007E]/; // non-ASCII chars
13 var regexSeparators = /[.\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
14 var OVERFLOW_ERROR = 'Overflow: input needs wider integers to process';
15 var baseMinusTMin = base - tMin;
16 var floor = Math.floor;
17 var stringFromCharCode = String.fromCharCode;
20 * Creates an array containing the numeric code points of each Unicode
21 * character in the string. While JavaScript uses UCS-2 internally,
22 * this function will convert a pair of surrogate halves (each of which
23 * UCS-2 exposes as separate characters) into a single code point,
26 var ucs2decode = function (string) {
29 var length = string.length;
30 while (counter < length) {
31 var value = string.charCodeAt(counter++);
32 if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
33 // It's a high surrogate, and there is a next character.
34 var extra = string.charCodeAt(counter++);
35 if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
36 output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
38 // It's an unmatched surrogate; only append this code unit, in case the
39 // next code unit is the high surrogate of a surrogate pair.
51 * Converts a digit/integer into a basic code point.
53 var digitToBasic = function (digit) {
54 // 0..25 map to ASCII a..z or A..Z
55 // 26..35 map to ASCII 0..9
56 return digit + 22 + 75 * (digit < 26);
60 * Bias adaptation function as per section 3.4 of RFC 3492.
61 * https://tools.ietf.org/html/rfc3492#section-3.4
63 var adapt = function (delta, numPoints, firstTime) {
65 delta = firstTime ? floor(delta / damp) : delta >> 1;
66 delta += floor(delta / numPoints);
67 for (; delta > baseMinusTMin * tMax >> 1; k += base) {
68 delta = floor(delta / baseMinusTMin);
70 return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
74 * Converts a string of Unicode symbols (e.g. a domain name label) to a
75 * Punycode string of ASCII-only symbols.
77 // eslint-disable-next-line max-statements -- TODO
78 var encode = function (input) {
81 // Convert the input in UCS-2 to an array of Unicode code points.
82 input = ucs2decode(input);
85 var inputLength = input.length;
87 // Initialize the state.
90 var bias = initialBias;
93 // Handle the basic code points.
94 for (i = 0; i < input.length; i++) {
95 currentValue = input[i];
96 if (currentValue < 0x80) {
97 output.push(stringFromCharCode(currentValue));
101 var basicLength = output.length; // number of basic code points.
102 var handledCPCount = basicLength; // number of code points that have been handled;
104 // Finish the basic string with a delimiter unless it's empty.
106 output.push(delimiter);
109 // Main encoding loop:
110 while (handledCPCount < inputLength) {
111 // All non-basic code points < n have been handled already. Find the next larger one:
113 for (i = 0; i < input.length; i++) {
114 currentValue = input[i];
115 if (currentValue >= n && currentValue < m) {
120 // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>, but guard against overflow.
121 var handledCPCountPlusOne = handledCPCount + 1;
122 if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
123 throw RangeError(OVERFLOW_ERROR);
126 delta += (m - n) * handledCPCountPlusOne;
129 for (i = 0; i < input.length; i++) {
130 currentValue = input[i];
131 if (currentValue < n && ++delta > maxInt) {
132 throw RangeError(OVERFLOW_ERROR);
134 if (currentValue == n) {
135 // Represent delta as a generalized variable-length integer.
137 for (var k = base; /* no condition */; k += base) {
138 var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
141 var baseMinusT = base - t;
142 output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT)));
143 q = floor(qMinusT / baseMinusT);
146 output.push(stringFromCharCode(digitToBasic(q)));
147 bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
156 return output.join('');
159 module.exports = function (input) {
161 var labels = input.toLowerCase().replace(regexSeparators, '\u002E').split('.');
163 for (i = 0; i < labels.length; i++) {
165 encoded.push(regexNonASCII.test(label) ? 'xn--' + encode(label) : label);
167 return encoded.join('.');