ig-serialize 1.0.4 → 1.0.6
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/README.md +27 -0
- package/package.json +1 -1
- package/serialize.js +67 -6
- package/test.js +65 -15
package/README.md
CHANGED
|
@@ -49,6 +49,33 @@ Thus, care must be taken when serializing structures containing function.
|
|
|
49
49
|
### `partialDeepCopy(..)`
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
## Format
|
|
53
|
+
|
|
54
|
+
The output of `.serialize(..)` is a strict superset of [standard JSON](https://www.json.org/json-en.html),
|
|
55
|
+
while the input format is a bit more relaxed than in several details.
|
|
56
|
+
|
|
57
|
+
Extensions to JSON:
|
|
58
|
+
- Recursion
|
|
59
|
+
- undefined / NaN
|
|
60
|
+
- BigInt
|
|
61
|
+
- Map / Set
|
|
62
|
+
- Function
|
|
63
|
+
|
|
64
|
+
### Structural paths
|
|
65
|
+
|
|
66
|
+
### Recursion
|
|
67
|
+
|
|
68
|
+
### null types
|
|
69
|
+
|
|
70
|
+
### BigInt
|
|
71
|
+
|
|
72
|
+
### Map / Set
|
|
73
|
+
|
|
74
|
+
### Functions
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
52
79
|
|
|
53
80
|
|
|
54
81
|
|
package/package.json
CHANGED
package/serialize.js
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
/**********************************************************************
|
|
2
2
|
*
|
|
3
|
+
* TODO would be useful to split this into:
|
|
4
|
+
* - object traversal using object path
|
|
5
|
+
* Object.walk(..) -- a-la Python's walk(..)
|
|
6
|
+
* Object.graph(..)
|
|
7
|
+
* like .map(..) but deep and paths instead of indexes...
|
|
8
|
+
* - get/set object by path
|
|
9
|
+
* Object.get(..) / Object.set(..)
|
|
10
|
+
*
|
|
11
|
+
* XXX the current path implementation is fully complient to the task at
|
|
12
|
+
* hand but it will not suite the diff task as there is no way to know
|
|
13
|
+
* the meaning of the path element without seeing the object (map/set
|
|
14
|
+
* indexes)...
|
|
15
|
+
* a different path format would suit both tasks and make things more
|
|
16
|
+
* universal:
|
|
17
|
+
* Current:
|
|
18
|
+
* [1, 'a', 5, 0, 3]
|
|
19
|
+
* \ \ +-++ +---------------- Set index (from context)
|
|
20
|
+
* \ \ +------------------- Map index (from context)
|
|
21
|
+
* \ +------------------------ Object key (string)
|
|
22
|
+
* +--------------------------- Array index (from context)
|
|
23
|
+
* Proposed:
|
|
24
|
+
* [1, 'a', ['map', 5, 0], ['set', 3]]
|
|
25
|
+
* \ \ +---------+-+ +------+-+
|
|
26
|
+
* \ \ \ +--- Set index
|
|
27
|
+
* \ \ +-------------- Map index
|
|
28
|
+
* \ +--------------------------- Object key (string)
|
|
29
|
+
* +------------------------------ Array index (number)
|
|
30
|
+
* And/or:
|
|
31
|
+
* [1, ['object', 3], ['map', 5, 0], ['set', 3]]
|
|
32
|
+
* +---------+-+
|
|
33
|
+
* +----- Object attr index
|
|
34
|
+
* The questions is which to use as default for objects, the key or
|
|
35
|
+
* position?
|
|
36
|
+
* (XXX move this note to diff.jx)
|
|
37
|
+
*
|
|
38
|
+
* XXX do a revision of the JSON standard for things I could have forgotten...
|
|
3
39
|
*
|
|
4
40
|
*
|
|
5
41
|
**********************************************************************/
|
|
@@ -41,7 +77,8 @@ var debug = {
|
|
|
41
77
|
|
|
42
78
|
//---------------------------------------------------------------------
|
|
43
79
|
|
|
44
|
-
module.STRING_LENGTH_REF =
|
|
80
|
+
module.STRING_LENGTH_REF = RECURSIVE.length * 8
|
|
81
|
+
|
|
45
82
|
|
|
46
83
|
//
|
|
47
84
|
// serialize(obj[, options])
|
|
@@ -101,7 +138,7 @@ module.STRING_LENGTH_REF = 64
|
|
|
101
138
|
// ]
|
|
102
139
|
//
|
|
103
140
|
//
|
|
104
|
-
// XXX BUG
|
|
141
|
+
// XXX BUG?: using non-whitespace as indent breaks the depth of the first
|
|
105
142
|
// or last elements in sequences
|
|
106
143
|
// ...breaks .trim*() in Map/Set/Object...
|
|
107
144
|
var _serialize =
|
|
@@ -131,7 +168,8 @@ function(obj, path=[], seen=new Map(), indent, depth=0, options={}){
|
|
|
131
168
|
return FUNCTION
|
|
132
169
|
.replace('%', s.length +','+ s) }
|
|
133
170
|
|
|
134
|
-
//
|
|
171
|
+
// long strings...
|
|
172
|
+
// NOTE: this saves on output size...
|
|
135
173
|
if(typeof(obj) == 'string'
|
|
136
174
|
&& obj.length > string_length_ref){
|
|
137
175
|
seen.set(obj, path) }
|
|
@@ -230,7 +268,7 @@ module.eJSON = {
|
|
|
230
268
|
|
|
231
269
|
0: 'number', 1: 'number', 2: 'number', 3: 'number', 4: 'number',
|
|
232
270
|
5: 'number', 6: 'number', 7: 'number', 8: 'number', 9: 'number',
|
|
233
|
-
'.': 'number', '-': 'number',
|
|
271
|
+
'.': 'number', '-': 'number', '+': 'number',
|
|
234
272
|
|
|
235
273
|
'[': 'array',
|
|
236
274
|
'{': 'object',
|
|
@@ -370,11 +408,34 @@ module.eJSON = {
|
|
|
370
408
|
&& str.slice(i, i+'-Infinity'.length) == '-Infinity'){
|
|
371
409
|
return [-Infinity, i+'-Infinity'.length, line] }
|
|
372
410
|
// numbers...
|
|
373
|
-
|
|
411
|
+
// XXX do we need to handle the odd case of 077 vs 088???
|
|
412
|
+
var j = i
|
|
413
|
+
var mode = 'dec'
|
|
414
|
+
if(str[j] == '0'
|
|
415
|
+
&& 'xXbBoO'.includes(str[j+1])){
|
|
416
|
+
mode = str[j+1].toLowerCase()
|
|
417
|
+
j++ }
|
|
418
|
+
j++
|
|
374
419
|
while(j < str.length
|
|
375
420
|
&& (str[j] == '.'
|
|
421
|
+
// dec/oct/bin...
|
|
422
|
+
// XXX do we need to be pedantic and check the rest
|
|
423
|
+
// of the modes explicitly???
|
|
376
424
|
|| (str[j] >= '0'
|
|
377
|
-
&& str[j] <= '9')
|
|
425
|
+
&& str[j] <= '9')
|
|
426
|
+
// hex...
|
|
427
|
+
|| (mode == 'x'
|
|
428
|
+
&& ((str[j] >= 'a'
|
|
429
|
+
&& str[j] <= 'f')
|
|
430
|
+
|| (str[j] >= 'A'
|
|
431
|
+
&& str[j] <= 'F')))
|
|
432
|
+
// exponent...
|
|
433
|
+
|| str[j] == 'e'
|
|
434
|
+
|| str[j] == 'E')){
|
|
435
|
+
// exponent sign...
|
|
436
|
+
if('eE'.includes(str[j])
|
|
437
|
+
&& '+-'.includes(str[j+1])){
|
|
438
|
+
j++ }
|
|
378
439
|
j++ }
|
|
379
440
|
// BigInt...
|
|
380
441
|
if(str[j] == 'n'){
|
package/test.js
CHANGED
|
@@ -45,6 +45,12 @@ var setups = test.Setups({
|
|
|
45
45
|
return ['123', json] },
|
|
46
46
|
'number-neg': function(assert){
|
|
47
47
|
return ['-123', json] },
|
|
48
|
+
//'number-pos': function(assert){
|
|
49
|
+
// return ['+123', json] },
|
|
50
|
+
'number-exp': function(assert){
|
|
51
|
+
return ['1e+100', json] },
|
|
52
|
+
'number-exp-neg': function(assert){
|
|
53
|
+
return ['1e-100', json] },
|
|
48
54
|
'number-zero': function(assert){
|
|
49
55
|
return ['0', json] },
|
|
50
56
|
'float-a': function(assert){
|
|
@@ -68,7 +74,8 @@ var setups = test.Setups({
|
|
|
68
74
|
// XXX also test diffrerent quotations...
|
|
69
75
|
string: function(assert){
|
|
70
76
|
return ['"string"', json] },
|
|
71
|
-
|
|
77
|
+
'string-empty': function(assert){
|
|
78
|
+
return ['""', json] },
|
|
72
79
|
'string-multiline': function(assert){
|
|
73
80
|
return ['"string\\nstring\\nstring"', json] },
|
|
74
81
|
|
|
@@ -106,7 +113,6 @@ var setups = test.Setups({
|
|
|
106
113
|
return ['Map([[<RECURSIVE[]>,"value"]])'] },
|
|
107
114
|
'map-recursive-value': function(assert){
|
|
108
115
|
return ['Map([["key",<RECURSIVE[]>]])'] },
|
|
109
|
-
|
|
110
116
|
})
|
|
111
117
|
|
|
112
118
|
test.Modifiers({
|
|
@@ -170,7 +176,6 @@ test.Tests({
|
|
|
170
176
|
// XXX
|
|
171
177
|
},
|
|
172
178
|
|
|
173
|
-
//* XXX ERR
|
|
174
179
|
'partial-deep-copy': function(assert, [setup]){
|
|
175
180
|
var obj = eJSON.deserialize(setup, true)
|
|
176
181
|
var funcs = []
|
|
@@ -185,12 +190,13 @@ test.Tests({
|
|
|
185
190
|
})
|
|
186
191
|
|
|
187
192
|
test.Cases({
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
193
|
+
//
|
|
194
|
+
// Format:
|
|
195
|
+
// [
|
|
196
|
+
// [ "<extended-syntax>", "<JSON-syntax>" ],
|
|
197
|
+
// ...
|
|
198
|
+
// ]
|
|
199
|
+
//
|
|
194
200
|
// NOTE: these syntax variants are not output by .serialize(..) this it
|
|
195
201
|
// is less critical to test them in the main loop.
|
|
196
202
|
// XXX though it would be nice to do so...
|
|
@@ -198,10 +204,20 @@ test.Cases({
|
|
|
198
204
|
// numbers/floats...
|
|
199
205
|
['.123', '0.123'],
|
|
200
206
|
['123.', '123'],
|
|
207
|
+
['+123', '123'],
|
|
208
|
+
['123e100', '123e+100'],
|
|
209
|
+
['123E100', '123e+100'],
|
|
210
|
+
['0xff', '255'],
|
|
211
|
+
['0Xff', '255'],
|
|
212
|
+
['0o77', '63'],
|
|
213
|
+
['0O77', '63'],
|
|
214
|
+
['0b11', '3'],
|
|
215
|
+
['0B11', '3'],
|
|
201
216
|
|
|
202
217
|
// string quotes...
|
|
203
|
-
|
|
204
|
-
['
|
|
218
|
+
// XXX test new lines...
|
|
219
|
+
["'abc'", '"abc"'],
|
|
220
|
+
['`abc`', '"abc"'],
|
|
205
221
|
|
|
206
222
|
// arrays...
|
|
207
223
|
['[1,2,]', '[1,2]'],
|
|
@@ -218,12 +234,46 @@ test.Cases({
|
|
|
218
234
|
`"${ a }" and "${ b }" should deserialize to the samve value.`,
|
|
219
235
|
'got:', aa, 'and', bb, 'resp.') } },
|
|
220
236
|
|
|
237
|
+
_make_object_with_methods: function(){
|
|
238
|
+
var in_closure = 123
|
|
239
|
+
return {
|
|
240
|
+
stateful: function(){
|
|
241
|
+
return typeof(in_closure) != 'undefined' ?
|
|
242
|
+
'state_retained'
|
|
243
|
+
: 'state_lost' },
|
|
244
|
+
stateless: function(){
|
|
245
|
+
return 'stateless' },
|
|
246
|
+
} },
|
|
221
247
|
'deep-copy-function': function(assert){
|
|
222
|
-
|
|
223
|
-
|
|
248
|
+
var obj = this._make_object_with_methods()
|
|
249
|
+
var obj_copy = eJSON.deepCopy(obj, true)
|
|
250
|
+
|
|
251
|
+
// sanity checks...
|
|
252
|
+
assert(obj.stateless() == 'stateless')
|
|
253
|
+
assert(obj.stateful() == 'state_retained')
|
|
254
|
+
assert(obj_copy.stateless() == 'stateless')
|
|
255
|
+
|
|
256
|
+
// context should be lost...
|
|
257
|
+
assert(
|
|
258
|
+
obj_copy.stateful() == 'state_lost',
|
|
259
|
+
'Function closure not lost.')
|
|
260
|
+
assert(obj.stateful !== obj_copy.stateful,
|
|
261
|
+
'Function objects retained.') },
|
|
224
262
|
'partial-deep-copy-function': function(assert){
|
|
225
|
-
|
|
226
|
-
|
|
263
|
+
var obj = this._make_object_with_methods()
|
|
264
|
+
var obj_copy = eJSON.partialDeepCopy(obj)
|
|
265
|
+
|
|
266
|
+
// sanity checks...
|
|
267
|
+
assert(obj.stateless() == 'stateless')
|
|
268
|
+
assert(obj.stateful() == 'state_retained')
|
|
269
|
+
assert(obj_copy.stateless() == 'stateless')
|
|
270
|
+
|
|
271
|
+
// context should be retained...
|
|
272
|
+
assert(
|
|
273
|
+
obj_copy.stateful() == 'state_retained',
|
|
274
|
+
'Function closure lost.')
|
|
275
|
+
assert(obj.stateful === obj_copy.stateful,
|
|
276
|
+
'Function objects not retained.') },
|
|
227
277
|
})
|
|
228
278
|
|
|
229
279
|
|