Convert Syndicate/js to use prefix-style trie
This commit is contained in:
parent
7b8b6c5da7
commit
062e4603af
|
@ -122,24 +122,8 @@ var modifiedSourceActions = {
|
|||
var label = maybeLabel.numChildren === 1
|
||||
? maybeLabel.children[0].interval.contents
|
||||
: JSON.stringify(typeName.interval.contents);
|
||||
var fragments = [];
|
||||
fragments.push(
|
||||
'var ' + typeName.asES5 + ' = (function() {',
|
||||
' var $SyndicateMeta$ = {',
|
||||
' label: ' + label + ',',
|
||||
' arguments: ' + JSON.stringify(formals),
|
||||
' };',
|
||||
' return function ' + typeName.asES5 + '(' + formalsRaw.asES5 + ') {',
|
||||
' return {');
|
||||
formals.forEach(function(f) {
|
||||
fragments.push(' ' + JSON.stringify(f) + ': ' + f + ',');
|
||||
});
|
||||
fragments.push(
|
||||
' "$SyndicateMeta$": $SyndicateMeta$',
|
||||
' };',
|
||||
' };',
|
||||
'})();');
|
||||
return fragments.join('\n');
|
||||
return 'var ' + typeName.asES5 + ' = Syndicate.Route.makeStructureConstructor(' +
|
||||
label + ', ' + JSON.stringify(formals) + ');';
|
||||
},
|
||||
|
||||
SendMessageStatement: function(_colons, expr, sc) {
|
||||
|
|
|
@ -1,32 +1,6 @@
|
|||
"use strict";
|
||||
var DOM = (function() {
|
||||
var $SyndicateMeta$ = {
|
||||
label: "DOM",
|
||||
arguments: ["containerSelector","fragmentClass","spec"]
|
||||
};
|
||||
return function DOM(containerSelector, fragmentClass, spec) {
|
||||
return {
|
||||
"containerSelector": containerSelector,
|
||||
"fragmentClass": fragmentClass,
|
||||
"spec": spec,
|
||||
"$SyndicateMeta$": $SyndicateMeta$
|
||||
};
|
||||
};
|
||||
})();
|
||||
var jQuery = (function() {
|
||||
var $SyndicateMeta$ = {
|
||||
label: "jQuery",
|
||||
arguments: ["selector","eventType","event"]
|
||||
};
|
||||
return function jQuery(selector, eventType, event) {
|
||||
return {
|
||||
"selector": selector,
|
||||
"eventType": eventType,
|
||||
"event": event,
|
||||
"$SyndicateMeta$": $SyndicateMeta$
|
||||
};
|
||||
};
|
||||
})();
|
||||
var DOM = Syndicate.DOM.DOM;
|
||||
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
|
||||
|
||||
$(document).ready(function() {
|
||||
new Syndicate.Ground(function () {
|
||||
|
@ -37,7 +11,7 @@ $(document).ready(function() {
|
|||
this.counter = 0;
|
||||
Syndicate.Actor.createFacet()
|
||||
.addAssertion((function() { var _ = Syndicate.__; return Syndicate.Patch.assert(DOM('#button-label','',Syndicate.seal(this.counter)), 0); }))
|
||||
.onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(jQuery('#counter','click',_), 0); }), (function() { var _ = Syndicate.__; return { assertion: jQuery('#counter','click',_), metalevel: 0 }; }), (function() {
|
||||
.onEvent(false, "message", (function() { var _ = Syndicate.__; return Syndicate.Patch.sub(jQueryEvent('#counter','click',_), 0); }), (function() { var _ = Syndicate.__; return { assertion: jQueryEvent('#counter','click',_), metalevel: 0 }; }), (function() {
|
||||
this.counter++;
|
||||
})).completeBuild();
|
||||
});
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
<head>
|
||||
<title>Syndicate: Button Example</title>
|
||||
<meta charset="utf-8">
|
||||
<link href="style.css" rel="stylesheet">
|
||||
<script src="../../third-party/jquery-2.2.0.min.js"></script>
|
||||
<script src="../../dist/syndicatecompiler.js"></script>
|
||||
<script src="../../dist/syndicate.js"></script>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
assertion type DOM(containerSelector, fragmentClass, spec);
|
||||
assertion type jQuery(selector, eventType, event);
|
||||
var DOM = Syndicate.DOM.DOM;
|
||||
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
|
||||
|
||||
$(document).ready(function() {
|
||||
ground dataspace {
|
||||
|
@ -10,7 +10,7 @@ $(document).ready(function() {
|
|||
this.counter = 0;
|
||||
forever {
|
||||
assert DOM('#button-label', '', Syndicate.seal(this.counter));
|
||||
on message jQuery('#counter', 'click', _) {
|
||||
on message jQueryEvent('#counter', 'click', _) {
|
||||
this.counter++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,15 +12,18 @@ $(document).ready(function () {
|
|||
console.log('starting ground boot');
|
||||
|
||||
Syndicate.DOM.spawnDOMDriver();
|
||||
var DOM = Syndicate.DOM.DOM;
|
||||
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
|
||||
|
||||
Dataspace.spawn({
|
||||
boot: function () {
|
||||
return assert(["DOM", "#clicker-holder", "clicker",
|
||||
seal(["button", ["span", [["style", "font-style: italic"]], "Click me!"]])])
|
||||
.andThen(sub(["jQuery", "button.clicker", "click", __]));
|
||||
return assert(DOM("#clicker-holder", "clicker",
|
||||
seal(["button", ["span", [["style", "font-style: italic"]],
|
||||
"Click me!"]])))
|
||||
.andThen(sub(jQueryEvent("button.clicker", "click", __)));
|
||||
},
|
||||
handleEvent: function (e) {
|
||||
if (e.type === "message" && e.message[0] === "jQuery") {
|
||||
if (e.type === "message" && jQueryEvent.isClassOf(e.message)) {
|
||||
Dataspace.send("bump_count");
|
||||
}
|
||||
}
|
||||
|
@ -33,11 +36,11 @@ $(document).ready(function () {
|
|||
return sub("bump_count");
|
||||
},
|
||||
updateState: function () {
|
||||
Dataspace.stateChange(retract(["DOM", __, __, __])
|
||||
.andThen(assert(["DOM", "#counter-holder", "counter",
|
||||
seal(["div",
|
||||
["p", "The current count is: ",
|
||||
this.counter]])])));
|
||||
Dataspace.stateChange(retract(DOM.pattern)
|
||||
.andThen(assert(DOM("#counter-holder", "counter",
|
||||
seal(["div",
|
||||
["p", "The current count is: ",
|
||||
this.counter]])))));
|
||||
},
|
||||
handleEvent: function (e) {
|
||||
if (e.type === "message" && e.message === "bump_count") {
|
||||
|
|
|
@ -6,8 +6,8 @@ assertion type tvAlert(text);
|
|||
assertion type switchAction(on);
|
||||
assertion type componentPresent(name);
|
||||
|
||||
assertion type DOM(containerSelector, fragmentClass, spec);
|
||||
assertion type jQuery(selector, eventType, event);
|
||||
var DOM = Syndicate.DOM.DOM;
|
||||
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// TV
|
||||
|
@ -48,7 +48,7 @@ function spawnRemoteControl() {
|
|||
actor {
|
||||
forever {
|
||||
assert componentPresent('remote control');
|
||||
on message jQuery('#remote-control', 'click', _) {
|
||||
on message jQueryEvent('#remote-control', 'click', _) {
|
||||
:: remoteClick();
|
||||
}
|
||||
}
|
||||
|
@ -92,14 +92,14 @@ function spawnStoveSwitch() {
|
|||
"img/stove-coil-element-" +
|
||||
(this.powerOn ? "hot" : "cold") + ".jpg"]]]));
|
||||
|
||||
on message jQuery('#stove-switch-on', 'click', _) { this.powerOn = true; }
|
||||
on message jQuery('#stove-switch-off', 'click', _) { this.powerOn = false; }
|
||||
on message jQueryEvent('#stove-switch-on', 'click', _) { this.powerOn = true; }
|
||||
on message jQueryEvent('#stove-switch-off', 'click', _) { this.powerOn = false; }
|
||||
|
||||
on message switchAction($newState) {
|
||||
this.powerOn = newState;
|
||||
}
|
||||
} until {
|
||||
case message jQuery('#kill-stove-switch', 'click', _);
|
||||
case message jQueryEvent('#kill-stove-switch', 'click', _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ function spawnPowerDrawMonitor() {
|
|||
this.watts = on ? 1500 : 0;
|
||||
}
|
||||
} until {
|
||||
case message jQuery('#kill-power-draw-monitor', 'click', _);
|
||||
case message jQueryEvent('#kill-power-draw-monitor', 'click', _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,10 +187,10 @@ function spawnFailureMonitor() {
|
|||
function spawnChaosMonkey() {
|
||||
actor {
|
||||
forever {
|
||||
on message jQuery('#spawn-power-draw-monitor', 'click', _) {
|
||||
on message jQueryEvent('#spawn-power-draw-monitor', 'click', _) {
|
||||
spawnPowerDrawMonitor();
|
||||
}
|
||||
on message jQuery('#spawn-stove-switch', 'click', _) {
|
||||
on message jQueryEvent('#spawn-stove-switch', 'click', _) {
|
||||
spawnStoveSwitch();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,10 +14,13 @@ $(document).ready(function () {
|
|||
|
||||
Dataspace.spawn({
|
||||
boot: function () {
|
||||
return sub(['jQuery', '#clicker', 'click', __]);
|
||||
return sub(Syndicate.JQuery.jQueryEvent('#clicker', 'click', __));
|
||||
},
|
||||
handleEvent: function (e) {
|
||||
if (e.type === 'message' && e.message[0] === 'jQuery' && e.message[1] === '#clicker') {
|
||||
if (e.type === 'message'
|
||||
&& Syndicate.JQuery.jQueryEvent.isClassOf(e.message)
|
||||
&& e.message.selector === '#clicker')
|
||||
{
|
||||
var r = $('#result');
|
||||
r.html(Number(r.html()) + 1);
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@ ground dataspace {
|
|||
|
||||
actor {
|
||||
forever {
|
||||
on message $m {
|
||||
console.log("Got message:", m);
|
||||
on message beep($counter) {
|
||||
console.log("beep!", counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
var beep = Syndicate.Route.makeStructureConstructor('beep', ['counter']);
|
||||
|
||||
var G;
|
||||
$(document).ready(function () {
|
||||
var Dataspace = Syndicate.Dataspace;
|
||||
|
@ -15,16 +17,16 @@ $(document).ready(function () {
|
|||
boot: function () {},
|
||||
handleEvent: function (e) {},
|
||||
step: function () {
|
||||
Dataspace.send(["beep", this.counter++]);
|
||||
Dataspace.send(beep(this.counter++));
|
||||
return this.counter <= 10;
|
||||
}
|
||||
});
|
||||
|
||||
Dataspace.spawn({
|
||||
boot: function () { return sub(["beep", __]); },
|
||||
boot: function () { return sub(beep.pattern); },
|
||||
handleEvent: function (e) {
|
||||
if (e.type === 'message') {
|
||||
console.log("beep!", e.message[1]);
|
||||
console.log("beep!", e.message.counter);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// GUI
|
||||
|
||||
assertion type jQuery(selector, eventType, event);
|
||||
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
|
||||
assertion type fieldCommand(detail);
|
||||
assertion type fieldContents(text, pos);
|
||||
assertion type highlight(state);
|
||||
|
@ -34,8 +34,8 @@ function spawnGui() {
|
|||
var text = this.text;
|
||||
var pos = this.pos;
|
||||
var highlight = this.highlightState;
|
||||
var hLeft = highlight ? highlight.get(0) : 0;
|
||||
var hRight = highlight ? highlight.get(1) : 0;
|
||||
var hLeft = highlight ? highlight[0] : 0;
|
||||
var hRight = highlight ? highlight[1] : 0;
|
||||
$("#fieldContents")[0].innerHTML = highlight
|
||||
? piece(text, pos, 0, hLeft, "normal") +
|
||||
piece(text, pos, hLeft, hRight, "highlight") +
|
||||
|
@ -44,7 +44,7 @@ function spawnGui() {
|
|||
};
|
||||
|
||||
forever {
|
||||
on message jQuery("#inputRow", "+keypress", $event) {
|
||||
on message jQueryEvent("#inputRow", "+keypress", $event) {
|
||||
var keycode = event.keyCode;
|
||||
var character = String.fromCharCode(event.charCode);
|
||||
if (keycode === 37 /* left */) {
|
||||
|
@ -79,11 +79,11 @@ function spawnGui() {
|
|||
|
||||
function spawnModel() {
|
||||
actor {
|
||||
this.fieldContents = "initial";
|
||||
this.cursorPos = this.fieldContents.length; /* positions address gaps between characters */
|
||||
this.fieldValue = "initial";
|
||||
this.cursorPos = this.fieldValue.length; /* positions address gaps between characters */
|
||||
|
||||
forever {
|
||||
assert fieldContents(this.fieldContents, this.cursorPos);
|
||||
assert fieldContents(this.fieldValue, this.cursorPos);
|
||||
|
||||
on message fieldCommand("cursorLeft") {
|
||||
this.cursorPos--;
|
||||
|
@ -93,24 +93,24 @@ function spawnModel() {
|
|||
|
||||
on message fieldCommand("cursorRight") {
|
||||
this.cursorPos++;
|
||||
if (this.cursorPos > this.fieldContents.length)
|
||||
this.cursorPos = this.fieldContents.length;
|
||||
if (this.cursorPos > this.fieldValue.length)
|
||||
this.cursorPos = this.fieldValue.length;
|
||||
}
|
||||
|
||||
on message fieldCommand("backspace") {
|
||||
if (this.cursorPos > 0) {
|
||||
this.fieldContents =
|
||||
this.fieldContents.substring(0, this.cursorPos - 1) +
|
||||
this.fieldContents.substring(this.cursorPos);
|
||||
this.fieldValue =
|
||||
this.fieldValue.substring(0, this.cursorPos - 1) +
|
||||
this.fieldValue.substring(this.cursorPos);
|
||||
this.cursorPos--;
|
||||
}
|
||||
}
|
||||
|
||||
on message fieldCommand(["insert", $newText]) {
|
||||
this.fieldContents =
|
||||
this.fieldContents.substring(0, this.cursorPos) +
|
||||
this.fieldValue =
|
||||
this.fieldValue.substring(0, this.cursorPos) +
|
||||
newText +
|
||||
this.fieldContents.substring(this.cursorPos);
|
||||
this.fieldValue.substring(this.cursorPos);
|
||||
this.cursorPos += newText.length;
|
||||
}
|
||||
}
|
||||
|
@ -122,13 +122,13 @@ function spawnModel() {
|
|||
|
||||
function spawnSearch() {
|
||||
actor {
|
||||
this.fieldContents = "";
|
||||
this.fieldValue = "";
|
||||
this.highlight = false;
|
||||
|
||||
this.search = function () {
|
||||
var searchtext = $("#searchBox")[0].value;
|
||||
if (searchtext) {
|
||||
var pos = this.fieldContents.indexOf(searchtext);
|
||||
var pos = this.fieldValue.indexOf(searchtext);
|
||||
this.highlight = (pos !== -1) && [pos, pos + searchtext.length];
|
||||
} else {
|
||||
this.highlight = false;
|
||||
|
@ -138,12 +138,12 @@ function spawnSearch() {
|
|||
forever {
|
||||
assert highlight(this.highlight);
|
||||
|
||||
on message jQuery("#searchBox", "input", $event) {
|
||||
on message jQueryEvent("#searchBox", "input", $event) {
|
||||
this.search();
|
||||
}
|
||||
|
||||
on asserted fieldContents($text, _) {
|
||||
this.fieldContents = text;
|
||||
this.fieldValue = text;
|
||||
this.search();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,11 @@ var Patch = Syndicate.Patch;
|
|||
var __ = Syndicate.__;
|
||||
var _$ = Syndicate._$;
|
||||
|
||||
var jQueryEvent = Syndicate.JQuery.jQueryEvent;
|
||||
var fieldContents = Route.makeStructureConstructor('fieldContents', ['text', 'pos']);
|
||||
var highlight = Route.makeStructureConstructor('highlight', ['state']);
|
||||
var fieldCommand = Route.makeStructureConstructor('fieldCommand', ['detail']);
|
||||
|
||||
function escapeText(text) {
|
||||
text = text.replace(/&/g, '&');
|
||||
text = text.replace(/</g, '<');
|
||||
|
@ -31,30 +36,30 @@ function spawnGui() {
|
|||
highlight: { state: false },
|
||||
|
||||
boot: function () {
|
||||
return Patch.sub(["jQuery", "#inputRow", "+keypress", __])
|
||||
.andThen(Patch.sub(["fieldContents", __, __]))
|
||||
.andThen(Patch.sub(["highlight", __]));
|
||||
return Patch.sub(jQueryEvent("#inputRow", "+keypress", __))
|
||||
.andThen(Patch.sub(fieldContents.pattern))
|
||||
.andThen(Patch.sub(highlight.pattern));
|
||||
},
|
||||
|
||||
fieldContentsProjection: Route.compileProjection(["fieldContents", _$("text"), _$("pos")]),
|
||||
highlightProjection: Route.compileProjection(["highlight", _$("state")]),
|
||||
fieldContentsProjection: fieldContents(_$("text"), _$("pos")),
|
||||
highlightProjection: highlight(_$("state")),
|
||||
handleEvent: function (e) {
|
||||
var self = this;
|
||||
switch (e.type) {
|
||||
case "message":
|
||||
var event = e.message[3];
|
||||
var event = e.message.eventValue;
|
||||
var keycode = event.keyCode;
|
||||
var character = String.fromCharCode(event.charCode);
|
||||
if (keycode === 37 /* left */) {
|
||||
Dataspace.send(["fieldCommand", "cursorLeft"]);
|
||||
Dataspace.send(fieldCommand("cursorLeft"));
|
||||
} else if (keycode === 39 /* right */) {
|
||||
Dataspace.send(["fieldCommand", "cursorRight"]);
|
||||
Dataspace.send(fieldCommand("cursorRight"));
|
||||
} else if (keycode === 9 /* tab */) {
|
||||
// ignore
|
||||
} else if (keycode === 8 /* backspace */) {
|
||||
Dataspace.send(["fieldCommand", "backspace"]);
|
||||
Dataspace.send(fieldCommand("backspace"));
|
||||
} else if (character) {
|
||||
Dataspace.send(["fieldCommand", ["insert", character]]);
|
||||
Dataspace.send(fieldCommand(["insert", character]));
|
||||
}
|
||||
break;
|
||||
case "stateChange":
|
||||
|
@ -73,8 +78,8 @@ function spawnGui() {
|
|||
var text = this.field ? this.field.text : "";
|
||||
var pos = this.field ? this.field.pos : 0;
|
||||
var highlight = this.highlight ? this.highlight.state : false;
|
||||
var hLeft = highlight ? highlight.get(0) : 0;
|
||||
var hRight = highlight ? highlight.get(1) : 0;
|
||||
var hLeft = highlight ? highlight[0] : 0;
|
||||
var hRight = highlight ? highlight[1] : 0;
|
||||
$("#fieldContents")[0].innerHTML = highlight
|
||||
? piece(text, pos, 0, hLeft, "normal") +
|
||||
piece(text, pos, hLeft, hRight, "highlight") +
|
||||
|
@ -90,36 +95,36 @@ function spawnGui() {
|
|||
function spawnModel() {
|
||||
var initialContents = "initial";
|
||||
Dataspace.spawn({
|
||||
fieldContents: initialContents,
|
||||
fieldValue: initialContents,
|
||||
cursorPos: initialContents.length, /* positions address gaps between characters */
|
||||
|
||||
boot: function () {
|
||||
this.publishState();
|
||||
return Patch.sub(["fieldCommand", __]);
|
||||
return Patch.sub(fieldCommand.pattern);
|
||||
},
|
||||
|
||||
handleEvent: function (e) {
|
||||
if (e.type === "message" && e.message[0] === "fieldCommand") {
|
||||
var command = e.message[1];
|
||||
if (e.type === "message" && fieldCommand.isClassOf(e.message)) {
|
||||
var command = e.message.detail;
|
||||
if (command === "cursorLeft") {
|
||||
this.cursorPos--;
|
||||
if (this.cursorPos < 0)
|
||||
this.cursorPos = 0;
|
||||
} else if (command === "cursorRight") {
|
||||
this.cursorPos++;
|
||||
if (this.cursorPos > this.fieldContents.length)
|
||||
this.cursorPos = this.fieldContents.length;
|
||||
if (this.cursorPos > this.fieldValue.length)
|
||||
this.cursorPos = this.fieldValue.length;
|
||||
} else if (command === "backspace" && this.cursorPos > 0) {
|
||||
this.fieldContents =
|
||||
this.fieldContents.substring(0, this.cursorPos - 1) +
|
||||
this.fieldContents.substring(this.cursorPos);
|
||||
this.fieldValue =
|
||||
this.fieldValue.substring(0, this.cursorPos - 1) +
|
||||
this.fieldValue.substring(this.cursorPos);
|
||||
this.cursorPos--;
|
||||
} else if (command.constructor === Array && command[0] === "insert") {
|
||||
var newText = command[1];
|
||||
this.fieldContents =
|
||||
this.fieldContents.substring(0, this.cursorPos) +
|
||||
this.fieldValue =
|
||||
this.fieldValue.substring(0, this.cursorPos) +
|
||||
newText +
|
||||
this.fieldContents.substring(this.cursorPos);
|
||||
this.fieldValue.substring(this.cursorPos);
|
||||
this.cursorPos += newText.length;
|
||||
}
|
||||
this.publishState();
|
||||
|
@ -128,8 +133,8 @@ function spawnModel() {
|
|||
|
||||
publishState: function () {
|
||||
Dataspace.stateChange(
|
||||
Patch.retract(["fieldContents", __, __])
|
||||
.andThen(Patch.assert(["fieldContents", this.fieldContents, this.cursorPos])));
|
||||
Patch.retract(fieldContents.pattern)
|
||||
.andThen(Patch.assert(fieldContents(this.fieldValue, this.cursorPos))));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -139,24 +144,24 @@ function spawnModel() {
|
|||
|
||||
function spawnSearch() {
|
||||
Dataspace.spawn({
|
||||
fieldContents: "",
|
||||
fieldValue: "",
|
||||
highlight: false,
|
||||
|
||||
boot: function () {
|
||||
this.publishState();
|
||||
return Patch.sub(["jQuery", "#searchBox", "input", __])
|
||||
.andThen(Patch.sub(["fieldContents", __, __]));
|
||||
return Patch.sub(jQueryEvent("#searchBox", "input", __))
|
||||
.andThen(Patch.sub(fieldContents.pattern));
|
||||
},
|
||||
|
||||
fieldContentsProjection: Route.compileProjection(["fieldContents", _$("text"), _$("pos")]),
|
||||
fieldContentsProjection: fieldContents(_$("text"), _$("pos")),
|
||||
handleEvent: function (e) {
|
||||
var self = this;
|
||||
if (e.type === "message" && e.message[0] === "jQuery") {
|
||||
if (jQueryEvent.isClassOf(e.message)) {
|
||||
this.search();
|
||||
}
|
||||
if (e.type === "stateChange") {
|
||||
Route.projectObjects(e.patch.added, this.fieldContentsProjection).forEach(function (c) {
|
||||
self.fieldContents = c.text;
|
||||
self.fieldValue = c.text;
|
||||
});
|
||||
this.search();
|
||||
}
|
||||
|
@ -164,15 +169,15 @@ function spawnSearch() {
|
|||
|
||||
publishState: function () {
|
||||
Dataspace.stateChange(
|
||||
Patch.retract(["highlight", __])
|
||||
.andThen(Patch.assert(["highlight", this.highlight])));
|
||||
Patch.retract(highlight.pattern)
|
||||
.andThen(Patch.assert(highlight(this.highlight))));
|
||||
},
|
||||
|
||||
search: function () {
|
||||
var searchtext = $("#searchBox")[0].value;
|
||||
var oldHighlight = this.highlight;
|
||||
if (searchtext) {
|
||||
var pos = this.fieldContents.indexOf(searchtext);
|
||||
var pos = this.fieldValue.indexOf(searchtext);
|
||||
this.highlight = (pos !== -1) && [pos, pos + searchtext.length];
|
||||
} else {
|
||||
this.highlight = false;
|
||||
|
|
|
@ -5,7 +5,7 @@ var Dataspace = require('./dataspace.js').Dataspace;
|
|||
var Route = require('./route.js');
|
||||
var Patch = require('./patch.js');
|
||||
|
||||
var $Ack = new Route.$Special('ack');
|
||||
var ack = Route.makeStructureConstructor('ack', ['id']);
|
||||
|
||||
function Ack(metaLevel, id) {
|
||||
this.metaLevel = metaLevel || 0;
|
||||
|
@ -14,19 +14,19 @@ function Ack(metaLevel, id) {
|
|||
}
|
||||
|
||||
Ack.prototype.arm = function () {
|
||||
Dataspace.stateChange(Patch.sub([$Ack, this.id], this.metaLevel));
|
||||
Dataspace.send([$Ack, this.id], this.metaLevel);
|
||||
Dataspace.stateChange(Patch.sub(ack(this.id), this.metaLevel));
|
||||
Dataspace.send(ack(this.id), this.metaLevel);
|
||||
};
|
||||
|
||||
Ack.prototype.disarm = function () {
|
||||
Dataspace.stateChange(Patch.unsub([$Ack, this.id], this.metaLevel));
|
||||
Dataspace.stateChange(Patch.unsub(ack(this.id), this.metaLevel));
|
||||
};
|
||||
|
||||
Ack.prototype.check = function (e) {
|
||||
if (!this.done) {
|
||||
if (e.type === 'message') {
|
||||
var m = Patch.stripAtMeta(e.message, this.metaLevel);
|
||||
if (m && m[0] === $Ack && m[1] === this.id) {
|
||||
if (ack.isClassOf(m) && m.id === this.id) {
|
||||
this.disarm();
|
||||
this.done = true;
|
||||
}
|
||||
|
@ -37,5 +37,5 @@ Ack.prototype.check = function (e) {
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module.exports.$Ack = $Ack;
|
||||
module.exports.ack = ack;
|
||||
module.exports.Ack = Ack;
|
||||
|
|
|
@ -94,11 +94,10 @@ Facet.prototype.onEvent = function(isTerminal, eventType, subscriptionFn, projec
|
|||
if (e.type === 'stateChange') {
|
||||
var proj = projectionFn.call(facet.actor.state);
|
||||
var spec = Patch.prependAtMeta(proj.assertion, proj.metalevel);
|
||||
var compiledSpec = Route.compileProjection(spec);
|
||||
var objects = Route.projectObjects(eventType === 'asserted'
|
||||
? e.patch.added
|
||||
: e.patch.removed,
|
||||
compiledSpec);
|
||||
spec);
|
||||
if (objects && objects.size > 0) {
|
||||
// console.log(objects.toArray());
|
||||
if (isTerminal) { facet.terminate(); }
|
||||
|
|
|
@ -229,11 +229,11 @@ Dataspace.prototype.interpretAction = function (pid, action) {
|
|||
return true;
|
||||
|
||||
case 'message':
|
||||
if (Patch.isObserve(action.message)) {
|
||||
if (Patch.observe.isClassOf(action.message)) {
|
||||
console.warn('Process ' + pid + ' send message containing query', action.message);
|
||||
}
|
||||
if (pid !== 'meta' && Patch.isAtMeta(action.message)) {
|
||||
Dataspace.send(action.message[1]);
|
||||
if (pid !== 'meta' && Patch.atMeta.isClassOf(action.message)) {
|
||||
Dataspace.send(action.message.assertion);
|
||||
} else {
|
||||
this.mux.routeMessage(action.message).forEach(function (pid) {
|
||||
self.deliverEvent(pid, action);
|
||||
|
|
|
@ -20,8 +20,10 @@ function DemandMatcher(demandSpec, supplySpec, options) {
|
|||
this.supplySpec = supplySpec;
|
||||
this.demandPattern = Route.projectionToPattern(demandSpec);
|
||||
this.supplyPattern = Route.projectionToPattern(supplySpec);
|
||||
this.demandProjection = Route.compileProjection(Patch.prependAtMeta(demandSpec, this.metaLevel));
|
||||
this.supplyProjection = Route.compileProjection(Patch.prependAtMeta(supplySpec, this.metaLevel));
|
||||
this.demandProjection = Patch.prependAtMeta(demandSpec, this.metaLevel);
|
||||
this.supplyProjection = Patch.prependAtMeta(supplySpec, this.metaLevel);
|
||||
this.demandProjectionNames = Route.projectionNames(this.demandProjection);
|
||||
this.supplyProjectionNames = Route.projectionNames(this.supplyProjection);
|
||||
this.currentDemand = Immutable.Set();
|
||||
this.currentSupply = Immutable.Set();
|
||||
}
|
||||
|
@ -40,10 +42,12 @@ DemandMatcher.prototype.handleEvent = function (e) {
|
|||
DemandMatcher.prototype.handlePatch = function (p) {
|
||||
var self = this;
|
||||
|
||||
var addedDemand = Route.trieKeys(Route.project(p.added, self.demandProjection));
|
||||
var removedDemand = Route.trieKeys(Route.project(p.removed, self.demandProjection));
|
||||
var addedSupply = Route.trieKeys(Route.project(p.added, self.supplyProjection));
|
||||
var removedSupply = Route.trieKeys(Route.project(p.removed, self.supplyProjection));
|
||||
var dN = self.demandProjectionNames.length;
|
||||
var sN = self.supplyProjectionNames.length;
|
||||
var addedDemand = Route.trieKeys(Route.project(p.added, self.demandProjection), dN);
|
||||
var removedDemand = Route.trieKeys(Route.project(p.removed, self.demandProjection), dN);
|
||||
var addedSupply = Route.trieKeys(Route.project(p.added, self.supplyProjection), sN);
|
||||
var removedSupply = Route.trieKeys(Route.project(p.removed, self.supplyProjection), sN);
|
||||
|
||||
if (addedDemand === null) {
|
||||
throw new Error("Syndicate: wildcard demand detected:\n" +
|
||||
|
@ -61,12 +65,12 @@ DemandMatcher.prototype.handlePatch = function (p) {
|
|||
|
||||
removedSupply.forEach(function (captures) {
|
||||
if (self.currentDemand.has(captures)) {
|
||||
self.onSupplyDecrease(Route.captureToObject(captures, self.supplyProjection));
|
||||
self.onSupplyDecrease(Route.captureToObject(captures, self.supplyProjectionNames));
|
||||
}
|
||||
});
|
||||
addedDemand.forEach(function (captures) {
|
||||
if (!self.currentSupply.has(captures)) {
|
||||
self.onDemandIncrease(Route.captureToObject(captures, self.demandProjection));
|
||||
self.onDemandIncrease(Route.captureToObject(captures, self.demandProjectionNames));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// DOM fragment display driver
|
||||
var Patch = require("./patch.js");
|
||||
var DemandMatcher = require('./demand-matcher.js').DemandMatcher;
|
||||
var Route = require('./route.js');
|
||||
var Ack = require('./ack.js').Ack;
|
||||
var Seal = require('./seal.js').Seal;
|
||||
|
||||
|
@ -9,27 +10,25 @@ var Dataspace = Dataspace_.Dataspace;
|
|||
var __ = Dataspace_.__;
|
||||
var _$ = Dataspace_._$;
|
||||
|
||||
var DOM = Route.makeStructureConstructor('DOM', ['selector', 'fragmentClass', 'fragmentSpec']);
|
||||
|
||||
function spawnDOMDriver(domWrapFunction, jQueryWrapFunction) {
|
||||
domWrapFunction = domWrapFunction || defaultWrapFunction;
|
||||
domWrapFunction = domWrapFunction || DOM;
|
||||
var spec = domWrapFunction(_$('selector'), _$('fragmentClass'), _$('fragmentSpec'));
|
||||
Dataspace.spawn(
|
||||
new DemandMatcher(spec,
|
||||
Patch.advertise(spec),
|
||||
Patch.advertise(spec), // TODO: are the embedded captures problematic here? If not, why not?
|
||||
{
|
||||
onDemandIncrease: function (c) {
|
||||
Dataspace.spawn(new DOMFragment(c.selector,
|
||||
c.fragmentClass,
|
||||
c.fragmentSpec,
|
||||
domWrapFunction,
|
||||
jQueryWrapFunction));
|
||||
c.fragmentClass,
|
||||
c.fragmentSpec,
|
||||
domWrapFunction,
|
||||
jQueryWrapFunction));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
function defaultWrapFunction(selector, fragmentClass, fragmentSpec) {
|
||||
return ["DOM", selector, fragmentClass, fragmentSpec];
|
||||
}
|
||||
|
||||
function DOMFragment(selector, fragmentClass, fragmentSpec, domWrapFunction, jQueryWrapFunction) {
|
||||
this.selector = selector;
|
||||
this.fragmentClass = fragmentClass;
|
||||
|
@ -138,4 +137,4 @@ DOMFragment.prototype.buildNodes = function () {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module.exports.spawnDOMDriver = spawnDOMDriver;
|
||||
module.exports.defaultWrapFunction = defaultWrapFunction;
|
||||
module.exports.DOM = DOM;
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
// JQuery event driver
|
||||
var Patch = require("./patch.js");
|
||||
var DemandMatcher = require('./demand-matcher.js').DemandMatcher;
|
||||
var Route = require('./route.js');
|
||||
|
||||
var Dataspace_ = require("./dataspace.js");
|
||||
var Dataspace = Dataspace_.Dataspace;
|
||||
var __ = Dataspace_.__;
|
||||
var _$ = Dataspace_._$;
|
||||
|
||||
var jQueryEvent = Route.makeStructureConstructor('jQueryEvent', ['selector', 'eventName', 'eventValue']);
|
||||
|
||||
function spawnJQueryDriver(baseSelector, metaLevel, wrapFunction) {
|
||||
metaLevel = metaLevel || 0;
|
||||
wrapFunction = wrapFunction || defaultWrapFunction;
|
||||
wrapFunction = wrapFunction || jQueryEvent;
|
||||
Dataspace.spawn(
|
||||
new DemandMatcher(Patch.observe(wrapFunction(_$('selector'), _$('eventName'), __)),
|
||||
Patch.advertise(wrapFunction(_$('selector'), _$('eventName'), __)),
|
||||
|
@ -17,25 +20,21 @@ function spawnJQueryDriver(baseSelector, metaLevel, wrapFunction) {
|
|||
metaLevel: metaLevel,
|
||||
onDemandIncrease: function (c) {
|
||||
Dataspace.spawn(new JQueryEventRouter(baseSelector,
|
||||
c.selector,
|
||||
c.eventName,
|
||||
metaLevel,
|
||||
wrapFunction));
|
||||
c.selector,
|
||||
c.eventName,
|
||||
metaLevel,
|
||||
wrapFunction));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
function defaultWrapFunction(selector, eventName, eventValue) {
|
||||
return ["jQuery", selector, eventName, eventValue];
|
||||
}
|
||||
|
||||
function JQueryEventRouter(baseSelector, selector, eventName, metaLevel, wrapFunction) {
|
||||
var self = this;
|
||||
this.baseSelector = baseSelector || null;
|
||||
this.selector = selector;
|
||||
this.eventName = eventName;
|
||||
this.metaLevel = metaLevel || 0;
|
||||
this.wrapFunction = wrapFunction || defaultWrapFunction;
|
||||
this.wrapFunction = wrapFunction || jQueryEvent;
|
||||
this.preventDefault = (this.eventName.charAt(0) !== "+");
|
||||
this.handler =
|
||||
Dataspace.wrap(function (e) {
|
||||
|
@ -88,4 +87,4 @@ function simplifyDOMEvent(e) {
|
|||
|
||||
module.exports.spawnJQueryDriver = spawnJQueryDriver;
|
||||
module.exports.simplifyDOMEvent = simplifyDOMEvent;
|
||||
module.exports.defaultWrapFunction = defaultWrapFunction;
|
||||
module.exports.jQueryEvent = jQueryEvent;
|
||||
|
|
|
@ -12,7 +12,7 @@ module.exports.Route = require("./route.js");
|
|||
copyKeys(['__', '_$', '$Capture', '$Special',
|
||||
'is_emptyTrie', 'emptyTrie',
|
||||
'embeddedTrie', 'compilePattern',
|
||||
'compileProjection', 'project', 'projectObjects',
|
||||
'project', 'projectObjects',
|
||||
'prettyTrie'],
|
||||
module.exports,
|
||||
module.exports.Route);
|
||||
|
@ -35,7 +35,6 @@ module.exports.Reflect = require("./reflect.js");
|
|||
module.exports.Patch = require("./patch.js");
|
||||
copyKeys(['emptyPatch',
|
||||
'observe', 'atMeta', 'advertise',
|
||||
'isObserve', 'isAtMeta', 'isAdvertise',
|
||||
'assert', 'retract', 'sub', 'unsub', 'pub', 'unpub',
|
||||
'patchSeq'],
|
||||
module.exports,
|
||||
|
|
|
@ -45,12 +45,12 @@ Mux.prototype.updateStream = function (pid, unclampedPatch) {
|
|||
};
|
||||
|
||||
var atMetaEverything = Route.compilePattern(true, Patch.atMeta(Route.__));
|
||||
var atMetaBranchKeys = Immutable.List([Route.SOA, Patch.$AtMeta]);
|
||||
var onlyMeta = Immutable.Set.of("meta");
|
||||
var atMetaBranchKeys = Immutable.List([[Patch.atMeta.meta.arguments.length, Patch.atMeta.meta]]);
|
||||
var onlyMeta = Route.trieSuccess(Immutable.Set.of("meta"));
|
||||
|
||||
function echoCancelledTrie(t) {
|
||||
return Route.subtract(t, atMetaEverything, function (v1, v2) {
|
||||
return v1.has("meta") ? onlyMeta : null;
|
||||
return v1.has("meta") ? onlyMeta : Route.emptyTrie;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -95,12 +95,10 @@ function computeEvents(oldMux, newMux, updateStreamResult) {
|
|||
|
||||
function computeAffectedPids(routingTable, delta) {
|
||||
var cover = Route._union(delta.added, delta.removed);
|
||||
routingTable = Route.trieStep(routingTable, Route.SOA);
|
||||
routingTable = Route.trieStep(routingTable, Patch.$Observe);
|
||||
routingTable =
|
||||
Route.trieStep(routingTable, Patch.observe.meta.arguments.length, Patch.observe.meta);
|
||||
return Route.matchTrie(cover, routingTable, Immutable.Set(),
|
||||
function (v, r, acc) {
|
||||
return acc.union(Route.trieStep(r, Route.EOA).value);
|
||||
});
|
||||
function (v1, v2, acc) { return acc.union(v2); });
|
||||
}
|
||||
|
||||
Mux.prototype.routeMessage = function (body) {
|
||||
|
|
|
@ -13,18 +13,11 @@ function Patch(added, removed) {
|
|||
|
||||
var emptyPatch = new Patch(Route.emptyTrie, Route.emptyTrie);
|
||||
var removeEverythingPatch = new Patch(Route.emptyTrie, Route.compilePattern(true, __));
|
||||
var trueLabel = Route.trieSuccess(true);
|
||||
|
||||
var $Observe = new Route.$Special("$Observe");
|
||||
var $AtMeta = new Route.$Special("$AtMeta");
|
||||
var $Advertise = new Route.$Special("$Advertise");
|
||||
|
||||
function observe(p) { return [$Observe, p]; }
|
||||
function atMeta(p) { return [$AtMeta, p]; }
|
||||
function advertise(p) { return [$Advertise, p]; }
|
||||
|
||||
function isObserve(p) { return p[0] === $Observe; }
|
||||
function isAtMeta(p) { return p[0] === $AtMeta; }
|
||||
function isAdvertise(p) { return p[0] === $Advertise; }
|
||||
var observe = Route.makeStructureConstructor('observe', ['assertion']);
|
||||
var atMeta = Route.makeStructureConstructor('atMeta', ['assertion']);
|
||||
var advertise = Route.makeStructureConstructor('advertise', ['assertion']);
|
||||
|
||||
function prependAtMeta(p, level) {
|
||||
while (level--) {
|
||||
|
@ -35,8 +28,8 @@ function prependAtMeta(p, level) {
|
|||
|
||||
function stripAtMeta(p, level) {
|
||||
while (level--) {
|
||||
if (p.length === 2 && p[0] === $AtMeta) {
|
||||
p = p[1];
|
||||
if (atMeta.isClassOf(p)) {
|
||||
p = p.assertion;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -115,7 +108,7 @@ Patch.prototype.lift = function () {
|
|||
Route.compilePattern(true, atMeta(Route.embeddedTrie(this.removed))));
|
||||
};
|
||||
|
||||
var atMetaProj = Route.compileProjection(atMeta(_$));
|
||||
var atMetaProj = atMeta(_$);
|
||||
Patch.prototype.drop = function () {
|
||||
return new Patch(Route.project(this.added, atMetaProj),
|
||||
Route.project(this.removed, atMetaProj));
|
||||
|
@ -132,8 +125,9 @@ Patch.prototype.label = function (labelValue) {
|
|||
};
|
||||
|
||||
Patch.prototype.limit = function (bound) {
|
||||
return new Patch(Route.subtract(this.added, bound, function (v1, v2) { return null; }),
|
||||
Route.intersect(this.removed, bound, function (v1, v2) { return v1; }));
|
||||
return new Patch(Route.subtract(this.added, bound, function (v1, v2) { return Route.emptyTrie; }),
|
||||
Route.intersect(this.removed, bound,
|
||||
function (v1, v2) { return Route.trieSuccess(v1); }));
|
||||
};
|
||||
|
||||
var metaLabelSet = Immutable.Set(["meta"]);
|
||||
|
@ -143,20 +137,20 @@ Patch.prototype.computeAggregate = function (label, base, removeMeta /* optional
|
|||
|
||||
function addCombiner(v1, v2) {
|
||||
if (removeMeta && Immutable.is(v2, metaLabelSet)) {
|
||||
return v1;
|
||||
return Route.trieSuccess(v1);
|
||||
} else {
|
||||
return null;
|
||||
return Route.emptyTrie;
|
||||
}
|
||||
}
|
||||
|
||||
function removeCombiner(v1, v2) {
|
||||
if (v2.size === 1) {
|
||||
return v1;
|
||||
return Route.trieSuccess(v1);
|
||||
} else {
|
||||
if (removeMeta && v2.size === 2 && v2.has("meta")) {
|
||||
return v1;
|
||||
return Route.trieSuccess(v1);
|
||||
} else {
|
||||
return null;
|
||||
return Route.emptyTrie;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,9 +161,11 @@ Patch.prototype.applyTo = function (base) {
|
|||
};
|
||||
|
||||
Patch.prototype.updateInterests = function (base) {
|
||||
return Route._union(Route.subtract(base, this.removed, function (v1, v2) { return null; }),
|
||||
return Route._union(Route.subtract(base,
|
||||
this.removed,
|
||||
function (v1, v2) { return Route.emptyTrie; }),
|
||||
this.added,
|
||||
function (v1, v2) { return true; });
|
||||
function (v1, v2) { return trueLabel; });
|
||||
};
|
||||
|
||||
Patch.prototype.unapplyTo = function (base) {
|
||||
|
@ -180,9 +176,9 @@ Patch.prototype.andThen = function (nextPatch) {
|
|||
return new Patch(nextPatch.updateInterests(this.added),
|
||||
Route._union(Route.subtract(this.removed,
|
||||
nextPatch.added,
|
||||
function (v1, v2) { return null; }),
|
||||
function (v1, v2) { return Route.emptyTrie; }),
|
||||
nextPatch.removed,
|
||||
function (v1, v2) { return true; }));
|
||||
function (v1, v2) { return trueLabel; }));
|
||||
};
|
||||
|
||||
function patchSeq(/* patch, patch, ... */) {
|
||||
|
@ -199,11 +195,8 @@ function computePatch(oldBase, newBase) {
|
|||
}
|
||||
|
||||
function biasedIntersection(object, subject) {
|
||||
subject = Route.trieStep(subject, Route.SOA);
|
||||
subject = Route.trieStep(subject, $Observe);
|
||||
return Route.intersect(object, subject,
|
||||
function (v1, v2) { return true; },
|
||||
function (v, r) { return Route.trieStep(r, Route.EOA); });
|
||||
subject = Route.trieStep(subject, observe.meta.arguments.length, observe.meta);
|
||||
return Route.intersect(object, subject, function (v1, v2) { return Route.trieSuccess(v1); });
|
||||
}
|
||||
|
||||
Patch.prototype.viewFrom = function (interests) {
|
||||
|
@ -240,15 +233,9 @@ module.exports.Patch = Patch;
|
|||
module.exports.emptyPatch = emptyPatch;
|
||||
module.exports.removeEverythingPatch = removeEverythingPatch;
|
||||
|
||||
module.exports.$Observe = $Observe;
|
||||
module.exports.$AtMeta = $AtMeta;
|
||||
module.exports.$Advertise = $Advertise;
|
||||
module.exports.observe = observe;
|
||||
module.exports.atMeta = atMeta;
|
||||
module.exports.advertise = advertise;
|
||||
module.exports.isObserve = isObserve;
|
||||
module.exports.isAtMeta = isAtMeta;
|
||||
module.exports.isAdvertise = isAdvertise;
|
||||
|
||||
module.exports.prependAtMeta = prependAtMeta;
|
||||
module.exports.stripAtMeta = stripAtMeta;
|
||||
|
|
1275
js/src/route.js
1275
js/src/route.js
File diff suppressed because it is too large
Load Diff
|
@ -32,13 +32,13 @@ describe('mux stream', function () {
|
|||
describe('addition', function () {
|
||||
it('should union interests appropriately', function () {
|
||||
var m = getM();
|
||||
checkPrettyTrie(m.routingTable, [' 1 >{[0]}',
|
||||
' 2 >{[0,1]}',
|
||||
' 3 >{[1]}']);
|
||||
checkPrettyTrie(m.interestsOf(0), [' 1 >{[0]}',
|
||||
' 2 >{[0]}']);
|
||||
checkPrettyTrie(m.interestsOf(1), [' 2 >{[1]}',
|
||||
' 3 >{[1]}']);
|
||||
checkPrettyTrie(m.routingTable, [' 1 {[0]}',
|
||||
' 2 {[0,1]}',
|
||||
' 3 {[1]}']);
|
||||
checkPrettyTrie(m.interestsOf(0), [' 1 {[0]}',
|
||||
' 2 {[0]}']);
|
||||
checkPrettyTrie(m.interestsOf(1), [' 2 {[1]}',
|
||||
' 3 {[1]}']);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -51,30 +51,30 @@ describe('mux stream', function () {
|
|||
.andThen(Patch.assert(4))
|
||||
.andThen(Patch.retract(99));
|
||||
checkPrettyPatch(rawPatch,
|
||||
[' 1 >{true}',
|
||||
' 4 >{true}'],
|
||||
[' 2 >{true}',
|
||||
' 3 >{true}',
|
||||
' 99 >{true}']);
|
||||
[' 1 {true}',
|
||||
' 4 {true}'],
|
||||
[' 2 {true}',
|
||||
' 3 {true}',
|
||||
' 99 {true}']);
|
||||
|
||||
var m = getM();
|
||||
var updateStreamResult = m.updateStream(1, rawPatch);
|
||||
expect(updateStreamResult.pid).to.equal(1);
|
||||
checkPrettyPatch(updateStreamResult.delta,
|
||||
[' 1 >{[1]}',
|
||||
' 4 >{[1]}'],
|
||||
[' 2 >{[1]}',
|
||||
' 3 >{[1]}']);
|
||||
checkPrettyTrie(m.routingTable, [' 1 >{[0,1]}',
|
||||
' 2 >{[0]}',
|
||||
' 4 >{[1]}']);
|
||||
checkPrettyTrie(m.interestsOf(0), [' 1 >{[0]}',
|
||||
' 2 >{[0]}']);
|
||||
checkPrettyTrie(m.interestsOf(1), [' 1 >{[1]}',
|
||||
' 4 >{[1]}']);
|
||||
[' 1 {[1]}',
|
||||
' 4 {[1]}'],
|
||||
[' 2 {[1]}',
|
||||
' 3 {[1]}']);
|
||||
checkPrettyTrie(m.routingTable, [' 1 {[0,1]}',
|
||||
' 2 {[0]}',
|
||||
' 4 {[1]}']);
|
||||
checkPrettyTrie(m.interestsOf(0), [' 1 {[0]}',
|
||||
' 2 {[0]}']);
|
||||
checkPrettyTrie(m.interestsOf(1), [' 1 {[1]}',
|
||||
' 4 {[1]}']);
|
||||
checkPrettyPatch(updateStreamResult.deltaAggregate,
|
||||
[' 4 >{[1]}'],
|
||||
[' 3 >{[1]}']);
|
||||
[' 4 {[1]}'],
|
||||
[' 3 {[1]}']);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -84,17 +84,17 @@ describe('mux stream', function () {
|
|||
var updateStreamResult = m.removeStream(1);
|
||||
expect(updateStreamResult.pid).to.equal(1);
|
||||
checkPrettyPatch(updateStreamResult.delta,
|
||||
['::: nothing'],
|
||||
[' 2 >{[1]}',
|
||||
' 3 >{[1]}']);
|
||||
checkPrettyTrie(m.routingTable, [' 1 >{[0]}',
|
||||
' 2 >{[0]}']);
|
||||
checkPrettyTrie(m.interestsOf(0), [' 1 >{[0]}',
|
||||
' 2 >{[0]}']);
|
||||
checkPrettyTrie(m.interestsOf(1), ['::: nothing']);
|
||||
[' ::: nothing'],
|
||||
[' 2 {[1]}',
|
||||
' 3 {[1]}']);
|
||||
checkPrettyTrie(m.routingTable, [' 1 {[0]}',
|
||||
' 2 {[0]}']);
|
||||
checkPrettyTrie(m.interestsOf(0), [' 1 {[0]}',
|
||||
' 2 {[0]}']);
|
||||
checkPrettyTrie(m.interestsOf(1), [' ::: nothing']);
|
||||
checkPrettyPatch(updateStreamResult.deltaAggregate,
|
||||
['::: nothing'],
|
||||
[' 3 >{[1]}']);
|
||||
[' ::: nothing'],
|
||||
[' 3 {[1]}']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,76 +19,76 @@ function checkPrettyPatch(p, expectedAdded, expectedRemoved) {
|
|||
describe('basic patch compilation', function () {
|
||||
it('should print as expected', function () {
|
||||
checkPrettyPatch(Patch.assert([1, 2]),
|
||||
[' < 1 2 > >{true}'],
|
||||
['::: nothing']);
|
||||
[' <2> 1 2 {true}'],
|
||||
[' ::: nothing']);
|
||||
checkPrettyPatch(Patch.assert(__),
|
||||
[' ★ >{true}'],
|
||||
['::: nothing']);
|
||||
[' ★ {true}'],
|
||||
[' ::: nothing']);
|
||||
checkPrettyPatch(Patch.sub(__),
|
||||
[' < $Observe ★ > >{true}'],
|
||||
['::: nothing']);
|
||||
[' observe<1> ★ {true}'],
|
||||
[' ::: nothing']);
|
||||
checkPrettyPatch(Patch.sub([1, 2]),
|
||||
[' < $Observe < 1 2 > > >{true}'],
|
||||
['::: nothing']);
|
||||
[' observe<1> <2> 1 2 {true}'],
|
||||
[' ::: nothing']);
|
||||
checkPrettyPatch(Patch.pub('x'),
|
||||
[' < $Advertise "x" > >{true}'],
|
||||
['::: nothing']);
|
||||
[' advertise<1> "x" {true}'],
|
||||
[' ::: nothing']);
|
||||
});
|
||||
|
||||
it('should work at nonzero metalevel', function () {
|
||||
checkPrettyPatch(Patch.assert([1, 2], 0),
|
||||
[' < 1 2 > >{true}'],
|
||||
['::: nothing']);
|
||||
[' <2> 1 2 {true}'],
|
||||
[' ::: nothing']);
|
||||
checkPrettyPatch(Patch.assert([1, 2], 1),
|
||||
[' < $AtMeta < 1 2 > > >{true}'],
|
||||
['::: nothing']);
|
||||
[' atMeta<1> <2> 1 2 {true}'],
|
||||
[' ::: nothing']);
|
||||
checkPrettyPatch(Patch.assert([1, 2], 2),
|
||||
[' < $AtMeta < $AtMeta < 1 2 > > > >{true}'],
|
||||
['::: nothing']);
|
||||
[' atMeta<1> atMeta<1> <2> 1 2 {true}'],
|
||||
[' ::: nothing']);
|
||||
|
||||
checkPrettyPatch(Patch.sub([1, 2], 0),
|
||||
[' < $Observe < 1 2 > > >{true}'],
|
||||
['::: nothing']);
|
||||
[' observe<1> <2> 1 2 {true}'],
|
||||
[' ::: nothing']);
|
||||
checkPrettyPatch(Patch.sub([1, 2], 1),
|
||||
[' < $AtMeta < $Observe < 1 2 > > > >{true}',
|
||||
' $Observe < $AtMeta < 1 2 > > > >{true}'],
|
||||
['::: nothing']);
|
||||
[' atMeta<1> observe<1> <2> 1 2 {true}',
|
||||
' observe<1> atMeta<1> <2> 1 2 {true}'],
|
||||
[' ::: nothing']);
|
||||
checkPrettyPatch(Patch.sub([1, 2], 2),
|
||||
[' < $AtMeta < $AtMeta < $Observe < 1 2 > > > > >{true}',
|
||||
' $Observe < $AtMeta < 1 2 > > > > >{true}',
|
||||
' $Observe < $AtMeta < $AtMeta < 1 2 > > > > >{true}'],
|
||||
['::: nothing']);
|
||||
[' atMeta<1> atMeta<1> observe<1> <2> 1 2 {true}',
|
||||
' observe<1> atMeta<1> <2> 1 2 {true}',
|
||||
' observe<1> atMeta<1> atMeta<1> <2> 1 2 {true}'],
|
||||
[' ::: nothing']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('patch sequencing', function () {
|
||||
it('should do the right thing in simple cases', function () {
|
||||
checkPrettyPatch(Patch.assert(__).andThen(Patch.retract(3)),
|
||||
[' ★ >{true}',
|
||||
' 3::: nothing'],
|
||||
[' 3 >{true}']);
|
||||
[' ★ {true}',
|
||||
' 3 ::: nothing'],
|
||||
[' 3 {true}']);
|
||||
checkPrettyPatch(Patch.assert(3).andThen(Patch.retract(__)),
|
||||
['::: nothing'],
|
||||
[' ★ >{true}']);
|
||||
[' ::: nothing'],
|
||||
[' ★ {true}']);
|
||||
checkPrettyPatch(Patch.assert(__).andThen(Patch.retract(__)),
|
||||
['::: nothing'],
|
||||
[' ★ >{true}']);
|
||||
[' ::: nothing'],
|
||||
[' ★ {true}']);
|
||||
checkPrettyPatch(Patch.assert(3).andThen(Patch.retract(3)),
|
||||
['::: nothing'],
|
||||
[' 3 >{true}']);
|
||||
[' ::: nothing'],
|
||||
[' 3 {true}']);
|
||||
checkPrettyPatch(Patch.sub([1, __]).andThen(Patch.unsub([1, 2])),
|
||||
[' < $Observe < 1 ★ > > >{true}',
|
||||
' 2::: nothing'],
|
||||
[' < $Observe < 1 2 > > >{true}']);
|
||||
[' observe<1> <2> 1 ★ {true}',
|
||||
' 2 ::: nothing'],
|
||||
[' observe<1> <2> 1 2 {true}']);
|
||||
checkPrettyPatch(Patch.sub([__, 2]).andThen(Patch.unsub([1, 2])),
|
||||
[' < $Observe < ★ 2 > > >{true}',
|
||||
' 1::: nothing'],
|
||||
[' < $Observe < 1 2 > > >{true}']);
|
||||
[' observe<1> <2> ★ 2 {true}',
|
||||
' 1 ::: nothing'],
|
||||
[' observe<1> <2> 1 2 {true}']);
|
||||
checkPrettyPatch(Patch.sub([__, __]).andThen(Patch.unsub([1, 2])),
|
||||
[' < $Observe < ★ ★ > > >{true}',
|
||||
' 1 ★ > > >{true}',
|
||||
' 2::: nothing'],
|
||||
[' < $Observe < 1 2 > > >{true}']);
|
||||
[' observe<1> <2> ★ ★ {true}',
|
||||
' 1 ★ {true}',
|
||||
' 2 ::: nothing'],
|
||||
[' observe<1> <2> 1 2 {true}']);
|
||||
});
|
||||
|
||||
it('works for longer chains of asserts and retracts', function () {
|
||||
|
@ -99,11 +99,11 @@ describe('patch sequencing', function () {
|
|||
.andThen(Patch.assert(4))
|
||||
.andThen(Patch.retract(99));
|
||||
checkPrettyPatch(rawPatch,
|
||||
[' 1 >{true}',
|
||||
' 4 >{true}'],
|
||||
[' 2 >{true}',
|
||||
' 3 >{true}',
|
||||
' 99 >{true}']);
|
||||
[' 1 {true}',
|
||||
' 4 {true}'],
|
||||
[' 2 {true}',
|
||||
' 3 {true}',
|
||||
' 99 {true}']);
|
||||
|
||||
});
|
||||
});
|
||||
|
@ -111,31 +111,31 @@ describe('patch sequencing', function () {
|
|||
describe('patch lifting', function () {
|
||||
it('should basically work', function () {
|
||||
checkPrettyPatch(Patch.assert([1, 2]).lift(),
|
||||
[' < $AtMeta < 1 2 > > >{true}'],
|
||||
['::: nothing']);
|
||||
[' atMeta<1> <2> 1 2 {true}'],
|
||||
[' ::: nothing']);
|
||||
checkPrettyPatch(Patch.sub([1, 2]).lift(),
|
||||
[' < $AtMeta < $Observe < 1 2 > > > >{true}'],
|
||||
['::: nothing']);
|
||||
[' atMeta<1> observe<1> <2> 1 2 {true}'],
|
||||
[' ::: nothing']);
|
||||
checkPrettyPatch(Patch.assert([1, 2]).andThen(Patch.assert(Patch.atMeta([1, 2]))).lift(),
|
||||
[' < $AtMeta < $AtMeta < 1 2 > > > >{true}',
|
||||
' 1 2 > > >{true}'],
|
||||
['::: nothing']);
|
||||
[' atMeta<1> atMeta<1> <2> 1 2 {true}',
|
||||
' <2> 1 2 {true}'],
|
||||
[' ::: nothing']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('patch dropping', function () {
|
||||
it('should basically work', function () {
|
||||
checkPrettyPatch(Patch.assert([1, 2]).drop(),
|
||||
['::: nothing'],
|
||||
['::: nothing']);
|
||||
[' ::: nothing'],
|
||||
[' ::: nothing']);
|
||||
checkPrettyPatch(Patch.sub([1, 2]).drop(),
|
||||
['::: nothing'],
|
||||
['::: nothing']);
|
||||
[' ::: nothing'],
|
||||
[' ::: nothing']);
|
||||
checkPrettyPatch(Patch.sub([1, 2], 1).drop(),
|
||||
[' < $Observe < 1 2 > > >{true}'],
|
||||
['::: nothing']);
|
||||
[' observe<1> <2> 1 2 {true}'],
|
||||
[' ::: nothing']);
|
||||
checkPrettyPatch(Patch.assert([1, 2]).andThen(Patch.assert(Patch.atMeta([1, 2]))).drop(),
|
||||
[' < 1 2 > >{true}'],
|
||||
['::: nothing']);
|
||||
[' <2> 1 2 {true}'],
|
||||
[' ::: nothing']);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,7 +10,20 @@ function checkPrettyTrie(m, expected) {
|
|||
}
|
||||
|
||||
function checkTrieKeys(actual, expected) {
|
||||
expect(actual.equals(Immutable.Set(expected).map(Immutable.List))).to.be(true);
|
||||
expect(Immutable.is(actual, Immutable.Set(expected).map(Immutable.List))).to.be(true);
|
||||
}
|
||||
|
||||
function checkProjectedObjects(actual, expected) {
|
||||
actual = Immutable.Set(actual);
|
||||
expected = Immutable.Set(expected);
|
||||
actual.forEach(function (e) { c(expected, e) });
|
||||
expected.forEach(function (e) { c(actual, e) });
|
||||
function c(s, e1) {
|
||||
if (!s.find(function (e2) { return expect.eql(e1, e2) })) {
|
||||
throw new Error("Comparison failed: actual " + JSON.stringify(actual.toArray()) +
|
||||
"; expected " + JSON.stringify(expected.toArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe("basic pattern compilation", function () {
|
||||
|
@ -20,8 +33,8 @@ describe("basic pattern compilation", function () {
|
|||
var mAAny = r.compilePattern(sAAny, ['A', r.__]);
|
||||
|
||||
it("should print as expected", function () {
|
||||
checkPrettyTrie(mAny, [' ★ >{["mAny"]}']);
|
||||
checkPrettyTrie(mAAny, [' < "A" ★ > >{["mAAny"]}']);
|
||||
checkPrettyTrie(mAny, [' ★ {["mAny"]}']);
|
||||
checkPrettyTrie(mAAny, [' <2> "A" ★ {["mAAny"]}']);
|
||||
});
|
||||
|
||||
describe("of wildcard", function () {
|
||||
|
@ -53,81 +66,78 @@ describe("unions", function () {
|
|||
it("should collapse common prefix wildcard", function () {
|
||||
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 'A']),
|
||||
r.compilePattern(Immutable.Set(['B']), [r.__, 'B'])),
|
||||
[' < ★ "A" > >{["A"]}',
|
||||
' "B" > >{["B"]}']);
|
||||
[' <2> ★ "A" {["A"]}',
|
||||
' "B" {["B"]}']);
|
||||
});
|
||||
|
||||
it("should unroll wildcard unioned with nonwildcard", function () {
|
||||
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 'A']),
|
||||
r.compilePattern(Immutable.Set(['W']), r.__)),
|
||||
[' ★ >{["W"]}',
|
||||
' < ★ "A" ★...> >{["W"]}',
|
||||
' > >{["W","A"]}',
|
||||
' ★...> >{["W"]}',
|
||||
' > >{["W"]}',
|
||||
' > >{["W"]}']);
|
||||
[' ★ {["W"]}',
|
||||
' <2> ★ ★ {["W"]}',
|
||||
' "A" {["A","W"]}']);
|
||||
});
|
||||
|
||||
it("should properly multiply out", function () {
|
||||
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 2]),
|
||||
r.compilePattern(Immutable.Set(['C']), [1, 3]),
|
||||
r.compilePattern(Immutable.Set(['B']), [3, 4])),
|
||||
[' < ★ 2 > >{["A"]}',
|
||||
' 1 2 > >{["A"]}',
|
||||
' 3 > >{["C"]}',
|
||||
' 3 2 > >{["A"]}',
|
||||
' 4 > >{["B"]}']);
|
||||
[' <2> ★ 2 {["A"]}',
|
||||
' 1 2 {["A"]}',
|
||||
' 3 {["C"]}',
|
||||
' 3 2 {["A"]}',
|
||||
' 4 {["B"]}']);
|
||||
|
||||
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['C']), [1, 3]),
|
||||
r.compilePattern(Immutable.Set(['B']), [3, 4])),
|
||||
[' < 1 3 > >{["C"]}',
|
||||
' 3 4 > >{["B"]}']);
|
||||
[' <2> 1 3 {["C"]}',
|
||||
' 3 4 {["B"]}']);
|
||||
|
||||
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 2]),
|
||||
r.compilePattern(Immutable.Set(['C']), [1, 3])),
|
||||
[' < ★ 2 > >{["A"]}',
|
||||
' 1 2 > >{["A"]}',
|
||||
' 3 > >{["C"]}']);
|
||||
[' <2> ★ 2 {["A"]}',
|
||||
' 1 2 {["A"]}',
|
||||
' 3 {["C"]}']);
|
||||
|
||||
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 2]),
|
||||
r.compilePattern(Immutable.Set(['B']), [3, 4])),
|
||||
[' < ★ 2 > >{["A"]}',
|
||||
' 3 2 > >{["A"]}',
|
||||
' 4 > >{["B"]}']);
|
||||
[' <2> ★ 2 {["A"]}',
|
||||
' 3 2 {["A"]}',
|
||||
' 4 {["B"]}']);
|
||||
});
|
||||
|
||||
it("should correctly construct intermediate values", function () {
|
||||
var MU = r.emptyTrie;
|
||||
MU = r.union(MU, r.compilePattern(Immutable.Set(['A']), [r.__, 2]));
|
||||
checkPrettyTrie(MU, [' < ★ 2 > >{["A"]}']);
|
||||
checkPrettyTrie(MU, [' <2> ★ 2 {["A"]}']);
|
||||
MU = r.union(MU, r.compilePattern(Immutable.Set(['C']), [1, 3]));
|
||||
checkPrettyTrie(MU, [' < ★ 2 > >{["A"]}',
|
||||
' 1 2 > >{["A"]}',
|
||||
' 3 > >{["C"]}']);
|
||||
checkPrettyTrie(MU, [' <2> ★ 2 {["A"]}',
|
||||
' 1 2 {["A"]}',
|
||||
' 3 {["C"]}']);
|
||||
MU = r.union(MU, r.compilePattern(Immutable.Set(['B']), [3, 4]));
|
||||
checkPrettyTrie(MU, [' < ★ 2 > >{["A"]}',
|
||||
' 1 2 > >{["A"]}',
|
||||
' 3 > >{["C"]}',
|
||||
' 3 2 > >{["A"]}',
|
||||
' 4 > >{["B"]}']);
|
||||
checkPrettyTrie(MU, [' <2> ★ 2 {["A"]}',
|
||||
' 1 2 {["A"]}',
|
||||
' 3 {["C"]}',
|
||||
' 3 2 {["A"]}',
|
||||
' 4 {["B"]}']);
|
||||
});
|
||||
|
||||
it("should handle identical patterns with different pids", function () {
|
||||
var m = r.union(r.compilePattern(Immutable.Set('B'), [2]),
|
||||
r.compilePattern(Immutable.Set('C'), [3]));
|
||||
checkPrettyTrie(m, [' < 2 > >{["B"]}',
|
||||
' 3 > >{["C"]}']);
|
||||
checkPrettyTrie(m, [' <1> 2 {["B"]}',
|
||||
' 3 {["C"]}']);
|
||||
m = r.union(r.compilePattern(Immutable.Set('A'), [2]), m);
|
||||
checkPrettyTrie(m, [' < 2 > >{["A","B"]}',
|
||||
' 3 > >{["C"]}']);
|
||||
checkPrettyTrie(m, [' <1> 2 {["A","B"]}',
|
||||
' 3 {["C"]}']);
|
||||
});
|
||||
|
||||
it('should work with subtraction and wildcards', function () {
|
||||
var x = r.compilePattern(Immutable.Set(["A"]), [r.__]);
|
||||
var y = r.compilePattern(Immutable.Set(["A"]), ["Y"]);
|
||||
var z = r.compilePattern(Immutable.Set(["A"]), ["Z"]);
|
||||
var expected = [' < "Y"::: nothing',
|
||||
' ★ > >{["A"]}'];
|
||||
var expected = [' <1> ★ {["A"]}',
|
||||
' "Y" ::: nothing'];
|
||||
checkPrettyTrie(r.subtract(r.union(x, z), y), expected);
|
||||
checkPrettyTrie(r.union(r.subtract(x, y), z), expected);
|
||||
});
|
||||
|
@ -135,42 +145,42 @@ describe("unions", function () {
|
|||
|
||||
describe("projections", function () {
|
||||
describe("with picky structure", function () {
|
||||
var proj = r.compileProjection(r._$("v", [[r.__]]));
|
||||
var proj = r._$("v", [[r.__]]);
|
||||
|
||||
it("should include things that match as well as wildcards", function () {
|
||||
checkPrettyTrie(r.project(r.union(r.compilePattern(Immutable.Set(['A']), r.__),
|
||||
r.compilePattern(Immutable.Set(['B']), [['b']])),
|
||||
proj),
|
||||
[' < < ★ > > >{["A"]}',
|
||||
' "b" > > >{["A","B"]}']);
|
||||
[' <1> <1> ★ {["A"]}',
|
||||
' "b" {["A","B"]}']);
|
||||
});
|
||||
|
||||
it("should exclude things that lack the required structure", function () {
|
||||
checkPrettyTrie(r.project(r.union(r.compilePattern(Immutable.Set(['A']), r.__),
|
||||
r.compilePattern(Immutable.Set(['B']), ['b'])),
|
||||
proj),
|
||||
[' < < ★ > > >{["A"]}']);
|
||||
[' <1> <1> ★ {["A"]}']);
|
||||
});
|
||||
});
|
||||
|
||||
describe("simple positional", function () {
|
||||
var proj = r.compileProjection([r._$, r._$]);
|
||||
var proj = [r._$, r._$];
|
||||
|
||||
it("should collapse common prefixes", function () {
|
||||
checkPrettyTrie(r.project(r.union(r.compilePattern(Immutable.Set(['A']), [1, 2]),
|
||||
r.compilePattern(Immutable.Set(['C']), [1, 3]),
|
||||
r.compilePattern(Immutable.Set(['B']), [3, 4])),
|
||||
proj),
|
||||
[' 1 2 >{["A"]}',
|
||||
' 3 >{["C"]}',
|
||||
' 3 4 >{["B"]}']);
|
||||
[' 1 2 {["A"]}',
|
||||
' 3 {["C"]}',
|
||||
' 3 4 {["B"]}']);
|
||||
});
|
||||
|
||||
it("should yield a correct set of results", function () {
|
||||
var u = r.union(r.compilePattern(Immutable.Set(['A']), [1, 2]),
|
||||
r.compilePattern(Immutable.Set(['C']), [1, 3]),
|
||||
r.compilePattern(Immutable.Set(['B']), [3, 4]));
|
||||
checkTrieKeys(r.trieKeys(r.project(u, proj)), [[1, 2], [1, 3], [3, 4]]);
|
||||
checkTrieKeys(r.trieKeys(r.project(u, proj), 2), [[1, 2], [1, 3], [3, 4]]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -179,29 +189,27 @@ describe("subtraction", function () {
|
|||
it("should basically work", function () {
|
||||
checkPrettyTrie(r.subtract(r.compilePattern(true, r.__),
|
||||
r.compilePattern(true, 3),
|
||||
function (v1, v2) { return null; }),
|
||||
[" ★ >{true}",
|
||||
" 3::: nothing"]);
|
||||
function (v1, v2) { return r.emptyTrie; }),
|
||||
[" ★ {true}",
|
||||
" 3 ::: nothing"]);
|
||||
checkPrettyTrie(r.subtract(r.compilePattern(true, r.__),
|
||||
r.compilePattern(true, [3]),
|
||||
function (v1, v2) { return null; }),
|
||||
[" ★ >{true}",
|
||||
" < ★...> >{true}",
|
||||
" > >{true}",
|
||||
" 3 ★...> >{true}",
|
||||
" >::: nothing"]);
|
||||
function (v1, v2) { return r.emptyTrie; }),
|
||||
[" ★ {true}",
|
||||
" <1> ★ {true}",
|
||||
" 3 ::: nothing"]);
|
||||
});
|
||||
|
||||
it("should be idempotent if the subtrahend doesn't overlap the minuend", function () {
|
||||
checkPrettyTrie(r.compilePattern(true, 1),
|
||||
[' 1 >{true}']);
|
||||
[' 1 {true}']);
|
||||
checkPrettyTrie(r.subtract(r.compilePattern(true, 1),
|
||||
r.compilePattern(true, 2)),
|
||||
[' 1 >{true}']);
|
||||
[' 1 {true}']);
|
||||
checkPrettyTrie(r.subtract(r.compilePattern(true, 1),
|
||||
r.compilePattern(true, 2),
|
||||
function (v1, v2) { return null; }),
|
||||
[' 1 >{true}']);
|
||||
[' 1 {true}']);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -211,11 +219,11 @@ describe("subtract after union", function () {
|
|||
var R12 = r.union(R1, R2);
|
||||
|
||||
it("should have sane preconditions", function () { // Am I doing this right?
|
||||
checkPrettyTrie(R1, [' < ★ "B" > >{["A"]}']);
|
||||
checkPrettyTrie(R2, [' < "A" ★ > >{["B"]}']);
|
||||
checkPrettyTrie(R12, [' < "A" "B" > >{["B","A"]}',
|
||||
' ★ > >{["B"]}',
|
||||
' ★ "B" > >{["A"]}']);
|
||||
checkPrettyTrie(R1, [' <2> ★ "B" {["A"]}']);
|
||||
checkPrettyTrie(R2, [' <2> "A" ★ {["B"]}']);
|
||||
checkPrettyTrie(R12, [' <2> ★ "B" {["A"]}',
|
||||
' "A" ★ {["B"]}',
|
||||
' "B" {["A","B"]}']);
|
||||
});
|
||||
|
||||
it("should yield the remaining ingredients of the union", function () {
|
||||
|
@ -248,28 +256,30 @@ describe("trieKeys on wild tries", function () {
|
|||
r.compilePattern(Immutable.Set(['C']), [1, 3]),
|
||||
r.compilePattern(Immutable.Set(['B']), [3, 4]));
|
||||
|
||||
it("should yield null to signal an infinite result", function () {
|
||||
expect(r.trieKeys(r.project(M, r.compileProjection([r._$, r._$])))).to.be(null);
|
||||
it("should yield false to signal an infinite result", function () {
|
||||
expect(r.trieKeys(r.project(M, [r._$, r._$]), 1)).to.be(false);
|
||||
});
|
||||
|
||||
it("should extract just the second array element successfully", function () {
|
||||
checkTrieKeys(r.trieKeys(r.project(M, r.compileProjection([r.__, r._$]))),
|
||||
checkTrieKeys(r.trieKeys(r.project(M, [r.__, r._$]), 1),
|
||||
[[2],[3],[4]]);
|
||||
});
|
||||
|
||||
var M2 = r.project(M, r.compileProjection([r._$, r._$]));
|
||||
var M2 = r.project(M, [r._$, r._$]);
|
||||
|
||||
it("should survive double-projection", function () {
|
||||
checkTrieKeys(r.trieKeys(r.project(M2, r.compileProjection(r.__, r._$))),
|
||||
checkTrieKeys(r.trieKeys(r.projectMany(M2, [r.__, r._$]), 1),
|
||||
[[2],[3],[4]]);
|
||||
});
|
||||
|
||||
it("should survive embedding and reprojection", function () {
|
||||
checkTrieKeys(r.trieKeys(r.project(r.compilePattern(true, [r.embeddedTrie(M2)]),
|
||||
r.compileProjection([r.__, r._$]))),
|
||||
checkTrieKeys(r.trieKeys(r.project(r.compilePattern(Immutable.Set(['A']),
|
||||
r.embeddedTrieArray(M2, 2)),
|
||||
[r.__, r._$]), 1),
|
||||
[[2],[3],[4]]);
|
||||
checkTrieKeys(r.trieKeys(r.project(r.compilePattern(true, [[r.embeddedTrie(M2)]]),
|
||||
r.compileProjection([[r.__, r._$]]))),
|
||||
checkTrieKeys(r.trieKeys(r.project(r.compilePattern(Immutable.Set(['A']),
|
||||
[r.embeddedTrieArray(M2, 2)]),
|
||||
[[r.__, r._$]]), 1),
|
||||
[[2],[3],[4]]);
|
||||
});
|
||||
});
|
||||
|
@ -278,23 +288,24 @@ describe("trieKeys using multiple-values in projections", function () {
|
|||
var M = r.union(r.compilePattern(Immutable.Set(['A']), [1, 2]),
|
||||
r.compilePattern(Immutable.Set(['C']), [1, 3]),
|
||||
r.compilePattern(Immutable.Set(['B']), [3, 4]));
|
||||
var proj = r.compileProjection([r._$, r._$]);
|
||||
var proj = [r._$, r._$];
|
||||
var M2 = r.project(M, proj);
|
||||
|
||||
it("should be able to extract ordinary values", function () {
|
||||
checkTrieKeys(r.trieKeys(M2), [[1,2],[1,3],[3,4]]);
|
||||
checkTrieKeys(r.trieKeys(M2, 2), [[1,2],[1,3],[3,4]]);
|
||||
});
|
||||
|
||||
it("should be able to be reprojected as a sequence of more than one value", function () {
|
||||
checkTrieKeys(r.trieKeys(r.project(M2, r.compileProjection(r._$, r._$))),
|
||||
checkTrieKeys(r.trieKeys(r.projectMany(M2, [r._$, r._$]), 2),
|
||||
[[1,2],[1,3],[3,4]]);
|
||||
});
|
||||
|
||||
it("should be convertible into objects with $-indexed fields", function () {
|
||||
expect(r.trieKeysToObjects(r.trieKeys(M2), proj).toArray())
|
||||
.to.eql([{'$0': 3, '$1': 4}, {'$0': 1, '$1': 2}, {'$0': 1, '$1': 3}]);
|
||||
expect(r.projectObjects(M, proj).toArray())
|
||||
.to.eql([{'$0': 3, '$1': 4}, {'$0': 1, '$1': 2}, {'$0': 1, '$1': 3}]);
|
||||
var names = r.projectionNames(proj);
|
||||
checkProjectedObjects(r.trieKeysToObjects(r.trieKeys(M2, names.length), names).toArray(),
|
||||
[{'$0': 3, '$1': 4}, {'$0': 1, '$1': 2}, {'$0': 1, '$1': 3}]);
|
||||
checkProjectedObjects(r.projectObjects(M, proj).toArray(),
|
||||
[{'$0': 3, '$1': 4}, {'$0': 1, '$1': 2}, {'$0': 1, '$1': 3}]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -304,15 +315,15 @@ describe("trieKeys using multiple-values in projections, with names", function (
|
|||
r.compilePattern(Immutable.Set(['B']), [3, 4]));
|
||||
|
||||
it("should yield named fields", function () {
|
||||
expect(r.projectObjects(M, r.compileProjection([r._$("fst"), r._$("snd")])).toArray())
|
||||
.to.eql([{'fst': 3, 'snd': 4}, {'fst': 1, 'snd': 2}, {'fst': 1, 'snd': 3}]);
|
||||
checkProjectedObjects(r.projectObjects(M, [r._$("fst"), r._$("snd")]).toArray(),
|
||||
[{'fst': 3, 'snd': 4}, {'fst': 1, 'snd': 2}, {'fst': 1, 'snd': 3}]);
|
||||
});
|
||||
|
||||
it("should yield numbered fields where names are missing", function () {
|
||||
expect(r.projectObjects(M, r.compileProjection([r._$, r._$("snd")])).toArray())
|
||||
.to.eql([{'$0': 3, 'snd': 4}, {'$0': 1, 'snd': 2}, {'$0': 1, 'snd': 3}]);
|
||||
expect(r.projectObjects(M, r.compileProjection([r._$("fst"), r._$])).toArray())
|
||||
.to.eql([{'fst': 3, '$1': 4}, {'fst': 1, '$1': 2}, {'fst': 1, '$1': 3}]);
|
||||
checkProjectedObjects(r.projectObjects(M, [r._$, r._$("snd")]).toArray(),
|
||||
[{'$0': 3, 'snd': 4}, {'$0': 1, 'snd': 2}, {'$0': 1, 'snd': 3}]);
|
||||
checkProjectedObjects(r.projectObjects(M, [r._$("fst"), r._$]).toArray(),
|
||||
[{'fst': 3, '$1': 4}, {'fst': 1, '$1': 2}, {'fst': 1, '$1': 3}]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -393,47 +404,51 @@ describe("calls to matchPattern", function () {
|
|||
var ctor = r.makeStructureConstructor('foo', ['bar', 'zot']);
|
||||
expect(r.matchPattern(ctor(123, 234), ctor(r._$("bar"), r._$("zot"))))
|
||||
.to.eql({ bar: 123, zot: 234, length: 2 });
|
||||
// Previously, structures were roughly the same as arrays:
|
||||
expect(r.matchPattern(["foo", 123, 234], ctor(r._$("bar"), r._$("zot"))))
|
||||
.to.eql({ bar: 123, zot: 234, length: 2 });
|
||||
.to.be(null);
|
||||
expect(r.matchPattern(ctor(123, 234), ["foo", r._$("bar"), r._$("zot")]))
|
||||
.to.eql({ bar: 123, zot: 234, length: 2 });
|
||||
.to.be(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Projection with no captures", function () {
|
||||
it("should yield the empty sequence when there's a match", function () {
|
||||
var emptySequence = [' >{["A"]}'];
|
||||
var emptySequence = [' {["A"]}'];
|
||||
|
||||
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
|
||||
r.compileProjection(r.__)),
|
||||
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]), r.__),
|
||||
emptySequence);
|
||||
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
|
||||
r.compileProjection([r.__, r.__])),
|
||||
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]), [r.__, r.__]),
|
||||
emptySequence);
|
||||
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
|
||||
r.compileProjection(["X", r.__])),
|
||||
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]), ["X", r.__]),
|
||||
emptySequence);
|
||||
});
|
||||
|
||||
it("should yield the empty trie when there's no match", function () {
|
||||
expect(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
|
||||
r.compileProjection(["Y", r.__]))).to.be(r.emptyTrie);
|
||||
["Y", r.__])).to.be(r.emptyTrie);
|
||||
});
|
||||
|
||||
it("should yield nonempty sequences when there are captures after all", function () {
|
||||
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
|
||||
r.compileProjection([r.__, r._$])),
|
||||
[' ★ >{["A"]}']);
|
||||
[r.__, r._$]),
|
||||
[' ★ {["A"]}']);
|
||||
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
|
||||
r.compileProjection([r._$, r._$])),
|
||||
[' "X" ★ >{["A"]}']);
|
||||
[r._$, r._$]),
|
||||
[' "X" ★ {["A"]}']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('trieStep', function () {
|
||||
it('should expand wildcard when given SOA', function () {
|
||||
expect(Immutable.is(r.trieStep(r.compilePattern(true, r.__), r.SOA),
|
||||
r._testing.rwildseq(r._testing.rseq(r.EOA, r._testing.rsuccess(true)))))
|
||||
expect(Immutable.is(r.trieStep(r.compilePattern(true, r.__), 0, r.SOA),
|
||||
r._testing.rsuccess(true)))
|
||||
.to.be(true);
|
||||
expect(Immutable.is(r.trieStep(r.compilePattern(true, r.__), 1, r.SOA),
|
||||
r._testing.rwild(r._testing.rsuccess(true))))
|
||||
.to.be(true);
|
||||
expect(Immutable.is(r.trieStep(r.compilePattern(true, r.__), 2, r.SOA),
|
||||
r._testing.rwild(r._testing.rwild(r._testing.rsuccess(true)))))
|
||||
.to.be(true);
|
||||
});
|
||||
});
|
||||
|
@ -443,60 +458,61 @@ describe('intersect', function () {
|
|||
var x = r.compilePattern(Immutable.Set([0]), ["fieldContents", r.__, r.__]);
|
||||
var y = r.compilePattern(Immutable.Set([0]), ["fieldContents", "initial", 7]);
|
||||
checkPrettyTrie(r.subtract(x, y), [
|
||||
' < "fieldContents" ★ ★ > >{[0]}',
|
||||
' "initial" ★ > >{[0]}',
|
||||
' 7::: nothing']);
|
||||
checkPrettyTrie(r.intersect(r.subtract(x, y), y), ['::: nothing']);
|
||||
' <3> "fieldContents" ★ ★ {[0]}',
|
||||
' "initial" ★ {[0]}',
|
||||
' 7 ::: nothing']);
|
||||
checkPrettyTrie(r.intersect(r.subtract(x, y), y), [' ::: nothing']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('triePruneBranch', function () {
|
||||
it('should not affect empty trie', function () {
|
||||
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([])), ['::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([r.SOA])), ['::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List(["x"])), ['::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([r.SOA, "x"])), ['::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([])), [' ::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([r.SOA])), [' ::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List(["x"])), [' ::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([r.SOA, "x"])), [' ::: nothing']);
|
||||
});
|
||||
|
||||
it('should leave a hole in a full trie', function () {
|
||||
var full = r.compilePattern(true, r.__);
|
||||
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([])), ['::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([r.SOA])),
|
||||
[' ★ >{true}',
|
||||
' <::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(full, Immutable.List(["x"])),
|
||||
[' ★ >{true}',
|
||||
' "x"::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([r.SOA, "x"])),
|
||||
[' ★ >{true}',
|
||||
' < ★...> >{true}',
|
||||
' > >{true}',
|
||||
' "x"::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([])), [' ::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([[0, r.SOA]])),
|
||||
[' ★ {true}',
|
||||
' <0> ::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([[0, "x"]])),
|
||||
[' ★ {true}',
|
||||
' "x" ::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([[2, r.SOA], [0, "x"]])),
|
||||
[' ★ {true}',
|
||||
' <2> ★ ★ {true}',
|
||||
' "x" ::: nothing']);
|
||||
});
|
||||
|
||||
it('should prune in a finite tree and leave the rest alone', function () {
|
||||
var A = r.compilePattern(true, ["y"])
|
||||
var B = r.union(r.compilePattern(true, ["x"]), A);
|
||||
var C = r.union(r.compilePattern(true, "z"), B);
|
||||
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([])), ['::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([])), ['::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([])), ['::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(A, Immutable.List(["z"])), [' < "y" > >{true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(B, Immutable.List(["z"])), [' < "x" > >{true}',
|
||||
' "y" > >{true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(C, Immutable.List(["z"])), [' < "x" > >{true}',
|
||||
' "y" > >{true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([r.SOA])), ['::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([r.SOA])), ['::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([r.SOA])), [' "z" >{true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([r.SOA, "x"])), [' < "y" > >{true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([r.SOA, "x"])), [' < "y" > >{true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([r.SOA, "x"])), [' < "y" > >{true}',
|
||||
' "z" >{true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([r.SOA, "y"])), ['::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([r.SOA, "y"])), [' < "x" > >{true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([r.SOA, "y"])), [' < "x" > >{true}',
|
||||
' "z" >{true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([])), [' ::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([])), [' ::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([])), [' ::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([[0, "z"]])), [' <1> "y" {true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([[0, "z"]])), [' <1> "x" {true}',
|
||||
' "y" {true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([[0, "z"]])), [' <1> "x" {true}',
|
||||
' "y" {true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([[1, r.SOA]])), [' ::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([[1, r.SOA]])), [' ::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([[1, r.SOA]])), [' "z" {true}']);
|
||||
var px = [[1, r.SOA], [0, "x"]];
|
||||
checkPrettyTrie(r.triePruneBranch(A, Immutable.List(px)), [' <1> "y" {true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(B, Immutable.List(px)), [' <1> "y" {true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(C, Immutable.List(px)), [' "z" {true}',
|
||||
' <1> "y" {true}']);
|
||||
var py = [[1, r.SOA], [0, "y"]];
|
||||
checkPrettyTrie(r.triePruneBranch(A, Immutable.List(py)), [' ::: nothing']);
|
||||
checkPrettyTrie(r.triePruneBranch(B, Immutable.List(py)), [' <1> "x" {true}']);
|
||||
checkPrettyTrie(r.triePruneBranch(C, Immutable.List(py)), [' "z" {true}',
|
||||
' <1> "x" {true}']);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -520,7 +536,7 @@ describe('makeStructureConstructor', function () {
|
|||
var ctor = r.makeStructureConstructor('foo', ['bar', 'zot']);
|
||||
var inst = ctor(123, 234);
|
||||
var x = r.compilePattern(sA, ctor(123, r.__));
|
||||
checkPrettyTrie(x, [' < "foo" 123 ★ > >{["A"]}']);
|
||||
checkPrettyTrie(x, [' foo<2> 123 ★ {["A"]}']);
|
||||
expect(r.matchValue(x, ctor(123, 234))).to.eql(sA);
|
||||
expect(r.matchValue(x, ctor(234, 123))).to.eql(null);
|
||||
});
|
||||
|
|
|
@ -60,10 +60,9 @@ describe("configurationTrace", function() {
|
|||
Dataspace.send(123);
|
||||
Dataspace.send(234);
|
||||
}, ['<<<<<<<< Removed:\n'+
|
||||
'::: nothing\n'+
|
||||
' ::: nothing\n'+
|
||||
'======== Added:\n'+
|
||||
' < $Observe ★ > >{[0]}\n'
|
||||
+' >::: nothing\n'+
|
||||
' observe<1> ★ {[0]}\n'+
|
||||
'>>>>>>>>',
|
||||
Syndicate.message(123),
|
||||
Syndicate.message(234)]);
|
||||
|
@ -84,9 +83,9 @@ describe("nonempty initial routes", function () {
|
|||
handleEvent: traceEvent(trace)
|
||||
});
|
||||
}, ['<<<<<<<< Removed:\n'+
|
||||
'::: nothing\n'+
|
||||
' ::: nothing\n'+
|
||||
'======== Added:\n'+
|
||||
' < "A" ★ > >{[1]}\n'+
|
||||
' <2> "A" ★ {[0]}\n'+
|
||||
'>>>>>>>>']);
|
||||
});
|
||||
});
|
||||
|
@ -104,14 +103,14 @@ describe("nested actor with an echoey protocol", function () {
|
|||
});
|
||||
}));
|
||||
}, ['<<<<<<<< Removed:\n'+
|
||||
'::: nothing\n'+
|
||||
' ::: nothing\n'+
|
||||
'======== Added:\n'+
|
||||
' < $AtMeta "X" > >{[0]}\n'+
|
||||
' atMeta<1> "X" {["meta"]}\n'+
|
||||
'>>>>>>>>',
|
||||
'<<<<<<<< Removed:\n'+
|
||||
' < $AtMeta "X" > >{[0]}\n'+
|
||||
' atMeta<1> "X" {["meta"]}\n'+
|
||||
'======== Added:\n'+
|
||||
'::: nothing\n'+
|
||||
' ::: nothing\n'+
|
||||
'>>>>>>>>']);
|
||||
})
|
||||
it("shouldn't see an echoed message", function () {
|
||||
|
@ -120,7 +119,7 @@ describe("nested actor with an echoey protocol", function () {
|
|||
Dataspace.spawn({
|
||||
boot: function () {
|
||||
Dataspace.send("X", 1); // happens after subs on next line!
|
||||
return Patch.sub("X", 1);
|
||||
return Patch.sub("X", 1);
|
||||
},
|
||||
handleEvent: traceEvent(trace)
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue