encode.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. 'use strict';
  2. var encodeCache = {};
  3. // Create a lookup array where anything but characters in `chars` string
  4. // and alphanumeric chars is percent-encoded.
  5. //
  6. function getEncodeCache(exclude) {
  7. var i, ch, cache = encodeCache[exclude];
  8. if (cache) { return cache; }
  9. cache = encodeCache[exclude] = [];
  10. for (i = 0; i < 128; i++) {
  11. ch = String.fromCharCode(i);
  12. if (/^[0-9a-z]$/i.test(ch)) {
  13. // always allow unencoded alphanumeric characters
  14. cache.push(ch);
  15. } else {
  16. cache.push('%' + ('0' + i.toString(16).toUpperCase()).slice(-2));
  17. }
  18. }
  19. for (i = 0; i < exclude.length; i++) {
  20. cache[exclude.charCodeAt(i)] = exclude[i];
  21. }
  22. return cache;
  23. }
  24. // Encode unsafe characters with percent-encoding, skipping already
  25. // encoded sequences.
  26. //
  27. // - string - string to encode
  28. // - exclude - list of characters to ignore (in addition to a-zA-Z0-9)
  29. // - keepEscaped - don't encode '%' in a correct escape sequence (default: true)
  30. //
  31. function encode(string, exclude, keepEscaped) {
  32. var i, l, code, nextCode, cache,
  33. result = '';
  34. if (typeof exclude !== 'string') {
  35. // encode(string, keepEscaped)
  36. keepEscaped = exclude;
  37. exclude = encode.defaultChars;
  38. }
  39. if (typeof keepEscaped === 'undefined') {
  40. keepEscaped = true;
  41. }
  42. cache = getEncodeCache(exclude);
  43. for (i = 0, l = string.length; i < l; i++) {
  44. code = string.charCodeAt(i);
  45. if (keepEscaped && code === 0x25 /* % */ && i + 2 < l) {
  46. if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) {
  47. result += string.slice(i, i + 3);
  48. i += 2;
  49. continue;
  50. }
  51. }
  52. if (code < 128) {
  53. result += cache[code];
  54. continue;
  55. }
  56. if (code >= 0xD800 && code <= 0xDFFF) {
  57. if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l) {
  58. nextCode = string.charCodeAt(i + 1);
  59. if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) {
  60. result += encodeURIComponent(string[i] + string[i + 1]);
  61. i++;
  62. continue;
  63. }
  64. }
  65. result += '%EF%BF%BD';
  66. continue;
  67. }
  68. result += encodeURIComponent(string[i]);
  69. }
  70. return result;
  71. }
  72. encode.defaultChars = ";/?:@&=+$,-_.!~*'()#";
  73. encode.componentChars = "-_.!~*'()";
  74. module.exports = encode;