Skip to content

Commit

Permalink
feat: agrega metodos al emulator y tambien Symbol.iterator al dummy f…
Browse files Browse the repository at this point in the history
…unction
  • Loading branch information
drusco committed Aug 4, 2023
1 parent 6f21b9f commit 3a0a50a
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 24 deletions.
40 changes: 38 additions & 2 deletions src/Emulator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,42 @@ describe("Emulator", () => {
});
});

describe("parent", () => {
it("Access a proxy parent", () => {
const parent = $.proxy();
const child = parent.child;
expect($.parent(child)).toBe(parent);
expect($.parent(parent)).toBe(undefined);
});
});

describe("children", () => {
it("Can access all the direct children of a proxy", () => {
const parent = $.proxy();
parent.girl = 10;
parent.boy = 5;
parent.alien = NaN;
parent.alien.notDirectChild = true;

expect($.children(parent).length).toBe(3);
});

it("Can use [Symbol.iterator] to access all children as well", () => {
const parent = $.proxy();

parent.girl = 1;
parent.boy = 2;

const children = [...parent];

for (const proxy of parent) {
expect($.parent(proxy)).toBe(parent);
}

expect(children.length).toBe(2);
});
});

describe("revoke", () => {
it("Turns a proxy unusable", () => {
const proxy = $.proxy();
Expand All @@ -106,7 +142,7 @@ describe("Emulator", () => {
});

describe("destroy", () => {
it("Destroys the $ and turns it unusable", () => {
it("Destroys the emulator and turns it unusable", () => {
const $ = new Emulator();
$.destroy();
expect($.proxy).toThrow();
Expand All @@ -115,7 +151,7 @@ describe("Emulator", () => {
});

describe("count", () => {
it("Returns the number of proxies in the $", () => {
it("Returns the number of proxies in the emulator", () => {
const current = $.count();
$.proxy();
expect($.count()).toBe(current + 1);
Expand Down
27 changes: 18 additions & 9 deletions src/Emulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { findProxy, map, createProxy } from "./utils";
import { EventEmitter } from "events";

export default class Emulator extends EventEmitter implements Exotic.Emulator {
static iterator = Symbol(90);

get refs(): Exotic.namespace[] {
const { bindings }: Exotic.emulator.data = map.emulators.get(this);
return Object.keys(bindings);
return Reflect.ownKeys(bindings);
}

constructor(options: Exotic.emulator.options = {}) {
Expand All @@ -21,19 +23,18 @@ export default class Emulator extends EventEmitter implements Exotic.Emulator {
map.emulators.set(this, data);
}

bind(selector: Exotic.namespace): Exotic.Proxy {
const data: Exotic.emulator.data = map.emulators.get(this);
const { bindings } = data;
const group = bindings[selector];
bind(namespace: Exotic.namespace): Exotic.Proxy {
const { bindings }: Exotic.emulator.data = map.emulators.get(this);
const group = bindings[namespace];

// return the first proxy in the existing group
if (group) return group.first;
if (group) return group.root;

// create the first proxy for a new group
return createProxy(this, undefined, selector);
return createProxy(this, undefined, namespace);
}

proxy(value?: unknown): Exotic.Proxy {
proxy(value?: any): Exotic.Proxy {
return createProxy(this, value);
}

Expand All @@ -44,13 +45,21 @@ export default class Emulator extends EventEmitter implements Exotic.Emulator {
return target;
}

parent(value?: any): undefined | Exotic.Proxy {
parent(value?: Exotic.traceable): undefined | Exotic.Proxy {
const proxy = findProxy(value);
if (!proxy) return;
const { origin } = map.proxies.get(proxy);
return origin && origin.proxy;
}

children(value?: Exotic.traceable): Exotic.Proxy[] {
const results = [];
const proxy = findProxy(value);
if (!proxy) return results;
const { sandbox } = map.proxies.get(proxy);
return Reflect.ownKeys(sandbox).map((key) => sandbox[key]);
}

count(): number {
const { activeItems }: Exotic.emulator.data = map.emulators.get(this);
return activeItems;
Expand Down
11 changes: 6 additions & 5 deletions src/types/Exotic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,27 @@ declare namespace Exotic {

interface Emulator extends EventEmitter {
refs: namespace[];
bind(selelctor: namespace): Proxy;
bind(x: namespace): Proxy;
proxy(value?: any): Proxy;
target(value?: any): any;
}

// eslint-disable-next-line @typescript-eslint/ban-types
interface FunctionLike extends Function {
interface FunctionLike {
(...args: any[]): void;
[x: namespace]: any;
[Symbol.iterator](): Iterator<any, any, undefined>;
}

interface Proxy extends FunctionLike {
[x: namespace]: any;
[Symbol.iterator](): Iterator<Proxy, any, undefined>;
}

// eslint-disable-next-line @typescript-eslint/no-namespace
namespace proxy {
interface group {
length: number;
first: Exotic.Proxy;
last: Exotic.Proxy;
root: Exotic.Proxy;
}

interface origin {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const globalNamespace: symbol = Symbol("global");
export const globalNamespace: symbol = Symbol("GLOBAL");
25 changes: 19 additions & 6 deletions src/utils/createProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ import isTraceable from "./isTraceable";
import { globalNamespace } from "./constants";
import traps from "./traps";

const dummyPrototype = Object.assign(Object.create(null), {
[Symbol.iterator]() {
const proxy = findProxy(this);
const { sandbox } = map.proxies.get(proxy);
return function* () {
for (const key of Reflect.ownKeys(sandbox)) {
yield sandbox[key];
}
};
},
});

const createProxy = (
scope: Exotic.Emulator,
target: any,
Expand All @@ -19,26 +31,27 @@ const createProxy = (
const { bindings } = data;

const id = ++data.itemCount;
const dummy: Exotic.FunctionLike = function () {};
const dummy = function () {} as Exotic.FunctionLike;

const traceable = isTraceable(target);
const { proxy, revoke } = Proxy.revocable<Exotic.Proxy>(dummy, traps);
const { proxy, revoke } = Proxy.revocable<Exotic.Proxy>(
Object.setPrototypeOf(dummy, dummyPrototype),
traps,
);

let group: Exotic.proxy.group = bindings[namespace];

if (!group) {
// create the new group
group = {
length: 0,
first: proxy,
last: proxy,
root: proxy,
};

bindings[namespace] = group;
scope.emit("bind", namespace);
}

group.last = proxy;

// set the proxy information
const proxyData: Exotic.proxy.data = {
id,
Expand Down
6 changes: 5 additions & 1 deletion src/utils/traps/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import createProxy from "../createProxy";
import findProxy from "../findProxy";
import map from "../map";

const get = (dummy: Exotic.FunctionLike, key: string): unknown => {
const get = (dummy: Exotic.FunctionLike, key: Exotic.namespace): unknown => {
const proxy = findProxy(dummy);
const { scope, namespace, target, sandbox } = map.proxies.get(proxy);

Expand All @@ -13,6 +13,10 @@ const get = (dummy: Exotic.FunctionLike, key: string): unknown => {
proxy,
};

if (key === Symbol.iterator) {
return dummy[key]();
}

let value: any = sandbox[key];

// get new target from sandbox
Expand Down

0 comments on commit 3a0a50a

Please sign in to comment.