statebus 6.1.28 → 6.1.30
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 +28 -0
- package/package.json +8 -1
- package/server.js +1 -1
- package/statebus.js +114 -33
package/extras/tests.js
CHANGED
|
@@ -967,6 +967,34 @@ test(function braid_proxies (done) {
|
|
|
967
967
|
// Getting a normal property should do a fetch
|
|
968
968
|
})
|
|
969
969
|
|
|
970
|
+
test(function key_patterns (done) {
|
|
971
|
+
bus('path/:pattern/stuff*').to_fetch = function (key, key_parts, t) {
|
|
972
|
+
t.done({ key: key, key_parts, val: 3 })
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
bus.fetch_once('path/foo/stuff(yes:maam,okay)', (o) => {
|
|
976
|
+
assert(o.val === 3)
|
|
977
|
+
assert(o.key_parts.pattern === 'foo')
|
|
978
|
+
done()
|
|
979
|
+
})
|
|
980
|
+
})
|
|
981
|
+
|
|
982
|
+
test(function kson (done) {
|
|
983
|
+
bus('kson_stuff/foo/stuff*').to_fetch = function (key, kson, t) {
|
|
984
|
+
t.done({
|
|
985
|
+
key: key,
|
|
986
|
+
kson: kson
|
|
987
|
+
})
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
bus.fetch_once('kson_stuff/foo/stuff(yes:maam,okay)', (o) => {
|
|
991
|
+
console.log(o)
|
|
992
|
+
assert(o.kson.yes === 'maam')
|
|
993
|
+
assert(o.kson.okay)
|
|
994
|
+
done()
|
|
995
|
+
})
|
|
996
|
+
})
|
|
997
|
+
|
|
970
998
|
test(function only_one (done) {
|
|
971
999
|
bus('only_one/*').to_fetch = function (k) {
|
|
972
1000
|
var id = k[k.length-1]
|
package/package.json
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "statebus",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.30",
|
|
4
4
|
"description": "Synchronize state.",
|
|
5
5
|
"main": "statebus.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "node extras/tests.js"
|
|
8
8
|
},
|
|
9
9
|
"author": "Michael Toomim",
|
|
10
|
+
"files": [
|
|
11
|
+
"statebus.js",
|
|
12
|
+
"client.js",
|
|
13
|
+
"server.js",
|
|
14
|
+
"extras/",
|
|
15
|
+
"readme.md"
|
|
16
|
+
],
|
|
10
17
|
"repository": "invisible-college/statebus",
|
|
11
18
|
"dependencies": {
|
|
12
19
|
"bcrypt-nodejs": "0.0.3",
|
package/server.js
CHANGED
package/statebus.js
CHANGED
|
@@ -263,10 +263,10 @@
|
|
|
263
263
|
var id = 'bus ' + Math.random().toString(36).substring(7)
|
|
264
264
|
bus.toString = function () { return bus.label || id }
|
|
265
265
|
bus.delete_bus = function () {
|
|
266
|
-
// // Forget all
|
|
267
|
-
// for (var i=0; i<
|
|
268
|
-
// console.log('Forgetting', funk_name(
|
|
269
|
-
//
|
|
266
|
+
// // Forget all pattern handlers
|
|
267
|
+
// for (var i=0; i<pattern_handlers.length; i++) {
|
|
268
|
+
// console.log('Forgetting', funk_name(pattern_handlers[i].funk))
|
|
269
|
+
// pattern_handlers[i].funk.forget()
|
|
270
270
|
// }
|
|
271
271
|
|
|
272
272
|
// // Forget all handlers
|
|
@@ -600,12 +600,12 @@
|
|
|
600
600
|
func.defined = func.defined || []
|
|
601
601
|
func.defined.push(
|
|
602
602
|
{as:'handler', bus:bus, method:method, key:key})
|
|
603
|
-
bind(key, method, func, '
|
|
603
|
+
bind(key, method, func, 'pattern')
|
|
604
604
|
},
|
|
605
605
|
get: function () {
|
|
606
606
|
var result = bindings(key, method)
|
|
607
607
|
for (var i=0; i<result.length; i++) result[i] = result[i].func
|
|
608
|
-
result.delete = function (func) { unbind (key, method, func, '
|
|
608
|
+
result.delete = function (func) { unbind (key, method, func, 'pattern') }
|
|
609
609
|
return result
|
|
610
610
|
}
|
|
611
611
|
})
|
|
@@ -628,6 +628,8 @@
|
|
|
628
628
|
case 'key':
|
|
629
629
|
case 'k':
|
|
630
630
|
handler.args['key'] = i; break
|
|
631
|
+
case 'key_parts':
|
|
632
|
+
handler.args['key_parts'] = i; break
|
|
631
633
|
case 'json':
|
|
632
634
|
case 'vars':
|
|
633
635
|
handler.args['vars'] = i; break
|
|
@@ -645,44 +647,71 @@
|
|
|
645
647
|
handler.args['obj'] = i; break
|
|
646
648
|
case 'old':
|
|
647
649
|
handler.args['old'] = i; break
|
|
650
|
+
case 'kson':
|
|
651
|
+
handler.args['kson'] = i; break
|
|
648
652
|
}
|
|
649
653
|
}
|
|
650
654
|
|
|
651
655
|
// The funks attached to each key, maps e.g. 'fetch /point/3' to '/30'
|
|
652
656
|
var handlers = new One_To_Many()
|
|
653
|
-
var
|
|
657
|
+
var pattern_handlers = [] // An array of {pattern, method, funk}
|
|
654
658
|
|
|
655
659
|
// A set of timers, for keys to send forgets on
|
|
656
660
|
var to_be_forgotten = {}
|
|
657
|
-
function bind (
|
|
658
|
-
bogus_check(
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
661
|
+
function bind (pattern, method, func, type) {
|
|
662
|
+
bogus_check(pattern)
|
|
663
|
+
|
|
664
|
+
function pattern_matcher (pattern) {
|
|
665
|
+
var param_names = []
|
|
666
|
+
var regex = new RegExp('^' + pattern.replace(/(?<=^|\/):[^/()]+|\*/g, function (match) {
|
|
667
|
+
// Replace * with .*
|
|
668
|
+
if (match === '*') return '.*'
|
|
669
|
+
|
|
670
|
+
// Replace :foo with ([^/]+), and remember the "foo" name
|
|
671
|
+
param_names.push(match.slice(1))
|
|
672
|
+
return '([^/]+)'
|
|
673
|
+
}) + '$')
|
|
674
|
+
|
|
675
|
+
return function (path) {
|
|
676
|
+
var match = path.match(regex)
|
|
677
|
+
if (!match) return null
|
|
678
|
+
var params = {}
|
|
679
|
+
match.slice(1).forEach(function (val, i) { return params[param_names[i]] = val} )
|
|
680
|
+
return params
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// Add patterns to the list, not the hash
|
|
685
|
+
if (type === 'pattern' && /[:*]/.test(pattern)) // Is it a pattern?
|
|
686
|
+
pattern_handlers.push({pattern: pattern,
|
|
687
|
+
matcher: pattern_matcher(pattern),
|
|
688
|
+
method: method,
|
|
689
|
+
funk: func})
|
|
690
|
+
|
|
691
|
+
// Add simple keys to the hash
|
|
663
692
|
else
|
|
664
|
-
handlers.add(method + ' ' +
|
|
693
|
+
handlers.add(method + ' ' + pattern, funk_key(func))
|
|
665
694
|
|
|
666
695
|
// Now check if the method is a fetch and there's a fetched
|
|
667
696
|
// key in this space, and if so call the handler.
|
|
668
697
|
}
|
|
669
|
-
function unbind (
|
|
670
|
-
bogus_check(
|
|
671
|
-
if (
|
|
672
|
-
// Delete
|
|
673
|
-
for (var i=0; i<
|
|
674
|
-
var handler =
|
|
675
|
-
if (handler.
|
|
698
|
+
function unbind (pattern, method, funk, type) {
|
|
699
|
+
bogus_check(pattern)
|
|
700
|
+
if (type === 'pattern' && /[:*]/.test(pattern)) // Is it a pattern?
|
|
701
|
+
// Delete pattern connection
|
|
702
|
+
for (var i=0; i < pattern_handlers.length; i++) {
|
|
703
|
+
var handler = pattern_handlers[i]
|
|
704
|
+
if (handler.pattern === pattern
|
|
676
705
|
&& handler.method === method
|
|
677
706
|
&& handler.funk === funk) {
|
|
678
707
|
|
|
679
|
-
|
|
680
|
-
i--
|
|
708
|
+
pattern_handlers.splice(i,1) // Splice this element out of the array
|
|
709
|
+
i-- // And decrement the counter while we're looping
|
|
681
710
|
}
|
|
682
711
|
}
|
|
683
712
|
else
|
|
684
713
|
// Delete direct connection
|
|
685
|
-
handlers.delete(method + ' ' +
|
|
714
|
+
handlers.delete(method + ' ' + pattern, funk_key(funk))
|
|
686
715
|
}
|
|
687
716
|
|
|
688
717
|
function bindings(key, method) {
|
|
@@ -707,16 +736,23 @@
|
|
|
707
736
|
}
|
|
708
737
|
}
|
|
709
738
|
|
|
710
|
-
// Now iterate through
|
|
711
|
-
for (var i=0; i <
|
|
712
|
-
handler =
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
&& method === handler.method // And it has the right method
|
|
739
|
+
// Now iterate through patterns
|
|
740
|
+
for (var i=0; i < pattern_handlers.length; i++) {
|
|
741
|
+
handler = pattern_handlers[i]
|
|
742
|
+
var matches = handler.matcher(key)
|
|
743
|
+
if (matches // If the pattern matches
|
|
744
|
+
&& method === handler.method // And it has the right method
|
|
717
745
|
&& !seen[funk_key(handler.funk)]) {
|
|
718
|
-
|
|
719
|
-
|
|
746
|
+
|
|
747
|
+
// Todo: add the match to statebus_binding or result.push
|
|
748
|
+
// below as necessary:
|
|
749
|
+
|
|
750
|
+
handler.funk.statebus_binding = {
|
|
751
|
+
key: handler.pattern,
|
|
752
|
+
method: method,
|
|
753
|
+
params: matches
|
|
754
|
+
}
|
|
755
|
+
result.push({method, key:handler.pattern, func:handler.funk})
|
|
720
756
|
seen[funk_key(handler.funk)] = true
|
|
721
757
|
}
|
|
722
758
|
}
|
|
@@ -795,6 +831,46 @@
|
|
|
795
831
|
return 'Bad JSON "' + r + '" for key ' + key_arg()
|
|
796
832
|
}
|
|
797
833
|
}
|
|
834
|
+
// Parse out query params for URLs in the style /foo/bar(param1,param2:val2).
|
|
835
|
+
// We're currently calling that (param1,param2:val2) part "kson", and presuming
|
|
836
|
+
// that it exists in the * part of the pattern like in /foo/bar*.
|
|
837
|
+
function kson_args () {
|
|
838
|
+
// This code is copied from Raphael Walker's parser.coffee
|
|
839
|
+
function split_once (str, char) {
|
|
840
|
+
var i = str.indexOf(char)
|
|
841
|
+
return i === -1 ? [str, ""] : [str.slice(0, i), str.slice(i + 1)]
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// KSON = Kinda Simple Object Notation
|
|
845
|
+
// but it rhymes with JSON
|
|
846
|
+
function parse_kson (str) {
|
|
847
|
+
// Coffeescript doesn't have object comprehensions :(
|
|
848
|
+
var ret = {}
|
|
849
|
+
|
|
850
|
+
// Now process the string:
|
|
851
|
+
str
|
|
852
|
+
// Pull out the parentheses
|
|
853
|
+
.slice(1, -1)
|
|
854
|
+
// Split by commas. TODO: Allow spaces after commas?
|
|
855
|
+
.split(",")
|
|
856
|
+
// Delete empty parts (this ensures that empty strings
|
|
857
|
+
// will properly result in empty KSON, and allows trailing
|
|
858
|
+
// commas)
|
|
859
|
+
.filter(function (part) { return part.length })
|
|
860
|
+
.forEach(function (part) {
|
|
861
|
+
// If the part has a comma, its a key:value, otherwise
|
|
862
|
+
// it's just a singleton
|
|
863
|
+
var [k, v] = split_once(part, ":")
|
|
864
|
+
|
|
865
|
+
if (v.length === 0) ret[k] = true
|
|
866
|
+
// If the value is itself a KSON object, parse it recursively
|
|
867
|
+
else if (v.startsWith("(")) ret[k] = parse_kson(v)
|
|
868
|
+
else ret[k] = v
|
|
869
|
+
})
|
|
870
|
+
return ret
|
|
871
|
+
}
|
|
872
|
+
return parse_kson(rest_arg())
|
|
873
|
+
}
|
|
798
874
|
var f = reactive(function () {
|
|
799
875
|
|
|
800
876
|
// Initialize transaction
|
|
@@ -861,6 +937,9 @@
|
|
|
861
937
|
switch (k) {
|
|
862
938
|
case 'key':
|
|
863
939
|
args[func.args[k]] = key_arg(); break
|
|
940
|
+
case 'key_parts':
|
|
941
|
+
args[func.args[k]] = func.statebus_binding && func.statebus_binding.params
|
|
942
|
+
break
|
|
864
943
|
case 'rest':
|
|
865
944
|
args[func.args[k]] = rest_arg(); break
|
|
866
945
|
case 'vars':
|
|
@@ -874,6 +953,8 @@
|
|
|
874
953
|
var key = key_arg()
|
|
875
954
|
args[func.args[k]] = bus.cache[key] || (bus.cache[key] = {key:key})
|
|
876
955
|
break
|
|
956
|
+
case 'kson':
|
|
957
|
+
args[func.args[k]] = kson_args(rest_arg()); break
|
|
877
958
|
}
|
|
878
959
|
}
|
|
879
960
|
|