Initial commit
[yaffs-website] / node_modules / jsonify / lib / stringify.js
1 var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
2     escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
3     gap,
4     indent,
5     meta = {    // table of character substitutions
6         '\b': '\\b',
7         '\t': '\\t',
8         '\n': '\\n',
9         '\f': '\\f',
10         '\r': '\\r',
11         '"' : '\\"',
12         '\\': '\\\\'
13     },
14     rep;
15
16 function quote(string) {
17     // If the string contains no control characters, no quote characters, and no
18     // backslash characters, then we can safely slap some quotes around it.
19     // Otherwise we must also replace the offending characters with safe escape
20     // sequences.
21     
22     escapable.lastIndex = 0;
23     return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
24         var c = meta[a];
25         return typeof c === 'string' ? c :
26             '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
27     }) + '"' : '"' + string + '"';
28 }
29
30 function str(key, holder) {
31     // Produce a string from holder[key].
32     var i,          // The loop counter.
33         k,          // The member key.
34         v,          // The member value.
35         length,
36         mind = gap,
37         partial,
38         value = holder[key];
39     
40     // If the value has a toJSON method, call it to obtain a replacement value.
41     if (value && typeof value === 'object' &&
42             typeof value.toJSON === 'function') {
43         value = value.toJSON(key);
44     }
45     
46     // If we were called with a replacer function, then call the replacer to
47     // obtain a replacement value.
48     if (typeof rep === 'function') {
49         value = rep.call(holder, key, value);
50     }
51     
52     // What happens next depends on the value's type.
53     switch (typeof value) {
54         case 'string':
55             return quote(value);
56         
57         case 'number':
58             // JSON numbers must be finite. Encode non-finite numbers as null.
59             return isFinite(value) ? String(value) : 'null';
60         
61         case 'boolean':
62         case 'null':
63             // If the value is a boolean or null, convert it to a string. Note:
64             // typeof null does not produce 'null'. The case is included here in
65             // the remote chance that this gets fixed someday.
66             return String(value);
67             
68         case 'object':
69             if (!value) return 'null';
70             gap += indent;
71             partial = [];
72             
73             // Array.isArray
74             if (Object.prototype.toString.apply(value) === '[object Array]') {
75                 length = value.length;
76                 for (i = 0; i < length; i += 1) {
77                     partial[i] = str(i, value) || 'null';
78                 }
79                 
80                 // Join all of the elements together, separated with commas, and
81                 // wrap them in brackets.
82                 v = partial.length === 0 ? '[]' : gap ?
83                     '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
84                     '[' + partial.join(',') + ']';
85                 gap = mind;
86                 return v;
87             }
88             
89             // If the replacer is an array, use it to select the members to be
90             // stringified.
91             if (rep && typeof rep === 'object') {
92                 length = rep.length;
93                 for (i = 0; i < length; i += 1) {
94                     k = rep[i];
95                     if (typeof k === 'string') {
96                         v = str(k, value);
97                         if (v) {
98                             partial.push(quote(k) + (gap ? ': ' : ':') + v);
99                         }
100                     }
101                 }
102             }
103             else {
104                 // Otherwise, iterate through all of the keys in the object.
105                 for (k in value) {
106                     if (Object.prototype.hasOwnProperty.call(value, k)) {
107                         v = str(k, value);
108                         if (v) {
109                             partial.push(quote(k) + (gap ? ': ' : ':') + v);
110                         }
111                     }
112                 }
113             }
114             
115         // Join all of the member texts together, separated with commas,
116         // and wrap them in braces.
117
118         v = partial.length === 0 ? '{}' : gap ?
119             '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
120             '{' + partial.join(',') + '}';
121         gap = mind;
122         return v;
123     }
124 }
125
126 module.exports = function (value, replacer, space) {
127     var i;
128     gap = '';
129     indent = '';
130     
131     // If the space parameter is a number, make an indent string containing that
132     // many spaces.
133     if (typeof space === 'number') {
134         for (i = 0; i < space; i += 1) {
135             indent += ' ';
136         }
137     }
138     // If the space parameter is a string, it will be used as the indent string.
139     else if (typeof space === 'string') {
140         indent = space;
141     }
142
143     // If there is a replacer, it must be a function or an array.
144     // Otherwise, throw an error.
145     rep = replacer;
146     if (replacer && typeof replacer !== 'function'
147     && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) {
148         throw new Error('JSON.stringify');
149     }
150     
151     // Make a fake root object containing our value under the key of ''.
152     // Return the result of stringifying the value.
153     return str('', {'': value});
154 };