UNPKG

10.2 kBJavaScriptView Raw
1var BigNumber = require('bignumber.js');
2/*
3 json_parse.js
4 2012-06-20
5
6 Public Domain.
7
8 NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
9
10 This file creates a json_parse function.
11
12 json_parse(text, reviver)
13 This method parses a JSON text to produce an object or array.
14 It can throw a SyntaxError exception.
15
16 The optional reviver parameter is a function that can filter and
17 transform the results. It receives each of the keys and values,
18 and its return value is used instead of the original value.
19 If it returns what it received, then the structure is not modified.
20 If it returns undefined then the member is deleted.
21
22 Example:
23
24 // Parse the text. Values that look like ISO date strings will
25 // be converted to Date objects.
26
27 myData = json_parse(text, function (key, value) {
28 var a;
29 if (typeof value === 'string') {
30 a =
31/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
32 if (a) {
33 return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
34 +a[5], +a[6]));
35 }
36 }
37 return value;
38 });
39
40 This is a reference implementation. You are free to copy, modify, or
41 redistribute.
42
43 This code should be minified before deployment.
44 See http://javascript.crockford.com/jsmin.html
45
46 USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
47 NOT CONTROL.
48*/
49
50/*members "", "\"", "\/", "\\", at, b, call, charAt, f, fromCharCode,
51 hasOwnProperty, message, n, name, prototype, push, r, t, text
52*/
53
54var json_parse = (function () {
55 "use strict";
56
57// This is a function that can parse a JSON text, producing a JavaScript
58// data structure. It is a simple, recursive descent parser. It does not use
59// eval or regular expressions, so it can be used as a model for implementing
60// a JSON parser in other languages.
61
62// We are defining the function inside of another function to avoid creating
63// global variables.
64
65 var at, // The index of the current character
66 ch, // The current character
67 escapee = {
68 '"': '"',
69 '\\': '\\',
70 '/': '/',
71 b: '\b',
72 f: '\f',
73 n: '\n',
74 r: '\r',
75 t: '\t'
76 },
77 text,
78
79 error = function (m) {
80
81// Call error when something is wrong.
82
83 throw {
84 name: 'SyntaxError',
85 message: m,
86 at: at,
87 text: text
88 };
89 },
90
91 next = function (c) {
92
93// If a c parameter is provided, verify that it matches the current character.
94
95 if (c && c !== ch) {
96 error("Expected '" + c + "' instead of '" + ch + "'");
97 }
98
99// Get the next character. When there are no more characters,
100// return the empty string.
101
102 ch = text.charAt(at);
103 at += 1;
104 return ch;
105 },
106
107 number = function () {
108// Parse a number value.
109
110 var number,
111 string = '';
112
113 if (ch === '-') {
114 string = '-';
115 next('-');
116 }
117 while (ch >= '0' && ch <= '9') {
118 string += ch;
119 next();
120 }
121 if (ch === '.') {
122 string += '.';
123 while (next() && ch >= '0' && ch <= '9') {
124 string += ch;
125 }
126 }
127 if (ch === 'e' || ch === 'E') {
128 string += ch;
129 next();
130 if (ch === '-' || ch === '+') {
131 string += ch;
132 next();
133 }
134 while (ch >= '0' && ch <= '9') {
135 string += ch;
136 next();
137 }
138 }
139 number = +string;
140 if (!isFinite(number)) {
141 error("Bad number");
142 } else {
143 if (number > 9007199254740992 || number < -9007199254740992)
144 return new BigNumber(string);
145 return number;
146 }
147 },
148
149 string = function () {
150
151// Parse a string value.
152
153 var hex,
154 i,
155 string = '',
156 uffff;
157
158// When parsing for string values, we must look for " and \ characters.
159
160 if (ch === '"') {
161 while (next()) {
162 if (ch === '"') {
163 next();
164 return string;
165 }
166 if (ch === '\\') {
167 next();
168 if (ch === 'u') {
169 uffff = 0;
170 for (i = 0; i < 4; i += 1) {
171 hex = parseInt(next(), 16);
172 if (!isFinite(hex)) {
173 break;
174 }
175 uffff = uffff * 16 + hex;
176 }
177 string += String.fromCharCode(uffff);
178 } else if (typeof escapee[ch] === 'string') {
179 string += escapee[ch];
180 } else {
181 break;
182 }
183 } else {
184 string += ch;
185 }
186 }
187 }
188 error("Bad string");
189 },
190
191 white = function () {
192
193// Skip whitespace.
194
195 while (ch && ch <= ' ') {
196 next();
197 }
198 },
199
200 word = function () {
201
202// true, false, or null.
203
204 switch (ch) {
205 case 't':
206 next('t');
207 next('r');
208 next('u');
209 next('e');
210 return true;
211 case 'f':
212 next('f');
213 next('a');
214 next('l');
215 next('s');
216 next('e');
217 return false;
218 case 'n':
219 next('n');
220 next('u');
221 next('l');
222 next('l');
223 return null;
224 }
225 error("Unexpected '" + ch + "'");
226 },
227
228 value, // Place holder for the value function.
229
230 array = function () {
231
232// Parse an array value.
233
234 var array = [];
235
236 if (ch === '[') {
237 next('[');
238 white();
239 if (ch === ']') {
240 next(']');
241 return array; // empty array
242 }
243 while (ch) {
244 array.push(value());
245 white();
246 if (ch === ']') {
247 next(']');
248 return array;
249 }
250 next(',');
251 white();
252 }
253 }
254 error("Bad array");
255 },
256
257 object = function () {
258
259// Parse an object value.
260
261 var key,
262 object = {};
263
264 if (ch === '{') {
265 next('{');
266 white();
267 if (ch === '}') {
268 next('}');
269 return object; // empty object
270 }
271 while (ch) {
272 key = string();
273 white();
274 next(':');
275 if (Object.hasOwnProperty.call(object, key)) {
276 error('Duplicate key "' + key + '"');
277 }
278 object[key] = value();
279 white();
280 if (ch === '}') {
281 next('}');
282 return object;
283 }
284 next(',');
285 white();
286 }
287 }
288 error("Bad object");
289 };
290
291 value = function () {
292
293// Parse a JSON value. It could be an object, an array, a string, a number,
294// or a word.
295
296 white();
297 switch (ch) {
298 case '{':
299 return object();
300 case '[':
301 return array();
302 case '"':
303 return string();
304 case '-':
305 return number();
306 default:
307 return ch >= '0' && ch <= '9' ? number() : word();
308 }
309 };
310
311// Return the json_parse function. It will have access to all of the above
312// functions and variables.
313
314 return function (source, reviver) {
315 var result;
316
317 text = source;
318 at = 0;
319 ch = ' ';
320 result = value();
321 white();
322 if (ch) {
323 error("Syntax error");
324 }
325
326// If there is a reviver function, we recursively walk the new structure,
327// passing each name/value pair to the reviver function for possible
328// transformation, starting with a temporary root object that holds the result
329// in an empty key. If there is not a reviver function, we simply return the
330// result.
331
332 return typeof reviver === 'function'
333 ? (function walk(holder, key) {
334 var k, v, value = holder[key];
335 if (value && typeof value === 'object') {
336 for (k in value) {
337 if (Object.prototype.hasOwnProperty.call(value, k)) {
338 v = walk(value, k);
339 if (v !== undefined) {
340 value[k] = v;
341 } else {
342 delete value[k];
343 }
344 }
345 }
346 }
347 return reviver.call(holder, key, value);
348 }({'': result}, ''))
349 : result;
350 };
351}());
352
353json_stringify = require('./stringify.js').stringify;
354
355module.exports = {
356 parse: json_parse,
357 stringify: json_stringify
358};