[Pkg-javascript-commits] [node-jsesc] 01/05: Imported Upstream version 2.1.0
Julien Puydt
julien.puydt at laposte.net
Tue May 31 16:13:00 UTC 2016
This is an automated email from the git hooks/post-receive script.
jpuydt-guest pushed a commit to branch master
in repository node-jsesc.
commit 94af1810785dd8627d48d1ca06e47da6b7efbcc6
Author: Julien Puydt <julien.puydt at laposte.net>
Date: Tue May 31 18:07:58 2016 +0200
Imported Upstream version 2.1.0
---
.editorconfig | 12 +
.travis.yml | 19 +-
Gruntfile.js | 55 +--
README.md | 117 ++++---
bower.json | 17 -
component.json | 17 -
jsesc.js | 519 ++++++++++++++---------------
package.json | 91 ++---
src/data.js | 8 +-
src/jsesc.js | 519 ++++++++++++++---------------
tests/tests.js | 1011 ++++++++++++++++----------------------------------------
11 files changed, 936 insertions(+), 1449 deletions(-)
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..dbd9e6b
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,12 @@
+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}]
+indent_style = space
+indent_size = 2
diff --git a/.travis.yml b/.travis.yml
index 3423994..332433c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,20 +1,7 @@
language: node_js
node_js:
+ - "4"
+ - "5"
- "6"
-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_7R5; wget https://github.com/mozilla/rhino/releases/download/Rhino1_7R5_RELEASE/$PACKAGE.zip && sudo unzip $PACKAGE -d /opt/ && rm $PACKAGE.zip"
- - "PACKAGE=rhino1_7R5; 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.11; wget https://github.com/ringo/ringojs/releases/download/v0.11.0/$PACKAGE.zip && sudo unzip $PACKAGE -d /opt/ && rm $PACKAGE.zip"
- - "PACKAGE=ringojs-0.11; 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"
+ - "npm run coveralls"
diff --git a/Gruntfile.js b/Gruntfile.js
index d9a8cb0..3a6a3ff 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,46 +1,10 @@
module.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" && coveralls < coverage/lcov.info; 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"'
- },
- '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
+ // Generate the regular expressions dynamically using Regenerate.
'data': require('./src/data.js')
},
'files': {
@@ -50,25 +14,10 @@ module.exports = function(grunt) {
}
});
- 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'
+ 'template'
]);
};
diff --git a/README.md b/README.md
index d9c8f59..7f0057a 100644
--- a/README.md
+++ b/README.md
@@ -8,62 +8,16 @@ 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](https://www.npmjs.com/):
```bash
npm install jsesc
```
-In a browser:
-
-```html
-<script src="jsesc.js"></script>
-```
-
-In [Node.js](https://nodejs.org/) and [RingoJS](http://ringojs.org/):
-
-```js
-var jsesc = require('jsesc');
-```
-
-In [Narwhal](http://narwhaljs.org/):
+In [Node.js](https://nodejs.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);
- }
-);
+const jsesc = require('jsesc');
```
## API
@@ -137,6 +91,32 @@ jsesc([ 'Ich ♥ Bücher', 'foo 𝌆 bar' ], {
// → '["Ich \\u2665 B\\xFCcher","foo \\uD834\\uDF06 bar"]'
```
+#### `numbers`
+
+The default value for the `numbers` option is `'decimal'`. This means that any numeric values will be represented using decimal integer literals. Other valid options are `binary`, `octal`, and `hexadecimal`, which result in binary integer literals, octal integer literals, and hexadecimal integer literals, respectively.
+
+```js
+jsesc(42, {
+ 'numbers': 'binary'
+});
+// → '0b101010'
+
+jsesc(42, {
+ 'numbers': 'octal'
+});
+// → '0o52'
+
+jsesc(42, {
+ 'numbers': 'decimal'
+});
+// → '42'
+
+jsesc(42, {
+ 'numbers': 'hexadecimal'
+});
+// → '0x2A'
+```
+
#### `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.
@@ -266,6 +246,24 @@ jsesc([ 'Ich ♥ Bücher', 'foo 𝌆 bar' ], {
This setting has no effect on the output for strings.
+#### `indentLevel`
+
+The `indentLevel` option takes a numeric value, and defaults to `0`. It represents the current indentation level, i.e. the number of times the value of [the `indent` option](#indent) is repeated.
+
+```js
+jsesc(['a', 'b', 'c'], {
+ 'compact': false,
+ 'indentLevel': 1
+});
+// → '[\n\t\t\'a\',\n\t\t\'b\',\n\t\t\'c\'\n\t]'
+
+jsesc(['a', 'b', 'c'], {
+ 'compact': false,
+ 'indentLevel': 2
+});
+// → '[\n\t\t\t\'a\',\n\t\t\t\'b\',\n\t\t\t\'c\'\n\t\t]'
+```
+
#### `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](https://mathiasbynens.be/notes/javascript-escapes#hexadecimal) and [the `\v` or `\0` escape sequences](https://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 [...]
@@ -303,14 +301,21 @@ jsesc([ undefined, -Infinity ], {
#### `lowercaseHex`
-The `lowercaseHex` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, the alphabetical hexadecimal digits in escape sequences in the output are in lowercase.
+The `lowercaseHex` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, any alphabetical hexadecimal digits in escape sequences as well as any hexadecimal integer literals (see [the `numbers` option](#numbers)) in the output are in lowercase.
```js
jsesc('Ich ♥ Bücher', {
- 'lowercaseHex': true,
+ 'lowercaseHex': true
});
// → 'Ich \\u2665 B\\xfccher'
// ^^
+
+jsesc(42, {
+ 'numbers': 'hexadecimal',
+ 'lowercaseHex': true
+});
+// → '0x2a'
+// ^^
```
### `jsesc.version`
@@ -375,17 +380,9 @@ See `jsesc --help` for the full list of options.
## Support
-This library has been tested in at least Chrome 27, Firefox 3, Safari 4, Opera 10, IE 6, Node.js v6.0.0, Narwhal 0.3.2, RingoJS 0.8-0.11, 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](https://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`.
+As of v2.0.0, jsesc supports Node.js v4+ only.
-To generate the code coverage report, use `grunt cover`.
+Older versions (up to jsesc v1.3.0) support Chrome 27, Firefox 3, Safari 4, Opera 10, IE 6, Node.js v6.0.0, Narwhal 0.3.2, RingoJS 0.8-0.11, 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](https://bestiejs.github.io/json3/).
## Author
diff --git a/bower.json b/bower.json
deleted file mode 100644
index f2ad633..0000000
--- a/bower.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "jsesc",
- "version": "1.2.0",
- "main": "jsesc.js",
- "ignore": [
- "bin",
- "coverage",
- "man",
- "src",
- "tests",
- ".*",
- "component.json",
- "Gruntfile.js",
- "node_modules",
- "package.json"
- ]
-}
diff --git a/component.json b/component.json
deleted file mode 100644
index 09591b8..0000000
--- a/component.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "jsesc",
- "version": "1.2.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"
- ]
-}
diff --git a/jsesc.js b/jsesc.js
index 8827ce3..13988de 100644
--- a/jsesc.js
+++ b/jsesc.js
@@ -1,296 +1,299 @@
-/*! https://mths.be/jsesc v1.2.0 by @mathias */
-;(function(root) {
+'use strict';
- // Detect free variables `exports`
- var freeExports = typeof exports == 'object' && exports;
+const object = {};
+const hasOwnProperty = object.hasOwnProperty;
+const forOwn = function(object, callback) {
+ for (const key in object) {
+ if (hasOwnProperty.call(object, key)) {
+ callback(key, object[key]);
+ }
+ }
+};
- // Detect free variable `module`
- var freeModule = typeof module == 'object' && module &&
- module.exports == freeExports && module;
+const extend = function(destination, source) {
+ if (!source) {
+ return destination;
+ }
+ forOwn(source, function(key, value) {
+ destination[key] = value;
+ });
+ return destination;
+};
- // 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;
+const forEach = function(array, callback) {
+ const length = array.length;
+ let index = -1;
+ while (++index < length) {
+ callback(array[index]);
}
+};
- /*--------------------------------------------------------------------------*/
+const toString = object.toString;
+const isArray = Array.isArray;
+const isObject = function(value) {
+ // This is a very simple check, but it’s good enough for what we need.
+ return toString.call(value) == '[object Object]';
+};
+const isString = function(value) {
+ return typeof value == 'string' ||
+ toString.call(value) == '[object String]';
+};
+const isNumber = function(value) {
+ return typeof value == 'number' ||
+ toString.call(value) == '[object Number]';
+};
+const isFunction = function(value) {
+ return typeof value == 'function';
+};
+const isMap = function(value) {
+ return toString.call(value) == '[object Map]';
+};
+const isSet = function(value) {
+ return toString.call(value) == '[object Set]';
+};
- 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;
- };
+// https://mathiasbynens.be/notes/javascript-escapes#single
+const singleEscapes = {
+ '"': '\\"',
+ '\'': '\\\'',
+ '\\': '\\\\',
+ '\b': '\\b',
+ '\f': '\\f',
+ '\n': '\\n',
+ '\r': '\\r',
+ '\t': '\\t'
+ // `\v` is omitted intentionally, because in IE < 9, '\v' == 'v'.
+ // '\v': '\\x0B'
+};
+const regexSingleEscape = /["'\\\b\f\n\r\t]/;
- var forEach = function(array, callback) {
- var length = array.length;
- var index = -1;
- while (++index < length) {
- callback(array[index]);
- }
- };
+const regexDigit = /[0-9]/;
+const regexWhitelist = /[ !#-&\(-\[\]-~]/;
- 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]';
+const jsesc = function(argument, options) {
+ const increaseIndentation = function() {
+ oldIndent = indent;
+ ++options.indentLevel;
+ indent = options.indent.repeat(options.indentLevel)
};
- var isMap = function(value) {
- return toString.call(value) == '[object Map]';
+ // Handle options
+ const defaults = {
+ 'escapeEverything': false,
+ 'escapeEtago': false,
+ 'quotes': 'single',
+ 'wrap': false,
+ 'es6': false,
+ 'json': false,
+ 'compact': true,
+ 'lowercaseHex': false,
+ 'numbers': 'decimal',
+ 'indent': '\t',
+ 'indentLevel': 0,
+ '__inline1__': false,
+ '__inline2__': false
};
- var isSet = function(value) {
- return toString.call(value) == '[object Set]';
- };
-
- /*--------------------------------------------------------------------------*/
-
- // https://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]/;
+ const 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';
+ }
+ const quote = options.quotes == 'double' ? '"' : '\'';
+ const compact = options.compact;
+ const lowercaseHex = options.lowercaseHex;
+ let indent = options.indent.repeat(options.indentLevel);
+ let oldIndent = '';
+ const inline1 = options.__inline1__;
+ const inline2 = options.__inline2__;
+ const newLine = compact ? '' : '\n';
+ let result;
+ let isEmpty = true;
+ const useBinNumbers = options.numbers == 'binary';
+ const useOctNumbers = options.numbers == 'octal';
+ const useDecNumbers = options.numbers == 'decimal';
+ const useHexNumbers = options.numbers == 'hexadecimal';
- var regexDigit = /[0-9]/;
- var regexWhitelist = /[ !#-&\(-\[\]-~]/;
+ if (json && argument && isFunction(argument.toJSON)) {
+ argument = argument.toJSON();
+ }
- var jsesc = function(argument, options) {
- // Handle options
- var defaults = {
- 'escapeEverything': false,
- 'escapeEtago': false,
- 'quotes': 'single',
- 'wrap': false,
- 'es6': false,
- 'json': false,
- 'compact': true,
- 'lowercaseHex': false,
- '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';
+ if (!isString(argument)) {
+ if (isMap(argument)) {
+ if (argument.size == 0) {
+ return 'new Map()';
+ }
+ if (!compact) {
+ options.__inline1__ = true;
+ options.__inline2__ = false;
+ }
+ return 'new Map(' + jsesc(Array.from(argument), options) + ')';
}
- 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 (isSet(argument)) {
+ if (argument.size == 0) {
+ return 'new Set()';
+ }
+ return 'new Set(' + jsesc(Array.from(argument), options) + ')';
}
-
- if (!isString(argument)) {
- if (isMap(argument)) {
- if (argument.size == 0) {
- return 'new Map()';
- }
- return 'new Map(' + jsesc(Array.from(argument), options) + ')';
+ if (isArray(argument)) {
+ result = [];
+ options.wrap = true;
+ if (inline1) {
+ options.__inline1__ = false;
+ options.__inline2__ = true;
}
- if (isSet(argument)) {
- if (argument.size == 0) {
- return 'new Set()';
- }
- return 'new Set(' + jsesc(Array.from(argument), options) + ')';
+ if (!inline2) {
+ increaseIndentation();
}
- 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';
+ forEach(argument, function(value) {
+ isEmpty = false;
+ if (inline2) {
+ options.__inline2__ = false;
}
+ result.push(
+ (compact || inline2 ? '' : indent) +
+ jsesc(value, options)
+ );
+ });
+ if (isEmpty) {
+ return '[]';
+ }
+ if (inline2) {
+ return '[' + result.join(', ') + ']';
+ }
+ return '[' + newLine + result.join(',' + newLine) + newLine +
+ (compact ? '' : oldIndent) + ']';
+ } else if (isNumber(argument)) {
+ if (json) {
+ // Some number values (e.g. `Infinity`) cannot be represented in JSON.
+ return JSON.stringify(argument);
+ }
+ if (useDecNumbers) {
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 '{}';
+ }
+ if (useHexNumbers) {
+ let hexadecimal = argument.toString(16);
+ if (!lowercaseHex) {
+ hexadecimal = hexadecimal.toUpperCase();
}
- return '{' + newLine + result.join(',' + newLine) + newLine +
- (compact ? '' : oldIndent) + '}';
+ return '0x' + hexadecimal;
+ }
+ if (useBinNumbers) {
+ return '0b' + argument.toString(2);
+ }
+ if (useOctNumbers) {
+ return '0o' + argument.toString(8);
+ }
+ } 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;
+ increaseIndentation();
+ 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
- // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
- codePoint = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
- var hexadecimal = codePoint.toString(16);
- if (!options.lowercaseHex) {
- hexadecimal = hexadecimal.toUpperCase();
- }
- result += '\\u{' + hexadecimal + '}';
- index++;
- continue;
+ const string = argument;
+ // Loop over each code unit in the string and escape it
+ let index = -1;
+ const length = string.length;
+ result = '';
+ while (++index < length) {
+ const character = string.charAt(index);
+ if (options.es6) {
+ const 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
+ ) {
+ const second = string.charCodeAt(index + 1);
+ if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate
+ // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+ const codePoint = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
+ let hexadecimal = codePoint.toString(16);
+ if (!lowercaseHex) {
+ hexadecimal = hexadecimal.toUpperCase();
}
- }
- }
- 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;
+ result += '\\u{' + hexadecimal + '}';
+ ++index;
continue;
}
}
- if (
- character == '\0' &&
- !json &&
- !regexDigit.test(string.charAt(index + 1))
- ) {
- result += '\\0';
+ }
+ 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 (regexSingleEscape.test(character)) {
- // no need for a `hasOwnProperty` check here
- result += singleEscapes[character];
+ if (character == '"') {
+ result += quote == character ? '\\"' : character;
continue;
}
- var charCode = character.charCodeAt(0);
- var hexadecimal = charCode.toString(16);
- if (!options.lowercaseHex) {
- hexadecimal = hexadecimal.toUpperCase();
+ if (character == '\'') {
+ result += quote == character ? '\\\'' : character;
+ continue;
}
- var longhand = hexadecimal.length > 2 || json;
- var escaped = '\\' + (longhand ? 'u' : 'x') +
- ('0000' + hexadecimal).slice(longhand ? -4 : -2);
- result += escaped;
+ }
+ if (
+ character == '\0' &&
+ !json &&
+ !regexDigit.test(string.charAt(index + 1))
+ ) {
+ result += '\\0';
continue;
}
- if (options.wrap) {
- result = quote + result + quote;
+ if (regexSingleEscape.test(character)) {
+ // no need for a `hasOwnProperty` check here
+ result += singleEscapes[character];
+ continue;
}
- if (options.escapeEtago) {
- // https://mathiasbynens.be/notes/etago
- return result.replace(/<\/(script|style)/gi, '<\\/$1');
+ const charCode = character.charCodeAt(0);
+ let hexadecimal = charCode.toString(16);
+ if (!lowercaseHex) {
+ hexadecimal = hexadecimal.toUpperCase();
}
- return result;
- };
-
- jsesc.version = '1.2.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;
+ const longhand = hexadecimal.length > 2 || json;
+ const escaped = '\\' + (longhand ? 'u' : 'x') +
+ ('0000' + hexadecimal).slice(longhand ? -4 : -2);
+ result += escaped;
+ continue;
}
+ if (options.wrap) {
+ result = quote + result + quote;
+ }
+ if (options.escapeEtago) {
+ // https://mathiasbynens.be/notes/etago
+ return result.replace(/<\/(script|style)/gi, '<\\/$1');
+ }
+ return result;
+};
+
+jsesc.version = '2.1.0';
-}(this));
+module.exports = jsesc;
diff --git a/package.json b/package.json
index 193b82a..b37bcd5 100644
--- a/package.json
+++ b/package.json
@@ -1,46 +1,49 @@
{
- "name": "jsesc",
- "version": "1.2.0",
- "description": "A JavaScript library for escaping JavaScript strings while generating the shortest possible valid output.",
- "homepage": "https://mths.be/jsesc",
- "main": "jsesc.js",
- "bin": "bin/jsesc",
- "man": "man/jsesc.1",
- "keywords": [
- "string",
- "escape",
- "javascript",
- "tool"
- ],
- "license": "MIT",
- "author": {
- "name": "Mathias Bynens",
- "url": "https://mathiasbynens.be/"
- },
- "repository": {
- "type": "git",
- "url": "https://github.com/mathiasbynens/jsesc.git"
- },
- "bugs": "https://github.com/mathiasbynens/jsesc/issues",
- "files": [
- "LICENSE-MIT.txt",
- "jsesc.js",
- "bin/",
- "man/"
- ],
- "scripts": {
- "test": "node tests/tests.js",
- "build": "grunt template"
- },
- "devDependencies": {
- "coveralls": "^2.11.6",
- "grunt": "^0.4.5",
- "grunt-shell": "^1.1.2",
- "grunt-template": "^0.2.3",
- "istanbul": "^0.4.2",
- "qunit-extras": "^1.4.5",
- "qunitjs": "~1.11.0",
- "regenerate": "^1.2.1",
- "requirejs": "^2.1.22"
- }
+ "name": "jsesc",
+ "version": "2.1.0",
+ "description": "A JavaScript library for escaping JavaScript strings while generating the shortest possible valid output.",
+ "homepage": "https://mths.be/jsesc",
+ "engines": {
+ "node": ">=4"
+ },
+ "main": "jsesc.js",
+ "bin": "bin/jsesc",
+ "man": "man/jsesc.1",
+ "keywords": [
+ "string",
+ "escape",
+ "javascript",
+ "tool"
+ ],
+ "license": "MIT",
+ "author": {
+ "name": "Mathias Bynens",
+ "url": "https://mathiasbynens.be/"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/mathiasbynens/jsesc.git"
+ },
+ "bugs": "https://github.com/mathiasbynens/jsesc/issues",
+ "files": [
+ "LICENSE-MIT.txt",
+ "jsesc.js",
+ "bin/",
+ "man/"
+ ],
+ "scripts": {
+ "build": "grunt template",
+ "coveralls": "istanbul cover --verbose --dir 'coverage' 'tests/tests.js' && coveralls < coverage/lcov.info'",
+ "cover": "istanbul cover --report 'html' --verbose --dir 'coverage' 'tests/tests.js'",
+ "test": "mocha tests"
+ },
+ "devDependencies": {
+ "coveralls": "^2.11.6",
+ "grunt": "^0.4.5",
+ "grunt-template": "^0.2.3",
+ "istanbul": "^0.4.2",
+ "mocha": "*",
+ "regenerate": "^1.3.0",
+ "requirejs": "^2.1.22"
+ }
}
diff --git a/src/data.js b/src/data.js
index 4c99c37..654cd41 100644
--- a/src/data.js
+++ b/src/data.js
@@ -1,7 +1,9 @@
-var regenerate = require('regenerate');
-var fs = require('fs');
+'use strict';
-var set = regenerate()
+const regenerate = require('regenerate');
+const fs = require('fs');
+
+const set = regenerate()
.addRange(0x20, 0x7E) // printable ASCII symbols
.remove('"') // not `"`
.remove('\'') // not `'`
diff --git a/src/jsesc.js b/src/jsesc.js
index 55b0518..1514eca 100644
--- a/src/jsesc.js
+++ b/src/jsesc.js
@@ -1,296 +1,299 @@
-/*! https://mths.be/jsesc v<%= version %> by @mathias */
-;(function(root) {
+'use strict';
- // Detect free variables `exports`
- var freeExports = typeof exports == 'object' && exports;
+const object = {};
+const hasOwnProperty = object.hasOwnProperty;
+const forOwn = function(object, callback) {
+ for (const key in object) {
+ if (hasOwnProperty.call(object, key)) {
+ callback(key, object[key]);
+ }
+ }
+};
- // Detect free variable `module`
- var freeModule = typeof module == 'object' && module &&
- module.exports == freeExports && module;
+const extend = function(destination, source) {
+ if (!source) {
+ return destination;
+ }
+ forOwn(source, function(key, value) {
+ destination[key] = value;
+ });
+ return destination;
+};
- // 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;
+const forEach = function(array, callback) {
+ const length = array.length;
+ let index = -1;
+ while (++index < length) {
+ callback(array[index]);
}
+};
- /*--------------------------------------------------------------------------*/
+const toString = object.toString;
+const isArray = Array.isArray;
+const isObject = function(value) {
+ // This is a very simple check, but it’s good enough for what we need.
+ return toString.call(value) == '[object Object]';
+};
+const isString = function(value) {
+ return typeof value == 'string' ||
+ toString.call(value) == '[object String]';
+};
+const isNumber = function(value) {
+ return typeof value == 'number' ||
+ toString.call(value) == '[object Number]';
+};
+const isFunction = function(value) {
+ return typeof value == 'function';
+};
+const isMap = function(value) {
+ return toString.call(value) == '[object Map]';
+};
+const isSet = function(value) {
+ return toString.call(value) == '[object Set]';
+};
- 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;
- };
+// https://mathiasbynens.be/notes/javascript-escapes#single
+const singleEscapes = {
+ '"': '\\"',
+ '\'': '\\\'',
+ '\\': '\\\\',
+ '\b': '\\b',
+ '\f': '\\f',
+ '\n': '\\n',
+ '\r': '\\r',
+ '\t': '\\t'
+ // `\v` is omitted intentionally, because in IE < 9, '\v' == 'v'.
+ // '\v': '\\x0B'
+};
+const regexSingleEscape = /["'\\\b\f\n\r\t]/;
- var forEach = function(array, callback) {
- var length = array.length;
- var index = -1;
- while (++index < length) {
- callback(array[index]);
- }
- };
+const regexDigit = /[0-9]/;
+const regexWhitelist = /<%= whitelist %>/;
- 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]';
+const jsesc = function(argument, options) {
+ const increaseIndentation = function() {
+ oldIndent = indent;
+ ++options.indentLevel;
+ indent = options.indent.repeat(options.indentLevel)
};
- var isMap = function(value) {
- return toString.call(value) == '[object Map]';
+ // Handle options
+ const defaults = {
+ 'escapeEverything': false,
+ 'escapeEtago': false,
+ 'quotes': 'single',
+ 'wrap': false,
+ 'es6': false,
+ 'json': false,
+ 'compact': true,
+ 'lowercaseHex': false,
+ 'numbers': 'decimal',
+ 'indent': '\t',
+ 'indentLevel': 0,
+ '__inline1__': false,
+ '__inline2__': false
};
- var isSet = function(value) {
- return toString.call(value) == '[object Set]';
- };
-
- /*--------------------------------------------------------------------------*/
-
- // https://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]/;
+ const 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';
+ }
+ const quote = options.quotes == 'double' ? '"' : '\'';
+ const compact = options.compact;
+ const lowercaseHex = options.lowercaseHex;
+ let indent = options.indent.repeat(options.indentLevel);
+ let oldIndent = '';
+ const inline1 = options.__inline1__;
+ const inline2 = options.__inline2__;
+ const newLine = compact ? '' : '\n';
+ let result;
+ let isEmpty = true;
+ const useBinNumbers = options.numbers == 'binary';
+ const useOctNumbers = options.numbers == 'octal';
+ const useDecNumbers = options.numbers == 'decimal';
+ const useHexNumbers = options.numbers == 'hexadecimal';
- var regexDigit = /[0-9]/;
- var regexWhitelist = /<%= whitelist %>/;
+ if (json && argument && isFunction(argument.toJSON)) {
+ argument = argument.toJSON();
+ }
- var jsesc = function(argument, options) {
- // Handle options
- var defaults = {
- 'escapeEverything': false,
- 'escapeEtago': false,
- 'quotes': 'single',
- 'wrap': false,
- 'es6': false,
- 'json': false,
- 'compact': true,
- 'lowercaseHex': false,
- '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';
+ if (!isString(argument)) {
+ if (isMap(argument)) {
+ if (argument.size == 0) {
+ return 'new Map()';
+ }
+ if (!compact) {
+ options.__inline1__ = true;
+ options.__inline2__ = false;
+ }
+ return 'new Map(' + jsesc(Array.from(argument), options) + ')';
}
- 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 (isSet(argument)) {
+ if (argument.size == 0) {
+ return 'new Set()';
+ }
+ return 'new Set(' + jsesc(Array.from(argument), options) + ')';
}
-
- if (!isString(argument)) {
- if (isMap(argument)) {
- if (argument.size == 0) {
- return 'new Map()';
- }
- return 'new Map(' + jsesc(Array.from(argument), options) + ')';
+ if (isArray(argument)) {
+ result = [];
+ options.wrap = true;
+ if (inline1) {
+ options.__inline1__ = false;
+ options.__inline2__ = true;
}
- if (isSet(argument)) {
- if (argument.size == 0) {
- return 'new Set()';
- }
- return 'new Set(' + jsesc(Array.from(argument), options) + ')';
+ if (!inline2) {
+ increaseIndentation();
}
- 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';
+ forEach(argument, function(value) {
+ isEmpty = false;
+ if (inline2) {
+ options.__inline2__ = false;
}
+ result.push(
+ (compact || inline2 ? '' : indent) +
+ jsesc(value, options)
+ );
+ });
+ if (isEmpty) {
+ return '[]';
+ }
+ if (inline2) {
+ return '[' + result.join(', ') + ']';
+ }
+ return '[' + newLine + result.join(',' + newLine) + newLine +
+ (compact ? '' : oldIndent) + ']';
+ } else if (isNumber(argument)) {
+ if (json) {
+ // Some number values (e.g. `Infinity`) cannot be represented in JSON.
+ return JSON.stringify(argument);
+ }
+ if (useDecNumbers) {
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 '{}';
+ }
+ if (useHexNumbers) {
+ let hexadecimal = argument.toString(16);
+ if (!lowercaseHex) {
+ hexadecimal = hexadecimal.toUpperCase();
}
- return '{' + newLine + result.join(',' + newLine) + newLine +
- (compact ? '' : oldIndent) + '}';
+ return '0x' + hexadecimal;
+ }
+ if (useBinNumbers) {
+ return '0b' + argument.toString(2);
+ }
+ if (useOctNumbers) {
+ return '0o' + argument.toString(8);
+ }
+ } 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;
+ increaseIndentation();
+ 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
- // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
- codePoint = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
- var hexadecimal = codePoint.toString(16);
- if (!options.lowercaseHex) {
- hexadecimal = hexadecimal.toUpperCase();
- }
- result += '\\u{' + hexadecimal + '}';
- index++;
- continue;
+ const string = argument;
+ // Loop over each code unit in the string and escape it
+ let index = -1;
+ const length = string.length;
+ result = '';
+ while (++index < length) {
+ const character = string.charAt(index);
+ if (options.es6) {
+ const 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
+ ) {
+ const second = string.charCodeAt(index + 1);
+ if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate
+ // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+ const codePoint = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
+ let hexadecimal = codePoint.toString(16);
+ if (!lowercaseHex) {
+ hexadecimal = hexadecimal.toUpperCase();
}
- }
- }
- 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;
+ result += '\\u{' + hexadecimal + '}';
+ ++index;
continue;
}
}
- if (
- character == '\0' &&
- !json &&
- !regexDigit.test(string.charAt(index + 1))
- ) {
- result += '\\0';
+ }
+ 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 (regexSingleEscape.test(character)) {
- // no need for a `hasOwnProperty` check here
- result += singleEscapes[character];
+ if (character == '"') {
+ result += quote == character ? '\\"' : character;
continue;
}
- var charCode = character.charCodeAt(0);
- var hexadecimal = charCode.toString(16);
- if (!options.lowercaseHex) {
- hexadecimal = hexadecimal.toUpperCase();
+ if (character == '\'') {
+ result += quote == character ? '\\\'' : character;
+ continue;
}
- var longhand = hexadecimal.length > 2 || json;
- var escaped = '\\' + (longhand ? 'u' : 'x') +
- ('0000' + hexadecimal).slice(longhand ? -4 : -2);
- result += escaped;
+ }
+ if (
+ character == '\0' &&
+ !json &&
+ !regexDigit.test(string.charAt(index + 1))
+ ) {
+ result += '\\0';
continue;
}
- if (options.wrap) {
- result = quote + result + quote;
+ if (regexSingleEscape.test(character)) {
+ // no need for a `hasOwnProperty` check here
+ result += singleEscapes[character];
+ continue;
}
- if (options.escapeEtago) {
- // https://mathiasbynens.be/notes/etago
- return result.replace(/<\/(script|style)/gi, '<\\/$1');
+ const charCode = character.charCodeAt(0);
+ let hexadecimal = charCode.toString(16);
+ if (!lowercaseHex) {
+ hexadecimal = hexadecimal.toUpperCase();
}
- 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;
+ const longhand = hexadecimal.length > 2 || json;
+ const escaped = '\\' + (longhand ? 'u' : 'x') +
+ ('0000' + hexadecimal).slice(longhand ? -4 : -2);
+ result += escaped;
+ continue;
}
+ if (options.wrap) {
+ result = quote + result + quote;
+ }
+ if (options.escapeEtago) {
+ // https://mathiasbynens.be/notes/etago
+ return result.replace(/<\/(script|style)/gi, '<\\/$1');
+ }
+ return result;
+};
+
+jsesc.version = '<%= version %>';
-}(this));
+module.exports = jsesc;
diff --git a/tests/tests.js b/tests/tests.js
index 5f53a14..51153f3 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -1,136 +1,134 @@
-(function(root) {
- 'use strict';
+'use strict';
- var noop = Function.prototype;
+const assert = require('assert');
+const jsesc = require('../jsesc.js');
- 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].slice(-4) == '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(
+describe('common usage', function() {
+ it('works correctly for common operations', function() {
+ assert.equal(
typeof jsesc.version,
'string',
'`jsesc.version` must be a string'
);
- equal(
+ assert.equal(
jsesc('\0\x31'),
'\\x001',
'`\\0` followed by `1`'
);
- equal(
+ assert.equal(
jsesc('\0\x38'),
'\\x008',
'`\\0` followed by `8`'
);
- equal(
+ assert.equal(
jsesc('\0\x39'),
'\\x009',
'`\\0` followed by `9`'
);
- equal(
+ assert.equal(
jsesc('\0a'),
'\\0a',
'`\\0` followed by `a`'
);
- equal(
+ assert.equal(
jsesc('foo"bar\'baz', {
'quotes': 'LOLWAT' // invalid setting
}),
'foo"bar\\\'baz',
'Invalid `quotes` setting'
);
- equal(
+ assert.equal(
jsesc('\\x00'),
'\\\\x00',
'`\\\\x00` shouldn’t be changed to `\\\\0`'
);
- equal(
+ assert.equal(
jsesc('a\\x00'),
'a\\\\x00',
'`a\\\\x00` shouldn’t be changed to `\\\\0`'
);
- equal(
+ assert.equal(
jsesc('\\\x00'),
'\\\\\\0',
'`\\\\\\x00` should be changed to `\\\\\\0`'
);
- equal(
+ assert.equal(
jsesc('\\\\x00'),
'\\\\\\\\x00',
'`\\\\\\\\x00` shouldn’t be changed to `\\\\\\\\0`'
);
- equal(
+ assert.equal(
jsesc('lolwat"foo\'bar', {
'escapeEverything': true
}),
'\\x6C\\x6F\\x6C\\x77\\x61\\x74\\"\\x66\\x6F\\x6F\\\'\\x62\\x61\\x72',
'escapeEverything'
);
- equal(
+ assert.equal(
jsesc('foo</script>bar</style>baz</script>qux', {
'escapeEtago': true
}),
'foo<\\/script>bar<\\/style>baz<\\/script>qux',
'escapeEtago'
);
- equal(
+ assert.equal(
jsesc('foo</sCrIpT>bar</STYLE>baz</SCRIPT>qux', {
'escapeEtago': true
}),
'foo<\\/sCrIpT>bar<\\/STYLE>baz<\\/SCRIPT>qux',
'escapeEtago'
);
- equal(
+ assert.equal(
+ jsesc([0x42, 0x1337], {
+ 'numbers': 'decimal'
+ }),
+ '[66,4919]',
+ '`numbers: \'decimal\'` (default)'
+ );
+ assert.equal(
+ jsesc([0x42, 0x1337], {
+ 'numbers': 'binary'
+ }),
+ '[0b1000010,0b1001100110111]',
+ '`numbers: \'binary\'`'
+ );
+ assert.equal(
+ jsesc([0x42, 0x1337, NaN, Infinity], {
+ 'numbers': 'binary',
+ 'json': true
+ }),
+ '[66,4919,null,null]',
+ '`json: true` takes precedence over `numbers: \'binary\'`'
+ );
+ assert.equal(
+ jsesc([0x42, 0x1337], {
+ 'numbers': 'octal'
+ }),
+ '[0o102,0o11467]',
+ '`numbers: \'octal\'`'
+ );
+ assert.equal(
+ jsesc([0x42, 0x1337], {
+ 'numbers': 'hexadecimal'
+ }),
+ '[0x42,0x1337]',
+ '`numbers: \'hexadecimal\'`'
+ );
+ assert.equal(
jsesc('a\uD834\uDF06b', {
'es6': true
}),
'a\\u{1D306}b',
'es6'
);
- equal(
+ assert.equal(
jsesc('a\uD834\uDF06b\uD83D\uDCA9c', {
'es6': true
}),
'a\\u{1D306}b\\u{1F4A9}c',
'es6'
);
- equal(
+ assert.equal(
jsesc('a\uD834\uDF06b\uD83D\uDCA9c', {
'es6': true,
'escapeEverything': true
@@ -138,28 +136,28 @@
'\\x61\\u{1D306}\\x62\\u{1F4A9}\\x63',
'es6 + escapeEverything'
);
- equal(
+ assert.equal(
jsesc({}, {
'compact': true
}),
'{}',
'Stringifying an empty object with `compact: true`'
);
- equal(
+ assert.equal(
jsesc({}, {
'compact': false
}),
'{}',
'Stringifying an empty object with `compact: false`'
);
- equal(
+ assert.equal(
jsesc([], {
'compact': true
}),
'[]',
'Stringifying an empty array with `compact: true`'
);
- equal(
+ assert.equal(
jsesc([], {
'compact': false
}),
@@ -167,26 +165,42 @@
'Stringifying an empty array with `compact: false`'
);
// Stringifying flat objects containing only string values
- equal(
+ assert.equal(
jsesc({ 'foo\x00bar\uFFFDbaz': 'foo\x00bar\uFFFDbaz' }),
'{\'foo\\0bar\\uFFFDbaz\':\'foo\\0bar\\uFFFDbaz\'}',
'Stringifying a flat object with default settings`'
);
- equal(
+ assert.equal(
jsesc({ 'foo\x00bar\uFFFDbaz': 'foo\x00bar\uFFFDbaz' }, {
'quotes': 'double'
}),
'{"foo\\0bar\\uFFFDbaz":"foo\\0bar\\uFFFDbaz"}',
'Stringifying a flat object with `quotes: \'double\'`'
);
- equal(
+ assert.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(
+ assert.equal(
+ jsesc(['a', 'b', 'c'], {
+ 'compact': false,
+ 'indentLevel': 1
+ }),
+ '[\n\t\t\'a\',\n\t\t\'b\',\n\t\t\'c\'\n\t]',
+ '`indentLevel: 1`'
+ );
+ assert.equal(
+ jsesc(['a', 'b', 'c'], {
+ 'compact': false,
+ 'indentLevel': 2
+ }),
+ '[\n\t\t\t\'a\',\n\t\t\t\'b\',\n\t\t\t\'c\'\n\t\t]',
+ '`indentLevel: 2`'
+ );
+ assert.equal(
jsesc({ 'foo\x00bar\uFFFDbaz': 'foo\x00bar\uFFFDbaz' }, {
'compact': false,
'indent': ' '
@@ -194,7 +208,7 @@
'{\n \'foo\\0bar\\uFFFDbaz\': \'foo\\0bar\\uFFFDbaz\'\n}',
'Stringifying a flat object with `compact: false, indent: \' \'`'
);
- equal(
+ assert.equal(
jsesc({ 'foo\x00bar\uFFFDbaz': 'foo\x00bar\uFFFDbaz' }, {
'escapeEverything': true
}),
@@ -202,102 +216,130 @@
'Stringifying a flat object with `escapeEverything: true`'
);
// Stringifying flat arrays containing only string values
- equal(
+ assert.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(
+ assert.equal(
jsesc(['foo\x00bar\uFFFDbaz', '\xA9'], {
'compact': false
}),
'[\n\t\'foo\\0bar\\uFFFDbaz\',\n\t\'\\xA9\'\n]',
'Stringifying a flat array with `compact: false`'
);
- // Maps
- if (typeof Map != 'undefined') {
- equal(
- jsesc(
- new Map([])
- ),
- 'new Map()',
- 'Stringifying an empty Map'
- );
- equal(
- jsesc(
- new Map([
- ['a', 1],
- ['b', 2]
- ]),
- {
- 'compact': true
- }
- ),
- 'new Map([[\'a\',1],[\'b\',2]])',
- 'Stringifying a Map with `compact: true`'
- );
- equal(
- jsesc(
- new Map([
- ['a', 1],
- ['b', 2]
- ]),
- {
- 'compact': false
- }
- ),
- 'new Map([\n\t[\n\t\t\'a\',\n\t\t1\n\t],\n\t[\n\t\t\'b\',\n\t\t2\n\t]\n])',
- 'Stringifying a Map with `compact: false`'
- );
- }
- if (typeof Set != 'undefined') {
- equal(
- jsesc(
- new Set([])
- ),
- 'new Set()',
- 'Stringifying an empty Set'
- );
- equal(
- jsesc(
- new Set([
- ['a'],
- 'b',
- {}
- ]),
- {
- 'compact': true
- }
- ),
- 'new Set([[\'a\'],\'b\',{}])',
- 'Stringifying a Set with `compact: true`'
- );
- equal(
- jsesc(
- new Set([
- ['a'],
- 'b',
- {}
- ]),
- {
- 'compact': false
- }
- ),
- 'new Set([\n\t[\n\t\t\'a\'\n\t],\n\t\'b\',\n\t{}\n])',
- 'Stringifying a Set with `compact: false`'
- );
- }
+ assert.equal(
+ jsesc(
+ new Map([])
+ ),
+ 'new Map()',
+ 'Stringifying an empty Map'
+ );
+ assert.equal(
+ jsesc(
+ new Map([
+ ['a', 1],
+ ['b', 2]
+ ]),
+ {
+ 'compact': true
+ }
+ ),
+ 'new Map([[\'a\',1],[\'b\',2]])',
+ 'Stringifying a Map with `compact: true`'
+ );
+ assert.equal(
+ jsesc(
+ new Map([
+ ['a', 1],
+ ['b', 2]
+ ]),
+ {
+ 'compact': false
+ }
+ ),
+ 'new Map([\n\t[\'a\', 1],\n\t[\'b\', 2]\n])',
+ 'Stringifying a Map with `compact: false`'
+ );
+ assert.equal(
+ jsesc(
+ new Map([
+ ['a', 1],
+ ['b', [
+ 'a',
+ 'nested',
+ 'array'
+ ]]
+ ]),
+ {
+ 'compact': false
+ }
+ ),
+ 'new Map([\n\t[\'a\', 1],\n\t[\'b\', [\n\t\t\'a\',\n\t\t\'nested\',\n\t\t\'array\'\n\t]]\n])',
+ 'Stringifying a Map with `compact: false`'
+ );
+ assert.equal(
+ jsesc(
+ new Map([
+ ['a', 1],
+ ['b', new Map([
+ ['x', 2],
+ ['y', 3]
+ ])]
+ ]),
+ {
+ 'compact': false
+ }
+ ),
+ 'new Map([\n\t[\'a\', 1],\n\t[\'b\', new Map([\n\t\t[\'x\', 2],\n\t\t[\'y\', 3]\n\t])]\n])',
+ 'Stringifying a Map with `compact: false`'
+ );
+ assert.equal(
+ jsesc(
+ new Set([])
+ ),
+ 'new Set()',
+ 'Stringifying an empty Set'
+ );
+ assert.equal(
+ jsesc(
+ new Set([
+ ['a'],
+ 'b',
+ {}
+ ]),
+ {
+ 'compact': true
+ }
+ ),
+ 'new Set([[\'a\'],\'b\',{}])',
+ 'Stringifying a Set with `compact: true`'
+ );
+ assert.equal(
+ jsesc(
+ new Set([
+ ['a'],
+ 'b',
+ {}
+ ]),
+ {
+ 'compact': false
+ }
+ ),
+ 'new Set([\n\t[\n\t\t\'a\'\n\t],\n\t\'b\',\n\t{}\n])',
+ 'Stringifying a Set with `compact: false`'
+ );
// JSON
- equal(
+ assert.equal(
jsesc('foo\x00bar\xFF\uFFFDbaz', {
'json': true
}),
'"foo\\u0000bar\\u00FF\\uFFFDbaz"',
'JSON-stringifying a string'
);
- equal(
+ assert.equal(
jsesc('foo\x00bar\uFFFDbaz', {
'escapeEverything': true,
'json': true
@@ -305,7 +347,7 @@
'"\\u0066\\u006F\\u006F\\u0000\\u0062\\u0061\\u0072\\uFFFD\\u0062\\u0061\\u007A"',
'JSON-stringifying a string with `escapeEverything: true`'
);
- equal(
+ assert.equal(
jsesc({ 'foo\x00bar\uFFFDbaz': 'foo\x00bar\uFFFDbaz' }, {
'escapeEverything': true,
'json': true
@@ -313,7 +355,7 @@
'{"\\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(
+ assert.equal(
jsesc(['foo\x00bar\uFFFDbaz', 'foo\x00bar\uFFFDbaz'], {
'escapeEverything': true,
'json': true
@@ -321,7 +363,7 @@
'["\\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(
+ assert.equal(
jsesc('foo\x00bar', {
'json': true,
'wrap': false // override default `wrap: true` when `json` is enabled
@@ -329,7 +371,7 @@
'foo\\u0000bar',
'Escaping as JSON with `wrap: false`'
);
- equal(
+ assert.equal(
jsesc('foo "\x00" bar', {
'json': true,
'wrap': false // override default `wrap: true` when `json` is enabled
@@ -337,7 +379,7 @@
'foo \\"\\u0000\\" bar',
'Escaping as JSON with `wrap: false` escapes double quotes correctly'
);
- equal(
+ assert.equal(
jsesc('foo "\x00" bar \' qux', {
'json': true,
'quotes': 'single', // override default `quotes: 'double'` when `json` is enabled
@@ -346,7 +388,7 @@
'foo "\\u0000" bar \\\' qux',
'Escaping as JSON with `wrap: false, quotes: \'single\'`'
);
- equal(
+ assert.equal(
jsesc('foo\uD834\uDF06bar\xA9baz', {
'json': true,
'es6': true // override default `es6: false` when `json` is enabled
@@ -354,7 +396,7 @@
'"foo\\u{1D306}bar\\u00A9baz"',
'Escaping as JSON with `es6: true`'
);
- var tmp = {
+ const tmp = {
'shouldn\u2019t be here': 10,
'toJSON': function() {
return {
@@ -364,31 +406,39 @@
};
}
};
- equal(
+ assert.equal(
jsesc(tmp, { 'json' : true }),
'{"hello":"world","\\uD83D\\uDCA9":"foo","pile":"\\uD83D\\uDCA9"}',
'`toJSON` methods are called when `json: true`'
);
- notEqual(
+ assert.notEqual(
jsesc(tmp),
'{"hello":"world","\\uD83D\\uDCA9":"foo","pile":"\\uD83D\\uDCA9"}',
'`toJSON` methods are not called when `json: false`'
);
- equal(
+ assert.equal(
+ jsesc(42, {
+ 'numbers': 'hexadecimal',
+ 'lowercaseHex': true
+ }),
+ '0x2a',
+ 'Hexadecimal integeral literals are lowercase when `lowercaseHex: true`'
+ );
+ assert.equal(
jsesc('\u2192\xE9', {
'lowercaseHex': true
}),
'\\u2192\\xe9',
'Alphabetical hexadecimal digits are lowercase when `lowercaseHex: true`'
);
- equal(
+ assert.equal(
jsesc('\u2192\xE9', {
'lowercaseHex': false
}),
'\\u2192\\xE9',
'Alphabetical hexadecimal digits are uppercase when `lowercaseHex: false`'
);
- equal(
+ assert.equal(
jsesc('\u2192\xE9', {
'lowercaseHex': true,
'json': true
@@ -396,7 +446,7 @@
'"\\u2192\\u00e9"',
'Alphabetical hexadecimal digits are lowercase when `lowercaseHex: false` and `json: true`'
);
- equal(
+ assert.equal(
jsesc('\u2192\xe9', {
'lowercaseHex': false,
'json': true
@@ -404,7 +454,7 @@
'"\\u2192\\u00E9"',
'Alphabetical hexadecimal digits are uppercase when `lowercaseHex: false` and `json: true`'
);
- equal(
+ assert.equal(
jsesc('\xE7\xE7a\xE7\xE7', {
'lowercaseHex': true,
'escapeEverything': true
@@ -412,7 +462,7 @@
'\\xe7\\xe7\\x61\\xe7\\xe7',
'Alphabetical hexadecimal digits are lowercase when `lowercaseHex: true` and `escapeEverything: true`'
);
- equal(
+ assert.equal(
jsesc('\xE7\xE7a\xE7\xE7', {
'lowercaseHex': false,
'escapeEverything': true
@@ -420,7 +470,7 @@
'\\xE7\\xE7\\x61\\xE7\\xE7',
'Alphabetical hexadecimal digits are uppercase when `lowercaseHex: false` and `escapeEverything: true`'
);
- equal(
+ assert.equal(
jsesc('\u2192\xE9\uD83D\uDCA9', {
'lowercaseHex': true,
'es6': true
@@ -428,7 +478,7 @@
'\\u2192\\xe9\\u{1f4a9}',
'Alphabetical hexadecimal digits are lowercase when `lowercaseHex: true` and `es6: true`'
);
- equal(
+ assert.equal(
jsesc('\u2192\xE9\uD83D\uDCA9', {
'lowercaseHex': false,
'es6': true
@@ -437,568 +487,83 @@
'Alphabetical hexadecimal digits are uppercase when `lowercaseHex: false` and `es6: true`'
);
});
+});
- 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 https://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:
- // https://mathiasbynens.be/notes/javascript-encoding
- for (codePoint = 0x000000; codePoint <= 0x10FFFF; codePoint += 0xF) {
- 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`'
- );
- }
- });
+describe('advanced tests', function() {
+ let allSymbols = '';
+ // Generate strings based on code points. Trickier than it seems:
+ // https://mathiasbynens.be/notes/javascript-encoding
+ for (let codePoint = 0x000000; codePoint <= 0x10FFFF; codePoint += 0xF) {
+ const symbol = String.fromCodePoint(codePoint);
+ // ok(
+ // eval('\'' + jsesc(symbol) + '\'') == symbol,
+ // 'U+' + codePoint.toString(16).toUpperCase()
+ // );
+ allSymbols += symbol + ' ';
}
+ it('works correctly for advanced operations', function() {
+ assert.ok(
+ eval('\'' + jsesc(allSymbols) + '\'') == allSymbols,
+ 'All Unicode symbols, space-separated, default quote type (single quotes)'
+ );
+ assert.ok(
+ eval('\'' + jsesc(allSymbols, {
+ 'quotes': 'single'
+ }) + '\'') == allSymbols,
+ 'All Unicode symbols, space-separated, single quotes'
+ );
+ assert.ok(
+ eval(jsesc(allSymbols, {
+ 'quotes': 'single',
+ 'wrap': true
+ })) == allSymbols,
+ 'All Unicode symbols, space-separated, single quotes, auto-wrap'
+ );
+ assert.ok(
+ eval('"' + jsesc(allSymbols, {
+ 'quotes': 'double'
+ }) + '"') == allSymbols,
+ 'All Unicode symbols, space-separated, double quotes'
+ );
+ assert.ok(
+ eval(jsesc(allSymbols, {
+ 'quotes': 'double',
+ 'wrap': true
+ })) == allSymbols,
+ 'All Unicode symbols, space-separated, double quotes, auto-wrap'
+ );
- // 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': '-t option',
- 'command': './bin/jsesc -t "foo</script>bar"',
- 'expected': {
- 'stdout': 'foo<\\/script>bar\n',
- 'stderr': '',
- 'exitStatus': 0
- }
- },
- {
- 'description': '-t option, piping content',
- 'command': 'echo "foo</script>bar" | ./bin/jsesc -t',
- 'expected': {
- 'stdout': 'foo<\\/script>bar\n',
- 'stderr': '',
- 'exitStatus': 0
- }
- },
- {
- 'description': '--escape-etago option',
- 'command': './bin/jsesc --escape-etago "foo</script>bar"',
- 'expected': {
- 'stdout': 'foo<\\/script>bar\n',
- 'stderr': '',
- 'exitStatus': 0
- }
- },
- {
- 'description': '--escape-etago option, piping content',
- 'command': 'echo "foo</script>bar" | ./bin/jsesc --escape-etago',
- 'expected': {
- 'stdout': 'foo<\\/script>bar\n',
- 'stderr': '',
- 'exitStatus': 0
- }
- },
- {
- 'description': '-l option',
- 'command': './bin/jsesc -l a\uD834\uDF06b\uD83D\uDCA9c',
- 'expected': {
- 'stdout': 'a\\ud834\\udf06b\\ud83d\\udca9c\n',
- 'stderr': '',
- 'exitStatus': 0
- }
- },
- {
- 'description': '-l option, piping content',
- 'command': 'echo a\uD834\uDF06b\uD83D\uDCA9c | ./bin/jsesc -l',
- 'expected': {
- 'stdout': 'a\\ud834\\udf06b\\ud83d\\udca9c\n',
- 'stderr': '',
- 'exitStatus': 0
- }
- },
- {
- 'description': '--lowercase-hex option',
- 'command': './bin/jsesc --lowercase-hex a\uD834\uDF06b\uD83D\uDCA9c',
- 'expected': {
- 'stdout': 'a\\ud834\\udf06b\\ud83d\\udca9c\n',
- 'stderr': '',
- 'exitStatus': 0
- }
- },
- {
- 'description': '--lowercase-hex option, piping content',
- 'command': 'echo a\uD834\uDF06b\uD83D\uDCA9c | ./bin/jsesc --lowercase-hex',
- 'expected': {
- 'stdout': 'a\\ud834\\udf06b\\ud83d\\udca9c\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();
+ // Some of these depend on `JSON.parse()`, so only test them in Node
+ const 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 } ]
}
-
- 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));
+ ];
+ assert.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'
+ );
+ assert.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`'
+ );
+ assert.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`'
+ );
+ }).timeout(15000);
+});
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-jsesc.git
More information about the Pkg-javascript-commits
mailing list