marko 6.3.33 → 6.3.34

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 (59) hide show
  1. package/cheatsheet.md +37 -33
  2. package/dist/common/errors.d.ts +1 -0
  3. package/dist/debug/dom/catch.feat.js +1 -1
  4. package/dist/debug/dom/catch.feat.mjs +1 -1
  5. package/dist/debug/dom/controllable-input.feat.js +1 -1
  6. package/dist/debug/dom/controllable-input.feat.mjs +1 -1
  7. package/dist/debug/dom/controllable-open.feat.js +1 -1
  8. package/dist/debug/dom/controllable-open.feat.mjs +1 -1
  9. package/dist/debug/dom/controllable-select.feat.js +1 -1
  10. package/dist/debug/dom/controllable-select.feat.mjs +1 -1
  11. package/dist/debug/dom/controllable-textarea.feat.js +1 -1
  12. package/dist/debug/dom/controllable-textarea.feat.mjs +1 -1
  13. package/dist/debug/dom/controllable.feat.js +1 -1
  14. package/dist/debug/dom/controllable.feat.mjs +1 -1
  15. package/dist/debug/{dom-CiFITSPN.js → dom-Bj58jt8y.js} +55 -30
  16. package/dist/debug/{dom-BJ93mcSe.mjs → dom-klf8Ec_o.mjs} +55 -30
  17. package/dist/debug/dom.js +3 -1
  18. package/dist/debug/dom.mjs +3 -1
  19. package/dist/debug/html.js +119 -79
  20. package/dist/debug/html.mjs +119 -79
  21. package/dist/dom/catch.feat.js +1 -1
  22. package/dist/dom/catch.feat.mjs +1 -1
  23. package/dist/dom/control-flow.d.ts +3 -1
  24. package/dist/dom/controllable-input.feat.js +1 -1
  25. package/dist/dom/controllable-input.feat.mjs +1 -1
  26. package/dist/dom/controllable-open.feat.js +1 -1
  27. package/dist/dom/controllable-open.feat.mjs +1 -1
  28. package/dist/dom/controllable-select.feat.js +1 -1
  29. package/dist/dom/controllable-select.feat.mjs +1 -1
  30. package/dist/dom/controllable-textarea.feat.js +1 -1
  31. package/dist/dom/controllable-textarea.feat.mjs +1 -1
  32. package/dist/dom/controllable.feat.js +1 -1
  33. package/dist/dom/controllable.feat.mjs +1 -1
  34. package/dist/{dom-Cj4HQ7T_.mjs → dom-6hBvZW7X.mjs} +27 -21
  35. package/dist/{dom-CI-06TZb.js → dom-B-XpL2_H.js} +27 -21
  36. package/dist/dom.js +3 -1
  37. package/dist/dom.mjs +3 -1
  38. package/dist/html/compat.d.ts +4 -2
  39. package/dist/html.js +73 -54
  40. package/dist/html.mjs +73 -54
  41. package/dist/translator/core/client.d.ts +1 -2
  42. package/dist/translator/core/server.d.ts +1 -2
  43. package/dist/translator/core/static.d.ts +1 -2
  44. package/dist/translator/index.js +377 -244
  45. package/dist/translator/util/constants/binding-type.d.ts +1 -0
  46. package/dist/translator/util/references.d.ts +8 -1
  47. package/dist/translator/util/serialize-reasons.d.ts +4 -4
  48. package/dist/translator/util/signals.d.ts +3 -0
  49. package/dist/translator/util/statement-tag.d.ts +2 -0
  50. package/dist/translator/visitors/program/index.d.ts +0 -1
  51. package/package.json +5 -4
  52. package/tags/html-comment.d.marko +2 -0
  53. package/tags/html-script.d.marko +2 -0
  54. package/tags/html-style.d.marko +2 -0
  55. package/tags/let.d.marko +2 -2
  56. package/tags/show.d.marko +6 -0
  57. package/tags/try.d.marko +1 -1
  58. package/tags-html.d.ts +6 -1
  59. /package/dist/translator/util/{get-accessor-char.d.ts → get-accessor-enums.d.ts} +0 -0
@@ -52,10 +52,21 @@ var runtime_info_default = {
52
52
  };
53
53
  //#endregion
54
54
  //#region src/translator/util/assert.ts
55
+ const docsAnchors = {
56
+ if: "if--else",
57
+ "else-if": "if--else",
58
+ else: "if--else",
59
+ effect: "",
60
+ attrs: ""
61
+ };
62
+ function coreTagDocsURL(tagName) {
63
+ const anchor = docsAnchors[tagName] ?? tagName;
64
+ return `https://markojs.com/docs/reference/core-tag${anchor && "#" + anchor}`;
65
+ }
55
66
  function assertNoSpreadAttrs(tag) {
56
67
  for (const attr of tag.get("attributes")) if (attr.isMarkoSpreadAttribute()) {
57
68
  const tagName = tag.get("name").node.value;
58
- throw attr.buildCodeFrameError(`The [\`<${tagName}>\`](https://markojs.com/docs/reference/core-tag#${tagName}) tag does not support \`...spread\` attributes.`);
69
+ throw attr.buildCodeFrameError(`The [\`<${tagName}>\`](${coreTagDocsURL(tagName)}) tag does not support \`...spread\` attributes.`);
59
70
  }
60
71
  }
61
72
  function assertNoTagVarMutation(tag) {
@@ -71,7 +82,7 @@ function assertNoBodyContent(tag) {
71
82
  if (tag.node.body.body.length) {
72
83
  const tagName = tag.get("name");
73
84
  const tagNameLiteral = tagName.node.value;
74
- throw tagName.buildCodeFrameError(`The [\`<${tagNameLiteral}>\`](https://markojs.com/docs/reference/core-tag#${tagNameLiteral}) tag does not support body content.`);
85
+ throw tagName.buildCodeFrameError(`The [\`<${tagNameLiteral}>\`](${coreTagDocsURL(tagNameLiteral)}) tag does not support body content.`);
75
86
  }
76
87
  }
77
88
  //#endregion
@@ -601,7 +612,7 @@ function getTagName(tag) {
601
612
  switch (tag.node.name.type) {
602
613
  case "StringLiteral": return tag.node.name.value;
603
614
  case "TemplateLiteral":
604
- if (tag.node.name.quasis.length === 1) return tag.node.name.quasis[0].value.raw;
615
+ if (tag.node.name.quasis.length === 1) return tag.node.name.quasis[0].value.cooked;
605
616
  break;
606
617
  }
607
618
  }
@@ -728,12 +739,8 @@ var Sorted = class {
728
739
  if (!Array.isArray(subset)) return this.findIndex(superset, subset) !== -1;
729
740
  if (!Array.isArray(superset)) return false;
730
741
  const subLen = subset.length;
731
- const supLen = superset.length;
732
- if (subLen > supLen) return false;
733
- for (let i = subLen; i--;) {
734
- const found = findIndexSorted(this.compare, superset, subset[i]);
735
- if (found === -1 || supLen - found <= i) return false;
736
- }
742
+ if (subLen > superset.length) return false;
743
+ for (let i = subLen; i--;) if (findIndexSorted(this.compare, superset, subset[i]) < i) return false;
737
744
  return true;
738
745
  }
739
746
  };
@@ -983,7 +990,7 @@ function getReadyId(file = (0, _marko_compiler_babel_utils.getFile)()) {
983
990
  return (markoOpts.optimize ? "_" : "ready:") + (0, _marko_compiler_babel_utils.getTemplateId)(markoOpts, file.opts.filename);
984
991
  }
985
992
  //#endregion
986
- //#region src/translator/util/get-accessor-char.ts
993
+ //#region src/translator/util/get-accessor-enums.ts
987
994
  function getAccessorPrefix() {
988
995
  return isOptimize() ? accessor_prefix_exports : accessor_prefix_debug_exports;
989
996
  }
@@ -994,6 +1001,8 @@ function getAccessorProp() {
994
1001
  //#region src/translator/util/serialize-reasons.ts
995
1002
  const scopeExprsBySection = /* @__PURE__ */ new WeakMap();
996
1003
  const propExprsBySection = /* @__PURE__ */ new WeakMap();
1004
+ const scopeProvenanceBySection = /* @__PURE__ */ new WeakMap();
1005
+ const propProvenanceBySection = /* @__PURE__ */ new WeakMap();
997
1006
  const serializePropsByBinding = /* @__PURE__ */ new WeakMap();
998
1007
  const serializePropByModifier = {};
999
1008
  function isSameReason(a, b) {
@@ -1003,43 +1012,46 @@ function isForceSerialized(section, prop, prefix) {
1003
1012
  return true === (prop ? section.serializeReasons.get(getPropKey(section, prop, prefix)) : section.serializeReason);
1004
1013
  }
1005
1014
  function addSerializeReason(section, reason, prop, prefix) {
1006
- if (reason) if (prop) {
1007
- const key = getPropKey(section, prop, prefix);
1008
- const curReason = section.serializeReasons.get(key);
1009
- if (curReason !== true) if (reason === true) forcePropSerialize(section, key);
1010
- else {
1011
- const newReason = mergeSerializeReasons(curReason, reason);
1012
- if (curReason !== newReason) setPropSerializeReason(section, key, newReason);
1013
- }
1014
- } else {
1015
- const curReason = section.serializeReason;
1016
- if (curReason !== true) if (reason === true) forceSerialize(section);
1017
- else {
1018
- const newReason = mergeSerializeReasons(curReason, reason);
1019
- if (curReason !== newReason) setSerializeReason(section, newReason);
1015
+ if (reason) {
1016
+ if (reason !== true) addProvenance(section, reason, prop && getPropKey(section, prop, prefix));
1017
+ if (prop) {
1018
+ const key = getPropKey(section, prop, prefix);
1019
+ const curReason = section.serializeReasons.get(key);
1020
+ if (curReason !== true) if (reason === true) forcePropSerialize(section, key);
1021
+ else {
1022
+ const newReason = mergeSerializeReasons(curReason, reason);
1023
+ if (curReason !== newReason) setPropSerializeReason(section, key, newReason);
1024
+ }
1025
+ } else {
1026
+ const curReason = section.serializeReason;
1027
+ if (curReason !== true) if (reason === true) forceSerialize(section);
1028
+ else {
1029
+ const newReason = mergeSerializeReasons(curReason, reason);
1030
+ if (curReason !== newReason) setSerializeReason(section, newReason);
1031
+ }
1020
1032
  }
1021
1033
  }
1022
1034
  }
1023
1035
  function addSerializeExpr(section, expr, prop, prefix) {
1024
- if (expr) {
1025
- if (prop) {
1026
- const key = getPropKey(section, prop, prefix);
1027
- if (section.serializeReasons.get(key) !== true) if (expr === true) forcePropSerialize(section, key);
1036
+ if (expr) if (prop) {
1037
+ const key = getPropKey(section, prop, prefix);
1038
+ if (expr === true) {
1039
+ if (section.serializeReasons.get(key) !== true) forcePropSerialize(section, key);
1040
+ } else {
1041
+ let curExpr;
1042
+ let curExprs = propExprsBySection.get(section);
1043
+ if (curExprs) curExpr = curExprs.get(key);
1028
1044
  else {
1029
- let curExpr;
1030
- let curExprs = propExprsBySection.get(section);
1031
- if (curExprs) curExpr = curExprs.get(key);
1032
- else {
1033
- curExprs = /* @__PURE__ */ new Map();
1034
- propExprsBySection.set(section, curExprs);
1035
- }
1036
- curExprs.set(key, curExpr ? concat(curExpr, expr) : expr);
1045
+ curExprs = /* @__PURE__ */ new Map();
1046
+ propExprsBySection.set(section, curExprs);
1037
1047
  }
1038
- } else if (section.serializeReason !== true) if (expr === true) forceSerialize(section);
1039
- else {
1040
- const curExpr = scopeExprsBySection.get(section);
1041
- scopeExprsBySection.set(section, curExpr ? concat(curExpr, expr) : expr);
1048
+ curExprs.set(key, curExpr ? concat(curExpr, expr) : expr);
1042
1049
  }
1050
+ } else if (expr === true) {
1051
+ if (section.serializeReason !== true) forceSerialize(section);
1052
+ } else {
1053
+ const curExpr = scopeExprsBySection.get(section);
1054
+ scopeExprsBySection.set(section, curExpr ? concat(curExpr, expr) : expr);
1043
1055
  }
1044
1056
  }
1045
1057
  function addOwnerSerializeReason(from, to, reason) {
@@ -1093,6 +1105,7 @@ function applySerializeExprs(section) {
1093
1105
  if (propExprs) {
1094
1106
  propExprsBySection.delete(section);
1095
1107
  for (const [key, exprs] of propExprs) {
1108
+ addProvenance(section, getProvenanceForExprs(exprs), key);
1096
1109
  const exprReason = getSerializeSourcesForExprs(exprs);
1097
1110
  if (exprReason) {
1098
1111
  const curReason = section.serializeReasons.get(key);
@@ -1103,8 +1116,9 @@ function applySerializeExprs(section) {
1103
1116
  }
1104
1117
  const scopeExprs = scopeExprsBySection.get(section);
1105
1118
  if (scopeExprs) {
1106
- const exprReason = getSerializeSourcesForExprs(scopeExprs);
1107
1119
  scopeExprsBySection.delete(section);
1120
+ addProvenance(section, getProvenanceForExprs(scopeExprs));
1121
+ const exprReason = getSerializeSourcesForExprs(scopeExprs);
1108
1122
  if (exprReason) {
1109
1123
  const curReason = section.serializeReason;
1110
1124
  const newReason = mergeSerializeReasons(curReason, exprReason);
@@ -1125,6 +1139,26 @@ function finalizeSerializeReason(section) {
1125
1139
  }
1126
1140
  if (newReason && curReason !== newReason) setSerializeReason(section, newReason);
1127
1141
  }
1142
+ const propProvenance = propProvenanceBySection.get(section);
1143
+ if (propProvenance) for (const provenance of propProvenance.values()) addProvenance(section, provenance);
1144
+ }
1145
+ function addProvenance(section, sources, key) {
1146
+ if (!sources) return;
1147
+ if (key) {
1148
+ let provenance = propProvenanceBySection.get(section);
1149
+ if (!provenance) propProvenanceBySection.set(section, provenance = /* @__PURE__ */ new Map());
1150
+ provenance.set(key, mergeSources(provenance.get(key), sources));
1151
+ } else scopeProvenanceBySection.set(section, mergeSources(scopeProvenanceBySection.get(section), sources));
1152
+ }
1153
+ function getProvenanceForExprs(exprs) {
1154
+ let sources;
1155
+ forEach(exprs, (expr) => {
1156
+ sources = mergeSources(sources, getSerializeSourcesForExpr(expr));
1157
+ forEach(expr.referencedBindingsInFunction, (binding) => {
1158
+ sources = mergeSources(sources, getSerializeSourcesForRef(binding));
1159
+ });
1160
+ });
1161
+ return sources;
1128
1162
  }
1129
1163
  function getPropKey(section, prop, prefix) {
1130
1164
  if (isStrOrSym(prop)) {
@@ -1142,12 +1176,10 @@ function getPropKey(section, prop, prefix) {
1142
1176
  }
1143
1177
  }
1144
1178
  function forceSerialize(section) {
1145
- scopeExprsBySection.delete(section);
1146
1179
  setSerializeReason(section, true);
1147
1180
  }
1148
1181
  function forcePropSerialize(section, key) {
1149
1182
  setPropSerializeReason(section, key, true);
1150
- propExprsBySection.get(section)?.delete(key);
1151
1183
  }
1152
1184
  function isStrOrSym(v) {
1153
1185
  switch (typeof v) {
@@ -1544,8 +1576,23 @@ var function_default = { analyze(fn) {
1544
1576
  if (refs === true) registerFunction(fnExtra, true);
1545
1577
  else if (refs.size) getReferencesByFn().set(fnExtra, refs);
1546
1578
  } else if (shouldAlwaysRegister(markoRoot)) registerFunction(fnExtra, true);
1547
- else getReferencesByFn().set(fnExtra, /* @__PURE__ */ new Set([exprRoot.node.extra ??= {}]));
1579
+ else {
1580
+ const refs = /* @__PURE__ */ new Set([exprRoot.node.extra ??= {}]);
1581
+ if (getConstTagVarRefs(markoRoot, refs) === true) registerFunction(fnExtra, true);
1582
+ else getReferencesByFn().set(fnExtra, refs);
1583
+ }
1548
1584
  } };
1585
+ function getConstTagVarRefs(markoRoot, refs, seen = /* @__PURE__ */ new Set()) {
1586
+ const tag = getTagFromMarkoRoot(markoRoot);
1587
+ if (!tag?.node.var || !isCoreTagName(tag, "const") || seen.has(tag.node)) return refs;
1588
+ seen.add(tag.node);
1589
+ const ids = tag.get("var").getOuterBindingIdentifiers();
1590
+ for (const name in ids) {
1591
+ const binding = tag.scope.getBinding(name);
1592
+ if (binding && addBindingRefs(binding, refs, seen) === true) return true;
1593
+ }
1594
+ return refs;
1595
+ }
1549
1596
  function finalizeFunctionRegistry() {
1550
1597
  for (const [fnExtra, exprExtras] of getReferencesByFn()) {
1551
1598
  const reason = resolveSerializeReason(exprExtras);
@@ -1676,7 +1723,10 @@ function addBindingRefs(binding, refs, seen) {
1676
1723
  if (isStaticRoot(markoRoot)) {
1677
1724
  if (getStaticDeclRefs(ref, refs, seen) === true) return true;
1678
1725
  } else if (shouldAlwaysRegister(markoRoot)) return true;
1679
- else refs.add(exprRoot.node.extra ??= {});
1726
+ else {
1727
+ refs.add(exprRoot.node.extra ??= {});
1728
+ if (getConstTagVarRefs(markoRoot, refs, seen) === true) return true;
1729
+ }
1680
1730
  }
1681
1731
  }
1682
1732
  function shouldAlwaysRegister(markoRoot) {
@@ -2143,8 +2193,8 @@ function nonVoidAttr(name, value) {
2143
2193
  }
2144
2194
  return " " + name + attrAssignment(value + "");
2145
2195
  }
2146
- const singleQuoteAttrReplacements = /'|&(?=[#a-zA-Z])/g;
2147
- const doubleQuoteAttrReplacements = /"|&(?=[#a-zA-Z])/g;
2196
+ const singleQuoteAttrReplacements = /['\r]|&(?=[#a-zA-Z])/g;
2197
+ const doubleQuoteAttrReplacements = /["\r]|&(?=[#a-zA-Z])/g;
2148
2198
  const needsQuotedAttr = /["'>\s]|&[#a-zA-Z]|\/$/g;
2149
2199
  function attrAssignment(value) {
2150
2200
  return value ? needsQuotedAttr.test(value) ? value[needsQuotedAttr.lastIndex - 1] === (needsQuotedAttr.lastIndex = 0, "\"") ? "='" + escapeSingleQuotedAttrValue(value) + "'" : "=\"" + escapeDoubleQuotedAttrValue(value) + "\"" : "=" + value : "";
@@ -2153,13 +2203,13 @@ function escapeSingleQuotedAttrValue(value) {
2153
2203
  return singleQuoteAttrReplacements.test(value) ? value.replace(singleQuoteAttrReplacements, replaceUnsafeSingleQuoteAttrChar) : value;
2154
2204
  }
2155
2205
  function replaceUnsafeSingleQuoteAttrChar(match) {
2156
- return match === "'" ? "&#39;" : "&amp;";
2206
+ return match === "'" ? "&#39;" : match === "\r" ? "&#13;" : "&amp;";
2157
2207
  }
2158
2208
  function escapeDoubleQuotedAttrValue(value) {
2159
2209
  return doubleQuoteAttrReplacements.test(value) ? value.replace(doubleQuoteAttrReplacements, replaceUnsafeDoubleQuoteAttrChar) : value;
2160
2210
  }
2161
2211
  function replaceUnsafeDoubleQuoteAttrChar(match) {
2162
- return match === "\"" ? "&#34;" : "&amp;";
2212
+ return match === "\"" ? "&#34;" : match === "\r" ? "&#13;" : "&amp;";
2163
2213
  }
2164
2214
  function normalizedValueMatches(a, b) {
2165
2215
  const value = normalizeStrAttrValue(b);
@@ -2690,6 +2740,17 @@ var return_default = {
2690
2740
  (0, _marko_compiler_babel_utils.assertNoParams)(tag);
2691
2741
  assertNoBodyContent(tag);
2692
2742
  (0, _marko_compiler_babel_utils.assertAllowedAttributes)(tag, ["value", "valueChange"]);
2743
+ let valueAttr;
2744
+ let valueChangeAttr;
2745
+ for (const attr of tag.node.attributes) if (_marko_compiler.types.isMarkoAttribute(attr)) {
2746
+ if (attr.name === "value") {
2747
+ if (valueAttr) throw tag.hub.buildError(attr, "Invalid duplicate value attribute.");
2748
+ valueAttr = attr;
2749
+ } else if (attr.name === "valueChange") {
2750
+ if (valueChangeAttr) throw tag.hub.buildError(attr, "Invalid duplicate valueChange attribute.");
2751
+ valueChangeAttr = attr;
2752
+ }
2753
+ }
2693
2754
  const parentTag = getParentTag(tag);
2694
2755
  if (parentTag) {
2695
2756
  if ((0, _marko_compiler_babel_utils.isNativeTag)(parentTag)) throw tag.get("name").buildCodeFrameError("The [`<return>` tag](https://markojs.com/docs/reference/core-tag#return) can not be used in a [native tag](https://markojs.com/docs/reference/native-tag).");
@@ -2998,6 +3059,7 @@ function getSignal(section, referencedBindings, name) {
2998
3059
  section,
2999
3060
  values: [],
3000
3061
  intersection: void 0,
3062
+ forwards: void 0,
3001
3063
  render: [],
3002
3064
  effect: [],
3003
3065
  hasHTMLEffect: false,
@@ -3074,12 +3136,13 @@ function isPureMemberForwarder(binding) {
3074
3136
  for (const alias of binding.propertyAliases.values()) if (alias.type !== 6) return true;
3075
3137
  return false;
3076
3138
  }
3077
- function pushMemberForwards(renderStatements, value, alias) {
3139
+ function pushMemberForwards(signal, value, alias) {
3078
3140
  if (isPureMemberForwarder(alias)) {
3079
- for (const [key, child] of alias.propertyAliases) if (child.type !== 6) pushMemberForwards(renderStatements, toMemberExpression(_marko_compiler.types.cloneNode(value, true), key, alias.nullable), child);
3141
+ for (const [key, child] of alias.propertyAliases) if (child.type !== 6) pushMemberForwards(signal, toMemberExpression(_marko_compiler.types.cloneNode(value, true), key, alias.nullable), child);
3080
3142
  } else {
3081
3143
  const aliasSignal = getSignal(alias.section, alias);
3082
- renderStatements.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(aliasSignal.identifier, [
3144
+ signal.forwards = push(signal.forwards, aliasSignal);
3145
+ signal.render.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(aliasSignal.identifier, [
3083
3146
  scopeIdentifier,
3084
3147
  value,
3085
3148
  ...getTranslatedExtraArgs(aliasSignal)
@@ -3094,32 +3157,35 @@ function getSignalFn(signal) {
3094
3157
  if (isValue) {
3095
3158
  for (const alias of binding.aliases) {
3096
3159
  const aliasSignal = getSignal(alias.section, alias);
3097
- if (signalHasStatements(aliasSignal)) if (alias.excludeProperties !== void 0) {
3098
- const aliasId = _marko_compiler.types.identifier(alias.name);
3099
- let pattern;
3100
- if (alias.restOffset) pattern = _marko_compiler.types.arrayPattern(new Array(alias.restOffset).fill(null).concat(_marko_compiler.types.restElement(aliasId)));
3101
- else {
3102
- const props = [];
3103
- forEach(alias.excludeProperties, (name) => {
3104
- const propId = toPropertyName(name);
3105
- const shorthand = propId.type === "Identifier" && _marko_compiler.types.isValidIdentifier(name);
3106
- props.push(_marko_compiler.types.objectProperty(propId, shorthand ? propId : generateUidIdentifier(name), false, shorthand));
3107
- });
3108
- props.push(_marko_compiler.types.restElement(aliasId));
3109
- pattern = _marko_compiler.types.objectPattern(props);
3110
- }
3111
- signal.render.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(_marko_compiler.types.arrowFunctionExpression([pattern], _marko_compiler.types.callExpression(aliasSignal.identifier, [
3160
+ if (signalHasStatements(aliasSignal)) {
3161
+ signal.forwards = push(signal.forwards, aliasSignal);
3162
+ if (alias.excludeProperties !== void 0) {
3163
+ const aliasId = _marko_compiler.types.identifier(alias.name);
3164
+ let pattern;
3165
+ if (alias.restOffset) pattern = _marko_compiler.types.arrayPattern(new Array(alias.restOffset).fill(null).concat(_marko_compiler.types.restElement(aliasId)));
3166
+ else {
3167
+ const props = [];
3168
+ forEach(alias.excludeProperties, (name) => {
3169
+ const propId = toPropertyName(name);
3170
+ const shorthand = propId.type === "Identifier" && _marko_compiler.types.isValidIdentifier(name);
3171
+ props.push(_marko_compiler.types.objectProperty(propId, shorthand ? propId : generateUidIdentifier(name), false, shorthand));
3172
+ });
3173
+ props.push(_marko_compiler.types.restElement(aliasId));
3174
+ pattern = _marko_compiler.types.objectPattern(props);
3175
+ }
3176
+ signal.render.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(_marko_compiler.types.arrowFunctionExpression([pattern], _marko_compiler.types.callExpression(aliasSignal.identifier, [
3177
+ scopeIdentifier,
3178
+ aliasId,
3179
+ ...getTranslatedExtraArgs(aliasSignal)
3180
+ ])), [binding.nullable ? _marko_compiler.types.logicalExpression("||", createScopeReadExpression(binding), alias.restOffset ? _marko_compiler.types.arrayExpression([]) : _marko_compiler.types.objectExpression([])) : createScopeReadExpression(binding)])));
3181
+ } else signal.render.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(aliasSignal.identifier, [
3112
3182
  scopeIdentifier,
3113
- aliasId,
3183
+ createScopeReadExpression(binding),
3114
3184
  ...getTranslatedExtraArgs(aliasSignal)
3115
- ])), [binding.nullable ? _marko_compiler.types.logicalExpression("||", createScopeReadExpression(binding), alias.restOffset ? _marko_compiler.types.arrayExpression([]) : _marko_compiler.types.objectExpression([])) : createScopeReadExpression(binding)])));
3116
- } else signal.render.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(aliasSignal.identifier, [
3117
- scopeIdentifier,
3118
- createScopeReadExpression(binding),
3119
- ...getTranslatedExtraArgs(aliasSignal)
3120
- ])));
3185
+ ])));
3186
+ }
3121
3187
  }
3122
- for (const [key, alias] of binding.propertyAliases) if (alias.type !== 6) pushMemberForwards(signal.render, toMemberExpression(createScopeReadExpression(binding), key, binding.nullable), alias);
3188
+ for (const [key, alias] of binding.propertyAliases) if (alias.type !== 6) pushMemberForwards(signal, toMemberExpression(createScopeReadExpression(binding), key, binding.nullable), alias);
3123
3189
  if (assertsHoists) signal.render.push(_marko_compiler.types.expressionStatement(callRuntime("_assert_hoist", createScopeReadExpression(binding))));
3124
3190
  }
3125
3191
  for (const value of signal.values) {
@@ -3255,9 +3321,9 @@ function addValue(targetSection, referencedBindings, signal, value) {
3255
3321
  }
3256
3322
  function buildResumeRegisterKey(section, referencedBindings, type) {
3257
3323
  let name = "";
3258
- if (referencedBindings) if (typeof referencedBindings === "string") name += `_${referencedBindings}`;
3259
- else if (Array.isArray(referencedBindings)) for (const ref of referencedBindings) name += `_${ref.name}`;
3260
- else name += `_${referencedBindings.name}`;
3324
+ if (referencedBindings) if (typeof referencedBindings === "string") name += `*${referencedBindings}`;
3325
+ else if (Array.isArray(referencedBindings)) for (const ref of referencedBindings) name += `_${ref.name}#${ref.id}`;
3326
+ else name += `_${referencedBindings.name}#${referencedBindings.id}`;
3261
3327
  return `${section.id}${name}${type ? "/" + type : ""}`;
3262
3328
  }
3263
3329
  function getResumeRegisterId(section, referencedBindings, type) {
@@ -3287,9 +3353,11 @@ function writeSignals(section) {
3287
3353
  let signalDeclaration;
3288
3354
  if (signal.build) {
3289
3355
  let value = signal.build();
3356
+ const buildsEagerForward = _marko_compiler.types.isIdentifier(value);
3290
3357
  if (!value || !signal.register && _marko_compiler.types.isFunction(value) && _marko_compiler.types.isBlockStatement(value.body) && !value.body.body.length) return;
3291
3358
  if (_marko_compiler.types.isCallExpression(value)) replaceNullishAndEmptyFunctionsWith0(value.arguments);
3292
3359
  if (signal.register) value = callRuntime("_var_resume", _marko_compiler.types.stringLiteral(getResumeRegisterId(section, signal.referencedBindings, "var")), value);
3360
+ if (buildsEagerForward) forEach(signal.forwards, writeSignal);
3293
3361
  const signalDeclarator = _marko_compiler.types.variableDeclarator(signal.identifier, value);
3294
3362
  signalDeclaration = !section.parent && !signal.referencedBindings && (_marko_compiler.types.isFunctionExpression(value) || _marko_compiler.types.isArrowFunctionExpression(value)) ? _marko_compiler.types.functionDeclaration(signal.identifier, value.params, _marko_compiler.types.isExpression(value.body) ? _marko_compiler.types.blockStatement([_marko_compiler.types.expressionStatement(value.body)]) : value.body) : _marko_compiler.types.variableDeclaration("const", [signalDeclarator]);
3295
3363
  if (signal.export) signalDeclaration = _marko_compiler.types.exportNamedDeclaration(signalDeclaration);
@@ -3576,15 +3644,15 @@ function replaceRegisteredFunctionNode$1(node) {
3576
3644
  switch (node.type) {
3577
3645
  case "ClassMethod": {
3578
3646
  const replacement = getRegisteredFnExpression$1(node);
3579
- return replacement && _marko_compiler.types.classProperty(node.key, replacement);
3647
+ return replacement && _marko_compiler.types.classProperty(node.key, replacement, void 0, void 0, node.computed, node.static);
3580
3648
  }
3581
3649
  case "ClassPrivateMethod": {
3582
3650
  const replacement = getRegisteredFnExpression$1(node);
3583
- return replacement && _marko_compiler.types.classPrivateProperty(node.key, replacement);
3651
+ return replacement && _marko_compiler.types.classPrivateProperty(node.key, replacement, void 0, node.static);
3584
3652
  }
3585
3653
  case "ObjectMethod": {
3586
3654
  const replacement = getRegisteredFnExpression$1(node);
3587
- return replacement && _marko_compiler.types.objectProperty(node.key, replacement);
3655
+ return replacement && _marko_compiler.types.objectProperty(node.key, replacement, node.computed);
3588
3656
  }
3589
3657
  case "ArrowFunctionExpression":
3590
3658
  case "FunctionExpression": return getRegisteredFnExpression$1(node);
@@ -4111,7 +4179,7 @@ function resumeOwnerByMarkerWhenStatic(tagSection, bodySection, nodeBinding, sta
4111
4179
  //#endregion
4112
4180
  //#region src/translator/util/is-event-or-change-handler.ts
4113
4181
  function isEventOrChangeHandler(prop) {
4114
- return /^on[-A-Z][a-zA-Z0-9_$]|[a-zA-Z_$][a-zA-Z0-9_$]*Change$/.test(prop);
4182
+ return /^on[-A-Z]|[a-zA-Z_$][a-zA-Z0-9_$]*Change$/.test(prop);
4115
4183
  }
4116
4184
  //#endregion
4117
4185
  //#region src/translator/util/is-non-html-text.ts
@@ -4176,7 +4244,12 @@ var for_default = {
4176
4244
  if (isAttrTag) return;
4177
4245
  const byAttr = getKnownAttrValues(tag.node).by;
4178
4246
  if (forType !== "of" && byAttr?.type === "StringLiteral") throw tag.hub.buildError(byAttr, `The [\`<for>\` tag](https://markojs.com/docs/reference/core-tag#for) only supports a string \`by\` key with \`of\`; use a \`by=(${forType === "in" ? "key, value" : "index"}) => ...\` function for \`<for ${forType}>\`.`);
4179
- if (byAttr?.type === "Identifier" && !tag.scope.getBinding(byAttr.name) && tag.node.body.params.some((param) => Object.hasOwn(_marko_compiler.types.getBindingIdentifiers(param), byAttr.name))) throw tag.hub.buildError(byAttr, `The \`by=\` attribute is evaluated before the loop runs, so \`${byAttr.name}\` is not in scope. Key with a property name string (\`by="id"\`) or a function (\`by=(${byAttr.name}) => key\`).`);
4247
+ if (byAttr) {
4248
+ const paramNames = /* @__PURE__ */ new Set();
4249
+ for (const param of tag.node.body.params) for (const name in _marko_compiler.types.getBindingIdentifiers(param)) paramNames.add(name);
4250
+ const paramRead = paramNames.size ? findLoopParamRead(byAttr, paramNames) : void 0;
4251
+ if (paramRead) throw tag.hub.buildError(paramRead, `The \`by=\` attribute is evaluated before the loop runs, so \`${paramRead.name}\` is not in scope. Key with a property name string (\`by="id"\`) or a function (\`by=(${paramRead.name}) => key\`).`);
4252
+ }
4180
4253
  const bodySection = startSection(tagBody);
4181
4254
  if (!bodySection) {
4182
4255
  dropNodes(getAllTagReferenceNodes(tag.node));
@@ -4234,7 +4307,7 @@ var for_default = {
4234
4307
  flushInto(tag);
4235
4308
  writeHTMLResumeStatements(tagBody);
4236
4309
  const forTagArgs = getBaseArgsInForTag(forType, forAttrs);
4237
- const forTagHTMLRuntime = branchSerializeReason ? forTypeToHTMLResumeRuntime(forType) : forTypeToRuntime(forType);
4310
+ const forTagHTMLRuntime = branchSerializeReason ? forTypeToBranchRuntime(forType) : forTypeToRuntime(forType);
4238
4311
  forTagArgs.push(_marko_compiler.types.arrowFunctionExpression(params, _marko_compiler.types.blockStatement(bodyStatements)));
4239
4312
  if (branchSerializeReason) {
4240
4313
  const skipParentEnd = onlyChildParentTagName && markerSerializeReason;
@@ -4280,7 +4353,7 @@ var for_default = {
4280
4353
  const forType = getForType(node);
4281
4354
  const signal = getSignal(tagSection, nodeRef, "for");
4282
4355
  signal.build = () => {
4283
- return callRuntime(forTypeToDOMRuntime(forType), getScopeAccessorLiteral(nodeRef, true), ...replaceNullishAndEmptyFunctionsWith0(getBranchRendererArgs(bodySection)));
4356
+ return callRuntime(forTypeToBranchRuntime(forType), getScopeAccessorLiteral(nodeRef, true), ...replaceNullishAndEmptyFunctionsWith0(getBranchRendererArgs(bodySection)));
4284
4357
  };
4285
4358
  const forAttrs = getKnownAttrValues(node);
4286
4359
  const loopArgs = getBaseArgsInForTag(forType, forAttrs);
@@ -4348,6 +4421,27 @@ function getForType(tag) {
4348
4421
  case "until": return attr.name;
4349
4422
  }
4350
4423
  }
4424
+ function findLoopParamRead(node, names) {
4425
+ switch (node.type) {
4426
+ case "Identifier": return names.has(node.name) ? node : void 0;
4427
+ case "MemberExpression":
4428
+ case "OptionalMemberExpression": return findLoopParamRead(node.object, names) || (node.computed ? findLoopParamRead(node.property, names) : void 0);
4429
+ }
4430
+ if (_marko_compiler.types.isFunction(node) || _marko_compiler.types.isClass(node)) return;
4431
+ for (const key of _marko_compiler.types.VISITOR_KEYS[node.type] || []) {
4432
+ if (key === "typeAnnotation" || key === "typeParameters") continue;
4433
+ if (key === "key" && !node.computed) continue;
4434
+ const value = node[key];
4435
+ if (Array.isArray(value)) for (const child of value) {
4436
+ const found = child?.type && findLoopParamRead(child, names);
4437
+ if (found) return found;
4438
+ }
4439
+ else if (value?.type) {
4440
+ const found = findLoopParamRead(value, names);
4441
+ if (found) return found;
4442
+ }
4443
+ }
4444
+ }
4351
4445
  function getLoopKeyBinding(byAttr, paramsBinding, forType) {
4352
4446
  if (!paramsBinding) return;
4353
4447
  if (byAttr) {
@@ -4390,15 +4484,7 @@ function forTypeToRuntime(type) {
4390
4484
  case "until": return "forUntil";
4391
4485
  }
4392
4486
  }
4393
- function forTypeToHTMLResumeRuntime(type) {
4394
- switch (type) {
4395
- case "of": return "_for_of";
4396
- case "in": return "_for_in";
4397
- case "to": return "_for_to";
4398
- case "until": return "_for_until";
4399
- }
4400
- }
4401
- function forTypeToDOMRuntime(type) {
4487
+ function forTypeToBranchRuntime(type) {
4402
4488
  switch (type) {
4403
4489
  case "of": return "_for_of";
4404
4490
  case "in": return "_for_in";
@@ -4764,7 +4850,7 @@ var native_tag_default = {
4764
4850
  }
4765
4851
  relatedControllable ||= getRelatedControllable(tagName, seen);
4766
4852
  if (relatedControllable && relatedControllable.attrs[1]) hasEventHandlers = true;
4767
- if (node.var || hasDynamicAttributes || hasEventHandlers || textPlaceholders || injectNonce || isDynamicControllable(relatedControllable)) {
4853
+ if (node.var || hasDynamicAttributes || hasEventHandlers || textPlaceholders || injectNonce || seen.content && tagName !== "meta" && !node.body.body.length || isDynamicControllable(relatedControllable)) {
4768
4854
  const tagExtra = node.extra ??= {};
4769
4855
  const tagSection = getOrCreateSection(tag);
4770
4856
  const nodeBinding = tagExtra[kNativeTagBinding] = createBinding("#" + tagName.toLowerCase(), 0, tagSection, void 0, void 0, void 0, void 0, !!node.var);
@@ -4875,6 +4961,7 @@ var native_tag_default = {
4875
4961
  if (hasChangeHandler) addHTMLEffectCall(tagSection, void 0);
4876
4962
  }
4877
4963
  let writeAtStartOfBody;
4964
+ if (tagName === "html" && getMarkoOpts().linkAssets && !tag.node.body.body.some((child) => child.type === "MarkoTag" && child.name.type === "StringLiteral" && child.name.value === "head")) writeAtStartOfBody = callRuntime("_flush_head");
4878
4965
  if (tagName === "select") {
4879
4966
  if (staticControllable) htmlSelectArgs.set(tag.node, {
4880
4967
  value: staticControllable.attrs[0]?.value || buildUndefined$1(),
@@ -5448,7 +5535,7 @@ function trackDelimitedAttrObjectProperties(obj, meta) {
5448
5535
  if (prop.key.type === "Identifier") key = prop.key.name;
5449
5536
  else {
5450
5537
  const keyEval = evaluate(prop.key);
5451
- if (keyEval.confident && typeof keyEval.computed === "string" && !/\s/.test(keyEval.computed)) key = keyEval.computed + "";
5538
+ if (keyEval.confident && typeof keyEval.computed === "string" && !/^$|\s/.test(keyEval.computed)) key = keyEval.computed + "";
5452
5539
  else {
5453
5540
  (dynamicProps ||= []).push(prop);
5454
5541
  continue;
@@ -5562,9 +5649,10 @@ const IfTag = {
5562
5649
  const tagBody = tag.get("body");
5563
5650
  const bodySection = getSectionForBody(tagBody);
5564
5651
  if (bodySection) {
5565
- const [[ifTag]] = getBranches(tag);
5652
+ const branches = getBranches(tag);
5653
+ const [ifTag] = branches[0];
5566
5654
  const ifTagSection = getSection(ifTag);
5567
- resumeOwnerByMarkerWhenStatic(ifTagSection, bodySection, getOptimizedOnlyChildNodeBinding(ifTag, ifTagSection), kStatefulReason$1);
5655
+ resumeOwnerByMarkerWhenStatic(ifTagSection, bodySection, getOptimizedOnlyChildNodeBinding(ifTag, ifTagSection, branches.length), kStatefulReason$1);
5568
5656
  flushInto(tag);
5569
5657
  writeHTMLResumeStatements(tagBody);
5570
5658
  }
@@ -5572,22 +5660,22 @@ const IfTag = {
5572
5660
  const branches = getBranches(tag);
5573
5661
  const [ifTag] = branches[0];
5574
5662
  const ifTagSection = getSection(ifTag);
5575
- const nodeBinding = getOptimizedOnlyChildNodeBinding(ifTag, ifTagSection);
5576
- const onlyChildParentTagName = getOnlyChildParentTagName(ifTag);
5663
+ const nodeBinding = getOptimizedOnlyChildNodeBinding(ifTag, ifTagSection, branches.length);
5664
+ const onlyChildParentTagName = getOnlyChildParentTagName(ifTag, branches.length);
5577
5665
  const markerSerializeReason = getSerializeReason(ifTagSection, nodeBinding);
5578
5666
  const nextTag = tag.getNextSibling();
5579
5667
  let branchSerializeReasons;
5580
5668
  let statement;
5581
5669
  let singleChild = true;
5582
- for (const [, branchBody] of branches) if (!(branchBody?.content?.singleChild && branchBody.content.startType !== 4)) {
5670
+ for (const [, branchBodySection] of branches) if (!(branchBodySection?.content?.singleChild && branchBodySection.content.startType !== 4)) {
5583
5671
  singleChild = false;
5584
5672
  break;
5585
5673
  }
5586
5674
  for (let i = branches.length; i--;) {
5587
- const [branchTag, branchBody] = branches[i];
5675
+ const [branchTag, branchBodySection] = branches[i];
5588
5676
  const bodyStatements = branchTag.node.body.body;
5589
- if (branchBody) {
5590
- const branchSerializeReason = getSerializeReason(branchBody, kBranchSerializeReason);
5677
+ if (branchBodySection) {
5678
+ const branchSerializeReason = getSerializeReason(branchBodySection, kBranchSerializeReason);
5591
5679
  if (branchSerializeReason) {
5592
5680
  if (branchSerializeReasons !== true) if (branchSerializeReason === true || branchSerializeReason.state) branchSerializeReasons = true;
5593
5681
  else if (branchSerializeReasons) branchSerializeReasons = addSorted(compareSources, branchSerializeReasons, branchSerializeReason);
@@ -5626,7 +5714,7 @@ const IfTag = {
5626
5714
  const [ifTag] = branches[0];
5627
5715
  const ifTagSection = getSection(ifTag);
5628
5716
  const ifTagExtra = branches[0][0].node.extra;
5629
- const nodeRef = getOptimizedOnlyChildNodeBinding(ifTag, ifTagSection);
5717
+ const nodeRef = getOptimizedOnlyChildNodeBinding(ifTag, ifTagSection, branches.length);
5630
5718
  let expr = _marko_compiler.types.numericLiteral(branches.length);
5631
5719
  for (let i = branches.length; i--;) {
5632
5720
  const [branchTag, branchBodySection] = branches[i];
@@ -5689,7 +5777,7 @@ function flattenTextOnlyConditional(rootTag) {
5689
5777
  const [attr] = node.attributes;
5690
5778
  if (isCoreTagName(tag, "else")) {
5691
5779
  if (node.attributes.length > 1 || attr && (!_marko_compiler.types.isMarkoAttribute(attr) || attr.name !== "if")) return;
5692
- } else if (node.attributes.length !== 1 || !_marko_compiler.types.isMarkoAttribute(attr) || !attr.default) return;
5780
+ } else if (node.attributes.length !== 1 || !_marko_compiler.types.isMarkoAttribute(attr) || !(attr.default || attr.name === "value")) return;
5693
5781
  for (const child of body) if (_marko_compiler.types.isMarkoText(child)) {
5694
5782
  if (_escape(child.value) !== child.value) return;
5695
5783
  } else if (!_marko_compiler.types.isMarkoPlaceholder(child) || !child.escape) return;
@@ -5745,7 +5833,7 @@ function assertHasBody$1(tag) {
5745
5833
  function assertHasValueAttribute$1(tag) {
5746
5834
  const { node } = tag;
5747
5835
  const [valueAttr] = node.attributes;
5748
- if (!_marko_compiler.types.isMarkoAttribute(valueAttr) || !valueAttr.default) throw tag.get("name").buildCodeFrameError(`The [\`${getTagName(tag)}\` tag](https://markojs.com/docs/reference/core-tag#if--else) requires a [\`value=\` attribute](https://markojs.com/docs/reference/language#shorthand-value).`);
5836
+ if (!_marko_compiler.types.isMarkoAttribute(valueAttr) || !(valueAttr.default || valueAttr.name === "value")) throw tag.get("name").buildCodeFrameError(`The [\`${getTagName(tag)}\` tag](https://markojs.com/docs/reference/core-tag#if--else) requires a [\`value=\` attribute](https://markojs.com/docs/reference/language#shorthand-value).`);
5749
5837
  if (node.attributes.length > 1) {
5750
5838
  const start = node.attributes[1].loc?.start;
5751
5839
  const end = node.attributes[node.attributes.length - 1].loc?.end;
@@ -5924,14 +6012,17 @@ function getChangeHandler(tag, attr) {
5924
6012
  if (_marko_compiler.types.isIdentifier(attr.value)) {
5925
6013
  const binding = tag.scope.getBinding(attr.value.name);
5926
6014
  if (!binding) return _marko_compiler.types.markoAttribute(changeAttrName, buildChangeHandlerFunction(attr.value, modifier));
5927
- const existingChangedAttr = BINDING_CHANGE_HANDLER.get(binding.identifier);
6015
+ const modifierKey = modifier?.name ?? "";
6016
+ let handlerByModifier = BINDING_CHANGE_HANDLER.get(binding.identifier);
6017
+ if (!handlerByModifier) BINDING_CHANGE_HANDLER.set(binding.identifier, handlerByModifier = /* @__PURE__ */ new Map());
6018
+ const existingChangedAttr = handlerByModifier.get(modifierKey);
5928
6019
  if (!existingChangedAttr) {
5929
6020
  const bindingIdentifierPath = binding.path.getOuterBindingIdentifierPaths()[binding.identifier.name];
5930
6021
  let changeAttrExpr = bindingIdentifierPath ? bindingIdentifierPath.parentPath === binding.path ? buildChangeHandlerFunction(attr.value, modifier) : bindingIdentifierPath.parentPath.isObjectProperty() ? getChangeHandlerFromObjectPattern(bindingIdentifierPath.parentPath) : void 0 : void 0;
5931
6022
  if (!changeAttrExpr) throw tag.hub.buildError(attr.value, bindingIdentifierPath?.parentPath?.isArrayPattern() ? `Cannot two-way bind to \`${attr.value.name}\` because it comes from array destructuring, which has no change handler. Use object destructuring or pass an explicit \`${changeAttrName}\` attribute.` : "Unable to bind to value.");
5932
6023
  if (modifier && _marko_compiler.types.isIdentifier(changeAttrExpr)) changeAttrExpr = _marko_compiler.types.logicalExpression("&&", changeAttrExpr, buildModifierForwarder(_marko_compiler.types.cloneNode(changeAttrExpr), modifier));
5933
6024
  const changeHandlerAttr = _marko_compiler.types.markoAttribute(changeAttrName, changeAttrExpr);
5934
- BINDING_CHANGE_HANDLER.set(binding.identifier, changeHandlerAttr);
6025
+ handlerByModifier.set(modifierKey, changeHandlerAttr);
5935
6026
  return changeHandlerAttr;
5936
6027
  }
5937
6028
  if (existingChangedAttr.type === "Identifier") return _marko_compiler.types.markoAttribute(changeAttrName, withPreviousLocation(_marko_compiler.types.identifier(existingChangedAttr.name), attr.value));
@@ -5939,7 +6030,7 @@ function getChangeHandler(tag, attr) {
5939
6030
  if (!(markoRoot?.isMarkoTag() || markoRoot?.isMarkoTagBody())) throw tag.hub.buildError(attr.value, "Unable to bind to value.");
5940
6031
  const changeHandlerId = generateUid(changeAttrName);
5941
6032
  const changeHandlerConst = _marko_compiler.types.markoTag(_marko_compiler.types.stringLiteral("const"), [_marko_compiler.types.markoAttribute("value", existingChangedAttr.value, null, null, true)], _marko_compiler.types.markoTagBody([]), null, _marko_compiler.types.identifier(changeHandlerId));
5942
- BINDING_CHANGE_HANDLER.set(binding.identifier, existingChangedAttr.value = _marko_compiler.types.identifier(changeHandlerId));
6033
+ handlerByModifier.set(modifierKey, existingChangedAttr.value = _marko_compiler.types.identifier(changeHandlerId));
5943
6034
  if (markoRoot.isMarkoTag()) markoRoot.insertAfter(changeHandlerConst);
5944
6035
  else markoRoot.unshiftContainer("body", changeHandlerConst);
5945
6036
  return _marko_compiler.types.markoAttribute(changeAttrName, withPreviousLocation(_marko_compiler.types.identifier(changeHandlerId), attr.value));
@@ -6252,7 +6343,8 @@ function knownTagAnalyze(tag, contentSection, propTree) {
6252
6343
  const varExpr = tagExtra.defineBodySection ? contentSection.returnValueExpr : mapParamReasonToExpr(exprs, contentSection.returnSerializeReason && (contentSection.returnSerializeReason === true || !!contentSection.returnSerializeReason.state || contentSection.returnSerializeReason.param));
6253
6344
  varBinding.scopeOffset = tagExtra[kChildOffsetScopeBinding$1] = createBinding("#scopeOffset", 0, section);
6254
6345
  setBindingDownstream(varBinding, varExpr);
6255
- addSerializeExpr(section, mutatesTagVar || varExpr, childScopeBinding);
6346
+ if (mutatesTagVar) addSerializeExpr(section, true, childScopeBinding);
6347
+ addSerializeExpr(section, varExpr, childScopeBinding);
6256
6348
  }
6257
6349
  addSerializeExpr(section, fromIter(attrExprs), childScopeBinding);
6258
6350
  }
@@ -6572,36 +6664,31 @@ function applyAttrObject(tag, propTree, tagInputIdentifier, info) {
6572
6664
  let translatedProps = propsToExpression(translatedAttrs.properties);
6573
6665
  if (translatedAttrs.statements.length) addStatement("render", info.tagSection, referencedBindings, translatedAttrs.statements);
6574
6666
  if ((0, _marko_compiler_babel_utils.isAttributeTag)(tag)) {
6575
- translatedProps = _marko_compiler.types.objectExpression(translatedAttrs.properties);
6576
- const attrTagName = getTagName(tag);
6577
- const parentTag = tag.parentPath;
6578
- if (analyzeAttributeTags(parentTag)?.[attrTagName]?.repeated) {
6579
- let attrTagCallsForTag = (info.attrTagCallsByTag ||= /* @__PURE__ */ new Map()).get(parentTag);
6580
- if (!attrTagCallsForTag) info.attrTagCallsByTag.set(parentTag, attrTagCallsForTag = /* @__PURE__ */ new Map());
6581
- const attrTagCall = attrTagCallsForTag.get(attrTagName);
6582
- if (attrTagCall) {
6583
- attrTagCall.expression = callRuntime("attrTags", attrTagCall.expression, translatedProps);
6584
- return;
6585
- } else attrTagCallsForTag.set(attrTagName, translatedProps = _marko_compiler.types.parenthesizedExpression(callRuntime("attrTag", translatedProps)));
6586
- } else translatedProps = callRuntime("attrTag", translatedProps);
6667
+ const repeated = analyzeAttributeTags(tag.parentPath)?.[getTagName(tag)]?.repeated;
6668
+ const mergedProps = getAttrTagProps(tag, repeated, _marko_compiler.types.objectExpression(translatedAttrs.properties), info);
6669
+ if (!mergedProps) return;
6670
+ translatedProps = mergedProps;
6587
6671
  }
6588
6672
  addStatement("render", info.tagSection, referencedBindings, _marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(tagInputIdentifier, [createScopeReadExpression(info.childScopeBinding, info.tagSection), translatedProps])), true);
6589
6673
  }
6590
6674
  function translateAttrTag(tag, attrTagMeta, info, statements) {
6591
6675
  const translatedAttrs = translateAttrs(tag, true, void 0, statements);
6592
- let translatedProps = _marko_compiler.types.objectExpression(translatedAttrs.properties);
6676
+ return getAttrTagProps(tag, attrTagMeta.repeated, _marko_compiler.types.objectExpression(translatedAttrs.properties), info);
6677
+ }
6678
+ function getAttrTagProps(tag, repeated, translatedProps, info) {
6679
+ if (!repeated) return callRuntime("attrTag", translatedProps);
6593
6680
  const attrTagName = getTagName(tag);
6594
6681
  const parentTag = tag.parentPath;
6595
- if (attrTagMeta.repeated) {
6596
- let attrTagCallsForTag = (info.attrTagCallsByTag ||= /* @__PURE__ */ new Map()).get(parentTag);
6597
- if (!attrTagCallsForTag) info.attrTagCallsByTag.set(parentTag, attrTagCallsForTag = /* @__PURE__ */ new Map());
6598
- const attrTagCall = attrTagCallsForTag.get(attrTagName);
6599
- if (attrTagCall) {
6600
- attrTagCall.expression = callRuntime("attrTags", attrTagCall.expression, translatedProps);
6601
- return;
6602
- } else attrTagCallsForTag.set(attrTagName, translatedProps = _marko_compiler.types.parenthesizedExpression(callRuntime("attrTag", translatedProps)));
6603
- } else translatedProps = callRuntime("attrTag", translatedProps);
6604
- return translatedProps;
6682
+ let attrTagCallsForTag = (info.attrTagCallsByTag ||= /* @__PURE__ */ new Map()).get(parentTag);
6683
+ if (!attrTagCallsForTag) info.attrTagCallsByTag.set(parentTag, attrTagCallsForTag = /* @__PURE__ */ new Map());
6684
+ const attrTagCall = attrTagCallsForTag.get(attrTagName);
6685
+ if (attrTagCall) {
6686
+ attrTagCall.expression = callRuntime("attrTags", attrTagCall.expression, translatedProps);
6687
+ return;
6688
+ }
6689
+ const wrappedProps = _marko_compiler.types.parenthesizedExpression(callRuntime("attrTag", translatedProps));
6690
+ attrTagCallsForTag.set(attrTagName, wrappedProps);
6691
+ return wrappedProps;
6605
6692
  }
6606
6693
  function writeAttrsToSignals(tag, propTree, importAlias, info) {
6607
6694
  if (!propTree.props) {
@@ -6776,11 +6863,11 @@ function mapParamReasonToExpr(exprs, reason) {
6776
6863
  }
6777
6864
  }
6778
6865
  function mapParamBindingToExpr(exprs, binding) {
6779
- const isRest = binding.property === void 0 && binding.excludeProperties !== void 0;
6866
+ const isWholeAlias = binding.property === void 0 && binding.upstreamAlias !== void 0;
6780
6867
  const props = [];
6781
- let curBinding = isRest ? binding.upstreamAlias : binding;
6782
- while (curBinding && curBinding.property !== void 0) {
6783
- props.push(curBinding.property);
6868
+ let curBinding = isWholeAlias ? binding.upstreamAlias : binding;
6869
+ while (curBinding && (curBinding.property !== void 0 || curBinding.upstreamAlias)) {
6870
+ if (curBinding.property !== void 0) props.push(curBinding.property);
6784
6871
  curBinding = curBinding.upstreamAlias;
6785
6872
  }
6786
6873
  let curExpr = exprs;
@@ -6789,7 +6876,7 @@ function mapParamBindingToExpr(exprs, binding) {
6789
6876
  if (!nestedExpr) return curExpr.value;
6790
6877
  curExpr = nestedExpr;
6791
6878
  }
6792
- if (isRest) {
6879
+ if (isWholeAlias) {
6793
6880
  let result = curExpr.value;
6794
6881
  if (curExpr.known) {
6795
6882
  for (const key in curExpr.known) if (!includes(binding.excludeProperties, key)) result = concat(result, curExpr.known[key].value);
@@ -6818,6 +6905,11 @@ function getRootSection(section) {
6818
6905
  //#endregion
6819
6906
  //#region src/translator/util/references.ts
6820
6907
  const kBranchSerializeReason = Symbol("branch serialize reason");
6908
+ const globalSources = {
6909
+ state: void 0,
6910
+ param: void 0,
6911
+ global: true
6912
+ };
6821
6913
  const [getBindings] = createProgramState(() => /* @__PURE__ */ new Set());
6822
6914
  const [getNextBindingId, setNextBindingId] = createProgramState(() => 0);
6823
6915
  function createBinding(name, type, refSection, upstreamAlias, property, excludeProperties, loc = null, refDeclared = false) {
@@ -6879,7 +6971,7 @@ function trackDomVarReferences(tag, binding) {
6879
6971
  const babelBinding = tag.scope.getBinding(tagVar.name);
6880
6972
  const section = getOrCreateSection(tag);
6881
6973
  binding.originalName = tagVar.name;
6882
- if (babelBinding.constantViolations.length) for (const ref of babelBinding.constantViolations) throw ref.type === "MarkoTag" ? ref.get("var").buildCodeFrameError(`Duplicate declaration ${JSON.stringify(binding.originalName)}`) : ref.buildCodeFrameError("Tag variables on native elements cannot be assigned to.");
6974
+ if (babelBinding.constantViolations.length) for (const ref of babelBinding.constantViolations) throw ref.type === "MarkoTag" ? ref.get("var").buildCodeFrameError(`Duplicate declaration of \`${binding.originalName}\`.`) : ref.buildCodeFrameError(`\`${binding.originalName}\` is a [tag variable](https://markojs.com/docs/reference/language#tag-variables) on a native element (an element reference) and cannot be assigned to.`);
6883
6975
  for (const ref of babelBinding.referencePaths) {
6884
6976
  const refSection = getOrCreateSection(ref);
6885
6977
  const invoked = isInvokedFunction(ref);
@@ -6957,7 +7049,7 @@ function trackReferencesForBinding(babelBinding, binding) {
6957
7049
  for (const ref of referencePaths) {
6958
7050
  const refSection = getOrCreateSection(ref);
6959
7051
  const markoRoot = getMarkoRoot(ref);
6960
- if (markoRoot?.type === "MarkoAttribute" && markoRoot.parentPath === babelBinding.path) throw ref.buildCodeFrameError(`Tag variable circular references are not supported.`);
7052
+ if (markoRoot?.type === "MarkoAttribute" && markoRoot.parentPath === babelBinding.path) throw ref.buildCodeFrameError(`\`${ref.node.name}\` is the [tag variable](https://markojs.com/docs/reference/language#tag-variables) this tag declares, so its own attributes cannot read it.`);
6961
7053
  else if (isReferenceHoisted(babelBinding.path, ref)) {
6962
7054
  const invoked = isInvokedFunction(ref);
6963
7055
  if (invoked) setReferencesScope(ref);
@@ -6979,8 +7071,8 @@ function trackReferencesForBinding(babelBinding, binding) {
6979
7071
  }
6980
7072
  }
6981
7073
  for (const ref of constantViolations) {
6982
- if (ref.type === "MarkoTag") throw ref.get("var").buildCodeFrameError(`Duplicate declaration ${JSON.stringify(binding.name)}`);
6983
- if (isReferenceHoisted(babelBinding.path, ref)) throw ref.buildCodeFrameError("Cannot assign to hoisted tag variable.");
7074
+ if (ref.type === "MarkoTag") throw ref.get("var").buildCodeFrameError(`Duplicate declaration of \`${binding.name}\`.`);
7075
+ if (isReferenceHoisted(babelBinding.path, ref)) throw ref.buildCodeFrameError(`\`${binding.name}\` is declared by a tag below this assignment; a [tag variable](https://markojs.com/docs/reference/language#tag-variables) can only be assigned below its declaration. Move the declaring tag above this code.`);
6984
7076
  if (ref.isUpdateExpression()) trackAssignment(ref.get("argument"), binding);
6985
7077
  else if (ref.isAssignmentExpression()) {
6986
7078
  trackAssignment(ref.get("left"), binding);
@@ -6993,7 +7085,7 @@ function trackReferencesForBinding(babelBinding, binding) {
6993
7085
  }
6994
7086
  function trackAssignment(assignment, binding) {
6995
7087
  const fnParent = getFnParent(assignment);
6996
- if (!fnParent) throw assignment.buildCodeFrameError(`Assignments to a tag ${binding.type === 3 ? "parameter" : "variable"} must be within a script or function.`);
7088
+ if (!fnParent) throw assignment.buildCodeFrameError(`\`${binding.name}\` is a tag ${binding.type === 3 ? "parameter" : "variable"} and can only be assigned within a script or function.`);
6997
7089
  const fnRoot = getFnRoot(fnParent);
6998
7090
  const fnExtra = fnRoot && (fnRoot.node.extra ??= {});
6999
7091
  const section = getOrCreateSection(assignment);
@@ -7022,6 +7114,10 @@ function setReferencesScope(path) {
7022
7114
  const fnRoot = getFnRoot(path);
7023
7115
  if (fnRoot) (fnRoot.node.extra ??= {}).referencesScope = true;
7024
7116
  }
7117
+ const [getGlobalBinding] = createProgramState(() => createBinding("$global", 7, getOrCreateSection((0, _marko_compiler_babel_utils.getProgram)())));
7118
+ function trackGlobalReference(path) {
7119
+ trackReference(path, getGlobalBinding());
7120
+ }
7025
7121
  function createBindingsAndTrackReferences(lVal, type, scope, section, upstreamAlias, property, excludeProperties, restOffset) {
7026
7122
  switch (lVal.type) {
7027
7123
  case "Identifier": {
@@ -7144,6 +7240,7 @@ function finalizeReferences() {
7144
7240
  const exprBindings = resolveReferencedBindings(expr, reads, intersectionsBySection);
7145
7241
  expr.referencedBindings = exprBindings.referencedBindings;
7146
7242
  expr.lazyBindings = exprBindings.lazyBindings;
7243
+ expr.globalBindings = exprBindings.globalBindings;
7147
7244
  if (!exprBindings.referencedBindings) addSetupStatement(expr.section);
7148
7245
  forEach(exprBindings.lazyBindings, (binding) => {
7149
7246
  binding.forcePersist = true;
@@ -7159,7 +7256,9 @@ function finalizeReferences() {
7159
7256
  forEach(exprBindings.lazyBindings, (binding) => {
7160
7257
  addSerializeReason(binding.section, true, binding);
7161
7258
  });
7162
- }
7259
+ } else forEach(reads, (read) => {
7260
+ if (read.serializedValue) addSerializeExpr(read.binding.section, expr, read.binding);
7261
+ });
7163
7262
  if (exprBindings.allBindings) {
7164
7263
  const exprFnReads = fnReadsByExpression.get(expr);
7165
7264
  if (exprFnReads) for (const [fn, fnReads] of exprFnReads) {
@@ -7189,6 +7288,10 @@ function finalizeReferences() {
7189
7288
  forEachSection(finalizeTagDownstreams);
7190
7289
  for (const binding of bindings) {
7191
7290
  const { name, section } = binding;
7291
+ if (binding.type === 7) {
7292
+ resolveBindingSources(binding);
7293
+ continue;
7294
+ }
7192
7295
  if (binding.type !== 0) {
7193
7296
  resolveBindingSources(binding);
7194
7297
  forEach(binding.assignmentSections, (assignedSection) => {
@@ -7223,7 +7326,8 @@ function finalizeReferences() {
7223
7326
  section.referencedClosures = bindingUtil.add(section.referencedClosures, canonicalUpstreamAlias);
7224
7327
  }
7225
7328
  setReadsOwner(section, canonicalUpstreamAlias.section);
7226
- addOwnerSerializeReason(section, canonicalUpstreamAlias.section, !!isEffect || canonicalUpstreamAlias.sources);
7329
+ if (isEffect) addOwnerSerializeReason(section, canonicalUpstreamAlias.section, true);
7330
+ addOwnerSerializeReason(section, canonicalUpstreamAlias.section, canonicalUpstreamAlias.sources);
7227
7331
  }
7228
7332
  }
7229
7333
  }
@@ -7235,7 +7339,8 @@ function finalizeReferences() {
7235
7339
  addOwnerSerializeReason(section, hoistedBinding.section, true);
7236
7340
  });
7237
7341
  if (section.parent && section.isBranch && section.sectionAccessor && section.upstreamExpression) {
7238
- addSerializeReason(section, !!(section.isHoistThrough || section.hoisted) || getSerializeSourcesForRef(getDirectClosures(section)), kBranchSerializeReason);
7342
+ if (section.isHoistThrough || section.hoisted) addSerializeReason(section, true, kBranchSerializeReason);
7343
+ addSerializeReason(section, getSerializeSourcesForRef(getDirectClosures(section)), kBranchSerializeReason);
7239
7344
  addSerializeExpr(section, section.upstreamExpression, kBranchSerializeReason);
7240
7345
  addSerializeExpr(section.parent, section.upstreamExpression, section.sectionAccessor.binding);
7241
7346
  }
@@ -7266,16 +7371,16 @@ function finalizeReferences() {
7266
7371
  forEach(section.referencedClosures, (closure) => {
7267
7372
  const sourceSection = closure.section;
7268
7373
  let currentSection = section;
7269
- let branchesReason;
7374
+ let branchesForced = false;
7375
+ let branchesSources;
7270
7376
  while (currentSection !== sourceSection) {
7271
7377
  const upstreamReason = currentSection.downstreamBinding ? getSectionRegisterReasons(currentSection) || void 0 : !currentSection.upstreamExpression || getSerializeSourcesForExpr(currentSection.upstreamExpression);
7272
- if (upstreamReason === true) {
7273
- branchesReason = true;
7274
- break;
7275
- }
7276
- branchesReason = mergeSerializeReasons(branchesReason, upstreamReason);
7378
+ if (upstreamReason === true) branchesForced = true;
7379
+ else if (upstreamReason) branchesSources = mergeSources(branchesSources, upstreamReason);
7277
7380
  currentSection = currentSection.parent;
7278
7381
  }
7382
+ const branchesReason = branchesForced || branchesSources;
7383
+ if (branchesForced) addSerializeReason(sourceSection, branchesSources, closure);
7279
7384
  addSerializeReason(sourceSection, branchesReason, closure);
7280
7385
  addSerializeReason(sourceSection, getSerializeReason(sourceSection, closure));
7281
7386
  if (isDynamicClosure(section, closure)) {
@@ -7426,6 +7531,9 @@ function resolveBindingSources(binding) {
7426
7531
  case 3:
7427
7532
  binding.sources = createSources(void 0, getCanonicalBinding(binding));
7428
7533
  return;
7534
+ case 7:
7535
+ binding.sources = globalSources;
7536
+ return;
7429
7537
  }
7430
7538
  const aliasRoot = getAliasRoot(binding);
7431
7539
  if (aliasRoot) {
@@ -7462,15 +7570,17 @@ function resolveDerivedSources(binding) {
7462
7570
  });
7463
7571
  }
7464
7572
  }
7465
- function createSources(state, param) {
7466
- if (!(state || param)) throw new Error("Cannot create a serialize reason that does not reference state or a param.");
7573
+ function createSources(state, param, global) {
7574
+ if (!(state || param || global)) throw new Error("Cannot create a serialize reason that does not reference state, a param, or $global.");
7467
7575
  return {
7468
7576
  state,
7469
- param
7577
+ param,
7578
+ global
7470
7579
  };
7471
7580
  }
7472
7581
  function compareSources(a, b) {
7473
7582
  let delta;
7583
+ if (a.global !== b.global) return a.global ? 1 : -1;
7474
7584
  if (a.param) {
7475
7585
  if (!b.param) return 1;
7476
7586
  if (delta = compareReferences(a.param, b.param)) return delta;
@@ -7484,8 +7594,8 @@ function compareSources(a, b) {
7484
7594
  function mergeSources(a, b) {
7485
7595
  if (!a) return b;
7486
7596
  if (!b) return a;
7487
- if (a.state === b.state && a.param === b.param) return a;
7488
- return createSources(bindingUtil.union(a.state, b.state), unionParamSources(a.param, b.param));
7597
+ if (a.state === b.state && a.param === b.param && a.global === b.global) return a;
7598
+ return createSources(bindingUtil.union(a.state, b.state), unionParamSources(a.param, b.param), a.global || b.global);
7489
7599
  }
7490
7600
  function unionParamSources(a, b) {
7491
7601
  const merged = bindingUtil.union(a, b);
@@ -7545,6 +7655,14 @@ function dropExtra(exprExtra) {
7545
7655
  });
7546
7656
  }
7547
7657
  }
7658
+ function isSerializedChangeHandlerRead(exprRoot) {
7659
+ const markoRoot = getMarkoRoot(exprRoot);
7660
+ if (!markoRoot?.isMarkoAttribute()) return false;
7661
+ const attr = markoRoot.node;
7662
+ if (!isEventOrChangeHandler(attr.name) || isEventHandler(attr.name) || _marko_compiler.types.isFunction(attr.value)) return false;
7663
+ const tag = markoRoot.parentPath;
7664
+ return tag.isMarkoTag() && (tag.node.name.type !== "StringLiteral" || (0, _marko_compiler_babel_utils.isNativeTag)(tag));
7665
+ }
7548
7666
  function addReadToExpression(root, binding, getter) {
7549
7667
  const { node } = root;
7550
7668
  const fnRoot = getFnRoot(root);
@@ -7552,6 +7670,7 @@ function addReadToExpression(root, binding, getter) {
7552
7670
  const section = getOrCreateSection(exprRoot);
7553
7671
  const exprExtra = getCanonicalExtra(exprRoot.node.extra ??= { section });
7554
7672
  const read = addRead(exprExtra, node.extra ??= {}, binding, section, getter);
7673
+ if (!fnRoot && isSerializedChangeHandlerRead(exprRoot)) read.serializedValue = true;
7555
7674
  const { parent } = root;
7556
7675
  if (parent.type === "BinaryExpression" && (parent.operator === "===" || parent.operator === "!==")) read.comparedTo = parent.left === node ? parent.right : parent.left;
7557
7676
  if (!getter && binding.type === 5) {
@@ -7758,13 +7877,13 @@ function resolveReferencedBindingsInFunction(refs, reads) {
7758
7877
  const { getter, binding } = read;
7759
7878
  if (getter) {} else if (binding.type === 6) {
7760
7879
  if (bindingUtil.find(refs, binding)) constantBindings = bindingUtil.add(constantBindings, binding);
7761
- } else if (binding.type !== 0) referencedBindings = bindingUtil.add(referencedBindings, findClosestReference(read.binding, refs));
7880
+ } else if (binding.type !== 0 && binding.type !== 7) referencedBindings = bindingUtil.add(referencedBindings, findClosestReference(read.binding, refs));
7762
7881
  }
7763
7882
  else {
7764
7883
  const { getter, binding } = reads;
7765
7884
  if (getter) {} else if (binding.type === 6) {
7766
7885
  if (bindingUtil.find(refs, binding)) constantBindings = binding;
7767
- } else if (binding.type !== 0) referencedBindings = findClosestReference(binding, refs);
7886
+ } else if (binding.type !== 0 && binding.type !== 7) referencedBindings = findClosestReference(binding, refs);
7768
7887
  }
7769
7888
  return {
7770
7889
  referencedBindings,
@@ -7823,6 +7942,7 @@ function resolveReferencedBindings(expr, reads, intersectionsBySection) {
7823
7942
  let hoistedBindings;
7824
7943
  let allBindings;
7825
7944
  let lazyBindings;
7945
+ let globalBindings;
7826
7946
  if (Array.isArray(reads)) {
7827
7947
  const rootBindings = getRootBindings(reads);
7828
7948
  for (const read of reads) {
@@ -7841,11 +7961,12 @@ function resolveReferencedBindings(expr, reads, intersectionsBySection) {
7841
7961
  if (isChangeHandlerRead) {
7842
7962
  const upstreamRoot = binding.upstreamAlias && findClosestReference(binding.upstreamAlias, rootBindings);
7843
7963
  if (upstreamRoot) binding = upstreamRoot;
7844
- } else {
7964
+ } else if (binding.type !== 7) {
7845
7965
  extra.section = expr.section;
7846
7966
  ({binding} = extra.read ??= resolveExpressionReference(rootBindings, binding));
7847
7967
  }
7848
- if (isLazyRead(expr, read, binding, isChangeHandlerRead)) lazyBindings = bindingUtil.add(lazyBindings, binding);
7968
+ if (binding.type === 7) globalBindings = bindingUtil.add(globalBindings, binding);
7969
+ else if (isLazyRead(expr, read, binding, isChangeHandlerRead)) lazyBindings = bindingUtil.add(lazyBindings, binding);
7849
7970
  else if (binding.type === 6) constantBindings = bindingUtil.add(constantBindings, binding);
7850
7971
  else if (binding.type !== 0) referencedBindings = bindingUtil.add(referencedBindings, binding);
7851
7972
  }
@@ -7860,7 +7981,8 @@ function resolveReferencedBindings(expr, reads, intersectionsBySection) {
7860
7981
  binding.hoists = sectionUtil.add(binding.hoists, getter.hoisted);
7861
7982
  hoistedBindings = bindingUtil.add(hoistedBindings, binding);
7862
7983
  }
7863
- } else {
7984
+ } else if (binding.type === 7) globalBindings = binding;
7985
+ else {
7864
7986
  extra.read = createRead(binding, void 0, ownVar);
7865
7987
  if (isLazyRead(expr, reads, binding, extra.assignmentTo === binding)) lazyBindings = binding;
7866
7988
  else if (binding.type === 6) constantBindings = binding;
@@ -7892,7 +8014,8 @@ function resolveReferencedBindings(expr, reads, intersectionsBySection) {
7892
8014
  constantBindings,
7893
8015
  hoistedBindings,
7894
8016
  allBindings,
7895
- lazyBindings
8017
+ lazyBindings,
8018
+ globalBindings
7896
8019
  };
7897
8020
  }
7898
8021
  function resolveExpressionReference(rootBindings, readBinding) {
@@ -8132,27 +8255,34 @@ var class_default = {
8132
8255
  }
8133
8256
  };
8134
8257
  //#endregion
8258
+ //#region src/translator/util/statement-tag.ts
8259
+ function createStatementTag(keyword) {
8260
+ const target = keyword === "static" ? void 0 : keyword;
8261
+ const keywordReg = new RegExp(`^${keyword}\\s*`);
8262
+ return {
8263
+ parse(tag) {
8264
+ const { node, hub: { file } } = tag;
8265
+ const rawValue = node.rawValue;
8266
+ const code = rawValue.replace(keywordReg, "");
8267
+ const start = node.start + (rawValue.length - code.length);
8268
+ let body = (0, _marko_compiler_babel_utils.parseStatements)(file, code, start, start + code.length);
8269
+ if (body.length === 1 && _marko_compiler.types.isBlockStatement(body[0])) body = body[0].body;
8270
+ tag.replaceWith(_marko_compiler.types.markoScriptlet(body, true, target));
8271
+ },
8272
+ parseOptions: {
8273
+ statement: true,
8274
+ rawOpenTag: true
8275
+ },
8276
+ autocomplete: [{
8277
+ displayText: `${keyword} <statement>`,
8278
+ description: `A JavaScript statement which is only evaluated once your template is loaded${target ? ` on the ${target}` : ""}.`,
8279
+ descriptionMoreURL: `https://markojs.com/docs/reference/language#${keyword === "static" ? "static" : "server-and-client"}`
8280
+ }]
8281
+ };
8282
+ }
8283
+ //#endregion
8135
8284
  //#region src/translator/core/client.ts
8136
- var client_default = {
8137
- parse(tag) {
8138
- const { node, hub: { file } } = tag;
8139
- const rawValue = node.rawValue;
8140
- const code = rawValue.replace(/^client\s*/, "");
8141
- const start = node.start + (rawValue.length - code.length);
8142
- let body = (0, _marko_compiler_babel_utils.parseStatements)(file, code, start, start + code.length);
8143
- if (body.length === 1 && _marko_compiler.types.isBlockStatement(body[0])) body = body[0].body;
8144
- tag.replaceWith(_marko_compiler.types.markoScriptlet(body, true, "client"));
8145
- },
8146
- parseOptions: {
8147
- statement: true,
8148
- rawOpenTag: true
8149
- },
8150
- autocomplete: [{
8151
- displayText: "client <statement>",
8152
- description: "A JavaScript statement which is only evaluated once your template is loaded on the client.",
8153
- descriptionMoreURL: "https://markojs.com/docs/syntax/#client-javascript"
8154
- }]
8155
- };
8285
+ var client_default = createStatementTag("client");
8156
8286
  //#endregion
8157
8287
  //#region src/translator/core/const.ts
8158
8288
  var const_default = {
@@ -8399,7 +8529,8 @@ var html_comment_default = {
8399
8529
  const tagExtra = mergeReferences(tagSection, tag.node, referenceNodes);
8400
8530
  nodeBinding = tagExtra[kNodeBinding$1] = createBinding("#comment", 0, tagSection, void 0, void 0, void 0, void 0, !!tagVar);
8401
8531
  trackDomVarReferences(tag, nodeBinding);
8402
- addSerializeExpr(tagSection, !!tagVar || tagExtra, nodeBinding);
8532
+ if (tagVar) addSerializeExpr(tagSection, true, nodeBinding);
8533
+ addSerializeExpr(tagSection, tagExtra, nodeBinding);
8403
8534
  }
8404
8535
  const write = writeTo(tag);
8405
8536
  if (nodeBinding) visit(tag, 32);
@@ -8532,7 +8663,7 @@ var import_default = {
8532
8663
  parse(tag) {
8533
8664
  const { node } = tag;
8534
8665
  const statements = (0, _marko_compiler_babel_utils.parseStatements)(tag.hub.file, node.rawValue, node.start, node.end);
8535
- if (statements.length > 1) throw tag.hub.buildError(statements[1], "The [`<import>` tag](https://markojs.com/docs/syntax/#importing-external-files) takes a single import statement.");
8666
+ if (statements.length > 1) throw tag.hub.buildError(statements[1], "The [`<import>` tag](https://markojs.com/docs/reference/language#import) takes a single import statement.");
8536
8667
  tag.replaceWith(statements[0]);
8537
8668
  },
8538
8669
  parseOptions: {
@@ -8543,7 +8674,7 @@ var import_default = {
8543
8674
  displayText: "import <scope> from \"<path>\"",
8544
8675
  description: "Use to import external modules, follows the same syntax as JavaScript imports.",
8545
8676
  snippet: "import ${2} from \"${1:path}\"",
8546
- descriptionMoreURL: "https://markojs.com/docs/syntax/#importing-external-files"
8677
+ descriptionMoreURL: "https://markojs.com/docs/reference/language#import"
8547
8678
  }]
8548
8679
  };
8549
8680
  //#endregion
@@ -8735,6 +8866,7 @@ var script_default = {
8735
8866
  const section = getSection(tag);
8736
8867
  const { value } = valueAttr;
8737
8868
  const referencedBindings = value.extra?.referencedBindings;
8869
+ if ((_marko_compiler.types.isFunctionExpression(value) || _marko_compiler.types.isArrowFunctionExpression(value)) && _marko_compiler.types.isBlockStatement(value.body) && traverseContains(value.body, isReturnedFunction)) (0, _marko_compiler_babel_utils.diagnosticWarn)(tag, { label: "The value returned from a [`<script>`](https://markojs.com/docs/reference/core-tag#script) body is discarded, so this cleanup function will never run. Register it with [`$signal.onabort`](https://markojs.com/docs/reference/language#signal) or use [`<lifecycle onDestroy>`](https://markojs.com/docs/reference/core-tag#lifecycle) instead." });
8738
8870
  if (isOutputDOM()) {
8739
8871
  const isFunction = _marko_compiler.types.isFunctionExpression(value) || _marko_compiler.types.isArrowFunctionExpression(value);
8740
8872
  let inlineBody = null;
@@ -8775,6 +8907,18 @@ function isAwaitExpression(node) {
8775
8907
  default: return false;
8776
8908
  }
8777
8909
  }
8910
+ function isReturnedFunction(node) {
8911
+ switch (node.type) {
8912
+ case "FunctionDeclaration":
8913
+ case "FunctionExpression":
8914
+ case "ArrowFunctionExpression":
8915
+ case "ClassMethod":
8916
+ case "ObjectMethod":
8917
+ case "ClassPrivateMethod": return skip;
8918
+ case "ReturnStatement": return _marko_compiler.types.isFunctionExpression(node.argument) || _marko_compiler.types.isArrowFunctionExpression(node.argument);
8919
+ default: return false;
8920
+ }
8921
+ }
8778
8922
  function isReturnStatement(node) {
8779
8923
  switch (node.type) {
8780
8924
  case "FunctionDeclaration":
@@ -8789,26 +8933,7 @@ function isReturnStatement(node) {
8789
8933
  }
8790
8934
  //#endregion
8791
8935
  //#region src/translator/core/server.ts
8792
- var server_default = {
8793
- parse(tag) {
8794
- const { node, hub: { file } } = tag;
8795
- const rawValue = node.rawValue;
8796
- const code = rawValue.replace(/^server\s*/, "");
8797
- const start = node.start + (rawValue.length - code.length);
8798
- let body = (0, _marko_compiler_babel_utils.parseStatements)(file, code, start, start + code.length);
8799
- if (body.length === 1 && _marko_compiler.types.isBlockStatement(body[0])) body = body[0].body;
8800
- tag.replaceWith(_marko_compiler.types.markoScriptlet(body, true, "server"));
8801
- },
8802
- parseOptions: {
8803
- statement: true,
8804
- rawOpenTag: true
8805
- },
8806
- autocomplete: [{
8807
- displayText: "server <statement>",
8808
- description: "A JavaScript statement which is only evaluated once your template is loaded on the server.",
8809
- descriptionMoreURL: "https://markojs.com/docs/syntax/#server-javascript"
8810
- }]
8811
- };
8936
+ var server_default = createStatementTag("server");
8812
8937
  //#endregion
8813
8938
  //#region src/translator/util/insertion-context.ts
8814
8939
  const discardsUnknownChildren = /* @__PURE__ */ new Set([
@@ -8947,7 +9072,8 @@ var show_default = {
8947
9072
  snippet: "show=${1:condition}",
8948
9073
  description: "Use to render content that is always mounted but only displayed when the condition is met.",
8949
9074
  descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#show"
8950
- }]
9075
+ }],
9076
+ types: runtime_info_default.name + "/tags/show.d.marko"
8951
9077
  };
8952
9078
  function isSingleNodeBody(tag) {
8953
9079
  let elements = 0;
@@ -8977,31 +9103,12 @@ function assertHasBody(tag) {
8977
9103
  function assertHasValueAttribute(tag) {
8978
9104
  const { node } = tag;
8979
9105
  const [valueAttr] = node.attributes;
8980
- if (!_marko_compiler.types.isMarkoAttribute(valueAttr) || !valueAttr.default) throw tag.get("name").buildCodeFrameError(`The [\`<${getTagName(tag)}>\` tag](https://markojs.com/docs/reference/core-tag#show) requires a [\`value=\` attribute](https://markojs.com/docs/reference/language#shorthand-value).`);
9106
+ if (!_marko_compiler.types.isMarkoAttribute(valueAttr) || !(valueAttr.default || valueAttr.name === "value")) throw tag.get("name").buildCodeFrameError(`The [\`<${getTagName(tag)}>\` tag](https://markojs.com/docs/reference/core-tag#show) requires a [\`value=\` attribute](https://markojs.com/docs/reference/language#shorthand-value).`);
8981
9107
  if (node.attributes.length > 1) throw tag.get("name").buildCodeFrameError(`The [\`<${getTagName(tag)}>\` tag](https://markojs.com/docs/reference/core-tag#show) only supports the [\`value=\` attribute](https://markojs.com/docs/reference/language#shorthand-value).`);
8982
9108
  }
8983
9109
  //#endregion
8984
9110
  //#region src/translator/core/static.ts
8985
- var static_default = {
8986
- parse(tag) {
8987
- const { node, hub: { file } } = tag;
8988
- const rawValue = node.rawValue;
8989
- const code = rawValue.replace(/^static\s*/, "");
8990
- const start = node.start + (rawValue.length - code.length);
8991
- let body = (0, _marko_compiler_babel_utils.parseStatements)(file, code, start, start + code.length);
8992
- if (body.length === 1 && _marko_compiler.types.isBlockStatement(body[0])) body = body[0].body;
8993
- tag.replaceWith(_marko_compiler.types.markoScriptlet(body, true));
8994
- },
8995
- parseOptions: {
8996
- statement: true,
8997
- rawOpenTag: true
8998
- },
8999
- autocomplete: [{
9000
- displayText: "static <statement>",
9001
- description: "A JavaScript statement which is only evaluated once your template is loaded.",
9002
- descriptionMoreURL: "https://markojs.com/docs/syntax/#static-javascript"
9003
- }]
9004
- };
9111
+ var static_default = createStatementTag("static");
9005
9112
  function checkStyleInterpolations(tag) {
9006
9113
  const { body } = tag.node.body;
9007
9114
  let stringQuote = "";
@@ -9279,7 +9386,13 @@ var try_default = {
9279
9386
  (0, _marko_compiler_babel_utils.assertNoArgs)(tag);
9280
9387
  (0, _marko_compiler_babel_utils.assertNoParams)(tag);
9281
9388
  (0, _marko_compiler_babel_utils.assertNoAttributes)(tag);
9282
- analyzeAttributeTags(tag);
9389
+ const attrTags = analyzeAttributeTags(tag);
9390
+ if (attrTags) {
9391
+ for (const name in attrTags) if (name !== "@placeholder" && name !== "@catch") {
9392
+ const suggestion = name[1] === "p" ? "`<@placeholder>`" : "`<@catch>`";
9393
+ throw tag.buildCodeFrameError(`The [\`<try>\` tag](https://markojs.com/docs/reference/core-tag#try) only supports the \`<@placeholder>\` and \`<@catch>\` attribute tags, but received \`<${name}>\`. Did you mean ${suggestion}?`);
9394
+ }
9395
+ }
9283
9396
  const section = getOrCreateSection(tag);
9284
9397
  const tagExtra = mergeReferences(section, tag.node, getAllTagReferenceNodes(tag.node));
9285
9398
  tagExtra[kDOMBinding$1] = createBinding("#text", 0, section);
@@ -9403,9 +9516,23 @@ var declaration_default = { translate: { enter(decl) {
9403
9516
  //#endregion
9404
9517
  //#region src/translator/visitors/document-type.ts
9405
9518
  var document_type_default = { translate: { exit(documentType) {
9406
- if (isOutputHTML()) writeTo$1(documentType)`<!${documentType.node.value}>`;
9519
+ if (isOutputHTML()) {
9520
+ writeTo$1(documentType)`<!${documentType.node.value}>`;
9521
+ if (getMarkoOpts().linkAssets && !isBeforeHtmlOrHead(documentType)) writeTo$1(documentType)`${callRuntime("_flush_head")}`;
9522
+ }
9407
9523
  documentType.remove();
9408
9524
  } } };
9525
+ function isBeforeHtmlOrHead(documentType) {
9526
+ let next = documentType.getNextSibling();
9527
+ while (next.node) {
9528
+ if (next.isMarkoTag()) {
9529
+ const { name } = next.node;
9530
+ return name.type === "StringLiteral" && (name.value === "html" || name.value === "head");
9531
+ }
9532
+ next = next.getNextSibling();
9533
+ }
9534
+ return false;
9535
+ }
9409
9536
  //#endregion
9410
9537
  //#region src/translator/visitors/import-declaration.ts
9411
9538
  const triggerRegExp = /\s*([\w-]+)\s*([^?|]+?)?\s*(?:\?([^|]*?))?\s*(?:\||$)/g;
@@ -9425,16 +9552,17 @@ var import_declaration_default = {
9425
9552
  }
9426
9553
  const loadAttrPath = node.attributes?.length ? importDecl.get("attributes").find((p) => (p.node.key.type === "Identifier" ? p.node.key.name : p.node.key.value) === "load") : void 0;
9427
9554
  if (loadAttrPath) {
9555
+ const loadImport = getLoadImportConfig(loadAttrPath.get("value"));
9556
+ if ((node.importKind || "value") !== "value") throw importDecl.buildCodeFrameError("Invalid load import.");
9557
+ for (const specifier of importDecl.get("specifiers")) if (!_marko_compiler.types.isImportDefaultSpecifier(specifier.node)) throw specifier.buildCodeFrameError("Invalid load import, only a default specifier is allowed.");
9558
+ if (!node.specifiers.some(_marko_compiler.types.isImportDefaultSpecifier)) throw importDecl.buildCodeFrameError("Invalid load import, a default specifier is required.");
9428
9559
  if (!getMarkoOpts().linkAssets) {
9429
9560
  loadAttrPath.remove();
9430
9561
  return;
9431
9562
  }
9432
- (node.extra ??= {}).loadImport = getLoadImportConfig(loadAttrPath.get("value"));
9563
+ (node.extra ??= {}).loadImport = loadImport;
9433
9564
  const { file } = importDecl.hub;
9434
9565
  if (!(tagImport && (0, _marko_compiler_babel_utils.loadFileForImport)(file, value))) throw importDecl.buildCodeFrameError("Unable to resolve marko file for load import.");
9435
- if ((node.importKind || "value") !== "value") throw importDecl.buildCodeFrameError("Invalid load import.");
9436
- for (const specifier of importDecl.get("specifiers")) if (!_marko_compiler.types.isImportDefaultSpecifier(specifier.node)) throw specifier.buildCodeFrameError("Invalid load import, only a default specifier is allowed.");
9437
- if (!node.specifiers.some(_marko_compiler.types.isImportDefaultSpecifier)) throw importDecl.buildCodeFrameError("Invalid load import, a default specifier is required.");
9438
9566
  }
9439
9567
  },
9440
9568
  translate: { exit(importDecl) {
@@ -9452,6 +9580,7 @@ var import_declaration_default = {
9452
9580
  const wrappedName = getOrCreateHtmlLoadWrapped(getReadyId(loadFile), _marko_compiler.types.identifier(local.name), loadFile.opts.filename, loadImport.render ? void 0 : loadImport.triggers);
9453
9581
  for (const ref of binding.referencePaths) ref.replaceWith(_marko_compiler.types.identifier(wrappedName));
9454
9582
  node.source.value = tagImport;
9583
+ node.attributes = void 0;
9455
9584
  return;
9456
9585
  } else if (binding.referencePaths.every((ref) => _marko_compiler.types.isMarkoTag(ref.parent) && ref.parent.extra?.tagNameLoad)) importDecl.remove();
9457
9586
  else {
@@ -9557,7 +9686,7 @@ function isStaticText(node) {
9557
9686
  case "MarkoPlaceholder":
9558
9687
  if (node.escape) {
9559
9688
  const { confident, computed } = evaluate(node.value);
9560
- return confident && isNotVoid(computed);
9689
+ return confident && getHTMLRuntime()._escape(computed) !== "";
9561
9690
  }
9562
9691
  return false;
9563
9692
  }
@@ -9569,7 +9698,7 @@ function getPrevStaticSibling(path) {
9569
9698
  }
9570
9699
  function isEmptyPlaceholder(placeholder) {
9571
9700
  const { confident, computed } = evaluate(placeholder.value);
9572
- return confident && isVoid(computed);
9701
+ return confident && getHTMLRuntime()[placeholder.escape ? "_escape" : "_unescaped"](computed) === "";
9573
9702
  }
9574
9703
  //#endregion
9575
9704
  //#region src/translator/visitors/placeholder.ts
@@ -9582,7 +9711,7 @@ var placeholder_default = {
9582
9711
  const { node } = placeholder;
9583
9712
  const valueExtra = evaluate(node.value);
9584
9713
  const { confident, computed } = valueExtra;
9585
- if (confident && isVoid(computed)) return;
9714
+ if (confident && getHTMLRuntime()[node.escape ? "_escape" : "_unescaped"](computed) === "") return;
9586
9715
  if (!isStaticText(node)) {
9587
9716
  const section = getOrCreateSection(placeholder);
9588
9717
  const nodeBinding = (node.extra ??= {})[kNodeBinding] = createBinding("#text", 0, section);
@@ -9595,9 +9724,10 @@ var placeholder_default = {
9595
9724
  if (isNonHTMLText(placeholder)) return;
9596
9725
  const { node } = placeholder;
9597
9726
  const { confident, computed } = evaluate(node.value);
9598
- if (confident && isVoid(computed)) return;
9727
+ const staticText = confident ? getHTMLRuntime()[node.escape ? "_escape" : "_unescaped"](computed) : void 0;
9728
+ if (staticText === "") return;
9599
9729
  const extra = node.extra || {};
9600
- if (confident && node.escape) writeTo(placeholder)`${getHTMLRuntime()._escape(computed)}`;
9730
+ if (confident && node.escape) writeTo(placeholder)`${staticText}`;
9601
9731
  else {
9602
9732
  const siblingText = extra[kSiblingText];
9603
9733
  if (siblingText === 1 || siblingText === 2) visit(placeholder, 37);
@@ -9620,7 +9750,7 @@ function translateExit(placeholder) {
9620
9750
  if (node.extra?.[kRawText]) injectTextCoercion(value);
9621
9751
  const valueExtra = evaluate(value);
9622
9752
  const { confident, computed } = valueExtra;
9623
- if (confident && isVoid(computed)) {
9753
+ if (confident && getHTMLRuntime()[node.escape ? "_escape" : "_unescaped"](computed) === "") {
9624
9754
  placeholder.remove();
9625
9755
  return;
9626
9756
  }
@@ -9738,8 +9868,10 @@ var referenced_identifier_default = {
9738
9868
  analyze(identifier) {
9739
9869
  const { name } = identifier.node;
9740
9870
  if (identifier.scope.hasBinding(name)) return;
9741
- if (name === "$global") setReferencesScope(identifier);
9742
- else if (name === "$signal") {
9871
+ if (name === "$global") {
9872
+ setReferencesScope(identifier);
9873
+ trackGlobalReference(identifier);
9874
+ } else if (name === "$signal") {
9743
9875
  const section = getOrCreateSection(identifier);
9744
9876
  section.hasAbortSignal = true;
9745
9877
  setReferencesScope(identifier);
@@ -10053,7 +10185,8 @@ var dynamic_tag_default = {
10053
10185
  }
10054
10186
  const bodySection = startSection(tagBody);
10055
10187
  trackParamsReferences(tagBody, 3);
10056
- addSerializeExpr(tagSection, hasVar || tagExtra, nodeBinding);
10188
+ if (hasVar) addSerializeExpr(tagSection, true, nodeBinding);
10189
+ addSerializeExpr(tagSection, tagExtra, nodeBinding);
10057
10190
  if (!hasVar && !node.arguments && !node.attributes.length && !node.body.body.length) tagExtra[kDirectContent] = true;
10058
10191
  if (tagExtra.featureType !== "class" || (0, _marko_compiler_babel_utils.getTagTemplate)(tag)) {
10059
10192
  visit(tag, hasVar ? 49 : 37);