what-core 0.6.0 → 0.6.1

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
@@ -285,43 +285,66 @@ function scheduleMicrotask() {
285
285
  });
286
286
  }
287
287
  }
288
+ var isFlushing = false;
288
289
  function flush() {
289
- let iterations = 0;
290
- while (pendingEffects.length > 0 && iterations < 25) {
291
- const batch2 = pendingEffects;
292
- pendingEffects = [];
293
- if (batch2.length > 1 && pendingNeedSort) {
294
- batch2.sort((a, b) => a._level - b._level);
295
- }
296
- pendingNeedSort = false;
297
- for (let i = 0; i < batch2.length; i++) {
298
- const e = batch2[i];
299
- e._pending = false;
300
- if (!e.disposed && !e._onNotify) {
301
- const prevDepsLen = e.deps.length;
302
- _runEffect(e);
303
- if (!e._computed && e.deps.length !== prevDepsLen) {
304
- _updateLevel(e);
290
+ if (isFlushing) return;
291
+ isFlushing = true;
292
+ try {
293
+ let iterations = 0;
294
+ while (pendingEffects.length > 0 && iterations < 25) {
295
+ const batch2 = pendingEffects;
296
+ pendingEffects = [];
297
+ if (batch2.length > 1 && pendingNeedSort) {
298
+ batch2.sort((a, b) => a._level - b._level);
299
+ }
300
+ pendingNeedSort = false;
301
+ for (let i = 0; i < batch2.length; i++) {
302
+ const e = batch2[i];
303
+ e._pending = false;
304
+ if (!e.disposed && !e._onNotify) {
305
+ const prevDepsLen = e.deps.length;
306
+ _runEffect(e);
307
+ if (!e._computed && e.deps.length !== prevDepsLen) {
308
+ _updateLevel(e);
309
+ }
305
310
  }
306
311
  }
312
+ iterations++;
313
+ }
314
+ if (iterations >= 25) {
315
+ for (let i = 0; i < pendingEffects.length; i++) pendingEffects[i]._pending = false;
316
+ pendingEffects.length = 0;
317
+ if (__DEV__) {
318
+ const remaining = pendingEffects.slice(0, 3);
319
+ const effectNames = remaining.map((e) => e.fn?.name || e.fn?.toString().slice(0, 60) || "(anonymous)");
320
+ console.warn(
321
+ `[what] Possible infinite effect loop detected (25 iterations). Likely cause: an effect writes to a signal it also reads, creating a cycle. Use untrack() to read signals without subscribing. Looping effects: ${effectNames.join(", ")}`
322
+ );
323
+ } else {
324
+ console.warn("[what] Possible infinite effect loop detected");
325
+ }
307
326
  }
308
- iterations++;
327
+ } finally {
328
+ isFlushing = false;
309
329
  }
310
- if (iterations >= 25) {
330
+ }
331
+ function flushSync() {
332
+ if (isFlushing) {
311
333
  if (__DEV__) {
312
- const remaining = pendingEffects.slice(0, 3);
313
- const effectNames = remaining.map((e) => e.fn?.name || e.fn?.toString().slice(0, 60) || "(anonymous)");
314
334
  console.warn(
315
- `[what] Possible infinite effect loop detected (25 iterations). Likely cause: an effect writes to a signal it also reads, creating a cycle. Use untrack() to read signals without subscribing. Looping effects: ${effectNames.join(", ")}`
335
+ "[what] flushSync() called during an active flush (e.g., inside a component render or effect). This is a no-op to prevent infinite loops. Move flushSync() to an event handler or onMount callback."
316
336
  );
317
- } else {
318
- console.warn("[what] Possible infinite effect loop detected");
319
337
  }
320
- for (let i = 0; i < pendingEffects.length; i++) pendingEffects[i]._pending = false;
321
- pendingEffects.length = 0;
338
+ return;
339
+ }
340
+ if (currentEffect) {
341
+ if (__DEV__) {
342
+ console.warn(
343
+ "[what] flushSync() called during effect execution. This is a no-op to prevent infinite loops. Move flushSync() to an event handler or onMount callback."
344
+ );
345
+ }
346
+ return;
322
347
  }
323
- }
324
- function flushSync() {
325
348
  microtaskScheduled = false;
326
349
  flush();
327
350
  }
@@ -762,8 +785,8 @@ function createComponent(vnode, parent, isSvg) {
762
785
  function createErrorBoundary(vnode, parent) {
763
786
  const { errorState, handleError, fallback, reset } = vnode.props;
764
787
  const children = vnode.children;
765
- const wrapper = document.createElement("span");
766
- wrapper.style.display = "contents";
788
+ const startComment = document.createComment("eb:start");
789
+ const endComment = document.createComment("eb:end");
767
790
  const boundaryCtx = {
768
791
  hooks: [],
769
792
  hookIndex: 0,
@@ -772,15 +795,24 @@ function createErrorBoundary(vnode, parent) {
772
795
  mounted: false,
773
796
  disposed: false,
774
797
  _parentCtx: componentStack[componentStack.length - 1] || null,
775
- _errorBoundary: handleError
798
+ _errorBoundary: handleError,
799
+ _startComment: startComment,
800
+ _endComment: endComment
776
801
  };
777
- wrapper._componentCtx = boundaryCtx;
802
+ _commentCtxMap.set(startComment, boundaryCtx);
803
+ const container2 = document.createDocumentFragment();
804
+ container2._componentCtx = boundaryCtx;
805
+ container2.appendChild(startComment);
806
+ container2.appendChild(endComment);
778
807
  const dispose = effect(() => {
779
808
  const error = errorState();
780
809
  componentStack.push(boundaryCtx);
781
- while (wrapper.firstChild) {
782
- disposeTree(wrapper.firstChild);
783
- wrapper.removeChild(wrapper.firstChild);
810
+ if (startComment.parentNode) {
811
+ while (startComment.nextSibling && startComment.nextSibling !== endComment) {
812
+ const old = startComment.nextSibling;
813
+ disposeTree(old);
814
+ old.parentNode.removeChild(old);
815
+ }
784
816
  }
785
817
  let vnodes;
786
818
  if (error) {
@@ -790,19 +822,25 @@ function createErrorBoundary(vnode, parent) {
790
822
  }
791
823
  vnodes = Array.isArray(vnodes) ? vnodes : [vnodes];
792
824
  for (const v of vnodes) {
793
- const node = createDOM(v, wrapper);
794
- if (node) wrapper.appendChild(node);
825
+ const node = createDOM(v, parent);
826
+ if (node) {
827
+ if (endComment.parentNode) {
828
+ endComment.parentNode.insertBefore(node, endComment);
829
+ } else {
830
+ container2.insertBefore(node, endComment);
831
+ }
832
+ }
795
833
  }
796
834
  componentStack.pop();
797
835
  });
798
836
  boundaryCtx.effects.push(dispose);
799
- return wrapper;
837
+ return container2;
800
838
  }
801
839
  function createSuspenseBoundary(vnode, parent) {
802
840
  const { boundary, fallback, loading } = vnode.props;
803
841
  const children = vnode.children;
804
- const wrapper = document.createElement("span");
805
- wrapper.style.display = "contents";
842
+ const startComment = document.createComment("sb:start");
843
+ const endComment = document.createComment("sb:end");
806
844
  const boundaryCtx = {
807
845
  hooks: [],
808
846
  hookIndex: 0,
@@ -810,26 +848,41 @@ function createSuspenseBoundary(vnode, parent) {
810
848
  cleanups: [],
811
849
  mounted: false,
812
850
  disposed: false,
813
- _parentCtx: componentStack[componentStack.length - 1] || null
851
+ _parentCtx: componentStack[componentStack.length - 1] || null,
852
+ _startComment: startComment,
853
+ _endComment: endComment
814
854
  };
815
- wrapper._componentCtx = boundaryCtx;
855
+ _commentCtxMap.set(startComment, boundaryCtx);
856
+ const container2 = document.createDocumentFragment();
857
+ container2._componentCtx = boundaryCtx;
858
+ container2.appendChild(startComment);
859
+ container2.appendChild(endComment);
816
860
  const dispose = effect(() => {
817
861
  const isLoading = loading();
818
862
  const vnodes = isLoading ? [fallback] : children;
819
863
  const normalized = Array.isArray(vnodes) ? vnodes : [vnodes];
820
864
  componentStack.push(boundaryCtx);
821
- while (wrapper.firstChild) {
822
- disposeTree(wrapper.firstChild);
823
- wrapper.removeChild(wrapper.firstChild);
865
+ if (startComment.parentNode) {
866
+ while (startComment.nextSibling && startComment.nextSibling !== endComment) {
867
+ const old = startComment.nextSibling;
868
+ disposeTree(old);
869
+ old.parentNode.removeChild(old);
870
+ }
824
871
  }
825
872
  for (const v of normalized) {
826
- const node = createDOM(v, wrapper);
827
- if (node) wrapper.appendChild(node);
873
+ const node = createDOM(v, parent);
874
+ if (node) {
875
+ if (endComment.parentNode) {
876
+ endComment.parentNode.insertBefore(node, endComment);
877
+ } else {
878
+ container2.insertBefore(node, endComment);
879
+ }
880
+ }
828
881
  }
829
882
  componentStack.pop();
830
883
  });
831
884
  boundaryCtx.effects.push(dispose);
832
- return wrapper;
885
+ return container2;
833
886
  }
834
887
  function createPortalDOM(vnode, parent) {
835
888
  const { container: container2 } = vnode.props;