]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/node_modules/read-package-json/node_modules/json-parse-helpfulerror/node_modules/jju/lib/stringify.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / node_modules / read-package-json / node_modules / json-parse-helpfulerror / node_modules / jju / lib / stringify.js
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