182 lines
No EOL
7 KiB
JavaScript
182 lines
No EOL
7 KiB
JavaScript
"use strict";
|
|
/*!
|
|
* Adapted from cssesc v3.0.0 <https://mths.be/cssesc>
|
|
*
|
|
* Copyright Mathias Bynens <https://mathiasbynens.be/>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.default = cssesc;
|
|
// The only behavioural difference from cssesc 3.0.0 is how redundant spaces
|
|
// after `\HEX` escapes are removed: upstream uses a regular expression that
|
|
// backtracks quadratically on long runs of backslashes, which a crafted
|
|
// selector could use to pin a CPU core. removeExcessiveSpaces() produces the
|
|
// same output in linear time. Upstream has not been released since 2019, and
|
|
// the pending fix there (mathiasbynens/cssesc#36) changes the output. An
|
|
// unreachable branch escaping \t, \n, \f, \r and \x0B was also dropped: those
|
|
// characters are below 0x20 and always take the hex escape path first.
|
|
var DEFAULTS = {
|
|
escapeEverything: false,
|
|
isIdentifier: false,
|
|
quotes: "single",
|
|
wrap: false,
|
|
};
|
|
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
function merge(options, defaults) {
|
|
if (!options) {
|
|
return defaults;
|
|
}
|
|
var result = {};
|
|
for (var key in defaults) {
|
|
result[key] = hasOwnProperty.call(options, key) ? options[key] : defaults[key];
|
|
}
|
|
return result;
|
|
}
|
|
var regexAnySingleEscape = /[ -,./:-@[-^`{-~]/;
|
|
var regexSingleEscape = /[ -,./:-@[\]^`{-~]/;
|
|
var BACKSLASH = 0x5c;
|
|
var SPACE = 0x20;
|
|
function isUpperHex(code) {
|
|
return (code >= 0x30 && code <= 0x39) || (code >= 0x41 && code <= 0x46);
|
|
}
|
|
function isHexOrSpace(code) {
|
|
return isUpperHex(code) || (code >= 0x61 && code <= 0x66) || code === SPACE;
|
|
}
|
|
/**
|
|
* Remove spaces after `\HEX` escapes that are not followed by a hex digit or a
|
|
* space, since they are redundant. This is only possible if the escape is not
|
|
* preceded by an odd number of backslashes, which would make its own backslash
|
|
* an escaped one.
|
|
*
|
|
* Same result as cssesc 3.0.0's
|
|
* `output.replace(/(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g, ...)`:
|
|
* a match can only start at the beginning of a run of backslashes and only
|
|
* its last backslash can open the escape, so each run is measured once
|
|
* instead of being re-scanned from every position inside it.
|
|
*/
|
|
function removeExcessiveSpaces(output) {
|
|
var length = output.length;
|
|
var result = "";
|
|
var copied = 0;
|
|
var i = 0;
|
|
while (i < length) {
|
|
if (output.charCodeAt(i) !== BACKSLASH) {
|
|
i++;
|
|
continue;
|
|
}
|
|
var runEnd = i + 1;
|
|
while (runEnd < length && output.charCodeAt(runEnd) === BACKSLASH) {
|
|
runEnd++;
|
|
}
|
|
// Look at up to 7 hex digits: more than 6 can never be followed directly
|
|
// by the space.
|
|
var hexEnd = runEnd;
|
|
while (hexEnd < length && hexEnd - runEnd < 7 && isUpperHex(output.charCodeAt(hexEnd))) {
|
|
hexEnd++;
|
|
}
|
|
var hexLength = hexEnd - runEnd;
|
|
if (hexLength >= 1 &&
|
|
hexLength <= 6 &&
|
|
output.charCodeAt(hexEnd) === SPACE &&
|
|
!isHexOrSpace(output.charCodeAt(hexEnd + 1))) {
|
|
// Backslashes preceding the one that opens the escape.
|
|
if ((runEnd - i - 1) % 2 === 0) {
|
|
result += output.slice(copied, hexEnd);
|
|
copied = hexEnd + 1;
|
|
}
|
|
i = hexEnd + 1;
|
|
}
|
|
else {
|
|
i = runEnd;
|
|
}
|
|
}
|
|
return copied === 0 ? output : result + output.slice(copied);
|
|
}
|
|
// https://mathiasbynens.be/notes/css-escapes#css
|
|
function cssesc(string, options) {
|
|
options = merge(options, DEFAULTS);
|
|
if (options.quotes !== "single" && options.quotes !== "double") {
|
|
options.quotes = "single";
|
|
}
|
|
var quote = options.quotes === "double" ? '"' : "'";
|
|
var isIdentifier = options.isIdentifier;
|
|
var firstChar = string.charAt(0);
|
|
var output = "";
|
|
var counter = 0;
|
|
var length = string.length;
|
|
while (counter < length) {
|
|
var character = string.charAt(counter++);
|
|
var codePoint = character.charCodeAt(0);
|
|
var value = void 0;
|
|
// If it's not a printable ASCII character...
|
|
if (codePoint < 0x20 || codePoint > 0x7e) {
|
|
if (codePoint >= 0xd800 && codePoint <= 0xdbff && counter < length) {
|
|
// It's a high surrogate, and there is a next character.
|
|
var extra = string.charCodeAt(counter++);
|
|
if ((extra & 0xfc00) === 0xdc00) {
|
|
// next character is low surrogate
|
|
codePoint = ((codePoint & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;
|
|
}
|
|
else {
|
|
// It's an unmatched surrogate; only append this code unit, in case
|
|
// the next code unit is the high surrogate of a surrogate pair.
|
|
counter--;
|
|
}
|
|
}
|
|
value = "\\" + codePoint.toString(16).toUpperCase() + " ";
|
|
}
|
|
else {
|
|
if (options.escapeEverything) {
|
|
if (regexAnySingleEscape.test(character)) {
|
|
value = "\\" + character;
|
|
}
|
|
else {
|
|
value = "\\" + codePoint.toString(16).toUpperCase() + " ";
|
|
}
|
|
}
|
|
else if (character === "\\" ||
|
|
(!isIdentifier &&
|
|
((character === '"' && quote === character) ||
|
|
(character === "'" && quote === character))) ||
|
|
(isIdentifier && regexSingleEscape.test(character))) {
|
|
value = "\\" + character;
|
|
}
|
|
else {
|
|
value = character;
|
|
}
|
|
}
|
|
output += value;
|
|
}
|
|
if (isIdentifier) {
|
|
if (/^-[-\d]/.test(output)) {
|
|
output = "\\-" + output.slice(1);
|
|
}
|
|
else if (/\d/.test(firstChar)) {
|
|
output = "\\3" + firstChar + " " + output.slice(1);
|
|
}
|
|
}
|
|
output = removeExcessiveSpaces(output);
|
|
if (!isIdentifier && options.wrap) {
|
|
return quote + output + quote;
|
|
}
|
|
return output;
|
|
}
|
|
//# sourceMappingURL=cssesc.js.map
|