@sprlab/wccompiler 0.12.1 → 0.14.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.
@@ -1,143 +1,143 @@
1
- /**
2
- * Template string containing the mini reactive runtime.
3
- * This gets inlined at the top of each compiled component so the output
4
- * is fully self-contained with zero imports.
5
- *
6
- * Implements:
7
- * - __signal(initialValue): getter/setter function with subscriber tracking
8
- * - __computed(fn): cached derived value that auto-invalidates
9
- * - __effect(fn): runs fn immediately and re-runs when dependencies change
10
- * - __batch(fn): batch multiple signal writes, flush effects once at the end
11
- * - __untrack(fn): run fn without tracking dependencies
12
- *
13
- * Dependency tracking uses a global stack (__currentEffect).
14
- * Batching uses a depth counter — nested batches are supported.
15
- */
16
-
17
- /** Shared globals (always included) */
18
- const runtimeGlobals = `
19
- let __currentEffect = null;
20
- let __batchDepth = 0;
21
- const __pendingEffects = new Set();
22
- `;
23
-
24
- /** __signal — always included */
25
- const runtimeSignal = `
26
- function __signal(initial) {
27
- let _value = initial;
28
- const _subs = new Set();
29
- return (...args) => {
30
- if (args.length === 0) {
31
- if (__currentEffect) _subs.add(__currentEffect);
32
- return _value;
33
- }
34
- const old = _value;
35
- _value = args[0];
36
- if (old !== _value) {
37
- if (__batchDepth > 0) {
38
- for (const fn of _subs) __pendingEffects.add(fn);
39
- } else {
40
- for (const fn of [..._subs]) fn();
41
- }
42
- }
43
- };
44
- }
45
- `;
46
-
47
- /** __computed — only if component uses computed() */
48
- const runtimeComputed = `
49
- function __computed(fn) {
50
- let _cached, _dirty = true;
51
- const _subs = new Set();
52
- const recompute = () => {
53
- _dirty = true;
54
- if (__batchDepth > 0) {
55
- for (const fn of _subs) __pendingEffects.add(fn);
56
- } else {
57
- for (const fn of [..._subs]) fn();
58
- }
59
- };
60
- return () => {
61
- if (__currentEffect) _subs.add(__currentEffect);
62
- if (_dirty) {
63
- const prev = __currentEffect;
64
- __currentEffect = recompute;
65
- _cached = fn();
66
- __currentEffect = prev;
67
- _dirty = false;
68
- }
69
- return _cached;
70
- };
71
- }
72
- `;
73
-
74
- /** __effect — only if component uses effects/bindings/show/model/attr/if/for/watchers/slots */
75
- const runtimeEffect = `
76
- function __effect(fn) {
77
- let _cleanup = null;
78
- let _active = true;
79
- const run = () => {
80
- if (!_active) return;
81
- try {
82
- if (typeof _cleanup === 'function') _cleanup();
83
- const prev = __currentEffect;
84
- __currentEffect = run;
85
- _cleanup = fn();
86
- __currentEffect = prev;
87
- } catch (e) {
88
- console.error('[wcc] Effect error:', e);
89
- _active = false;
90
- }
91
- };
92
- run();
93
- return () => { _active = false; if (typeof _cleanup === 'function') _cleanup(); };
94
- }
95
- `;
96
-
97
- /** __batch — only if component uses batch() */
98
- const runtimeBatch = `
99
- function __batch(fn) {
100
- __batchDepth++;
101
- try {
102
- fn();
103
- } finally {
104
- __batchDepth--;
105
- if (__batchDepth === 0) {
106
- const pending = [...__pendingEffects];
107
- __pendingEffects.clear();
108
- for (const f of pending) f();
109
- }
110
- }
111
- }
112
- `;
113
-
114
- /** __untrack — only if component uses watchers */
115
- const runtimeUntrack = `
116
- function __untrack(fn) {
117
- const prev = __currentEffect;
118
- __currentEffect = null;
119
- try { return fn(); }
120
- finally { __currentEffect = prev; }
121
- }
122
- `;
123
-
124
- /**
125
- * Full runtime (for backward compatibility and shared mode export).
126
- * @type {string}
127
- */
128
- export const reactiveRuntime = runtimeGlobals + runtimeSignal + runtimeComputed + runtimeEffect + runtimeBatch + runtimeUntrack;
129
-
130
- /**
131
- * Build a tree-shaken inline runtime containing only the functions this component needs.
132
- *
133
- * @param {{ needsComputed: boolean, needsEffect: boolean, needsBatch: boolean, needsUntrack: boolean }} usage
134
- * @returns {string}
135
- */
136
- export function buildInlineRuntime(usage) {
137
- let code = runtimeGlobals + runtimeSignal;
138
- if (usage.needsComputed) code += runtimeComputed;
139
- if (usage.needsEffect) code += runtimeEffect;
140
- if (usage.needsBatch) code += runtimeBatch;
141
- if (usage.needsUntrack) code += runtimeUntrack;
142
- return code;
143
- }
1
+ /**
2
+ * Template string containing the mini reactive runtime.
3
+ * This gets inlined at the top of each compiled component so the output
4
+ * is fully self-contained with zero imports.
5
+ *
6
+ * Implements:
7
+ * - __signal(initialValue): getter/setter function with subscriber tracking
8
+ * - __computed(fn): cached derived value that auto-invalidates
9
+ * - __effect(fn): runs fn immediately and re-runs when dependencies change
10
+ * - __batch(fn): batch multiple signal writes, flush effects once at the end
11
+ * - __untrack(fn): run fn without tracking dependencies
12
+ *
13
+ * Dependency tracking uses a global stack (__currentEffect).
14
+ * Batching uses a depth counter — nested batches are supported.
15
+ */
16
+
17
+ /** Shared globals (always included) */
18
+ const runtimeGlobals = `
19
+ let __currentEffect = null;
20
+ let __batchDepth = 0;
21
+ const __pendingEffects = new Set();
22
+ `;
23
+
24
+ /** __signal — always included */
25
+ const runtimeSignal = `
26
+ function __signal(initial) {
27
+ let _value = initial;
28
+ const _subs = new Set();
29
+ return (...args) => {
30
+ if (args.length === 0) {
31
+ if (__currentEffect) _subs.add(__currentEffect);
32
+ return _value;
33
+ }
34
+ const old = _value;
35
+ _value = args[0];
36
+ if (old !== _value) {
37
+ if (__batchDepth > 0) {
38
+ for (const fn of _subs) __pendingEffects.add(fn);
39
+ } else {
40
+ for (const fn of [..._subs]) fn();
41
+ }
42
+ }
43
+ };
44
+ }
45
+ `;
46
+
47
+ /** __computed — only if component uses computed() */
48
+ const runtimeComputed = `
49
+ function __computed(fn) {
50
+ let _cached, _dirty = true;
51
+ const _subs = new Set();
52
+ const recompute = () => {
53
+ _dirty = true;
54
+ if (__batchDepth > 0) {
55
+ for (const fn of _subs) __pendingEffects.add(fn);
56
+ } else {
57
+ for (const fn of [..._subs]) fn();
58
+ }
59
+ };
60
+ return () => {
61
+ if (__currentEffect) _subs.add(__currentEffect);
62
+ if (_dirty) {
63
+ const prev = __currentEffect;
64
+ __currentEffect = recompute;
65
+ _cached = fn();
66
+ __currentEffect = prev;
67
+ _dirty = false;
68
+ }
69
+ return _cached;
70
+ };
71
+ }
72
+ `;
73
+
74
+ /** __effect — only if component uses effects/bindings/show/model/attr/if/for/watchers/slots */
75
+ const runtimeEffect = `
76
+ function __effect(fn) {
77
+ let _cleanup = null;
78
+ let _active = true;
79
+ const run = () => {
80
+ if (!_active) return;
81
+ try {
82
+ if (typeof _cleanup === 'function') _cleanup();
83
+ const prev = __currentEffect;
84
+ __currentEffect = run;
85
+ _cleanup = fn();
86
+ __currentEffect = prev;
87
+ } catch (e) {
88
+ console.error('[wcc] Effect error:', e);
89
+ _active = false;
90
+ }
91
+ };
92
+ run();
93
+ return () => { _active = false; if (typeof _cleanup === 'function') _cleanup(); };
94
+ }
95
+ `;
96
+
97
+ /** __batch — only if component uses batch() */
98
+ const runtimeBatch = `
99
+ function __batch(fn) {
100
+ __batchDepth++;
101
+ try {
102
+ fn();
103
+ } finally {
104
+ __batchDepth--;
105
+ if (__batchDepth === 0) {
106
+ const pending = [...__pendingEffects];
107
+ __pendingEffects.clear();
108
+ for (const f of pending) f();
109
+ }
110
+ }
111
+ }
112
+ `;
113
+
114
+ /** __untrack — only if component uses watchers */
115
+ const runtimeUntrack = `
116
+ function __untrack(fn) {
117
+ const prev = __currentEffect;
118
+ __currentEffect = null;
119
+ try { return fn(); }
120
+ finally { __currentEffect = prev; }
121
+ }
122
+ `;
123
+
124
+ /**
125
+ * Full runtime (for backward compatibility and shared mode export).
126
+ * @type {string}
127
+ */
128
+ export const reactiveRuntime = runtimeGlobals + runtimeSignal + runtimeComputed + runtimeEffect + runtimeBatch + runtimeUntrack;
129
+
130
+ /**
131
+ * Build a tree-shaken inline runtime containing only the functions this component needs.
132
+ *
133
+ * @param {{ needsComputed: boolean, needsEffect: boolean, needsBatch: boolean, needsUntrack: boolean }} usage
134
+ * @returns {string}
135
+ */
136
+ export function buildInlineRuntime(usage) {
137
+ let code = runtimeGlobals + runtimeSignal;
138
+ if (usage.needsComputed) code += runtimeComputed;
139
+ if (usage.needsEffect) code += runtimeEffect;
140
+ if (usage.needsBatch) code += runtimeBatch;
141
+ if (usage.needsUntrack) code += runtimeUntrack;
142
+ return code;
143
+ }