| 213 | } |
| 214 | |
| 215 | function Str(key, holder, stack) { |
| 216 | var value = holder[key], |
| 217 | type = typeof value; |
| 218 | |
| 219 | if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') { |
| 220 | value = value.toJSON(key); |
| 221 | } |
| 222 | |
| 223 | var _class = _toString.call(value); |
| 224 | |
| 225 | switch (_class) { |
| 226 | case NUMBER_CLASS: |
| 227 | case BOOLEAN_CLASS: |
| 228 | case STRING_CLASS: |
| 229 | value = value.valueOf(); |
| 230 | } |
| 231 | |
| 232 | switch (value) { |
| 233 | case null: return 'null'; |
| 234 | case true: return 'true'; |
| 235 | case false: return 'false'; |
| 236 | } |
| 237 | |
| 238 | type = typeof value; |
| 239 | switch (type) { |
| 240 | case 'string': |
| 241 | return value.inspect(true); |
| 242 | case 'number': |
| 243 | return isFinite(value) ? String(value) : 'null'; |
| 244 | case 'object': |
| 245 | |
| 246 | for (var i = 0, length = stack.length; i < length; i++) { |
| 247 | if (stack[i] === value) { throw new TypeError(); } |
| 248 | } |
| 249 | stack.push(value); |
| 250 | |
| 251 | var partial = []; |
| 252 | if (_class === ARRAY_CLASS) { |
| 253 | for (var i = 0, length = value.length; i < length; i++) { |
| 254 | var str = Str(i, value, stack); |
| 255 | partial.push(typeof str === 'undefined' ? 'null' : str); |
| 256 | } |
| 257 | partial = '[' + partial.join(',') + ']'; |
| 258 | } else { |
| 259 | var keys = Object.keys(value); |
| 260 | for (var i = 0, length = keys.length; i < length; i++) { |
| 261 | var key = keys[i], str = Str(key, value, stack); |
| 262 | if (typeof str !== "undefined") { |
| 263 | partial.push(key.inspect(true)+ ':' + str); |
| 264 | } |
| 265 | } |
| 266 | partial = '{' + partial.join(',') + '}'; |
| 267 | } |
| 268 | stack.pop(); |
| 269 | return partial; |
| 270 | } |
| 271 | } |
| 272 | |