From a10b322157478bdb266d4a59fd841251e82d86ab Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Thu, 1 Aug 2024 16:29:50 -0700 Subject: [PATCH] remove custom stores, remove tracker's reliance on them --- packages/lib/src/Store.ts | 353 ------------------------------------ packages/lib/src/index.ts | 1 - packages/net/src/Tracker.ts | 26 +-- tag.sh | 1 + 4 files changed, 11 insertions(+), 370 deletions(-) delete mode 100644 packages/lib/src/Store.ts diff --git a/packages/lib/src/Store.ts b/packages/lib/src/Store.ts deleted file mode 100644 index c69bedc..0000000 --- a/packages/lib/src/Store.ts +++ /dev/null @@ -1,353 +0,0 @@ -import {throttle} from "throttle-debounce" -import {ensurePlural, identity} from "./Tools" - -// Deprecated: use svelte's stores instead. I did all this to add a `get` convenience -// method that was more perfomant than subscribing/unsubscribing. That turned out to be -// a mistake, since that makes it much harder to make custom stores that don't run when -// there are no subscribers. - -export type Invalidator = (value?: T) => void -export type Subscriber = (value: T) => void - -type Derivable = IDerivable | IDerivable[] -type Unsubscriber = () => void -type R = Record -type M = Map - -export interface ISubscribable { - subscribe(this: void, run: Subscriber, invalidate?: Invalidator): Unsubscriber -} - -export interface ISettable { - set: (xs: T) => void -} - -export interface IDerivable extends ISubscribable { - get: () => T -} - -export interface IReadable extends IDerivable { - derived: (f: (v: T) => U) => IReadable - throttle(t: number): IReadable -} - -export interface IWritable extends IReadable { - set: (xs: T) => void -} - -export class Writable implements IWritable { - value: T - subs: Subscriber[] = [] - - constructor(defaultValue: T, t?: number) { - this.value = defaultValue - - if (t) { - this.notify = throttle(t, this.notify) - } - } - - notify = () => { - for (const sub of this.subs) { - sub(this.value) - } - } - - get() { - return this.value - } - - set(newValue: T) { - this.value = newValue - this.notify() - } - - update(f: (v: T) => T) { - this.set(f(this.value)) - } - - subscribe(f: Subscriber) { - this.subs.push(f) - - f(this.value) - - return () => { - this.subs.splice(this.subs.findIndex(x => x === f), 1) - } - } - - derived(f: (v: T) => U): Derived { - return new Derived(this, f) - } - - throttle = (t: number): Derived => { - return new Derived(this, identity, t) - } -} - -export class Derived implements IReadable { - callerSubs: Subscriber[] = [] - mySubs: Unsubscriber[] = [] - stores: Derivable - getValue: (values: any) => T - latestValue: T | undefined - - constructor(stores: Derivable, getValue: (values: any) => T, t = 0) { - this.stores = stores - this.getValue = getValue - - if (t) { - this.notify = throttle(t, this.notify) - } - } - - notify = () => { - this.latestValue = undefined - this.callerSubs.forEach(f => f(this.get())) - } - - getInput() { - if (Array.isArray(this.stores)) { - return this.stores.map(s => s.get()) - } else { - return this.stores.get() - } - } - - get = (): T => { - // Recalculate if we're not subscribed, because we won't get notified when deps change - if (this.latestValue === undefined || this.mySubs.length === 0) { - this.latestValue = this.getValue(this.getInput()) - } - - return this.latestValue - } - - subscribe(f: Subscriber) { - if (this.callerSubs.length === 0) { - for (const s of ensurePlural(this.stores)) { - this.mySubs.push(s.subscribe(this.notify)) - } - } - - this.callerSubs.push(f) - - f(this.get()) - - return () => { - this.callerSubs.splice(this.callerSubs.findIndex(x => x === f), 1) - - if (this.callerSubs.length === 0) { - for (const unsub of this.mySubs.splice(0)) { - unsub() - } - } - } - } - - derived(f: (v: T) => U): IReadable { - return new Derived(this, f) as IReadable - } - - throttle = (t: number): IReadable => { - return new Derived(this, identity, t) - } -} - -export class Key implements IReadable { - readonly pk: string - readonly key: string - base: Writable> - store: IReadable - - constructor(base: Writable>, pk: string, key: string) { - if (!(base.get() instanceof Map)) { - throw new Error("`key` can only be used on map collections") - } - - this.pk = pk - this.key = key - this.base = base - this.store = base.derived(m => m.get(key) as T) - } - - get = () => this.base.get().get(this.key) as T - - subscribe = (f: Subscriber) => this.store.subscribe(f) - - derived = (f: (v: T) => U) => this.store.derived(f) - - throttle = (t: number) => this.store.throttle(t) - - exists = () => this.base.get().has(this.key) - - update = (f: (v: T) => T) => - this.base.update((m: M) => { - if (!this.key) { - throw new Error(`Cannot set key: "${this.key}"`) - } - - // Make sure the pk always get set on the record - const {pk, key} = this - const oldValue = {...m.get(key), [pk]: key} as T - const newValue = {...f(oldValue), [pk]: key} - - m.set(this.key, newValue) - - return m - }) - - set = (v: T) => this.update(() => v) - - merge = (d: Partial) => this.update(v => ({...v, ...d})) - - remove = () => - this.base.update(m => { - m.delete(this.key) - - return m - }) - - pop = () => { - const v = this.get() - - this.remove() - - return v - } -} - -export class DerivedKey implements IReadable { - readonly pk: string - readonly key: string - base: IReadable> - store: IReadable - - constructor(base: IReadable>, pk: string, key: string) { - if (!(base.get() instanceof Map)) { - throw new Error("`key` can only be used on map collections") - } - - this.pk = pk - this.key = key - this.base = base - this.store = base.derived(m => m.get(key) as T) - } - - get = () => this.base.get().get(this.key) as T - - subscribe = (f: Subscriber) => this.store.subscribe(f) - - derived = (f: (v: T) => U) => this.store.derived(f) - - throttle = (t: number) => this.store.throttle(t) - - exists = () => this.base.get().has(this.key) -} - -export class Collection implements IReadable { - readonly pk: string - readonly mapStore: Writable> - readonly listStore: IReadable - - constructor(pk: string, t?: number) { - this.pk = pk - this.mapStore = writable(new Map()) - this.listStore = this.mapStore.derived((m: M) => Array.from(m.values())) - - if (t) { - this.mapStore.notify = throttle(t, this.mapStore.notify) - } - } - - get = () => this.listStore.get() - - getMap = () => this.mapStore.get() - - subscribe = (f: Subscriber) => this.listStore.subscribe(f) - - derived = (f: (v: T[]) => U) => this.listStore.derived(f) - - throttle = (t: number) => this.listStore.throttle(t) - - key = (k: string) => new Key(this.mapStore, this.pk, k) - - set = (xs: T[]) => { - const m = new Map() - - for (const x of xs) { - if (!x) { - console.error("Empty value passed to collection store") - } else if (!x[this.pk]) { - console.error(`Value with empty ${this.pk} passed to collection store`, x) - } else { - m.set(x[this.pk], x) - } - } - - this.mapStore.set(m) - } - - update = (f: (v: T[]) => T[]) => this.set(f(this.get())) - - updateAsync = async (f: (v: T[]) => Promise) => this.set(await f(this.get())) - - reject = (f: (v: T) => boolean) => this.update((xs: T[]) => xs.filter(x => !f(x))) - - filter = (f: (v: T) => boolean) => this.update((xs: T[]) => xs.filter(f)) - - map = (f: (v: T) => T) => this.update((xs: T[]) => xs.map(f)) -} - -export class DerivedCollection implements IReadable { - readonly listStore: Derived - readonly mapStore: IReadable> - - constructor( - readonly pk: string, - stores: Derivable, - getValue: (values: any) => T[], - t = 0, - ) { - this.listStore = new Derived(stores, getValue, t) - this.mapStore = new Derived(this.listStore, xs => new Map(xs.map((x: T) => [x[pk], x]))) - } - - get = () => this.listStore.get() - - getMap = () => this.mapStore.get() - - subscribe = (f: Subscriber) => this.listStore.subscribe(f) - - derived = (f: (v: T[]) => U) => this.listStore.derived(f) - - throttle = (t: number) => this.listStore.throttle(t) - - key = (k: string) => new DerivedKey(this.mapStore, this.pk, k) -} - -export const writable = (v: T) => new Writable(v) - -export const derived = (stores: Derivable, getValue: (values: any) => T) => - new Derived(stores, getValue) - -export const readable = (v: T) => derived(new Writable(v), identity) as IReadable - -export const derivedCollection = ( - pk: string, - stores: Derivable, - getValue: (values: any) => T[], -) => new DerivedCollection(pk, stores, getValue) - -export const key = (base: Writable>, pk: string, key: string) => - new Key(base, pk, key) - -export const collection = (pk: string) => new Collection(pk) - -export const asReadable = (store: IDerivable) => { - return { - ...store, - derived: (f: (v: T) => U) => new Derived(store, f), - throttle: (t: number) => new Derived(store, identity, t), - } -} diff --git a/packages/lib/src/index.ts b/packages/lib/src/index.ts index 667162c..86942bf 100644 --- a/packages/lib/src/index.ts +++ b/packages/lib/src/index.ts @@ -2,7 +2,6 @@ export * from './Deferred' export * from './Emitter' export * from './Fluent' export * from './LRUCache' -export * from './Store' export * from './Tools' export * from './Worker' export {default as normalizeUrl} from './normalize-url' diff --git a/packages/net/src/Tracker.ts b/packages/net/src/Tracker.ts index 36bfc76..09adf37 100644 --- a/packages/net/src/Tracker.ts +++ b/packages/net/src/Tracker.ts @@ -1,12 +1,12 @@ -import {writable} from '@welshman/lib' +import {Emitter} from '@welshman/lib' -export class Tracker { - data = writable(new Map>()) +export class Tracker extends Emitter { + data = new Map>() getRelays = (eventId: string) => { const relays = new Set() - for (const relay of this.data.get().get(eventId) || []) { + for (const relay of this.data.get(eventId) || []) { relays.add(relay) } @@ -18,19 +18,16 @@ export class Tracker { } addRelay = (eventId: string, relay: string) => { - const relays = this.data.get().get(eventId) || new Set() + const relays = this.data.get(eventId) || new Set() relays.add(relay) - this.data.update(m => { - m.set(eventId, relays) - - return m - }) + this.data.set(eventId, relays) + this.emit('update') } track = (eventId: string, relay: string) => { - const seen = this.data.get().has(eventId) + const seen = this.data.has(eventId) this.addRelay(eventId, relay) @@ -44,10 +41,7 @@ export class Tracker { } clear = () => { - this.data.update(m => { - m.clear() - - return m - }) + this.data.clear() + this.emit('update') } } diff --git a/tag.sh b/tag.sh index 278846b..504dcbf 100755 --- a/tag.sh +++ b/tag.sh @@ -12,4 +12,5 @@ for pkg in $(./get_packages.py); do git tag "$pkg/$version" >/dev/null 2>&1 done +git push git push --tags