electron-event-flux
Version:
Redux store which synchronizes between instances in multiple process
123 lines (110 loc) • 4.21 kB
text/typescript
const isEmpty = require('lodash/isEmpty');
interface ListStorePathUnit {
index?: string;
name: string;
type: 'Map' | 'List';
};
type StorePathUnit = ListStorePathUnit | string;
type StoreType = 'Store' | 'StoreList' | 'StoreMap';
interface StoreShape {
type: StoreType; // The type of store
filters: { // Store's children store
[key: string]: StoreShape;
} | null;
path?: StorePathUnit[]; // The path of store in the store tree
};
type StoreFilters = {
[name: string]: StoreShape;
}
const ListenForwardKeys = [
'listen', 'unlisten'
];
const IndexForwardKeys = [
'listen', 'unlisten', 'listenForKeys', 'unlistenForKeys'
];
type Stores = { [storeKey: string]: any };
export default class StoreProxyHandler {
storeProxyCache = new Map();
/* Gen proxy for the storePath such as [todoMapStore, todoStore]
forwardStore standard for the forward path
*/
genProxy(storePath: StorePathUnit[], forwardStore: Stores | null, forwarder: Function) {
return new Proxy(forwarder, {
get: function(target, propName) {
if (!propName) return;
if (forwardStore && forwardStore[propName as string]) return forwardStore[propName as string];
if (ListenForwardKeys.indexOf(propName as string) !== -1) {
return function(...args: any[]) {
args.unshift((window as any)['clientId']);
return forwarder({ store: storePath, method: propName, args });
};
}
return function(...args: any[]) {
return forwarder({ store: storePath, method: propName, args });
};
}
})
}
genIndexProxy(storePath: StorePathUnit[], childFilters: { [key: string]: StoreShape }, forwarder: Function) {
let storePathKey = storePath.slice(0, storePath.length - 1).toString();
let newProxy = new Proxy(forwarder, {
get: (target, propName) => {
if (!propName) return;
const retIndexFunc = (index: string) => {
let cacheStore = this.storeProxyCache.get(storePathKey + index);
if (cacheStore) return cacheStore;
let mapStorepath = [
...storePath.slice(0, -1),
{ ...(storePath[storePath.length - 1] as ListStorePathUnit), index }
];
let childStores = this.proxyStore(mapStorepath, childFilters, forwarder);
let newStore = this.genProxy(mapStorepath, childStores, forwarder);
this.storeProxyCache.set(storePathKey + index, newStore);
return newStore;
}
if (IndexForwardKeys.indexOf(propName as string) !== -1) {
let oneStorePath = [
...storePath.slice(0, -1), (storePath[storePath.length - 1] as ListStorePathUnit).name
];
return function(...args: any[]) {
args.unshift((window as any)['clientId']);
return forwarder({ store: oneStorePath, method: propName, args });
};
}
if (propName === 'get') {
return retIndexFunc;
}
return retIndexFunc(propName as string);
}
});
return newProxy;
}
proxyStore(parentStore: StorePathUnit[], storeFilters: StoreFilters, forwarder: Function): Stores | null {
if (isEmpty(storeFilters)) return null;
let stores: { [storeKey: string]: any } = {};
for (let name in storeFilters) {
let storeInfo = storeFilters[name];
if (storeInfo) {
let { type, filters, path = parentStore } = storeInfo;
let names: StorePathUnit[] = [];
if (type === 'Store') {
names = [...path, name];
} else if (type === 'StoreList') {
names = [...path, { name, type: 'List' }];
} else if (type === 'StoreMap') {
names = [...path, { name, type: 'Map' }];
}
if (type === 'Store') {
let childStores = this.proxyStore(names, filters!, forwarder);
stores[name] = this.genProxy(names, childStores, forwarder);
} else {
stores[name] = this.genIndexProxy(names, filters!, forwarder);
}
}
}
return stores;
}
proxyStores(storeFilters: StoreFilters, forwarder: Function): any {
return this.proxyStore([], storeFilters, forwarder);
}
}