json2-rails 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -0
- data/lib/json2-rails/version.rb +1 -1
- data/vendor/assets/javascripts/cycle.js +172 -0
- data/vendor/assets/javascripts/json.js +529 -0
- data/vendor/assets/javascripts/json_parse.js +349 -0
- data/vendor/assets/javascripts/json_parse_state.js +397 -0
- metadata +6 -2
@@ -0,0 +1,349 @@
|
|
1
|
+
/*
|
2
|
+
json_parse.js
|
3
|
+
2012-06-20
|
4
|
+
|
5
|
+
Public Domain.
|
6
|
+
|
7
|
+
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
8
|
+
|
9
|
+
This file creates a json_parse function.
|
10
|
+
|
11
|
+
json_parse(text, reviver)
|
12
|
+
This method parses a JSON text to produce an object or array.
|
13
|
+
It can throw a SyntaxError exception.
|
14
|
+
|
15
|
+
The optional reviver parameter is a function that can filter and
|
16
|
+
transform the results. It receives each of the keys and values,
|
17
|
+
and its return value is used instead of the original value.
|
18
|
+
If it returns what it received, then the structure is not modified.
|
19
|
+
If it returns undefined then the member is deleted.
|
20
|
+
|
21
|
+
Example:
|
22
|
+
|
23
|
+
// Parse the text. Values that look like ISO date strings will
|
24
|
+
// be converted to Date objects.
|
25
|
+
|
26
|
+
myData = json_parse(text, function (key, value) {
|
27
|
+
var a;
|
28
|
+
if (typeof value === 'string') {
|
29
|
+
a =
|
30
|
+
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
31
|
+
if (a) {
|
32
|
+
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
33
|
+
+a[5], +a[6]));
|
34
|
+
}
|
35
|
+
}
|
36
|
+
return value;
|
37
|
+
});
|
38
|
+
|
39
|
+
This is a reference implementation. You are free to copy, modify, or
|
40
|
+
redistribute.
|
41
|
+
|
42
|
+
This code should be minified before deployment.
|
43
|
+
See http://javascript.crockford.com/jsmin.html
|
44
|
+
|
45
|
+
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
46
|
+
NOT CONTROL.
|
47
|
+
*/
|
48
|
+
|
49
|
+
/*members "", "\"", "\/", "\\", at, b, call, charAt, f, fromCharCode,
|
50
|
+
hasOwnProperty, message, n, name, prototype, push, r, t, text
|
51
|
+
*/
|
52
|
+
|
53
|
+
var json_parse = (function () {
|
54
|
+
"use strict";
|
55
|
+
|
56
|
+
// This is a function that can parse a JSON text, producing a JavaScript
|
57
|
+
// data structure. It is a simple, recursive descent parser. It does not use
|
58
|
+
// eval or regular expressions, so it can be used as a model for implementing
|
59
|
+
// a JSON parser in other languages.
|
60
|
+
|
61
|
+
// We are defining the function inside of another function to avoid creating
|
62
|
+
// global variables.
|
63
|
+
|
64
|
+
var at, // The index of the current character
|
65
|
+
ch, // The current character
|
66
|
+
escapee = {
|
67
|
+
'"': '"',
|
68
|
+
'\\': '\\',
|
69
|
+
'/': '/',
|
70
|
+
b: '\b',
|
71
|
+
f: '\f',
|
72
|
+
n: '\n',
|
73
|
+
r: '\r',
|
74
|
+
t: '\t'
|
75
|
+
},
|
76
|
+
text,
|
77
|
+
|
78
|
+
error = function (m) {
|
79
|
+
|
80
|
+
// Call error when something is wrong.
|
81
|
+
|
82
|
+
throw {
|
83
|
+
name: 'SyntaxError',
|
84
|
+
message: m,
|
85
|
+
at: at,
|
86
|
+
text: text
|
87
|
+
};
|
88
|
+
},
|
89
|
+
|
90
|
+
next = function (c) {
|
91
|
+
|
92
|
+
// If a c parameter is provided, verify that it matches the current character.
|
93
|
+
|
94
|
+
if (c && c !== ch) {
|
95
|
+
error("Expected '" + c + "' instead of '" + ch + "'");
|
96
|
+
}
|
97
|
+
|
98
|
+
// Get the next character. When there are no more characters,
|
99
|
+
// return the empty string.
|
100
|
+
|
101
|
+
ch = text.charAt(at);
|
102
|
+
at += 1;
|
103
|
+
return ch;
|
104
|
+
},
|
105
|
+
|
106
|
+
number = function () {
|
107
|
+
|
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
|
+
return number;
|
144
|
+
}
|
145
|
+
},
|
146
|
+
|
147
|
+
string = function () {
|
148
|
+
|
149
|
+
// Parse a string value.
|
150
|
+
|
151
|
+
var hex,
|
152
|
+
i,
|
153
|
+
string = '',
|
154
|
+
uffff;
|
155
|
+
|
156
|
+
// When parsing for string values, we must look for " and \ characters.
|
157
|
+
|
158
|
+
if (ch === '"') {
|
159
|
+
while (next()) {
|
160
|
+
if (ch === '"') {
|
161
|
+
next();
|
162
|
+
return string;
|
163
|
+
}
|
164
|
+
if (ch === '\\') {
|
165
|
+
next();
|
166
|
+
if (ch === 'u') {
|
167
|
+
uffff = 0;
|
168
|
+
for (i = 0; i < 4; i += 1) {
|
169
|
+
hex = parseInt(next(), 16);
|
170
|
+
if (!isFinite(hex)) {
|
171
|
+
break;
|
172
|
+
}
|
173
|
+
uffff = uffff * 16 + hex;
|
174
|
+
}
|
175
|
+
string += String.fromCharCode(uffff);
|
176
|
+
} else if (typeof escapee[ch] === 'string') {
|
177
|
+
string += escapee[ch];
|
178
|
+
} else {
|
179
|
+
break;
|
180
|
+
}
|
181
|
+
} else {
|
182
|
+
string += ch;
|
183
|
+
}
|
184
|
+
}
|
185
|
+
}
|
186
|
+
error("Bad string");
|
187
|
+
},
|
188
|
+
|
189
|
+
white = function () {
|
190
|
+
|
191
|
+
// Skip whitespace.
|
192
|
+
|
193
|
+
while (ch && ch <= ' ') {
|
194
|
+
next();
|
195
|
+
}
|
196
|
+
},
|
197
|
+
|
198
|
+
word = function () {
|
199
|
+
|
200
|
+
// true, false, or null.
|
201
|
+
|
202
|
+
switch (ch) {
|
203
|
+
case 't':
|
204
|
+
next('t');
|
205
|
+
next('r');
|
206
|
+
next('u');
|
207
|
+
next('e');
|
208
|
+
return true;
|
209
|
+
case 'f':
|
210
|
+
next('f');
|
211
|
+
next('a');
|
212
|
+
next('l');
|
213
|
+
next('s');
|
214
|
+
next('e');
|
215
|
+
return false;
|
216
|
+
case 'n':
|
217
|
+
next('n');
|
218
|
+
next('u');
|
219
|
+
next('l');
|
220
|
+
next('l');
|
221
|
+
return null;
|
222
|
+
}
|
223
|
+
error("Unexpected '" + ch + "'");
|
224
|
+
},
|
225
|
+
|
226
|
+
value, // Place holder for the value function.
|
227
|
+
|
228
|
+
array = function () {
|
229
|
+
|
230
|
+
// Parse an array value.
|
231
|
+
|
232
|
+
var array = [];
|
233
|
+
|
234
|
+
if (ch === '[') {
|
235
|
+
next('[');
|
236
|
+
white();
|
237
|
+
if (ch === ']') {
|
238
|
+
next(']');
|
239
|
+
return array; // empty array
|
240
|
+
}
|
241
|
+
while (ch) {
|
242
|
+
array.push(value());
|
243
|
+
white();
|
244
|
+
if (ch === ']') {
|
245
|
+
next(']');
|
246
|
+
return array;
|
247
|
+
}
|
248
|
+
next(',');
|
249
|
+
white();
|
250
|
+
}
|
251
|
+
}
|
252
|
+
error("Bad array");
|
253
|
+
},
|
254
|
+
|
255
|
+
object = function () {
|
256
|
+
|
257
|
+
// Parse an object value.
|
258
|
+
|
259
|
+
var key,
|
260
|
+
object = {};
|
261
|
+
|
262
|
+
if (ch === '{') {
|
263
|
+
next('{');
|
264
|
+
white();
|
265
|
+
if (ch === '}') {
|
266
|
+
next('}');
|
267
|
+
return object; // empty object
|
268
|
+
}
|
269
|
+
while (ch) {
|
270
|
+
key = string();
|
271
|
+
white();
|
272
|
+
next(':');
|
273
|
+
if (Object.hasOwnProperty.call(object, key)) {
|
274
|
+
error('Duplicate key "' + key + '"');
|
275
|
+
}
|
276
|
+
object[key] = value();
|
277
|
+
white();
|
278
|
+
if (ch === '}') {
|
279
|
+
next('}');
|
280
|
+
return object;
|
281
|
+
}
|
282
|
+
next(',');
|
283
|
+
white();
|
284
|
+
}
|
285
|
+
}
|
286
|
+
error("Bad object");
|
287
|
+
};
|
288
|
+
|
289
|
+
value = function () {
|
290
|
+
|
291
|
+
// Parse a JSON value. It could be an object, an array, a string, a number,
|
292
|
+
// or a word.
|
293
|
+
|
294
|
+
white();
|
295
|
+
switch (ch) {
|
296
|
+
case '{':
|
297
|
+
return object();
|
298
|
+
case '[':
|
299
|
+
return array();
|
300
|
+
case '"':
|
301
|
+
return string();
|
302
|
+
case '-':
|
303
|
+
return number();
|
304
|
+
default:
|
305
|
+
return ch >= '0' && ch <= '9' ? number() : word();
|
306
|
+
}
|
307
|
+
};
|
308
|
+
|
309
|
+
// Return the json_parse function. It will have access to all of the above
|
310
|
+
// functions and variables.
|
311
|
+
|
312
|
+
return function (source, reviver) {
|
313
|
+
var result;
|
314
|
+
|
315
|
+
text = source;
|
316
|
+
at = 0;
|
317
|
+
ch = ' ';
|
318
|
+
result = value();
|
319
|
+
white();
|
320
|
+
if (ch) {
|
321
|
+
error("Syntax error");
|
322
|
+
}
|
323
|
+
|
324
|
+
// If there is a reviver function, we recursively walk the new structure,
|
325
|
+
// passing each name/value pair to the reviver function for possible
|
326
|
+
// transformation, starting with a temporary root object that holds the result
|
327
|
+
// in an empty key. If there is not a reviver function, we simply return the
|
328
|
+
// result.
|
329
|
+
|
330
|
+
return typeof reviver === 'function'
|
331
|
+
? (function walk(holder, key) {
|
332
|
+
var k, v, value = holder[key];
|
333
|
+
if (value && typeof value === 'object') {
|
334
|
+
for (k in value) {
|
335
|
+
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
336
|
+
v = walk(value, k);
|
337
|
+
if (v !== undefined) {
|
338
|
+
value[k] = v;
|
339
|
+
} else {
|
340
|
+
delete value[k];
|
341
|
+
}
|
342
|
+
}
|
343
|
+
}
|
344
|
+
}
|
345
|
+
return reviver.call(holder, key, value);
|
346
|
+
}({'': result}, ''))
|
347
|
+
: result;
|
348
|
+
};
|
349
|
+
}());
|
@@ -0,0 +1,397 @@
|
|
1
|
+
/*
|
2
|
+
json_parse_state.js
|
3
|
+
2012-06-01
|
4
|
+
|
5
|
+
Public Domain.
|
6
|
+
|
7
|
+
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
8
|
+
|
9
|
+
This file creates a json_parse function.
|
10
|
+
|
11
|
+
json_parse(text, reviver)
|
12
|
+
This method parses a JSON text to produce an object or array.
|
13
|
+
It can throw a SyntaxError exception.
|
14
|
+
|
15
|
+
The optional reviver parameter is a function that can filter and
|
16
|
+
transform the results. It receives each of the keys and values,
|
17
|
+
and its return value is used instead of the original value.
|
18
|
+
If it returns what it received, then the structure is not modified.
|
19
|
+
If it returns undefined then the member is deleted.
|
20
|
+
|
21
|
+
Example:
|
22
|
+
|
23
|
+
// Parse the text. Values that look like ISO date strings will
|
24
|
+
// be converted to Date objects.
|
25
|
+
|
26
|
+
myData = json_parse(text, function (key, value) {
|
27
|
+
var a;
|
28
|
+
if (typeof value === 'string') {
|
29
|
+
a =
|
30
|
+
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
31
|
+
if (a) {
|
32
|
+
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
33
|
+
+a[5], +a[6]));
|
34
|
+
}
|
35
|
+
}
|
36
|
+
return value;
|
37
|
+
});
|
38
|
+
|
39
|
+
This is a reference implementation. You are free to copy, modify, or
|
40
|
+
redistribute.
|
41
|
+
|
42
|
+
This code should be minified before deployment.
|
43
|
+
See http://javascript.crockford.com/jsmin.html
|
44
|
+
|
45
|
+
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
46
|
+
NOT CONTROL.
|
47
|
+
*/
|
48
|
+
|
49
|
+
/*jslint regexp: false*/
|
50
|
+
|
51
|
+
/*members "", "\"", ",", "\/", ":", "[", "\\", "]", acomma, avalue, b,
|
52
|
+
call, colon, container, exec, f, false, firstavalue, firstokey,
|
53
|
+
fromCharCode, go, hasOwnProperty, key, length, n, null, ocomma, okey,
|
54
|
+
ovalue, pop, prototype, push, r, replace, slice, state, t, test, true,
|
55
|
+
value, "{", "}"
|
56
|
+
*/
|
57
|
+
|
58
|
+
var json_parse = (function () {
|
59
|
+
"use strict";
|
60
|
+
|
61
|
+
// This function creates a JSON parse function that uses a state machine rather
|
62
|
+
// than the dangerous eval function to parse a JSON text.
|
63
|
+
|
64
|
+
var state, // The state of the parser, one of
|
65
|
+
// 'go' The starting state
|
66
|
+
// 'ok' The final, accepting state
|
67
|
+
// 'firstokey' Ready for the first key of the object or
|
68
|
+
// the closing of an empty object
|
69
|
+
// 'okey' Ready for the next key of the object
|
70
|
+
// 'colon' Ready for the colon
|
71
|
+
// 'ovalue' Ready for the value half of a key/value pair
|
72
|
+
// 'ocomma' Ready for a comma or closing }
|
73
|
+
// 'firstavalue' Ready for the first value of an array or
|
74
|
+
// an empty array
|
75
|
+
// 'avalue' Ready for the next value of an array
|
76
|
+
// 'acomma' Ready for a comma or closing ]
|
77
|
+
stack, // The stack, for controlling nesting.
|
78
|
+
container, // The current container object or array
|
79
|
+
key, // The current key
|
80
|
+
value, // The current value
|
81
|
+
escapes = { // Escapement translation table
|
82
|
+
'\\': '\\',
|
83
|
+
'"': '"',
|
84
|
+
'/': '/',
|
85
|
+
't': '\t',
|
86
|
+
'n': '\n',
|
87
|
+
'r': '\r',
|
88
|
+
'f': '\f',
|
89
|
+
'b': '\b'
|
90
|
+
},
|
91
|
+
string = { // The actions for string tokens
|
92
|
+
go: function () {
|
93
|
+
state = 'ok';
|
94
|
+
},
|
95
|
+
firstokey: function () {
|
96
|
+
key = value;
|
97
|
+
state = 'colon';
|
98
|
+
},
|
99
|
+
okey: function () {
|
100
|
+
key = value;
|
101
|
+
state = 'colon';
|
102
|
+
},
|
103
|
+
ovalue: function () {
|
104
|
+
state = 'ocomma';
|
105
|
+
},
|
106
|
+
firstavalue: function () {
|
107
|
+
state = 'acomma';
|
108
|
+
},
|
109
|
+
avalue: function () {
|
110
|
+
state = 'acomma';
|
111
|
+
}
|
112
|
+
},
|
113
|
+
number = { // The actions for number tokens
|
114
|
+
go: function () {
|
115
|
+
state = 'ok';
|
116
|
+
},
|
117
|
+
ovalue: function () {
|
118
|
+
state = 'ocomma';
|
119
|
+
},
|
120
|
+
firstavalue: function () {
|
121
|
+
state = 'acomma';
|
122
|
+
},
|
123
|
+
avalue: function () {
|
124
|
+
state = 'acomma';
|
125
|
+
}
|
126
|
+
},
|
127
|
+
action = {
|
128
|
+
|
129
|
+
// The action table describes the behavior of the machine. It contains an
|
130
|
+
// object for each token. Each object contains a method that is called when
|
131
|
+
// a token is matched in a state. An object will lack a method for illegal
|
132
|
+
// states.
|
133
|
+
|
134
|
+
'{': {
|
135
|
+
go: function () {
|
136
|
+
stack.push({state: 'ok'});
|
137
|
+
container = {};
|
138
|
+
state = 'firstokey';
|
139
|
+
},
|
140
|
+
ovalue: function () {
|
141
|
+
stack.push({container: container, state: 'ocomma', key: key});
|
142
|
+
container = {};
|
143
|
+
state = 'firstokey';
|
144
|
+
},
|
145
|
+
firstavalue: function () {
|
146
|
+
stack.push({container: container, state: 'acomma'});
|
147
|
+
container = {};
|
148
|
+
state = 'firstokey';
|
149
|
+
},
|
150
|
+
avalue: function () {
|
151
|
+
stack.push({container: container, state: 'acomma'});
|
152
|
+
container = {};
|
153
|
+
state = 'firstokey';
|
154
|
+
}
|
155
|
+
},
|
156
|
+
'}': {
|
157
|
+
firstokey: function () {
|
158
|
+
var pop = stack.pop();
|
159
|
+
value = container;
|
160
|
+
container = pop.container;
|
161
|
+
key = pop.key;
|
162
|
+
state = pop.state;
|
163
|
+
},
|
164
|
+
ocomma: function () {
|
165
|
+
var pop = stack.pop();
|
166
|
+
container[key] = value;
|
167
|
+
value = container;
|
168
|
+
container = pop.container;
|
169
|
+
key = pop.key;
|
170
|
+
state = pop.state;
|
171
|
+
}
|
172
|
+
},
|
173
|
+
'[': {
|
174
|
+
go: function () {
|
175
|
+
stack.push({state: 'ok'});
|
176
|
+
container = [];
|
177
|
+
state = 'firstavalue';
|
178
|
+
},
|
179
|
+
ovalue: function () {
|
180
|
+
stack.push({container: container, state: 'ocomma', key: key});
|
181
|
+
container = [];
|
182
|
+
state = 'firstavalue';
|
183
|
+
},
|
184
|
+
firstavalue: function () {
|
185
|
+
stack.push({container: container, state: 'acomma'});
|
186
|
+
container = [];
|
187
|
+
state = 'firstavalue';
|
188
|
+
},
|
189
|
+
avalue: function () {
|
190
|
+
stack.push({container: container, state: 'acomma'});
|
191
|
+
container = [];
|
192
|
+
state = 'firstavalue';
|
193
|
+
}
|
194
|
+
},
|
195
|
+
']': {
|
196
|
+
firstavalue: function () {
|
197
|
+
var pop = stack.pop();
|
198
|
+
value = container;
|
199
|
+
container = pop.container;
|
200
|
+
key = pop.key;
|
201
|
+
state = pop.state;
|
202
|
+
},
|
203
|
+
acomma: function () {
|
204
|
+
var pop = stack.pop();
|
205
|
+
container.push(value);
|
206
|
+
value = container;
|
207
|
+
container = pop.container;
|
208
|
+
key = pop.key;
|
209
|
+
state = pop.state;
|
210
|
+
}
|
211
|
+
},
|
212
|
+
':': {
|
213
|
+
colon: function () {
|
214
|
+
if (Object.hasOwnProperty.call(container, key)) {
|
215
|
+
throw new SyntaxError('Duplicate key "' + key + '"');
|
216
|
+
}
|
217
|
+
state = 'ovalue';
|
218
|
+
}
|
219
|
+
},
|
220
|
+
',': {
|
221
|
+
ocomma: function () {
|
222
|
+
container[key] = value;
|
223
|
+
state = 'okey';
|
224
|
+
},
|
225
|
+
acomma: function () {
|
226
|
+
container.push(value);
|
227
|
+
state = 'avalue';
|
228
|
+
}
|
229
|
+
},
|
230
|
+
'true': {
|
231
|
+
go: function () {
|
232
|
+
value = true;
|
233
|
+
state = 'ok';
|
234
|
+
},
|
235
|
+
ovalue: function () {
|
236
|
+
value = true;
|
237
|
+
state = 'ocomma';
|
238
|
+
},
|
239
|
+
firstavalue: function () {
|
240
|
+
value = true;
|
241
|
+
state = 'acomma';
|
242
|
+
},
|
243
|
+
avalue: function () {
|
244
|
+
value = true;
|
245
|
+
state = 'acomma';
|
246
|
+
}
|
247
|
+
},
|
248
|
+
'false': {
|
249
|
+
go: function () {
|
250
|
+
value = false;
|
251
|
+
state = 'ok';
|
252
|
+
},
|
253
|
+
ovalue: function () {
|
254
|
+
value = false;
|
255
|
+
state = 'ocomma';
|
256
|
+
},
|
257
|
+
firstavalue: function () {
|
258
|
+
value = false;
|
259
|
+
state = 'acomma';
|
260
|
+
},
|
261
|
+
avalue: function () {
|
262
|
+
value = false;
|
263
|
+
state = 'acomma';
|
264
|
+
}
|
265
|
+
},
|
266
|
+
'null': {
|
267
|
+
go: function () {
|
268
|
+
value = null;
|
269
|
+
state = 'ok';
|
270
|
+
},
|
271
|
+
ovalue: function () {
|
272
|
+
value = null;
|
273
|
+
state = 'ocomma';
|
274
|
+
},
|
275
|
+
firstavalue: function () {
|
276
|
+
value = null;
|
277
|
+
state = 'acomma';
|
278
|
+
},
|
279
|
+
avalue: function () {
|
280
|
+
value = null;
|
281
|
+
state = 'acomma';
|
282
|
+
}
|
283
|
+
}
|
284
|
+
};
|
285
|
+
|
286
|
+
function debackslashify(text) {
|
287
|
+
|
288
|
+
// Remove and replace any backslash escapement.
|
289
|
+
|
290
|
+
return text.replace(/\\(?:u(.{4})|([^u]))/g, function (a, b, c) {
|
291
|
+
return b ? String.fromCharCode(parseInt(b, 16)) : escapes[c];
|
292
|
+
});
|
293
|
+
}
|
294
|
+
|
295
|
+
return function (source, reviver) {
|
296
|
+
|
297
|
+
// A regular expression is used to extract tokens from the JSON text.
|
298
|
+
// The extraction process is cautious.
|
299
|
+
|
300
|
+
var r, // The result of the exec method.
|
301
|
+
tx = /^[\x20\t\n\r]*(?:([,:\[\]{}]|true|false|null)|(-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)|"((?:[^\r\n\t\\\"]|\\(?:["\\\/trnfb]|u[0-9a-fA-F]{4}))*)")/;
|
302
|
+
|
303
|
+
// Set the starting state.
|
304
|
+
|
305
|
+
state = 'go';
|
306
|
+
|
307
|
+
// The stack records the container, key, and state for each object or array
|
308
|
+
// that contains another object or array while processing nested structures.
|
309
|
+
|
310
|
+
stack = [];
|
311
|
+
|
312
|
+
// If any error occurs, we will catch it and ultimately throw a syntax error.
|
313
|
+
|
314
|
+
try {
|
315
|
+
|
316
|
+
// For each token...
|
317
|
+
|
318
|
+
for (;;) {
|
319
|
+
r = tx.exec(source);
|
320
|
+
if (!r) {
|
321
|
+
break;
|
322
|
+
}
|
323
|
+
|
324
|
+
// r is the result array from matching the tokenizing regular expression.
|
325
|
+
// r[0] contains everything that matched, including any initial whitespace.
|
326
|
+
// r[1] contains any punctuation that was matched, or true, false, or null.
|
327
|
+
// r[2] contains a matched number, still in string form.
|
328
|
+
// r[3] contains a matched string, without quotes but with escapement.
|
329
|
+
|
330
|
+
if (r[1]) {
|
331
|
+
|
332
|
+
// Token: Execute the action for this state and token.
|
333
|
+
|
334
|
+
action[r[1]][state]();
|
335
|
+
|
336
|
+
} else if (r[2]) {
|
337
|
+
|
338
|
+
// Number token: Convert the number string into a number value and execute
|
339
|
+
// the action for this state and number.
|
340
|
+
|
341
|
+
value = +r[2];
|
342
|
+
number[state]();
|
343
|
+
} else {
|
344
|
+
|
345
|
+
// String token: Replace the escapement sequences and execute the action for
|
346
|
+
// this state and string.
|
347
|
+
|
348
|
+
value = debackslashify(r[3]);
|
349
|
+
string[state]();
|
350
|
+
}
|
351
|
+
|
352
|
+
// Remove the token from the string. The loop will continue as long as there
|
353
|
+
// are tokens. This is a slow process, but it allows the use of ^ matching,
|
354
|
+
// which assures that no illegal tokens slip through.
|
355
|
+
|
356
|
+
source = source.slice(r[0].length);
|
357
|
+
}
|
358
|
+
|
359
|
+
// If we find a state/token combination that is illegal, then the action will
|
360
|
+
// cause an error. We handle the error by simply changing the state.
|
361
|
+
|
362
|
+
} catch (e) {
|
363
|
+
state = e;
|
364
|
+
}
|
365
|
+
|
366
|
+
// The parsing is finished. If we are not in the final 'ok' state, or if the
|
367
|
+
// remaining source contains anything except whitespace, then we did not have
|
368
|
+
//a well-formed JSON text.
|
369
|
+
|
370
|
+
if (state !== 'ok' || /[^\x20\t\n\r]/.test(source)) {
|
371
|
+
throw state instanceof SyntaxError ? state : new SyntaxError('JSON');
|
372
|
+
}
|
373
|
+
|
374
|
+
// If there is a reviver function, we recursively walk the new structure,
|
375
|
+
// passing each name/value pair to the reviver function for possible
|
376
|
+
// transformation, starting with a temporary root object that holds the current
|
377
|
+
// value in an empty key. If there is not a reviver function, we simply return
|
378
|
+
// that value.
|
379
|
+
|
380
|
+
return typeof reviver === 'function' ? (function walk(holder, key) {
|
381
|
+
var k, v, value = holder[key];
|
382
|
+
if (value && typeof value === 'object') {
|
383
|
+
for (k in value) {
|
384
|
+
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
385
|
+
v = walk(value, k);
|
386
|
+
if (v !== undefined) {
|
387
|
+
value[k] = v;
|
388
|
+
} else {
|
389
|
+
delete value[k];
|
390
|
+
}
|
391
|
+
}
|
392
|
+
}
|
393
|
+
}
|
394
|
+
return reviver.call(holder, key, value);
|
395
|
+
}({'': value}, '')) : value;
|
396
|
+
};
|
397
|
+
}());
|