pax_global_header00006660000000000000000000000064123743532140014516gustar00rootroot0000000000000052 comment=8d47e39a463b1a954b8ca6661b7804166a773154 jsesc-0.5.0/000077500000000000000000000000001237435321400126275ustar00rootroot00000000000000jsesc-0.5.0/.gitattributes000066400000000000000000000001141237435321400155160ustar00rootroot00000000000000# Automatically normalize line endings for all text-based files * text=auto jsesc-0.5.0/.gitignore000066400000000000000000000003471237435321400146230ustar00rootroot00000000000000# Coverage report coverage # 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 jsesc-0.5.0/.travis.yml000066400000000000000000000025621237435321400147450ustar00rootroot00000000000000language: node_js node_js: - "0.10" before_script: - "npm install -g grunt-cli" # Narwhal uses a hardcoded path to openjdk v6, so use that version - "sudo apt-get update -qq" - "sudo apt-get install -qq openjdk-6-jre" - "PACKAGE=rhino1_7R3; wget http://ftp.mozilla.org/pub/mozilla.org/js/$PACKAGE.zip && sudo unzip $PACKAGE -d /opt/ && rm $PACKAGE.zip" - "PACKAGE=rhino1_7R3; echo -e '#!/bin/sh\\njava -jar /opt/'$PACKAGE'/js.jar $@' | sudo tee /usr/local/bin/rhino && sudo chmod +x /usr/local/bin/rhino" - "PACKAGE=ringojs-0.9; wget http://ringojs.org/downloads/$PACKAGE.zip && sudo unzip $PACKAGE -d /opt/ && rm $PACKAGE.zip" - "PACKAGE=ringojs-0.9; sudo ln -s /opt/$PACKAGE/bin/ringo /usr/local/bin/ringo && sudo chmod +x /usr/local/bin/ringo" - "PACKAGE=v0.3.2; wget https://github.com/280north/narwhal/archive/$PACKAGE.zip && sudo unzip $PACKAGE -d /opt/ && rm $PACKAGE.zip" - "PACKAGE=narwhal-0.3.2; sudo ln -s /opt/$PACKAGE/bin/narwhal /usr/local/bin/narwhal && sudo chmod +x /usr/local/bin/narwhal" # If the enviroment stores rt.jar in a different directory, find it and symlink the directory - "PREFIX=/usr/lib/jvm; if [ ! -d $PREFIX/java-6-openjdk ]; then for d in $PREFIX/java-6-openjdk-*; do if [ -e $d/jre/lib/rt.jar ]; then sudo ln -s $d $PREFIX/java-6-openjdk; break; fi; done; fi" script: - "grunt ci" after_script: - "grunt shell:cover-coveralls" jsesc-0.5.0/Gruntfile.js000066400000000000000000000036711237435321400151330ustar00rootroot00000000000000module.exports = function(grunt) { grunt.initConfig({ 'shell': { 'options': { 'stdout': true, 'stderr': true, 'failOnError': true }, 'cover-html': { 'command': 'istanbul cover --report "html" --verbose --dir "coverage" "tests/tests.js"' }, 'cover-coveralls': { 'command': 'istanbul cover --verbose --dir "coverage" "tests/tests.js" && cat coverage/lcov.info | coveralls; rm -rf coverage/lcov*' }, 'test-narwhal': { 'command': 'echo "Testing in Narwhal..."; export NARWHAL_OPTIMIZATION=-1; narwhal "tests/tests.js"' }, 'test-phantomjs': { 'command': 'echo "Testing in PhantomJS..."; phantomjs "tests/tests.js"' }, // Rhino 1.7R4 has a bug that makes it impossible to test in. // https://bugzilla.mozilla.org/show_bug.cgi?id=775566 // To test, use Rhino 1.7R3, or wait (heh) for the 1.7R5 release. 'test-rhino': { 'command': 'echo "Testing in Rhino..."; rhino -opt -1 "tests.js"', 'options': { 'execOptions': { 'cwd': 'tests' } } }, 'test-ringo': { 'command': 'echo "Testing in Ringo..."; ringo -o -1 "tests/tests.js"' }, 'test-node': { 'command': 'echo "Testing in Node..."; node "tests/tests.js"' }, 'test-browser': { 'command': 'echo "Testing in a browser..."; open "tests/index.html"' } }, 'template': { 'build': { 'options': { // Generate the regular expressions dynamically using Regenerate 'data': require('./src/data.js') }, 'files': { 'jsesc.js': ['src/jsesc.js'] } } } }); grunt.loadNpmTasks('grunt-shell'); grunt.loadNpmTasks('grunt-template'); grunt.registerTask('cover', 'shell:cover-html'); grunt.registerTask('ci', [ 'shell:test-narwhal', 'shell:test-phantomjs', 'shell:test-rhino', 'shell:test-ringo', 'shell:test-node' ]); grunt.registerTask('test', [ 'ci', 'shell:test-browser' ]); grunt.registerTask('default', [ 'template', 'shell:test-node' ]); }; jsesc-0.5.0/LICENSE-MIT.txt000066400000000000000000000020641237435321400151030ustar00rootroot00000000000000Copyright 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. jsesc-0.5.0/README.md000066400000000000000000000302371237435321400141130ustar00rootroot00000000000000# jsesc [![Build status](https://travis-ci.org/mathiasbynens/jsesc.svg?branch=master)](https://travis-ci.org/mathiasbynens/jsesc) [![Code coverage status](http://img.shields.io/coveralls/mathiasbynens/jsesc/master.svg)](https://coveralls.io/r/mathiasbynens/jsesc) [![Dependency status](https://gemnasium.com/mathiasbynens/jsesc.svg)](https://gemnasium.com/mathiasbynens/jsesc) This is a JavaScript library for [escaping JavaScript strings](http://mathiasbynens.be/notes/javascript-escapes) while generating the shortest possible valid ASCII-only output. [Here’s an online demo.](http://mothereff.in/js-escapes) This can be used to avoid [mojibake](http://en.wikipedia.org/wiki/Mojibake) and other encoding issues, or even to [avoid errors](https://twitter.com/annevk/status/380000829643571200) when passing JSON-formatted data (which may contain U+2028 LINE SEPARATOR, U+2029 PARAGRAPH SEPARATOR, or [lone surrogates](http://esdiscuss.org/topic/code-points-vs-unicode-scalar-values#content-14)) to a JavaScript parser or an UTF-8 encoder, respectively. Feel free to fork if you see possible improvements! ## Installation Via [Bower](http://bower.io/): ```bash bower install jsesc ``` Via [Component](https://github.com/component/component): ```bash component install mathiasbynens/jsesc ``` Via [npm](http://npmjs.org/): ```bash npm install jsesc ``` In a browser: ```html ``` In [Node.js](http://nodejs.org/) and [RingoJS](http://ringojs.org/): ```js var jsesc = require('jsesc'); ``` In [Narwhal](http://narwhaljs.org/): ```js var jsesc = require('jsesc').jsesc; ``` In [Rhino](http://www.mozilla.org/rhino/): ```js load('jsesc.js'); ``` Using an AMD loader like [RequireJS](http://requirejs.org/): ```js require( { 'paths': { 'jsesc': 'path/to/jsesc' } }, ['jsesc'], function(jsesc) { console.log(jsesc); } ); ``` ## API ### `jsesc(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 JavaScript strings](http://mathiasbynens.be/notes/javascript-escapes). The first supported value type is strings: ```js jsesc('Ich ♥ Bücher'); // → 'Ich \\u2665 B\\xFCcher' jsesc('foo 𝌆 bar'); // → 'foo \\uD834\\uDF06 bar' ``` Instead of a string, the `value` can also be an array, or an object. In such cases, `jsesc` will return a stringified version of the value where any characters that are not printable ASCII symbols are escaped in the same way. ```js // Escaping an array jsesc([ 'Ich ♥ Bücher', 'foo 𝌆 bar' ]); // → '[\'Ich \\u2665 B\\xFCcher\',\'foo \\uD834\\uDF06 bar\']' // Escaping an object jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }); // → '{\'Ich \\u2665 B\\xFCcher\':\'foo \\uD834\\uDF06 bar\'}' ``` The optional `options` argument accepts an object with the following options: #### `quotes` The default value for the `quotes` option is `'single'`. This means that any occurences of `'` in the input string will be escaped as `\'`, so that the output can be used in a string literal wrapped in single quotes. ```js jsesc('Lorem ipsum "dolor" sit \'amet\' etc.'); // → 'Lorem ipsum "dolor" sit \\\'amet\\\' etc.' jsesc('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 string literal wrapped in double quotes, set the `quotes` option to `'double'`. ```js jsesc('Lorem ipsum "dolor" sit \'amet\' etc.', { 'quotes': 'double' }); // → 'Lorem ipsum \\"dolor\\" sit \'amet\' etc.' // → "Lorem ipsum \\\"dolor\\\" sit 'amet' etc." ``` This setting also affects the output for arrays and objects: ```js jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, { 'quotes': 'double' }); // → '{"Ich \\u2665 B\\xFCcher":"foo \\uD834\\uDF06 bar"}' jsesc([ 'Ich ♥ Bücher', 'foo 𝌆 bar' ], { 'quotes': 'double' }); // → '["Ich \\u2665 B\\xFCcher","foo \\uD834\\uDF06 bar"]' ``` #### `wrap` The `wrap` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, the output will be a valid JavaScript string literal wrapped in quotes. The type of quotes can be specified through the `quotes` setting. ```js jsesc('Lorem ipsum "dolor" sit \'amet\' etc.', { 'quotes': 'single', 'wrap': true }); // → '\'Lorem ipsum "dolor" sit \\\'amet\\\' etc.\'' // → "\'Lorem ipsum \"dolor\" sit \\\'amet\\\' etc.\'" jsesc('Lorem ipsum "dolor" sit \'amet\' etc.', { 'quotes': 'double', 'wrap': true }); // → '"Lorem ipsum \\"dolor\\" sit \'amet\' etc."' // → "\"Lorem ipsum \\\"dolor\\\" sit \'amet\' etc.\"" ``` #### `es6` The `es6` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, any astral Unicode symbols in the input will be escaped using [ECMAScript 6 Unicode code point escape sequences](http://mathiasbynens.be/notes/javascript-escapes#unicode-code-point) instead of using separate escape sequences for each surrogate half. If backwards compatibility with ES5 environments is a concern, don’t enable this setting. If the `json` setting is enabled, the value for the `es6` setting is ignored (as if it was `false`). ```js // By default, the `es6` option is disabled: jsesc('foo 𝌆 bar 💩 baz'); // → 'foo \\uD834\\uDF06 bar \\uD83D\\uDCA9 baz' // To explicitly disable it: jsesc('foo 𝌆 bar 💩 baz', { 'es6': false }); // → 'foo \\uD834\\uDF06 bar \\uD83D\\uDCA9 baz' // To enable it: jsesc('foo 𝌆 bar 💩 baz', { 'es6': true }); // → 'foo \\u{1D306} bar \\u{1F4A9} baz' ``` #### `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 jsesc('lolwat"foo\'bar', { 'escapeEverything': true }); // → '\\x6C\\x6F\\x6C\\x77\\x61\\x74\\"\\x66\\x6F\\x6F\\\'\\x62\\x61\\x72' // → "\\x6C\\x6F\\x6C\\x77\\x61\\x74\\\"\\x66\\x6F\\x6F\\'\\x62\\x61\\x72" ``` This setting also affects the output for arrays and objects: ```js jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, { 'escapeEverything': true }); // → '{\'\x49\x63\x68\x20\u2665\x20\x42\xFC\x63\x68\x65\x72\':\'\x66\x6F\x6F\x20\uD834\uDF06\x20\x62\x61\x72\'}' // → "{'\x49\x63\x68\x20\u2665\x20\x42\xFC\x63\x68\x65\x72':'\x66\x6F\x6F\x20\uD834\uDF06\x20\x62\x61\x72'}" jsesc([ 'Ich ♥ Bücher': 'foo 𝌆 bar' ], { 'escapeEverything': true }); // → '[\'\x49\x63\x68\x20\u2665\x20\x42\xFC\x63\x68\x65\x72\',\'\x66\x6F\x6F\x20\uD834\uDF06\x20\x62\x61\x72\']' ``` #### `compact` The `compact` option takes a boolean value (`true` or `false`), and defaults to `true` (enabled). When enabled, the output for arrays and objects will be as compact as possible; it won’t be formatted nicely. ```js jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, { 'compact': true // this is the default }); // → '{\'Ich \u2665 B\xFCcher\':\'foo \uD834\uDF06 bar\'}' jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, { 'compact': false }); // → '{\n\t\'Ich \u2665 B\xFCcher\': \'foo \uD834\uDF06 bar\'\n}' jsesc([ 'Ich ♥ Bücher', 'foo 𝌆 bar' ], { 'compact': false }); // → '[\n\t\'Ich \u2665 B\xFCcher\',\n\t\'foo \uD834\uDF06 bar\'\n]' ``` This setting has no effect on the output for strings. #### `indent` The `indent` option takes a string value, and defaults to `'\t'`. When the `compact` setting is enabled (`true`), the value of the `indent` option is used to format the output for arrays and objects. ```js jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, { 'compact': false, 'indent': '\t' // this is the default }); // → '{\n\t\'Ich \u2665 B\xFCcher\': \'foo \uD834\uDF06 bar\'\n}' jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, { 'compact': false, 'indent': ' ' }); // → '{\n \'Ich \u2665 B\xFCcher\': \'foo \uD834\uDF06 bar\'\n}' jsesc([ 'Ich ♥ Bücher', 'foo 𝌆 bar' ], { 'compact': false, 'indent': ' ' }); // → '[\n \'Ich \u2665 B\xFCcher\',\n\ t\'foo \uD834\uDF06 bar\'\n]' ``` This setting has no effect on the output for strings. #### `json` The `json` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, the output is valid JSON. [Hexadecimal character escape sequences](http://mathiasbynens.be/notes/javascript-escapes#hexadecimal) and [the `\v` or `\0` escape sequences](http://mathiasbynens.be/notes/javascript-escapes#single) will not be used. Setting `json: true` implies `quotes: 'double', wrap: true, es6: false`, although these values can still be overridden if needed — but in such cases, the output won’t be valid JSON anymore. ```js jsesc('foo\x00bar\xFF\uFFFDbaz', { 'json': true }); // → '"foo\\u0000bar\\u00FF\\uFFFDbaz"' jsesc({ 'foo\x00bar\xFF\uFFFDbaz': 'foo\x00bar\xFF\uFFFDbaz' }, { 'json': true }); // → '{"foo\\u0000bar\\u00FF\\uFFFDbaz":"foo\\u0000bar\\u00FF\\uFFFDbaz"}' jsesc([ 'foo\x00bar\xFF\uFFFDbaz', 'foo\x00bar\xFF\uFFFDbaz' ], { 'json': true }); // → '["foo\\u0000bar\\u00FF\\uFFFDbaz","foo\\u0000bar\\u00FF\\uFFFDbaz"]' // Values that are acceptable in JSON but aren’t strings, arrays, or object // literals can’t be escaped, so they’ll just be preserved: jsesc([ 'foo\x00bar', [1, '©', { 'foo': true, 'qux': null }], 42 ], { 'json': true }); // → '["foo\\u0000bar",[1,"\\u00A9",{"foo":true,"qux":null}],42]' // Values that aren’t allowed in JSON are run through `JSON.stringify()`: jsesc([ undefined, -Infinity ], { 'json': true }); // → '[null,null]' ``` **Note:** Using this option on objects or arrays that contain non-string values relies on `JSON.stringify()`. For legacy environments like IE ≤ 7, use [a `JSON` polyfill](http://bestiejs.github.io/json3/). ### `jsesc.version` A string representing the semantic version number. ### Using the `jsesc` binary To use the `jsesc` binary in your shell, simply install jsesc globally using npm: ```bash npm install -g jsesc ``` After that you will be able to escape strings from the command line: ```bash $ jsesc 'föo ♥ bår 𝌆 baz' f\xF6o \u2665 b\xE5r \uD834\uDF06 baz ``` To escape arrays or objects containing string values, use the `-o`/`--object` option: ```bash $ jsesc --object '{ "föo": "♥", "bår": "𝌆 baz" }' {'f\xF6o':'\u2665','b\xE5r':'\uD834\uDF06 baz'} ``` To prettify the output in such cases, use the `-p`/`--pretty` option: ```bash $ jsesc --pretty '{ "föo": "♥", "bår": "𝌆 baz" }' { 'f\xF6o': '\u2665', 'b\xE5r': '\uD834\uDF06 baz' } ``` For valid JSON output, use the `-j`/`--json` option: ```bash $ jsesc --json --pretty '{ "föo": "♥", "bår": "𝌆 baz" }' { "f\u00F6o": "\u2665", "b\u00E5r": "\uD834\uDF06 baz" } ``` Read a local JSON file, escape any non-ASCII symbols, and save the result to a new file: ```bash $ jsesc --json --object < data-raw.json > data-escaped.json ``` Or do the same with an online JSON file: ```bash $ curl -sL "http://git.io/aorKgQ" | jsesc --json --object > data-escaped.json ``` See `jsesc --help` for the full list of options. ## Support This library has been tested in at least Chrome 27-29, Firefox 3-22, Safari 4-6, Opera 10-12, IE 6-10, Node.js v0.10.0, Narwhal 0.3.2, RingoJS 0.8-0.9, PhantomJS 1.9.0, and Rhino 1.7RC4. **Note:** Using the `json` option on objects or arrays that contain non-string values relies on `JSON.parse()`. For legacy environments like IE ≤ 7, use [a `JSON` polyfill](http://bestiejs.github.io/json3/). ## Unit tests & code coverage After cloning this repository, run `npm install` to install the dependencies needed for development and testing. You may want to install Istanbul _globally_ using `npm install istanbul -g`. Once that’s done, you can run the unit tests in Node using `npm test` or `node tests/tests.js`. To run the tests in Rhino, Ringo, Narwhal, and web browsers as well, use `grunt test`. To generate the code coverage report, use `grunt cover`. ## Author | [![twitter/mathias](https://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | |---| | [Mathias Bynens](http://mathiasbynens.be/) | ## License This library is available under the [MIT](http://mths.be/mit) license. jsesc-0.5.0/bin/000077500000000000000000000000001237435321400133775ustar00rootroot00000000000000jsesc-0.5.0/bin/jsesc000077500000000000000000000067251237435321400144460ustar00rootroot00000000000000#!/usr/bin/env node (function() { var fs = require('fs'); var stringEscape = require('../jsesc.js'); var strings = process.argv.splice(2); var stdin = process.stdin; var data; var timeout; var isObject = false; var options = {}; var log = console.log; var main = function() { var option = strings[0]; if (/^(?:-h|--help|undefined)$/.test(option)) { log( 'jsesc v%s - http://mths.be/jsesc', stringEscape.version ); log([ '\nUsage:\n', '\tjsesc [string]', '\tjsesc [-s | --single-quotes] [string]', '\tjsesc [-d | --double-quotes] [string]', '\tjsesc [-w | --wrap] [string]', '\tjsesc [-e | --escape-everything] [string]', '\tjsesc [-6 | --es6] [string]', '\tjsesc [-j | --json] [string]', '\tjsesc [-o | --object] [stringified_object]', // `JSON.parse()` the argument '\tjsesc [-p | --pretty] [string]', // `compact: false` '\tjsesc [-v | --version]', '\tjsesc [-h | --help]', '\nExamples:\n', '\tjsesc \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'', '\tjsesc --json \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'', '\tjsesc --json --escape-everything \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'', '\tjsesc --double-quotes --wrap \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'', '\techo \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\' | jsesc' ].join('\n')); return process.exit(1); } if (/^(?:-v|--version)$/.test(option)) { log('v%s', stringEscape.version); return process.exit(1); } strings.forEach(function(string) { // Process options 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 (/^(?:-6|--es6)$/.test(string)) { options.es6 = true; return; } if (/^(?:-e|--escape-everything)$/.test(string)) { options.escapeEverything = true; return; } if (/^(?:-j|--json)$/.test(string)) { options.json = true; return; } if (/^(?:-o|--object)$/.test(string)) { isObject = true; return; } if (/^(?:-p|--pretty)$/.test(string)) { isObject = true; options.compact = false; return; } // Process string(s) var result; try { if (isObject) { string = JSON.parse(string); } result = stringEscape(string, options); log(result); } catch(error) { log(error.message + '\n'); log('Error: failed to escape.'); log('If you think this is a bug in jsesc, please report it:'); log('https://github.com/mathiasbynens/jsesc/issues/new'); log( '\nStack trace using jsesc@%s:\n', stringEscape.version ); log(error.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 { // Either the script is called from within a non-TTY context, // or `stdin` content is being piped in. if (!process.stdout.isTTY) { // called from a non-TTY context timeout = setTimeout(function() { // if no piped data arrived after a while, handle shell arguments main(); }, 250); } data = ''; stdin.on('data', function(chunk) { clearTimeout(timeout); data += chunk; }); stdin.on('end', function() { strings.push(data.trim()); main(); }); stdin.resume(); } }()); jsesc-0.5.0/bower.json000066400000000000000000000003251237435321400146400ustar00rootroot00000000000000{ "name": "jsesc", "version": "0.5.0", "main": "jsesc.js", "ignore": [ "bin", "coverage", "man", "src", "tests", ".*", "component.json", "Gruntfile.js", "node_modules", "package.json" ] } jsesc-0.5.0/component.json000066400000000000000000000005271237435321400155300ustar00rootroot00000000000000{ "name": "jsesc", "version": "0.5.0", "description": "A JavaScript library for escaping JavaScript strings while generating the shortest possible ASCII-only output.", "repo": "mathiasbynens/jsesc", "license": "MIT", "scripts": [ "jsesc.js" ], "main": "jsesc.js", "keywords": [ "string", "escape", "javascript", "tool" ] } jsesc-0.5.0/jsesc.js000066400000000000000000000160751237435321400143050ustar00rootroot00000000000000/*! http://mths.be/jsesc v0.5.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; if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { root = freeGlobal; } /*--------------------------------------------------------------------------*/ var object = {}; var hasOwnProperty = object.hasOwnProperty; var forOwn = function(object, callback) { var key; for (key in object) { if (hasOwnProperty.call(object, key)) { callback(key, object[key]); } } }; var extend = function(destination, source) { if (!source) { return destination; } forOwn(source, function(key, value) { destination[key] = value; }); return destination; }; var forEach = function(array, callback) { var length = array.length; var index = -1; while (++index < length) { callback(array[index]); } }; var toString = object.toString; var isArray = function(value) { return toString.call(value) == '[object Array]'; }; var isObject = function(value) { // This is a very simple check, but it’s good enough for what we need. return toString.call(value) == '[object Object]'; }; var isString = function(value) { return typeof value == 'string' || toString.call(value) == '[object String]'; }; var isFunction = function(value) { // In a perfect world, the `typeof` check would be sufficient. However, // in Chrome 1–12, `typeof /x/ == 'object'`, and in IE 6–8 // `typeof alert == 'object'` and similar for other host objects. return typeof value == 'function' || toString.call(value) == '[object Function]'; }; /*--------------------------------------------------------------------------*/ // http://mathiasbynens.be/notes/javascript-escapes#single var singleEscapes = { '"': '\\"', '\'': '\\\'', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t' // `\v` is omitted intentionally, because in IE < 9, '\v' == 'v'. // '\v': '\\x0B' }; var regexSingleEscape = /["'\\\b\f\n\r\t]/; var regexDigit = /[0-9]/; var regexWhitelist = /[ !#-&\(-\[\]-~]/; var jsesc = function(argument, options) { // Handle options var defaults = { 'escapeEverything': false, 'quotes': 'single', 'wrap': false, 'es6': false, 'json': false, 'compact': true, 'indent': '\t', '__indent__': '' }; var json = options && options.json; if (json) { defaults.quotes = 'double'; defaults.wrap = true; } options = extend(defaults, options); if (options.quotes != 'single' && options.quotes != 'double') { options.quotes = 'single'; } var quote = options.quotes == 'double' ? '"' : '\''; var compact = options.compact; var indent = options.indent; var oldIndent; var newLine = compact ? '' : '\n'; var result; var isEmpty = true; if (json && argument && isFunction(argument.toJSON)) { argument = argument.toJSON(); } if (!isString(argument)) { if (isArray(argument)) { result = []; options.wrap = true; oldIndent = options.__indent__; indent += oldIndent; options.__indent__ = indent; forEach(argument, function(value) { isEmpty = false; result.push( (compact ? '' : indent) + jsesc(value, options) ); }); if (isEmpty) { return '[]'; } return '[' + newLine + result.join(',' + newLine) + newLine + (compact ? '' : oldIndent) + ']'; } else if (!isObject(argument)) { if (json) { // For some values (e.g. `undefined`, `function` objects), // `JSON.stringify(value)` returns `undefined` (which isn’t valid // JSON) instead of `'null'`. return JSON.stringify(argument) || 'null'; } return String(argument); } else { // it’s an object result = []; options.wrap = true; oldIndent = options.__indent__; indent += oldIndent; options.__indent__ = indent; forOwn(argument, function(key, value) { isEmpty = false; result.push( (compact ? '' : indent) + jsesc(key, options) + ':' + (compact ? '' : ' ') + jsesc(value, options) ); }); if (isEmpty) { return '{}'; } return '{' + newLine + result.join(',' + newLine) + newLine + (compact ? '' : oldIndent) + '}'; } } var string = argument; // Loop over each code unit in the string and escape it var index = -1; var length = string.length; var first; var second; var codePoint; result = ''; while (++index < length) { var character = string.charAt(index); if (options.es6) { first = string.charCodeAt(index); if ( // check if it’s the start of a surrogate pair first >= 0xD800 && first <= 0xDBFF && // high surrogate length > index + 1 // there is a next code unit ) { second = string.charCodeAt(index + 1); if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae codePoint = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; result += '\\u{' + codePoint.toString(16).toUpperCase() + '}'; index++; continue; } } } if (!options.escapeEverything) { if (regexWhitelist.test(character)) { // It’s a printable ASCII character that is not `"`, `'` or `\`, // so don’t escape it. result += character; continue; } if (character == '"') { result += quote == character ? '\\"' : character; continue; } if (character == '\'') { result += quote == character ? '\\\'' : character; continue; } } if ( character == '\0' && !json && !regexDigit.test(string.charAt(index + 1)) ) { result += '\\0'; continue; } if (regexSingleEscape.test(character)) { // no need for a `hasOwnProperty` check here result += singleEscapes[character]; continue; } var charCode = character.charCodeAt(0); var hexadecimal = charCode.toString(16).toUpperCase(); var longhand = hexadecimal.length > 2 || json; var escaped = '\\' + (longhand ? 'u' : 'x') + ('0000' + hexadecimal).slice(longhand ? -4 : -2); result += escaped; continue; } if (options.wrap) { result = quote + result + quote; } return result; }; jsesc.version = '0.5.0'; /*--------------------------------------------------------------------------*/ // Some AMD build optimizers, like r.js, check for specific condition patterns // like the following: if ( typeof define == 'function' && typeof define.amd == 'object' && define.amd ) { define(function() { return jsesc; }); } else if (freeExports && !freeExports.nodeType) { if (freeModule) { // in Node.js or RingoJS v0.8.0+ freeModule.exports = jsesc; } else { // in Narwhal or RingoJS v0.7.0- freeExports.jsesc = jsesc; } } else { // in Rhino or a web browser root.jsesc = jsesc; } }(this)); jsesc-0.5.0/man/000077500000000000000000000000001237435321400134025ustar00rootroot00000000000000jsesc-0.5.0/man/jsesc.1000066400000000000000000000052741237435321400146030ustar00rootroot00000000000000.Dd October 25, 2013 .Dt jsesc 1 .Sh NAME .Nm jsesc .Nd escape strings for use in JavaScript string literals .Sh SYNOPSIS .Nm .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 6 | -es6 Ar string .br .Op Fl e | -escape-everything Ar string .br .Op Fl j | -json Ar string .br .Op Fl p | -object Ar string .br .Op Fl p | -pretty Ar string .br .Op Fl v | -version .br .Op Fl h | -help .Sh DESCRIPTION .Nm escapes strings for use in JavaScript string literals 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 JavaScript 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 JavaScript string literal wrapped in double quotes. .It Sy "-w, --wrap" Make sure the output is a valid JavaScript 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 "-6, --es6" Escape any astral Unicode symbols using ECMAScript 6 Unicode code point escape sequences. .It Sy "-e, --escape-everything" Escape all the symbols in the output, even printable ASCII symbols. .It Sy "-j, --json" Make sure the output is valid JSON. Hexadecimal character escape sequences and the \\v or \\0 escape sequences will not be used. Setting this flag enables the .Ar -d | --double-quotes and .Ar -w | --wrap settings. .It Sy "-o, --object" Treat the input as a JavaScript object rather than a string. Accepted values are flat arrays containing only string values, and flat objects containing only string values. .It Sy "-p, --pretty" Pretty-print the output for objects, using whitespace to make it more readable. Setting this flag enables the .Ar -o | --object setting. .It Sy "-v, --version" Print jsesc's version. .It Sy "-h, --help" Show the help screen. .El .Sh EXIT STATUS The .Nm jsesc utility exits with one of the following values: .Pp .Bl -tag -width flag -compact .It Li 0 .Nm successfully escaped the given string 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 "jsesc 'foo bar baz'" Print an escaped version of the given string. .It Sy echo\ 'foo bar baz'\ |\ jsesc Print an escaped version of the string that gets piped in. .El .Sh BUGS jsesc's bug tracker is located at . .Sh AUTHOR Mathias Bynens .Sh WWW jsesc-0.5.0/package.json000066400000000000000000000020631237435321400151160ustar00rootroot00000000000000{ "name": "jsesc", "version": "0.5.0", "description": "A JavaScript library for escaping JavaScript strings while generating the shortest possible valid output.", "homepage": "http://mths.be/jsesc", "main": "jsesc.js", "bin": "bin/jsesc", "man": "man/jsesc.1", "keywords": [ "string", "escape", "javascript", "tool" ], "licenses": [ { "type": "MIT", "url": "http://mths.be/mit" } ], "author": { "name": "Mathias Bynens", "url": "http://mathiasbynens.be/" }, "repository": { "type": "git", "url": "https://github.com/mathiasbynens/jsesc.git" }, "bugs": { "url": "https://github.com/mathiasbynens/jsesc/issues" }, "files": [ "LICENSE-MIT.txt", "jsesc.js", "bin/", "man/" ], "directories": { "test": "tests" }, "scripts": { "test": "node tests/tests.js" }, "devDependencies": { "coveralls": "^2.10.0", "grunt": "^0.4.5", "grunt-shell": "^0.7.0", "grunt-template": "^0.2.3", "istanbul": "^0.3.0", "qunit-extras": "^1.2.0", "qunitjs": "~1.11.0", "regenerate": "^0.6.2", "requirejs": "^2.1.14" } } jsesc-0.5.0/src/000077500000000000000000000000001237435321400134165ustar00rootroot00000000000000jsesc-0.5.0/src/data.js000066400000000000000000000005241237435321400146660ustar00rootroot00000000000000var regenerate = require('regenerate'); var fs = require('fs'); var set = regenerate() .addRange(0x20, 0x7E) // printable ASCII symbols .remove('"') // not `"` .remove('\'') // not `'` .remove('\\'); // not `\` module.exports = { 'whitelist': set.toString(), 'version': require('../package.json').version }; jsesc-0.5.0/src/jsesc.js000066400000000000000000000161171237435321400150710ustar00rootroot00000000000000/*! http://mths.be/jsesc v<%= version %> 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; if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { root = freeGlobal; } /*--------------------------------------------------------------------------*/ var object = {}; var hasOwnProperty = object.hasOwnProperty; var forOwn = function(object, callback) { var key; for (key in object) { if (hasOwnProperty.call(object, key)) { callback(key, object[key]); } } }; var extend = function(destination, source) { if (!source) { return destination; } forOwn(source, function(key, value) { destination[key] = value; }); return destination; }; var forEach = function(array, callback) { var length = array.length; var index = -1; while (++index < length) { callback(array[index]); } }; var toString = object.toString; var isArray = function(value) { return toString.call(value) == '[object Array]'; }; var isObject = function(value) { // This is a very simple check, but it’s good enough for what we need. return toString.call(value) == '[object Object]'; }; var isString = function(value) { return typeof value == 'string' || toString.call(value) == '[object String]'; }; var isFunction = function(value) { // In a perfect world, the `typeof` check would be sufficient. However, // in Chrome 1–12, `typeof /x/ == 'object'`, and in IE 6–8 // `typeof alert == 'object'` and similar for other host objects. return typeof value == 'function' || toString.call(value) == '[object Function]'; }; /*--------------------------------------------------------------------------*/ // http://mathiasbynens.be/notes/javascript-escapes#single var singleEscapes = { '"': '\\"', '\'': '\\\'', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t' // `\v` is omitted intentionally, because in IE < 9, '\v' == 'v'. // '\v': '\\x0B' }; var regexSingleEscape = /["'\\\b\f\n\r\t]/; var regexDigit = /[0-9]/; var regexWhitelist = /<%= whitelist %>/; var jsesc = function(argument, options) { // Handle options var defaults = { 'escapeEverything': false, 'quotes': 'single', 'wrap': false, 'es6': false, 'json': false, 'compact': true, 'indent': '\t', '__indent__': '' }; var json = options && options.json; if (json) { defaults.quotes = 'double'; defaults.wrap = true; } options = extend(defaults, options); if (options.quotes != 'single' && options.quotes != 'double') { options.quotes = 'single'; } var quote = options.quotes == 'double' ? '"' : '\''; var compact = options.compact; var indent = options.indent; var oldIndent; var newLine = compact ? '' : '\n'; var result; var isEmpty = true; if (json && argument && isFunction(argument.toJSON)) { argument = argument.toJSON(); } if (!isString(argument)) { if (isArray(argument)) { result = []; options.wrap = true; oldIndent = options.__indent__; indent += oldIndent; options.__indent__ = indent; forEach(argument, function(value) { isEmpty = false; result.push( (compact ? '' : indent) + jsesc(value, options) ); }); if (isEmpty) { return '[]'; } return '[' + newLine + result.join(',' + newLine) + newLine + (compact ? '' : oldIndent) + ']'; } else if (!isObject(argument)) { if (json) { // For some values (e.g. `undefined`, `function` objects), // `JSON.stringify(value)` returns `undefined` (which isn’t valid // JSON) instead of `'null'`. return JSON.stringify(argument) || 'null'; } return String(argument); } else { // it’s an object result = []; options.wrap = true; oldIndent = options.__indent__; indent += oldIndent; options.__indent__ = indent; forOwn(argument, function(key, value) { isEmpty = false; result.push( (compact ? '' : indent) + jsesc(key, options) + ':' + (compact ? '' : ' ') + jsesc(value, options) ); }); if (isEmpty) { return '{}'; } return '{' + newLine + result.join(',' + newLine) + newLine + (compact ? '' : oldIndent) + '}'; } } var string = argument; // Loop over each code unit in the string and escape it var index = -1; var length = string.length; var first; var second; var codePoint; result = ''; while (++index < length) { var character = string.charAt(index); if (options.es6) { first = string.charCodeAt(index); if ( // check if it’s the start of a surrogate pair first >= 0xD800 && first <= 0xDBFF && // high surrogate length > index + 1 // there is a next code unit ) { second = string.charCodeAt(index + 1); if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae codePoint = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; result += '\\u{' + codePoint.toString(16).toUpperCase() + '}'; index++; continue; } } } if (!options.escapeEverything) { if (regexWhitelist.test(character)) { // It’s a printable ASCII character that is not `"`, `'` or `\`, // so don’t escape it. result += character; continue; } if (character == '"') { result += quote == character ? '\\"' : character; continue; } if (character == '\'') { result += quote == character ? '\\\'' : character; continue; } } if ( character == '\0' && !json && !regexDigit.test(string.charAt(index + 1)) ) { result += '\\0'; continue; } if (regexSingleEscape.test(character)) { // no need for a `hasOwnProperty` check here result += singleEscapes[character]; continue; } var charCode = character.charCodeAt(0); var hexadecimal = charCode.toString(16).toUpperCase(); var longhand = hexadecimal.length > 2 || json; var escaped = '\\' + (longhand ? 'u' : 'x') + ('0000' + hexadecimal).slice(longhand ? -4 : -2); result += escaped; continue; } if (options.wrap) { result = quote + result + quote; } return result; }; jsesc.version = '<%= version %>'; /*--------------------------------------------------------------------------*/ // Some AMD build optimizers, like r.js, check for specific condition patterns // like the following: if ( typeof define == 'function' && typeof define.amd == 'object' && define.amd ) { define(function() { return jsesc; }); } else if (freeExports && !freeExports.nodeType) { if (freeModule) { // in Node.js or RingoJS v0.8.0+ freeModule.exports = jsesc; } else { // in Narwhal or RingoJS v0.7.0- freeExports.jsesc = jsesc; } } else { // in Rhino or a web browser root.jsesc = jsesc; } }(this)); jsesc-0.5.0/tests/000077500000000000000000000000001237435321400137715ustar00rootroot00000000000000jsesc-0.5.0/tests/index.html000066400000000000000000000016441237435321400157730ustar00rootroot00000000000000 jsesc test suite
jsesc-0.5.0/tests/tests.js000066400000000000000000000551171237435321400155020ustar00rootroot00000000000000(function(root) { 'use strict'; var noop = Function.prototype; var load = (typeof require == 'function' && !(root.define && define.amd)) ? require : (!root.document && root.java && root.load) || noop; var QUnit = (function() { return root.QUnit || ( root.addEventListener || (root.addEventListener = noop), root.setTimeout || (root.setTimeout = noop), root.QUnit = load('../node_modules/qunitjs/qunit/qunit.js') || root.QUnit, addEventListener === noop && delete root.addEventListener, root.QUnit ); }()); var qe = load('../node_modules/qunit-extras/qunit-extras.js'); if (qe) { qe.runInContext(root); } // Extend `Object.prototype` to see if this library can handle it. Object.prototype['\u2665'] = '...'; /** The `regenerate` object to test */ var jsesc = root.jsesc || (root.jsesc = ( jsesc = load('../jsesc.js') || root.jsesc, jsesc = jsesc.jsesc || jsesc )); /*--------------------------------------------------------------------------*/ // Quick and dirty test to see if we’re in PhantomJS or Node var isNode = typeof process != 'undefined' && process.argv && process.argv[0] == 'node'; var runExtendedTests = root.phantom || isNode; // explicitly call `QUnit.module()` instead of `module()` // in case we are in a CLI environment QUnit.module('jsesc'); test('common usage', function() { equal( typeof jsesc.version, 'string', '`jsesc.version` must be a string' ); equal( jsesc('\0\x31'), '\\x001', '`\\0` followed by `1`' ); equal( jsesc('\0\x38'), '\\x008', '`\\0` followed by `8`' ); equal( jsesc('\0\x39'), '\\x009', '`\\0` followed by `9`' ); equal( jsesc('\0a'), '\\0a', '`\\0` followed by `a`' ); equal( jsesc('foo"bar\'baz', { 'quotes': 'LOLWAT' // invalid setting }), 'foo"bar\\\'baz', 'Invalid `quotes` setting' ); equal( jsesc('\\x00'), '\\\\x00', '`\\\\x00` shouldn’t be changed to `\\\\0`' ); equal( jsesc('a\\x00'), 'a\\\\x00', '`a\\\\x00` shouldn’t be changed to `\\\\0`' ); equal( jsesc('\\\x00'), '\\\\\\0', '`\\\\\\x00` should be changed to `\\\\\\0`' ); equal( jsesc('\\\\x00'), '\\\\\\\\x00', '`\\\\\\\\x00` shouldn’t be changed to `\\\\\\\\0`' ); equal( jsesc('lolwat"foo\'bar', { 'escapeEverything': true }), '\\x6C\\x6F\\x6C\\x77\\x61\\x74\\"\\x66\\x6F\\x6F\\\'\\x62\\x61\\x72', 'escapeEverything' ); equal( jsesc('a\uD834\uDF06b', { 'es6': true }), 'a\\u{1D306}b', 'es6' ); equal( jsesc('a\uD834\uDF06b\uD83D\uDCA9c', { 'es6': true }), 'a\\u{1D306}b\\u{1F4A9}c', 'es6' ); equal( jsesc('a\uD834\uDF06b\uD83D\uDCA9c', { 'es6': true, 'escapeEverything': true }), '\\x61\\u{1D306}\\x62\\u{1F4A9}\\x63', 'es6 + escapeEverything' ); equal( jsesc({}, { 'compact': true }), '{}', 'Stringifying an empty object with `compact: true`' ); equal( jsesc({}, { 'compact': false }), '{}', 'Stringifying an empty object with `compact: false`' ); equal( jsesc([], { 'compact': true }), '[]', 'Stringifying an empty array with `compact: true`' ); equal( jsesc([], { 'compact': false }), '[]', 'Stringifying an empty array with `compact: false`' ); // Stringifying flat objects containing only string values equal( jsesc({ 'foo\x00bar\uFFFDbaz': 'foo\x00bar\uFFFDbaz' }), '{\'foo\\0bar\\uFFFDbaz\':\'foo\\0bar\\uFFFDbaz\'}', 'Stringifying a flat object with default settings`' ); equal( jsesc({ 'foo\x00bar\uFFFDbaz': 'foo\x00bar\uFFFDbaz' }, { 'quotes': 'double' }), '{"foo\\0bar\\uFFFDbaz":"foo\\0bar\\uFFFDbaz"}', 'Stringifying a flat object with `quotes: \'double\'`' ); equal( jsesc({ 'foo\x00bar\uFFFDbaz': 'foo\x00bar\uFFFDbaz' }, { 'compact': false }), '{\n\t\'foo\\0bar\\uFFFDbaz\': \'foo\\0bar\\uFFFDbaz\'\n}', 'Stringifying a flat object with `compact: false`' ); equal( jsesc({ 'foo\x00bar\uFFFDbaz': 'foo\x00bar\uFFFDbaz' }, { 'compact': false, 'indent': ' ' }), '{\n \'foo\\0bar\\uFFFDbaz\': \'foo\\0bar\\uFFFDbaz\'\n}', 'Stringifying a flat object with `compact: false, indent: \' \'`' ); equal( jsesc({ 'foo\x00bar\uFFFDbaz': 'foo\x00bar\uFFFDbaz' }, { 'escapeEverything': true }), '{\'\\x66\\x6F\\x6F\\0\\x62\\x61\\x72\\uFFFD\\x62\\x61\\x7A\':\'\\x66\\x6F\\x6F\\0\\x62\\x61\\x72\\uFFFD\\x62\\x61\\x7A\'}', 'Stringifying a flat object with `escapeEverything: true`' ); // Stringifying flat arrays containing only string values equal( jsesc(['foo\x00bar\uFFFDbaz', '\xA9'], { 'escapeEverything': true }), '[\'\\x66\\x6F\\x6F\\0\\x62\\x61\\x72\\uFFFD\\x62\\x61\\x7A\',\'\\xA9\']', 'Stringifying a flat array with `escapeEverything: true`' ); equal( jsesc(['foo\x00bar\uFFFDbaz', '\xA9'], { 'compact': false }), '[\n\t\'foo\\0bar\\uFFFDbaz\',\n\t\'\\xA9\'\n]', 'Stringifying a flat array with `compact: false`' ); // JSON equal( jsesc('foo\x00bar\xFF\uFFFDbaz', { 'json': true }), '"foo\\u0000bar\\u00FF\\uFFFDbaz"', 'JSON-stringifying a string' ); equal( jsesc('foo\x00bar\uFFFDbaz', { 'escapeEverything': true, 'json': true }), '"\\u0066\\u006F\\u006F\\u0000\\u0062\\u0061\\u0072\\uFFFD\\u0062\\u0061\\u007A"', 'JSON-stringifying a string with `escapeEverything: true`' ); equal( jsesc({ 'foo\x00bar\uFFFDbaz': 'foo\x00bar\uFFFDbaz' }, { 'escapeEverything': true, 'json': true }), '{"\\u0066\\u006F\\u006F\\u0000\\u0062\\u0061\\u0072\\uFFFD\\u0062\\u0061\\u007A":"\\u0066\\u006F\\u006F\\u0000\\u0062\\u0061\\u0072\\uFFFD\\u0062\\u0061\\u007A"}', 'JSON-stringifying a flat object with `escapeEverything: true`' ); equal( jsesc(['foo\x00bar\uFFFDbaz', 'foo\x00bar\uFFFDbaz'], { 'escapeEverything': true, 'json': true }), '["\\u0066\\u006F\\u006F\\u0000\\u0062\\u0061\\u0072\\uFFFD\\u0062\\u0061\\u007A","\\u0066\\u006F\\u006F\\u0000\\u0062\\u0061\\u0072\\uFFFD\\u0062\\u0061\\u007A"]', 'JSON-stringifying a flat array with `escapeEverything: true`' ); equal( jsesc('foo\x00bar', { 'json': true, 'wrap': false // override default `wrap: true` when `json` is enabled }), 'foo\\u0000bar', 'Escaping as JSON with `wrap: false`' ); equal( jsesc('foo "\x00" bar', { 'json': true, 'wrap': false // override default `wrap: true` when `json` is enabled }), 'foo \\"\\u0000\\" bar', 'Escaping as JSON with `wrap: false` escapes double quotes correctly' ); equal( jsesc('foo "\x00" bar \' qux', { 'json': true, 'quotes': 'single', // override default `quotes: 'double'` when `json` is enabled 'wrap': false // override default `wrap: true` when `json` is enabled }), 'foo "\\u0000" bar \\\' qux', 'Escaping as JSON with `wrap: false, quotes: \'single\'`' ); equal( jsesc('foo\uD834\uDF06bar\xA9baz', { 'json': true, 'es6': true // override default `es6: false` when `json` is enabled }), '"foo\\u{1D306}bar\\u00A9baz"', 'Escaping as JSON with `es6: true`' ); var tmp = { 'shouldn\u2019t be here': 10, 'toJSON': function() { return { 'hello': 'world', '\uD83D\uDCA9': 'foo', 'pile': '\uD83D\uDCA9' }; } }; equal( jsesc(tmp, { 'json' : true }), '{"hello":"world","\\uD83D\\uDCA9":"foo","pile":"\\uD83D\\uDCA9"}', '`toJSON` methods are called when `json: true`' ); notEqual( jsesc(tmp), '{"hello":"world","\\uD83D\\uDCA9":"foo","pile":"\\uD83D\\uDCA9"}', '`toJSON` methods are not called when `json: false`' ); }); if (runExtendedTests) { test('advanced tests', function() { var map = function(array, fn) { var length = array.length; while (length--) { array[length] = fn(array[length]); } return array; }; // taken from http://mths.be/punycode var stringFromCharCode = String.fromCharCode; var ucs2encode = function(value) { var output = ''; if (value > 0xFFFF) { value -= 0x10000; output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); value = 0xDC00 | value & 0x3FF; } output += stringFromCharCode(value); return output; }; var allSymbols = ''; var codePoint; var symbol = ''; // Generate strings based on code points. Trickier than it seems: // http://mathiasbynens.be/notes/javascript-encoding for (codePoint = 0x000000; codePoint <= 0x10FFFF; codePoint++) { symbol = ucs2encode(codePoint); // ok( // eval('\'' + jsesc(symbol) + '\'') == symbol, // 'U+' + codePoint.toString(16).toUpperCase() // ); allSymbols += symbol + ' '; } ok( eval('\'' + jsesc(allSymbols) + '\'') == allSymbols, 'All Unicode symbols, space-separated, default quote type (single quotes)' ); ok( eval('\'' + jsesc(allSymbols, { 'quotes': 'single' }) + '\'') == allSymbols, 'All Unicode symbols, space-separated, single quotes' ); ok( eval(jsesc(allSymbols, { 'quotes': 'single', 'wrap': true })) == allSymbols, 'All Unicode symbols, space-separated, single quotes, auto-wrap' ); ok( eval('"' + jsesc(allSymbols, { 'quotes': 'double' }) + '"') == allSymbols, 'All Unicode symbols, space-separated, double quotes' ); ok( eval(jsesc(allSymbols, { 'quotes': 'double', 'wrap': true })) == allSymbols, 'All Unicode symbols, space-separated, double quotes, auto-wrap' ); // Some of these depend on `JSON.parse()`, so only test them in Node if (isNode) { var testArray = [ undefined, Infinity, new Number(Infinity), -Infinity, new Number(-Infinity), 0, new Number(0), -0, new Number(-0), +0, new Number(+0), new Function(), 'str', function zomg() { return 'desu'; }, null, true, new Boolean(true), false, new Boolean(false), { "foo": 42, "hah": [ 1, 2, 3, { "foo" : 42 } ] } ]; equal( jsesc(testArray, { 'json': false }), '[undefined,Infinity,Infinity,-Infinity,-Infinity,0,0,0,0,0,0,function anonymous() {\n\n},\'str\',function zomg() { return \'desu\'; },null,true,true,false,false,{\'foo\':42,\'hah\':[1,2,3,{\'foo\':42}]}]', 'Escaping a non-flat array with all kinds of values' ); equal( jsesc(testArray, { 'json': true }), '[null,null,null,null,null,0,0,0,0,0,0,null,"str",null,null,true,true,false,false,{"foo":42,"hah":[1,2,3,{"foo":42}]}]', 'Escaping a non-flat array with all kinds of values, with `json: true`' ); equal( jsesc(testArray, { 'json': true, 'compact': false }), '[\n\tnull,\n\tnull,\n\tnull,\n\tnull,\n\tnull,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\tnull,\n\t"str",\n\tnull,\n\tnull,\n\ttrue,\n\ttrue,\n\tfalse,\n\tfalse,\n\t{\n\t\t"foo": 42,\n\t\t"hah": [\n\t\t\t1,\n\t\t\t2,\n\t\t\t3,\n\t\t\t{\n\t\t\t\t"foo": 42\n\t\t\t}\n\t\t]\n\t}\n]', 'Escaping a non-flat array with all kinds of values, with `json: true, compact: false`' ); } }); } // Test binary if (isNode) { asyncTest('jsesc binary', function() { var exec = require('child_process').exec; var shellTest = function(command, callback) { exec(command, function(error, stdout, stderr) { callback({ 'stdout': stdout, 'stderr': stderr, 'exitStatus': error ? error.code : 0 }); }); }; var tests = [ { 'description': 'No arguments', 'command': './bin/jsesc', 'expected': { 'exitStatus': 1 } }, { 'description': '-h option', 'command': './bin/jsesc -h', 'expected': { 'exitStatus': 1 } }, { 'description': '--help option', 'command': './bin/jsesc --help', 'expected': { 'exitStatus': 1 } }, { 'description': '-v option', 'command': './bin/jsesc -v', 'expected': { 'exitStatus': 1 } }, { 'description': '--version option', 'command': './bin/jsesc --version', 'expected': { 'exitStatus': 1 } }, { 'description': 'No options', 'command': './bin/jsesc "f\xF6o \u2665 b\xE5r \uD834\uDF06 baz"', 'expected': { 'stdout': 'f\\xF6o \\u2665 b\\xE5r \\uD834\\uDF06 baz\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': 'No options, piping content', 'command': 'echo "f\xF6o \u2665 b\xE5r \uD834\uDF06 baz" | ./bin/jsesc', 'expected': { 'stdout': 'f\\xF6o \\u2665 b\\xE5r \\uD834\\uDF06 baz\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-s option', 'command': './bin/jsesc -s f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz', 'expected': { 'stdout': 'f\\xF6o \\u2665 \\\'"\\\'" b\\xE5r \\uD834\\uDF06 baz\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-s option, piping content', 'command': 'echo f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz | ./bin/jsesc -s', 'expected': { 'stdout': 'f\\xF6o \\u2665 \\\'"\\\'" b\\xE5r \\uD834\\uDF06 baz\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--single-quotes option', 'command': './bin/jsesc --single-quotes f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz', 'expected': { 'stdout': 'f\\xF6o \\u2665 \\\'"\\\'" b\\xE5r \\uD834\\uDF06 baz\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--single-quotes option, piping content', 'command': 'echo f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz | ./bin/jsesc --single-quotes', 'expected': { 'stdout': 'f\\xF6o \\u2665 \\\'"\\\'" b\\xE5r \\uD834\\uDF06 baz\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-d option', 'command': './bin/jsesc -d f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz', 'expected': { 'stdout': 'f\\xF6o \\u2665 \'\\"\'\\" b\\xE5r \\uD834\\uDF06 baz\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-d option, piping content', 'command': 'echo f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz | ./bin/jsesc -d', 'expected': { 'stdout': 'f\\xF6o \\u2665 \'\\"\'\\" b\\xE5r \\uD834\\uDF06 baz\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--double-quotes option', 'command': './bin/jsesc --double-quotes f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz', 'expected': { 'stdout': 'f\\xF6o \\u2665 \'\\"\'\\" b\\xE5r \\uD834\\uDF06 baz\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--double-quotes option, piping content', 'command': 'echo f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz | ./bin/jsesc --double-quotes', 'expected': { 'stdout': 'f\\xF6o \\u2665 \'\\"\'\\" b\\xE5r \\uD834\\uDF06 baz\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-w option', 'command': './bin/jsesc -w f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz', 'expected': { 'stdout': '\'f\\xF6o \\u2665 \\\'"\\\'" b\\xE5r \\uD834\\uDF06 baz\'\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-w option, piping content', 'command': 'echo f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz | ./bin/jsesc -w', 'expected': { 'stdout': '\'f\\xF6o \\u2665 \\\'"\\\'" b\\xE5r \\uD834\\uDF06 baz\'\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--wrap option', 'command': './bin/jsesc --wrap f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz', 'expected': { 'stdout': '\'f\\xF6o \\u2665 \\\'"\\\'" b\\xE5r \\uD834\\uDF06 baz\'\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--wrap option, piping content', 'command': 'echo f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz | ./bin/jsesc --wrap', 'expected': { 'stdout': '\'f\\xF6o \\u2665 \\\'"\\\'" b\\xE5r \\uD834\\uDF06 baz\'\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-6 option', 'command': './bin/jsesc -6 a\uD834\uDF06b\uD83D\uDCA9c', 'expected': { 'stdout': 'a\\u{1D306}b\\u{1F4A9}c\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-6 option, piping content', 'command': 'echo a\uD834\uDF06b\uD83D\uDCA9c | ./bin/jsesc -6', 'expected': { 'stdout': 'a\\u{1D306}b\\u{1F4A9}c\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--es6 option', 'command': './bin/jsesc --es6 a\uD834\uDF06b\uD83D\uDCA9c', 'expected': { 'stdout': 'a\\u{1D306}b\\u{1F4A9}c\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--es6 option, piping content', 'command': 'echo a\uD834\uDF06b\uD83D\uDCA9c | ./bin/jsesc --es6', 'expected': { 'stdout': 'a\\u{1D306}b\\u{1F4A9}c\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-e option', 'command': './bin/jsesc -e f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz', 'expected': { 'stdout': '\\x66\\xF6\\x6F\\x20\\u2665\\x20\\\'\\"\\\'\\"\\x20\\x62\\xE5\\x72\\x20\\uD834\\uDF06\\x20\\x62\\x61\\x7A\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-e option, piping content', 'command': 'echo f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz | ./bin/jsesc -e', 'expected': { 'stdout': '\\x66\\xF6\\x6F\\x20\\u2665\\x20\\\'\\"\\\'\\"\\x20\\x62\\xE5\\x72\\x20\\uD834\\uDF06\\x20\\x62\\x61\\x7A\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--escape-everything option', 'command': './bin/jsesc --escape-everything f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz', 'expected': { 'stdout': '\\x66\\xF6\\x6F\\x20\\u2665\\x20\\\'\\"\\\'\\"\\x20\\x62\\xE5\\x72\\x20\\uD834\\uDF06\\x20\\x62\\x61\\x7A\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--escape-everything option, piping content', 'command': 'echo f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz | ./bin/jsesc --escape-everything', 'expected': { 'stdout': '\\x66\\xF6\\x6F\\x20\\u2665\\x20\\\'\\"\\\'\\"\\x20\\x62\\xE5\\x72\\x20\\uD834\\uDF06\\x20\\x62\\x61\\x7A\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-j option', 'command': './bin/jsesc -j f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz', 'expected': { 'stdout': '"f\\u00F6o \\u2665 \'\\"\'\\" b\\u00E5r \\uD834\\uDF06 baz"\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-j option, piping content', 'command': 'echo f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz | ./bin/jsesc -j', 'expected': { 'stdout': '"f\\u00F6o \\u2665 \'\\"\'\\" b\\u00E5r \\uD834\\uDF06 baz"\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--json option', 'command': './bin/jsesc --json f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz', 'expected': { 'stdout': '"f\\u00F6o \\u2665 \'\\"\'\\" b\\u00E5r \\uD834\\uDF06 baz"\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--json option, piping content', 'command': 'echo f\xF6o\\ \u2665\\ \\\'\\"\\\'\\"\\ b\xE5r\\ \uD834\uDF06\\ baz | ./bin/jsesc --json', 'expected': { 'stdout': '"f\\u00F6o \\u2665 \'\\"\'\\" b\\u00E5r \\uD834\\uDF06 baz"\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-o option', 'command': './bin/jsesc -o \\{\\"f\xF6o\\":\\"b\xE5r\\ \uD834\uDF06\\ baz\\"\\}', 'expected': { 'stdout': '{\'f\\xF6o\':\'b\\xE5r \\uD834\\uDF06 baz\'}\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-o option, piping content', 'command': 'echo \\{\\"f\xF6o\\":\\"b\xE5r\\ \uD834\uDF06\\ baz\\"\\} | ./bin/jsesc -o', 'expected': { 'stdout': '{\'f\\xF6o\':\'b\\xE5r \\uD834\\uDF06 baz\'}\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--object option', 'command': './bin/jsesc --object \\{\\"f\xF6o\\":\\"b\xE5r\\ \uD834\uDF06\\ baz\\"\\}', 'expected': { 'stdout': '{\'f\\xF6o\':\'b\\xE5r \\uD834\\uDF06 baz\'}\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--object option, piping content', 'command': 'echo \\{\\"f\xF6o\\":\\"b\xE5r\\ \uD834\uDF06\\ baz\\"\\} | ./bin/jsesc --object', 'expected': { 'stdout': '{\'f\\xF6o\':\'b\\xE5r \\uD834\\uDF06 baz\'}\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-p option', 'command': './bin/jsesc --json -p \\{\\"f\xF6o\\":\\"b\xE5r\\ \uD834\uDF06\\ baz\\"\\}', 'expected': { 'stdout': '{\n\t"f\\u00F6o": "b\\u00E5r \\uD834\\uDF06 baz"\n}\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '-p option, piping content', 'command': 'echo \\{\\"f\xF6o\\":\\"b\xE5r\\ \uD834\uDF06\\ baz\\"\\} | ./bin/jsesc --json -p', 'expected': { 'stdout': '{\n\t"f\\u00F6o": "b\\u00E5r \\uD834\\uDF06 baz"\n}\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--pretty option', 'command': './bin/jsesc --json --pretty \\{\\"f\xF6o\\":\\"b\xE5r\\ \uD834\uDF06\\ baz\\"\\}', 'expected': { 'stdout': '{\n\t"f\\u00F6o": "b\\u00E5r \\uD834\\uDF06 baz"\n}\n', 'stderr': '', 'exitStatus': 0 } }, { 'description': '--pretty option, piping content', 'command': 'echo \\{\\"f\xF6o\\":\\"b\xE5r\\ \uD834\uDF06\\ baz\\"\\} | ./bin/jsesc --json --pretty', 'expected': { 'stdout': '{\n\t"f\\u00F6o": "b\\u00E5r \\uD834\\uDF06 baz"\n}\n', 'stderr': '', 'exitStatus': 0 } } ]; var counter = tests.length; function done() { --counter || QUnit.start(); } tests.forEach(function(object) { shellTest(object.command, function(data) { // We can’t use `deepEqual` since sometimes not all expected values are provided Object.keys(object.expected).forEach(function(key) { equal(object.expected[key], data[key], object.description); }); done(); }); }); }); } /*--------------------------------------------------------------------------*/ // configure QUnit and call `QUnit.start()` for // Narwhal, Node.js, PhantomJS, Rhino, and RingoJS if (!root.document || root.phantom) { QUnit.config.noglobals = true; QUnit.start(); } }(typeof global == 'object' && global || this));