json.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. define("dojo/json", ["./has"], function(has){
  2. "use strict";
  3. var hasJSON = typeof JSON != "undefined";
  4. has.add("json-parse", hasJSON); // all the parsers work fine
  5. // Firefox 3.5/Gecko 1.9 fails to use replacer in stringify properly https://bugzilla.mozilla.org/show_bug.cgi?id=509184
  6. has.add("json-stringify", hasJSON && JSON.stringify({a:0}, function(k,v){return v||1;}) == '{"a":1}');
  7. if(has("json-stringify")){
  8. return JSON;
  9. }
  10. else{
  11. var escapeString = function(/*String*/str){
  12. //summary:
  13. // Adds escape sequences for non-visual characters, double quote and
  14. // backslash and surrounds with double quotes to form a valid string
  15. // literal.
  16. return ('"' + str.replace(/(["\\])/g, '\\$1') + '"').
  17. replace(/[\f]/g, "\\f").replace(/[\b]/g, "\\b").replace(/[\n]/g, "\\n").
  18. replace(/[\t]/g, "\\t").replace(/[\r]/g, "\\r"); // string
  19. };
  20. return {
  21. parse: has("json-parse") ? JSON.parse : function(str, strict){
  22. // summary:
  23. // Parses a [JSON](http://json.org) string to return a JavaScript object.
  24. // description:
  25. // This function follows [native JSON API](https://developer.mozilla.org/en/JSON)
  26. // Throws for invalid JSON strings. This delegates to eval() if native JSON
  27. // support is not available. By default this will evaluate any valid JS expression.
  28. // With the strict parameter set to true, the parser will ensure that only
  29. // valid JSON strings are parsed (otherwise throwing an error). Without the strict
  30. // parameter, the content passed to this method must come
  31. // from a trusted source.
  32. // str:
  33. // a string literal of a JSON item, for instance:
  34. // `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
  35. // strict:
  36. // When set to true, this will ensure that only valid, secure JSON is ever parsed.
  37. // Make sure this is set to true for untrusted content. Note that on browsers/engines
  38. // without native JSON support, setting this to true will run slower.
  39. if(strict && !/^([\s\[\{]*(?:"(?:\\.|[^"])+"|-?\d[\d\.]*(?:[Ee][+-]?\d+)?|null|true|false|)[\s\]\}]*(?:,|:|$))+$/.test(str)){
  40. throw new SyntaxError("Invalid characters in JSON");
  41. }
  42. return eval('(' + str + ')');
  43. },
  44. stringify: function(value, replacer, spacer){
  45. // summary:
  46. // Returns a [JSON](http://json.org) serialization of an object.
  47. // description:
  48. // Returns a [JSON](http://json.org) serialization of an object.
  49. // This function follows [native JSON API](https://developer.mozilla.org/en/JSON)
  50. // Note that this doesn't check for infinite recursion, so don't do that!
  51. // value:
  52. // A value to be serialized.
  53. // replacer:
  54. // A replacer function that is called for each value and can return a replacement
  55. // spacer:
  56. // A spacer string to be used for pretty printing of JSON
  57. //
  58. // example:
  59. // simple serialization of a trivial object
  60. // | define(["dojo/json"], function(JSON){
  61. // | var jsonStr = JSON.stringify({ howdy: "stranger!", isStrange: true });
  62. // | doh.is('{"howdy":"stranger!","isStrange":true}', jsonStr);
  63. var undef;
  64. if(typeof replacer == "string"){
  65. spacer = replacer;
  66. replacer = null;
  67. }
  68. function stringify(it, indent, key){
  69. if(replacer){
  70. it = replacer(key, it);
  71. }
  72. var val, objtype = typeof it;
  73. if(objtype == "number"){
  74. return isFinite(it) ? it + "" : "null";
  75. }
  76. if(objtype == "boolean"){
  77. return it + "";
  78. }
  79. if(it === null){
  80. return "null";
  81. }
  82. if(typeof it == "string"){
  83. return escapeString(it);
  84. }
  85. if(objtype == "function" || objtype == "undefined"){
  86. return undef; // undefined
  87. }
  88. // short-circuit for objects that support "json" serialization
  89. // if they return "self" then just pass-through...
  90. if(typeof it.toJSON == "function"){
  91. return stringify(it.toJSON(key), indent, key);
  92. }
  93. if(it instanceof Date){
  94. return '"{FullYear}-{Month+}-{Date}T{Hours}:{Minutes}:{Seconds}Z"'.replace(/\{(\w+)(\+)?\}/g, function(t, prop, plus){
  95. var num = it["getUTC" + prop]() + (plus ? 1 : 0);
  96. return num < 10 ? "0" + num : num;
  97. });
  98. }
  99. if(it.valueOf() !== it){
  100. // primitive wrapper, try again unwrapped:
  101. return stringify(it.valueOf(), indent, key);
  102. }
  103. var nextIndent= spacer ? (indent + spacer) : "";
  104. /* we used to test for DOM nodes and throw, but FF serializes them as {}, so cross-browser consistency is probably not efficiently attainable */
  105. var sep = spacer ? " " : "";
  106. var newLine = spacer ? "\n" : "";
  107. // array
  108. if(it instanceof Array){
  109. var itl = it.length, res = [];
  110. for(key = 0; key < itl; key++){
  111. var obj = it[key];
  112. val = stringify(obj, nextIndent, key);
  113. if(typeof val != "string"){
  114. val = "null";
  115. }
  116. res.push(newLine + nextIndent + val);
  117. }
  118. return "[" + res.join(",") + newLine + indent + "]";
  119. }
  120. // generic object code path
  121. var output = [];
  122. for(key in it){
  123. var keyStr;
  124. if(typeof key == "number"){
  125. keyStr = '"' + key + '"';
  126. }else if(typeof key == "string"){
  127. keyStr = escapeString(key);
  128. }else{
  129. // skip non-string or number keys
  130. continue;
  131. }
  132. val = stringify(it[key], nextIndent, key);
  133. if(typeof val != "string"){
  134. // skip non-serializable values
  135. continue;
  136. }
  137. // At this point, the most non-IE browsers don't get in this branch
  138. // (they have native JSON), so push is definitely the way to
  139. output.push(newLine + nextIndent + keyStr + ":" + sep + val);
  140. }
  141. return "{" + output.join(",") + newLine + indent + "}"; // String
  142. }
  143. return stringify(value, "", "");
  144. }
  145. };
  146. }
  147. });