statebus 7.1.1 → 7.2.2
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/extras/tests.js +230 -50
- package/package.json +1 -1
- package/statebus.js +209 -61
package/extras/tests.js
CHANGED
|
@@ -81,12 +81,13 @@ test(function validation (done) {
|
|
|
81
81
|
[{a: false}, {a: 'boolean'}, true],
|
|
82
82
|
[{a: 1, b: 2}, {a: 1}, false],
|
|
83
83
|
[{a: 1, b: 2}, {a: 1, '*':'*'}, true],
|
|
84
|
-
[{a: 2, b: 2}, {a: 1, '*':'*'}, false]
|
|
84
|
+
[{a: 2, b: 2}, {a: 1, '*':'*'}, false],
|
|
85
|
+
[{a: {link: "foo"}}, {a: 'link'}, true]
|
|
85
86
|
]
|
|
86
87
|
|
|
87
88
|
for (var i=0; i<v_tests.length; i++)
|
|
88
89
|
assert(bus.validate(v_tests[i][0], v_tests[i][1]) === v_tests[i][2],
|
|
89
|
-
'Validation test failed'
|
|
90
|
+
'Validation test failed: ' + i + ' ' + JSON.stringify(v_tests[i]))
|
|
90
91
|
|
|
91
92
|
done()
|
|
92
93
|
})
|
|
@@ -319,60 +320,82 @@ test(function proxy_link (done) {
|
|
|
319
320
|
done()
|
|
320
321
|
})
|
|
321
322
|
|
|
322
|
-
|
|
323
|
-
|
|
323
|
+
function verify_no_proxies (bus) {
|
|
324
|
+
bus.deep_map(bus.cache, o => {
|
|
325
|
+
if ((typeof o === 'object' || typeof o === 'function')
|
|
326
|
+
&& o[bus.symbols.is_proxy]) {
|
|
327
|
+
console.trace('NOOOO proxy is here', obj)
|
|
328
|
+
throw 'We got a bad one!!!'
|
|
329
|
+
}
|
|
330
|
+
return o
|
|
331
|
+
})
|
|
332
|
+
}
|
|
324
333
|
|
|
325
|
-
|
|
334
|
+
// Disable the version of proxy_links_through where the user does not have to
|
|
335
|
+
// explicitly traverse links with ._()
|
|
336
|
+
if (true)
|
|
337
|
+
test(function proxy_links_through3 (done) {
|
|
338
|
+
var bus = require('../statebus')()
|
|
326
339
|
|
|
327
|
-
|
|
328
|
-
bus.state.b = bus.link('c')
|
|
329
|
-
bus.state.c = 'see'
|
|
330
|
-
|
|
331
|
-
log('state.c is', bus.state.c)
|
|
332
|
-
log('state.b is', bus.state.b, 'from cache', bus.cache.b)
|
|
333
|
-
log('state.a is', bus.state.a)
|
|
334
|
-
log('state.a[0] is', bus.state.a[0])
|
|
335
|
-
log('state.a[0] is', bus.state.a[0])
|
|
336
|
-
assert(bus.state.a[0] === 'see')
|
|
340
|
+
// First try to dereference through three links
|
|
337
341
|
|
|
338
|
-
|
|
342
|
+
bus.state.a = [bus.link('b')]
|
|
343
|
+
bus.state.b = bus.link('c')
|
|
344
|
+
bus.state.c = 'see'
|
|
339
345
|
|
|
340
|
-
|
|
341
|
-
log('nested is', bus.state.nested)
|
|
342
|
-
log('nested[1].a[0] is', bus.state.nested[1].a[0])
|
|
343
|
-
assert(bus.state.nested[1].a[0] === 'see')
|
|
346
|
+
verify_no_proxies(bus)
|
|
344
347
|
|
|
345
|
-
|
|
348
|
+
log('state.c is', bus.state.c)
|
|
349
|
+
log('state.b is', bus.state.b, 'from cache', bus.cache.b)
|
|
350
|
+
log('state.a is', bus.state.a)
|
|
351
|
+
log('state.a[0] is', bus.state.a[0])
|
|
352
|
+
log('state.a[0]() is', bus.state.a[0]())
|
|
353
|
+
log('state.a[0]()() is', bus.state.a[0]()())
|
|
354
|
+
assert(bus.state.a[0]()() === 'see')
|
|
346
355
|
|
|
347
|
-
|
|
348
|
-
log('Raw is', bus.raw(bus.state).nested)
|
|
349
|
-
assert(bus.deep_equals(
|
|
350
|
-
bus.state[bus.symbols.raw].nested,
|
|
351
|
-
bus.raw(bus.state).nested
|
|
352
|
-
))
|
|
356
|
+
verify_no_proxies(bus)
|
|
353
357
|
|
|
354
|
-
|
|
355
|
-
bus.raw(bus.state).nested,
|
|
356
|
-
[ 99, { a: { link: 'a' } } ])
|
|
358
|
+
// Add a little more wrapping and try some more
|
|
357
359
|
|
|
358
|
-
|
|
359
|
-
bus.
|
|
360
|
-
|
|
361
|
-
|
|
360
|
+
bus.state.nested = [99, {a: bus.link('a')}]
|
|
361
|
+
log('nested is', bus.state.nested, bus.state.nested[bus.symbols.is_proxy])
|
|
362
|
+
log('raw nested is', bus.state[bus.symbols.raw].nested)
|
|
363
|
+
log('raw cache is', bus.cache.nested)
|
|
362
364
|
|
|
363
|
-
|
|
365
|
+
log('nested[1].a()[0]()() is', bus.state.nested[1].a()[0]()())
|
|
366
|
+
assert(bus.state.nested[1].a()[0]()() === 'see')
|
|
364
367
|
|
|
365
|
-
|
|
368
|
+
verify_no_proxies(bus)
|
|
366
369
|
|
|
367
|
-
|
|
370
|
+
// Now try to go raw at the top-level
|
|
368
371
|
|
|
369
|
-
|
|
370
|
-
|
|
372
|
+
log('Raw is', bus.state[bus.symbols.raw].nested)
|
|
373
|
+
log('Raw is', bus.raw(bus.state).nested)
|
|
374
|
+
assert(bus.deep_equals(
|
|
375
|
+
bus.state[bus.symbols.raw].nested,
|
|
376
|
+
bus.raw(bus.state).nested
|
|
377
|
+
))
|
|
371
378
|
|
|
379
|
+
verify_no_proxies(bus)
|
|
372
380
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
381
|
+
log('Gonna deep_quals between:',
|
|
382
|
+
bus.raw(bus.state).nested.val,
|
|
383
|
+
[ 99, { a: { link: 'a' } } ])
|
|
384
|
+
|
|
385
|
+
assert(bus.deep_equals(
|
|
386
|
+
bus.raw(bus.state).nested.val,
|
|
387
|
+
[ 99, { a: { link: 'a' } } ]
|
|
388
|
+
))
|
|
389
|
+
|
|
390
|
+
// Now try to go raw within
|
|
391
|
+
|
|
392
|
+
log('Raw inner is', bus.raw(bus.state.nested[1]))
|
|
393
|
+
|
|
394
|
+
log('Bad raw call is', bus.raw(bus.state.nested[0]))
|
|
395
|
+
|
|
396
|
+
done()
|
|
397
|
+
})
|
|
398
|
+
else if (false)
|
|
376
399
|
test(function proxy_links_through2 (done) {
|
|
377
400
|
var bus = require('../statebus')()
|
|
378
401
|
|
|
@@ -386,16 +409,16 @@ if (false)
|
|
|
386
409
|
log('state.b is', bus.state.b, 'from cache', bus.cache.b)
|
|
387
410
|
log('state.a is', bus.state.a)
|
|
388
411
|
log('state.a[0] is', bus.state.a[0])
|
|
389
|
-
log('state.a[0]() is', bus.state.a[0]())
|
|
390
|
-
log('state.a[0]()() is', bus.state.a[0]()())
|
|
391
|
-
assert(bus.state.a[0]()() === 'see')
|
|
412
|
+
log('state.a[0]._() is', bus.state.a[0]._())
|
|
413
|
+
log('state.a[0]._()._() is', bus.state.a[0]._()._())
|
|
414
|
+
assert(bus.state.a[0]._()._() === 'see')
|
|
392
415
|
|
|
393
416
|
// Add a little more wrapping and try some more
|
|
394
417
|
|
|
395
418
|
bus.state.nested = [99, {a: bus.link('a')}]
|
|
396
419
|
log('nested is', bus.state.nested)
|
|
397
|
-
log('nested[1].a()[0]()() is', bus.state.nested[1].a()[0]()())
|
|
398
|
-
assert(bus.state.nested[1].a()[0]()() === 'see')
|
|
420
|
+
log('nested[1].a._()[0]._()._() is', bus.state.nested[1].a._()[0]._()._())
|
|
421
|
+
assert(bus.state.nested[1].a._()[0]._()._() === 'see')
|
|
399
422
|
|
|
400
423
|
// Now try to go raw at the top-level
|
|
401
424
|
|
|
@@ -406,9 +429,9 @@ if (false)
|
|
|
406
429
|
bus.raw(bus.state).nested
|
|
407
430
|
))
|
|
408
431
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
432
|
+
log('Gonna deep_quals between:',
|
|
433
|
+
bus.raw(bus.state).nested,
|
|
434
|
+
[ 99, { a: { link: 'a' } } ])
|
|
412
435
|
|
|
413
436
|
assert(bus.deep_equals(
|
|
414
437
|
bus.raw(bus.state).nested,
|
|
@@ -423,8 +446,163 @@ if (false)
|
|
|
423
446
|
|
|
424
447
|
done()
|
|
425
448
|
})
|
|
449
|
+
else
|
|
450
|
+
test(function proxy_links_through1 (done) {
|
|
451
|
+
var bus = require('../statebus')()
|
|
426
452
|
|
|
453
|
+
// First try to dereference through three links
|
|
427
454
|
|
|
455
|
+
bus.state.a = [bus.link('b')]
|
|
456
|
+
bus.state.b = bus.link('c')
|
|
457
|
+
bus.state.c = 'see'
|
|
458
|
+
|
|
459
|
+
log('state.c is', bus.state.c)
|
|
460
|
+
log('state.b is', bus.state.b, 'from cache', bus.cache.b)
|
|
461
|
+
log('state.a is', bus.state.a)
|
|
462
|
+
log('state.a[0] is', bus.state.a[0])
|
|
463
|
+
log('state.a[0] is', bus.state.a[0])
|
|
464
|
+
assert(bus.state.a[0] === 'see')
|
|
465
|
+
|
|
466
|
+
// Add a little more wrapping and try some more
|
|
467
|
+
|
|
468
|
+
bus.state.nested = [99, {a: bus.link('a')}]
|
|
469
|
+
log('nested is', bus.state.nested)
|
|
470
|
+
log('nested[1].a[0] is', bus.state.nested[1].a[0])
|
|
471
|
+
assert(bus.state.nested[1].a[0] === 'see')
|
|
472
|
+
|
|
473
|
+
// Now try to go raw at the top-level
|
|
474
|
+
|
|
475
|
+
log('Raw is', bus.state[bus.symbols.raw].nested)
|
|
476
|
+
log('Raw is', bus.raw(bus.state).nested)
|
|
477
|
+
assert(bus.deep_equals(
|
|
478
|
+
bus.state[bus.symbols.raw].nested,
|
|
479
|
+
bus.raw(bus.state).nested
|
|
480
|
+
))
|
|
481
|
+
|
|
482
|
+
log('Gonna deep_quals between:',
|
|
483
|
+
bus.raw(bus.state).nested,
|
|
484
|
+
[ 99, { a: { link: 'a' } } ])
|
|
485
|
+
|
|
486
|
+
assert(bus.deep_equals(
|
|
487
|
+
bus.raw(bus.state).nested,
|
|
488
|
+
[ 99, { a: { link: 'a' } } ]
|
|
489
|
+
))
|
|
490
|
+
|
|
491
|
+
// Now try to go raw within
|
|
492
|
+
|
|
493
|
+
log('Raw inner is', bus.raw(bus.state.nested[1]))
|
|
494
|
+
|
|
495
|
+
log('Bad raw call is', bus.raw(bus.state.nested[0]))
|
|
496
|
+
|
|
497
|
+
done()
|
|
498
|
+
})
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
test(function copy_link (done) {
|
|
502
|
+
var bus = require('../statebus')(), state = bus.state
|
|
503
|
+
|
|
504
|
+
state.a = [bus.link('b')]
|
|
505
|
+
state.b = 3
|
|
506
|
+
state.copy_of_a = state.a
|
|
507
|
+
state.copy_of_a0 = state.a[0]
|
|
508
|
+
|
|
509
|
+
console.log(bus.cache.a)
|
|
510
|
+
console.log(bus.cache.b)
|
|
511
|
+
console.log(bus.cache.copy_of_a)
|
|
512
|
+
console.log(bus.cache.copy_of_a0)
|
|
513
|
+
|
|
514
|
+
assert(bus.cache.a.val[0].link === 'b')
|
|
515
|
+
assert(bus.cache.b.val === 3)
|
|
516
|
+
assert(bus.cache.copy_of_a.val[0].link === 'b')
|
|
517
|
+
assert(bus.cache.copy_of_a0.val.link === 'b')
|
|
518
|
+
|
|
519
|
+
done()
|
|
520
|
+
})
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
// This was useful test code for figuring out how to set custom formatters on
|
|
525
|
+
// proxies. It's not needed anymore.
|
|
526
|
+
//
|
|
527
|
+
// test(function proxy_printing_in_node (done) {
|
|
528
|
+
// var bus = require('../statebus')(), state = bus.state
|
|
529
|
+
//
|
|
530
|
+
// state.a = [bus.link('b')]
|
|
531
|
+
// state.b = 3
|
|
532
|
+
// state.c = {a: 3, link: 99}
|
|
533
|
+
//
|
|
534
|
+
// log('a in cache is', bus.cache.a,
|
|
535
|
+
// {'typeof': typeof bus.cache.a === 'object',
|
|
536
|
+
// symbolsin: bus.symbols.link in bus.cache.a})
|
|
537
|
+
//
|
|
538
|
+
// log('state:', state)
|
|
539
|
+
// log('state.a:', state.a)
|
|
540
|
+
// log('state.b:', state.b)
|
|
541
|
+
// log('state.c:', state.c)
|
|
542
|
+
//
|
|
543
|
+
// var util = require('util')
|
|
544
|
+
//
|
|
545
|
+
// assert(util.inspect(state.a) === "Proxy [ { link: 'b' } ]")
|
|
546
|
+
// assert(util.inspect(state.b) === "3")
|
|
547
|
+
// assert(util.inspect(state.c) === "Proxy { a: 3, link: 99 }")
|
|
548
|
+
//
|
|
549
|
+
// log('passed!')
|
|
550
|
+
//
|
|
551
|
+
// // This version is abstracted and tested:
|
|
552
|
+
// var util = require('util')
|
|
553
|
+
// function make_proxy(target) {
|
|
554
|
+
// // Don't proxy null or non-objects
|
|
555
|
+
// if (!target || typeof target !== 'object') return target
|
|
556
|
+
//
|
|
557
|
+
// // Create proxies for all nested objects
|
|
558
|
+
// var clean = Array.isArray(target) ? [] : {}
|
|
559
|
+
// for (let prop of Object.getOwnPropertyNames(target)) {
|
|
560
|
+
// clean[prop] = make_proxy(target[prop])
|
|
561
|
+
// }
|
|
562
|
+
//
|
|
563
|
+
// // Create the proxy
|
|
564
|
+
// var proxy = new Proxy(clean, {
|
|
565
|
+
// get(target, prop) {
|
|
566
|
+
// return target[prop]
|
|
567
|
+
// }
|
|
568
|
+
// })
|
|
569
|
+
//
|
|
570
|
+
// // Add custom inspector
|
|
571
|
+
// proxy[util.inspect.custom] = function(depth, opts) {
|
|
572
|
+
// var formatted = Array.isArray(target) ? [] : {}
|
|
573
|
+
// for (let prop of Object.getOwnPropertyNames(target)) {
|
|
574
|
+
// formatted[prop] = target[prop]
|
|
575
|
+
// }
|
|
576
|
+
// return `Proxy ${util.inspect(formatted, { ...opts, customInspect: true })}`
|
|
577
|
+
// }
|
|
578
|
+
//
|
|
579
|
+
// return proxy
|
|
580
|
+
// }
|
|
581
|
+
//
|
|
582
|
+
// // Test various scenarios
|
|
583
|
+
// var data = {
|
|
584
|
+
// name: 'parent',
|
|
585
|
+
// child: {
|
|
586
|
+
// name: 'kid',
|
|
587
|
+
// toy: {
|
|
588
|
+
// name: 'teddy'
|
|
589
|
+
// }
|
|
590
|
+
// },
|
|
591
|
+
// numbers: [1, 2, {x: 3}], // Test with array containing object
|
|
592
|
+
// nullVal: null, // Test with null
|
|
593
|
+
// primitive: 42 // Test with primitive
|
|
594
|
+
// }
|
|
595
|
+
//
|
|
596
|
+
// var proxied = make_proxy(data)
|
|
597
|
+
// console.log('Full object:', proxied)
|
|
598
|
+
// console.log('Child:', proxied.child)
|
|
599
|
+
// console.log('Toy:', proxied.child.toy)
|
|
600
|
+
// console.log('Numbers:', proxied.numbers)
|
|
601
|
+
// console.log('Null value:', proxied.nullVal)
|
|
602
|
+
// console.log('Primitive:', proxied.primitive)
|
|
603
|
+
//
|
|
604
|
+
// done()
|
|
605
|
+
// })
|
|
428
606
|
|
|
429
607
|
test(function translate_fields (done) {
|
|
430
608
|
// Translate Statebus -> Proxy format
|
|
@@ -887,6 +1065,8 @@ test(function proxies (done) {
|
|
|
887
1065
|
var bus = require('../statebus').serve({file_store: false})
|
|
888
1066
|
var state = bus.state
|
|
889
1067
|
|
|
1068
|
+
log('Top-level proxy looks like:', bus.state)
|
|
1069
|
+
|
|
890
1070
|
assert(state.array === undefined)
|
|
891
1071
|
assert(state.bar === undefined)
|
|
892
1072
|
|
package/package.json
CHANGED
package/statebus.js
CHANGED
|
@@ -1462,14 +1462,17 @@
|
|
|
1462
1462
|
if (k === symbols.is_proxy)
|
|
1463
1463
|
return true
|
|
1464
1464
|
if (k === symbols.raw)
|
|
1465
|
-
return
|
|
1466
|
-
if (k === 'inspect' || k === 'valueOf' || typeof k === 'symbol')
|
|
1467
|
-
|
|
1465
|
+
return bus.cache
|
|
1466
|
+
// if (k === 'inspect' || k === 'valueOf' || typeof k === 'symbol')
|
|
1467
|
+
// return undefined
|
|
1468
1468
|
bogus_check(k)
|
|
1469
1469
|
var base = bus.get(k)
|
|
1470
1470
|
return json_proxy(base, '', base.val)
|
|
1471
1471
|
},
|
|
1472
1472
|
set: function set(o, key, val) {
|
|
1473
|
+
if (typeof key === 'symbol')
|
|
1474
|
+
return true
|
|
1475
|
+
|
|
1473
1476
|
bus.set({
|
|
1474
1477
|
key: key,
|
|
1475
1478
|
val: escape_json_to_bus(val)
|
|
@@ -1495,42 +1498,59 @@
|
|
|
1495
1498
|
|
|
1496
1499
|
return o
|
|
1497
1500
|
|
|
1498
|
-
//
|
|
1499
|
-
if (typeof o === 'object' && 'link' in o) {
|
|
1500
|
-
var new_base = bus.get(o.link)
|
|
1501
|
-
return json_proxy(new_base, '', new_base.val)
|
|
1502
|
-
// return link(o.link)
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
// For function proxies:
|
|
1507
|
-
//
|
|
1508
|
-
// // Javascript won't let us function call a proxy unless the
|
|
1509
|
-
// // "target" is a function. So we make a dummy target, and
|
|
1510
|
-
// // don't use it.
|
|
1511
|
-
// var dummy = function () {}
|
|
1501
|
+
// Then o must be an object, array, or link
|
|
1512
1502
|
|
|
1503
|
+
// First, handle links.
|
|
1504
|
+
if (typeof o === 'object' && 'link' in o) {
|
|
1505
|
+
// var new_base = bus.get(o.link)
|
|
1506
|
+
// return json_proxy(new_base, '', new_base.val)
|
|
1507
|
+
return link(o.link)
|
|
1508
|
+
|
|
1509
|
+
// Todo: to allow modifying links, or adding new fields to them,
|
|
1510
|
+
// we'll need to treat them more like a json_proxy, that passes
|
|
1511
|
+
// the base into the proxy creator, allowing edits, etc.
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
// Now it must be an array or object. Shallow clone it, so we can set
|
|
1515
|
+
// a custom formatter on it
|
|
1516
|
+
var target = o
|
|
1517
|
+
if (Array.isArray(target)) target = [...o]
|
|
1518
|
+
else target = {...o}
|
|
1519
|
+
|
|
1520
|
+
// Now set the custom formatter
|
|
1521
|
+
if (nodejs)
|
|
1522
|
+
target[util.inspect.custom] = function print_as_proxy (depth, opts) {
|
|
1523
|
+
var formatted = Array.isArray(target) ? [] : {}
|
|
1524
|
+
for (let prop of Object.getOwnPropertyNames(target))
|
|
1525
|
+
formatted[prop] = target[prop]
|
|
1526
|
+
formatted = unescape_bus_to_json(formatted)
|
|
1527
|
+
|
|
1528
|
+
return `Proxy ${util.inspect(formatted, { ...opts, customInspect: true })}`
|
|
1529
|
+
}
|
|
1513
1530
|
|
|
1514
|
-
|
|
1531
|
+
var proxy = new Proxy(target, {
|
|
1515
1532
|
get: function (o, k) {
|
|
1516
1533
|
if (k === 'inspect' || k === 'valueOf')
|
|
1517
1534
|
return undefined
|
|
1518
|
-
// if (custom_inspect && k === custom_inspect)
|
|
1519
|
-
// return custom_inspect
|
|
1520
1535
|
if (k === symbols.is_proxy)
|
|
1521
1536
|
return true
|
|
1522
1537
|
if (k === symbols.raw)
|
|
1523
1538
|
return o
|
|
1524
|
-
if (typeof k === 'symbol')
|
|
1525
|
-
return undefined
|
|
1526
1539
|
|
|
1527
1540
|
// Compute the new path
|
|
1528
1541
|
var new_path = path + '[' + JSON.stringify(k) + ']'
|
|
1529
1542
|
return json_proxy(base, new_path, o[escape_field_json_to_bus(k)])
|
|
1530
1543
|
},
|
|
1531
|
-
set: function (
|
|
1544
|
+
set: function (target, k, v) {
|
|
1532
1545
|
var value = escape_json_to_bus(v)
|
|
1533
|
-
|
|
1546
|
+
var escaped_key = escape_field_json_to_bus(k)
|
|
1547
|
+
|
|
1548
|
+
// Now mutate both the shallow-copied target and the original
|
|
1549
|
+
// object because we have two because es6 proxies are stupidly
|
|
1550
|
+
// designed and we had to make a copy to make custom inspect
|
|
1551
|
+
// symbol work
|
|
1552
|
+
o[escaped_key] = value
|
|
1553
|
+
target[escaped_key] = value
|
|
1534
1554
|
var new_path = path + '[' + JSON.stringify(k) + ']'
|
|
1535
1555
|
bus.set.sync(
|
|
1536
1556
|
base,
|
|
@@ -1541,20 +1561,20 @@
|
|
|
1541
1561
|
)
|
|
1542
1562
|
return true
|
|
1543
1563
|
},
|
|
1544
|
-
has: function (o, k) {
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
},
|
|
1555
|
-
deleteProperty: function del (o, k) {
|
|
1564
|
+
// has: function (o, k) {
|
|
1565
|
+
// return o.hasOwnProperty(escape_field_json_to_bus(k))
|
|
1566
|
+
// },
|
|
1567
|
+
// ownKeys: function () {
|
|
1568
|
+
// return Object.keys(target).map(unescape_field_bus_to_json)
|
|
1569
|
+
// },
|
|
1570
|
+
// getOwnPropertyDescriptor: function (target, key) {
|
|
1571
|
+
// return { enumerable: true, configurable: true, value: this.get(target, key) }
|
|
1572
|
+
// },
|
|
1573
|
+
deleteProperty: function del (target, k) {
|
|
1556
1574
|
var new_path = path + '[' + JSON.stringify(k) + ']'
|
|
1557
|
-
|
|
1575
|
+
var escaped_key = escape_field_json_to_bus(k)
|
|
1576
|
+
delete o[escaped_key]
|
|
1577
|
+
delete target[escaped_key]
|
|
1558
1578
|
bus.set(
|
|
1559
1579
|
base,
|
|
1560
1580
|
// Forward the patches too
|
|
@@ -1563,17 +1583,32 @@
|
|
|
1563
1583
|
content: undefined}]}
|
|
1564
1584
|
)
|
|
1565
1585
|
return true // Report success to Proxy
|
|
1566
|
-
}
|
|
1567
|
-
// For function proxies:
|
|
1568
|
-
//
|
|
1569
|
-
// apply: function apply (o, This, args) {
|
|
1570
|
-
// return translate_fields(o, unescape_field_from_bus)
|
|
1571
|
-
// }
|
|
1586
|
+
},
|
|
1572
1587
|
})
|
|
1588
|
+
|
|
1589
|
+
return proxy
|
|
1573
1590
|
}
|
|
1574
1591
|
|
|
1575
1592
|
bus.state = top_level_proxy
|
|
1576
1593
|
|
|
1594
|
+
// This doesn't work because custom inspectors only work when the
|
|
1595
|
+
// util.inspect.custom symbol is defined on the "target" of the
|
|
1596
|
+
// proxy... which right now is `cache` for the top_level_proxy. I could
|
|
1597
|
+
// shallow-copy cache into a new target variable, and add this symbol to
|
|
1598
|
+
// it, and keep them in sync, but that sounds annoying. I'm just going to
|
|
1599
|
+
// ignore the custom proxy formatter on the top-level-proxy for now.
|
|
1600
|
+
|
|
1601
|
+
// if (nodejs) {
|
|
1602
|
+
// var util = require('util')
|
|
1603
|
+
// top_level_proxy[util.inspect.custom] = function(depth, opts) {
|
|
1604
|
+
// var formatted = {}
|
|
1605
|
+
// for (let prop of Object.getOwnPropertyNames(cache)) {
|
|
1606
|
+
// formatted[prop] = cache[prop].val
|
|
1607
|
+
// }
|
|
1608
|
+
// return `STATE ${util.inspect(formatted, { ...opts, customInspect: true })}`
|
|
1609
|
+
// }
|
|
1610
|
+
// }
|
|
1611
|
+
|
|
1577
1612
|
// This is temporary code to wrap the cache as a flat key/valuel store
|
|
1578
1613
|
// that returns raw objects, dereferencing .val. We can remove it once we
|
|
1579
1614
|
// remove the internal .val stuff from statebus.
|
|
@@ -1589,22 +1624,29 @@
|
|
|
1589
1624
|
})
|
|
1590
1625
|
}
|
|
1591
1626
|
|
|
1592
|
-
// How proxy links work right now:
|
|
1593
|
-
// - The user creates a link with bus.link(key)
|
|
1594
|
-
// - which produces a {[symbols.link]: key}
|
|
1595
|
-
// - which when set() into a proxy, is replaced with a {link: key}, to store internally
|
|
1596
|
-
// - Then, when get()ing that internal {link: key} through Proxy:
|
|
1597
|
-
// - We auto-dereference the key, with another get()
|
|
1598
|
-
// - So the user actually sees the value of the resource on the other side of the link
|
|
1599
|
-
function link (url) {
|
|
1600
|
-
return {[symbols.link]: url}
|
|
1601
|
-
}
|
|
1602
1627
|
|
|
1603
|
-
//
|
|
1604
|
-
|
|
1628
|
+
// Old link code:
|
|
1629
|
+
|
|
1630
|
+
// // How proxy links work right now:
|
|
1631
|
+
// // - The user creates a link with bus.link(key)
|
|
1632
|
+
// // - which produces a {[symbols.link]: key}
|
|
1633
|
+
// // - which when set() into a proxy, is replaced with a {link: key}, to store internally
|
|
1634
|
+
// // - Then, when get()ing that internal {link: key} through Proxy:
|
|
1635
|
+
// // - We auto-dereference the key, with another get()
|
|
1636
|
+
// // - So the user actually sees the value of the resource on the other side of the link
|
|
1637
|
+
// function link (url) {
|
|
1638
|
+
// return {
|
|
1639
|
+
// link: url,
|
|
1640
|
+
// [symbols.link]: true,
|
|
1641
|
+
// _: (args, o) => (o = get(url), json_proxy(o, '', o.val))
|
|
1642
|
+
// }
|
|
1643
|
+
// }
|
|
1644
|
+
|
|
1645
|
+
// The proxy object for links. Disabled for now.
|
|
1646
|
+
// This type of link has to be function called, as link(), to dereference.
|
|
1605
1647
|
// function proxy_link (url) {
|
|
1606
1648
|
// function follow_link () {}
|
|
1607
|
-
//
|
|
1649
|
+
// var proxy = new Proxy(follow_link, {
|
|
1608
1650
|
// get: function (o, k) {
|
|
1609
1651
|
// console.log('get', k)
|
|
1610
1652
|
// if (k === 'inspect' || k === 'valueOf')
|
|
@@ -1682,7 +1724,109 @@
|
|
|
1682
1724
|
// return top_level_proxy[url]
|
|
1683
1725
|
// }
|
|
1684
1726
|
// })
|
|
1727
|
+
|
|
1728
|
+
// proxy[util.inspect.custom] = function(depth, opts) {
|
|
1729
|
+
// var formatted = Array.isArray(o) ? [] : {}
|
|
1730
|
+
// for (let prop of Object.getOwnPropertyNames(o)) {
|
|
1731
|
+
// formatted[prop] = o[prop]
|
|
1732
|
+
// }
|
|
1733
|
+
// return `*${util.inspect({link: url})}`
|
|
1734
|
+
// }
|
|
1735
|
+
|
|
1736
|
+
// return proxy
|
|
1737
|
+
|
|
1738
|
+
// }
|
|
1739
|
+
|
|
1740
|
+
// function proxy_link2 (url) {
|
|
1741
|
+
// var target = {link: url}
|
|
1742
|
+
|
|
1743
|
+
// Object.setPrototypeOf(obj, Function.prototype);
|
|
1744
|
+
// Object.defineProperty(obj, 'toString', {
|
|
1745
|
+
// value: function() { return `{link: "${this.link}"}`; },
|
|
1746
|
+
// writable: true,
|
|
1747
|
+
// configurable: true
|
|
1748
|
+
// })
|
|
1749
|
+
|
|
1750
|
+
// return new Proxy(target, {
|
|
1751
|
+
// apply(target, this_arg, args) {
|
|
1752
|
+
// return top_level_proxy[url]
|
|
1753
|
+
// }
|
|
1754
|
+
// })
|
|
1685
1755
|
// }
|
|
1756
|
+
|
|
1757
|
+
|
|
1758
|
+
// New link code
|
|
1759
|
+
function link (url) {
|
|
1760
|
+
var target = () => {}
|
|
1761
|
+
|
|
1762
|
+
// Use non-enumerable properties for function stuff
|
|
1763
|
+
Object.defineProperties(target, {
|
|
1764
|
+
// 'length': { value: 0, enumerable: false },
|
|
1765
|
+
'name': { value: '', enumerable: false },
|
|
1766
|
+
'prototype': { value: {}, enumerable: false },
|
|
1767
|
+
|
|
1768
|
+
// Make link enumerable
|
|
1769
|
+
'link': { value: url, enumerable: true, writable: true, configurable: true },
|
|
1770
|
+
'toString': {
|
|
1771
|
+
value: function() { return `{link: "${this.link}"}` },
|
|
1772
|
+
enumerable: false
|
|
1773
|
+
},
|
|
1774
|
+
|
|
1775
|
+
// Add toJSON method
|
|
1776
|
+
'toJSON': {
|
|
1777
|
+
value: function() { return { link: this.link } },
|
|
1778
|
+
enumerable: false
|
|
1779
|
+
}
|
|
1780
|
+
})
|
|
1781
|
+
|
|
1782
|
+
var proxy = new Proxy(target, {
|
|
1783
|
+
get: function (o, k) {
|
|
1784
|
+
// console.log('link getting',k)
|
|
1785
|
+
// if (k === 'inspect' || k === 'valueOf')
|
|
1786
|
+
// return undefined
|
|
1787
|
+
|
|
1788
|
+
// if (custom_inspect && k === custom_inspect)
|
|
1789
|
+
// return custom_inspect
|
|
1790
|
+
if (k === symbols.is_proxy)
|
|
1791
|
+
return true
|
|
1792
|
+
if (k === symbols.link)
|
|
1793
|
+
return true
|
|
1794
|
+
if (k === symbols.raw)
|
|
1795
|
+
return {link: url}
|
|
1796
|
+
// if (typeof k === 'symbol')
|
|
1797
|
+
// return undefined
|
|
1798
|
+
|
|
1799
|
+
// if (k === 'link')
|
|
1800
|
+
// return url
|
|
1801
|
+
|
|
1802
|
+
return target[k]
|
|
1803
|
+
|
|
1804
|
+
// return undefined
|
|
1805
|
+
|
|
1806
|
+
},
|
|
1807
|
+
apply(target, this_arg, args) {
|
|
1808
|
+
return top_level_proxy[url]
|
|
1809
|
+
},
|
|
1810
|
+
has: function (o, k) {
|
|
1811
|
+
if (k === symbols.link)
|
|
1812
|
+
return true
|
|
1813
|
+
return Reflect.has(o, k)
|
|
1814
|
+
},
|
|
1815
|
+
})
|
|
1816
|
+
|
|
1817
|
+
if (nodejs)
|
|
1818
|
+
proxy[util.inspect.custom] = function(depth, opts) {
|
|
1819
|
+
var formatted = Array.isArray(target) ? [] : {}
|
|
1820
|
+
for (let prop of Object.getOwnPropertyNames(target)) {
|
|
1821
|
+
formatted[prop] = target[prop]
|
|
1822
|
+
}
|
|
1823
|
+
formatted = {link: url}
|
|
1824
|
+
return `Proxy ${util.inspect(formatted, { ...opts, customInspect: true })}`
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
return proxy
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1686
1830
|
function raw (proxy) {
|
|
1687
1831
|
if (!(typeof proxy === 'object' && proxy[symbols.is_proxy]))
|
|
1688
1832
|
return proxy
|
|
@@ -2095,13 +2239,14 @@
|
|
|
2095
2239
|
var unescape_field_bus_to_json = (field) =>
|
|
2096
2240
|
unescape_field_from_nelson(unescape_field_from_bus(field))
|
|
2097
2241
|
|
|
2098
|
-
var escape_json_to_bus
|
|
2242
|
+
var escape_json_to_bus = (obj) => {
|
|
2099
2243
|
obj = translate_fields(obj, escape_field_json_to_bus)
|
|
2100
|
-
return deep_map(obj, o => (typeof o === 'object'
|
|
2101
|
-
|
|
2244
|
+
return deep_map(obj, o => ((typeof o === 'object' || typeof o === 'function')
|
|
2245
|
+
&& symbols.link in o
|
|
2246
|
+
? {link: o.link}
|
|
2102
2247
|
: o))
|
|
2103
2248
|
}
|
|
2104
|
-
var unescape_bus_to_json
|
|
2249
|
+
var unescape_bus_to_json = (obj) =>
|
|
2105
2250
|
translate_fields(obj, field => unescape_field_bus_to_json(field))
|
|
2106
2251
|
|
|
2107
2252
|
|
|
@@ -2439,6 +2584,8 @@
|
|
|
2439
2584
|
|
|
2440
2585
|
if (typeof obj === 'object') {
|
|
2441
2586
|
if (schema === 'object') return true
|
|
2587
|
+
if (schema === 'link')
|
|
2588
|
+
return validate(obj, {link: 'string'})
|
|
2442
2589
|
|
|
2443
2590
|
if (typeof schema === 'object') {
|
|
2444
2591
|
for (var k in obj) {
|
|
@@ -2595,8 +2742,9 @@
|
|
|
2595
2742
|
if (nodejs)
|
|
2596
2743
|
// Use require.call() instead of require() to fool jsdelivr.net into ignoring the require
|
|
2597
2744
|
require.call(null, './server-library').import_server(bus, make_bus, options)
|
|
2598
|
-
|
|
2745
|
+
|
|
2599
2746
|
bus.render_when_loading = true
|
|
2747
|
+
|
|
2600
2748
|
return bus
|
|
2601
2749
|
}
|
|
2602
2750
|
|