marko 6.3.15 → 6.3.17

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright 2024 eBay Inc. and contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -30,6 +30,7 @@ export declare enum AccessorProp {
30
30
  Id = "L",
31
31
  Load = "X",
32
32
  LoopKey = "M",
33
+ LoopIndex = "I",
33
34
  ParentBranch = "N",
34
35
  PendingEffects = "J",
35
36
  PendingRenders = "W",
@@ -30,6 +30,7 @@ export declare enum AccessorProp {
30
30
  Id = "#Id",
31
31
  Load = "#Load",
32
32
  LoopKey = "#LoopKey",
33
+ LoopIndex = "#LoopIndex",
33
34
  ParentBranch = "#ParentBranch",
34
35
  PendingEffects = "#PendingEffects",
35
36
  PendingRenders = "#PendingRenders",
@@ -1,6 +1,8 @@
1
1
  export declare function assertValidAttrValue(name: string, value: unknown): void;
2
2
  export declare function assertValidTextValue(value: unknown): void;
3
3
  export declare function assertValidLoopKey(key: unknown, seenKeys?: Set<unknown>): void;
4
+ export declare function assertValidList(value: unknown): void;
5
+ export declare function assertValidRangeBound(name: string, value: unknown): void;
4
6
  export declare function assertValidAttrName(name: string): void;
5
7
  export declare function _el_read_error(): void;
6
8
  export declare function _hoist_read_error(): void;
@@ -50,7 +50,6 @@ export declare enum NodeType {
50
50
  }
51
51
  export declare enum WalkCode {
52
52
  Get = 32,
53
- Inside = 36,
54
53
  Replace = 37,
55
54
  EndChild = 38,
56
55
  BeginChild = 47,
package/dist/debug/dom.js CHANGED
@@ -159,6 +159,15 @@ function assertValidLoopKey(key, seenKeys) {
159
159
  seenKeys.add(key);
160
160
  }
161
161
  }
162
+ function assertValidList(value) {
163
+ if (value && typeof value[Symbol.iterator] !== "function") throw new Error(`A \`<for>\` tag's \`of\` attribute must be an iterable, such as an array, but received ${describeForValue(value)}.`);
164
+ }
165
+ function assertValidRangeBound(name, value) {
166
+ if (!isFinite(value)) throw new Error(`A \`<for>\` tag's \`${name}\` attribute must be a finite number, but received ${describeForValue(value)}.`);
167
+ }
168
+ function describeForValue(value) {
169
+ return typeof value === "number" || typeof value === "bigint" ? `\`${value}\`` : value === null ? "null" : `type "${typeof value}"`;
170
+ }
162
171
  function assertValidAttrName(name) {
163
172
  if (htmlAttrNameReg.test(name)) throw new Error(`Invalid attribute name: ${JSON.stringify(name)}`);
164
173
  const suggestion = getWrongAttrSuggestion(name);
@@ -211,17 +220,20 @@ function forIn(obj, cb) {
211
220
  for (const key in obj) cb(key, obj[key]);
212
221
  }
213
222
  function forOf(list, cb) {
223
+ assertValidList(list);
214
224
  if (list) {
215
225
  let i = 0;
216
226
  for (const item of list) cb(item, i++);
217
227
  }
218
228
  }
219
229
  function forTo(to, from, step, cb) {
230
+ assertValidRangeBound("to", to);
220
231
  const start = from || 0;
221
232
  const delta = step || 1;
222
233
  for (let steps = (to - start) / delta, i = 0; i <= steps; i++) cb(start + i * delta);
223
234
  }
224
235
  function forUntil(until, from, step, cb) {
236
+ assertValidRangeBound("until", until);
225
237
  const start = from || 0;
226
238
  const delta = step || 1;
227
239
  for (let steps = (until - start) / delta, i = 0; i < steps; i++) cb(start + i * delta);
@@ -979,9 +991,12 @@ function _attr_input_checkedValue_script(scope, nodeAccessor) {
979
991
  if (checkedValueChange) {
980
992
  const controlledValueKey = "ControlledValue:" + nodeAccessor;
981
993
  const oldValue = scope[controlledValueKey];
982
- const newValue = Array.isArray(oldValue) ? updateList(oldValue, el.value, el.checked) : el.checked ? el.value : void 0;
994
+ let newValue = Array.isArray(oldValue) ? updateList(oldValue, el.value, el.checked) : el.checked ? el.value : void 0;
983
995
  if (el.name && el.type[0] === "r") {
984
- for (const radio of document.querySelectorAll(`[type=radio][name=${CSS.escape(el.name)}]`)) if (radio.form === el.form) radio.checked = Array.isArray(oldValue) ? oldValue.includes(radio.value) : controlledValueKey in scope ? oldValue === radio.value : radio.defaultChecked;
996
+ for (const radio of document.querySelectorAll(`[type=radio][name=${CSS.escape(el.name)}]`)) if (radio.form === el.form) {
997
+ if (newValue === void 0 && radio.defaultChecked) newValue = radio.value;
998
+ radio.checked = Array.isArray(oldValue) ? oldValue.includes(radio.value) : controlledValueKey in scope ? oldValue === radio.value : radio.defaultChecked;
999
+ }
985
1000
  } else el.checked = !el.checked;
986
1001
  checkedValueChange(newValue);
987
1002
  run();
@@ -1488,7 +1503,9 @@ function _await_promise(nodeAccessor, params) {
1488
1503
  }
1489
1504
  }, (error) => {
1490
1505
  if (thisPromise === scope[promiseAccessor]) {
1491
- awaitCounter.i = scope[promiseAccessor] = 0;
1506
+ scope[promiseAccessor] = 0;
1507
+ if (tryPlaceholder && !awaitCounter.m) awaitCounter.c();
1508
+ else awaitCounter.i = 0;
1492
1509
  queueAsyncRender(scope, renderCatch, error);
1493
1510
  }
1494
1511
  });
@@ -1721,12 +1738,17 @@ function loop(forEach) {
1721
1738
  const parentNode = referenceNode.nodeType > 1 ? referenceNode.parentNode || oldScopes[0]?.["#StartNode"].parentNode : referenceNode;
1722
1739
  let oldScopesByKey;
1723
1740
  let hasPotentialMoves;
1741
+ let start = 0;
1724
1742
  var seenKeys = /* @__PURE__ */ new Set();
1725
1743
  forEach(value, (key, args) => {
1726
1744
  assertValidLoopKey(key, seenKeys);
1727
- let branch = oldLen && (oldScopesByKey ||= oldScopes.reduce((map, scope, i) => map.set(scope["#LoopKey"] ?? i, scope), /* @__PURE__ */ new Map())).get(key);
1728
- if (branch) hasPotentialMoves = oldScopesByKey.delete(key);
1729
- else branch = createAndSetupBranch(scope["$global"], renderer, scope, parentNode);
1745
+ const i = newScopes.length;
1746
+ const oldScope = oldScopes[i];
1747
+ let branch = oldLen && (oldScopesByKey || key !== (oldScope?.["#LoopKey"] ?? i) ? (oldScopesByKey ||= oldScopes.reduce((map, scope, j) => j < i ? map : (scope["#LoopIndex"] = j, map.set(scope["#LoopKey"] ?? j, scope)), /* @__PURE__ */ new Map())).get(key) : oldScope && (start++, oldScope));
1748
+ if (branch) {
1749
+ hasPotentialMoves = true;
1750
+ oldScopesByKey?.delete(key);
1751
+ } else branch = createAndSetupBranch(scope["$global"], renderer, scope, parentNode);
1730
1752
  branch["#LoopKey"] = key;
1731
1753
  newScopes.push(branch);
1732
1754
  params?.(branch, args);
@@ -1736,7 +1758,6 @@ function loop(forEach) {
1736
1758
  let afterReference = null;
1737
1759
  let oldEnd = oldLen - 1;
1738
1760
  let newEnd = newLen - 1;
1739
- let start = 0;
1740
1761
  if (hasSiblings) {
1741
1762
  if (oldLen) {
1742
1763
  afterReference = oldScopes[oldEnd]["#EndNode"].nextSibling;
@@ -1754,19 +1775,18 @@ function loop(forEach) {
1754
1775
  for (const newScope of newScopes) insertBranchBefore(newScope, parentNode, afterReference);
1755
1776
  return;
1756
1777
  }
1757
- for (const branch of oldScopesByKey.values()) removeAndDestroyBranch(branch);
1758
- while (start < oldLen && start < newLen && oldScopes[start] === newScopes[start]) start++;
1778
+ if (oldScopesByKey) oldScopesByKey.forEach(removeAndDestroyBranch);
1779
+ else for (let i = newLen; i < oldLen; i++) removeAndDestroyBranch(oldScopes[i]);
1759
1780
  while (oldEnd >= start && newEnd >= start && oldScopes[oldEnd] === newScopes[newEnd]) {
1760
1781
  oldEnd--;
1761
1782
  newEnd--;
1762
1783
  }
1763
1784
  if (oldEnd + 1 < oldLen) afterReference = oldScopes[oldEnd + 1]["#StartNode"];
1764
- if (start > oldEnd) {
1765
- if (start <= newEnd) for (let i = start; i <= newEnd; i++) insertBranchBefore(newScopes[i], parentNode, afterReference);
1785
+ if (start > oldEnd || start > newEnd) {
1786
+ for (let i = start; i <= newEnd; i++) insertBranchBefore(newScopes[i], parentNode, afterReference);
1766
1787
  return;
1767
- } else if (start > newEnd) return;
1788
+ }
1768
1789
  const diffLen = newEnd - start + 1;
1769
- const oldPos = /* @__PURE__ */ new Map();
1770
1790
  const sources = new Array(diffLen);
1771
1791
  const pred = new Array(diffLen);
1772
1792
  const tails = [];
@@ -1774,8 +1794,7 @@ function loop(forEach) {
1774
1794
  let lo;
1775
1795
  let hi;
1776
1796
  let mid;
1777
- for (let i = start; i <= oldEnd; i++) oldPos.set(oldScopes[i], i);
1778
- for (let i = diffLen; i--;) sources[i] = oldPos.get(newScopes[start + i]) ?? -1;
1797
+ for (let i = diffLen; i--;) sources[i] = newScopes[start + i]["#LoopIndex"] ?? -1;
1779
1798
  for (let i = 0; i < diffLen; i++) if (~sources[i]) if (tail < 0 || sources[tails[tail]] < sources[i]) {
1780
1799
  if (~tail) pred[i] = tails[tail];
1781
1800
  tails[++tail] = i;
@@ -2205,7 +2224,8 @@ function insertLoaded(renderer, branch, marker, awaitCounter) {
2205
2224
  }
2206
2225
  function loadFailed(scope, awaitCounter) {
2207
2226
  return (error) => {
2208
- if (awaitCounter) awaitCounter.i = 0;
2227
+ if (awaitCounter) if (awaitCounter.m) awaitCounter.i = 0;
2228
+ else awaitCounter.c();
2209
2229
  queueAsyncRender(scope, renderCatch, error);
2210
2230
  };
2211
2231
  }
@@ -157,6 +157,15 @@ function assertValidLoopKey(key, seenKeys) {
157
157
  seenKeys.add(key);
158
158
  }
159
159
  }
160
+ function assertValidList(value) {
161
+ if (value && typeof value[Symbol.iterator] !== "function") throw new Error(`A \`<for>\` tag's \`of\` attribute must be an iterable, such as an array, but received ${describeForValue(value)}.`);
162
+ }
163
+ function assertValidRangeBound(name, value) {
164
+ if (!isFinite(value)) throw new Error(`A \`<for>\` tag's \`${name}\` attribute must be a finite number, but received ${describeForValue(value)}.`);
165
+ }
166
+ function describeForValue(value) {
167
+ return typeof value === "number" || typeof value === "bigint" ? `\`${value}\`` : value === null ? "null" : `type "${typeof value}"`;
168
+ }
160
169
  function assertValidAttrName(name) {
161
170
  if (htmlAttrNameReg.test(name)) throw new Error(`Invalid attribute name: ${JSON.stringify(name)}`);
162
171
  const suggestion = getWrongAttrSuggestion(name);
@@ -209,17 +218,20 @@ function forIn(obj, cb) {
209
218
  for (const key in obj) cb(key, obj[key]);
210
219
  }
211
220
  function forOf(list, cb) {
221
+ assertValidList(list);
212
222
  if (list) {
213
223
  let i = 0;
214
224
  for (const item of list) cb(item, i++);
215
225
  }
216
226
  }
217
227
  function forTo(to, from, step, cb) {
228
+ assertValidRangeBound("to", to);
218
229
  const start = from || 0;
219
230
  const delta = step || 1;
220
231
  for (let steps = (to - start) / delta, i = 0; i <= steps; i++) cb(start + i * delta);
221
232
  }
222
233
  function forUntil(until, from, step, cb) {
234
+ assertValidRangeBound("until", until);
223
235
  const start = from || 0;
224
236
  const delta = step || 1;
225
237
  for (let steps = (until - start) / delta, i = 0; i < steps; i++) cb(start + i * delta);
@@ -977,9 +989,12 @@ function _attr_input_checkedValue_script(scope, nodeAccessor) {
977
989
  if (checkedValueChange) {
978
990
  const controlledValueKey = "ControlledValue:" + nodeAccessor;
979
991
  const oldValue = scope[controlledValueKey];
980
- const newValue = Array.isArray(oldValue) ? updateList(oldValue, el.value, el.checked) : el.checked ? el.value : void 0;
992
+ let newValue = Array.isArray(oldValue) ? updateList(oldValue, el.value, el.checked) : el.checked ? el.value : void 0;
981
993
  if (el.name && el.type[0] === "r") {
982
- for (const radio of document.querySelectorAll(`[type=radio][name=${CSS.escape(el.name)}]`)) if (radio.form === el.form) radio.checked = Array.isArray(oldValue) ? oldValue.includes(radio.value) : controlledValueKey in scope ? oldValue === radio.value : radio.defaultChecked;
994
+ for (const radio of document.querySelectorAll(`[type=radio][name=${CSS.escape(el.name)}]`)) if (radio.form === el.form) {
995
+ if (newValue === void 0 && radio.defaultChecked) newValue = radio.value;
996
+ radio.checked = Array.isArray(oldValue) ? oldValue.includes(radio.value) : controlledValueKey in scope ? oldValue === radio.value : radio.defaultChecked;
997
+ }
983
998
  } else el.checked = !el.checked;
984
999
  checkedValueChange(newValue);
985
1000
  run();
@@ -1486,7 +1501,9 @@ function _await_promise(nodeAccessor, params) {
1486
1501
  }
1487
1502
  }, (error) => {
1488
1503
  if (thisPromise === scope[promiseAccessor]) {
1489
- awaitCounter.i = scope[promiseAccessor] = 0;
1504
+ scope[promiseAccessor] = 0;
1505
+ if (tryPlaceholder && !awaitCounter.m) awaitCounter.c();
1506
+ else awaitCounter.i = 0;
1490
1507
  queueAsyncRender(scope, renderCatch, error);
1491
1508
  }
1492
1509
  });
@@ -1719,12 +1736,17 @@ function loop(forEach) {
1719
1736
  const parentNode = referenceNode.nodeType > 1 ? referenceNode.parentNode || oldScopes[0]?.["#StartNode"].parentNode : referenceNode;
1720
1737
  let oldScopesByKey;
1721
1738
  let hasPotentialMoves;
1739
+ let start = 0;
1722
1740
  var seenKeys = /* @__PURE__ */ new Set();
1723
1741
  forEach(value, (key, args) => {
1724
1742
  assertValidLoopKey(key, seenKeys);
1725
- let branch = oldLen && (oldScopesByKey ||= oldScopes.reduce((map, scope, i) => map.set(scope["#LoopKey"] ?? i, scope), /* @__PURE__ */ new Map())).get(key);
1726
- if (branch) hasPotentialMoves = oldScopesByKey.delete(key);
1727
- else branch = createAndSetupBranch(scope["$global"], renderer, scope, parentNode);
1743
+ const i = newScopes.length;
1744
+ const oldScope = oldScopes[i];
1745
+ let branch = oldLen && (oldScopesByKey || key !== (oldScope?.["#LoopKey"] ?? i) ? (oldScopesByKey ||= oldScopes.reduce((map, scope, j) => j < i ? map : (scope["#LoopIndex"] = j, map.set(scope["#LoopKey"] ?? j, scope)), /* @__PURE__ */ new Map())).get(key) : oldScope && (start++, oldScope));
1746
+ if (branch) {
1747
+ hasPotentialMoves = true;
1748
+ oldScopesByKey?.delete(key);
1749
+ } else branch = createAndSetupBranch(scope["$global"], renderer, scope, parentNode);
1728
1750
  branch["#LoopKey"] = key;
1729
1751
  newScopes.push(branch);
1730
1752
  params?.(branch, args);
@@ -1734,7 +1756,6 @@ function loop(forEach) {
1734
1756
  let afterReference = null;
1735
1757
  let oldEnd = oldLen - 1;
1736
1758
  let newEnd = newLen - 1;
1737
- let start = 0;
1738
1759
  if (hasSiblings) {
1739
1760
  if (oldLen) {
1740
1761
  afterReference = oldScopes[oldEnd]["#EndNode"].nextSibling;
@@ -1752,19 +1773,18 @@ function loop(forEach) {
1752
1773
  for (const newScope of newScopes) insertBranchBefore(newScope, parentNode, afterReference);
1753
1774
  return;
1754
1775
  }
1755
- for (const branch of oldScopesByKey.values()) removeAndDestroyBranch(branch);
1756
- while (start < oldLen && start < newLen && oldScopes[start] === newScopes[start]) start++;
1776
+ if (oldScopesByKey) oldScopesByKey.forEach(removeAndDestroyBranch);
1777
+ else for (let i = newLen; i < oldLen; i++) removeAndDestroyBranch(oldScopes[i]);
1757
1778
  while (oldEnd >= start && newEnd >= start && oldScopes[oldEnd] === newScopes[newEnd]) {
1758
1779
  oldEnd--;
1759
1780
  newEnd--;
1760
1781
  }
1761
1782
  if (oldEnd + 1 < oldLen) afterReference = oldScopes[oldEnd + 1]["#StartNode"];
1762
- if (start > oldEnd) {
1763
- if (start <= newEnd) for (let i = start; i <= newEnd; i++) insertBranchBefore(newScopes[i], parentNode, afterReference);
1783
+ if (start > oldEnd || start > newEnd) {
1784
+ for (let i = start; i <= newEnd; i++) insertBranchBefore(newScopes[i], parentNode, afterReference);
1764
1785
  return;
1765
- } else if (start > newEnd) return;
1786
+ }
1766
1787
  const diffLen = newEnd - start + 1;
1767
- const oldPos = /* @__PURE__ */ new Map();
1768
1788
  const sources = new Array(diffLen);
1769
1789
  const pred = new Array(diffLen);
1770
1790
  const tails = [];
@@ -1772,8 +1792,7 @@ function loop(forEach) {
1772
1792
  let lo;
1773
1793
  let hi;
1774
1794
  let mid;
1775
- for (let i = start; i <= oldEnd; i++) oldPos.set(oldScopes[i], i);
1776
- for (let i = diffLen; i--;) sources[i] = oldPos.get(newScopes[start + i]) ?? -1;
1795
+ for (let i = diffLen; i--;) sources[i] = newScopes[start + i]["#LoopIndex"] ?? -1;
1777
1796
  for (let i = 0; i < diffLen; i++) if (~sources[i]) if (tail < 0 || sources[tails[tail]] < sources[i]) {
1778
1797
  if (~tail) pred[i] = tails[tail];
1779
1798
  tails[++tail] = i;
@@ -2203,7 +2222,8 @@ function insertLoaded(renderer, branch, marker, awaitCounter) {
2203
2222
  }
2204
2223
  function loadFailed(scope, awaitCounter) {
2205
2224
  return (error) => {
2206
- if (awaitCounter) awaitCounter.i = 0;
2225
+ if (awaitCounter) if (awaitCounter.m) awaitCounter.i = 0;
2226
+ else awaitCounter.c();
2207
2227
  queueAsyncRender(scope, renderCatch, error);
2208
2228
  };
2209
2229
  }
@@ -158,6 +158,15 @@ function assertValidLoopKey(key, seenKeys) {
158
158
  seenKeys.add(key);
159
159
  }
160
160
  }
161
+ function assertValidList(value) {
162
+ if (value && typeof value[Symbol.iterator] !== "function") throw new Error(`A \`<for>\` tag's \`of\` attribute must be an iterable, such as an array, but received ${describeForValue(value)}.`);
163
+ }
164
+ function assertValidRangeBound(name, value) {
165
+ if (!isFinite(value)) throw new Error(`A \`<for>\` tag's \`${name}\` attribute must be a finite number, but received ${describeForValue(value)}.`);
166
+ }
167
+ function describeForValue(value) {
168
+ return typeof value === "number" || typeof value === "bigint" ? `\`${value}\`` : value === null ? "null" : `type "${typeof value}"`;
169
+ }
161
170
  function assertValidAttrName(name) {
162
171
  if (htmlAttrNameReg.test(name)) throw new Error(`Invalid attribute name: ${JSON.stringify(name)}`);
163
172
  const suggestion = getWrongAttrSuggestion(name);
@@ -230,8 +239,8 @@ function _escape_script(val) {
230
239
  assertValidTextValue(val);
231
240
  return val ? escapeScriptStr(val + "") : val === 0 ? "0" : "";
232
241
  }
233
- const unsafeStyleReg = /<\/style/gi;
234
- const escapeStyleStr = (str) => unsafeStyleReg.test(str) ? str.replace(unsafeStyleReg, "\\3C/style") : str;
242
+ const unsafeStyleReg = /<(\/style)/gi;
243
+ const escapeStyleStr = (str) => unsafeStyleReg.test(str) ? str.replace(unsafeStyleReg, "\\3C$1") : str;
235
244
  function _escape_style(val) {
236
245
  assertValidTextValue(val);
237
246
  return val ? escapeStyleStr(val + "") : val === 0 ? "0" : "";
@@ -897,11 +906,18 @@ function writeDate(state, val) {
897
906
  state.buf.push("new Date(" + +val + ")");
898
907
  return true;
899
908
  }
900
- const unsafeRegExpSourceReg = /\\[\s\S]|</g;
901
- const replaceUnsafeRegExpSourceChar = (match) => match === "<" || match === "\\<" ? "\\x3C" : match;
909
+ const unsafeRegExpSourceReg = /\\[\s\S]|[<\0\ud800-\udfff]/gu;
910
+ const unsafeRegExpSourceDetect = /[<\0\ud800-\udfff]/u;
911
+ const replaceUnsafeRegExpSourceChar = (match) => {
912
+ const ch = match.length === 3 ? "" : match[match.length - 1];
913
+ if (ch === "<") return "\\x3C";
914
+ if (ch === "\0") return "\\x00";
915
+ const code = ch.charCodeAt(0);
916
+ return code >= 55296 && code <= 57343 ? "\\u" + code.toString(16).padStart(4, "0") : match;
917
+ };
902
918
  function writeRegExp(state, val) {
903
919
  const { source } = val;
904
- state.buf.push("/" + (source.includes("<") ? source.replace(unsafeRegExpSourceReg, replaceUnsafeRegExpSourceChar) : source) + "/" + val.flags);
920
+ state.buf.push("/" + (unsafeRegExpSourceDetect.test(source) ? source.replace(unsafeRegExpSourceReg, replaceUnsafeRegExpSourceChar) : source) + "/" + val.flags);
905
921
  return true;
906
922
  }
907
923
  function writePromise(state, val, ref) {
@@ -1528,17 +1544,20 @@ function forIn(obj, cb) {
1528
1544
  for (const key in obj) cb(key, obj[key]);
1529
1545
  }
1530
1546
  function forOf(list, cb) {
1547
+ assertValidList(list);
1531
1548
  if (list) {
1532
1549
  let i = 0;
1533
1550
  for (const item of list) cb(item, i++);
1534
1551
  }
1535
1552
  }
1536
1553
  function forTo(to, from, step, cb) {
1554
+ assertValidRangeBound("to", to);
1537
1555
  const start = from || 0;
1538
1556
  const delta = step || 1;
1539
1557
  for (let steps = (to - start) / delta, i = 0; i <= steps; i++) cb(start + i * delta);
1540
1558
  }
1541
1559
  function forUntil(until, from, step, cb) {
1560
+ assertValidRangeBound("until", until);
1542
1561
  const start = from || 0;
1543
1562
  const delta = step || 1;
1544
1563
  for (let steps = (until - start) / delta, i = 0; i < steps; i++) cb(start + i * delta);
@@ -2570,15 +2589,21 @@ const kSelectedValue = Symbol("selectedValue");
2570
2589
  const kSelectedValueMatched = Symbol("selectedValueMatched");
2571
2590
  function _attr_select_value(scopeId, nodeAccessor, value, valueChange, content, serializeType) {
2572
2591
  if (valueChange) writeControlledScope(3, scopeId, nodeAccessor, void 0, valueChange, serializeType);
2573
- if (content) if (valueChange) {
2574
- const matched = { value: false };
2575
- withContext(kSelectedValue, value, () => withContext(kSelectedValueMatched, matched, content));
2576
- if (!matched.value && (Array.isArray(value) ? value.some((v) => normalizeStrAttrValue(v) !== "") : normalizeStrAttrValue(value) !== "")) console.error("A controlled `<select>`'s `value` has no matching `<option>`:", value);
2577
- } else withContext(kSelectedValue, value, content);
2592
+ if (content) {
2593
+ const selectedValue = value ?? "";
2594
+ if (valueChange) {
2595
+ const matched = { value: false };
2596
+ withContext(kSelectedValue, selectedValue, () => withContext(kSelectedValueMatched, matched, content));
2597
+ if (!matched.value && (Array.isArray(value) ? value.some((v) => normalizeStrAttrValue(v) !== "") : normalizeStrAttrValue(value) !== "")) console.error("A controlled `<select>`'s `value` has no matching `<option>`:", value);
2598
+ } else withContext(kSelectedValue, selectedValue, content);
2599
+ }
2578
2600
  }
2579
2601
  function _attr_textarea_value(scopeId, nodeAccessor, value, valueChange, serializeType) {
2580
2602
  if (valueChange) writeControlledScope(2, scopeId, nodeAccessor, void 0, valueChange, serializeType);
2581
- return _escape(value);
2603
+ return _textarea_value(value);
2604
+ }
2605
+ function _textarea_value(value) {
2606
+ return _escape(normalizeStrAttrValue(value));
2582
2607
  }
2583
2608
  function _attr_input_value(scopeId, nodeAccessor, value, valueChange, serializeType) {
2584
2609
  if (valueChange) writeControlledScope(2, scopeId, nodeAccessor, void 0, valueChange, serializeType);
@@ -2754,7 +2779,7 @@ function normalizedValueMatches(a, b) {
2754
2779
  return false;
2755
2780
  }
2756
2781
  function normalizeStrAttrValue(value) {
2757
- return value && value !== true || value === 0 ? value + "" : "";
2782
+ return isNotVoid(value) && value !== true ? value + "" : "";
2758
2783
  }
2759
2784
  //#endregion
2760
2785
  //#region src/html/dynamic-tag.ts
@@ -2833,6 +2858,7 @@ const patchDynamicTag = ((originalDynamicTag) => (patch) => {
2833
2858
  })(_dynamic_tag);
2834
2859
  //#endregion
2835
2860
  //#region src/html/template.ts
2861
+ const CONSUMED_RESULT_MESSAGE = "Cannot read from a consumed render result";
2836
2862
  const _template = (templateId, renderer, page) => {
2837
2863
  renderer.render = render;
2838
2864
  renderer["embed"] = !page;
@@ -2995,7 +3021,7 @@ var ServerRendered = class {
2995
3021
  return this.#cachedPromise ||= new Promise((resolve, reject) => {
2996
3022
  const head = this.#head;
2997
3023
  this.#head = null;
2998
- if (!head) return reject(/* @__PURE__ */ new Error("Cannot read from a consumed render result"));
3024
+ if (!head) return reject(/* @__PURE__ */ new Error(CONSUMED_RESULT_MESSAGE));
2999
3025
  const { boundary } = head;
3000
3026
  (boundary.onNext = () => {
3001
3027
  switch (!boundary.count && boundary.flush()) {
@@ -3017,7 +3043,7 @@ var ServerRendered = class {
3017
3043
  let head = this.#head;
3018
3044
  this.#head = null;
3019
3045
  if (!head) {
3020
- onAbort(/* @__PURE__ */ new Error("Cannot read from a consumed render result"));
3046
+ onAbort(/* @__PURE__ */ new Error(CONSUMED_RESULT_MESSAGE));
3021
3047
  return;
3022
3048
  }
3023
3049
  const { boundary } = head;
@@ -3047,7 +3073,7 @@ var ServerRendered = class {
3047
3073
  toString() {
3048
3074
  const head = this.#head;
3049
3075
  this.#head = null;
3050
- if (!head) throw new Error("Cannot read from a consumed render result");
3076
+ if (!head) throw new Error(CONSUMED_RESULT_MESSAGE);
3051
3077
  const { boundary } = head;
3052
3078
  switch (boundary.flush()) {
3053
3079
  case 2: throw boundary.signal.reason;
@@ -3331,6 +3357,7 @@ exports._show_start = _show_start;
3331
3357
  exports._style_html = _style_html;
3332
3358
  exports._subscribe = _subscribe;
3333
3359
  exports._template = _template;
3360
+ exports._textarea_value = _textarea_value;
3334
3361
  exports._to_text = _to_text;
3335
3362
  exports._trailers = _trailers;
3336
3363
  exports._try = _try;
@@ -156,6 +156,15 @@ function assertValidLoopKey(key, seenKeys) {
156
156
  seenKeys.add(key);
157
157
  }
158
158
  }
159
+ function assertValidList(value) {
160
+ if (value && typeof value[Symbol.iterator] !== "function") throw new Error(`A \`<for>\` tag's \`of\` attribute must be an iterable, such as an array, but received ${describeForValue(value)}.`);
161
+ }
162
+ function assertValidRangeBound(name, value) {
163
+ if (!isFinite(value)) throw new Error(`A \`<for>\` tag's \`${name}\` attribute must be a finite number, but received ${describeForValue(value)}.`);
164
+ }
165
+ function describeForValue(value) {
166
+ return typeof value === "number" || typeof value === "bigint" ? `\`${value}\`` : value === null ? "null" : `type "${typeof value}"`;
167
+ }
159
168
  function assertValidAttrName(name) {
160
169
  if (htmlAttrNameReg.test(name)) throw new Error(`Invalid attribute name: ${JSON.stringify(name)}`);
161
170
  const suggestion = getWrongAttrSuggestion(name);
@@ -228,8 +237,8 @@ function _escape_script(val) {
228
237
  assertValidTextValue(val);
229
238
  return val ? escapeScriptStr(val + "") : val === 0 ? "0" : "";
230
239
  }
231
- const unsafeStyleReg = /<\/style/gi;
232
- const escapeStyleStr = (str) => unsafeStyleReg.test(str) ? str.replace(unsafeStyleReg, "\\3C/style") : str;
240
+ const unsafeStyleReg = /<(\/style)/gi;
241
+ const escapeStyleStr = (str) => unsafeStyleReg.test(str) ? str.replace(unsafeStyleReg, "\\3C$1") : str;
233
242
  function _escape_style(val) {
234
243
  assertValidTextValue(val);
235
244
  return val ? escapeStyleStr(val + "") : val === 0 ? "0" : "";
@@ -895,11 +904,18 @@ function writeDate(state, val) {
895
904
  state.buf.push("new Date(" + +val + ")");
896
905
  return true;
897
906
  }
898
- const unsafeRegExpSourceReg = /\\[\s\S]|</g;
899
- const replaceUnsafeRegExpSourceChar = (match) => match === "<" || match === "\\<" ? "\\x3C" : match;
907
+ const unsafeRegExpSourceReg = /\\[\s\S]|[<\0\ud800-\udfff]/gu;
908
+ const unsafeRegExpSourceDetect = /[<\0\ud800-\udfff]/u;
909
+ const replaceUnsafeRegExpSourceChar = (match) => {
910
+ const ch = match.length === 3 ? "" : match[match.length - 1];
911
+ if (ch === "<") return "\\x3C";
912
+ if (ch === "\0") return "\\x00";
913
+ const code = ch.charCodeAt(0);
914
+ return code >= 55296 && code <= 57343 ? "\\u" + code.toString(16).padStart(4, "0") : match;
915
+ };
900
916
  function writeRegExp(state, val) {
901
917
  const { source } = val;
902
- state.buf.push("/" + (source.includes("<") ? source.replace(unsafeRegExpSourceReg, replaceUnsafeRegExpSourceChar) : source) + "/" + val.flags);
918
+ state.buf.push("/" + (unsafeRegExpSourceDetect.test(source) ? source.replace(unsafeRegExpSourceReg, replaceUnsafeRegExpSourceChar) : source) + "/" + val.flags);
903
919
  return true;
904
920
  }
905
921
  function writePromise(state, val, ref) {
@@ -1526,17 +1542,20 @@ function forIn(obj, cb) {
1526
1542
  for (const key in obj) cb(key, obj[key]);
1527
1543
  }
1528
1544
  function forOf(list, cb) {
1545
+ assertValidList(list);
1529
1546
  if (list) {
1530
1547
  let i = 0;
1531
1548
  for (const item of list) cb(item, i++);
1532
1549
  }
1533
1550
  }
1534
1551
  function forTo(to, from, step, cb) {
1552
+ assertValidRangeBound("to", to);
1535
1553
  const start = from || 0;
1536
1554
  const delta = step || 1;
1537
1555
  for (let steps = (to - start) / delta, i = 0; i <= steps; i++) cb(start + i * delta);
1538
1556
  }
1539
1557
  function forUntil(until, from, step, cb) {
1558
+ assertValidRangeBound("until", until);
1540
1559
  const start = from || 0;
1541
1560
  const delta = step || 1;
1542
1561
  for (let steps = (until - start) / delta, i = 0; i < steps; i++) cb(start + i * delta);
@@ -2568,15 +2587,21 @@ const kSelectedValue = Symbol("selectedValue");
2568
2587
  const kSelectedValueMatched = Symbol("selectedValueMatched");
2569
2588
  function _attr_select_value(scopeId, nodeAccessor, value, valueChange, content, serializeType) {
2570
2589
  if (valueChange) writeControlledScope(3, scopeId, nodeAccessor, void 0, valueChange, serializeType);
2571
- if (content) if (valueChange) {
2572
- const matched = { value: false };
2573
- withContext(kSelectedValue, value, () => withContext(kSelectedValueMatched, matched, content));
2574
- if (!matched.value && (Array.isArray(value) ? value.some((v) => normalizeStrAttrValue(v) !== "") : normalizeStrAttrValue(value) !== "")) console.error("A controlled `<select>`'s `value` has no matching `<option>`:", value);
2575
- } else withContext(kSelectedValue, value, content);
2590
+ if (content) {
2591
+ const selectedValue = value ?? "";
2592
+ if (valueChange) {
2593
+ const matched = { value: false };
2594
+ withContext(kSelectedValue, selectedValue, () => withContext(kSelectedValueMatched, matched, content));
2595
+ if (!matched.value && (Array.isArray(value) ? value.some((v) => normalizeStrAttrValue(v) !== "") : normalizeStrAttrValue(value) !== "")) console.error("A controlled `<select>`'s `value` has no matching `<option>`:", value);
2596
+ } else withContext(kSelectedValue, selectedValue, content);
2597
+ }
2576
2598
  }
2577
2599
  function _attr_textarea_value(scopeId, nodeAccessor, value, valueChange, serializeType) {
2578
2600
  if (valueChange) writeControlledScope(2, scopeId, nodeAccessor, void 0, valueChange, serializeType);
2579
- return _escape(value);
2601
+ return _textarea_value(value);
2602
+ }
2603
+ function _textarea_value(value) {
2604
+ return _escape(normalizeStrAttrValue(value));
2580
2605
  }
2581
2606
  function _attr_input_value(scopeId, nodeAccessor, value, valueChange, serializeType) {
2582
2607
  if (valueChange) writeControlledScope(2, scopeId, nodeAccessor, void 0, valueChange, serializeType);
@@ -2752,7 +2777,7 @@ function normalizedValueMatches(a, b) {
2752
2777
  return false;
2753
2778
  }
2754
2779
  function normalizeStrAttrValue(value) {
2755
- return value && value !== true || value === 0 ? value + "" : "";
2780
+ return isNotVoid(value) && value !== true ? value + "" : "";
2756
2781
  }
2757
2782
  //#endregion
2758
2783
  //#region src/html/dynamic-tag.ts
@@ -2831,6 +2856,7 @@ const patchDynamicTag = ((originalDynamicTag) => (patch) => {
2831
2856
  })(_dynamic_tag);
2832
2857
  //#endregion
2833
2858
  //#region src/html/template.ts
2859
+ const CONSUMED_RESULT_MESSAGE = "Cannot read from a consumed render result";
2834
2860
  const _template = (templateId, renderer, page) => {
2835
2861
  renderer.render = render;
2836
2862
  renderer["embed"] = !page;
@@ -2993,7 +3019,7 @@ var ServerRendered = class {
2993
3019
  return this.#cachedPromise ||= new Promise((resolve, reject) => {
2994
3020
  const head = this.#head;
2995
3021
  this.#head = null;
2996
- if (!head) return reject(/* @__PURE__ */ new Error("Cannot read from a consumed render result"));
3022
+ if (!head) return reject(/* @__PURE__ */ new Error(CONSUMED_RESULT_MESSAGE));
2997
3023
  const { boundary } = head;
2998
3024
  (boundary.onNext = () => {
2999
3025
  switch (!boundary.count && boundary.flush()) {
@@ -3015,7 +3041,7 @@ var ServerRendered = class {
3015
3041
  let head = this.#head;
3016
3042
  this.#head = null;
3017
3043
  if (!head) {
3018
- onAbort(/* @__PURE__ */ new Error("Cannot read from a consumed render result"));
3044
+ onAbort(/* @__PURE__ */ new Error(CONSUMED_RESULT_MESSAGE));
3019
3045
  return;
3020
3046
  }
3021
3047
  const { boundary } = head;
@@ -3045,7 +3071,7 @@ var ServerRendered = class {
3045
3071
  toString() {
3046
3072
  const head = this.#head;
3047
3073
  this.#head = null;
3048
- if (!head) throw new Error("Cannot read from a consumed render result");
3074
+ if (!head) throw new Error(CONSUMED_RESULT_MESSAGE);
3049
3075
  const { boundary } = head;
3050
3076
  switch (boundary.flush()) {
3051
3077
  case 2: throw boundary.signal.reason;
@@ -3257,4 +3283,4 @@ const compat = {
3257
3283
  };
3258
3284
  function NOOP() {}
3259
3285
  //#endregion
3260
- export { $global, _assert_hoist, _attr, _attr_and, _attr_class, _attr_content, _attr_details_or_dialog_open as _attr_details_open, _attr_details_or_dialog_open as _attr_dialog_open, _attr_input_checked, _attr_input_checkedValue, _attr_input_value, _attr_nonce, _attr_nullish, _attr_option_value, _attr_or, _attr_select_value, _attr_style, _attr_textarea_value, _attrs, _attrs_content, _attrs_partial, _attrs_partial_content, _await, _content, _content_resume, _dynamic_tag, _el, _el_read_error, _el_resume, _escape, _escape_comment, _escape_script, _escape_style, _escape_style_value, _existing_scope, _flush_head, _for_in, _for_of, _for_to, _for_until, _hoist, _hoist_read_error, _html, _id, _if, _peek_scope_id, _resume, _resume_branch, writeScope as _scope, _scope_id, _scope_reason, _scope_with_id, _script, _sep, _serialize_guard, _serialize_if, _set_serialize_reason, _show_end, _show_start, _style_html, _subscribe, _template, _to_text, _trailers, _try, _unescaped, _var, attrTag, attrTags, compat, forIn, forInBy, forOf, forOfBy, forStepBy, forTo, forUntil, withLoadAssets, withPageAssets };
3286
+ export { $global, _assert_hoist, _attr, _attr_and, _attr_class, _attr_content, _attr_details_or_dialog_open as _attr_details_open, _attr_details_or_dialog_open as _attr_dialog_open, _attr_input_checked, _attr_input_checkedValue, _attr_input_value, _attr_nonce, _attr_nullish, _attr_option_value, _attr_or, _attr_select_value, _attr_style, _attr_textarea_value, _attrs, _attrs_content, _attrs_partial, _attrs_partial_content, _await, _content, _content_resume, _dynamic_tag, _el, _el_read_error, _el_resume, _escape, _escape_comment, _escape_script, _escape_style, _escape_style_value, _existing_scope, _flush_head, _for_in, _for_of, _for_to, _for_until, _hoist, _hoist_read_error, _html, _id, _if, _peek_scope_id, _resume, _resume_branch, writeScope as _scope, _scope_id, _scope_reason, _scope_with_id, _script, _sep, _serialize_guard, _serialize_if, _set_serialize_reason, _show_end, _show_start, _style_html, _subscribe, _template, _textarea_value, _to_text, _trailers, _try, _unescaped, _var, attrTag, attrTags, compat, forIn, forInBy, forOf, forOfBy, forStepBy, forTo, forUntil, withLoadAssets, withPageAssets };