1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- const observable = initial => {
- let internal = initial;
- const listeners = new Set();
- const obs = {};
- obs.get = () => internal;
- obs.set = newValue => {
- const oldValue = internal;
- internal = newValue;
- listeners.forEach(listener => listener(newValue, oldValue));
- };
- obs.sub = callback => {
- listeners.add(callback);
- return () => {
- listeners.delete(callback);
- };
- };
- // ADDED FOR MOCKING
- obs.reset = () => {
- internal = initial;
- };
- // MOCKING MAKES THIS A DIRECT GET
- const useValue = obs.get;
- return [obs, useValue];
- };
- const storeProxy = (store, actions) => {
- const read = key => store[key].get();
- const write = (key, value) => store[key].set(value);
- return new Proxy(
- changes =>
- Object.entries(changes).forEach(([key, change]) =>
- write(key, typeof change === "function" ? change(read(key)) : change)
- ),
- {
- ownKeys: () => [...Reflect.ownKeys(store), ...Reflect.ownKeys(actions)],
- get: (_, key) => actions[key] ?? read(key),
- set: (_, key, value) => {
- if (Object.prototype.hasOwnProperty.call(store, key)) {
- write(key, value);
- return true;
- }
- return false;
- },
- }
- );
- };
- const create = definition => {
- const store = Object.create(null);
- const hooks = Object.create(null);
- const actions = Object.create(null);
- const watch = {
- onChange: callback =>
- Object.entries(store).forEach(([key, obs]) =>
- obs.sub((newValue, oldValue) => callback(key, newValue, oldValue))
- ),
- onCall: callback =>
- Object.entries(actions).forEach(([key, act]) => {
- actions[key] = (...args) => {
- callback(key, ...args);
- return act(...args);
- };
- }),
- setGlobal: storeName => {
- window[storeName] = storeProxy(store, actions);
- },
- };
- Object.entries(definition(storeProxy(store, actions))).forEach(
- ([key, value]) => {
- if (typeof value === "function") {
- actions[key] = value;
- } else {
- const hookName = `use${key.charAt(0).toUpperCase()}${key.slice(1)}`;
- [store[key], hooks[hookName]] = observable(value);
- }
- }
- );
- // ADDED FOR MOCKING
- actions.GET_STORED_VALUE = key => store[key].get();
- // ADDED FOR MOCKING
- actions.SET_STORED_VALUE = (key, value) => store[key].set(value);
- // ADDED FOR MOCKING
- actions.RESET_STORE = () =>
- Object.entries(store).forEach(([, { reset }]) => reset());
- return [hooks, actions, watch];
- };
- export default create;
|