marko 6.3.24 → 6.3.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/html.mjs CHANGED
@@ -956,11 +956,15 @@ function writeGenerator(state, iter, ref) {
956
956
  needsId ||= isDedupedMember(value), yields.push(value);
957
957
  }
958
958
  if (returnValue === void 0 && !yields.length) return state.buf.push("(function*(){})()"), !0;
959
- if (state.buf.push(returnValue === void 0 ? "(function*(a){yield*a})(" : "(function*(a,r){yield*a;return r})("), needsId) {
959
+ let heldReturn = returnValue !== void 0 && isAncestorMember(state, ref, returnValue);
960
+ if (state.buf.push(returnValue === void 0 ? "(function*(a){yield*a})(" : heldReturn ? "(function*(a,r){yield*a;return r.v})(" : "(function*(a,r){yield*a;return r})("), needsId) {
960
961
  let arrayRef = new Reference(ref, null, state.flush, null, nextRefAccess(state));
961
962
  state.buf.push(arrayRef.id + "="), writeArray(state, yields, arrayRef);
962
963
  } else writeArray(state, yields, new Reference(ref, null, state.flush, state.buf.length));
963
- if (returnValue !== void 0) {
964
+ if (heldReturn) {
965
+ let holder = new Reference(ref, null, state.flush, null, nextRefAccess(state));
966
+ state.buf.push("," + holder.id + "={}"), writeProp(state, returnValue, holder, "v");
967
+ } else if (returnValue !== void 0) {
964
968
  let sepIndex = state.buf.push(",") - 1;
965
969
  if (writeProp(state, returnValue, ref, "") && isDedupedMember(returnValue)) {
966
970
  let retRef = typeof returnValue == "string" ? state.strs.get(returnValue) : state.refs.get(returnValue);
@@ -1819,7 +1823,8 @@ function _attr_textarea_value(scopeId, nodeAccessor, value, valueChange, seriali
1819
1823
  return valueChange && writeControlledScope(2, scopeId, nodeAccessor, void 0, valueChange, serializeType), _textarea_value(value);
1820
1824
  }
1821
1825
  function _textarea_value(value) {
1822
- return _escape(normalizeStrAttrValue(value));
1826
+ let escaped = _escape(normalizeStrAttrValue(value));
1827
+ return escaped[0] === "\n" || escaped[0] === "\r" ? "\n" + escaped : escaped;
1823
1828
  }
1824
1829
  function _attr_input_value(scopeId, nodeAccessor, value, valueChange, serializeType) {
1825
1830
  return valueChange && writeControlledScope(2, scopeId, nodeAccessor, void 0, valueChange, serializeType), _attr("value", value);
@@ -110,6 +110,7 @@ var accessor_prefix_debug_exports = /* @__PURE__ */ __exportAll({
110
110
  ClosureSignalIndex: () => ClosureSignalIndex$1,
111
111
  ConditionalRenderer: () => ConditionalRenderer$1,
112
112
  ControlledHandler: () => ControlledHandler$1,
113
+ ControlledObserver: () => ControlledObserver$1,
113
114
  ControlledType: () => ControlledType$1,
114
115
  ControlledValue: () => ControlledValue$1,
115
116
  DynamicHTMLLastChild: () => DynamicHTMLLastChild$1,
@@ -123,6 +124,7 @@ const BranchScopes$3 = "BranchScopes:";
123
124
  const ClosureScopes$1 = "ClosureScopes:";
124
125
  const ClosureSignalIndex$1 = "ClosureSignalIndex:";
125
126
  const ConditionalRenderer$1 = "ConditionalRenderer:";
127
+ const ControlledObserver$1 = "ControlledObserver:";
126
128
  const ControlledHandler$1 = "ControlledHandler:";
127
129
  const ControlledType$1 = "ControlledType:";
128
130
  const ControlledValue$1 = "ControlledValue:";
@@ -238,7 +240,7 @@ function isNullableExpr(expr) {
238
240
  case "|=":
239
241
  case "**=": return false;
240
242
  case "||=":
241
- case "??=": return isNullableExpr(expr.right) || isNullableExpr(expr.left);
243
+ case "??=": return isNullableExpr(expr.right);
242
244
  case "&&=": return isNullableExpr(expr.left) || isNullableExpr(expr.right);
243
245
  default: return true;
244
246
  }
@@ -246,7 +248,7 @@ function isNullableExpr(expr) {
246
248
  case "ConditionalExpression": return isNullableExpr(expr.consequent) || isNullableExpr(expr.alternate);
247
249
  case "LogicalExpression": switch (expr.operator) {
248
250
  case "||":
249
- case "??": return isNullableExpr(expr.right) || isNullableExpr(expr.left);
251
+ case "??": return isNullableExpr(expr.right);
250
252
  case "&&": return isNullableExpr(expr.left) || isNullableExpr(expr.right);
251
253
  default: return true;
252
254
  }
@@ -908,6 +910,7 @@ var accessor_prefix_exports = /* @__PURE__ */ __exportAll({
908
910
  ClosureSignalIndex: () => "C",
909
911
  ConditionalRenderer: () => "D",
910
912
  ControlledHandler: () => "E",
913
+ ControlledObserver: () => "N",
911
914
  ControlledType: () => "F",
912
915
  ControlledValue: () => "G",
913
916
  DynamicHTMLLastChild: () => "H",
@@ -1903,7 +1906,8 @@ function _attr_textarea_value(scopeId, nodeAccessor, value, valueChange, seriali
1903
1906
  return _textarea_value(value);
1904
1907
  }
1905
1908
  function _textarea_value(value) {
1906
- return _escape(normalizeStrAttrValue(value));
1909
+ const escaped = _escape(normalizeStrAttrValue(value));
1910
+ return escaped[0] === "\n" || escaped[0] === "\r" ? "\n" + escaped : escaped;
1907
1911
  }
1908
1912
  function _attr_input_value(scopeId, nodeAccessor, value, valueChange, serializeType) {
1909
1913
  if (valueChange) writeControlledScope(2, scopeId, nodeAccessor, void 0, valueChange, serializeType);
@@ -2524,7 +2528,7 @@ function visitInternal(section) {
2524
2528
  }
2525
2529
  function nCodeString(code, number) {
2526
2530
  switch (code) {
2527
- case 67: return toCharString(number, code, 20);
2531
+ case 67: return toCharString(number, code, 25);
2528
2532
  case 97: return toCharString(number, code, 10);
2529
2533
  case 107: return toCharString(number, code, 10);
2530
2534
  default: throw new Error(`Unexpected walk code: ${code}`);
@@ -2540,6 +2544,16 @@ function toCharString(number, startCode, rangeSize) {
2540
2544
  result += String.fromCharCode(startCode + number);
2541
2545
  return result;
2542
2546
  }
2547
+ /** `_content` strips trailing exit codes before it walks, so a renderer that
2548
+ * reaches the runtime through it never needs them on the wire. */
2549
+ function trimTrailingExits(walks) {
2550
+ if (!_marko_compiler.types.isStringLiteral(walks)) return walks;
2551
+ const value = walks.value.replace(/[^\0-1]+$/, "");
2552
+ return value === walks.value ? walks : value ? withLeadingComment(_marko_compiler.types.stringLiteral(value), getComment(walks)) : void 0;
2553
+ }
2554
+ function getComment(node) {
2555
+ return node.leadingComments?.[0]?.value.trim() || "";
2556
+ }
2543
2557
  function getWalkString(section) {
2544
2558
  if (section.content?.endType === 1) getSteps(section).push(0, 1);
2545
2559
  visitInternal(section);
@@ -3471,7 +3485,14 @@ function replaceAssignedNode(node) {
3471
3485
  switch (node.left.type) {
3472
3486
  case "Identifier": {
3473
3487
  const { extra } = node.left;
3474
- return isAssignedBindingExtra(extra) && getBuildAssignment(extra)?.(extra.section, node.operator === "=" ? node.right : _marko_compiler.types.binaryExpression(node.operator.slice(0, -1), createScopeReadExpression(extra.assignment, extra.section), node.right)) || extra?.assignment && withLeadingComment(node.right, getDebugName(extra.assignment));
3488
+ if (isAssignedBindingExtra(extra)) {
3489
+ const { operator } = node;
3490
+ const shortCircuits = operator === "||=" || operator === "&&=" || operator === "??=";
3491
+ const readAssigned = () => createScopeReadExpression(extra.assignment, extra.section);
3492
+ const builtAssignment = getBuildAssignment(extra)?.(extra.section, operator === "=" || shortCircuits ? node.right : _marko_compiler.types.binaryExpression(operator.slice(0, -1), readAssigned(), node.right));
3493
+ if (builtAssignment) return shortCircuits ? _marko_compiler.types.logicalExpression(operator.slice(0, -1), readAssigned(), builtAssignment) : builtAssignment;
3494
+ }
3495
+ return extra?.assignment && withLeadingComment(node.right, getDebugName(extra.assignment));
3475
3496
  }
3476
3497
  case "ArrayPattern":
3477
3498
  case "ObjectPattern": {
@@ -3612,7 +3633,8 @@ var dom_default = { translate: {
3612
3633
  if (childSection !== section) {
3613
3634
  const tagParamsSignal = childSection.params && initValue(childSection.params);
3614
3635
  const tagParamsIdentifier = tagParamsSignal && signalHasStatements(tagParamsSignal) ? tagParamsSignal.identifier : void 0;
3615
- const { walks, writes, decls } = getSectionMeta(childSection);
3636
+ const { writes, decls } = getSectionMeta(childSection);
3637
+ const walks = trimTrailingExits(getSectionMeta(childSection).walks);
3616
3638
  const setup = getSetup(childSection);
3617
3639
  const written = writeSignals(childSection);
3618
3640
  const setupIdentifier = setup && written.has(setup) ? setup.identifier : void 0;
@@ -4284,8 +4306,8 @@ function translateAttrs(tag, propTree = true, skip, statements = [], contentKey
4284
4306
  else {
4285
4307
  const translatedAttrTag = translateAttrs(child, getKnownFromPropTree(propTree, attrTagMeta.name), void 0, statements, contentKey);
4286
4308
  const prevProp = attrTagMeta.repeated ? findObjectProperty(attrTagMeta.name, contentProperties) : void 0;
4287
- if (prevProp) prevProp.value = callRuntime("attrTags", prevProp.value, propsToExpression(translatedAttrTag.properties));
4288
- else contentProperties.push(toObjectProperty(attrTagMeta.name, callRuntime("attrTag", propsToExpression(translatedAttrTag.properties))));
4309
+ if (prevProp) prevProp.value = callRuntime("attrTags", prevProp.value, _marko_compiler.types.objectExpression(translatedAttrTag.properties));
4310
+ else contentProperties.push(toObjectProperty(attrTagMeta.name, callRuntime("attrTag", _marko_compiler.types.objectExpression(translatedAttrTag.properties))));
4289
4311
  }
4290
4312
  } else i = addDynamicAttrTagStatements(attrTags, i, attrTagLookup, statements, propTree, contentKey);
4291
4313
  }
@@ -4325,8 +4347,8 @@ function addDynamicAttrTagStatements(attrTags, index, attrTagLookup, statements,
4325
4347
  const attrTagExport = getKnownFromPropTree(propTree, attrTagMeta.name);
4326
4348
  if (attrTagExport && attrTagMeta.dynamic) {
4327
4349
  const translatedAttrTag = translateAttrs(tag, attrTagExport, void 0, statements, contentKey);
4328
- if (attrTagMeta.repeated) statements.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.assignmentExpression("=", getAttrTagIdentifier(attrTagMeta), callRuntime("attrTags", getAttrTagIdentifier(attrTagMeta), propsToExpression(translatedAttrTag.properties)))));
4329
- else statements.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.assignmentExpression("=", getAttrTagIdentifier(attrTagMeta), callRuntime("attrTag", propsToExpression(translatedAttrTag.properties)))));
4350
+ if (attrTagMeta.repeated) statements.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.assignmentExpression("=", getAttrTagIdentifier(attrTagMeta), callRuntime("attrTags", getAttrTagIdentifier(attrTagMeta), _marko_compiler.types.objectExpression(translatedAttrTag.properties)))));
4351
+ else statements.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.assignmentExpression("=", getAttrTagIdentifier(attrTagMeta), callRuntime("attrTag", _marko_compiler.types.objectExpression(translatedAttrTag.properties)))));
4330
4352
  }
4331
4353
  } else switch (getTagName(tag)) {
4332
4354
  case "if": return translateIfAttrTag(attrTags, index, attrTagLookup, statements, propTree, contentKey);
@@ -4334,6 +4356,8 @@ function addDynamicAttrTagStatements(attrTags, index, attrTagLookup, statements,
4334
4356
  }
4335
4357
  return index;
4336
4358
  }
4359
+ /** Unwraps a lone spread to the spread argument itself, so the result may alias
4360
+ * a caller binding; anything the runtime writes to needs its own object. */
4337
4361
  function propsToExpression(props) {
4338
4362
  return props.length === 1 && _marko_compiler.types.isSpreadElement(props[0]) ? props[0].argument : _marko_compiler.types.objectExpression(props);
4339
4363
  }
@@ -4745,8 +4769,12 @@ var native_tag_default = {
4745
4769
  }
4746
4770
  if (spreadExpression) {
4747
4771
  const canHaveAttrContent = !(isTextOnly || isOpenOnly || hasChildren || staticContentAttr);
4748
- if (skipExpression) addStatement("render", tagSection, tagExtra.referencedBindings, _marko_compiler.types.expressionStatement(callRuntime(canHaveAttrContent ? "_attrs_partial_content" : "_attrs_partial", scopeIdentifier, visitAccessor, spreadExpression, skipExpression)));
4749
- else addStatement("render", tagSection, tagExtra.referencedBindings, _marko_compiler.types.expressionStatement(callRuntime(canHaveAttrContent ? "_attrs_content" : "_attrs", scopeIdentifier, visitAccessor, spreadExpression)));
4772
+ const name = tag.get("name");
4773
+ const staticName = name.isStringLiteral() ? name.node.value : void 0;
4774
+ const controllable = !staticControllable && controllableClaimFor(staticName);
4775
+ if (skipExpression) addStatement("render", tagSection, tagExtra.referencedBindings, _marko_compiler.types.expressionStatement(callRuntime(canHaveAttrContent ? "_attrs_partial_content" : "_attrs_partial", scopeIdentifier, visitAccessor, spreadExpression, skipExpression, controllable && importRuntime(controllable))));
4776
+ else addStatement("render", tagSection, tagExtra.referencedBindings, _marko_compiler.types.expressionStatement(callRuntime(canHaveAttrContent ? "_attrs_content" : "_attrs", scopeIdentifier, visitAccessor, spreadExpression, controllable && importRuntime(controllable))));
4777
+ enableControllable(controllableScriptLatchFor(staticName));
4750
4778
  addStatement("effect", tagSection, tagExtra.referencedBindings, _marko_compiler.types.expressionStatement(callRuntime("_attrs_script", scopeIdentifier, visitAccessor)), false);
4751
4779
  }
4752
4780
  if (staticContentAttr) addStatement("render", tagSection, staticContentAttr.value.extra?.referencedBindings, _marko_compiler.types.expressionStatement(callRuntime("_attr_content", scopeIdentifier, visitAccessor, staticContentAttr.value)), void 0, true);
@@ -5156,6 +5184,41 @@ function isDynamicControllable(controllable) {
5156
5184
  function buildUndefined$1() {
5157
5185
  return _marko_compiler.types.unaryExpression("void", _marko_compiler.types.numericLiteral(0));
5158
5186
  }
5187
+ /** How a spread claims its controlled attrs during render; nothing for the many
5188
+ * tags that control nothing, and nothing when a static attr owns the
5189
+ * controllable, since then the spread must leave the slots it wrote alone. */
5190
+ function controllableClaimFor(tagName) {
5191
+ switch (tagName) {
5192
+ case "input": return "_controllable_input";
5193
+ case "textarea": return "_controllable_textarea";
5194
+ case "select": return "_controllable_select";
5195
+ case "details":
5196
+ case "dialog": return "_controllable_open";
5197
+ }
5198
+ }
5199
+ /** The resume-pass latch for a tag: `_attrs_script` resolves the control kind
5200
+ * at run time, and a run-time tag name can be any of them. */
5201
+ function controllableScriptLatchFor(tagName) {
5202
+ switch (tagName) {
5203
+ case "input": return "_enable_controllable_input";
5204
+ case "textarea": return "_enable_controllable_textarea";
5205
+ case "select": return "_enable_controllable_select";
5206
+ case "details":
5207
+ case "dialog": return "_enable_controllable_open";
5208
+ case void 0: return "_enable_controllable";
5209
+ }
5210
+ }
5211
+ const enabledControllables = /* @__PURE__ */ new WeakMap();
5212
+ /** Emits the latch once per program, like `_enable_catch`. */
5213
+ function enableControllable(helper) {
5214
+ if (!helper) return;
5215
+ const program = (0, _marko_compiler_babel_utils.getProgram)().node;
5216
+ let enabled = enabledControllables.get(program);
5217
+ if (!enabled) enabledControllables.set(program, enabled = /* @__PURE__ */ new Set());
5218
+ if (enabled.has(helper)) return;
5219
+ enabled.add(helper);
5220
+ program.body.push(_marko_compiler.types.expressionStatement(callRuntime(helper)));
5221
+ }
5159
5222
  //#endregion
5160
5223
  //#region src/translator/util/is-only-child-in-parent.ts
5161
5224
  const kOnlyChildInParent = Symbol("only child in parent");
@@ -6246,6 +6309,7 @@ function applyAttrObject(tag, propTree, tagInputIdentifier, info) {
6246
6309
  let translatedProps = propsToExpression(translatedAttrs.properties);
6247
6310
  if (translatedAttrs.statements.length) addStatement("render", info.tagSection, referencedBindings, translatedAttrs.statements);
6248
6311
  if ((0, _marko_compiler_babel_utils.isAttributeTag)(tag)) {
6312
+ translatedProps = _marko_compiler.types.objectExpression(translatedAttrs.properties);
6249
6313
  const attrTagName = getTagName(tag);
6250
6314
  const parentTag = tag.parentPath;
6251
6315
  if (analyzeAttributeTags(parentTag)?.[attrTagName]?.repeated) {
@@ -6261,7 +6325,8 @@ function applyAttrObject(tag, propTree, tagInputIdentifier, info) {
6261
6325
  addStatement("render", info.tagSection, referencedBindings, _marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(tagInputIdentifier, [createScopeReadExpression(info.childScopeBinding, info.tagSection), translatedProps])), void 0, true);
6262
6326
  }
6263
6327
  function translateAttrTag(tag, attrTagMeta, info, statements) {
6264
- let translatedProps = propsToExpression(translateAttrs(tag, true, void 0, statements).properties);
6328
+ const translatedAttrs = translateAttrs(tag, true, void 0, statements);
6329
+ let translatedProps = _marko_compiler.types.objectExpression(translatedAttrs.properties);
6265
6330
  const attrTagName = getTagName(tag);
6266
6331
  const parentTag = tag.parentPath;
6267
6332
  if (attrTagMeta.repeated) {
@@ -7970,17 +8035,17 @@ var define_default = {
7970
8035
  let allDirectReferences = true;
7971
8036
  for (const ref of babelBinding.referencePaths) if (ref.parent.type === "MarkoTag" && ref.parent.name === ref.node) hasDirectReferences = true;
7972
8037
  else allDirectReferences = false;
7973
- if (hasDirectReferences) {
8038
+ if (allDirectReferences) {
7974
8039
  const bodySection = getSectionForBody(tag.get("body"));
7975
8040
  if (bodySection) {
7976
- const signal = getSignal(bodySection, void 0);
7977
- signal.build = () => {
7978
- if (signalHasStatements(signal)) return callRuntime("_child_setup", getSignalFn(signal));
7979
- };
7980
- if (allDirectReferences) {
7981
- tag.remove();
7982
- return;
8041
+ if (hasDirectReferences) {
8042
+ const signal = getSignal(bodySection, void 0);
8043
+ signal.build = () => {
8044
+ if (signalHasStatements(signal)) return callRuntime("_child_setup", getSignalFn(signal));
8045
+ };
7983
8046
  }
8047
+ tag.remove();
8048
+ return;
7984
8049
  }
7985
8050
  }
7986
8051
  }
@@ -8025,7 +8090,9 @@ var effect_default = {
8025
8090
  var export_default = {
8026
8091
  parse(tag) {
8027
8092
  const { node } = tag;
8028
- tag.replaceWith((0, _marko_compiler_babel_utils.parseStatements)(tag.hub.file, node.rawValue, node.start, node.end)[0]);
8093
+ const statements = (0, _marko_compiler_babel_utils.parseStatements)(tag.hub.file, node.rawValue, node.start, node.end);
8094
+ if (statements.length > 1) throw tag.hub.buildError(statements[1], "The `<export>` tag takes a single export statement.");
8095
+ tag.replaceWith(statements[0]);
8029
8096
  },
8030
8097
  parseOptions: {
8031
8098
  statement: true,
@@ -8190,7 +8257,9 @@ var id_default = {
8190
8257
  var import_default = {
8191
8258
  parse(tag) {
8192
8259
  const { node } = tag;
8193
- tag.replaceWith((0, _marko_compiler_babel_utils.parseStatements)(tag.hub.file, node.rawValue, node.start, node.end)[0]);
8260
+ const statements = (0, _marko_compiler_babel_utils.parseStatements)(tag.hub.file, node.rawValue, node.start, node.end);
8261
+ if (statements.length > 1) throw tag.hub.buildError(statements[1], "The [`<import>` tag](https://markojs.com/docs/syntax/#importing-external-files) takes a single import statement.");
8262
+ tag.replaceWith(statements[0]);
8194
8263
  },
8195
8264
  parseOptions: {
8196
8265
  statement: true,
@@ -9633,12 +9702,13 @@ const kDOMBinding = Symbol("dynamic tag dom binding");
9633
9702
  const kChildOffsetScopeBinding = Symbol("custom tag scope offset");
9634
9703
  const importedDynamicTagResume = /* @__PURE__ */ new WeakSet();
9635
9704
  const [getCompatRegistrations] = createProgramState(() => /* @__PURE__ */ new Set());
9705
+ const [getCompatBoundaryCalls] = createProgramState(() => /* @__PURE__ */ new Map());
9636
9706
  function pushCompatRegistration(key, statement) {
9637
9707
  const keys = getCompatRegistrations();
9638
- if (!keys.has(key)) {
9639
- keys.add(key);
9640
- (0, _marko_compiler_babel_utils.getProgram)().node.body.push(statement);
9641
- }
9708
+ if (keys.has(key)) return false;
9709
+ keys.add(key);
9710
+ (0, _marko_compiler_babel_utils.getProgram)().node.body.push(statement);
9711
+ return true;
9642
9712
  }
9643
9713
  var dynamic_tag_default = {
9644
9714
  analyze: { enter(tag) {
@@ -9720,11 +9790,19 @@ var dynamic_tag_default = {
9720
9790
  if (_marko_compiler.types.isStringLiteral(tagExpression)) tagExpression = (0, _marko_compiler_babel_utils.importDefault)(tag.hub.file, getTagRelativePath(tag), tagExpression.value);
9721
9791
  if (classTagTemplate) {
9722
9792
  const preserveBoundary = !tagsSerializeReason && (classHydration === "descendant" || classHydration === "self" && !!classFile?.metadata.marko.hasComponentBrowser);
9723
- if (isOutputHTML() ? serializeReason || classHydration : serializeReason) pushCompatRegistration(classFile.metadata.marko.id, isOutputHTML() ? _marko_compiler.types.markoScriptlet([_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression((0, _marko_compiler_babel_utils.importNamed)(tag.hub.file, getCompatRuntimeFile(), "s"), [
9724
- _marko_compiler.types.stringLiteral(classFile.metadata.marko.id),
9793
+ const classId = classFile.metadata.marko.id;
9794
+ const registration = isOutputHTML() ? _marko_compiler.types.callExpression((0, _marko_compiler_babel_utils.importNamed)(tag.hub.file, getCompatRuntimeFile(), "s"), [
9795
+ _marko_compiler.types.stringLiteral(classId),
9725
9796
  _marko_compiler.types.identifier(tagExpression.name),
9726
9797
  ...preserveBoundary ? [_marko_compiler.types.stringLiteral("preserve")] : []
9727
- ]))], true) : _marko_compiler.types.expressionStatement(callRuntime("_resume", _marko_compiler.types.stringLiteral(classFile.metadata.marko.id), _marko_compiler.types.identifier(tagExpression.name))));
9798
+ ]) : void 0;
9799
+ if (isOutputHTML() ? serializeReason || classHydration : serializeReason) {
9800
+ if (pushCompatRegistration(classId, registration ? _marko_compiler.types.markoScriptlet([_marko_compiler.types.expressionStatement(registration)], true) : _marko_compiler.types.expressionStatement(callRuntime("_resume", _marko_compiler.types.stringLiteral(classId), _marko_compiler.types.identifier(tagExpression.name)))) && registration) getCompatBoundaryCalls().set(classId, registration);
9801
+ }
9802
+ if (!preserveBoundary) {
9803
+ const emitted = getCompatBoundaryCalls().get(classId);
9804
+ if (emitted) emitted.arguments.length = 2;
9805
+ }
9728
9806
  } else {
9729
9807
  const rendererName = tagExpression.name;
9730
9808
  pushCompatRegistration(rendererName, _marko_compiler.types.markoScriptlet([_marko_compiler.types.expressionStatement(_marko_compiler.types.assignmentExpression("??=", _marko_compiler.types.memberExpression(_marko_compiler.types.identifier(rendererName), _marko_compiler.types.identifier("_")), _marko_compiler.types.identifier(rendererName)))], true));
@@ -9778,13 +9856,25 @@ var dynamic_tag_default = {
9778
9856
  const argsOrInput = hasTagArgs ? _marko_compiler.types.arrayExpression(args) : args[0];
9779
9857
  if (!_marko_compiler.types.isObjectExpression(argsOrInput) || argsOrInput.properties.length) signal.extraArgs = [_marko_compiler.types.arrowFunctionExpression([], statements.length ? _marko_compiler.types.blockStatement(statements.concat(_marko_compiler.types.returnStatement(argsOrInput))) : argsOrInput)];
9780
9858
  }
9781
- if (!isClassAPI) enableDynamicTagResume(tag);
9859
+ if (!isClassAPI) {
9860
+ enableDynamicTagResume(tag);
9861
+ enableDynamicTagControllables(tag);
9862
+ }
9782
9863
  addValue(section, tagExtra.referencedBindings, signal, tagExpression);
9783
9864
  tag.remove();
9784
9865
  }
9785
9866
  }
9786
9867
  }
9787
9868
  };
9869
+ const controlledAttrs = /^(?:value|checked(?:Value)?|open)(?:Change)?$/;
9870
+ /** The name resolves at run time, so any control kind is possible. */
9871
+ function enableDynamicTagControllables(tag) {
9872
+ if (analyzeTagNameType(tag, true) === 1) return;
9873
+ for (const attr of tag.node.attributes) if (attr.type === "MarkoSpreadAttribute" || attr.type === "MarkoAttribute" && controlledAttrs.test(attr.name)) {
9874
+ enableControllable(controllableScriptLatchFor(void 0));
9875
+ return;
9876
+ }
9877
+ }
9788
9878
  function enableDynamicTagResume(tag) {
9789
9879
  const program = (0, _marko_compiler_babel_utils.getProgram)().node;
9790
9880
  if (!importedDynamicTagResume.has(program) && analyzeTagNameType(tag, true) !== 1) {
@@ -9913,7 +10003,7 @@ var text_default = {
9913
10003
  function buildAggregateError(file, rootMsg, ...paths) {
9914
10004
  const err = /* @__PURE__ */ new SyntaxError();
9915
10005
  const fileName = path.default.relative(_marko_compiler_modules.cwd, file.opts.filename);
9916
- const finalMsg = `${rootMsg}:\n\n${paths.map(([msg, path$10]) => `\x1b[90m${msg} at ${getFileNameWithLoc(fileName, path$10)}:\x1b[0m\n${getFrame(file, path$10)}`).join("\n\n")}`;
10006
+ const finalMsg = `${rootMsg}:\n\n${paths.map(([msg, path$12]) => `\x1b[90m${msg} at ${getFileNameWithLoc(fileName, path$12)}:\x1b[0m\n${getFrame(file, path$12)}`).join("\n\n")}`;
9917
10007
  if (!("MARKO_DEBUG" in process.env)) err.stack = finalMsg;
9918
10008
  Object.defineProperty(err, "message", {
9919
10009
  get() {
@@ -10030,9 +10120,11 @@ function getFeatureTypeFromCoreTagName(tagName) {
10030
10120
  case "macro":
10031
10121
  case "module-code":
10032
10122
  case "while": return Class;
10123
+ case "attrs":
10033
10124
  case "const":
10034
10125
  case "debug":
10035
10126
  case "define":
10127
+ case "effect":
10036
10128
  case "id":
10037
10129
  case "let":
10038
10130
  case "lifecycle":
@@ -10185,11 +10277,15 @@ function mergeTagDef(def5, def6) {
10185
10277
  }
10186
10278
  function mergeObjects(a, b, cb) {
10187
10279
  const merged = {};
10280
+ const assign = (key, aValue, bValue) => {
10281
+ const value = cb(key, aValue, bValue);
10282
+ if (value !== void 0) merged[key] = value;
10283
+ };
10188
10284
  if (a) if (b) {
10189
- for (const key in a) merged[key] = cb(key, a[key], b[key]);
10190
- for (const key in b) if (!(key in a)) merged[key] = cb(key, void 0, b[key]);
10191
- } else for (const key in a) merged[key] = cb(key, a[key], void 0);
10192
- else if (b) for (const key in b) merged[key] = cb(key, void 0, b[key]);
10285
+ for (const key in a) assign(key, a[key], b[key]);
10286
+ for (const key in b) if (!(key in a)) assign(key, void 0, b[key]);
10287
+ } else for (const key in a) assign(key, a[key], void 0);
10288
+ else if (b) for (const key in b) assign(key, void 0, b[key]);
10193
10289
  return merged;
10194
10290
  }
10195
10291
  function normalizeTagDef(tagDef) {
@@ -10215,8 +10311,34 @@ function normalizeVisitor(visitor) {
10215
10311
  return visitor?.default ?? visitor;
10216
10312
  }
10217
10313
  function normalizeVisit(visitor) {
10314
+ if (Array.isArray(visitor)) {
10315
+ let merged;
10316
+ for (const entry of visitor) merged = sequenceVisit(merged, normalizeVisit(entry));
10317
+ return merged;
10318
+ }
10218
10319
  return typeof visitor === "function" ? visitor : normalizeVisitor(visitor);
10219
10320
  }
10321
+ function sequenceVisit(first, second) {
10322
+ if (!first || !second) return first || second;
10323
+ const enterFirst = getVisitorEnter(first);
10324
+ const enterSecond = getVisitorEnter(second);
10325
+ const enter = (enterFirst || enterSecond) && function enter(path$10, state) {
10326
+ const { node } = path$10;
10327
+ enterFirst?.call(this, path$10, state);
10328
+ if (path$10.node === node) enterSecond?.call(this, path$10, state);
10329
+ };
10330
+ const exitFirst = getVisitorExit(first);
10331
+ const exitSecond = getVisitorExit(second);
10332
+ const exit = (exitFirst || exitSecond) && function exit(path$11, state) {
10333
+ const { node } = path$11;
10334
+ exitFirst?.call(this, path$11, state);
10335
+ if (path$11.node === node) exitSecond?.call(this, path$11, state);
10336
+ };
10337
+ return exit ? enter ? {
10338
+ enter,
10339
+ exit
10340
+ } : { exit } : enter;
10341
+ }
10220
10342
  function getVisitorEnter(visit) {
10221
10343
  return typeof visit === "function" ? visit : visit?.enter;
10222
10344
  }
@@ -10,5 +10,7 @@ export declare function getTranslatedBodyContentProperty(props: t.ObjectExpressi
10
10
  value: t.Expression;
11
11
  }) | undefined;
12
12
  export declare function addDynamicAttrTagStatements(attrTags: t.NodePath<t.MarkoTag["attributeTags"][number]>[], index: number, attrTagLookup: AttrTagLookup, statements: t.Statement[], propTree: BindingPropTree | true, contentKey?: ContentKey): number;
13
+ /** Unwraps a lone spread to the spread argument itself, so the result may alias
14
+ * a caller binding; anything the runtime writes to needs its own object. */
13
15
  export declare function propsToExpression(props: t.ObjectExpression["properties"]): t.Expression;
14
16
  export {};
@@ -11,4 +11,7 @@ export declare function exit(path: t.NodePath<any>): void;
11
11
  export declare function enterShallow(path: t.NodePath<any>): void;
12
12
  export declare function injectWalks(tag: t.NodePath<t.MarkoTag>, name: string, expr?: Walk): void;
13
13
  export declare function visit(path: t.NodePath<t.MarkoTag | t.MarkoPlaceholder | t.Program>, code: VisitCodes): void;
14
+ /** `_content` strips trailing exit codes before it walks, so a renderer that
15
+ * reaches the runtime through it never needs them on the wire. */
16
+ export declare function trimTrailingExits(walks: t.Expression | undefined): t.ArrayExpression | t.ArrowFunctionExpression | t.AssignmentExpression | t.AwaitExpression | t.BigIntLiteral | t.BinaryExpression | t.BindExpression | t.BooleanLiteral | t.CallExpression | t.ClassExpression | t.ConditionalExpression | t.DecimalLiteral | t.DoExpression | t.FunctionExpression | t.Identifier | t.Import | t.ImportExpression | t.JSXElement | t.JSXFragment | t.LogicalExpression | t.MarkoParseError | t.MemberExpression | t.MetaProperty | t.ModuleExpression | t.NewExpression | t.NullLiteral | t.NumericLiteral | t.ObjectExpression | t.OptionalCallExpression | t.OptionalMemberExpression | t.ParenthesizedExpression | t.PipelineBareFunction | t.PipelinePrimaryTopicReference | t.PipelineTopicExpression | t.RecordExpression | t.RegExpLiteral | t.SequenceExpression | t.StringLiteral | t.Super | t.TSAsExpression | t.TSInstantiationExpression | t.TSNonNullExpression | t.TSSatisfiesExpression | t.TSTypeAssertion | t.TaggedTemplateExpression | t.TemplateLiteral | t.ThisExpression | t.TopicReference | t.TupleExpression | t.TypeCastExpression | t.UnaryExpression | t.UpdateExpression | t.YieldExpression | undefined;
14
17
  export declare function getWalkString(section: Section): t.Expression | undefined;
@@ -1,5 +1,6 @@
1
1
  import { types as t } from "@marko/compiler";
2
2
  import { type Binding } from "../../util/references";
3
+ import { type DOMRuntimeHelpers } from "../../util/runtime";
3
4
  export declare const kNativeTagBinding: unique symbol;
4
5
  export declare const kSkipEndTag: unique symbol;
5
6
  declare const kTagContentAttr: unique symbol;
@@ -20,3 +21,12 @@ declare const _default: {
20
21
  };
21
22
  };
22
23
  export default _default;
24
+ /** How a spread claims its controlled attrs during render; nothing for the many
25
+ * tags that control nothing, and nothing when a static attr owns the
26
+ * controllable, since then the spread must leave the slots it wrote alone. */
27
+ export declare function controllableClaimFor(tagName: string | undefined): "_controllable_input" | "_controllable_open" | "_controllable_select" | "_controllable_textarea" | undefined;
28
+ /** The resume-pass latch for a tag: `_attrs_script` resolves the control kind
29
+ * at run time, and a run-time tag name can be any of them. */
30
+ export declare function controllableScriptLatchFor(tagName: string | undefined): "_enable_controllable" | "_enable_controllable_input" | "_enable_controllable_open" | "_enable_controllable_select" | "_enable_controllable_textarea" | undefined;
31
+ /** Emits the latch once per program, like `_enable_catch`. */
32
+ export declare function enableControllable(helper: DOMRuntimeHelpers | undefined): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "marko",
3
- "version": "6.3.24",
3
+ "version": "6.3.26",
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.9",
51
+ "@marko/compiler": "^5.41.10",
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.24",
58
- "marko": "5.39.29"
57
+ "marko": "5.39.30",
58
+ "@marko/runtime-tags": "npm:marko@6.3.26"
59
59
  },
60
60
  "engines": {
61
61
  "node": ">=22"