a reactive (signals based) hypermedia web framework (wip)
stormlightlabs.github.io/volt/
hypermedia
frontend
signals
1/**
2 * Volt.js Debug Utilities
3 *
4 * Lazy-loadable debugging module for signal introspection and visualization.
5 * Import from 'voltx.js/debug' to access these utilities without affecting production bundle size.
6 *
7 * @example
8 * ```ts
9 * import { debugSignal, debugComputed, logAllSignals } from 'voltx.js/debug';
10 *
11 * const count = debugSignal(0, 'count');
12 * const doubled = debugComputed(() => count.get() * 2, 'doubled');
13 *
14 * logAllSignals();
15 * ```
16 *
17 * @module voltx.js/debug
18 * @packageDocumentation
19 */
20
21import type { ComputedSignal, Signal, SignalType } from "$types/volt";
22import {
23 buildDependencyGraph,
24 detectCircularDependencies,
25 getDependencies,
26 getDependents,
27 getSignalDepth,
28 recordDependencies,
29} from "./debug/graph";
30import {
31 disableGlobalTracing,
32 enableGlobalTracing,
33 logAllReactives,
34 logAllSignals,
35 logReactive,
36 logSignal,
37 logSignalTable,
38 trace,
39 watch,
40} from "./debug/logger";
41import {
42 clearRegistry,
43 getAllReactives,
44 getAllSignals,
45 getReactiveInfo,
46 getRegistryStats,
47 getSignalInfo,
48 nameReactive,
49 nameSignal,
50 registerReactive,
51 registerSignal,
52} from "./debug/registry";
53import { computed as coreComputed, reactive as coreReactive, signal as coreSignal } from "./index";
54
55/**
56 * Create a signal with automatic debug registration.
57 *
58 * @param initialValue - The initial value
59 * @param name - Optional name for debugging
60 * @returns A Signal with debug metadata
61 */
62export function debugSignal<T>(initialValue: T, name?: string): Signal<T> {
63 const sig = coreSignal(initialValue);
64 registerSignal(sig, "signal", name);
65 return sig;
66}
67
68/**
69 * Create a computed signal with automatic debug registration.
70 *
71 * @param compute - Computation function
72 * @param name - Optional name for debugging
73 * @returns A ComputedSignal with debug metadata
74 */
75export function debugComputed<T>(compute: () => T, name?: string): ComputedSignal<T> {
76 const comp = coreComputed(compute);
77 registerSignal(comp, "computed", name);
78 const deps = extractComputedDeps(comp);
79 if (deps.length > 0) {
80 recordDependencies(comp, deps);
81 }
82 return comp;
83}
84
85/**
86 * Create a reactive object with automatic debug registration.
87 *
88 * @param target - The object or array to make reactive
89 * @param name - Optional name for debugging
90 * @returns A reactive proxy with debug metadata
91 */
92export function debugReactive<T extends object>(target: T, name?: string): T {
93 const proxy = coreReactive(target);
94 registerReactive(proxy, name);
95 return proxy;
96}
97
98/**
99 * Extract dependencies from a computed signal by running it in a tracking context.
100 * This is a helper that uses the same tracking mechanism as the core.
101 */
102function extractComputedDeps(_comp: ComputedSignal<unknown>): Array<Signal<unknown> | ComputedSignal<unknown>> {
103 // The computed has already run and subscribed to its dependencies
104 // TODO: We need to access the internal dependency tracking
105 return [];
106}
107
108export function attachDebugger(sig: Signal<unknown> | ComputedSignal<unknown>, type: SignalType, name?: string): void {
109 registerSignal(sig, type, name);
110}
111
112export const vdebugger = {
113 signal: debugSignal,
114 computed: debugComputed,
115 reactive: debugReactive,
116 attach: attachDebugger,
117 getAllSignals,
118 getAllReactives,
119 getSignalInfo,
120 getReactiveInfo,
121 getStats: getRegistryStats,
122 nameSignal,
123 nameReactive,
124 getDependencies,
125 getDependents,
126 buildGraph: buildDependencyGraph,
127 detectCycles: detectCircularDependencies,
128 getDepth: getSignalDepth,
129 log: logSignal,
130 logReactive,
131 logAll: logAllSignals,
132 logAllReactives,
133 logTable: logSignalTable,
134 trace,
135 watch,
136 enableTracing: enableGlobalTracing,
137 disableTracing: disableGlobalTracing,
138 clear: clearRegistry,
139};
140
141export type { GraphNode, SignalMetadata, SignalType } from "$types/volt";
142export { hasDependency } from "./debug/graph";
143export {
144 buildDependencyGraph,
145 detectCircularDependencies,
146 getDependencies,
147 getDependents,
148 getSignalDepth,
149} from "./debug/graph";
150export {
151 disableGlobalTracing,
152 enableGlobalTracing,
153 logAllReactives,
154 logAllSignals,
155 logReactive,
156 logSignal,
157 logSignalTable,
158 trace,
159 watch,
160} from "./debug/logger";
161export {
162 clearRegistry,
163 getAllReactives,
164 getAllSignals,
165 getReactiveInfo,
166 getReactiveMetadata,
167 getRegistryStats,
168 getSignalInfo,
169 getSignalMetadata,
170 nameReactive,
171} from "./debug/registry";
172export { nameSignal } from "./debug/registry";