Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80556 views
1
var at, // The index of the current character
2
ch, // The current character
3
escapee = {
4
'"': '"',
5
'\\': '\\',
6
'/': '/',
7
b: '\b',
8
f: '\f',
9
n: '\n',
10
r: '\r',
11
t: '\t'
12
},
13
text,
14
15
error = function (m) {
16
// Call error when something is wrong.
17
throw {
18
name: 'SyntaxError',
19
message: m,
20
at: at,
21
text: text
22
};
23
},
24
25
next = function (c) {
26
// If a c parameter is provided, verify that it matches the current character.
27
if (c && c !== ch) {
28
error("Expected '" + c + "' instead of '" + ch + "'");
29
}
30
31
// Get the next character. When there are no more characters,
32
// return the empty string.
33
34
ch = text.charAt(at);
35
at += 1;
36
return ch;
37
},
38
39
number = function () {
40
// Parse a number value.
41
var number,
42
string = '';
43
44
if (ch === '-') {
45
string = '-';
46
next('-');
47
}
48
while (ch >= '0' && ch <= '9') {
49
string += ch;
50
next();
51
}
52
if (ch === '.') {
53
string += '.';
54
while (next() && ch >= '0' && ch <= '9') {
55
string += ch;
56
}
57
}
58
if (ch === 'e' || ch === 'E') {
59
string += ch;
60
next();
61
if (ch === '-' || ch === '+') {
62
string += ch;
63
next();
64
}
65
while (ch >= '0' && ch <= '9') {
66
string += ch;
67
next();
68
}
69
}
70
number = +string;
71
if (!isFinite(number)) {
72
error("Bad number");
73
} else {
74
return number;
75
}
76
},
77
78
string = function () {
79
// Parse a string value.
80
var hex,
81
i,
82
string = '',
83
uffff;
84
85
// When parsing for string values, we must look for " and \ characters.
86
if (ch === '"') {
87
while (next()) {
88
if (ch === '"') {
89
next();
90
return string;
91
} else if (ch === '\\') {
92
next();
93
if (ch === 'u') {
94
uffff = 0;
95
for (i = 0; i < 4; i += 1) {
96
hex = parseInt(next(), 16);
97
if (!isFinite(hex)) {
98
break;
99
}
100
uffff = uffff * 16 + hex;
101
}
102
string += String.fromCharCode(uffff);
103
} else if (typeof escapee[ch] === 'string') {
104
string += escapee[ch];
105
} else {
106
break;
107
}
108
} else {
109
string += ch;
110
}
111
}
112
}
113
error("Bad string");
114
},
115
116
white = function () {
117
118
// Skip whitespace.
119
120
while (ch && ch <= ' ') {
121
next();
122
}
123
},
124
125
word = function () {
126
127
// true, false, or null.
128
129
switch (ch) {
130
case 't':
131
next('t');
132
next('r');
133
next('u');
134
next('e');
135
return true;
136
case 'f':
137
next('f');
138
next('a');
139
next('l');
140
next('s');
141
next('e');
142
return false;
143
case 'n':
144
next('n');
145
next('u');
146
next('l');
147
next('l');
148
return null;
149
}
150
error("Unexpected '" + ch + "'");
151
},
152
153
value, // Place holder for the value function.
154
155
array = function () {
156
157
// Parse an array value.
158
159
var array = [];
160
161
if (ch === '[') {
162
next('[');
163
white();
164
if (ch === ']') {
165
next(']');
166
return array; // empty array
167
}
168
while (ch) {
169
array.push(value());
170
white();
171
if (ch === ']') {
172
next(']');
173
return array;
174
}
175
next(',');
176
white();
177
}
178
}
179
error("Bad array");
180
},
181
182
object = function () {
183
184
// Parse an object value.
185
186
var key,
187
object = {};
188
189
if (ch === '{') {
190
next('{');
191
white();
192
if (ch === '}') {
193
next('}');
194
return object; // empty object
195
}
196
while (ch) {
197
key = string();
198
white();
199
next(':');
200
if (Object.hasOwnProperty.call(object, key)) {
201
error('Duplicate key "' + key + '"');
202
}
203
object[key] = value();
204
white();
205
if (ch === '}') {
206
next('}');
207
return object;
208
}
209
next(',');
210
white();
211
}
212
}
213
error("Bad object");
214
};
215
216
value = function () {
217
218
// Parse a JSON value. It could be an object, an array, a string, a number,
219
// or a word.
220
221
white();
222
switch (ch) {
223
case '{':
224
return object();
225
case '[':
226
return array();
227
case '"':
228
return string();
229
case '-':
230
return number();
231
default:
232
return ch >= '0' && ch <= '9' ? number() : word();
233
}
234
};
235
236
// Return the json_parse function. It will have access to all of the above
237
// functions and variables.
238
239
module.exports = function (source, reviver) {
240
var result;
241
242
text = source;
243
at = 0;
244
ch = ' ';
245
result = value();
246
white();
247
if (ch) {
248
error("Syntax error");
249
}
250
251
// If there is a reviver function, we recursively walk the new structure,
252
// passing each name/value pair to the reviver function for possible
253
// transformation, starting with a temporary root object that holds the result
254
// in an empty key. If there is not a reviver function, we simply return the
255
// result.
256
257
return typeof reviver === 'function' ? (function walk(holder, key) {
258
var k, v, value = holder[key];
259
if (value && typeof value === 'object') {
260
for (k in value) {
261
if (Object.prototype.hasOwnProperty.call(value, k)) {
262
v = walk(value, k);
263
if (v !== undefined) {
264
value[k] = v;
265
} else {
266
delete value[k];
267
}
268
}
269
}
270
}
271
return reviver.call(holder, key, value);
272
}({'': result}, '')) : result;
273
};
274
275