@muze-nl/simplystore 0.5.1 → 0.5.3

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/simplystore",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "main": "src/server.mjs",
5
5
  "type": "module",
6
6
  "scripts": {
package/src/fastParse.mjs CHANGED
@@ -567,9 +567,9 @@ export default function parse(input, meta, immutable=true)
567
567
  error("Input stopped early")
568
568
  }
569
569
 
570
- let object = function()
570
+ let object = function(object={})
571
571
  {
572
- let key, val, object={}
572
+ let key, val
573
573
  if (ch !== '{') {
574
574
  error("Syntax Error")
575
575
  }
@@ -638,10 +638,10 @@ export default function parse(input, meta, immutable=true)
638
638
  return parseInt(numString)
639
639
  }
640
640
 
641
- let parseValue = function(position) {
641
+ let parseValue = function(position, ob={}) {
642
642
  at = position.start
643
643
  next()
644
- return value()
644
+ return value(ob)
645
645
  }
646
646
 
647
647
  const makeChildProxies = function(parent) {
@@ -704,7 +704,7 @@ export default function parse(input, meta, immutable=true)
704
704
  if (i != index) {
705
705
  return encoder.encode('~'+index)
706
706
  }
707
- // return newly stringified contents of cache
707
+ // return newly stringified contents of target
708
708
  return encoder.encode(fastStringify(target, meta, true, i))
709
709
  }
710
710
  break
@@ -726,7 +726,7 @@ export default function parse(input, meta, immutable=true)
726
726
  if (JSONTag.getType(value)==='object' && !value[isProxy]) {
727
727
  value = getNewValueProxy(value)
728
728
  }
729
- cache[prop] = val
729
+ target[prop] = val
730
730
  return true
731
731
  }
732
732
  }
@@ -744,11 +744,17 @@ export default function parse(input, meta, immutable=true)
744
744
  start: at-1,
745
745
  end: at-1+length
746
746
  }
747
- let cache = {} // use a single global dummy cache object here to preserve memory
747
+ let cache = {}
748
748
  let targetIsChanged = false
749
749
  let parsed = false
750
750
  at += length
751
751
  next()
752
+ let firstParse = function() {
753
+ if (!parsed) {
754
+ parseValue(position, cache)
755
+ parsed = true
756
+ }
757
+ }
752
758
  // newValueHandler makes sure that value[getBuffer] runs stringify
753
759
  // arrayHandler makes sure that changes in the array set targetIsChanged to true
754
760
  let arrayHandler = {
@@ -794,13 +800,10 @@ export default function parse(input, meta, immutable=true)
794
800
  }
795
801
  let handler = {
796
802
  get(target, prop, receiver) {
797
- if (!parsed) {
798
- cache = parseValue(position)
799
- parsed = true
800
- }
803
+ firstParse()
801
804
  switch(prop) {
802
805
  case source:
803
- return cache
806
+ return target
804
807
  break
805
808
  case isProxy:
806
809
  return true
@@ -812,8 +815,8 @@ export default function parse(input, meta, immutable=true)
812
815
  }
813
816
  if (targetIsChanged) {
814
817
  // return newly stringified contents of cache
815
- let temp = fastStringify(cache, null, true)
816
- return encoder.encode(fastStringify(cache, null, true))
818
+ let temp = fastStringify(target, null, true)
819
+ return encoder.encode(fastStringify(target, null, true))
817
820
  }
818
821
  return input.slice(position.start,position.end)
819
822
  }
@@ -825,57 +828,41 @@ export default function parse(input, meta, immutable=true)
825
828
  return targetIsChanged
826
829
  break
827
830
  default:
828
- if (!immutable && Array.isArray(cache[prop])) {
829
- return new Proxy(cache[prop], arrayHandler)
831
+ if (!immutable && Array.isArray(target[prop])) {
832
+ return new Proxy(target[prop], arrayHandler)
830
833
  }
831
- return cache[prop] // FIXME: make arrays immutable as well
834
+ return target[prop] // FIXME: make arrays immutable as well
832
835
  break
833
836
  }
834
837
  },
835
- has(target, prop) {
836
- if (!parsed) {
837
- cache = parseValue(position)
838
- parsed = true
839
- }
840
- return typeof cache[prop] !== 'undefined'
841
- },
842
- ownKeys() {
843
- if (!parsed) {
844
- cache = parseValue(position)
845
- parsed = true
846
- }
847
- return Reflect.ownKeys(cache)
848
- }
849
- }
850
- if (!immutable) {
851
- Object.assign(handler, {
852
- set: (target, prop, val) => {
853
- if (!parsed) {
854
- cache = parseValue(position)
855
- parsed = true
856
- }
857
- if (JSONTag.getType(val)==='object' && !val[isProxy]) {
858
- val = getNewValueProxy(val)
838
+ set(target, prop, value) {
839
+ if (!immutable) {
840
+ firstParse()
841
+ if (JSONTag.getType(value)==='object' && !value[isProxy]) {
842
+ value = getNewValueProxy(value)
859
843
  }
860
- cache[prop] = val
844
+ target[prop] = value
861
845
  targetIsChanged = true
862
846
  return true
863
- },
864
- deleteProperty: (target, prop) => {
865
- if (!parsed) {
866
- cache = parseValue(position)
867
- parsed = true
868
- }
869
- delete cache[prop]
847
+ }
848
+ },
849
+ deleteProperty: (target, prop) => {
850
+ if (!immutable) {
851
+ firstParse()
852
+ delete target[prop]
870
853
  targetIsChanged = true
871
854
  return true
872
855
  }
873
- })
856
+ },
857
+ 'ownKeys': (target) => {
858
+ firstParse()
859
+ return Reflect.ownKeys(target)
860
+ }
874
861
  }
875
862
  return new Proxy(cache, handler)
876
863
  }
877
864
 
878
- value = function()
865
+ value = function(ob={})
879
866
  {
880
867
  let tagOb, result, tagName;
881
868
  whitespace()
@@ -893,7 +880,7 @@ export default function parse(input, meta, immutable=true)
893
880
  if (tagName && tagName!=='object') {
894
881
  isTypeError(tagName, ch)
895
882
  }
896
- result = object()
883
+ result = object(ob)
897
884
  break
898
885
  case '[':
899
886
  if (tagName && tagName!=='array') {
@@ -6,7 +6,7 @@ import {source,isProxy,getIndex, getBuffer} from './symbols.mjs'
6
6
  const encoder = new TextEncoder()
7
7
  const decoder = new TextDecoder()
8
8
 
9
- export default function stringify(value, meta, skipLength=false, index) {
9
+ export default function stringify(value, meta, skipLength=false, index=false) {
10
10
  let resultArray = []
11
11
  if (!meta) {
12
12
  meta = {}
@@ -19,7 +19,87 @@ export default function stringify(value, meta, skipLength=false, index) {
19
19
  }
20
20
  let references = new WeakMap()
21
21
 
22
- const innerStringify = (value) => {
22
+ function stringifyValue(value) {
23
+ let prop
24
+ let typeString = JSONTag.getTypeString(value)
25
+ let type = JSONTag.getType(value)
26
+ switch (type) {
27
+ case 'string':
28
+ case 'decimal':
29
+ case 'money':
30
+ case 'link':
31
+ case 'text':
32
+ case 'blob':
33
+ case 'color':
34
+ case 'email':
35
+ case 'hash':
36
+ case 'duration':
37
+ case 'phone':
38
+ case 'url':
39
+ case 'uuid':
40
+ case 'date':
41
+ case 'time':
42
+ case 'datetime':
43
+ if (JSONTag.isNull(value)) {
44
+ value = 'null'
45
+ } else {
46
+ value = JSON.stringify(''+value)
47
+ }
48
+ prop = typeString + value
49
+ break
50
+ case 'int':
51
+ case 'uint':
52
+ case 'int8':
53
+ case 'uint8':
54
+ case 'int16':
55
+ case 'uint16':
56
+ case 'int32':
57
+ case 'uint32':
58
+ case 'int64':
59
+ case 'uint64':
60
+ case 'float':
61
+ case 'float32':
62
+ case 'float64':
63
+ case 'timestamp':
64
+ case 'number':
65
+ case 'boolean':
66
+ if (JSONTag.isNull(value)) {
67
+ value = 'null'
68
+ } else {
69
+ value = JSON.stringify(value)
70
+ }
71
+ prop = typeString + value
72
+ break
73
+ case 'array':
74
+ let entries = value.map(e => stringifyValue(e)).join(',')
75
+ prop = typeString + '[' + entries + ']'
76
+ break
77
+ case 'object':
78
+ if (!value) {
79
+ prop = 'null'
80
+ } else if (value[isProxy]) {
81
+ prop = decoder.decode(value[getBuffer](current))
82
+ } else {
83
+ if (!references.has(value)) {
84
+ references.set(value, resultArray.length)
85
+ resultArray.push(value)
86
+ }
87
+ prop = '~'+references.get(value)
88
+ }
89
+ break
90
+ default:
91
+ throw new Error(JSONTag.getType(value)+' type not yet implemented')
92
+ break
93
+ }
94
+ return prop
95
+ }
96
+
97
+ const encoder = new TextEncoder()
98
+ const decoder = new TextDecoder()
99
+
100
+ // is only ever called on object values
101
+ // and should always return a stringified object, not a reference (~n)
102
+ const innerStringify = (current) => {
23
103
  let indent = ""
24
104
  let gap = ""
25
105
 
@@ -29,147 +109,26 @@ export default function stringify(value, meta, skipLength=false, index) {
29
109
  indent = space
30
110
  }
31
111
 
32
- const encodeProperties = (obj) => {
33
- return Object.getOwnPropertyNames(obj).map(prop => {
34
- let enumerable = obj.propertyIsEnumerable(prop) ? '' : '#'
35
- return enumerable+'"'+prop+'":'+str(prop, obj)
36
- }).join(',')
37
- }
112
+ let object = resultArray[current]
113
+ let result
38
114
 
39
- const encodeEntries = (arr) => {
40
- let result = arr.map((value,index) => {
41
- return str(index, arr)
42
- }).join(",")
43
- return result
115
+ // if value is a valueProxy, just copy the input slice
116
+ if (object && !JSONTag.isNull(object) && object[isProxy]) {
117
+ return decoder.decode(object[getBuffer](current))
44
118
  }
45
-
46
- const createId = (value) => {
47
- if (typeof crypto === 'undefined') {
48
- console.error('JSONTag: cannot generate uuid, crypto support is disabled.')
49
- throw new Error('Cannot create links to resolve references, crypto support is disabled')
50
- }
51
- if (typeof crypto.randomUUID === 'function') {
52
- var id = crypto.randomUUID()
53
- } else {
54
- var id = ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
55
- (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
56
- );
57
- }
58
- JSONTag.setAttribute(value, 'id', id)
59
- return id
119
+ if (typeof object === 'undefined' || object === null) {
120
+ return 'null'
60
121
  }
61
-
62
- const encoder = new TextEncoder()
63
- const decoder = new TextDecoder()
64
-
65
- const str = (key, holder) => {
66
- let value = holder[key]
67
- let result, updateReference
68
- // if value is a valueProxy, just copy the input slice
69
- if (value && !JSONTag.isNull(value) && value[isProxy]) {
70
- if (index===0) {
71
- resultArray.push(decoder.decode(value[getBuffer](index)))
72
- }
73
- return decoder.decode(value[getBuffer](index))
74
- }
75
- if (typeof value === 'undefined' || value === null) {
76
- return 'null'
77
- }
78
- if (JSONTag.getType(value) === 'object' && !Array.isArray(value)) {
79
- let id = JSONTag.getAttribute(value, 'id')
80
- if (!references.has(value)) {
81
- let reference = resultArray.length
82
- updateReference = reference
83
- references.set(value, updateReference)
84
- resultArray.push('')
85
- if (id && !meta.index.id.has(id)) {
86
- meta.index.id.set(id, updateReference)
87
- }
88
- } else {
89
- return '~'+references.get(value)
90
- }
91
- }
92
- if (Array.isArray(value)) {
93
- result = JSONTag.getTypeString(value) + "["+encodeEntries(value)+"]"
94
- } else if (value instanceof Object) {
95
- let typeString = JSONTag.getTypeString(value)
96
- let type = JSONTag.getType(value)
97
- switch (type) {
98
- case 'string':
99
- case 'decimal':
100
- case 'money':
101
- case 'link':
102
- case 'text':
103
- case 'blob':
104
- case 'color':
105
- case 'email':
106
- case 'hash':
107
- case 'duration':
108
- case 'phone':
109
- case 'url':
110
- case 'uuid':
111
- case 'date':
112
- case 'time':
113
- case 'datetime':
114
- if (JSONTag.isNull(value)) {
115
- value = 'null'
116
- } else {
117
- value = JSON.stringify(''+value)
118
- }
119
- result = typeString + value
120
- break
121
- case 'int':
122
- case 'uint':
123
- case 'int8':
124
- case 'uint8':
125
- case 'int16':
126
- case 'uint16':
127
- case 'int32':
128
- case 'uint32':
129
- case 'int64':
130
- case 'uint64':
131
- case 'float':
132
- case 'float32':
133
- case 'float64':
134
- case 'timestamp':
135
- case 'number':
136
- case 'boolean':
137
- if (JSONTag.isNull(value)) {
138
- value = 'null'
139
- } else {
140
- value = JSON.stringify(value)
141
- }
142
- result = typeString + value
143
- break
144
- case 'array':
145
- let entries = encodeEntries(value) // calculate children first so parent references can add id attribute
146
- result = typeString + '[' + entries + '}'
147
- break
148
- case 'object':
149
- if (JSONTag.isNull(value)) {
150
- result = typeString + "null"
151
- } else {
152
- let props = encodeProperties(value); // calculate children first so parent references can add id attribute
153
- result = typeString + '{' + props + '}'
154
- }
155
- break
156
- default:
157
- throw new Error(JSONTag.getType(value)+' type not yet implemented')
158
- break
159
- }
160
- } else {
161
- result = JSON.stringify(value)
162
- }
163
- if (typeof updateReference != 'undefined') {
164
- resultArray[updateReference] = result
165
- if (index!==updateReference) {
166
- result = '~'+updateReference
167
- }
168
- }
169
- return result
122
+
123
+ let props = []
124
+ for (let key of Object.getOwnPropertyNames(object)) {
125
+ let value = object[key]
126
+ let prop = stringifyValue(value)
127
+ let enumerable = object.propertyIsEnumerable(key) ? '' : '#'
128
+ props.push(enumerable+'"'+key+'":'+prop)
170
129
  }
171
-
172
- return str("", {"": value})
130
+ result = JSONTag.getTypeString(object)+'{'+props.join(',')+'}'
131
+ return result
173
132
  }
174
133
 
175
134
  const encode = (s) => {
@@ -180,7 +139,13 @@ export default function stringify(value, meta, skipLength=false, index) {
180
139
  return '('+length+')'+s
181
140
  }
182
141
 
183
- innerStringify(value)
142
+ resultArray.push(value)
143
+ let current = 0
144
+ while(current<resultArray.length) {
145
+ resultArray[current] = innerStringify(current)
146
+ current++
147
+ }
148
+
184
149
  return resultArray.map(encode).join("\n")
185
150
  }
186
151