escapeHtml.js 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. 'use strict';
  2. const internals = {};
  3. module.exports = function (input) {
  4. if (!input) {
  5. return '';
  6. }
  7. let escaped = '';
  8. for (let i = 0; i < input.length; ++i) {
  9. const charCode = input.charCodeAt(i);
  10. if (internals.isSafe(charCode)) {
  11. escaped += input[i];
  12. }
  13. else {
  14. escaped += internals.escapeHtmlChar(charCode);
  15. }
  16. }
  17. return escaped;
  18. };
  19. internals.escapeHtmlChar = function (charCode) {
  20. const namedEscape = internals.namedHtml[charCode];
  21. if (typeof namedEscape !== 'undefined') {
  22. return namedEscape;
  23. }
  24. if (charCode >= 256) {
  25. return '&#' + charCode + ';';
  26. }
  27. const hexValue = charCode.toString(16).padStart(2, '0');
  28. return `&#x${hexValue};`;
  29. };
  30. internals.isSafe = function (charCode) {
  31. return (typeof internals.safeCharCodes[charCode] !== 'undefined');
  32. };
  33. internals.namedHtml = {
  34. '38': '&amp;',
  35. '60': '&lt;',
  36. '62': '&gt;',
  37. '34': '&quot;',
  38. '160': '&nbsp;',
  39. '162': '&cent;',
  40. '163': '&pound;',
  41. '164': '&curren;',
  42. '169': '&copy;',
  43. '174': '&reg;'
  44. };
  45. internals.safeCharCodes = (function () {
  46. const safe = {};
  47. for (let i = 32; i < 123; ++i) {
  48. if ((i >= 97) || // a-z
  49. (i >= 65 && i <= 90) || // A-Z
  50. (i >= 48 && i <= 57) || // 0-9
  51. i === 32 || // space
  52. i === 46 || // .
  53. i === 44 || // ,
  54. i === 45 || // -
  55. i === 58 || // :
  56. i === 95) { // _
  57. safe[i] = null;
  58. }
  59. }
  60. return safe;
  61. }());