@retreon/cells 0.1.0 → 0.1.1-2025-06-19.ef01c21
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.
- package/README.md +26 -13
- package/dist/cells.cjs +1 -1
- package/dist/cells.d.ts +13 -9
- package/dist/cells.js +74 -75
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -125,19 +125,6 @@ batch((swap) => {
|
|
|
125
125
|
});
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
### `watch(signal, handler)`
|
|
129
|
-
|
|
130
|
-
Subscribes to changes in a signal. Returns a cleanup function. For formulas, watches all transitive dependencies.
|
|
131
|
-
|
|
132
|
-
```ts
|
|
133
|
-
const dispose = watch(total, () => {
|
|
134
|
-
console.log('Total updated:', get(total));
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// Later: stop watching
|
|
138
|
-
dispose();
|
|
139
|
-
```
|
|
140
|
-
|
|
141
128
|
### `untracked(fn)`
|
|
142
129
|
|
|
143
130
|
Executes a function without tracking any signal dependencies. When called inside a formula computation, any signals read within the untracked function will not be registered as dependencies.
|
|
@@ -164,3 +151,29 @@ const visited = visitDependencies(receipt, (sig) => {
|
|
|
164
151
|
});
|
|
165
152
|
// Logs: "Found formula", "Found cell", "Found cell", "Found source"
|
|
166
153
|
```
|
|
154
|
+
|
|
155
|
+
> [!WARNING]
|
|
156
|
+
> This API does not evaluate formulas. If the formula hasn't been re-evaluated since dependencies changed, this API may return stale data.
|
|
157
|
+
|
|
158
|
+
### `watch(signal, handler)`
|
|
159
|
+
|
|
160
|
+
Subscribes to changes in a signal. Returns a cleanup and renewal function. For formulas, watches all transitive dependencies.
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
const [dispose, renew] = watch(total, () => {
|
|
164
|
+
console.log('Total updated:', renew());
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Later: stop watching
|
|
168
|
+
dispose();
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
This is a low-level function that prioritizes power over simplicity. It's easy to misuse.
|
|
172
|
+
|
|
173
|
+
- **dispose:** Stops watching for changes.
|
|
174
|
+
- **renew:** Re-evaluates the expression and watches the new dependency set.
|
|
175
|
+
|
|
176
|
+
> [!WARNING]
|
|
177
|
+
> Careful attention is required when watching formulas. `watch()` does not invoke formulas automatically unless you call `renew()`. This means `watch()` may be watching stale dependencies.
|
|
178
|
+
>
|
|
179
|
+
> It's recommended to call `renew()` inside the watch handler (re-evaluating any formulas) to ensure you're always observing the correct dependencies.
|
package/dist/cells.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let o=0;function h(){return++o}const b=(t,e)=>{t.w.add(e)},w=(t,e)=>{t.w.delete(e)},k=t=>({t:"c",c:t,v:o,w:new Set});let c=null,i=!1;const C=t=>{c&&V(c,t)},D=(t,e)=>{const n=c;c=t;try{return e()}finally{c=n}},x=t=>{const e=i;i=!0;try{return t()}finally{i=e}},E=t=>{const e=c;c=null;try{return t()}finally{c=e}},F=t=>({t:"f",f:t,c:void 0,v:-1,d:new Map,x:!1}),V=(t,e)=>{t.d.set(e,e.v)},T=t=>{if(t.x)return!0;if(t.v===o)return!1;for(const[e,n]of t.d)if(e.t==="s"&&e.x||e.v!==n)return!0;return t.v===-1},z=t=>{if(!T(t))return t.c;t.d.clear(),t.x=!1;const e=D(t,t.f);for(const n of t.d.keys())if(n.t==="s"&&n.x||n.t==="f"&&n.x){t.x=!0;break}return t.c=e,t.v=o,e},d={};function S(t,e){const n=new Set;function r(s){if(!n.has(s)&&(n.add(s),e==null||e(s),s.t==="f"))for(const[u]of s.d)r(u)}return r(t),n}const y=t=>(C(t),t.t==="c"?t.c:t.t==="f"?z(t):A(t)),M=(t,e)=>({s:t,c:e,d:new Set}),l=(t,e=!0)=>{const n=x(()=>S(t.s));n.forEach(r=>{t.d.has(r)||(r.t==="c"?b(r,t):r.t==="s"&&B(r,t))}),t.d.forEach(r=>{n.has(r)||(r.t==="c"?w(r,t):r.t==="s"&&p(r,t))}),t.d=n,e&&(0,t.c)()},N=t=>{t.d.forEach(e=>{e.t==="c"?w(e,t):e.t==="s"&&p(e,t)}),t.d.clear()},j=(t,e)=>{const n=M(t,e);return l(n,!1),[()=>N(n),()=>{const u=x(()=>y(t));return l(n,!1),u}]},A=t=>(t.x&&i&&W(t),t.x?(0,t.r)():(t.c===d&&(t.c=t.r()),t.c)),W=t=>{t.x&&t.s&&(t.x=!1,t.d=t.s(()=>{t.c=d,t.v=h();for(const e of t.w)l(e)}))},B=(t,e)=>{t.w.add(e),t.w.size===1&&W(t)},p=(t,e)=>{t.w.delete(e),t.w.size===0&&(t.x=!0,t.d&&(t.d(),t.d=void 0),t.c=d)},I=(t,e)=>({t:"s",r:t,s:e,c:d,v:o,w:new Set,x:!0,d:void 0});let f=!1;const a=new Set;function L(t){if(f)return t(v);f=!0,a.clear();try{const e=t(v);for(const n of a)l(n);return e}finally{f=!1,a.clear()}}function v(t,e){if(!f)throw new Error("Cell mutations must occur within a batch()");if(t.c!==e){t.c=e,t.v=h();for(const n of t.w)a.add(n)}}exports.batch=L;exports.cell=k;exports.formula=F;exports.get=y;exports.source=I;exports.untracked=E;exports.visitDependencies=S;exports.watch=j;
|
package/dist/cells.d.ts
CHANGED
|
@@ -9,19 +9,22 @@ declare type BaseSignal = Signal<unknown>;
|
|
|
9
9
|
* - No intermediate inconsistent states are observable
|
|
10
10
|
*
|
|
11
11
|
* @param fn - Function that receives a swap function for updating cells
|
|
12
|
+
* @returns The return value of the provided function
|
|
12
13
|
*
|
|
13
14
|
* @example
|
|
14
15
|
* ```typescript
|
|
15
16
|
* const x = cell(1);
|
|
16
17
|
* const y = cell(2);
|
|
17
18
|
*
|
|
18
|
-
* batch((swap) => {
|
|
19
|
+
* const result = batch((swap) => {
|
|
19
20
|
* swap(x, 10);
|
|
20
21
|
* swap(y, 20);
|
|
22
|
+
* return 'updated';
|
|
21
23
|
* });
|
|
24
|
+
* // result === 'updated'
|
|
22
25
|
* ```
|
|
23
26
|
*/
|
|
24
|
-
export declare function batch(fn: (swap: SwapFunction) =>
|
|
27
|
+
export declare function batch<T>(fn: (swap: SwapFunction) => T): T;
|
|
25
28
|
|
|
26
29
|
export declare interface Cell<T> {
|
|
27
30
|
/** Type */
|
|
@@ -130,9 +133,7 @@ export declare interface Source<T> {
|
|
|
130
133
|
/** Disposer for the subscription */
|
|
131
134
|
d?: Disposer;
|
|
132
135
|
/** Cached value */
|
|
133
|
-
c: T |
|
|
134
|
-
/** Whether the cache is primed */
|
|
135
|
-
p: boolean;
|
|
136
|
+
c: T | typeof STALE;
|
|
136
137
|
/** Volatile flag */
|
|
137
138
|
x: boolean;
|
|
138
139
|
/** Version */
|
|
@@ -171,6 +172,9 @@ export declare interface Source<T> {
|
|
|
171
172
|
*/
|
|
172
173
|
export declare const source: <T>(read: () => T, subscribe?: (onChange: () => void) => () => void) => Source<T>;
|
|
173
174
|
|
|
175
|
+
/** Sentinel value indicating cache is empty. */
|
|
176
|
+
declare const STALE: {};
|
|
177
|
+
|
|
174
178
|
export declare type SwapFunction = <T>(cell: Cell<T>, newValue: T) => void;
|
|
175
179
|
|
|
176
180
|
/**
|
|
@@ -227,14 +231,14 @@ export declare function visitDependencies<T>(signal: Signal<T>, visitor?: (signa
|
|
|
227
231
|
*
|
|
228
232
|
* @param signal - The signal to watch
|
|
229
233
|
* @param onChange - Function to call when the signal changes
|
|
230
|
-
* @returns A
|
|
234
|
+
* @returns A tuple of [dispose, renew] functions
|
|
231
235
|
*
|
|
232
236
|
* @example
|
|
233
237
|
* ```typescript
|
|
234
238
|
* const count = cell(0);
|
|
235
239
|
*
|
|
236
|
-
* const dispose = watch(count, () => {
|
|
237
|
-
* console.log('Count changed to:',
|
|
240
|
+
* const [dispose, renew] = watch(count, () => {
|
|
241
|
+
* console.log('Count changed to:', renew());
|
|
238
242
|
* });
|
|
239
243
|
*
|
|
240
244
|
* batch((swap) => {
|
|
@@ -244,7 +248,7 @@ export declare function visitDependencies<T>(signal: Signal<T>, visitor?: (signa
|
|
|
244
248
|
* dispose(); // Stop watching
|
|
245
249
|
* ```
|
|
246
250
|
*/
|
|
247
|
-
export declare const watch: <T>(signal: Signal<T>, onChange: ChangeHandler) => Disposer;
|
|
251
|
+
export declare const watch: <T>(signal: Signal<T>, onChange: ChangeHandler) => [dispose: Disposer, renew: () => T];
|
|
248
252
|
|
|
249
253
|
declare interface Watcher<T> {
|
|
250
254
|
/** Signal */
|
package/dist/cells.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
let
|
|
2
|
-
function
|
|
3
|
-
return ++
|
|
1
|
+
let o = 0;
|
|
2
|
+
function x() {
|
|
3
|
+
return ++o;
|
|
4
4
|
}
|
|
5
|
-
const
|
|
5
|
+
const W = (t, e) => {
|
|
6
6
|
t.w.add(e);
|
|
7
|
-
},
|
|
7
|
+
}, h = (t, e) => {
|
|
8
8
|
t.w.delete(e);
|
|
9
|
-
},
|
|
9
|
+
}, A = (t) => ({
|
|
10
10
|
t: "c",
|
|
11
11
|
c: t,
|
|
12
|
-
v:
|
|
12
|
+
v: o,
|
|
13
13
|
w: /* @__PURE__ */ new Set()
|
|
14
14
|
});
|
|
15
|
-
let c = null,
|
|
16
|
-
const
|
|
15
|
+
let c = null, i = !1;
|
|
16
|
+
const p = (t) => {
|
|
17
17
|
c && k(c, t);
|
|
18
|
-
},
|
|
18
|
+
}, C = (t, e) => {
|
|
19
19
|
const n = c;
|
|
20
20
|
c = t;
|
|
21
21
|
try {
|
|
@@ -23,13 +23,13 @@ const y = (t) => {
|
|
|
23
23
|
} finally {
|
|
24
24
|
c = n;
|
|
25
25
|
}
|
|
26
|
-
},
|
|
27
|
-
const e =
|
|
28
|
-
|
|
26
|
+
}, w = (t) => {
|
|
27
|
+
const e = i;
|
|
28
|
+
i = !0;
|
|
29
29
|
try {
|
|
30
30
|
return t();
|
|
31
31
|
} finally {
|
|
32
|
-
|
|
32
|
+
i = e;
|
|
33
33
|
}
|
|
34
34
|
}, B = (t) => {
|
|
35
35
|
const e = c;
|
|
@@ -51,108 +51,107 @@ const y = (t) => {
|
|
|
51
51
|
}, D = (t) => {
|
|
52
52
|
if (t.x)
|
|
53
53
|
return !0;
|
|
54
|
-
if (t.v ===
|
|
54
|
+
if (t.v === o)
|
|
55
55
|
return !1;
|
|
56
56
|
for (const [e, n] of t.d)
|
|
57
57
|
if (e.t === "s" && e.x || e.v !== n)
|
|
58
58
|
return !0;
|
|
59
59
|
return t.v === -1;
|
|
60
|
-
},
|
|
60
|
+
}, E = (t) => {
|
|
61
61
|
if (!D(t))
|
|
62
62
|
return t.c;
|
|
63
63
|
t.d.clear(), t.x = !1;
|
|
64
|
-
const e =
|
|
64
|
+
const e = C(t, t.f);
|
|
65
65
|
for (const n of t.d.keys())
|
|
66
66
|
if (n.t === "s" && n.x || n.t === "f" && n.x) {
|
|
67
67
|
t.x = !0;
|
|
68
68
|
break;
|
|
69
69
|
}
|
|
70
|
-
return t.c = e, t.v =
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
t.c = void 0, t.p = !1, t.v = l();
|
|
74
|
-
for (const e of t.w)
|
|
75
|
-
e.c();
|
|
76
|
-
}));
|
|
77
|
-
}, E = (t, e) => {
|
|
78
|
-
t.w.add(e), t.w.size === 1 && x(t);
|
|
79
|
-
}, h = (t, e) => {
|
|
80
|
-
t.w.delete(e), t.w.size === 0 && (t.x = !0, t.d && (t.d(), t.d = void 0), t.c = void 0, t.p = !1);
|
|
81
|
-
}, M = (t, e) => ({
|
|
82
|
-
t: "s",
|
|
83
|
-
r: t,
|
|
84
|
-
s: e,
|
|
85
|
-
c: void 0,
|
|
86
|
-
v: f,
|
|
87
|
-
w: /* @__PURE__ */ new Set(),
|
|
88
|
-
x: !0,
|
|
89
|
-
p: !1,
|
|
90
|
-
d: void 0
|
|
91
|
-
}), T = (t) => (y(t), t.t === "c" ? t.c : t.t === "f" ? v(t) : b(t));
|
|
92
|
-
function F(t, e) {
|
|
70
|
+
return t.c = e, t.v = o, e;
|
|
71
|
+
}, l = {};
|
|
72
|
+
function b(t, e) {
|
|
93
73
|
const n = /* @__PURE__ */ new Set();
|
|
94
|
-
function r(
|
|
95
|
-
if (!n.has(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
r(p);
|
|
99
|
-
}
|
|
74
|
+
function r(s) {
|
|
75
|
+
if (!n.has(s) && (n.add(s), e == null || e(s), s.t === "f"))
|
|
76
|
+
for (const [u] of s.d)
|
|
77
|
+
r(u);
|
|
100
78
|
}
|
|
101
79
|
return r(t), n;
|
|
102
80
|
}
|
|
103
|
-
const V = (t, e) => ({
|
|
81
|
+
const F = (t) => (p(t), t.t === "c" ? t.c : t.t === "f" ? E(t) : N(t)), V = (t, e) => ({
|
|
104
82
|
s: t,
|
|
105
83
|
c: e,
|
|
106
84
|
d: /* @__PURE__ */ new Set()
|
|
107
|
-
}),
|
|
108
|
-
const n =
|
|
109
|
-
() =>
|
|
85
|
+
}), d = (t, e = !0) => {
|
|
86
|
+
const n = w(
|
|
87
|
+
() => b(t.s)
|
|
110
88
|
);
|
|
111
89
|
n.forEach((r) => {
|
|
112
|
-
t.d.has(r) || (r.t === "c" ?
|
|
90
|
+
t.d.has(r) || (r.t === "c" ? W(r, t) : r.t === "s" && T(r, t));
|
|
113
91
|
}), t.d.forEach((r) => {
|
|
114
|
-
n.has(r) || (r.t === "c" ?
|
|
92
|
+
n.has(r) || (r.t === "c" ? h(r, t) : r.t === "s" && y(r, t));
|
|
115
93
|
}), t.d = n, e && (0, t.c)();
|
|
116
94
|
}, z = (t) => {
|
|
117
95
|
t.d.forEach((e) => {
|
|
118
|
-
e.t === "c" ?
|
|
96
|
+
e.t === "c" ? h(e, t) : e.t === "s" && y(e, t);
|
|
119
97
|
}), t.d.clear();
|
|
120
|
-
},
|
|
98
|
+
}, L = (t, e) => {
|
|
121
99
|
const n = V(t, e);
|
|
122
|
-
return
|
|
123
|
-
|
|
124
|
-
|
|
100
|
+
return d(n, !1), [() => z(n), () => {
|
|
101
|
+
const u = w(() => F(t));
|
|
102
|
+
return d(n, !1), u;
|
|
103
|
+
}];
|
|
104
|
+
}, N = (t) => (t.x && i && S(t), t.x ? (0, t.r)() : (t.c === l && (t.c = t.r()), t.c)), S = (t) => {
|
|
105
|
+
t.x && t.s && (t.x = !1, t.d = t.s(() => {
|
|
106
|
+
t.c = l, t.v = x();
|
|
107
|
+
for (const e of t.w)
|
|
108
|
+
d(e);
|
|
109
|
+
}));
|
|
110
|
+
}, T = (t, e) => {
|
|
111
|
+
t.w.add(e), t.w.size === 1 && S(t);
|
|
112
|
+
}, y = (t, e) => {
|
|
113
|
+
t.w.delete(e), t.w.size === 0 && (t.x = !0, t.d && (t.d(), t.d = void 0), t.c = l);
|
|
114
|
+
}, M = (t, e) => ({
|
|
115
|
+
t: "s",
|
|
116
|
+
r: t,
|
|
117
|
+
s: e,
|
|
118
|
+
c: l,
|
|
119
|
+
v: o,
|
|
120
|
+
w: /* @__PURE__ */ new Set(),
|
|
121
|
+
x: !0,
|
|
122
|
+
d: void 0
|
|
123
|
+
});
|
|
124
|
+
let f = !1;
|
|
125
125
|
const a = /* @__PURE__ */ new Set();
|
|
126
|
-
function
|
|
127
|
-
if (
|
|
128
|
-
t(
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
s = !0, a.clear();
|
|
126
|
+
function j(t) {
|
|
127
|
+
if (f)
|
|
128
|
+
return t(v);
|
|
129
|
+
f = !0, a.clear();
|
|
132
130
|
try {
|
|
133
|
-
t(
|
|
134
|
-
for (const
|
|
135
|
-
|
|
131
|
+
const e = t(v);
|
|
132
|
+
for (const n of a)
|
|
133
|
+
d(n);
|
|
134
|
+
return e;
|
|
136
135
|
} finally {
|
|
137
|
-
|
|
136
|
+
f = !1, a.clear();
|
|
138
137
|
}
|
|
139
138
|
}
|
|
140
|
-
function
|
|
141
|
-
if (!
|
|
139
|
+
function v(t, e) {
|
|
140
|
+
if (!f)
|
|
142
141
|
throw new Error("Cell mutations must occur within a batch()");
|
|
143
142
|
if (t.c !== e) {
|
|
144
|
-
t.c = e, t.v =
|
|
143
|
+
t.c = e, t.v = x();
|
|
145
144
|
for (const n of t.w)
|
|
146
145
|
a.add(n);
|
|
147
146
|
}
|
|
148
147
|
}
|
|
149
148
|
export {
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
j as batch,
|
|
150
|
+
A as cell,
|
|
152
151
|
I as formula,
|
|
153
|
-
|
|
152
|
+
F as get,
|
|
154
153
|
M as source,
|
|
155
154
|
B as untracked,
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
b as visitDependencies,
|
|
156
|
+
L as watch
|
|
158
157
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@retreon/cells",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.1-2025-06-19.ef01c21",
|
|
5
5
|
"description": "A minimal spreadsheet engine",
|
|
6
6
|
"author": "Jesse Gibson <JesseTheGibson@gmail.com>",
|
|
7
7
|
"license": "MIT",
|