@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/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
- }