marko 6.1.23 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -96,6 +96,7 @@ let AccessorPrefix$1 = /* @__PURE__ */ function(AccessorPrefix) {
96
96
  AccessorPrefix["DynamicHTMLLastChild"] = "DynamicHTMLLastChild:";
97
97
  AccessorPrefix["EventAttributes"] = "EventAttributes:";
98
98
  AccessorPrefix["Getter"] = "Getter:";
99
+ AccessorPrefix["KeyedScopes"] = "KeyedScopes:";
99
100
  AccessorPrefix["Lifecycle"] = "Lifecycle:";
100
101
  AccessorPrefix["Promise"] = "Promise:";
101
102
  AccessorPrefix["TagVariableChange"] = "TagVariableChange:";
@@ -799,7 +800,8 @@ function isControlFlowTag(tag) {
799
800
  case "else":
800
801
  case "for":
801
802
  case "await":
802
- case "try": return true;
803
+ case "try":
804
+ case "show": return true;
803
805
  }
804
806
  return false;
805
807
  }
@@ -1073,6 +1075,7 @@ let AccessorPrefix = /* @__PURE__ */ function(AccessorPrefix) {
1073
1075
  AccessorPrefix["DynamicHTMLLastChild"] = "H";
1074
1076
  AccessorPrefix["EventAttributes"] = "I";
1075
1077
  AccessorPrefix["Getter"] = "J";
1078
+ AccessorPrefix["KeyedScopes"] = "O";
1076
1079
  AccessorPrefix["Lifecycle"] = "K";
1077
1080
  AccessorPrefix["Promise"] = "L";
1078
1081
  AccessorPrefix["TagVariableChange"] = "M";
@@ -1534,10 +1537,12 @@ function getNodeContentType(path, extraMember, contentInfo) {
1534
1537
  case "html-comment": return 0;
1535
1538
  case "html-script":
1536
1539
  case "html-style": return 3;
1540
+ case "style": return tag.node.body.body.some((child) => _marko_compiler.types.isMarkoPlaceholder(child)) ? 3 : null;
1537
1541
  case "for":
1538
1542
  case "if":
1539
1543
  case "await":
1540
- case "try": return 1;
1544
+ case "try":
1545
+ case "show": return 1;
1541
1546
  default: return null;
1542
1547
  }
1543
1548
  else if ((0, _marko_compiler_babel_utils.isNativeTag)(tag)) return 3;
@@ -1643,7 +1648,9 @@ function isNativeNode(tag) {
1643
1648
  if (isCoreTag(tag)) switch (tag.node.name.value) {
1644
1649
  case "html-comment":
1645
1650
  case "html-script":
1646
- case "html-style": return true;
1651
+ case "html-style":
1652
+ case "show": return true;
1653
+ case "style": return tag.node.body.body.some((child) => _marko_compiler.types.isMarkoPlaceholder(child));
1647
1654
  default: return false;
1648
1655
  }
1649
1656
  return analyzeTagNameType(tag) === 0;
@@ -2240,6 +2247,7 @@ const pureDOMFunctions = new Set([
2240
2247
  "_child_setup",
2241
2248
  "_if",
2242
2249
  "_if_closure",
2250
+ "_show",
2243
2251
  "_try",
2244
2252
  "_dynamic_tag",
2245
2253
  "_dynamic_tag_content",
@@ -2250,6 +2258,7 @@ const pureDOMFunctions = new Set([
2250
2258
  "_closure_get",
2251
2259
  "_or",
2252
2260
  "_for_closure",
2261
+ "_for_selector",
2253
2262
  "_for_in",
2254
2263
  "_for_of",
2255
2264
  "_for_to",
@@ -2824,7 +2833,79 @@ function forEachIdentifierPath(nodePath, cb) {
2824
2833
  }
2825
2834
  }
2826
2835
  //#endregion
2836
+ //#region src/translator/util/for-selector.ts
2837
+ const forSelectorsBySection = /* @__PURE__ */ new WeakMap();
2838
+ const forSelectorValues = /* @__PURE__ */ new WeakSet();
2839
+ function getForSelectorKey(bodySection, closure) {
2840
+ const selectors = forSelectorsBySection.get(bodySection);
2841
+ if (selectors?.closures.has(getCanonicalBinding(closure))) return selectors.keyBinding;
2842
+ }
2843
+ function isForSelectorValue(binding) {
2844
+ return forSelectorValues.has(binding);
2845
+ }
2846
+ function detectForSelector(bodySection, keyBinding) {
2847
+ let closures;
2848
+ for (const expr of keyBinding.reads) {
2849
+ if (expr.section !== bodySection) continue;
2850
+ forEach(expr.referencedBindings, (closure) => {
2851
+ const canonical = getCanonicalBinding(closure);
2852
+ if (closure.type !== 6 && isDirectClosure(bodySection, closure) && !closures?.has(canonical) && onlyComparesKey(closure, canonical, bodySection, keyBinding)) {
2853
+ (closures ||= /* @__PURE__ */ new Set()).add(canonical);
2854
+ forSelectorValues.add(closure);
2855
+ }
2856
+ });
2857
+ }
2858
+ if (closures) forSelectorsBySection.set(bodySection, {
2859
+ keyBinding,
2860
+ closures
2861
+ });
2862
+ }
2863
+ function onlyComparesKey(closure, canonical, bodySection, keyBinding) {
2864
+ let found = false;
2865
+ for (let chain = closure; chain; chain = chain.upstreamAlias) for (const expr of chain.reads) {
2866
+ if (expr.section !== bodySection) continue;
2867
+ let other = false;
2868
+ forEach(getExpressionReads(expr), (read) => {
2869
+ const resolved = read.extra.read;
2870
+ const at = resolved && resolvesTo(resolved, canonical);
2871
+ if (!at) return;
2872
+ if (at === 2 || resolved.getter || !readsKey(read.comparedTo?.extra?.read, keyBinding)) other = true;
2873
+ else found = true;
2874
+ });
2875
+ if (other) return false;
2876
+ }
2877
+ return found;
2878
+ }
2879
+ function resolvesTo(read, canonical) {
2880
+ let binding = read.binding;
2881
+ let through = 0;
2882
+ forEach(read.props, (prop) => {
2883
+ if (binding) {
2884
+ if (getCanonicalBinding(binding) === canonical) through = 2;
2885
+ binding = binding.propertyAliases.get(prop);
2886
+ }
2887
+ });
2888
+ return binding && getCanonicalBinding(binding) === canonical ? 1 : through;
2889
+ }
2890
+ function readsKey(read, keyBinding) {
2891
+ if (!read || read.getter) return false;
2892
+ let binding = read.binding;
2893
+ forEach(read.props, (prop) => {
2894
+ binding = binding?.propertyAliases.get(prop);
2895
+ });
2896
+ return !!binding && getCanonicalBinding(binding) === getCanonicalBinding(keyBinding);
2897
+ }
2898
+ //#endregion
2827
2899
  //#region src/translator/util/to-property-name.ts
2900
+ function getMemberExpressionPropString(expr) {
2901
+ switch (expr.property.type) {
2902
+ case "StringLiteral": return expr.property.value;
2903
+ case "NumericLiteral": return "" + expr.property.value;
2904
+ case "Identifier":
2905
+ if (expr.computed) return;
2906
+ return expr.property.name;
2907
+ }
2908
+ }
2828
2909
  function isValidPropertyIdentifier(name) {
2829
2910
  return /^[a-z_$][a-z0-9_$]*$/i.test(name);
2830
2911
  }
@@ -2974,6 +3055,8 @@ function getSignal(section, referencedBindings, name) {
2974
3055
  export: !!exportName,
2975
3056
  hasSideEffect: !!(referencedBindings && (Array.isArray(referencedBindings) || referencedBindings.type === 0 || referencedBindings.type === 1 || referencedBindings.section !== section || referencedBindings.closureSections || referencedBindings.hoists)),
2976
3057
  hasDynamicSubscribers: false,
3058
+ forcePersist: false,
3059
+ inline: void 0,
2977
3060
  extraArgs: void 0,
2978
3061
  prependStatements: void 0,
2979
3062
  buildAssignment: void 0
@@ -2981,8 +3064,18 @@ function getSignal(section, referencedBindings, name) {
2981
3064
  if (isOutputHTML()) return signal;
2982
3065
  else if (!referencedBindings) signal.build = () => getSignalFn(signal);
2983
3066
  else if (Array.isArray(referencedBindings)) {
2984
- subscribe(referencedBindings, signal);
2985
- signal.build = () => {
3067
+ const collapseSource = collapsedIntersectionSource.get(referencedBindings);
3068
+ subscribe(collapseSource || referencedBindings, signal);
3069
+ if (collapseSource) {
3070
+ const sourceSignal = getSignal(section, collapseSource);
3071
+ forEach(referencedBindings, (member) => {
3072
+ const memberSignal = getSignal(section, member);
3073
+ const inline = member.type === 5 && !member.upstreamAlias && member.reads.size === 1 && sourceSignal.values.find((v) => v.signal === memberSignal);
3074
+ if (inline) memberSignal.inline = inline;
3075
+ else memberSignal.hasSideEffect = memberSignal.forcePersist = true;
3076
+ });
3077
+ signal.build = () => getSignalFn(signal);
3078
+ } else signal.build = () => {
2986
3079
  const { id, scopeOffset } = intersectionMeta.get(referencedBindings);
2987
3080
  return callRuntime("_or", _marko_compiler.types.numericLiteral(id), getSignalFn(signal), scopeOffset || referencedBindings.length > 2 ? _marko_compiler.types.numericLiteral(referencedBindings.length - 1) : void 0, scopeOffset && getScopeAccessorLiteral(scopeOffset, true));
2988
3081
  };
@@ -3010,7 +3103,8 @@ function initValue(binding, isLet = false) {
3010
3103
  signal.build = () => {
3011
3104
  if (isPureMemberForwarder(binding)) return;
3012
3105
  const fn = getSignalFn(signal);
3013
- if (binding.upstreamAlias && binding.property === void 0 && binding.excludeProperties === void 0 || !signal.hasSideEffect || !signalHasStatements(signal)) return fn;
3106
+ const isDirectAlias = binding.upstreamAlias && binding.property === void 0 && binding.excludeProperties === void 0;
3107
+ if (!signal.forcePersist && (isDirectAlias || !signal.hasSideEffect || !signalHasStatements(signal))) return fn;
3014
3108
  return callRuntime(isLet ? signal.extraArgs ? "_let_change" : "_let" : "_const", getScopeAccessorLiteral(binding, true, isLet), fn);
3015
3109
  };
3016
3110
  for (const alias of binding.aliases) if (alias.type !== 6) initValue(alias);
@@ -3018,7 +3112,7 @@ function initValue(binding, isLet = false) {
3018
3112
  return signal;
3019
3113
  }
3020
3114
  function signalHasStatements(signal) {
3021
- if (signal.extraArgs || signal.render.length || signal.effect.length || signal.values.length || signal.intersection) return true;
3115
+ if (signal.extraArgs || signal.forcePersist || signal.render.length || signal.effect.length || signal.values.length || signal.intersection) return true;
3022
3116
  const binding = signal.referencedBindings;
3023
3117
  if (binding) {
3024
3118
  if (!Array.isArray(binding) && (binding.closureSections || binding.type === 0 || binding.section === signal.section && (binding.hoists || binding.aliases.size || hasNonConstantPropertyAlias(binding)))) return true;
@@ -3026,7 +3120,7 @@ function signalHasStatements(signal) {
3026
3120
  return false;
3027
3121
  }
3028
3122
  function isPureMemberForwarder(binding) {
3029
- if (binding.property === void 0 || binding.reads.size || binding.exposed || binding.aliases.size || binding.assignmentSections || getSerializeReason(binding.section, binding) || getSignal(binding.section, binding).hasSideEffect) return false;
3123
+ if (binding.property === void 0 || binding.reads.size || binding.exposed || binding.aliases.size || binding.assignmentSections || isForSelectorValue(binding) || getSerializeReason(binding.section, binding) || getSignal(binding.section, binding).hasSideEffect) return false;
3030
3124
  for (const alias of binding.propertyAliases.values()) if (alias.type !== 6) return true;
3031
3125
  return false;
3032
3126
  }
@@ -3078,12 +3172,15 @@ function getSignalFn(signal) {
3078
3172
  for (const [key, alias] of binding.propertyAliases) if (alias.type !== 6) pushMemberForwards(signal.render, toMemberExpression(createScopeReadExpression(binding), key, binding.nullable), alias);
3079
3173
  if (assertsHoists) signal.render.push(_marko_compiler.types.expressionStatement(callRuntime("_assert_hoist", createScopeReadExpression(binding))));
3080
3174
  }
3081
- for (const value of signal.values) if (signalHasStatements(value.signal)) signal.render.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(value.signal.identifier, [
3082
- scopeIdentifier,
3083
- value.value,
3084
- ...getTranslatedExtraArgs(value.signal)
3085
- ])));
3086
- else signal.render.push(_marko_compiler.types.expressionStatement(withLeadingComment(value.value, getDebugNames(value.signal.referencedBindings))));
3175
+ for (const value of signal.values) {
3176
+ if (value.signal.inline) continue;
3177
+ if (signalHasStatements(value.signal)) signal.render.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(value.signal.identifier, [
3178
+ scopeIdentifier,
3179
+ value.value,
3180
+ ...getTranslatedExtraArgs(value.signal)
3181
+ ])));
3182
+ else signal.render.push(_marko_compiler.types.expressionStatement(withLeadingComment(value.value, getDebugNames(value.signal.referencedBindings))));
3183
+ }
3087
3184
  forEach(signal.intersection, (intersection) => {
3088
3185
  signal.render.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(intersection.identifier, [scopeIdentifier])));
3089
3186
  });
@@ -3785,7 +3882,8 @@ function isNonHTMLText(placeholder) {
3785
3882
  if (isCoreTag(parentTag)) switch (parentTag.node.name.value) {
3786
3883
  case "html-comment":
3787
3884
  case "html-script":
3788
- case "html-style": return true;
3885
+ case "html-style":
3886
+ case "style": return true;
3789
3887
  }
3790
3888
  else if (isTextOnlyNativeTag(parentTag)) return true;
3791
3889
  }
@@ -3797,7 +3895,7 @@ function isTextOnlyNativeTag(tag) {
3797
3895
  }
3798
3896
  //#endregion
3799
3897
  //#region src/translator/core/for.ts
3800
- const kStatefulReason$1 = Symbol("<for> stateful reason");
3898
+ const kStatefulReason$2 = Symbol("<for> stateful reason");
3801
3899
  var for_default = {
3802
3900
  analyze(tag) {
3803
3901
  const tagSection = getOrCreateSection(tag);
@@ -3842,13 +3940,17 @@ var for_default = {
3842
3940
  }
3843
3941
  const nodeBinding = getOptimizedOnlyChildNodeBinding(tag, tagSection);
3844
3942
  const tagExtra = mergeReferences(tagSection, tag.node, getAllTagReferenceNodes(tag.node));
3845
- addSerializeExpr(tagSection, tagExtra, kStatefulReason$1);
3943
+ addSerializeExpr(tagSection, tagExtra, kStatefulReason$2);
3846
3944
  if (paramsBinding) {
3847
3945
  setBindingDownstream(paramsBinding, tagExtra);
3848
- const keyBinding = paramsBinding.propertyAliases.get(forType === "of" ? "1" : "0");
3849
- if (keyBinding && !getKnownAttrValues(tag.node).by) {
3850
- keyBinding.type = 6;
3851
- keyBinding.scopeAccessor = getAccessorProp().LoopKey;
3946
+ const byAttr = getKnownAttrValues(tag.node).by;
3947
+ const keyBinding = getLoopKeyBinding(byAttr, paramsBinding, forType);
3948
+ if (keyBinding) {
3949
+ if (!byAttr) {
3950
+ keyBinding.type = 6;
3951
+ keyBinding.scopeAccessor = getAccessorProp().LoopKey;
3952
+ }
3953
+ onFinalizeReferences(() => detectForSelector(bodySection, keyBinding));
3852
3954
  }
3853
3955
  }
3854
3956
  bodySection.sectionAccessor = {
@@ -3897,7 +3999,7 @@ var for_default = {
3897
3999
  forTagArgs.push(_marko_compiler.types.arrowFunctionExpression(params, _marko_compiler.types.blockStatement(bodyStatements)));
3898
4000
  if (branchSerializeReason) {
3899
4001
  const skipParentEnd = onlyChildParentTagName && markerSerializeReason;
3900
- const statefulSerializeArg = getSerializeGuard(tagSection, getSerializeReason(tagSection, kStatefulReason$1), !(skipParentEnd || singleChild));
4002
+ const statefulSerializeArg = getSerializeGuard(tagSection, getSerializeReason(tagSection, kStatefulReason$2), !(skipParentEnd || singleChild));
3901
4003
  const markerSerializeArg = getSerializeGuard(tagSection, markerSerializeReason, !statefulSerializeArg);
3902
4004
  forTagArgs.push(forAttrs.by || _marko_compiler.types.numericLiteral(0), getScopeIdIdentifier(tagSection), getScopeAccessorLiteral(nodeBinding), getSerializeGuard(tagSection, branchSerializeReason, !markerSerializeArg), markerSerializeArg, statefulSerializeArg);
3903
4005
  if (skipParentEnd) {
@@ -3935,7 +4037,9 @@ var for_default = {
3935
4037
  const { node } = tag;
3936
4038
  const { referencedBindings } = node.extra;
3937
4039
  const nodeRef = getOptimizedOnlyChildNodeBinding(tag, tagSection);
3938
- setClosureSignalBuilder(tag, (_closure, render) => {
4040
+ setClosureSignalBuilder(tag, (closure, render) => {
4041
+ const selectorKeyBinding = getForSelectorKey(bodySection, closure);
4042
+ if (selectorKeyBinding) return callRuntime("_for_selector", getScopeAccessorLiteral(nodeRef, true), getScopeAccessorLiteral(closure, true), getScopeAccessorLiteral(selectorKeyBinding, true), render);
3939
4043
  return callRuntime("_for_closure", getScopeAccessorLiteral(nodeRef, true), render);
3940
4044
  });
3941
4045
  const forType = getForType(node);
@@ -4009,6 +4113,40 @@ function getForType(tag) {
4009
4113
  case "until": return attr.name;
4010
4114
  }
4011
4115
  }
4116
+ function getLoopKeyBinding(byAttr, paramsBinding, forType) {
4117
+ if (!paramsBinding) return;
4118
+ if (byAttr) {
4119
+ const keyChain = getByKeyChain(byAttr);
4120
+ if (!keyChain) return;
4121
+ let keyBinding = paramsBinding.propertyAliases.get("0");
4122
+ for (const property of keyChain) keyBinding = keyBinding?.propertyAliases.get(property);
4123
+ return keyBinding;
4124
+ }
4125
+ return paramsBinding.propertyAliases.get(forType === "of" ? "1" : "0");
4126
+ }
4127
+ function getByKeyChain(byAttr) {
4128
+ if (byAttr.type === "StringLiteral") return [byAttr.value];
4129
+ if (byAttr.type === "ArrowFunctionExpression" || byAttr.type === "FunctionExpression") {
4130
+ const itemParam = byAttr.params[0];
4131
+ let body = byAttr.body;
4132
+ if (body.type === "BlockStatement") {
4133
+ const [statement] = body.body;
4134
+ body = body.body.length === 1 && statement.type === "ReturnStatement" ? statement.argument : void 0;
4135
+ }
4136
+ if (itemParam?.type === "Identifier" && body) return getStaticMemberChain(body, itemParam.name);
4137
+ }
4138
+ }
4139
+ function getStaticMemberChain(node, rootName) {
4140
+ const chain = [];
4141
+ let cur = node;
4142
+ while (cur.type === "MemberExpression" || cur.type === "OptionalMemberExpression") {
4143
+ const property = getMemberExpressionPropString(cur);
4144
+ if (property === void 0) return;
4145
+ chain.push(property);
4146
+ cur = cur.object;
4147
+ }
4148
+ if (cur.type === "Identifier" && cur.name === rootName) return chain.reverse();
4149
+ }
4012
4150
  function forTypeToRuntime(type) {
4013
4151
  switch (type) {
4014
4152
  case "of": return "forOf";
@@ -4986,7 +5124,7 @@ function toFirstStatementOrBlock(body) {
4986
5124
  }
4987
5125
  //#endregion
4988
5126
  //#region src/translator/core/if.ts
4989
- const kStatefulReason = Symbol("<if> stateful reason");
5127
+ const kStatefulReason$1 = Symbol("<if> stateful reason");
4990
5128
  const BRANCHES_LOOKUP = /* @__PURE__ */ new WeakMap();
4991
5129
  const IfTag = {
4992
5130
  analyze(tag) {
@@ -5011,7 +5149,7 @@ const IfTag = {
5011
5149
  if (branchTag.node.attributes.length) mergeReferenceNodes.push(branchTag.node.attributes[0].value);
5012
5150
  }
5013
5151
  mergeReferences(ifTagSection, ifTag.node, mergeReferenceNodes);
5014
- addSerializeExpr(ifTagSection, ifTagExtra, kStatefulReason);
5152
+ addSerializeExpr(ifTagSection, ifTagExtra, kStatefulReason$1);
5015
5153
  }
5016
5154
  },
5017
5155
  translate: translateByTarget({
@@ -5069,7 +5207,7 @@ const IfTag = {
5069
5207
  if (branchSerializeReasons) {
5070
5208
  const skipParentEnd = onlyChildParentTagName && markerSerializeReason;
5071
5209
  if (skipParentEnd) getParentTag(ifTag).node.extra[kSkipEndTag] = true;
5072
- const statefulSerializeArg = getSerializeGuard(ifTagSection, getSerializeReason(ifTagSection, kStatefulReason), !(skipParentEnd || singleChild));
5210
+ const statefulSerializeArg = getSerializeGuard(ifTagSection, getSerializeReason(ifTagSection, kStatefulReason$1), !(skipParentEnd || singleChild));
5073
5211
  const markerSerializeArg = getSerializeGuard(ifTagSection, markerSerializeReason, !statefulSerializeArg);
5074
5212
  const cbNode = _marko_compiler.types.arrowFunctionExpression([], _marko_compiler.types.blockStatement([statement]));
5075
5213
  statement = _marko_compiler.types.expressionStatement(callRuntime("_if", cbNode, getScopeIdIdentifier(ifTagSection), getScopeAccessorLiteral(nodeBinding), getSerializeGuardForAny(ifTagSection, branchSerializeReasons, !markerSerializeArg), markerSerializeArg, statefulSerializeArg, skipParentEnd ? _marko_compiler.types.stringLiteral(`</${onlyChildParentTagName}>`) : singleChild ? _marko_compiler.types.numericLiteral(0) : void 0, singleChild ? _marko_compiler.types.numericLiteral(1) : void 0));
@@ -5181,14 +5319,14 @@ function assertValidCondition(tag) {
5181
5319
  (0, _marko_compiler_babel_utils.assertNoVar)(tag);
5182
5320
  (0, _marko_compiler_babel_utils.assertNoArgs)(tag);
5183
5321
  (0, _marko_compiler_babel_utils.assertNoParams)(tag);
5184
- assertHasBody(tag);
5322
+ assertHasBody$1(tag);
5185
5323
  assertNoSpreadAttrs(tag);
5186
5324
  switch (getTagName(tag)) {
5187
5325
  case "if":
5188
- assertHasValueAttribute(tag);
5326
+ assertHasValueAttribute$1(tag);
5189
5327
  break;
5190
5328
  case "else-if":
5191
- assertHasValueAttribute(tag);
5329
+ assertHasValueAttribute$1(tag);
5192
5330
  assertHasPrecedingCondition(tag);
5193
5331
  break;
5194
5332
  case "else":
@@ -5202,10 +5340,10 @@ function assertHasPrecedingCondition(tag) {
5202
5340
  while (prev.node && prev.isMarkoComment()) prev = prev.getPrevSibling();
5203
5341
  if (!isConditionTag(prev) || getTagName(prev) === "else" && !prev.node.attributes.length) throw tag.buildCodeFrameError(`The [\`<${getTagName(tag)}>\` tag](https://markojs.com/docs/reference/core-tag#if--else) must have a preceding \`<if=cond>\` or \`<else if=cond>\`.`);
5204
5342
  }
5205
- function assertHasBody(tag) {
5343
+ function assertHasBody$1(tag) {
5206
5344
  if (!(tag.node.body.body.length || tag.node.attributeTags.length)) throw tag.get("name").buildCodeFrameError(`The [\`${getTagName(tag)}\` tag](https://markojs.com/docs/reference/core-tag#if--else) requires [body content](https://markojs.com/docs/reference/language#tag-content).`);
5207
5345
  }
5208
- function assertHasValueAttribute(tag) {
5346
+ function assertHasValueAttribute$1(tag) {
5209
5347
  const { node } = tag;
5210
5348
  const [valueAttr] = node.attributes;
5211
5349
  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).`);
@@ -5543,7 +5681,7 @@ var program_default = {
5543
5681
  const isDOMPageEntry = output === "dom" && entry === "page" || output === "hydrate";
5544
5682
  const isServerEntry = output === "html" && entry === "page";
5545
5683
  if (entry && !markoOpts.linkAssets) throw program.buildCodeFrameError("The \"entry\" option requires the `linkAssets` compiler option to be configured.");
5546
- if (runtimeId && !/^[_$a-z][_$a-z0-9]*$/i.test(runtimeId)) throw program.buildCodeFrameError(`Invalid runtimeId: "${runtimeId}". The runtimeId must be a valid JavaScript identifier.`);
5684
+ if (runtimeId && !/^[_a-z][_a-z0-9]*$/i.test(runtimeId)) throw program.buildCodeFrameError(`Invalid runtimeId: "${runtimeId}". The runtimeId must start with a letter or underscore and only contain letters, numbers, and underscores.`);
5547
5685
  if (isLoadEntry) {
5548
5686
  const entryFile = program.hub.file;
5549
5687
  const { filename } = entryFile.opts;
@@ -6721,7 +6859,11 @@ function finalizeReferences() {
6721
6859
  forEachSection((section) => {
6722
6860
  const { id, bindings } = section;
6723
6861
  const isOwnedBinding = ({ section }) => section.id === id;
6724
- let intersections = intersectionsBySection.get(section) || [];
6862
+ let intersections = (intersectionsBySection.get(section) || []).filter((intersection) => {
6863
+ const collapseSource = getCollapsibleIntersectionSource(intersection, section);
6864
+ if (collapseSource) collapsedIntersectionSource.set(intersection, collapseSource);
6865
+ return !collapseSource;
6866
+ });
6725
6867
  if (intersections.length) {
6726
6868
  const anchors = /* @__PURE__ */ new Map();
6727
6869
  for (const intersection of intersections) for (let i = intersection.length; i--;) if (isOwnedBinding(intersection[i])) {
@@ -6754,6 +6896,7 @@ function finalizeReferences() {
6754
6896
  });
6755
6897
  const programSection = (0, _marko_compiler_babel_utils.getProgram)().node.extra.section;
6756
6898
  if (programSection.returnValueExpr) programSection.returnSerializeReason = getSerializeSourcesForExpr(programSection.returnValueExpr);
6899
+ for (const finalize of getReferenceFinalizers()) finalize();
6757
6900
  readsByExpression.clear();
6758
6901
  fnReadsByExpression.clear();
6759
6902
  }
@@ -6769,6 +6912,19 @@ function getMaxOwnSourceOffset(intersection, section) {
6769
6912
  return scopeOffset;
6770
6913
  }
6771
6914
  const intersectionMeta = /* @__PURE__ */ new WeakMap();
6915
+ const collapsedIntersectionSource = /* @__PURE__ */ new WeakMap();
6916
+ function getCollapsibleIntersectionSource(intersection, section) {
6917
+ let sources;
6918
+ for (const member of intersection) {
6919
+ if (!member.sources) return void 0;
6920
+ const isDirectAlias = member.upstreamAlias && member.property === void 0 && member.excludeProperties === void 0;
6921
+ if (member.section !== section || isDirectAlias) return void 0;
6922
+ sources = mergeSources(sources, member.sources);
6923
+ }
6924
+ if (!sources || sources.state && sources.param) return;
6925
+ const source = sources.state || sources.param;
6926
+ return source && !Array.isArray(source) && source.section === section && !source.scopeOffset ? source : void 0;
6927
+ }
6772
6928
  function setBindingDownstream(binding, expr) {
6773
6929
  getBindingValueExprs().set(binding, expr || false);
6774
6930
  if (expr && expr !== true) forEach(expr, (expr) => {
@@ -6878,13 +7034,21 @@ const propsUtil = new Sorted(function compareProps(a, b) {
6878
7034
  });
6879
7035
  const [getReadsByExpression] = createProgramState(() => /* @__PURE__ */ new Map());
6880
7036
  const [getFunctionReadsByExpression] = createProgramState(() => /* @__PURE__ */ new Map());
7037
+ const [getReferenceFinalizers] = createProgramState(() => []);
7038
+ function onFinalizeReferences(finalize) {
7039
+ getReferenceFinalizers().push(finalize);
7040
+ }
7041
+ function getExpressionReads(exprExtra) {
7042
+ return getReadsByExpression().get(exprExtra);
7043
+ }
6881
7044
  function addRead(exprExtra, extra, binding, section, getter) {
6882
7045
  const readsByExpression = getReadsByExpression();
6883
7046
  const read = {
6884
7047
  binding,
6885
7048
  extra,
6886
7049
  getter,
6887
- ownVar: false
7050
+ ownVar: false,
7051
+ comparedTo: void 0
6888
7052
  };
6889
7053
  binding.reads.add(exprExtra);
6890
7054
  exprExtra.section = section;
@@ -6914,6 +7078,8 @@ function addReadToExpression(root, binding, getter) {
6914
7078
  const section = getOrCreateSection(exprRoot);
6915
7079
  const exprExtra = exprRoot.node.extra ??= { section };
6916
7080
  const read = addRead(exprExtra, node.extra ??= {}, binding, section, getter);
7081
+ const { parent } = root;
7082
+ if (parent.type === "BinaryExpression" && (parent.operator === "===" || parent.operator === "!==")) read.comparedTo = parent.left === node ? parent.right : parent.left;
6917
7083
  if (!getter && binding.type === 5) {
6918
7084
  const babelBinding = root.scope.getBinding(binding.name);
6919
7085
  read.ownVar = !!babelBinding && babelBinding.kind !== "param" && isReferenceInOwnBody(babelBinding.path, root);
@@ -7020,13 +7186,16 @@ function getReadReplacement(node, signal) {
7020
7186
  let replacement;
7021
7187
  if (read.props === void 0) {
7022
7188
  if (read.getter?.invoked) return;
7023
- if (isOutputDOM()) if (signal?.referencedBindings === readBinding && !signal.hasSideEffect) replacement = getSignalValueIdentifier(signal);
7024
- else if (read.getter?.hoisted) replacement = _marko_compiler.types.callExpression(getBindingGetterIdentifier(readBinding, read.getter.hoisted), [getScopeExpression(extra.section, read.getter.hoisted)]);
7025
- else if (readBinding.type === 0) {
7026
- if (read.getter) replacement = _marko_compiler.types.callExpression(getBindingGetterIdentifier(readBinding, readBinding.section), [getScopeExpression(extra.section, readBinding.section)]);
7027
- } else if (!isOptimize() && read.ownVar) replacement = callRuntime("_assert_init", extra.section ? getScopeExpression(extra.section, readBinding.section) : scopeIdentifier, getScopeAccessorLiteral(readBinding));
7028
- else replacement = createScopeReadExpression(readBinding, extra.section);
7029
- else if (node.type !== "Identifier") replacement = _marko_compiler.types.identifier(readBinding.name);
7189
+ if (isOutputDOM()) {
7190
+ const inlined = getSignals(extra.section).get(readBinding)?.inline?.value;
7191
+ if (inlined) replacement = _marko_compiler.types.cloneNode(inlined, true);
7192
+ else if (signal?.referencedBindings === readBinding && !signal.hasSideEffect) replacement = getSignalValueIdentifier(signal);
7193
+ else if (read.getter?.hoisted) replacement = _marko_compiler.types.callExpression(getBindingGetterIdentifier(readBinding, read.getter.hoisted), [getScopeExpression(extra.section, read.getter.hoisted)]);
7194
+ else if (readBinding.type === 0) {
7195
+ if (read.getter) replacement = _marko_compiler.types.callExpression(getBindingGetterIdentifier(readBinding, readBinding.section), [getScopeExpression(extra.section, readBinding.section)]);
7196
+ } else if (!isOptimize() && read.ownVar) replacement = callRuntime("_assert_init", extra.section ? getScopeExpression(extra.section, readBinding.section) : scopeIdentifier, getScopeAccessorLiteral(readBinding));
7197
+ else replacement = createScopeReadExpression(readBinding, extra.section);
7198
+ } else if (node.type !== "Identifier") replacement = _marko_compiler.types.identifier(readBinding.name);
7030
7199
  else if (read.getter?.hoisted) replacement = getBindingGetterIdentifier(readBinding, read.getter.hoisted);
7031
7200
  else if (readBinding.type === 0) {
7032
7201
  if (readBinding.getters.has(readBinding.section)) replacement = getBindingGetterIdentifier(readBinding, readBinding.section);
@@ -7237,15 +7406,6 @@ function createGetterRead(binding, props, getter) {
7237
7406
  getter
7238
7407
  };
7239
7408
  }
7240
- function getMemberExpressionPropString(expr) {
7241
- switch (expr.property.type) {
7242
- case "StringLiteral": return expr.property.value;
7243
- case "NumericLiteral": return "" + expr.property.value;
7244
- case "Identifier":
7245
- if (expr.computed) return;
7246
- return expr.property.name;
7247
- }
7248
- }
7249
7409
  function isReferencedExtra(extra) {
7250
7410
  return !!(extra && !extra.pruned && extra.section);
7251
7411
  }
@@ -8056,6 +8216,163 @@ var server_default = {
8056
8216
  }]
8057
8217
  };
8058
8218
  //#endregion
8219
+ //#region src/translator/core/show.ts
8220
+ const kStatefulReason = Symbol("<show> stateful reason");
8221
+ const kStartBinding = Symbol("<show> range start binding");
8222
+ const kStaticDisplay = Symbol("<show> static display");
8223
+ const kSingleNodeBody = Symbol("<show> single node body");
8224
+ const kDisplayRef = Symbol("<show> hoisted display reference");
8225
+ var show_default = {
8226
+ analyze: {
8227
+ enter(tag) {
8228
+ assertValidShow(tag);
8229
+ const tagExtra = tag.node.extra ??= {};
8230
+ const display = tag.node.attributes[0].value;
8231
+ const displayEval = evaluate(display);
8232
+ tagExtra[kSingleNodeBody] = isSingleNodeBody(tag);
8233
+ if (displayEval.confident) tagExtra[kStaticDisplay] = !!displayEval.computed;
8234
+ if (tagExtra[kStaticDisplay] === true) return;
8235
+ const tagSection = getOrCreateSection(tag);
8236
+ if (getOnlyChildParentTagName(tag)) getOptimizedOnlyChildNodeBinding(tag, tagSection);
8237
+ else tagExtra[kStartBinding] = createBinding("#text", 0, tagSection);
8238
+ if (tagExtra[kStaticDisplay] === void 0) {
8239
+ mergeReferences(tagSection, tag.node, [display]);
8240
+ addSerializeExpr(tagSection, tagExtra, kStatefulReason);
8241
+ }
8242
+ },
8243
+ exit(tag) {
8244
+ const tagExtra = tag.node.extra;
8245
+ if (tagExtra[kStaticDisplay] === true) return;
8246
+ const tagSection = getSection(tag);
8247
+ const nodeBinding = getOptimizedOnlyChildNodeBinding(tag, tagSection);
8248
+ if (tagExtra[kStaticDisplay] === void 0) addSerializeExpr(tagSection, tagExtra, nodeBinding);
8249
+ }
8250
+ },
8251
+ translate: translateByTarget({
8252
+ html: {
8253
+ enter(tag) {
8254
+ const tagExtra = tag.node.extra;
8255
+ flushBefore(tag);
8256
+ const staticDisplay = tagExtra[kStaticDisplay];
8257
+ if (staticDisplay === true) return;
8258
+ if (staticDisplay === false) {
8259
+ writeTo(tag)`<t hidden>`;
8260
+ return;
8261
+ }
8262
+ const display = tag.node.attributes[0].value;
8263
+ if (!_marko_compiler.types.isIdentifier(display) && !isLiteral(display)) {
8264
+ const displayRef = generateUidIdentifier("show");
8265
+ tag.insertBefore(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(displayRef, display)]));
8266
+ tagExtra[kDisplayRef] = displayRef;
8267
+ }
8268
+ },
8269
+ exit(tag) {
8270
+ const tagExtra = tag.node.extra;
8271
+ const staticDisplay = tagExtra[kStaticDisplay];
8272
+ if (staticDisplay === false) writeTo(tag)`</t>`;
8273
+ flushInto(tag);
8274
+ const bodyStatements = tag.node.body.body;
8275
+ if (staticDisplay !== void 0) {
8276
+ for (const replacement of tag.replaceWithMultiple(bodyStatements)) replacement.skip();
8277
+ return;
8278
+ }
8279
+ const tagSection = getSection(tag);
8280
+ const display = tagExtra[kDisplayRef] || tag.node.attributes[0].value;
8281
+ const nodeBinding = getOptimizedOnlyChildNodeBinding(tag, tagSection);
8282
+ const onlyChildParentTagName = getOnlyChildParentTagName(tag);
8283
+ const singleNode = tagExtra[kSingleNodeBody];
8284
+ const statefulReason = getSerializeReason(tagSection, kStatefulReason);
8285
+ const markerSerializeReason = getSerializeReason(tagSection, nodeBinding);
8286
+ const skipParentEnd = onlyChildParentTagName && markerSerializeReason;
8287
+ if (skipParentEnd) getParentTag(tag).node.extra[kSkipEndTag] = true;
8288
+ const statefulSerializeArg = getSerializeGuard(tagSection, statefulReason, !(skipParentEnd || singleNode));
8289
+ const markerSerializeArg = getSerializeGuard(tagSection, markerSerializeReason, !statefulSerializeArg);
8290
+ let startMark;
8291
+ if (!singleNode) {
8292
+ startMark = getSerializeGuard(tagSection, markerSerializeReason, false);
8293
+ if (skipParentEnd) startMark = _marko_compiler.types.logicalExpression("&&", startMark, getSerializeGuard(tagSection, statefulReason, false));
8294
+ }
8295
+ for (const replacement of tag.replaceWithMultiple([
8296
+ _marko_compiler.types.expressionStatement(callRuntime("_show_start", _marko_compiler.types.cloneNode(display, true), startMark)),
8297
+ ...bodyStatements,
8298
+ _marko_compiler.types.expressionStatement(callRuntime("_show_end", getScopeIdIdentifier(tagSection), getScopeAccessorLiteral(nodeBinding), display, markerSerializeArg, statefulSerializeArg, skipParentEnd ? _marko_compiler.types.stringLiteral(`</${onlyChildParentTagName}>`) : singleNode ? _marko_compiler.types.numericLiteral(0) : void 0, singleNode ? _marko_compiler.types.numericLiteral(1) : void 0))
8299
+ ])) replacement.skip();
8300
+ }
8301
+ },
8302
+ dom: {
8303
+ enter(tag) {
8304
+ if (tag.node.extra[kStartBinding]) {
8305
+ visit(tag, 37);
8306
+ enterShallow(tag);
8307
+ }
8308
+ },
8309
+ exit(tag) {
8310
+ const tagExtra = tag.node.extra;
8311
+ if (tagExtra[kStaticDisplay] === true) {
8312
+ tag.remove();
8313
+ return;
8314
+ }
8315
+ const tagSection = getSection(tag);
8316
+ const nodeBinding = getOptimizedOnlyChildNodeBinding(tag, tagSection);
8317
+ const startBinding = tagExtra[kStartBinding];
8318
+ const display = tagExtra[kStaticDisplay] === false ? _marko_compiler.types.booleanLiteral(false) : tag.node.attributes[0].value;
8319
+ if (startBinding) {
8320
+ visit(tag, 37);
8321
+ enterShallow(tag);
8322
+ }
8323
+ const signal = getSignal(tagSection, nodeBinding, "show");
8324
+ signal.build = () => {
8325
+ return callRuntime("_show", getScopeAccessorLiteral(nodeBinding, true), startBinding ? getScopeAccessorLiteral(startBinding, true) : void 0);
8326
+ };
8327
+ addValue(tagSection, tagExtra.referencedBindings, signal, display);
8328
+ tag.remove();
8329
+ }
8330
+ }
8331
+ }),
8332
+ parseOptions: { controlFlow: true },
8333
+ autocomplete: [{
8334
+ snippet: "show=${1:condition}",
8335
+ description: "Use to render content that is always mounted but only displayed when the condition is met.",
8336
+ descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#show"
8337
+ }]
8338
+ };
8339
+ function isSingleNodeBody(tag) {
8340
+ let elements = 0;
8341
+ for (const child of tag.get("body").get("body")) {
8342
+ if (child.isMarkoComment()) continue;
8343
+ if (child.isMarkoTag() && analyzeTagNameType(child) === 0 && _marko_compiler.types.isStringLiteral(child.node.name)) elements++;
8344
+ else return false;
8345
+ }
8346
+ return elements === 1;
8347
+ }
8348
+ function isLiteral(expr) {
8349
+ switch (expr.type) {
8350
+ case "BooleanLiteral":
8351
+ case "NumericLiteral":
8352
+ case "StringLiteral":
8353
+ case "NullLiteral": return true;
8354
+ default: return false;
8355
+ }
8356
+ }
8357
+ function assertValidShow(tag) {
8358
+ (0, _marko_compiler_babel_utils.assertNoVar)(tag);
8359
+ (0, _marko_compiler_babel_utils.assertNoArgs)(tag);
8360
+ (0, _marko_compiler_babel_utils.assertNoParams)(tag);
8361
+ assertNoSpreadAttrs(tag);
8362
+ assertHasBody(tag);
8363
+ assertHasValueAttribute(tag);
8364
+ }
8365
+ function assertHasBody(tag) {
8366
+ if (!tag.node.body.body.length) throw tag.get("name").buildCodeFrameError(`The [\`<${getTagName(tag)}>\` tag](https://markojs.com/docs/reference/core-tag#show) requires [body content](https://markojs.com/docs/reference/language#tag-content).`);
8367
+ if (tag.node.body.attributeTags) throw tag.get("name").buildCodeFrameError(`The [\`<${getTagName(tag)}>\` tag](https://markojs.com/docs/reference/core-tag#show) does not support [attribute tags](https://markojs.com/docs/reference/language#attribute-tags).`);
8368
+ }
8369
+ function assertHasValueAttribute(tag) {
8370
+ const { node } = tag;
8371
+ const [valueAttr] = node.attributes;
8372
+ 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).`);
8373
+ 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).`);
8374
+ }
8375
+ //#endregion
8059
8376
  //#region src/translator/core/static.ts
8060
8377
  var static_default = {
8061
8378
  parse(tag) {
@@ -8078,36 +8395,109 @@ var static_default = {
8078
8395
  }]
8079
8396
  };
8080
8397
  //#endregion
8398
+ //#region src/translator/util/style-interpolation.ts
8399
+ const htmlStyleTagAlternateMsg = " For a native html [`<style>` tag](https://markojs.com/docs/reference/core-tag#style) use the `html-style` core tag instead.";
8400
+ function checkStyleInterpolations(tag) {
8401
+ const { body } = tag.node.body;
8402
+ let stringQuote = "";
8403
+ let inComment = false;
8404
+ let groupDepth = 0;
8405
+ let blockDepth = 0;
8406
+ let valueColon = false;
8407
+ let runPlaceholder;
8408
+ let runAfterColon = false;
8409
+ let runDecl = false;
8410
+ const endRun = (selector) => {
8411
+ if (runPlaceholder && !runAfterColon && (selector || runDecl)) throw tag.hub.buildError(runPlaceholder, selector ? styleSelectorMsg : stylePropertyMsg);
8412
+ valueColon = false;
8413
+ runPlaceholder = void 0;
8414
+ };
8415
+ for (let i = 0; i < body.length; i++) {
8416
+ const child = body[i];
8417
+ if (_marko_compiler.types.isMarkoPlaceholder(child)) {
8418
+ if (stringQuote) throw tag.hub.buildError(child, styleStringMsg);
8419
+ if (!runPlaceholder) {
8420
+ runPlaceholder = child;
8421
+ runAfterColon = valueColon;
8422
+ runDecl = blockDepth > 0;
8423
+ }
8424
+ const prev = body[i - 1];
8425
+ if (_marko_compiler.types.isMarkoText(prev) && cssGluedBefore.test(prev.value)) throw tag.hub.buildError(child, styleGluedBeforeMsg);
8426
+ const next = body[i + 1];
8427
+ if (_marko_compiler.types.isMarkoText(next) && cssGluedValue.test(next.value)) throw tag.hub.buildError(child, styleGluedMsg);
8428
+ continue;
8429
+ }
8430
+ const text = child.value;
8431
+ for (let j = 0; j < text.length; j++) {
8432
+ const c = text[j];
8433
+ if (inComment) {
8434
+ if (c === "*" && text[j + 1] === "/") {
8435
+ inComment = false;
8436
+ j++;
8437
+ }
8438
+ } else if (stringQuote) {
8439
+ if (c === "\\") j++;
8440
+ else if (c === stringQuote) stringQuote = "";
8441
+ } else if (c === "\\") j++;
8442
+ else if (c === "/" && text[j + 1] === "*") {
8443
+ inComment = true;
8444
+ j++;
8445
+ } else if (c === "\"" || c === "'") stringQuote = c;
8446
+ else if (c === "(" || c === "[") groupDepth++;
8447
+ else if (c === ")" || c === "]") {
8448
+ if (groupDepth) groupDepth--;
8449
+ } else if (!groupDepth) switch (c) {
8450
+ case ":":
8451
+ if (blockDepth) valueColon = true;
8452
+ break;
8453
+ case "{":
8454
+ endRun(true);
8455
+ blockDepth++;
8456
+ break;
8457
+ case ";":
8458
+ endRun(!blockDepth);
8459
+ break;
8460
+ case "}":
8461
+ endRun(false);
8462
+ if (blockDepth) blockDepth--;
8463
+ break;
8464
+ }
8465
+ }
8466
+ }
8467
+ endRun(!blockDepth);
8468
+ }
8469
+ const styleInterpolationMsg = "A `${...}` interpolation in a [`<style>` tag](https://markojs.com/docs/reference/core-tag#style) is substituted as a `var(--…)` custom property reference, which";
8470
+ const styleSelectorMsg = `${styleInterpolationMsg} only resolves in a declaration value, not in a selector or at-rule prelude. For a native html [\`<style>\` tag](https://markojs.com/docs/reference/core-tag#style) use the \`html-style\` core tag instead.`;
8471
+ const stylePropertyMsg = `${styleInterpolationMsg} cannot be used as a property name. For a native html [\`<style>\` tag](https://markojs.com/docs/reference/core-tag#style) use the \`html-style\` core tag instead.`;
8472
+ const styleStringMsg = `${styleInterpolationMsg} is not substituted inside a quoted CSS string — the literal text \`var(--…)\` would be rendered instead of the value. For a native html [\`<style>\` tag](https://markojs.com/docs/reference/core-tag#style) use the \`html-style\` core tag instead.`;
8473
+ const styleGluedMsg = `${styleInterpolationMsg} CSS does not re-tokenize, so a unit written directly after it (eg \`\${x}px\`) becomes the invalid \`var(--…)px\`. Move the unit into the interpolated value (so it resolves to eg \`"10px"\`) or use \`calc(var(--…) * 1px)\`.`;
8474
+ const styleGluedBeforeMsg = `${styleInterpolationMsg} CSS does not re-tokenize, so text written directly before it (eg \`10\${x}\`) merges with the \`var(--…)\` into a single invalid token. Add whitespace before the interpolation or move the text into the interpolated value.`;
8475
+ const cssGluedValue = /^(?:[%.\d]|(?:p[xtc]|in|[cm]m|q|r?em|ex|ch|r?lh|v[whib]|vmin|vmax|fr|deg|g?rad|turn|m?s|k?hz|dp(?:i|cm|px)|cq[whib]|cqmin|cqmax)(?![\w-]))/i;
8476
+ const cssGluedBefore = /[\w%]$/;
8477
+ //#endregion
8081
8478
  //#region src/translator/core/style.ts
8082
8479
  const STYLE_EXT_REG = /^style((?:\.[a-zA-Z0-9$_-]+)+)?/;
8083
- const htmlStyleTagAlternateMsg = " For a native html [`<style>` tag](https://markojs.com/docs/reference/core-tag#style) use the `html-style` core tag instead.";
8084
8480
  var style_default = {
8085
8481
  analyze(tag) {
8086
8482
  (0, _marko_compiler_babel_utils.assertNoArgs)(tag);
8087
8483
  (0, _marko_compiler_babel_utils.assertNoParams)(tag);
8088
8484
  (0, _marko_compiler_babel_utils.assertNoAttributeTags)(tag);
8089
8485
  const { node, hub: { file } } = tag;
8090
- const extClass = (STYLE_EXT_REG.exec(node.rawValue || "")?.[1]?.slice(1))?.replace(/\./g, " ");
8091
- for (const attr of node.attributes) {
8092
- if (attr.start == null && attr.type === "MarkoAttribute" && attr.name === "class" && attr.value.type === "StringLiteral" && attr.value.value === extClass) continue;
8093
- throw tag.hub.buildError(attr.value, "The `style` does not support html attributes." + htmlStyleTagAlternateMsg);
8486
+ assertNoStyleAttributes(tag);
8487
+ const names = collectDynamicStyleNames(tag);
8488
+ if (names) {
8489
+ checkStyleInterpolations(tag);
8490
+ checkDynamicStylePlacement(tag);
8094
8491
  }
8095
- for (const child of node.body.body) if (child.type !== "MarkoText") throw tag.hub.buildError(child, "The [`<style>` tag](https://markojs.com/docs/reference/core-tag#style) currently only supports static content." + htmlStyleTagAlternateMsg);
8096
- const importPath = getStyleImportPath(file, node);
8492
+ const importPath = getStyleImportPath(file, node, names);
8097
8493
  (node.extra ??= {}).styleImportPath = importPath;
8098
8494
  if (importPath) addAssetImport(file, importPath);
8495
+ if (names) analyzeDynamicStyle(tag, names);
8099
8496
  },
8100
- translate(tag) {
8101
- const { node, hub: { file } } = tag;
8102
- const importPath = node.extra?.styleImportPath;
8103
- if (importPath) if (!node.var) (0, _marko_compiler_babel_utils.getProgram)().node.body.push(_marko_compiler.types.importDeclaration([], _marko_compiler.types.stringLiteral(importPath)));
8104
- else if (_marko_compiler.types.isIdentifier(node.var)) (0, _marko_compiler_babel_utils.getProgram)().node.body.push(_marko_compiler.types.importDeclaration([_marko_compiler.types.importNamespaceSpecifier(node.var)], _marko_compiler.types.stringLiteral(importPath)));
8105
- else {
8106
- const varDecl = _marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(node.var, (0, _marko_compiler_babel_utils.importStar)(file, importPath, "style"))]);
8107
- (0, _marko_compiler_babel_utils.getProgram)().node.body.push(isOutputDOM() ? varDecl : _marko_compiler.types.markoScriptlet([varDecl], true));
8108
- }
8109
- tag.remove();
8110
- },
8497
+ translate: translateByTarget({
8498
+ html: { exit: translateHTML$1 },
8499
+ dom: { exit: translateDOM$1 }
8500
+ }),
8111
8501
  parseOptions: {
8112
8502
  html: false,
8113
8503
  text: true,
@@ -8116,34 +8506,154 @@ var style_default = {
8116
8506
  },
8117
8507
  attributes: {}
8118
8508
  };
8509
+ function analyzeDynamicStyle(tag, names) {
8510
+ const { node } = tag;
8511
+ const section = getOrCreateSection(tag);
8512
+ const binding = createBinding("#style", 0, section);
8513
+ node.extra.dynamicStyle = {
8514
+ names,
8515
+ binding
8516
+ };
8517
+ let exprExtras = mergeReferences(section, node, []);
8518
+ for (const value of dynamicStyleValues(node)) exprExtras = push(exprExtras, value.extra ??= {});
8519
+ addSerializeExpr(section, exprExtras, binding);
8520
+ }
8521
+ function collectDynamicStyleNames(tag) {
8522
+ let names;
8523
+ let index = 0;
8524
+ for (const child of tag.node.body.body) if (_marko_compiler.types.isMarkoPlaceholder(child)) {
8525
+ if (!names) {
8526
+ names = [];
8527
+ index = dynamicStyleNameOffset(tag);
8528
+ }
8529
+ names.push(dynamicStyleName(tag, index++));
8530
+ } else if (!_marko_compiler.types.isMarkoText(child)) throw tag.hub.buildError(child, "The [`<style>` tag](https://markojs.com/docs/reference/core-tag#style) only supports text and `${...}` interpolations." + htmlStyleTagAlternateMsg);
8531
+ return names;
8532
+ }
8533
+ function dynamicStyleNameOffset(tag) {
8534
+ const { start } = tag.node;
8535
+ let offset = 0;
8536
+ if (start != null) _marko_compiler.types.traverseFast((0, _marko_compiler_babel_utils.getProgram)().node, (node) => {
8537
+ const dynamicStyle = node.extra?.dynamicStyle;
8538
+ if (dynamicStyle && node.start != null && node.start < start) offset += dynamicStyle.names.length;
8539
+ });
8540
+ return offset;
8541
+ }
8542
+ const styleNameUnsafeReg = /[^a-zA-Z0-9_]/g;
8543
+ const encodeStyleNameChar = (c) => "-" + c.charCodeAt(0).toString(36);
8544
+ function dynamicStyleName(tag, index) {
8545
+ const { file } = tag.hub;
8546
+ const id = (0, _marko_compiler_babel_utils.getTemplateId)(file.markoOpts, file.opts.filename, index.toString(36));
8547
+ return "--" + ((file.markoOpts.runtimeId || "M_") + id).replace(styleNameUnsafeReg, encodeStyleNameChar);
8548
+ }
8549
+ function checkDynamicStylePlacement(tag) {
8550
+ for (const sibling of tag.getAllPrevSiblings()) {
8551
+ if (isCoreTagName(sibling, "style")) continue;
8552
+ if (sibling.isMarkoText() ? /\S/.test(sibling.node.value) : getNodeContentType(sibling, "startType") !== null) {
8553
+ (0, _marko_compiler_babel_utils.diagnosticWarn)(tag, { label: "The `${...}` values of a [`<style>` tag](https://markojs.com/docs/reference/core-tag#style) only apply to elements rendered after it, so the content before this tag will not receive them. Move the `<style>` tag above the content it styles." });
8554
+ return;
8555
+ }
8556
+ }
8557
+ }
8558
+ function assertNoStyleAttributes(tag) {
8559
+ const { node } = tag;
8560
+ const extClass = (STYLE_EXT_REG.exec(node.rawValue || "")?.[1]?.slice(1))?.replace(/\./g, " ");
8561
+ for (const attr of node.attributes) {
8562
+ if (attr.start == null && attr.type === "MarkoAttribute" && attr.name === "class" && attr.value.type === "StringLiteral" && attr.value.value === extClass) continue;
8563
+ throw tag.hub.buildError(attr.value, "The `style` does not support html attributes." + htmlStyleTagAlternateMsg);
8564
+ }
8565
+ }
8566
+ function translateHTML$1(tag) {
8567
+ const { node } = tag;
8568
+ const dynamic = node.extra?.dynamicStyle;
8569
+ if (dynamic) {
8570
+ const { binding } = dynamic;
8571
+ const section = getSection(tag);
8572
+ writeTo(tag)`${callRuntime("_style_html", buildStyleDecls(node))}`;
8573
+ markNode(tag, binding, getSerializeReason(section, binding));
8574
+ }
8575
+ emitStyleImport(tag);
8576
+ tag.remove();
8577
+ }
8578
+ function translateDOM$1(tag) {
8579
+ const { node } = tag;
8580
+ const dynamic = node.extra?.dynamicStyle;
8581
+ if (dynamic) {
8582
+ const { names, binding } = dynamic;
8583
+ const section = getSection(tag);
8584
+ const write = writeTo(tag);
8585
+ const readEl = () => createScopeReadExpression(binding);
8586
+ visit(tag, 32);
8587
+ write`<style>`;
8588
+ addStatement("render", section, void 0, [_marko_compiler.types.expressionStatement(callRuntime("_attr_nonce", scopeIdentifier, getScopeAccessorLiteral(binding))), _marko_compiler.types.expressionStatement(callRuntime("_style_shell", scopeIdentifier, getScopeAccessorLiteral(binding)))], void 0, true);
8589
+ dynamicStyleValues(node).forEach((value, i) => {
8590
+ const valueRef = value.extra?.referencedBindings;
8591
+ addStatement("render", section, valueRef, _marko_compiler.types.expressionStatement(callRuntime("_style_rule_item", readEl(), _marko_compiler.types.stringLiteral(names[i]), value)), void 0, !valueRef);
8592
+ });
8593
+ write`</style>`;
8594
+ }
8595
+ emitStyleImport(tag);
8596
+ tag.remove();
8597
+ }
8598
+ function dynamicStyleValues(node) {
8599
+ const values = [];
8600
+ for (const child of node.body.body) if (_marko_compiler.types.isMarkoPlaceholder(child)) values.push(child.value);
8601
+ return values;
8602
+ }
8603
+ function emitStyleImport(tag) {
8604
+ const { node, hub: { file } } = tag;
8605
+ const importPath = node.extra?.styleImportPath;
8606
+ if (!importPath) return;
8607
+ if (!node.var) (0, _marko_compiler_babel_utils.getProgram)().node.body.push(_marko_compiler.types.importDeclaration([], _marko_compiler.types.stringLiteral(importPath)));
8608
+ else if (_marko_compiler.types.isIdentifier(node.var)) (0, _marko_compiler_babel_utils.getProgram)().node.body.push(_marko_compiler.types.importDeclaration([_marko_compiler.types.importNamespaceSpecifier(node.var)], _marko_compiler.types.stringLiteral(importPath)));
8609
+ else {
8610
+ const varDecl = _marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(node.var, (0, _marko_compiler_babel_utils.importStar)(file, importPath, "style"))]);
8611
+ (0, _marko_compiler_babel_utils.getProgram)().node.body.push(isOutputDOM() ? varDecl : _marko_compiler.types.markoScriptlet([varDecl], true));
8612
+ }
8613
+ }
8614
+ function buildStyleDecls(node) {
8615
+ const { names } = node.extra.dynamicStyle;
8616
+ const parts = [];
8617
+ dynamicStyleValues(node).forEach((value, i) => {
8618
+ parts.push(`${names[i]}:`);
8619
+ parts.push(callRuntime("_escape_style_value", value));
8620
+ parts.push(";");
8621
+ });
8622
+ return normalizeStringExpression(parts);
8623
+ }
8119
8624
  /**
8120
8625
  * Resolves a `<style>` block's text content to its client side import path
8121
8626
  * (eg `./template.marko.css`) by handing the css off to the configured
8122
8627
  * `resolveVirtualDependency` hook.
8123
8628
  */
8124
- function getStyleImportPath(file, node) {
8629
+ function getStyleImportPath(file, node, names) {
8125
8630
  const { resolveVirtualDependency } = file.markoOpts;
8126
8631
  if (!resolveVirtualDependency) return;
8127
8632
  const { filename, sourceMaps } = file.opts;
8128
8633
  let ext = STYLE_EXT_REG.exec(node.rawValue || "")?.[1] || ".css";
8129
8634
  if (node.var && !/\.module\./.test(ext)) ext = ".module" + ext;
8130
- let magicString;
8635
+ const magicString = sourceMaps ? new magic_string.default(file.code, { filename }) : void 0;
8131
8636
  let code = "";
8132
8637
  let last = 0;
8133
8638
  let map;
8639
+ let nameIndex = 0;
8134
8640
  for (const child of node.body.body) {
8135
- code += child.value;
8136
- if (sourceMaps) {
8641
+ const placeholder = _marko_compiler.types.isMarkoPlaceholder(child);
8642
+ const text = placeholder ? `var(${names[nameIndex++]})` : child.value;
8643
+ if (magicString) {
8137
8644
  const start = (0, _marko_compiler_babel_utils.getStart)(file, child);
8138
- if (start !== null) {
8139
- magicString ||= new magic_string.default(file.code, { filename });
8645
+ if (start === null) magicString.appendLeft(last, text);
8646
+ else {
8647
+ const end = (0, _marko_compiler_babel_utils.getEnd)(file, child);
8140
8648
  if (start > last) magicString.remove(last, start);
8141
- last = (0, _marko_compiler_babel_utils.getEnd)(file, child);
8649
+ if (placeholder) magicString.update(start, end, text);
8650
+ last = end;
8142
8651
  }
8143
- }
8652
+ } else code += text;
8144
8653
  }
8145
8654
  if (magicString) {
8146
8655
  if (file.code.length > last) magicString.remove(last, file.code.length);
8656
+ code = magicString.toString();
8147
8657
  map = magicString.generateMap({
8148
8658
  source: filename,
8149
8659
  includeContent: true
@@ -8271,6 +8781,7 @@ var core_default = {
8271
8781
  "<return>": return_default,
8272
8782
  "<script>": script_default,
8273
8783
  "<server>": server_default,
8784
+ "<show>": show_default,
8274
8785
  "<static>": static_default,
8275
8786
  "<style>": style_default,
8276
8787
  "<try>": try_default