Initial commit
This commit is contained in:
commit
afed023152
8152 files changed
+2086461
No files matched your search
+172
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* Get the named reference for an XML special character or U+00A0.
|
||||
* @param char Code unit matched by one of the escape regexes.
|
||||
*/
|
||||
function getEscape(char) {
|
||||
return char === 34
|
||||
? """
|
||||
: char === 38
|
||||
? "&"
|
||||
: char === 39
|
||||
? "'"
|
||||
: char === 60
|
||||
? "<"
|
||||
: char === 62
|
||||
? ">"
|
||||
: " ";
|
||||
}
|
||||
/**
|
||||
* Read a code point at a given index.
|
||||
* @param input String to read the code point from.
|
||||
* @param index Current read position in the input string.
|
||||
* @returns The code point at `index`, or `undefined` if `index` is out of range.
|
||||
* @deprecated Use `String.prototype.codePointAt` directly instead; this export
|
||||
* will be removed in the next major.
|
||||
*/
|
||||
export const getCodePoint = (input, index) => input.codePointAt(index);
|
||||
/**
|
||||
* Bitset for ASCII characters that need to be escaped in XML.
|
||||
*/
|
||||
export const XML_BITSET_VALUE = 0x50_00_00_c4; // 32..63 -> 34 ("),38 (&),39 ('),60 (<),62 (>)
|
||||
/**
|
||||
* Matches exactly the characters `encodeXML` escapes: the five XML special
|
||||
* characters plus every non-ASCII code unit (lone surrogates included — no
|
||||
* `u` flag). Kept in sync with `XML_BITSET_VALUE`.
|
||||
*
|
||||
* Shared with `encodeNonAsciiHTML` in `encode.ts`. Because the regex is
|
||||
* stateful (`g` flag), every call site must set `lastIndex` before use.
|
||||
*/
|
||||
// eslint-disable-next-line unicorn/prefer-unicode-code-point-escapes -- the `\u{...}` form requires the `u` flag, which we deliberately omit so lone surrogates match by code unit
|
||||
export const xmlEncodeRegex = /["&'<>\u0080-\uFFFF]/g;
|
||||
/**
|
||||
* Whether `code` (a UTF-16 code unit) is escaped by {@link encodeXML}: a
|
||||
* non-ASCII unit, or one of the five XML specials flagged in
|
||||
* `XML_BITSET_VALUE` (which is only meaningful for code units 32-63).
|
||||
* @param code Code unit to test.
|
||||
*/
|
||||
function isXmlEscapable(code) {
|
||||
return (code >= 0x80 ||
|
||||
(code >= 32 && code < 64 && ((XML_BITSET_VALUE >>> code) & 1) === 1));
|
||||
}
|
||||
/**
|
||||
* Encodes all non-ASCII characters, as well as characters not valid in XML
|
||||
* documents using XML entities.
|
||||
*
|
||||
* If a character has no equivalent entity, a numeric hexadecimal reference
|
||||
* (eg. `ü`) will be used.
|
||||
* @param input Input string to encode.
|
||||
*/
|
||||
export function encodeXML(input) {
|
||||
const { length } = input;
|
||||
let out;
|
||||
let last = 0;
|
||||
let index = 0;
|
||||
while (index < length) {
|
||||
const char = input.charCodeAt(index);
|
||||
/*
|
||||
* Find the next character to escape: scan a short window inline
|
||||
* (escapable characters cluster in markup-heavy input), then fall
|
||||
* back to the regex, which skips clean spans in native code.
|
||||
*/
|
||||
if (!isXmlEscapable(char)) {
|
||||
const bound = Math.min(index + 32, length);
|
||||
let next = index + 1;
|
||||
while (next < bound && !isXmlEscapable(input.charCodeAt(next))) {
|
||||
next++;
|
||||
}
|
||||
if (next < bound) {
|
||||
index = next;
|
||||
continue;
|
||||
}
|
||||
if (next >= length)
|
||||
break;
|
||||
xmlEncodeRegex.lastIndex = next;
|
||||
if (!xmlEncodeRegex.test(input))
|
||||
break;
|
||||
index = xmlEncodeRegex.lastIndex - 1;
|
||||
continue;
|
||||
}
|
||||
if (out === undefined)
|
||||
out = input.substring(0, index);
|
||||
else if (last !== index)
|
||||
out += input.substring(last, index);
|
||||
if (char < 64) {
|
||||
// Known replacement
|
||||
out += getEscape(char);
|
||||
last = index += 1;
|
||||
continue;
|
||||
}
|
||||
// Non-ASCII: encode as numeric entity (handle surrogate pair)
|
||||
const cp = input.codePointAt(index);
|
||||
out += `&#x${cp.toString(16)};`;
|
||||
if (cp !== char)
|
||||
index++; // Skip trailing surrogate
|
||||
last = index += 1;
|
||||
}
|
||||
if (out === undefined)
|
||||
return input;
|
||||
if (last < length)
|
||||
out += input.substr(last);
|
||||
return out;
|
||||
}
|
||||
/**
|
||||
* Encodes all non-ASCII characters, as well as characters not valid in XML
|
||||
* documents using numeric hexadecimal reference (eg. `ü`).
|
||||
*
|
||||
* Have a look at `escapeUTF8` if you want a more concise output at the expense
|
||||
* of reduced transportability.
|
||||
* @param data String to escape.
|
||||
*/
|
||||
export const escape = encodeXML;
|
||||
/**
|
||||
* Escape `data` using `re`, mapping each matched character to its entity.
|
||||
* Every match is one UTF-16 code unit, so its index is `lastIndex - 1`.
|
||||
* @param re Global regex matching exactly the characters to escape
|
||||
* (`"`, `&`, `'`, `<`, `>`, `\u00A0` at most).
|
||||
* @param data String to escape.
|
||||
*/
|
||||
function escapeWithRegex(re, data) {
|
||||
re.lastIndex = 0;
|
||||
if (!re.test(data))
|
||||
return data;
|
||||
let out = "";
|
||||
let last = 0;
|
||||
do {
|
||||
const index = re.lastIndex - 1;
|
||||
if (last !== index)
|
||||
out += data.substring(last, index);
|
||||
const char = data.charCodeAt(index);
|
||||
out += getEscape(char);
|
||||
last = index + 1;
|
||||
} while (re.test(data));
|
||||
return out + data.substring(last);
|
||||
}
|
||||
const xmlEscapeRegex = /["&'<>]/g;
|
||||
/**
|
||||
* Encodes all characters not valid in XML documents using XML entities.
|
||||
*
|
||||
* Note that the output will be character-set dependent.
|
||||
* @param data String to escape.
|
||||
*/
|
||||
export function escapeUTF8(data) {
|
||||
return escapeWithRegex(xmlEscapeRegex, data);
|
||||
}
|
||||
const attributeEscapeRegex = /["&\u{A0}]/gu;
|
||||
/**
|
||||
* Encodes all characters that have to be escaped in HTML attributes,
|
||||
* following {@link https://html.spec.whatwg.org/multipage/parsing.html#escapingString}.
|
||||
* @param data String to escape.
|
||||
*/
|
||||
export function escapeAttribute(data) {
|
||||
return escapeWithRegex(attributeEscapeRegex, data);
|
||||
}
|
||||
const textEscapeRegex = /[&<>\u{A0}]/gu;
|
||||
/**
|
||||
* Encodes all characters that have to be escaped in HTML text,
|
||||
* following {@link https://html.spec.whatwg.org/multipage/parsing.html#escapingString}.
|
||||
* @param data String to escape.
|
||||
*/
|
||||
export function escapeText(data) {
|
||||
return escapeWithRegex(textEscapeRegex, data);
|
||||
}
|
||||
//# sourceMappingURL=escape.js.map
|
||||
Reference in new issue
Block a user