@tanstack/store 0.7.6 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,12 +26,8 @@ class Derived {
26
26
  this.recompute = () => {
27
27
  var _a, _b;
28
28
  this.prevState = this.state;
29
- const { prevDepVals, currDepVals, prevVal } = this.getDepVals();
30
- this.state = this.options.fn({
31
- prevDepVals,
32
- currDepVals,
33
- prevVal
34
- });
29
+ const depVals = this.getDepVals();
30
+ this.state = this.options.fn(depVals);
35
31
  (_b = (_a = this.options).onUpdate) == null ? void 0 : _b.call(_a);
36
32
  };
37
33
  this.checkIfRecalculationNeededDeeply = () => {
@@ -80,6 +76,7 @@ class Derived {
80
76
  });
81
77
  }
82
78
  registerOnGraph(deps = this.options.deps) {
79
+ const toSort = /* @__PURE__ */ new Set();
83
80
  for (const dep of deps) {
84
81
  if (dep instanceof Derived) {
85
82
  dep.registerOnGraph();
@@ -87,10 +84,12 @@ class Derived {
87
84
  } else if (dep instanceof store.Store) {
88
85
  let relatedLinkedDerivedVals = scheduler.__storeToDerived.get(dep);
89
86
  if (!relatedLinkedDerivedVals) {
90
- relatedLinkedDerivedVals = /* @__PURE__ */ new Set();
87
+ relatedLinkedDerivedVals = [this];
91
88
  scheduler.__storeToDerived.set(dep, relatedLinkedDerivedVals);
89
+ } else if (!relatedLinkedDerivedVals.includes(this)) {
90
+ relatedLinkedDerivedVals.push(this);
91
+ toSort.add(relatedLinkedDerivedVals);
92
92
  }
93
- relatedLinkedDerivedVals.add(this);
94
93
  let relatedStores = scheduler.__derivedToStore.get(this);
95
94
  if (!relatedStores) {
96
95
  relatedStores = /* @__PURE__ */ new Set();
@@ -99,6 +98,13 @@ class Derived {
99
98
  relatedStores.add(dep);
100
99
  }
101
100
  }
101
+ for (const arr of toSort) {
102
+ arr.sort((a, b) => {
103
+ if (a instanceof Derived && a.options.deps.includes(b)) return 1;
104
+ if (b instanceof Derived && b.options.deps.includes(a)) return -1;
105
+ return 0;
106
+ });
107
+ }
102
108
  }
103
109
  unregisterFromGraph(deps = this.options.deps) {
104
110
  for (const dep of deps) {
@@ -107,7 +113,10 @@ class Derived {
107
113
  } else if (dep instanceof store.Store) {
108
114
  const relatedLinkedDerivedVals = scheduler.__storeToDerived.get(dep);
109
115
  if (relatedLinkedDerivedVals) {
110
- relatedLinkedDerivedVals.delete(this);
116
+ relatedLinkedDerivedVals.splice(
117
+ relatedLinkedDerivedVals.indexOf(this),
118
+ 1
119
+ );
111
120
  }
112
121
  const relatedStores = scheduler.__derivedToStore.get(this);
113
122
  if (relatedStores) {
@@ -1 +1 @@
1
- {"version":3,"file":"derived.cjs","sources":["../../src/derived.ts"],"sourcesContent":["import { Store } from './store'\nimport { __derivedToStore, __storeToDerived } from './scheduler'\nimport type { Listener } from './types'\n\nexport type UnwrapDerivedOrStore<T> =\n T extends Derived<infer InnerD>\n ? InnerD\n : T extends Store<infer InnerS>\n ? InnerS\n : never\n\ntype UnwrapReadonlyDerivedOrStoreArray<\n TArr extends ReadonlyArray<Derived<any> | Store<any>>,\n> = TArr extends readonly []\n ? []\n : TArr extends readonly [infer Head, ...infer Tail]\n ? Head extends Derived<any> | Store<any>\n ? Tail extends ReadonlyArray<Derived<any> | Store<any>>\n ? [\n UnwrapDerivedOrStore<Head>,\n ...UnwrapReadonlyDerivedOrStoreArray<Tail>,\n ]\n : [UnwrapDerivedOrStore<Head>]\n : []\n : TArr extends ReadonlyArray<Derived<any> | Store<any>>\n ? Array<UnwrapDerivedOrStore<TArr[number]>>\n : []\n\n// Can't have currVal, as it's being evaluated from the current derived fn\nexport interface DerivedFnProps<\n TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n TUnwrappedArr extends\n UnwrapReadonlyDerivedOrStoreArray<TArr> = UnwrapReadonlyDerivedOrStoreArray<TArr>,\n> {\n // `undefined` if it's the first run\n /**\n * `undefined` if it's the first run\n * @privateRemarks this also cannot be typed as TState, as it breaks the inferencing of the function's return type when an argument is used - even with `NoInfer` usage\n */\n prevVal: unknown | undefined\n prevDepVals: TUnwrappedArr | undefined\n currDepVals: TUnwrappedArr\n}\n\nexport interface DerivedOptions<\n TState,\n TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n> {\n onSubscribe?: (\n listener: Listener<TState>,\n derived: Derived<TState>,\n ) => () => void\n onUpdate?: () => void\n deps: TArr\n /**\n * Values of the `deps` from before and after the current invocation of `fn`\n */\n fn: (props: DerivedFnProps<TArr>) => TState\n}\n\nexport class Derived<\n TState,\n const TArr extends ReadonlyArray<\n Derived<any> | Store<any>\n > = ReadonlyArray<any>,\n> {\n listeners = new Set<Listener<TState>>()\n state: TState\n prevState: TState | undefined\n options: DerivedOptions<TState, TArr>\n\n /**\n * Functions representing the subscriptions. Call a function to cleanup\n * @private\n */\n _subscriptions: Array<() => void> = []\n\n lastSeenDepValues: Array<unknown> = []\n getDepVals = () => {\n const l = this.options.deps.length\n const prevDepVals = new Array<unknown>(l)\n const currDepVals = new Array<unknown>(l)\n for (let i = 0; i < l; i++) {\n const dep = this.options.deps[i]!\n prevDepVals[i] = dep.prevState\n currDepVals[i] = dep.state\n }\n this.lastSeenDepValues = currDepVals\n return {\n prevDepVals,\n currDepVals,\n prevVal: this.prevState ?? undefined,\n }\n }\n\n constructor(options: DerivedOptions<TState, TArr>) {\n this.options = options\n this.state = options.fn({\n prevDepVals: undefined,\n prevVal: undefined,\n currDepVals: this.getDepVals().currDepVals as never,\n })\n }\n\n registerOnGraph(\n deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n ) {\n for (const dep of deps) {\n if (dep instanceof Derived) {\n // First register the intermediate derived value if it's not already registered\n dep.registerOnGraph()\n // Then register this derived with the dep's underlying stores\n this.registerOnGraph(dep.options.deps)\n } else if (dep instanceof Store) {\n // Register the derived as related derived to the store\n let relatedLinkedDerivedVals = __storeToDerived.get(dep)\n if (!relatedLinkedDerivedVals) {\n relatedLinkedDerivedVals = new Set()\n __storeToDerived.set(dep, relatedLinkedDerivedVals)\n }\n relatedLinkedDerivedVals.add(this as never)\n\n // Register the store as a related store to this derived\n let relatedStores = __derivedToStore.get(this as never)\n if (!relatedStores) {\n relatedStores = new Set()\n __derivedToStore.set(this as never, relatedStores)\n }\n relatedStores.add(dep)\n }\n }\n }\n\n unregisterFromGraph(\n deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n ) {\n for (const dep of deps) {\n if (dep instanceof Derived) {\n this.unregisterFromGraph(dep.options.deps)\n } else if (dep instanceof Store) {\n const relatedLinkedDerivedVals = __storeToDerived.get(dep)\n if (relatedLinkedDerivedVals) {\n relatedLinkedDerivedVals.delete(this as never)\n }\n\n const relatedStores = __derivedToStore.get(this as never)\n if (relatedStores) {\n relatedStores.delete(dep)\n }\n }\n }\n }\n\n recompute = () => {\n this.prevState = this.state\n const { prevDepVals, currDepVals, prevVal } = this.getDepVals()\n this.state = this.options.fn({\n prevDepVals: prevDepVals as never,\n currDepVals: currDepVals as never,\n prevVal,\n })\n\n this.options.onUpdate?.()\n }\n\n checkIfRecalculationNeededDeeply = () => {\n for (const dep of this.options.deps) {\n if (dep instanceof Derived) {\n dep.checkIfRecalculationNeededDeeply()\n }\n }\n let shouldRecompute = false\n const lastSeenDepValues = this.lastSeenDepValues\n const { currDepVals } = this.getDepVals()\n for (let i = 0; i < currDepVals.length; i++) {\n if (currDepVals[i] !== lastSeenDepValues[i]) {\n shouldRecompute = true\n break\n }\n }\n\n if (shouldRecompute) {\n this.recompute()\n }\n }\n\n mount = () => {\n this.registerOnGraph()\n this.checkIfRecalculationNeededDeeply()\n\n return () => {\n this.unregisterFromGraph()\n for (const cleanup of this._subscriptions) {\n cleanup()\n }\n }\n }\n\n subscribe = (listener: Listener<TState>) => {\n this.listeners.add(listener)\n const unsub = this.options.onSubscribe?.(listener, this)\n return () => {\n this.listeners.delete(listener)\n unsub?.()\n }\n }\n}\n"],"names":["Store","__storeToDerived","__derivedToStore"],"mappings":"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"}
1
+ {"version":3,"file":"derived.cjs","sources":["../../src/derived.ts"],"sourcesContent":["import { Store } from './store'\nimport { __derivedToStore, __storeToDerived } from './scheduler'\nimport type { Listener } from './types'\n\nexport type UnwrapDerivedOrStore<T> =\n T extends Derived<infer InnerD>\n ? InnerD\n : T extends Store<infer InnerS>\n ? InnerS\n : never\n\ntype UnwrapReadonlyDerivedOrStoreArray<\n TArr extends ReadonlyArray<Derived<any> | Store<any>>,\n> = TArr extends readonly []\n ? []\n : TArr extends readonly [infer Head, ...infer Tail]\n ? Head extends Derived<any> | Store<any>\n ? Tail extends ReadonlyArray<Derived<any> | Store<any>>\n ? [\n UnwrapDerivedOrStore<Head>,\n ...UnwrapReadonlyDerivedOrStoreArray<Tail>,\n ]\n : [UnwrapDerivedOrStore<Head>]\n : []\n : TArr extends ReadonlyArray<Derived<any> | Store<any>>\n ? Array<UnwrapDerivedOrStore<TArr[number]>>\n : []\n\n// Can't have currVal, as it's being evaluated from the current derived fn\nexport interface DerivedFnProps<\n TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n TUnwrappedArr extends\n UnwrapReadonlyDerivedOrStoreArray<TArr> = UnwrapReadonlyDerivedOrStoreArray<TArr>,\n> {\n // `undefined` if it's the first run\n /**\n * `undefined` if it's the first run\n * @privateRemarks this also cannot be typed as TState, as it breaks the inferencing of the function's return type when an argument is used - even with `NoInfer` usage\n */\n prevVal: unknown | undefined\n prevDepVals: TUnwrappedArr | undefined\n currDepVals: TUnwrappedArr\n}\n\nexport interface DerivedOptions<\n TState,\n TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n> {\n onSubscribe?: (\n listener: Listener<TState>,\n derived: Derived<TState>,\n ) => () => void\n onUpdate?: () => void\n deps: TArr\n /**\n * Values of the `deps` from before and after the current invocation of `fn`\n */\n fn: (props: DerivedFnProps<TArr>) => TState\n}\n\nexport class Derived<\n TState,\n const TArr extends ReadonlyArray<\n Derived<any> | Store<any>\n > = ReadonlyArray<any>,\n> {\n listeners = new Set<Listener<TState>>()\n state: TState\n prevState: TState | undefined\n options: DerivedOptions<TState, TArr>\n\n /**\n * Functions representing the subscriptions. Call a function to cleanup\n * @private\n */\n _subscriptions: Array<() => void> = []\n\n lastSeenDepValues: Array<unknown> = []\n getDepVals = () => {\n const l = this.options.deps.length\n const prevDepVals = new Array<unknown>(l)\n const currDepVals = new Array<unknown>(l)\n for (let i = 0; i < l; i++) {\n const dep = this.options.deps[i]!\n prevDepVals[i] = dep.prevState\n currDepVals[i] = dep.state\n }\n this.lastSeenDepValues = currDepVals\n return {\n prevDepVals,\n currDepVals,\n prevVal: this.prevState ?? undefined,\n }\n }\n\n constructor(options: DerivedOptions<TState, TArr>) {\n this.options = options\n this.state = options.fn({\n prevDepVals: undefined,\n prevVal: undefined,\n currDepVals: this.getDepVals().currDepVals as never,\n })\n }\n\n registerOnGraph(\n deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n ) {\n const toSort = new Set<Array<Derived<unknown>>>()\n for (const dep of deps) {\n if (dep instanceof Derived) {\n // First register the intermediate derived value if it's not already registered\n dep.registerOnGraph()\n // Then register this derived with the dep's underlying stores\n this.registerOnGraph(dep.options.deps)\n } else if (dep instanceof Store) {\n // Register the derived as related derived to the store\n let relatedLinkedDerivedVals = __storeToDerived.get(dep)\n if (!relatedLinkedDerivedVals) {\n relatedLinkedDerivedVals = [this as never]\n __storeToDerived.set(dep, relatedLinkedDerivedVals)\n } else if (!relatedLinkedDerivedVals.includes(this as never)) {\n relatedLinkedDerivedVals.push(this as never)\n toSort.add(relatedLinkedDerivedVals)\n }\n\n // Register the store as a related store to this derived\n let relatedStores = __derivedToStore.get(this as never)\n if (!relatedStores) {\n relatedStores = new Set()\n __derivedToStore.set(this as never, relatedStores)\n }\n relatedStores.add(dep)\n }\n }\n for (const arr of toSort) {\n // First sort deriveds by dependency order\n arr.sort((a, b) => {\n // If a depends on b, b should go first\n if (a instanceof Derived && a.options.deps.includes(b)) return 1\n // If b depends on a, a should go first\n if (b instanceof Derived && b.options.deps.includes(a)) return -1\n return 0\n })\n }\n }\n\n unregisterFromGraph(\n deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n ) {\n for (const dep of deps) {\n if (dep instanceof Derived) {\n this.unregisterFromGraph(dep.options.deps)\n } else if (dep instanceof Store) {\n const relatedLinkedDerivedVals = __storeToDerived.get(dep)\n if (relatedLinkedDerivedVals) {\n relatedLinkedDerivedVals.splice(\n relatedLinkedDerivedVals.indexOf(this as never),\n 1,\n )\n }\n\n const relatedStores = __derivedToStore.get(this as never)\n if (relatedStores) {\n relatedStores.delete(dep)\n }\n }\n }\n }\n\n recompute = () => {\n this.prevState = this.state\n const depVals = this.getDepVals()\n this.state = this.options.fn(depVals as never)\n\n this.options.onUpdate?.()\n }\n\n checkIfRecalculationNeededDeeply = () => {\n for (const dep of this.options.deps) {\n if (dep instanceof Derived) {\n dep.checkIfRecalculationNeededDeeply()\n }\n }\n let shouldRecompute = false\n const lastSeenDepValues = this.lastSeenDepValues\n const { currDepVals } = this.getDepVals()\n for (let i = 0; i < currDepVals.length; i++) {\n if (currDepVals[i] !== lastSeenDepValues[i]) {\n shouldRecompute = true\n break\n }\n }\n\n if (shouldRecompute) {\n this.recompute()\n }\n }\n\n mount = () => {\n this.registerOnGraph()\n this.checkIfRecalculationNeededDeeply()\n\n return () => {\n this.unregisterFromGraph()\n for (const cleanup of this._subscriptions) {\n cleanup()\n }\n }\n }\n\n subscribe = (listener: Listener<TState>) => {\n this.listeners.add(listener)\n const unsub = this.options.onSubscribe?.(listener, this)\n return () => {\n this.listeners.delete(listener)\n unsub?.()\n }\n }\n}\n"],"names":["Store","__storeToDerived","__derivedToStore"],"mappings":";;;;AA4DO,MAAM,QAKX;AAAA,EA8BA,YAAY,SAAuC;AA7BnD,SAAA,gCAAgB,IAAA;AAShB,SAAA,iBAAoC,CAAA;AAEpC,SAAA,oBAAoC,CAAA;AACpC,SAAA,aAAa,MAAM;AACjB,YAAM,IAAI,KAAK,QAAQ,KAAK;AAC5B,YAAM,cAAc,IAAI,MAAe,CAAC;AACxC,YAAM,cAAc,IAAI,MAAe,CAAC;AACxC,eAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,cAAM,MAAM,KAAK,QAAQ,KAAK,CAAC;AAC/B,oBAAY,CAAC,IAAI,IAAI;AACrB,oBAAY,CAAC,IAAI,IAAI;AAAA,MACvB;AACA,WAAK,oBAAoB;AACzB,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,SAAS,KAAK,aAAa;AAAA,MAAA;AAAA,IAE/B;AA4EA,SAAA,YAAY,MAAM;;AAChB,WAAK,YAAY,KAAK;AACtB,YAAM,UAAU,KAAK,WAAA;AACrB,WAAK,QAAQ,KAAK,QAAQ,GAAG,OAAgB;AAE7C,uBAAK,SAAQ,aAAb;AAAA,IACF;AAEA,SAAA,mCAAmC,MAAM;AACvC,iBAAW,OAAO,KAAK,QAAQ,MAAM;AACnC,YAAI,eAAe,SAAS;AAC1B,cAAI,iCAAA;AAAA,QACN;AAAA,MACF;AACA,UAAI,kBAAkB;AACtB,YAAM,oBAAoB,KAAK;AAC/B,YAAM,EAAE,YAAA,IAAgB,KAAK,WAAA;AAC7B,eAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,YAAI,YAAY,CAAC,MAAM,kBAAkB,CAAC,GAAG;AAC3C,4BAAkB;AAClB;AAAA,QACF;AAAA,MACF;AAEA,UAAI,iBAAiB;AACnB,aAAK,UAAA;AAAA,MACP;AAAA,IACF;AAEA,SAAA,QAAQ,MAAM;AACZ,WAAK,gBAAA;AACL,WAAK,iCAAA;AAEL,aAAO,MAAM;AACX,aAAK,oBAAA;AACL,mBAAW,WAAW,KAAK,gBAAgB;AACzC,kBAAA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,SAAA,YAAY,CAAC,aAA+B;;AAC1C,WAAK,UAAU,IAAI,QAAQ;AAC3B,YAAM,SAAQ,gBAAK,SAAQ,gBAAb,4BAA2B,UAAU;AACnD,aAAO,MAAM;AACX,aAAK,UAAU,OAAO,QAAQ;AAC9B;AAAA,MACF;AAAA,IACF;AAzHE,SAAK,UAAU;AACf,SAAK,QAAQ,QAAQ,GAAG;AAAA,MACtB,aAAa;AAAA,MACb,SAAS;AAAA,MACT,aAAa,KAAK,aAAa;AAAA,IAAA,CAChC;AAAA,EACH;AAAA,EAEA,gBACE,OAAiD,KAAK,QAAQ,MAC9D;AACA,UAAM,6BAAa,IAAA;AACnB,eAAW,OAAO,MAAM;AACtB,UAAI,eAAe,SAAS;AAE1B,YAAI,gBAAA;AAEJ,aAAK,gBAAgB,IAAI,QAAQ,IAAI;AAAA,MACvC,WAAW,eAAeA,aAAO;AAE/B,YAAI,2BAA2BC,UAAAA,iBAAiB,IAAI,GAAG;AACvD,YAAI,CAAC,0BAA0B;AAC7B,qCAA2B,CAAC,IAAa;AACzCA,qCAAiB,IAAI,KAAK,wBAAwB;AAAA,QACpD,WAAW,CAAC,yBAAyB,SAAS,IAAa,GAAG;AAC5D,mCAAyB,KAAK,IAAa;AAC3C,iBAAO,IAAI,wBAAwB;AAAA,QACrC;AAGA,YAAI,gBAAgBC,UAAAA,iBAAiB,IAAI,IAAa;AACtD,YAAI,CAAC,eAAe;AAClB,8CAAoB,IAAA;AACpBA,qCAAiB,IAAI,MAAe,aAAa;AAAA,QACnD;AACA,sBAAc,IAAI,GAAG;AAAA,MACvB;AAAA,IACF;AACA,eAAW,OAAO,QAAQ;AAExB,UAAI,KAAK,CAAC,GAAG,MAAM;AAEjB,YAAI,aAAa,WAAW,EAAE,QAAQ,KAAK,SAAS,CAAC,EAAG,QAAO;AAE/D,YAAI,aAAa,WAAW,EAAE,QAAQ,KAAK,SAAS,CAAC,EAAG,QAAO;AAC/D,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,oBACE,OAAiD,KAAK,QAAQ,MAC9D;AACA,eAAW,OAAO,MAAM;AACtB,UAAI,eAAe,SAAS;AAC1B,aAAK,oBAAoB,IAAI,QAAQ,IAAI;AAAA,MAC3C,WAAW,eAAeF,aAAO;AAC/B,cAAM,2BAA2BC,UAAAA,iBAAiB,IAAI,GAAG;AACzD,YAAI,0BAA0B;AAC5B,mCAAyB;AAAA,YACvB,yBAAyB,QAAQ,IAAa;AAAA,YAC9C;AAAA,UAAA;AAAA,QAEJ;AAEA,cAAM,gBAAgBC,UAAAA,iBAAiB,IAAI,IAAa;AACxD,YAAI,eAAe;AACjB,wBAAc,OAAO,GAAG;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAmDF;;"}
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const derived = require("./derived.cjs");
4
3
  const __storeToDerived = /* @__PURE__ */ new WeakMap();
5
4
  const __derivedToStore = /* @__PURE__ */ new WeakMap();
6
5
  const __depsThatHaveWrittenThisTick = {
@@ -11,22 +10,17 @@ let __batchDepth = 0;
11
10
  const __pendingUpdates = /* @__PURE__ */ new Set();
12
11
  const __initialBatchValues = /* @__PURE__ */ new Map();
13
12
  function __flush_internals(relatedVals) {
14
- const sorted = Array.from(relatedVals).sort((a, b) => {
15
- if (a instanceof derived.Derived && a.options.deps.includes(b)) return 1;
16
- if (b instanceof derived.Derived && b.options.deps.includes(a)) return -1;
17
- return 0;
18
- });
19
- for (const derived2 of sorted) {
20
- if (__depsThatHaveWrittenThisTick.current.includes(derived2)) {
13
+ for (const derived of relatedVals) {
14
+ if (__depsThatHaveWrittenThisTick.current.includes(derived)) {
21
15
  continue;
22
16
  }
23
- __depsThatHaveWrittenThisTick.current.push(derived2);
24
- derived2.recompute();
25
- const stores = __derivedToStore.get(derived2);
17
+ __depsThatHaveWrittenThisTick.current.push(derived);
18
+ derived.recompute();
19
+ const stores = __derivedToStore.get(derived);
26
20
  if (stores) {
27
21
  for (const store of stores) {
28
22
  const relatedLinkedDerivedVals = __storeToDerived.get(store);
29
- if (!relatedLinkedDerivedVals) continue;
23
+ if (!(relatedLinkedDerivedVals == null ? void 0 : relatedLinkedDerivedVals.length)) continue;
30
24
  __flush_internals(relatedLinkedDerivedVals);
31
25
  }
32
26
  }
@@ -41,12 +35,12 @@ function __notifyListeners(store) {
41
35
  listener(value);
42
36
  }
43
37
  }
44
- function __notifyDerivedListeners(derived2) {
38
+ function __notifyDerivedListeners(derived) {
45
39
  const value = {
46
- prevVal: derived2.prevState,
47
- currentVal: derived2.state
40
+ prevVal: derived.prevState,
41
+ currentVal: derived.state
48
42
  };
49
- for (const listener of derived2.listeners) {
43
+ for (const listener of derived.listeners) {
50
44
  listener(value);
51
45
  }
52
46
  }
@@ -76,8 +70,8 @@ function __flush(store) {
76
70
  for (const store2 of stores) {
77
71
  const derivedVals = __storeToDerived.get(store2);
78
72
  if (!derivedVals) continue;
79
- for (const derived2 of derivedVals) {
80
- __notifyDerivedListeners(derived2);
73
+ for (const derived of derivedVals) {
74
+ __notifyDerivedListeners(derived);
81
75
  }
82
76
  }
83
77
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.cjs","sources":["../../src/scheduler.ts"],"sourcesContent":["import { Derived } from './derived'\nimport type { Store } from './store'\n\n/**\n * This is here to solve the pyramid dependency problem where:\n * A\n * / \\\n * B C\n * \\ /\n * D\n *\n * Where we deeply traverse this tree, how do we avoid D being recomputed twice; once when B is updated, once when C is.\n *\n * To solve this, we create linkedDeps that allows us to sync avoid writes to the state until all of the deps have been\n * resolved.\n *\n * This is a record of stores, because derived stores are not able to write values to, but stores are\n */\nexport const __storeToDerived = new WeakMap<\n Store<unknown>,\n Set<Derived<unknown>>\n>()\nexport const __derivedToStore = new WeakMap<\n Derived<unknown>,\n Set<Store<unknown>>\n>()\n\nexport const __depsThatHaveWrittenThisTick = {\n current: [] as Array<Derived<unknown> | Store<unknown>>,\n}\n\nlet __isFlushing = false\nlet __batchDepth = 0\nconst __pendingUpdates = new Set<Store<unknown>>()\n// Add a map to store initial values before batch\nconst __initialBatchValues = new Map<Store<unknown>, unknown>()\n\nfunction __flush_internals(relatedVals: Set<Derived<unknown>>) {\n // First sort deriveds by dependency order\n const sorted = Array.from(relatedVals).sort((a, b) => {\n // If a depends on b, b should go first\n if (a instanceof Derived && a.options.deps.includes(b)) return 1\n // If b depends on a, a should go first\n if (b instanceof Derived && b.options.deps.includes(a)) return -1\n return 0\n })\n\n for (const derived of sorted) {\n if (__depsThatHaveWrittenThisTick.current.includes(derived)) {\n continue\n }\n\n __depsThatHaveWrittenThisTick.current.push(derived)\n derived.recompute()\n\n const stores = __derivedToStore.get(derived)\n if (stores) {\n for (const store of stores) {\n const relatedLinkedDerivedVals = __storeToDerived.get(store)\n if (!relatedLinkedDerivedVals) continue\n __flush_internals(relatedLinkedDerivedVals)\n }\n }\n }\n}\n\nfunction __notifyListeners(store: Store<unknown>) {\n const value = {\n prevVal: store.prevState as never,\n currentVal: store.state as never,\n }\n for (const listener of store.listeners) {\n listener(value)\n }\n}\n\nfunction __notifyDerivedListeners(derived: Derived<unknown>) {\n const value = {\n prevVal: derived.prevState as never,\n currentVal: derived.state as never,\n }\n for (const listener of derived.listeners) {\n listener(value)\n }\n}\n\n/**\n * @private only to be called from `Store` on write\n */\nexport function __flush(store: Store<unknown>) {\n // If we're starting a batch, store the initial values\n if (__batchDepth > 0 && !__initialBatchValues.has(store)) {\n __initialBatchValues.set(store, store.prevState)\n }\n\n __pendingUpdates.add(store)\n\n if (__batchDepth > 0) return\n if (__isFlushing) return\n\n try {\n __isFlushing = true\n\n while (__pendingUpdates.size > 0) {\n const stores = Array.from(__pendingUpdates)\n __pendingUpdates.clear()\n\n // First notify listeners with updated values\n for (const store of stores) {\n // Use initial batch values for prevState if we have them\n const prevState = __initialBatchValues.get(store) ?? store.prevState\n store.prevState = prevState\n __notifyListeners(store)\n }\n\n // Then update all derived values\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n __depsThatHaveWrittenThisTick.current.push(store)\n __flush_internals(derivedVals)\n }\n\n // Notify derived listeners after recomputing\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n for (const derived of derivedVals) {\n __notifyDerivedListeners(derived)\n }\n }\n }\n } finally {\n __isFlushing = false\n __depsThatHaveWrittenThisTick.current = []\n __initialBatchValues.clear()\n }\n}\n\nexport function batch(fn: () => void) {\n __batchDepth++\n try {\n fn()\n } finally {\n __batchDepth--\n if (__batchDepth === 0) {\n const pendingUpdateToFlush = __pendingUpdates.values().next().value\n if (pendingUpdateToFlush) {\n __flush(pendingUpdateToFlush) // Trigger flush of all pending updates\n }\n }\n }\n}\n"],"names":["Derived","derived","store"],"mappings":";;;AAkBO,MAAM,uCAAuB,QAAA;AAI7B,MAAM,uCAAuB,QAAA;AAK7B,MAAM,gCAAgC;AAAA,EAC3C,SAAS,CAAA;AACX;AAEA,IAAI,eAAe;AACnB,IAAI,eAAe;AACnB,MAAM,uCAAuB,IAAA;AAE7B,MAAM,2CAA2B,IAAA;AAEjC,SAAS,kBAAkB,aAAoC;AAE7D,QAAM,SAAS,MAAM,KAAK,WAAW,EAAE,KAAK,CAAC,GAAG,MAAM;AAEpD,QAAI,aAAaA,QAAAA,WAAW,EAAE,QAAQ,KAAK,SAAS,CAAC,EAAG,QAAO;AAE/D,QAAI,aAAaA,QAAAA,WAAW,EAAE,QAAQ,KAAK,SAAS,CAAC,EAAG,QAAO;AAC/D,WAAO;AAAA,EACT,CAAC;AAED,aAAWC,YAAW,QAAQ;AAC5B,QAAI,8BAA8B,QAAQ,SAASA,QAAO,GAAG;AAC3D;AAAA,IACF;AAEA,kCAA8B,QAAQ,KAAKA,QAAO;AAClD,IAAAA,SAAQ,UAAA;AAER,UAAM,SAAS,iBAAiB,IAAIA,QAAO;AAC3C,QAAI,QAAQ;AACV,iBAAW,SAAS,QAAQ;AAC1B,cAAM,2BAA2B,iBAAiB,IAAI,KAAK;AAC3D,YAAI,CAAC,yBAA0B;AAC/B,0BAAkB,wBAAwB;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,OAAuB;AAChD,QAAM,QAAQ;AAAA,IACZ,SAAS,MAAM;AAAA,IACf,YAAY,MAAM;AAAA,EAAA;AAEpB,aAAW,YAAY,MAAM,WAAW;AACtC,aAAS,KAAK;AAAA,EAChB;AACF;AAEA,SAAS,yBAAyBA,UAA2B;AAC3D,QAAM,QAAQ;AAAA,IACZ,SAASA,SAAQ;AAAA,IACjB,YAAYA,SAAQ;AAAA,EAAA;AAEtB,aAAW,YAAYA,SAAQ,WAAW;AACxC,aAAS,KAAK;AAAA,EAChB;AACF;AAKO,SAAS,QAAQ,OAAuB;AAE7C,MAAI,eAAe,KAAK,CAAC,qBAAqB,IAAI,KAAK,GAAG;AACxD,yBAAqB,IAAI,OAAO,MAAM,SAAS;AAAA,EACjD;AAEA,mBAAiB,IAAI,KAAK;AAE1B,MAAI,eAAe,EAAG;AACtB,MAAI,aAAc;AAElB,MAAI;AACF,mBAAe;AAEf,WAAO,iBAAiB,OAAO,GAAG;AAChC,YAAM,SAAS,MAAM,KAAK,gBAAgB;AAC1C,uBAAiB,MAAA;AAGjB,iBAAWC,UAAS,QAAQ;AAE1B,cAAM,YAAY,qBAAqB,IAAIA,MAAK,KAAKA,OAAM;AAC3DA,eAAM,YAAY;AAClB,0BAAkBA,MAAK;AAAA,MACzB;AAGA,iBAAWA,UAAS,QAAQ;AAC1B,cAAM,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAElB,sCAA8B,QAAQ,KAAKA,MAAK;AAChD,0BAAkB,WAAW;AAAA,MAC/B;AAGA,iBAAWA,UAAS,QAAQ;AAC1B,cAAM,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAElB,mBAAWD,YAAW,aAAa;AACjC,mCAAyBA,QAAO;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAA;AACE,mBAAe;AACf,kCAA8B,UAAU,CAAA;AACxC,yBAAqB,MAAA;AAAA,EACvB;AACF;AAEO,SAAS,MAAM,IAAgB;AACpC;AACA,MAAI;AACF,OAAA;AAAA,EACF,UAAA;AACE;AACA,QAAI,iBAAiB,GAAG;AACtB,YAAM,uBAAuB,iBAAiB,OAAA,EAAS,OAAO;AAC9D,UAAI,sBAAsB;AACxB,gBAAQ,oBAAoB;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AACF;;;;;;"}
1
+ {"version":3,"file":"scheduler.cjs","sources":["../../src/scheduler.ts"],"sourcesContent":["import type { Derived } from './derived'\nimport type { Store } from './store'\n\n/**\n * This is here to solve the pyramid dependency problem where:\n * A\n * / \\\n * B C\n * \\ /\n * D\n *\n * Where we deeply traverse this tree, how do we avoid D being recomputed twice; once when B is updated, once when C is.\n *\n * To solve this, we create linkedDeps that allows us to sync avoid writes to the state until all of the deps have been\n * resolved.\n *\n * This is a record of stores, because derived stores are not able to write values to, but stores are\n */\nexport const __storeToDerived = new WeakMap<\n Store<unknown>,\n Array<Derived<unknown>>\n>()\nexport const __derivedToStore = new WeakMap<\n Derived<unknown>,\n Set<Store<unknown>>\n>()\n\nexport const __depsThatHaveWrittenThisTick = {\n current: [] as Array<Derived<unknown> | Store<unknown>>,\n}\n\nlet __isFlushing = false\nlet __batchDepth = 0\nconst __pendingUpdates = new Set<Store<unknown>>()\n// Add a map to store initial values before batch\nconst __initialBatchValues = new Map<Store<unknown>, unknown>()\n\nfunction __flush_internals(relatedVals: ReadonlyArray<Derived<unknown>>) {\n for (const derived of relatedVals) {\n if (__depsThatHaveWrittenThisTick.current.includes(derived)) {\n continue\n }\n\n __depsThatHaveWrittenThisTick.current.push(derived)\n derived.recompute()\n\n const stores = __derivedToStore.get(derived)\n if (stores) {\n for (const store of stores) {\n const relatedLinkedDerivedVals = __storeToDerived.get(store)\n if (!relatedLinkedDerivedVals?.length) continue\n __flush_internals(relatedLinkedDerivedVals)\n }\n }\n }\n}\n\nfunction __notifyListeners(store: Store<unknown>) {\n const value = {\n prevVal: store.prevState as never,\n currentVal: store.state as never,\n }\n for (const listener of store.listeners) {\n listener(value)\n }\n}\n\nfunction __notifyDerivedListeners(derived: Derived<unknown>) {\n const value = {\n prevVal: derived.prevState as never,\n currentVal: derived.state as never,\n }\n for (const listener of derived.listeners) {\n listener(value)\n }\n}\n\n/**\n * @private only to be called from `Store` on write\n */\nexport function __flush(store: Store<unknown>) {\n // If we're starting a batch, store the initial values\n if (__batchDepth > 0 && !__initialBatchValues.has(store)) {\n __initialBatchValues.set(store, store.prevState)\n }\n\n __pendingUpdates.add(store)\n\n if (__batchDepth > 0) return\n if (__isFlushing) return\n\n try {\n __isFlushing = true\n\n while (__pendingUpdates.size > 0) {\n const stores = Array.from(__pendingUpdates)\n __pendingUpdates.clear()\n\n // First notify listeners with updated values\n for (const store of stores) {\n // Use initial batch values for prevState if we have them\n const prevState = __initialBatchValues.get(store) ?? store.prevState\n store.prevState = prevState\n __notifyListeners(store)\n }\n\n // Then update all derived values\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n __depsThatHaveWrittenThisTick.current.push(store)\n __flush_internals(derivedVals)\n }\n\n // Notify derived listeners after recomputing\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n for (const derived of derivedVals) {\n __notifyDerivedListeners(derived)\n }\n }\n }\n } finally {\n __isFlushing = false\n __depsThatHaveWrittenThisTick.current = []\n __initialBatchValues.clear()\n }\n}\n\nexport function batch(fn: () => void) {\n __batchDepth++\n try {\n fn()\n } finally {\n __batchDepth--\n if (__batchDepth === 0) {\n const pendingUpdateToFlush = __pendingUpdates.values().next().value\n if (pendingUpdateToFlush) {\n __flush(pendingUpdateToFlush) // Trigger flush of all pending updates\n }\n }\n }\n}\n"],"names":["store"],"mappings":";;AAkBO,MAAM,uCAAuB,QAAA;AAI7B,MAAM,uCAAuB,QAAA;AAK7B,MAAM,gCAAgC;AAAA,EAC3C,SAAS,CAAA;AACX;AAEA,IAAI,eAAe;AACnB,IAAI,eAAe;AACnB,MAAM,uCAAuB,IAAA;AAE7B,MAAM,2CAA2B,IAAA;AAEjC,SAAS,kBAAkB,aAA8C;AACvE,aAAW,WAAW,aAAa;AACjC,QAAI,8BAA8B,QAAQ,SAAS,OAAO,GAAG;AAC3D;AAAA,IACF;AAEA,kCAA8B,QAAQ,KAAK,OAAO;AAClD,YAAQ,UAAA;AAER,UAAM,SAAS,iBAAiB,IAAI,OAAO;AAC3C,QAAI,QAAQ;AACV,iBAAW,SAAS,QAAQ;AAC1B,cAAM,2BAA2B,iBAAiB,IAAI,KAAK;AAC3D,YAAI,EAAC,qEAA0B,QAAQ;AACvC,0BAAkB,wBAAwB;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,OAAuB;AAChD,QAAM,QAAQ;AAAA,IACZ,SAAS,MAAM;AAAA,IACf,YAAY,MAAM;AAAA,EAAA;AAEpB,aAAW,YAAY,MAAM,WAAW;AACtC,aAAS,KAAK;AAAA,EAChB;AACF;AAEA,SAAS,yBAAyB,SAA2B;AAC3D,QAAM,QAAQ;AAAA,IACZ,SAAS,QAAQ;AAAA,IACjB,YAAY,QAAQ;AAAA,EAAA;AAEtB,aAAW,YAAY,QAAQ,WAAW;AACxC,aAAS,KAAK;AAAA,EAChB;AACF;AAKO,SAAS,QAAQ,OAAuB;AAE7C,MAAI,eAAe,KAAK,CAAC,qBAAqB,IAAI,KAAK,GAAG;AACxD,yBAAqB,IAAI,OAAO,MAAM,SAAS;AAAA,EACjD;AAEA,mBAAiB,IAAI,KAAK;AAE1B,MAAI,eAAe,EAAG;AACtB,MAAI,aAAc;AAElB,MAAI;AACF,mBAAe;AAEf,WAAO,iBAAiB,OAAO,GAAG;AAChC,YAAM,SAAS,MAAM,KAAK,gBAAgB;AAC1C,uBAAiB,MAAA;AAGjB,iBAAWA,UAAS,QAAQ;AAE1B,cAAM,YAAY,qBAAqB,IAAIA,MAAK,KAAKA,OAAM;AAC3DA,eAAM,YAAY;AAClB,0BAAkBA,MAAK;AAAA,MACzB;AAGA,iBAAWA,UAAS,QAAQ;AAC1B,cAAM,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAElB,sCAA8B,QAAQ,KAAKA,MAAK;AAChD,0BAAkB,WAAW;AAAA,MAC/B;AAGA,iBAAWA,UAAS,QAAQ;AAC1B,cAAM,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAElB,mBAAW,WAAW,aAAa;AACjC,mCAAyB,OAAO;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAA;AACE,mBAAe;AACf,kCAA8B,UAAU,CAAA;AACxC,yBAAqB,MAAA;AAAA,EACvB;AACF;AAEO,SAAS,MAAM,IAAgB;AACpC;AACA,MAAI;AACF,OAAA;AAAA,EACF,UAAA;AACE;AACA,QAAI,iBAAiB,GAAG;AACtB,YAAM,uBAAuB,iBAAiB,OAAA,EAAS,OAAO;AAC9D,UAAI,sBAAsB;AACxB,gBAAQ,oBAAoB;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AACF;;;;;;"}
@@ -15,7 +15,7 @@ import { Store } from './store.cjs';
15
15
  *
16
16
  * This is a record of stores, because derived stores are not able to write values to, but stores are
17
17
  */
18
- export declare const __storeToDerived: WeakMap<Store<unknown, (cb: unknown) => unknown>, Set<Derived<unknown, readonly any[]>>>;
18
+ export declare const __storeToDerived: WeakMap<Store<unknown, (cb: unknown) => unknown>, Derived<unknown, readonly any[]>[]>;
19
19
  export declare const __derivedToStore: WeakMap<Derived<unknown, readonly any[]>, Set<Store<unknown, (cb: unknown) => unknown>>>;
20
20
  export declare const __depsThatHaveWrittenThisTick: {
21
21
  current: Array<Derived<unknown> | Store<unknown>>;
@@ -24,12 +24,8 @@ class Derived {
24
24
  this.recompute = () => {
25
25
  var _a, _b;
26
26
  this.prevState = this.state;
27
- const { prevDepVals, currDepVals, prevVal } = this.getDepVals();
28
- this.state = this.options.fn({
29
- prevDepVals,
30
- currDepVals,
31
- prevVal
32
- });
27
+ const depVals = this.getDepVals();
28
+ this.state = this.options.fn(depVals);
33
29
  (_b = (_a = this.options).onUpdate) == null ? void 0 : _b.call(_a);
34
30
  };
35
31
  this.checkIfRecalculationNeededDeeply = () => {
@@ -78,6 +74,7 @@ class Derived {
78
74
  });
79
75
  }
80
76
  registerOnGraph(deps = this.options.deps) {
77
+ const toSort = /* @__PURE__ */ new Set();
81
78
  for (const dep of deps) {
82
79
  if (dep instanceof Derived) {
83
80
  dep.registerOnGraph();
@@ -85,10 +82,12 @@ class Derived {
85
82
  } else if (dep instanceof Store) {
86
83
  let relatedLinkedDerivedVals = __storeToDerived.get(dep);
87
84
  if (!relatedLinkedDerivedVals) {
88
- relatedLinkedDerivedVals = /* @__PURE__ */ new Set();
85
+ relatedLinkedDerivedVals = [this];
89
86
  __storeToDerived.set(dep, relatedLinkedDerivedVals);
87
+ } else if (!relatedLinkedDerivedVals.includes(this)) {
88
+ relatedLinkedDerivedVals.push(this);
89
+ toSort.add(relatedLinkedDerivedVals);
90
90
  }
91
- relatedLinkedDerivedVals.add(this);
92
91
  let relatedStores = __derivedToStore.get(this);
93
92
  if (!relatedStores) {
94
93
  relatedStores = /* @__PURE__ */ new Set();
@@ -97,6 +96,13 @@ class Derived {
97
96
  relatedStores.add(dep);
98
97
  }
99
98
  }
99
+ for (const arr of toSort) {
100
+ arr.sort((a, b) => {
101
+ if (a instanceof Derived && a.options.deps.includes(b)) return 1;
102
+ if (b instanceof Derived && b.options.deps.includes(a)) return -1;
103
+ return 0;
104
+ });
105
+ }
100
106
  }
101
107
  unregisterFromGraph(deps = this.options.deps) {
102
108
  for (const dep of deps) {
@@ -105,7 +111,10 @@ class Derived {
105
111
  } else if (dep instanceof Store) {
106
112
  const relatedLinkedDerivedVals = __storeToDerived.get(dep);
107
113
  if (relatedLinkedDerivedVals) {
108
- relatedLinkedDerivedVals.delete(this);
114
+ relatedLinkedDerivedVals.splice(
115
+ relatedLinkedDerivedVals.indexOf(this),
116
+ 1
117
+ );
109
118
  }
110
119
  const relatedStores = __derivedToStore.get(this);
111
120
  if (relatedStores) {
@@ -1 +1 @@
1
- {"version":3,"file":"derived.js","sources":["../../src/derived.ts"],"sourcesContent":["import { Store } from './store'\nimport { __derivedToStore, __storeToDerived } from './scheduler'\nimport type { Listener } from './types'\n\nexport type UnwrapDerivedOrStore<T> =\n T extends Derived<infer InnerD>\n ? InnerD\n : T extends Store<infer InnerS>\n ? InnerS\n : never\n\ntype UnwrapReadonlyDerivedOrStoreArray<\n TArr extends ReadonlyArray<Derived<any> | Store<any>>,\n> = TArr extends readonly []\n ? []\n : TArr extends readonly [infer Head, ...infer Tail]\n ? Head extends Derived<any> | Store<any>\n ? Tail extends ReadonlyArray<Derived<any> | Store<any>>\n ? [\n UnwrapDerivedOrStore<Head>,\n ...UnwrapReadonlyDerivedOrStoreArray<Tail>,\n ]\n : [UnwrapDerivedOrStore<Head>]\n : []\n : TArr extends ReadonlyArray<Derived<any> | Store<any>>\n ? Array<UnwrapDerivedOrStore<TArr[number]>>\n : []\n\n// Can't have currVal, as it's being evaluated from the current derived fn\nexport interface DerivedFnProps<\n TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n TUnwrappedArr extends\n UnwrapReadonlyDerivedOrStoreArray<TArr> = UnwrapReadonlyDerivedOrStoreArray<TArr>,\n> {\n // `undefined` if it's the first run\n /**\n * `undefined` if it's the first run\n * @privateRemarks this also cannot be typed as TState, as it breaks the inferencing of the function's return type when an argument is used - even with `NoInfer` usage\n */\n prevVal: unknown | undefined\n prevDepVals: TUnwrappedArr | undefined\n currDepVals: TUnwrappedArr\n}\n\nexport interface DerivedOptions<\n TState,\n TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n> {\n onSubscribe?: (\n listener: Listener<TState>,\n derived: Derived<TState>,\n ) => () => void\n onUpdate?: () => void\n deps: TArr\n /**\n * Values of the `deps` from before and after the current invocation of `fn`\n */\n fn: (props: DerivedFnProps<TArr>) => TState\n}\n\nexport class Derived<\n TState,\n const TArr extends ReadonlyArray<\n Derived<any> | Store<any>\n > = ReadonlyArray<any>,\n> {\n listeners = new Set<Listener<TState>>()\n state: TState\n prevState: TState | undefined\n options: DerivedOptions<TState, TArr>\n\n /**\n * Functions representing the subscriptions. Call a function to cleanup\n * @private\n */\n _subscriptions: Array<() => void> = []\n\n lastSeenDepValues: Array<unknown> = []\n getDepVals = () => {\n const l = this.options.deps.length\n const prevDepVals = new Array<unknown>(l)\n const currDepVals = new Array<unknown>(l)\n for (let i = 0; i < l; i++) {\n const dep = this.options.deps[i]!\n prevDepVals[i] = dep.prevState\n currDepVals[i] = dep.state\n }\n this.lastSeenDepValues = currDepVals\n return {\n prevDepVals,\n currDepVals,\n prevVal: this.prevState ?? undefined,\n }\n }\n\n constructor(options: DerivedOptions<TState, TArr>) {\n this.options = options\n this.state = options.fn({\n prevDepVals: undefined,\n prevVal: undefined,\n currDepVals: this.getDepVals().currDepVals as never,\n })\n }\n\n registerOnGraph(\n deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n ) {\n for (const dep of deps) {\n if (dep instanceof Derived) {\n // First register the intermediate derived value if it's not already registered\n dep.registerOnGraph()\n // Then register this derived with the dep's underlying stores\n this.registerOnGraph(dep.options.deps)\n } else if (dep instanceof Store) {\n // Register the derived as related derived to the store\n let relatedLinkedDerivedVals = __storeToDerived.get(dep)\n if (!relatedLinkedDerivedVals) {\n relatedLinkedDerivedVals = new Set()\n __storeToDerived.set(dep, relatedLinkedDerivedVals)\n }\n relatedLinkedDerivedVals.add(this as never)\n\n // Register the store as a related store to this derived\n let relatedStores = __derivedToStore.get(this as never)\n if (!relatedStores) {\n relatedStores = new Set()\n __derivedToStore.set(this as never, relatedStores)\n }\n relatedStores.add(dep)\n }\n }\n }\n\n unregisterFromGraph(\n deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n ) {\n for (const dep of deps) {\n if (dep instanceof Derived) {\n this.unregisterFromGraph(dep.options.deps)\n } else if (dep instanceof Store) {\n const relatedLinkedDerivedVals = __storeToDerived.get(dep)\n if (relatedLinkedDerivedVals) {\n relatedLinkedDerivedVals.delete(this as never)\n }\n\n const relatedStores = __derivedToStore.get(this as never)\n if (relatedStores) {\n relatedStores.delete(dep)\n }\n }\n }\n }\n\n recompute = () => {\n this.prevState = this.state\n const { prevDepVals, currDepVals, prevVal } = this.getDepVals()\n this.state = this.options.fn({\n prevDepVals: prevDepVals as never,\n currDepVals: currDepVals as never,\n prevVal,\n })\n\n this.options.onUpdate?.()\n }\n\n checkIfRecalculationNeededDeeply = () => {\n for (const dep of this.options.deps) {\n if (dep instanceof Derived) {\n dep.checkIfRecalculationNeededDeeply()\n }\n }\n let shouldRecompute = false\n const lastSeenDepValues = this.lastSeenDepValues\n const { currDepVals } = this.getDepVals()\n for (let i = 0; i < currDepVals.length; i++) {\n if (currDepVals[i] !== lastSeenDepValues[i]) {\n shouldRecompute = true\n break\n }\n }\n\n if (shouldRecompute) {\n this.recompute()\n }\n }\n\n mount = () => {\n this.registerOnGraph()\n this.checkIfRecalculationNeededDeeply()\n\n return () => {\n this.unregisterFromGraph()\n for (const cleanup of this._subscriptions) {\n cleanup()\n }\n }\n }\n\n subscribe = (listener: Listener<TState>) => {\n this.listeners.add(listener)\n const unsub = this.options.onSubscribe?.(listener, this)\n return () => {\n this.listeners.delete(listener)\n unsub?.()\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"derived.js","sources":["../../src/derived.ts"],"sourcesContent":["import { Store } from './store'\nimport { __derivedToStore, __storeToDerived } from './scheduler'\nimport type { Listener } from './types'\n\nexport type UnwrapDerivedOrStore<T> =\n T extends Derived<infer InnerD>\n ? InnerD\n : T extends Store<infer InnerS>\n ? InnerS\n : never\n\ntype UnwrapReadonlyDerivedOrStoreArray<\n TArr extends ReadonlyArray<Derived<any> | Store<any>>,\n> = TArr extends readonly []\n ? []\n : TArr extends readonly [infer Head, ...infer Tail]\n ? Head extends Derived<any> | Store<any>\n ? Tail extends ReadonlyArray<Derived<any> | Store<any>>\n ? [\n UnwrapDerivedOrStore<Head>,\n ...UnwrapReadonlyDerivedOrStoreArray<Tail>,\n ]\n : [UnwrapDerivedOrStore<Head>]\n : []\n : TArr extends ReadonlyArray<Derived<any> | Store<any>>\n ? Array<UnwrapDerivedOrStore<TArr[number]>>\n : []\n\n// Can't have currVal, as it's being evaluated from the current derived fn\nexport interface DerivedFnProps<\n TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n TUnwrappedArr extends\n UnwrapReadonlyDerivedOrStoreArray<TArr> = UnwrapReadonlyDerivedOrStoreArray<TArr>,\n> {\n // `undefined` if it's the first run\n /**\n * `undefined` if it's the first run\n * @privateRemarks this also cannot be typed as TState, as it breaks the inferencing of the function's return type when an argument is used - even with `NoInfer` usage\n */\n prevVal: unknown | undefined\n prevDepVals: TUnwrappedArr | undefined\n currDepVals: TUnwrappedArr\n}\n\nexport interface DerivedOptions<\n TState,\n TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n> {\n onSubscribe?: (\n listener: Listener<TState>,\n derived: Derived<TState>,\n ) => () => void\n onUpdate?: () => void\n deps: TArr\n /**\n * Values of the `deps` from before and after the current invocation of `fn`\n */\n fn: (props: DerivedFnProps<TArr>) => TState\n}\n\nexport class Derived<\n TState,\n const TArr extends ReadonlyArray<\n Derived<any> | Store<any>\n > = ReadonlyArray<any>,\n> {\n listeners = new Set<Listener<TState>>()\n state: TState\n prevState: TState | undefined\n options: DerivedOptions<TState, TArr>\n\n /**\n * Functions representing the subscriptions. Call a function to cleanup\n * @private\n */\n _subscriptions: Array<() => void> = []\n\n lastSeenDepValues: Array<unknown> = []\n getDepVals = () => {\n const l = this.options.deps.length\n const prevDepVals = new Array<unknown>(l)\n const currDepVals = new Array<unknown>(l)\n for (let i = 0; i < l; i++) {\n const dep = this.options.deps[i]!\n prevDepVals[i] = dep.prevState\n currDepVals[i] = dep.state\n }\n this.lastSeenDepValues = currDepVals\n return {\n prevDepVals,\n currDepVals,\n prevVal: this.prevState ?? undefined,\n }\n }\n\n constructor(options: DerivedOptions<TState, TArr>) {\n this.options = options\n this.state = options.fn({\n prevDepVals: undefined,\n prevVal: undefined,\n currDepVals: this.getDepVals().currDepVals as never,\n })\n }\n\n registerOnGraph(\n deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n ) {\n const toSort = new Set<Array<Derived<unknown>>>()\n for (const dep of deps) {\n if (dep instanceof Derived) {\n // First register the intermediate derived value if it's not already registered\n dep.registerOnGraph()\n // Then register this derived with the dep's underlying stores\n this.registerOnGraph(dep.options.deps)\n } else if (dep instanceof Store) {\n // Register the derived as related derived to the store\n let relatedLinkedDerivedVals = __storeToDerived.get(dep)\n if (!relatedLinkedDerivedVals) {\n relatedLinkedDerivedVals = [this as never]\n __storeToDerived.set(dep, relatedLinkedDerivedVals)\n } else if (!relatedLinkedDerivedVals.includes(this as never)) {\n relatedLinkedDerivedVals.push(this as never)\n toSort.add(relatedLinkedDerivedVals)\n }\n\n // Register the store as a related store to this derived\n let relatedStores = __derivedToStore.get(this as never)\n if (!relatedStores) {\n relatedStores = new Set()\n __derivedToStore.set(this as never, relatedStores)\n }\n relatedStores.add(dep)\n }\n }\n for (const arr of toSort) {\n // First sort deriveds by dependency order\n arr.sort((a, b) => {\n // If a depends on b, b should go first\n if (a instanceof Derived && a.options.deps.includes(b)) return 1\n // If b depends on a, a should go first\n if (b instanceof Derived && b.options.deps.includes(a)) return -1\n return 0\n })\n }\n }\n\n unregisterFromGraph(\n deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n ) {\n for (const dep of deps) {\n if (dep instanceof Derived) {\n this.unregisterFromGraph(dep.options.deps)\n } else if (dep instanceof Store) {\n const relatedLinkedDerivedVals = __storeToDerived.get(dep)\n if (relatedLinkedDerivedVals) {\n relatedLinkedDerivedVals.splice(\n relatedLinkedDerivedVals.indexOf(this as never),\n 1,\n )\n }\n\n const relatedStores = __derivedToStore.get(this as never)\n if (relatedStores) {\n relatedStores.delete(dep)\n }\n }\n }\n }\n\n recompute = () => {\n this.prevState = this.state\n const depVals = this.getDepVals()\n this.state = this.options.fn(depVals as never)\n\n this.options.onUpdate?.()\n }\n\n checkIfRecalculationNeededDeeply = () => {\n for (const dep of this.options.deps) {\n if (dep instanceof Derived) {\n dep.checkIfRecalculationNeededDeeply()\n }\n }\n let shouldRecompute = false\n const lastSeenDepValues = this.lastSeenDepValues\n const { currDepVals } = this.getDepVals()\n for (let i = 0; i < currDepVals.length; i++) {\n if (currDepVals[i] !== lastSeenDepValues[i]) {\n shouldRecompute = true\n break\n }\n }\n\n if (shouldRecompute) {\n this.recompute()\n }\n }\n\n mount = () => {\n this.registerOnGraph()\n this.checkIfRecalculationNeededDeeply()\n\n return () => {\n this.unregisterFromGraph()\n for (const cleanup of this._subscriptions) {\n cleanup()\n }\n }\n }\n\n subscribe = (listener: Listener<TState>) => {\n this.listeners.add(listener)\n const unsub = this.options.onSubscribe?.(listener, this)\n return () => {\n this.listeners.delete(listener)\n unsub?.()\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -15,7 +15,7 @@ import { Store } from './store.js';
15
15
  *
16
16
  * This is a record of stores, because derived stores are not able to write values to, but stores are
17
17
  */
18
- export declare const __storeToDerived: WeakMap<Store<unknown, (cb: unknown) => unknown>, Set<Derived<unknown, readonly any[]>>>;
18
+ export declare const __storeToDerived: WeakMap<Store<unknown, (cb: unknown) => unknown>, Derived<unknown, readonly any[]>[]>;
19
19
  export declare const __derivedToStore: WeakMap<Derived<unknown, readonly any[]>, Set<Store<unknown, (cb: unknown) => unknown>>>;
20
20
  export declare const __depsThatHaveWrittenThisTick: {
21
21
  current: Array<Derived<unknown> | Store<unknown>>;
@@ -1,4 +1,3 @@
1
- import { Derived } from "./derived.js";
2
1
  const __storeToDerived = /* @__PURE__ */ new WeakMap();
3
2
  const __derivedToStore = /* @__PURE__ */ new WeakMap();
4
3
  const __depsThatHaveWrittenThisTick = {
@@ -9,12 +8,7 @@ let __batchDepth = 0;
9
8
  const __pendingUpdates = /* @__PURE__ */ new Set();
10
9
  const __initialBatchValues = /* @__PURE__ */ new Map();
11
10
  function __flush_internals(relatedVals) {
12
- const sorted = Array.from(relatedVals).sort((a, b) => {
13
- if (a instanceof Derived && a.options.deps.includes(b)) return 1;
14
- if (b instanceof Derived && b.options.deps.includes(a)) return -1;
15
- return 0;
16
- });
17
- for (const derived of sorted) {
11
+ for (const derived of relatedVals) {
18
12
  if (__depsThatHaveWrittenThisTick.current.includes(derived)) {
19
13
  continue;
20
14
  }
@@ -24,7 +18,7 @@ function __flush_internals(relatedVals) {
24
18
  if (stores) {
25
19
  for (const store of stores) {
26
20
  const relatedLinkedDerivedVals = __storeToDerived.get(store);
27
- if (!relatedLinkedDerivedVals) continue;
21
+ if (!(relatedLinkedDerivedVals == null ? void 0 : relatedLinkedDerivedVals.length)) continue;
28
22
  __flush_internals(relatedLinkedDerivedVals);
29
23
  }
30
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.js","sources":["../../src/scheduler.ts"],"sourcesContent":["import { Derived } from './derived'\nimport type { Store } from './store'\n\n/**\n * This is here to solve the pyramid dependency problem where:\n * A\n * / \\\n * B C\n * \\ /\n * D\n *\n * Where we deeply traverse this tree, how do we avoid D being recomputed twice; once when B is updated, once when C is.\n *\n * To solve this, we create linkedDeps that allows us to sync avoid writes to the state until all of the deps have been\n * resolved.\n *\n * This is a record of stores, because derived stores are not able to write values to, but stores are\n */\nexport const __storeToDerived = new WeakMap<\n Store<unknown>,\n Set<Derived<unknown>>\n>()\nexport const __derivedToStore = new WeakMap<\n Derived<unknown>,\n Set<Store<unknown>>\n>()\n\nexport const __depsThatHaveWrittenThisTick = {\n current: [] as Array<Derived<unknown> | Store<unknown>>,\n}\n\nlet __isFlushing = false\nlet __batchDepth = 0\nconst __pendingUpdates = new Set<Store<unknown>>()\n// Add a map to store initial values before batch\nconst __initialBatchValues = new Map<Store<unknown>, unknown>()\n\nfunction __flush_internals(relatedVals: Set<Derived<unknown>>) {\n // First sort deriveds by dependency order\n const sorted = Array.from(relatedVals).sort((a, b) => {\n // If a depends on b, b should go first\n if (a instanceof Derived && a.options.deps.includes(b)) return 1\n // If b depends on a, a should go first\n if (b instanceof Derived && b.options.deps.includes(a)) return -1\n return 0\n })\n\n for (const derived of sorted) {\n if (__depsThatHaveWrittenThisTick.current.includes(derived)) {\n continue\n }\n\n __depsThatHaveWrittenThisTick.current.push(derived)\n derived.recompute()\n\n const stores = __derivedToStore.get(derived)\n if (stores) {\n for (const store of stores) {\n const relatedLinkedDerivedVals = __storeToDerived.get(store)\n if (!relatedLinkedDerivedVals) continue\n __flush_internals(relatedLinkedDerivedVals)\n }\n }\n }\n}\n\nfunction __notifyListeners(store: Store<unknown>) {\n const value = {\n prevVal: store.prevState as never,\n currentVal: store.state as never,\n }\n for (const listener of store.listeners) {\n listener(value)\n }\n}\n\nfunction __notifyDerivedListeners(derived: Derived<unknown>) {\n const value = {\n prevVal: derived.prevState as never,\n currentVal: derived.state as never,\n }\n for (const listener of derived.listeners) {\n listener(value)\n }\n}\n\n/**\n * @private only to be called from `Store` on write\n */\nexport function __flush(store: Store<unknown>) {\n // If we're starting a batch, store the initial values\n if (__batchDepth > 0 && !__initialBatchValues.has(store)) {\n __initialBatchValues.set(store, store.prevState)\n }\n\n __pendingUpdates.add(store)\n\n if (__batchDepth > 0) return\n if (__isFlushing) return\n\n try {\n __isFlushing = true\n\n while (__pendingUpdates.size > 0) {\n const stores = Array.from(__pendingUpdates)\n __pendingUpdates.clear()\n\n // First notify listeners with updated values\n for (const store of stores) {\n // Use initial batch values for prevState if we have them\n const prevState = __initialBatchValues.get(store) ?? store.prevState\n store.prevState = prevState\n __notifyListeners(store)\n }\n\n // Then update all derived values\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n __depsThatHaveWrittenThisTick.current.push(store)\n __flush_internals(derivedVals)\n }\n\n // Notify derived listeners after recomputing\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n for (const derived of derivedVals) {\n __notifyDerivedListeners(derived)\n }\n }\n }\n } finally {\n __isFlushing = false\n __depsThatHaveWrittenThisTick.current = []\n __initialBatchValues.clear()\n }\n}\n\nexport function batch(fn: () => void) {\n __batchDepth++\n try {\n fn()\n } finally {\n __batchDepth--\n if (__batchDepth === 0) {\n const pendingUpdateToFlush = __pendingUpdates.values().next().value\n if (pendingUpdateToFlush) {\n __flush(pendingUpdateToFlush) // Trigger flush of all pending updates\n }\n }\n }\n}\n"],"names":["store"],"mappings":";AAkBO,MAAM,uCAAuB,QAAA;AAI7B,MAAM,uCAAuB,QAAA;AAK7B,MAAM,gCAAgC;AAAA,EAC3C,SAAS,CAAA;AACX;AAEA,IAAI,eAAe;AACnB,IAAI,eAAe;AACnB,MAAM,uCAAuB,IAAA;AAE7B,MAAM,2CAA2B,IAAA;AAEjC,SAAS,kBAAkB,aAAoC;AAE7D,QAAM,SAAS,MAAM,KAAK,WAAW,EAAE,KAAK,CAAC,GAAG,MAAM;AAEpD,QAAI,aAAa,WAAW,EAAE,QAAQ,KAAK,SAAS,CAAC,EAAG,QAAO;AAE/D,QAAI,aAAa,WAAW,EAAE,QAAQ,KAAK,SAAS,CAAC,EAAG,QAAO;AAC/D,WAAO;AAAA,EACT,CAAC;AAED,aAAW,WAAW,QAAQ;AAC5B,QAAI,8BAA8B,QAAQ,SAAS,OAAO,GAAG;AAC3D;AAAA,IACF;AAEA,kCAA8B,QAAQ,KAAK,OAAO;AAClD,YAAQ,UAAA;AAER,UAAM,SAAS,iBAAiB,IAAI,OAAO;AAC3C,QAAI,QAAQ;AACV,iBAAW,SAAS,QAAQ;AAC1B,cAAM,2BAA2B,iBAAiB,IAAI,KAAK;AAC3D,YAAI,CAAC,yBAA0B;AAC/B,0BAAkB,wBAAwB;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,OAAuB;AAChD,QAAM,QAAQ;AAAA,IACZ,SAAS,MAAM;AAAA,IACf,YAAY,MAAM;AAAA,EAAA;AAEpB,aAAW,YAAY,MAAM,WAAW;AACtC,aAAS,KAAK;AAAA,EAChB;AACF;AAEA,SAAS,yBAAyB,SAA2B;AAC3D,QAAM,QAAQ;AAAA,IACZ,SAAS,QAAQ;AAAA,IACjB,YAAY,QAAQ;AAAA,EAAA;AAEtB,aAAW,YAAY,QAAQ,WAAW;AACxC,aAAS,KAAK;AAAA,EAChB;AACF;AAKO,SAAS,QAAQ,OAAuB;AAE7C,MAAI,eAAe,KAAK,CAAC,qBAAqB,IAAI,KAAK,GAAG;AACxD,yBAAqB,IAAI,OAAO,MAAM,SAAS;AAAA,EACjD;AAEA,mBAAiB,IAAI,KAAK;AAE1B,MAAI,eAAe,EAAG;AACtB,MAAI,aAAc;AAElB,MAAI;AACF,mBAAe;AAEf,WAAO,iBAAiB,OAAO,GAAG;AAChC,YAAM,SAAS,MAAM,KAAK,gBAAgB;AAC1C,uBAAiB,MAAA;AAGjB,iBAAWA,UAAS,QAAQ;AAE1B,cAAM,YAAY,qBAAqB,IAAIA,MAAK,KAAKA,OAAM;AAC3DA,eAAM,YAAY;AAClB,0BAAkBA,MAAK;AAAA,MACzB;AAGA,iBAAWA,UAAS,QAAQ;AAC1B,cAAM,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAElB,sCAA8B,QAAQ,KAAKA,MAAK;AAChD,0BAAkB,WAAW;AAAA,MAC/B;AAGA,iBAAWA,UAAS,QAAQ;AAC1B,cAAM,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAElB,mBAAW,WAAW,aAAa;AACjC,mCAAyB,OAAO;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAA;AACE,mBAAe;AACf,kCAA8B,UAAU,CAAA;AACxC,yBAAqB,MAAA;AAAA,EACvB;AACF;AAEO,SAAS,MAAM,IAAgB;AACpC;AACA,MAAI;AACF,OAAA;AAAA,EACF,UAAA;AACE;AACA,QAAI,iBAAiB,GAAG;AACtB,YAAM,uBAAuB,iBAAiB,OAAA,EAAS,OAAO;AAC9D,UAAI,sBAAsB;AACxB,gBAAQ,oBAAoB;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AACF;"}
1
+ {"version":3,"file":"scheduler.js","sources":["../../src/scheduler.ts"],"sourcesContent":["import type { Derived } from './derived'\nimport type { Store } from './store'\n\n/**\n * This is here to solve the pyramid dependency problem where:\n * A\n * / \\\n * B C\n * \\ /\n * D\n *\n * Where we deeply traverse this tree, how do we avoid D being recomputed twice; once when B is updated, once when C is.\n *\n * To solve this, we create linkedDeps that allows us to sync avoid writes to the state until all of the deps have been\n * resolved.\n *\n * This is a record of stores, because derived stores are not able to write values to, but stores are\n */\nexport const __storeToDerived = new WeakMap<\n Store<unknown>,\n Array<Derived<unknown>>\n>()\nexport const __derivedToStore = new WeakMap<\n Derived<unknown>,\n Set<Store<unknown>>\n>()\n\nexport const __depsThatHaveWrittenThisTick = {\n current: [] as Array<Derived<unknown> | Store<unknown>>,\n}\n\nlet __isFlushing = false\nlet __batchDepth = 0\nconst __pendingUpdates = new Set<Store<unknown>>()\n// Add a map to store initial values before batch\nconst __initialBatchValues = new Map<Store<unknown>, unknown>()\n\nfunction __flush_internals(relatedVals: ReadonlyArray<Derived<unknown>>) {\n for (const derived of relatedVals) {\n if (__depsThatHaveWrittenThisTick.current.includes(derived)) {\n continue\n }\n\n __depsThatHaveWrittenThisTick.current.push(derived)\n derived.recompute()\n\n const stores = __derivedToStore.get(derived)\n if (stores) {\n for (const store of stores) {\n const relatedLinkedDerivedVals = __storeToDerived.get(store)\n if (!relatedLinkedDerivedVals?.length) continue\n __flush_internals(relatedLinkedDerivedVals)\n }\n }\n }\n}\n\nfunction __notifyListeners(store: Store<unknown>) {\n const value = {\n prevVal: store.prevState as never,\n currentVal: store.state as never,\n }\n for (const listener of store.listeners) {\n listener(value)\n }\n}\n\nfunction __notifyDerivedListeners(derived: Derived<unknown>) {\n const value = {\n prevVal: derived.prevState as never,\n currentVal: derived.state as never,\n }\n for (const listener of derived.listeners) {\n listener(value)\n }\n}\n\n/**\n * @private only to be called from `Store` on write\n */\nexport function __flush(store: Store<unknown>) {\n // If we're starting a batch, store the initial values\n if (__batchDepth > 0 && !__initialBatchValues.has(store)) {\n __initialBatchValues.set(store, store.prevState)\n }\n\n __pendingUpdates.add(store)\n\n if (__batchDepth > 0) return\n if (__isFlushing) return\n\n try {\n __isFlushing = true\n\n while (__pendingUpdates.size > 0) {\n const stores = Array.from(__pendingUpdates)\n __pendingUpdates.clear()\n\n // First notify listeners with updated values\n for (const store of stores) {\n // Use initial batch values for prevState if we have them\n const prevState = __initialBatchValues.get(store) ?? store.prevState\n store.prevState = prevState\n __notifyListeners(store)\n }\n\n // Then update all derived values\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n __depsThatHaveWrittenThisTick.current.push(store)\n __flush_internals(derivedVals)\n }\n\n // Notify derived listeners after recomputing\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n for (const derived of derivedVals) {\n __notifyDerivedListeners(derived)\n }\n }\n }\n } finally {\n __isFlushing = false\n __depsThatHaveWrittenThisTick.current = []\n __initialBatchValues.clear()\n }\n}\n\nexport function batch(fn: () => void) {\n __batchDepth++\n try {\n fn()\n } finally {\n __batchDepth--\n if (__batchDepth === 0) {\n const pendingUpdateToFlush = __pendingUpdates.values().next().value\n if (pendingUpdateToFlush) {\n __flush(pendingUpdateToFlush) // Trigger flush of all pending updates\n }\n }\n }\n}\n"],"names":["store"],"mappings":"AAkBO,MAAM,uCAAuB,QAAA;AAI7B,MAAM,uCAAuB,QAAA;AAK7B,MAAM,gCAAgC;AAAA,EAC3C,SAAS,CAAA;AACX;AAEA,IAAI,eAAe;AACnB,IAAI,eAAe;AACnB,MAAM,uCAAuB,IAAA;AAE7B,MAAM,2CAA2B,IAAA;AAEjC,SAAS,kBAAkB,aAA8C;AACvE,aAAW,WAAW,aAAa;AACjC,QAAI,8BAA8B,QAAQ,SAAS,OAAO,GAAG;AAC3D;AAAA,IACF;AAEA,kCAA8B,QAAQ,KAAK,OAAO;AAClD,YAAQ,UAAA;AAER,UAAM,SAAS,iBAAiB,IAAI,OAAO;AAC3C,QAAI,QAAQ;AACV,iBAAW,SAAS,QAAQ;AAC1B,cAAM,2BAA2B,iBAAiB,IAAI,KAAK;AAC3D,YAAI,EAAC,qEAA0B,QAAQ;AACvC,0BAAkB,wBAAwB;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,OAAuB;AAChD,QAAM,QAAQ;AAAA,IACZ,SAAS,MAAM;AAAA,IACf,YAAY,MAAM;AAAA,EAAA;AAEpB,aAAW,YAAY,MAAM,WAAW;AACtC,aAAS,KAAK;AAAA,EAChB;AACF;AAEA,SAAS,yBAAyB,SAA2B;AAC3D,QAAM,QAAQ;AAAA,IACZ,SAAS,QAAQ;AAAA,IACjB,YAAY,QAAQ;AAAA,EAAA;AAEtB,aAAW,YAAY,QAAQ,WAAW;AACxC,aAAS,KAAK;AAAA,EAChB;AACF;AAKO,SAAS,QAAQ,OAAuB;AAE7C,MAAI,eAAe,KAAK,CAAC,qBAAqB,IAAI,KAAK,GAAG;AACxD,yBAAqB,IAAI,OAAO,MAAM,SAAS;AAAA,EACjD;AAEA,mBAAiB,IAAI,KAAK;AAE1B,MAAI,eAAe,EAAG;AACtB,MAAI,aAAc;AAElB,MAAI;AACF,mBAAe;AAEf,WAAO,iBAAiB,OAAO,GAAG;AAChC,YAAM,SAAS,MAAM,KAAK,gBAAgB;AAC1C,uBAAiB,MAAA;AAGjB,iBAAWA,UAAS,QAAQ;AAE1B,cAAM,YAAY,qBAAqB,IAAIA,MAAK,KAAKA,OAAM;AAC3DA,eAAM,YAAY;AAClB,0BAAkBA,MAAK;AAAA,MACzB;AAGA,iBAAWA,UAAS,QAAQ;AAC1B,cAAM,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAElB,sCAA8B,QAAQ,KAAKA,MAAK;AAChD,0BAAkB,WAAW;AAAA,MAC/B;AAGA,iBAAWA,UAAS,QAAQ;AAC1B,cAAM,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAElB,mBAAW,WAAW,aAAa;AACjC,mCAAyB,OAAO;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAA;AACE,mBAAe;AACf,kCAA8B,UAAU,CAAA;AACxC,yBAAqB,MAAA;AAAA,EACvB;AACF;AAEO,SAAS,MAAM,IAAgB;AACpC;AACA,MAAI;AACF,OAAA;AAAA,EACF,UAAA;AACE;AACA,QAAI,iBAAiB,GAAG;AACtB,YAAM,uBAAuB,iBAAiB,OAAA,EAAS,OAAO;AAC9D,UAAI,sBAAsB;AACxB,gBAAQ,oBAAoB;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AACF;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/store",
3
- "version": "0.7.6",
3
+ "version": "0.8.0",
4
4
  "description": "Framework agnostic type-safe store w/ reactive framework adapters",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -44,7 +44,7 @@
44
44
  "@angular/core": "^19.2.15",
45
45
  "@preact/signals": "^1.3.2",
46
46
  "solid-js": "^1.9.9",
47
- "vue": "^3.5.21"
47
+ "vue": "^3.5.22"
48
48
  },
49
49
  "scripts": {
50
50
  "clean": "premove ./dist ./coverage",
package/src/derived.ts CHANGED
@@ -105,6 +105,7 @@ export class Derived<
105
105
  registerOnGraph(
106
106
  deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,
107
107
  ) {
108
+ const toSort = new Set<Array<Derived<unknown>>>()
108
109
  for (const dep of deps) {
109
110
  if (dep instanceof Derived) {
110
111
  // First register the intermediate derived value if it's not already registered
@@ -115,10 +116,12 @@ export class Derived<
115
116
  // Register the derived as related derived to the store
116
117
  let relatedLinkedDerivedVals = __storeToDerived.get(dep)
117
118
  if (!relatedLinkedDerivedVals) {
118
- relatedLinkedDerivedVals = new Set()
119
+ relatedLinkedDerivedVals = [this as never]
119
120
  __storeToDerived.set(dep, relatedLinkedDerivedVals)
121
+ } else if (!relatedLinkedDerivedVals.includes(this as never)) {
122
+ relatedLinkedDerivedVals.push(this as never)
123
+ toSort.add(relatedLinkedDerivedVals)
120
124
  }
121
- relatedLinkedDerivedVals.add(this as never)
122
125
 
123
126
  // Register the store as a related store to this derived
124
127
  let relatedStores = __derivedToStore.get(this as never)
@@ -129,6 +132,16 @@ export class Derived<
129
132
  relatedStores.add(dep)
130
133
  }
131
134
  }
135
+ for (const arr of toSort) {
136
+ // First sort deriveds by dependency order
137
+ arr.sort((a, b) => {
138
+ // If a depends on b, b should go first
139
+ if (a instanceof Derived && a.options.deps.includes(b)) return 1
140
+ // If b depends on a, a should go first
141
+ if (b instanceof Derived && b.options.deps.includes(a)) return -1
142
+ return 0
143
+ })
144
+ }
132
145
  }
133
146
 
134
147
  unregisterFromGraph(
@@ -140,7 +153,10 @@ export class Derived<
140
153
  } else if (dep instanceof Store) {
141
154
  const relatedLinkedDerivedVals = __storeToDerived.get(dep)
142
155
  if (relatedLinkedDerivedVals) {
143
- relatedLinkedDerivedVals.delete(this as never)
156
+ relatedLinkedDerivedVals.splice(
157
+ relatedLinkedDerivedVals.indexOf(this as never),
158
+ 1,
159
+ )
144
160
  }
145
161
 
146
162
  const relatedStores = __derivedToStore.get(this as never)
@@ -153,12 +169,8 @@ export class Derived<
153
169
 
154
170
  recompute = () => {
155
171
  this.prevState = this.state
156
- const { prevDepVals, currDepVals, prevVal } = this.getDepVals()
157
- this.state = this.options.fn({
158
- prevDepVals: prevDepVals as never,
159
- currDepVals: currDepVals as never,
160
- prevVal,
161
- })
172
+ const depVals = this.getDepVals()
173
+ this.state = this.options.fn(depVals as never)
162
174
 
163
175
  this.options.onUpdate?.()
164
176
  }
package/src/scheduler.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Derived } from './derived'
1
+ import type { Derived } from './derived'
2
2
  import type { Store } from './store'
3
3
 
4
4
  /**
@@ -18,7 +18,7 @@ import type { Store } from './store'
18
18
  */
19
19
  export const __storeToDerived = new WeakMap<
20
20
  Store<unknown>,
21
- Set<Derived<unknown>>
21
+ Array<Derived<unknown>>
22
22
  >()
23
23
  export const __derivedToStore = new WeakMap<
24
24
  Derived<unknown>,
@@ -35,17 +35,8 @@ const __pendingUpdates = new Set<Store<unknown>>()
35
35
  // Add a map to store initial values before batch
36
36
  const __initialBatchValues = new Map<Store<unknown>, unknown>()
37
37
 
38
- function __flush_internals(relatedVals: Set<Derived<unknown>>) {
39
- // First sort deriveds by dependency order
40
- const sorted = Array.from(relatedVals).sort((a, b) => {
41
- // If a depends on b, b should go first
42
- if (a instanceof Derived && a.options.deps.includes(b)) return 1
43
- // If b depends on a, a should go first
44
- if (b instanceof Derived && b.options.deps.includes(a)) return -1
45
- return 0
46
- })
47
-
48
- for (const derived of sorted) {
38
+ function __flush_internals(relatedVals: ReadonlyArray<Derived<unknown>>) {
39
+ for (const derived of relatedVals) {
49
40
  if (__depsThatHaveWrittenThisTick.current.includes(derived)) {
50
41
  continue
51
42
  }
@@ -57,7 +48,7 @@ function __flush_internals(relatedVals: Set<Derived<unknown>>) {
57
48
  if (stores) {
58
49
  for (const store of stores) {
59
50
  const relatedLinkedDerivedVals = __storeToDerived.get(store)
60
- if (!relatedLinkedDerivedVals) continue
51
+ if (!relatedLinkedDerivedVals?.length) continue
61
52
  __flush_internals(relatedLinkedDerivedVals)
62
53
  }
63
54
  }