zkjson 0.3.2 → 0.4.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.
Files changed (3) hide show
  1. package/encoder-v2.js +1048 -0
  2. package/encoder.js +1 -1
  3. package/package.json +1 -1
package/encoder-v2.js ADDED
@@ -0,0 +1,1048 @@
1
+ const {
2
+ clone,
3
+ uniq,
4
+ sortBy,
5
+ map,
6
+ concat,
7
+ compose,
8
+ is,
9
+ descend,
10
+ ascend,
11
+ sortWith,
12
+ prop,
13
+ equals,
14
+ append,
15
+ isNil,
16
+ includes,
17
+ splitEvery,
18
+ flatten,
19
+ } = require("ramda")
20
+ const ops = {
21
+ $eq: 10,
22
+ $ne: 11,
23
+ $gt: 12,
24
+ $gte: 13,
25
+ $lt: 14,
26
+ $lte: 15,
27
+ $in: 16,
28
+ $nin: 17,
29
+ $contains: 18,
30
+ $contains_any: 19,
31
+ $contains_all: 20,
32
+ $contains_none: 21,
33
+ }
34
+ const opMap = {}
35
+ for (let k in ops) opMap[ops[k]] = k
36
+
37
+ const base64Map = {
38
+ A: "00",
39
+ B: "01",
40
+ C: "02",
41
+ D: "03",
42
+ E: "04",
43
+ F: "05",
44
+ G: "06",
45
+ H: "07",
46
+ I: "08",
47
+ J: "09",
48
+ K: "10",
49
+ L: "11",
50
+ M: "12",
51
+ N: "13",
52
+ O: "14",
53
+ P: "15",
54
+ Q: "16",
55
+ R: "17",
56
+ S: "18",
57
+ T: "19",
58
+ U: "20",
59
+ V: "21",
60
+ W: "22",
61
+ X: "23",
62
+ Y: "24",
63
+ Z: "25",
64
+ a: "26",
65
+ b: "27",
66
+ c: "28",
67
+ d: "29",
68
+ e: "30",
69
+ f: "31",
70
+ g: "32",
71
+ h: "33",
72
+ i: "34",
73
+ j: "35",
74
+ k: "36",
75
+ l: "37",
76
+ m: "38",
77
+ n: "39",
78
+ o: "40",
79
+ p: "41",
80
+ q: "42",
81
+ r: "43",
82
+ s: "44",
83
+ t: "45",
84
+ u: "46",
85
+ v: "47",
86
+ w: "48",
87
+ x: "49",
88
+ y: "50",
89
+ z: "51",
90
+ 0: "52",
91
+ 1: "53",
92
+ 2: "54",
93
+ 3: "55",
94
+ 4: "56",
95
+ 5: "57",
96
+ 6: "58",
97
+ 7: "59",
98
+ 8: "60",
99
+ 9: "61",
100
+ "-": "62",
101
+ _: "63",
102
+ }
103
+
104
+ let strMap = {}
105
+ for (const k in base64Map) strMap[base64Map[k]] = k
106
+
107
+ function pad(arr, max = 0) {
108
+ arr = arr.map(n => n.toString())
109
+ for (let i = arr.length; i < max; i++) {
110
+ arr.push("0")
111
+ }
112
+ return arr
113
+ }
114
+
115
+ function encodePath(path) {
116
+ const parts = []
117
+ let str = ""
118
+ let num = 0
119
+ for (const s of path) {
120
+ if (num == 2 && !(s == "." || s == "[")) throw Error()
121
+ if (s == ".") {
122
+ if (num == 2) {
123
+ num = 0
124
+ } else {
125
+ parts.push(str)
126
+ str = ""
127
+ }
128
+ } else if (s == "[") {
129
+ if (num != 2) {
130
+ if (str != "" || parts.length > 0) parts.push(str)
131
+ str = ""
132
+ }
133
+ num = 1
134
+ } else if (s == "]") {
135
+ if (num != 1) throw Error()
136
+ num = 2
137
+ if (str == "" || Number.isNaN(+str)) throw Error()
138
+ parts.push(+str)
139
+ str = ""
140
+ } else {
141
+ str += s
142
+ }
143
+ }
144
+ if (str != "") parts.push(str)
145
+ if (parts.length == 0) parts.push("")
146
+ let encoded = [parts.length]
147
+ for (const p of parts) {
148
+ if (typeof p == "number") {
149
+ encoded = encoded.concat([0, 0, p])
150
+ } else {
151
+ let plen = [p.length]
152
+ if (p.length == 0) plen.push(1)
153
+ encoded = encoded.concat([
154
+ ...plen,
155
+ ...p.split("").map(c => c.charCodeAt(0)),
156
+ ])
157
+ }
158
+ }
159
+ return encoded
160
+ }
161
+
162
+ function decodePath(path) {
163
+ let str = ""
164
+ let p = []
165
+ let len = path.shift()
166
+ while (path.length > 0) {
167
+ const type = path.shift()
168
+ let val = null
169
+ if (type == 0) {
170
+ const type2 = path.shift()
171
+ if (type2 == 0) {
172
+ val = [type2, path.shift()]
173
+ } else {
174
+ val = [type2]
175
+ }
176
+ } else {
177
+ val = []
178
+ for (let i = 0; i < type; i++) {
179
+ val.push(path.shift())
180
+ }
181
+ }
182
+ p.push([type, ...val])
183
+ }
184
+ let i = 0
185
+ for (let s of p) {
186
+ if (s[0] == 0 && s[1] == 0) str += `[${s[2]}]`
187
+ else if (s[0] == 0 && s[1] == 1) {
188
+ if (str != "") str += "."
189
+ } else {
190
+ str += `${i == 0 ? "" : "."}${s
191
+ .slice(1)
192
+ .map(c => String.fromCharCode(Number(c)))
193
+ .join("")}`
194
+ }
195
+ i++
196
+ }
197
+ return str
198
+ }
199
+
200
+ function flattenPath(path) {
201
+ let p = [path.length]
202
+ for (const v of path) p = p.concat(v)
203
+ return p
204
+ }
205
+
206
+ function _encode(v, path = []) {
207
+ let vals = []
208
+ if (typeof v == "number") vals.push([path, encodeVal(v)])
209
+ else if (typeof v == "boolean") vals.push([path, encodeVal(v)])
210
+ else if (v == null) vals.push([path, encodeVal(v)])
211
+ else if (typeof v == "string") vals.push([path, encodeVal(v)])
212
+ else if (Array.isArray(v)) {
213
+ let i = 0
214
+ for (const v2 of v) {
215
+ for (const v3 of _encode(v2, [...path, i])) vals.push(v3)
216
+ i++
217
+ }
218
+ } else if (typeof v == "object") {
219
+ for (const k in v) for (let v4 of _encode(v[k], [...path, k])) vals.push(v4)
220
+ }
221
+ return vals
222
+ }
223
+
224
+ const filterDic = keys => keys.filter(entry => entry.count > 1)
225
+
226
+ function countKeys(keys) {
227
+ let keys2 = []
228
+ for (let v of keys) {
229
+ let i = 0
230
+ for (let v2 of v) {
231
+ const _key = v.slice(0, i + 1)
232
+ let exists = false
233
+ for (let v3 of keys2) {
234
+ if (equals(_key, v3.key)) {
235
+ v3.count += 1
236
+ exists = true
237
+ }
238
+ }
239
+ if (!exists) keys2.push({ key: _key, count: 1 })
240
+ i++
241
+ }
242
+ }
243
+ return keys2
244
+ }
245
+
246
+ function sortKeys(keys) {
247
+ return keys.sort((a, b) => {
248
+ if (b.count !== a.count) return b.count - a.count
249
+ for (let i = 0; i < Math.min(a.key.length, b.key.length); i++) {
250
+ const aVal = a.key[i]
251
+ const bVal = b.key[i]
252
+ if (typeof aVal === "number" && typeof bVal === "string") return -1
253
+ if (typeof aVal === "string" && typeof bVal === "number") return 1
254
+ if (aVal < bVal) return -1
255
+ if (aVal > bVal) return 1
256
+ }
257
+
258
+ return a.key.length - b.key.length
259
+ })
260
+ }
261
+
262
+ function buildDic(data) {
263
+ // --- Step 1. (Optional) Save original input order if needed.
264
+ data.forEach((entry, idx) => (entry._origIdx = idx))
265
+
266
+ // --- Step 2. Sort the data in "dictionary order."
267
+ // Primary: by key array length (shorter arrays come first).
268
+ // Secondary: for keys of equal length, by the total character length (ascending)
269
+ // so that, for example, ["jane"] (4 chars) comes before ["alice"] (5 chars).
270
+ // Tertiary: if still equal, compare element-by-element using natural order.
271
+ data.sort((a, b) => {
272
+ const keyA = a.key
273
+ const keyB = b.key
274
+
275
+ // Primary: Compare array lengths.
276
+ if (keyA.length !== keyB.length) return keyA.length - keyB.length
277
+
278
+ // Secondary: Compare total character lengths (ascending).
279
+ const totalA = keyA.reduce((acc, x) => acc + x.toString().length, 0)
280
+ const totalB = keyB.reduce((acc, x) => acc + x.toString().length, 0)
281
+ if (totalA !== totalB) return totalA - totalB
282
+ // Tertiary: Compare element-by-element using natural order.
283
+ for (let i = 0; i < keyA.length; i++) {
284
+ const elA = keyA[i]
285
+ const elB = keyB[i]
286
+
287
+ if (typeof elA === typeof elB) {
288
+ if (typeof elA === "number") {
289
+ if (elA !== elB) return elA - elB
290
+ } else if (typeof elA === "string") {
291
+ const cmp = elA.localeCompare(elB, undefined, { numeric: true })
292
+ if (cmp !== 0) return cmp
293
+ } else {
294
+ // Fallback: compare string representations.
295
+ const cmp = elA
296
+ .toString()
297
+ .localeCompare(elB.toString(), undefined, { numeric: true })
298
+ if (cmp !== 0) return cmp
299
+ }
300
+ } else {
301
+ // If types differ, compare string representations.
302
+ const cmp = elA
303
+ .toString()
304
+ .localeCompare(elB.toString(), undefined, { numeric: true })
305
+ if (cmp !== 0) return cmp
306
+ }
307
+ }
308
+
309
+ return 0
310
+ })
311
+
312
+ // --- Step 3. Build the dictionary.
313
+ // Each dictionary entry will be stored as an object with:
314
+ // - original: the original key (an array)
315
+ // - compressed: the computed compressed representation.
316
+ const dict = []
317
+
318
+ // Helper: For a given string, look for a previously defined simple key (an array of length 1).
319
+ function getPointerIndex(str) {
320
+ for (let i = 0; i < dict.length; i++) {
321
+ if (dict[i].original.length === 1 && dict[i].original[0] === str) return i
322
+ }
323
+ return -1
324
+ }
325
+
326
+ // Helper: Element-by-element compression.
327
+ // For each element in a composite key, if it is a string that already exists as a simple key,
328
+ // replace one or more consecutive occurrences with a pointer.
329
+ // A single occurrence becomes [dictIndex]; a group becomes [dictIndex, 0].
330
+ function compressElementByElement(key) {
331
+ const rep = []
332
+ let i = 0
333
+ while (i < key.length) {
334
+ const el = key[i]
335
+ if (typeof el === "string") {
336
+ const ptrIndex = getPointerIndex(el)
337
+ if (ptrIndex !== -1) {
338
+ let j = i
339
+ while (j < key.length && key[j] === el) {
340
+ j++
341
+ }
342
+ const groupLen = j - i
343
+ rep.push(groupLen === 1 ? [ptrIndex] : [ptrIndex, 0])
344
+ i = j
345
+ continue
346
+ }
347
+ }
348
+ rep.push(el)
349
+ i++
350
+ }
351
+ return rep
352
+ }
353
+
354
+ // Helper: Compute a "cost" for a given representation.
355
+ // Each literal (number or string) counts as 1; a pointer array counts as the number of numbers it holds.
356
+ function computeCost(rep) {
357
+ let cost = 0
358
+ for (const token of rep) cost += Array.isArray(token) ? token.length : 1
359
+ return cost
360
+ }
361
+
362
+ // Helper: Full segmentation compression.
363
+ // Try to segment the entire key as a concatenation of one or more previously defined dictionary entries.
364
+ // Uses dynamic programming over the key array.
365
+ // Returns an object { cost, seg } where seg is an array of dictionary indices.
366
+ function segmentKey(key) {
367
+ const n = key.length
368
+ const dp = Array(n + 1).fill(null)
369
+ dp[n] = { cost: 0, seg: [] }
370
+
371
+ for (let i = n - 1; i >= 0; i--) {
372
+ let best = null
373
+ // Try every dictionary entry.
374
+ for (let d = 0; d < dict.length; d++) {
375
+ const candidate = dict[d].original
376
+ const m = candidate.length
377
+ if (i + m <= n) {
378
+ let match = true
379
+ for (let k = 0; k < m; k++) {
380
+ if (key[i + k] !== candidate[k]) {
381
+ match = false
382
+ break
383
+ }
384
+ }
385
+ if (match && dp[i + m] !== null) {
386
+ const candidateCost = 1 + dp[i + m].cost // cost 1 for using this pointer.
387
+ if (best === null || candidateCost < best.cost) {
388
+ best = { cost: candidateCost, seg: [d].concat(dp[i + m].seg) }
389
+ }
390
+ }
391
+ }
392
+ }
393
+ dp[i] = best
394
+ }
395
+ return dp[0]
396
+ }
397
+
398
+ // Process each entry (in the sorted, deterministic order).
399
+ for (const entry of data) {
400
+ const key = entry.key
401
+ let compressed
402
+ if (key.length === 1) {
403
+ // For simple keys, copy as-is.
404
+ compressed = key.slice()
405
+ } else {
406
+ // Try element-by-element compression.
407
+ const repA = compressElementByElement(key)
408
+ let bestCost = computeCost(repA)
409
+ let bestRep = repA
410
+
411
+ // Also try full segmentation over the entire key.
412
+ const segRes = segmentKey(key)
413
+ if (segRes !== null) {
414
+ const repB = [segRes.seg] // Represent segmentation as a pointer.
415
+ const costB = segRes.cost
416
+ if (costB < bestCost) {
417
+ bestCost = costB
418
+ bestRep = repB
419
+ }
420
+ }
421
+
422
+ // Now try partial segmentation: try segmenting a prefix and then appending the literal remainder.
423
+ const n = key.length
424
+ for (let i = 1; i < n; i++) {
425
+ const prefixSeg = segmentKey(key.slice(0, i))
426
+ if (prefixSeg !== null) {
427
+ const literalPart = key.slice(i)
428
+ const candidateCost = prefixSeg.cost + computeCost(literalPart)
429
+ if (candidateCost < bestCost) {
430
+ bestCost = candidateCost
431
+ // Build candidate representation: pointer for the segmented prefix followed by literal remainder.
432
+ bestRep = [prefixSeg.seg].concat(literalPart)
433
+ }
434
+ }
435
+ }
436
+
437
+ compressed = bestRep
438
+ }
439
+ dict.push({ original: key, compressed })
440
+ }
441
+
442
+ // --- Step 4. Return the dictionary and key map.
443
+ // "dictionary" is an array of compressed keys.
444
+ // "keyMap" is the array of original keys (in the same, deterministic order).
445
+ return {
446
+ dictionary: dict.map(entry => {
447
+ return entry.compressed.length === 1 && !is(Array, entry.compressed[0])
448
+ ? entry.compressed[0]
449
+ : entry.compressed
450
+ }),
451
+ keyMap: dict.map(entry => entry.original),
452
+ }
453
+ }
454
+ const genDic = compose(buildDic, filterDic, sortKeys, countKeys, listKeys)
455
+
456
+ function listKeys(v, key = [], keys = []) {
457
+ if (Array.isArray(v)) {
458
+ let i = 0
459
+ for (const v2 of v) {
460
+ listKeys(v2, append(i, key), keys)
461
+ i++
462
+ }
463
+ } else if (typeof v == "object") {
464
+ for (const k in v) listKeys(v[k], append(k, key), keys)
465
+ } else {
466
+ keys.push(key)
467
+ }
468
+ return keys
469
+ }
470
+
471
+ function isPrefix(path, prefix) {
472
+ if (prefix.length > path.length) return false
473
+ for (let i = 0; i < prefix.length; i++) {
474
+ if (!equals(path[i], prefix[i])) return false
475
+ }
476
+ return true
477
+ }
478
+ function applyDicToPath(path, sortedDic) {
479
+ // Base case: if the path is empty, nothing to replace.
480
+ if (path.length === 0) return []
481
+ // Iterate over the dictionary entries in descending order.
482
+ for (const { entry, index } of sortedDic) {
483
+ if (isPrefix(path, entry)) {
484
+ // Found a match: remove the matched prefix.
485
+ const remainder = path.slice(entry.length)
486
+ // Recursively apply dictionary replacement on the remainder.
487
+ const replacedRemainder = applyDicToPath(remainder, sortedDic)
488
+ // If the remainder is completely replaced (i.e. replacedRemainder is a single dictionary reference array),
489
+ // then merge the current dictionary index with that.
490
+ if (replacedRemainder.length === 0) {
491
+ // No remainder: simply return the dictionary reference.
492
+ return [[index]]
493
+ }
494
+ if (Array.isArray(replacedRemainder[0])) {
495
+ // The first component is already a dictionary reference: merge the indices.
496
+ return [[index, ...replacedRemainder[0]]]
497
+ } else {
498
+ // Otherwise, return the dictionary reference for the prefix and then the literal remainder.
499
+ return [[index]].concat(replacedRemainder)
500
+ }
501
+ }
502
+ }
503
+ // If no dictionary entry applies, return the original literal path.
504
+ return path
505
+ }
506
+
507
+ function applyDic(arr, dic) {
508
+ // Build sorted dictionary entries in descending order by length.
509
+ const sortedDic = dic
510
+ .map((entry, index) => ({ entry, index }))
511
+ .sort((a, b) => b.entry.length - a.entry.length)
512
+ // For each pair, apply dictionary replacement to the path.
513
+ return arr.map(pair => {
514
+ const newPath = applyDicToPath(pair[0], sortedDic)
515
+ return [newPath, pair[1]]
516
+ })
517
+ }
518
+
519
+ function encodePaths(data) {
520
+ for (let v of data) {
521
+ let path = []
522
+ for (let v2 of v[0]) {
523
+ if (is(Number, v2)) path.push([0, 0, v2])
524
+ else if (is(String, v2)) {
525
+ const key = v2.split("").map(c => c.charCodeAt(0))
526
+ path.push([key.length, ...(key.length == 0 ? [1] : key)])
527
+ } else if (is(Array, v2)) {
528
+ if (v2.length === 1) path.push([0, 3, v2[0]])
529
+ else path.push([0, 4, v2.length, ...v2])
530
+ }
531
+ }
532
+ v[0] = path
533
+ }
534
+ return data
535
+ }
536
+
537
+ function mapDic(dic, len) {
538
+ let _map = []
539
+ while (dic.length > 0) {
540
+ let dlen = dic.shift()
541
+ let _elms = []
542
+ while (dlen > 0) {
543
+ let type = dic.shift()
544
+ let elms = []
545
+ if (type == 7) {
546
+ let slen = dic.shift()
547
+ elms.push(slen)
548
+ for (let i = 0; i < slen; i++) elms.push(dic.shift())
549
+ _elms.push(elms)
550
+ } else if (type == 3) {
551
+ elms = concat(elms, [0, 0, dic.shift()])
552
+ _elms.push(elms)
553
+ } else if (type == 9) {
554
+ for (let v2 of _map[dic.shift()]) _elms.push(v2)
555
+ }
556
+ dlen--
557
+ }
558
+ _map.push(_elms)
559
+ if (_map.length === len) break
560
+ }
561
+ return _map
562
+ }
563
+
564
+ function encodeDic(dict) {
565
+ let enc = []
566
+ for (let v of dict) {
567
+ let len = 1
568
+ let elms = []
569
+ if (!is(String, v)) {
570
+ len = 0
571
+ for (let v2 of v) {
572
+ if (is(Array, v2)) {
573
+ len += v2.length
574
+ for (let v3 of v2) elms = concat(elms, [9, v3])
575
+ } else {
576
+ len += 1
577
+ if (is(String, v2)) {
578
+ elms.push(7)
579
+ elms.push(v2.length)
580
+ elms = concat(
581
+ elms,
582
+ v2.split("").map(c => c.charCodeAt(0)),
583
+ )
584
+ } else {
585
+ elms = concat(elms, [3, v2])
586
+ }
587
+ }
588
+ }
589
+ } else {
590
+ elms.push(7)
591
+ elms.push(v.length)
592
+ elms = concat(
593
+ elms,
594
+ v.split("").map(c => c.charCodeAt(0)),
595
+ )
596
+ }
597
+ enc = concat(enc, [len, ...elms])
598
+ }
599
+ return enc
600
+ }
601
+
602
+ function encode(json, nodic = false) {
603
+ let dic = null
604
+ let dictionary, keyMap
605
+ if (nodic !== true) {
606
+ ;({ dictionary, keyMap } = genDic(json))
607
+ if (dictionary.length > 0) dic = encodeDic(dictionary)
608
+ }
609
+ let enc = _encode(json)
610
+ if (dic) enc = applyDic(enc, keyMap)
611
+
612
+ enc = encodePaths(enc)
613
+ enc.sort((a, b) => {
614
+ const isUndefined = v => typeof v == "undefined"
615
+ const max = Math.max(a[0].length, b[0].length)
616
+ if (max > 0) {
617
+ for (let i = 0; i < max; i++) {
618
+ const exA = !isUndefined(a[0][i])
619
+ const exB = !isUndefined(b[0][i])
620
+ if (exA && !exB) return 1
621
+ if (!exA && exB) return -1
622
+ const max2 = Math.max(a[0][i].length, b[0][i].length)
623
+ if (max2 > 0) {
624
+ for (let i2 = 0; i2 < max2; i2++) {
625
+ const vA = a[0][i][i2]
626
+ const vB = b[0][i][i2]
627
+ const exA = !isUndefined(vA)
628
+ const exB = !isUndefined(vB)
629
+ if (exA && !exB) return 1
630
+ if (!exA && exB) return -1
631
+ if (vA > vB) return 1
632
+ if (vA < vB) return -1
633
+ }
634
+ }
635
+ }
636
+ }
637
+ return 0
638
+ })
639
+ const _dic = dic ? [1, 0, 2, dictionary.length, ...dic] : []
640
+ return concat(
641
+ _dic,
642
+ enc.reduce((arr, v) => arr.concat([...flattenPath(v[0]), ...v[1]]), []),
643
+ )
644
+ }
645
+
646
+ function _decode(arr) {
647
+ let vals = []
648
+ let dic = []
649
+ while (arr.length > 0) {
650
+ let plen = arr.shift()
651
+ let keys = []
652
+ let val = null
653
+ let skip = false
654
+ while (plen > 0) {
655
+ const plen2 = arr.shift()
656
+ if (plen2 == 0) {
657
+ const plen3 = arr.shift()
658
+ if (plen3 == 1) {
659
+ keys.push([plen2, plen3])
660
+ } else if (plen3 == 0) {
661
+ keys.push([plen2, plen3, arr.shift()])
662
+ } else if (plen3 == 2) {
663
+ const dict = arr.shift()
664
+ dic = mapDic(arr, dict)
665
+ skip = true
666
+ } else if (plen3 == 3) {
667
+ const _keys = dic[arr.shift()]
668
+ for (const k of _keys) keys.push(k)
669
+ } else if (plen3 == 4) {
670
+ let key = []
671
+ let plen4 = arr.shift()
672
+ for (let i2 = 0; i2 < plen4; i2++) {
673
+ const _keys = dic[arr.shift()]
674
+ for (const k of _keys) keys.push(k)
675
+ }
676
+ }
677
+ } else if (plen2 != 0) {
678
+ const plen3 = plen2
679
+ let key = []
680
+ for (let i2 = 0; i2 < plen3; i2++) key.push(arr.shift())
681
+ keys.push([plen2, ...key])
682
+ }
683
+ plen--
684
+ }
685
+ if (skip) continue
686
+ const type = arr.shift()
687
+ val = [type]
688
+ if (type == 5 || type == 6) {
689
+ val.push(arr.shift())
690
+ val.push(arr.shift())
691
+ } else if (type == 3 || type == 4) {
692
+ val.push(arr.shift())
693
+ } else if (type == 7) {
694
+ const strlen = arr.shift()
695
+ val.push(strlen)
696
+ for (let i2 = 0; i2 < strlen; i2++) val.push(arr.shift())
697
+ }
698
+ vals.push([keys, val])
699
+ }
700
+ return vals
701
+ }
702
+
703
+ // 0: null, 1: true, 2: false, 3: positive integer, 4: negative integer, 5: positive float, 6: negative float, 7: string, 8: object, 9: ref
704
+
705
+ function encodeVal(v) {
706
+ let vals = []
707
+ if (typeof v == "number" || typeof v == "bigint") {
708
+ const int = Number.isInteger(v)
709
+ let moved = 0
710
+ let num = v
711
+ while (num % 1 != 0) {
712
+ num *= 10
713
+ moved += 1
714
+ }
715
+ let type = 3
716
+ if (v >= 0) {
717
+ if (moved > 0) type = 5
718
+ } else {
719
+ if (moved > 0) type = 6
720
+ else type = 4
721
+ }
722
+ vals.push(type)
723
+ if (moved > 0) vals.push(moved)
724
+ if (v < 0) vals.push(-num)
725
+ else vals.push(num)
726
+ } else if (typeof v == "boolean") vals.push(v ? 1 : 2)
727
+ else if (v == null) vals = [0]
728
+ else if (typeof v == "string") {
729
+ vals = [7, v.length, ...v.split("").map(c => c.charCodeAt(0))]
730
+ } else vals = [8, ...encode(v)]
731
+ return vals
732
+ }
733
+
734
+ function decodeVal(arr) {
735
+ const type = arr[0]
736
+ const _val = arr[1]
737
+ let val = null
738
+ if (type == 0) {
739
+ val = null
740
+ } else if (type == 1) {
741
+ val = true
742
+ } else if (type == 2) {
743
+ val = false
744
+ } else if (type == 3) {
745
+ val = arr[1]
746
+ } else if (type == 4) {
747
+ val = arr[1] * -1
748
+ } else if (type == 5) {
749
+ val = arr[2]
750
+ for (let i = 0; i < arr[1]; i++) {
751
+ val /= 10
752
+ }
753
+ } else if (type == 6) {
754
+ val = arr[2] * -1
755
+ for (let i = 0; i < arr[1]; i++) {
756
+ val /= 10
757
+ }
758
+ } else if (type == 7) {
759
+ val = arr
760
+ .slice(2)
761
+ .map(c => String.fromCharCode(Number(c)))
762
+ .join("")
763
+ } else if (type == 8) {
764
+ val = decode(arr.slice(1))
765
+ }
766
+ return val
767
+ }
768
+
769
+ function decode(arr) {
770
+ const decoded = _decode(arr)
771
+ let json =
772
+ decoded[0]?.[0]?.[0]?.[0] == 0 && decoded[0]?.[0]?.[0]?.[1] == 0 ? [] : {}
773
+ for (const v of decoded) {
774
+ const keys = v[0].map(v2 => {
775
+ if (v2[0] == 0) {
776
+ if (v2[1] == 1) return ""
777
+ return v2[2]
778
+ } else {
779
+ return v2
780
+ .slice(1)
781
+ .map(c => String.fromCharCode(Number(c)))
782
+ .join("")
783
+ }
784
+ })
785
+ if (keys.length == 0) {
786
+ json = decodeVal(v[1])
787
+ } else {
788
+ let obj = json
789
+ let i = 0
790
+ for (const k of keys) {
791
+ if (typeof k == "number") {
792
+ if (typeof keys[i + 1] == "undefined") {
793
+ obj[k] = decodeVal(v[1])
794
+ } else {
795
+ if (typeof obj[k] == "undefined") {
796
+ if (typeof keys[i + 1] == "string") {
797
+ obj[k] = {}
798
+ } else {
799
+ obj[k] = []
800
+ }
801
+ }
802
+ }
803
+ } else {
804
+ if (typeof obj[k] == "undefined") {
805
+ if (typeof keys[i + 1] == "undefined") {
806
+ obj[k] = decodeVal(v[1])
807
+ } else if (typeof keys[i + 1] == "string") {
808
+ obj[k] = {}
809
+ } else {
810
+ obj[k] = []
811
+ }
812
+ }
813
+ }
814
+ obj = obj[k]
815
+ i++
816
+ }
817
+ }
818
+ }
819
+ return json
820
+ }
821
+
822
+ const toIndex = str => {
823
+ return (
824
+ "1" +
825
+ str
826
+ .split("")
827
+ .map(s => base64Map[s])
828
+ .join("")
829
+ )
830
+ }
831
+
832
+ const fromIndex = id => {
833
+ let _id = id.toString().split("")
834
+ _id.shift()
835
+ return splitEvery(2, _id)
836
+ .map(s => {
837
+ return strMap[s.join("")]
838
+ })
839
+ .join("")
840
+ }
841
+
842
+ function toSignal(arr, uint_len = 75) {
843
+ const _arr = flatten(
844
+ arr.map(n => {
845
+ let str = splitEvery(8, n.toString().split(""))
846
+ let i = 0
847
+ str = str.map(s => {
848
+ const len = i == str.length - 1 ? s.length : 9
849
+ i++
850
+ return len.toString() + s.join("")
851
+ })
852
+ return str
853
+ }),
854
+ )
855
+ let _arr2 = []
856
+ let one = 0
857
+ let i = 0
858
+ let start = null
859
+ if (!uint_len) uint_len = _arr * 100
860
+ for (let v of _arr) {
861
+ _arr2.push(v)
862
+ if (v.length - 1 == 1) {
863
+ if (start == null) start = i
864
+ one += v.length - 1
865
+ if (one == 9) {
866
+ _arr2[start] = `0${one}${_arr2[start][1]}`
867
+ for (let i2 = start + 1; i2 <= i; i2++) _arr2[i2] = `${_arr2[i2][1]}`
868
+ one = 0
869
+ start = null
870
+ }
871
+ } else {
872
+ if (one > 2) {
873
+ _arr2[start] = `0${one}${_arr2[start][1]}`
874
+ for (let i2 = start + 1; i2 < i; i2++) _arr2[i2] = `${_arr2[i2][1]}`
875
+ }
876
+ one = 0
877
+ start = null
878
+ }
879
+ i++
880
+ }
881
+ if (one > 2) {
882
+ _arr2[start] = `0${one}${_arr2[start][1]}`
883
+ for (let i2 = start + 1; i2 <= i - 1; i2++) _arr2[i2] = `${_arr2[i2][1]}`
884
+ }
885
+ let _arr3 = []
886
+ let chain = null
887
+ let cur = 0
888
+ let num = ""
889
+ for (let v of _arr2) {
890
+ if (chain == null && +v[0] == 0) {
891
+ chain = +v[1]
892
+ cur = 1
893
+ num = v
894
+ } else if (chain != null) {
895
+ num += v
896
+ cur++
897
+ if (chain == cur) {
898
+ _arr3.push(num)
899
+ chain = null
900
+ num = ""
901
+ cur = 0
902
+ }
903
+ } else {
904
+ _arr3.push(v)
905
+ }
906
+ }
907
+ if (chain != null) _arr3.push(num)
908
+ let arrs2 = []
909
+ let len2 = 0
910
+ let str2 = ""
911
+ for (let v of _arr3) {
912
+ if (len2 + v.length > uint_len) {
913
+ arrs2.push("1" + str2)
914
+ if (+v[0] == 0) {
915
+ let len3 = uint_len - len2
916
+ if (len3 == 2 || len3 == 3) {
917
+ arrs2[arrs2.length - 1] += `1${v[2]}`
918
+ let new_len = +v[1] - 1
919
+ if (new_len == 2) {
920
+ v = `1${v[3]}1${v[4]}`
921
+ } else {
922
+ v = `0${new_len}${v.slice(3)}`
923
+ }
924
+ } else if (len3 > 3) {
925
+ let new_len = +v[1] - 2
926
+ let old_len = 2
927
+ if (len3 == 4) {
928
+ arrs2[arrs2.length - 1] += `1${v[2]}1${v[3]}`
929
+ } else {
930
+ old_len = len3 - 2
931
+ new_len = +v[1] - old_len
932
+ arrs2[arrs2.length - 1] += `0${old_len}${v.slice(2, 2 + old_len)}`
933
+ }
934
+ if (new_len == 1) {
935
+ v = `1${v[old_len + 2]}`
936
+ } else if (new_len == 2) {
937
+ v = `1${v[old_len + 2]}1${v[old_len + 3]}`
938
+ } else {
939
+ v = `0${new_len}${v.slice(old_len + 2)}`
940
+ }
941
+ }
942
+ }
943
+ len2 = 0
944
+ str2 = ""
945
+ }
946
+ len2 += v.length
947
+ str2 += v
948
+ }
949
+ if (str2 != "") arrs2.push("1" + str2)
950
+ return arrs2
951
+ }
952
+
953
+ function fromSignal(arr) {
954
+ let _arr = []
955
+ let prev = ""
956
+ for (let s of arr) {
957
+ s = s.slice(1)
958
+ let str = s.split("")
959
+ while (str.length > 0) {
960
+ const len = +str.shift()
961
+ if (len == 0) {
962
+ const len2 = +str.shift()
963
+ for (let i2 = 0; i2 < len2; i2++) {
964
+ _arr.push(+str[i2])
965
+ }
966
+ str = str.slice(len2)
967
+ } else if (len == 9) {
968
+ prev += str.slice(0, 8).join("")
969
+ str = str.slice(8)
970
+ } else {
971
+ const nums = str.slice(0, len).join("")
972
+ str = str.slice(len)
973
+ _arr.push(+(prev + nums))
974
+ prev = ""
975
+ }
976
+ }
977
+ }
978
+ return _arr
979
+ }
980
+
981
+ const path = p => toSignal(encodePath(p))
982
+ const val = v => toSignal(encodeVal(v))
983
+ const query = v => toSignal(encodeQuery(v))
984
+
985
+ function encodeQuery(v) {
986
+ if (!Array.isArray(v)) throw Error("query must be an array")
987
+ const op = v[0]
988
+ if (isNil(ops[op])) throw Error(`query not supported: ${op}`)
989
+ return [ops[op], ...encodeVal(v[1])]
990
+ }
991
+
992
+ function decodeQuery(v) {
993
+ const op = opMap[v[0]]
994
+ if (isNil(op)) throw Error("op doens't exist")
995
+ return [op, decodeVal(v.slice(1))]
996
+ }
997
+
998
+ function toUint8(sig) {
999
+ let num = BigInt(sig)
1000
+ let byteArray = []
1001
+ while (num > 0) {
1002
+ byteArray.push(Number(num % 256n))
1003
+ num /= 256n
1004
+ }
1005
+ return new Uint8Array(byteArray.reverse())
1006
+ }
1007
+ function compress(arr) {
1008
+ let sig = toSignal(arr, false)
1009
+ return toUint8(sig)
1010
+ }
1011
+
1012
+ function decompress(arr) {
1013
+ const str = fromUint8(arr)
1014
+ return fromSignal([str])
1015
+ }
1016
+
1017
+ function fromUint8(arr) {
1018
+ let num = 0n
1019
+ for (let byte of arr) {
1020
+ num = num * 256n + BigInt(byte)
1021
+ }
1022
+ return num.toString()
1023
+ }
1024
+
1025
+ module.exports = {
1026
+ encode,
1027
+ decode,
1028
+ encodePath,
1029
+ decodePath,
1030
+ encodeVal,
1031
+ decodeVal,
1032
+ pad,
1033
+ _encode,
1034
+ flattenPath,
1035
+ toSignal,
1036
+ fromSignal,
1037
+ toIndex,
1038
+ fromIndex,
1039
+ path,
1040
+ val,
1041
+ query,
1042
+ encodeQuery,
1043
+ decodeQuery,
1044
+ compress,
1045
+ decompress,
1046
+ toUint8,
1047
+ fromUint8,
1048
+ }
package/encoder.js CHANGED
@@ -270,7 +270,7 @@ function _decode(arr) {
270
270
  }
271
271
  } else if (plen2 != 0) {
272
272
  const plen3 = plen2
273
- const key = []
273
+ let key = []
274
274
  for (let i2 = 0; i2 < plen3; i2++) key.push(arr.shift())
275
275
  keys.push([plen2, ...key])
276
276
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zkjson",
3
- "version": "0.3.2",
3
+ "version": "0.4.1",
4
4
  "description": "Zero Knowledge Provable JSON",
5
5
  "main": "index.js",
6
6
  "license": "MIT",