1/*! https://mths.be/cssesc v3.0.0 by @mathias */ 2'use strict'; 3 4var object = {}; 5var hasOwnProperty = object.hasOwnProperty; 6var merge = function merge(options, defaults) { 7 if (!options) { 8 return defaults; 9 } 10 var result = {}; 11 for (var key in defaults) { 12 // `if (defaults.hasOwnProperty(key) { … }` is not needed here, since 13 // only recognized option names are used. 14 result[key] = hasOwnProperty.call(options, key) ? options[key] : defaults[key]; 15 } 16 return result; 17}; 18 19var regexAnySingleEscape = /[ -,\.\/:-@\[-\^`\{-~]/; 20var regexSingleEscape = /[ -,\.\/:-@\[\]\^`\{-~]/; 21var regexAlwaysEscape = /['"\\]/; 22var regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g; 23 24// https://mathiasbynens.be/notes/css-escapes#css 25var cssesc = function cssesc(string, options) { 26 options = merge(options, cssesc.options); 27 if (options.quotes != 'single' && options.quotes != 'double') { 28 options.quotes = 'single'; 29 } 30 var quote = options.quotes == 'double' ? '"' : '\''; 31 var isIdentifier = options.isIdentifier; 32 33 var firstChar = string.charAt(0); 34 var output = ''; 35 var counter = 0; 36 var length = string.length; 37 while (counter < length) { 38 var character = string.charAt(counter++); 39 var codePoint = character.charCodeAt(); 40 var value = void 0; 41 // If it’s not a printable ASCII character… 42 if (codePoint < 0x20 || codePoint > 0x7E) { 43 if (codePoint >= 0xD800 && codePoint <= 0xDBFF && counter < length) { 44 // It’s a high surrogate, and there is a next character. 45 var extra = string.charCodeAt(counter++); 46 if ((extra & 0xFC00) == 0xDC00) { 47 // next character is low surrogate 48 codePoint = ((codePoint & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000; 49 } else { 50 // It’s an unmatched surrogate; only append this code unit, in case 51 // the next code unit is the high surrogate of a surrogate pair. 52 counter--; 53 } 54 } 55 value = '\\' + codePoint.toString(16).toUpperCase() + ' '; 56 } else { 57 if (options.escapeEverything) { 58 if (regexAnySingleEscape.test(character)) { 59 value = '\\' + character; 60 } else { 61 value = '\\' + codePoint.toString(16).toUpperCase() + ' '; 62 } 63 } else if (/[\t\n\f\r\x0B]/.test(character)) { 64 value = '\\' + codePoint.toString(16).toUpperCase() + ' '; 65 } else if (character == '\\' || !isIdentifier && (character == '"' && quote == character || character == '\'' && quote == character) || isIdentifier && regexSingleEscape.test(character)) { 66 value = '\\' + character; 67 } else { 68 value = character; 69 } 70 } 71 output += value; 72 } 73 74 if (isIdentifier) { 75 if (/^-[-\d]/.test(output)) { 76 output = '\\-' + output.slice(1); 77 } else if (/\d/.test(firstChar)) { 78 output = '\\3' + firstChar + ' ' + output.slice(1); 79 } 80 } 81 82 // Remove spaces after `\HEX` escapes that are not followed by a hex digit, 83 // since they’re redundant. Note that this is only possible if the escape 84 // sequence isn’t preceded by an odd number of backslashes. 85 output = output.replace(regexExcessiveSpaces, function ($0, $1, $2) { 86 if ($1 && $1.length % 2) { 87 // It’s not safe to remove the space, so don’t. 88 return $0; 89 } 90 // Strip the space. 91 return ($1 || '') + $2; 92 }); 93 94 if (!isIdentifier && options.wrap) { 95 return quote + output + quote; 96 } 97 return output; 98}; 99 100// Expose default options (so they can be overridden globally). 101cssesc.options = { 102 'escapeEverything': false, 103 'isIdentifier': false, 104 'quotes': 'single', 105 'wrap': false 106}; 107 108cssesc.version = '3.0.0'; 109 110module.exports = cssesc; 111