marko 6.0.40 → 6.0.41

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.
@@ -10,7 +10,9 @@ export declare function controllable_input_checkedValue(scopeId: number, nodeAcc
10
10
  export declare function controllable_detailsOrDialog_open(scopeId: number, nodeAccessor: Accessor, open: unknown, openChange: unknown): string;
11
11
  export declare function attr(name: string, value: unknown): string;
12
12
  export declare function attrs(data: Record<string, unknown>, nodeAccessor: Accessor, scopeId: number, tagName: string): string;
13
+ export declare function writeAttrsAndContent(data: Record<string, unknown>, nodeAccessor: Accessor, scopeId: number, tagName: string, serializeReason?: 1 | 0): void;
13
14
  export declare function partialAttrs(data: Record<string, unknown>, skip: Record<string, 1>, nodeAccessor: Accessor, scopeId: number, tagName: string): string;
15
+ export declare function writePartialAttrsAndContent(data: Record<string, unknown>, skip: Record<string, 1>, nodeAccessor: Accessor, scopeId: number, tagName: string, serializeReason?: 1 | 0): void;
14
16
  export declare function attrAssignment(value: string): string;
15
17
  export declare function escapeSingleQuotedAttrValue(value: string): string;
16
18
  export declare function escapeDoubleQuotedAttrValue(value: string): string;
@@ -1,5 +1,6 @@
1
1
  import { type $Global, type Accessor, type Falsy, ResumeSymbol } from "../common/types";
2
2
  import { Serializer } from "./serializer";
3
+ import type { ServerRenderer } from "./template";
3
4
  export type PartialScope = Record<Accessor, unknown>;
4
5
  type ScopeInternals = PartialScope & {
5
6
  [K_SCOPE_ID]?: number;
@@ -17,6 +18,8 @@ export declare function getScopeId(scope: unknown): number | undefined;
17
18
  export declare function write(html: string): void;
18
19
  export declare function writeScript(script: string): void;
19
20
  export declare function writeEffect(scopeId: number, registryId: string): void;
21
+ export declare function writeContent(nodeAccessor: Accessor, scopeId: number, content: unknown, serializeReason?: 1 | 0): void;
22
+ export declare function normalizeServerRender(value: unknown): ServerRenderer | undefined;
20
23
  export declare function withContext<T>(key: PropertyKey, value: unknown, cb: () => T): T;
21
24
  export declare function setTagVar(parentScopeId: number, scopeOffsetAccessor: Accessor, childScopeId: number, registryId: string): void;
22
25
  export declare function register<T extends WeakKey>(val: T, id: string, scopeId?: number): T;
package/dist/html.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  export { attrTag, attrTags } from "./common/attr-tag";
2
- export { attr, attrs, classAttr, controllable_detailsOrDialog_open, controllable_input_checked, controllable_input_checkedValue, controllable_input_value, controllable_select_value, controllable_textarea_value, optionValueAttr, partialAttrs, styleAttr, } from "./html/attrs";
2
+ export { attr, attrs, classAttr, controllable_detailsOrDialog_open, controllable_input_checked, controllable_input_checkedValue, controllable_input_value, controllable_select_value, controllable_textarea_value, optionValueAttr, partialAttrs, styleAttr, writeAttrsAndContent, writePartialAttrsAndContent, } from "./html/attrs";
3
3
  export { compat } from "./html/compat";
4
4
  export { escapeScript, escapeStyle, escapeXML, toString } from "./html/content";
5
5
  export { createContent, dynamicTag, registerContent } from "./html/dynamic-tag";
6
6
  export { forIn, forInBy, forOf, forOfBy, forTo, forToBy } from "./html/for";
7
7
  export { createTemplate } from "./html/template";
8
- export { $global, commentSeparator, ensureScopeWithId, fork, getScopeById, hoist, markResumeNode, nextScopeId, nextTagId, nodeRef, peekNextScopeId, register, resumeClosestBranch, resumeConditional, resumeForIn, resumeForOf, resumeForTo, serializeGuard, serializeIf, setTagVar, tryContent, write, writeEffect, writeExistingScope, writeScope, writeSubscribe, writeTrailers, } from "./html/writer";
8
+ export { $global, commentSeparator, ensureScopeWithId, fork, getScopeById, hoist, markResumeNode, nextScopeId, nextTagId, nodeRef, peekNextScopeId, register, resumeClosestBranch, resumeConditional, resumeForIn, resumeForOf, resumeForTo, serializeGuard, serializeIf, setTagVar, tryContent, write, writeContent, writeEffect, writeExistingScope, writeScope, writeSubscribe, writeTrailers, } from "./html/writer";
package/dist/html.js CHANGED
@@ -68,8 +68,11 @@ __export(html_exports, {
68
68
  toString: () => toString,
69
69
  tryContent: () => tryContent,
70
70
  write: () => write,
71
+ writeAttrsAndContent: () => writeAttrsAndContent,
72
+ writeContent: () => writeContent,
71
73
  writeEffect: () => writeEffect,
72
74
  writeExistingScope: () => writeExistingScope,
75
+ writePartialAttrsAndContent: () => writePartialAttrsAndContent,
73
76
  writeScope: () => writeScope,
74
77
  writeSubscribe: () => writeSubscribe,
75
78
  writeTrailers: () => writeTrailers
@@ -1102,6 +1105,21 @@ function writeScript(script) {
1102
1105
  function writeEffect(scopeId, registryId) {
1103
1106
  $chunk.boundary.state.needsMainRuntime = !0, $chunk.writeEffect(scopeId, registryId);
1104
1107
  }
1108
+ function writeContent(nodeAccessor, scopeId, content, serializeReason) {
1109
+ let shouldResume = serializeReason !== 0, render2 = normalizeServerRender(content), branchId = peekNextScopeId();
1110
+ render2 && (shouldResume ? withBranchId(branchId, render2) : render2()), peekNextScopeId() !== branchId ? shouldResume && writeScope(scopeId, {
1111
+ ["d" /* ConditionalScope */ + nodeAccessor]: writeScope(
1112
+ branchId,
1113
+ {}
1114
+ ),
1115
+ ["c" /* ConditionalRenderer */ + nodeAccessor]: render2?.h
1116
+ }) : nextScopeId();
1117
+ }
1118
+ function normalizeServerRender(value) {
1119
+ let renderer = normalizeDynamicRenderer(value);
1120
+ if (renderer && typeof renderer == "function")
1121
+ return renderer;
1122
+ }
1105
1123
  var kPendingContexts = Symbol("Pending Contexts");
1106
1124
  function withContext(key, value, cb) {
1107
1125
  let ctx = $chunk.context ||= { [kPendingContexts]: 0 }, prev = ctx[key];
@@ -1772,12 +1790,18 @@ function attrs(data, nodeAccessor, scopeId, tagName) {
1772
1790
  }
1773
1791
  return result;
1774
1792
  }
1793
+ function writeAttrsAndContent(data, nodeAccessor, scopeId, tagName, serializeReason) {
1794
+ write(`${attrs(data, nodeAccessor, scopeId, tagName)}>`), writeContent(nodeAccessor, scopeId, data?.content, serializeReason);
1795
+ }
1775
1796
  function partialAttrs(data, skip, nodeAccessor, scopeId, tagName) {
1776
1797
  let partial = {};
1777
1798
  for (let key in data)
1778
1799
  skip[key] || (partial[key] = data[key]);
1779
1800
  return attrs(partial, nodeAccessor, scopeId, tagName);
1780
1801
  }
1802
+ function writePartialAttrsAndContent(data, skip, nodeAccessor, scopeId, tagName, serializeReason) {
1803
+ write(`${partialAttrs(data, skip, nodeAccessor, scopeId, tagName)}>`), writeContent(nodeAccessor, scopeId, data?.content, serializeReason);
1804
+ }
1781
1805
  function writeControlledScope(type, scopeId, nodeAccessor, value, valueChange) {
1782
1806
  writeScope(scopeId, {
1783
1807
  ["f" /* ControlledType */ + nodeAccessor]: type,
@@ -1981,23 +2005,31 @@ function NOOP2() {
1981
2005
  var voidElementsReg = /^(?:area|b(?:ase|r)|col|embed|hr|i(?:mg|nput)|link|meta|param|source|track|wbr)$/, dynamicTag = (scopeId, accessor, tag, inputOrArgs, content, inputIsArgs, serializeReason) => {
1982
2006
  let shouldResume = serializeReason !== 0, renderer = normalizeDynamicRenderer(tag), state = getState(), branchId = peekNextScopeId(), result;
1983
2007
  if (typeof renderer == "string") {
1984
- let input = (inputIsArgs ? inputOrArgs[0] : inputOrArgs) || {};
2008
+ let input = (inputIsArgs ? inputOrArgs[0] : inputOrArgs) || {}, renderContent = content || normalizeDynamicRenderer(input.content);
1985
2009
  if (nextScopeId(), write(`<${renderer}${attrs(input, accessor, scopeId, renderer)}>`), !voidElementsReg.test(renderer)) {
1986
2010
  let renderNativeTag = () => {
1987
- renderer === "textarea" ? write(
1988
- controllable_textarea_value(
2011
+ if (renderer === "textarea")
2012
+ write(
2013
+ controllable_textarea_value(
2014
+ scopeId,
2015
+ accessor,
2016
+ input.value,
2017
+ input.valueChange
2018
+ )
2019
+ );
2020
+ else if (renderContent) {
2021
+ if (typeof renderContent != "function")
2022
+ throw new Error(
2023
+ `Body content is not supported for the \`<${renderer}>\` tag.`
2024
+ );
2025
+ renderer === "select" && ("value" in input || "valueChange" in input) ? controllable_select_value(
1989
2026
  scopeId,
1990
2027
  accessor,
1991
2028
  input.value,
1992
- input.valueChange
1993
- )
1994
- ) : content && (renderer === "select" && ("value" in input || "valueChange" in input) ? controllable_select_value(
1995
- scopeId,
1996
- accessor,
1997
- input.value,
1998
- input.valueChange,
1999
- content
2000
- ) : content());
2029
+ input.valueChange,
2030
+ renderContent
2031
+ ) : renderContent();
2032
+ }
2001
2033
  };
2002
2034
  shouldResume ? withBranchId(branchId, renderNativeTag) : renderNativeTag(), write(`</${renderer}>`);
2003
2035
  }
@@ -2177,8 +2209,11 @@ var K_TAGS_API_STATE = Symbol(), COMPAT_REGISTRY = /* @__PURE__ */ new WeakMap()
2177
2209
  toString,
2178
2210
  tryContent,
2179
2211
  write,
2212
+ writeAttrsAndContent,
2213
+ writeContent,
2180
2214
  writeEffect,
2181
2215
  writeExistingScope,
2216
+ writePartialAttrsAndContent,
2182
2217
  writeScope,
2183
2218
  writeSubscribe,
2184
2219
  writeTrailers
package/dist/html.mjs CHANGED
@@ -1024,6 +1024,21 @@ function writeScript(script) {
1024
1024
  function writeEffect(scopeId, registryId) {
1025
1025
  $chunk.boundary.state.needsMainRuntime = !0, $chunk.writeEffect(scopeId, registryId);
1026
1026
  }
1027
+ function writeContent(nodeAccessor, scopeId, content, serializeReason) {
1028
+ let shouldResume = serializeReason !== 0, render2 = normalizeServerRender(content), branchId = peekNextScopeId();
1029
+ render2 && (shouldResume ? withBranchId(branchId, render2) : render2()), peekNextScopeId() !== branchId ? shouldResume && writeScope(scopeId, {
1030
+ ["d" /* ConditionalScope */ + nodeAccessor]: writeScope(
1031
+ branchId,
1032
+ {}
1033
+ ),
1034
+ ["c" /* ConditionalRenderer */ + nodeAccessor]: render2?.h
1035
+ }) : nextScopeId();
1036
+ }
1037
+ function normalizeServerRender(value) {
1038
+ let renderer = normalizeDynamicRenderer(value);
1039
+ if (renderer && typeof renderer == "function")
1040
+ return renderer;
1041
+ }
1027
1042
  var kPendingContexts = Symbol("Pending Contexts");
1028
1043
  function withContext(key, value, cb) {
1029
1044
  let ctx = $chunk.context ||= { [kPendingContexts]: 0 }, prev = ctx[key];
@@ -1694,12 +1709,18 @@ function attrs(data, nodeAccessor, scopeId, tagName) {
1694
1709
  }
1695
1710
  return result;
1696
1711
  }
1712
+ function writeAttrsAndContent(data, nodeAccessor, scopeId, tagName, serializeReason) {
1713
+ write(`${attrs(data, nodeAccessor, scopeId, tagName)}>`), writeContent(nodeAccessor, scopeId, data?.content, serializeReason);
1714
+ }
1697
1715
  function partialAttrs(data, skip, nodeAccessor, scopeId, tagName) {
1698
1716
  let partial = {};
1699
1717
  for (let key in data)
1700
1718
  skip[key] || (partial[key] = data[key]);
1701
1719
  return attrs(partial, nodeAccessor, scopeId, tagName);
1702
1720
  }
1721
+ function writePartialAttrsAndContent(data, skip, nodeAccessor, scopeId, tagName, serializeReason) {
1722
+ write(`${partialAttrs(data, skip, nodeAccessor, scopeId, tagName)}>`), writeContent(nodeAccessor, scopeId, data?.content, serializeReason);
1723
+ }
1703
1724
  function writeControlledScope(type, scopeId, nodeAccessor, value, valueChange) {
1704
1725
  writeScope(scopeId, {
1705
1726
  ["f" /* ControlledType */ + nodeAccessor]: type,
@@ -1903,23 +1924,31 @@ function NOOP2() {
1903
1924
  var voidElementsReg = /^(?:area|b(?:ase|r)|col|embed|hr|i(?:mg|nput)|link|meta|param|source|track|wbr)$/, dynamicTag = (scopeId, accessor, tag, inputOrArgs, content, inputIsArgs, serializeReason) => {
1904
1925
  let shouldResume = serializeReason !== 0, renderer = normalizeDynamicRenderer(tag), state = getState(), branchId = peekNextScopeId(), result;
1905
1926
  if (typeof renderer == "string") {
1906
- let input = (inputIsArgs ? inputOrArgs[0] : inputOrArgs) || {};
1927
+ let input = (inputIsArgs ? inputOrArgs[0] : inputOrArgs) || {}, renderContent = content || normalizeDynamicRenderer(input.content);
1907
1928
  if (nextScopeId(), write(`<${renderer}${attrs(input, accessor, scopeId, renderer)}>`), !voidElementsReg.test(renderer)) {
1908
1929
  let renderNativeTag = () => {
1909
- renderer === "textarea" ? write(
1910
- controllable_textarea_value(
1930
+ if (renderer === "textarea")
1931
+ write(
1932
+ controllable_textarea_value(
1933
+ scopeId,
1934
+ accessor,
1935
+ input.value,
1936
+ input.valueChange
1937
+ )
1938
+ );
1939
+ else if (renderContent) {
1940
+ if (typeof renderContent != "function")
1941
+ throw new Error(
1942
+ `Body content is not supported for the \`<${renderer}>\` tag.`
1943
+ );
1944
+ renderer === "select" && ("value" in input || "valueChange" in input) ? controllable_select_value(
1911
1945
  scopeId,
1912
1946
  accessor,
1913
1947
  input.value,
1914
- input.valueChange
1915
- )
1916
- ) : content && (renderer === "select" && ("value" in input || "valueChange" in input) ? controllable_select_value(
1917
- scopeId,
1918
- accessor,
1919
- input.value,
1920
- input.valueChange,
1921
- content
1922
- ) : content());
1948
+ input.valueChange,
1949
+ renderContent
1950
+ ) : renderContent();
1951
+ }
1923
1952
  };
1924
1953
  shouldResume ? withBranchId(branchId, renderNativeTag) : renderNativeTag(), write(`</${renderer}>`);
1925
1954
  }
@@ -2098,8 +2127,11 @@ export {
2098
2127
  toString,
2099
2128
  tryContent,
2100
2129
  write,
2130
+ writeAttrsAndContent,
2131
+ writeContent,
2101
2132
  writeEffect,
2102
2133
  writeExistingScope,
2134
+ writePartialAttrsAndContent,
2103
2135
  writeScope,
2104
2136
  writeSubscribe,
2105
2137
  writeTrailers
@@ -3949,25 +3949,34 @@ function replaceBindingReadNode2(node) {
3949
3949
  }
3950
3950
  }
3951
3951
  }
3952
+ var updateExpressions = /* @__PURE__ */ new WeakSet();
3952
3953
  function replaceAssignedNode(node) {
3953
3954
  switch (node.type) {
3955
+ case "ExpressionStatement": {
3956
+ if (node.expression.type === "SequenceExpression" && updateExpressions.delete(node.expression)) {
3957
+ return node.expression.expressions[0];
3958
+ }
3959
+ break;
3960
+ }
3954
3961
  case "UpdateExpression": {
3955
3962
  const { extra } = node.argument;
3956
3963
  if (isAssignedBindingExtra(extra)) {
3957
3964
  const buildAssignment = getBuildAssignment(extra);
3958
3965
  if (buildAssignment) {
3959
- const replacement = buildAssignment(
3960
- extra.section,
3961
- import_compiler20.types.binaryExpression(
3962
- node.operator === "++" ? "+" : "-",
3963
- node.argument,
3964
- import_compiler20.types.numericLiteral(1)
3965
- )
3966
- );
3967
3966
  if (!node.prefix) {
3968
- return import_compiler20.types.sequenceExpression([replacement, node.argument]);
3967
+ node.prefix = true;
3968
+ const replacement = import_compiler20.types.sequenceExpression([
3969
+ buildAssignment(extra.section, node),
3970
+ import_compiler20.types.binaryExpression(
3971
+ node.operator === "++" ? "-" : "+",
3972
+ node.argument,
3973
+ import_compiler20.types.numericLiteral(1)
3974
+ )
3975
+ ]);
3976
+ updateExpressions.add(replacement);
3977
+ return replacement;
3969
3978
  }
3970
- return replacement;
3979
+ return buildAssignment(extra.section, node);
3971
3980
  }
3972
3981
  }
3973
3982
  break;
@@ -3979,17 +3988,24 @@ function replaceAssignedNode(node) {
3979
3988
  if (isAssignedBindingExtra(extra)) {
3980
3989
  const buildAssignment = getBuildAssignment(extra);
3981
3990
  if (buildAssignment) {
3982
- return buildAssignment(
3983
- extra.section,
3984
- node.operator === "=" ? node.right : import_compiler20.types.binaryExpression(
3985
- node.operator.slice(
3986
- 0,
3987
- -1
3988
- ),
3989
- node.left,
3990
- node.right
3991
- )
3992
- );
3991
+ if (bindingUtil.has(
3992
+ extra.fnExtra?.referencedBindingsInFunction,
3993
+ extra.assignment
3994
+ )) {
3995
+ return buildAssignment(extra.section, node);
3996
+ } else {
3997
+ return buildAssignment(
3998
+ extra.section,
3999
+ node.operator === "=" ? node.right : import_compiler20.types.binaryExpression(
4000
+ node.operator.slice(
4001
+ 0,
4002
+ -1
4003
+ ),
4004
+ node.left,
4005
+ node.right
4006
+ )
4007
+ );
4008
+ }
3993
4009
  }
3994
4010
  }
3995
4011
  break;
@@ -4003,19 +4019,24 @@ function replaceAssignedNode(node) {
4003
4019
  if (isAssignedBindingExtra(extra)) {
4004
4020
  const buildAssignment = getBuildAssignment(extra);
4005
4021
  if (buildAssignment) {
4006
- id.name = generateUid(id.name);
4007
- (params ||= []).push(import_compiler20.types.identifier(id.name));
4022
+ if (!bindingUtil.has(
4023
+ extra.fnExtra?.referencedBindingsInFunction,
4024
+ extra.assignment
4025
+ )) {
4026
+ id.name = generateUid(id.name);
4027
+ (params ||= []).push(import_compiler20.types.identifier(id.name));
4028
+ }
4008
4029
  (assignments ||= []).push(
4009
4030
  buildAssignment(extra.section, import_compiler20.types.identifier(id.name))
4010
4031
  );
4011
4032
  }
4012
4033
  }
4013
4034
  });
4014
- if (params && assignments) {
4035
+ if (assignments) {
4015
4036
  const resultId = generateUid("result");
4016
4037
  return import_compiler20.types.callExpression(
4017
4038
  import_compiler20.types.arrowFunctionExpression(
4018
- [import_compiler20.types.identifier(resultId), ...params],
4039
+ [import_compiler20.types.identifier(resultId), ...params || []],
4019
4040
  import_compiler20.types.sequenceExpression([
4020
4041
  import_compiler20.types.assignmentExpression(
4021
4042
  "=",
@@ -4620,6 +4641,8 @@ function trackReferencesForBinding(babelBinding, binding) {
4620
4641
  }
4621
4642
  }
4622
4643
  function trackAssignment(assignment, binding) {
4644
+ const fnRoot = getFnRoot(assignment);
4645
+ const fnExtra = fnRoot && (fnRoot.node.extra ??= {});
4623
4646
  const section = getOrCreateSection(assignment);
4624
4647
  setReferencesScope(assignment);
4625
4648
  forEachIdentifierPath(assignment, (id) => {
@@ -4646,6 +4669,7 @@ function trackAssignment(assignment, binding) {
4646
4669
  );
4647
4670
  extra.assignment = binding;
4648
4671
  extra.section = section;
4672
+ extra.fnExtra = fnExtra;
4649
4673
  }
4650
4674
  });
4651
4675
  }
@@ -5273,6 +5297,7 @@ function addReadToExpression(root, binding) {
5273
5297
  if (fnRoot) {
5274
5298
  const readsByFn = getReadsByFunction();
5275
5299
  const fnExtra = fnRoot.node.extra ??= {};
5300
+ exprExtra.fnExtra = fnExtra;
5276
5301
  fnExtra.section = section;
5277
5302
  readsByFn.set(fnExtra, push(readsByFn.get(fnExtra), read));
5278
5303
  }
@@ -5981,6 +6006,7 @@ var import_babel_utils23 = require("@marko/compiler/babel-utils");
5981
6006
  var kNativeTagBinding = Symbol("native tag binding");
5982
6007
  var kSkipEndTag = Symbol("skip native tag mark");
5983
6008
  var kGetterId = Symbol("node getter id");
6009
+ var kTagContentAttr = Symbol("tag could have dynamic content attribute");
5984
6010
  var htmlSelectArgs = /* @__PURE__ */ new WeakMap();
5985
6011
  var native_tag_default = {
5986
6012
  transform: {
@@ -6245,15 +6271,19 @@ var native_tag_default = {
6245
6271
  break;
6246
6272
  }
6247
6273
  }
6274
+ const isOpenOnly = !!(tagDef && tagDef.parseOptions?.openTagOnly);
6275
+ const hasChildren = !!tag.node.body.body.length;
6248
6276
  if (spreadExpression) {
6249
6277
  addHTMLEffectCall(tagSection, tagExtra.referencedBindings);
6250
- if (skipExpression) {
6251
- write2`${callRuntime("partialAttrs", spreadExpression, skipExpression, visitAccessor, getScopeIdIdentifier(tagSection), tag.node.name)}`;
6252
- } else {
6253
- write2`${callRuntime("attrs", spreadExpression, visitAccessor, getScopeIdIdentifier(tagSection), tag.node.name)}`;
6278
+ if (isOpenOnly || hasChildren || usedAttrs.staticContentAttr) {
6279
+ if (skipExpression) {
6280
+ write2`${callRuntime("partialAttrs", spreadExpression, skipExpression, visitAccessor, getScopeIdIdentifier(tagSection), tag.node.name)}`;
6281
+ } else {
6282
+ write2`${callRuntime("attrs", spreadExpression, visitAccessor, getScopeIdIdentifier(tagSection), tag.node.name)}`;
6283
+ }
6254
6284
  }
6255
6285
  }
6256
- if (tagDef && tagDef.parseOptions?.openTagOnly) {
6286
+ if (isOpenOnly) {
6257
6287
  switch (tagDef.htmlType) {
6258
6288
  case "svg":
6259
6289
  case "math":
@@ -6264,7 +6294,54 @@ var native_tag_default = {
6264
6294
  break;
6265
6295
  }
6266
6296
  } else {
6267
- write2`>`;
6297
+ if (usedAttrs.staticContentAttr) {
6298
+ write2`>`;
6299
+ tagExtra[kTagContentAttr] = true;
6300
+ tag.node.body.body = [
6301
+ import_compiler31.types.expressionStatement(
6302
+ callRuntime(
6303
+ "writeContent",
6304
+ visitAccessor,
6305
+ getScopeIdIdentifier(tagSection),
6306
+ usedAttrs.staticContentAttr.value,
6307
+ getSerializeGuard(
6308
+ nodeBinding && getBindingSerializeReason(tagSection, nodeBinding),
6309
+ true
6310
+ )
6311
+ )
6312
+ )
6313
+ ];
6314
+ } else if (spreadExpression && !hasChildren) {
6315
+ const serializeReason = getSerializeGuard(
6316
+ nodeBinding && getBindingSerializeReason(tagSection, nodeBinding),
6317
+ true
6318
+ );
6319
+ tagExtra[kTagContentAttr] = true;
6320
+ tag.node.body.body = [
6321
+ skipExpression ? import_compiler31.types.expressionStatement(
6322
+ callRuntime(
6323
+ "writePartialAttrsAndContent",
6324
+ spreadExpression,
6325
+ skipExpression,
6326
+ visitAccessor,
6327
+ getScopeIdIdentifier(tagSection),
6328
+ tag.node.name,
6329
+ serializeReason
6330
+ )
6331
+ ) : import_compiler31.types.expressionStatement(
6332
+ callRuntime(
6333
+ "writeAttrsAndContent",
6334
+ spreadExpression,
6335
+ visitAccessor,
6336
+ getScopeIdIdentifier(tagSection),
6337
+ tag.node.name,
6338
+ serializeReason
6339
+ )
6340
+ )
6341
+ ];
6342
+ } else {
6343
+ write2`>`;
6344
+ }
6268
6345
  }
6269
6346
  if (tagExtra.tagNameNullable) {
6270
6347
  tag.insertBefore(
@@ -6282,6 +6359,9 @@ var native_tag_default = {
6282
6359
  const selectArgs = htmlSelectArgs.get(tag.node);
6283
6360
  const tagName = getTagName(tag);
6284
6361
  const tagSection = getSection(tag);
6362
+ if (tagExtra[kTagContentAttr]) {
6363
+ flushBefore(tag);
6364
+ }
6285
6365
  if (tagExtra.tagNameNullable) {
6286
6366
  flushInto(tag);
6287
6367
  }
@@ -6395,6 +6475,8 @@ var native_tag_default = {
6395
6475
  const usedAttrs = getUsedAttrs(tagName, tag.node);
6396
6476
  const { staticAttrs, staticControllable, skipExpression } = usedAttrs;
6397
6477
  const { spreadExpression } = usedAttrs;
6478
+ const isOpenOnly = !!(tagDef && tagDef.parseOptions?.openTagOnly);
6479
+ const hasChildren = !!tag.node.body.body.length;
6398
6480
  if (staticControllable) {
6399
6481
  const { helper, attrs: attrs2 } = staticControllable;
6400
6482
  const firstAttr = attrs2.find(Boolean);
@@ -6521,6 +6603,7 @@ var native_tag_default = {
6521
6603
  }
6522
6604
  }
6523
6605
  if (spreadExpression) {
6606
+ const canHaveAttrContent = !(isOpenOnly || hasChildren || usedAttrs.staticContentAttr);
6524
6607
  if (skipExpression) {
6525
6608
  addStatement(
6526
6609
  "render",
@@ -6528,7 +6611,7 @@ var native_tag_default = {
6528
6611
  tagExtra.referencedBindings,
6529
6612
  import_compiler31.types.expressionStatement(
6530
6613
  callRuntime(
6531
- "partialAttrs",
6614
+ canHaveAttrContent ? "partialAttrsAndContent" : "partialAttrs",
6532
6615
  scopeIdentifier,
6533
6616
  visitAccessor,
6534
6617
  spreadExpression,
@@ -6543,7 +6626,7 @@ var native_tag_default = {
6543
6626
  tagExtra.referencedBindings,
6544
6627
  import_compiler31.types.expressionStatement(
6545
6628
  callRuntime(
6546
- "attrs",
6629
+ canHaveAttrContent ? "attrsAndContent" : "attrs",
6547
6630
  scopeIdentifier,
6548
6631
  visitAccessor,
6549
6632
  spreadExpression
@@ -6561,7 +6644,23 @@ var native_tag_default = {
6561
6644
  false
6562
6645
  );
6563
6646
  }
6564
- if (tagDef && tagDef.parseOptions?.openTagOnly) {
6647
+ if (usedAttrs.staticContentAttr) {
6648
+ const contentAttrValue = usedAttrs.staticContentAttr.value;
6649
+ addStatement(
6650
+ "render",
6651
+ tagSection,
6652
+ contentAttrValue.extra?.referencedBindings,
6653
+ import_compiler31.types.expressionStatement(
6654
+ callRuntime(
6655
+ "insertContent",
6656
+ scopeIdentifier,
6657
+ visitAccessor,
6658
+ contentAttrValue
6659
+ )
6660
+ )
6661
+ );
6662
+ }
6663
+ if (isOpenOnly) {
6565
6664
  switch (tagDef.htmlType) {
6566
6665
  case "svg":
6567
6666
  case "math":
@@ -6665,6 +6764,7 @@ function getUsedAttrs(tagName, tag) {
6665
6764
  let spreadProps;
6666
6765
  let skipProps;
6667
6766
  let staticControllable;
6767
+ let staticContentAttr;
6668
6768
  for (let i = attributes.length; i--; ) {
6669
6769
  const attr2 = attributes[i];
6670
6770
  const { value } = attr2;
@@ -6683,10 +6783,12 @@ function getUsedAttrs(tagName, tag) {
6683
6783
  }
6684
6784
  }
6685
6785
  spreadProps.push(import_compiler31.types.spreadElement(value));
6686
- } else if (!seen[attr2.name]) {
6786
+ } else if (!seen[attr2.name] || !(attr2.name === "content" && tag.body.body.length)) {
6687
6787
  seen[attr2.name] = attr2;
6688
6788
  if (spreadProps) {
6689
6789
  spreadProps.push(toObjectProperty(attr2.name, attr2.value));
6790
+ } else if (attr2.name === "content") {
6791
+ staticContentAttr = attr2;
6690
6792
  } else {
6691
6793
  maybeStaticAttrs.add(attr2);
6692
6794
  }
@@ -6720,13 +6822,14 @@ function getUsedAttrs(tagName, tag) {
6720
6822
  for (const { name: name2 } of staticAttrs) {
6721
6823
  (skipProps ||= []).push(toObjectProperty(name2, import_compiler31.types.numericLiteral(1)));
6722
6824
  }
6723
- if (skipProps) {
6724
- skipExpression = import_compiler31.types.objectExpression(skipProps);
6725
- }
6726
6825
  spreadExpression = propsToExpression(spreadProps);
6727
6826
  }
6827
+ if (skipProps) {
6828
+ skipExpression = import_compiler31.types.objectExpression(skipProps);
6829
+ }
6728
6830
  return {
6729
6831
  staticAttrs,
6832
+ staticContentAttr,
6730
6833
  staticControllable,
6731
6834
  spreadExpression,
6732
6835
  skipExpression
@@ -45,6 +45,9 @@ export interface InputBinding extends Binding {
45
45
  }
46
46
  export type ReferencedBindings = Opt<Binding>;
47
47
  export type Intersection = Many<Binding>;
48
+ type FnExtra = (t.FunctionExpressionExtra | t.ArrowFunctionExpressionExtra | t.FunctionDeclarationExtra) & {
49
+ section: Section;
50
+ };
48
51
  declare module "@marko/compiler/dist/types" {
49
52
  interface NodeExtra {
50
53
  section?: Section;
@@ -103,6 +106,7 @@ export declare function getSectionInstancesAccessorLiteral(section: Section): t.
103
106
  export declare function getReadReplacement(node: t.Identifier | t.MemberExpression): t.Node | undefined;
104
107
  export interface ReferencedExtra extends t.NodeExtra {
105
108
  section: Section;
109
+ fnExtra?: FnExtra;
106
110
  }
107
111
  export declare function isReferencedExtra(extra: t.NodeExtra | undefined): extra is ReferencedExtra;
108
112
  export interface AssignedBindingExtra extends ReferencedExtra {
@@ -3,11 +3,13 @@ import { type Binding } from "../../util/references";
3
3
  export declare const kNativeTagBinding: unique symbol;
4
4
  export declare const kSkipEndTag: unique symbol;
5
5
  declare const kGetterId: unique symbol;
6
+ declare const kTagContentAttr: unique symbol;
6
7
  declare module "@marko/compiler/dist/types" {
7
8
  interface NodeExtra {
8
9
  [kNativeTagBinding]?: Binding;
9
10
  [kSkipEndTag]?: true;
10
11
  [kGetterId]?: string;
12
+ [kTagContentAttr]?: true;
11
13
  }
12
14
  }
13
15
  declare const _default: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "marko",
3
- "version": "6.0.40",
3
+ "version": "6.0.41",
4
4
  "description": "Optimized runtime for Marko templates.",
5
5
  "keywords": [
6
6
  "api",
package/tags-html.d.ts CHANGED
@@ -4346,7 +4346,10 @@ declare global {
4346
4346
  * Provide body content for the tag as a Marko.Body.
4347
4347
  * @see Marko.Body
4348
4348
  */
4349
- content?: Marko.Body<[], void>;
4349
+ content?:
4350
+ | AttrMissing
4351
+ | Marko.Body<[], void>
4352
+ | Marko.Template<Record<any, never>, void>;
4350
4353
 
4351
4354
  /**
4352
4355
  * data-* global attributes form a class of attributes called custom data attributes, that allow proprietary