@muze-nl/od-jsontag 0.3.4 → 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.
- package/README.md +10 -10
- package/package.json +6 -4
- package/src/parse.mjs +631 -996
- package/src/serialize.mjs +219 -220
- package/src/symbols.mjs +0 -1
- package/src/jsontag.mjs +0 -61
package/src/parse.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import JSONTag from '@muze-nl/jsontag';
|
|
2
2
|
import Null from '@muze-nl/jsontag/src/lib/Null.mjs'
|
|
3
3
|
import serialize from './serialize.mjs'
|
|
4
|
-
import {source,isProxy,proxyType,getBuffer,getIndex,isChanged,isParsed,
|
|
4
|
+
import {source,isProxy,proxyType,getBuffer,getIndex,isChanged,isParsed,position,parent,resultSet} from './symbols.mjs'
|
|
5
5
|
|
|
6
|
-
const decoder = new TextDecoder()
|
|
7
6
|
const encoder = new TextEncoder()
|
|
8
|
-
const
|
|
7
|
+
const decoder = new TextDecoder()
|
|
9
8
|
|
|
10
|
-
function stringToSAB(strData)
|
|
9
|
+
function stringToSAB(strData)
|
|
10
|
+
{
|
|
11
11
|
const buffer = encoder.encode(strData)
|
|
12
12
|
const sab = new SharedArrayBuffer(buffer.length)
|
|
13
13
|
let uint8sab = new Uint8Array(sab)
|
|
@@ -15,7 +15,8 @@ function stringToSAB(strData) {
|
|
|
15
15
|
return uint8sab
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
function SABtoString(arr)
|
|
18
|
+
function SABtoString(arr)
|
|
19
|
+
{
|
|
19
20
|
let string = '';
|
|
20
21
|
for (let c of arr) {
|
|
21
22
|
string+= String.fromCharCode(c)
|
|
@@ -23,612 +24,459 @@ function SABtoString(arr) {
|
|
|
23
24
|
return string
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
class Slice
|
|
27
|
-
|
|
27
|
+
class Slice
|
|
28
|
+
{
|
|
29
|
+
constructor(start, end)
|
|
30
|
+
{
|
|
28
31
|
this.start = start;
|
|
29
32
|
this.end = end;
|
|
30
33
|
}
|
|
31
34
|
}
|
|
32
35
|
|
|
33
|
-
const isSlice = function(r)
|
|
36
|
+
const isSlice = function(r)
|
|
37
|
+
{
|
|
34
38
|
return r instanceof Slice
|
|
35
39
|
}
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
const resetObject = function(ob)
|
|
38
42
|
{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
meta.unresolved = new Map()
|
|
44
|
-
}
|
|
45
|
-
if (!meta.baseURL) {
|
|
46
|
-
meta.baseURL = 'http://localhost/'
|
|
47
|
-
}
|
|
48
|
-
let at, ch, value, result;
|
|
49
|
-
let escapee = {
|
|
50
|
-
'"': '"',
|
|
51
|
-
"\\":"\\",
|
|
52
|
-
'/': '/',
|
|
53
|
-
b: "\b",
|
|
54
|
-
f: "\f",
|
|
55
|
-
n: "\n",
|
|
56
|
-
r: "\r",
|
|
57
|
-
t: "\t"
|
|
58
|
-
}
|
|
59
|
-
let offsetArray = []
|
|
60
|
-
if (!meta.resultArray) {
|
|
61
|
-
meta.resultArray = []
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
at = 0
|
|
65
|
-
ch = " "
|
|
66
|
-
|
|
67
|
-
let error = function(m)
|
|
68
|
-
{
|
|
69
|
-
let context
|
|
70
|
-
try {
|
|
71
|
-
context = decoder.decode(input.slice(at-100,at+100));
|
|
72
|
-
} catch(err) {}
|
|
73
|
-
throw {
|
|
74
|
-
name: 'SyntaxError',
|
|
75
|
-
message: m,
|
|
76
|
-
at: at,
|
|
77
|
-
input: context
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (typeof input == 'string' || input instanceof String) {
|
|
82
|
-
input = stringToSAB(input)
|
|
83
|
-
}
|
|
84
|
-
if (!(input instanceof Uint8Array)) {
|
|
85
|
-
error('parse only accepts Uint8Array or String as input')
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
let next = function(c)
|
|
89
|
-
{
|
|
90
|
-
if (c && c!==ch) {
|
|
91
|
-
let source = SABtoString(input)
|
|
92
|
-
error("Expected '"+c+"' instead of '"+ch+"': "+at+':'+source)
|
|
93
|
-
}
|
|
94
|
-
ch = String.fromCharCode(input.at(at))
|
|
95
|
-
at+=1
|
|
96
|
-
return ch
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
let number = function(tagName)
|
|
100
|
-
{
|
|
101
|
-
let numString = ''
|
|
102
|
-
if (ch==='-') {
|
|
103
|
-
numString = '-'
|
|
104
|
-
next('-')
|
|
105
|
-
}
|
|
106
|
-
while(ch>='0' && ch<='9') {
|
|
107
|
-
numString += ch
|
|
108
|
-
next()
|
|
109
|
-
}
|
|
110
|
-
if (ch==='.') {
|
|
111
|
-
numString+='.'
|
|
112
|
-
while(next() && ch >= '0' && ch <= '9') {
|
|
113
|
-
numString += ch
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
if (ch === 'e' || ch === 'E') {
|
|
117
|
-
numString += ch
|
|
118
|
-
next()
|
|
119
|
-
if (ch === '-' || ch === '+') {
|
|
120
|
-
numString += ch
|
|
121
|
-
next()
|
|
122
|
-
}
|
|
123
|
-
while (ch >= '0' && ch <= '9') {
|
|
124
|
-
numString += ch
|
|
125
|
-
next()
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
let result = new Number(numString).valueOf()
|
|
129
|
-
if (tagName) {
|
|
130
|
-
switch(tagName) {
|
|
131
|
-
case "int":
|
|
132
|
-
isInt(numString)
|
|
133
|
-
break
|
|
134
|
-
case "uint":
|
|
135
|
-
isInt(numString, [0,Infinity])
|
|
136
|
-
break
|
|
137
|
-
case "int8":
|
|
138
|
-
isInt(numString, [-128,127])
|
|
139
|
-
break
|
|
140
|
-
case "uint8":
|
|
141
|
-
isInt(numString, [0,255])
|
|
142
|
-
break
|
|
143
|
-
case "int16":
|
|
144
|
-
isInt(numString, [-32768,32767])
|
|
145
|
-
break
|
|
146
|
-
case "uint16":
|
|
147
|
-
isInt(numString, [0,65535])
|
|
148
|
-
break
|
|
149
|
-
case "int32":
|
|
150
|
-
isInt(numString, [-2147483648, 2147483647])
|
|
151
|
-
break
|
|
152
|
-
case "uint32":
|
|
153
|
-
isInt(numString, [0,4294967295])
|
|
154
|
-
break
|
|
155
|
-
case "timestamp":
|
|
156
|
-
case "int64":
|
|
157
|
-
isInt(numString, [-9223372036854775808,9223372036854775807])
|
|
158
|
-
break
|
|
159
|
-
case "uint64":
|
|
160
|
-
isInt(numString, [0,18446744073709551615])
|
|
161
|
-
break
|
|
162
|
-
case "float":
|
|
163
|
-
isFloat(numString)
|
|
164
|
-
break
|
|
165
|
-
case "float32":
|
|
166
|
-
isFloat(numString, [-3.4e+38,3.4e+38])
|
|
167
|
-
break
|
|
168
|
-
case "float64":
|
|
169
|
-
isFloat(numString, [-1.7e+308,+1.7e+308])
|
|
170
|
-
break
|
|
171
|
-
case "number":
|
|
172
|
-
//FIXME: what to check? should already be covered by JSON parsing rules?
|
|
173
|
-
break
|
|
174
|
-
default:
|
|
175
|
-
isTypeError(tagName, numString)
|
|
176
|
-
break
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
return result
|
|
43
|
+
delete ob[Symbol['JSONTag:Type']]
|
|
44
|
+
delete ob[Symbol['JSONTag:Attributes']]
|
|
45
|
+
for (let prop of Object.getOwnPropertyNames(ob)) {
|
|
46
|
+
delete ob[prop]
|
|
180
47
|
}
|
|
48
|
+
}
|
|
181
49
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
error('Syntax error, expected '+type+', got: '+value)
|
|
185
|
-
}
|
|
50
|
+
export default class Parser extends JSONTag.Parser
|
|
51
|
+
{
|
|
186
52
|
|
|
187
|
-
|
|
188
|
-
color: /^(rgb|hsl)a?\((\d+%?(deg|rad|grad|turn)?[,\s]+){2,3}[\s\/]*[\d\.]+%?\)$/i,
|
|
189
|
-
email: /^[A-Za-z0-9_!#$%&'*+\/=?`{|}~^.-]+@[A-Za-z0-9.-]+$/,
|
|
190
|
-
uuid: /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/,
|
|
191
|
-
decimal: /^\d*\.?\d*$/,
|
|
192
|
-
money: /^[A-Z]+\$\d*\.?\d*$/,
|
|
193
|
-
duration: /^(-?)P(?=\d|T\d)(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)([DW]))?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/,
|
|
194
|
-
phone: /^[+]?(?:\(\d+(?:\.\d+)?\)|\d+(?:\.\d+)?)(?:[ -]?(?:\(\d+(?:\.\d+)?\)|\d+(?:\.\d+)?))*(?:[ ]?(?:x|ext)\.?[ ]?\d{1,5})?$/,
|
|
195
|
-
time: /^(\d{2}):(\d{2})(?::(\d{2}(?:\.\d+)?))?$/,
|
|
196
|
-
date: /^-?[1-9][0-9]{3,}-([0][1-9]|[1][0-2])-([1-2][0-9]|[0][1-9]|[3][0-1])$/,
|
|
197
|
-
datetime: /^(\d{4,})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})(?::(\d{2}(?:\.\d+)?))?$/,
|
|
198
|
-
range: /^\[-?(\d+\.)?\d+\,-?(\d+\.)?\d+\]$/
|
|
199
|
-
}
|
|
53
|
+
handlers
|
|
200
54
|
|
|
201
|
-
|
|
55
|
+
constructor(baseURL, immutable=true)
|
|
202
56
|
{
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
57
|
+
super(baseURL)
|
|
58
|
+
this.cachedProxies = new Map() //FIXME: set back to WeakMap
|
|
59
|
+
this.immutable = immutable
|
|
60
|
+
this.handlers = {
|
|
61
|
+
newArrayHandler: {
|
|
62
|
+
get: (target, prop) => {
|
|
63
|
+
switch(prop) {
|
|
64
|
+
case source:
|
|
65
|
+
return target
|
|
66
|
+
break
|
|
67
|
+
case isProxy:
|
|
68
|
+
return true
|
|
69
|
+
break
|
|
70
|
+
case proxyType:
|
|
71
|
+
return 'new'
|
|
72
|
+
break
|
|
73
|
+
}
|
|
74
|
+
if (target[prop] instanceof Function) {
|
|
75
|
+
return (...args) => {
|
|
76
|
+
args = args.map(arg => {
|
|
77
|
+
const type = JSONTag.getType(arg)
|
|
78
|
+
if (type==='object' || type==='link') {
|
|
79
|
+
arg = this.getNewValueProxy(arg)
|
|
80
|
+
}
|
|
81
|
+
return arg
|
|
82
|
+
})
|
|
83
|
+
return target[prop].apply(target, args)
|
|
84
|
+
}
|
|
85
|
+
} else if (prop===isChanged) {
|
|
86
|
+
return true
|
|
87
|
+
} else {
|
|
88
|
+
if (this.meta.access && !this.meta.access(target, prop)) {
|
|
89
|
+
return undefined
|
|
90
|
+
}
|
|
91
|
+
if (Array.isArray(target[prop])) {
|
|
92
|
+
return this.getArrayProxy(target[prop], target, this.handlers.newArrayHandler)
|
|
93
|
+
}
|
|
94
|
+
return target[prop]
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
set: (target, prop, value) => {
|
|
98
|
+
if (prop === isChanged || prop === parent) {
|
|
99
|
+
// prevent infinite loops, parent is only needed to mark it isChanged
|
|
100
|
+
// but this is a new array proxy, parent is already dirty
|
|
101
|
+
return true
|
|
102
|
+
}
|
|
103
|
+
if (this.meta.access && !this.meta.access(target, prop)) {
|
|
104
|
+
return undefined
|
|
105
|
+
}
|
|
106
|
+
const type = JSONTag.getType(arg)
|
|
107
|
+
if ((type==='object' || type==='link')
|
|
108
|
+
&& typeof prop !== 'symbol'
|
|
109
|
+
) {
|
|
110
|
+
value = this.getNewValueProxy(value)
|
|
111
|
+
}
|
|
112
|
+
target[prop] = value
|
|
113
|
+
return true
|
|
217
114
|
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
115
|
+
},
|
|
116
|
+
newValueHandler: {
|
|
117
|
+
get: (target, prop) => {
|
|
118
|
+
switch(prop) {
|
|
119
|
+
case resultSet:
|
|
120
|
+
return this.meta.resultArray
|
|
121
|
+
break;
|
|
122
|
+
case source:
|
|
123
|
+
return target
|
|
124
|
+
break
|
|
125
|
+
case isProxy:
|
|
126
|
+
return true
|
|
127
|
+
break
|
|
128
|
+
case proxyType:
|
|
129
|
+
return 'new'
|
|
130
|
+
break
|
|
131
|
+
case getBuffer:
|
|
132
|
+
return (i) => {
|
|
133
|
+
let index = target[getIndex]
|
|
134
|
+
if (i != index) {
|
|
135
|
+
return encoder.encode('~'+index)
|
|
136
|
+
}
|
|
137
|
+
return serialize(target, {meta:this.meta, skipLength:true})
|
|
138
|
+
}
|
|
139
|
+
break
|
|
140
|
+
case getIndex:
|
|
141
|
+
return target[getIndex]
|
|
142
|
+
break
|
|
143
|
+
case isChanged:
|
|
144
|
+
return true
|
|
145
|
+
break
|
|
146
|
+
default:
|
|
147
|
+
if (this.meta.access && !this.meta.access(target, prop, 'get')) {
|
|
148
|
+
return undefined
|
|
149
|
+
}
|
|
150
|
+
if (Array.isArray(target[prop])) {
|
|
151
|
+
return this.getArrayProxy(target[prop], target, this.handlers.newArrayHandler)
|
|
152
|
+
}
|
|
153
|
+
return target[prop]
|
|
154
|
+
break
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
set: (target, prop, value) => {
|
|
158
|
+
if (this.meta.access && !this.meta.access(target, prop, 'set')) {
|
|
159
|
+
return undefined
|
|
160
|
+
}
|
|
161
|
+
const type = JSONTag.getType(arg)
|
|
162
|
+
if ((type==='object' || type==='link')
|
|
163
|
+
&& typeof prop !== 'symbol'
|
|
164
|
+
) {
|
|
165
|
+
value = this.getNewValueProxy(value)
|
|
166
|
+
}
|
|
167
|
+
target[prop] = value
|
|
168
|
+
return true
|
|
233
169
|
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
170
|
+
},
|
|
171
|
+
arrayHandler: {
|
|
172
|
+
get: (target, prop, receiver) => {
|
|
173
|
+
switch(prop) {
|
|
174
|
+
case source:
|
|
175
|
+
return target
|
|
176
|
+
break
|
|
177
|
+
case isProxy:
|
|
178
|
+
return true
|
|
179
|
+
break
|
|
180
|
+
case proxyType:
|
|
181
|
+
return 'array'
|
|
182
|
+
break
|
|
183
|
+
}
|
|
184
|
+
const value = target?.[prop]
|
|
185
|
+
if (value instanceof Function) {
|
|
186
|
+
if (['copyWithin','fill','pop','push','reverse','shift','sort','splice','unshift'].indexOf(prop)!==-1) {
|
|
187
|
+
if (this.immutable) {
|
|
188
|
+
throw new Error('dataspace is immutable')
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return (...args) => {
|
|
192
|
+
args = args.map(arg => {
|
|
193
|
+
if (!arg[isProxy]) {
|
|
194
|
+
let type = JSONTag.getType(arg)
|
|
195
|
+
if (type==='object' || type==='link') { //FIXME: check if other types need handling
|
|
196
|
+
arg = this.getNewValueProxy(arg)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return arg
|
|
200
|
+
})
|
|
201
|
+
return value.apply(receiver, args)
|
|
202
|
+
}
|
|
203
|
+
} else if (prop===isChanged) {
|
|
204
|
+
return target[isChanged] || target[parent][isChanged]
|
|
205
|
+
} else if (prop===source) {
|
|
206
|
+
return target
|
|
207
|
+
} else {
|
|
208
|
+
if (this.meta.access && !this.meta.access(target, prop, 'get')) {
|
|
209
|
+
return undefined
|
|
210
|
+
}
|
|
211
|
+
if (Array.isArray(value)) {
|
|
212
|
+
return this.getArrayProxy(value, target)
|
|
213
|
+
}
|
|
214
|
+
return value
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
set: (target, prop, value) => {
|
|
218
|
+
if (prop == parent) {
|
|
219
|
+
target[parent] = value
|
|
220
|
+
return true
|
|
221
|
+
}
|
|
222
|
+
if (this.immutable) {
|
|
223
|
+
throw new Error('dataspace is immutable')
|
|
224
|
+
}
|
|
225
|
+
if (this.meta.access && !this.meta.access(target, prop, 'set')) {
|
|
226
|
+
return undefined
|
|
227
|
+
}
|
|
228
|
+
const type = JSONTag.getType(value)
|
|
229
|
+
if ((type==='object' || type==='link') //FIXME: check if other types need handling
|
|
230
|
+
&& typeof prop !== 'symbol'
|
|
231
|
+
) {
|
|
232
|
+
value = this.getNewValueProxy(value)
|
|
233
|
+
}
|
|
234
|
+
if (target[prop] === value) {
|
|
235
|
+
return true
|
|
236
|
+
}
|
|
237
|
+
target[prop] = value
|
|
238
|
+
target[isChanged] = true
|
|
239
|
+
target[parent][isChanged] = true
|
|
240
|
+
return true
|
|
241
|
+
},
|
|
242
|
+
deleteProperty: (target, prop) => {
|
|
243
|
+
if (this.immutable) {
|
|
244
|
+
throw new Error('dataspace is immutable')
|
|
245
|
+
}
|
|
246
|
+
if (this.meta.access && !this.meta.access(target, prop, 'deleteProperty')) {
|
|
247
|
+
return undefined
|
|
248
|
+
}
|
|
249
|
+
//FIXME: if target[prop] was the last reference to an object
|
|
250
|
+
//that object should be deleted so that its line will become empty
|
|
251
|
+
//when stringifying resultArray again
|
|
252
|
+
if (typeof target[prop] === 'undefined') {
|
|
253
|
+
return true
|
|
254
|
+
}
|
|
255
|
+
delete target[prop]
|
|
256
|
+
target[isChanged] = true
|
|
257
|
+
target[parent][isChanged] = true
|
|
258
|
+
return true
|
|
238
259
|
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
let isDuration = function(duration)
|
|
307
|
-
{
|
|
308
|
-
let result = regexes.duration.test(duration)
|
|
309
|
-
if (!result) {
|
|
310
|
-
isTypeError('duration',duration)
|
|
311
|
-
}
|
|
312
|
-
return true
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
let isPhone = function(phone)
|
|
316
|
-
{
|
|
317
|
-
let result = regexes.phone.test(phone)
|
|
318
|
-
if (!result) {
|
|
319
|
-
isTypeError('phone',phone)
|
|
320
|
-
}
|
|
321
|
-
return true
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
let isRange = function(range)
|
|
325
|
-
{
|
|
326
|
-
let result = regexes.range.test(range)
|
|
327
|
-
if (!result) {
|
|
328
|
-
isTypeError('range',range)
|
|
329
|
-
}
|
|
330
|
-
return true
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
let isTime = function(time)
|
|
334
|
-
{
|
|
335
|
-
let result = regexes.time.test(time)
|
|
336
|
-
if (!result) {
|
|
337
|
-
isTypeError('time',time)
|
|
338
|
-
}
|
|
339
|
-
return true
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
let isDate = function(date)
|
|
343
|
-
{
|
|
344
|
-
let result = regexes.date.test(date)
|
|
345
|
-
if (!result) {
|
|
346
|
-
isTypeError('date',date)
|
|
347
|
-
}
|
|
348
|
-
return true
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
let isDatetime = function(datetime)
|
|
352
|
-
{
|
|
353
|
-
let result = regexes.datetime.test(datetime)
|
|
354
|
-
if (!result) {
|
|
355
|
-
isTypeError('datetime',datetime)
|
|
356
|
-
}
|
|
357
|
-
return true
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
let checkStringType = function(tagName, value)
|
|
361
|
-
{
|
|
362
|
-
if (!tagName) {
|
|
363
|
-
return
|
|
364
|
-
}
|
|
365
|
-
switch(tagName){
|
|
366
|
-
case "object":
|
|
367
|
-
case "array":
|
|
368
|
-
case "int8":
|
|
369
|
-
case "uint8":
|
|
370
|
-
case "int16":
|
|
371
|
-
case "uint16":
|
|
372
|
-
case "int32":
|
|
373
|
-
case "uint32":
|
|
374
|
-
case "int64":
|
|
375
|
-
case "uint64":
|
|
376
|
-
case "int":
|
|
377
|
-
case "uint":
|
|
378
|
-
case "float32":
|
|
379
|
-
case "float64":
|
|
380
|
-
case "float":
|
|
381
|
-
case "timestamp":
|
|
382
|
-
isTypeError(tagName, value)
|
|
383
|
-
break
|
|
384
|
-
case "uuid":
|
|
385
|
-
return isUuid(value)
|
|
386
|
-
case "decimal":
|
|
387
|
-
return isDecimal(value)
|
|
388
|
-
case "money":
|
|
389
|
-
return isMoney(value)
|
|
390
|
-
case "url":
|
|
391
|
-
return isUrl(value)
|
|
392
|
-
case "link":
|
|
393
|
-
case "string":
|
|
394
|
-
case "text":
|
|
395
|
-
case "blob":
|
|
396
|
-
case "hash":
|
|
397
|
-
//anything goes
|
|
398
|
-
return true
|
|
399
|
-
case "color":
|
|
400
|
-
return isColor(value)
|
|
401
|
-
case "email":
|
|
402
|
-
return isEmail(value)
|
|
403
|
-
case "duration":
|
|
404
|
-
return isDuration(value)
|
|
405
|
-
case "phone":
|
|
406
|
-
return isPhone(value)
|
|
407
|
-
case "range":
|
|
408
|
-
return isRange(value)
|
|
409
|
-
case "time":
|
|
410
|
-
return isTime(value)
|
|
411
|
-
case "date":
|
|
412
|
-
return isDate(value)
|
|
413
|
-
case "datetime":
|
|
414
|
-
return isDatetime(value)
|
|
415
|
-
}
|
|
416
|
-
error('Syntax error: unknown tagName '+tagName)
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
let string = function(tagName)
|
|
420
|
-
{
|
|
421
|
-
let value = [], hex, i, uffff;
|
|
422
|
-
if (ch !== '"') {
|
|
423
|
-
error("Syntax Error")
|
|
424
|
-
}
|
|
425
|
-
next('"')
|
|
426
|
-
while(ch) {
|
|
427
|
-
if (ch==='"') {
|
|
428
|
-
next()
|
|
429
|
-
let bytes = new Uint8Array(value)
|
|
430
|
-
value = decoder.decode(bytes)
|
|
431
|
-
checkStringType(tagName, value)
|
|
432
|
-
return value
|
|
433
|
-
}
|
|
434
|
-
if (ch==='\\') {
|
|
435
|
-
next()
|
|
436
|
-
if (ch==='u') {
|
|
437
|
-
for (i=0; i<4; i++) {
|
|
438
|
-
hex = parseInt(next(), 16)
|
|
439
|
-
if (!isFinite(hex)) {
|
|
260
|
+
},
|
|
261
|
+
defaultHandler: {
|
|
262
|
+
get: (target, prop, receiver) => {
|
|
263
|
+
switch(prop) {
|
|
264
|
+
case resultSet:
|
|
265
|
+
return this.meta.resultArray
|
|
266
|
+
break;
|
|
267
|
+
case isProxy:
|
|
268
|
+
return true
|
|
269
|
+
break
|
|
270
|
+
case proxyType:
|
|
271
|
+
return 'parse'
|
|
272
|
+
break
|
|
273
|
+
case getBuffer:
|
|
274
|
+
return (i) => {
|
|
275
|
+
let index = target[getIndex]
|
|
276
|
+
if (i != index) {
|
|
277
|
+
return encoder.encode('~'+index)
|
|
278
|
+
}
|
|
279
|
+
if (target[isChanged]) {
|
|
280
|
+
return serialize(target, {skipLength: true})
|
|
281
|
+
}
|
|
282
|
+
return target[position].input.slice(target[position].start,target[position].end)
|
|
283
|
+
}
|
|
284
|
+
break
|
|
285
|
+
case getIndex:
|
|
286
|
+
return target[getIndex]
|
|
287
|
+
break
|
|
288
|
+
case isChanged:
|
|
289
|
+
return target[isChanged]
|
|
290
|
+
break
|
|
291
|
+
}
|
|
292
|
+
this.firstParse(target, receiver)
|
|
293
|
+
switch(prop) {
|
|
294
|
+
case source:
|
|
295
|
+
if (this.meta.access && !this.meta.access(target, prop, 'get')) {
|
|
296
|
+
return undefined
|
|
297
|
+
}
|
|
298
|
+
return target
|
|
299
|
+
break
|
|
300
|
+
default:
|
|
301
|
+
if (this.meta.access && !this.meta.access(target, prop, 'get')) {
|
|
302
|
+
return undefined
|
|
303
|
+
}
|
|
304
|
+
if (Array.isArray(target[prop])) {
|
|
305
|
+
return this.getArrayProxy(target[prop], target)
|
|
306
|
+
}
|
|
307
|
+
return target[prop]
|
|
308
|
+
break
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
set: (target, prop, value, receiver) => {
|
|
312
|
+
if (this.immutable && prop!==resultSet && prop!==source && prop!==isChanged) {
|
|
313
|
+
throw new Error('dataspace is immutable')
|
|
314
|
+
}
|
|
315
|
+
switch(prop) {
|
|
316
|
+
case isChanged:
|
|
317
|
+
break
|
|
318
|
+
case source:
|
|
319
|
+
resetObject(target)
|
|
320
|
+
target[position] = value[position]
|
|
321
|
+
target[isParsed] = false
|
|
322
|
+
target[isChanged] = false
|
|
323
|
+
return true
|
|
324
|
+
break
|
|
325
|
+
case resultSet:
|
|
440
326
|
break
|
|
441
|
-
}
|
|
442
|
-
uffff = uffff * 16 + hex
|
|
443
327
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
328
|
+
this.firstParse(target, receiver)
|
|
329
|
+
if (this.meta.access && !this.meta.access(target, prop, 'set')) {
|
|
330
|
+
return undefined
|
|
331
|
+
}
|
|
332
|
+
const type = JSONTag.getType(value)
|
|
333
|
+
if ((type==='object' || type==='link') //FIXME: check if other types need handling
|
|
334
|
+
&& typeof prop !== 'symbol'
|
|
335
|
+
) {
|
|
336
|
+
value = this.getNewValueProxy(value)
|
|
337
|
+
}
|
|
338
|
+
if (target[prop] === value) {
|
|
339
|
+
return true
|
|
340
|
+
}
|
|
341
|
+
target[prop] = value
|
|
342
|
+
target[isChanged] = true
|
|
343
|
+
return true
|
|
344
|
+
},
|
|
345
|
+
deleteProperty: (target, prop) => {
|
|
346
|
+
if (this.immutable) {
|
|
347
|
+
throw new Error('dataspace is immutable')
|
|
348
|
+
}
|
|
349
|
+
if (this.meta.access && !this.meta.access(target, prop, 'deleteProperty')) {
|
|
350
|
+
return undefined
|
|
351
|
+
}
|
|
352
|
+
this.firstParse(target)
|
|
353
|
+
if (typeof target[prop] === 'undefined') {
|
|
354
|
+
return true
|
|
355
|
+
}
|
|
356
|
+
delete target[prop]
|
|
357
|
+
target[isChanged] = true
|
|
358
|
+
return true
|
|
359
|
+
},
|
|
360
|
+
ownKeys: (target) => {
|
|
361
|
+
this.firstParse(target)
|
|
362
|
+
return Reflect.ownKeys(target)
|
|
363
|
+
},
|
|
364
|
+
getOwnPropertyDescriptor: (target, prop) => {
|
|
365
|
+
this.firstParse(target)
|
|
366
|
+
return Reflect.getOwnPropertyDescriptor(target, prop)
|
|
367
|
+
},
|
|
368
|
+
defineProperty: (target, prop, descriptor) => {
|
|
369
|
+
if (this.immutable) {
|
|
370
|
+
throw new Error('dataspace is immutable')
|
|
371
|
+
}
|
|
372
|
+
if (this.meta.access && !this.meta.access(target, prop, 'defineProperty')) {
|
|
373
|
+
return undefined
|
|
374
|
+
}
|
|
375
|
+
this.firstParse(target)
|
|
376
|
+
target[isChanged] = true
|
|
377
|
+
return Object.defineProperty(target, prop, descriptor)
|
|
378
|
+
},
|
|
379
|
+
has: (target, prop) => {
|
|
380
|
+
if (this.meta.access && !this.meta.access(target, prop, 'has')) {
|
|
381
|
+
return false
|
|
382
|
+
}
|
|
383
|
+
this.firstParse()
|
|
384
|
+
return prop in target
|
|
385
|
+
},
|
|
386
|
+
setPrototypeOf: () => {
|
|
387
|
+
throw new Error('changing prototypes is not supported')
|
|
453
388
|
}
|
|
454
|
-
} else {
|
|
455
|
-
value.push(ch.charCodeAt(0))
|
|
456
|
-
next()
|
|
457
389
|
}
|
|
458
390
|
}
|
|
459
|
-
error("Syntax error: incomplete string")
|
|
460
391
|
}
|
|
461
392
|
|
|
462
|
-
|
|
393
|
+
next(c)
|
|
463
394
|
{
|
|
464
|
-
|
|
465
|
-
|
|
395
|
+
if (c && c!==this.ch) {
|
|
396
|
+
let source = SABtoString(this.input)
|
|
397
|
+
this.error("Expected '"+c+"' instead of '"+this.ch+"':"+this.at+':'+source)
|
|
466
398
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
next('<')
|
|
471
|
-
key = word()
|
|
472
|
-
if (!key) {
|
|
473
|
-
error('Syntax Error: expected tag name')
|
|
474
|
-
}
|
|
475
|
-
tagOb.tagName = key
|
|
476
|
-
whitespace()
|
|
477
|
-
while(ch) {
|
|
478
|
-
if (ch==='>') {
|
|
479
|
-
next('>')
|
|
480
|
-
return tagOb
|
|
481
|
-
}
|
|
482
|
-
key = word()
|
|
483
|
-
if (!key) {
|
|
484
|
-
error('Syntax Error: expected attribute name')
|
|
485
|
-
}
|
|
486
|
-
whitespace()
|
|
487
|
-
next('=')
|
|
488
|
-
whitespace()
|
|
489
|
-
val = string()
|
|
490
|
-
tagOb.attributes[key] = val
|
|
491
|
-
whitespace()
|
|
492
|
-
}
|
|
493
|
-
error('Syntax Error: unexpected end of input')
|
|
399
|
+
this.ch = String.fromCharCode(this.input.at(this.at))
|
|
400
|
+
this.at+=1
|
|
401
|
+
return this.ch
|
|
494
402
|
}
|
|
495
403
|
|
|
496
|
-
|
|
404
|
+
error(m)
|
|
497
405
|
{
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
case "\r":
|
|
503
|
-
case "\n":
|
|
504
|
-
next()
|
|
505
|
-
break
|
|
506
|
-
default:
|
|
507
|
-
return
|
|
508
|
-
break
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
let word = function()
|
|
514
|
-
{
|
|
515
|
-
//[a-z][a-z0-9_]*
|
|
516
|
-
let val='';
|
|
517
|
-
if ((ch>='a' && ch<='z') || (ch>='A' && ch<='Z')) {
|
|
518
|
-
val += ch
|
|
519
|
-
next()
|
|
520
|
-
} else {
|
|
521
|
-
error('Syntax Error: expected word')
|
|
522
|
-
}
|
|
523
|
-
while((ch>='a' && ch<='z') || (ch>='A' && ch<='Z') || (ch>='0' && ch<='9') || ch=='_') {
|
|
524
|
-
val += ch
|
|
525
|
-
next()
|
|
526
|
-
}
|
|
527
|
-
return val
|
|
528
|
-
}
|
|
406
|
+
let context
|
|
407
|
+
try {
|
|
408
|
+
context = decoder.decode(this.input.slice(this.at,this.at+100));
|
|
409
|
+
} catch(e) {
|
|
529
410
|
|
|
530
|
-
let boolOrNull = function(tagName)
|
|
531
|
-
{
|
|
532
|
-
let w = word()
|
|
533
|
-
if (!w || typeof w !== 'string') {
|
|
534
|
-
error('Syntax error: expected boolean or null, got "'+w+'"')
|
|
535
|
-
}
|
|
536
|
-
switch(w.toLowerCase()) {
|
|
537
|
-
case 'true':
|
|
538
|
-
if (tagName && tagName!=='boolean') {
|
|
539
|
-
isTypeError(tagName,w)
|
|
540
|
-
}
|
|
541
|
-
return true
|
|
542
|
-
break
|
|
543
|
-
case 'false':
|
|
544
|
-
if (tagName && tagName!=='boolean') {
|
|
545
|
-
isTypeError(tagName,w)
|
|
546
|
-
}
|
|
547
|
-
return false
|
|
548
|
-
break
|
|
549
|
-
case 'null':
|
|
550
|
-
return null
|
|
551
|
-
break
|
|
552
|
-
default:
|
|
553
|
-
error('Syntax error: expected boolean or null, got "'+w+'"')
|
|
554
|
-
break
|
|
555
411
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
let link = ''+item
|
|
562
|
-
let links = meta.unresolved.get(link)
|
|
563
|
-
if (typeof links === 'undefined') {
|
|
564
|
-
meta.unresolved.set(link,[])
|
|
565
|
-
links = meta.unresolved.get(link)
|
|
566
|
-
}
|
|
567
|
-
let count = links.push({
|
|
568
|
-
src: new WeakRef(object),
|
|
569
|
-
key: key
|
|
570
|
-
})
|
|
412
|
+
throw {
|
|
413
|
+
name: 'SyntaxError',
|
|
414
|
+
message: m,
|
|
415
|
+
at: this.at,
|
|
416
|
+
input: context
|
|
571
417
|
}
|
|
572
418
|
}
|
|
573
419
|
|
|
574
|
-
|
|
420
|
+
array()
|
|
575
421
|
{
|
|
576
422
|
let item, array = []
|
|
577
|
-
if (ch !== '[') {
|
|
578
|
-
error("Syntax error")
|
|
423
|
+
if (this.ch !== '[') {
|
|
424
|
+
this.error("Syntax error")
|
|
579
425
|
}
|
|
580
|
-
next('[')
|
|
581
|
-
whitespace()
|
|
582
|
-
if (ch===']') {
|
|
583
|
-
next(']')
|
|
426
|
+
this.next('[')
|
|
427
|
+
this.whitespace()
|
|
428
|
+
if (this.ch===']') {
|
|
429
|
+
this.next(']')
|
|
584
430
|
return array
|
|
585
431
|
}
|
|
586
|
-
while(ch) {
|
|
587
|
-
item = value()
|
|
588
|
-
checkUnresolved(item, array, array.length)
|
|
432
|
+
while(this.ch) {
|
|
433
|
+
item = this.value()
|
|
434
|
+
this.checkUnresolved(item, array, array.length)
|
|
589
435
|
if (isSlice(item)) {
|
|
590
|
-
array = array.concat(meta.resultArray.slice(item.start, item.end))
|
|
436
|
+
array = array.concat(this.meta.resultArray.slice(item.start, item.end))
|
|
591
437
|
} else {
|
|
592
438
|
array.push(item)
|
|
593
439
|
}
|
|
594
|
-
whitespace()
|
|
595
|
-
if (ch===']') {
|
|
596
|
-
next(']')
|
|
440
|
+
this.whitespace()
|
|
441
|
+
if (this.ch===']') {
|
|
442
|
+
this.next(']')
|
|
597
443
|
return array
|
|
598
444
|
}
|
|
599
|
-
next(',')
|
|
600
|
-
whitespace()
|
|
445
|
+
this.next(',')
|
|
446
|
+
this.whitespace()
|
|
601
447
|
}
|
|
602
|
-
error("Input stopped early")
|
|
448
|
+
this.error("Input stopped early")
|
|
603
449
|
}
|
|
604
450
|
|
|
605
|
-
|
|
451
|
+
|
|
452
|
+
object(object={})
|
|
606
453
|
{
|
|
607
454
|
let key, val
|
|
608
|
-
if (ch !== '{') {
|
|
609
|
-
error("Syntax Error")
|
|
610
|
-
}
|
|
611
|
-
next('{')
|
|
612
|
-
whitespace()
|
|
613
|
-
|
|
614
|
-
|
|
455
|
+
if (this.ch !== '{') {
|
|
456
|
+
this.error("Syntax Error")
|
|
457
|
+
}
|
|
458
|
+
this.next('{')
|
|
459
|
+
this.whitespace()
|
|
460
|
+
resetObject(object)
|
|
461
|
+
if (this.ch==='}') {
|
|
462
|
+
this.next('}')
|
|
615
463
|
return object
|
|
616
464
|
}
|
|
617
465
|
let enumerable = true
|
|
618
|
-
while(ch) {
|
|
619
|
-
if (ch==='#') {
|
|
466
|
+
while(this.ch) {
|
|
467
|
+
if (this.ch==='#') {
|
|
620
468
|
enumerable = false
|
|
621
|
-
next()
|
|
469
|
+
this.next()
|
|
622
470
|
} else {
|
|
623
471
|
enumerable = true
|
|
624
472
|
}
|
|
625
|
-
key = string()
|
|
473
|
+
key = this.string()
|
|
626
474
|
if (key==='__proto__') {
|
|
627
|
-
error("Attempt at prototype pollution")
|
|
475
|
+
this.error("Attempt at prototype pollution")
|
|
628
476
|
}
|
|
629
|
-
whitespace()
|
|
630
|
-
next(':')
|
|
631
|
-
val = value()
|
|
477
|
+
this.whitespace()
|
|
478
|
+
this.next(':')
|
|
479
|
+
val = this.value()
|
|
632
480
|
if (!enumerable) {
|
|
633
481
|
Object.defineProperty(object, key, {
|
|
634
482
|
configurable: true, //important, must be true, otherwise Proxies cannot use it
|
|
@@ -639,479 +487,158 @@ export default function parse(input, meta, immutable=true)
|
|
|
639
487
|
} else {
|
|
640
488
|
object[key] = val
|
|
641
489
|
}
|
|
642
|
-
checkUnresolved(val, object, key)
|
|
643
|
-
whitespace()
|
|
644
|
-
if (ch==='}') {
|
|
645
|
-
next('}')
|
|
490
|
+
this.checkUnresolved(val, object, key)
|
|
491
|
+
this.whitespace()
|
|
492
|
+
if (this.ch==='}') {
|
|
493
|
+
this.next('}')
|
|
646
494
|
return object
|
|
647
495
|
}
|
|
648
|
-
next(',')
|
|
649
|
-
whitespace()
|
|
650
|
-
}
|
|
651
|
-
error("Input stopped early")
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
let length = function()
|
|
655
|
-
{
|
|
656
|
-
whitespace()
|
|
657
|
-
next('(')
|
|
658
|
-
let numString=''
|
|
659
|
-
while(ch>='0' && ch<='9') {
|
|
660
|
-
numString += ch
|
|
661
|
-
next()
|
|
496
|
+
this.next(',')
|
|
497
|
+
this.whitespace()
|
|
662
498
|
}
|
|
663
|
-
|
|
664
|
-
error('Syntax error: not a length')
|
|
665
|
-
}
|
|
666
|
-
next()
|
|
667
|
-
return parseInt(numString)
|
|
499
|
+
this.error("Input stopped early")
|
|
668
500
|
}
|
|
669
501
|
|
|
670
|
-
|
|
502
|
+
string(tagName)
|
|
671
503
|
{
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
numString += ch
|
|
676
|
-
next()
|
|
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
|
-
}
|
|
687
|
-
return parseInt(numString)
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
let parseValue = function(position, ob={}) {
|
|
691
|
-
input = position.input
|
|
692
|
-
at = position.start
|
|
693
|
-
next()
|
|
694
|
-
return value(ob)
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
const makeChildProxies = function(parent) {
|
|
698
|
-
Object.entries(parent).forEach(([key,entry]) => {
|
|
699
|
-
if (Array.isArray(entry)) {
|
|
700
|
-
makeChildProxies(entry)
|
|
701
|
-
} else if (entry && JSONTag.getType(entry)==='object') {
|
|
702
|
-
if (entry[isProxy]) {
|
|
703
|
-
// do nothing
|
|
704
|
-
} else {
|
|
705
|
-
parent[key] = getNewValueProxy(entry)
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
})
|
|
709
|
-
}
|
|
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))
|
|
504
|
+
let value = [], hex, i, uffff;
|
|
505
|
+
if (this.ch !== '"') {
|
|
506
|
+
this.error("Syntax Error")
|
|
717
507
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
if (target[prop] instanceof Function) {
|
|
727
|
-
return (...args) => {
|
|
728
|
-
args = args.map(arg => {
|
|
729
|
-
if (JSONTag.getType(arg)==='object' && !arg[isProxy]) {
|
|
730
|
-
arg = getNewValueProxy(arg)
|
|
731
|
-
}
|
|
732
|
-
return arg
|
|
733
|
-
})
|
|
734
|
-
return target[prop].apply(target, args)
|
|
735
|
-
}
|
|
736
|
-
} else if (prop===isChanged) {
|
|
737
|
-
return true
|
|
738
|
-
} else {
|
|
739
|
-
if (meta.access && !meta.access(target, prop)) {
|
|
740
|
-
return undefined
|
|
741
|
-
}
|
|
742
|
-
if (Array.isArray(target[prop])) {
|
|
743
|
-
return getArrayProxy(target[prop], target, handlers.newArrayHandler)
|
|
744
|
-
}
|
|
745
|
-
return target[prop]
|
|
746
|
-
}
|
|
747
|
-
},
|
|
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
|
-
}
|
|
754
|
-
if (meta.access && !meta.access(target, prop)) {
|
|
755
|
-
return undefined
|
|
756
|
-
}
|
|
757
|
-
if (JSONTag.getType(value)==='object' && !value[isProxy]) {
|
|
758
|
-
value = getNewValueProxy(value)
|
|
759
|
-
}
|
|
760
|
-
target[prop] = value
|
|
761
|
-
return true
|
|
508
|
+
this.next('"')
|
|
509
|
+
while(this.ch) {
|
|
510
|
+
if (this.ch==='"') {
|
|
511
|
+
this.next()
|
|
512
|
+
let bytes = new Uint8Array(value)
|
|
513
|
+
value = decoder.decode(bytes)
|
|
514
|
+
this.checkStringType(tagName, value)
|
|
515
|
+
return value
|
|
762
516
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
case source:
|
|
771
|
-
return target
|
|
772
|
-
break
|
|
773
|
-
case isProxy:
|
|
774
|
-
return true
|
|
775
|
-
break
|
|
776
|
-
case proxyType:
|
|
777
|
-
return 'new'
|
|
778
|
-
break
|
|
779
|
-
case getBuffer:
|
|
780
|
-
return (i) => {
|
|
781
|
-
let index = target[getIndex]
|
|
782
|
-
if (i != index) {
|
|
783
|
-
return encoder.encode('~'+index)
|
|
784
|
-
}
|
|
785
|
-
return serialize(target, {meta, skipLength:true})
|
|
786
|
-
}
|
|
787
|
-
break
|
|
788
|
-
case getIndex:
|
|
789
|
-
return target[getIndex]
|
|
790
|
-
break
|
|
791
|
-
case isChanged:
|
|
792
|
-
return true
|
|
793
|
-
break
|
|
794
|
-
default:
|
|
795
|
-
if (meta.access && !meta.access(target, prop, 'get')) {
|
|
796
|
-
return undefined
|
|
797
|
-
}
|
|
798
|
-
if (Array.isArray(target[prop])) {
|
|
799
|
-
return getArrayProxy(target[prop], target, handlers.newArrayHandler)
|
|
517
|
+
if (this.ch==='\\') {
|
|
518
|
+
this.next()
|
|
519
|
+
if (this.ch==='u') {
|
|
520
|
+
for (i=0; i<4; i++) {
|
|
521
|
+
hex = parseInt(this.next(), 16)
|
|
522
|
+
if (!this.isFinite(hex)) {
|
|
523
|
+
break
|
|
800
524
|
}
|
|
801
|
-
|
|
802
|
-
break
|
|
803
|
-
}
|
|
804
|
-
},
|
|
805
|
-
set(target, prop, value) {
|
|
806
|
-
if (meta.access && !meta.access(target, prop, 'set')) {
|
|
807
|
-
return undefined
|
|
808
|
-
}
|
|
809
|
-
if (JSONTag.getType(value)==='object' && !value[isProxy]) {
|
|
810
|
-
value = getNewValueProxy(value)
|
|
811
|
-
}
|
|
812
|
-
target[prop] = value
|
|
813
|
-
return true
|
|
814
|
-
}
|
|
815
|
-
},
|
|
816
|
-
arrayHandler: {
|
|
817
|
-
get(target, prop, receiver) {
|
|
818
|
-
const value = target?.[prop]
|
|
819
|
-
if (value instanceof Function) {
|
|
820
|
-
// if (['copyWithin','fill','pop','push','reverse','shift','sort','splice','unshift'].indexOf(prop)!==-1) {
|
|
821
|
-
// if (immutable) {
|
|
822
|
-
// throw new Error('dataspace is immutable')
|
|
823
|
-
// }
|
|
824
|
-
// }
|
|
825
|
-
return (...args) => {
|
|
826
|
-
args = args.map(arg => {
|
|
827
|
-
if (JSONTag.getType(arg)==='object' && !arg[isProxy]) {
|
|
828
|
-
arg = getNewValueProxy(arg)
|
|
829
|
-
}
|
|
830
|
-
return arg
|
|
831
|
-
})
|
|
832
|
-
return value.apply(receiver, args)
|
|
525
|
+
uffff = uffff * 16 + hex
|
|
833
526
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
527
|
+
let str = String.fromCharCode(uffff)
|
|
528
|
+
let bytes = encoder.encode(str)
|
|
529
|
+
value.push.apply(value, bytes)
|
|
530
|
+
this.next()
|
|
531
|
+
} else if (typeof this.escapee[this.ch] === 'string') {
|
|
532
|
+
value.push(this.escapee[this.ch].charCodeAt(0))
|
|
533
|
+
this.next()
|
|
838
534
|
} else {
|
|
839
|
-
if (meta.access && !meta.access(target, prop, 'get')) {
|
|
840
|
-
return undefined
|
|
841
|
-
}
|
|
842
|
-
if (Array.isArray(value)) {
|
|
843
|
-
return getArrayProxy(value, target)
|
|
844
|
-
}
|
|
845
|
-
return value
|
|
846
|
-
}
|
|
847
|
-
},
|
|
848
|
-
set(target, prop, value) {
|
|
849
|
-
if (prop == parent) {
|
|
850
|
-
target[parent] = value
|
|
851
|
-
return true
|
|
852
|
-
}
|
|
853
|
-
if (immutable) {
|
|
854
|
-
throw new Error('dataspace is immutable')
|
|
855
|
-
}
|
|
856
|
-
if (meta.access && !meta.access(target, prop, 'set')) {
|
|
857
|
-
return undefined
|
|
858
|
-
}
|
|
859
|
-
if (JSONTag.getType(value)==='object' && !value[isProxy]) {
|
|
860
|
-
value = getNewValueProxy(value)
|
|
861
|
-
}
|
|
862
|
-
if (target[prop] === value) {
|
|
863
|
-
return true
|
|
864
|
-
}
|
|
865
|
-
target[prop] = value
|
|
866
|
-
target[isChanged] = true
|
|
867
|
-
target[parent][isChanged] = true
|
|
868
|
-
return true
|
|
869
|
-
},
|
|
870
|
-
deleteProperty(target, prop) {
|
|
871
|
-
if (immutable) {
|
|
872
|
-
throw new Error('dataspace is immutable')
|
|
873
|
-
}
|
|
874
|
-
if (meta.access && !meta.access(target, prop, 'deleteProperty')) {
|
|
875
|
-
return undefined
|
|
876
|
-
}
|
|
877
|
-
//FIXME: if target[prop] was the last reference to an object
|
|
878
|
-
//that object should be deleted so that its line will become empty
|
|
879
|
-
//when stringifying resultArray again
|
|
880
|
-
if (typeof target[prop] === 'undefined') {
|
|
881
|
-
return true
|
|
882
|
-
}
|
|
883
|
-
delete target[prop]
|
|
884
|
-
target[isChanged] = true
|
|
885
|
-
target[parent][isChanged] = true
|
|
886
|
-
return true
|
|
887
|
-
}
|
|
888
|
-
},
|
|
889
|
-
handler: {
|
|
890
|
-
get(target, prop, receiver) {
|
|
891
|
-
switch(prop) {
|
|
892
|
-
case resultSet:
|
|
893
|
-
return meta.resultArray
|
|
894
|
-
break;
|
|
895
|
-
case isProxy:
|
|
896
|
-
return true
|
|
897
|
-
break
|
|
898
|
-
case proxyType:
|
|
899
|
-
return 'parse'
|
|
900
|
-
break
|
|
901
|
-
case getBuffer:
|
|
902
|
-
return (i) => {
|
|
903
|
-
let index = target[getIndex]
|
|
904
|
-
if (i != index) {
|
|
905
|
-
return encoder.encode('~'+index)
|
|
906
|
-
}
|
|
907
|
-
if (target[isChanged]) {
|
|
908
|
-
return serialize(target, {skipLength: true})
|
|
909
|
-
}
|
|
910
|
-
return target[position].input.slice(target[position].start,target[position].end)
|
|
911
|
-
}
|
|
912
|
-
break
|
|
913
|
-
case getIndex:
|
|
914
|
-
return target[getIndex]
|
|
915
|
-
break
|
|
916
|
-
case isChanged:
|
|
917
|
-
return target[isChanged]
|
|
918
535
|
break
|
|
919
536
|
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
if (meta.access && !meta.access(target, prop, 'get')) {
|
|
924
|
-
return undefined
|
|
925
|
-
}
|
|
926
|
-
return target
|
|
927
|
-
break
|
|
928
|
-
default:
|
|
929
|
-
if (meta.access && !meta.access(target, prop, 'get')) {
|
|
930
|
-
return undefined
|
|
931
|
-
}
|
|
932
|
-
if (Array.isArray(target[prop])) {
|
|
933
|
-
return getArrayProxy(target[prop], target)
|
|
934
|
-
}
|
|
935
|
-
return target[prop]
|
|
936
|
-
break
|
|
937
|
-
}
|
|
938
|
-
},
|
|
939
|
-
set(target, prop, value, receiver) {
|
|
940
|
-
if (immutable && prop!==resultSet && prop!==source && prop!==isChanged) {
|
|
941
|
-
throw new Error('dataspace is immutable')
|
|
942
|
-
}
|
|
943
|
-
switch(prop) {
|
|
944
|
-
case isChanged:
|
|
945
|
-
break
|
|
946
|
-
case source:
|
|
947
|
-
resetObject(target)
|
|
948
|
-
target[position] = value[position]
|
|
949
|
-
target[isParsed] = false
|
|
950
|
-
target[isChanged] = false
|
|
951
|
-
return true
|
|
952
|
-
break
|
|
953
|
-
case resultSet:
|
|
954
|
-
break
|
|
955
|
-
}
|
|
956
|
-
firstParse(target, receiver)
|
|
957
|
-
if (meta.access && !meta.access(target, prop, 'set')) {
|
|
958
|
-
return undefined
|
|
959
|
-
}
|
|
960
|
-
if (value && JSONTag.getType(value)==='object' && !value[isProxy]) {
|
|
961
|
-
value = getNewValueProxy(value)
|
|
962
|
-
}
|
|
963
|
-
if (target[prop] === value) {
|
|
964
|
-
return true
|
|
965
|
-
}
|
|
966
|
-
target[prop] = value
|
|
967
|
-
target[isChanged] = true
|
|
968
|
-
return true
|
|
969
|
-
},
|
|
970
|
-
deleteProperty(target, prop) {
|
|
971
|
-
if (immutable) {
|
|
972
|
-
throw new Error('dataspace is immutable')
|
|
973
|
-
}
|
|
974
|
-
if (meta.access && !meta.access(target, prop, 'deleteProperty')) {
|
|
975
|
-
return undefined
|
|
976
|
-
}
|
|
977
|
-
firstParse(target)
|
|
978
|
-
if (typeof target[prop] === 'undefined') {
|
|
979
|
-
return true
|
|
980
|
-
}
|
|
981
|
-
delete target[prop]
|
|
982
|
-
target[isChanged] = true
|
|
983
|
-
return true
|
|
984
|
-
},
|
|
985
|
-
ownKeys(target) {
|
|
986
|
-
firstParse(target)
|
|
987
|
-
return Reflect.ownKeys(target)
|
|
988
|
-
},
|
|
989
|
-
getOwnPropertyDescriptor(target, prop) {
|
|
990
|
-
firstParse(target)
|
|
991
|
-
return Reflect.getOwnPropertyDescriptor(target, prop)
|
|
992
|
-
},
|
|
993
|
-
defineProperty(target, prop, descriptor) {
|
|
994
|
-
if (immutable) {
|
|
995
|
-
throw new Error('dataspace is immutable')
|
|
996
|
-
}
|
|
997
|
-
if (meta.access && !meta.access(target, prop, 'defineProperty')) {
|
|
998
|
-
return undefined
|
|
999
|
-
}
|
|
1000
|
-
firstParse(target)
|
|
1001
|
-
target[isChanged] = true
|
|
1002
|
-
return Object.defineProperty(target, prop, descriptor)
|
|
1003
|
-
},
|
|
1004
|
-
has(target, prop) {
|
|
1005
|
-
if (meta.access && !meta.access(target, prop, 'has')) {
|
|
1006
|
-
return false
|
|
1007
|
-
}
|
|
1008
|
-
firstParse()
|
|
1009
|
-
return prop in target
|
|
1010
|
-
},
|
|
1011
|
-
setPrototypeOf(target,proto) {
|
|
1012
|
-
throw new Error('changing prototypes is not supported')
|
|
537
|
+
} else {
|
|
538
|
+
value.push(this.ch.charCodeAt(0))
|
|
539
|
+
this.next()
|
|
1013
540
|
}
|
|
1014
541
|
}
|
|
542
|
+
this.error("Syntax error: incomplete string")
|
|
1015
543
|
}
|
|
1016
544
|
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
545
|
+
length()
|
|
546
|
+
{
|
|
547
|
+
this.whitespace()
|
|
548
|
+
this.next('(')
|
|
549
|
+
let numString=''
|
|
550
|
+
while(this.ch>='0' && this.ch<='9') {
|
|
551
|
+
numString += this.ch
|
|
552
|
+
this.next()
|
|
1021
553
|
}
|
|
1022
|
-
if (
|
|
1023
|
-
|
|
1024
|
-
//e.g. odJSONTag and a call to ownKeys triggering the first parse
|
|
1025
|
-
let tag = JSONTag.getType(target)
|
|
1026
|
-
if (tag) {
|
|
1027
|
-
JSONTag.setType(receiver, tag)
|
|
1028
|
-
}
|
|
1029
|
-
let attributes = JSONTag.getAttributes(target)
|
|
1030
|
-
if (attributes) {
|
|
1031
|
-
JSONTag.setAttributes(receiver, attributes)
|
|
1032
|
-
}
|
|
1033
|
-
target[isReceived] = true
|
|
554
|
+
if (this.ch!==')') {
|
|
555
|
+
this.error('Syntax error: not a length')
|
|
1034
556
|
}
|
|
557
|
+
this.next()
|
|
558
|
+
return parseInt(numString)
|
|
1035
559
|
}
|
|
1036
560
|
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
561
|
+
offset()
|
|
562
|
+
{
|
|
563
|
+
this.next('~')
|
|
564
|
+
let numString = ''
|
|
565
|
+
while(this.ch>='0' && this.ch<='9') {
|
|
566
|
+
numString += this.ch
|
|
567
|
+
this.next()
|
|
1040
568
|
}
|
|
569
|
+
if (this.ch=='-') {
|
|
570
|
+
this.next('-')
|
|
571
|
+
let endString = ''
|
|
572
|
+
while(this.ch>='0' && this.ch<='9') {
|
|
573
|
+
endString += this.ch
|
|
574
|
+
this.next()
|
|
575
|
+
}
|
|
576
|
+
return new Slice(parseInt(numString),parseInt(endString)+1) // +1 because array.slice(start,end) slices upto but not including end
|
|
577
|
+
}
|
|
578
|
+
return parseInt(numString)
|
|
1041
579
|
}
|
|
1042
580
|
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
581
|
+
parseValue(position, ob={})
|
|
582
|
+
{
|
|
583
|
+
this.input = position.input
|
|
584
|
+
this.at = position.start
|
|
585
|
+
this.next()
|
|
586
|
+
let result = this.value(ob)
|
|
587
|
+
if (result instanceof JSONTag.Link) {
|
|
588
|
+
result = this.handleLink(result)
|
|
1046
589
|
}
|
|
1047
|
-
let index = meta.resultArray.length
|
|
1048
|
-
meta.resultArray.push('')
|
|
1049
|
-
value[getIndex] = index
|
|
1050
|
-
makeChildProxies(value)
|
|
1051
|
-
let result = new Proxy(value, handlers.newValueHandler)
|
|
1052
|
-
meta.resultArray[index] = result
|
|
1053
590
|
return result
|
|
1054
591
|
}
|
|
1055
592
|
|
|
1056
|
-
|
|
593
|
+
handleLink(link)
|
|
1057
594
|
{
|
|
1058
|
-
let
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
// current offset + length contains jsontag of this value
|
|
1063
|
-
cache[position] = {
|
|
1064
|
-
input,
|
|
1065
|
-
start: at-1,
|
|
1066
|
-
end: at-1+length
|
|
595
|
+
let id = ''+link
|
|
596
|
+
let links = this.meta.unresolved.get(id)
|
|
597
|
+
if (links.length) {
|
|
598
|
+
throw Error('nyi')
|
|
1067
599
|
}
|
|
1068
|
-
at += length
|
|
1069
|
-
next()
|
|
1070
|
-
// newValueHandler makes sure that value[getBuffer] runs stringify
|
|
1071
|
-
// arrayHandler makes sure that changes in the array set targetIsChanged to true
|
|
1072
|
-
return new Proxy(cache, handlers.handler)
|
|
1073
600
|
}
|
|
1074
601
|
|
|
1075
602
|
value = function(ob={})
|
|
1076
603
|
{
|
|
1077
604
|
let tagOb, result, tagName;
|
|
1078
|
-
whitespace()
|
|
1079
|
-
if (ch==='~') {
|
|
1080
|
-
let vOffset = offset()
|
|
605
|
+
this.whitespace()
|
|
606
|
+
if (this.ch==='~') {
|
|
607
|
+
let vOffset = this.offset()
|
|
1081
608
|
if (isSlice(vOffset)) {
|
|
1082
609
|
return vOffset
|
|
1083
610
|
}
|
|
1084
|
-
return meta.resultArray[vOffset]
|
|
611
|
+
return this.meta.resultArray[vOffset]
|
|
1085
612
|
}
|
|
1086
|
-
if (ch==='<') {
|
|
1087
|
-
tagOb = tag()
|
|
613
|
+
if (this.ch==='<') {
|
|
614
|
+
tagOb = this.tag()
|
|
1088
615
|
tagName = tagOb.tagName
|
|
1089
|
-
whitespace()
|
|
616
|
+
this.whitespace()
|
|
1090
617
|
}
|
|
1091
|
-
switch(ch) {
|
|
618
|
+
switch(this.ch) {
|
|
1092
619
|
case '{':
|
|
1093
620
|
if (tagName && tagName!=='object') {
|
|
1094
|
-
|
|
621
|
+
this.typeError(tagName, this.ch)
|
|
1095
622
|
}
|
|
1096
|
-
result = object(ob)
|
|
623
|
+
result = this.object(ob)
|
|
1097
624
|
break
|
|
1098
625
|
case '[':
|
|
1099
626
|
if (tagName && tagName!=='array') {
|
|
1100
|
-
|
|
627
|
+
this.typeError(tagName, this.ch)
|
|
1101
628
|
}
|
|
1102
|
-
result = array()
|
|
629
|
+
result = this.array()
|
|
1103
630
|
break
|
|
1104
631
|
case '"':
|
|
1105
|
-
result = string(tagName)
|
|
632
|
+
result = this.string(tagName)
|
|
1106
633
|
break
|
|
1107
634
|
case '-':
|
|
1108
|
-
result = number(tagName)
|
|
635
|
+
result = this.number(tagName)
|
|
1109
636
|
break
|
|
1110
637
|
default:
|
|
1111
|
-
if (ch>='0' && ch<='9') {
|
|
1112
|
-
result = number(tagName)
|
|
638
|
+
if (this.ch>='0' && this.ch<='9') {
|
|
639
|
+
result = this.number(tagName)
|
|
1113
640
|
} else {
|
|
1114
|
-
result = boolOrNull(tagName)
|
|
641
|
+
result = this.boolOrNull(tagName)
|
|
1115
642
|
}
|
|
1116
643
|
break
|
|
1117
644
|
}
|
|
@@ -1128,7 +655,7 @@ export default function parse(input, meta, immutable=true)
|
|
|
1128
655
|
result = new Number(result)
|
|
1129
656
|
break
|
|
1130
657
|
default:
|
|
1131
|
-
error('Syntax Error: unexpected type '+(typeof result))
|
|
658
|
+
this.error('Syntax Error: unexpected type '+(typeof result))
|
|
1132
659
|
break
|
|
1133
660
|
}
|
|
1134
661
|
}
|
|
@@ -1141,41 +668,149 @@ export default function parse(input, meta, immutable=true)
|
|
|
1141
668
|
}
|
|
1142
669
|
return result
|
|
1143
670
|
}
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
671
|
+
|
|
672
|
+
jump()
|
|
673
|
+
{
|
|
674
|
+
this.next('+')
|
|
675
|
+
return this.number()
|
|
1148
676
|
}
|
|
1149
677
|
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
678
|
+
lengthValue(i)
|
|
679
|
+
{
|
|
680
|
+
this.whitespace()
|
|
681
|
+
if (!this.ch) {
|
|
682
|
+
this.next()
|
|
1154
683
|
}
|
|
1155
684
|
let l, v
|
|
1156
|
-
if (ch=='+') {
|
|
1157
|
-
i += jump()
|
|
685
|
+
if (this.ch=='+') {
|
|
686
|
+
i += this.jump()
|
|
1158
687
|
} else {
|
|
1159
|
-
l = length()
|
|
1160
|
-
v = valueProxy(l,i)
|
|
688
|
+
l = this.length()
|
|
689
|
+
v = this.valueProxy(l,i)
|
|
1161
690
|
}
|
|
1162
691
|
return [l, v, i]
|
|
1163
692
|
}
|
|
1164
693
|
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
694
|
+
valueProxy(length, index)
|
|
695
|
+
{
|
|
696
|
+
let cache = {}
|
|
697
|
+
cache[getIndex] = index
|
|
698
|
+
cache[isChanged] = false
|
|
699
|
+
cache[isParsed] = false
|
|
700
|
+
// current offset + length contains jsontag of this value
|
|
701
|
+
cache[position] = {
|
|
702
|
+
input: this.input,
|
|
703
|
+
start: this.at-1,
|
|
704
|
+
end: this.at-1+length
|
|
705
|
+
}
|
|
706
|
+
this.at += length
|
|
707
|
+
this.next()
|
|
708
|
+
// newValueHandler makes sure that value[getBuffer] runs stringify
|
|
709
|
+
// arrayHandler makes sure that changes in the array set targetIsChanged to true
|
|
710
|
+
let result = new Proxy(cache, this.handlers.defaultHandler)
|
|
711
|
+
this.cachedProxies.set(cache, result)
|
|
712
|
+
return result
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
makeChildProxies(parent)
|
|
716
|
+
{
|
|
717
|
+
Object.entries(parent).forEach(([key,entry]) => {
|
|
718
|
+
if (Array.isArray(entry)) {
|
|
719
|
+
this.makeChildProxies(entry)
|
|
720
|
+
} else if (entry && !entry[isProxy]) {
|
|
721
|
+
let type = JSONTag.getType(entry)
|
|
722
|
+
if (type==='object' || type==='link') {//FIXME: check for other types
|
|
723
|
+
parent[key] = this.getNewValueProxy(entry)
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
})
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
getArrayProxy(arr, par, handler)
|
|
730
|
+
{
|
|
731
|
+
if (!handler) {
|
|
732
|
+
handler = this.handlers.arrayHandler
|
|
733
|
+
}
|
|
734
|
+
if (!this.cachedProxies.has(arr)) {
|
|
735
|
+
this.cachedProxies.set(arr, new Proxy(arr, handler))
|
|
736
|
+
}
|
|
737
|
+
let aProxy = this.cachedProxies.get(arr)
|
|
738
|
+
aProxy[parent] = par
|
|
739
|
+
return aProxy
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
firstParse(target)
|
|
743
|
+
{
|
|
744
|
+
if (!target[isParsed]) {
|
|
745
|
+
this.parseValue(target[position], target)
|
|
746
|
+
target[isParsed] = true
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
getNewValueProxy(value)
|
|
752
|
+
{
|
|
753
|
+
if (value === null) {
|
|
754
|
+
return null
|
|
755
|
+
}
|
|
756
|
+
if (value[isProxy]) {
|
|
757
|
+
return value
|
|
758
|
+
}
|
|
759
|
+
if (JSONTag.getType(value)=='link') {
|
|
760
|
+
let index = this.meta.index.id.get(''+value)
|
|
761
|
+
if (typeof index != 'undefined') {
|
|
762
|
+
return this.meta.resultArray[index]
|
|
1176
763
|
}
|
|
1177
|
-
line++
|
|
1178
764
|
}
|
|
765
|
+
let index = this.meta.resultArray.length
|
|
766
|
+
this.meta.resultArray.push('')
|
|
767
|
+
value[getIndex] = index
|
|
768
|
+
this.makeChildProxies(value)
|
|
769
|
+
let result = new Proxy(value, this.handlers.newValueHandler)
|
|
770
|
+
this.cachedProxies.set(value, result)
|
|
771
|
+
this.meta.resultArray[index] = result
|
|
772
|
+
return result
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
parse(input)
|
|
776
|
+
{
|
|
777
|
+
if (typeof input == 'string' || input instanceof String) {
|
|
778
|
+
input = stringToSAB(input)
|
|
779
|
+
}
|
|
780
|
+
if (!(input instanceof Uint8Array)) {
|
|
781
|
+
this.error('parse only accepts Uint8Array or String as input')
|
|
782
|
+
}
|
|
783
|
+
if (!this.meta.resultArray) {
|
|
784
|
+
this.meta.resultArray = []
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
this.ch = ' '
|
|
788
|
+
this.at = 0
|
|
789
|
+
this.input = input
|
|
790
|
+
|
|
791
|
+
let line = 0
|
|
792
|
+
while(this.ch && this.at<this.input.length) {
|
|
793
|
+
let result = this.lengthValue(line) // needs to return current line nr
|
|
794
|
+
this.whitespace()
|
|
795
|
+
line = result[2]
|
|
796
|
+
if (result[1]) {
|
|
797
|
+
if (!this.meta.resultArray[line] || this.meta.resultArray[line][proxyType]=='new') {
|
|
798
|
+
this.meta.resultArray[line] = result[1]
|
|
799
|
+
} else {
|
|
800
|
+
this.meta.resultArray[line][source] = result[1]
|
|
801
|
+
}
|
|
802
|
+
line++
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
return this.meta.resultArray[0]
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
checkUnresolved(item, object, key) {
|
|
809
|
+
// TODO:
|
|
810
|
+
// for now assume there are no <link> objects in od-jsontag
|
|
811
|
+
// JSONTag Parser.checkUnresolved triggers firstParse,
|
|
812
|
+
// while parsing the current object
|
|
813
|
+
// incorrect: when adding a new object from a JSONTag string
|
|
814
|
+
// it may contain links which cannot yet be resolved... these need to be handled
|
|
1179
815
|
}
|
|
1180
|
-
return meta.resultArray[0]
|
|
1181
816
|
}
|