what-core 0.6.0 → 0.6.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/dist/index.js CHANGED
@@ -383,40 +383,47 @@ function scheduleMicrotask() {
383
383
  });
384
384
  }
385
385
  }
386
+ var isFlushing = false;
386
387
  function flush() {
387
- let iterations = 0;
388
- while (pendingEffects.length > 0 && iterations < 25) {
389
- const batch2 = pendingEffects;
390
- pendingEffects = [];
391
- if (batch2.length > 1 && pendingNeedSort) {
392
- batch2.sort((a, b) => a._level - b._level);
393
- }
394
- pendingNeedSort = false;
395
- for (let i = 0; i < batch2.length; i++) {
396
- const e = batch2[i];
397
- e._pending = false;
398
- if (!e.disposed && !e._onNotify) {
399
- const prevDepsLen = e.deps.length;
400
- _runEffect(e);
401
- if (!e._computed && e.deps.length !== prevDepsLen) {
402
- _updateLevel(e);
388
+ if (isFlushing) return;
389
+ isFlushing = true;
390
+ try {
391
+ let iterations = 0;
392
+ while (pendingEffects.length > 0 && iterations < 25) {
393
+ const batch2 = pendingEffects;
394
+ pendingEffects = [];
395
+ if (batch2.length > 1 && pendingNeedSort) {
396
+ batch2.sort((a, b) => a._level - b._level);
397
+ }
398
+ pendingNeedSort = false;
399
+ for (let i = 0; i < batch2.length; i++) {
400
+ const e = batch2[i];
401
+ e._pending = false;
402
+ if (!e.disposed && !e._onNotify) {
403
+ const prevDepsLen = e.deps.length;
404
+ _runEffect(e);
405
+ if (!e._computed && e.deps.length !== prevDepsLen) {
406
+ _updateLevel(e);
407
+ }
403
408
  }
404
409
  }
410
+ iterations++;
405
411
  }
406
- iterations++;
407
- }
408
- if (iterations >= 25) {
409
- if (__DEV__) {
410
- const remaining = pendingEffects.slice(0, 3);
411
- const effectNames = remaining.map((e) => e.fn?.name || e.fn?.toString().slice(0, 60) || "(anonymous)");
412
- console.warn(
413
- `[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(", ")}`
414
- );
415
- } else {
416
- console.warn("[what] Possible infinite effect loop detected");
412
+ if (iterations >= 25) {
413
+ for (let i = 0; i < pendingEffects.length; i++) pendingEffects[i]._pending = false;
414
+ pendingEffects.length = 0;
415
+ if (__DEV__) {
416
+ const remaining = pendingEffects.slice(0, 3);
417
+ const effectNames = remaining.map((e) => e.fn?.name || e.fn?.toString().slice(0, 60) || "(anonymous)");
418
+ console.warn(
419
+ `[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(", ")}`
420
+ );
421
+ } else {
422
+ console.warn("[what] Possible infinite effect loop detected");
423
+ }
417
424
  }
418
- for (let i = 0; i < pendingEffects.length; i++) pendingEffects[i]._pending = false;
419
- pendingEffects.length = 0;
425
+ } finally {
426
+ isFlushing = false;
420
427
  }
421
428
  }
422
429
  function memo(fn) {
@@ -461,6 +468,22 @@ function memo(fn) {
461
468
  return read;
462
469
  }
463
470
  function flushSync() {
471
+ if (isFlushing) {
472
+ if (__DEV__) {
473
+ console.warn(
474
+ "[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."
475
+ );
476
+ }
477
+ return;
478
+ }
479
+ if (currentEffect) {
480
+ if (__DEV__) {
481
+ console.warn(
482
+ "[what] flushSync() called during effect execution. This is a no-op to prevent infinite loops. Move flushSync() to an event handler or onMount callback."
483
+ );
484
+ }
485
+ return;
486
+ }
464
487
  microtaskScheduled = false;
465
488
  flush();
466
489
  }
@@ -1372,8 +1395,8 @@ function createComponent(vnode, parent, isSvg) {
1372
1395
  function createErrorBoundary(vnode, parent) {
1373
1396
  const { errorState, handleError, fallback, reset } = vnode.props;
1374
1397
  const children = vnode.children;
1375
- const wrapper = document.createElement("span");
1376
- wrapper.style.display = "contents";
1398
+ const startComment = document.createComment("eb:start");
1399
+ const endComment = document.createComment("eb:end");
1377
1400
  const boundaryCtx = {
1378
1401
  hooks: [],
1379
1402
  hookIndex: 0,
@@ -1382,15 +1405,24 @@ function createErrorBoundary(vnode, parent) {
1382
1405
  mounted: false,
1383
1406
  disposed: false,
1384
1407
  _parentCtx: componentStack[componentStack.length - 1] || null,
1385
- _errorBoundary: handleError
1408
+ _errorBoundary: handleError,
1409
+ _startComment: startComment,
1410
+ _endComment: endComment
1386
1411
  };
1387
- wrapper._componentCtx = boundaryCtx;
1412
+ _commentCtxMap.set(startComment, boundaryCtx);
1413
+ const container = document.createDocumentFragment();
1414
+ container._componentCtx = boundaryCtx;
1415
+ container.appendChild(startComment);
1416
+ container.appendChild(endComment);
1388
1417
  const dispose = effect(() => {
1389
1418
  const error = errorState();
1390
1419
  componentStack.push(boundaryCtx);
1391
- while (wrapper.firstChild) {
1392
- disposeTree(wrapper.firstChild);
1393
- wrapper.removeChild(wrapper.firstChild);
1420
+ if (startComment.parentNode) {
1421
+ while (startComment.nextSibling && startComment.nextSibling !== endComment) {
1422
+ const old = startComment.nextSibling;
1423
+ disposeTree(old);
1424
+ old.parentNode.removeChild(old);
1425
+ }
1394
1426
  }
1395
1427
  let vnodes;
1396
1428
  if (error) {
@@ -1400,19 +1432,25 @@ function createErrorBoundary(vnode, parent) {
1400
1432
  }
1401
1433
  vnodes = Array.isArray(vnodes) ? vnodes : [vnodes];
1402
1434
  for (const v of vnodes) {
1403
- const node = createDOM(v, wrapper);
1404
- if (node) wrapper.appendChild(node);
1435
+ const node = createDOM(v, parent);
1436
+ if (node) {
1437
+ if (endComment.parentNode) {
1438
+ endComment.parentNode.insertBefore(node, endComment);
1439
+ } else {
1440
+ container.insertBefore(node, endComment);
1441
+ }
1442
+ }
1405
1443
  }
1406
1444
  componentStack.pop();
1407
1445
  });
1408
1446
  boundaryCtx.effects.push(dispose);
1409
- return wrapper;
1447
+ return container;
1410
1448
  }
1411
1449
  function createSuspenseBoundary(vnode, parent) {
1412
1450
  const { boundary, fallback, loading } = vnode.props;
1413
1451
  const children = vnode.children;
1414
- const wrapper = document.createElement("span");
1415
- wrapper.style.display = "contents";
1452
+ const startComment = document.createComment("sb:start");
1453
+ const endComment = document.createComment("sb:end");
1416
1454
  const boundaryCtx = {
1417
1455
  hooks: [],
1418
1456
  hookIndex: 0,
@@ -1420,26 +1458,41 @@ function createSuspenseBoundary(vnode, parent) {
1420
1458
  cleanups: [],
1421
1459
  mounted: false,
1422
1460
  disposed: false,
1423
- _parentCtx: componentStack[componentStack.length - 1] || null
1461
+ _parentCtx: componentStack[componentStack.length - 1] || null,
1462
+ _startComment: startComment,
1463
+ _endComment: endComment
1424
1464
  };
1425
- wrapper._componentCtx = boundaryCtx;
1465
+ _commentCtxMap.set(startComment, boundaryCtx);
1466
+ const container = document.createDocumentFragment();
1467
+ container._componentCtx = boundaryCtx;
1468
+ container.appendChild(startComment);
1469
+ container.appendChild(endComment);
1426
1470
  const dispose = effect(() => {
1427
1471
  const isLoading = loading();
1428
1472
  const vnodes = isLoading ? [fallback] : children;
1429
1473
  const normalized = Array.isArray(vnodes) ? vnodes : [vnodes];
1430
1474
  componentStack.push(boundaryCtx);
1431
- while (wrapper.firstChild) {
1432
- disposeTree(wrapper.firstChild);
1433
- wrapper.removeChild(wrapper.firstChild);
1475
+ if (startComment.parentNode) {
1476
+ while (startComment.nextSibling && startComment.nextSibling !== endComment) {
1477
+ const old = startComment.nextSibling;
1478
+ disposeTree(old);
1479
+ old.parentNode.removeChild(old);
1480
+ }
1434
1481
  }
1435
1482
  for (const v of normalized) {
1436
- const node = createDOM(v, wrapper);
1437
- if (node) wrapper.appendChild(node);
1483
+ const node = createDOM(v, parent);
1484
+ if (node) {
1485
+ if (endComment.parentNode) {
1486
+ endComment.parentNode.insertBefore(node, endComment);
1487
+ } else {
1488
+ container.insertBefore(node, endComment);
1489
+ }
1490
+ }
1438
1491
  }
1439
1492
  componentStack.pop();
1440
1493
  });
1441
1494
  boundaryCtx.effects.push(dispose);
1442
- return wrapper;
1495
+ return container;
1443
1496
  }
1444
1497
  function createPortalDOM(vnode, parent) {
1445
1498
  const { container } = vnode.props;
@@ -1789,6 +1842,12 @@ function sameNodeArray(a, b) {
1789
1842
  return true;
1790
1843
  }
1791
1844
  function reconcileInsert(parent, value, current, marker) {
1845
+ if (!parent || typeof parent.insertBefore !== "function") {
1846
+ if (__DEV__) {
1847
+ console.warn("[what] reconcileInsert called with invalid parent:", parent);
1848
+ }
1849
+ return current;
1850
+ }
1792
1851
  const targetMarker = marker || null;
1793
1852
  if (value == null || typeof value === "boolean") {
1794
1853
  const oldNodes2 = asNodeArray(current);
@@ -2302,6 +2361,12 @@ function spread(el, props) {
2302
2361
  }
2303
2362
  }
2304
2363
  function setProp2(el, key, value) {
2364
+ if (key === "ref") {
2365
+ if (typeof value === "function") value(el);
2366
+ else if (value && typeof value === "object") value.current = el;
2367
+ return;
2368
+ }
2369
+ if (key === "key") return;
2305
2370
  if (URL_ATTRS.has(key) || URL_ATTRS.has(key.toLowerCase())) {
2306
2371
  if (!isSafeUrl(value)) {
2307
2372
  if (typeof console !== "undefined") {
@@ -5703,7 +5768,7 @@ function levenshtein(a, b) {
5703
5768
  }
5704
5769
 
5705
5770
  // packages/core/src/agent-context.js
5706
- var VERSION = "0.5.6";
5771
+ var VERSION = "0.6.0";
5707
5772
  var mountedComponents2 = [];
5708
5773
  function registerComponent(component) {
5709
5774
  if (!__DEV__) return;