import { Subject, Observable } from 'rxjs'; import { share, filter, map } from 'rxjs/operators'; import { ElectronStore as ElectronStoreBase, ElectronStoreOptions, JsonValue, } from './types'; const Base = require('electron-store'); export type ElectronStore = ElectronStoreBase & { events$: Observable; changes$: Observable>; }; export type StoreEvent = IStoreChangeEvent | IStoreClearedEvent; export type IStoreChangeEvent = { type: 'CHANGE'; key: keyof T | string; path: string; from: JsonValue | undefined; to: JsonValue | undefined; }; export type IStoreClearedEvent = { type: 'CLEARED'; }; /** * Create a new electron store. */ export function create(options?: ElectronStoreOptions) { const store = new Store(options) as unknown; return store as ElectronStore; } /** * Extended store with an observable for changes. */ export class Store extends Base { private _events$: Subject>; public readonly events$: Observable>; public readonly changes$: Observable>; constructor(options?: ElectronStoreOptions) { super(options); this._events$ = new Subject>(); this.events$ = this._events$.pipe(share()); this.changes$ = this.events$.pipe( filter(e => e.type === 'CHANGE'), map(e => e as IStoreChangeEvent), ); } public set(key: K, value: T[K]): void { const e = toChangeEvent(key, this.get(key), value); super.set(key, value); if (e.from !== e.to) { this._events$.next(e); } } public delete(key: keyof T | string): void { const e = toChangeEvent(key, this.get(key), undefined); super.delete(key); if (e.from !== e.to) { this._events$.next(e); } } public clear(): void { super.clear(); this._events$.next({ type: 'CLEARED' }); } } /** * INTERNAL */ function toChangeEvent( key: string | keyof T, from: unknown, to: unknown, ): IStoreChangeEvent { let path = key as string; const index = path.lastIndexOf('.'); path = index > -1 ? path.substr(index + 1) : path; return { type: 'CHANGE', key, path, from: from as JsonValue, to: to as JsonValue, }; }