UNPKG

tosource-polyfill

Version:

Firefox toSource() function polyfill for browser and Node.js

152 lines (107 loc) 2.98 kB
const DEFAULT_INDENT = ' ' const KEYWORD_REGEXP = new RegExp ('^('+ 'abstract|boolean|break|byte|case|catch|char|class|const|continue|debugger|'+ 'default|delete|do|double|else|enum|export|extends|false|final|finally|'+ 'float|for|function|goto|if|implements|import|in|instanceof|int|interface|'+ 'long|native|new|null|package|private|protected|public|return|short|static|'+ 'super|switch|synchronized|this|throw|throws|transient|true|try|typeof|'+ 'undefined|var|void|volatile|while|with'+ ')$') var _filter var _indent = DEFAULT_INDENT var seen = [] function applyToSource(prototype, func) { if(prototype.toSource === undefined) Object.defineProperty(prototype, 'toSource', {value: func}) } function fill(keys, func, thisArg) { thisArg = thisArg || keys var items = '' if(keys.length) { seen.push(thisArg) items = join(keys.map(func, thisArg)) seen.pop() } return items } function getIndent(indent) { switch(typeof indent) { case 'boolean': return indent ? DEFAULT_INDENT : '' case 'number': return Array(indent+1).join(' ') case 'string': return indent case 'undefined': return DEFAULT_INDENT } if(indent === null) return '' throw SyntaxError('Invalid indent: '+indent) } function join(elements) { if(elements.length < 2) return elements var offset = Array(seen.length).join(_indent) var newLine = (_indent&&'\n')+offset+_indent return newLine + elements.join(','+newLine) + (_indent&&'\n')+offset; } function legalKey(string) { return /^[a-z_$][0-9a-z_$]*$/gi.test(string) && !KEYWORD_REGEXP.test(string) } function walk(object) { object = _filter ? _filter(object) : object if (object === null) return 'null' if (typeof object === 'undefined') return 'undefined' var index = seen.indexOf(object); if (index >= 0) return '{$circularReference:'+index+'}' return object.toSource(); } // Objects where toSource is equal to toString [Boolean, Function, Number, RegExp].forEach(function(constructor) { var prototype = constructor.prototype applyToSource(prototype, prototype.toString) }); // Regular objects applyToSource(Date.prototype, function() { return 'new Date('+this.getTime()+')' }) applyToSource(String.prototype, function() { return JSON.stringify(this) }) applyToSource(Math, function() { return 'Math' }) // Recursive objects (Array & Object) applyToSource(Array.prototype, function() { return '[' + fill(this, walk) + ']' }) applyToSource(Object.prototype, function() { var keys = Object.keys(this) function keyValue(key) { var s_key = legalKey(key) ? key : JSON.stringify(key) var value = walk(this[key]) return s_key + ': ' + value } return '{' + fill(keys, keyValue, this) + '}' }) module.exports = function(object, filter, indent) { _filter = filter _indent = getIndent(indent) var result = walk(object) _filter = undefined _indent = DEFAULT_INDENT return result }