Repository: mathiasbynens/cssesc Branch: master Commit: cb894eb42f27 Files: 20 Total size: 93.6 KB Directory structure: gitextract_vao26tjg/ ├── .babelrc ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .travis.yml ├── Gruntfile.js ├── LICENSE-MIT.txt ├── README.md ├── bin/ │ └── cssesc ├── coverage/ │ ├── cssesc/ │ │ ├── cssesc.js.html │ │ └── index.html │ ├── index.html │ ├── prettify.css │ └── prettify.js ├── cssesc.js ├── man/ │ └── cssesc.1 ├── package.json ├── src/ │ ├── cssesc.js │ └── data.js └── tests/ └── tests.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .babelrc ================================================ { "presets": [ ["env", { "targets": { "node": "4.0", "browsers": ["last 2 versions", "safari >= 7", "ie >= 11"] } }] ] } ================================================ FILE: .editorconfig ================================================ root = true [*] charset = utf-8 indent_style = tab end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true [{README.md,package.json,.travis.yml,.babelrc}] indent_style = space indent_size = 2 ================================================ FILE: .gitattributes ================================================ # Automatically normalize line endings for all text-based files * text=auto ================================================ FILE: .gitignore ================================================ # JSON version of coverage report coverage/coverage.json # Installed npm modules node_modules # Folder view configuration files .DS_Store Desktop.ini # Thumbnail cache files ._* Thumbs.db # Files that might appear on external disks .Spotlight-V100 .Trashes ================================================ FILE: .travis.yml ================================================ sudo: false language: node_js node_js: - "4" - "5" - "6" after_script: - 'istanbul cover --report html node_modules/.bin/_mocha tests -- -u exports -R spec && codecov' git: depth: 1 ================================================ FILE: Gruntfile.js ================================================ module.exports = function(grunt) { grunt.initConfig({ 'template': { 'build': { 'options': { // Generate the regular expressions dynamically using Regenerate. 'data': require('./src/data.js') }, 'files': { 'cssesc.js': ['src/cssesc.js'] } } } }); grunt.loadNpmTasks('grunt-template'); grunt.registerTask('default', [ 'template' ]); }; ================================================ FILE: LICENSE-MIT.txt ================================================ Copyright Mathias Bynens 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. ================================================ FILE: README.md ================================================ # cssesc [![Build status](https://travis-ci.org/mathiasbynens/cssesc.svg?branch=master)](https://travis-ci.org/mathiasbynens/cssesc) [![Code coverage status](https://img.shields.io/codecov/c/github/mathiasbynens/cssesc.svg)](https://codecov.io/gh/mathiasbynens/cssesc) A JavaScript library for escaping CSS strings and identifiers while generating the shortest possible ASCII-only output. This is a JavaScript library for [escaping text for use in CSS strings or identifiers](https://mathiasbynens.be/notes/css-escapes) while generating the shortest possible valid ASCII-only output. [Here’s an online demo.](https://mothereff.in/css-escapes) [A polyfill for the CSSOM `CSS.escape()` method is available in a separate repository.](https://mths.be/cssescape) (In comparison, _cssesc_ is much more powerful.) Feel free to fork if you see possible improvements! ## Installation Via [npm](https://www.npmjs.com/): ```bash npm install cssesc ``` In a browser: ```html ``` In [Node.js](https://nodejs.org/): ```js const cssesc = require('cssesc'); ``` In Ruby using [the `ruby-cssesc` wrapper gem](https://github.com/borodean/ruby-cssesc): ```bash gem install ruby-cssesc ``` ```ruby require 'ruby-cssesc' CSSEsc.escape('I ♥ Ruby', is_identifier: true) ``` In Sass using [`sassy-escape`](https://github.com/borodean/sassy-escape): ```bash gem install sassy-escape ``` ```scss body { content: escape('I ♥ Sass', $is-identifier: true); } ``` ## API ### `cssesc(value, options)` This function takes a value and returns an escaped version of the value where any characters that are not printable ASCII symbols are escaped using the shortest possible (but valid) [escape sequences for use in CSS strings or identifiers](https://mathiasbynens.be/notes/css-escapes). ```js cssesc('Ich ♥ Bücher'); // → 'Ich \\2665 B\\FC cher' cssesc('foo 𝌆 bar'); // → 'foo \\1D306 bar' ``` By default, `cssesc` returns a string that can be used as part of a CSS string. If the target is a CSS identifier rather than a CSS string, use the `isIdentifier: true` setting (see below). The optional `options` argument accepts an object with the following options: #### `isIdentifier` The default value for the `isIdentifier` option is `false`. This means that the input text will be escaped for use in a CSS string literal. If you want to use the result as a CSS identifier instead (in a selector, for example), set this option to `true`. ```js cssesc('123a2b'); // → '123a2b' cssesc('123a2b', { 'isIdentifier': true }); // → '\\31 23a2b' ``` #### `quotes` The default value for the `quotes` option is `'single'`. This means that any occurences of `'` in the input text will be escaped as `\'`, so that the output can be used in a CSS string literal wrapped in single quotes. ```js cssesc('Lorem ipsum "dolor" sit \'amet\' etc.'); // → 'Lorem ipsum "dolor" sit \\\'amet\\\' etc.' // → "Lorem ipsum \"dolor\" sit \\'amet\\' etc." cssesc('Lorem ipsum "dolor" sit \'amet\' etc.', { 'quotes': 'single' }); // → 'Lorem ipsum "dolor" sit \\\'amet\\\' etc.' // → "Lorem ipsum \"dolor\" sit \\'amet\\' etc." ``` If you want to use the output as part of a CSS string literal wrapped in double quotes, set the `quotes` option to `'double'`. ```js cssesc('Lorem ipsum "dolor" sit \'amet\' etc.', { 'quotes': 'double' }); // → 'Lorem ipsum \\"dolor\\" sit \'amet\' etc.' // → "Lorem ipsum \\\"dolor\\\" sit 'amet' etc." ``` #### `wrap` The `wrap` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, the output will be a valid CSS string literal wrapped in quotes. The type of quotes can be specified through the `quotes` setting. ```js cssesc('Lorem ipsum "dolor" sit \'amet\' etc.', { 'quotes': 'single', 'wrap': true }); // → '\'Lorem ipsum "dolor" sit \\\'amet\\\' etc.\'' // → "\'Lorem ipsum \"dolor\" sit \\\'amet\\\' etc.\'" cssesc('Lorem ipsum "dolor" sit \'amet\' etc.', { 'quotes': 'double', 'wrap': true }); // → '"Lorem ipsum \\"dolor\\" sit \'amet\' etc."' // → "\"Lorem ipsum \\\"dolor\\\" sit \'amet\' etc.\"" ``` #### `escapeEverything` The `escapeEverything` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, all the symbols in the output will be escaped, even printable ASCII symbols. ```js cssesc('lolwat"foo\'bar', { 'escapeEverything': true }); // → '\\6C\\6F\\6C\\77\\61\\74\\"\\66\\6F\\6F\\\'\\62\\61\\72' // → "\\6C\\6F\\6C\\77\\61\\74\\\"\\66\\6F\\6F\\'\\62\\61\\72" ``` #### Overriding the default options globally The global default settings can be overridden by modifying the `css.options` object. This saves you from passing in an `options` object for every call to `encode` if you want to use the non-default setting. ```js // Read the global default setting for `escapeEverything`: cssesc.options.escapeEverything; // → `false` by default // Override the global default setting for `escapeEverything`: cssesc.options.escapeEverything = true; // Using the global default setting for `escapeEverything`, which is now `true`: cssesc('foo © bar ≠ baz 𝌆 qux'); // → '\\66\\6F\\6F\\ \\A9\\ \\62\\61\\72\\ \\2260\\ \\62\\61\\7A\\ \\1D306\\ \\71\\75\\78' ``` ### `cssesc.version` A string representing the semantic version number. ### Using the `cssesc` binary To use the `cssesc` binary in your shell, simply install cssesc globally using npm: ```bash npm install -g cssesc ``` After that you will be able to escape text for use in CSS strings or identifiers from the command line: ```bash $ cssesc 'föo ♥ bår 𝌆 baz' f\F6o \2665 b\E5r \1D306 baz ``` If the output needs to be a CSS identifier rather than part of a string literal, use the `-i`/`--identifier` option: ```bash $ cssesc --identifier 'föo ♥ bår 𝌆 baz' f\F6o\ \2665\ b\E5r\ \1D306\ baz ``` See `cssesc --help` for the full list of options. ## Support This library supports the Node.js and browser versions mentioned in [`.babelrc`](https://github.com/mathiasbynens/cssesc/blob/master/.babelrc). For a version that supports a wider variety of legacy browsers and environments out-of-the-box, [see v0.1.0](https://github.com/mathiasbynens/cssesc/releases/tag/v0.1.0). ## Author | [![twitter/mathias](https://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | |---| | [Mathias Bynens](https://mathiasbynens.be/) | ## License This library is available under the [MIT](https://mths.be/mit) license. ================================================ FILE: bin/cssesc ================================================ #!/usr/bin/env node const fs = require('fs'); const cssesc = require('../cssesc.js'); const strings = process.argv.splice(2); const stdin = process.stdin; const options = {}; const log = console.log; const main = function() { const option = strings[0]; if (/^(?:-h|--help|undefined)$/.test(option)) { log( 'cssesc v%s - https://mths.be/cssesc', cssesc.version ); log([ '\nUsage:\n', '\tcssesc [string]', '\tcssesc [-i | --identifier] [string]', '\tcssesc [-s | --single-quotes] [string]', '\tcssesc [-d | --double-quotes] [string]', '\tcssesc [-w | --wrap] [string]', '\tcssesc [-e | --escape-everything] [string]', '\tcssesc [-v | --version]', '\tcssesc [-h | --help]', '\nExamples:\n', '\tcssesc \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'', '\tcssesc --identifier \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'', '\tcssesc --escape-everything \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'', '\tcssesc --double-quotes --wrap \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'', '\techo \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\' | cssesc' ].join('\n')); return process.exit(1); } if (/^(?:-v|--version)$/.test(option)) { log('v%s', cssesc.version); return process.exit(1); } strings.forEach(function(string) { // Process options if (/^(?:-i|--identifier)$/.test(string)) { options.isIdentifier = true; return; } if (/^(?:-s|--single-quotes)$/.test(string)) { options.quotes = 'single'; return; } if (/^(?:-d|--double-quotes)$/.test(string)) { options.quotes = 'double'; return; } if (/^(?:-w|--wrap)$/.test(string)) { options.wrap = true; return; } if (/^(?:-e|--escape-everything)$/.test(string)) { options.escapeEverything = true; return; } // Process string(s) let result; try { result = cssesc(string, options); log(result); } catch (exception) { log(exception.message + '\n'); log('Error: failed to escape.'); log('If you think this is a bug in cssesc, please report it:'); log('https://github.com/mathiasbynens/cssesc/issues/new'); log( '\nStack trace using cssesc@%s:\n', cssesc.version ); log(exception.stack); return process.exit(1); } }); // Return with exit status 0 outside of the `forEach` loop, in case // multiple strings were passed in. return process.exit(0); }; if (stdin.isTTY) { // handle shell arguments main(); } else { let timeout; // Either the script is called from within a non-TTY context, or `stdin` // content is being piped in. if (!process.stdout.isTTY) { // The script was called from a non-TTY context. This is a rather uncommon // use case we don’t actively support. However, we don’t want the script // to wait forever in such cases, so… timeout = setTimeout(function() { // …if no piped data arrived after a whole minute, handle shell // arguments instead. main(); }, 60000); } let data = ''; stdin.on('data', function(chunk) { clearTimeout(timeout); data += chunk; }); stdin.on('end', function() { strings.push(data.trim()); main(); }); stdin.resume(); } ================================================ FILE: coverage/cssesc/cssesc.js.html ================================================ Code coverage report for cssesc/cssesc.js

Code coverage report for cssesc/cssesc.js

Statements: 95% (76 / 80)      Branches: 91.46% (75 / 82)      Functions: 80% (4 / 5)      Lines: 95% (76 / 80)     

All files » cssesc/ » cssesc.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178  1     1     1         1 1 1         1 1 1 31 10   21 21 21     105       21         1 1 1 1     1     31 31 1   31 31   31 31 31 31 31 31 31 31   31 193 193   193 15   2 2 1       1     15   178 15 2   13     163 2 1   1   161                     11   150     193     31 8     1 7 3 4 2             31 22   3     19     31 4   27       1             1           1               1 1 1                  
/*! https://mths.be/cssesc v0.1.0 by @mathias */
;(function(root) {
 
	// Detect free variables `exports`
	var freeExports = typeof exports == 'object' && exports;
 
	// Detect free variable `module`
	var freeModule = typeof module == 'object' && module &&
		module.exports == freeExports && module;
 
	// Detect free variable `global`, from Node.js or Browserified code,
	// and use it as `root`
	var freeGlobal = typeof global == 'object' && global;
	Eif (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
		root = freeGlobal;
	}
 
	/*--------------------------------------------------------------------------*/
 
	var object = {};
	var hasOwnProperty = object.hasOwnProperty;
	var merge = function(options, defaults) {
		if (!options) {
			return defaults;
		}
		var key;
		var result = {};
		for (key in defaults) {
			// `if (defaults.hasOwnProperty(key) { … }` is not needed here, since
			// only recognized option names are used
			result[key] = hasOwnProperty.call(options, key)
				? options[key]
				: defaults[key];
		}
		return result;
	};
 
	/*--------------------------------------------------------------------------*/
 
	var regexAnySingleEscape = /[\x20-\x2C\x2E\x2F\x3B-\x40\x5B-\x5E\x60\x7B-\x7E]/;
	var regexSingleEscape = /[\x20\x21\x23-\x26\x28-\x2C\x2E\x2F\x3B-\x40\x5B\x5D\x5E\x60\x7B-\x7E]/;
	var regexAlwaysEscape = /['"\\]/;
	var regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g;
 
	// https://mathiasbynens.be/notes/css-escapes#css
	var cssesc = function(string, options) {
 
		// Handle options
		options = merge(options, cssesc.options);
		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;
		var value;
		var character;
		var codePoint;
		var extra; // used for potential low surrogates
 
		while (counter < length) {
			character = string.charAt(counter++);
			codePoint = character.charCodeAt();
			// if it’s not a printable ASCII character
			if (codePoint < 0x20 || codePoint > 0x7E) {
				if (codePoint >= 0xD800 && codePoint <= 0xDBFF && counter < length) {
					// high surrogate, and there is a next character
					extra = string.charCodeAt(counter++);
					if ((extra & 0xFC00) == 0xDC00) { // next character is low surrogate
						codePoint = ((codePoint & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000;
					} else {
						// 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() + ' ';
					}
				// `:` can be escaped as `\:`, but that fails in IE < 8
				} else if (/[\t\n\f\r\x0B:]/.test(character)) {
					if (!isIdentifier && 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 (/^_/.test(output)) {
				// Prevent IE6 from ignoring the rule altogether (in case this is for an
				// identifier used as a selector)
				output = '\\_' + output.slice(1);
			} else if (/^-[-\d]/.test(output)) {
				output = '\\-' + output.slice(1);
			} else if (/\d/.test(firstChar)) {
				output = '\\3' + firstChar + ' ' + output.slice(1);
			}
		}
 
		// Remove spaces after `\HEX` escapes that are not followed by a hex digit,
		// since they’re redundant. Note that this is only possible if the escape
		// sequence isn’t preceded by an odd number of backslashes.
		output = output.replace(regexExcessiveSpaces, function($0, $1, $2) {
			if ($1 && $1.length % 2) {
				// it’s not safe to remove the space, so don’t
				return $0;
			}
			// strip the space
			return ($1 || '') + $2;
		});
 
		if (!isIdentifier && options.wrap) {
			return quote + output + quote;
		}
		return output;
	};
 
	// Expose default options (so they can be overridden globally)
	cssesc.options = {
		'escapeEverything': false,
		'isIdentifier': false,
		'quotes': 'single',
		'wrap': false
	};
 
	cssesc.version = '0.1.0';
 
	/*--------------------------------------------------------------------------*/
 
	// Some AMD build optimizers, like r.js, check for specific condition patterns
	// like the following:
	Iif (
		typeof define == 'function' &&
		typeof define.amd == 'object' &&
		define.amd
	) {
		define(function() {
			return cssesc;
		});
	}	else Eif (freeExports && !freeExports.nodeType) {
		Eif (freeModule) { // in Node.js or RingoJS v0.8.0+
			freeModule.exports = cssesc;
		} else { // in Narwhal or RingoJS v0.7.0-
			freeExports.cssesc = cssesc;
		}
	} else { // in Rhino or a web browser
		root.cssesc = cssesc;
	}
 
}(this));
 
================================================ FILE: coverage/cssesc/index.html ================================================ Code coverage report for cssesc/

Code coverage report for cssesc/

Statements: 95% (76 / 80)      Branches: 91.46% (75 / 82)      Functions: 80% (4 / 5)      Lines: 95% (76 / 80)     

All files » cssesc/
File Statements Branches Functions Lines
cssesc.js 95% (76 / 80) 91.46% (75 / 82) 80% (4 / 5) 95% (76 / 80)
================================================ FILE: coverage/index.html ================================================ Code coverage report for All files

Code coverage report for All files

Statements: 95% (76 / 80)      Branches: 91.46% (75 / 82)      Functions: 80% (4 / 5)      Lines: 95% (76 / 80)     

File Statements Branches Functions Lines
cssesc/ 95% (76 / 80) 91.46% (75 / 82) 80% (4 / 5) 95% (76 / 80)
================================================ FILE: coverage/prettify.css ================================================ .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} ================================================ FILE: coverage/prettify.js ================================================ window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); ================================================ FILE: cssesc.js ================================================ /*! https://mths.be/cssesc v3.0.0 by @mathias */ 'use strict'; var object = {}; var hasOwnProperty = object.hasOwnProperty; var merge = function merge(options, defaults) { if (!options) { return defaults; } var result = {}; for (var key in defaults) { // `if (defaults.hasOwnProperty(key) { … }` is not needed here, since // only recognized option names are used. result[key] = hasOwnProperty.call(options, key) ? options[key] : defaults[key]; } return result; }; var regexAnySingleEscape = /[ -,\.\/:-@\[-\^`\{-~]/; var regexSingleEscape = /[ -,\.\/:-@\[\]\^`\{-~]/; var regexAlwaysEscape = /['"\\]/; var regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g; // https://mathiasbynens.be/notes/css-escapes#css var cssesc = function cssesc(string, options) { options = merge(options, cssesc.options); 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(); 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 (/[\t\n\f\r\x0B]/.test(character)) { 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); } } // Remove spaces after `\HEX` escapes that are not followed by a hex digit, // since they’re redundant. Note that this is only possible if the escape // sequence isn’t preceded by an odd number of backslashes. output = output.replace(regexExcessiveSpaces, function ($0, $1, $2) { if ($1 && $1.length % 2) { // It’s not safe to remove the space, so don’t. return $0; } // Strip the space. return ($1 || '') + $2; }); if (!isIdentifier && options.wrap) { return quote + output + quote; } return output; }; // Expose default options (so they can be overridden globally). cssesc.options = { 'escapeEverything': false, 'isIdentifier': false, 'quotes': 'single', 'wrap': false }; cssesc.version = '3.0.0'; module.exports = cssesc; ================================================ FILE: man/cssesc.1 ================================================ .Dd August 9, 2013 .Dt cssesc 1 .Sh NAME .Nm cssesc .Nd escape text for use in CSS string literals or identifiers .Sh SYNOPSIS .Nm .Op Fl i | -identifier Ar string .br .Op Fl s | -single-quotes Ar string .br .Op Fl d | -double-quotes Ar string .br .Op Fl w | -wrap Ar string .br .Op Fl e | -escape-everything Ar string .br .Op Fl v | -version .br .Op Fl h | -help .Sh DESCRIPTION .Nm escapes strings for use in CSS string literals or identifiers while generating the shortest possible valid ASCII-only output. .Sh OPTIONS .Bl -ohang -offset .It Sy "-s, --single-quotes" Escape any occurences of ' in the input string as \\', so that the output can be used in a CSS string literal wrapped in single quotes. .It Sy "-d, --double-quotes" Escape any occurences of " in the input string as \\", so that the output can be used in a CSS string literal wrapped in double quotes. .It Sy "-w, --wrap" Make sure the output is a valid CSS string literal wrapped in quotes. The type of quotes can be specified using the .Ar -s | --single-quotes or .Ar -d | --double-quotes settings. .It Sy "-e, --escape-everything" Escape all the symbols in the output, even printable ASCII symbols. .It Sy "-v, --version" Print cssesc's version. .It Sy "-h, --help" Show the help screen. .El .Sh EXIT STATUS The .Nm cssesc utility exits with one of the following values: .Pp .Bl -tag -width flag -compact .It Li 0 .Nm successfully escaped the given text and printed the result. .It Li 1 .Nm wasn't instructed to escape anything (for example, the .Ar --help flag was set); or, an error occurred. .El .Sh EXAMPLES .Bl -ohang -offset .It Sy "cssesc 'foo bar baz'" Print an escaped version of the given text. .It Sy echo\ 'foo bar baz'\ |\ cssesc Print an escaped version of the text that gets piped in. .El .Sh BUGS cssesc's bug tracker is located at . .Sh AUTHOR Mathias Bynens .Sh WWW ================================================ FILE: package.json ================================================ { "name": "cssesc", "version": "3.0.0", "description": "A JavaScript library for escaping CSS strings and identifiers while generating the shortest possible ASCII-only output.", "homepage": "https://mths.be/cssesc", "engines": { "node": ">=4" }, "main": "cssesc.js", "bin": "bin/cssesc", "man": "man/cssesc.1", "keywords": [ "css", "escape", "identifier", "string", "tool" ], "license": "MIT", "author": { "name": "Mathias Bynens", "url": "https://mathiasbynens.be/" }, "repository": { "type": "git", "url": "https://github.com/mathiasbynens/cssesc.git" }, "bugs": "https://github.com/mathiasbynens/cssesc/issues", "files": [ "LICENSE-MIT.txt", "cssesc.js", "bin/", "man/" ], "scripts": { "build": "grunt template && babel cssesc.js -o cssesc.js", "test": "mocha tests", "cover": "istanbul cover --report html node_modules/.bin/_mocha tests -- -u exports -R spec" }, "devDependencies": { "babel-cli": "^6.26.0", "babel-preset-env": "^1.6.1", "codecov": "^1.0.1", "grunt": "^1.0.1", "grunt-template": "^1.0.0", "istanbul": "^0.4.4", "mocha": "^2.5.3", "regenerate": "^1.2.1", "requirejs": "^2.1.16" } } ================================================ FILE: src/cssesc.js ================================================ /*! https://mths.be/cssesc v<%= version %> by @mathias */ 'use strict'; const object = {}; const hasOwnProperty = object.hasOwnProperty; const merge = (options, defaults) => { if (!options) { return defaults; } const result = {}; for (let key in defaults) { // `if (defaults.hasOwnProperty(key) { … }` is not needed here, since // only recognized option names are used. result[key] = hasOwnProperty.call(options, key) ? options[key] : defaults[key]; } return result; }; const regexAnySingleEscape = /<%= anySingleEscape %>/; const regexSingleEscape = /<%= singleEscapes %>/; const regexAlwaysEscape = /['"\\]/; const regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g; // https://mathiasbynens.be/notes/css-escapes#css const cssesc = (string, options) => { options = merge(options, cssesc.options); if (options.quotes != 'single' && options.quotes != 'double') { options.quotes = 'single'; } const quote = options.quotes == 'double' ? '"' : '\''; const isIdentifier = options.isIdentifier; const firstChar = string.charAt(0); let output = ''; let counter = 0; const length = string.length; while (counter < length) { const character = string.charAt(counter++); let codePoint = character.charCodeAt(); let value; // 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. const 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 (/[\t\n\f\r\x0B]/.test(character)) { 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); } } // Remove spaces after `\HEX` escapes that are not followed by a hex digit, // since they’re redundant. Note that this is only possible if the escape // sequence isn’t preceded by an odd number of backslashes. output = output.replace(regexExcessiveSpaces, function($0, $1, $2) { if ($1 && $1.length % 2) { // It’s not safe to remove the space, so don’t. return $0; } // Strip the space. return ($1 || '') + $2; }); if (!isIdentifier && options.wrap) { return quote + output + quote; } return output; }; // Expose default options (so they can be overridden globally). cssesc.options = { 'escapeEverything': false, 'isIdentifier': false, 'quotes': 'single', 'wrap': false }; cssesc.version = '<%= version %>'; module.exports = cssesc; ================================================ FILE: src/data.js ================================================ var regenerate = require('regenerate'); var fs = require('fs'); // Characters with special meaning in CSS, except for quotes and backslashes // (they get a separate regex) var set = regenerate().add( ' ', '!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '.', '/', ';', '<', ':', '=', '>', '?', '@', '[', ']', '^', '`', '{', '|', '}', '~', '"', '\'', '\\' ); module.exports = { 'anySingleEscape': set.toString(), 'singleEscapes': set.remove('\\').toString(), 'version': JSON.parse(fs.readFileSync('package.json', 'utf8')).version }; ================================================ FILE: tests/tests.js ================================================ 'use strict'; const assert = require('assert'); const cssesc = require('../cssesc.js'); describe('common usage', () => { it('works as expected', () => { assert.equal( typeof cssesc.version, 'string', '`cssesc.version` must be a string' ); assert.equal( cssesc('-foo'), '-foo', '-foo' ); assert.equal( cssesc('--foo', { 'isIdentifier': false }), '--foo', '--foo with `isIdentifier: false`' ); assert.equal( cssesc('--foo', { 'isIdentifier': true }), '\\--foo', '--foo with `isIdentifier: true`' ); assert.equal( cssesc('-0foo', { 'isIdentifier': false }), '-0foo', '-0foo with `isIdentifier: false`' ); assert.equal( cssesc('-0foo', { 'isIdentifier': true }), '\\-0foo', '-0foo with `isIdentifier: true`' ); assert.equal( cssesc('-9foo', { 'isIdentifier': false }), '-9foo', '-9foo with `isIdentifier: false`' ); assert.equal( cssesc('-9foo', { 'isIdentifier': true }), '\\-9foo', '-9foo with `isIdentifier: true`' ); assert.equal( cssesc('foo:bar', { 'isIdentifier': false }), 'foo:bar', 'foo:bar with `isIdentifier: false`' ); assert.equal( cssesc('foo:bar', { 'isIdentifier': true }), 'foo\\:bar', 'foo:bar with `isIdentifier: true`' ); assert.equal( cssesc('_foo_bar', { 'isIdentifier': false }), '_foo_bar', '_foo_bar with `isIdentifier: false`' ); assert.equal( cssesc('_foo_bar', { 'isIdentifier': true }), '_foo_bar', '_foo_bar with `isIdentifier: true`' ); assert.equal( cssesc('a\t\n\v\f\rb'), 'a\\9\\A\\B\\C\\D b', 'whitespace characters' ); assert.equal( cssesc('\\A _'), '\\\\A _', 'backslash escapes that look like a hex escape: space is preserved' ); assert.equal( cssesc('\\\\A _'), '\\\\\\\\A _', 'backslash escapes that look like a hex escape: space is preserved' ); assert.equal( cssesc('a\\b'), 'a\\\\b', 'backslash' ); assert.equal( cssesc('-\\ABC -', { 'isIdentifier': false }), '-\\\\ABC -', 'more backslashes with `isIdentifier: false`' ); assert.equal( cssesc('-\\ABC -', { 'isIdentifier': true }), '-\\\\ABC\\ -', 'more backslashes with `isIdentifier: true`' ); assert.equal( cssesc('id"ent\'ifier', { 'isIdentifier': true }), 'id\\"ent\\\'ifier', 'quotes are escaped with `isIdentifier: true`' ); assert.equal( cssesc('a"b\'c\xA9d', { 'wrap': true }), '\'a"b\\\'c\\A9 d\'', 'quotes with `wrap: true`' ); assert.equal( cssesc('a"b\'c\xA9d', { 'wrap': true, 'quotes': 'LOLWAT' }), '\'a"b\\\'c\\A9 d\'', 'quotes with `wrap: true, quotes: \'LOLWAT\'` (incorrect value)' ); assert.equal( cssesc('a"b\'c\xA9d', { 'wrap': true, 'quotes': 'single' }), '\'a"b\\\'c\\A9 d\'', 'quotes with `wrap: true, quotes: \'single\'`' ); assert.equal( cssesc('a"b\'c\xA9d', { 'wrap': true, 'quotes': 'double' }), '"a\\"b\'c\\A9 d"', 'quotes with `wrap: true, quotes: \'double\'`' ); assert.equal( cssesc('a\xA9b'), 'a\\A9 b', 'non-ASCII symbol' ); assert.equal( cssesc('Ich \u2665 B\xFCcher'), 'Ich \\2665 B\\FC cher', 'non-ASCII symbols' ); assert.equal( cssesc('a123b'), 'a123b', 'numbers not at the start of the string' ); assert.equal( cssesc('123a2b', { 'isIdentifier': false }), '123a2b', 'numbers at the start of the string with `isIdentifier: false`' ); assert.equal( cssesc('123a2b', { 'isIdentifier': true }), '\\31 23a2b', 'numbers at the start of the string with `isIdentifier: true`' ); assert.equal( cssesc('1_23a2b', { 'isIdentifier': false }), '1_23a2b', 'numbers at the start of the string with `isIdentifier: false`' ); assert.equal( cssesc('1_23a2b', { 'isIdentifier': true }), '\\31_23a2b', 'numbers at the start of the string with `isIdentifier: true`' ); assert.equal( cssesc('foo\\bar', { 'isIdentifier': false }), 'foo\\\\bar', 'backslashes are escaped with `isIdentifier: false`' ); assert.equal( cssesc('foo\\bar', { 'isIdentifier': true }), 'foo\\\\bar', 'backslashes are escaped with `isIdentifier: true`' ); assert.equal( cssesc('a\uD834\uDF06b'), 'a\\1D306 b', 'astral symbol' ); assert.equal( cssesc('a\uD834b'), 'a\\D834 b', 'lone high surrogate' ); assert.equal( cssesc('lolwat"foo\'bar\xA9k', { 'escapeEverything': true }), '\\6C\\6F\\6C\\77\\61\\74\\"\\66\\6F\\6F\\\'\\62\\61\\72\\A9\\6B', '`escapeEverything: true`' ); }); });