decode.js 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. 'use strict';
  2. var punycode = require('punycode/');
  3. var $encode = punycode.ucs2.encode;
  4. var regexTest = require('safe-regex-test');
  5. var callBound = require('call-bound');
  6. var $TypeError = require('es-errors/type');
  7. var entities = require('./entities.json');
  8. var endsInSemicolon = regexTest(/;$/);
  9. var $replace = callBound('String.prototype.replace');
  10. var $exec = callBound('RegExp.prototype.exec');
  11. var $parseInt = parseInt;
  12. module.exports = function decode(str) {
  13. if (typeof str !== 'string') {
  14. throw new $TypeError('Expected a String');
  15. }
  16. return $replace(str, /&(#?[^;\W]+;?)/g, function (_, match) {
  17. var m = $exec(/^#(\d+);?$/, match);
  18. if (m) {
  19. return $encode([$parseInt(m[1], 10)]);
  20. }
  21. var m2 = $exec(/^#[Xx]([A-Fa-f0-9]+);?/, match);
  22. if (m2) {
  23. return $encode([$parseInt(m2[1], 16)]);
  24. }
  25. // named entity
  26. var hasSemi = endsInSemicolon(match);
  27. var withoutSemi = hasSemi ? $replace(match, /;$/, '') : match;
  28. var target = entities[withoutSemi] || (hasSemi && entities[match]);
  29. if (typeof target === 'number') {
  30. return $encode([target]);
  31. } else if (typeof target === 'string') {
  32. return target;
  33. }
  34. return '&' + match;
  35. });
  36. };