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