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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ig-serialize",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "experimental extended json serializaion...",
5
5
  "main": "serialize.js",
6
6
  "scripts": {
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 = 64
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: using non-whitespace as indent breaks the depth of the first
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
- // special case: long strings...
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
- var j = i+1
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
- // XXX ERR this breaks...
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
- /* XXX for some magical reason hese break as soon as we add [setup] to arguments...
189
- 'deep-copy-function': function(assert, [setup]){
190
- // XXX check function isolation...
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
- ['"abc"', "'abc'"],
204
- ['"abc"', '`abc`'],
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
- // XXX check function isolation...
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
- // XXX check function isolation...
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