aberdeen 1.18.2 → 1.19.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.
Files changed (152) hide show
  1. package/README.md +9 -0
  2. package/dist/src/aberdeen.d.ts +27 -0
  3. package/{dist-docs/assets/aberdeen/aberdeen.js → dist/src/aberdeen.dev.js} +776 -15
  4. package/dist/src/aberdeen.dev.js.map +12 -0
  5. package/dist/src/aberdeen.js +59 -13
  6. package/dist/src/aberdeen.js.map +3 -3
  7. package/dist/src/devtools.d.ts +26 -0
  8. package/html-to-aberdeen +9 -5
  9. package/package.json +17 -10
  10. package/skill/A.md +127 -0
  11. package/skill/Dispatcher.md +51 -0
  12. package/skill/OPAQUE.md +15 -0
  13. package/skill/PromiseProxy.md +25 -0
  14. package/skill/Route.md +50 -0
  15. package/skill/SKILL.md +272 -156
  16. package/skill/applyCanon.md +20 -0
  17. package/skill/applyPrediction.md +15 -0
  18. package/skill/back.md +11 -0
  19. package/skill/clean.md +43 -0
  20. package/skill/clone.md +15 -0
  21. package/skill/copy.md +40 -0
  22. package/skill/count.md +32 -0
  23. package/skill/cssVars.md +15 -0
  24. package/skill/darkMode.md +26 -0
  25. package/skill/derive.md +56 -0
  26. package/skill/developer-tools.md +23 -0
  27. package/skill/disableCreateDestroy.md +11 -0
  28. package/skill/dump.md +37 -0
  29. package/skill/freeze.md +20 -0
  30. package/skill/full-example-multi-page-app.md +146 -0
  31. package/skill/go.md +25 -0
  32. package/skill/grow.md +13 -0
  33. package/skill/html-to-aberdeen.md +9 -0
  34. package/skill/insertCss.md +79 -0
  35. package/skill/insertGlobalCss.md +68 -0
  36. package/skill/interceptLinks.md +19 -0
  37. package/skill/invertString.md +32 -0
  38. package/skill/isEmpty.md +38 -0
  39. package/skill/map.md +16 -0
  40. package/skill/matchCurrent.md +27 -0
  41. package/skill/merge.md +27 -0
  42. package/skill/mount.md +48 -0
  43. package/skill/multiMap.md +15 -0
  44. package/skill/onEach.md +14 -0
  45. package/skill/partition.md +15 -0
  46. package/skill/peek.md +36 -0
  47. package/skill/persistScroll.md +13 -0
  48. package/skill/proxy.md +11 -0
  49. package/skill/push.md +13 -0
  50. package/skill/ref.md +39 -0
  51. package/skill/runQueue.md +34 -0
  52. package/skill/setErrorHandler.md +48 -0
  53. package/skill/setLog.md +9 -0
  54. package/skill/setSpacingCssVars.md +31 -0
  55. package/skill/shrink.md +13 -0
  56. package/skill/unmountAll.md +9 -0
  57. package/skill/unproxy.md +43 -0
  58. package/skill/up.md +13 -0
  59. package/src/aberdeen.ts +194 -73
  60. package/src/devtools.ts +685 -0
  61. package/dist-docs/.nojekyll +0 -1
  62. package/dist-docs/Tutorial/index.html +0 -305
  63. package/dist-docs/aberdeen/A/index.html +0 -116
  64. package/dist-docs/aberdeen/CUSTOM_DUMP/index.html +0 -7
  65. package/dist-docs/aberdeen/NO_COPY/index.html +0 -2
  66. package/dist-docs/aberdeen/OPAQUE/index.html +0 -12
  67. package/dist-docs/aberdeen/PromiseProxy/index.html +0 -8
  68. package/dist-docs/aberdeen/clean/index.html +0 -11
  69. package/dist-docs/aberdeen/clone/index.html +0 -5
  70. package/dist-docs/aberdeen/copy/index.html +0 -22
  71. package/dist-docs/aberdeen/count/index.html +0 -7
  72. package/dist-docs/aberdeen/cssVars/index.html +0 -11
  73. package/dist-docs/aberdeen/darkMode/index.html +0 -9
  74. package/dist-docs/aberdeen/default/index.html +0 -342
  75. package/dist-docs/aberdeen/derive/index.html +0 -18
  76. package/dist-docs/aberdeen/disableCreateDestroy/index.html +0 -6
  77. package/dist-docs/aberdeen/dump/index.html +0 -11
  78. package/dist-docs/aberdeen/index.html +0 -54
  79. package/dist-docs/aberdeen/insertCss/index.html +0 -30
  80. package/dist-docs/aberdeen/insertGlobalCss/index.html +0 -19
  81. package/dist-docs/aberdeen/invertString/index.html +0 -13
  82. package/dist-docs/aberdeen/isEmpty/index.html +0 -12
  83. package/dist-docs/aberdeen/map/index.html +0 -26
  84. package/dist-docs/aberdeen/merge/index.html +0 -11
  85. package/dist-docs/aberdeen/mount/index.html +0 -17
  86. package/dist-docs/aberdeen/multiMap/index.html +0 -28
  87. package/dist-docs/aberdeen/onEach/index.html +0 -19
  88. package/dist-docs/aberdeen/partition/index.html +0 -36
  89. package/dist-docs/aberdeen/peek/index.html +0 -40
  90. package/dist-docs/aberdeen/proxy/index.html +0 -35
  91. package/dist-docs/aberdeen/ref/index.html +0 -13
  92. package/dist-docs/aberdeen/runQueue/index.html +0 -13
  93. package/dist-docs/aberdeen/setErrorHandler/index.html +0 -16
  94. package/dist-docs/aberdeen/setSpacingCssVars/index.html +0 -8
  95. package/dist-docs/aberdeen/unmountAll/index.html +0 -5
  96. package/dist-docs/aberdeen/unproxy/index.html +0 -11
  97. package/dist-docs/assets/aberdeen/aberdeen.d.ts +0 -963
  98. package/dist-docs/assets/aberdeen/aberdeen.js.map +0 -11
  99. package/dist-docs/assets/aberdeen/dispatcher.d.ts +0 -57
  100. package/dist-docs/assets/aberdeen/dispatcher.js +0 -66
  101. package/dist-docs/assets/aberdeen/dispatcher.js.map +0 -10
  102. package/dist-docs/assets/aberdeen/helpers/reverseSortedSet.d.ts +0 -96
  103. package/dist-docs/assets/aberdeen/prediction.d.ts +0 -33
  104. package/dist-docs/assets/aberdeen/prediction.js +0 -112
  105. package/dist-docs/assets/aberdeen/prediction.js.map +0 -10
  106. package/dist-docs/assets/aberdeen/route.d.ts +0 -137
  107. package/dist-docs/assets/aberdeen/route.js +0 -287
  108. package/dist-docs/assets/aberdeen/route.js.map +0 -10
  109. package/dist-docs/assets/aberdeen/transitions.d.ts +0 -18
  110. package/dist-docs/assets/aberdeen/transitions.js +0 -47
  111. package/dist-docs/assets/aberdeen/transitions.js.map +0 -10
  112. package/dist-docs/assets/custom.js +0 -573
  113. package/dist-docs/assets/favicon.png +0 -0
  114. package/dist-docs/assets/hierarchy.js +0 -1
  115. package/dist-docs/assets/highlight.css +0 -134
  116. package/dist-docs/assets/icons.js +0 -18
  117. package/dist-docs/assets/icons.svg +0 -1
  118. package/dist-docs/assets/main.js +0 -60
  119. package/dist-docs/assets/navigation.js +0 -1
  120. package/dist-docs/assets/search.js +0 -1
  121. package/dist-docs/assets/style.css +0 -1640
  122. package/dist-docs/dispatcher/Dispatcher/index.html +0 -21
  123. package/dist-docs/dispatcher/MATCH_FAILED/index.html +0 -2
  124. package/dist-docs/dispatcher/MATCH_REST/index.html +0 -2
  125. package/dist-docs/dispatcher/index.html +0 -4
  126. package/dist-docs/hierarchy.html +0 -1
  127. package/dist-docs/index.html +0 -61
  128. package/dist-docs/media/CHANGELOG.md +0 -266
  129. package/dist-docs/modules.html +0 -1
  130. package/dist-docs/prediction/applyCanon/index.html +0 -13
  131. package/dist-docs/prediction/applyPrediction/index.html +0 -8
  132. package/dist-docs/prediction/index.html +0 -9
  133. package/dist-docs/route/Route/index.html +0 -23
  134. package/dist-docs/route/back/index.html +0 -4
  135. package/dist-docs/route/current/index.html +0 -2
  136. package/dist-docs/route/go/index.html +0 -14
  137. package/dist-docs/route/index.html +0 -15
  138. package/dist-docs/route/interceptLinks/index.html +0 -8
  139. package/dist-docs/route/matchCurrent/index.html +0 -10
  140. package/dist-docs/route/persistScroll/index.html +0 -6
  141. package/dist-docs/route/push/index.html +0 -6
  142. package/dist-docs/route/setLog/index.html +0 -3
  143. package/dist-docs/route/up/index.html +0 -5
  144. package/dist-docs/sitemap.xml +0 -239
  145. package/dist-docs/transitions/grow/index.html +0 -6
  146. package/dist-docs/transitions/index.html +0 -5
  147. package/dist-docs/transitions/shrink/index.html +0 -6
  148. package/skill/aberdeen.md +0 -4586
  149. package/skill/dispatcher.md +0 -129
  150. package/skill/prediction.md +0 -73
  151. package/skill/route.md +0 -322
  152. package/skill/transitions.md +0 -59
@@ -101,6 +101,7 @@ class ReverseSortedSet {
101
101
  // src/aberdeen.ts
102
102
  var sortedQueue;
103
103
  var runQueueDepth = 0;
104
+ var freezeCount = 0;
104
105
  var topRedrawScope;
105
106
  var survivingEl;
106
107
  function recordSideEffect(scope, type, key, value) {
@@ -145,6 +146,8 @@ function queue(runner) {
145
146
  sortedQueue.add(runner);
146
147
  }
147
148
  function runQueue() {
149
+ if (freezeCount)
150
+ return;
148
151
  let time = Date.now();
149
152
  while (sortedQueue) {
150
153
  const runner = sortedQueue.fetchLast();
@@ -160,6 +163,17 @@ function runQueue() {
160
163
  if (time > 9)
161
164
  console.debug(`Aberdeen queue took ${time}ms`);
162
165
  }
166
+ function freeze() {
167
+ freezeCount++;
168
+ let released = false;
169
+ return () => {
170
+ if (released)
171
+ return;
172
+ released = true;
173
+ if (!--freezeCount)
174
+ runQueue();
175
+ };
176
+ }
163
177
  function arrayToStr(parts) {
164
178
  let result = "";
165
179
  for (const part of parts) {
@@ -248,6 +262,7 @@ class ContentScope extends Scope {
248
262
  if (!this.changes) {
249
263
  this.changes = new Map;
250
264
  queue(this);
265
+ dev?.schedule(this, index, oldData, newData, new Error);
251
266
  }
252
267
  let targetDelta = this.changes.get(target);
253
268
  if (!targetDelta) {
@@ -305,6 +320,7 @@ class ChainedScope extends ContentScope {
305
320
  }
306
321
  if (!useParentCleaners)
307
322
  currentScope.cleaners.push(this);
323
+ dev?.create(this, currentScope, new Error);
308
324
  }
309
325
  getPrecedingNode() {
310
326
  return findLastNodeInPrevSiblings(this.prevSibling);
@@ -324,6 +340,7 @@ class RegularScope extends ChainedScope {
324
340
  redraw() {
325
341
  const savedScope = currentScope;
326
342
  currentScope = this;
343
+ dev?.render(this);
327
344
  try {
328
345
  this.renderer();
329
346
  } catch (e) {
@@ -350,6 +367,7 @@ class MountScope extends ContentScope {
350
367
  this.el = el;
351
368
  this.renderer = renderer;
352
369
  this.svg = el.namespaceURI === "http://www.w3.org/2000/svg";
370
+ dev?.create(this, currentScope, new Error);
353
371
  const oldTopRedrawScope = topRedrawScope;
354
372
  topRedrawScope = this;
355
373
  this.redraw();
@@ -454,6 +472,7 @@ class OnEachScope extends Scope {
454
472
  this.prevSibling = currentScope.getChildPrevSibling();
455
473
  currentScope.lastChild = this;
456
474
  currentScope.cleaners.push(this);
475
+ dev?.create(this, currentScope, new Error);
457
476
  if (target instanceof Array) {
458
477
  for (let i = 0;i < target.length; i++) {
459
478
  new OnEachItemScope(this, i, false);
@@ -484,8 +503,10 @@ class OnEachScope extends Scope {
484
503
  this.changedIndexes = new Map;
485
504
  for (const index of indexes.keys()) {
486
505
  const oldScope = this.byIndex.get(index);
487
- if (oldScope)
506
+ if (oldScope) {
488
507
  oldScope.remove();
508
+ dev?.delete(oldScope);
509
+ }
489
510
  if (this.target instanceof Set || this.target instanceof Map ? this.target.has(index) : (index in this.target)) {
490
511
  new OnEachItemScope(this, index, true);
491
512
  } else {
@@ -527,6 +548,7 @@ class OnEachItemScope extends ContentScope {
527
548
  this.svg = currentScope.svg;
528
549
  this.parent.byIndex.set(this.itemIndex, this);
529
550
  this.lastChild = this;
551
+ dev?.create(this, this.parent, new Error);
530
552
  if (topRedraw)
531
553
  topRedrawScope = this;
532
554
  this.redraw();
@@ -585,6 +607,7 @@ class OnEachItemScope extends ContentScope {
585
607
  }
586
608
  const savedScope = currentScope;
587
609
  currentScope = this;
610
+ dev?.render(this);
588
611
  let sortKey;
589
612
  try {
590
613
  if (this.parent.makeSortKey) {
@@ -629,15 +652,31 @@ class OnEachItemScope extends ContentScope {
629
652
  function addNode(el, node) {
630
653
  if (el !== currentScope.el) {
631
654
  el.appendChild(node);
655
+ dev?.node(currentScope, node, false);
632
656
  return;
633
657
  }
634
658
  const parentEl = currentScope.el;
635
659
  const prevNode = currentScope.getInsertAfterNode();
636
660
  parentEl.insertBefore(node, prevNode ? prevNode.nextSibling : parentEl.firstChild);
637
661
  currentScope.lastChild = node;
662
+ dev?.node(currentScope, node, true);
638
663
  }
639
664
  var ROOT_SCOPE = new RootScope;
640
665
  var currentScope = ROOT_SCOPE;
666
+ var dev;
667
+ function _setDev(hooks) {
668
+ dev = hooks;
669
+ if (!hooks)
670
+ return;
671
+ const childScopes = (scope) => scope instanceof OnEachScope ? [...scope.byIndex.values()] : scope.cleaners.filter((c) => c instanceof Scope);
672
+ const replay = (scope, parent) => {
673
+ hooks.create(scope, parent, undefined);
674
+ for (const child of childScopes(scope))
675
+ replay(child, scope);
676
+ };
677
+ for (const child of childScopes(ROOT_SCOPE))
678
+ replay(child, ROOT_SCOPE);
679
+ }
641
680
  function leakScope(func) {
642
681
  const savedScope = currentScope;
643
682
  currentScope = new RootScope;
@@ -655,6 +694,8 @@ var peeking = 0;
655
694
  function subscribe(target, index, observer = currentScope) {
656
695
  if (observer === ROOT_SCOPE || peeking)
657
696
  return;
697
+ if (observer === currentScope)
698
+ dev?.read(currentScope, target, index);
658
699
  let byTarget = subscribers.get(target);
659
700
  if (!byTarget)
660
701
  subscribers.set(target, byTarget = new Map);
@@ -1560,12 +1601,22 @@ function insertCss(style) {
1560
1601
  const prefix = `.AbdStl${++cssCount}`;
1561
1602
  const css = typeof style === "string" ? styleStringToCss(style, prefix) : objectToCss(style, prefix);
1562
1603
  if (css) {
1563
- let cnt = cssSnippetCount++;
1564
- cssSnippets[cnt] = css;
1565
- clean(() => delete cssSnippets[cnt]);
1604
+ const cnt = cssSnippetCount++;
1605
+ const key = arrayToStr([currentScope.prio, cnt]);
1606
+ cssSnippets[key] = css;
1607
+ clean(() => delete cssSnippets[key]);
1566
1608
  }
1567
1609
  return prefix;
1568
1610
  }
1611
+ function insertGlobalCss(style) {
1612
+ const css = objectToCss(style, "");
1613
+ if (css) {
1614
+ const cnt = cssSnippetCount++;
1615
+ const key = arrayToStr([currentScope.prio, cnt]);
1616
+ cssSnippets[key] = css;
1617
+ clean(() => delete cssSnippets[key]);
1618
+ }
1619
+ }
1569
1620
  var cssSnippets = proxy({});
1570
1621
  var cssSnippetCount = 0;
1571
1622
  function combinePrefixSelector(prefix, key) {
@@ -1637,14 +1688,6 @@ function styleStringToCss(styleStr, selector) {
1637
1688
  return props ? `${selector}{${props}}
1638
1689
  ` : "";
1639
1690
  }
1640
- function insertGlobalCss(style) {
1641
- const css = objectToCss(style, "");
1642
- if (css) {
1643
- let cnt = cssSnippetCount++;
1644
- cssSnippets[cnt] = css;
1645
- clean(() => delete cssSnippets[cnt]);
1646
- }
1647
- }
1648
1691
  var CSS_SHORT = {
1649
1692
  m: "margin",
1650
1693
  mt: "margin-top",
@@ -1938,6 +1981,7 @@ var aberdeen_default = Object.assign(A, {
1938
1981
  derive,
1939
1982
  disableCreateDestroy,
1940
1983
  dump,
1984
+ freeze,
1941
1985
  insertCss,
1942
1986
  insertGlobalCss,
1943
1987
  invertString,
@@ -1959,6 +2003,721 @@ var aberdeen_default = Object.assign(A, {
1959
2003
  unmountAll,
1960
2004
  unproxy
1961
2005
  });
2006
+
2007
+ // src/devtools.ts
2008
+ var devtools_default = aberdeen_default;
2009
+ var tool;
2010
+ function activate() {
2011
+ if (tool)
2012
+ return;
2013
+ try {
2014
+ Error.stackTraceLimit = 50;
2015
+ } catch {}
2016
+ const t = new DevTools;
2017
+ tool = t;
2018
+ _setDev(t);
2019
+ }
2020
+ var TYPES = {
2021
+ RegularScope: { label: "scope", color: "#34d399" },
2022
+ MountScope: { label: "mount", color: "#60a5fa" },
2023
+ OnEachScope: { label: "onEach", color: "#c084fc" },
2024
+ OnEachItemScope: { label: "item", color: "#f472b6" },
2025
+ ResultScope: { label: "derive", color: "#fbbf24" },
2026
+ SetArgScope: { label: "attr", color: "#94a3b8" },
2027
+ RootScope: { label: "root", color: "#64748b" }
2028
+ };
2029
+ var typeInfo = (t) => TYPES[t] || { label: t, color: "#cbd5e1" };
2030
+ var STYLE = `
2031
+ /* Whole overlay tree is click-through (pointer-events inherits); only the dialog opts in. */
2032
+ :host { all: initial; position: fixed; top: 0; left: 0; pointer-events: none; }
2033
+ * { box-sizing: border-box; font-family: ui-monospace, monospace; }
2034
+
2035
+ .box { position: fixed; pointer-events: none; border-radius: 2px; z-index: 2147483000; }
2036
+ .box.parent { border: 2px dotted #f59e0b; background: rgba(245,158,11,.06); }
2037
+ .box.child { border: 2px solid #34d399; background: rgba(52,211,153,.10); }
2038
+
2039
+ .dlg {
2040
+ position: fixed; left: 16px; top: 16px; width: 660px; max-width: 95vw; height: 480px; max-height: 90vh;
2041
+ background: #1e1b2e; color: #ede9fe; border: 1px solid #6d28d9; border-radius: 8px;
2042
+ box-shadow: 0 10px 36px rgba(0,0,0,.6); display: flex; flex-direction: column;
2043
+ font-size: 12px; pointer-events: auto; z-index: 2147483600; /* above the highlight boxes */
2044
+ }
2045
+ .hd { display: flex; align-items: center; justify-content: space-between; gap: 10px;
2046
+ padding: 6px 6px 6px 12px; border-bottom: 1px solid #4c1d95; cursor: move; user-select: none; }
2047
+ .hd .title { font-weight: bold; color: #c4b5fd; }
2048
+ .hd .x { cursor: pointer; color: #c4b5fd; padding: 2px 8px; border-radius: 4px; }
2049
+ .hd .x:hover { background: #6d28d9; color: #fff; }
2050
+ .cols { display: flex; flex: 1; min-height: 0; }
2051
+ .left { width: 56%; display: flex; flex-direction: column; min-width: 0; border-right: 1px solid #4c1d95; }
2052
+ .right { width: 44%; overflow: auto; padding: 8px 10px; }
2053
+
2054
+ .menu { display: flex; flex-wrap: wrap; gap: 6px; padding: 6px 8px; border-bottom: 1px solid #2e2a40; }
2055
+ .menu button { font: inherit; background: #2e2a40; color: #ddd6fe; border: 1px solid #4c1d95;
2056
+ border-radius: 5px; padding: 3px 8px; cursor: pointer; }
2057
+ .menu button:hover { background: #6d28d9; }
2058
+ .menu button.on { background: #6d28d9; color: #fff; }
2059
+
2060
+ .tree { flex: 1; overflow: auto; padding: 4px 0; }
2061
+ .node { white-space: nowrap; display: flex; align-items: center; gap: 6px; padding: 1px 8px; cursor: pointer; }
2062
+ .node:hover { background: #312a4a; }
2063
+ .node.sel { background: #4c1d95; }
2064
+ .node .tw { width: 12px; color: #94a3b8; text-align: center; flex: none; }
2065
+ .badge { flex: none; font-size: 10px; padding: 0 5px; border-radius: 3px; color: #0b0a12; font-weight: bold; }
2066
+ .node .loc { color: #e2e8f0; overflow: hidden; text-overflow: ellipsis; }
2067
+ .node .t { color: #8b82a8; flex: none; }
2068
+
2069
+ .right h4 { margin: 0 0 6px; color: #c4b5fd; font-size: 12px; }
2070
+ .right .row { margin-bottom: 3px; }
2071
+ .right .k { color: #94a3b8; }
2072
+ .sec { color: #a78bfa; font-weight: bold; font-size: 10px; text-transform: uppercase; letter-spacing: .06em;
2073
+ margin: 12px 0 5px; border-bottom: 1px solid #3a3450; padding-bottom: 3px; }
2074
+ .loclink { color: #93c5fd; cursor: pointer; text-decoration: underline dotted; }
2075
+ .loclink:hover { color: #c4d9ff; }
2076
+ .logbtn { font: inherit; font-size: 10px; background: #2e2a40; color: #ddd6fe; border: 1px solid #4c1d95;
2077
+ border-radius: 4px; padding: 0 6px; cursor: pointer; }
2078
+ .logbtn:hover { background: #6d28d9; }
2079
+ .stack { white-space: pre-wrap; color: #cbd5e1; font-size: 11px; line-height: 1.5; margin-top: 2px;
2080
+ border-left: 2px solid #3a3450; padding-left: 6px; }
2081
+ .muted { color: #64748b; }
2082
+ .reads .key { color: #fbbf24; } .reads .val { color: #93c5fd; }
2083
+ .empty { color: #64748b; padding: 16px; text-align: center; white-space: pre-line; line-height: 1.5; }
2084
+ `;
2085
+ var lastPos;
2086
+
2087
+ class DevTools {
2088
+ root = { id: 0, scope: null, type: "RootScope", parent: undefined, children: [], createdTime: 0, renderCount: 0, topNodes: [] };
2089
+ scopeMap = new WeakMap;
2090
+ pending = new WeakMap;
2091
+ nodeMap = new WeakMap;
2092
+ elOwner = new WeakMap;
2093
+ origin = -1;
2094
+ nextId = 1;
2095
+ host = document.createElement("div");
2096
+ shadow;
2097
+ overlay;
2098
+ dlg;
2099
+ treeEl;
2100
+ rightEl;
2101
+ menuEl;
2102
+ mode = "tree";
2103
+ selectedId;
2104
+ collapsed = new Set;
2105
+ recentSince = 0;
2106
+ boxes = [];
2107
+ thaw;
2108
+ altPressed = false;
2109
+ rebuildScheduled = false;
2110
+ lastX = -1;
2111
+ lastY = -1;
2112
+ constructor() {
2113
+ this.shadow = this.host.attachShadow({ mode: "open" });
2114
+ const style = document.createElement("style");
2115
+ style.textContent = STYLE;
2116
+ this.shadow.appendChild(style);
2117
+ this.overlay = eln("div");
2118
+ this.shadow.appendChild(this.overlay);
2119
+ this.buildDialog();
2120
+ document.body.appendChild(this.host);
2121
+ this.positionDialog();
2122
+ this.renderEmptyDetails();
2123
+ window.addEventListener("keydown", this.onKeyDown, true);
2124
+ window.addEventListener("keyup", this.onKeyUp, true);
2125
+ window.addEventListener("blur", this.onBlur, true);
2126
+ window.addEventListener("pointermove", this.onPointerMove, true);
2127
+ window.addEventListener("scroll", this.reposition, true);
2128
+ window.addEventListener("resize", this.reposition, true);
2129
+ }
2130
+ destroy() {
2131
+ this.savePos();
2132
+ window.removeEventListener("keydown", this.onKeyDown, true);
2133
+ window.removeEventListener("keyup", this.onKeyUp, true);
2134
+ window.removeEventListener("blur", this.onBlur, true);
2135
+ window.removeEventListener("pointermove", this.onPointerMove, true);
2136
+ window.removeEventListener("scroll", this.reposition, true);
2137
+ window.removeEventListener("resize", this.reposition, true);
2138
+ this.clearBoxes();
2139
+ if (this.thaw)
2140
+ this.thaw();
2141
+ this.host.remove();
2142
+ tool = undefined;
2143
+ _setDev(undefined);
2144
+ }
2145
+ stamp() {
2146
+ const now = performance.now();
2147
+ if (this.origin < 0)
2148
+ this.origin = now;
2149
+ return now - this.origin;
2150
+ }
2151
+ create(scope, parentScope, err) {
2152
+ const parent = this.scopeMap.get(parentScope) || this.root;
2153
+ const d = {
2154
+ id: ++this.nextId,
2155
+ scope,
2156
+ type: scope.constructor.name,
2157
+ parent,
2158
+ children: [],
2159
+ el: scope.el instanceof Element ? scope.el : undefined,
2160
+ createdTime: err ? this.stamp() : undefined,
2161
+ createError: err,
2162
+ renderCount: 0,
2163
+ topNodes: []
2164
+ };
2165
+ this.scopeMap.set(scope, d);
2166
+ parent.children.push(d);
2167
+ if (d.el)
2168
+ this.elOwner.set(d.el, d);
2169
+ this.scheduleRebuild();
2170
+ }
2171
+ render(scope) {
2172
+ const d = this.scopeMap.get(scope);
2173
+ if (!d)
2174
+ return;
2175
+ d.children.length = 0;
2176
+ d.topNodes = [];
2177
+ d.subs = [];
2178
+ const p = this.pending.get(scope);
2179
+ if (p) {
2180
+ d.renderTime = this.stamp();
2181
+ d.renderCount++;
2182
+ d.renderError = p.error;
2183
+ d.renderChange = p.change;
2184
+ this.pending.delete(scope);
2185
+ }
2186
+ this.scheduleRebuild();
2187
+ }
2188
+ schedule(scope, index, oldData, newData, err) {
2189
+ this.pending.set(scope, { change: { index, oldData, newData }, error: err });
2190
+ }
2191
+ node(scope, node, top) {
2192
+ const d = this.scopeMap.get(scope);
2193
+ if (!d)
2194
+ return;
2195
+ this.nodeMap.set(node, d);
2196
+ if (top)
2197
+ d.topNodes.push(node);
2198
+ }
2199
+ read(scope, target, index) {
2200
+ const d = this.scopeMap.get(scope);
2201
+ if (d) {
2202
+ d.subs ||= [];
2203
+ if (d.subs.length < 500)
2204
+ d.subs.push([target, index]);
2205
+ }
2206
+ }
2207
+ delete(scope) {
2208
+ const d = this.scopeMap.get(scope);
2209
+ if (!d)
2210
+ return;
2211
+ if (d.parent) {
2212
+ const i = d.parent.children.indexOf(d);
2213
+ if (i >= 0)
2214
+ d.parent.children.splice(i, 1);
2215
+ }
2216
+ this.scopeMap.delete(scope);
2217
+ this.scheduleRebuild();
2218
+ }
2219
+ buildDialog() {
2220
+ this.dlg = eln("div", "dlg");
2221
+ const hd = eln("div", "hd");
2222
+ hd.appendChild(eln("div", "title", "Aberdeen dev tools"));
2223
+ const x = eln("div", "x", "✕");
2224
+ x.addEventListener("click", () => this.destroy());
2225
+ hd.appendChild(x);
2226
+ this.dlg.appendChild(hd);
2227
+ this.setupDrag(hd);
2228
+ const cols = eln("div", "cols");
2229
+ const left = eln("div", "left");
2230
+ this.menuEl = eln("div", "menu");
2231
+ this.treeEl = eln("div", "tree");
2232
+ left.appendChild(this.menuEl);
2233
+ left.appendChild(this.treeEl);
2234
+ this.rightEl = eln("div", "right");
2235
+ cols.appendChild(left);
2236
+ cols.appendChild(this.rightEl);
2237
+ this.dlg.appendChild(cols);
2238
+ this.shadow.appendChild(this.dlg);
2239
+ this.buildMenu();
2240
+ }
2241
+ positionDialog() {
2242
+ const m = 16;
2243
+ const w = this.dlg.offsetWidth, h = this.dlg.offsetHeight;
2244
+ const left = lastPos ? lastPos.left : Math.max(m, window.innerWidth - w - m);
2245
+ const top = lastPos ? lastPos.top : Math.max(m, window.innerHeight - h - m);
2246
+ this.dlg.style.left = left + "px";
2247
+ this.dlg.style.top = top + "px";
2248
+ }
2249
+ savePos() {
2250
+ lastPos = { left: this.dlg.offsetLeft, top: this.dlg.offsetTop };
2251
+ }
2252
+ buildMenu() {
2253
+ this.menuEl.textContent = "";
2254
+ const btn = (label, on, fn) => {
2255
+ const b = eln("button", on ? "on" : undefined, label);
2256
+ b.addEventListener("click", () => {
2257
+ fn();
2258
+ this.buildMenu();
2259
+ });
2260
+ this.menuEl.appendChild(b);
2261
+ };
2262
+ btn("Tree", this.mode === "tree", () => {
2263
+ this.mode = "tree";
2264
+ this.rebuild();
2265
+ });
2266
+ btn("Recent", this.mode === "recent", () => {
2267
+ this.mode = "recent";
2268
+ this.rebuild();
2269
+ });
2270
+ btn("Freeze", !!this.thaw, () => {
2271
+ if (this.thaw) {
2272
+ this.thaw();
2273
+ this.thaw = undefined;
2274
+ } else
2275
+ this.thaw = aberdeen_default.freeze();
2276
+ });
2277
+ if (this.mode === "recent")
2278
+ btn("Clear", false, () => {
2279
+ this.recentSince = this.lastEventTime();
2280
+ this.rebuild();
2281
+ });
2282
+ this.menuEl.appendChild(eln("span", "muted", " Alt-hover an element to select its scope"));
2283
+ }
2284
+ lastEventTime() {
2285
+ let max = 0;
2286
+ const walk = (d) => {
2287
+ if (d.renderTime != null && d.renderTime > max)
2288
+ max = d.renderTime;
2289
+ d.children.forEach(walk);
2290
+ };
2291
+ this.root.children.forEach(walk);
2292
+ return max;
2293
+ }
2294
+ scheduleRebuild() {
2295
+ if (this.rebuildScheduled)
2296
+ return;
2297
+ this.rebuildScheduled = true;
2298
+ requestAnimationFrame(() => {
2299
+ this.rebuildScheduled = false;
2300
+ this.rebuild();
2301
+ });
2302
+ }
2303
+ rebuild() {
2304
+ const scrollTop = this.treeEl.scrollTop;
2305
+ this.treeEl.textContent = "";
2306
+ if (this.mode === "tree") {
2307
+ for (const child of this.root.children)
2308
+ this.renderNode(child, 0);
2309
+ if (!this.root.children.length)
2310
+ this.treeEl.appendChild(eln("div", "empty", "No live scopes yet."));
2311
+ } else {
2312
+ this.renderRecent();
2313
+ }
2314
+ this.treeEl.scrollTop = scrollTop;
2315
+ const d = this.selectedId != null ? this.findScope(this.selectedId) : undefined;
2316
+ if (d) {
2317
+ this.renderDetails(d);
2318
+ this.highlight(d);
2319
+ } else {
2320
+ this.selectedId = undefined;
2321
+ this.clearBoxes();
2322
+ this.renderEmptyDetails();
2323
+ }
2324
+ }
2325
+ renderEmptyDetails() {
2326
+ if (this.rightEl.firstElementChild?.classList.contains("empty"))
2327
+ return;
2328
+ this.rightEl.textContent = "";
2329
+ this.rightEl.appendChild(eln("div", "empty", `No scope selected.
2330
+
2331
+ Click a scope in the tree — or hold Alt and hover an element on the page to select the scope that drew it.`));
2332
+ }
2333
+ renderRecent() {
2334
+ const all = [];
2335
+ const walk = (d) => {
2336
+ if (d.renderTime != null && d.renderTime > this.recentSince)
2337
+ all.push(d);
2338
+ d.children.forEach(walk);
2339
+ };
2340
+ this.root.children.forEach(walk);
2341
+ all.sort((x, y) => y.renderTime - x.renderTime);
2342
+ if (!all.length) {
2343
+ this.treeEl.appendChild(eln("div", "empty", "No re-renders observed yet."));
2344
+ return;
2345
+ }
2346
+ for (const d of all.slice(0, 60)) {
2347
+ const row = eln("div", "node" + (d.id === this.selectedId ? " sel" : ""));
2348
+ row.dataset.id = String(d.id);
2349
+ row.style.paddingLeft = "8px";
2350
+ const info = typeInfo(d.type);
2351
+ const badge = eln("span", "badge", info.label);
2352
+ badge.style.background = info.color;
2353
+ row.appendChild(badge);
2354
+ row.appendChild(eln("span", "loc", d.renderChange ? changeSummary(d.renderChange) : appFrame(d.createError) || d.type));
2355
+ row.appendChild(eln("span", "t", ms(d.renderTime, 0)));
2356
+ row.addEventListener("click", () => this.select(d));
2357
+ row.addEventListener("pointerenter", () => this.highlight(d));
2358
+ row.addEventListener("pointerleave", () => this.highlight(this.selectedId != null ? this.findScope(this.selectedId) : undefined));
2359
+ this.treeEl.appendChild(row);
2360
+ }
2361
+ }
2362
+ renderNode(d, depth) {
2363
+ const row = eln("div", "node" + (d.id === this.selectedId ? " sel" : ""));
2364
+ row.dataset.id = String(d.id);
2365
+ row.style.paddingLeft = 8 + depth * 14 + "px";
2366
+ const hasKids = d.children.length > 0;
2367
+ const tw = eln("div", "tw", hasKids ? this.collapsed.has(d.id) ? "▸" : "▾" : "");
2368
+ if (hasKids)
2369
+ tw.addEventListener("click", (e) => {
2370
+ e.stopPropagation();
2371
+ if (this.collapsed.has(d.id))
2372
+ this.collapsed.delete(d.id);
2373
+ else
2374
+ this.collapsed.add(d.id);
2375
+ this.rebuild();
2376
+ });
2377
+ row.appendChild(tw);
2378
+ const info = typeInfo(d.type);
2379
+ const badge = eln("span", "badge", info.label);
2380
+ badge.style.background = info.color;
2381
+ row.appendChild(badge);
2382
+ row.appendChild(eln("span", "loc", appFrame(d.createError) || (d.createError === undefined ? "(pre-open)" : "(internal)")));
2383
+ if (d.createdTime != null)
2384
+ row.appendChild(eln("span", "t", ms(d.createdTime, 0)));
2385
+ row.addEventListener("click", () => this.select(d));
2386
+ row.addEventListener("pointerenter", () => this.highlight(d));
2387
+ row.addEventListener("pointerleave", () => this.highlight(this.selectedId != null ? this.findScope(this.selectedId) : undefined));
2388
+ this.treeEl.appendChild(row);
2389
+ if (hasKids && !this.collapsed.has(d.id))
2390
+ for (const c of d.children)
2391
+ this.renderNode(c, depth + 1);
2392
+ }
2393
+ findScope(id, node = this.root) {
2394
+ if (node.id === id)
2395
+ return node;
2396
+ for (const c of node.children) {
2397
+ const r = this.findScope(id, c);
2398
+ if (r)
2399
+ return r;
2400
+ }
2401
+ return;
2402
+ }
2403
+ select(d) {
2404
+ this.selectedId = d ? d.id : undefined;
2405
+ for (const el of this.treeEl.querySelectorAll(".node.sel"))
2406
+ el.classList.remove("sel");
2407
+ if (!d) {
2408
+ this.renderEmptyDetails();
2409
+ this.clearBoxes();
2410
+ return;
2411
+ }
2412
+ const row = this.treeEl.querySelector(`.node[data-id="${d.id}"]`);
2413
+ if (row) {
2414
+ row.classList.add("sel");
2415
+ row.scrollIntoView({ block: "nearest" });
2416
+ }
2417
+ this.renderDetails(d);
2418
+ this.highlight(d);
2419
+ }
2420
+ renderDetails(d) {
2421
+ const r = this.rightEl;
2422
+ r.textContent = "";
2423
+ const info = typeInfo(d.type);
2424
+ const head = eln("h4");
2425
+ const badge = eln("span", "badge", info.label);
2426
+ badge.style.background = info.color;
2427
+ head.appendChild(badge);
2428
+ head.appendChild(document.createTextNode(" " + d.type));
2429
+ r.appendChild(head);
2430
+ r.appendChild(kv("owned nodes", String(d.topNodes.length)));
2431
+ r.appendChild(kv("child scopes", String(d.children.length)));
2432
+ if (d.type === "OnEachItemScope" && d.scope)
2433
+ r.appendChild(renderItemValue(d.scope));
2434
+ if (d.subs && d.subs.length)
2435
+ r.appendChild(this.renderReads(d));
2436
+ r.appendChild(section("Creation"));
2437
+ r.appendChild(kv("time", d.createdTime != null ? ms(d.createdTime) : "unknown"));
2438
+ r.appendChild(stackRow("stack", d.createError, "unknown"));
2439
+ if (!d.createError)
2440
+ r.appendChild(eln("div", "muted", "Reload with ?abdev=1 to capture creation stacks."));
2441
+ r.appendChild(section("Last trigger"));
2442
+ if (d.renderTime != null) {
2443
+ r.appendChild(kv("time", ms(d.renderTime) + " (" + d.renderCount + "×)"));
2444
+ if (d.renderChange)
2445
+ r.appendChild(kv("change", changeSummary(d.renderChange)));
2446
+ r.appendChild(stackRow("stack", d.renderError, "(no application frame)"));
2447
+ } else {
2448
+ r.appendChild(eln("div", "muted", "not triggered yet"));
2449
+ }
2450
+ }
2451
+ renderReads(d) {
2452
+ const wrap = eln("div", "row reads");
2453
+ wrap.appendChild(eln("div", "k", "observing:"));
2454
+ const groups = new Map;
2455
+ for (const [obj, key] of d.subs) {
2456
+ let s = groups.get(obj);
2457
+ if (!s)
2458
+ groups.set(obj, s = new Set);
2459
+ s.add(key);
2460
+ }
2461
+ if (!groups.size) {
2462
+ wrap.appendChild(eln("div", "muted", "(none)"));
2463
+ return wrap;
2464
+ }
2465
+ let n = 0;
2466
+ for (const [obj, keys] of groups) {
2467
+ if (n++ > 16) {
2468
+ wrap.appendChild(eln("div", "muted", "…"));
2469
+ break;
2470
+ }
2471
+ const line = eln("div");
2472
+ line.appendChild(document.createTextNode("{ "));
2473
+ let first = true;
2474
+ for (const k of [...keys].slice(0, 16)) {
2475
+ if (!first)
2476
+ line.appendChild(document.createTextNode(", "));
2477
+ first = false;
2478
+ line.appendChild(eln("span", "key", readKey(k)));
2479
+ if (typeof k !== "symbol") {
2480
+ line.appendChild(document.createTextNode("="));
2481
+ let v;
2482
+ try {
2483
+ v = obj[k];
2484
+ } catch {
2485
+ v = "?";
2486
+ }
2487
+ line.appendChild(eln("span", "val", preview(v)));
2488
+ }
2489
+ }
2490
+ line.appendChild(document.createTextNode(" }"));
2491
+ wrap.appendChild(line);
2492
+ }
2493
+ return wrap;
2494
+ }
2495
+ highlight(d) {
2496
+ this.clearBoxes();
2497
+ if (!d)
2498
+ return;
2499
+ if (d.el instanceof Element)
2500
+ this.box(d.el.getBoundingClientRect(), "parent");
2501
+ for (const n of d.topNodes)
2502
+ if (n instanceof Element)
2503
+ this.box(n.getBoundingClientRect(), "child");
2504
+ for (const c of d.children)
2505
+ this.box(regionRect(c), "child");
2506
+ }
2507
+ box(rect, kind) {
2508
+ if (!rect || !rect.width && !rect.height)
2509
+ return;
2510
+ const b = eln("div", "box " + kind);
2511
+ Object.assign(b.style, { left: rect.left + "px", top: rect.top + "px", width: rect.width + "px", height: rect.height + "px" });
2512
+ this.overlay.appendChild(b);
2513
+ this.boxes.push(b);
2514
+ }
2515
+ clearBoxes() {
2516
+ for (const b of this.boxes)
2517
+ b.remove();
2518
+ this.boxes.length = 0;
2519
+ }
2520
+ reposition = () => {
2521
+ const d = this.selectedId != null ? this.findScope(this.selectedId) : undefined;
2522
+ if (d)
2523
+ this.highlight(d);
2524
+ };
2525
+ overUI(t) {
2526
+ return !(t instanceof Node) || t === this.host || this.host.contains(t);
2527
+ }
2528
+ onKeyDown = (e) => {
2529
+ if (e.key === "Alt") {
2530
+ this.altPressed = true;
2531
+ this.resolveAt(this.lastX, this.lastY);
2532
+ } else if (e.key === "Escape") {
2533
+ e.preventDefault();
2534
+ this.destroy();
2535
+ }
2536
+ };
2537
+ onKeyUp = (e) => {
2538
+ if (e.key === "Alt")
2539
+ this.altPressed = false;
2540
+ };
2541
+ onBlur = () => {
2542
+ this.altPressed = false;
2543
+ };
2544
+ onPointerMove = (e) => {
2545
+ this.lastX = e.clientX;
2546
+ this.lastY = e.clientY;
2547
+ if (this.altPressed)
2548
+ this.resolveAt(this.lastX, this.lastY);
2549
+ };
2550
+ resolveAt(x, y) {
2551
+ if (x < 0)
2552
+ return;
2553
+ const target = document.elementFromPoint(x, y);
2554
+ if (!target || this.overUI(target))
2555
+ return;
2556
+ let node = target;
2557
+ let d;
2558
+ while (node) {
2559
+ d = (node instanceof Element ? this.elOwner.get(node) : undefined) || this.nodeMap.get(node);
2560
+ if (d)
2561
+ break;
2562
+ node = node.parentNode;
2563
+ }
2564
+ if (d && d.id !== this.selectedId)
2565
+ this.select(d);
2566
+ }
2567
+ setupDrag(handle) {
2568
+ let sx = 0, sy = 0, ox = 0, oy = 0, down = false;
2569
+ handle.addEventListener("pointerdown", (e) => {
2570
+ if (e.target.classList.contains("x"))
2571
+ return;
2572
+ down = true;
2573
+ sx = e.clientX;
2574
+ sy = e.clientY;
2575
+ ox = this.dlg.offsetLeft;
2576
+ oy = this.dlg.offsetTop;
2577
+ handle.setPointerCapture(e.pointerId);
2578
+ });
2579
+ handle.addEventListener("pointermove", (e) => {
2580
+ if (!down)
2581
+ return;
2582
+ this.dlg.style.left = Math.max(0, Math.min(window.innerWidth - 80, ox + e.clientX - sx)) + "px";
2583
+ this.dlg.style.top = Math.max(0, Math.min(window.innerHeight - 24, oy + e.clientY - sy)) + "px";
2584
+ });
2585
+ handle.addEventListener("pointerup", () => {
2586
+ down = false;
2587
+ this.savePos();
2588
+ });
2589
+ }
2590
+ }
2591
+ function eln(tag, cls, text) {
2592
+ const e = document.createElement(tag);
2593
+ if (cls)
2594
+ e.className = cls;
2595
+ if (text != null)
2596
+ e.textContent = text;
2597
+ return e;
2598
+ }
2599
+ function kv(k, v) {
2600
+ const row = eln("div", "row");
2601
+ row.appendChild(eln("span", "k", k + ": "));
2602
+ row.appendChild(document.createTextNode(v));
2603
+ return row;
2604
+ }
2605
+ function section(title) {
2606
+ return eln("div", "sec", title);
2607
+ }
2608
+ function stackRow(label, err, emptyMsg) {
2609
+ const row = eln("div", "row");
2610
+ row.appendChild(eln("span", "k", label + ": "));
2611
+ const full = formatStack(err && err.stack);
2612
+ if (!full) {
2613
+ row.appendChild(eln("span", "muted", emptyMsg));
2614
+ return row;
2615
+ }
2616
+ const link = eln("span", "loclink", appFrame(err) || "(internal)");
2617
+ const pre = eln("div", "stack");
2618
+ pre.textContent = full;
2619
+ pre.style.display = "none";
2620
+ link.addEventListener("click", () => {
2621
+ pre.style.display = pre.style.display ? "" : "none";
2622
+ });
2623
+ row.appendChild(link);
2624
+ row.appendChild(pre);
2625
+ return row;
2626
+ }
2627
+ function readKey(k) {
2628
+ if (typeof k !== "symbol")
2629
+ return String(k);
2630
+ return k.description === "any" ? "*" : k.description === "mapSize" ? "size" : k.description || "?";
2631
+ }
2632
+ function changeSummary(c) {
2633
+ return `${readKey(c.index)}: ${preview(c.oldData)} → ${preview(c.newData)}`;
2634
+ }
2635
+ function renderItemValue(scope) {
2636
+ const target = scope.parent?.target;
2637
+ const idx = scope.itemIndex;
2638
+ const isSet = target instanceof Set;
2639
+ const value = isSet ? idx : target instanceof Map ? target.get(idx) : target ? target[idx] : undefined;
2640
+ const wrap = eln("div", "row");
2641
+ if (!isSet)
2642
+ wrap.appendChild(kv("key", String(idx)));
2643
+ const line = eln("div");
2644
+ line.appendChild(eln("span", "k", "value: "));
2645
+ line.appendChild(eln("span", "val", preview(value)));
2646
+ const btn = eln("button", "logbtn", "to console");
2647
+ btn.addEventListener("click", () => console.log(value));
2648
+ line.appendChild(document.createTextNode(" "));
2649
+ line.appendChild(btn);
2650
+ wrap.appendChild(line);
2651
+ return wrap;
2652
+ }
2653
+ function ms(t, dp = 1) {
2654
+ return "+" + t.toLocaleString(undefined, { minimumFractionDigits: dp, maximumFractionDigits: dp }) + "ms";
2655
+ }
2656
+ function preview(v) {
2657
+ if (v === null)
2658
+ return "null";
2659
+ if (typeof v === "string")
2660
+ return JSON.stringify(v.length > 30 ? v.slice(0, 30) + "…" : v);
2661
+ if (typeof v === "object")
2662
+ return Array.isArray(v) ? `[${v.length}]` : "{…}";
2663
+ if (typeof v === "function")
2664
+ return "fn";
2665
+ return String(v);
2666
+ }
2667
+ function deepNodes(d, out = []) {
2668
+ for (const n of d.topNodes)
2669
+ out.push(n);
2670
+ for (const c of d.children)
2671
+ deepNodes(c, out);
2672
+ return out;
2673
+ }
2674
+ function regionRect(d) {
2675
+ let l = Infinity, t = Infinity, r = -Infinity, b = -Infinity;
2676
+ for (const n of deepNodes(d)) {
2677
+ if (!(n instanceof Element))
2678
+ continue;
2679
+ const q = n.getBoundingClientRect();
2680
+ if (!q.width && !q.height)
2681
+ continue;
2682
+ l = Math.min(l, q.left);
2683
+ t = Math.min(t, q.top);
2684
+ r = Math.max(r, q.right);
2685
+ b = Math.max(b, q.bottom);
2686
+ }
2687
+ if (l === Infinity)
2688
+ return;
2689
+ return new DOMRect(l, t, r - l, b - t);
2690
+ }
2691
+ function appFrame(err) {
2692
+ const s = formatStack(err && err.stack);
2693
+ if (!s)
2694
+ return "";
2695
+ const first = s.split(`
2696
+ `)[0];
2697
+ const m = first.match(/([^\/\\(]+):(\d+):\d+\)?$/);
2698
+ return m ? `${m[1]}:${m[2]}` : first.replace(/^at\s+/, "");
2699
+ }
2700
+ function formatStack(stack) {
2701
+ if (!stack)
2702
+ return "";
2703
+ const origin = location.protocol + "//" + location.host;
2704
+ return stack.split(`
2705
+ `).map((l) => l.trim().split(origin).join("")).filter((l) => (l.startsWith("at ") || l.includes("@")) && !/aberdeen(\.dev)?\.[jt]s|devtools\.[jt]s/.test(l)).join(`
2706
+ `);
2707
+ }
2708
+ if (typeof window !== "undefined" && typeof document !== "undefined") {
2709
+ if (/[?&]abdev=1\b/.test(location.search))
2710
+ activate();
2711
+ window.addEventListener("keydown", (e) => {
2712
+ if ((e.ctrlKey || e.metaKey) && e.altKey && e.code === "KeyA") {
2713
+ e.preventDefault();
2714
+ if (tool)
2715
+ tool.destroy();
2716
+ else
2717
+ activate();
2718
+ }
2719
+ });
2720
+ }
1962
2721
  export {
1963
2722
  withEmitHandler,
1964
2723
  unproxy,
@@ -1980,17 +2739,19 @@ export {
1980
2739
  invertString,
1981
2740
  insertGlobalCss,
1982
2741
  insertCss,
2742
+ freeze,
1983
2743
  dump,
1984
2744
  disableCreateDestroy,
1985
2745
  derive,
1986
2746
  defaultEmitHandler,
1987
- aberdeen_default as default,
2747
+ devtools_default as default,
1988
2748
  darkMode,
1989
2749
  cssVars,
1990
2750
  count,
1991
2751
  copy,
1992
2752
  clone,
1993
2753
  clean,
2754
+ _setDev,
1994
2755
  OPAQUE,
1995
2756
  NO_COPY,
1996
2757
  MAP_SIZE_SYMBOL,
@@ -1999,5 +2760,5 @@ export {
1999
2760
  A
2000
2761
  };
2001
2762
 
2002
- //# debugId=3B000DCA54AF8FFA64756E2164756E21
2003
- //# sourceMappingURL=aberdeen.js.map
2763
+ //# debugId=5E581450DD669A5F64756E2164756E21
2764
+ //# sourceMappingURL=aberdeen.dev.js.map