@graphrefly/graphrefly 0.24.0 → 0.26.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.
- package/README.md +8 -0
- package/dist/{chunk-QOWVNWOC.js → chunk-3ZWCKRHX.js} +27 -25
- package/dist/{chunk-QOWVNWOC.js.map → chunk-3ZWCKRHX.js.map} +1 -1
- package/dist/chunk-6LDQFTYS.js +102 -0
- package/dist/chunk-6LDQFTYS.js.map +1 -0
- package/dist/{chunk-5WGT55R4.js → chunk-AMCG74RZ.js} +195 -24
- package/dist/chunk-AMCG74RZ.js.map +1 -0
- package/dist/{chunk-AOCBDH4T.js → chunk-BVZYTZ5H.js} +76 -103
- package/dist/chunk-BVZYTZ5H.js.map +1 -0
- package/dist/chunk-FQMKGR6L.js +330 -0
- package/dist/chunk-FQMKGR6L.js.map +1 -0
- package/dist/chunk-HXZEYDUR.js +94 -0
- package/dist/chunk-HXZEYDUR.js.map +1 -0
- package/dist/{chunk-IPLKX3L2.js → chunk-IZYUSJC7.js} +16 -14
- package/dist/{chunk-IPLKX3L2.js.map → chunk-IZYUSJC7.js.map} +1 -1
- package/dist/chunk-J22W6HV3.js +107 -0
- package/dist/chunk-J22W6HV3.js.map +1 -0
- package/dist/{chunk-HWPIFSW2.js → chunk-JSCT3CR4.js} +6 -4
- package/dist/{chunk-HWPIFSW2.js.map → chunk-JSCT3CR4.js.map} +1 -1
- package/dist/chunk-JYXEWPH4.js +62 -0
- package/dist/chunk-JYXEWPH4.js.map +1 -0
- package/dist/chunk-LCE3GF5P.js +866 -0
- package/dist/chunk-LCE3GF5P.js.map +1 -0
- package/dist/chunk-MJ2NKQQL.js +119 -0
- package/dist/chunk-MJ2NKQQL.js.map +1 -0
- package/dist/chunk-N6UR7YVY.js +198 -0
- package/dist/chunk-N6UR7YVY.js.map +1 -0
- package/dist/chunk-OHISZPOJ.js +97 -0
- package/dist/chunk-OHISZPOJ.js.map +1 -0
- package/dist/{chunk-5DJTTKX3.js → chunk-PHOUUNK7.js} +74 -111
- package/dist/chunk-PHOUUNK7.js.map +1 -0
- package/dist/{chunk-PY4XCDLR.js → chunk-RB6QPHJ7.js} +8 -6
- package/dist/{chunk-PY4XCDLR.js.map → chunk-RB6QPHJ7.js.map} +1 -1
- package/dist/chunk-SN4YWWYO.js +171 -0
- package/dist/chunk-SN4YWWYO.js.map +1 -0
- package/dist/chunk-SX52TAR4.js +110 -0
- package/dist/chunk-SX52TAR4.js.map +1 -0
- package/dist/{chunk-XOFWRC73.js → chunk-THTWHNU4.js} +319 -24
- package/dist/chunk-THTWHNU4.js.map +1 -0
- package/dist/{chunk-H4RVA4VE.js → chunk-VYPWMZ6H.js} +2 -2
- package/dist/chunk-XGPU467M.js +136 -0
- package/dist/chunk-XGPU467M.js.map +1 -0
- package/dist/{chunk-TDEXAMGO.js → chunk-ZQMEI34O.js} +206 -574
- package/dist/chunk-ZQMEI34O.js.map +1 -0
- package/dist/compat/index.cjs +7656 -0
- package/dist/compat/index.cjs.map +1 -0
- package/dist/compat/index.d.cts +18 -0
- package/dist/compat/index.d.ts +18 -0
- package/dist/compat/index.js +49 -0
- package/dist/compat/index.js.map +1 -0
- package/dist/compat/jotai/index.cjs +2048 -0
- package/dist/compat/jotai/index.cjs.map +1 -0
- package/dist/compat/jotai/index.d.cts +2 -0
- package/dist/compat/jotai/index.d.ts +2 -0
- package/dist/compat/jotai/index.js +9 -0
- package/dist/compat/jotai/index.js.map +1 -0
- package/dist/compat/nanostores/index.cjs +2175 -0
- package/dist/compat/nanostores/index.cjs.map +1 -0
- package/dist/compat/nanostores/index.d.cts +2 -0
- package/dist/compat/nanostores/index.d.ts +2 -0
- package/dist/compat/nanostores/index.js +23 -0
- package/dist/compat/nanostores/index.js.map +1 -0
- package/dist/compat/nestjs/index.cjs +350 -16
- package/dist/compat/nestjs/index.cjs.map +1 -1
- package/dist/compat/nestjs/index.d.cts +6 -6
- package/dist/compat/nestjs/index.d.ts +6 -6
- package/dist/compat/nestjs/index.js +10 -9
- package/dist/compat/react/index.cjs +141 -0
- package/dist/compat/react/index.cjs.map +1 -0
- package/dist/compat/react/index.d.cts +2 -0
- package/dist/compat/react/index.d.ts +2 -0
- package/dist/compat/react/index.js +12 -0
- package/dist/compat/react/index.js.map +1 -0
- package/dist/compat/solid/index.cjs +128 -0
- package/dist/compat/solid/index.cjs.map +1 -0
- package/dist/compat/solid/index.d.cts +2 -0
- package/dist/compat/solid/index.d.ts +2 -0
- package/dist/compat/solid/index.js +12 -0
- package/dist/compat/solid/index.js.map +1 -0
- package/dist/compat/svelte/index.cjs +131 -0
- package/dist/compat/svelte/index.cjs.map +1 -0
- package/dist/compat/svelte/index.d.cts +2 -0
- package/dist/compat/svelte/index.d.ts +2 -0
- package/dist/compat/svelte/index.js +12 -0
- package/dist/compat/svelte/index.js.map +1 -0
- package/dist/compat/vue/index.cjs +146 -0
- package/dist/compat/vue/index.cjs.map +1 -0
- package/dist/compat/vue/index.d.cts +3 -0
- package/dist/compat/vue/index.d.ts +3 -0
- package/dist/compat/vue/index.js +12 -0
- package/dist/compat/vue/index.js.map +1 -0
- package/dist/compat/zustand/index.cjs +4931 -0
- package/dist/compat/zustand/index.cjs.map +1 -0
- package/dist/compat/zustand/index.d.cts +5 -0
- package/dist/compat/zustand/index.d.ts +5 -0
- package/dist/compat/zustand/index.js +12 -0
- package/dist/compat/zustand/index.js.map +1 -0
- package/dist/core/index.cjs +53 -4
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +3 -3
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js +26 -24
- package/dist/demo-shell-26p5fVxn.d.cts +102 -0
- package/dist/demo-shell-DEp-nMTl.d.ts +102 -0
- package/dist/extra/index.cjs +290 -110
- package/dist/extra/index.cjs.map +1 -1
- package/dist/extra/index.d.cts +5 -4
- package/dist/extra/index.d.ts +5 -4
- package/dist/extra/index.js +8 -5
- package/dist/extra/sources.cjs +2486 -0
- package/dist/extra/sources.cjs.map +1 -0
- package/dist/extra/sources.d.cts +465 -0
- package/dist/extra/sources.d.ts +465 -0
- package/dist/extra/sources.js +57 -0
- package/dist/extra/sources.js.map +1 -0
- package/dist/graph/index.cjs +408 -14
- package/dist/graph/index.cjs.map +1 -1
- package/dist/graph/index.d.cts +5 -5
- package/dist/graph/index.d.ts +5 -5
- package/dist/graph/index.js +13 -5
- package/dist/{graph-D-3JIQme.d.cts → graph-6tZ5jEzr.d.cts} +195 -4
- package/dist/{graph-B6NFqv3z.d.ts → graph-DQ69XU0g.d.ts} +195 -4
- package/dist/index-B4MP_8V_.d.cts +37 -0
- package/dist/index-BEfE8H_G.d.cts +121 -0
- package/dist/{index-D7XgsUt7.d.ts → index-BW1z3BN9.d.ts} +169 -127
- package/dist/index-BYOHF0zP.d.ts +34 -0
- package/dist/index-B_IP40nB.d.cts +36 -0
- package/dist/index-Bd_fwmLf.d.cts +45 -0
- package/dist/{index-BysCTzJz.d.ts → index-BeIdBfcb.d.cts} +121 -547
- package/dist/index-BjI6ty9z.d.ts +121 -0
- package/dist/index-Bxb5ZYc9.d.cts +34 -0
- package/dist/{index-BJB7t9gg.d.cts → index-C0ZXMaXO.d.cts} +2 -2
- package/dist/{index-b5BYtczN.d.cts → index-C8mdwMXc.d.cts} +169 -127
- package/dist/index-CDAjUFIv.d.ts +36 -0
- package/dist/index-CPgZ5wRl.d.ts +44 -0
- package/dist/{index-AMWewNDe.d.cts → index-CUwyr1Kk.d.cts} +33 -4
- package/dist/index-CUyrtuOf.d.cts +127 -0
- package/dist/{index-C-TXEa7C.d.ts → index-CY2TljO4.d.ts} +2 -2
- package/dist/index-CmnuOibw.d.ts +37 -0
- package/dist/{index-DiobMNwE.d.ts → index-CuYwdKO-.d.ts} +3 -3
- package/dist/index-DFhjO4Gg.d.cts +44 -0
- package/dist/{index-1z8vRTCt.d.cts → index-DdD5MVDL.d.ts} +121 -547
- package/dist/index-DrISNAOm.d.ts +45 -0
- package/dist/index-QBpffFW-.d.cts +86 -0
- package/dist/{index-J7Kc0oIQ.d.cts → index-_oMEWlDq.d.cts} +3 -3
- package/dist/{index-CYkjxu3s.d.ts → index-eJ6T_qGM.d.ts} +33 -4
- package/dist/index-qldRdbQw.d.ts +86 -0
- package/dist/index-xdGjv0nO.d.ts +127 -0
- package/dist/index.cjs +2334 -195
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1007 -648
- package/dist/index.d.ts +1007 -648
- package/dist/index.js +1204 -1172
- package/dist/index.js.map +1 -1
- package/dist/{meta-CnkLA_43.d.ts → meta-BGqSZ7mt.d.ts} +1 -1
- package/dist/{meta-DWbkoq1s.d.cts → meta-C0-8XW6Q.d.cts} +1 -1
- package/dist/{node-B-f-Lu-k.d.cts → node-C_IBuvX2.d.cts} +26 -1
- package/dist/{node-B-f-Lu-k.d.ts → node-C_IBuvX2.d.ts} +26 -1
- package/dist/{observable-DBnrwcar.d.cts → observable-Crr1jgzx.d.cts} +1 -1
- package/dist/{observable-uP-wy_uK.d.ts → observable-DCk45RH5.d.ts} +1 -1
- package/dist/patterns/demo-shell.cjs +5604 -0
- package/dist/patterns/demo-shell.cjs.map +1 -0
- package/dist/patterns/demo-shell.d.cts +6 -0
- package/dist/patterns/demo-shell.d.ts +6 -0
- package/dist/patterns/demo-shell.js +15 -0
- package/dist/patterns/demo-shell.js.map +1 -0
- package/dist/patterns/reactive-layout/index.cjs +843 -29
- package/dist/patterns/reactive-layout/index.cjs.map +1 -1
- package/dist/patterns/reactive-layout/index.d.cts +6 -5
- package/dist/patterns/reactive-layout/index.d.ts +6 -5
- package/dist/patterns/reactive-layout/index.js +25 -10
- package/dist/reactive-layout-BaOQefHu.d.cts +183 -0
- package/dist/reactive-layout-D9gejYXE.d.ts +183 -0
- package/dist/{storage-BuTdpCI1.d.cts → storage-BMycWEh2.d.ts} +9 -1
- package/dist/{storage-F2X1U1x0.d.ts → storage-DiqWHzVI.d.cts} +9 -1
- package/package.json +32 -2
- package/dist/chunk-5DJTTKX3.js.map +0 -1
- package/dist/chunk-5WGT55R4.js.map +0 -1
- package/dist/chunk-AOCBDH4T.js.map +0 -1
- package/dist/chunk-MW4VAKAO.js +0 -47
- package/dist/chunk-MW4VAKAO.js.map +0 -1
- package/dist/chunk-TDEXAMGO.js.map +0 -1
- package/dist/chunk-XOFWRC73.js.map +0 -1
- /package/dist/{chunk-H4RVA4VE.js.map → chunk-VYPWMZ6H.js.map} +0 -0
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
COMPLETE,
|
|
3
|
-
DATA,
|
|
4
|
-
DIRTY,
|
|
5
|
-
ERROR,
|
|
6
|
-
RESOLVED,
|
|
7
2
|
node,
|
|
8
3
|
producer,
|
|
9
4
|
state,
|
|
10
5
|
wallClockNs
|
|
11
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-PHOUUNK7.js";
|
|
7
|
+
import {
|
|
8
|
+
COMPLETE,
|
|
9
|
+
DATA,
|
|
10
|
+
DIRTY,
|
|
11
|
+
ERROR,
|
|
12
|
+
RESOLVED
|
|
13
|
+
} from "./chunk-SX52TAR4.js";
|
|
12
14
|
|
|
13
15
|
// src/extra/cron.ts
|
|
14
16
|
function parseField(field, min, max) {
|
|
@@ -54,8 +56,6 @@ function matchesCron(schedule, date) {
|
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
// src/extra/sources.ts
|
|
57
|
-
import { existsSync, watch } from "fs";
|
|
58
|
-
import { resolve as resolvePath } from "path";
|
|
59
59
|
function sourceOpts(opts) {
|
|
60
60
|
return { describeKind: "producer", ...opts };
|
|
61
61
|
}
|
|
@@ -149,6 +149,72 @@ function fromTimer(ms, opts) {
|
|
|
149
149
|
return cleanup;
|
|
150
150
|
}, sourceOpts(rest));
|
|
151
151
|
}
|
|
152
|
+
function fromRaf(opts) {
|
|
153
|
+
const { signal, ...rest } = opts ?? {};
|
|
154
|
+
return producer((a) => {
|
|
155
|
+
let done = false;
|
|
156
|
+
let rafId;
|
|
157
|
+
let fallbackTimer;
|
|
158
|
+
let abortListenerAdded = false;
|
|
159
|
+
let visibilityListenerAdded = false;
|
|
160
|
+
const raf = typeof requestAnimationFrame === "function" ? requestAnimationFrame : void 0;
|
|
161
|
+
const caf = typeof cancelAnimationFrame === "function" ? cancelAnimationFrame : void 0;
|
|
162
|
+
const doc = typeof document !== "undefined" ? document : void 0;
|
|
163
|
+
const clearPending = () => {
|
|
164
|
+
if (rafId !== void 0 && caf) caf(rafId);
|
|
165
|
+
if (fallbackTimer !== void 0) clearTimeout(fallbackTimer);
|
|
166
|
+
rafId = void 0;
|
|
167
|
+
fallbackTimer = void 0;
|
|
168
|
+
};
|
|
169
|
+
const cleanup = () => {
|
|
170
|
+
done = true;
|
|
171
|
+
clearPending();
|
|
172
|
+
if (abortListenerAdded) {
|
|
173
|
+
signal?.removeEventListener("abort", onAbort);
|
|
174
|
+
abortListenerAdded = false;
|
|
175
|
+
}
|
|
176
|
+
if (visibilityListenerAdded && doc) {
|
|
177
|
+
doc.removeEventListener("visibilitychange", onVisibilityChange);
|
|
178
|
+
visibilityListenerAdded = false;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
const onAbort = () => {
|
|
182
|
+
if (done) return;
|
|
183
|
+
cleanup();
|
|
184
|
+
a.down([[ERROR, signal.reason]]);
|
|
185
|
+
};
|
|
186
|
+
const tick = (now) => {
|
|
187
|
+
if (done) return;
|
|
188
|
+
a.emit(now);
|
|
189
|
+
scheduleNext();
|
|
190
|
+
};
|
|
191
|
+
const scheduleNext = () => {
|
|
192
|
+
if (done) return;
|
|
193
|
+
if (raf && (!doc || doc.visibilityState !== "hidden")) {
|
|
194
|
+
rafId = raf(tick);
|
|
195
|
+
} else {
|
|
196
|
+
fallbackTimer = setTimeout(() => tick(performance.now()), 16);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
const onVisibilityChange = () => {
|
|
200
|
+
if (done) return;
|
|
201
|
+
clearPending();
|
|
202
|
+
scheduleNext();
|
|
203
|
+
};
|
|
204
|
+
if (signal?.aborted) {
|
|
205
|
+
onAbort();
|
|
206
|
+
return cleanup;
|
|
207
|
+
}
|
|
208
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
209
|
+
abortListenerAdded = signal !== void 0;
|
|
210
|
+
if (doc && raf) {
|
|
211
|
+
doc.addEventListener("visibilitychange", onVisibilityChange);
|
|
212
|
+
visibilityListenerAdded = true;
|
|
213
|
+
}
|
|
214
|
+
scheduleNext();
|
|
215
|
+
return cleanup;
|
|
216
|
+
}, sourceOpts(rest));
|
|
217
|
+
}
|
|
152
218
|
function fromCron(expr, opts) {
|
|
153
219
|
const schedule = parseCron(expr);
|
|
154
220
|
const { tickMs: tickOpt, output, ...rest } = opts ?? {};
|
|
@@ -183,99 +249,6 @@ function fromEvent(target, type, opts) {
|
|
|
183
249
|
return () => target.removeEventListener(type, handler, options);
|
|
184
250
|
}, sourceOpts(rest));
|
|
185
251
|
}
|
|
186
|
-
function fromFSWatch(paths, opts) {
|
|
187
|
-
const list = Array.isArray(paths) ? paths : [paths];
|
|
188
|
-
if (list.length === 0) {
|
|
189
|
-
throw new RangeError("fromFSWatch expects at least one path");
|
|
190
|
-
}
|
|
191
|
-
const { recursive = true, debounce = 100, include, exclude, ...rest } = opts ?? {};
|
|
192
|
-
const includePatterns = include?.map(globToRegExp) ?? [];
|
|
193
|
-
const excludePatterns = (exclude ?? ["**/node_modules/**", "**/.git/**", "**/dist/**"]).map(
|
|
194
|
-
globToRegExp
|
|
195
|
-
);
|
|
196
|
-
return producer((a) => {
|
|
197
|
-
const pending = /* @__PURE__ */ new Map();
|
|
198
|
-
const watchers = [];
|
|
199
|
-
let stopped = false;
|
|
200
|
-
let terminalEmitted = false;
|
|
201
|
-
let generation = 0;
|
|
202
|
-
const closeWatchers = () => {
|
|
203
|
-
for (const watcher of watchers.splice(0)) watcher.close();
|
|
204
|
-
};
|
|
205
|
-
const emitError = (err) => {
|
|
206
|
-
if (terminalEmitted) return;
|
|
207
|
-
terminalEmitted = true;
|
|
208
|
-
stopped = true;
|
|
209
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
210
|
-
timer = void 0;
|
|
211
|
-
pending.clear();
|
|
212
|
-
closeWatchers();
|
|
213
|
-
a.down([[ERROR, err]]);
|
|
214
|
-
};
|
|
215
|
-
let timer;
|
|
216
|
-
const flush = (token) => {
|
|
217
|
-
timer = void 0;
|
|
218
|
-
if (stopped || terminalEmitted) return;
|
|
219
|
-
if (pending.size === 0) return;
|
|
220
|
-
const batchMessages = [];
|
|
221
|
-
for (const evt of pending.values()) batchMessages.push([DATA, evt]);
|
|
222
|
-
pending.clear();
|
|
223
|
-
if (stopped || terminalEmitted || token !== generation) return;
|
|
224
|
-
a.down(batchMessages);
|
|
225
|
-
};
|
|
226
|
-
try {
|
|
227
|
-
for (const basePath of list) {
|
|
228
|
-
const watcher = watch(
|
|
229
|
-
basePath,
|
|
230
|
-
{ recursive },
|
|
231
|
-
(eventType, fileName) => {
|
|
232
|
-
if (stopped || terminalEmitted) return;
|
|
233
|
-
if (fileName == null) return;
|
|
234
|
-
const rel = String(fileName).replaceAll("\\", "/");
|
|
235
|
-
const abs = resolvePath(basePath, String(fileName));
|
|
236
|
-
const normalized = abs.replaceAll("\\", "/");
|
|
237
|
-
const root = resolvePath(basePath).replaceAll("\\", "/");
|
|
238
|
-
const relForMatch = rel.startsWith("./") ? rel.slice(2) : rel;
|
|
239
|
-
const included = includePatterns.length === 0 || matchesAnyPattern(normalized, includePatterns) || matchesAnyPattern(relForMatch, includePatterns);
|
|
240
|
-
if (!included) return;
|
|
241
|
-
const excluded = matchesAnyPattern(normalized, excludePatterns) || matchesAnyPattern(relForMatch, excludePatterns);
|
|
242
|
-
if (excluded) return;
|
|
243
|
-
let kind = "change";
|
|
244
|
-
if (eventType === "rename") {
|
|
245
|
-
try {
|
|
246
|
-
kind = existsSync(normalized) ? "create" : "delete";
|
|
247
|
-
} catch {
|
|
248
|
-
kind = "rename";
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
pending.set(normalized, {
|
|
252
|
-
type: kind,
|
|
253
|
-
path: normalized,
|
|
254
|
-
root,
|
|
255
|
-
relative_path: relForMatch,
|
|
256
|
-
timestamp_ns: wallClockNs()
|
|
257
|
-
});
|
|
258
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
259
|
-
const token = generation;
|
|
260
|
-
timer = setTimeout(() => flush(token), debounce);
|
|
261
|
-
}
|
|
262
|
-
);
|
|
263
|
-
watcher.on("error", (err) => emitError(err));
|
|
264
|
-
watchers.push(watcher);
|
|
265
|
-
}
|
|
266
|
-
} catch (err) {
|
|
267
|
-
emitError(err);
|
|
268
|
-
}
|
|
269
|
-
return () => {
|
|
270
|
-
stopped = true;
|
|
271
|
-
generation += 1;
|
|
272
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
273
|
-
timer = void 0;
|
|
274
|
-
closeWatchers();
|
|
275
|
-
pending.clear();
|
|
276
|
-
};
|
|
277
|
-
}, sourceOpts(rest));
|
|
278
|
-
}
|
|
279
252
|
function fromIter(iterable, opts) {
|
|
280
253
|
return producer((a) => {
|
|
281
254
|
let cancelled = false;
|
|
@@ -601,9 +574,9 @@ export {
|
|
|
601
574
|
globToRegExp,
|
|
602
575
|
matchesAnyPattern,
|
|
603
576
|
fromTimer,
|
|
577
|
+
fromRaf,
|
|
604
578
|
fromCron,
|
|
605
579
|
fromEvent,
|
|
606
|
-
fromFSWatch,
|
|
607
580
|
fromIter,
|
|
608
581
|
fromPromise,
|
|
609
582
|
fromAsyncIter,
|
|
@@ -623,4 +596,4 @@ export {
|
|
|
623
596
|
keepalive,
|
|
624
597
|
reactiveCounter
|
|
625
598
|
};
|
|
626
|
-
//# sourceMappingURL=chunk-
|
|
599
|
+
//# sourceMappingURL=chunk-BVZYTZ5H.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/extra/cron.ts","../src/extra/sources.ts"],"sourcesContent":["/**\n * Minimal 5-field cron parser and matcher (minute hour day-of-month month day-of-week).\n * Ported from callbag-recharge `extra/cron.ts` for `fromCron` (roadmap §2.3).\n */\nexport interface CronSchedule {\n\tminutes: Set<number>;\n\thours: Set<number>;\n\tdaysOfMonth: Set<number>;\n\tmonths: Set<number>;\n\tdaysOfWeek: Set<number>;\n}\n\nfunction parseField(field: string, min: number, max: number): Set<number> {\n\tconst result = new Set<number>();\n\tfor (const part of field.split(\",\")) {\n\t\tconst [range, stepStr] = part.split(\"/\");\n\t\tconst step = stepStr ? Number.parseInt(stepStr, 10) : 1;\n\t\tif (Number.isNaN(step) || step < 1) throw new Error(`Invalid cron step: ${part}`);\n\t\tlet start: number;\n\t\tlet end: number;\n\t\tif (range === \"*\") {\n\t\t\tstart = min;\n\t\t\tend = max;\n\t\t} else if (range.includes(\"-\")) {\n\t\t\tconst [a, b] = range.split(\"-\");\n\t\t\tstart = Number.parseInt(a, 10);\n\t\t\tend = Number.parseInt(b, 10);\n\t\t} else {\n\t\t\tstart = Number.parseInt(range, 10);\n\t\t\tend = start;\n\t\t}\n\t\tif (Number.isNaN(start) || Number.isNaN(end)) throw new Error(`Invalid cron field: ${field}`);\n\t\tif (start < min || end > max)\n\t\t\tthrow new Error(`Cron field out of range: ${field} (${min}-${max})`);\n\t\tif (start > end) throw new Error(`Invalid cron range: ${start}-${end} in ${field}`);\n\t\tfor (let i = start; i <= end; i += step) result.add(i);\n\t}\n\treturn result;\n}\n\n/**\n * Parses a standard 5-field cron expression into a {@link CronSchedule}.\n *\n * Supports `*`, ranges (`1-5`), steps (`*\\/5`, `0-30/10`), and comma-separated\n * lists. Fields are: minute (0–59), hour (0–23), day-of-month (1–31),\n * month (1–12), day-of-week (0–6, Sunday = 0).\n *\n * @param expr - Five-field whitespace-separated cron string (e.g. `\"0 9 * * 1-5\"`).\n * @returns Parsed {@link CronSchedule} with one `Set<number>` per field.\n * @throws Error when the expression does not have exactly 5 fields, contains\n * out-of-range values, or uses an invalid step.\n *\n * @example\n * ```ts\n * import { parseCron } from \"@graphrefly/graphrefly-ts\";\n *\n * const sched = parseCron(\"0 9 * * 1-5\"); // weekdays at 09:00\n * sched.hours; // Set { 9 }\n * sched.daysOfWeek; // Set { 1, 2, 3, 4, 5 }\n * ```\n */\nexport function parseCron(expr: string): CronSchedule {\n\tconst parts = expr.trim().split(/\\s+/);\n\tif (parts.length !== 5) throw new Error(`Invalid cron: expected 5 fields, got ${parts.length}`);\n\treturn {\n\t\tminutes: parseField(parts[0], 0, 59),\n\t\thours: parseField(parts[1], 0, 23),\n\t\tdaysOfMonth: parseField(parts[2], 1, 31),\n\t\tmonths: parseField(parts[3], 1, 12),\n\t\tdaysOfWeek: parseField(parts[4], 0, 6),\n\t};\n}\n\n/**\n * Returns `true` if `date` satisfies every field of `schedule`.\n *\n * @param schedule - Parsed schedule from {@link parseCron}.\n * @param date - Moment to test (local time via `getMinutes`, `getHours`, etc.).\n * @returns `true` when all five cron fields match the given date.\n *\n * @example\n * ```ts\n * import { parseCron, matchesCron } from \"@graphrefly/graphrefly-ts\";\n *\n * const sched = parseCron(\"30 8 * * 1\"); // Mondays at 08:30\n * const monday = new Date(\"2026-03-30T08:30:00\"); // a Monday\n * matchesCron(sched, monday); // true\n * ```\n */\nexport function matchesCron(schedule: CronSchedule, date: Date): boolean {\n\treturn (\n\t\tschedule.minutes.has(date.getMinutes()) &&\n\t\tschedule.hours.has(date.getHours()) &&\n\t\tschedule.daysOfMonth.has(date.getDate()) &&\n\t\tschedule.months.has(date.getMonth() + 1) &&\n\t\tschedule.daysOfWeek.has(date.getDay())\n\t);\n}\n","/**\n * Core reactive sources, sinks, and utilities (roadmap §2.3).\n *\n * Each API returns a {@link Node} built with {@link node}, {@link producer},\n * {@link derived}, or {@link effect} — no second protocol.\n *\n * Protocol/system/ingest adapters (fromHTTP, fromWebSocket, fromKafka, etc.)\n * live in {@link ./adapters.ts}.\n */\n\nimport { wallClockNs } from \"../core/clock.js\";\nimport { COMPLETE, DATA, DIRTY, ERROR, RESOLVED } from \"../core/messages.js\";\nimport { type Node, type NodeOptions, type NodeSink, node } from \"../core/node.js\";\nimport { producer, state } from \"../core/sugar.js\";\nimport { type CronSchedule, matchesCron, parseCron } from \"./cron.js\";\n\ntype ExtraOpts = Omit<NodeOptions<unknown>, \"describeKind\">;\n\nfunction sourceOpts<T = unknown>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"producer\", ...opts } as NodeOptions<T>;\n}\n\n/** Options for {@link fromTimer} / {@link fromPromise} / {@link fromAsyncIter}. */\nexport type AsyncSourceOpts = ExtraOpts & { signal?: AbortSignal };\n\n/**\n * Values accepted by {@link fromAny}.\n *\n * @category extra\n */\nexport type NodeInput<T> = Node<T> | PromiseLike<T> | AsyncIterable<T> | Iterable<T> | T;\n\n/** Options for {@link fromCron}. */\nexport type FromCronOptions = ExtraOpts & {\n\t/** Polling interval in ms. Default `60_000`. */\n\ttickMs?: number;\n\t/** Output format: `\"timestamp_ns\"` (default) emits wall-clock nanoseconds; `\"date\"` emits a `Date` object. */\n\toutput?: \"timestamp_ns\" | \"date\";\n};\n\n/** DOM-style event target (browser or `node:events`). */\nexport type EventTargetLike = {\n\taddEventListener(\n\t\ttype: string,\n\t\tlistener: (ev: unknown) => void,\n\t\toptions?: boolean | { capture?: boolean; passive?: boolean; once?: boolean },\n\t): void;\n\tremoveEventListener(\n\t\ttype: string,\n\t\tlistener: (ev: unknown) => void,\n\t\toptions?: boolean | { capture?: boolean; passive?: boolean; once?: boolean },\n\t): void;\n};\n\n/** @internal Shared with adapters.ts and sources-fs.ts for glob matching. */\nexport function escapeRegexChar(ch: string): string {\n\treturn /[\\\\^$+?.()|[\\]{}]/.test(ch) ? `\\\\${ch}` : ch;\n}\n\n/** @internal */\nexport function globToRegExp(glob: string): RegExp {\n\tlet out = \"^\";\n\tfor (let i = 0; i < glob.length; i += 1) {\n\t\tconst ch = glob[i];\n\t\tif (ch === \"*\") {\n\t\t\tconst next = glob[i + 1];\n\t\t\tif (next === \"*\") {\n\t\t\t\tout += \".*\";\n\t\t\t\ti += 1;\n\t\t\t} else {\n\t\t\t\tout += \"[^/]*\";\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tout += escapeRegexChar(ch);\n\t}\n\tout += \"$\";\n\treturn new RegExp(out);\n}\n\n/** @internal */\nexport function matchesAnyPattern(path: string, patterns: RegExp[]): boolean {\n\tfor (const pattern of patterns) {\n\t\tif (pattern.test(path)) return true;\n\t}\n\treturn false;\n}\n\nfunction wrapSubscribeHook<T>(inner: Node<T>, before: (sink: NodeSink) => void): Node<T> {\n\t// node() passthrough instead of derived([inner], ([v]) => v) — derived uses\n\t// .at(-1) and would drop intermediate values from multi-DATA batches (D1 gap).\n\tconst wrapper = node<T>(\n\t\t[inner as Node],\n\t\t(data, a) => {\n\t\t\tconst batch0 = data[0];\n\t\t\tif (batch0 == null || batch0.length === 0) {\n\t\t\t\ta.down([[RESOLVED]]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const v of batch0) a.emit(v as T);\n\t\t},\n\t\t{ describeKind: \"derived\", initial: inner.cache as T },\n\t);\n\tconst origSubscribe = wrapper.subscribe.bind(wrapper);\n\t(wrapper as { subscribe: typeof wrapper.subscribe }).subscribe = (sink, actor) => {\n\t\tbefore(sink);\n\t\treturn origSubscribe(sink, actor);\n\t};\n\treturn wrapper;\n}\n\n/**\n * Builds a timer-driven source: one-shot (first tick then `COMPLETE`) or periodic (`0`, `1`, `2`, …).\n *\n * @param ms - Milliseconds before the first emission.\n * @param opts - Producer options plus optional `period` for repeating ticks and optional `signal` (`AbortSignal`) to cancel with `ERROR`.\n * @returns `Node<number>` — tick counter from `0`; teardown clears timers.\n *\n * @example\n * ```ts\n * import { fromTimer } from \"@graphrefly/graphrefly-ts\";\n *\n * fromTimer(250, { period: 1_000 });\n * ```\n *\n * @category extra\n */\nexport function fromTimer(ms: number, opts?: AsyncSourceOpts & { period?: number }): Node<number> {\n\tconst { signal, period, ...rest } = opts ?? {};\n\treturn producer<number>((a) => {\n\t\tlet done = false;\n\t\tlet count = 0;\n\t\tlet t: ReturnType<typeof setTimeout> | undefined;\n\t\tlet iv: ReturnType<typeof setInterval> | undefined;\n\t\tconst cleanup = () => {\n\t\t\tdone = true;\n\t\t\tif (t !== undefined) clearTimeout(t);\n\t\t\tif (iv !== undefined) clearInterval(iv);\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t};\n\t\tconst finish = () => {\n\t\t\tif (done) return;\n\t\t\tif (period != null) {\n\t\t\t\ta.emit(count++);\n\t\t\t\tiv = setInterval(() => {\n\t\t\t\t\tif (done) return;\n\t\t\t\t\ta.emit(count++);\n\t\t\t\t}, period);\n\t\t\t} else {\n\t\t\t\t// One-shot: mark done, emit, complete synchronously.\n\t\t\t\t// a.emit() delivers DATA to downstream synchronously before\n\t\t\t\t// COMPLETE arrives — no queueMicrotask needed.\n\t\t\t\tdone = true;\n\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\ta.emit(count++);\n\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t}\n\t\t};\n\t\tconst onAbort = () => {\n\t\t\tif (done) return;\n\t\t\tcleanup();\n\t\t\ta.down([[ERROR, signal!.reason]]);\n\t\t};\n\t\tif (signal?.aborted) {\n\t\t\tonAbort();\n\t\t\treturn;\n\t\t}\n\t\tt = setTimeout(finish, ms);\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\treturn cleanup;\n\t}, sourceOpts(rest));\n}\n\n/**\n * Animation-frame-driven source. Emits on every `requestAnimationFrame` tick,\n * yielding the frame timestamp (DOMHighResTimeStamp, ms since navigation).\n *\n * Use instead of `fromTimer({ period: 16 })` when animation smoothness matters.\n * In a real browser, `requestAnimationFrame` synchronizes with the display\n * refresh. The source keeps ticking even when the tab is hidden — it\n * transparently switches to `setTimeout` while the tab is backgrounded (so\n * downstream state updates continue) and returns to `requestAnimationFrame`\n * when the tab regains focus.\n *\n * When `requestAnimationFrame` is unavailable (Node test environments, SSR),\n * this falls back to `setTimeout(~16ms)` unconditionally. Abortable via\n * `signal` (emits `ERROR`).\n *\n * @example\n * ```ts\n * import { fromRaf, derived } from \"@graphrefly/graphrefly-ts\";\n *\n * const frame = fromRaf();\n * const bouncingX = derived([frame], ([t]) => 50 + 40 * Math.sin((t as number) * 0.001));\n * ```\n *\n * @category extra\n */\nexport function fromRaf(opts?: AsyncSourceOpts): Node<number> {\n\tconst { signal, ...rest } = opts ?? {};\n\treturn producer<number>((a) => {\n\t\tlet done = false;\n\t\tlet rafId: number | undefined;\n\t\tlet fallbackTimer: ReturnType<typeof setTimeout> | undefined;\n\t\tlet abortListenerAdded = false;\n\t\tlet visibilityListenerAdded = false;\n\n\t\tconst raf: typeof requestAnimationFrame | undefined =\n\t\t\ttypeof requestAnimationFrame === \"function\" ? requestAnimationFrame : undefined;\n\t\tconst caf: typeof cancelAnimationFrame | undefined =\n\t\t\ttypeof cancelAnimationFrame === \"function\" ? cancelAnimationFrame : undefined;\n\t\tconst doc: Document | undefined = typeof document !== \"undefined\" ? document : undefined;\n\n\t\tconst clearPending = () => {\n\t\t\tif (rafId !== undefined && caf) caf(rafId);\n\t\t\tif (fallbackTimer !== undefined) clearTimeout(fallbackTimer);\n\t\t\trafId = undefined;\n\t\t\tfallbackTimer = undefined;\n\t\t};\n\t\tconst cleanup = () => {\n\t\t\tdone = true;\n\t\t\tclearPending();\n\t\t\tif (abortListenerAdded) {\n\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\tabortListenerAdded = false;\n\t\t\t}\n\t\t\tif (visibilityListenerAdded && doc) {\n\t\t\t\tdoc.removeEventListener(\"visibilitychange\", onVisibilityChange);\n\t\t\t\tvisibilityListenerAdded = false;\n\t\t\t}\n\t\t};\n\t\tconst onAbort = () => {\n\t\t\tif (done) return;\n\t\t\tcleanup();\n\t\t\ta.down([[ERROR, signal!.reason]]);\n\t\t};\n\t\tconst tick = (now: number) => {\n\t\t\tif (done) return;\n\t\t\ta.emit(now);\n\t\t\tscheduleNext();\n\t\t};\n\t\tconst scheduleNext = () => {\n\t\t\tif (done) return;\n\t\t\t// Prefer rAF for display-synced ticks when the tab is visible; when\n\t\t\t// hidden, rAF is throttled to ~0 by the browser, so fall back to\n\t\t\t// setTimeout so downstream state continues updating.\n\t\t\tif (raf && (!doc || doc.visibilityState !== \"hidden\")) {\n\t\t\t\trafId = raf(tick);\n\t\t\t} else {\n\t\t\t\tfallbackTimer = setTimeout(() => tick(performance.now()), 16);\n\t\t\t}\n\t\t};\n\t\tconst onVisibilityChange = () => {\n\t\t\tif (done) return;\n\t\t\t// Cancel any pending schedule and re-schedule via the path now\n\t\t\t// appropriate for the current visibility state.\n\t\t\tclearPending();\n\t\t\tscheduleNext();\n\t\t};\n\n\t\tif (signal?.aborted) {\n\t\t\tonAbort();\n\t\t\treturn cleanup;\n\t\t}\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\tabortListenerAdded = signal !== undefined;\n\t\tif (doc && raf) {\n\t\t\tdoc.addEventListener(\"visibilitychange\", onVisibilityChange);\n\t\t\tvisibilityListenerAdded = true;\n\t\t}\n\t\tscheduleNext();\n\t\treturn cleanup;\n\t}, sourceOpts(rest));\n}\n\n/**\n * Polls on an interval; when the current minute matches a 5-field cron expression, emits once (see {@link parseCron}).\n *\n * @param expr - Cron string (`min hour dom month dow`).\n * @param opts - Producer options plus `tickMs` (default `60_000`) and `output` (`timestamp_ns` default, or `date` for `Date` values).\n * @returns `Node<number>` (nanosecond timestamp) or `Node<Date>` when `output: \"date\"`.\n *\n * @example\n * ```ts\n * import { fromCron } from \"@graphrefly/graphrefly-ts\";\n *\n * fromCron(\"0 9 * * 1\");\n * ```\n *\n * @category extra\n */\nexport function fromCron(expr: string, opts?: FromCronOptions & { output: \"date\" }): Node<Date>;\nexport function fromCron(expr: string, opts?: FromCronOptions): Node<number>;\nexport function fromCron(expr: string, opts?: FromCronOptions): Node<number | Date> {\n\tconst schedule: CronSchedule = parseCron(expr);\n\tconst { tickMs: tickOpt, output, ...rest } = opts ?? {};\n\tconst tickMs = tickOpt ?? 60_000;\n\tconst emitDate = output === \"date\";\n\treturn producer<number | Date>(\n\t\t(a) => {\n\t\t\tlet lastFiredKey = -1;\n\t\t\tconst check = () => {\n\t\t\t\tconst now = new Date();\n\t\t\t\tconst key =\n\t\t\t\t\tnow.getFullYear() * 100_000_000 +\n\t\t\t\t\t(now.getMonth() + 1) * 1_000_000 +\n\t\t\t\t\tnow.getDate() * 10_000 +\n\t\t\t\t\tnow.getHours() * 100 +\n\t\t\t\t\tnow.getMinutes();\n\t\t\t\tif (key !== lastFiredKey && matchesCron(schedule, now)) {\n\t\t\t\t\tlastFiredKey = key;\n\t\t\t\t\ta.emit(emitDate ? now : wallClockNs());\n\t\t\t\t}\n\t\t\t};\n\t\t\tcheck();\n\t\t\tconst id = setInterval(check, tickMs);\n\t\t\treturn () => clearInterval(id);\n\t\t},\n\t\t{ ...sourceOpts(rest), name: rest.name ?? `cron:${expr}` },\n\t);\n}\n\n/**\n * Wraps a DOM-style `addEventListener` target; each event becomes a `DATA` emission.\n *\n * @param target - Object with `addEventListener` / `removeEventListener`.\n * @param type - Event name (e.g. `\"click\"`).\n * @param opts - Producer options plus listener options (`capture`, `passive`, `once`).\n * @returns `Node<T>` — event payloads; teardown removes the listener.\n *\n * @example\n * ```ts\n * import { fromEvent } from \"@graphrefly/graphrefly-ts\";\n *\n * fromEvent(document.body, \"click\");\n * ```\n *\n * @category extra\n */\nexport function fromEvent<T = unknown>(\n\ttarget: EventTargetLike,\n\ttype: string,\n\topts?: ExtraOpts & { capture?: boolean; passive?: boolean; once?: boolean },\n): Node<T> {\n\tconst { capture, passive, once, ...rest } = opts ?? {};\n\treturn producer<T>((a) => {\n\t\tconst handler = (e: unknown) => {\n\t\t\ta.emit(e as T);\n\t\t};\n\t\tconst options = { capture, passive, once };\n\t\ttarget.addEventListener(type, handler, options);\n\t\treturn () => target.removeEventListener(type, handler, options);\n\t}, sourceOpts(rest));\n}\n\n/**\n * Drains a synchronous iterable; each item is `DATA`, then `COMPLETE`, or `ERROR` if iteration throws.\n *\n * @param iterable - Values to emit in order.\n * @param opts - Optional producer options.\n * @returns `Node<T>` — one emission per element.\n *\n * @example\n * ```ts\n * import { fromIter } from \"@graphrefly/graphrefly-ts\";\n *\n * fromIter([1, 2, 3]);\n * ```\n *\n * @category extra\n */\nexport function fromIter<T>(iterable: Iterable<T>, opts?: ExtraOpts): Node<T> {\n\treturn producer<T>((a) => {\n\t\tlet cancelled = false;\n\t\ttry {\n\t\t\tfor (const x of iterable) {\n\t\t\t\tif (cancelled) return;\n\t\t\t\ta.emit(x);\n\t\t\t}\n\t\t\tif (!cancelled) a.down([[COMPLETE]]);\n\t\t} catch (e) {\n\t\t\tif (!cancelled) a.down([[ERROR, e]]);\n\t\t}\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, sourceOpts(opts));\n}\n\nfunction isThenable(x: unknown): x is PromiseLike<unknown> {\n\treturn x != null && typeof (x as PromiseLike<unknown>).then === \"function\";\n}\n\n/**\n * Lifts a Promise (or thenable) to a single-value stream: one `DATA` then `COMPLETE`, or `ERROR` on rejection.\n *\n * @param p - Promise to await.\n * @param opts - Producer options plus optional `signal` for abort → `ERROR` with reason.\n * @returns `Node<T>` — settles once.\n *\n * @example\n * ```ts\n * import { fromPromise } from \"@graphrefly/graphrefly-ts\";\n *\n * fromPromise(Promise.resolve(42));\n * ```\n *\n * @category extra\n */\nexport function fromPromise<T>(p: Promise<T> | PromiseLike<T>, opts?: AsyncSourceOpts): Node<T> {\n\tconst { signal, ...rest } = opts ?? {};\n\treturn producer<T>((a) => {\n\t\tlet settled = false;\n\t\tconst onAbort = () => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\ta.down([[ERROR, signal!.reason]]);\n\t\t};\n\t\tif (signal?.aborted) {\n\t\t\tonAbort();\n\t\t\treturn;\n\t\t}\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\tvoid Promise.resolve(p).then(\n\t\t\t(v) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\ta.emit(v as T);\n\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t},\n\t\t\t(e) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\ta.down([[ERROR, e]]);\n\t\t\t},\n\t\t);\n\t\treturn () => {\n\t\t\tsettled = true;\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t};\n\t}, sourceOpts(rest));\n}\n\n/**\n * Reads an async iterable; each `next()` value becomes `DATA`; `COMPLETE` when done; `ERROR` on failure.\n *\n * @param iterable - Async source (`for await` shape).\n * @param opts - Producer options plus optional `signal` to abort the pump.\n * @returns `Node<T>` — async pull stream.\n *\n * @example\n * ```ts\n * import { fromAsyncIter } from \"@graphrefly/graphrefly-ts\";\n *\n * async function* gen() {\n * yield 1;\n * }\n * fromAsyncIter(gen());\n * ```\n *\n * @category extra\n */\nexport function fromAsyncIter<T>(iterable: AsyncIterable<T>, opts?: AsyncSourceOpts): Node<T> {\n\tconst { signal: outerSignal, ...rest } = opts ?? {};\n\treturn producer<T>((a) => {\n\t\tconst ac = new AbortController();\n\t\tconst onOuterAbort = () => ac.abort(outerSignal?.reason);\n\t\tif (outerSignal?.aborted) {\n\t\t\tac.abort(outerSignal.reason);\n\t\t} else {\n\t\t\touterSignal?.addEventListener(\"abort\", onOuterAbort, { once: true });\n\t\t}\n\t\tconst signal = outerSignal ?? ac.signal;\n\t\tlet cancelled = false;\n\t\tconst it = iterable[Symbol.asyncIterator]();\n\t\t// Each pump() call chains directly into the next via Promise.then —\n\t\t// no queueMicrotask needed; Promise resolution already yields to the\n\t\t// microtask queue. COMPLETE is delivered synchronously after the last\n\t\t// value, same as fromIter semantics.\n\t\tconst pump = (): void => {\n\t\t\tif (cancelled || signal.aborted) return;\n\t\t\tvoid Promise.resolve(it.next()).then(\n\t\t\t\t(step) => {\n\t\t\t\t\tif (cancelled || signal.aborted) return;\n\t\t\t\t\tif (step.done) {\n\t\t\t\t\t\ta.down([[COMPLETE]]);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\ta.emit(step.value as T);\n\t\t\t\t\tpump();\n\t\t\t\t},\n\t\t\t\t(e) => {\n\t\t\t\t\tif (!cancelled && !signal.aborted) a.down([[ERROR, e]]);\n\t\t\t\t},\n\t\t\t);\n\t\t};\n\t\tpump();\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t\touterSignal?.removeEventListener(\"abort\", onOuterAbort);\n\t\t\tac.abort();\n\t\t\tvoid Promise.resolve(it.return?.()).catch(() => undefined);\n\t\t};\n\t}, sourceOpts(rest));\n}\n\nfunction isNode(x: unknown): x is Node {\n\treturn (\n\t\tx != null &&\n\t\ttypeof x === \"object\" &&\n\t\t\"cache\" in x &&\n\t\ttypeof (x as Node).subscribe === \"function\"\n\t);\n}\n\n/**\n * Coerces a value to a `Node` by shape: existing `Node` passthrough, thenable → {@link fromPromise},\n * async iterable → {@link fromAsyncIter}, sync iterable → {@link fromIter}, else scalar → {@link of}.\n *\n * @param input - Any value to wrap.\n * @param opts - Passed through when a Promise/async path is chosen.\n * @returns `Node` of the inferred element type.\n *\n * @example\n * ```ts\n * import { fromAny, state } from \"@graphrefly/graphrefly-ts\";\n *\n * fromAny(state(1));\n * fromAny(Promise.resolve(2));\n * ```\n *\n * @category extra\n */\nexport function fromAny<T>(input: NodeInput<T>, opts?: AsyncSourceOpts): Node<T> {\n\tif (isNode(input)) {\n\t\treturn input as Node<T>;\n\t}\n\tif (isThenable(input)) {\n\t\treturn fromPromise(input as PromiseLike<T>, opts);\n\t}\n\tif (input !== null && input !== undefined) {\n\t\tconst candidate = input as { [Symbol.asyncIterator]?: unknown; [Symbol.iterator]?: unknown };\n\t\tif (typeof candidate[Symbol.asyncIterator] === \"function\") {\n\t\t\treturn fromAsyncIter(input as AsyncIterable<T>, opts);\n\t\t}\n\t\tif (typeof candidate[Symbol.iterator] === \"function\") {\n\t\t\treturn fromIter(input as Iterable<T>, opts);\n\t\t}\n\t}\n\t// scalar fallback\n\treturn of(input as T);\n}\n\n/**\n * Emits each argument as `DATA` in order, then `COMPLETE` (implemented via {@link fromIter}).\n *\n * @param values - Values to emit.\n * @returns `Node<T>` — finite sequence.\n *\n * @example\n * ```ts\n * import { of } from \"@graphrefly/graphrefly-ts\";\n *\n * of(1, 2, 3);\n * ```\n *\n * @category extra\n */\nexport function of<T>(...values: T[]): Node<T> {\n\treturn fromIter(values, undefined);\n}\n\n/**\n * Completes immediately with no `DATA` (cold `EMPTY` analogue).\n *\n * @param opts - Optional producer options.\n * @returns `Node<T>` — terminal `COMPLETE` only.\n *\n * @example\n * ```ts\n * import { empty } from \"@graphrefly/graphrefly-ts\";\n *\n * empty();\n * ```\n *\n * @category extra\n */\nexport function empty<T = never>(opts?: ExtraOpts): Node<T> {\n\treturn producer<T>((a) => {\n\t\ta.down([[COMPLETE]]);\n\t\treturn undefined;\n\t}, sourceOpts(opts));\n}\n\n/**\n * Never emits and never completes until teardown (cold `NEVER` analogue).\n *\n * @param opts - Optional producer options.\n * @returns `Node<T>` — silent until unsubscribed.\n *\n * @example\n * ```ts\n * import { never } from \"@graphrefly/graphrefly-ts\";\n *\n * never();\n * ```\n *\n * @category extra\n */\nexport function never<T = never>(opts?: ExtraOpts): Node<T> {\n\treturn producer<T>(() => undefined, sourceOpts(opts));\n}\n\n/**\n * Emits `ERROR` as soon as the producer starts (cold error source).\n *\n * @param err - Error payload forwarded as `ERROR` data.\n * @param opts - Optional producer options.\n * @returns `Node<never>` — terminates with `ERROR`.\n *\n * @example\n * ```ts\n * import { throwError } from \"@graphrefly/graphrefly-ts\";\n *\n * throwError(new Error(\"fail\"));\n * ```\n *\n * @category extra\n */\nexport function throwError(err: unknown, opts?: ExtraOpts): Node<never> {\n\treturn producer<never>((a) => {\n\t\ta.down([[ERROR, err]]);\n\t\treturn undefined;\n\t}, sourceOpts(opts));\n}\n\n/**\n * Subscribes immediately and runs `fn` for each upstream `DATA`; returns unsubscribe.\n *\n * @param source - Upstream node.\n * @param fn - Side effect per value.\n * @param opts - Effect node options.\n * @returns Unsubscribe function (idempotent).\n *\n * @example\n * ```ts\n * import { forEach, state } from \"@graphrefly/graphrefly-ts\";\n *\n * const u = forEach(state(1), (v) => console.log(v));\n * u();\n * ```\n *\n * @category extra\n */\nexport function forEach<T>(source: Node<T>, fn: (value: T) => void, opts?: ExtraOpts): () => void {\n\tconst inner = node(\n\t\t[source as Node],\n\t\t(data, _actions) => {\n\t\t\tconst batch0 = data[0];\n\t\t\tif (batch0 != null && batch0.length > 0) {\n\t\t\t\tfor (const v of batch0) fn(v as T);\n\t\t\t}\n\t\t},\n\t\t{ describeKind: \"effect\", ...opts } as NodeOptions,\n\t);\n\treturn inner.subscribe(() => {});\n}\n\n/**\n * Buffers every `DATA`; on upstream `COMPLETE` emits one `DATA` with the full array then `COMPLETE`.\n *\n * @param source - Upstream node.\n * @param opts - Optional node options (derived describe kind).\n * @returns `Node<T[]>` — single array emission before completion.\n *\n * @example\n * ```ts\n * import { of, toArray } from \"@graphrefly/graphrefly-ts\";\n *\n * toArray(of(1, 2, 3));\n * ```\n *\n * @category extra\n */\nexport function toArray<T>(source: Node<T>, opts?: ExtraOpts): Node<T[]> {\n\treturn node<T[]>(\n\t\t[source as Node],\n\t\t(data, actions, ctx) => {\n\t\t\tif (!ctx.store.buf) ctx.store.buf = [];\n\t\t\tconst buf = ctx.store.buf as T[];\n\t\t\t// Accumulate DATA first — must happen before the COMPLETE check so\n\t\t\t// that a same-wave DATA+COMPLETE batch (e.g. fromTimer one-shot,\n\t\t\t// fromIter last item) is included in the emitted array.\n\t\t\tconst batch0 = data[0];\n\t\t\tif (batch0 != null && batch0.length > 0) {\n\t\t\t\tfor (const v of batch0) buf.push(v as T);\n\t\t\t}\n\t\t\t// COMPLETE: emit accumulated array then complete.\n\t\t\t// ERROR: autoError propagates; do NOT emit the partial buffer.\n\t\t\tif (ctx.terminalDeps[0] === true) {\n\t\t\t\tactions.emit([...buf]);\n\t\t\t\tactions.down([[COMPLETE]]);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// RESOLVED wave: propagate RESOLVED. Covers first-wave case; after first\n\t\t\t// call the pre-fn skip handles this automatically.\n\t\t\tif (batch0 == null || batch0.length === 0) {\n\t\t\t\tactions.down([[RESOLVED]]);\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tdescribeKind: \"derived\",\n\t\t\tcompleteWhenDepsComplete: false,\n\t\t\t...opts,\n\t\t} as NodeOptions<T[]>,\n\t);\n}\n\n/**\n * Multicasts upstream: one subscription to `source` while this wrapper has subscribers (via {@link producer}).\n *\n * @param source - Upstream node to share.\n * @param opts - Producer options; `initial` seeds from `source.cache` when set by factory.\n * @returns `Node<T>` — hot ref-counted bridge.\n *\n * @example\n * ```ts\n * import { share, state } from \"@graphrefly/graphrefly-ts\";\n *\n * share(state(0));\n * ```\n *\n * @category extra\n */\nexport function share<T>(source: Node<T>, opts?: ExtraOpts): Node<T> {\n\treturn producer<T>(\n\t\t(a) =>\n\t\t\tsource.subscribe((msgs) => {\n\t\t\t\ta.down(msgs);\n\t\t\t}),\n\t\t{ ...sourceOpts<T>(opts), initial: source.cache },\n\t);\n}\n\n/**\n * Like {@link share} with a bounded replay buffer: new subscribers receive the last `bufferSize`\n * `DATA` payloads (as separate batches) before live updates.\n *\n * @param source - Upstream node.\n * @param bufferSize - Maximum past values to replay (≥ 1).\n * @param opts - Producer options.\n * @returns `Node<T>` — multicast with replay on subscribe.\n *\n * @example\n * ```ts\n * import { replay, state } from \"@graphrefly/graphrefly-ts\";\n *\n * replay(state(0), 3);\n * ```\n *\n * @category extra\n */\nexport function replay<T>(source: Node<T>, bufferSize: number, opts?: ExtraOpts): Node<T> {\n\tif (bufferSize < 1) throw new RangeError(\"replay expects bufferSize >= 1\");\n\tconst buf: T[] = [];\n\tconst inner = producer<T>(\n\t\t(a) =>\n\t\t\tsource.subscribe((msgs) => {\n\t\t\t\tfor (const m of msgs) {\n\t\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\t\tbuf.push(m[1] as T);\n\t\t\t\t\t\tif (buf.length > bufferSize) buf.shift();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ta.down(msgs);\n\t\t\t}),\n\t\t{ ...sourceOpts<T>(opts), initial: source.cache },\n\t);\n\treturn wrapSubscribeHook(inner, (sink) => {\n\t\tfor (const v of buf) {\n\t\t\tsink([[DATA, v]]);\n\t\t}\n\t});\n}\n\n/**\n * {@link replay} with `bufferSize === 1` — replays the latest `DATA` to new subscribers.\n *\n * @param source - Upstream node.\n * @param opts - Producer options.\n * @returns `Node<T>` — share + last-value replay.\n *\n * @example\n * ```ts\n * import { cached, state } from \"@graphrefly/graphrefly-ts\";\n *\n * cached(state(0));\n * ```\n *\n * @category extra\n */\nexport function cached<T>(source: Node<T>, opts?: ExtraOpts): Node<T> {\n\treturn replay(source, 1, opts);\n}\n\n/**\n * Converts the first `DATA` on `source` into a Promise; rejects on `ERROR` or `COMPLETE` without data.\n *\n * **Important:** This subscribes and waits for a **future** emission. Data that\n * has already flowed is gone and will not be seen. Call this *before* the upstream\n * emits, or use `source.cache` / `source.status` for already-cached state.\n * See COMPOSITION-GUIDE §2 (subscription ordering).\n *\n * @param source - Node to read once.\n * @returns Promise of the first value.\n *\n * @example\n * ```ts\n * import { firstValueFrom, of } from \"@graphrefly/graphrefly-ts\";\n *\n * await firstValueFrom(of(42));\n * ```\n *\n * @category extra\n */\nexport function firstValueFrom<T>(source: Node<T>): Promise<T> {\n\treturn new Promise<T>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet shouldUnsub = false;\n\t\tlet unsub: (() => void) | undefined;\n\t\tunsub = source.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (settled) return;\n\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tresolve(m[1] as T);\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (m[0] === ERROR) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\treject(m[1]);\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\treject(new Error(\"completed without DATA\"));\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tif (shouldUnsub) {\n\t\t\tunsub?.();\n\t\t\tunsub = undefined;\n\t\t}\n\t});\n}\n\n/**\n * Wait for the first DATA value from `source` that satisfies `predicate`.\n *\n * Subscribes directly and resolves on the first DATA value where\n * `predicate` returns true. Reactive, no polling. Use in tests and\n * bridging code where you need a single matching value as a Promise.\n *\n * **Important:** This only captures **future** emissions — data that has\n * already flowed through the node is gone. Call this *before* the upstream\n * emits. For already-cached values, use `source.cache` / `source.status`.\n * See COMPOSITION-GUIDE §2 (subscription ordering).\n *\n * ```ts\n * const val = await firstWhere(strategy.node, snap => snap.size > 0);\n * ```\n *\n * @category extra\n */\nexport function firstWhere<T>(source: Node<T>, predicate: (value: T) => boolean): Promise<T> {\n\treturn new Promise<T>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet shouldUnsub = false;\n\t\tlet unsub: (() => void) | undefined;\n\t\tunsub = source.subscribe((msgs) => {\n\t\t\tfor (const m of msgs) {\n\t\t\t\tif (settled) return;\n\t\t\t\tif (m[0] === DATA) {\n\t\t\t\t\tconst v = m[1] as T;\n\t\t\t\t\tif (predicate(v)) {\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tresolve(v);\n\t\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\t\tunsub();\n\t\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (m[0] === ERROR) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\treject(m[1]);\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (m[0] === COMPLETE) {\n\t\t\t\t\tsettled = true;\n\t\t\t\t\treject(new Error(\"completed without matching value\"));\n\t\t\t\t\tif (unsub) {\n\t\t\t\t\t\tunsub();\n\t\t\t\t\t\tunsub = undefined;\n\t\t\t\t\t} else shouldUnsub = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tif (shouldUnsub) {\n\t\t\tunsub?.();\n\t\t\tunsub = undefined;\n\t\t}\n\t});\n}\n\n// ——————————————————————————————————————————————————————————————\n// RxJS-compatible aliases\n// ——————————————————————————————————————————————————————————————\n\n/**\n * RxJS-named alias for {@link replay} — multicast with a replay buffer of size `bufferSize`.\n *\n * @param source - Upstream node.\n * @param bufferSize - Replay depth (≥ 1).\n * @param opts - Producer options.\n * @returns Same behavior as `replay`.\n *\n * @example\n * ```ts\n * import { shareReplay, state } from \"@graphrefly/graphrefly-ts\";\n *\n * shareReplay(state(0), 5);\n * ```\n *\n * @category extra\n */\nexport const shareReplay = replay;\n\n// ---------------------------------------------------------------------------\n// keepalive\n// ---------------------------------------------------------------------------\n\n/**\n * Activate a compute node's upstream wiring without a real sink.\n *\n * Derived/effect nodes are lazy — they don't compute until at least one\n * subscriber exists (COMPOSITION-GUIDE §5). `keepalive` subscribes with an\n * empty sink so the node stays wired for `.cache` and upstream propagation.\n *\n * Returns the unsubscribe handle. Common usage:\n * `graph.addDisposer(keepalive(node))`.\n *\n * @category extra\n */\nexport function keepalive(n: Node<unknown>): () => void {\n\treturn n.subscribe(() => {});\n}\n\n// ---------------------------------------------------------------------------\n// reactiveCounter\n// ---------------------------------------------------------------------------\n\n/** Bundle returned by {@link reactiveCounter}. */\nexport type ReactiveCounterBundle = {\n\t/** Reactive node holding the current count. */\n\treadonly node: Node<number>;\n\t/** Increment by 1. Returns `false` if cap would be exceeded. */\n\tincrement(): boolean;\n\t/** Current count (synchronous read). */\n\tget(): number;\n\t/** Whether the counter has reached its cap. */\n\tatCap(): boolean;\n};\n\n/**\n * Reactive counter with a cap — the building block for circuit breakers.\n *\n * Wraps a `state(0)` node with `increment()` that respects a maximum.\n * The `node` is subscribable and composable like any reactive node. When\n * the cap is reached, `increment()` returns `false`.\n *\n * ```ts\n * const retries = reactiveCounter(10);\n * retries.increment(); // true — count is now 1\n * retries.node.subscribe(...); // reactive updates\n * retries.atCap(); // false\n * ```\n *\n * @param cap - Maximum value (inclusive). 0 = no increments allowed.\n * @category extra\n */\nexport function reactiveCounter(cap: number): ReactiveCounterBundle {\n\tconst counter = state(0);\n\treturn {\n\t\tnode: counter,\n\t\tincrement() {\n\t\t\tconst current = counter.cache ?? 0;\n\t\t\tif (current >= cap) return false;\n\t\t\tcounter.down([[DIRTY], [DATA, current + 1]]);\n\t\t\treturn true;\n\t\t},\n\t\tget() {\n\t\t\treturn counter.cache ?? 0;\n\t\t},\n\t\tatCap() {\n\t\t\treturn (counter.cache ?? 0) >= cap;\n\t\t},\n\t};\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import {
|
|
2
|
+
analyzeAndMeasure,
|
|
3
|
+
computeLineBreaks
|
|
4
|
+
} from "./chunk-LCE3GF5P.js";
|
|
5
|
+
import {
|
|
6
|
+
Graph
|
|
7
|
+
} from "./chunk-THTWHNU4.js";
|
|
8
|
+
import {
|
|
9
|
+
describeNode,
|
|
10
|
+
resolveDescribeFields
|
|
11
|
+
} from "./chunk-VYPWMZ6H.js";
|
|
12
|
+
import {
|
|
13
|
+
batch,
|
|
14
|
+
derived,
|
|
15
|
+
effect,
|
|
16
|
+
state
|
|
17
|
+
} from "./chunk-PHOUUNK7.js";
|
|
18
|
+
import {
|
|
19
|
+
__export
|
|
20
|
+
} from "./chunk-SX52TAR4.js";
|
|
21
|
+
|
|
22
|
+
// src/patterns/demo-shell.ts
|
|
23
|
+
var demo_shell_exports = {};
|
|
24
|
+
__export(demo_shell_exports, {
|
|
25
|
+
demoShell: () => demoShell
|
|
26
|
+
});
|
|
27
|
+
function clamp01(v) {
|
|
28
|
+
return Math.max(0, Math.min(1, v));
|
|
29
|
+
}
|
|
30
|
+
function demoShell(opts) {
|
|
31
|
+
const mainRatioInit = clamp01(opts?.mainRatio ?? 0.65);
|
|
32
|
+
const sideSplitInit = clamp01(opts?.sideSplit ?? 0.5);
|
|
33
|
+
const viewportInit = Math.max(0, opts?.viewportWidth ?? 1280);
|
|
34
|
+
const registry = opts?.nodeRegistry ?? /* @__PURE__ */ new Map();
|
|
35
|
+
const adapter = opts?.adapter ?? null;
|
|
36
|
+
const layoutFont = opts?.layoutFont ?? "14px monospace";
|
|
37
|
+
const onHighlight = opts?.onHighlight;
|
|
38
|
+
const g = new Graph("demo-shell");
|
|
39
|
+
const paneMainRatio = state(mainRatioInit, { name: "pane/main-ratio" });
|
|
40
|
+
const paneSideSplit = state(sideSplitInit, { name: "pane/side-split" });
|
|
41
|
+
const paneFullscreen = state(null, {
|
|
42
|
+
name: "pane/fullscreen"
|
|
43
|
+
});
|
|
44
|
+
const viewportWidth = state(viewportInit, { name: "viewport/width" });
|
|
45
|
+
g.add("pane/main-ratio", paneMainRatio);
|
|
46
|
+
g.add("pane/side-split", paneSideSplit);
|
|
47
|
+
g.add("pane/fullscreen", paneFullscreen);
|
|
48
|
+
g.add("viewport/width", viewportWidth);
|
|
49
|
+
const paneMainWidth = derived(
|
|
50
|
+
[paneMainRatio, viewportWidth, paneFullscreen],
|
|
51
|
+
([ratio, vw, fs]) => {
|
|
52
|
+
const r = ratio;
|
|
53
|
+
const w = vw;
|
|
54
|
+
const fullscreen = fs;
|
|
55
|
+
if (fullscreen === "main") return w;
|
|
56
|
+
if (fullscreen === "graph" || fullscreen === "code") return 0;
|
|
57
|
+
return Math.round(w * r);
|
|
58
|
+
},
|
|
59
|
+
{ name: "pane/main-width" }
|
|
60
|
+
);
|
|
61
|
+
const paneSideWidth = derived(
|
|
62
|
+
[paneMainWidth, viewportWidth, paneFullscreen],
|
|
63
|
+
([main, vw, fs]) => {
|
|
64
|
+
const fullscreen = fs;
|
|
65
|
+
const w = vw;
|
|
66
|
+
if (fullscreen === "main") return 0;
|
|
67
|
+
if (fullscreen === "graph" || fullscreen === "code") return w;
|
|
68
|
+
return w - main;
|
|
69
|
+
},
|
|
70
|
+
{ name: "pane/side-width" }
|
|
71
|
+
);
|
|
72
|
+
const paneGraphHeight = derived(
|
|
73
|
+
[paneSideSplit, paneFullscreen],
|
|
74
|
+
([split, fs]) => {
|
|
75
|
+
const fullscreen = fs;
|
|
76
|
+
if (fullscreen === "graph") return 1;
|
|
77
|
+
if (fullscreen === "code") return 0;
|
|
78
|
+
if (fullscreen === "main") return 0;
|
|
79
|
+
return clamp01(split);
|
|
80
|
+
},
|
|
81
|
+
{ name: "pane/graph-height-ratio" }
|
|
82
|
+
);
|
|
83
|
+
const paneCodeHeight = derived(
|
|
84
|
+
[paneGraphHeight, paneFullscreen],
|
|
85
|
+
([graphH, fs]) => {
|
|
86
|
+
const fullscreen = fs;
|
|
87
|
+
if (fullscreen === "code") return 1;
|
|
88
|
+
if (fullscreen === "graph" || fullscreen === "main") return 0;
|
|
89
|
+
return 1 - graphH;
|
|
90
|
+
},
|
|
91
|
+
{ name: "pane/code-height-ratio" }
|
|
92
|
+
);
|
|
93
|
+
g.add("pane/main-width", paneMainWidth);
|
|
94
|
+
g.add("pane/side-width", paneSideWidth);
|
|
95
|
+
g.add("pane/graph-height-ratio", paneGraphHeight);
|
|
96
|
+
g.add("pane/code-height-ratio", paneCodeHeight);
|
|
97
|
+
const demoGraphRef = state(null, {
|
|
98
|
+
name: "demo/graph-ref"
|
|
99
|
+
});
|
|
100
|
+
const demoGraphTick = state(0, { name: "demo/graph-tick" });
|
|
101
|
+
g.add("demo/graph-ref", demoGraphRef);
|
|
102
|
+
g.add("demo/graph-tick", demoGraphTick);
|
|
103
|
+
const graphMermaid = derived(
|
|
104
|
+
[demoGraphRef, demoGraphTick],
|
|
105
|
+
([ref, _tick]) => {
|
|
106
|
+
const demo = ref;
|
|
107
|
+
if (!demo) return "";
|
|
108
|
+
return demo.describe({ format: "mermaid" });
|
|
109
|
+
},
|
|
110
|
+
{ name: "graph/mermaid" }
|
|
111
|
+
);
|
|
112
|
+
const graphDescribe = derived(
|
|
113
|
+
[demoGraphRef, demoGraphTick],
|
|
114
|
+
([ref, _tick]) => {
|
|
115
|
+
const demo = ref;
|
|
116
|
+
if (!demo) return null;
|
|
117
|
+
const { expand: _, ...snapshot } = demo.describe({ detail: "standard" });
|
|
118
|
+
return snapshot;
|
|
119
|
+
},
|
|
120
|
+
{ name: "graph/describe" }
|
|
121
|
+
);
|
|
122
|
+
g.add("graph/mermaid", graphMermaid);
|
|
123
|
+
g.add("graph/describe", graphDescribe);
|
|
124
|
+
const hoverTarget = state(null, { name: "hover/target" });
|
|
125
|
+
g.add("hover/target", hoverTarget);
|
|
126
|
+
const highlightCodeScroll = derived(
|
|
127
|
+
[hoverTarget],
|
|
128
|
+
([target]) => {
|
|
129
|
+
const t = target;
|
|
130
|
+
if (!t) return null;
|
|
131
|
+
const entry = registry.get(t.id);
|
|
132
|
+
return entry ? entry.codeLine : null;
|
|
133
|
+
},
|
|
134
|
+
{ name: "highlight/code-scroll" }
|
|
135
|
+
);
|
|
136
|
+
const highlightVisual = derived(
|
|
137
|
+
[hoverTarget],
|
|
138
|
+
([target]) => {
|
|
139
|
+
const t = target;
|
|
140
|
+
if (!t) return null;
|
|
141
|
+
const entry = registry.get(t.id);
|
|
142
|
+
return entry ? entry.visualSelector : null;
|
|
143
|
+
},
|
|
144
|
+
{ name: "highlight/visual" }
|
|
145
|
+
);
|
|
146
|
+
const highlightGraph = derived(
|
|
147
|
+
[hoverTarget],
|
|
148
|
+
([target]) => {
|
|
149
|
+
const t = target;
|
|
150
|
+
if (!t) return null;
|
|
151
|
+
return t.id;
|
|
152
|
+
},
|
|
153
|
+
{ name: "highlight/graph" }
|
|
154
|
+
);
|
|
155
|
+
g.add("highlight/code-scroll", highlightCodeScroll);
|
|
156
|
+
g.add("highlight/visual", highlightVisual);
|
|
157
|
+
g.add("highlight/graph", highlightGraph);
|
|
158
|
+
if (onHighlight?.codeScroll) {
|
|
159
|
+
const cb = onHighlight.codeScroll;
|
|
160
|
+
const applyCodeScroll = effect([highlightCodeScroll], ([line]) => {
|
|
161
|
+
cb(line);
|
|
162
|
+
});
|
|
163
|
+
g.add("highlight/apply-code-scroll", applyCodeScroll);
|
|
164
|
+
}
|
|
165
|
+
if (onHighlight?.visual) {
|
|
166
|
+
const cb = onHighlight.visual;
|
|
167
|
+
const applyVisual = effect([highlightVisual], ([selector]) => {
|
|
168
|
+
cb(selector);
|
|
169
|
+
});
|
|
170
|
+
g.add("highlight/apply-visual", applyVisual);
|
|
171
|
+
}
|
|
172
|
+
if (onHighlight?.graph) {
|
|
173
|
+
const cb = onHighlight.graph;
|
|
174
|
+
const applyGraph = effect([highlightGraph], ([nodeId]) => {
|
|
175
|
+
cb(nodeId);
|
|
176
|
+
});
|
|
177
|
+
g.add("highlight/apply-graph", applyGraph);
|
|
178
|
+
}
|
|
179
|
+
const inspectSelected = state(null, {
|
|
180
|
+
name: "inspect/selected-node"
|
|
181
|
+
});
|
|
182
|
+
g.add("inspect/selected-node", inspectSelected);
|
|
183
|
+
const standardFields = resolveDescribeFields("standard");
|
|
184
|
+
const inspectNodeDetail = derived(
|
|
185
|
+
[inspectSelected, demoGraphRef, demoGraphTick],
|
|
186
|
+
([path, ref, _tick]) => {
|
|
187
|
+
const demo = ref;
|
|
188
|
+
const p = path;
|
|
189
|
+
if (!demo || !p) return null;
|
|
190
|
+
try {
|
|
191
|
+
const nd = demo.resolve(p);
|
|
192
|
+
const nodeDesc = describeNode(nd, standardFields);
|
|
193
|
+
return { path: p, ...nodeDesc, value: nd.cache };
|
|
194
|
+
} catch {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
{ name: "inspect/node-detail" }
|
|
199
|
+
);
|
|
200
|
+
const inspectTraceLog = derived(
|
|
201
|
+
[demoGraphRef, demoGraphTick],
|
|
202
|
+
([ref, _tick]) => {
|
|
203
|
+
const demo = ref;
|
|
204
|
+
if (!demo) return [];
|
|
205
|
+
return demo.trace();
|
|
206
|
+
},
|
|
207
|
+
{ name: "inspect/trace-log" }
|
|
208
|
+
);
|
|
209
|
+
g.add("inspect/node-detail", inspectNodeDetail);
|
|
210
|
+
g.add("inspect/trace-log", inspectTraceLog);
|
|
211
|
+
const metaDebug = state(false, { name: "meta/debug" });
|
|
212
|
+
g.add("meta/debug", metaDebug);
|
|
213
|
+
const metaShellMermaid = derived(
|
|
214
|
+
[metaDebug, demoGraphTick],
|
|
215
|
+
([debug, _tick]) => {
|
|
216
|
+
if (!debug) return "";
|
|
217
|
+
return g.describe({ format: "mermaid" });
|
|
218
|
+
},
|
|
219
|
+
{ name: "meta/shell-mermaid" }
|
|
220
|
+
);
|
|
221
|
+
g.add("meta/shell-mermaid", metaShellMermaid);
|
|
222
|
+
const codeTextNode = state("", { name: "layout/code-text" });
|
|
223
|
+
g.add("layout/code-text", codeTextNode);
|
|
224
|
+
if (adapter) {
|
|
225
|
+
const measureCache = /* @__PURE__ */ new Map();
|
|
226
|
+
const graphLabels = derived(
|
|
227
|
+
[graphDescribe],
|
|
228
|
+
([desc]) => {
|
|
229
|
+
const d = desc;
|
|
230
|
+
if (!d) return /* @__PURE__ */ new Map();
|
|
231
|
+
const result = /* @__PURE__ */ new Map();
|
|
232
|
+
for (const [name] of Object.entries(d.nodes)) {
|
|
233
|
+
const segments = analyzeAndMeasure(name, layoutFont, adapter, measureCache);
|
|
234
|
+
const lb = computeLineBreaks(segments, Infinity, adapter, layoutFont, measureCache);
|
|
235
|
+
const width = lb.lines.reduce((max, l) => Math.max(max, l.width), 0);
|
|
236
|
+
const height = lb.lineCount * 20;
|
|
237
|
+
result.set(name, { width, height });
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
name: "layout/graph-labels",
|
|
243
|
+
equals: (a, b) => {
|
|
244
|
+
if (a === b) return true;
|
|
245
|
+
const ma = a;
|
|
246
|
+
const mb = b;
|
|
247
|
+
if (ma.size !== mb.size) return false;
|
|
248
|
+
for (const [k, v] of ma) {
|
|
249
|
+
const bv = mb.get(k);
|
|
250
|
+
if (!bv || bv.width !== v.width || bv.height !== v.height) return false;
|
|
251
|
+
}
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
const codeLines = derived(
|
|
257
|
+
[codeTextNode, paneSideWidth],
|
|
258
|
+
([text, sideW]) => {
|
|
259
|
+
const t = text;
|
|
260
|
+
if (!t) return { lineCount: 0, lines: [] };
|
|
261
|
+
const segments = analyzeAndMeasure(t, layoutFont, adapter, measureCache);
|
|
262
|
+
const maxW = sideW - 40;
|
|
263
|
+
return computeLineBreaks(segments, Math.max(100, maxW), adapter, layoutFont, measureCache);
|
|
264
|
+
},
|
|
265
|
+
{ name: "layout/code-lines" }
|
|
266
|
+
);
|
|
267
|
+
const sideWidthHint = derived(
|
|
268
|
+
[graphLabels],
|
|
269
|
+
([labels]) => {
|
|
270
|
+
const m = labels;
|
|
271
|
+
if (m.size === 0) return 200;
|
|
272
|
+
let maxW = 0;
|
|
273
|
+
for (const { width } of m.values()) {
|
|
274
|
+
if (width > maxW) maxW = width;
|
|
275
|
+
}
|
|
276
|
+
return Math.max(200, Math.round(maxW + 80));
|
|
277
|
+
},
|
|
278
|
+
{ name: "layout/side-width-hint" }
|
|
279
|
+
);
|
|
280
|
+
g.add("layout/graph-labels", graphLabels);
|
|
281
|
+
g.add("layout/code-lines", codeLines);
|
|
282
|
+
g.add("layout/side-width-hint", sideWidthHint);
|
|
283
|
+
}
|
|
284
|
+
let tickCounter = 0;
|
|
285
|
+
return {
|
|
286
|
+
graph: g,
|
|
287
|
+
setMainRatio(ratio) {
|
|
288
|
+
g.set("pane/main-ratio", clamp01(ratio));
|
|
289
|
+
},
|
|
290
|
+
setSideSplit(ratio) {
|
|
291
|
+
g.set("pane/side-split", clamp01(ratio));
|
|
292
|
+
},
|
|
293
|
+
setFullscreen(pane) {
|
|
294
|
+
g.set("pane/fullscreen", pane);
|
|
295
|
+
},
|
|
296
|
+
setViewportWidth(width) {
|
|
297
|
+
g.set("viewport/width", Math.max(0, width));
|
|
298
|
+
},
|
|
299
|
+
setHoverTarget(target) {
|
|
300
|
+
g.set("hover/target", target);
|
|
301
|
+
},
|
|
302
|
+
setDemoGraph(demo) {
|
|
303
|
+
g.set("demo/graph-ref", demo);
|
|
304
|
+
},
|
|
305
|
+
bumpGraphTick() {
|
|
306
|
+
g.set("demo/graph-tick", ++tickCounter);
|
|
307
|
+
},
|
|
308
|
+
selectNode(path) {
|
|
309
|
+
g.set("inspect/selected-node", path);
|
|
310
|
+
},
|
|
311
|
+
setMetaDebug(on) {
|
|
312
|
+
g.set("meta/debug", on);
|
|
313
|
+
},
|
|
314
|
+
setCodeText(text) {
|
|
315
|
+
g.set("layout/code-text", text);
|
|
316
|
+
},
|
|
317
|
+
batch(fn) {
|
|
318
|
+
batch(fn);
|
|
319
|
+
},
|
|
320
|
+
destroy() {
|
|
321
|
+
g.destroy();
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export {
|
|
327
|
+
demoShell,
|
|
328
|
+
demo_shell_exports
|
|
329
|
+
};
|
|
330
|
+
//# sourceMappingURL=chunk-FQMKGR6L.js.map
|