"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/jju/lib/stringify.js" (7 Feb 2017, 11039 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * Author: Alex Kocharin <alex@kocharin.ru>
    3  * GIT: https://github.com/rlidwka/jju
    4  * License: WTFPL, grab your copy here: http://www.wtfpl.net/txt/copying/
    5  */
    6 
    7 var Uni = require('./unicode')
    8 
    9 // Fix Function#name on browsers that do not support it (IE)
   10 // http://stackoverflow.com/questions/6903762/function-name-not-supported-in-ie
   11 if (!(function f(){}).name) {
   12   Object.defineProperty((function(){}).constructor.prototype, 'name', {
   13     get: function() {
   14       var name = this.toString().match(/^\s*function\s*(\S*)\s*\(/)[1]
   15       // For better performance only parse once, and then cache the
   16       // result through a new accessor for repeated access.
   17       Object.defineProperty(this, 'name', { value: name })
   18       return name
   19     }
   20   })
   21 }
   22 
   23 var special_chars = {
   24   0: '\\0', // this is not an octal literal
   25   8: '\\b',
   26   9: '\\t',
   27   10: '\\n',
   28   11: '\\v',
   29   12: '\\f',
   30   13: '\\r',
   31   92: '\\\\',
   32 }
   33 
   34 // for oddballs
   35 var hasOwnProperty = Object.prototype.hasOwnProperty
   36 
   37 // some people escape those, so I'd copy this to be safe
   38 var escapable = /[\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/
   39 
   40 function _stringify(object, options, recursiveLvl, currentKey) {
   41   var json5 = (options.mode === 'json5' || !options.mode)
   42   /*
   43    * Opinionated decision warning:
   44    *
   45    * Objects are serialized in the following form:
   46    * { type: 'Class', data: DATA }
   47    *
   48    * Class is supposed to be a function, and new Class(DATA) is
   49    * supposed to be equivalent to the original value
   50    */
   51   /*function custom_type() {
   52     return stringify({
   53       type: object.constructor.name,
   54       data: object.toString()
   55     })
   56   }*/
   57 
   58   // if add, it's an internal indentation, so we add 1 level and a eol
   59   // if !add, it's an ending indentation, so we just indent
   60   function indent(str, add) {
   61     var prefix = options._prefix ? options._prefix : ''
   62     if (!options.indent) return prefix + str
   63     var result = ''
   64     var count = recursiveLvl + (add || 0)
   65     for (var i=0; i<count; i++) result += options.indent
   66     return prefix + result + str + (add ? '\n' : '')
   67   }
   68 
   69   function _stringify_key(key) {
   70     if (options.quote_keys) return _stringify_str(key)
   71     if (String(Number(key)) == key && key[0] != '-') return key
   72     if (key == '') return _stringify_str(key)
   73 
   74     var result = ''
   75     for (var i=0; i<key.length; i++) {
   76       if (i > 0) {
   77         if (!Uni.isIdentifierPart(key[i]))
   78           return _stringify_str(key)
   79 
   80       } else {
   81         if (!Uni.isIdentifierStart(key[i]))
   82           return _stringify_str(key)
   83       }
   84 
   85       var chr = key.charCodeAt(i)
   86 
   87       if (options.ascii) {
   88         if (chr < 0x80) {
   89           result += key[i]
   90 
   91         } else {
   92           result += '\\u' + ('0000' + chr.toString(16)).slice(-4)
   93         }
   94 
   95       } else {
   96         if (escapable.exec(key[i])) {
   97           result += '\\u' + ('0000' + chr.toString(16)).slice(-4)
   98 
   99         } else {
  100           result += key[i]
  101         }
  102       }
  103     }
  104 
  105     return result
  106   }
  107 
  108   function _stringify_str(key) {
  109     var quote = options.quote
  110     var quoteChr = quote.charCodeAt(0)
  111 
  112     var result = ''
  113     for (var i=0; i<key.length; i++) {
  114       var chr = key.charCodeAt(i)
  115 
  116       if (chr < 0x10) {
  117         if (chr === 0 && json5) {
  118           result += '\\0'
  119         } else if (chr >= 8 && chr <= 13 && (json5 || chr !== 11)) {
  120           result += special_chars[chr]
  121         } else if (json5) {
  122           result += '\\x0' + chr.toString(16)
  123         } else {
  124           result += '\\u000' + chr.toString(16)
  125         }
  126 
  127       } else if (chr < 0x20) {
  128         if (json5) {
  129           result += '\\x' + chr.toString(16)
  130         } else {
  131           result += '\\u00' + chr.toString(16)
  132         }
  133 
  134       } else if (chr >= 0x20 && chr < 0x80) {
  135         // ascii range
  136         if (chr === 47 && i && key[i-1] === '<') {
  137           // escaping slashes in </script>
  138           result += '\\' + key[i]
  139 
  140         } else if (chr === 92) {
  141           result += '\\\\'
  142 
  143         } else if (chr === quoteChr) {
  144           result += '\\' + quote
  145 
  146         } else {
  147           result += key[i]
  148         }
  149 
  150       } else if (options.ascii || Uni.isLineTerminator(key[i]) || escapable.exec(key[i])) {
  151         if (chr < 0x100) {
  152           if (json5) {
  153             result += '\\x' + chr.toString(16)
  154           } else {
  155             result += '\\u00' + chr.toString(16)
  156           }
  157 
  158         } else if (chr < 0x1000) {
  159           result += '\\u0' + chr.toString(16)
  160 
  161         } else if (chr < 0x10000) {
  162           result += '\\u' + chr.toString(16)
  163 
  164         } else {
  165           throw Error('weird codepoint')
  166         }
  167       } else {
  168         result += key[i]
  169       }
  170     }
  171     return quote + result + quote
  172   }
  173 
  174   function _stringify_object() {
  175     if (object === null) return 'null'
  176     var result = []
  177       , len = 0
  178       , braces
  179 
  180     if (Array.isArray(object)) {
  181       braces = '[]'
  182       for (var i=0; i<object.length; i++) {
  183         var s = _stringify(object[i], options, recursiveLvl+1, String(i))
  184         if (s === undefined) s = 'null'
  185         len += s.length + 2
  186         result.push(s + ',')
  187       }
  188 
  189     } else {
  190       braces = '{}'
  191       var fn = function(key) {
  192         var t = _stringify(object[key], options, recursiveLvl+1, key)
  193         if (t !== undefined) {
  194           t = _stringify_key(key) + ':' + (options.indent ? ' ' : '') + t + ','
  195           len += t.length + 1
  196           result.push(t)
  197         }
  198       }
  199 
  200       if (Array.isArray(options.replacer)) {
  201         for (var i=0; i<options.replacer.length; i++)
  202           if (hasOwnProperty.call(object, options.replacer[i]))
  203             fn(options.replacer[i])
  204       } else {
  205         var keys = Object.keys(object)
  206         if (options.sort_keys)
  207           keys = keys.sort(typeof(options.sort_keys) === 'function'
  208                            ? options.sort_keys : undefined)
  209         keys.forEach(fn)
  210       }
  211     }
  212 
  213     // objects shorter than 30 characters are always inlined
  214     // objects longer than 60 characters are always splitted to multiple lines
  215     // anything in the middle depends on indentation level
  216     len -= 2
  217     if (options.indent && (len > options._splitMax - recursiveLvl * options.indent.length || len > options._splitMin) ) {
  218       // remove trailing comma in multiline if asked to
  219       if (options.no_trailing_comma && result.length) {
  220         result[result.length-1] = result[result.length-1].substring(0, result[result.length-1].length-1)
  221       }
  222 
  223       var innerStuff = result.map(function(x) {return indent(x, 1)}).join('')
  224       return braces[0]
  225           + (options.indent ? '\n' : '')
  226           + innerStuff
  227           + indent(braces[1])
  228     } else {
  229       // always remove trailing comma in one-lined arrays
  230       if (result.length) {
  231         result[result.length-1] = result[result.length-1].substring(0, result[result.length-1].length-1)
  232       }
  233 
  234       var innerStuff = result.join(options.indent ? ' ' : '')
  235       return braces[0]
  236           + innerStuff
  237           + braces[1]
  238     }
  239   }
  240 
  241   function _stringify_nonobject(object) {
  242     if (typeof(options.replacer) === 'function') {
  243       object = options.replacer.call(null, currentKey, object)
  244     }
  245 
  246     switch(typeof(object)) {
  247       case 'string':
  248         return _stringify_str(object)
  249 
  250       case 'number':
  251         if (object === 0 && 1/object < 0) {
  252           // Opinionated decision warning:
  253           //
  254           // I want cross-platform negative zero in all js engines
  255           // I know they're equal, but why lose that tiny bit of
  256           // information needlessly?
  257           return '-0'
  258         }
  259         if (!json5 && !Number.isFinite(object)) {
  260           // json don't support infinity (= sucks)
  261           return 'null'
  262         }
  263         return object.toString()
  264 
  265       case 'boolean':
  266         return object.toString()
  267 
  268       case 'undefined':
  269         return undefined
  270 
  271       case 'function':
  272 //        return custom_type()
  273 
  274       default:
  275         // fallback for something weird
  276         return JSON.stringify(object)
  277     }
  278   }
  279 
  280   if (options._stringify_key) {
  281     return _stringify_key(object)
  282   }
  283 
  284   if (typeof(object) === 'object') {
  285     if (object === null) return 'null'
  286 
  287     var str
  288     if (typeof(str = object.toJSON5) === 'function' && options.mode !== 'json') {
  289       object = str.call(object, currentKey)
  290 
  291     } else if (typeof(str = object.toJSON) === 'function') {
  292       object = str.call(object, currentKey)
  293     }
  294 
  295     if (object === null) return 'null'
  296     if (typeof(object) !== 'object') return _stringify_nonobject(object)
  297 
  298     if (object.constructor === Number || object.constructor === Boolean || object.constructor === String) {
  299       object = object.valueOf()
  300       return _stringify_nonobject(object)
  301 
  302     } else if (object.constructor === Date) {
  303       // only until we can't do better
  304       return _stringify_nonobject(object.toISOString())
  305 
  306     } else {
  307       if (typeof(options.replacer) === 'function') {
  308         object = options.replacer.call(null, currentKey, object)
  309         if (typeof(object) !== 'object') return _stringify_nonobject(object)
  310       }
  311 
  312       return _stringify_object(object)
  313     }
  314   } else {
  315     return _stringify_nonobject(object)
  316   }
  317 }
  318 
  319 /*
  320  * stringify(value, options)
  321  * or
  322  * stringify(value, replacer, space)
  323  *
  324  * where:
  325  * value - anything
  326  * options - object
  327  * replacer - function or array
  328  * space - boolean or number or string
  329  */
  330 module.exports.stringify = function stringifyJSON(object, options, _space) {
  331   // support legacy syntax
  332   if (typeof(options) === 'function' || Array.isArray(options)) {
  333     options = {
  334       replacer: options
  335     }
  336   } else if (typeof(options) === 'object' && options !== null) {
  337     // nothing to do
  338   } else {
  339     options = {}
  340   }
  341   if (_space != null) options.indent = _space
  342 
  343   if (options.indent == null) options.indent = '\t'
  344   if (options.quote == null) options.quote = "'"
  345   if (options.ascii == null) options.ascii = false
  346   if (options.mode == null) options.mode = 'json5'
  347 
  348   if (options.mode === 'json' || options.mode === 'cjson') {
  349     // json only supports double quotes (= sucks)
  350     options.quote = '"'
  351 
  352     // json don't support trailing commas (= sucks)
  353     options.no_trailing_comma = true
  354 
  355     // json don't support unquoted property names (= sucks)
  356     options.quote_keys = true
  357   }
  358 
  359   // why would anyone use such objects?
  360   if (typeof(options.indent) === 'object') {
  361     if (options.indent.constructor === Number
  362     ||  options.indent.constructor === Boolean
  363     ||  options.indent.constructor === String)
  364       options.indent = options.indent.valueOf()
  365   }
  366 
  367   // gap is capped at 10 characters
  368   if (typeof(options.indent) === 'number') {
  369     if (options.indent >= 0) {
  370       options.indent = Array(Math.min(~~options.indent, 10) + 1).join(' ')
  371     } else {
  372       options.indent = false
  373     }
  374   } else if (typeof(options.indent) === 'string') {
  375     options.indent = options.indent.substr(0, 10)
  376   }
  377 
  378   if (options._splitMin == null) options._splitMin = 50
  379   if (options._splitMax == null) options._splitMax = 70
  380 
  381   return _stringify(object, options, 0, '')
  382 }
  383