flex-json 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FlexJsonClass.js +1750 -0
- package/FlexJsonConstants.js +57 -0
- package/FlexJsonMeta.js +26 -0
- package/FlexJsonPosition.js +32 -0
- package/LICENSE.txt +21 -0
- package/README.md +178 -0
- package/package.json +29 -0
package/FlexJsonClass.js
ADDED
|
@@ -0,0 +1,1750 @@
|
|
|
1
|
+
const FlexJsonConstants = require("./FlexJsonConstants.js");
|
|
2
|
+
const FlexJsonPosition = require("./FlexJsonPosition.js");
|
|
3
|
+
const FlexJsonMeta = require("./FlexJsonMeta.js");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const StringBuilder = require("string-builder");
|
|
6
|
+
|
|
7
|
+
class FlexJson {
|
|
8
|
+
_status = 0;
|
|
9
|
+
_jsonType = "";
|
|
10
|
+
_key = null;
|
|
11
|
+
_value = null;
|
|
12
|
+
_value_valid = false;
|
|
13
|
+
_jsonString = "";
|
|
14
|
+
_jsonString_valid = false;
|
|
15
|
+
|
|
16
|
+
Parent;
|
|
17
|
+
ALLOW_SINGLE_QUOTE_STRINGS = true;
|
|
18
|
+
ENCODE_SINGLE_QUOTES = false;
|
|
19
|
+
|
|
20
|
+
_UseFlexJson = false;
|
|
21
|
+
|
|
22
|
+
_meta = null;
|
|
23
|
+
_NoStatsOrMsgs = false;
|
|
24
|
+
|
|
25
|
+
constructor(InitialJSON, UseFlexJsonFlag) {
|
|
26
|
+
if (UseFlexJsonFlag == true || UseFlexJsonFlag == false) {
|
|
27
|
+
this.UseFlexJson = UseFlexJsonFlag;
|
|
28
|
+
}
|
|
29
|
+
if (InitialJSON) {
|
|
30
|
+
this.Deserialize(InitialJSON + "", 0, false);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
createMetaIfNeeded(force = false) {
|
|
35
|
+
if (this._NoStatsOrMsgs && !force) {
|
|
36
|
+
return;
|
|
37
|
+
} // Do not track stats/message/meta-data
|
|
38
|
+
if (this._meta == null) {
|
|
39
|
+
this._meta = new FlexJsonMeta();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get trackingStats() {
|
|
44
|
+
if (this._meta == null) return false;
|
|
45
|
+
if (this._meta.stats == null) return false;
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get statusMsg() {
|
|
50
|
+
if (this._meta != null) {
|
|
51
|
+
if (this._meta.statusMsg != null) {
|
|
52
|
+
return this._meta.statusMsg;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return "";
|
|
56
|
+
}
|
|
57
|
+
set statusMsg(value) {
|
|
58
|
+
if (this.NoStatsOrMsgs) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
this.createMetaIfNeeded();
|
|
62
|
+
if (this._meta != null) {
|
|
63
|
+
this._meta.statusMsg = value;
|
|
64
|
+
}
|
|
65
|
+
if (this._meta.msgLogOn) {
|
|
66
|
+
if (this._meta != null) {
|
|
67
|
+
this._meta.msgLog.add(value);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get tmpStatusMsg() {
|
|
73
|
+
if (this._meta != null) {
|
|
74
|
+
if (this._meta.tmpStatusMsg != null) {
|
|
75
|
+
return this._meta.tmpStatusMsg;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return "";
|
|
79
|
+
}
|
|
80
|
+
set tmpStatusMsg(value) {
|
|
81
|
+
this.createMetaIfNeeded();
|
|
82
|
+
if (_meta != null) {
|
|
83
|
+
_meta.tmpStatusMsg = value;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get key() {
|
|
88
|
+
return this._key;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
set key(value) {
|
|
92
|
+
this._key = value + "";
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get preSpace() {
|
|
96
|
+
if (this._meta != null) {
|
|
97
|
+
if (this._meta.preSpace != null) {
|
|
98
|
+
return this._meta.preSpace;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
set preSpace(value) {
|
|
105
|
+
this.createMetaIfNeeded();
|
|
106
|
+
if (this._meta != null) {
|
|
107
|
+
this._meta.preSpace = value;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
get postSpace() {
|
|
112
|
+
if (this._meta != null) {
|
|
113
|
+
if (this._meta.postSpace != null) {
|
|
114
|
+
return this._meta.postSpace;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
set postSpace(value) {
|
|
121
|
+
this.createMetaIfNeeded();
|
|
122
|
+
if (this._meta != null) {
|
|
123
|
+
this._meta.postSpace = value;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
get finalSpace() {
|
|
128
|
+
if (this._meta != null) {
|
|
129
|
+
if (this._meta.finalSpace != null) {
|
|
130
|
+
return this._meta.finalSpace;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
set finalSpace(value) {
|
|
137
|
+
this.createMetaIfNeeded();
|
|
138
|
+
if (this._meta != null) {
|
|
139
|
+
this._meta.finalSpace = value;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
get preKey() {
|
|
144
|
+
if (this._meta != null) {
|
|
145
|
+
if (this._meta.preKey != null) {
|
|
146
|
+
return this._meta.preKey;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
set preKey(value) {
|
|
153
|
+
this.createMetaIfNeeded();
|
|
154
|
+
if (this._meta != null) {
|
|
155
|
+
this._meta.preKey = value;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
get postKey() {
|
|
160
|
+
if (this._meta != null) {
|
|
161
|
+
if (this._meta.postKey != null) {
|
|
162
|
+
return this._meta.postKey;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
set postKey(value) {
|
|
169
|
+
this.createMetaIfNeeded();
|
|
170
|
+
if (this._meta != null) {
|
|
171
|
+
this._meta.postKey = value;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
get keepSpacing() {
|
|
176
|
+
if (this._meta != null) {
|
|
177
|
+
return this._meta.keepSpacing;
|
|
178
|
+
}
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
set keepSpacing(value) {
|
|
182
|
+
this.createMetaIfNeeded();
|
|
183
|
+
if (this._meta != null) {
|
|
184
|
+
this._meta.keepSpacing = value;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
get keepComments() {
|
|
189
|
+
if (this._meta != null) {
|
|
190
|
+
return this._meta.keepComments;
|
|
191
|
+
}
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
set keepComments(value) {
|
|
195
|
+
this.createMetaIfNeeded();
|
|
196
|
+
if (this._meta != null) {
|
|
197
|
+
this._meta.keepComments = value;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
get UseFlexJson() {
|
|
202
|
+
return this._UseFlexJson;
|
|
203
|
+
}
|
|
204
|
+
set UseFlexJson(value) {
|
|
205
|
+
this._UseFlexJson = value;
|
|
206
|
+
this.InvalidateJsonString(1); // If we switch to FlexJson then all our stored JSON strings could be incorrect.
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
get Status() {
|
|
210
|
+
return this._status;
|
|
211
|
+
} // End Property
|
|
212
|
+
|
|
213
|
+
get jsonType() {
|
|
214
|
+
return this._jsonType;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
get jsonString() {
|
|
218
|
+
// if (trackingStats) { IncStats("stat_jsonString_get"); }
|
|
219
|
+
if (this._status != 0) {
|
|
220
|
+
return "";
|
|
221
|
+
} // *** ERROR - status is invalid
|
|
222
|
+
if (!this._jsonString_valid) {
|
|
223
|
+
if (!this._value_valid) {
|
|
224
|
+
// *** Neither is valid - this JSON object is null
|
|
225
|
+
return "";
|
|
226
|
+
} else {
|
|
227
|
+
// *** First we need to serialize
|
|
228
|
+
this.SerializeMe();
|
|
229
|
+
if (this._status != 0) {
|
|
230
|
+
return "";
|
|
231
|
+
} // *** ERROR - status is invalid
|
|
232
|
+
return this._jsonString;
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
// jsonString was already valid.
|
|
236
|
+
return this._jsonString;
|
|
237
|
+
}
|
|
238
|
+
} // end getJsonString()
|
|
239
|
+
|
|
240
|
+
set jsonString(value) {
|
|
241
|
+
//if (trackingStats) { IncStats("stat_jsonString_set"); }
|
|
242
|
+
if (
|
|
243
|
+
this._status == 0 &&
|
|
244
|
+
this._jsonString_valid &&
|
|
245
|
+
this._jsonString == value
|
|
246
|
+
) {
|
|
247
|
+
return;
|
|
248
|
+
} else {
|
|
249
|
+
this.Clear(false, 1); // *** This clears _value AND notifies Parent that we have changed.
|
|
250
|
+
this._jsonString = value;
|
|
251
|
+
this._jsonString_valid = true; // *** This does not indicate 'valid JSON syntax' but only that the string has been populated.
|
|
252
|
+
}
|
|
253
|
+
} //End Set jsonString
|
|
254
|
+
|
|
255
|
+
// Gets Array.Length or Dictionary.Count for array/object. Gets 1 for all other types (string, number, null, etc.) Returns 0 if _value is not valid.
|
|
256
|
+
get length() {
|
|
257
|
+
if (this._status != 0 || !this._value_valid) {
|
|
258
|
+
return 0;
|
|
259
|
+
}
|
|
260
|
+
if (this._jsonType == "null") {
|
|
261
|
+
return 0;
|
|
262
|
+
}
|
|
263
|
+
if (this._jsonType != "array" && this._jsonType != "object") {
|
|
264
|
+
return 1;
|
|
265
|
+
}
|
|
266
|
+
// otherwise we are a _jsonType="object" or _jsonType="array"
|
|
267
|
+
try {
|
|
268
|
+
return this._value.length;
|
|
269
|
+
} catch {
|
|
270
|
+
return -1;
|
|
271
|
+
} //Error occurred... return -1 to indicate an error
|
|
272
|
+
}
|
|
273
|
+
// There is no "set" for length
|
|
274
|
+
|
|
275
|
+
Clear(ClearParent = true, src = 0, bClearStats = false) {
|
|
276
|
+
this._status = 0;
|
|
277
|
+
this._jsonType = "";
|
|
278
|
+
this._value = null;
|
|
279
|
+
this._value_valid = false;
|
|
280
|
+
this.InvalidateJsonString(src); // *** Resets _jsonString and _jsonString_valid (and notifies Parent of changes)
|
|
281
|
+
this.endpos = 0;
|
|
282
|
+
if (ClearParent) {
|
|
283
|
+
this.Parent = null;
|
|
284
|
+
}
|
|
285
|
+
} // end Clear()
|
|
286
|
+
|
|
287
|
+
InvalidateJsonString(src = 0) {
|
|
288
|
+
this._jsonString = "";
|
|
289
|
+
this._jsonString_valid = false;
|
|
290
|
+
// *** if our jsonString is invalid, { the PARENT jsonString would also be invalid
|
|
291
|
+
if (!(this.Parent == null)) {
|
|
292
|
+
this.Parent.InvalidateJsonString(2);
|
|
293
|
+
}
|
|
294
|
+
} // end InvalidateJsonString()
|
|
295
|
+
|
|
296
|
+
keepSpacingAndComments(spacing_flag = -1, comments_flag = -1) {
|
|
297
|
+
if (typeof spacing_flag == "boolean") {
|
|
298
|
+
this.keepSpacing = spacing_flag;
|
|
299
|
+
} else {
|
|
300
|
+
if (spacing_flag == 0) {
|
|
301
|
+
this.keepSpacing = false;
|
|
302
|
+
}
|
|
303
|
+
if (spacing_flag == 1) {
|
|
304
|
+
this.keepSpacing = true;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (typeof comments_flag == "boolean") {
|
|
308
|
+
this.keepComments = comments_flag;
|
|
309
|
+
} else {
|
|
310
|
+
if (comments_flag == 0) {
|
|
311
|
+
this.keepComments = false;
|
|
312
|
+
}
|
|
313
|
+
if (comments_flag == 1) {
|
|
314
|
+
this.keepComments = true;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
ValidateValue() {
|
|
320
|
+
if (this._status != 0) {
|
|
321
|
+
return false;
|
|
322
|
+
} // *** ERROR - status is invalid
|
|
323
|
+
if (!this._value_valid) {
|
|
324
|
+
if (!this._jsonString_valid) {
|
|
325
|
+
// *** Neither is valid - this JSON object is null - Cannot validate value
|
|
326
|
+
return false;
|
|
327
|
+
} else {
|
|
328
|
+
// *** First we need to Deserialize
|
|
329
|
+
DeserializeMe();
|
|
330
|
+
if (this._status != 0) {
|
|
331
|
+
return false;
|
|
332
|
+
} // *** ERROR - status is invalid - failed to Deserialize
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
} else {
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
value(idx, dotNotation = true) {
|
|
341
|
+
return this.v(idx, dotNotation);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
v(idx, dotNotation = true) {
|
|
345
|
+
//if (trackingStats) { IncStats("stat_Value_get"); } // FUTURE-NEW
|
|
346
|
+
if (!idx) {
|
|
347
|
+
// retun the value of this item
|
|
348
|
+
if (!this.ValidateValue()) {
|
|
349
|
+
return null;
|
|
350
|
+
} // *** Unable to validate/Deserialize the value
|
|
351
|
+
// If object or array, return null
|
|
352
|
+
if (this._jsonType == "object" || this._jsonType == "array") {
|
|
353
|
+
return null;
|
|
354
|
+
} // FUTURE-NEW: return object/array converted into javascript object/array? (indicate iteration level in method parameters)
|
|
355
|
+
return this._value;
|
|
356
|
+
} else {
|
|
357
|
+
return this.i(idx, dotNotation).v();
|
|
358
|
+
}
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
get thisValue() {
|
|
363
|
+
return this.v();
|
|
364
|
+
}
|
|
365
|
+
set thisValue(value) {
|
|
366
|
+
// sets the value of the FlexJson object and the jsonType
|
|
367
|
+
this.InvalidateJsonString(); // indicate that the JsonString has changed
|
|
368
|
+
this._status = 0;
|
|
369
|
+
this._jsonType = this.convertType(value);
|
|
370
|
+
if (this._jsonType == "string") {
|
|
371
|
+
this._value = value + ""; // force conversion to string
|
|
372
|
+
this._value_valid = true;
|
|
373
|
+
} else if (this._jsonType) {
|
|
374
|
+
this._value = value;
|
|
375
|
+
this._value_valid = true;
|
|
376
|
+
} else {
|
|
377
|
+
this._jsonType = "error";
|
|
378
|
+
this._value = null;
|
|
379
|
+
this._value_valid = false;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
toJsonArray(idx, dotNotation = true) {
|
|
384
|
+
//if (trackingStats) { IncStats("stat_Value_get"); } // FUTURE-NEW
|
|
385
|
+
if (!idx) {
|
|
386
|
+
// retun the value of this item
|
|
387
|
+
if (!this.ValidateValue()) {
|
|
388
|
+
return null;
|
|
389
|
+
} // *** Unable to validate/Deserialize the value
|
|
390
|
+
// If object or array, return null
|
|
391
|
+
if (this._jsonType == "object" || this._jsonType == "array") {
|
|
392
|
+
return this._value;
|
|
393
|
+
} // FUTURE-NEW: return object/array converted into javascript object/array? (indicate iteration level in method parameters)
|
|
394
|
+
return null;
|
|
395
|
+
} else {
|
|
396
|
+
return this.i(idx, dotNotation).toJsonArray();
|
|
397
|
+
}
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
ConvertToArray() {
|
|
402
|
+
// convert this FlexJson from an Object to an Array
|
|
403
|
+
// We can do this because the only real different between an array and an object is that the object has key values.
|
|
404
|
+
if (this._jsonType != "object") {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
this._jsonType = "array";
|
|
408
|
+
this.InvalidateJsonString();
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
item(idx, dotNotation = true) {
|
|
412
|
+
return this.i(idx, dotNotation);
|
|
413
|
+
}
|
|
414
|
+
i(idx, dotNotation = true) {
|
|
415
|
+
//if (trackingStats) { IncStats("stat_Item_get"); } // FUTURE-NEW
|
|
416
|
+
|
|
417
|
+
if (Number.isInteger(idx)) {
|
|
418
|
+
if (this.jsonType != "array" && this.jsonType != "object") {
|
|
419
|
+
return FlexJson.CreateNull();
|
|
420
|
+
}
|
|
421
|
+
if (idx < 0 || idx > this.length) {
|
|
422
|
+
return null;
|
|
423
|
+
} // error: we are past the end of the array/object
|
|
424
|
+
return this._value[idx];
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
var searchList;
|
|
428
|
+
let nextItem = this;
|
|
429
|
+
let k = -99; // tells loop not to perform 'next' function
|
|
430
|
+
if (dotNotation) {
|
|
431
|
+
searchList = idx.split(".");
|
|
432
|
+
} else {
|
|
433
|
+
searchList = [idx];
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
for (let sToken of searchList) {
|
|
437
|
+
let sKey = sToken.trim();
|
|
438
|
+
k = -1;
|
|
439
|
+
// Note: missing sKey causes failure to find item FUTURE: should we throw an error?
|
|
440
|
+
if (
|
|
441
|
+
sKey &&
|
|
442
|
+
(nextItem._jsonType == "object" || nextItem._jsonType == "array")
|
|
443
|
+
) {
|
|
444
|
+
let nKey = null;
|
|
445
|
+
try {
|
|
446
|
+
nCheck = parseInt(sKey);
|
|
447
|
+
if (!isNaN(nCheck)) {
|
|
448
|
+
nKey = nCheck;
|
|
449
|
+
}
|
|
450
|
+
} catch (Exception) {}
|
|
451
|
+
if (nKey) {
|
|
452
|
+
if (nKey < 0 || nKey >= this._value.length) {
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
k = nKey;
|
|
456
|
+
} else {
|
|
457
|
+
if (nextItem._jsonType == "object") {
|
|
458
|
+
k = nextItem.indexOfKey(sKey);
|
|
459
|
+
} else {
|
|
460
|
+
// type array: error because IDX for an array must be an integer
|
|
461
|
+
// FUTURE - throw error here?
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if (k < 0) {
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
nextItem = nextItem._value[k];
|
|
470
|
+
}
|
|
471
|
+
if (k < 0) {
|
|
472
|
+
return FlexJson.CreateNull();
|
|
473
|
+
} // NOTE! You can check that there is no PARENT on this null object to see that it was NOT-FOUND
|
|
474
|
+
|
|
475
|
+
return nextItem;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
forEach(callback) {
|
|
479
|
+
if (this.jsonType == "object" || this.jsonType == "array") {
|
|
480
|
+
for (let i = 0; i < this.length; i++) {
|
|
481
|
+
let jj = this.i(i); // debugger
|
|
482
|
+
callback(this.i(i));
|
|
483
|
+
} // end for
|
|
484
|
+
} else {
|
|
485
|
+
callback(this); // if we are not an object/array, then callback one time for this object
|
|
486
|
+
// FUTURE: Should we call back 0 times if we are a NULL or status!=0?
|
|
487
|
+
}
|
|
488
|
+
} // end forEach()
|
|
489
|
+
|
|
490
|
+
// This replaces addToObjBase and addToArrayBase (if array, second argument is not needed)
|
|
491
|
+
addToBase(value, idx = "") {
|
|
492
|
+
this.add(value, idx, false);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
add(value, idx = "", dotNotation = true) {
|
|
496
|
+
var newV;
|
|
497
|
+
var debugType = typeof value; /// debug debug debug
|
|
498
|
+
if (value === null) {
|
|
499
|
+
/// debug debug debug
|
|
500
|
+
console.log("is null");
|
|
501
|
+
}
|
|
502
|
+
if (
|
|
503
|
+
value !== null &&
|
|
504
|
+
typeof value === "object" &&
|
|
505
|
+
value.constructor.name === "FlexJson"
|
|
506
|
+
) {
|
|
507
|
+
newV = value; // FUTURE: clone?
|
|
508
|
+
} else {
|
|
509
|
+
newV = new FlexJson();
|
|
510
|
+
newV.thisValue = value; // This also sets the jsonType
|
|
511
|
+
}
|
|
512
|
+
newV.Parent = this;
|
|
513
|
+
|
|
514
|
+
// Can only add to an Object or Array
|
|
515
|
+
if (this._jsonType == "object") {
|
|
516
|
+
let foundItem = this.i(idx, dotNotation);
|
|
517
|
+
if (foundItem.Parent) {
|
|
518
|
+
// Item exists... replace the value
|
|
519
|
+
foundItem.thisValue = value; // this also sets jsonType
|
|
520
|
+
this.InvalidateJsonString(); // indicate that the JsonString has changed.
|
|
521
|
+
} else {
|
|
522
|
+
this.InvalidateJsonString(); // indicate that the JsonString has changed.
|
|
523
|
+
// Item does not exist... we need to add the item (be aware of dotNotation)
|
|
524
|
+
if (dotNotation && idx.indexOf(".") >= 0) {
|
|
525
|
+
// FUTURE: WHAT TO DO HERE!!
|
|
526
|
+
} else {
|
|
527
|
+
newV.key = idx;
|
|
528
|
+
this._value.push(newV);
|
|
529
|
+
//}
|
|
530
|
+
} // else
|
|
531
|
+
} // else
|
|
532
|
+
} else if (this._jsonType == "array") {
|
|
533
|
+
this.InvalidateJsonString(); // indicate that the JsonString has changed.
|
|
534
|
+
// Always push array value onto the end of the array
|
|
535
|
+
newV.key = "";
|
|
536
|
+
this._value.push(newV);
|
|
537
|
+
} else {
|
|
538
|
+
throw "ERROR: add() is only available for FlexJson object or array types.";
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
indexOfKey(Search) {
|
|
543
|
+
if (Search == null) {
|
|
544
|
+
return -1;
|
|
545
|
+
}
|
|
546
|
+
let s = Search.toLowerCase();
|
|
547
|
+
if (!this.ValidateValue()) {
|
|
548
|
+
return -1;
|
|
549
|
+
}
|
|
550
|
+
if (this._jsonType != "object") {
|
|
551
|
+
return -1;
|
|
552
|
+
} // Future: do we want to search for values here? probably not. Implement IndexOf for search of values?
|
|
553
|
+
let k = 0;
|
|
554
|
+
// NOTE: Here we do a linear search. FUTURE: if list is sorted, do a binary search.
|
|
555
|
+
for (let o of this._value) {
|
|
556
|
+
try {
|
|
557
|
+
if (o._key.toLowerCase() == s) {
|
|
558
|
+
return k;
|
|
559
|
+
}
|
|
560
|
+
} catch {}
|
|
561
|
+
k++;
|
|
562
|
+
}
|
|
563
|
+
return -1;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
contains(idx, dotNotation = true) {
|
|
567
|
+
let foundItem = this.i(idx, dotNotation);
|
|
568
|
+
if (foundItem.Parent) {
|
|
569
|
+
return true;
|
|
570
|
+
} else {
|
|
571
|
+
return false;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
getStr(idx, defaultValue = "", dotNotation = true) {
|
|
576
|
+
let foundItem = this.i(idx, dotNotation);
|
|
577
|
+
if (foundItem.Parent) {
|
|
578
|
+
return foundItem.toStr(defaultValue);
|
|
579
|
+
} else {
|
|
580
|
+
return defaultValue;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
getNum(idx, defaultValue = 0, dotNotation = true) {
|
|
585
|
+
// FUTURE-NEW: is there a more efficient way?
|
|
586
|
+
let foundItem = this.i(idx, dotNotation);
|
|
587
|
+
if (foundItem.Parent) {
|
|
588
|
+
return foundItem.toNum(defaultValue);
|
|
589
|
+
} else {
|
|
590
|
+
return defaultValue;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
getBool(idx, defaultValue = false, dotNotation = true) {
|
|
595
|
+
// FUTURE-NEW: is there a more efficient way?
|
|
596
|
+
let foundItem = this.i(idx, dotNotation);
|
|
597
|
+
if (foundItem.Parent) {
|
|
598
|
+
return foundItem.toBool(defaultValue);
|
|
599
|
+
} else {
|
|
600
|
+
return defaultValue;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
toStr(defaultValue = "") {
|
|
605
|
+
if (this._status != 0) {
|
|
606
|
+
return defaultValue;
|
|
607
|
+
} // Invalid status
|
|
608
|
+
if (!this._value_valid) {
|
|
609
|
+
return defaultValue;
|
|
610
|
+
}
|
|
611
|
+
if (this._jsonType == FlexJsonConstants.typeString) {
|
|
612
|
+
return this._value;
|
|
613
|
+
}
|
|
614
|
+
if (
|
|
615
|
+
this._jsonType == FlexJsonConstants.typeNull ||
|
|
616
|
+
this._jsonType == FlexJsonConstants.typeObject ||
|
|
617
|
+
this._jsonType == FlexJsonConstants.typeArray
|
|
618
|
+
) {
|
|
619
|
+
return defaultValue;
|
|
620
|
+
}
|
|
621
|
+
return this._value + "";
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
toNum(defaultValue = "") {
|
|
625
|
+
if (this._status != 0) {
|
|
626
|
+
return defaultValue;
|
|
627
|
+
} // Invalid status
|
|
628
|
+
if (!this._value_valid) {
|
|
629
|
+
return defaultValue;
|
|
630
|
+
}
|
|
631
|
+
if (this._jsonType == FlexJsonConstants.typeNumber) {
|
|
632
|
+
return this._value;
|
|
633
|
+
}
|
|
634
|
+
if (
|
|
635
|
+
this._jsonType == FlexJsonConstants.typeNull ||
|
|
636
|
+
this._jsonType == FlexJsonConstants.typeObject ||
|
|
637
|
+
this._jsonType == FlexJsonConstants.typeArray
|
|
638
|
+
) {
|
|
639
|
+
return defaultValue;
|
|
640
|
+
}
|
|
641
|
+
return Number(this._value);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
toBool(defaultValue = "") {
|
|
645
|
+
if (this._status != 0) {
|
|
646
|
+
return defaultValue;
|
|
647
|
+
} // Invalid status
|
|
648
|
+
if (!this._value_valid) {
|
|
649
|
+
return defaultValue;
|
|
650
|
+
}
|
|
651
|
+
if (this._jsonType == FlexJsonConstants.typeBoolean) {
|
|
652
|
+
return this._value;
|
|
653
|
+
}
|
|
654
|
+
if (
|
|
655
|
+
this._jsonType == FlexJsonConstants.typeNull ||
|
|
656
|
+
this._jsonType == FlexJsonConstants.typeObject ||
|
|
657
|
+
this._jsonType == FlexJsonConstants.typeArray
|
|
658
|
+
) {
|
|
659
|
+
return defaultValue;
|
|
660
|
+
}
|
|
661
|
+
return this.parseBoolean(this._value);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
parseBoolean(v) {
|
|
665
|
+
return !v || v === "false" || v === "False" || v === "FALSE" ? false : true;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
static CreateNull() {
|
|
669
|
+
let j = new FlexJson();
|
|
670
|
+
j._value = null;
|
|
671
|
+
j._jsonType = "null";
|
|
672
|
+
j._value_valid = true;
|
|
673
|
+
j._jsonString = "null";
|
|
674
|
+
j._jsonString_valid = true;
|
|
675
|
+
j._status = 0;
|
|
676
|
+
return j;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// SerializeMe() - Use this to Serialize the items that are already in the FlexJson object.
|
|
680
|
+
// Return: 0=OK, -1=Error
|
|
681
|
+
SerializeMe() {
|
|
682
|
+
let s = new StringBuilder();
|
|
683
|
+
let i = 0;
|
|
684
|
+
let k = 0;
|
|
685
|
+
let preKey = "";
|
|
686
|
+
let postKey = "";
|
|
687
|
+
//if (this.trackingStats) { IncStats("stat_SerializeMe"); }
|
|
688
|
+
if (this._status != 0) {
|
|
689
|
+
return -1;
|
|
690
|
+
}
|
|
691
|
+
if (!this.ValidateValue()) {
|
|
692
|
+
return -1;
|
|
693
|
+
}
|
|
694
|
+
try {
|
|
695
|
+
let preSpace = this.preSpace;
|
|
696
|
+
if (preSpace) {
|
|
697
|
+
// Here we ignore keepSpacing/keepComments - these flags are only used during the deserialize process
|
|
698
|
+
s.append(preSpace); // preSpace of overall object/array or item
|
|
699
|
+
}
|
|
700
|
+
switch (this._jsonType) {
|
|
701
|
+
case "object":
|
|
702
|
+
s.append("{");
|
|
703
|
+
i = 0;
|
|
704
|
+
this._value.forEach((o) => {
|
|
705
|
+
if (i > 0) {
|
|
706
|
+
s.append(",");
|
|
707
|
+
}
|
|
708
|
+
if (o.key == "data") {
|
|
709
|
+
console.log("debug here111"); // debug debug debug
|
|
710
|
+
}
|
|
711
|
+
let k = o.SerializeMe();
|
|
712
|
+
|
|
713
|
+
// Here we ignore keepSpacing/keepComments - these flags are only used during the deserialize process
|
|
714
|
+
// preSpace and postSpace are already added during the SerializeMe() call above. Here we add preKye and postKey.
|
|
715
|
+
let oPreKey = o.preKey || "";
|
|
716
|
+
let oPostKey = o.postKey || "";
|
|
717
|
+
|
|
718
|
+
if (k == 0 && o.Status == 0) {
|
|
719
|
+
s.append(
|
|
720
|
+
oPreKey +
|
|
721
|
+
'"' +
|
|
722
|
+
o.key.toString() +
|
|
723
|
+
'"' +
|
|
724
|
+
oPostKey +
|
|
725
|
+
":" +
|
|
726
|
+
o.jsonString
|
|
727
|
+
);
|
|
728
|
+
} else {
|
|
729
|
+
this._status = -53;
|
|
730
|
+
this.AddStatusMessage(
|
|
731
|
+
"ERROR: Failed to serialize Object item " +
|
|
732
|
+
i +
|
|
733
|
+
" [err-53][" +
|
|
734
|
+
o.Status +
|
|
735
|
+
":" +
|
|
736
|
+
o.StatusMessage +
|
|
737
|
+
"]"
|
|
738
|
+
);
|
|
739
|
+
return -1;
|
|
740
|
+
}
|
|
741
|
+
i++;
|
|
742
|
+
}); // end foreach
|
|
743
|
+
s.append("}");
|
|
744
|
+
break;
|
|
745
|
+
case "array":
|
|
746
|
+
s.append("[");
|
|
747
|
+
i = 0;
|
|
748
|
+
this._value.forEach((o) => {
|
|
749
|
+
if (i > 0) {
|
|
750
|
+
s.append(",");
|
|
751
|
+
}
|
|
752
|
+
k = o.SerializeMe();
|
|
753
|
+
if (k == 0 && o.Status == 0) {
|
|
754
|
+
s.append(o.jsonString);
|
|
755
|
+
} else {
|
|
756
|
+
this._status = -52;
|
|
757
|
+
this.AddStatusMessage(
|
|
758
|
+
"ERROR: Failed to serialize Array item " + i + " [err-52]"
|
|
759
|
+
);
|
|
760
|
+
return -1;
|
|
761
|
+
}
|
|
762
|
+
i++;
|
|
763
|
+
});
|
|
764
|
+
s.append("]");
|
|
765
|
+
break;
|
|
766
|
+
case "null":
|
|
767
|
+
s.append("null");
|
|
768
|
+
break;
|
|
769
|
+
case "string":
|
|
770
|
+
s.append('"' + this.EncodeString(this.toStr()) + '"');
|
|
771
|
+
break;
|
|
772
|
+
default:
|
|
773
|
+
s.append(this.toStr()); // FUTURE: better approach? seems prone to problems
|
|
774
|
+
break;
|
|
775
|
+
}
|
|
776
|
+
let postSpace = "" + (this.postSpace || "") + (this.finalSpace || "");
|
|
777
|
+
if (postSpace) {
|
|
778
|
+
s.append(postSpace);
|
|
779
|
+
}
|
|
780
|
+
this._jsonString = s.toString();
|
|
781
|
+
this._jsonString_valid = true;
|
|
782
|
+
} catch (err94) {
|
|
783
|
+
this._jsonString = "";
|
|
784
|
+
this.InvalidateJsonString(1);
|
|
785
|
+
this._status = -94;
|
|
786
|
+
// FUTURE: Remove err94.message below?
|
|
787
|
+
this.AddStatusMessage(
|
|
788
|
+
"ERROR: SerializeMe() failed to serialize the FlexJson object. [err-94] " +
|
|
789
|
+
err94.message
|
|
790
|
+
);
|
|
791
|
+
return -1;
|
|
792
|
+
}
|
|
793
|
+
return 0;
|
|
794
|
+
} // end SerializeMe()
|
|
795
|
+
|
|
796
|
+
EncodeString(vString = "") {
|
|
797
|
+
let s;
|
|
798
|
+
// *** NOTE: This is a simple encode. It needs to be expanded in the future!
|
|
799
|
+
s = vString;
|
|
800
|
+
s = s.replace(/\\/g, "\\\\"); // **** NOTE: THIS MUST BE FIRST (so we do not double-escape the items below!)
|
|
801
|
+
s = s.replace(/\t/g, "\\t");
|
|
802
|
+
s = s.replace(/\n/g, "\\n");
|
|
803
|
+
s = s.replace(/\r/g, "\\r");
|
|
804
|
+
s = s.replace(/"/g, '\\"');
|
|
805
|
+
if (this.ENCODE_SINGLE_QUOTES) {
|
|
806
|
+
s = s.replace(/'/g, "\\'");
|
|
807
|
+
}
|
|
808
|
+
return s;
|
|
809
|
+
} // End Function
|
|
810
|
+
|
|
811
|
+
Deserialize(snewString, start = 0, OkToClip = false) {
|
|
812
|
+
if (this.trackingStats) {
|
|
813
|
+
IncStats("stat_Deserialize");
|
|
814
|
+
}
|
|
815
|
+
this.Clear(false, 1);
|
|
816
|
+
this._jsonString = snewString;
|
|
817
|
+
this._jsonString_valid = true;
|
|
818
|
+
|
|
819
|
+
let startPos = new FlexJsonPosition(0, start, start);
|
|
820
|
+
// FUTURE: determine start position LINE COUNT???
|
|
821
|
+
// if (start>0) { lineCount = countLines(ref _jsonString, start); }
|
|
822
|
+
|
|
823
|
+
this.DeserializeMeI(this._jsonString, startPos, OkToClip);
|
|
824
|
+
return this._status;
|
|
825
|
+
} // End Function
|
|
826
|
+
|
|
827
|
+
DeserializeFlex(snewString, start = 0, OkToClip = false) {
|
|
828
|
+
this.UseFlexJson = true;
|
|
829
|
+
this.Deserialize(snewString, start, OkToClip);
|
|
830
|
+
return this._status;
|
|
831
|
+
} // End Function
|
|
832
|
+
|
|
833
|
+
DeserializeMeI(
|
|
834
|
+
meJsonString,
|
|
835
|
+
start,
|
|
836
|
+
OkToClip = false,
|
|
837
|
+
MustBeString = false,
|
|
838
|
+
SearchFor1 = "*",
|
|
839
|
+
SearchFor2 = "*",
|
|
840
|
+
SearchFor3 = "*"
|
|
841
|
+
) {
|
|
842
|
+
var c;
|
|
843
|
+
var c2;
|
|
844
|
+
let getSpace = "";
|
|
845
|
+
let meString = "";
|
|
846
|
+
//if (trackingStats) { IncStats("stat_DeserializeMeI"); } // FUTURE-NEW
|
|
847
|
+
this._status = 0;
|
|
848
|
+
this.StartPosition = start.clone(); // store in meta (if ok to do so)
|
|
849
|
+
let meStatus = FlexJsonConstants.ST_BEFORE_ITEM;
|
|
850
|
+
let quoteChar = "";
|
|
851
|
+
this._key = null; // *** Default
|
|
852
|
+
this._value = null; // *** Default
|
|
853
|
+
this._value_valid = false; // *** In case of error, default is invalid
|
|
854
|
+
this._jsonType = FlexJsonConstants.typeNull; // default
|
|
855
|
+
let jsonEndPoint = meJsonString.length - 1;
|
|
856
|
+
|
|
857
|
+
let mePos = start.clone(); // FlexJsonPosition USE THIS TO TRACK POSITION, THEN SET endpos ONCE DONE OR ON ERROR
|
|
858
|
+
let keepSP = this.keepSpacing;
|
|
859
|
+
let keepCM = this.keepComments;
|
|
860
|
+
|
|
861
|
+
//FlexJsonPosition startOfMe = null;
|
|
862
|
+
let safety = jsonEndPoint + 999;
|
|
863
|
+
let ok = false;
|
|
864
|
+
let breakBreak = false;
|
|
865
|
+
let storeStatus = FlexJsonConstants.ST_BEFORE_ITEM; // should not matter, but just in case
|
|
866
|
+
while (
|
|
867
|
+
meStatus >= 0 &&
|
|
868
|
+
this._status >= 0 &&
|
|
869
|
+
mePos.absolutePosition <= jsonEndPoint
|
|
870
|
+
) {
|
|
871
|
+
c = meJsonString.charAt(mePos.absolutePosition);
|
|
872
|
+
if (mePos.absolutePosition < jsonEndPoint) {
|
|
873
|
+
c2 = meJsonString.substr(mePos.absolutePosition, 2);
|
|
874
|
+
} else {
|
|
875
|
+
c2 = "";
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
switch (meStatus) {
|
|
879
|
+
case FlexJsonConstants.ST_BEFORE_ITEM:
|
|
880
|
+
if (SearchFor1 != "*" && c == SearchFor1) {
|
|
881
|
+
breakBreak = true;
|
|
882
|
+
break;
|
|
883
|
+
} // Found search character
|
|
884
|
+
if (SearchFor2 != "*" && c == SearchFor2) {
|
|
885
|
+
breakBreak = true;
|
|
886
|
+
break;
|
|
887
|
+
} // Found search character
|
|
888
|
+
if (SearchFor3 != "*" && c == SearchFor3) {
|
|
889
|
+
breakBreak = true;
|
|
890
|
+
break;
|
|
891
|
+
} // Found search character
|
|
892
|
+
if (c == " " || c == "\t" || c == "\n" || c == "\r") {
|
|
893
|
+
// white space before item
|
|
894
|
+
ok = true;
|
|
895
|
+
if (keepSP) {
|
|
896
|
+
getSpace += c;
|
|
897
|
+
}
|
|
898
|
+
} else if (c == "{") {
|
|
899
|
+
if (MustBeString) {
|
|
900
|
+
this._status = -124;
|
|
901
|
+
this.AddStatusMessage(
|
|
902
|
+
"Invalid character '{' found. Expected string. @Line:" +
|
|
903
|
+
mePos.lineNumber +
|
|
904
|
+
", @Position:" +
|
|
905
|
+
mePos.linePosition +
|
|
906
|
+
" [err-124]"
|
|
907
|
+
);
|
|
908
|
+
breakBreak = true;
|
|
909
|
+
break;
|
|
910
|
+
}
|
|
911
|
+
ok = true;
|
|
912
|
+
//startOfMe=mePos;
|
|
913
|
+
this._jsonType = FlexJsonConstants.typeObject;
|
|
914
|
+
mePos = this.DeserializeObject(meJsonString, mePos, keepSP, keepCM);
|
|
915
|
+
meStatus = FlexJsonConstants.ST_AFTER_ITEM;
|
|
916
|
+
if (this._status != 0) {
|
|
917
|
+
breakBreak = true;
|
|
918
|
+
break;
|
|
919
|
+
} // ERROR message should have already been generated.
|
|
920
|
+
} else if (c == "[") {
|
|
921
|
+
if (MustBeString) {
|
|
922
|
+
this._status = -125;
|
|
923
|
+
this.AddStatusMessage(
|
|
924
|
+
"Invalid character '[' found. Expected string. @Line:" +
|
|
925
|
+
mePos.lineNumber +
|
|
926
|
+
", @Position:" +
|
|
927
|
+
mePos.linePosition +
|
|
928
|
+
" [err-125]"
|
|
929
|
+
);
|
|
930
|
+
breakBreak = true;
|
|
931
|
+
break;
|
|
932
|
+
}
|
|
933
|
+
ok = true;
|
|
934
|
+
//startOfMe=mePos;
|
|
935
|
+
this._jsonType = FlexJsonConstants.typeArray;
|
|
936
|
+
mePos = this.DeserializeArray(meJsonString, mePos, keepSP, keepCM);
|
|
937
|
+
meStatus = FlexJsonConstants.ST_AFTER_ITEM;
|
|
938
|
+
if (this._status != 0) {
|
|
939
|
+
breakBreak = true;
|
|
940
|
+
break;
|
|
941
|
+
} // ERROR message should have already been generated.
|
|
942
|
+
} else if (c == '"') {
|
|
943
|
+
ok = true;
|
|
944
|
+
//startOfMe=mePos;
|
|
945
|
+
this._jsonType = FlexJsonConstants.typeString;
|
|
946
|
+
quoteChar = '"';
|
|
947
|
+
this._stringQuote = '"';
|
|
948
|
+
meStatus = FlexJsonConstants.ST_STRING;
|
|
949
|
+
} else if (this.ALLOW_SINGLE_QUOTE_STRINGS && c == "'") {
|
|
950
|
+
ok = true;
|
|
951
|
+
//startOfMe=mePos;
|
|
952
|
+
this._jsonType = FlexJsonConstants.typeString;
|
|
953
|
+
quoteChar = "'";
|
|
954
|
+
this._stringQuote = "'";
|
|
955
|
+
meStatus = FlexJsonConstants.ST_STRING;
|
|
956
|
+
} else if (this._UseFlexJson) {
|
|
957
|
+
if (c2 == "//") {
|
|
958
|
+
// start of to-end-of-line comment
|
|
959
|
+
ok = true;
|
|
960
|
+
meStatus = FlexJsonConstants.ST_EOL_COMMENT;
|
|
961
|
+
mePos.increment(); // so we skip 2 characters
|
|
962
|
+
if (keepCM) {
|
|
963
|
+
getSpace += c2;
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
if (c2 == "/*") {
|
|
967
|
+
// start of asterix comment
|
|
968
|
+
ok = true;
|
|
969
|
+
meStatus = FlexJsonConstants.ST_AST_COMMENT;
|
|
970
|
+
mePos.increment(); // so we skip 2 characters
|
|
971
|
+
if (keepCM) {
|
|
972
|
+
getSpace += c2;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
// With or without FlexJSON, we allow simple strings without quotes - cannot contain commas, spaces, special characters, etc
|
|
977
|
+
// Later we will determine if this is a number, boolean, null, or unquoted-string (string is only allowed with FlexJSON)
|
|
978
|
+
if (
|
|
979
|
+
(c >= "A" && c <= "Z") ||
|
|
980
|
+
(c >= "a" && c <= "z") ||
|
|
981
|
+
(c >= "0" && c <= "9") ||
|
|
982
|
+
c == "-" ||
|
|
983
|
+
c == "_" ||
|
|
984
|
+
c == "."
|
|
985
|
+
) {
|
|
986
|
+
ok = true;
|
|
987
|
+
//startOfMe=mePos;
|
|
988
|
+
this._jsonType = "nqstring"; // NOTE! THIS IS NOT A REAL TYPE - IT IS A FLAG FOR LATER
|
|
989
|
+
this._stringQuote = " ";
|
|
990
|
+
meStatus = FlexJsonConstants.ST_STRING_NO_QUOTE;
|
|
991
|
+
}
|
|
992
|
+
if (!ok) {
|
|
993
|
+
// generate error condition - invalid character
|
|
994
|
+
this._status = -102;
|
|
995
|
+
this.AddStatusMessage("ERROR: Invalid charater. [err-102]");
|
|
996
|
+
breakBreak = true;
|
|
997
|
+
break;
|
|
998
|
+
}
|
|
999
|
+
// if we are no longer in pre-space territory, the we need to store the whitespace/comments
|
|
1000
|
+
if (meStatus >= FlexJsonConstants.ST_STRING) {
|
|
1001
|
+
if (keepCM || keepSP) {
|
|
1002
|
+
preSpace = getSpace;
|
|
1003
|
+
getSpace = ""; // clear
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
if (
|
|
1007
|
+
meStatus == FlexJsonConstants.ST_STRING ||
|
|
1008
|
+
meStatus == FlexJsonConstants.ST_STRING_NO_QUOTE
|
|
1009
|
+
) {
|
|
1010
|
+
meString = "";
|
|
1011
|
+
if (c != '"' && c != "'") {
|
|
1012
|
+
meString += c;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
break;
|
|
1016
|
+
case FlexJsonConstants.ST_AFTER_ITEM:
|
|
1017
|
+
if (SearchFor1 != "*" && c == SearchFor1) {
|
|
1018
|
+
breakBreak = true;
|
|
1019
|
+
break;
|
|
1020
|
+
} // Found search character
|
|
1021
|
+
if (SearchFor2 != "*" && c == SearchFor2) {
|
|
1022
|
+
breakBreak = true;
|
|
1023
|
+
break;
|
|
1024
|
+
} // Found search character
|
|
1025
|
+
if (SearchFor3 != "*" && c == SearchFor3) {
|
|
1026
|
+
breakBreak = true;
|
|
1027
|
+
break;
|
|
1028
|
+
} // Found search character
|
|
1029
|
+
if (c == " " || c == "\t" || c == "\n" || c == "\r") {
|
|
1030
|
+
// white space before item
|
|
1031
|
+
ok = true;
|
|
1032
|
+
if (keepSP) {
|
|
1033
|
+
getSpace += c;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
if (this._UseFlexJson) {
|
|
1037
|
+
if (c2 == "//") {
|
|
1038
|
+
// start of to-end-of-line comment
|
|
1039
|
+
ok = true;
|
|
1040
|
+
storeStatus = meStatus;
|
|
1041
|
+
meStatus = FlexJsonConstants.ST_EOL_COMMENT_POST;
|
|
1042
|
+
mePos.increment(); // so we skip 2 characters
|
|
1043
|
+
if (keepCM) {
|
|
1044
|
+
getSpace += c2;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
if (c2 == "/*") {
|
|
1048
|
+
// start of asterix comment
|
|
1049
|
+
ok = true;
|
|
1050
|
+
storeStatus = meStatus;
|
|
1051
|
+
meStatus = FlexJsonConstants.ST_AST_COMMENT_POST;
|
|
1052
|
+
mePos.increment(); // so we skip 2 characters
|
|
1053
|
+
if (keepCM) {
|
|
1054
|
+
getSpace += c2;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
if (!ok) {
|
|
1059
|
+
// generate error condition (unless OKToClip)
|
|
1060
|
+
if (OkToClip) {
|
|
1061
|
+
// if we are keeping comments+ then we should probably grab this garbage text
|
|
1062
|
+
// This will allow us to modify a FlexJSON text file/block and write it back "AS IS"
|
|
1063
|
+
if (keepCM) {
|
|
1064
|
+
let finalGarbage = meJsonString.substr(
|
|
1065
|
+
mePos.absolutePosition,
|
|
1066
|
+
meJsonString.length - mePos.absolutePosition
|
|
1067
|
+
);
|
|
1068
|
+
getSpace += finalGarbage;
|
|
1069
|
+
}
|
|
1070
|
+
breakBreak = true;
|
|
1071
|
+
break;
|
|
1072
|
+
}
|
|
1073
|
+
this._status = -192;
|
|
1074
|
+
this.AddStatusMessage(
|
|
1075
|
+
"ERROR: Additional text found after end of JSON. [err-192]"
|
|
1076
|
+
);
|
|
1077
|
+
breakBreak = true;
|
|
1078
|
+
break;
|
|
1079
|
+
}
|
|
1080
|
+
break;
|
|
1081
|
+
case FlexJsonConstants.ST_EOL_COMMENT:
|
|
1082
|
+
case FlexJsonConstants.ST_EOL_COMMENT_POST:
|
|
1083
|
+
if (c2 == FlexJsonConstants.NEWLINE) {
|
|
1084
|
+
ok = true;
|
|
1085
|
+
if (keepSP) {
|
|
1086
|
+
getSpace += c2;
|
|
1087
|
+
}
|
|
1088
|
+
meStatus = storeStatus;
|
|
1089
|
+
|
|
1090
|
+
mePos.incrementLine(2);
|
|
1091
|
+
continue; // NOTE: Here we must skip the end of the do loop so that we do not increment the counter again
|
|
1092
|
+
} else if (c == "\n" || c == "\r") {
|
|
1093
|
+
ok = true;
|
|
1094
|
+
if (keepSP) {
|
|
1095
|
+
getSpace += c;
|
|
1096
|
+
}
|
|
1097
|
+
meStatus = storeStatus;
|
|
1098
|
+
} else {
|
|
1099
|
+
// absorb all comment characters
|
|
1100
|
+
ok = true;
|
|
1101
|
+
if (keepSP) {
|
|
1102
|
+
getSpace += c;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
break;
|
|
1106
|
+
case FlexJsonConstants.ST_AST_COMMENT:
|
|
1107
|
+
case FlexJsonConstants.ST_AST_COMMENT_POST:
|
|
1108
|
+
if (c2 == "*/") {
|
|
1109
|
+
ok = true;
|
|
1110
|
+
if (keepSP) {
|
|
1111
|
+
getSpace += c2;
|
|
1112
|
+
}
|
|
1113
|
+
meStatus = storeStatus;
|
|
1114
|
+
|
|
1115
|
+
mePos.increment(); // increment by 1 here - increments again at bottom of do loop
|
|
1116
|
+
} else {
|
|
1117
|
+
// absorb all comment characters
|
|
1118
|
+
ok = true;
|
|
1119
|
+
if (keepSP) {
|
|
1120
|
+
getSpace += c;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
break;
|
|
1124
|
+
case FlexJsonConstants.ST_STRING:
|
|
1125
|
+
if (c == quoteChar) {
|
|
1126
|
+
// we reached the end of the string
|
|
1127
|
+
ok = true;
|
|
1128
|
+
meStatus = FlexJsonConstants.ST_AFTER_ITEM;
|
|
1129
|
+
} else if (c == "\\") {
|
|
1130
|
+
// escaped character
|
|
1131
|
+
mePos.increment();
|
|
1132
|
+
c = meJsonString[mePos.absolutePosition];
|
|
1133
|
+
switch (c) {
|
|
1134
|
+
case "\\":
|
|
1135
|
+
case "/":
|
|
1136
|
+
case "'":
|
|
1137
|
+
case '"':
|
|
1138
|
+
meString += c;
|
|
1139
|
+
break;
|
|
1140
|
+
case "t":
|
|
1141
|
+
meString += "\t"; //Tab character
|
|
1142
|
+
break;
|
|
1143
|
+
case "b":
|
|
1144
|
+
meString += Convert.ToChar(8);
|
|
1145
|
+
break;
|
|
1146
|
+
case "c":
|
|
1147
|
+
meString += Convert.ToChar(13);
|
|
1148
|
+
break;
|
|
1149
|
+
case "n":
|
|
1150
|
+
meString += "\n"; //New Line Character
|
|
1151
|
+
break;
|
|
1152
|
+
case "r":
|
|
1153
|
+
meString += "\r"; //LineFeedCarriageReturn
|
|
1154
|
+
break;
|
|
1155
|
+
case "v":
|
|
1156
|
+
meString += "*"; // ***** FUTURE: Need to determine this character!
|
|
1157
|
+
break;
|
|
1158
|
+
case "u":
|
|
1159
|
+
// *** Here we need to get the next 4 digits and turn them into a character
|
|
1160
|
+
if (mePos.absolutePosition > jsonEndPoint - 4) {
|
|
1161
|
+
this._status = -157;
|
|
1162
|
+
this.AddStatusMessage(
|
|
1163
|
+
"ERROR: Invalid \\u escape sequence. [err-157]"
|
|
1164
|
+
);
|
|
1165
|
+
breakBreak = true;
|
|
1166
|
+
break;
|
|
1167
|
+
}
|
|
1168
|
+
c2 = substr(meJsonString, mePos.absolutePosition + 1, 4);
|
|
1169
|
+
if (IsHex4(c2)) {
|
|
1170
|
+
// FUTURE-NEW!!! FIX THIS! TODO - NOW- PROBLEM!!!
|
|
1171
|
+
let asciiValue = "####"; //System.Convert.ToChar(System.Convert.ToUInt32(c, 16)) + "";
|
|
1172
|
+
meString += asciiValue;
|
|
1173
|
+
mePos.increment(4);
|
|
1174
|
+
} else {
|
|
1175
|
+
// *** Invalid format
|
|
1176
|
+
this._status = -151;
|
|
1177
|
+
this.AddStatusMessage(
|
|
1178
|
+
"Expected \\u escape sequence to be followed by a valid four-digit hex value @Line:" +
|
|
1179
|
+
mePos.lineNumber +
|
|
1180
|
+
" @Position:" +
|
|
1181
|
+
mePos.linePosition +
|
|
1182
|
+
" (e-151)"
|
|
1183
|
+
);
|
|
1184
|
+
breakBreak = true;
|
|
1185
|
+
break;
|
|
1186
|
+
}
|
|
1187
|
+
break;
|
|
1188
|
+
default:
|
|
1189
|
+
// *** Invalid format
|
|
1190
|
+
this._status = -152;
|
|
1191
|
+
this.AddStatusMessage(
|
|
1192
|
+
"The \\ escape character is not followed by a valid value @Line:" +
|
|
1193
|
+
mePos.lineNumber +
|
|
1194
|
+
" @Position:" +
|
|
1195
|
+
mePos.linePosition +
|
|
1196
|
+
" (e-152)"
|
|
1197
|
+
);
|
|
1198
|
+
breakBreak = true;
|
|
1199
|
+
break;
|
|
1200
|
+
} //End switch
|
|
1201
|
+
} else {
|
|
1202
|
+
meString += c;
|
|
1203
|
+
}
|
|
1204
|
+
break;
|
|
1205
|
+
case FlexJsonConstants.ST_STRING_NO_QUOTE:
|
|
1206
|
+
if (SearchFor1 != "*" && c == SearchFor1) {
|
|
1207
|
+
breakBreak = true;
|
|
1208
|
+
break;
|
|
1209
|
+
} // Found search character
|
|
1210
|
+
if (SearchFor2 != "*" && c == SearchFor2) {
|
|
1211
|
+
breakBreak = true;
|
|
1212
|
+
break;
|
|
1213
|
+
} // Found search character
|
|
1214
|
+
if (SearchFor3 != "*" && c == SearchFor3) {
|
|
1215
|
+
breakBreak = true;
|
|
1216
|
+
break;
|
|
1217
|
+
} // Found search character
|
|
1218
|
+
if (
|
|
1219
|
+
(c >= "A" && c <= "Z") ||
|
|
1220
|
+
(c >= "a" && c <= "z") ||
|
|
1221
|
+
(c >= "0" && c <= "9") ||
|
|
1222
|
+
c == "-" ||
|
|
1223
|
+
c == "_" ||
|
|
1224
|
+
c == "."
|
|
1225
|
+
) {
|
|
1226
|
+
ok = true;
|
|
1227
|
+
meString += c;
|
|
1228
|
+
} else if (c2 == FlexJsonConstants.NEWLINE) {
|
|
1229
|
+
// consume this as whitespace
|
|
1230
|
+
ok = true;
|
|
1231
|
+
if (keepSP) {
|
|
1232
|
+
getSpace += c2;
|
|
1233
|
+
}
|
|
1234
|
+
mePos.incrementLine(2);
|
|
1235
|
+
meStatus = FlexJsonConstants.ST_AFTER_ITEM;
|
|
1236
|
+
continue; // so that we do not increment mePos again
|
|
1237
|
+
} else if (c == " " || c == "\t" || c == "\r" || c == "\n") {
|
|
1238
|
+
// consume this as whitespace
|
|
1239
|
+
ok = true;
|
|
1240
|
+
if (keepSP) {
|
|
1241
|
+
getSpace += c;
|
|
1242
|
+
}
|
|
1243
|
+
meStatus = FlexJsonConstants.ST_AFTER_ITEM;
|
|
1244
|
+
} else {
|
|
1245
|
+
// not a valid character
|
|
1246
|
+
this._status = -159;
|
|
1247
|
+
this.AddStatusMessage(
|
|
1248
|
+
"Invalid character found in non-quoted string: char:[" +
|
|
1249
|
+
c +
|
|
1250
|
+
"] @Line:" +
|
|
1251
|
+
mePos.lineNumber +
|
|
1252
|
+
" @Position:" +
|
|
1253
|
+
mePos.linePosition +
|
|
1254
|
+
" (e-159)"
|
|
1255
|
+
);
|
|
1256
|
+
breakBreak = true;
|
|
1257
|
+
break;
|
|
1258
|
+
}
|
|
1259
|
+
break;
|
|
1260
|
+
}
|
|
1261
|
+
if (breakBreak) {
|
|
1262
|
+
break;
|
|
1263
|
+
}
|
|
1264
|
+
// move to next character
|
|
1265
|
+
if (c == "\n") {
|
|
1266
|
+
mePos.incrementLine(1);
|
|
1267
|
+
} else {
|
|
1268
|
+
mePos.increment();
|
|
1269
|
+
}
|
|
1270
|
+
safety--;
|
|
1271
|
+
if (safety <= 0) {
|
|
1272
|
+
this._status = -169;
|
|
1273
|
+
this.AddStatusMessage(
|
|
1274
|
+
"Maximum iterations reached: DeserializeMe(): @Line:" +
|
|
1275
|
+
mePos.lineNumber +
|
|
1276
|
+
" @Position:" +
|
|
1277
|
+
mePos.linePosition +
|
|
1278
|
+
" (e-169)"
|
|
1279
|
+
);
|
|
1280
|
+
break;
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
if (this._status == 0) {
|
|
1285
|
+
switch (this._jsonType) {
|
|
1286
|
+
case FlexJsonConstants.typeString:
|
|
1287
|
+
this._value = meString;
|
|
1288
|
+
break;
|
|
1289
|
+
case "nqstring": // NOTE! This is objType must be converted to another type here! nqstring is not a real type.
|
|
1290
|
+
let tmpString = meString; // do not need to trim since we should have consumed the whitespace in getSpace
|
|
1291
|
+
if (!MustBeString) {
|
|
1292
|
+
if (tmpString.length < 7) {
|
|
1293
|
+
var tmpStringUpper = tmpString.trim().toUpperCase();
|
|
1294
|
+
if (tmpStringUpper == "" || tmpStringUpper == "NULL") {
|
|
1295
|
+
this._value = "";
|
|
1296
|
+
this._jsonType = FlexJsonConstants.typeNull;
|
|
1297
|
+
} else if (tmpStringUpper == "TRUE") {
|
|
1298
|
+
this._value = true;
|
|
1299
|
+
this._jsonType = FlexJsonConstants.typeBoolean;
|
|
1300
|
+
} else if (tmpStringUpper == "FALSE") {
|
|
1301
|
+
this._value = false;
|
|
1302
|
+
this._jsonType = FlexJsonConstants.typeBoolean;
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
// If the above did not match, lets see if this text is numeric...
|
|
1306
|
+
if (this._jsonType == "nqstring") {
|
|
1307
|
+
try {
|
|
1308
|
+
valueCheck = parseFloat(tmpString);
|
|
1309
|
+
if (!isNaN(valueCheck)) {
|
|
1310
|
+
this._value = valueCheck;
|
|
1311
|
+
|
|
1312
|
+
// It worked... keep going...
|
|
1313
|
+
this._jsonType = FlexJsonConstants.typeNumber;
|
|
1314
|
+
}
|
|
1315
|
+
} catch (Exception) {}
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
// If STILL not identified, then it must be a STRING (ONLY valid as an unquoted string if using FlexJson!)
|
|
1319
|
+
if (this._jsonType == "nqstring") {
|
|
1320
|
+
this._value = tmpString;
|
|
1321
|
+
this._jsonType = FlexJsonConstants.typeString;
|
|
1322
|
+
if (!this._UseFlexJson) {
|
|
1323
|
+
// ERROR: we found an unquoted string and we are not using FlexJson
|
|
1324
|
+
// NOTE! Error occurred at the START of this item
|
|
1325
|
+
this._status = -199;
|
|
1326
|
+
this.AddStatusMessage(
|
|
1327
|
+
"Encountered unquoted string: @Line:" +
|
|
1328
|
+
start.lineNumber +
|
|
1329
|
+
" @Position:" +
|
|
1330
|
+
start.linePosition +
|
|
1331
|
+
" (e-199)"
|
|
1332
|
+
);
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
break;
|
|
1336
|
+
// NOTE: other cases fall through: object, array, null(default if nothing found)
|
|
1337
|
+
} // end switch
|
|
1338
|
+
} // end if (this._status != 0)
|
|
1339
|
+
|
|
1340
|
+
// indicate if the new _value is valid
|
|
1341
|
+
if (this._status == 0) {
|
|
1342
|
+
this._value_valid = true;
|
|
1343
|
+
} else {
|
|
1344
|
+
this._value_valid = false;
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
// Store original JSON string and mark as "valid"
|
|
1348
|
+
if (this._status == 0) {
|
|
1349
|
+
this._jsonString = meJsonString.substr(
|
|
1350
|
+
start.absolutePosition,
|
|
1351
|
+
mePos.absolutePosition - start.absolutePosition
|
|
1352
|
+
);
|
|
1353
|
+
this._jsonString_valid = true;
|
|
1354
|
+
} else {
|
|
1355
|
+
this._jsonString = meJsonString;
|
|
1356
|
+
this._jsonString_valid = false;
|
|
1357
|
+
}
|
|
1358
|
+
if (getSpace != null) {
|
|
1359
|
+
this.finalSpace = getSpace;
|
|
1360
|
+
}
|
|
1361
|
+
this.EndPosition = mePos;
|
|
1362
|
+
|
|
1363
|
+
return mePos;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
CreatePartClone(keepSP = false, keepCM = false) {
|
|
1367
|
+
let jClone = new FlexJson();
|
|
1368
|
+
jClone.UseFlexJson = this.UseFlexJson;
|
|
1369
|
+
jClone.ALLOW_SINGLE_QUOTE_STRINGS = this.ALLOW_SINGLE_QUOTE_STRINGS;
|
|
1370
|
+
return jClone;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
DeserializeObject(meJsonString, start, keepSP, keepCM) {
|
|
1374
|
+
var j2;
|
|
1375
|
+
var jNew;
|
|
1376
|
+
let Key = "";
|
|
1377
|
+
var c;
|
|
1378
|
+
|
|
1379
|
+
let v = [];
|
|
1380
|
+
let mePos = start;
|
|
1381
|
+
mePos.increment(); // *** IMPORTANT! Move past { symbol
|
|
1382
|
+
let skipToNext = false;
|
|
1383
|
+
|
|
1384
|
+
let safety = 99999;
|
|
1385
|
+
while (true) {
|
|
1386
|
+
skipToNext = false;
|
|
1387
|
+
j2 = this.CreatePartClone(keepSP, keepCM);
|
|
1388
|
+
let newPos = j2.DeserializeMeI(
|
|
1389
|
+
meJsonString,
|
|
1390
|
+
mePos.clone(),
|
|
1391
|
+
true,
|
|
1392
|
+
true,
|
|
1393
|
+
":",
|
|
1394
|
+
",",
|
|
1395
|
+
"}"
|
|
1396
|
+
); // finding a } means there are no more items in the object
|
|
1397
|
+
|
|
1398
|
+
if (j2._status == 0 && j2._jsonType == FlexJsonConstants.typeNull) {
|
|
1399
|
+
// special case where item is NULL/BLANK - ok to skip...
|
|
1400
|
+
c = meJsonString.charAt(newPos.absolutePosition);
|
|
1401
|
+
if (c == "," || c == "}") {
|
|
1402
|
+
mePos = newPos;
|
|
1403
|
+
skipToNext = true;
|
|
1404
|
+
} else {
|
|
1405
|
+
this.StatusErr(
|
|
1406
|
+
-18,
|
|
1407
|
+
"Failed to find key in key:value pair @Line:" +
|
|
1408
|
+
mePos.lineNumber +
|
|
1409
|
+
" @Position:" +
|
|
1410
|
+
mePos.linePosition +
|
|
1411
|
+
" (e-18) [" +
|
|
1412
|
+
j2.StatusMessage +
|
|
1413
|
+
"]"
|
|
1414
|
+
);
|
|
1415
|
+
break;
|
|
1416
|
+
}
|
|
1417
|
+
} else if (j2._status != 0) {
|
|
1418
|
+
this.StatusErr(
|
|
1419
|
+
-19,
|
|
1420
|
+
"Failed to find key in key:value pair @Line:" +
|
|
1421
|
+
mePos.lineNumber +
|
|
1422
|
+
" @Position:" +
|
|
1423
|
+
mePos.linePosition +
|
|
1424
|
+
" (e-19) [" +
|
|
1425
|
+
j2.StatusMessage +
|
|
1426
|
+
"]"
|
|
1427
|
+
);
|
|
1428
|
+
break;
|
|
1429
|
+
// }
|
|
1430
|
+
} else if (j2._jsonType != "string") {
|
|
1431
|
+
this.StatusErr(
|
|
1432
|
+
-21,
|
|
1433
|
+
"Key name in key:value pair must be a string @Line:" +
|
|
1434
|
+
mePos.lineNumber +
|
|
1435
|
+
" @Position:" +
|
|
1436
|
+
mePos.linePosition +
|
|
1437
|
+
" (e-21)"
|
|
1438
|
+
);
|
|
1439
|
+
break;
|
|
1440
|
+
} else {
|
|
1441
|
+
// capture the white space/comments here
|
|
1442
|
+
if (keepCM || keepSP) {
|
|
1443
|
+
this.preKey = j2.preSpace;
|
|
1444
|
+
this.postKey = j2.finalSpace;
|
|
1445
|
+
}
|
|
1446
|
+
Key = j2._value; // already verified that this is type "string"
|
|
1447
|
+
this._keyQuote = j2._stringQuote;
|
|
1448
|
+
mePos = newPos;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
j2 = null;
|
|
1452
|
+
|
|
1453
|
+
if (!skipToNext) {
|
|
1454
|
+
let cColon = "\0";
|
|
1455
|
+
if (mePos.absolutePosition < meJsonString.length) {
|
|
1456
|
+
cColon = meJsonString.charAt(mePos.absolutePosition);
|
|
1457
|
+
}
|
|
1458
|
+
// *** Consume the :
|
|
1459
|
+
if (cColon != ":") {
|
|
1460
|
+
this.StatusErr(
|
|
1461
|
+
-16,
|
|
1462
|
+
"Expected : symbol in key:value pair @Line:" +
|
|
1463
|
+
mePos.lineNumber +
|
|
1464
|
+
" @Position:" +
|
|
1465
|
+
mePos.linePosition +
|
|
1466
|
+
" (e-16)"
|
|
1467
|
+
);
|
|
1468
|
+
break;
|
|
1469
|
+
}
|
|
1470
|
+
mePos.increment();
|
|
1471
|
+
|
|
1472
|
+
// *** Expecting value after the : symbol in value/pair combo
|
|
1473
|
+
// Space/comments here are after the separator
|
|
1474
|
+
jNew = this.CreatePartClone(keepSP, keepCM);
|
|
1475
|
+
let finalPos = jNew.DeserializeMeI(
|
|
1476
|
+
meJsonString,
|
|
1477
|
+
mePos.clone(),
|
|
1478
|
+
true,
|
|
1479
|
+
false,
|
|
1480
|
+
",",
|
|
1481
|
+
"}"
|
|
1482
|
+
);
|
|
1483
|
+
|
|
1484
|
+
// Check for blank=null (return status -11 and _jsonType=null)
|
|
1485
|
+
// DEBUGGER: FUTURE-NOW: Should not be looking for -11???
|
|
1486
|
+
if (
|
|
1487
|
+
jNew.Status == -11 &&
|
|
1488
|
+
jNew.jsonType == "null" &&
|
|
1489
|
+
_UseFlexJson == true
|
|
1490
|
+
) {
|
|
1491
|
+
// Note: jNew.status=-11 indicates nothing was found where there should have been a value - for FLEX JSON this is legitimate.
|
|
1492
|
+
jNew._status = 0; // this is OK
|
|
1493
|
+
}
|
|
1494
|
+
if (jNew.Status != 0) {
|
|
1495
|
+
this.StatusErr(
|
|
1496
|
+
-21,
|
|
1497
|
+
"Failed to find value in key:value pair. @Line:" +
|
|
1498
|
+
mePos.lineNumber +
|
|
1499
|
+
" @Position:" +
|
|
1500
|
+
mePos.linePosition +
|
|
1501
|
+
" (e-21) [" +
|
|
1502
|
+
jNew.StatusMessage +
|
|
1503
|
+
"]"
|
|
1504
|
+
);
|
|
1505
|
+
break;
|
|
1506
|
+
} else {
|
|
1507
|
+
// Note: Above, jNew.status=-11 indicates nothing was found where there should have been a value - for FLEX JSON this is legitimate.
|
|
1508
|
+
// *** For all cases: object, array, string, number, boolean, or null
|
|
1509
|
+
jNew.Parent = this;
|
|
1510
|
+
jNew._key = Key;
|
|
1511
|
+
v.push(jNew); // FUTURE: IS THIS WRONG? SHOULD WE CHECK TO SEE IF THE KEY ALREADY EXISTS? AS IS, THE FIRST VALUE WILL "overshadow" ANY SUBSEQUENT VALUE. MAYBE THIS IS OK.
|
|
1512
|
+
mePos = finalPos;
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
jNew = null;
|
|
1516
|
+
|
|
1517
|
+
// *** Check if we are past the end of the string
|
|
1518
|
+
if (mePos.absolutePosition >= meJsonString.length) {
|
|
1519
|
+
this.StatusErr(
|
|
1520
|
+
-15,
|
|
1521
|
+
"Past end of string before we found the } symbol as the end of the object @Line:" +
|
|
1522
|
+
mePos.lineNumber +
|
|
1523
|
+
" @Position:" +
|
|
1524
|
+
mePos.linePosition +
|
|
1525
|
+
" (e-15)"
|
|
1526
|
+
);
|
|
1527
|
+
break;
|
|
1528
|
+
}
|
|
1529
|
+
} // end if (!skipToNext)
|
|
1530
|
+
|
|
1531
|
+
let cNext = meJsonString[mePos.absolutePosition];
|
|
1532
|
+
// *** Check if we reached the end of the object
|
|
1533
|
+
if (cNext == "}") {
|
|
1534
|
+
break;
|
|
1535
|
+
} // return. we are done buildng the JSON object
|
|
1536
|
+
// *** Comma required between items in object
|
|
1537
|
+
if (cNext != ",") {
|
|
1538
|
+
this.StatusErr(
|
|
1539
|
+
-17,
|
|
1540
|
+
"Expected , symbol to separate value pairs @Line:" +
|
|
1541
|
+
mePos.lineNumber +
|
|
1542
|
+
" @Position:" +
|
|
1543
|
+
mePos.linePosition +
|
|
1544
|
+
" (e-17)"
|
|
1545
|
+
);
|
|
1546
|
+
break;
|
|
1547
|
+
}
|
|
1548
|
+
mePos.increment();
|
|
1549
|
+
|
|
1550
|
+
safety--;
|
|
1551
|
+
if (safety <= 0) {
|
|
1552
|
+
this.StatusErr(
|
|
1553
|
+
-117,
|
|
1554
|
+
"Max deserialization iterations reached in DeserializeObject. @Line:" +
|
|
1555
|
+
mePos.lineNumber +
|
|
1556
|
+
" @Position:" +
|
|
1557
|
+
mePos.linePosition +
|
|
1558
|
+
" (e-117)"
|
|
1559
|
+
);
|
|
1560
|
+
break;
|
|
1561
|
+
}
|
|
1562
|
+
} // end do
|
|
1563
|
+
|
|
1564
|
+
this._value = v;
|
|
1565
|
+
jNew = null;
|
|
1566
|
+
j2 = null;
|
|
1567
|
+
return mePos; // negative value indicated an error
|
|
1568
|
+
} // End DeserializeObject2()
|
|
1569
|
+
|
|
1570
|
+
// DeserializeArray()
|
|
1571
|
+
// *** Look for comma separated value list as a JSON array
|
|
1572
|
+
// NOTE: Parent routine DeserializeMeI() keeps track of the before/after spacing of the array
|
|
1573
|
+
DeserializeArray(meJsonString, start, keepSP, keepCM) {
|
|
1574
|
+
var jNew;
|
|
1575
|
+
|
|
1576
|
+
let v = [];
|
|
1577
|
+
let mePos = start;
|
|
1578
|
+
mePos.increment(); // *** IMPORTANT! Move past [ symbol
|
|
1579
|
+
|
|
1580
|
+
let safety = 99999;
|
|
1581
|
+
while (true) {
|
|
1582
|
+
// *** Expecting value
|
|
1583
|
+
jNew = this.CreatePartClone(keepSP, keepCM);
|
|
1584
|
+
let finalPos = jNew.DeserializeMeI(
|
|
1585
|
+
meJsonString,
|
|
1586
|
+
mePos.clone(),
|
|
1587
|
+
true,
|
|
1588
|
+
false,
|
|
1589
|
+
",",
|
|
1590
|
+
"]"
|
|
1591
|
+
);
|
|
1592
|
+
|
|
1593
|
+
if (jNew.Status != 0) {
|
|
1594
|
+
this.StatusErr(
|
|
1595
|
+
-21,
|
|
1596
|
+
"Failed to find value in array. @Line:" +
|
|
1597
|
+
mePos.lineNumber +
|
|
1598
|
+
" @Position:" +
|
|
1599
|
+
mePos.linePosition +
|
|
1600
|
+
" (e-21) [" +
|
|
1601
|
+
jNew.StatusMessage +
|
|
1602
|
+
"]"
|
|
1603
|
+
);
|
|
1604
|
+
break;
|
|
1605
|
+
} else {
|
|
1606
|
+
// Note: Above, jNew.status=-11 indicates nothing was found where there should have been a value - for FLEX JSON this is legitimate.
|
|
1607
|
+
// *** For all cases: object, array, string, number, boolean, or null
|
|
1608
|
+
jNew.Parent = this;
|
|
1609
|
+
// If jNew is a blank string, then we need to create an empty array rather than an array with a null value.
|
|
1610
|
+
if (jNew._jsonString.trim() != "") {
|
|
1611
|
+
v.push(jNew);
|
|
1612
|
+
}
|
|
1613
|
+
mePos = finalPos;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
jNew = null;
|
|
1617
|
+
|
|
1618
|
+
// *** Check if we are past the end of the string
|
|
1619
|
+
if (mePos.absolutePosition >= meJsonString.length) {
|
|
1620
|
+
this.StatusErr(
|
|
1621
|
+
-115,
|
|
1622
|
+
"Past end of string before we found the ] symbol as the end of the object @Line:" +
|
|
1623
|
+
mePos.lineNumber +
|
|
1624
|
+
" @Position:" +
|
|
1625
|
+
mePos.linePosition +
|
|
1626
|
+
" (e-115)"
|
|
1627
|
+
);
|
|
1628
|
+
break;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
let cNext = meJsonString[mePos.absolutePosition];
|
|
1632
|
+
// *** Check if we reached the end of the object
|
|
1633
|
+
if (cNext == "]") {
|
|
1634
|
+
break;
|
|
1635
|
+
} // return. we are done buildng the JSON object
|
|
1636
|
+
// *** Comma required between items in object
|
|
1637
|
+
if (cNext != ",") {
|
|
1638
|
+
this.StatusErr(
|
|
1639
|
+
-37,
|
|
1640
|
+
"Expected , symbol to separate values @Line:" +
|
|
1641
|
+
mePos.lineNumber +
|
|
1642
|
+
" @Position:" +
|
|
1643
|
+
mePos.linePosition +
|
|
1644
|
+
" (e-37)"
|
|
1645
|
+
);
|
|
1646
|
+
break;
|
|
1647
|
+
}
|
|
1648
|
+
mePos.increment();
|
|
1649
|
+
|
|
1650
|
+
safety--;
|
|
1651
|
+
if (safety <= 0) {
|
|
1652
|
+
this.StatusErr(
|
|
1653
|
+
-119,
|
|
1654
|
+
"Max deserialization iterations reached in DeserializeObject. @Line:" +
|
|
1655
|
+
mePos.lineNumber +
|
|
1656
|
+
" @Position:" +
|
|
1657
|
+
mePos.linePosition +
|
|
1658
|
+
" (e-119)"
|
|
1659
|
+
);
|
|
1660
|
+
break;
|
|
1661
|
+
}
|
|
1662
|
+
} // end do
|
|
1663
|
+
|
|
1664
|
+
this._value = v;
|
|
1665
|
+
jNew = null;
|
|
1666
|
+
return mePos; // negative value indicated an error
|
|
1667
|
+
} // End DeserializeArray()
|
|
1668
|
+
DeserializeFile(FilePath, OkToClip = false) {
|
|
1669
|
+
//if ( !System.IO.File.Exists(FilePath) ) { _status=-31; return _status; }
|
|
1670
|
+
try {
|
|
1671
|
+
/*
|
|
1672
|
+
fs.readFile(FilePath, (err, data) => {
|
|
1673
|
+
if (err) throw err;
|
|
1674
|
+
|
|
1675
|
+
const fsData = data.toString();
|
|
1676
|
+
this.Deserialize(fsData,0,OkToClip);
|
|
1677
|
+
})
|
|
1678
|
+
*/
|
|
1679
|
+
const fsData = fs.readFileSync(FilePath, "utf8");
|
|
1680
|
+
this.Deserialize(fsData, 0, OkToClip);
|
|
1681
|
+
} catch (err) {
|
|
1682
|
+
this._status = -32;
|
|
1683
|
+
this.statusMsg = err.message;
|
|
1684
|
+
return this._status;
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
DeserializeFlexFile(
|
|
1689
|
+
FilePath,
|
|
1690
|
+
OkToClip = false,
|
|
1691
|
+
spacing_flag = -1,
|
|
1692
|
+
comments_flag = -1
|
|
1693
|
+
) {
|
|
1694
|
+
this.UseFlexJson = true;
|
|
1695
|
+
if (spacing_flag >= 0 || comments_flag >= 0) {
|
|
1696
|
+
this.keepSpacingAndComments(spacing_flag, comments_flag);
|
|
1697
|
+
}
|
|
1698
|
+
return this.DeserializeFile(FilePath, OkToClip);
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
StatusErr(nErr, strErr) {
|
|
1702
|
+
this._status = nErr;
|
|
1703
|
+
this.AddStatusMessage(strErr);
|
|
1704
|
+
} // End
|
|
1705
|
+
|
|
1706
|
+
// FUTURE: Replace this with this.statusMsg=...
|
|
1707
|
+
// AddStatusMessage()
|
|
1708
|
+
// Set _statusMsg to the new message/error string
|
|
1709
|
+
// Also add the message to a log in stats object, if stats are being tracked.
|
|
1710
|
+
AddStatusMessage(msg) {
|
|
1711
|
+
this.statusMsg = msg;
|
|
1712
|
+
if (this.NoStatsOrMsgs) {
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1715
|
+
if (!this.trackingStats) {
|
|
1716
|
+
return;
|
|
1717
|
+
} // verifies that _meta.stats exists as an object
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
// Convert Javascript type to FlexJson type
|
|
1721
|
+
convertType(v) {
|
|
1722
|
+
if (v === null) {
|
|
1723
|
+
return "null";
|
|
1724
|
+
}
|
|
1725
|
+
const vType = typeof v;
|
|
1726
|
+
switch (vType) {
|
|
1727
|
+
case "bigint":
|
|
1728
|
+
case "number":
|
|
1729
|
+
return "number";
|
|
1730
|
+
break;
|
|
1731
|
+
case "boolean":
|
|
1732
|
+
return "boolean";
|
|
1733
|
+
break;
|
|
1734
|
+
case "object": // must be FlexJson object or it is not a true "object"
|
|
1735
|
+
return ""; // indicates an error/invlid type
|
|
1736
|
+
break;
|
|
1737
|
+
case "FlexJson":
|
|
1738
|
+
return FlexJson.jsonType;
|
|
1739
|
+
break;
|
|
1740
|
+
case "function":
|
|
1741
|
+
return ""; // indicate error/invalid type
|
|
1742
|
+
break;
|
|
1743
|
+
default:
|
|
1744
|
+
return "string";
|
|
1745
|
+
break;
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
module.exports = FlexJson;
|