~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/static/javascript/yui/build/json/json.js

  • Committer: Martin Albisetti
  • Date: 2008-10-22 11:05:23 UTC
  • mfrom: (230 trunk)
  • mto: This revision was merged to the branch mainline in revision 233.
  • Revision ID: martin.albisetti@canonical.com-20081022110523-sb3mjicez8ktsc3x
MergeĀ fromĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
 
3
Code licensed under the BSD License:
 
4
http://developer.yahoo.net/yui/license.txt
 
5
version: 3.0.0pr1
 
6
*/
 
7
YUI.add('json-parse', function(Y) {
 
8
 
 
9
/**
 
10
 * The JSON Utility provides methods to serialize JavaScript objects into
 
11
 * JSON strings and parse JavaScript objects from strings containing JSON data.
 
12
 * Three modules are available for inclusion:
 
13
 * <ol>
 
14
 * <li>1. <code>json-parse</code> for parsing JSON strings into native JavaScript data</li>
 
15
 * <li>2. <code>json-stringify</code> for stringification of JavaScript objects into JSON strings</li>
 
16
 * <li>3. <code>json</code> for both parsing and stringification</li>
 
17
 * </ol>
 
18
 * 
 
19
 * Both <code>json-parse</code> and <code>json-stringify</code> create functions in a static JSON class under your YUI instance (e.g. Y.JSON.parse(..)).
 
20
 * @module json
 
21
 * @class JSON
 
22
 * @static
 
23
 */
 
24
 
 
25
/**
 
26
 * Provides Y.JSON.parse method to take JSON strings and return native
 
27
 * JavaScript objects.
 
28
 * @module json
 
29
 * @submodule json-parse
 
30
 * @for JSON
 
31
 * @static
 
32
 */
 
33
Y.JSON = Y.JSON || {};
 
34
 
 
35
// All internals kept private for security reasons
 
36
 
 
37
/**
 
38
 * Replace certain Unicode characters that JavaScript may handle incorrectly
 
39
 * during eval--either by deleting them or treating them as line endings--with
 
40
 * escae sequences.
 
41
 * IMPORTANT NOTE: This regex will be used to modify the input if a match is
 
42
 * found.
 
43
 * @property _UNICODE_EXCEPTIONS
 
44
 * @type {RegExp}
 
45
 * @private
 
46
 */
 
47
var _UNICODE_EXCEPTIONS = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
 
48
 
 
49
 
 
50
/**
 
51
 * First step in the validation.  Regex used to replace all escape
 
52
 * sequences (i.e. "\\", etc) with '@' characters (a non-JSON character).
 
53
 * @property _ESCAPES
 
54
 * @type {RegExp}
 
55
 * @private
 
56
 */
 
57
    _ESCAPES = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
 
58
 
 
59
/**
 
60
 * Second step in the validation.  Regex used to replace all simple
 
61
 * values with ']' characters.
 
62
 * @property _VALUES
 
63
 * @type {RegExp}
 
64
 * @private
 
65
 */
 
66
    _VALUES  = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
 
67
 
 
68
/**
 
69
 * Third step in the validation.  Regex used to remove all open square
 
70
 * brackets following a colon, comma, or at the beginning of the string.
 
71
 * @property _BRACKETS
 
72
 * @type {RegExp}
 
73
 * @private
 
74
 */
 
75
 
 
76
    _BRACKETS = /(?:^|:|,)(?:\s*\[)+/g,
 
77
 
 
78
/**
 
79
 * Final step in the validation.  Regex used to test the string left after
 
80
 * all previous replacements for invalid characters.
 
81
 * @property _INVALID
 
82
 * @type {RegExp}
 
83
 * @private
 
84
 */
 
85
    _INVALID  = /^[\],:{}\s]*$/,
 
86
 
 
87
    has = Object.prototype.hasOwnProperty,
 
88
/**
 
89
 * Traverses nested objects, applying a reviver function to each (key,value)
 
90
 * from the scope if the key:value's containing object.  The value returned
 
91
 * from the function will replace the original value in the key:value pair.
 
92
 * If the value returned is undefined, the key will be omitted from the
 
93
 * returned object.
 
94
 * @method _revive
 
95
 * @param data {MIXED} Any JavaScript data
 
96
 * @param reviver {Function} filter or mutation function
 
97
 * @return {MIXED} The results of the filtered data
 
98
 * @private
 
99
 */
 
100
    _revive = function (data, reviver) {
 
101
        var walk = function (o,key) {
 
102
            var k,v,value = o[key];
 
103
            if (value && typeof value === 'object') {
 
104
                for (k in value) {
 
105
                    if (has.call(value,k)) {
 
106
                        v = walk(value, k);
 
107
                        if (v === undefined) {
 
108
                            delete value[k];
 
109
                        } else {
 
110
                            value[k] = v;
 
111
                        }
 
112
                    }
 
113
                }
 
114
            }
 
115
            return reviver.call(o,key,value);
 
116
        };
 
117
 
 
118
        return typeof reviver === 'function' ? walk({'':data},'') : data;
 
119
    };
 
120
 
 
121
/**
 
122
 * Parse a JSON string, returning the native JavaScript representation.
 
123
 * @param s {string} JSON string data
 
124
 * @param reviver {function} (optional) function(k,v) passed each key value pair of object literals, allowing pruning or altering values
 
125
 * @return {MIXED} the native JavaScript representation of the JSON string
 
126
 * @throws SyntaxError
 
127
 * @method parse
 
128
 * @static
 
129
 * @public
 
130
 */
 
131
Y.JSON.parse = function (s,reviver) {
 
132
    // Ensure valid JSON
 
133
    if (typeof s === 'string') {
 
134
        // Replace certain Unicode characters that are otherwise handled
 
135
        // incorrectly by some browser implementations.
 
136
        // NOTE: This modifies the input if such characters are found!
 
137
        s = s.replace(_UNICODE_EXCEPTIONS, function (c) {
 
138
            return '\\u'+('0000'+(+(c.charCodeAt(0))).toString(16)).slice(-4);
 
139
        });
 
140
        
 
141
        // Test for validity
 
142
        if (_INVALID.test(s.replace(_ESCAPES,'@').
 
143
                            replace(_VALUES,']').
 
144
                            replace(_BRACKETS,''))) {
 
145
 
 
146
            // Eval the text into a JavaScript data structure, apply any
 
147
            // reviver function, and return
 
148
            return _revive( eval('(' + s + ')'), reviver );
 
149
        }
 
150
    }
 
151
 
 
152
    // The text is not JSON parsable
 
153
    throw new SyntaxError('parseJSON');
 
154
};
 
155
 
 
156
 
 
157
}, '3.0.0pr1' );
 
158
YUI.add('json-stringify', function(Y) {
 
159
 
 
160
/**
 
161
 * Provides Y.JSON.stringify method for converting objects to JSON strings.
 
162
 * @module json
 
163
 * @submodule json-stringify
 
164
 * @for JSON
 
165
 * @static
 
166
 */
 
167
var isA = Y.Lang.isArray;
 
168
 
 
169
Y.JSON = Y.JSON || {};
 
170
 
 
171
Y.mix(Y.JSON,{
 
172
    /**
 
173
     * Regex used to capture characters that need escaping before enclosing
 
174
     * their containing string in quotes.
 
175
     * @property _SPECIAL_CHARS
 
176
     * @type {RegExp}
 
177
     * @private
 
178
     */
 
179
    _SPECIAL_CHARS : /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
 
180
 
 
181
    /**
 
182
     * Character substitution map for common escapes and special characters.
 
183
     * @property _CHARS
 
184
     * @type {Object}
 
185
     * @static
 
186
     * @private
 
187
     */
 
188
    _CHARS : {
 
189
        '\b': '\\b',
 
190
        '\t': '\\t',
 
191
        '\n': '\\n',
 
192
        '\f': '\\f',
 
193
        '\r': '\\r',
 
194
        '"' : '\\"',
 
195
        '\\': '\\\\'
 
196
    },
 
197
 
 
198
    /**
 
199
     * Serializes a Date instance as a UTC date string.  Used internally by
 
200
     * stringify.  Override this method if you need Dates serialized in a
 
201
     * different format.
 
202
     * @method dateToString
 
203
     * @param d {Date} The Date to serialize
 
204
     * @return {String} stringified Date in UTC format YYYY-MM-DDTHH:mm:SSZ
 
205
     * @static
 
206
     */
 
207
    dateToString : function (d) {
 
208
        function _zeroPad(v) {
 
209
            return v < 10 ? '0' + v : v;
 
210
        }
 
211
 
 
212
        return '"' + d.getUTCFullYear()   + '-' +
 
213
            _zeroPad(d.getUTCMonth() + 1) + '-' +
 
214
            _zeroPad(d.getUTCDate())      + 'T' +
 
215
            _zeroPad(d.getUTCHours())     + ':' +
 
216
            _zeroPad(d.getUTCMinutes())   + ':' +
 
217
            _zeroPad(d.getUTCSeconds())   + 'Z"';
 
218
    },
 
219
 
 
220
    /**
 
221
     * Converts an arbitrary value to a JSON string representation.
 
222
     * Cyclical object or array references are replaced with null.
 
223
     * If a whitelist is provided, only matching object keys will be included.
 
224
     * If a depth limit is provided, objects and arrays at that depth will
 
225
     * be stringified as empty.
 
226
     * @method stringify
 
227
     * @param o {MIXED} any arbitrary object to convert to JSON string
 
228
     * @param w {Array|Function} (optional) whitelist of acceptable object
 
229
     *                  keys to include, or a replacer function to modify the
 
230
     *                  raw value before serialization
 
231
     * @param d {number} (optional) depth limit to recurse objects/arrays
 
232
     *                   (practical minimum 1)
 
233
     * @return {string} JSON string representation of the input
 
234
     * @static
 
235
     * @public
 
236
     */
 
237
    stringify : function (o,w,d) {
 
238
 
 
239
        var m      = Y.JSON._CHARS,
 
240
            str_re = Y.JSON._SPECIAL_CHARS,
 
241
            rep    = typeof w === 'function' ? w : null,
 
242
            pstack = []; // Processing stack used for cyclical ref protection
 
243
 
 
244
        if (rep || typeof w !== 'object') {
 
245
            w = undefined;
 
246
        }
 
247
 
 
248
        // escape encode special characters
 
249
        var _char = function (c) {
 
250
            if (!m[c]) {
 
251
                m[c]='\\u'+('0000'+(+(c.charCodeAt(0))).toString(16)).slice(-4);
 
252
            }
 
253
            return m[c];
 
254
        };
 
255
 
 
256
        // Enclose the escaped string in double quotes
 
257
        var _string = function (s) {
 
258
            return '"' + s.replace(str_re, _char) + '"';
 
259
        };
 
260
 
 
261
        // Use the configured date conversion
 
262
        var _date = Y.JSON.dateToString;
 
263
    
 
264
        // Worker function.  Fork behavior on data type and recurse objects and
 
265
        // arrays per the configured depth.
 
266
        var _stringify = function (h,key,d) {
 
267
            var o = typeof rep === 'function' ? rep.call(h,key,h[key]) : h[key],
 
268
                t = typeof o,
 
269
                i,len,j, // array iteration
 
270
                k,v,     // object iteration
 
271
                a;       // composition array for performance over string concat
 
272
 
 
273
            // String
 
274
            if (t === 'string') {
 
275
                return _string(o);
 
276
            }
 
277
 
 
278
            // native boolean and Boolean instance
 
279
            if (t === 'boolean' || o instanceof Boolean) {
 
280
                return String(o);
 
281
            }
 
282
 
 
283
            // native number and Number instance
 
284
            if (t === 'number' || o instanceof Number) {
 
285
                return isFinite(o) ? String(o) : 'null';
 
286
            }
 
287
 
 
288
            // Date
 
289
            if (o instanceof Date) {
 
290
                return _date(o);
 
291
            }
 
292
 
 
293
            // Object types
 
294
            if (t === 'object') {
 
295
                if (!o) {
 
296
                    return 'null';
 
297
                }
 
298
 
 
299
                // Check for cyclical references
 
300
                for (i = pstack.length - 1; i >= 0; --i) {
 
301
                    if (pstack[i] === o) {
 
302
                        return 'null';
 
303
                    }
 
304
                }
 
305
 
 
306
                // Add the object to the processing stack
 
307
                pstack[pstack.length] = o;
 
308
 
 
309
                a = [];
 
310
 
 
311
                // Only recurse if we're above depth config
 
312
                if (d > 0) {
 
313
                    // Array
 
314
                    if (isA(o)) {
 
315
                        for (i = o.length - 1; i >= 0; --i) {
 
316
                            a[i] = _stringify(o,i,d-1) || 'null';
 
317
                        }
 
318
 
 
319
                    // Object
 
320
                    } else {
 
321
                        // If whitelist provided, take only those keys
 
322
                        k = isA(w) ? w : Y.Object.keys(w||o);
 
323
 
 
324
                        for (i = 0, j = 0, len = k.length; i < len; ++i) {
 
325
                            if (typeof k[i] === 'string') {
 
326
                                v = _stringify(o,k[i],d-1);
 
327
                                if (v) {
 
328
                                    a[j++] = _string(k[i]) + ':' + v;
 
329
                                }
 
330
                            }
 
331
                        }
 
332
                    }
 
333
                }
 
334
 
 
335
                // remove the array from the stack
 
336
                pstack.pop();
 
337
 
 
338
                return isA(o) ? '['+a.join(',')+']' : '{'+a.join(',')+'}';
 
339
            }
 
340
 
 
341
            return undefined; // invalid input
 
342
        };
 
343
 
 
344
        // Default depth to POSITIVE_INFINITY
 
345
        d = d >= 0 ? d : 1/0;
 
346
 
 
347
        // process the input
 
348
        return _stringify({'':o},'',d);
 
349
    }
 
350
});
 
351
 
 
352
 
 
353
}, '3.0.0pr1' );
 
354
 
 
355
 
 
356
YUI.add('json', function(Y){}, '3.0.0pr1' ,{use:['json-parse', 'json-stringify']});
 
357