@muze-nl/od-jsontag 0.2.9 → 0.3.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/package.json +1 -1
- package/src/jsontag.mjs +17 -3
- package/src/parse.mjs +71 -11
- package/src/serialize.mjs +28 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@muze-nl/od-jsontag",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "On Demand JSONTag: parse/serialize large datastructures on demand, useful for sharing data between threads",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Auke van Slooten <auke@muze.nl>",
|
package/src/jsontag.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import JSONTag from '@muze-nl/jsontag'
|
|
2
|
-
import {source} from './symbols.mjs'
|
|
2
|
+
import {source, isChanged} from './symbols.mjs'
|
|
3
3
|
|
|
4
4
|
export function getType(obj) {
|
|
5
5
|
return JSONTag.getType(obj?.[source] ?? obj)
|
|
@@ -26,22 +26,36 @@ export function isNull(obj) {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export function setAttribute(obj, attr, value) {
|
|
29
|
+
if (obj?.[source]) {
|
|
30
|
+
obj[isChanged] = true
|
|
31
|
+
}
|
|
29
32
|
return JSONTag.setAttribute(obj?.[source] ?? obj, attr, value)
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
export function setAttributes(obj, attr) {
|
|
36
|
+
if (obj?.[source]) {
|
|
37
|
+
obj[isChanged] = true
|
|
38
|
+
}
|
|
33
39
|
return JSONTag.setAttribute(obj?.[source] ?? obj, attr)
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
export function setType(obj, type) {
|
|
43
|
+
if (obj?.[source]) {
|
|
44
|
+
obj[isChanged] = true
|
|
45
|
+
}
|
|
37
46
|
return JSONTag.setType(obj?.[source] ?? obj, type)
|
|
38
47
|
}
|
|
39
48
|
|
|
40
49
|
export function addAttribute(obj, attr, value) {
|
|
50
|
+
if (obj?.[source]) {
|
|
51
|
+
obj[isChanged] = true
|
|
52
|
+
}
|
|
41
53
|
return JSONTag.addAttribute(obj?.[source] ?? obj, attr, value)
|
|
42
54
|
}
|
|
43
55
|
|
|
44
56
|
export function removeAttribute(obj, attr) {
|
|
57
|
+
if (obj?.[source]) {
|
|
58
|
+
obj[isChanged] = true
|
|
59
|
+
}
|
|
45
60
|
return JSONTag.removeAttribute(obj?.[source] ?? obj, attr)
|
|
46
|
-
}
|
|
47
|
-
|
|
61
|
+
}
|
package/src/parse.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import {source,isProxy,proxyType,getBuffer,getIndex,isChanged,isParsed,position,
|
|
|
5
5
|
|
|
6
6
|
const decoder = new TextDecoder()
|
|
7
7
|
const encoder = new TextEncoder()
|
|
8
|
+
const arrayProxies = new WeakMap()
|
|
8
9
|
|
|
9
10
|
function stringToSAB(strData) {
|
|
10
11
|
const buffer = encoder.encode(strData)
|
|
@@ -14,6 +15,25 @@ function stringToSAB(strData) {
|
|
|
14
15
|
return uint8sab
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
function SABtoString(arr) {
|
|
19
|
+
let string = '';
|
|
20
|
+
for (let c of arr) {
|
|
21
|
+
string+= String.fromCharCode(c)
|
|
22
|
+
}
|
|
23
|
+
return string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
class Slice {
|
|
27
|
+
constructor(start, end) {
|
|
28
|
+
this.start = start;
|
|
29
|
+
this.end = end;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const isSlice = function(r) {
|
|
34
|
+
return r instanceof Slice
|
|
35
|
+
}
|
|
36
|
+
|
|
17
37
|
export default function parse(input, meta, immutable=true)
|
|
18
38
|
{
|
|
19
39
|
if (!meta) {
|
|
@@ -68,7 +88,8 @@ export default function parse(input, meta, immutable=true)
|
|
|
68
88
|
let next = function(c)
|
|
69
89
|
{
|
|
70
90
|
if (c && c!==ch) {
|
|
71
|
-
|
|
91
|
+
let source = SABtoString(input)
|
|
92
|
+
error("Expected '"+c+"' instead of '"+ch+"': "+at+':'+source)
|
|
72
93
|
}
|
|
73
94
|
ch = String.fromCharCode(input.at(at))
|
|
74
95
|
at+=1
|
|
@@ -565,7 +586,11 @@ export default function parse(input, meta, immutable=true)
|
|
|
565
586
|
while(ch) {
|
|
566
587
|
item = value()
|
|
567
588
|
checkUnresolved(item, array, array.length)
|
|
568
|
-
|
|
589
|
+
if (isSlice(item)) {
|
|
590
|
+
array = array.concat(meta.resultArray.slice(item.start, item.end))
|
|
591
|
+
} else {
|
|
592
|
+
array.push(item)
|
|
593
|
+
}
|
|
569
594
|
whitespace()
|
|
570
595
|
if (ch===']') {
|
|
571
596
|
next(']')
|
|
@@ -650,6 +675,15 @@ export default function parse(input, meta, immutable=true)
|
|
|
650
675
|
numString += ch
|
|
651
676
|
next()
|
|
652
677
|
}
|
|
678
|
+
if (ch=='-') {
|
|
679
|
+
next('-')
|
|
680
|
+
let endString = ''
|
|
681
|
+
while(ch>='0' && ch<='9') {
|
|
682
|
+
endString += ch
|
|
683
|
+
next()
|
|
684
|
+
}
|
|
685
|
+
return new Slice(parseInt(numString),parseInt(endString)+1) // +1 because array.slice(start,end) slices upto but not including end
|
|
686
|
+
}
|
|
653
687
|
return parseInt(numString)
|
|
654
688
|
}
|
|
655
689
|
|
|
@@ -674,6 +708,18 @@ export default function parse(input, meta, immutable=true)
|
|
|
674
708
|
})
|
|
675
709
|
}
|
|
676
710
|
|
|
711
|
+
const getArrayProxy = (arr, par, handler) => {
|
|
712
|
+
if (!handler) {
|
|
713
|
+
handler = handlers.arrayHandler
|
|
714
|
+
}
|
|
715
|
+
if (!arrayProxies.has(arr)) {
|
|
716
|
+
arrayProxies.set(arr, new Proxy(arr, handler))
|
|
717
|
+
}
|
|
718
|
+
let aProxy = arrayProxies.get(arr)
|
|
719
|
+
aProxy[parent] = par
|
|
720
|
+
return aProxy
|
|
721
|
+
}
|
|
722
|
+
|
|
677
723
|
const handlers = {
|
|
678
724
|
newArrayHandler: {
|
|
679
725
|
get(target, prop) {
|
|
@@ -694,12 +740,17 @@ export default function parse(input, meta, immutable=true)
|
|
|
694
740
|
return undefined
|
|
695
741
|
}
|
|
696
742
|
if (Array.isArray(target[prop])) {
|
|
697
|
-
return
|
|
743
|
+
return getArrayProxy(target[prop], target, handlers.newArrayHandler)
|
|
698
744
|
}
|
|
699
745
|
return target[prop]
|
|
700
746
|
}
|
|
701
747
|
},
|
|
702
748
|
set(target, prop, value) {
|
|
749
|
+
if (prop === isChanged || prop === parent) {
|
|
750
|
+
// prevent infinite loops, parent is only needed to mark it isChanged
|
|
751
|
+
// but this is a new array proxy, parent is already dirty
|
|
752
|
+
return true
|
|
753
|
+
}
|
|
703
754
|
if (meta.access && !meta.access(target, prop)) {
|
|
704
755
|
return undefined
|
|
705
756
|
}
|
|
@@ -745,7 +796,7 @@ export default function parse(input, meta, immutable=true)
|
|
|
745
796
|
return undefined
|
|
746
797
|
}
|
|
747
798
|
if (Array.isArray(target[prop])) {
|
|
748
|
-
return
|
|
799
|
+
return getArrayProxy(target[prop], target, handlers.newArrayHandler)
|
|
749
800
|
}
|
|
750
801
|
return target[prop]
|
|
751
802
|
break
|
|
@@ -782,19 +833,24 @@ export default function parse(input, meta, immutable=true)
|
|
|
782
833
|
return result
|
|
783
834
|
}
|
|
784
835
|
} else if (prop===isChanged) {
|
|
785
|
-
return target[parent][isChanged]
|
|
836
|
+
return target[isChanged] || target[parent][isChanged]
|
|
837
|
+
} else if (prop===source) {
|
|
838
|
+
return target
|
|
786
839
|
} else {
|
|
787
840
|
if (meta.access && !meta.access(target, prop, 'get')) {
|
|
788
841
|
return undefined
|
|
789
842
|
}
|
|
790
843
|
if (Array.isArray(target[prop])) {
|
|
791
|
-
target[prop]
|
|
792
|
-
return new Proxy(target[prop], handlers.arrayHandler)
|
|
844
|
+
return getArrayProxy(target[prop], target)
|
|
793
845
|
}
|
|
794
846
|
return target[prop]
|
|
795
847
|
}
|
|
796
848
|
},
|
|
797
849
|
set(target, prop, value) {
|
|
850
|
+
if (prop == parent) {
|
|
851
|
+
target[parent] = value
|
|
852
|
+
return true
|
|
853
|
+
}
|
|
798
854
|
if (immutable) {
|
|
799
855
|
throw new Error('dataspace is immutable')
|
|
800
856
|
}
|
|
@@ -805,6 +861,7 @@ export default function parse(input, meta, immutable=true)
|
|
|
805
861
|
value = getNewValueProxy(value)
|
|
806
862
|
}
|
|
807
863
|
target[prop] = value
|
|
864
|
+
target[isChanged] = true
|
|
808
865
|
target[parent][isChanged] = true
|
|
809
866
|
return true
|
|
810
867
|
},
|
|
@@ -819,6 +876,7 @@ export default function parse(input, meta, immutable=true)
|
|
|
819
876
|
//that object should be deleted so that its line will become empty
|
|
820
877
|
//when stringifying resultArray again
|
|
821
878
|
delete target[prop]
|
|
879
|
+
target[isChanged] = true
|
|
822
880
|
target[parent][isChanged] = true
|
|
823
881
|
return true
|
|
824
882
|
}
|
|
@@ -867,15 +925,14 @@ export default function parse(input, meta, immutable=true)
|
|
|
867
925
|
return undefined
|
|
868
926
|
}
|
|
869
927
|
if (Array.isArray(target[prop])) {
|
|
870
|
-
target[prop]
|
|
871
|
-
return new Proxy(target[prop], handlers.arrayHandler)
|
|
928
|
+
return getArrayProxy(target[prop], target)
|
|
872
929
|
}
|
|
873
930
|
return target[prop]
|
|
874
931
|
break
|
|
875
932
|
}
|
|
876
933
|
},
|
|
877
934
|
set(target, prop, value, receiver) {
|
|
878
|
-
if (immutable && prop!==resultSet && prop!==source) {
|
|
935
|
+
if (immutable && prop!==resultSet && prop!==source && prop!==isChanged) {
|
|
879
936
|
throw new Error('dataspace is immutable')
|
|
880
937
|
}
|
|
881
938
|
switch(prop) {
|
|
@@ -930,7 +987,7 @@ export default function parse(input, meta, immutable=true)
|
|
|
930
987
|
return undefined
|
|
931
988
|
}
|
|
932
989
|
firstParse(target)
|
|
933
|
-
Object.defineProperty(target, prop, descriptor)
|
|
990
|
+
return Object.defineProperty(target, prop, descriptor)
|
|
934
991
|
},
|
|
935
992
|
has(target, prop) {
|
|
936
993
|
if (meta.access && !meta.access(target, prop, 'has')) {
|
|
@@ -1003,6 +1060,9 @@ export default function parse(input, meta, immutable=true)
|
|
|
1003
1060
|
whitespace()
|
|
1004
1061
|
if (ch==='~') {
|
|
1005
1062
|
let vOffset = offset()
|
|
1063
|
+
if (isSlice(vOffset)) {
|
|
1064
|
+
return vOffset
|
|
1065
|
+
}
|
|
1006
1066
|
return meta.resultArray[vOffset]
|
|
1007
1067
|
}
|
|
1008
1068
|
if (ch==='<') {
|
package/src/serialize.mjs
CHANGED
|
@@ -32,7 +32,7 @@ export default function serialize(value, options={}) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
if (!resultArray) {
|
|
35
|
-
resultArray = value[resultSet]
|
|
35
|
+
resultArray = value?.[resultSet]
|
|
36
36
|
}
|
|
37
37
|
if (!resultArray) {
|
|
38
38
|
resultArray = []
|
|
@@ -90,7 +90,29 @@ export default function serialize(value, options={}) {
|
|
|
90
90
|
prop = typeString + value
|
|
91
91
|
break
|
|
92
92
|
case 'array':
|
|
93
|
-
let entries = value.map(e => stringifyValue(e, true, current))
|
|
93
|
+
let entries = value.map(e => stringifyValue(e, true, current))
|
|
94
|
+
let mergedEntries = []
|
|
95
|
+
let previousIndex = null
|
|
96
|
+
let startSlice = null
|
|
97
|
+
entries.forEach(e => {
|
|
98
|
+
if (e[0]=='~') {
|
|
99
|
+
let currIndex = parseInt(e.substr(1))
|
|
100
|
+
if (startSlice && currIndex === (previousIndex + 1)) {
|
|
101
|
+
mergedEntries.pop()
|
|
102
|
+
mergedEntries.push('~' + startSlice + '-' + currIndex)
|
|
103
|
+
previousIndex = currIndex
|
|
104
|
+
} else {
|
|
105
|
+
mergedEntries.push(e)
|
|
106
|
+
previousIndex = currIndex
|
|
107
|
+
startSlice = currIndex
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
mergedEntries.push(e)
|
|
111
|
+
previousIndex = null
|
|
112
|
+
startSlice = null
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
entries = mergedEntries.join(',')
|
|
94
116
|
prop = typeString + '[' + entries + ']'
|
|
95
117
|
break
|
|
96
118
|
case 'object':
|
|
@@ -159,7 +181,7 @@ export default function serialize(value, options={}) {
|
|
|
159
181
|
return u8arr
|
|
160
182
|
}
|
|
161
183
|
|
|
162
|
-
if (!value[resultSet]) {
|
|
184
|
+
if (!value?.[resultSet]) {
|
|
163
185
|
resultArray.push(value)
|
|
164
186
|
}
|
|
165
187
|
let currentSource = 0
|
|
@@ -205,7 +227,9 @@ export default function serialize(value, options={}) {
|
|
|
205
227
|
for (let line of arr) {
|
|
206
228
|
length += line.length+1
|
|
207
229
|
}
|
|
208
|
-
length
|
|
230
|
+
if (length) {
|
|
231
|
+
length -= 1 // skip last newline
|
|
232
|
+
}
|
|
209
233
|
let sab = new SharedArrayBuffer(length)
|
|
210
234
|
let u8arr = new Uint8Array(sab)
|
|
211
235
|
let offset = 0
|