Skip to content

Commit

Permalink
fix: ajusta la manera en que los grupos son creados
Browse files Browse the repository at this point in the history
  • Loading branch information
drusco committed Aug 5, 2023
1 parent e7c2eae commit faaab51
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 168 deletions.
255 changes: 148 additions & 107 deletions src/Emulator.spec.ts

Large diffs are not rendered by default.

79 changes: 53 additions & 26 deletions src/Emulator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Exotic from "./types/Exotic";
import { findProxy, map, createProxy } from "./utils";
import { symbols } from "./utils/constants";
import { EventEmitter } from "events";

export default class Emulator extends EventEmitter implements Exotic.Emulator {
Expand All @@ -8,17 +9,17 @@ export default class Emulator extends EventEmitter implements Exotic.Emulator {

const data: Exotic.emulator.data = {
options,
keys: Object.create(null),
refs: Object.create(null),
totalProxies: 0, // total item count including revoked items, it only increases
activeProxies: 0, // items that are not revoked
};

map.emulators.set(this, data);
}

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

get active(): number {
Expand All @@ -38,8 +39,8 @@ export default class Emulator extends EventEmitter implements Exotic.Emulator {
}

bind(key: Exotic.key): Exotic.Proxy {
const { keys }: Exotic.emulator.data = map.emulators.get(this);
const group = keys[key];
const { refs }: Exotic.emulator.data = map.emulators.get(this);
const group = refs[key];

// return the first proxy in the existing group
if (group) return group.root;
Expand All @@ -48,7 +49,7 @@ export default class Emulator extends EventEmitter implements Exotic.Emulator {
return createProxy(this, undefined, key);
}

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

Expand All @@ -75,16 +76,15 @@ export default class Emulator extends EventEmitter implements Exotic.Emulator {
}

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

encode(value: unknown): unknown {
if (findProxy(value)) {
const { id } = map.proxies.get(this.proxy(value));
const { id } = map.proxies.get(this.use(value));
return { id, encoded: true }; // TODO: usar Symbol para saber si es encoded o no
}

Expand All @@ -105,23 +105,26 @@ export default class Emulator extends EventEmitter implements Exotic.Emulator {
const proxy = findProxy(value);
if (!proxy) return;

const { id, binding, mock, revoke, target } = map.proxies.get(proxy);
const { id, refKey, mock, revoke, target, origin } = map.proxies.get(proxy);
const data = map.emulators.get(this);
const { keys } = data;
const group = keys[binding];

if (group) {
group.length -= 1;
const { refs } = data;
const group = refs[refKey];

if (!group.length) {
// delete empty group
delete keys[binding];
this.emit("unbind", binding);
}
if (group.root === proxy) {
// delete group
delete refs[refKey];
this.emit("unbind", refKey);
}

// remove item references

if (origin) {
const { action, key, proxy: parentProxy } = origin;
if (action === "get" || action === "set") {
if (parentProxy) delete parentProxy[key];
}
}

map.mocks.delete(mock);
map.targets.delete(target);
map.proxies.delete(proxy);
Expand All @@ -133,15 +136,39 @@ export default class Emulator extends EventEmitter implements Exotic.Emulator {
this.emit("revoke", id);
}

destroy(): void {
this.removeAllListeners();
map.emulators.delete(this);
//revokeAll(value?: Exotic.traceable): void {
// const proxy = findProxy(value);
// if (!proxy) {
// this.keys.forEach(key => this.revoke())
// return;
// }
//}

*entries(value?: Exotic.traceable): Iterable<[Exotic.key, Exotic.Proxy]> {
if (value === undefined) {
for (const ref of this.refs) {
console.log("--ref", ref, this.ownKeys(this.bind(ref)));
this.entries(this.bind(ref));
}
return;
}

console.log("prox", value);

const proxy = findProxy(value);
if (!proxy) return;

const { sandbox } = map.proxies.get(proxy);

for (const key of Reflect.ownKeys(sandbox)) {
yield [key, sandbox[key]];
}
}

resolve(value: any): Exotic.proxy.public {
if (!findProxy(value)) return value;
const proxy = this.proxy(value);
const proxy = this.use(value);
const { id, target } = map.proxies.get(proxy);
return { id, target };
return { id, target, [symbols.PROXY]: true };
}
}
16 changes: 9 additions & 7 deletions src/types/Exotic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ declare namespace Exotic {
type key = string | symbol;

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

Expand All @@ -26,8 +26,8 @@ declare namespace Exotic {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace proxy {
interface group {
length: number;
root: Exotic.Proxy;
last: Exotic.Proxy;
}

interface sandbox {
Expand All @@ -51,10 +51,12 @@ declare namespace Exotic {
interface data extends public {
revoke(): void;
mock: Mock;
origin?: proxy.origin;
origin?: proxy.origin | undefined;
scope: Emulator;
sandbox: sandbox;
binding: key;
refKey: key;
next?: Proxy;
prev?: Proxy;
}
}

Expand All @@ -64,13 +66,13 @@ declare namespace Exotic {
[x: string]: any;
}

interface bindings {
interface refs {
[x: key]: proxy.group;
}

interface data {
options: options;
keys: bindings;
refs: refs;
totalProxies: number;
activeProxies: number;
}
Expand Down
5 changes: 4 additions & 1 deletion src/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export const globalKey: symbol = Symbol("GLOBAL");
export const symbols = {
GLOBAL: Symbol("GLOBAL"),
PROXY: Symbol("PROXY"),
};
32 changes: 22 additions & 10 deletions src/utils/createProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ import Exotic from "../types/Exotic";
import map from "./map";
import findProxy from "./findProxy";
import isTraceable from "./isTraceable";
import { globalKey } from "./constants";
import { symbols } from "./constants";
import mockPrototype from "./mockPrototype";
import traps from "./traps";

const createProxy = (
scope: Exotic.Emulator,
target: any,
binding: Exotic.key = globalKey,
refKey: Exotic.key = symbols.GLOBAL,
origin?: Exotic.proxy.origin, // the action used to create the proxy
): Exotic.Proxy => {
// target is already a proxy; no proxy out of proxy; no duplicates
const currentProxy = findProxy(target);
if (currentProxy) return currentProxy;

const data: Exotic.emulator.data = map.emulators.get(scope);
const { keys } = data;
const { refs } = data;

const id = ++data.totalProxies;
const mock = function mock() {} as Exotic.Mock;
Expand All @@ -28,19 +28,21 @@ const createProxy = (
traps,
);

let group: Exotic.proxy.group = keys[binding];
let group: Exotic.proxy.group = refs[refKey];

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

keys[binding] = group;
scope.emit("bind", binding);
refs[refKey] = group;
scope.emit("bind", refKey);
}

const previousProxy = group.last === proxy ? undefined : group.last;

// set the proxy information
const proxyData: Exotic.proxy.data = {
id,
Expand All @@ -50,17 +52,27 @@ const createProxy = (
revoke,
scope,
sandbox: Object.create(null),
binding,
refKey,
prev: previousProxy,
next: undefined,
};

if (previousProxy) {
// update previous proxy
const prevData = map.proxies.get(previousProxy);
if (prevData) {
prevData.next = proxy;
}
}

scope.emit("proxy", {
id,
proxy,
origin,
binding,
ref: refKey,
});

group.length += 1;
group.last = proxy;
data.activeProxies += 1;

map.mocks.set(mock, proxy);
Expand Down
10 changes: 4 additions & 6 deletions src/utils/mockPrototype.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import findProxy from "./findProxy";
import map from "./map";

export default Object.assign(Object.create(null), {
[Symbol.iterator]() {
*[Symbol.iterator]() {
const proxy = findProxy(this);
const { sandbox } = map.proxies.get(proxy);
return function* () {
for (const key of Reflect.ownKeys(sandbox)) {
yield sandbox[key];
}
};
for (const key of Reflect.ownKeys(sandbox)) {
yield sandbox[key];
}
},
});
6 changes: 3 additions & 3 deletions src/utils/traps/apply.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import map from "../map";

const apply = (mock: Exotic.Mock, that?: any, args?: any[]): any => {
const proxy = findProxy(mock);
const { scope, binding, target } = map.proxies.get(proxy);
const { scope, refKey, target } = map.proxies.get(proxy);

const origin: Exotic.proxy.origin = {
action: "apply",
Expand All @@ -20,10 +20,10 @@ const apply = (mock: Exotic.Mock, that?: any, args?: any[]): any => {
value = Reflect.apply(scope.target(target), scope.target(that), args);
}

const argList = args.map((arg) => createProxy(scope, arg, binding, origin));
const argList = args.map((arg) => createProxy(scope, arg, refKey, origin));
origin.args = argList;

return createProxy(scope, value, binding, origin);
return createProxy(scope, value, refKey, origin);
};

export default apply;
6 changes: 3 additions & 3 deletions src/utils/traps/construct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import map from "../map";

const construct = (mock: Exotic.Mock, args: any[]): object => {
const proxy = findProxy(mock);
const { scope, binding, target } = map.proxies.get(proxy);
const { scope, refKey, target } = map.proxies.get(proxy);

const origin: Exotic.proxy.origin = {
action: "construct",
Expand All @@ -19,10 +19,10 @@ const construct = (mock: Exotic.Mock, args: any[]): object => {
value = Reflect.construct(target, args);
}

const argList = args.map((arg) => createProxy(scope, arg, binding, origin));
const argList = args.map((arg) => createProxy(scope, arg, refKey, origin));
origin.args = argList;

return createProxy(scope, value, binding, origin);
return createProxy(scope, value, refKey, origin);
};

export default construct;
6 changes: 3 additions & 3 deletions src/utils/traps/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import map from "../map";

const get = (mock: Exotic.Mock, key: Exotic.key): any => {
const proxy = findProxy(mock);
const { scope, binding, target, sandbox } = map.proxies.get(proxy);
const { scope, refKey, target, sandbox } = map.proxies.get(proxy);

const origin: Exotic.proxy.origin = {
action: "get",
Expand All @@ -14,7 +14,7 @@ const get = (mock: Exotic.Mock, key: Exotic.key): any => {
};

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

let value: any;
Expand All @@ -31,7 +31,7 @@ const get = (mock: Exotic.Mock, key: Exotic.key): any => {
value = sandbox[key];
}

sandbox[key] = createProxy(scope, value, binding, origin);
sandbox[key] = createProxy(scope, value, refKey, origin);

return Reflect.get(sandbox, key);
};
Expand Down
4 changes: 2 additions & 2 deletions src/utils/traps/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import map from "../map";

const set = (mock: Exotic.Mock, key: Exotic.key, value: any): boolean => {
const proxy = findProxy(mock);
const { scope, binding, sandbox, target } = map.proxies.get(proxy);
const { scope, refKey, sandbox, target } = map.proxies.get(proxy);

const origin: Exotic.proxy.origin = {
action: "set",
Expand All @@ -14,7 +14,7 @@ const set = (mock: Exotic.Mock, key: Exotic.key, value: any): boolean => {
value,
};

const newValue = createProxy(scope, value, binding, origin);
const newValue = createProxy(scope, value, refKey, origin);
origin.value = newValue;

scope.emit("action", {
Expand Down

0 comments on commit faaab51

Please sign in to comment.