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.
Files changed (3) hide show
  1. package/extras/tests.js +230 -50
  2. package/package.json +1 -1
  3. 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', v_tests[i])
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
- test(function proxy_links_through1 (done) {
323
- var bus = require('../statebus')()
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
- // First try to dereference through three links
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
- bus.state.a = [bus.link('b')]
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
- // Add a little more wrapping and try some more
342
+ bus.state.a = [bus.link('b')]
343
+ bus.state.b = bus.link('c')
344
+ bus.state.c = 'see'
339
345
 
340
- bus.state.nested = [99, {a: bus.link('a')}]
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
- // Now try to go raw at the top-level
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
- log('Raw is', bus.state[bus.symbols.raw].nested)
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
- log('Gonna deep_quals between:',
355
- bus.raw(bus.state).nested,
356
- [ 99, { a: { link: 'a' } } ])
358
+ // Add a little more wrapping and try some more
357
359
 
358
- assert(bus.deep_equals(
359
- bus.raw(bus.state).nested,
360
- [ 99, { a: { link: 'a' } } ]
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
- // Now try to go raw within
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
- log('Raw inner is', bus.raw(bus.state.nested[1]))
368
+ verify_no_proxies(bus)
366
369
 
367
- log('Bad raw call is', bus.raw(bus.state.nested[0]))
370
+ // Now try to go raw at the top-level
368
371
 
369
- done()
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
- // Disable the version of proxy_links_through where the user has to explicitly
374
- // traverse links with ()
375
- if (false)
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
- console.log('Gonna deep_quals between:',
410
- bus.raw(bus.state).nested,
411
- [ 99, { a: { link: 'a' } } ])
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "statebus",
3
- "version": "7.1.1",
3
+ "version": "7.2.2",
4
4
  "description": "Synchronize state.",
5
5
  "main": "statebus.js",
6
6
  "scripts": {
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 raw_proxy()
1466
- if (k === 'inspect' || k === 'valueOf' || typeof k === 'symbol')
1467
- return undefined
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
- // We recursively descend through {key: ...} links
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
- return new Proxy(o, {
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 (o, k, v) {
1544
+ set: function (target, k, v) {
1532
1545
  var value = escape_json_to_bus(v)
1533
- o[escape_field_json_to_bus(k)] = value
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
- // if (custom_inspect && k === custom_inspect)
1546
- // return true
1547
- return o.hasOwnProperty(escape_field_json_to_bus(k))
1548
- },
1549
- ownKeys: function () {
1550
- return Object.keys(o).map(unescape_field_bus_to_json)
1551
- },
1552
- getOwnPropertyDescriptor: function (target, key) {
1553
- return { enumerable: true, configurable: true, value: this.get(o, key) }
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
- delete o[escape_field_json_to_bus(k)]
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
- // // The proxy object for links. Disabled for now.
1604
- // // This type of link has to be function called, as link(), to dereference.
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
- // return new Proxy(follow_link, {
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 = (obj) => {
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' && symbols.link in o
2101
- ? {link: o[symbols.link]}
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 = (obj) =>
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