@zenithbuild/runtime 0.1.9 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenithbuild/runtime",
3
- "version": "0.1.9",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -16,4 +16,4 @@
16
16
  "devDependencies": {
17
17
  "typescript": "^5.3.3"
18
18
  }
19
- }
19
+ }
package/src/index.ts CHANGED
@@ -1,6 +1,18 @@
1
1
  // Zenith Runtime
2
2
  // Ported from hydration_runtime.js
3
3
 
4
+ // Exported Types
5
+ export type Signal<T> = ((v?: T) => T) & { _isSignal: true };
6
+ export type Memo<T> = Signal<T>;
7
+ export type Ref<T> = { current: T };
8
+ export type EffectFn = () => (void | (() => void));
9
+ export type DisposeFn = () => void;
10
+ export type Subscriber = { run: () => void; dependencies: Set<Set<any>>; isRunning: boolean };
11
+ export type TrackingContext = { subscriber: Subscriber };
12
+
13
+ export type MountCallback = () => void;
14
+ export type UnmountCallback = () => void;
15
+
4
16
  // Global types for internal use
5
17
  declare global {
6
18
  interface Window {
@@ -28,15 +40,60 @@ declare global {
28
40
 
29
41
  // Internal reactivity state
30
42
  let cE: any = null;
31
- const cS: any[] = [];
43
+ let cS: any[] = [];
32
44
  let bD = 0;
45
+ let isFlushing = false;
46
+ let flushScheduled = false;
33
47
  const pE = new Set<any>();
48
+
49
+ // Lifecycle State
50
+ let isMounted = false;
51
+ const unmountCallbacks = new Set<() => void>();
52
+
53
+ // Public Reactivity Utilities
54
+ export const trackDependency = (s: Set<any>) => { if (cE) { s.add(cE); cE.dependencies.add(s); } };
55
+ export const notifySubscribers = (s: Set<any> | undefined) => {
56
+ if (!s) return;
57
+ const es = Array.from(s);
58
+ for (const e of es) {
59
+ if (e.isRunning) continue;
60
+ if (bD > 0 || isFlushing) pE.add(e);
61
+ else e.run();
62
+ }
63
+ };
64
+ export const getCurrentContext = () => cE;
65
+ export const pushContext = (e: any) => { cS.push(cE); cE = e; };
66
+ export const popContext = () => { cE = cS.pop(); };
67
+ export const cleanupContext = (e: any) => { for (const d of e.dependencies) d.delete(e); e.dependencies.clear(); };
68
+ export const startBatch = () => { bD++; };
69
+ export const endBatch = () => { bD--; if (bD === 0) flushEffects(); };
70
+ export const isBatching = () => bD > 0;
71
+ export const runUntracked = <T>(fn: () => T): T => {
72
+ pushContext(null);
73
+ try { return fn(); } finally { popContext(); }
74
+ };
75
+
76
+ // Public Lifecycle Utilities
77
+ export const triggerMount = () => { isMounted = true; };
78
+ export const triggerUnmount = () => {
79
+ isMounted = false;
80
+ executeUnmountCallbacks();
81
+ };
82
+ export const executeUnmountCallbacks = () => {
83
+ for (const cb of unmountCallbacks) {
84
+ try { cb(); } catch (e) { console.error('Error in unmount callback:', e); }
85
+ }
86
+ unmountCallbacks.clear();
87
+ };
88
+ export const getIsMounted = () => isMounted;
89
+ export const getUnmountCallbackCount = () => unmountCallbacks.size;
90
+ export const resetMountState = () => { isMounted = false; };
91
+ export const resetUnmountState = () => { unmountCallbacks.clear(); };
92
+
34
93
  if (typeof window !== 'undefined') {
35
94
  window.__ZENITH_EXPRESSIONS__ = new Map();
36
95
  window.__ZENITH_SCOPES__ = {};
37
96
  }
38
- let isFlushing = false;
39
- let flushScheduled = false;
40
97
 
41
98
  // Phase A3: Post-Mount Execution Hook
42
99
  const mountedScopes = new Set<string>();
@@ -53,9 +110,12 @@ export function mountComponent(scopeId: string) {
53
110
  }
54
111
  }
55
112
 
56
- function pC(e: any) { cS.push(cE); cE = e; }
57
- function oC() { cE = cS.pop(); }
58
- function tD(s: Set<any>) { if (cE) { s.add(cE); cE.dependencies.add(s); } }
113
+ // Internal shorthand helpers (matching original compiled code requirements if any)
114
+ const pC = pushContext;
115
+ const oC = popContext;
116
+ const tD = trackDependency;
117
+ const nS = notifySubscribers;
118
+ const cEf = cleanupContext;
59
119
 
60
120
  export function zenRoute() {
61
121
  if (typeof window === 'undefined') return { path: '/', slugs: [] };
@@ -66,16 +126,6 @@ export function zenRoute() {
66
126
  };
67
127
  }
68
128
 
69
- function nS(s: Set<any> | undefined) {
70
- if (!s) return;
71
- const es = Array.from(s);
72
- for (const e of es) {
73
- if (e.isRunning) continue;
74
- if (bD > 0 || isFlushing) pE.add(e);
75
- else e.run();
76
- }
77
- }
78
-
79
129
  function scheduleFlush() {
80
130
  if (flushScheduled) return;
81
131
  flushScheduled = true;
@@ -101,8 +151,6 @@ function flushEffects() {
101
151
  }
102
152
  }
103
153
 
104
- function cEf(e: any) { for (const d of e.dependencies) d.delete(e); e.dependencies.clear(); }
105
-
106
154
  export const signal = function (v: any) {
107
155
  const s = new Set<any>();
108
156
  function sig(nV?: any) {
@@ -190,21 +238,27 @@ export const memo = function (fn: () => any) {
190
238
  };
191
239
 
192
240
  export const batch = function (fn: () => void) {
193
- bD++;
194
- try { fn(); } finally {
195
- bD--;
196
- if (bD === 0) flushEffects();
197
- }
241
+ startBatch();
242
+ try { fn(); } finally { endBatch(); }
198
243
  };
199
244
 
200
245
  export const untrack = function (fn: () => any) {
201
- pC(null);
202
- try { return fn(); } finally { oC(); }
246
+ return runUntracked(fn);
203
247
  };
204
248
 
205
249
  export const ref = (i: any) => ({ current: i || null });
206
- export const onMount = (cb: () => void) => { if (window.__zenith && window.__zenith.activeInstance) window.__zenith.activeInstance.mountHooks.push(cb); };
207
- export const onUnmount = (cb: () => void) => { /* TODO */ };
250
+
251
+ export const onMount = (cb: () => void) => {
252
+ if (typeof window !== 'undefined' && window.__zenith && window.__zenith.activeInstance) {
253
+ window.__zenith.activeInstance.mountHooks.push(cb);
254
+ } else {
255
+ // Fallback for non-component context or SSR
256
+ if (isMounted) cb();
257
+ }
258
+ };
259
+ export const onUnmount = (cb: () => void) => {
260
+ unmountCallbacks.add(cb);
261
+ };
208
262
 
209
263
  // DOM Helper (hC)
210
264
  function hC(parent: Node, child: any) {
@@ -295,24 +349,6 @@ export function hydrate(state: any, container: Element | Document = document, lo
295
349
  oldTitle = document.createElement('title');
296
350
  headMount.appendChild(oldTitle);
297
351
  }
298
- const resolveContent = (children: any): string => {
299
- let result = '';
300
- (Array.isArray(children) ? children : [children]).forEach(child => {
301
- if (child == null || child === false) return;
302
- if (typeof child === 'function') {
303
- const val = child();
304
- if (val != null && val !== false) result += String(val);
305
- } else if (typeof child === 'object' && child.fn) {
306
- const val = child.fn();
307
- if (val != null && val !== false) result += String(val);
308
- } else if (child instanceof Node) {
309
- result += child.textContent || '';
310
- } else {
311
- result += String(child);
312
- }
313
- });
314
- return result;
315
- };
316
352
  const titleContent = newTitle.childNodes.length > 0
317
353
  ? Array.from(newTitle.childNodes).map((n: any) => n.textContent).join('')
318
354
  : '';
@@ -407,7 +443,6 @@ export function h(tag: string, props: any, children: any) {
407
443
  if (v && typeof v === 'object' && (v as any).fn) fn = (v as any).fn;
408
444
  if (typeof fn === 'function') {
409
445
  el.addEventListener(k.slice(2).toLowerCase(), (e) => {
410
- // Fix: this binding via call(el, e, el)
411
446
  const h = (fn as Function).call(el, e, el);
412
447
  if (typeof h === 'function') h.call(el, e, el);
413
448
  });
package/tsconfig.json CHANGED
@@ -1,16 +1,28 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "declaration": true,
7
- "outDir": "./dist",
3
+ "module": "ESNext",
4
+ "target": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "allowImportingTsExtensions": false,
7
+ "verbatimModuleSyntax": false,
8
+ "noEmit": false,
9
+ "outDir": "dist",
8
10
  "strict": true,
9
- "esModuleInterop": true,
10
11
  "skipLibCheck": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "sourceMap": true,
15
+ "esModuleInterop": true,
11
16
  "forceConsistentCasingInFileNames": true
12
17
  },
13
18
  "include": [
14
19
  "src/**/*"
20
+ ],
21
+ "exclude": [
22
+ "node_modules",
23
+ "dist",
24
+ "src/**/*.test.ts",
25
+ "src/**/*.spec.ts",
26
+ "tests/**/*"
15
27
  ]
16
28
  }