const encodeCache = {} // Create a lookup array where anything but characters in `chars` string // and alphanumeric chars is percent-encoded. // function getEncodeCache (exclude) { let cache = encodeCache[exclude] if (cache) { return cache } cache = encodeCache[exclude] = [] for (let i = 0; i < 128; i++) { const ch = String.fromCharCode(i) if (/^[0-9a-z]$/i.test(ch)) { // always allow unencoded alphanumeric characters cache.push(ch) } else { cache.push('%' + ('0' + i.toString(16).toUpperCase()).slice(-2)) } } for (let i = 0; i < exclude.length; i++) { cache[exclude.charCodeAt(i)] = exclude[i] } return cache } // Encode unsafe characters with percent-encoding, skipping already // encoded sequences. // // - string - string to encode // - exclude - list of characters to ignore (in addition to a-zA-Z0-9) // - keepEscaped - don't encode '%' in a correct escape sequence (default: true) // function encode (string, exclude, keepEscaped) { if (typeof exclude !== 'string') { // encode(string, keepEscaped) keepEscaped = exclude exclude = encode.defaultChars } if (typeof keepEscaped === 'undefined') { keepEscaped = true } const cache = getEncodeCache(exclude) let result = '' for (let i = 0, l = string.length; i < l; i++) { const code = string.charCodeAt(i) if (keepEscaped && code === 0x25 /* % */ && i + 2 < l) { if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) { result += string.slice(i, i + 3) i += 2 continue } } if (code < 128) { result += cache[code] continue } if (code >= 0xD800 && code <= 0xDFFF) { if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l) { const nextCode = string.charCodeAt(i + 1) if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) { result += encodeURIComponent(string[i] + string[i + 1]) i++ continue } } result += '%EF%BF%BD' continue } result += encodeURIComponent(string[i]) } return result } encode.defaultChars = ";/?:@&=+$,-_.!~*'()#" encode.componentChars = "-_.!~*'()" export default encode