ig-serialize 1.0.4 → 1.0.5
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 +66 -6
- package/test.js +56 -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,33 @@ 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]
|
|
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
|
+
if('eE'.includes(str[j])
|
|
436
|
+
&& '+-'.includes(str[j+1])){
|
|
437
|
+
j++ }
|
|
378
438
|
j++ }
|
|
379
439
|
// BigInt...
|
|
380
440
|
if(str[j] == 'n'){
|
package/test.js
CHANGED
|
@@ -45,6 +45,10 @@ 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] },
|
|
48
52
|
'number-zero': function(assert){
|
|
49
53
|
return ['0', json] },
|
|
50
54
|
'float-a': function(assert){
|
|
@@ -68,7 +72,8 @@ var setups = test.Setups({
|
|
|
68
72
|
// XXX also test diffrerent quotations...
|
|
69
73
|
string: function(assert){
|
|
70
74
|
return ['"string"', json] },
|
|
71
|
-
|
|
75
|
+
'string-empty': function(assert){
|
|
76
|
+
return ['""', json] },
|
|
72
77
|
'string-multiline': function(assert){
|
|
73
78
|
return ['"string\\nstring\\nstring"', json] },
|
|
74
79
|
|
|
@@ -106,7 +111,6 @@ var setups = test.Setups({
|
|
|
106
111
|
return ['Map([[<RECURSIVE[]>,"value"]])'] },
|
|
107
112
|
'map-recursive-value': function(assert){
|
|
108
113
|
return ['Map([["key",<RECURSIVE[]>]])'] },
|
|
109
|
-
|
|
110
114
|
})
|
|
111
115
|
|
|
112
116
|
test.Modifiers({
|
|
@@ -170,7 +174,6 @@ test.Tests({
|
|
|
170
174
|
// XXX
|
|
171
175
|
},
|
|
172
176
|
|
|
173
|
-
//* XXX ERR
|
|
174
177
|
'partial-deep-copy': function(assert, [setup]){
|
|
175
178
|
var obj = eJSON.deserialize(setup, true)
|
|
176
179
|
var funcs = []
|
|
@@ -185,12 +188,13 @@ test.Tests({
|
|
|
185
188
|
})
|
|
186
189
|
|
|
187
190
|
test.Cases({
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
191
|
+
//
|
|
192
|
+
// Format:
|
|
193
|
+
// [
|
|
194
|
+
// [ "<extended-syntax>", "<JSON-syntax>" ],
|
|
195
|
+
// ...
|
|
196
|
+
// ]
|
|
197
|
+
//
|
|
194
198
|
// NOTE: these syntax variants are not output by .serialize(..) this it
|
|
195
199
|
// is less critical to test them in the main loop.
|
|
196
200
|
// XXX though it would be nice to do so...
|
|
@@ -198,10 +202,13 @@ test.Cases({
|
|
|
198
202
|
// numbers/floats...
|
|
199
203
|
['.123', '0.123'],
|
|
200
204
|
['123.', '123'],
|
|
205
|
+
['+123', '123'],
|
|
206
|
+
['123e100', '123e+100'],
|
|
207
|
+
['0xff', '255'],
|
|
201
208
|
|
|
202
209
|
// string quotes...
|
|
203
|
-
['
|
|
204
|
-
['
|
|
210
|
+
["'abc'", '"abc"'],
|
|
211
|
+
['`abc`', '"abc"'],
|
|
205
212
|
|
|
206
213
|
// arrays...
|
|
207
214
|
['[1,2,]', '[1,2]'],
|
|
@@ -218,12 +225,46 @@ test.Cases({
|
|
|
218
225
|
`"${ a }" and "${ b }" should deserialize to the samve value.`,
|
|
219
226
|
'got:', aa, 'and', bb, 'resp.') } },
|
|
220
227
|
|
|
228
|
+
_make_object_with_methods: function(){
|
|
229
|
+
var in_closure = 123
|
|
230
|
+
return {
|
|
231
|
+
stateful: function(){
|
|
232
|
+
return typeof(in_closure) != 'undefined' ?
|
|
233
|
+
'state_retained'
|
|
234
|
+
: 'state_lost' },
|
|
235
|
+
stateless: function(){
|
|
236
|
+
return 'stateless' },
|
|
237
|
+
} },
|
|
221
238
|
'deep-copy-function': function(assert){
|
|
222
|
-
|
|
223
|
-
|
|
239
|
+
var obj = this._make_object_with_methods()
|
|
240
|
+
var obj_copy = eJSON.deepCopy(obj, true)
|
|
241
|
+
|
|
242
|
+
// sanity checks...
|
|
243
|
+
assert(obj.stateless() == 'stateless')
|
|
244
|
+
assert(obj.stateful() == 'state_retained')
|
|
245
|
+
assert(obj_copy.stateless() == 'stateless')
|
|
246
|
+
|
|
247
|
+
// context should be lost...
|
|
248
|
+
assert(
|
|
249
|
+
obj_copy.stateful() == 'state_lost',
|
|
250
|
+
'Function closure not lost.')
|
|
251
|
+
assert(obj.stateful !== obj_copy.stateful,
|
|
252
|
+
'Function objects retained.') },
|
|
224
253
|
'partial-deep-copy-function': function(assert){
|
|
225
|
-
|
|
226
|
-
|
|
254
|
+
var obj = this._make_object_with_methods()
|
|
255
|
+
var obj_copy = eJSON.partialDeepCopy(obj)
|
|
256
|
+
|
|
257
|
+
// sanity checks...
|
|
258
|
+
assert(obj.stateless() == 'stateless')
|
|
259
|
+
assert(obj.stateful() == 'state_retained')
|
|
260
|
+
assert(obj_copy.stateless() == 'stateless')
|
|
261
|
+
|
|
262
|
+
// context should be retained...
|
|
263
|
+
assert(
|
|
264
|
+
obj_copy.stateful() == 'state_retained',
|
|
265
|
+
'Function closure lost.')
|
|
266
|
+
assert(obj.stateful === obj_copy.stateful,
|
|
267
|
+
'Function objects not retained.') },
|
|
227
268
|
})
|
|
228
269
|
|
|
229
270
|
|