what-core 0.6.2 → 0.8.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/dist/testing.js CHANGED
@@ -8,42 +8,41 @@ var insideComputed = false;
8
8
  var batchDepth = 0;
9
9
  var pendingEffects = [];
10
10
  var pendingNeedSort = false;
11
- var subSetOwner = /* @__PURE__ */ new WeakMap();
12
11
  var NEEDS_UPSTREAM = /* @__PURE__ */ Symbol("needs_upstream");
13
12
  function signal(initial, debugName) {
14
13
  let value = initial;
15
14
  const subs = /* @__PURE__ */ new Set();
16
- function sig(...args) {
17
- if (args.length === 0) {
18
- if (currentEffect) {
19
- subs.add(currentEffect);
20
- currentEffect.deps.push(subs);
21
- }
22
- return value;
23
- }
15
+ let lastTracked = null;
16
+ let lastTrackedEpoch = 0;
17
+ function _sigWrite(next) {
24
18
  if (__DEV__ && insideComputed) {
25
19
  console.warn(
26
20
  "[what] Signal.set() called inside a computed function. This may cause infinite loops. Use effect() instead." + (debugName ? ` (signal: ${debugName})` : "")
27
21
  );
28
22
  }
29
- const nextVal = typeof args[0] === "function" ? args[0](value) : args[0];
30
- if (Object.is(value, nextVal)) return;
23
+ const nextVal = typeof next === "function" ? next(value) : next;
24
+ if (value === nextVal || value !== value && nextVal !== nextVal) return;
31
25
  value = nextVal;
26
+ lastTracked = null;
32
27
  if (__DEV__ && __devtools) __devtools.onSignalUpdate(sig);
33
28
  if (subs.size > 0) notify(subs);
34
29
  }
35
- sig.set = (next) => {
36
- if (__DEV__ && insideComputed) {
37
- console.warn(
38
- "[what] Signal.set() called inside a computed function. This may cause infinite loops. Use effect() instead." + (debugName ? ` (signal: ${debugName})` : "")
39
- );
30
+ function sig(newVal) {
31
+ if (arguments.length === 0) {
32
+ const ce = currentEffect;
33
+ if (ce !== null) {
34
+ if (ce !== lastTracked || ce._epoch !== lastTrackedEpoch) {
35
+ lastTracked = ce;
36
+ lastTrackedEpoch = ce._epoch;
37
+ subs.add(ce);
38
+ ce.deps.push(subs);
39
+ }
40
+ }
41
+ return value;
40
42
  }
41
- const nextVal = typeof next === "function" ? next(value) : next;
42
- if (Object.is(value, nextVal)) return;
43
- value = nextVal;
44
- if (__DEV__ && __devtools) __devtools.onSignalUpdate(sig);
45
- if (subs.size > 0) notify(subs);
46
- };
43
+ _sigWrite(newVal);
44
+ }
45
+ sig.set = _sigWrite;
47
46
  sig.peek = () => value;
48
47
  sig.subscribe = (fn) => {
49
48
  return effect(() => fn(sig()));
@@ -60,7 +59,7 @@ function _updateLevel(e) {
60
59
  let maxDepLevel = 0;
61
60
  const deps = e.deps;
62
61
  for (let i = 0; i < deps.length; i++) {
63
- const owner = subSetOwner.get(deps[i]);
62
+ const owner = deps[i]._owner;
64
63
  if (owner) {
65
64
  const depLevel = owner._level;
66
65
  if (depLevel > maxDepLevel) maxDepLevel = depLevel;
@@ -106,8 +105,12 @@ function _createEffect(fn, lazy) {
106
105
  // reference to the computed's subscriber set
107
106
  _isDirty: null,
108
107
  // function to check if computed is dirty (set by computed())
109
- _markDirty: null
108
+ _markDirty: null,
110
109
  // function to mark computed dirty (set by computed())
110
+ _cleanup: null,
111
+ // cleanup function returned by effect fn (declared upfront for shape)
112
+ _epoch: 0
113
+ // incremented on cleanup — used by signal lastTracked cache
111
114
  };
112
115
  if (__DEV__ && __devtools) __devtools.onEffectCreate(e);
113
116
  return e;
@@ -137,12 +140,13 @@ function _runEffect(e) {
137
140
  if (__DEV__ && __devtools?.onEffectRun) __devtools.onEffectRun(e);
138
141
  return;
139
142
  }
143
+ const singleDep = e.deps.length === 1 ? e.deps[0] : null;
140
144
  cleanup(e);
141
145
  if (e._cleanup) {
142
146
  try {
143
147
  e._cleanup();
144
148
  } catch (err) {
145
- if (__devtools?.onError) __devtools.onError(err, { type: "effect-cleanup", effect: e });
149
+ if (__DEV__ && __devtools?.onError) __devtools.onError(err, { type: "effect-cleanup", effect: e });
146
150
  if (__DEV__) console.warn("[what] Error in effect cleanup:", err);
147
151
  }
148
152
  e._cleanup = null;
@@ -156,11 +160,14 @@ function _runEffect(e) {
156
160
  }
157
161
  } catch (err) {
158
162
  if (err === NEEDS_UPSTREAM) throw err;
159
- if (__devtools?.onError) __devtools.onError(err, { type: "effect", effect: e });
163
+ if (__DEV__ && __devtools?.onError) __devtools.onError(err, { type: "effect", effect: e });
160
164
  throw err;
161
165
  } finally {
162
166
  currentEffect = prev;
163
167
  }
168
+ if (singleDep !== null && e.deps.length === 1 && e.deps[0] === singleDep && !e._cleanup && !e._pending) {
169
+ e._stable = true;
170
+ }
164
171
  if (__DEV__ && __devtools?.onEffectRun) __devtools.onEffectRun(e);
165
172
  }
166
173
  function _disposeEffect(e) {
@@ -180,45 +187,51 @@ function cleanup(e) {
180
187
  const deps = e.deps;
181
188
  for (let i = 0; i < deps.length; i++) deps[i].delete(e);
182
189
  deps.length = 0;
190
+ e._epoch++;
183
191
  }
184
192
  var notifyDepth = 0;
185
193
  var notifyQueue = null;
186
194
  var notifyQueueLen = 0;
195
+ function _processSubscriber(e) {
196
+ if (e.disposed) return;
197
+ if (e._onNotify) {
198
+ e._onNotify();
199
+ } else if (!e._pending) {
200
+ if (batchDepth === 0 && e._stable) {
201
+ const prev = currentEffect;
202
+ currentEffect = null;
203
+ try {
204
+ const result = e.fn();
205
+ if (typeof result === "function") {
206
+ if (e._cleanup) try {
207
+ e._cleanup();
208
+ } catch (err) {
209
+ }
210
+ e._cleanup = result;
211
+ }
212
+ } catch (err) {
213
+ if (__DEV__ && __devtools?.onError) __devtools.onError(err, { type: "effect", effect: e });
214
+ if (__DEV__) console.warn("[what] Error in stable effect:", err);
215
+ } finally {
216
+ currentEffect = prev;
217
+ }
218
+ } else {
219
+ e._pending = true;
220
+ const level = e._level;
221
+ const len = pendingEffects.length;
222
+ if (len > 0 && pendingEffects[len - 1]._level > level) {
223
+ pendingNeedSort = true;
224
+ }
225
+ pendingEffects.push(e);
226
+ }
227
+ }
228
+ }
187
229
  function notify(subs) {
188
230
  if (notifyDepth === 0) {
189
231
  notifyDepth = 1;
190
232
  try {
191
233
  for (const e of subs) {
192
- if (e.disposed) continue;
193
- if (e._onNotify) {
194
- e._onNotify();
195
- } else if (batchDepth === 0 && e._stable) {
196
- const prev = currentEffect;
197
- currentEffect = null;
198
- try {
199
- const result = e.fn();
200
- if (typeof result === "function") {
201
- if (e._cleanup) try {
202
- e._cleanup();
203
- } catch (err) {
204
- }
205
- e._cleanup = result;
206
- }
207
- } catch (err) {
208
- if (__devtools?.onError) __devtools.onError(err, { type: "effect", effect: e });
209
- if (__DEV__) console.warn("[what] Error in stable effect:", err);
210
- } finally {
211
- currentEffect = prev;
212
- }
213
- } else if (!e._pending) {
214
- e._pending = true;
215
- const level = e._level;
216
- const len = pendingEffects.length;
217
- if (len > 0 && pendingEffects[len - 1]._level > level) {
218
- pendingNeedSort = true;
219
- }
220
- pendingEffects.push(e);
221
- }
234
+ _processSubscriber(e);
222
235
  }
223
236
  if (notifyQueueLen > 0) {
224
237
  let qi = 0;
@@ -227,36 +240,7 @@ function notify(subs) {
227
240
  notifyQueue[qi] = null;
228
241
  qi++;
229
242
  for (const e of queuedSubs) {
230
- if (e.disposed) continue;
231
- if (e._onNotify) {
232
- e._onNotify();
233
- } else if (batchDepth === 0 && e._stable) {
234
- const prev = currentEffect;
235
- currentEffect = null;
236
- try {
237
- const result = e.fn();
238
- if (typeof result === "function") {
239
- if (e._cleanup) try {
240
- e._cleanup();
241
- } catch (err) {
242
- }
243
- e._cleanup = result;
244
- }
245
- } catch (err) {
246
- if (__devtools?.onError) __devtools.onError(err, { type: "effect", effect: e });
247
- if (__DEV__) console.warn("[what] Error in stable effect:", err);
248
- } finally {
249
- currentEffect = prev;
250
- }
251
- } else if (!e._pending) {
252
- e._pending = true;
253
- const level = e._level;
254
- const len = pendingEffects.length;
255
- if (len > 0 && pendingEffects[len - 1]._level > level) {
256
- pendingNeedSort = true;
257
- }
258
- pendingEffects.push(e);
259
- }
243
+ _processSubscriber(e);
260
244
  }
261
245
  }
262
246
  notifyQueueLen = 0;
@@ -312,8 +296,6 @@ function flush() {
312
296
  iterations++;
313
297
  }
314
298
  if (iterations >= 25) {
315
- for (let i = 0; i < pendingEffects.length; i++) pendingEffects[i]._pending = false;
316
- pendingEffects.length = 0;
317
299
  if (__DEV__) {
318
300
  const remaining = pendingEffects.slice(0, 3);
319
301
  const effectNames = remaining.map((e) => e.fn?.name || e.fn?.toString().slice(0, 60) || "(anonymous)");
@@ -323,6 +305,8 @@ function flush() {
323
305
  } else {
324
306
  console.warn("[what] Possible infinite effect loop detected");
325
307
  }
308
+ for (let i = 0; i < pendingEffects.length; i++) pendingEffects[i]._pending = false;
309
+ pendingEffects.length = 0;
326
310
  }
327
311
  } finally {
328
312
  isFlushing = false;
@@ -411,9 +395,22 @@ function _disposeRoot(root) {
411
395
 
412
396
  // packages/core/src/h.js
413
397
  var EMPTY_OBJ = /* @__PURE__ */ Object.create(null);
414
- function h(tag, props, ...children) {
398
+ var EMPTY_ARR = [];
399
+ function h(tag, props) {
415
400
  props = props || EMPTY_OBJ;
416
- const flat = flattenChildren(children);
401
+ const argLen = arguments.length;
402
+ let flat;
403
+ if (argLen <= 2) {
404
+ flat = EMPTY_ARR;
405
+ } else if (argLen === 3) {
406
+ flat = _flattenSingle(arguments[2]);
407
+ } else {
408
+ const out = [];
409
+ for (let i = 2; i < argLen; i++) {
410
+ _flattenInto(arguments[i], out);
411
+ }
412
+ flat = out;
413
+ }
417
414
  const key = props.key ?? null;
418
415
  if (props.key !== void 0) {
419
416
  props = { ...props };
@@ -421,22 +418,30 @@ function h(tag, props, ...children) {
421
418
  }
422
419
  return { tag, props, children: flat, key, _vnode: true };
423
420
  }
424
- function flattenChildren(children) {
425
- const out = [];
426
- for (let i = 0; i < children.length; i++) {
427
- const child = children[i];
428
- if (child == null || child === false || child === true) continue;
429
- if (Array.isArray(child)) {
430
- out.push(...flattenChildren(child));
431
- } else if (typeof child === "object" && child._vnode) {
432
- out.push(child);
433
- } else if (typeof child === "function") {
434
- out.push(child);
435
- } else {
436
- out.push(String(child));
437
- }
421
+ function _flattenSingle(child) {
422
+ if (child == null || child === false || child === true) return EMPTY_ARR;
423
+ if (Array.isArray(child)) {
424
+ const out = [];
425
+ _flattenInto(child, out);
426
+ return out;
427
+ }
428
+ if (typeof child === "object" && child._vnode) return [child];
429
+ if (typeof child === "function") return [child];
430
+ return [String(child)];
431
+ }
432
+ function _flattenInto(child, out) {
433
+ if (child == null || child === false || child === true) return;
434
+ if (Array.isArray(child)) {
435
+ for (let i = 0; i < child.length; i++) {
436
+ _flattenInto(child[i], out);
437
+ }
438
+ } else if (typeof child === "object" && child._vnode) {
439
+ out.push(child);
440
+ } else if (typeof child === "function") {
441
+ out.push(child);
442
+ } else {
443
+ out.push(String(child));
438
444
  }
439
- return out;
440
445
  }
441
446
 
442
447
  // packages/core/src/components.js
@@ -570,9 +575,11 @@ function disposeTree(node) {
570
575
  if (node._componentCtx) {
571
576
  disposeComponent(node._componentCtx);
572
577
  }
573
- const commentCtx = _commentCtxMap.get(node);
574
- if (commentCtx) {
575
- disposeComponent(commentCtx);
578
+ if (node.nodeType === 8) {
579
+ const commentCtx = _commentCtxMap.get(node);
580
+ if (commentCtx) {
581
+ disposeComponent(commentCtx);
582
+ }
576
583
  }
577
584
  if (node._dispose) {
578
585
  try {
@@ -588,9 +595,10 @@ function disposeTree(node) {
588
595
  }
589
596
  }
590
597
  }
591
- if (node.childNodes) {
592
- for (const child of node.childNodes) {
593
- disposeTree(child);
598
+ const children = node.childNodes;
599
+ if (children && children.length > 0) {
600
+ for (let i = 0; i < children.length; i++) {
601
+ disposeTree(children[i]);
594
602
  }
595
603
  }
596
604
  }
@@ -668,6 +676,27 @@ function createDOM(vnode, parent, isSvg) {
668
676
  }
669
677
  return document.createTextNode(String(vnode));
670
678
  }
679
+ var _propsProxyHandler = {
680
+ get(target, key) {
681
+ if (key === "_sig") return void 0;
682
+ return target._sig()[key];
683
+ },
684
+ has(target, key) {
685
+ if (key === "_sig") return false;
686
+ return key in target._sig();
687
+ },
688
+ ownKeys(target) {
689
+ return Reflect.ownKeys(target._sig());
690
+ },
691
+ getOwnPropertyDescriptor(target, key) {
692
+ if (key === "_sig") return void 0;
693
+ const current = target._sig();
694
+ if (key in current) {
695
+ return { value: current[key], writable: false, enumerable: true, configurable: true };
696
+ }
697
+ return void 0;
698
+ }
699
+ };
671
700
  var componentStack = [];
672
701
  function getCurrentComponent() {
673
702
  return componentStack[componentStack.length - 1];
@@ -693,6 +722,21 @@ function createComponent(vnode, parent, isSvg) {
693
722
  if (Component === "__portal" || vnode.tag === "__portal") {
694
723
  return createPortalDOM(vnode, parent);
695
724
  }
725
+ const parentCtx = componentStack[componentStack.length - 1] || null;
726
+ let errorBoundary = null;
727
+ if (parentCtx) {
728
+ errorBoundary = parentCtx._errorBoundary || null;
729
+ if (!errorBoundary) {
730
+ let p = parentCtx._parentCtx;
731
+ while (p) {
732
+ if (p._errorBoundary) {
733
+ errorBoundary = p._errorBoundary;
734
+ break;
735
+ }
736
+ p = p._parentCtx;
737
+ }
738
+ }
739
+ }
696
740
  const ctx = {
697
741
  hooks: [],
698
742
  hookIndex: 0,
@@ -701,15 +745,8 @@ function createComponent(vnode, parent, isSvg) {
701
745
  mounted: false,
702
746
  disposed: false,
703
747
  Component,
704
- _parentCtx: componentStack[componentStack.length - 1] || null,
705
- _errorBoundary: (() => {
706
- let p = componentStack[componentStack.length - 1];
707
- while (p) {
708
- if (p._errorBoundary) return p._errorBoundary;
709
- p = p._parentCtx;
710
- }
711
- return null;
712
- })()
748
+ _parentCtx: parentCtx,
749
+ _errorBoundary: errorBoundary
713
750
  };
714
751
  const startComment = document.createComment("c:start");
715
752
  const endComment = document.createComment("c:end");
@@ -722,29 +759,15 @@ function createComponent(vnode, parent, isSvg) {
722
759
  mountedComponents.add(ctx);
723
760
  if (__DEV__ && __devtools?.onComponentMount) __devtools.onComponentMount(ctx);
724
761
  const propsChildren = children.length === 0 ? void 0 : children.length === 1 ? children[0] : children;
725
- const propsSignal = signal({ ...props, children: propsChildren });
762
+ let mergedProps;
763
+ if (propsChildren !== void 0) {
764
+ mergedProps = props ? Object.assign({}, props, { children: propsChildren }) : { children: propsChildren };
765
+ } else {
766
+ mergedProps = props ? Object.assign({}, props) : {};
767
+ }
768
+ const propsSignal = signal(mergedProps);
726
769
  ctx._propsSignal = propsSignal;
727
- const reactiveProps = new Proxy({}, {
728
- get(_, key) {
729
- const current = propsSignal();
730
- return current[key];
731
- },
732
- has(_, key) {
733
- const current = propsSignal();
734
- return key in current;
735
- },
736
- ownKeys() {
737
- const current = propsSignal();
738
- return Reflect.ownKeys(current);
739
- },
740
- getOwnPropertyDescriptor(_, key) {
741
- const current = propsSignal();
742
- if (key in current) {
743
- return { value: current[key], writable: false, enumerable: true, configurable: true };
744
- }
745
- return void 0;
746
- }
747
- });
770
+ const reactiveProps = new Proxy({ _sig: propsSignal }, _propsProxyHandler);
748
771
  componentStack.push(ctx);
749
772
  let result;
750
773
  try {
@@ -925,21 +948,22 @@ function createElementFromVNode(vnode, parent, isSvg) {
925
948
  if (props) {
926
949
  applyProps(el, props, {}, svgContext);
927
950
  }
928
- for (const child of children) {
929
- const node = createDOM(child, el, svgContext && tag !== "foreignObject");
951
+ const isSvgChildren = svgContext && tag !== "foreignObject";
952
+ for (let i = 0; i < children.length; i++) {
953
+ const node = createDOM(children[i], el, isSvgChildren);
930
954
  if (node) el.appendChild(node);
931
955
  }
932
956
  el._vnode = vnode;
933
957
  return el;
934
958
  }
935
959
  function applyProps(el, newProps, oldProps, isSvg) {
936
- newProps = newProps || {};
937
- oldProps = oldProps || {};
960
+ if (!newProps) return;
938
961
  for (const key in newProps) {
939
962
  if (key === "key" || key === "children") continue;
940
963
  if (key === "ref") {
941
- if (typeof newProps.ref === "function") newProps.ref(el);
942
- else if (newProps.ref) newProps.ref.current = el;
964
+ const ref = newProps.ref;
965
+ if (typeof ref === "function") ref(el);
966
+ else if (ref) ref.current = el;
943
967
  continue;
944
968
  }
945
969
  setProp(el, key, newProps[key], isSvg);
@@ -976,8 +1000,9 @@ function setProp(el, key, value, isSvg) {
976
1000
  if (!el._events) el._events = {};
977
1001
  const wrappedHandler = (e) => {
978
1002
  if (!e.nativeEvent) e.nativeEvent = e;
979
- return untrack(() => value(e));
1003
+ return untrack(() => wrappedHandler._handler(e));
980
1004
  };
1005
+ wrappedHandler._handler = value;
981
1006
  wrappedHandler._original = value;
982
1007
  el._events[storageKey] = wrappedHandler;
983
1008
  const eventOpts = value._eventOpts;