@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muze-nl/od-jsontag",
3
- "version": "0.2.9",
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
- error("Expected '"+c+"' instead of '"+ch+"': "+at+':'+input)
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
- array.push(item)
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 new Proxy(target[prop], handlers.newArrayHandler)
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 new Proxy(target[prop], handlers.newArrayHandler)
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][parent] = target[parent]
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][parent] = target
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)).join(',')
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 -= 1 // skip last newline
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