marko 6.3.34 → 6.3.35

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 (53) hide show
  1. package/cheatsheet.md +2 -2
  2. package/dist/common/constants/accessor-prefix.d.ts +1 -0
  3. package/dist/common/constants/accessor-prefix.debug.d.ts +1 -0
  4. package/dist/common/errors.d.ts +1 -0
  5. package/dist/common/types.d.ts +10 -0
  6. package/dist/debug/dom/catch.feat.js +1 -1
  7. package/dist/debug/dom/catch.feat.mjs +1 -1
  8. package/dist/debug/dom/controllable-input.feat.js +1 -1
  9. package/dist/debug/dom/controllable-input.feat.mjs +1 -1
  10. package/dist/debug/dom/controllable-open.feat.js +1 -1
  11. package/dist/debug/dom/controllable-open.feat.mjs +1 -1
  12. package/dist/debug/dom/controllable-select.feat.js +1 -1
  13. package/dist/debug/dom/controllable-select.feat.mjs +1 -1
  14. package/dist/debug/dom/controllable-textarea.feat.js +1 -1
  15. package/dist/debug/dom/controllable-textarea.feat.mjs +1 -1
  16. package/dist/debug/dom/controllable.feat.js +1 -1
  17. package/dist/debug/dom/controllable.feat.mjs +1 -1
  18. package/dist/debug/{dom-klf8Ec_o.mjs → dom-B57LrRnX.mjs} +34 -16
  19. package/dist/debug/{dom-Bj58jt8y.js → dom-Bt4OoZ-j.js} +34 -16
  20. package/dist/debug/dom.js +1 -1
  21. package/dist/debug/dom.mjs +1 -1
  22. package/dist/debug/html.js +88 -21
  23. package/dist/debug/html.mjs +88 -21
  24. package/dist/dom/catch.feat.js +1 -1
  25. package/dist/dom/catch.feat.mjs +1 -1
  26. package/dist/dom/control-flow.d.ts +1 -0
  27. package/dist/dom/controllable-input.feat.js +1 -1
  28. package/dist/dom/controllable-input.feat.mjs +1 -1
  29. package/dist/dom/controllable-open.feat.js +1 -1
  30. package/dist/dom/controllable-open.feat.mjs +1 -1
  31. package/dist/dom/controllable-select.feat.js +1 -1
  32. package/dist/dom/controllable-select.feat.mjs +1 -1
  33. package/dist/dom/controllable-textarea.feat.js +1 -1
  34. package/dist/dom/controllable-textarea.feat.mjs +1 -1
  35. package/dist/dom/controllable.feat.js +1 -1
  36. package/dist/dom/controllable.feat.mjs +1 -1
  37. package/dist/dom/signals.d.ts +3 -3
  38. package/dist/{dom-6hBvZW7X.mjs → dom-BP2XSglG.mjs} +19 -12
  39. package/dist/{dom-B-XpL2_H.js → dom-BeF9xIzO.js} +19 -12
  40. package/dist/dom.js +1 -1
  41. package/dist/dom.mjs +1 -1
  42. package/dist/html/dynamic-tag.d.ts +1 -1
  43. package/dist/html/serializer.d.ts +9 -1
  44. package/dist/html/template.d.ts +1 -0
  45. package/dist/html/writer.d.ts +1 -0
  46. package/dist/html.js +15 -9
  47. package/dist/html.mjs +15 -9
  48. package/dist/translator/index.js +137 -70
  49. package/dist/translator/util/signals.d.ts +2 -0
  50. package/dist/translator/util/translate-var.d.ts +1 -1
  51. package/dist/translator/visitors/export-declaration.d.ts +8 -0
  52. package/package.json +4 -4
  53. package/tags/let.d.marko +3 -4
@@ -126,6 +126,7 @@ var accessor_prefix_debug_exports = /* @__PURE__ */ __exportAll({
126
126
  ControlledValue: () => ControlledValue$1,
127
127
  DynamicHTMLLastChild: () => DynamicHTMLLastChild$1,
128
128
  EventAttributes: () => EventAttributes$1,
129
+ IdFallback: () => IdFallback$1,
129
130
  KeyedScopes: () => KeyedScopes$1,
130
131
  Lifecycle: () => Lifecycle$1,
131
132
  Promise: () => Promise$2,
@@ -141,6 +142,7 @@ const ControlledType$1 = "ControlledType:";
141
142
  const ControlledValue$1 = "ControlledValue:";
142
143
  const DynamicHTMLLastChild$1 = "DynamicHTMLLastChild:";
143
144
  const EventAttributes$1 = "EventAttributes:";
145
+ const IdFallback$1 = "IdFallback:";
144
146
  const KeyedScopes$1 = "KeyedScopes:";
145
147
  const Lifecycle$1 = "Lifecycle:";
146
148
  const Promise$2 = "Promise:";
@@ -203,6 +205,7 @@ const StartNode$1 = "#StartNode";
203
205
  const Subscriptions$1 = "#Subscriptions";
204
206
  const TagVariable$1 = "#TagVariable";
205
207
  const TagVariableChange$2 = "#TagVariableChange";
208
+ const Owner$1 = "owner";
206
209
  //#endregion
207
210
  //#region src/translator/util/evaluate.ts
208
211
  function evaluate(value) {
@@ -933,6 +936,7 @@ var accessor_prefix_exports = /* @__PURE__ */ __exportAll({
933
936
  ControlledValue: () => "G",
934
937
  DynamicHTMLLastChild: () => "H",
935
938
  EventAttributes: () => "I",
939
+ IdFallback: () => "J",
936
940
  KeyedScopes: () => "O",
937
941
  Lifecycle: () => "K",
938
942
  Promise: () => "L",
@@ -1937,7 +1941,10 @@ function assertExclusiveAttrs(attrs, onError = throwErr) {
1937
1941
  (exclusiveAttrs ||= []).push("checkedValueChange");
1938
1942
  if ("checked" in attrs) exclusiveAttrs.push("checked");
1939
1943
  }
1940
- if (attrs.valueChange) (exclusiveAttrs ||= []).push("valueChange");
1944
+ if (attrs.valueChange) {
1945
+ (exclusiveAttrs ||= []).push("valueChange");
1946
+ if ("checked" in attrs && !exclusiveAttrs.includes("checked")) exclusiveAttrs.push("checked");
1947
+ }
1941
1948
  if (exclusiveAttrs && exclusiveAttrs.length > 1) onError(`The attributes ${joinWithAnd(exclusiveAttrs)} are mutually exclusive.`);
1942
1949
  }
1943
1950
  }
@@ -1957,8 +1964,8 @@ function joinWithAnd(a) {
1957
1964
  function _unescaped(val) {
1958
1965
  return val ? val + "" : val === 0 ? "0" : "";
1959
1966
  }
1960
- const unsafeXMLReg = /[<&]/g;
1961
- const replaceUnsafeXML = (c) => c === "&" ? "&amp;" : "&lt;";
1967
+ const unsafeXMLReg = /[<&\r]/g;
1968
+ const replaceUnsafeXML = (c) => c === "&" ? "&amp;" : c === "<" ? "&lt;" : "&#13;";
1962
1969
  const escapeXMLStr = (str) => unsafeXMLReg.test(str) ? str.replace(unsafeXMLReg, replaceUnsafeXML) : str;
1963
1970
  function _escape(val) {
1964
1971
  return val ? escapeXMLStr(val + "") : val === 0 ? "0" : "";
@@ -1987,6 +1994,9 @@ function getContext(key) {
1987
1994
  function getState() {
1988
1995
  return $chunk.boundary.state;
1989
1996
  }
1997
+ function rendererKey(renderer) {
1998
+ return renderer?.["owner"] === void 0 ? renderer?.["id"] || renderer : renderer["id"] + " " + renderer[Owner$1];
1999
+ }
1990
2000
  function getScopeById(scopeId) {
1991
2001
  if (scopeId !== void 0) return $chunk.boundary.state.scopes.get(scopeId);
1992
2002
  }
@@ -2081,7 +2091,7 @@ function _attr_textarea_value(scopeId, nodeAccessor, value, valueChange, seriali
2081
2091
  }
2082
2092
  function _textarea_value(value) {
2083
2093
  const escaped = _escape(normalizeStrAttrValue(value));
2084
- return escaped[0] === "\n" || escaped[0] === "\r" ? "\n" + escaped : escaped;
2094
+ return escaped[0] === "\n" ? "\n" + escaped : escaped;
2085
2095
  }
2086
2096
  function _attr_input_value(scopeId, nodeAccessor, value, valueChange, serializeType) {
2087
2097
  if (valueChange) writeControlledScope(2, scopeId, nodeAccessor, void 0, valueChange, serializeType);
@@ -2276,7 +2286,7 @@ let _dynamic_tag = (scopeId, accessor, tag, inputOrArgs, content, inputIsArgs, s
2276
2286
  }
2277
2287
  }
2278
2288
  if (rendered) {
2279
- if (shouldResume) writeScope(scopeId, { [ConditionalRenderer$1 + accessor]: renderer?.["id"] || renderer });
2289
+ if (shouldResume) writeScope(scopeId, { [ConditionalRenderer$1 + accessor]: rendererKey(renderer) });
2280
2290
  } else _scope_id();
2281
2291
  return result;
2282
2292
  };
@@ -3012,10 +3022,25 @@ function setSectionSerializedValue(section, prop, expression) {
3012
3022
  }
3013
3023
  function setBindingSerializedValue(section, binding, expression, prefix) {
3014
3024
  const reason = getSerializeReason(section, binding, prefix);
3015
- if (reason) getSerializedAccessors(section).set(prefix === void 0 ? getScopeAccessor(binding) : getPrefixedScopeAccessor(binding, prefix), {
3025
+ if (reason) if (prefix === void 0) getSerializedAccessors(section).set(getScopeAccessor(binding), {
3016
3026
  expression,
3017
3027
  reason
3018
3028
  });
3029
+ else {
3030
+ const accessor = getPrefixedScopeAccessor(binding, prefix);
3031
+ getSerializedAccessors(section).set(accessor, {
3032
+ expression,
3033
+ reason
3034
+ });
3035
+ if (!isOptimize() && prefix === getAccessorPrefix().TagVariableChange) {
3036
+ const { root, access } = getDebugScopeAccess(binding);
3037
+ setSectionDebugVar(section, accessor, `${root.name + access}Change`, root.loc);
3038
+ }
3039
+ }
3040
+ }
3041
+ const [getSectionDebugVars] = createSectionState("sectionDebugVars", () => /* @__PURE__ */ new Map());
3042
+ function setSectionDebugVar(section, accessor, name, loc) {
3043
+ if (!isOptimize()) getSectionDebugVars(section).set(accessor, loc ? [name, `${loc.start.line}:${loc.start.column + 1}`] : [name]);
3019
3044
  }
3020
3045
  const nonAnalyzedForceSerializedSection = /* @__PURE__ */ new WeakSet();
3021
3046
  function setSerializedValue(section, key, expression) {
@@ -3354,7 +3379,7 @@ function writeSignals(section) {
3354
3379
  if (signal.build) {
3355
3380
  let value = signal.build();
3356
3381
  const buildsEagerForward = _marko_compiler.types.isIdentifier(value);
3357
- if (!value || !signal.register && _marko_compiler.types.isFunction(value) && _marko_compiler.types.isBlockStatement(value.body) && !value.body.body.length) return;
3382
+ if (!value || !signal.register && !signal.referenced && _marko_compiler.types.isFunction(value) && _marko_compiler.types.isBlockStatement(value.body) && !value.body.body.length) return;
3358
3383
  if (_marko_compiler.types.isCallExpression(value)) replaceNullishAndEmptyFunctionsWith0(value.arguments);
3359
3384
  if (signal.register) value = callRuntime("_var_resume", _marko_compiler.types.stringLiteral(getResumeRegisterId(section, signal.referencedBindings, "var")), value);
3360
3385
  if (buildsEagerForward) forEach(signal.forwards, writeSignal);
@@ -3401,7 +3426,8 @@ function writeRegisteredFns() {
3401
3426
  params = [localsIdentifier];
3402
3427
  if (registeredFn.referencedBindings || registeredFn.referencesScope) prologue = [_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(scopeIdentifier, _marko_compiler.types.memberExpression(localsIdentifier, _marko_compiler.types.identifier(getAccessorProp().Owner)))])];
3403
3428
  } else params = [scopeIdentifier];
3404
- fn = _marko_compiler.types.functionDeclaration(_marko_compiler.types.identifier(registeredFn.id), params, _marko_compiler.types.blockStatement(toReturnedFunction(registeredFn.node, prologue)));
3429
+ const body = toReturnedFunction(registeredFn.node, prologue);
3430
+ fn = _marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(_marko_compiler.types.identifier(registeredFn.id), _marko_compiler.types.arrowFunctionExpression(params, body.length === 1 && body[0].type === "ReturnStatement" ? body[0].argument : _marko_compiler.types.blockStatement(body)))]);
3405
3431
  } else if (registeredFn.node.type === "FunctionDeclaration" && registeredFn.node.id?.name === registeredFn.id) fn = registeredFn.node;
3406
3432
  else fn = _marko_compiler.types.functionDeclaration(_marko_compiler.types.identifier(registeredFn.id), registeredFn.node.params, registeredFn.node.body.type === "BlockStatement" ? registeredFn.node.body : _marko_compiler.types.blockStatement([_marko_compiler.types.returnStatement(registeredFn.node.body)]), registeredFn.node.generator, registeredFn.node.async);
3407
3433
  statements.push(fn);
@@ -3507,6 +3533,7 @@ function writeHTMLResumeStatements(path) {
3507
3533
  const writeScopeArgs = [scopeIdIdentifier, _marko_compiler.types.objectExpression(serializedProperties)];
3508
3534
  if (debug) {
3509
3535
  writeScopeArgs.push(_marko_compiler.types.stringLiteral(path.hub.file.opts.filenameRelative), section.loc && section.loc.start.line != null ? _marko_compiler.types.stringLiteral(`${section.loc.start.line}:${section.loc.start.column + 1}`) : _marko_compiler.types.numericLiteral(0));
3536
+ for (const [accessor, varLoc] of getSectionDebugVars(section)) (debugVars ||= []).push(toObjectProperty(accessor, _marko_compiler.types.valueToNode(varLoc)));
3510
3537
  if (debugVars) writeScopeArgs.push(_marko_compiler.types.objectExpression(debugVars));
3511
3538
  }
3512
3539
  body.push(_marko_compiler.types.expressionStatement(getExprIfSerialized(section, sectionSerializeReason, writeScopeBuilder ? writeScopeBuilder(callRuntime("_scope", ...writeScopeArgs)) : callRuntime("_scope", ...writeScopeArgs))));
@@ -3560,7 +3587,7 @@ function replaceAssignedNode(node) {
3560
3587
  case "UpdateExpression": {
3561
3588
  const { extra } = node.argument;
3562
3589
  if (isAssignedBindingExtra(extra)) {
3563
- let builtAssignment = getBuildAssignment(extra)?.(extra.section, _marko_compiler.types.binaryExpression(node.operator === "++" ? "+" : "-", createScopeReadExpression(extra.assignment, extra.section), _marko_compiler.types.numericLiteral(1)));
3590
+ let builtAssignment = getBuildAssignment(extra)?.(extra.section, _marko_compiler.types.binaryExpression(node.operator === "++" ? "+" : "-", _marko_compiler.types.unaryExpression("+", createScopeReadExpression(extra.assignment, extra.section)), _marko_compiler.types.numericLiteral(1)));
3564
3591
  if (builtAssignment) {
3565
3592
  if (!node.prefix) {
3566
3593
  builtAssignment = _marko_compiler.types.binaryExpression(node.operator === "++" ? "-" : "+", builtAssignment, _marko_compiler.types.numericLiteral(1));
@@ -4753,7 +4780,7 @@ function buildContent(body) {
4753
4780
  }
4754
4781
  if (dynamicSerializeReason) body.node.body.unshift(getScopeReasonDeclaration(bodySection));
4755
4782
  else body.node.body.unshift(_marko_compiler.types.expressionStatement(callRuntime("_scope_reason")));
4756
- return callRuntime(serialized ? "_content_resume" : "_content", _marko_compiler.types.stringLiteral(getResumeRegisterId(bodySection, "content")), _marko_compiler.types.arrowFunctionExpression(body.node.params, _marko_compiler.types.blockStatement(body.node.body)), serialized ? getScopeIdIdentifier(getSection(getAttributeTagParent(body.parentPath))) : void 0);
4783
+ return callRuntime(serialized ? "_content_resume" : "_content", _marko_compiler.types.stringLiteral(getResumeRegisterId(bodySection, "content")), _marko_compiler.types.arrowFunctionExpression(body.node.params, _marko_compiler.types.blockStatement(body.node.body)), getScopeIdIdentifier(getSection(getAttributeTagParent(body.parentPath))));
4757
4784
  } else {
4758
4785
  if (isSectionRendererElided(bodySection)) return;
4759
4786
  return _marko_compiler.types.callExpression(_marko_compiler.types.identifier(bodySection.name), bodySection.referencedLocalClosures ? [scopeIdentifier, _marko_compiler.types.objectExpression(toArray(bodySection.referencedLocalClosures, (ref) => {
@@ -4849,6 +4876,11 @@ var native_tag_default = {
4849
4876
  else if (!_marko_compiler.types.isMarkoText(child)) throw tag.hub.buildError(child, `Only text is allowed inside a \`<${tagName}>\`.`);
4850
4877
  }
4851
4878
  relatedControllable ||= getRelatedControllable(tagName, seen);
4879
+ const valueChangeEval = tagName === "input" && seen.valueChange ? evaluate(seen.valueChange.value) : void 0;
4880
+ if (valueChangeEval && !(valueChangeEval.confident && valueChangeEval.computed == null) && getInputValueMode(seen.type) === "attribute") {
4881
+ const type = evaluate(seen.type.value).computed;
4882
+ throw tag.hub.buildError(seen.valueChange, `\`valueChange\` cannot be used on a \`type="${type}"\` \`<input>\` — user interaction can never change its \`value\`.` + (/^[cr]/i.test(type) ? " Bind `checked` or `checkedValue` instead." : ""));
4883
+ }
4852
4884
  if (relatedControllable && relatedControllable.attrs[1]) hasEventHandlers = true;
4853
4885
  if (node.var || hasDynamicAttributes || hasEventHandlers || textPlaceholders || injectNonce || seen.content && tagName !== "meta" && !node.body.body.length || isDynamicControllable(relatedControllable)) {
4854
4886
  const tagExtra = node.extra ??= {};
@@ -4952,6 +4984,20 @@ var native_tag_default = {
4952
4984
  const usedAttrs = getUsedAttrs(tagName, tag.node);
4953
4985
  const { staticAttrs, staticControllable, staticContentAttr, skipExpression, injectNonce } = usedAttrs;
4954
4986
  let { spreadExpression } = usedAttrs;
4987
+ if (!isOptimize() && nodeBinding) {
4988
+ const changeAttr = staticControllable?.attrs[1];
4989
+ if (changeAttr) {
4990
+ const handler = evaluate(changeAttr.value);
4991
+ if (!(handler.confident && handler.computed == null)) setSectionDebugVar(tagSection, getPrefixedScopeAccessor(nodeBinding, getAccessorPrefix().ControlledHandler), changeAttr.name, changeAttr.loc);
4992
+ } else if (spreadExpression) {
4993
+ const spreads = tag.node.attributes.filter((attr) => _marko_compiler.types.isMarkoSpreadAttribute(attr));
4994
+ const spreadLoc = spreads.length === 1 && spreads[0].value.loc;
4995
+ if (spreadLoc && spreadLoc.start.index != null) {
4996
+ const name = "..." + tag.hub.file.code.slice(spreadLoc.start.index, spreadLoc.end.index);
4997
+ for (const prefix of [getAccessorPrefix().ControlledHandler, getAccessorPrefix().EventAttributes]) if (prefix !== getAccessorPrefix().ControlledHandler || getSpreadControllableValueProps(tagName)) setSectionDebugVar(tagSection, getPrefixedScopeAccessor(nodeBinding, prefix), name, spreadLoc);
4998
+ }
4999
+ }
5000
+ }
4955
5001
  if (tagName === "select" && (staticControllable || spreadExpression)) flushBefore(tag);
4956
5002
  write`<${tagName}`;
4957
5003
  if (injectNonce) write`${callRuntime("_attr_nonce")}`;
@@ -5128,7 +5174,7 @@ var native_tag_default = {
5128
5174
  stmt = _marko_compiler.types.expressionStatement(callRuntime(`_attr_${name}_items`, nodeExpr, _marko_compiler.types.objectExpression(props)));
5129
5175
  }
5130
5176
  }
5131
- if (stmt) addStatement("render", tagSection, valueReferences, stmt, !!meta.dynamicItems);
5177
+ if (stmt) addStatement("render", tagSection, valueReferences, stmt, true);
5132
5178
  }
5133
5179
  break;
5134
5180
  }
@@ -6019,7 +6065,7 @@ function getChangeHandler(tag, attr) {
6019
6065
  if (!existingChangedAttr) {
6020
6066
  const bindingIdentifierPath = binding.path.getOuterBindingIdentifierPaths()[binding.identifier.name];
6021
6067
  let changeAttrExpr = bindingIdentifierPath ? bindingIdentifierPath.parentPath === binding.path ? buildChangeHandlerFunction(attr.value, modifier) : bindingIdentifierPath.parentPath.isObjectProperty() ? getChangeHandlerFromObjectPattern(bindingIdentifierPath.parentPath) : void 0 : void 0;
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.");
6068
+ 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.` : bindingIdentifierPath?.parentPath?.isObjectProperty({ computed: true }) ? `Cannot two-way bind to \`${attr.value.name}\` because it is destructured with a dynamically computed key, so its change handler cannot be derived. Use a static key or pass an explicit \`${changeAttrName}\` attribute.` : "Unable to bind to value.");
6023
6069
  if (modifier && _marko_compiler.types.isIdentifier(changeAttrExpr)) changeAttrExpr = _marko_compiler.types.logicalExpression("&&", changeAttrExpr, buildModifierForwarder(_marko_compiler.types.cloneNode(changeAttrExpr), modifier));
6024
6070
  const changeHandlerAttr = _marko_compiler.types.markoAttribute(changeAttrName, changeAttrExpr);
6025
6071
  handlerByModifier.set(modifierKey, changeHandlerAttr);
@@ -6060,25 +6106,21 @@ function buildChangeHandlerFunction(id, modifier) {
6060
6106
  function getChangeHandlerFromObjectPattern(parent) {
6061
6107
  let changeKey;
6062
6108
  const pattern = parent.parentPath;
6063
- if (parent.node.computed) {
6064
- changeKey = generateUidIdentifier("dynamicChange");
6065
- pattern.pushContainer("properties", _marko_compiler.types.objectProperty(_marko_compiler.types.binaryExpression("+", parent.get("key").node, _marko_compiler.types.stringLiteral("Change")), changeKey, true));
6066
- } else {
6067
- const searchKey = `${getStringOrIdentifierValue(parent.get("key"))}Change`;
6068
- for (const prop of pattern.get("properties")) if (prop.isObjectProperty()) {
6069
- const propKey = prop.get("key");
6070
- const propValue = prop.get("value");
6071
- if (!prop.node.computed && getStringOrIdentifierValue(propKey) === searchKey && propValue.isIdentifier()) {
6072
- changeKey = propValue.node;
6073
- break;
6074
- }
6109
+ const keyName = getStaticKeyName(parent.node);
6110
+ if (keyName === void 0) return;
6111
+ const searchKey = `${keyName}Change`;
6112
+ for (const prop of pattern.get("properties")) if (prop.isObjectProperty()) {
6113
+ const propValue = prop.get("value");
6114
+ if (getStaticKeyName(prop.node) === searchKey && propValue.isIdentifier()) {
6115
+ changeKey = propValue.node;
6116
+ break;
6075
6117
  }
6076
- if (!changeKey) pattern.unshiftContainer("properties", _marko_compiler.types.objectProperty(_marko_compiler.types.stringLiteral(searchKey), changeKey = generateUidIdentifier(searchKey)));
6077
6118
  }
6119
+ if (!changeKey) pattern.unshiftContainer("properties", _marko_compiler.types.objectProperty(_marko_compiler.types.stringLiteral(searchKey), changeKey = generateUidIdentifier(searchKey)));
6078
6120
  return changeKey;
6079
6121
  }
6080
- function getStringOrIdentifierValue(path) {
6081
- return getLiteralName(path.node);
6122
+ function getStaticKeyName(prop) {
6123
+ return prop.computed && !_marko_compiler.types.isStringLiteral(prop.key) ? void 0 : getLiteralName(prop.key);
6082
6124
  }
6083
6125
  function getLiteralName(node) {
6084
6126
  switch (node.type) {
@@ -6272,7 +6314,7 @@ function crawlSectionsAndSetBinding(tag, binding, properties, skip) {
6272
6314
  }
6273
6315
  //#endregion
6274
6316
  //#region src/translator/util/translate-var.ts
6275
- function translateVar(tag, initialValue, kind = "const") {
6317
+ function translateVar(tag, initialValue, kind = "const", statements) {
6276
6318
  const { node: { var: tagVar } } = tag;
6277
6319
  if (!tagVar) return;
6278
6320
  const tagSection = getOrCreateSection(tag);
@@ -6307,7 +6349,9 @@ function translateVar(tag, initialValue, kind = "const") {
6307
6349
  restPath.remove();
6308
6350
  }
6309
6351
  });
6310
- tag.insertBefore(_marko_compiler.types.variableDeclaration(kind, [_marko_compiler.types.variableDeclarator(tagVar, initialValue)]));
6352
+ const declaration = _marko_compiler.types.variableDeclaration(kind, [_marko_compiler.types.variableDeclarator(tagVar, initialValue)]);
6353
+ if (statements) statements.push(declaration);
6354
+ else tag.insertBefore(declaration);
6311
6355
  }
6312
6356
  function getDestructurePattern(id) {
6313
6357
  let cur = id;
@@ -6362,13 +6406,13 @@ function knownTagTranslateHTML(tag, tagIdentifier, contentSection, propTree) {
6362
6406
  statements: []
6363
6407
  };
6364
6408
  const childScopeBinding = tagExtra[kChildScopeBinding];
6365
- if (getSerializeReason(section, childScopeBinding)) {
6409
+ const childScopeSerializeReason = getSerializeReason(section, childScopeBinding);
6410
+ let varStatement;
6411
+ if (childScopeSerializeReason) {
6366
6412
  const peekScopeId = generateUidIdentifier(childScopeBinding?.name);
6367
- const peekScopeDeclaration = _marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(peekScopeId, callRuntime("_peek_scope_id"))]);
6368
- if (tagVar) tag.insertBefore(peekScopeDeclaration);
6369
- else statements.push(peekScopeDeclaration);
6413
+ statements.push(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(peekScopeId, callRuntime("_peek_scope_id"))]));
6370
6414
  setBindingSerializedValue(section, childScopeBinding, callRuntime("_existing_scope", peekScopeId));
6371
- if (tagVar) statements.push(_marko_compiler.types.expressionStatement(callRuntime("_var", getScopeIdIdentifier(section), getScopeAccessorLiteral(tag.node.extra[kChildOffsetScopeBinding$1]), peekScopeId, _marko_compiler.types.stringLiteral(getResumeRegisterId(section, tagVar.extra?.binding, "var")))));
6415
+ if (tagVar) varStatement = _marko_compiler.types.expressionStatement(callRuntime("_var", getScopeIdIdentifier(section), getScopeAccessorLiteral(tag.node.extra[kChildOffsetScopeBinding$1]), peekScopeId, _marko_compiler.types.stringLiteral(getResumeRegisterId(section, tagVar.extra?.binding, "var"))));
6372
6416
  }
6373
6417
  if (contentSection.paramReasonGroups) {
6374
6418
  let childSerializeReasonExpr;
@@ -6406,8 +6450,10 @@ function knownTagTranslateHTML(tag, tagIdentifier, contentSection, propTree) {
6406
6450
  if (!tag.node.arguments?.length || properties.length) renderArgs.push(propsToExpression(properties));
6407
6451
  return renderArgs;
6408
6452
  };
6409
- if (tagVar) translateVar(tag, callExpression(tagIdentifier, ...getArgs()), "let");
6410
- else statements.push(callStatement(tagIdentifier, ...getArgs()));
6453
+ if (tagVar) {
6454
+ translateVar(tag, callExpression(tagIdentifier, ...getArgs()), "let", statements);
6455
+ if (varStatement) statements.push(varStatement);
6456
+ } else statements.push(callStatement(tagIdentifier, ...getArgs()));
6411
6457
  for (const replacement of tag.replaceWithMultiple(statements)) replacement.skip();
6412
6458
  }
6413
6459
  function knownTagTranslateDOM(tag, propTree, getBindingIdentifier, callSetup) {
@@ -6417,7 +6463,8 @@ function knownTagTranslateDOM(tag, propTree, getBindingIdentifier, callSetup) {
6417
6463
  if (node.var) {
6418
6464
  const varBinding = node.var.extra.binding;
6419
6465
  const source = initValue(varBinding);
6420
- source.register = !!getSerializeReason(tagSection, childScopeBinding) || !signalHasStatements(source);
6466
+ source.register = !!getSerializeReason(tagSection, childScopeBinding);
6467
+ source.referenced = true;
6421
6468
  source.buildAssignment = (valueSection, value) => {
6422
6469
  const changeArgs = [createScopeReadExpression(childScopeBinding, valueSection), value];
6423
6470
  if (!isOptimize()) changeArgs.push(_marko_compiler.types.stringLiteral(varBinding.name));
@@ -6994,9 +7041,9 @@ function trackVarReferences(tag, type, upstreamAlias) {
6994
7041
  const section = getOrCreateSection(tag);
6995
7042
  let canonicalUpstreamAlias = upstreamAlias && getCanonicalBinding(upstreamAlias);
6996
7043
  if (canonicalUpstreamAlias) {
6997
- const { excludeProperties } = canonicalUpstreamAlias;
7044
+ const { excludeProperties, restOffset } = canonicalUpstreamAlias;
6998
7045
  if (excludeProperties !== void 0) canonicalUpstreamAlias = canonicalUpstreamAlias.upstreamAlias;
6999
- createBindingsAndTrackReferences(tagVar, canonicalUpstreamAlias.type, tag.scope, section, canonicalUpstreamAlias, void 0, excludeProperties);
7046
+ createBindingsAndTrackReferences(tagVar, canonicalUpstreamAlias.type, tag.scope, section, canonicalUpstreamAlias, void 0, excludeProperties, restOffset);
7000
7047
  return canonicalUpstreamAlias;
7001
7048
  }
7002
7049
  createBindingsAndTrackReferences(tagVar, type, tag.scope, section, void 0, void 0, void 0);
@@ -7080,12 +7127,13 @@ function trackReferencesForBinding(babelBinding, binding) {
7080
7127
  const left = ref.get("left");
7081
7128
  if (left.isIdentifier()) trackReference(left, binding);
7082
7129
  }
7083
- }
7130
+ } else if (ref.isForXStatement()) throw ref.get("left").buildCodeFrameError(`\`${binding.name}\` is a [tag variable](https://markojs.com/docs/reference/language#tag-variables), so a \`for...${ref.isForOfStatement() ? "of" : "in"}\` cannot assign to it. Loop into a local variable and assign \`${binding.name}\` from it instead.`);
7084
7131
  }
7085
7132
  }
7086
7133
  function trackAssignment(assignment, binding) {
7087
7134
  const fnParent = getFnParent(assignment);
7088
7135
  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.`);
7136
+ if (binding.type === 4) throw assignment.buildCodeFrameError(`\`${binding.name}\` is a tag parameter and cannot be assigned to.`);
7089
7137
  const fnRoot = getFnRoot(fnParent);
7090
7138
  const fnExtra = fnRoot && (fnRoot.node.extra ??= {});
7091
7139
  const section = getOrCreateSection(assignment);
@@ -7145,14 +7193,14 @@ function createBindingsAndTrackReferences(lVal, type, scope, section, upstreamAl
7145
7193
  }
7146
7194
  case "ArrayPattern": {
7147
7195
  const patternBinding = (property ? upstreamAlias.propertyAliases.get(property) : upstreamAlias) || ((lVal.extra ??= {}).binding = createBinding(generateUid(property || "pattern"), type, section, upstreamAlias, property, excludeProperties, lVal.loc));
7148
- let i = -1;
7196
+ let index = (restOffset || 0) - 1;
7149
7197
  for (const element of lVal.elements) {
7150
- i++;
7198
+ index++;
7151
7199
  if (element) {
7152
7200
  if (element.type === "RestElement") {
7153
- excludeProperties = i > 0 ? addNumericPropertiesUntil(excludeProperties, i) : void 0;
7154
- createBindingsAndTrackReferences(element.argument, type, scope, section, patternBinding, void 0, excludeProperties, i);
7155
- } else if (_marko_compiler.types.isLVal(element)) createBindingsAndTrackReferences(element, type, scope, section, patternBinding, `${i}`, void 0);
7201
+ excludeProperties = index > 0 ? addNumericPropertiesUntil(excludeProperties, index) : void 0;
7202
+ createBindingsAndTrackReferences(element.argument, type, scope, section, patternBinding, void 0, excludeProperties, index);
7203
+ } else if (_marko_compiler.types.isLVal(element)) createBindingsAndTrackReferences(element, type, scope, section, patternBinding, `${index}`, void 0);
7156
7204
  }
7157
7205
  }
7158
7206
  break;
@@ -8419,8 +8467,8 @@ var define_default = {
8419
8467
  if (isOutputHTML()) {
8420
8468
  flushInto(tag);
8421
8469
  writeHTMLResumeStatements(tag.get("body"));
8470
+ translateVar(tag, propsToExpression(translatedAttrs.properties), "const", translatedAttrs.statements);
8422
8471
  tag.insertBefore(translatedAttrs.statements);
8423
- translateVar(tag, propsToExpression(translatedAttrs.properties));
8424
8472
  } else {
8425
8473
  if (_marko_compiler.types.isIdentifier(node.var)) {
8426
8474
  const babelBinding = tag.scope.getBinding(node.var.name);
@@ -8642,7 +8690,7 @@ var id_default = {
8642
8690
  const source = initValue(node.var.extra.binding);
8643
8691
  if (valueAttr) {
8644
8692
  const { value } = valueAttr;
8645
- addValue(section, value.extra?.referencedBindings, source, _marko_compiler.types.logicalExpression("||", value, id));
8693
+ addValue(section, value.extra?.referencedBindings, source, _marko_compiler.types.logicalExpression("||", value, evaluate(value).confident ? id : callRuntime("_id", scopeIdentifier, _marko_compiler.types.stringLiteral(getPrefixedScopeAccessor(node.var.extra.binding, getAccessorPrefix().IdFallback)))));
8646
8694
  } else addValue(section, void 0, source, id);
8647
8695
  tag.remove();
8648
8696
  }
@@ -9114,6 +9162,7 @@ function checkStyleInterpolations(tag) {
9114
9162
  let stringQuote = "";
9115
9163
  let inComment = false;
9116
9164
  let groupDepth = 0;
9165
+ let urlDepth = 0;
9117
9166
  let blockDepth = 0;
9118
9167
  let valueColon = false;
9119
9168
  let runPlaceholder;
@@ -9128,6 +9177,7 @@ function checkStyleInterpolations(tag) {
9128
9177
  const child = body[i];
9129
9178
  if (_marko_compiler.types.isMarkoPlaceholder(child)) {
9130
9179
  if (stringQuote) throw tag.hub.buildError(child, styleStringMsg);
9180
+ if (urlDepth) throw tag.hub.buildError(child, styleUrlMsg);
9131
9181
  if (!runPlaceholder) {
9132
9182
  runPlaceholder = child;
9133
9183
  runAfterColon = valueColon;
@@ -9155,9 +9205,14 @@ function checkStyleInterpolations(tag) {
9155
9205
  inComment = true;
9156
9206
  j++;
9157
9207
  } else if (c === "\"" || c === "'") stringQuote = c;
9158
- else if (c === "(" || c === "[") groupDepth++;
9159
- else if (c === ")" || c === "]") {
9160
- if (groupDepth) groupDepth--;
9208
+ else if (c === "(" || c === "[") {
9209
+ groupDepth++;
9210
+ if (!urlDepth && cssUrlBefore.test(text.slice(0, j + 1)) && !cssQuotedArg.test(text.slice(j + 1))) urlDepth = groupDepth;
9211
+ } else if (c === ")" || c === "]") {
9212
+ if (groupDepth) {
9213
+ if (urlDepth === groupDepth) urlDepth = 0;
9214
+ groupDepth--;
9215
+ }
9161
9216
  } else if (!groupDepth) switch (c) {
9162
9217
  case ":":
9163
9218
  if (blockDepth) valueColon = true;
@@ -9182,10 +9237,13 @@ const styleInterpolationMsg = "A `${...}` interpolation in a [`<style>` tag](htt
9182
9237
  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.`;
9183
9238
  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.`;
9184
9239
  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.`;
9240
+ const styleUrlMsg = `${styleInterpolationMsg} is not substituted inside an unquoted \`url()\` — the raw url token consumes the \`var(--…)\` text literally, invalidating the declaration. Move the whole \`url(...)\` into the interpolated value. For a native html [\`<style>\` tag](https://markojs.com/docs/reference/core-tag#style) use the \`html-style\` core tag instead.`;
9185
9241
  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)\`.`;
9186
9242
  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.`;
9187
9243
  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;
9188
9244
  const cssGluedBefore = /[\w%]$/;
9245
+ const cssUrlBefore = /(?:^|[^\w-])url\($/i;
9246
+ const cssQuotedArg = /^\s*["']/;
9189
9247
  //#endregion
9190
9248
  //#region src/translator/core/style.ts
9191
9249
  const STYLE_EXT_REG = /^style((?:\.[a-zA-Z0-9$_-]+)+)?/;
@@ -9534,6 +9592,27 @@ function isBeforeHtmlOrHead(documentType) {
9534
9592
  return false;
9535
9593
  }
9536
9594
  //#endregion
9595
+ //#region src/translator/visitors/export-declaration.ts
9596
+ var export_declaration_default = {
9597
+ analyze(exportDecl) {
9598
+ const { node } = exportDecl;
9599
+ const { source } = node;
9600
+ if (source) {
9601
+ const tagImport = (0, _marko_compiler_babel_utils.resolveTagImport)(exportDecl, source.value);
9602
+ if (tagImport) {
9603
+ (node.extra ??= {}).tagImport = tagImport;
9604
+ const tags = exportDecl.hub.file.metadata.marko.tags;
9605
+ if (!tags.includes(tagImport)) tags.push(tagImport);
9606
+ }
9607
+ }
9608
+ },
9609
+ translate: { exit(exportDecl) {
9610
+ const { node } = exportDecl;
9611
+ const tagImport = node.extra?.tagImport;
9612
+ if (tagImport) node.source.value = tagImport;
9613
+ } }
9614
+ };
9615
+ //#endregion
9537
9616
  //#region src/translator/visitors/import-declaration.ts
9538
9617
  const triggerRegExp = /\s*([\w-]+)\s*([^?|]+?)?\s*(?:\?([^|]*?))?\s*(?:\||$)/g;
9539
9618
  const [getHtmlLoadWrapped] = createProgramState(() => /* @__PURE__ */ new Map());
@@ -10287,7 +10366,7 @@ var dynamic_tag_default = {
10287
10366
  if (tag.node.var) {
10288
10367
  const varBinding = tag.node.var.extra.binding;
10289
10368
  tagVarSignal = initValue(varBinding);
10290
- tagVarSignal.register = true;
10369
+ tagVarSignal.register = tagVarSignal.referenced = true;
10291
10370
  tagVarSignal.buildAssignment = (valueSection, value) => {
10292
10371
  const changeArgs = [_marko_compiler.types.memberExpression(getScopeExpression(tagVarSignal.section, valueSection), _marko_compiler.types.stringLiteral(getAccessorPrefix().BranchScopes + getScopeAccessor(nodeBinding)), true), value];
10293
10372
  if (!isOptimize()) changeArgs.push(_marko_compiler.types.stringLiteral(varBinding.name));
@@ -10488,7 +10567,7 @@ function isTagsAPI(file = (0, _marko_compiler_babel_utils.getFile)()) {
10488
10567
  let { featureType } = programExtra;
10489
10568
  if (!featureType) {
10490
10569
  const lookup = (0, _marko_compiler_babel_utils.getTaglibLookup)(file);
10491
- const tagsDir = getTagsDir(file.opts.filename);
10570
+ const tagsDir = getTagsDir(lookup, file.opts.filename);
10492
10571
  const state = {};
10493
10572
  if (tagsDir && !lookup.manualTagsDirs?.has(tagsDir)) addFeature(state, Tags, "Template file within a tags directory", program);
10494
10573
  scanBody(state, program.get("body"));
@@ -10496,24 +10575,10 @@ function isTagsAPI(file = (0, _marko_compiler_babel_utils.getFile)()) {
10496
10575
  }
10497
10576
  return featureType === Tags;
10498
10577
  }
10499
- function getTagsDir(filename) {
10500
- const pathSeparator = /\/|\\/.exec(filename)?.[0];
10501
- if (pathSeparator) {
10502
- let previousIndex = filename.length - 1;
10503
- while (previousIndex > 0) {
10504
- const index = filename.lastIndexOf(pathSeparator, previousIndex);
10505
- switch (previousIndex - index) {
10506
- case 4:
10507
- if (filename.startsWith("tags", index + 1)) return filename.slice(0, index + 5);
10508
- break;
10509
- case 10:
10510
- if (filename.startsWith("components", index + 1)) return false;
10511
- break;
10512
- }
10513
- previousIndex = index - 1;
10514
- }
10515
- }
10516
- return false;
10578
+ function getTagsDir(lookup, filename) {
10579
+ let nearest;
10580
+ for (const dir of lookup.discoveryDirs || []) if (filename.startsWith(dir) && (filename[dir.length] === "/" || filename[dir.length] === "\\") && (!nearest || dir.length > nearest.length)) nearest = dir;
10581
+ return !!nearest && /[/\\]tags$/.test(nearest) && nearest;
10517
10582
  }
10518
10583
  function scanBody(state, body) {
10519
10584
  if (body?.length) for (const child of body) switch (child.type) {
@@ -10801,6 +10866,8 @@ const visitors = extractVisitors({
10801
10866
  Function: function_default,
10802
10867
  ReferencedIdentifier: referenced_identifier_default,
10803
10868
  ImportDeclaration: import_declaration_default,
10869
+ ExportNamedDeclaration: export_declaration_default,
10870
+ ExportAllDeclaration: export_declaration_default,
10804
10871
  MarkoDocumentType: document_type_default,
10805
10872
  MarkoDeclaration: declaration_default,
10806
10873
  MarkoCDATA: cdata_default,
@@ -9,6 +9,7 @@ export interface Signal {
9
9
  section: Section;
10
10
  build: undefined | (() => t.Expression | undefined);
11
11
  register?: boolean;
12
+ referenced?: boolean;
12
13
  values: Array<{
13
14
  signal: Signal;
14
15
  value: t.Expression;
@@ -37,6 +38,7 @@ export declare const getTryHasPlaceholder: (section: Section) => true | undefine
37
38
  export declare function setSectionOwnerResumedByMarker(section: Section): void;
38
39
  export declare function setSectionSerializedValue(section: Section, prop: AccessorProp, expression: t.Expression): void;
39
40
  export declare function setBindingSerializedValue(section: Section, binding: Binding, expression: t.Expression, prefix?: AccessorPrefix): void;
41
+ export declare function setSectionDebugVar(section: Section, accessor: string, name: string, loc: t.SourceLocation | null | undefined): void;
40
42
  export declare function setSerializedValue(section: Section, key: string, expression: t.Expression): void;
41
43
  export declare function addWriteScopeBuilder(section: Section, builder: (writeCall: t.Expression) => t.Expression): void;
42
44
  export declare const getHTMLSectionStatements: (section: Section) => t.Statement[];
@@ -1,2 +1,2 @@
1
1
  import { types as t } from "@marko/compiler";
2
- export default function translateVar(tag: t.NodePath<t.MarkoTag>, initialValue: t.Expression, kind?: "let" | "const"): void;
2
+ export default function translateVar(tag: t.NodePath<t.MarkoTag>, initialValue: t.Expression, kind?: "let" | "const", statements?: t.Statement[]): void;
@@ -0,0 +1,8 @@
1
+ import { types as t } from "@marko/compiler";
2
+ declare const _default: {
3
+ analyze(this: unknown, exportDecl: t.NodePath<t.ExportAllDeclaration | t.ExportNamedDeclaration>): void;
4
+ translate: {
5
+ exit(this: unknown, exportDecl: t.NodePath<t.ExportAllDeclaration | t.ExportNamedDeclaration>): void;
6
+ };
7
+ };
8
+ export default _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "marko",
3
- "version": "6.3.34",
3
+ "version": "6.3.35",
4
4
  "description": "Optimized runtime for Marko templates.",
5
5
  "keywords": [
6
6
  "api",
@@ -48,14 +48,14 @@
48
48
  }
49
49
  },
50
50
  "dependencies": {
51
- "@marko/compiler": "^5.41.18",
51
+ "@marko/compiler": "^5.42.0",
52
52
  "csstype": "^3.2.3",
53
53
  "fastest-levenshtein": "^1.0.16",
54
54
  "magic-string": "^0.30.21"
55
55
  },
56
56
  "devDependencies": {
57
- "@marko/runtime-tags": "npm:marko@6.3.34",
58
- "marko": "5.39.32"
57
+ "@marko/runtime-tags": "npm:marko@6.3.35",
58
+ "marko": "5.39.33"
59
59
  },
60
60
  "engines": {
61
61
  "node": ">=22"
package/tags/let.d.marko CHANGED
@@ -1,8 +1,7 @@
1
1
  /** File for types only, not actual implementation **/
2
2
 
3
- export interface Input<T, K = T> {
4
- value?: T;
5
- valueChange?: ((newValue: K) => void) | false | null;
6
- }
3
+ export type Input<T = undefined, K = T> =
4
+ | { value: T; valueChange?: ((newValue: K) => void) | false | null }
5
+ | { value?: undefined; valueChange?: ((newValue: K) => void) | false | null };
7
6
 
8
7
  return=(input.value as T) valueChange=(input.valueChange as (newValue: K) => void)