[ Index ]

PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008]

title

Body

[close]

/lib/yui/json/ -> json-debug.js (source)

   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: 2.6.0
   6  */
   7  /**
   8   * Provides methods to parse JSON strings and convert objects to JSON strings.
   9   * @module json
  10   * @class JSON
  11   * @static
  12   */
  13  YAHOO.lang.JSON = (function () {
  14  
  15  var l = YAHOO.lang,
  16  
  17      /**
  18       * Replace certain Unicode characters that JavaScript may handle incorrectly
  19       * during eval--either by deleting them or treating them as line
  20       * endings--with escape sequences.
  21       * IMPORTANT NOTE: This regex will be used to modify the input if a match is
  22       * found.
  23       * @property _UNICODE_EXCEPTIONS
  24       * @type {RegExp}
  25       * @private
  26       */
  27      _UNICODE_EXCEPTIONS = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  28  
  29      /**
  30       * First step in the validation.  Regex used to replace all escape
  31       * sequences (i.e. "\\", etc) with '@' characters (a non-JSON character).
  32       * @property _ESCAPES
  33       * @type {RegExp}
  34       * @static
  35       * @private
  36       */
  37      _ESCAPES = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
  38  
  39      /**
  40       * Second step in the validation.  Regex used to replace all simple
  41       * values with ']' characters.
  42       * @property _VALUES
  43       * @type {RegExp}
  44       * @static
  45       * @private
  46       */
  47      _VALUES  = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
  48  
  49      /**
  50       * Third step in the validation.  Regex used to remove all open square
  51       * brackets following a colon, comma, or at the beginning of the string.
  52       * @property _BRACKETS
  53       * @type {RegExp}
  54       * @static
  55       * @private
  56       */
  57      _BRACKETS = /(?:^|:|,)(?:\s*\[)+/g,
  58  
  59      /**
  60       * Final step in the validation.  Regex used to test the string left after
  61       * all previous replacements for invalid characters.
  62       * @property _INVALID
  63       * @type {RegExp}
  64       * @static
  65       * @private
  66       */
  67      _INVALID  = /^[\],:{}\s]*$/,
  68  
  69      /**
  70       * Regex used to replace special characters in strings for JSON
  71       * stringification.
  72       * @property _SPECIAL_CHARS
  73       * @type {RegExp}
  74       * @static
  75       * @private
  76       */
  77      _SPECIAL_CHARS = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  78  
  79      /**
  80       * Character substitution map for common escapes and special characters.
  81       * @property _CHARS
  82       * @type {Object}
  83       * @static
  84       * @private
  85       */
  86      _CHARS = {
  87          '\b': '\\b',
  88          '\t': '\\t',
  89          '\n': '\\n',
  90          '\f': '\\f',
  91          '\r': '\\r',
  92          '"' : '\\"',
  93          '\\': '\\\\'
  94      };
  95  
  96  /**
  97   * Traverses nested objects, applying a filter or reviver function to
  98   * each value.  The value returned from the function will replace the
  99   * original value in the key:value pair.  If the value returned is
 100   * undefined, the key will be omitted from the returned object.
 101   * @method _revive
 102   * @param data {MIXED} Any JavaScript data
 103   * @param reviver {Function} filter or mutation function
 104   * @return {MIXED} The results of the filtered/mutated data structure
 105   * @private
 106   */
 107  function _revive(data, reviver) {
 108      var walk = function (o,key) {
 109          var k,v,value = o[key];
 110          if (value && typeof value === 'object') {
 111              for (k in value) {
 112                  if (l.hasOwnProperty(value,k)) {
 113                      v = walk(value, k);
 114                      if (v === undefined) {
 115                          delete value[k];
 116                      } else {
 117                          value[k] = v;
 118                      }
 119                  }
 120              }
 121          }
 122          return reviver.call(o,key,value);
 123      };
 124  
 125      return typeof reviver === 'function' ? walk({'':data},'') : data;
 126  }
 127  
 128  /**
 129   * Escapes a special character to a safe Unicode representation
 130   * @method _char
 131   * @param c {String} single character to escape
 132   * @return {String} safe Unicode escape
 133   */
 134  function _char(c) {
 135      if (!_CHARS[c]) {
 136          _CHARS[c] =  '\\u'+('0000'+(+(c.charCodeAt(0))).toString(16)).slice(-4);
 137      }
 138      return _CHARS[c];
 139  }
 140  
 141  /**
 142   * Replace certain Unicode characters that may be handled incorrectly by
 143   * some browser implementations.
 144   * @method _prepare
 145   * @param s {String} parse input
 146   * @return {String} sanitized JSON string ready to be validated/parsed
 147   * @private
 148   */
 149  function _prepare(s) {
 150      return s.replace(_UNICODE_EXCEPTIONS, _char);
 151  }
 152  
 153  /**
 154   * Four step determination whether a string is valid JSON.  In three steps,
 155   * escape sequences, safe values, and properly placed open square brackets
 156   * are replaced with placeholders or removed.  Then in the final step, the
 157   * result of all these replacements is checked for invalid characters.
 158   * @method _isValid
 159   * @param str {String} JSON string to be tested
 160   * @return {boolean} is the string safe for eval?
 161   * @static
 162   */
 163  function _isValid(str) {
 164      return l.isString(str) &&
 165              _INVALID.test(str.
 166              replace(_ESCAPES,'@').
 167              replace(_VALUES,']').
 168              replace(_BRACKETS,''));
 169  }
 170  
 171  /**
 172   * Enclose escaped strings in quotes
 173   * @method _string
 174   * @param s {String} string to wrap
 175   * @return {String} '"'+s+'"' after s has had special characters escaped
 176   * @private
 177   */
 178  function _string(s) {
 179      return '"' + s.replace(_SPECIAL_CHARS, _char) + '"';
 180  }
 181  
 182  /**
 183   * Worker function used by public stringify.
 184   * @method _stringify
 185   * @param h {Object} object holding the key
 186   * @param key {String} String key in object h to serialize
 187   * @param depth {Number} depth to serialize
 188   * @param w {Array|Function} array of whitelisted keys OR replacer function
 189   * @param pstack {Array} used to protect against recursion
 190   * @return {String} serialized version of o
 191   */
 192  function _stringify(h,key,d,w,pstack) {
 193      var o = typeof w === 'function' ? w.call(h,key,h[key]) : h[key],
 194          i,len,j, // array iteration
 195          k,v,     // object iteration
 196          isArray, // forking in typeof 'object'
 197          a;       // composition array for performance over string concat
 198  
 199      if (o instanceof Date) {
 200          o = l.JSON.dateToString(o);
 201      } else if (o instanceof String || o instanceof Boolean || o instanceof Number) {
 202          o = o.valueOf();
 203      }
 204  
 205      switch (typeof o) {
 206          case 'string' : return _string(o);
 207          case 'number' : return isFinite(o) ? String(o) : 'null';
 208          case 'boolean': return String(o);
 209          case 'object' :
 210              // null
 211              if (o === null) {
 212                  return 'null';
 213              }
 214  
 215              // Check for cyclical references
 216              for (i = pstack.length - 1; i >= 0; --i) {
 217                  if (pstack[i] === o) {
 218                      return 'null';
 219                  }
 220              }
 221  
 222              // Add the object to the processing stack
 223              pstack[pstack.length] = o;
 224  
 225              a = [];
 226              isArray = l.isArray(o);
 227  
 228              // Only recurse if we're above depth config
 229              if (d > 0) {
 230                  // Array
 231                  if (isArray) {
 232                      for (i = o.length - 1; i >= 0; --i) {
 233                          a[i] = _stringify(o,i,d-1,w,pstack) || 'null';
 234                      }
 235  
 236                  // Object
 237                  } else {
 238                      j = 0;
 239                      // Use whitelist keys if provided as an array
 240                      if (l.isArray(w)) {
 241                          for (i = 0, len = w.length; i < len; ++i) {
 242                              k = w[i];
 243                              v = _stringify(o,k,d-1,w,pstack);
 244                              if (v) {
 245                                  a[j++] = _string(k) + ':' + v;
 246                              }
 247                          }
 248                      } else {
 249                          for (k in o) {
 250                              if (typeof k === 'string' && l.hasOwnProperty(o,k)) {
 251                                  v = _stringify(o,k,d-1,w,pstack);
 252                                  if (v) {
 253                                      a[j++] = _string(k) + ':' + v;
 254                                  }
 255                              }
 256                          }
 257                      }
 258  
 259                      // sort object keys for easier readability
 260                      a.sort();
 261                  }
 262              }
 263  
 264              // remove the object from the stack
 265              pstack.pop();
 266  
 267              return isArray ? '['+a.join(',')+']' : '{'+a.join(',')+'}';
 268      }
 269  
 270      return undefined; // invalid input
 271  }
 272  
 273  // Return the public API
 274  return {
 275      /**
 276       * Four step determination whether a string is valid JSON.  In three steps,
 277       * escape sequences, safe values, and properly placed open square brackets
 278       * are replaced with placeholders or removed.  Then in the final step, the
 279       * result of all these replacements is checked for invalid characters.
 280       * @method isValid
 281       * @param str {String} JSON string to be tested
 282       * @return {boolean} is the string safe for eval?
 283       * @static
 284       */
 285      isValid : function (s) {
 286          return _isValid(_prepare(s));
 287      },
 288  
 289      /**
 290       * Parse a JSON string, returning the native JavaScript representation.
 291       * Only minor modifications from http://www.json.org/json2.js.
 292       * @param s {string} JSON string data
 293       * @param reviver {function} (optional) function(k,v) passed each key:value
 294       *          pair of object literals, allowing pruning or altering values
 295       * @return {MIXED} the native JavaScript representation of the JSON string
 296       * @throws SyntaxError
 297       * @method parse
 298       * @static
 299       */
 300      parse : function (s,reviver) {
 301          // sanitize
 302          s = _prepare(s);
 303  
 304          // Ensure valid JSON
 305          if (_isValid(s)) {
 306              // Eval the text into a JavaScript data structure, apply the
 307              // reviver function if provided, and return
 308              return _revive( eval('(' + s + ')'), reviver );
 309          }
 310  
 311          // The text is not valid JSON
 312          throw new SyntaxError('parseJSON');
 313      },
 314  
 315      /**
 316       * Converts an arbitrary value to a JSON string representation.
 317       * Cyclical object or array references are replaced with null.
 318       * If a whitelist is provided, only matching object keys will be included.
 319       * If a depth limit is provided, objects and arrays at that depth will
 320       * be stringified as empty.
 321       * @method stringify
 322       * @param o {MIXED} any arbitrary object to convert to JSON string
 323       * @param w {Array|Function} (optional) whitelist of acceptable object keys to include OR a function(value,key) to alter values before serialization
 324       * @param d {number} (optional) depth limit to recurse objects/arrays (practical minimum 1)
 325       * @return {string} JSON string representation of the input
 326       * @static
 327       */
 328      stringify : function (o,w,d) {
 329          if (o !== undefined) {
 330              // Ensure whitelist keys are unique (bug 2110391)
 331              if (l.isArray(w)) {
 332                  w = (function (a) {
 333                      var uniq=[],map={},v,i,j,len;
 334                      for (i=0,j=0,len=a.length; i<len; ++i) {
 335                          v = a[i];
 336                          if (typeof v === 'string' && map[v] === undefined) {
 337                              uniq[(map[v] = j++)] = v;
 338                          }
 339                      }
 340                      return uniq;
 341                  })(w);
 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,w,[]);
 349          }
 350  
 351          return undefined;
 352      },
 353  
 354      /**
 355       * Serializes a Date instance as a UTC date string.  Used internally by
 356       * stringify.  Override this method if you need Dates serialized in a
 357       * different format.
 358       * @method dateToString
 359       * @param d {Date} The Date to serialize
 360       * @return {String} stringified Date in UTC format YYYY-MM-DDTHH:mm:SSZ
 361       * @static
 362       */
 363      dateToString : function (d) {
 364          function _zeroPad(v) {
 365              return v < 10 ? '0' + v : v;
 366          }
 367  
 368          return d.getUTCFullYear()         + '-' +
 369              _zeroPad(d.getUTCMonth() + 1) + '-' +
 370              _zeroPad(d.getUTCDate())      + 'T' +
 371              _zeroPad(d.getUTCHours())     + ':' +
 372              _zeroPad(d.getUTCMinutes())   + ':' +
 373              _zeroPad(d.getUTCSeconds())   + 'Z';
 374      },
 375  
 376      /**
 377       * Reconstitute Date instances from the default JSON UTC serialization.
 378       * Reference this from a reviver function to rebuild Dates during the
 379       * parse operation.
 380       * @method stringToDate
 381       * @param str {String} String serialization of a Date
 382       * @return {Date}
 383       */
 384      stringToDate : function (str) {
 385          if (/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$/.test(str)) {
 386              var d = new Date();
 387              d.setUTCFullYear(RegExp.$1, (RegExp.$2|0)-1, RegExp.$3);
 388              d.setUTCHours(RegExp.$4, RegExp.$5, RegExp.$6);
 389              return d;
 390          }
 391          return str;
 392      }
 393  };
 394  
 395  })();
 396  YAHOO.register("json", YAHOO.lang.JSON, {version: "2.6.0", build: "1321"});


Generated: Wed Jan 14 11:33:29 2009 Cross-referenced by PHPXref 0.7