var inverseXML = getInverseObj(require("../maps/xml.json")), xmlReplacer = getInverseReplacer(inverseXML); exports.XML = getInverse(inverseXML, xmlReplacer); var inverseHTML = getInverseObj(require("../maps/entities.json")), htmlReplacer = getInverseReplacer(inverseHTML); exports.HTML = getInverse(inverseHTML, htmlReplacer); function getInverseObj(obj) { return Object.keys(obj) .sort() .reduce(function(inverse, name) { inverse[obj[name]] = "&" + name + ";"; return inverse; }, {}); } function getInverseReplacer(inverse) { var single = [], multiple = []; Object.keys(inverse).forEach(function(k) { if (k.length === 1) { single.push("\\" + k); } else { multiple.push(k); } }); //TODO add ranges multiple.unshift("[" + single.join("") + "]"); return new RegExp(multiple.join("|"), "g"); } var re_nonASCII = /[^\0-\x7F]/g, re_astralSymbols = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g; function singleCharReplacer(c) { return ( "&#x" + c .charCodeAt(0) .toString(16) .toUpperCase() + ";" ); } function astralReplacer(c) { // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae var high = c.charCodeAt(0); var low = c.charCodeAt(1); var codePoint = (high - 0xd800) * 0x400 + low - 0xdc00 + 0x10000; return "&#x" + codePoint.toString(16).toUpperCase() + ";"; } function getInverse(inverse, re) { function func(name) { return inverse[name]; } return function(data) { return data .replace(re, func) .replace(re_astralSymbols, astralReplacer) .replace(re_nonASCII, singleCharReplacer); }; } var re_xmlChars = getInverseReplacer(inverseXML); function escapeXML(data) { return data .replace(re_xmlChars, singleCharReplacer) .replace(re_astralSymbols, astralReplacer) .replace(re_nonASCII, singleCharReplacer); } exports.escape = escapeXML;