Skip to content

Commit

Permalink
95% code coverage, bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
seyacat committed Dec 21, 2023
1 parent d9e91be commit 9350ec2
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 31 deletions.
66 changes: 38 additions & 28 deletions reactive.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,18 +153,8 @@ function Reactive(ob, options = { prefix: "r-", subscriptionDelay: 0 }) {
const ret = this.target.data[this.prop].bind(this.target.data)(
...arguments
);
//Rebuild parent relationship
for ([key, value] of Object.entries(this.target.data)) {
if (value?.isReactive) {
value._target._parent = {
prop:
this.target.data.constructor.name === "Array"
? parseInt(key)
: key,
receiver: newProxy,
};
}
}
//REBUILD RELATIONSHIPS
this.target.rebuildRelationships.bind(this)();
//POST TRIGGER
this.target.triggerSubs.bind(this.receiver)({
prop: this.prop,
Expand All @@ -179,20 +169,41 @@ function Reactive(ob, options = { prefix: "r-", subscriptionDelay: 0 }) {
const prop = this.target._parent.prop;
delete this.target._parent;

delete parentReceiver[prop];
if (parentTarget.data.constructor.name === "Array") {
parentTarget.data.splice(prop, 1);
} else {
delete parentReceiver[prop];
}

//REBUILD RELATIONSHIPS
parentReceiver.rebuildRelationships();

return this.receiver;
},
rebuildRelationships: function () {
//Rebuild parent relationship
for ([key, value] of Object.entries(this.target.data)) {
if (value?.isReactive) {
value._target._parent = {
prop:
this.target.data.constructor.name === "Array"
? parseInt(key)
: key,
receiver: newProxy,
};
}
}
},
},
{
get: (target, prop, receiver) => {
if (prop === Symbol.iterator) {
const dataArr = Object.entries(target.data);
return dataArr[Symbol.iterator].bind(dataArr);
}
let currentTarget = target;
if (target.isReactive) {
currentTarget = target._data;
if (target.data.constructor.name === "Array") {
return target.data[Symbol.iterator].bind(target.data);
} else {
const dataArr = Object.entries(target.data);
return dataArr[Symbol.iterator].bind(dataArr);
}
}
switch (prop) {
case "_path":
Expand All @@ -205,14 +216,15 @@ function Reactive(ob, options = { prefix: "r-", subscriptionDelay: 0 }) {
return ret;
case "_parent":
case "_prefix":
case "_proxy":
return target[prop];
case "_target":
return target;
case "_data":
case "_":
if (currentTarget.data.constructor.name === "Object") {
if (target.data.constructor.name === "Object") {
const ret = Object.fromEntries(
Object.entries(currentTarget.data).map(([key, val]) => {
Object.entries(target.data).map(([key, val]) => {
if (val?.isReactive) {
return [key, val._data];
} else {
Expand All @@ -222,8 +234,8 @@ function Reactive(ob, options = { prefix: "r-", subscriptionDelay: 0 }) {
);
return ret;
}
if (currentTarget.data.constructor.name === "Array") {
const ret = currentTarget.data.map((val) => {
if (target.data.constructor.name === "Array") {
const ret = target.data.map((val) => {
if (val?.isReactive) {
return val._data;
} else {
Expand All @@ -232,23 +244,21 @@ function Reactive(ob, options = { prefix: "r-", subscriptionDelay: 0 }) {
});
return ret;
}
return currentTarget.data;
return target.data;
case "isReactive":
return true;
case "subscribe":
return target.subscribe.bind({ receiver, target });
case "triggerSubs":
return target.triggerSubs.bind(receiver);
case "triggerDelayedSubs":
return target.triggerDelayedSubs.bind(receiver);
case "triggerChange":
return target.triggerChange.bind(receiver);
case "triggerUpTree":
return target.triggerUpTree.bind(receiver);
case "keys":
return target.keys.bind(receiver);
case "orphan":
return target.orphan.bind({ receiver, target });
case "rebuildRelationships":
return target.rebuildRelationships.bind({ receiver, target });
}
if (
typeof target.data[prop] === "function" &&
Expand Down
101 changes: 98 additions & 3 deletions test/reactive.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,25 +60,29 @@ it("Trigger change when subscribe", function () {
assert.equal(pathValues[0], 1);
assert.equal(value, 1);
assert.equal(oldValue, undefined);
games.ok = "OK";
},
{ triggerChange: true }
);

assert.equal(games.ok, "OK");
//Multiple property subcription
games.subscribe(["test2", "test3"], (data) => {
const { base, prop, path, pathValues, value, oldValue } = data;
assert.equal(prop.includes("test"), true);
assert.equal(path.length, 1);
assert.equal(value, "OK");
assert.equal(oldValue, undefined);
games.ok = "OK2";
});
games.test2 = "OK";
games.test3 = "OK";
assert.equal(games.ok, "OK2");
});

it("Reactive Chain", function () {
const games = Reactive(
{
number: 1,
level1: Reactive([Reactive({ level3: "OK" }, { prefix: "level2" })], {
prefix: "level1",
}),
Expand All @@ -95,6 +99,10 @@ it("Reactive Chain", function () {
});
assert.equal(games.level1[0].level3, "OK");
games.level1[0].level3 = "KO";
assert.equal(
JSON.stringify(games._),
JSON.stringify({ number: 1, level1: [{ level3: "KO" }] })
);
});

it("Delayed trigger", async function () {
Expand All @@ -109,10 +117,13 @@ it("Delayed trigger", async function () {
assert.equal(pathValues[0], 2);
assert.equal(value, 2);
assert.equal(oldValue, undefined);
games.ok = "OK";
});
games.test = 1; //<--- this value ignored because of subscriptionDelay
games.test = 2;
assert.equal(games.ok, undefined);
await new Promise((resolve) => setTimeout(resolve, 20));
assert.equal(games.ok, "OK");
});

it("Delayed trigger on subscription", async function () {
Expand Down Expand Up @@ -195,7 +206,6 @@ it("Manual trigger loop on tree", function () {
//SUBSCRIBE to every change in Reactive chain
games.subscribe(null, (data) => {
const { base, prop, path, pathValues, value, oldValue } = data;
console.log(data);
assert.equal(prop, "targetReactive");
assert.equal(
JSON.stringify(path),
Expand All @@ -206,5 +216,90 @@ it("Manual trigger loop on tree", function () {
});

targetReactive.triggerChange();
console.log(targetReactive);
});

it("Reactive Array", function () {
const games = Reactive(
[
Reactive([1, 2, 3, 5]),
Reactive([1, 2, 3, 5]),
Reactive([1, 2, 3, 5]),
Reactive([1, 2, 3, 5]),
],
{ prefix: "base" }
);
//SUBSCRIBE to every change in Reactive chain
games.subscribe(null, (data) => {
const { base, prop, path, pathValues, value, oldValue } = data;
});

games[0].push(Reactive({ test: "IM HERE" }));
games[1].shift();
games[2].pop();
games[3].unshift(Reactive([7, 7, 7]));

assert.equal(
JSON.stringify(games._),
JSON.stringify([
[1, 2, 3, 5, { test: "IM HERE" }],
[2, 3, 5],
[1, 2, 3],
[[7, 7, 7], 1, 2, 3, 5],
])
);
});

it("Remove reactive from parent as itself", function () {
const target1 = Reactive(["IM 1"]);
const target2 = Reactive(["IM 2"]);
const item3 = Reactive(["IM 3"]);
const target3 = Reactive({ item3, item4: Reactive() });
const games = Reactive([target1, target2], { prefix: "base" });
//SUBSCRIBE to every change in Reactive chain

assert.equal(target1._target._parent.prop, 0);
assert.equal(target2._target._parent.prop, 1);
assert.equal(item3._target._parent.prop, "item3");
target1.orphan();
assert.equal(target1._target._parent, null);
assert.equal(target2._target._parent.prop, 0);
item3.orphan();
assert.equal(item3._target._parent, null);
});

it("Iterators", function () {
const games = Reactive([1, 2, 3, 4, 5, 6, 7, 8]);
const games2 = Reactive({ 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8 });
let counter = 0;
for (const game of games) {
counter++;
assert.equal(game, counter);
}
counter = 0;
for (const [key, value] of games2) {
counter++;
assert.equal(value, counter);
}
});

it("Reactive of non object", function () {
const games = Reactive(1);
assert.equal(games._, 1);
});

it("Set inner properties", function () {
const child = Reactive();
const games = Reactive({ child });
assert.equal(child._parent.receiver, games);
assert.equal(games._proxy, games);
assert.equal(games._target._proxy, games);
games._prefix = "test";
games._proxy = null;
child._parent = null;
assert.equal(games._prefix, "test");
assert.equal(games._target._prefix, "test");
assert.equal(games._proxy, null);
assert.equal(games._target._proxy, null);
assert.equal(child._parent, null);
assert.equal(games._target._parent, null);
});

0 comments on commit 9350ec2

Please sign in to comment.