jsesc
Advanced tools
Comparing version 2.5.2 to 3.0.0
132
jsesc.js
@@ -31,2 +31,12 @@ 'use strict'; | ||
const fourHexEscape = (hex) => { | ||
return '\\u' + ('0000' + hex).slice(-4); | ||
} | ||
const hexadecimal = (code, lowercase) => { | ||
let hexadecimal = code.toString(16); | ||
if (lowercase) return hexadecimal; | ||
return hexadecimal.toUpperCase(); | ||
}; | ||
const toString = object.toString; | ||
@@ -61,4 +71,2 @@ const isArray = Array.isArray; | ||
const singleEscapes = { | ||
'"': '\\"', | ||
'\'': '\\\'', | ||
'\\': '\\\\', | ||
@@ -73,7 +81,9 @@ '\b': '\\b', | ||
}; | ||
const regexSingleEscape = /["'\\\b\f\n\r\t]/; | ||
const regexSingleEscape = /[\\\b\f\n\r\t]/; | ||
const regexDigit = /[0-9]/; | ||
const regexWhitelist = /[ !#-&\(-\[\]-_a-~]/; | ||
const escapeEverythingRegex = /([\uD800-\uDBFF][\uDC00-\uDFFF])|([\uD800-\uDFFF])|(['"`])|[^]/g; | ||
const escapeNonAsciiRegex = /([\uD800-\uDBFF][\uDC00-\uDFFF])|([\uD800-\uDFFF])|(['"`])|[^ !#-&\(-\[\]-_a-~]/g; | ||
const jsesc = (argument, options) => { | ||
@@ -240,94 +250,70 @@ const increaseIndentation = () => { | ||
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(); | ||
} | ||
result += '\\u{' + hexadecimal + '}'; | ||
++index; | ||
continue; | ||
} | ||
const regex = options.escapeEverything ? escapeEverythingRegex : escapeNonAsciiRegex; | ||
result = argument.replace(regex, (char, pair, lone, quoteChar, index, string) => { | ||
if (pair) { | ||
if (options.minimal) return pair; | ||
const first = pair.charCodeAt(0); | ||
const second = pair.charCodeAt(1); | ||
if (options.es6) { | ||
// https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae | ||
const codePoint = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; | ||
const hex = hexadecimal(codePoint, lowercaseHex); | ||
return '\\u{' + hex + '}'; | ||
} | ||
return fourHexEscape(hexadecimal(first, lowercaseHex)) + fourHexEscape(hexadecimal(second, lowercaseHex)); | ||
} | ||
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 == '\'') { | ||
result += quote == character ? '\\\'' : character; | ||
continue; | ||
} | ||
if (lone) { | ||
return fourHexEscape(hexadecimal(lone.charCodeAt(0), lowercaseHex)); | ||
} | ||
if ( | ||
character == '\0' && | ||
char == '\0' && | ||
!json && | ||
!regexDigit.test(string.charAt(index + 1)) | ||
) { | ||
result += '\\0'; | ||
continue; | ||
return '\\0'; | ||
} | ||
if (regexSingleEscape.test(character)) { | ||
if (quoteChar) { | ||
if (quoteChar == quote || options.escapeEverything) { | ||
return '\\' + quoteChar; | ||
} | ||
return quoteChar; | ||
} | ||
if (regexSingleEscape.test(char)) { | ||
// no need for a `hasOwnProperty` check here | ||
result += singleEscapes[character]; | ||
continue; | ||
return singleEscapes[char]; | ||
} | ||
const charCode = character.charCodeAt(0); | ||
if (options.minimal && charCode != 0x2028 && charCode != 0x2029) { | ||
result += character; | ||
continue; | ||
if (options.minimal && char != '\u2028' && char != '\u2029') { | ||
return char; | ||
} | ||
let hexadecimal = charCode.toString(16); | ||
if (!lowercaseHex) { | ||
hexadecimal = hexadecimal.toUpperCase(); | ||
const hex = hexadecimal(char.charCodeAt(0), lowercaseHex); | ||
if (json || hex.length > 2) { | ||
return fourHexEscape(hex); | ||
} | ||
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; | ||
} | ||
return '\\x' + ('00' + hex).slice(-2); | ||
}); | ||
if (quote == '`') { | ||
result = result.replace(/\$\{/g, '\\\$\{'); | ||
result = result.replace(/\$\{/g, '\\${'); | ||
} | ||
if (options.isScriptContext) { | ||
// https://mathiasbynens.be/notes/etago | ||
return result | ||
result = result | ||
.replace(/<\/(script|style)/gi, '<\\/$1') | ||
.replace(/<!--/g, json ? '\\u003C!--' : '\\x3C!--'); | ||
} | ||
if (options.wrap) { | ||
result = quote + result + quote; | ||
} | ||
return result; | ||
}; | ||
jsesc.version = '2.5.2'; | ||
jsesc.version = '3.0.0'; | ||
module.exports = jsesc; |
{ | ||
"name": "jsesc", | ||
"version": "2.5.2", | ||
"version": "3.0.0", | ||
"description": "Given some data, jsesc returns the shortest possible stringified & ASCII-safe representation of that data.", | ||
"homepage": "https://mths.be/jsesc", | ||
"engines": { | ||
"node": ">=4" | ||
"node": ">=6" | ||
}, | ||
@@ -48,5 +48,6 @@ "main": "jsesc.js", | ||
"grunt": "^0.4.5", | ||
"grunt-cli": "^1.3.2", | ||
"grunt-template": "^0.2.3", | ||
"istanbul": "^0.4.2", | ||
"mocha": "*", | ||
"mocha": "^5.2.0", | ||
"regenerate": "^1.3.0", | ||
@@ -53,0 +54,0 @@ "requirejs": "^2.1.22" |
@@ -1,2 +0,2 @@ | ||
# jsesc [![Build status](https://travis-ci.org/mathiasbynens/jsesc.svg?branch=master)](https://travis-ci.org/mathiasbynens/jsesc) [![Code coverage status](https://coveralls.io/repos/mathiasbynens/jsesc/badge.svg)](https://coveralls.io/r/mathiasbynens/jsesc) [![Dependency status](https://gemnasium.com/mathiasbynens/jsesc.svg)](https://gemnasium.com/mathiasbynens/jsesc) | ||
# jsesc [![Build status](https://travis-ci.org/mathiasbynens/jsesc.svg?branch=master)](https://travis-ci.org/mathiasbynens/jsesc) [![Code coverage status](https://coveralls.io/repos/mathiasbynens/jsesc/badge.svg)](https://coveralls.io/r/mathiasbynens/jsesc) | ||
@@ -205,2 +205,3 @@ Given some data, _jsesc_ returns a stringified representation of that data. jsesc is similar to `JSON.stringify()` except: | ||
* whatever symbol is being used for wrapping string literals (based on [the `quotes` option](#quotes)) | ||
* [lone surrogates](https://esdiscuss.org/topic/code-points-vs-unicode-scalar-values#content-14) | ||
@@ -252,3 +253,3 @@ Note: with this option enabled, jsesc output is no longer guaranteed to be ASCII-safe. | ||
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. | ||
The `indent` option takes a string value, and defaults to `'\t'`. When the `compact` setting is disabled (`false`), the value of the `indent` option is used to format the output for arrays and objects. | ||
@@ -411,3 +412,3 @@ ```js | ||
As of v2.0.0, jsesc supports Node.js v4+ only. | ||
As of v3.0.0, jsesc supports Node.js v6+ only. | ||
@@ -414,0 +415,0 @@ 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/). |
423
31558
8
291