diff options
Diffstat (limited to 'node_modules/javascript-stringify/javascript-stringify.js')
| -rw-r--r-- | node_modules/javascript-stringify/javascript-stringify.js | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/node_modules/javascript-stringify/javascript-stringify.js b/node_modules/javascript-stringify/javascript-stringify.js new file mode 100644 index 00000000..6a2c7bac --- /dev/null +++ b/node_modules/javascript-stringify/javascript-stringify.js @@ -0,0 +1,384 @@ +(function (root, stringify) { + /* istanbul ignore else */ + if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') { + // Node. + module.exports = stringify(); + } else if (typeof define === 'function' && define.amd) { + // AMD, registers as an anonymous module. + define(function () { + return stringify(); + }); + } else { + // Browser global. + root.javascriptStringify = stringify(); + } +})(this, function () { + /** + * Match all characters that need to be escaped in a string. Modified from + * source to match single quotes instead of double. + * + * Source: https://github.com/douglascrockford/JSON-js/blob/master/json2.js + */ + var ESCAPABLE = /[\\\'\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + + /** + * Map of characters to escape characters. + */ + var META_CHARS = { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + "'": "\\'", + '"': '\\"', + '\\': '\\\\' + }; + + /** + * Escape any character into its literal JavaScript string. + * + * @param {string} char + * @return {string} + */ + function escapeChar (char) { + var meta = META_CHARS[char]; + + return meta || '\\u' + ('0000' + char.charCodeAt(0).toString(16)).slice(-4); + }; + + /** + * JavaScript reserved word list. + */ + var RESERVED_WORDS = {}; + + /** + * Map reserved words to the object. + */ + ( + 'break else new var case finally return void catch for switch while ' + + 'continue function this with default if throw delete in try ' + + 'do instanceof typeof abstract enum int short boolean export ' + + 'interface static byte extends long super char final native synchronized ' + + 'class float package throws const goto private transient debugger ' + + 'implements protected volatile double import public let yield' + ).split(' ').map(function (key) { + RESERVED_WORDS[key] = true; + }); + + /** + * Test for valid JavaScript identifier. + */ + var IS_VALID_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/; + + /** + * Check if a variable name is valid. + * + * @param {string} name + * @return {boolean} + */ + function isValidVariableName (name) { + return !RESERVED_WORDS[name] && IS_VALID_IDENTIFIER.test(name); + } + + /** + * Return the global variable name. + * + * @return {string} + */ + function toGlobalVariable (value) { + return 'Function(' + stringify('return this;') + ')()'; + } + + /** + * Serialize the path to a string. + * + * @param {Array} path + * @return {string} + */ + function toPath (path) { + var result = ''; + + for (var i = 0; i < path.length; i++) { + if (isValidVariableName(path[i])) { + result += '.' + path[i]; + } else { + result += '[' + stringify(path[i]) + ']'; + } + } + + return result; + } + + /** + * Stringify an array of values. + * + * @param {Array} array + * @param {string} indent + * @param {Function} next + * @return {string} + */ + function stringifyArray (array, indent, next) { + // Map array values to their stringified values with correct indentation. + var values = array.map(function (value, index) { + var str = next(value, index); + + if (str === undefined) { + return String(str); + } + + return indent + str.split('\n').join('\n' + indent); + }).join(indent ? ',\n' : ','); + + // Wrap the array in newlines if we have indentation set. + if (indent && values) { + return '[\n' + values + '\n]'; + } + + return '[' + values + ']'; + } + + /** + * Stringify a map of values. + * + * @param {Object} object + * @param {string} indent + * @param {Function} next + * @return {string} + */ + function stringifyObject (object, indent, next) { + // Iterate over object keys and concat string together. + var values = Object.keys(object).reduce(function (values, key) { + var value = next(object[key], key); + + // Omit `undefined` object values. + if (value === undefined) { + return values; + } + + // String format the key and value data. + key = isValidVariableName(key) ? key : stringify(key); + value = String(value).split('\n').join('\n' + indent); + + // Push the current object key and value into the values array. + values.push(indent + key + ':' + (indent ? ' ' : '') + value); + + return values; + }, []).join(indent ? ',\n' : ','); + + // Wrap the object in newlines if we have indentation set. + if (indent && values) { + return '{\n' + values + '\n}'; + } + + return '{' + values + '}'; + } + + /** + * Convert JavaScript objects into strings. + */ + var OBJECT_TYPES = { + '[object Array]': stringifyArray, + '[object Object]': stringifyObject, + '[object Error]': function (error) { + return 'new Error(' + stringify(error.message) + ')'; + }, + '[object Date]': function (date) { + return 'new Date(' + date.getTime() + ')'; + }, + '[object String]': function (string) { + return 'new String(' + stringify(string.toString()) + ')'; + }, + '[object Number]': function (number) { + return 'new Number(' + number + ')'; + }, + '[object Boolean]': function (boolean) { + return 'new Boolean(' + boolean + ')'; + }, + '[object Uint8Array]': function (array, indent) { + return 'new Uint8Array(' + stringifyArray(array) + ')'; + }, + '[object Set]': function (array, indent, next) { + if (typeof Array.from === 'function') { + return 'new Set(' + stringify(Array.from(array), indent, next) + ')'; + } else return undefined; + }, + '[object Map]': function (array, indent, next) { + if (typeof Array.from === 'function') { + return 'new Map(' + stringify(Array.from(array), indent, next) + ')'; + } else return undefined; + }, + '[object RegExp]': String, + '[object Function]': String, + '[object global]': toGlobalVariable, + '[object Window]': toGlobalVariable + }; + + /** + * Convert JavaScript primitives into strings. + */ + var PRIMITIVE_TYPES = { + 'string': function (string) { + return "'" + string.replace(ESCAPABLE, escapeChar) + "'"; + }, + 'number': String, + 'object': String, + 'boolean': String, + 'symbol': String, + 'undefined': String + }; + + /** + * Convert any value to a string. + * + * @param {*} value + * @param {string} indent + * @param {Function} next + * @return {string} + */ + function stringify (value, indent, next) { + // Convert primitives into strings. + if (Object(value) !== value) { + return PRIMITIVE_TYPES[typeof value](value, indent, next); + } + + // Handle buffer objects before recursing (node < 6 was an object, node >= 6 is a `Uint8Array`). + if (typeof Buffer === 'function' && Buffer.isBuffer(value)) { + return 'new Buffer(' + next(value.toString()) + ')'; + } + + // Use the internal object string to select stringification method. + var toString = OBJECT_TYPES[Object.prototype.toString.call(value)]; + + // Convert objects into strings. + return toString ? toString(value, indent, next) : undefined; + } + + /** + * Stringify an object into the literal string. + * + * @param {*} value + * @param {Function} [replacer] + * @param {(number|string)} [space] + * @param {Object} [options] + * @return {string} + */ + return function (value, replacer, space, options) { + options = options || {} + + // Convert the spaces into a string. + if (typeof space !== 'string') { + space = new Array(Math.max(0, space|0) + 1).join(' '); + } + + var maxDepth = Number(options.maxDepth) || 100; + var references = !!options.references; + var skipUndefinedProperties = !!options.skipUndefinedProperties; + var valueCount = Number(options.maxValues) || 100000; + + var path = []; + var stack = []; + var encountered = []; + var paths = []; + var restore = []; + + /** + * Stringify the next value in the stack. + * + * @param {*} value + * @param {string} key + * @return {string} + */ + function next (value, key) { + if (skipUndefinedProperties && value === undefined) { + return undefined; + } + + path.push(key); + var result = recurse(value, stringify); + path.pop(); + return result; + } + + /** + * Handle recursion by checking if we've visited this node every iteration. + * + * @param {*} value + * @param {Function} stringify + * @return {string} + */ + var recurse = references ? + function (value, stringify) { + if (value && (typeof value === 'object' || typeof value === 'function')) { + var seen = encountered.indexOf(value); + + // Track nodes to restore later. + if (seen > -1) { + restore.push(path.slice(), paths[seen]); + return; + } + + // Track encountered nodes. + encountered.push(value); + paths.push(path.slice()); + } + + // Stop when we hit the max depth. + if (path.length > maxDepth || valueCount-- <= 0) { + return; + } + + // Stringify the value and fallback to + return stringify(value, space, next); + } : + function (value, stringify) { + var seen = stack.indexOf(value); + + if (seen > -1 || path.length > maxDepth || valueCount-- <= 0) { + return; + } + + stack.push(value); + var value = stringify(value, space, next); + stack.pop(); + return value; + }; + + // If the user defined a replacer function, make the recursion function + // a double step process - `recurse -> replacer -> stringify`. + if (typeof replacer === 'function') { + var before = recurse + + // Intertwine the replacer function with the regular recursion. + recurse = function (value, stringify) { + return before(value, function (value, space, next) { + return replacer(value, space, function (value) { + return stringify(value, space, next); + }); + }); + }; + } + + var result = recurse(value, stringify); + + // Attempt to restore circular references. + if (restore.length) { + var sep = space ? '\n' : ''; + var assignment = space ? ' = ' : '='; + var eol = ';' + sep; + var before = space ? '(function () {' : '(function(){' + var after = '}())' + var results = ['var x' + assignment + result]; + + for (var i = 0; i < restore.length; i += 2) { + results.push('x' + toPath(restore[i]) + assignment + 'x' + toPath(restore[i + 1])); + } + + results.push('return x'); + + return before + sep + results.join(eol) + eol + after + } + + return result; + }; +}); |
