@zenithbuild/compiler 1.0.2
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/LICENSE +21 -0
- package/README.md +30 -0
- package/dist/build-analyzer.d.ts +44 -0
- package/dist/build-analyzer.js +87 -0
- package/dist/bundler.d.ts +31 -0
- package/dist/bundler.js +86 -0
- package/dist/core/components/index.d.ts +9 -0
- package/dist/core/components/index.js +13 -0
- package/dist/core/config/index.d.ts +11 -0
- package/dist/core/config/index.js +10 -0
- package/dist/core/config/loader.d.ts +17 -0
- package/dist/core/config/loader.js +60 -0
- package/dist/core/config/types.d.ts +98 -0
- package/dist/core/config/types.js +32 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.js +6 -0
- package/dist/core/lifecycle/index.d.ts +16 -0
- package/dist/core/lifecycle/index.js +19 -0
- package/dist/core/lifecycle/zen-mount.d.ts +66 -0
- package/dist/core/lifecycle/zen-mount.js +151 -0
- package/dist/core/lifecycle/zen-unmount.d.ts +54 -0
- package/dist/core/lifecycle/zen-unmount.js +76 -0
- package/dist/core/plugins/bridge.d.ts +116 -0
- package/dist/core/plugins/bridge.js +121 -0
- package/dist/core/plugins/index.d.ts +6 -0
- package/dist/core/plugins/index.js +6 -0
- package/dist/core/plugins/registry.d.ts +67 -0
- package/dist/core/plugins/registry.js +113 -0
- package/dist/core/reactivity/index.d.ts +30 -0
- package/dist/core/reactivity/index.js +33 -0
- package/dist/core/reactivity/tracking.d.ts +74 -0
- package/dist/core/reactivity/tracking.js +136 -0
- package/dist/core/reactivity/zen-batch.d.ts +45 -0
- package/dist/core/reactivity/zen-batch.js +54 -0
- package/dist/core/reactivity/zen-effect.d.ts +48 -0
- package/dist/core/reactivity/zen-effect.js +98 -0
- package/dist/core/reactivity/zen-memo.d.ts +43 -0
- package/dist/core/reactivity/zen-memo.js +100 -0
- package/dist/core/reactivity/zen-ref.d.ts +44 -0
- package/dist/core/reactivity/zen-ref.js +34 -0
- package/dist/core/reactivity/zen-signal.d.ts +48 -0
- package/dist/core/reactivity/zen-signal.js +84 -0
- package/dist/core/reactivity/zen-state.d.ts +35 -0
- package/dist/core/reactivity/zen-state.js +147 -0
- package/dist/core/reactivity/zen-untrack.d.ts +38 -0
- package/dist/core/reactivity/zen-untrack.js +41 -0
- package/dist/css/index.d.ts +73 -0
- package/dist/css/index.js +246 -0
- package/dist/discovery/componentDiscovery.d.ts +42 -0
- package/dist/discovery/componentDiscovery.js +56 -0
- package/dist/discovery/layouts.d.ts +13 -0
- package/dist/discovery/layouts.js +41 -0
- package/dist/errors/compilerError.d.ts +31 -0
- package/dist/errors/compilerError.js +51 -0
- package/dist/finalize/finalizeOutput.d.ts +32 -0
- package/dist/finalize/finalizeOutput.js +62 -0
- package/dist/finalize/generateFinalBundle.d.ts +24 -0
- package/dist/finalize/generateFinalBundle.js +68 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +51 -0
- package/dist/ir/types.d.ts +181 -0
- package/dist/ir/types.js +8 -0
- package/dist/output/types.d.ts +30 -0
- package/dist/output/types.js +6 -0
- package/dist/parse/detectMapExpressions.d.ts +45 -0
- package/dist/parse/detectMapExpressions.js +77 -0
- package/dist/parse/parseScript.d.ts +8 -0
- package/dist/parse/parseScript.js +36 -0
- package/dist/parse/parseTemplate.d.ts +11 -0
- package/dist/parse/parseTemplate.js +487 -0
- package/dist/parse/parseZenFile.d.ts +11 -0
- package/dist/parse/parseZenFile.js +50 -0
- package/dist/parse/scriptAnalysis.d.ts +25 -0
- package/dist/parse/scriptAnalysis.js +60 -0
- package/dist/parse/trackLoopContext.d.ts +20 -0
- package/dist/parse/trackLoopContext.js +62 -0
- package/dist/parseZenFile.d.ts +10 -0
- package/dist/parseZenFile.js +55 -0
- package/dist/runtime/analyzeAndEmit.d.ts +20 -0
- package/dist/runtime/analyzeAndEmit.js +70 -0
- package/dist/runtime/build.d.ts +6 -0
- package/dist/runtime/build.js +13 -0
- package/dist/runtime/bundle-generator.d.ts +27 -0
- package/dist/runtime/bundle-generator.js +1263 -0
- package/dist/runtime/client-runtime.d.ts +41 -0
- package/dist/runtime/client-runtime.js +397 -0
- package/dist/runtime/dataExposure.d.ts +52 -0
- package/dist/runtime/dataExposure.js +227 -0
- package/dist/runtime/generateDOM.d.ts +21 -0
- package/dist/runtime/generateDOM.js +194 -0
- package/dist/runtime/generateHydrationBundle.d.ts +15 -0
- package/dist/runtime/generateHydrationBundle.js +399 -0
- package/dist/runtime/hydration.d.ts +53 -0
- package/dist/runtime/hydration.js +271 -0
- package/dist/runtime/navigation.d.ts +58 -0
- package/dist/runtime/navigation.js +372 -0
- package/dist/runtime/serve.d.ts +13 -0
- package/dist/runtime/serve.js +76 -0
- package/dist/runtime/thinRuntime.d.ts +23 -0
- package/dist/runtime/thinRuntime.js +158 -0
- package/dist/runtime/transformIR.d.ts +19 -0
- package/dist/runtime/transformIR.js +285 -0
- package/dist/runtime/wrapExpression.d.ts +24 -0
- package/dist/runtime/wrapExpression.js +76 -0
- package/dist/runtime/wrapExpressionWithLoop.d.ts +17 -0
- package/dist/runtime/wrapExpressionWithLoop.js +75 -0
- package/dist/spa-build.d.ts +26 -0
- package/dist/spa-build.js +866 -0
- package/dist/ssg-build.d.ts +32 -0
- package/dist/ssg-build.js +408 -0
- package/dist/test/analyze-emit.test.d.ts +1 -0
- package/dist/test/analyze-emit.test.js +88 -0
- package/dist/test/bundler-contract.test.d.ts +1 -0
- package/dist/test/bundler-contract.test.js +137 -0
- package/dist/test/compiler-authority.test.d.ts +1 -0
- package/dist/test/compiler-authority.test.js +90 -0
- package/dist/test/component-instance-test.d.ts +1 -0
- package/dist/test/component-instance-test.js +115 -0
- package/dist/test/error-native-bridge.test.d.ts +1 -0
- package/dist/test/error-native-bridge.test.js +51 -0
- package/dist/test/error-serialization.test.d.ts +1 -0
- package/dist/test/error-serialization.test.js +38 -0
- package/dist/test/macro-inlining.test.d.ts +1 -0
- package/dist/test/macro-inlining.test.js +178 -0
- package/dist/test/validate-test.d.ts +6 -0
- package/dist/test/validate-test.js +95 -0
- package/dist/transform/classifyExpression.d.ts +46 -0
- package/dist/transform/classifyExpression.js +354 -0
- package/dist/transform/componentResolver.d.ts +15 -0
- package/dist/transform/componentResolver.js +30 -0
- package/dist/transform/expressionTransformer.d.ts +19 -0
- package/dist/transform/expressionTransformer.js +333 -0
- package/dist/transform/fragmentLowering.d.ts +25 -0
- package/dist/transform/fragmentLowering.js +468 -0
- package/dist/transform/layoutProcessor.d.ts +5 -0
- package/dist/transform/layoutProcessor.js +34 -0
- package/dist/transform/transformTemplate.d.ts +11 -0
- package/dist/transform/transformTemplate.js +33 -0
- package/dist/validate/invariants.d.ts +23 -0
- package/dist/validate/invariants.js +55 -0
- package/native/compiler-native/compiler-native.node +0 -0
- package/native/compiler-native/index.d.ts +113 -0
- package/native/compiler-native/index.js +19 -0
- package/native/compiler-native/package.json +19 -0
- package/package.json +49 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zenith Plugin Registry
|
|
3
|
+
*
|
|
4
|
+
* Manages plugin registration and initialization
|
|
5
|
+
*
|
|
6
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
7
|
+
* HOOK OWNERSHIP RULE (CANONICAL)
|
|
8
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
9
|
+
*
|
|
10
|
+
* The plugin registry is part of core infrastructure.
|
|
11
|
+
* It MUST remain plugin-agnostic:
|
|
12
|
+
* - No plugin-specific types
|
|
13
|
+
* - No plugin-specific logic
|
|
14
|
+
* - Generic data handling only
|
|
15
|
+
*
|
|
16
|
+
* Plugins own their data structures; core provides the storage mechanism.
|
|
17
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Global plugin data store
|
|
21
|
+
*
|
|
22
|
+
* Plugins store their data here using namespaced keys.
|
|
23
|
+
* Core does not interpret this data - it just stores and serves it.
|
|
24
|
+
*/
|
|
25
|
+
const pluginDataStore = {};
|
|
26
|
+
/**
|
|
27
|
+
* Get all plugin data (for runtime access)
|
|
28
|
+
*/
|
|
29
|
+
export function getPluginData() {
|
|
30
|
+
return { ...pluginDataStore };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get plugin data by namespace
|
|
34
|
+
*/
|
|
35
|
+
export function getPluginDataByNamespace(namespace) {
|
|
36
|
+
return pluginDataStore[namespace] || [];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Plugin registry for managing Zenith plugins
|
|
40
|
+
*/
|
|
41
|
+
export class PluginRegistry {
|
|
42
|
+
plugins = new Map();
|
|
43
|
+
/**
|
|
44
|
+
* Register a plugin
|
|
45
|
+
*/
|
|
46
|
+
register(plugin) {
|
|
47
|
+
if (this.plugins.has(plugin.name)) {
|
|
48
|
+
console.warn(`[Zenith] Plugin "${plugin.name}" is already registered. Overwriting.`);
|
|
49
|
+
}
|
|
50
|
+
this.plugins.set(plugin.name, plugin);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get a plugin by name
|
|
54
|
+
*/
|
|
55
|
+
get(name) {
|
|
56
|
+
return this.plugins.get(name);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Check if a plugin is registered
|
|
60
|
+
*/
|
|
61
|
+
has(name) {
|
|
62
|
+
return this.plugins.has(name);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get all registered plugins
|
|
66
|
+
*/
|
|
67
|
+
all() {
|
|
68
|
+
return Array.from(this.plugins.values());
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Initialize all plugins with the provided context
|
|
72
|
+
*/
|
|
73
|
+
async initAll(ctx) {
|
|
74
|
+
for (const plugin of this.plugins.values()) {
|
|
75
|
+
try {
|
|
76
|
+
await plugin.setup(ctx);
|
|
77
|
+
console.log(`[Zenith] Plugin "${plugin.name}" initialized`);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
81
|
+
console.error(`[Zenith] Failed to initialize plugin "${plugin.name}":`, message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Clear all registered plugins
|
|
87
|
+
*/
|
|
88
|
+
clear() {
|
|
89
|
+
this.plugins.clear();
|
|
90
|
+
// Also clear plugin data
|
|
91
|
+
for (const key of Object.keys(pluginDataStore)) {
|
|
92
|
+
delete pluginDataStore[key];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Create a plugin context for initialization
|
|
98
|
+
*
|
|
99
|
+
* Uses a generic data setter that stores data by namespace.
|
|
100
|
+
* Plugins define their own data structures internally.
|
|
101
|
+
*
|
|
102
|
+
* @param projectRoot - Absolute path to the project root
|
|
103
|
+
* @returns A PluginContext for plugin initialization
|
|
104
|
+
*/
|
|
105
|
+
export function createPluginContext(projectRoot) {
|
|
106
|
+
return {
|
|
107
|
+
projectRoot,
|
|
108
|
+
setPluginData: (namespace, data) => {
|
|
109
|
+
pluginDataStore[namespace] = data;
|
|
110
|
+
},
|
|
111
|
+
options: {}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zenith Reactivity System
|
|
3
|
+
*
|
|
4
|
+
* This module exports all reactive primitives for the Zenith framework.
|
|
5
|
+
*
|
|
6
|
+
* Exports both explicit `zen*` names (internal) and clean aliases (public DX).
|
|
7
|
+
*/
|
|
8
|
+
import { zenSignal as _zenSignal, type Signal } from './zen-signal';
|
|
9
|
+
import { zenState as _zenState } from './zen-state';
|
|
10
|
+
import { zenEffect as _zenEffect, type EffectFn, type DisposeFn } from './zen-effect';
|
|
11
|
+
import { zenMemo as _zenMemo, type Memo } from './zen-memo';
|
|
12
|
+
import { zenRef as _zenRef, type Ref } from './zen-ref';
|
|
13
|
+
import { zenBatch as _zenBatch } from './zen-batch';
|
|
14
|
+
import { zenUntrack as _zenUntrack } from './zen-untrack';
|
|
15
|
+
export declare const zenSignal: typeof _zenSignal;
|
|
16
|
+
export declare const zenState: typeof _zenState;
|
|
17
|
+
export declare const zenEffect: typeof _zenEffect;
|
|
18
|
+
export declare const zenMemo: typeof _zenMemo;
|
|
19
|
+
export declare const zenRef: typeof _zenRef;
|
|
20
|
+
export declare const zenBatch: typeof _zenBatch;
|
|
21
|
+
export declare const zenUntrack: typeof _zenUntrack;
|
|
22
|
+
export type { Signal, Memo, Ref, EffectFn, DisposeFn };
|
|
23
|
+
export { type Subscriber, type TrackingContext, trackDependency, notifySubscribers, getCurrentContext, pushContext, popContext, cleanupContext, runUntracked, startBatch, endBatch, isBatching } from './tracking';
|
|
24
|
+
export declare const signal: typeof _zenSignal;
|
|
25
|
+
export declare const state: typeof _zenState;
|
|
26
|
+
export declare const effect: typeof _zenEffect;
|
|
27
|
+
export declare const memo: typeof _zenMemo;
|
|
28
|
+
export declare const ref: typeof _zenRef;
|
|
29
|
+
export declare const batch: typeof _zenBatch;
|
|
30
|
+
export declare const untrack: typeof _zenUntrack;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zenith Reactivity System
|
|
3
|
+
*
|
|
4
|
+
* This module exports all reactive primitives for the Zenith framework.
|
|
5
|
+
*
|
|
6
|
+
* Exports both explicit `zen*` names (internal) and clean aliases (public DX).
|
|
7
|
+
*/
|
|
8
|
+
// Core primitives - explicit names
|
|
9
|
+
import { zenSignal as _zenSignal } from './zen-signal';
|
|
10
|
+
import { zenState as _zenState } from './zen-state';
|
|
11
|
+
import { zenEffect as _zenEffect } from './zen-effect';
|
|
12
|
+
import { zenMemo as _zenMemo } from './zen-memo';
|
|
13
|
+
import { zenRef as _zenRef } from './zen-ref';
|
|
14
|
+
import { zenBatch as _zenBatch } from './zen-batch';
|
|
15
|
+
import { zenUntrack as _zenUntrack } from './zen-untrack';
|
|
16
|
+
// Re-export with explicit names
|
|
17
|
+
export const zenSignal = _zenSignal;
|
|
18
|
+
export const zenState = _zenState;
|
|
19
|
+
export const zenEffect = _zenEffect;
|
|
20
|
+
export const zenMemo = _zenMemo;
|
|
21
|
+
export const zenRef = _zenRef;
|
|
22
|
+
export const zenBatch = _zenBatch;
|
|
23
|
+
export const zenUntrack = _zenUntrack;
|
|
24
|
+
// Internal tracking utilities (for advanced use)
|
|
25
|
+
export { trackDependency, notifySubscribers, getCurrentContext, pushContext, popContext, cleanupContext, runUntracked, startBatch, endBatch, isBatching } from './tracking';
|
|
26
|
+
// Public DX aliases - clean names
|
|
27
|
+
export const signal = _zenSignal;
|
|
28
|
+
export const state = _zenState;
|
|
29
|
+
export const effect = _zenEffect;
|
|
30
|
+
export const memo = _zenMemo;
|
|
31
|
+
export const ref = _zenRef;
|
|
32
|
+
export const batch = _zenBatch;
|
|
33
|
+
export const untrack = _zenUntrack;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zenith Reactivity Tracking System
|
|
3
|
+
*
|
|
4
|
+
* This module provides the core dependency tracking mechanism used by
|
|
5
|
+
* signals, effects, and memos. It uses a stack-based approach to track
|
|
6
|
+
* which reactive values are accessed during effect/memo execution.
|
|
7
|
+
*
|
|
8
|
+
* Key concepts:
|
|
9
|
+
* - Subscriber: A function that should be called when a dependency changes
|
|
10
|
+
* - Tracking context: The currently executing effect/memo that should collect dependencies
|
|
11
|
+
* - Dependency: A reactive value that an effect/memo depends on
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* A subscriber is a function that gets called when a reactive value changes
|
|
15
|
+
*/
|
|
16
|
+
export type Subscriber = () => void;
|
|
17
|
+
/**
|
|
18
|
+
* Tracking context - represents an effect or memo that is collecting dependencies
|
|
19
|
+
*/
|
|
20
|
+
export interface TrackingContext {
|
|
21
|
+
/** The function to call when dependencies change */
|
|
22
|
+
execute: Subscriber;
|
|
23
|
+
/** Set of dependency subscriber sets this context is registered with */
|
|
24
|
+
dependencies: Set<Set<Subscriber>>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get the current tracking context (if any)
|
|
28
|
+
*/
|
|
29
|
+
export declare function getCurrentContext(): TrackingContext | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Push a new tracking context onto the stack
|
|
32
|
+
*/
|
|
33
|
+
export declare function pushContext(context: TrackingContext): void;
|
|
34
|
+
/**
|
|
35
|
+
* Pop the current tracking context from the stack
|
|
36
|
+
*/
|
|
37
|
+
export declare function popContext(): TrackingContext | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Track a dependency - called when a reactive value is read
|
|
40
|
+
*
|
|
41
|
+
* @param subscribers - The subscriber set of the reactive value being read
|
|
42
|
+
*/
|
|
43
|
+
export declare function trackDependency(subscribers: Set<Subscriber>): void;
|
|
44
|
+
/**
|
|
45
|
+
* Notify subscribers that a reactive value has changed
|
|
46
|
+
*
|
|
47
|
+
* @param subscribers - The subscriber set to notify
|
|
48
|
+
*/
|
|
49
|
+
export declare function notifySubscribers(subscribers: Set<Subscriber>): void;
|
|
50
|
+
/**
|
|
51
|
+
* Clean up a tracking context - remove it from all dependency sets
|
|
52
|
+
*
|
|
53
|
+
* @param context - The context to clean up
|
|
54
|
+
*/
|
|
55
|
+
export declare function cleanupContext(context: TrackingContext): void;
|
|
56
|
+
/**
|
|
57
|
+
* Run a function without tracking dependencies
|
|
58
|
+
*
|
|
59
|
+
* @param fn - The function to run
|
|
60
|
+
* @returns The return value of the function
|
|
61
|
+
*/
|
|
62
|
+
export declare function runUntracked<T>(fn: () => T): T;
|
|
63
|
+
/**
|
|
64
|
+
* Start a batch - defer effect execution until batch ends
|
|
65
|
+
*/
|
|
66
|
+
export declare function startBatch(): void;
|
|
67
|
+
/**
|
|
68
|
+
* End a batch - run all pending effects
|
|
69
|
+
*/
|
|
70
|
+
export declare function endBatch(): void;
|
|
71
|
+
/**
|
|
72
|
+
* Check if currently inside a batch
|
|
73
|
+
*/
|
|
74
|
+
export declare function isBatching(): boolean;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zenith Reactivity Tracking System
|
|
3
|
+
*
|
|
4
|
+
* This module provides the core dependency tracking mechanism used by
|
|
5
|
+
* signals, effects, and memos. It uses a stack-based approach to track
|
|
6
|
+
* which reactive values are accessed during effect/memo execution.
|
|
7
|
+
*
|
|
8
|
+
* Key concepts:
|
|
9
|
+
* - Subscriber: A function that should be called when a dependency changes
|
|
10
|
+
* - Tracking context: The currently executing effect/memo that should collect dependencies
|
|
11
|
+
* - Dependency: A reactive value that an effect/memo depends on
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Stack of currently executing tracking contexts
|
|
15
|
+
* When an effect runs, it pushes itself onto this stack.
|
|
16
|
+
* When a signal is read, it registers the top of the stack as a subscriber.
|
|
17
|
+
*/
|
|
18
|
+
const trackingStack = [];
|
|
19
|
+
/**
|
|
20
|
+
* Flag to disable tracking (used by zenUntrack)
|
|
21
|
+
*/
|
|
22
|
+
let trackingDisabled = false;
|
|
23
|
+
/**
|
|
24
|
+
* Batch depth counter - when > 0, effect execution is deferred
|
|
25
|
+
*/
|
|
26
|
+
let batchDepth = 0;
|
|
27
|
+
/**
|
|
28
|
+
* Queue of effects to run after batch completes
|
|
29
|
+
*/
|
|
30
|
+
const pendingEffects = new Set();
|
|
31
|
+
/**
|
|
32
|
+
* Get the current tracking context (if any)
|
|
33
|
+
*/
|
|
34
|
+
export function getCurrentContext() {
|
|
35
|
+
if (trackingDisabled)
|
|
36
|
+
return undefined;
|
|
37
|
+
return trackingStack[trackingStack.length - 1];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Push a new tracking context onto the stack
|
|
41
|
+
*/
|
|
42
|
+
export function pushContext(context) {
|
|
43
|
+
trackingStack.push(context);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Pop the current tracking context from the stack
|
|
47
|
+
*/
|
|
48
|
+
export function popContext() {
|
|
49
|
+
return trackingStack.pop();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Track a dependency - called when a reactive value is read
|
|
53
|
+
*
|
|
54
|
+
* @param subscribers - The subscriber set of the reactive value being read
|
|
55
|
+
*/
|
|
56
|
+
export function trackDependency(subscribers) {
|
|
57
|
+
const context = getCurrentContext();
|
|
58
|
+
if (context) {
|
|
59
|
+
// Register this effect as a subscriber to the signal
|
|
60
|
+
subscribers.add(context.execute);
|
|
61
|
+
// Track that this effect depends on this signal
|
|
62
|
+
context.dependencies.add(subscribers);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Notify subscribers that a reactive value has changed
|
|
67
|
+
*
|
|
68
|
+
* @param subscribers - The subscriber set to notify
|
|
69
|
+
*/
|
|
70
|
+
export function notifySubscribers(subscribers) {
|
|
71
|
+
// Copy subscribers to avoid issues if the set is modified during iteration
|
|
72
|
+
const toNotify = [...subscribers];
|
|
73
|
+
for (const subscriber of toNotify) {
|
|
74
|
+
if (batchDepth > 0) {
|
|
75
|
+
// Batching - defer effect execution
|
|
76
|
+
pendingEffects.add(subscriber);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Execute immediately
|
|
80
|
+
subscriber();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Clean up a tracking context - remove it from all dependency sets
|
|
86
|
+
*
|
|
87
|
+
* @param context - The context to clean up
|
|
88
|
+
*/
|
|
89
|
+
export function cleanupContext(context) {
|
|
90
|
+
for (const deps of context.dependencies) {
|
|
91
|
+
deps.delete(context.execute);
|
|
92
|
+
}
|
|
93
|
+
context.dependencies.clear();
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Run a function without tracking dependencies
|
|
97
|
+
*
|
|
98
|
+
* @param fn - The function to run
|
|
99
|
+
* @returns The return value of the function
|
|
100
|
+
*/
|
|
101
|
+
export function runUntracked(fn) {
|
|
102
|
+
const wasDisabled = trackingDisabled;
|
|
103
|
+
trackingDisabled = true;
|
|
104
|
+
try {
|
|
105
|
+
return fn();
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
trackingDisabled = wasDisabled;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Start a batch - defer effect execution until batch ends
|
|
113
|
+
*/
|
|
114
|
+
export function startBatch() {
|
|
115
|
+
batchDepth++;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* End a batch - run all pending effects
|
|
119
|
+
*/
|
|
120
|
+
export function endBatch() {
|
|
121
|
+
batchDepth--;
|
|
122
|
+
if (batchDepth === 0 && pendingEffects.size > 0) {
|
|
123
|
+
// Run all pending effects
|
|
124
|
+
const effects = [...pendingEffects];
|
|
125
|
+
pendingEffects.clear();
|
|
126
|
+
for (const effect of effects) {
|
|
127
|
+
effect();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Check if currently inside a batch
|
|
133
|
+
*/
|
|
134
|
+
export function isBatching() {
|
|
135
|
+
return batchDepth > 0;
|
|
136
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zenith Batch - Deferred Effect Execution
|
|
3
|
+
*
|
|
4
|
+
* Batching allows you to make multiple reactive updates without
|
|
5
|
+
* triggering effects until all updates are complete. This improves
|
|
6
|
+
* performance by preventing redundant effect executions.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Groups multiple mutations
|
|
10
|
+
* - Defers effect execution until batch completes
|
|
11
|
+
* - Supports nested batches
|
|
12
|
+
* - Automatically flushes on completion
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* const firstName = zenSignal('John')
|
|
17
|
+
* const lastName = zenSignal('Doe')
|
|
18
|
+
*
|
|
19
|
+
* zenEffect(() => {
|
|
20
|
+
* console.log(`${firstName()} ${lastName()}`)
|
|
21
|
+
* })
|
|
22
|
+
* // Logs: "John Doe"
|
|
23
|
+
*
|
|
24
|
+
* // Without batch - effect runs twice
|
|
25
|
+
* firstName('Jane') // Logs: "Jane Doe"
|
|
26
|
+
* lastName('Smith') // Logs: "Jane Smith"
|
|
27
|
+
*
|
|
28
|
+
* // With batch - effect runs once
|
|
29
|
+
* zenBatch(() => {
|
|
30
|
+
* firstName('Bob')
|
|
31
|
+
* lastName('Brown')
|
|
32
|
+
* })
|
|
33
|
+
* // Logs: "Bob Brown" (only once)
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* Execute a function with batched updates
|
|
38
|
+
*
|
|
39
|
+
* All reactive updates inside the batch will be collected,
|
|
40
|
+
* and effects will only run once after the batch completes.
|
|
41
|
+
*
|
|
42
|
+
* @param fn - The function to execute
|
|
43
|
+
* @returns The return value of the function
|
|
44
|
+
*/
|
|
45
|
+
export declare function zenBatch<T>(fn: () => T): T;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zenith Batch - Deferred Effect Execution
|
|
3
|
+
*
|
|
4
|
+
* Batching allows you to make multiple reactive updates without
|
|
5
|
+
* triggering effects until all updates are complete. This improves
|
|
6
|
+
* performance by preventing redundant effect executions.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Groups multiple mutations
|
|
10
|
+
* - Defers effect execution until batch completes
|
|
11
|
+
* - Supports nested batches
|
|
12
|
+
* - Automatically flushes on completion
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* const firstName = zenSignal('John')
|
|
17
|
+
* const lastName = zenSignal('Doe')
|
|
18
|
+
*
|
|
19
|
+
* zenEffect(() => {
|
|
20
|
+
* console.log(`${firstName()} ${lastName()}`)
|
|
21
|
+
* })
|
|
22
|
+
* // Logs: "John Doe"
|
|
23
|
+
*
|
|
24
|
+
* // Without batch - effect runs twice
|
|
25
|
+
* firstName('Jane') // Logs: "Jane Doe"
|
|
26
|
+
* lastName('Smith') // Logs: "Jane Smith"
|
|
27
|
+
*
|
|
28
|
+
* // With batch - effect runs once
|
|
29
|
+
* zenBatch(() => {
|
|
30
|
+
* firstName('Bob')
|
|
31
|
+
* lastName('Brown')
|
|
32
|
+
* })
|
|
33
|
+
* // Logs: "Bob Brown" (only once)
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
import { startBatch, endBatch } from './tracking';
|
|
37
|
+
/**
|
|
38
|
+
* Execute a function with batched updates
|
|
39
|
+
*
|
|
40
|
+
* All reactive updates inside the batch will be collected,
|
|
41
|
+
* and effects will only run once after the batch completes.
|
|
42
|
+
*
|
|
43
|
+
* @param fn - The function to execute
|
|
44
|
+
* @returns The return value of the function
|
|
45
|
+
*/
|
|
46
|
+
export function zenBatch(fn) {
|
|
47
|
+
startBatch();
|
|
48
|
+
try {
|
|
49
|
+
return fn();
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
endBatch();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zenith Effect - Auto-Tracked Side Effect
|
|
3
|
+
*
|
|
4
|
+
* Effects are functions that automatically track their reactive dependencies
|
|
5
|
+
* and re-run when those dependencies change. They are the bridge between
|
|
6
|
+
* reactive state and side effects (DOM updates, logging, API calls, etc.)
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Automatic dependency tracking (no dependency arrays)
|
|
10
|
+
* - Runs immediately on creation
|
|
11
|
+
* - Re-runs when dependencies change
|
|
12
|
+
* - Supports cleanup functions
|
|
13
|
+
* - Can be manually disposed
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const count = zenSignal(0)
|
|
18
|
+
*
|
|
19
|
+
* // Effect runs immediately, then re-runs when count changes
|
|
20
|
+
* const dispose = zenEffect(() => {
|
|
21
|
+
* console.log('Count:', count())
|
|
22
|
+
*
|
|
23
|
+
* // Optional cleanup - runs before next execution or on dispose
|
|
24
|
+
* return () => {
|
|
25
|
+
* console.log('Cleanup')
|
|
26
|
+
* }
|
|
27
|
+
* })
|
|
28
|
+
*
|
|
29
|
+
* count(1) // Logs: "Cleanup", then "Count: 1"
|
|
30
|
+
*
|
|
31
|
+
* dispose() // Cleanup and stop watching
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* Effect function type - can optionally return a cleanup function
|
|
36
|
+
*/
|
|
37
|
+
export type EffectFn = () => void | (() => void);
|
|
38
|
+
/**
|
|
39
|
+
* Dispose function - call to stop the effect
|
|
40
|
+
*/
|
|
41
|
+
export type DisposeFn = () => void;
|
|
42
|
+
/**
|
|
43
|
+
* Create an auto-tracked side effect
|
|
44
|
+
*
|
|
45
|
+
* @param fn - The effect function to run
|
|
46
|
+
* @returns A dispose function to stop the effect
|
|
47
|
+
*/
|
|
48
|
+
export declare function zenEffect(fn: EffectFn): DisposeFn;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zenith Effect - Auto-Tracked Side Effect
|
|
3
|
+
*
|
|
4
|
+
* Effects are functions that automatically track their reactive dependencies
|
|
5
|
+
* and re-run when those dependencies change. They are the bridge between
|
|
6
|
+
* reactive state and side effects (DOM updates, logging, API calls, etc.)
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Automatic dependency tracking (no dependency arrays)
|
|
10
|
+
* - Runs immediately on creation
|
|
11
|
+
* - Re-runs when dependencies change
|
|
12
|
+
* - Supports cleanup functions
|
|
13
|
+
* - Can be manually disposed
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const count = zenSignal(0)
|
|
18
|
+
*
|
|
19
|
+
* // Effect runs immediately, then re-runs when count changes
|
|
20
|
+
* const dispose = zenEffect(() => {
|
|
21
|
+
* console.log('Count:', count())
|
|
22
|
+
*
|
|
23
|
+
* // Optional cleanup - runs before next execution or on dispose
|
|
24
|
+
* return () => {
|
|
25
|
+
* console.log('Cleanup')
|
|
26
|
+
* }
|
|
27
|
+
* })
|
|
28
|
+
*
|
|
29
|
+
* count(1) // Logs: "Cleanup", then "Count: 1"
|
|
30
|
+
*
|
|
31
|
+
* dispose() // Cleanup and stop watching
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
import { pushContext, popContext, cleanupContext } from './tracking';
|
|
35
|
+
/**
|
|
36
|
+
* Create an auto-tracked side effect
|
|
37
|
+
*
|
|
38
|
+
* @param fn - The effect function to run
|
|
39
|
+
* @returns A dispose function to stop the effect
|
|
40
|
+
*/
|
|
41
|
+
export function zenEffect(fn) {
|
|
42
|
+
const state = {
|
|
43
|
+
fn,
|
|
44
|
+
cleanup: null,
|
|
45
|
+
context: {
|
|
46
|
+
execute: () => runEffect(state),
|
|
47
|
+
dependencies: new Set()
|
|
48
|
+
},
|
|
49
|
+
disposed: false
|
|
50
|
+
};
|
|
51
|
+
// Run the effect immediately
|
|
52
|
+
runEffect(state);
|
|
53
|
+
// Return dispose function
|
|
54
|
+
return () => disposeEffect(state);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Run an effect, tracking dependencies
|
|
58
|
+
*/
|
|
59
|
+
function runEffect(state) {
|
|
60
|
+
if (state.disposed)
|
|
61
|
+
return;
|
|
62
|
+
// Run cleanup from previous execution
|
|
63
|
+
if (state.cleanup) {
|
|
64
|
+
state.cleanup();
|
|
65
|
+
state.cleanup = null;
|
|
66
|
+
}
|
|
67
|
+
// Clean up old dependencies
|
|
68
|
+
cleanupContext(state.context);
|
|
69
|
+
// Push this effect onto the tracking stack
|
|
70
|
+
pushContext(state.context);
|
|
71
|
+
try {
|
|
72
|
+
// Run the effect function
|
|
73
|
+
const result = state.fn();
|
|
74
|
+
// Store cleanup if returned
|
|
75
|
+
if (typeof result === 'function') {
|
|
76
|
+
state.cleanup = result;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
// Pop from tracking stack
|
|
81
|
+
popContext();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Dispose an effect - run cleanup and stop watching
|
|
86
|
+
*/
|
|
87
|
+
function disposeEffect(state) {
|
|
88
|
+
if (state.disposed)
|
|
89
|
+
return;
|
|
90
|
+
state.disposed = true;
|
|
91
|
+
// Run cleanup
|
|
92
|
+
if (state.cleanup) {
|
|
93
|
+
state.cleanup();
|
|
94
|
+
state.cleanup = null;
|
|
95
|
+
}
|
|
96
|
+
// Remove from all dependency sets
|
|
97
|
+
cleanupContext(state.context);
|
|
98
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zenith Memo - Computed/Derived Value
|
|
3
|
+
*
|
|
4
|
+
* A memo is a lazily-evaluated, cached computation that automatically
|
|
5
|
+
* tracks its dependencies and only recomputes when those dependencies change.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Lazy evaluation (only computes when read)
|
|
9
|
+
* - Automatic dependency tracking
|
|
10
|
+
* - Cached value until dependencies change
|
|
11
|
+
* - Read-only (no setter)
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const firstName = zenSignal('John')
|
|
16
|
+
* const lastName = zenSignal('Doe')
|
|
17
|
+
*
|
|
18
|
+
* // Memo computes full name, tracks firstName and lastName
|
|
19
|
+
* const fullName = zenMemo(() => `${firstName()} ${lastName()}`)
|
|
20
|
+
*
|
|
21
|
+
* console.log(fullName()) // "John Doe"
|
|
22
|
+
*
|
|
23
|
+
* firstName('Jane')
|
|
24
|
+
* console.log(fullName()) // "Jane Doe" (recomputed)
|
|
25
|
+
* console.log(fullName()) // "Jane Doe" (cached, no recomputation)
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Memo interface - callable getter
|
|
30
|
+
*/
|
|
31
|
+
export interface Memo<T> {
|
|
32
|
+
/** Get the current computed value */
|
|
33
|
+
(): T;
|
|
34
|
+
/** Peek at cached value without tracking (may be stale) */
|
|
35
|
+
peek(): T;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a memoized computed value
|
|
39
|
+
*
|
|
40
|
+
* @param fn - The computation function
|
|
41
|
+
* @returns A memo that can be read to get the computed value
|
|
42
|
+
*/
|
|
43
|
+
export declare function zenMemo<T>(fn: () => T): Memo<T>;
|