mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
3.2 KiB
132 lines
3.2 KiB
8 years ago
|
'use strict';
|
||
|
|
||
|
var entities = require('character-entities-html4');
|
||
|
var legacy = require('character-entities-legacy');
|
||
|
var has = require('has');
|
||
|
var hexadecimal = require('is-hexadecimal');
|
||
|
var alphanumerical = require('is-alphanumerical');
|
||
|
var dangerous = require('./dangerous.json');
|
||
|
|
||
|
/* Expose. */
|
||
|
module.exports = encode;
|
||
|
|
||
|
encode.escape = escape;
|
||
|
|
||
|
/* List of enforced escapes. */
|
||
|
var escapes = ['"', '\'', '<', '>', '&', '`'];
|
||
|
|
||
|
/* Map of characters to names. */
|
||
|
var characters = construct();
|
||
|
|
||
|
/* Default escapes. */
|
||
|
var EXPRESSION_ESCAPE = toExpression(escapes);
|
||
|
|
||
|
/* Surrogate pairs. */
|
||
|
var EXPRESSION_SURROGATE_PAIR = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
||
|
|
||
|
/* Non-ASCII characters. */
|
||
|
// eslint-disable-next-line no-control-regex
|
||
|
var EXPRESSION_BMP = /[\x01-\t\x0B\f\x0E-\x1F\x7F\x81\x8D\x8F\x90\x9D\xA0-\uFFFF]/g;
|
||
|
|
||
|
/* Encode special characters in `value`. */
|
||
|
function encode(value, options) {
|
||
|
var settings = options || {};
|
||
|
var subset = settings.subset;
|
||
|
var set = subset ? toExpression(subset) : EXPRESSION_ESCAPE;
|
||
|
var escapeOnly = settings.escapeOnly;
|
||
|
var omit = settings.omitOptionalSemicolons;
|
||
|
|
||
|
value = value.replace(set, function (char, pos, val) {
|
||
|
return one(char, val.charAt(pos + 1), settings);
|
||
|
});
|
||
|
|
||
|
if (subset || escapeOnly) {
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
return value
|
||
|
.replace(EXPRESSION_SURROGATE_PAIR, function (pair, pos, val) {
|
||
|
return toHexReference(
|
||
|
((pair.charCodeAt(0) - 0xD800) * 0x400) +
|
||
|
pair.charCodeAt(1) - 0xDC00 + 0x10000,
|
||
|
val.charAt(pos + 2),
|
||
|
omit
|
||
|
);
|
||
|
})
|
||
|
.replace(EXPRESSION_BMP, function (char, pos, val) {
|
||
|
return one(char, val.charAt(pos + 1), settings);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/* Shortcut to escape special characters in HTML. */
|
||
|
function escape(value) {
|
||
|
return encode(value, {
|
||
|
escapeOnly: true,
|
||
|
useNamedReferences: true
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/* Encode `char` according to `options`. */
|
||
|
function one(char, next, options) {
|
||
|
var shortest = options.useShortestReferences;
|
||
|
var omit = options.omitOptionalSemicolons;
|
||
|
var named;
|
||
|
var numeric;
|
||
|
|
||
|
if (
|
||
|
(shortest || options.useNamedReferences) &&
|
||
|
has(characters, char)
|
||
|
) {
|
||
|
named = toNamed(characters[char], next, omit, options.attribute);
|
||
|
}
|
||
|
|
||
|
if (shortest || !named) {
|
||
|
numeric = toHexReference(char.charCodeAt(0), next, omit);
|
||
|
}
|
||
|
|
||
|
if (named && (!shortest || named.length < numeric.length)) {
|
||
|
return named;
|
||
|
}
|
||
|
|
||
|
return numeric;
|
||
|
}
|
||
|
|
||
|
/* Transform `code` into an entity. */
|
||
|
function toNamed(name, next, omit, attribute) {
|
||
|
var value = '&' + name;
|
||
|
|
||
|
if (
|
||
|
omit &&
|
||
|
has(legacy, name) &&
|
||
|
dangerous.indexOf(name) === -1 &&
|
||
|
(!attribute || (next && next !== '=' && !alphanumerical(next)))
|
||
|
) {
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
return value + ';';
|
||
|
}
|
||
|
|
||
|
/* Transform `code` into a hexadecimal character reference. */
|
||
|
function toHexReference(code, next, omit) {
|
||
|
var value = '&#x' + code.toString(16).toUpperCase();
|
||
|
return omit && next && !hexadecimal(next) ? value : value + ';';
|
||
|
}
|
||
|
|
||
|
/* Create an expression for `characters`. */
|
||
|
function toExpression(characters) {
|
||
|
return new RegExp('[' + characters.join('') + ']', 'g');
|
||
|
}
|
||
|
|
||
|
/* Construct the map. */
|
||
|
function construct() {
|
||
|
var chars = {};
|
||
|
var name;
|
||
|
|
||
|
for (name in entities) {
|
||
|
chars[entities[name]] = name;
|
||
|
}
|
||
|
|
||
|
return chars;
|
||
|
}
|