utils.js (6204B)
1 'use strict'; 2 3 var has = Object.prototype.hasOwnProperty; 4 var isArray = Array.isArray; 5 6 var hexTable = (function () { 7 var array = []; 8 for (var i = 0; i < 256; ++i) { 9 array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase()); 10 } 11 12 return array; 13 }()); 14 15 var compactQueue = function compactQueue(queue) { 16 while (queue.length > 1) { 17 var item = queue.pop(); 18 var obj = item.obj[item.prop]; 19 20 if (isArray(obj)) { 21 var compacted = []; 22 23 for (var j = 0; j < obj.length; ++j) { 24 if (typeof obj[j] !== 'undefined') { 25 compacted.push(obj[j]); 26 } 27 } 28 29 item.obj[item.prop] = compacted; 30 } 31 } 32 }; 33 34 var arrayToObject = function arrayToObject(source, options) { 35 var obj = options && options.plainObjects ? Object.create(null) : {}; 36 for (var i = 0; i < source.length; ++i) { 37 if (typeof source[i] !== 'undefined') { 38 obj[i] = source[i]; 39 } 40 } 41 42 return obj; 43 }; 44 45 var merge = function merge(target, source, options) { 46 if (!source) { 47 return target; 48 } 49 50 if (typeof source !== 'object') { 51 if (isArray(target)) { 52 target.push(source); 53 } else if (target && typeof target === 'object') { 54 if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) { 55 target[source] = true; 56 } 57 } else { 58 return [target, source]; 59 } 60 61 return target; 62 } 63 64 if (!target || typeof target !== 'object') { 65 return [target].concat(source); 66 } 67 68 var mergeTarget = target; 69 if (isArray(target) && !isArray(source)) { 70 mergeTarget = arrayToObject(target, options); 71 } 72 73 if (isArray(target) && isArray(source)) { 74 source.forEach(function (item, i) { 75 if (has.call(target, i)) { 76 var targetItem = target[i]; 77 if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') { 78 target[i] = merge(targetItem, item, options); 79 } else { 80 target.push(item); 81 } 82 } else { 83 target[i] = item; 84 } 85 }); 86 return target; 87 } 88 89 return Object.keys(source).reduce(function (acc, key) { 90 var value = source[key]; 91 92 if (has.call(acc, key)) { 93 acc[key] = merge(acc[key], value, options); 94 } else { 95 acc[key] = value; 96 } 97 return acc; 98 }, mergeTarget); 99 }; 100 101 var assign = function assignSingleSource(target, source) { 102 return Object.keys(source).reduce(function (acc, key) { 103 acc[key] = source[key]; 104 return acc; 105 }, target); 106 }; 107 108 var decode = function (str, decoder, charset) { 109 var strWithoutPlus = str.replace(/\+/g, ' '); 110 if (charset === 'iso-8859-1') { 111 // unescape never throws, no try...catch needed: 112 return strWithoutPlus.replace(/%[0-9a-f]{2}/gi, unescape); 113 } 114 // utf-8 115 try { 116 return decodeURIComponent(strWithoutPlus); 117 } catch (e) { 118 return strWithoutPlus; 119 } 120 }; 121 122 var encode = function encode(str, defaultEncoder, charset) { 123 // This code was originally written by Brian White (mscdex) for the io.js core querystring library. 124 // It has been adapted here for stricter adherence to RFC 3986 125 if (str.length === 0) { 126 return str; 127 } 128 129 var string = typeof str === 'string' ? str : String(str); 130 131 if (charset === 'iso-8859-1') { 132 return escape(string).replace(/%u[0-9a-f]{4}/gi, function ($0) { 133 return '%26%23' + parseInt($0.slice(2), 16) + '%3B'; 134 }); 135 } 136 137 var out = ''; 138 for (var i = 0; i < string.length; ++i) { 139 var c = string.charCodeAt(i); 140 141 if ( 142 c === 0x2D // - 143 || c === 0x2E // . 144 || c === 0x5F // _ 145 || c === 0x7E // ~ 146 || (c >= 0x30 && c <= 0x39) // 0-9 147 || (c >= 0x41 && c <= 0x5A) // a-z 148 || (c >= 0x61 && c <= 0x7A) // A-Z 149 ) { 150 out += string.charAt(i); 151 continue; 152 } 153 154 if (c < 0x80) { 155 out = out + hexTable[c]; 156 continue; 157 } 158 159 if (c < 0x800) { 160 out = out + (hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)]); 161 continue; 162 } 163 164 if (c < 0xD800 || c >= 0xE000) { 165 out = out + (hexTable[0xE0 | (c >> 12)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]); 166 continue; 167 } 168 169 i += 1; 170 c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF)); 171 out += hexTable[0xF0 | (c >> 18)] 172 + hexTable[0x80 | ((c >> 12) & 0x3F)] 173 + hexTable[0x80 | ((c >> 6) & 0x3F)] 174 + hexTable[0x80 | (c & 0x3F)]; 175 } 176 177 return out; 178 }; 179 180 var compact = function compact(value) { 181 var queue = [{ obj: { o: value }, prop: 'o' }]; 182 var refs = []; 183 184 for (var i = 0; i < queue.length; ++i) { 185 var item = queue[i]; 186 var obj = item.obj[item.prop]; 187 188 var keys = Object.keys(obj); 189 for (var j = 0; j < keys.length; ++j) { 190 var key = keys[j]; 191 var val = obj[key]; 192 if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) { 193 queue.push({ obj: obj, prop: key }); 194 refs.push(val); 195 } 196 } 197 } 198 199 compactQueue(queue); 200 201 return value; 202 }; 203 204 var isRegExp = function isRegExp(obj) { 205 return Object.prototype.toString.call(obj) === '[object RegExp]'; 206 }; 207 208 var isBuffer = function isBuffer(obj) { 209 if (!obj || typeof obj !== 'object') { 210 return false; 211 } 212 213 return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj)); 214 }; 215 216 var combine = function combine(a, b) { 217 return [].concat(a, b); 218 }; 219 220 module.exports = { 221 arrayToObject: arrayToObject, 222 assign: assign, 223 combine: combine, 224 compact: compact, 225 decode: decode, 226 encode: encode, 227 isBuffer: isBuffer, 228 isRegExp: isRegExp, 229 merge: merge 230 };