feat: content attr in native tags (#2746)

* feat: content attr in native tags

* chore: add changeset

* chore: rerun tests

* fix: edge case
This commit is contained in:
Luke LaValva 2025-07-22 14:57:58 -07:00 committed by GitHub
parent 34bc21e3d6
commit 064f068fdb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 1331 additions and 355 deletions

View File

@ -0,0 +1,6 @@
---
"@marko/runtime-tags": patch
"marko": patch
---
Allow `content` attribute in native tags

View File

@ -7,8 +7,8 @@
{
"name": "*",
"total": {
"min": 19080,
"brotli": 7252
"min": 19321,
"brotli": 7333
}
},
{
@ -18,12 +18,12 @@
"brotli": 151
},
"runtime": {
"min": 3956,
"brotli": 1748
"min": 3960,
"brotli": 1760
},
"total": {
"min": 4140,
"brotli": 1899
"min": 4144,
"brotli": 1911
}
},
{
@ -34,11 +34,11 @@
},
"runtime": {
"min": 2188,
"brotli": 1146
"brotli": 1143
},
"total": {
"min": 2294,
"brotli": 1243
"brotli": 1240
}
},
{
@ -49,11 +49,11 @@
},
"runtime": {
"min": 7019,
"brotli": 2996
"brotli": 3005
},
"total": {
"min": 7910,
"brotli": 3451
"brotli": 3460
}
},
{
@ -64,11 +64,11 @@
},
"runtime": {
"min": 2355,
"brotli": 1198
"brotli": 1202
},
"total": {
"min": 2495,
"brotli": 1317
"brotli": 1321
}
}
]

View File

@ -1,4 +1,4 @@
// size: 19080 (min) 7252 (brotli)
// size: 19321 (min) 7333 (brotli)
var empty = [],
rest = Symbol();
function attrTag(attrs2) {
@ -188,7 +188,7 @@ function init(runtimeId = "M") {
}
}
},
o(scope) {
p(scope) {
let parentBranchId =
scope.g || parentBranchIds.get(scopeId);
if (
@ -200,7 +200,7 @@ function init(runtimeId = "M") {
parentBranch = branch.k;
((scope.k = branch),
parentBranch &&
((branch.u = parentBranch),
((branch.y = parentBranch),
(parentBranch.A ||= new Set()).add(branch)));
}
},
@ -248,11 +248,11 @@ function init(runtimeId = "M") {
scope,
scopeLookup[scopeId],
)),
branches && branches.o(scope))
branches && branches.p(scope))
: (($global = scope || {}),
($global.runtimeId = runtimeId),
($global.renderId = renderId),
($global.p = 1e6));
($global.q = 1e6));
} finally {
isResuming = visits.length = resumes.length = 0;
}
@ -544,269 +544,33 @@ function normalizeBoolProp(value2) {
function toValueProp(it) {
return it.value;
}
var parsers = {};
var isScheduled,
channel,
parsers = {};
function parseHTML(html2, ns) {
let parser = (parsers[ns] ||= document.createElementNS(ns, "template"));
return ((parser.innerHTML = html2), parser.content || parser);
}
function attr(element, name, value2) {
setAttribute(element, name, normalizeAttrValue(value2));
}
function setAttribute(element, name, value2) {
element.getAttribute(name) != value2 &&
(void 0 === value2
? element.removeAttribute(name)
: element.setAttribute(name, value2));
}
function classAttr(element, value2) {
setAttribute(
element,
"class",
toDelimitedString(value2, " ", stringifyClassObject) || void 0,
);
}
function classItems(element, items) {
for (let key in items) classItem(element, key, items[key]);
}
function classItem(element, name, value2) {
element.classList.toggle(name, !!value2);
}
function styleAttr(element, value2) {
setAttribute(
element,
"style",
toDelimitedString(value2, ";", stringifyStyleObject) || void 0,
);
}
function styleItems(element, items) {
for (let key in items) styleItem(element, key, items[key]);
}
function styleItem(element, name, value2) {
element.style.setProperty(name, value2 || 0 === value2 ? value2 + "" : "");
}
function data(node, value2) {
let normalizedValue = normalizeString(value2);
node.data !== normalizedValue && (node.data = normalizedValue);
}
function textContent(node, value2) {
let normalizedValue = normalizeString(value2);
node.textContent !== normalizedValue && (node.textContent = normalizedValue);
}
function attrs(scope, nodeAccessor, nextAttrs) {
let el = scope[nodeAccessor];
for (let i = el.attributes.length; i--; ) {
let { name: name } = el.attributes.item(i);
(nextAttrs && (name in nextAttrs || hasAttrAlias(el, name, nextAttrs))) ||
el.removeAttribute(name);
}
attrsInternal(scope, nodeAccessor, nextAttrs);
}
function hasAttrAlias(element, attr2, nextAttrs) {
return (
"checked" === attr2 &&
"INPUT" === element.tagName &&
"checkedValue" in nextAttrs
);
}
function partialAttrs(scope, nodeAccessor, nextAttrs, skip) {
let el = scope[nodeAccessor],
partial = {};
for (let i = el.attributes.length; i--; ) {
let { name: name } = el.attributes.item(i);
!skip[name] &&
(!nextAttrs || !(name in nextAttrs)) &&
el.removeAttribute(name);
}
for (let key in nextAttrs) skip[key] || (partial[key] = nextAttrs[key]);
attrsInternal(scope, nodeAccessor, partial);
}
function attrsInternal(scope, nodeAccessor, nextAttrs) {
let events,
skip,
el = scope[nodeAccessor];
switch (el.tagName) {
case "INPUT":
if ("checked" in nextAttrs || "checkedChange" in nextAttrs)
controllable_input_checked(
scope,
nodeAccessor,
nextAttrs.checked,
nextAttrs.checkedChange,
);
else if ("checkedValue" in nextAttrs || "checkedValueChange" in nextAttrs)
controllable_input_checkedValue(
scope,
nodeAccessor,
nextAttrs.checkedValue,
nextAttrs.checkedValueChange,
nextAttrs.value,
);
else {
if (!("value" in nextAttrs) && !("valueChange" in nextAttrs)) break;
controllable_input_value(
scope,
nodeAccessor,
nextAttrs.value,
nextAttrs.valueChange,
);
}
skip = /^(?:value|checked(?:Value)?)(?:Change)?$/;
break;
case "SELECT":
("value" in nextAttrs || "valueChange" in nextAttrs) &&
(controllable_select_value(
scope,
nodeAccessor,
nextAttrs.value,
nextAttrs.valueChange,
),
(skip = /^value(?:Change)?$/));
break;
case "TEXTAREA":
("value" in nextAttrs || "valueChange" in nextAttrs) &&
(controllable_input_value(
scope,
nodeAccessor,
nextAttrs.value,
nextAttrs.valueChange,
),
(skip = /^value(?:Change)?$/));
break;
case "DETAILS":
case "DIALOG":
("open" in nextAttrs || "openChange" in nextAttrs) &&
(controllable_detailsOrDialog_open(
scope,
nodeAccessor,
nextAttrs.open,
nextAttrs.openChange,
),
(skip = /^open(?:Change)?$/));
}
for (let name in nextAttrs) {
let value2 = nextAttrs[name];
switch (name) {
case "class":
classAttr(el, value2);
break;
case "style":
styleAttr(el, value2);
break;
case "content":
break;
default:
isEventHandler(name)
? ((events ||= scope["i" + nodeAccessor] = {})[
getEventHandlerName(name)
] = value2)
: skip?.test(name) || attr(el, name, value2);
}
}
}
function attrsEvents(scope, nodeAccessor) {
let el = scope[nodeAccessor],
events = scope["i" + nodeAccessor];
switch (scope["f" + nodeAccessor]) {
case 0:
controllable_input_checked_effect(scope, nodeAccessor);
break;
case 1:
controllable_input_checkedValue_effect(scope, nodeAccessor);
break;
case 2:
controllable_input_value_effect(scope, nodeAccessor);
break;
case 3:
controllable_select_value_effect(scope, nodeAccessor);
break;
case 4:
controllable_detailsOrDialog_open_effect(scope, nodeAccessor);
}
for (let name in events) on(el, name, events[name]);
}
function html(scope, value2, accessor) {
let firstChild = scope[accessor],
parentNode = firstChild.parentNode,
lastChild = scope["h" + accessor] || firstChild,
newContent = parseHTML(
value2 || 0 === value2 ? value2 + "" : "",
parentNode.namespaceURI,
);
(insertChildNodes(
parentNode,
firstChild,
(scope[accessor] =
newContent.firstChild || newContent.appendChild(new Text())),
(scope["h" + accessor] = newContent.lastChild),
),
removeChildNodes(firstChild, lastChild));
}
function props(scope, nodeIndex, index) {
let nextProps = scope[index],
prevProps = scope[index + "-"],
node = scope[nodeIndex];
if (prevProps)
for (let name in prevProps) name in nextProps || (node[name] = void 0);
for (let name in nextProps) node[name] = nextProps[name];
scope[index + "-"] = nextProps;
}
function normalizeAttrValue(value2) {
if (value2 || 0 === value2) return !0 === value2 ? "" : value2 + "";
}
function normalizeString(value2) {
return value2 || 0 === value2 ? value2 + "" : "";
}
function lifecycle(scope, index, thisObj) {
let instance = scope[index];
instance
? (Object.assign(instance, thisObj), instance.onUpdate?.())
: ((scope[index] = thisObj),
thisObj.onMount?.(),
(getAbortSignal(scope, "k" + index).onabort = () =>
thisObj.onDestroy?.()));
}
function removeChildNodes(startNode, endNode) {
let stop = endNode.nextSibling,
current = startNode;
for (; current !== stop; ) {
let next = current.nextSibling;
(current.remove(), (current = next));
}
}
function insertChildNodes(parentNode, referenceNode, startNode, endNode) {
parentNode.insertBefore(toInsertNode(startNode, endNode), referenceNode);
}
function toInsertNode(startNode, endNode) {
if (startNode === endNode) return startNode;
let parent = new DocumentFragment(),
stop = endNode.nextSibling,
current = startNode;
for (; current !== stop; ) {
let next = current.nextSibling;
(parent.appendChild(current), (current = next));
}
return parent;
}
function createScope($global, closestBranch) {
let scope = { l: $global.p++, q: 1, k: closestBranch, $global: $global };
let scope = { l: $global.q++, t: 1, k: closestBranch, $global: $global };
return (pendingScopes.push(scope), scope);
}
function skipScope(scope) {
return scope.$global.p++;
return scope.$global.q++;
}
function findBranchWithKey(scope, key) {
let branch = scope.k;
for (; branch && !branch[key]; ) branch = branch.u;
for (; branch && !branch[key]; ) branch = branch.y;
return branch;
}
function destroyBranch(branch) {
(branch.u?.A?.delete(branch), destroyNestedBranches(branch));
(branch.y?.A?.delete(branch), destroyNestedBranches(branch));
}
function destroyNestedBranches(branch) {
((branch.B = 1),
branch.A?.forEach(destroyNestedBranches),
branch.K?.forEach((scope) => {
for (let id in scope.x) scope.x[id]?.abort();
for (let id in scope.z) scope.z[id]?.abort();
}));
}
function removeAndDestroyBranch(branch) {
@ -820,7 +584,6 @@ function tempDetachBranch(branch) {
((fragment.namespaceURI = branch.h.parentNode.namespaceURI),
insertChildNodes(fragment, null, branch.h, branch.j));
}
var isScheduled, channel;
function schedule() {
isScheduled || ((isScheduled = 1), queueMicrotask(flushAndWaitFrame));
}
@ -860,7 +623,7 @@ function value(valueAccessor, fn = () => {}) {
}
function intersection(id, fn, defaultPending = 1, scopeIdAccessor = "l") {
return (scope) => {
scope.q
scope.t
? void 0 === scope[id]
? (scope[id] = defaultPending)
: --scope[id] || fn(scope)
@ -883,7 +646,7 @@ function loopClosure(valueAccessor, ownerLoopNodeAccessor, fn) {
ownerScope,
() => {
for (let scope of scopes)
!scope.q && !scope.B && childSignal(scope);
!scope.t && !scope.B && childSignal(scope);
},
-1,
0,
@ -904,7 +667,7 @@ function conditionalClosure(
ownerSignal = (scope) => {
let ifScope = scope[scopeAccessor];
ifScope &&
!ifScope.q &&
!ifScope.t &&
scope[branchAccessor] === branch &&
queueRender(ifScope, childSignal, -1);
};
@ -925,7 +688,7 @@ function dynamicClosure(...closureSignals) {
return (scope) => {
if (scope[___scopeInstancesAccessor])
for (let childScope of scope[___scopeInstancesAccessor])
childScope.q ||
childScope.t ||
queueRender(
childScope,
closureSignals[childScope[___signalIndexAccessor]],
@ -1050,10 +813,10 @@ function createBranch($global, renderer, parentScope, parentNode) {
let branch = createScope($global),
parentBranch = parentScope?.k;
return (
(branch._ = renderer.y || parentScope),
(branch._ = renderer.u || parentScope),
(branch.k = branch),
parentBranch &&
((branch.u = parentBranch), (parentBranch.A ||= new Set()).add(branch)),
((branch.y = parentBranch), (parentBranch.A ||= new Set()).add(branch)),
renderer.C?.(branch, parentNode.namespaceURI),
branch
);
@ -1111,10 +874,10 @@ function createContent(
return (owner) => ({
l: id,
C: clone,
y: owner,
u: owner,
D: setup,
m: params,
z: dynamicScopesAccessor,
n: dynamicScopesAccessor,
});
}
function registerContent(
@ -1146,6 +909,263 @@ function createRenderer(template, walks, setup, params) {
return createContent("", template, walks, setup, params)();
}
var cloneCache = {};
function attr(element, name, value2) {
setAttribute(element, name, normalizeAttrValue(value2));
}
function setAttribute(element, name, value2) {
element.getAttribute(name) != value2 &&
(void 0 === value2
? element.removeAttribute(name)
: element.setAttribute(name, value2));
}
function classAttr(element, value2) {
setAttribute(
element,
"class",
toDelimitedString(value2, " ", stringifyClassObject) || void 0,
);
}
function classItems(element, items) {
for (let key in items) classItem(element, key, items[key]);
}
function classItem(element, name, value2) {
element.classList.toggle(name, !!value2);
}
function styleAttr(element, value2) {
setAttribute(
element,
"style",
toDelimitedString(value2, ";", stringifyStyleObject) || void 0,
);
}
function styleItems(element, items) {
for (let key in items) styleItem(element, key, items[key]);
}
function styleItem(element, name, value2) {
element.style.setProperty(name, value2 || 0 === value2 ? value2 + "" : "");
}
function data(node, value2) {
let normalizedValue = normalizeString(value2);
node.data !== normalizedValue && (node.data = normalizedValue);
}
function textContent(node, value2) {
let normalizedValue = normalizeString(value2);
node.textContent !== normalizedValue && (node.textContent = normalizedValue);
}
function attrs(scope, nodeAccessor, nextAttrs) {
let el = scope[nodeAccessor];
for (let i = el.attributes.length; i--; ) {
let { name: name } = el.attributes.item(i);
(nextAttrs && (name in nextAttrs || hasAttrAlias(el, name, nextAttrs))) ||
el.removeAttribute(name);
}
attrsInternal(scope, nodeAccessor, nextAttrs);
}
function attrsAndContent(scope, nodeAccessor, nextAttrs) {
(attrs(scope, nodeAccessor, nextAttrs),
insertContent(scope, nodeAccessor, nextAttrs?.content));
}
function hasAttrAlias(element, attr2, nextAttrs) {
return (
"checked" === attr2 &&
"INPUT" === element.tagName &&
"checkedValue" in nextAttrs
);
}
function partialAttrs(scope, nodeAccessor, nextAttrs, skip) {
let el = scope[nodeAccessor],
partial = {};
for (let i = el.attributes.length; i--; ) {
let { name: name } = el.attributes.item(i);
!skip[name] &&
(!nextAttrs || !(name in nextAttrs)) &&
el.removeAttribute(name);
}
for (let key in nextAttrs) skip[key] || (partial[key] = nextAttrs[key]);
attrsInternal(scope, nodeAccessor, partial);
}
function partialAttrsAndContent(scope, nodeAccessor, nextAttrs, skip) {
(partialAttrs(scope, nodeAccessor, nextAttrs, skip),
insertContent(scope, nodeAccessor, nextAttrs?.content));
}
function attrsInternal(scope, nodeAccessor, nextAttrs) {
let events,
skip,
el = scope[nodeAccessor];
switch (el.tagName) {
case "INPUT":
if ("checked" in nextAttrs || "checkedChange" in nextAttrs)
controllable_input_checked(
scope,
nodeAccessor,
nextAttrs.checked,
nextAttrs.checkedChange,
);
else if ("checkedValue" in nextAttrs || "checkedValueChange" in nextAttrs)
controllable_input_checkedValue(
scope,
nodeAccessor,
nextAttrs.checkedValue,
nextAttrs.checkedValueChange,
nextAttrs.value,
);
else {
if (!("value" in nextAttrs) && !("valueChange" in nextAttrs)) break;
controllable_input_value(
scope,
nodeAccessor,
nextAttrs.value,
nextAttrs.valueChange,
);
}
skip = /^(?:value|checked(?:Value)?)(?:Change)?$/;
break;
case "SELECT":
("value" in nextAttrs || "valueChange" in nextAttrs) &&
(controllable_select_value(
scope,
nodeAccessor,
nextAttrs.value,
nextAttrs.valueChange,
),
(skip = /^value(?:Change)?$/));
break;
case "TEXTAREA":
("value" in nextAttrs || "valueChange" in nextAttrs) &&
(controllable_input_value(
scope,
nodeAccessor,
nextAttrs.value,
nextAttrs.valueChange,
),
(skip = /^value(?:Change)?$/));
break;
case "DETAILS":
case "DIALOG":
("open" in nextAttrs || "openChange" in nextAttrs) &&
(controllable_detailsOrDialog_open(
scope,
nodeAccessor,
nextAttrs.open,
nextAttrs.openChange,
),
(skip = /^open(?:Change)?$/));
}
for (let name in nextAttrs) {
let value2 = nextAttrs[name];
switch (name) {
case "class":
classAttr(el, value2);
break;
case "style":
styleAttr(el, value2);
break;
case "content":
break;
default:
isEventHandler(name)
? ((events ||= scope["i" + nodeAccessor] = {})[
getEventHandlerName(name)
] = value2)
: skip?.test(name) || attr(el, name, value2);
}
}
}
function insertContent(scope, nodeAccessor, value2) {
let content = (function (value2) {
let renderer = normalizeDynamicRenderer(value2);
if (renderer && renderer.l) return renderer;
})(value2),
rendererAccessor = "c" + nodeAccessor;
scope[rendererAccessor] !== (scope[rendererAccessor] = content?.l) &&
(setConditionalRenderer(scope, nodeAccessor, content, createAndSetupBranch),
content?.n &&
subscribeToScopeSet(content.u, content.n, scope["d" + nodeAccessor]));
}
function attrsEvents(scope, nodeAccessor) {
let el = scope[nodeAccessor],
events = scope["i" + nodeAccessor];
switch (scope["f" + nodeAccessor]) {
case 0:
controllable_input_checked_effect(scope, nodeAccessor);
break;
case 1:
controllable_input_checkedValue_effect(scope, nodeAccessor);
break;
case 2:
controllable_input_value_effect(scope, nodeAccessor);
break;
case 3:
controllable_select_value_effect(scope, nodeAccessor);
break;
case 4:
controllable_detailsOrDialog_open_effect(scope, nodeAccessor);
}
for (let name in events) on(el, name, events[name]);
}
function html(scope, value2, accessor) {
let firstChild = scope[accessor],
parentNode = firstChild.parentNode,
lastChild = scope["h" + accessor] || firstChild,
newContent = parseHTML(
value2 || 0 === value2 ? value2 + "" : "",
parentNode.namespaceURI,
);
(insertChildNodes(
parentNode,
firstChild,
(scope[accessor] =
newContent.firstChild || newContent.appendChild(new Text())),
(scope["h" + accessor] = newContent.lastChild),
),
removeChildNodes(firstChild, lastChild));
}
function props(scope, nodeIndex, index) {
let nextProps = scope[index],
prevProps = scope[index + "-"],
node = scope[nodeIndex];
if (prevProps)
for (let name in prevProps) name in nextProps || (node[name] = void 0);
for (let name in nextProps) node[name] = nextProps[name];
scope[index + "-"] = nextProps;
}
function normalizeAttrValue(value2) {
if (value2 || 0 === value2) return !0 === value2 ? "" : value2 + "";
}
function normalizeString(value2) {
return value2 || 0 === value2 ? value2 + "" : "";
}
function lifecycle(scope, index, thisObj) {
let instance = scope[index];
instance
? (Object.assign(instance, thisObj), instance.onUpdate?.())
: ((scope[index] = thisObj),
thisObj.onMount?.(),
(getAbortSignal(scope, "k" + index).onabort = () =>
thisObj.onDestroy?.()));
}
function removeChildNodes(startNode, endNode) {
let stop = endNode.nextSibling,
current = startNode;
for (; current !== stop; ) {
let next = current.nextSibling;
(current.remove(), (current = next));
}
}
function insertChildNodes(parentNode, referenceNode, startNode, endNode) {
parentNode.insertBefore(toInsertNode(startNode, endNode), referenceNode);
}
function toInsertNode(startNode, endNode) {
if (startNode === endNode) return startNode;
let parent = new DocumentFragment(),
stop = endNode.nextSibling,
current = startNode;
for (; current !== stop; ) {
let next = current.nextSibling;
(parent.appendChild(current), (current = next));
}
return parent;
}
function awaitTag(nodeAccessor, renderer) {
let promiseAccessor = "n" + nodeAccessor,
branchAccessor = "d" + nodeAccessor;
@ -1156,10 +1176,10 @@ function awaitTag(nodeAccessor, renderer) {
tryWithPlaceholder
? (placeholderShown.add(pendingEffects),
!scope[promiseAccessor] &&
1 === (tryWithPlaceholder.n = (tryWithPlaceholder.n || 0) + 1) &&
1 === (tryWithPlaceholder.o = (tryWithPlaceholder.o || 0) + 1) &&
requestAnimationFrame(
() =>
tryWithPlaceholder.n &&
tryWithPlaceholder.o &&
runEffects(
prepareEffects(() =>
queueRender(
@ -1213,7 +1233,7 @@ function awaitTag(nodeAccessor, renderer) {
renderer.m?.(awaitBranch, [data2]),
tryWithPlaceholder &&
(placeholderShown.add(pendingEffects),
!--tryWithPlaceholder.n))
!--tryWithPlaceholder.o))
) {
let placeholderBranch = tryWithPlaceholder.c;
((tryWithPlaceholder.c = 0),
@ -1231,7 +1251,7 @@ function awaitTag(nodeAccessor, renderer) {
},
(error) => {
thisPromise === scope[promiseAccessor] &&
(tryWithPlaceholder && (tryWithPlaceholder.n = 0),
(tryWithPlaceholder && (tryWithPlaceholder.o = 0),
(scope[promiseAccessor] = 0),
schedule(),
queueRender(scope, renderCatch, -1, error));
@ -1263,7 +1283,7 @@ function renderCatch(scope, error) {
let owner = tryWithCatch._,
placeholderBranch = tryWithCatch.c;
(placeholderBranch &&
((tryWithCatch.n = 0),
((tryWithCatch.o = 0),
(owner["d" + tryWithCatch.a] = placeholderBranch),
destroyBranch(tryWithCatch)),
caughtError.add(pendingEffects),
@ -1322,18 +1342,18 @@ var dynamicTag = function (nodeAccessor, getContent, getTagVar, inputIsArgs) {
content,
createAndSetupBranch,
),
content.z &&
content.n &&
subscribeToScopeSet(
content.y,
content.z,
content.u,
content.n,
scope[childScopeAccessor].d0,
));
}
} else
normalizedRenderer?.z &&
normalizedRenderer?.n &&
subscribeToScopeSet(
normalizedRenderer.y,
normalizedRenderer.z,
normalizedRenderer.u,
normalizedRenderer.n,
scope[childScopeAccessor],
);
if (normalizedRenderer) {
@ -1627,12 +1647,12 @@ function queueRender(scope, signal, signalKey, value2, scopeKey = scope.l) {
existingRender = signalKey >= 0 && pendingRendersLookup.get(key);
if (existingRender) existingRender.I = value2;
else {
let render = { t: key, o: scope, N: signal, I: value2 },
let render = { x: key, p: scope, N: signal, I: value2 },
i = pendingRenders.push(render) - 1;
for (; i; ) {
let parentIndex = (i - 1) >> 1,
parent = pendingRenders[parentIndex];
if (key - parent.t >= 0) break;
if (key - parent.x >= 0) break;
((pendingRenders[i] = parent), (i = parentIndex));
}
(signalKey >= 0 && pendingRendersLookup.set(key, render),
@ -1681,33 +1701,33 @@ function runRenders() {
if (render !== item) {
let i = 0,
mid = pendingRenders.length >> 1,
key = (pendingRenders[0] = item).t;
key = (pendingRenders[0] = item).x;
for (; i < mid; ) {
let bestChild = 1 + (i << 1),
right = bestChild + 1;
if (
(right < pendingRenders.length &&
pendingRenders[right].t - pendingRenders[bestChild].t < 0 &&
pendingRenders[right].x - pendingRenders[bestChild].x < 0 &&
(bestChild = right),
pendingRenders[bestChild].t - key >= 0)
pendingRenders[bestChild].x - key >= 0)
)
break;
((pendingRenders[i] = pendingRenders[bestChild]), (i = bestChild));
}
pendingRenders[i] = item;
}
render.o.k?.B || runRender(render);
render.p.k?.B || runRender(render);
}
for (let scope of pendingScopes) scope.q = 0;
for (let scope of pendingScopes) scope.t = 0;
pendingScopes = [];
}
var runRender = (render) => render.N(render.o, render.I),
var runRender = (render) => render.N(render.p, render.I),
enableCatch = () => {
((enableCatch = () => {}), enableBranches());
let handlePendingTry = (fn, scope, branch) => {
for (; branch; ) {
if (branch.n) return (branch.H ||= []).push(fn, scope);
branch = branch.u;
if (branch.o) return (branch.H ||= []).push(fn, scope);
branch = branch.y;
}
};
((runEffects = (
@ -1732,18 +1752,18 @@ var runRender = (render) => render.N(render.o, render.I),
try {
runRender2(render);
} catch (error) {
renderCatch(render.o, error);
renderCatch(render.p, error);
}
})(runRender)));
};
function resetAbortSignal(scope, id) {
let ctrl = scope.x?.[id];
ctrl && (queueEffect(ctrl, abort), (scope.x[id] = void 0));
let ctrl = scope.z?.[id];
ctrl && (queueEffect(ctrl, abort), (scope.z[id] = void 0));
}
function getAbortSignal(scope, id) {
return (
scope.k && (scope.k.K ||= new Set()).add(scope),
((scope.x ||= {})[id] ||= new AbortController()).signal
((scope.z ||= {})[id] ||= new AbortController()).signal
);
}
function abort(ctrl) {
@ -1820,12 +1840,12 @@ var classIdToBranch = new Map(),
((component.effects = prepareEffects(() => {
(branch
? (existing = 1)
: ((out.global.p ||= 0),
: ((out.global.q ||= 0),
(branch = component.scope =
createAndSetupBranch(
out.global,
renderer,
renderer.y,
renderer.u,
document.body,
))),
renderer.m?.(branch, renderer._ ? args[0] : args));
@ -1851,8 +1871,8 @@ function mount(input = {}, reference, position) {
switch (
($global
? (({ $global: $global, ...input } = input),
($global = { p: 0, runtimeId: "M", renderId: "_", ...$global }))
: ($global = { p: 0, runtimeId: "M", renderId: "_" }),
($global = { q: 0, runtimeId: "M", renderId: "_", ...$global }))
: ($global = { q: 0, runtimeId: "M", renderId: "_" }),
position)
) {
case "beforebegin":

View File

@ -1 +1 @@
{"vars":{"props":{"$empty":"e","$rest":"t","$attrTag":"n","$attrTags":"r","$attrTagIterator":"l","$forIn":"o","$forOf":"i","$forTo":"u","$stringifyClassObject":"f","$stringifyStyleObject":"a","$toDelimitedString":"c","$isEventHandler":"s","$getEventHandlerName":"d","$normalizeDynamicRenderer":"h","$defaultDelegator":"g","$on":"p","$createDelegator":"v","$handleDelegated":"b","$stripSpacesAndPunctuation":"m","$branchesEnabled":"y","$isResuming":"k","$registeredValues":"C","$enableBranches":"N","$init":"w","$register":"A","$registerBoundSignal":"S","$nodeRef":"x","$controllable_input_checked":"_","$controllable_input_checked_effect":"M","$controllable_input_checkedValue":"I","$controllable_input_checkedValue_effect":"$","$controllable_input_value":"j","$controllable_input_value_effect":"E","$controllable_select_value":"T","$controllable_select_value_effect":"L","$setSelectOptions":"O","$controllable_detailsOrDialog_open":"R","$controllable_detailsOrDialog_open_effect":"q","$inputType":"B","$setValueAndUpdateSelection":"D","$setCheckboxValue":"V","$controllableDelegate":"F","$syncControllable":"U","$handleChange":"W","$handleFormReset":"P","$hasValueChanged":"z","$hasCheckboxChanged":"G","$hasSelectChanged":"H","$hasFormElementChanged":"J","$normalizeStrProp":"K","$normalizeBoolProp":"X","$toValueProp":"Z","$isScheduled":"Q","$channel":"Y","$parsers":"ee","$parseHTML":"te","$attr":"ne","$setAttribute":"re","$classAttr":"le","$classItems":"oe","$classItem":"ie","$styleAttr":"ue","$styleItems":"fe","$styleItem":"ae","$data":"ce","$textContent":"se","$attrs":"de","$hasAttrAlias":"he","$partialAttrs":"ge","$attrsInternal":"pe","$attrsEvents":"ve","$html":"be","$props":"me","$normalizeAttrValue":"ye","$normalizeString":"ke","$lifecycle":"Ce","$removeChildNodes":"Ne","$insertChildNodes":"we","$toInsertNode":"Ae","$createScope":"Se","$skipScope":"xe","$findBranchWithKey":"_e","$destroyBranch":"Me","$destroyNestedBranches":"Ie","$removeAndDestroyBranch":"$e","$insertBranchBefore":"je","$tempDetachBranch":"Ee","$schedule":"Te","$flushAndWaitFrame":"Le","$triggerMacroTask":"Oe","$state":"Re","$value":"qe","$intersection":"Be","$loopClosure":"De","$conditionalClosure":"Ve","$subscribeToScopeSet":"Fe","$dynamicClosure":"Ue","$dynamicClosureRead":"We","$closure":"Pe","$setTagVar":"ze","$tagVarSignal":"Ge","$setTagVarChange":"He","$tagVarSignalChange":"Je","$tagIdsByGlobal":"Ke","$nextTagId":"Xe","$effect":"Ze","$traverseAllHoisted":"Qe","$hoist":"Ye","$walker":"et","$walk":"tt","$walkInternal":"nt","$createBranch":"rt","$createAndSetupBranch":"lt","$setupBranch":"ot","$createContent":"it","$registerContent":"ut","$localClosures":"ft","$createRenderer":"at","$cloneCache":"ct","$awaitTag":"st","$createTry":"dt","$renderCatch":"ht","$conditional":"gt","$dynamicTag":"pt","$setConditionalRenderer":"vt","$loopOf":"bt","$loopIn":"mt","$loopTo":"yt","$loop":"kt","$createBranchWithTagNameOrRenderer":"Ct","$bySecondArg":"Nt","$byFirstArg":"wt","$rendering":"At","$pendingRenders":"St","$pendingRendersLookup":"xt","$caughtError":"_t","$placeholderShown":"Mt","$pendingEffects":"It","$pendingScopes":"$t","$scopeKeyOffset":"jt","$queueRender":"Et","$queueEffect":"Tt","$run":"Lt","$prepareEffects":"Ot","$runEffects":"Rt","$runRenders":"qt","$runRender":"Bt","$enableCatch":"Dt","$resetAbortSignal":"Vt","$getAbortSignal":"Ft","$abort":"Ut","$classIdToBranch":"Wt","$compat":"Pt","$createTemplate":"zt","$mount":"Gt","$$clickCount_effect":"Zt","$$clickCount":"Ht","$$setup":"Jt","$$setup$if$content":"ss","$$expr_comment_comments_id$if$content":"ts","$$comment_comments$if$content":"as","$$id$if$content":"ns","$$if_content":"os","$$id$for$content":"cs","$$expr_input_path_i$for$content":"ms","$$input_path$for$content":"is","$$i$for$content":"ls","$$open$for$content_effect":"us","$$open$for$content":"es","$$setup$for$content":"bs","$$comment_text$for$content":"ps","$$if$for$content":"hs","$$comment_comments$for$content":"_s","$$params2$for$content":"ds","$$comment$for$content":"fs","$$for":"rs","$$input_comments":"gs","$$input$1":"$s","$$input_path":"js"}}}
{"vars":{"props":{"$empty":"e","$rest":"t","$attrTag":"n","$attrTags":"r","$attrTagIterator":"l","$forIn":"o","$forOf":"i","$forTo":"u","$stringifyClassObject":"f","$stringifyStyleObject":"a","$toDelimitedString":"c","$isEventHandler":"s","$getEventHandlerName":"d","$normalizeDynamicRenderer":"h","$defaultDelegator":"g","$on":"p","$createDelegator":"v","$handleDelegated":"b","$stripSpacesAndPunctuation":"m","$branchesEnabled":"y","$isResuming":"k","$registeredValues":"C","$enableBranches":"N","$init":"w","$register":"A","$registerBoundSignal":"S","$nodeRef":"x","$controllable_input_checked":"_","$controllable_input_checked_effect":"M","$controllable_input_checkedValue":"I","$controllable_input_checkedValue_effect":"$","$controllable_input_value":"j","$controllable_input_value_effect":"E","$controllable_select_value":"T","$controllable_select_value_effect":"L","$setSelectOptions":"O","$controllable_detailsOrDialog_open":"R","$controllable_detailsOrDialog_open_effect":"q","$inputType":"B","$setValueAndUpdateSelection":"D","$setCheckboxValue":"V","$controllableDelegate":"F","$syncControllable":"U","$handleChange":"W","$handleFormReset":"P","$hasValueChanged":"z","$hasCheckboxChanged":"G","$hasSelectChanged":"H","$hasFormElementChanged":"J","$normalizeStrProp":"K","$normalizeBoolProp":"X","$toValueProp":"Z","$isScheduled":"Q","$channel":"Y","$parsers":"ee","$parseHTML":"te","$attr":"ne","$setAttribute":"re","$classAttr":"le","$classItems":"oe","$classItem":"ie","$styleAttr":"ue","$styleItems":"fe","$styleItem":"ae","$data":"ce","$textContent":"se","$attrs":"de","$hasAttrAlias":"he","$partialAttrs":"ge","$attrsInternal":"pe","$attrsEvents":"ve","$html":"be","$props":"me","$normalizeAttrValue":"ye","$normalizeString":"ke","$lifecycle":"Ce","$removeChildNodes":"Ne","$insertChildNodes":"we","$toInsertNode":"Ae","$createScope":"Se","$skipScope":"xe","$findBranchWithKey":"_e","$destroyBranch":"Me","$destroyNestedBranches":"Ie","$removeAndDestroyBranch":"$e","$insertBranchBefore":"je","$tempDetachBranch":"Ee","$schedule":"Te","$flushAndWaitFrame":"Le","$triggerMacroTask":"Oe","$state":"Re","$value":"qe","$intersection":"Be","$loopClosure":"De","$conditionalClosure":"Ve","$subscribeToScopeSet":"Fe","$dynamicClosure":"Ue","$dynamicClosureRead":"We","$closure":"Pe","$setTagVar":"ze","$tagVarSignal":"Ge","$setTagVarChange":"He","$tagVarSignalChange":"Je","$tagIdsByGlobal":"Ke","$nextTagId":"Xe","$effect":"Ze","$traverseAllHoisted":"Qe","$hoist":"Ye","$walker":"et","$walk":"tt","$walkInternal":"nt","$createBranch":"rt","$createAndSetupBranch":"lt","$setupBranch":"ot","$createContent":"it","$registerContent":"ut","$localClosures":"ft","$createRenderer":"at","$cloneCache":"ct","$awaitTag":"st","$createTry":"dt","$renderCatch":"ht","$conditional":"gt","$dynamicTag":"pt","$setConditionalRenderer":"vt","$loopOf":"bt","$loopIn":"mt","$loopTo":"yt","$loop":"kt","$createBranchWithTagNameOrRenderer":"Ct","$bySecondArg":"Nt","$byFirstArg":"wt","$rendering":"At","$pendingRenders":"St","$pendingRendersLookup":"xt","$caughtError":"_t","$placeholderShown":"Mt","$pendingEffects":"It","$pendingScopes":"$t","$scopeKeyOffset":"jt","$queueRender":"Et","$queueEffect":"Tt","$run":"Lt","$prepareEffects":"Ot","$runEffects":"Rt","$runRenders":"qt","$runRender":"Bt","$enableCatch":"Dt","$resetAbortSignal":"Vt","$getAbortSignal":"Ft","$abort":"Ut","$classIdToBranch":"Wt","$compat":"Pt","$createTemplate":"zt","$mount":"Gt","$$clickCount_effect":"Zt","$$clickCount":"Ht","$$setup":"Jt","$$setup$if$content":"ss","$$expr_comment_comments_id$if$content":"ts","$$comment_comments$if$content":"as","$$id$if$content":"ns","$$if_content":"os","$$id$for$content":"cs","$$expr_input_path_i$for$content":"ms","$$input_path$for$content":"is","$$i$for$content":"ls","$$open$for$content_effect":"us","$$open$for$content":"es","$$setup$for$content":"bs","$$comment_text$for$content":"ps","$$if$for$content":"hs","$$comment_comments$for$content":"_s","$$params2$for$content":"ds","$$comment$for$content":"fs","$$for":"rs","$$input_comments":"gs","$$input$1":"$s","$$input_path":"js","$attrsAndContent":"Kt","$partialAttrsAndContent":"Xt","$insertContent":"Qt"}}}

View File

@ -16,7 +16,7 @@ const $params4$for$content = /* @__PURE__ */_$.value("$params4", ($scope, $param
const $for_content3 = /* @__PURE__ */_$.createRenderer("<div class=row><!></div>", /* get, next(1), replace */" D%", 0, $params4$for$content);
const $col$for$content_effect = _$.effect("__tests__/tags/hello/index.marko_2_col", $scope => _$.attrsEvents($scope, "#div/0"));
const $col$for$content = /* @__PURE__ */_$.value("col", ($scope, col) => {
_$.partialAttrs($scope, "#div/0", col, {
_$.partialAttrsAndContent($scope, "#div/0", col, {
class: 1
});
$col_row$for$content($scope, col?.row);

View File

@ -17,9 +17,11 @@ export default _$.createTemplate("__tests__/tags/hello/index.marko", (input, $se
}, 0, $scope0_id, "#text/0", _$.serializeGuard($serialize, /* input.list.item */1), _$.serializeGuard($serialize, /* input.list.item */1), 0, 1);
_$.resumeForOf(input.col, col => {
const $scope2_id = _$.nextScopeId();
_$.write(`<div class=col${_$.partialAttrs(col, {
_$.write("<div class=col");
_$.writePartialAttrsAndContent(col, {
class: 1
}, "#div/0", $scope2_id, "div")}></div>${_$.markResumeNode($scope2_id, "#div/0")}`);
}, "#div/0", $scope2_id, "div");
_$.write(`</div>${_$.markResumeNode($scope2_id, "#div/0")}`);
_$.resumeForOf(col.row, row => {
const $scope3_id = _$.nextScopeId();
_$.write(`<div class=row${_$.partialAttrs(row, {

View File

@ -35,54 +35,54 @@
row="a"
>
a
<!--M_*11 #text/0-->
<!--M_*12 #text/0-->
</div>
<!--M_*10 #div/0-->
<!--M_*11 #div/0-->
<div
class="row"
row="b"
>
b
<!--M_*13 #text/0-->
<!--M_*14 #text/0-->
</div>
<!--M_*12 #div/0-->
<!--M_*13 #div/0-->
<div
class="col"
row="[object Object]"
x="1"
/>
<!--M_*14 #div/0-->
<!--M_*15 #div/0-->
<div
class="row"
row="c"
>
c
<!--M_*16 #text/0-->
<!--M_*18 #text/0-->
</div>
<!--M_*15 #div/0-->
<!--M_*17 #div/0-->
<div
class="row"
row="d"
>
d
<!--M_*18 #text/0-->
<!--M_*20 #text/0-->
</div>
<!--M_*17 #div/0-->
<!--M_*19 #div/0-->
<div
class="col"
outside=""
row="[object Object]"
/>
<!--M_*19 #div/0-->
<!--M_*21 #div/0-->
<div
class="row"
row="-1"
>
Outside
</div>
<!--M_*20 #div/0-->
<!--M_*23 #div/0-->
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.q=[0,2,{item:_.c={style:{color:"red"},content:_._["__tests__/template.marko_1_renderer"](_.a={}),*[(_.b=[,_.d={style:{color:"blue"},content:_._["__tests__/template.marko_2_renderer"](_.a)},_.e={style:{color:"green"},content:_._["__tests__/template.marko_2_renderer"](_.a)}],Symbol.iterator)](){yield*_.b}}},1,{item:_.d},1,{item:_.e},1,{col:_.i={x:0,row:_.g={row:"a",content:_._["__tests__/template.marko_3_renderer"](_.a),*[(_.f=[,_.l={row:"b",content:_._["__tests__/template.marko_3_renderer"](_.a)}],Symbol.iterator)](){yield*_.f}},*[(_.h=[,_.m={x:1,row:_.k={row:"c",content:_._["__tests__/template.marko_3_renderer"](_.a),*[(_.j=[,_.n={row:"d",content:_._["__tests__/template.marko_3_renderer"](_.a)}],Symbol.iterator)](){yield*_.j}}},_.o={outside:!0,row:_.p={row:-1,content:_._["__tests__/template.marko_4_renderer"](_.a),*[Symbol.iterator](){yield this}}}],Symbol.iterator)](){yield*_.h}}},{row:_.g},{row:"a"},{row:_.l},{row:"b"},{col:_.m},{row:_.k},{row:"c"},{row:_.n},{row:"d"},{col:_.o},{row:_.p}],_.b[0]=_.c,_.f[0]=_.g,_.h[0]=_.i,_.j[0]=_.k,_.q),"__tests__/tags/hello/index.marko_1_item",3,5,7,"__tests__/tags/hello/index.marko_3_row",10,12,"__tests__/tags/hello/index.marko_2_col",9,"__tests__/tags/hello/index.marko_3_row",15,17,"__tests__/tags/hello/index.marko_2_col",14,"__tests__/tags/hello/index.marko_3_row",20,"__tests__/tags/hello/index.marko_2_col",19];M._.w()
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.q=[0,2,{item:_.c={style:{color:"red"},content:_._["__tests__/template.marko_1_renderer"](_.a={}),*[(_.b=[,_.d={style:{color:"blue"},content:_._["__tests__/template.marko_2_renderer"](_.a)},_.e={style:{color:"green"},content:_._["__tests__/template.marko_2_renderer"](_.a)}],Symbol.iterator)](){yield*_.b}}},1,{item:_.d},1,{item:_.e},1,{col:_.i={x:0,row:_.g={row:"a",content:_._["__tests__/template.marko_3_renderer"](_.a),*[(_.f=[,_.l={row:"b",content:_._["__tests__/template.marko_3_renderer"](_.a)}],Symbol.iterator)](){yield*_.f}},*[(_.h=[,_.m={x:1,row:_.k={row:"c",content:_._["__tests__/template.marko_3_renderer"](_.a),*[(_.j=[,_.n={row:"d",content:_._["__tests__/template.marko_3_renderer"](_.a)}],Symbol.iterator)](){yield*_.j}}},_.o={outside:!0,row:_.p={row:-1,content:_._["__tests__/template.marko_4_renderer"](_.a),*[Symbol.iterator](){yield this}}}],Symbol.iterator)](){yield*_.h}}},1,{row:_.g},{row:"a"},{row:_.l},{row:"b"},{col:_.m},1,{row:_.k},{row:"c"},{row:_.n},{row:"d"},{col:_.o},1,{row:_.p}],_.b[0]=_.c,_.f[0]=_.g,_.h[0]=_.i,_.j[0]=_.k,_.q),"__tests__/tags/hello/index.marko_1_item",3,5,7,"__tests__/tags/hello/index.marko_3_row",11,13,"__tests__/tags/hello/index.marko_2_col",9,"__tests__/tags/hello/index.marko_3_row",17,19,"__tests__/tags/hello/index.marko_2_col",15,"__tests__/tags/hello/index.marko_3_row",23,"__tests__/tags/hello/index.marko_2_col",21];M._.w()
</script>
</body>
</html>

View File

@ -1,6 +1,6 @@
# Write
```html
<div class=item style=color:red>foo</div><!--M_*3 #div/0--><div class=item style=color:blue>bar</div><!--M_*5 #div/0--><div class=item style=color:green>bar</div><!--M_*7 #div/0--><div class=col x=0 row="[object Object]"></div><!--M_*9 #div/0--><div class=row row=a>a<!--M_*11 #text/0--></div><!--M_*10 #div/0--><div class=row row=b>b<!--M_*13 #text/0--></div><!--M_*12 #div/0--><div class=col x=1 row="[object Object]"></div><!--M_*14 #div/0--><div class=row row=c>c<!--M_*16 #text/0--></div><!--M_*15 #div/0--><div class=row row=d>d<!--M_*18 #text/0--></div><!--M_*17 #div/0--><div class=col outside row="[object Object]"></div><!--M_*19 #div/0--><div class=row row=-1>Outside</div><!--M_*20 #div/0--><script>WALKER_RUNTIME("M")("_");M._.r=[_=>(_.q=[0,2,{item:_.c={style:{color:"red"},content:_._["__tests__/template.marko_1_renderer"](_.a={}),*[(_.b=[,_.d={style:{color:"blue"},content:_._["__tests__/template.marko_2_renderer"](_.a)},_.e={style:{color:"green"},content:_._["__tests__/template.marko_2_renderer"](_.a)}],Symbol.iterator)](){yield*_.b}}},1,{item:_.d},1,{item:_.e},1,{col:_.i={x:0,row:_.g={row:"a",content:_._["__tests__/template.marko_3_renderer"](_.a),*[(_.f=[,_.l={row:"b",content:_._["__tests__/template.marko_3_renderer"](_.a)}],Symbol.iterator)](){yield*_.f}},*[(_.h=[,_.m={x:1,row:_.k={row:"c",content:_._["__tests__/template.marko_3_renderer"](_.a),*[(_.j=[,_.n={row:"d",content:_._["__tests__/template.marko_3_renderer"](_.a)}],Symbol.iterator)](){yield*_.j}}},_.o={outside:!0,row:_.p={row:-1,content:_._["__tests__/template.marko_4_renderer"](_.a),*[Symbol.iterator](){yield this}}}],Symbol.iterator)](){yield*_.h}}},{row:_.g},{row:"a"},{row:_.l},{row:"b"},{col:_.m},{row:_.k},{row:"c"},{row:_.n},{row:"d"},{col:_.o},{row:_.p}],_.b[0]=_.c,_.f[0]=_.g,_.h[0]=_.i,_.j[0]=_.k,_.q),"__tests__/tags/hello/index.marko_1_item",3,5,7,"__tests__/tags/hello/index.marko_3_row",10,12,"__tests__/tags/hello/index.marko_2_col",9,"__tests__/tags/hello/index.marko_3_row",15,17,"__tests__/tags/hello/index.marko_2_col",14,"__tests__/tags/hello/index.marko_3_row",20,"__tests__/tags/hello/index.marko_2_col",19];M._.w()</script>
<div class=item style=color:red>foo</div><!--M_*3 #div/0--><div class=item style=color:blue>bar</div><!--M_*5 #div/0--><div class=item style=color:green>bar</div><!--M_*7 #div/0--><div class=col x=0 row="[object Object]"></div><!--M_*9 #div/0--><div class=row row=a>a<!--M_*12 #text/0--></div><!--M_*11 #div/0--><div class=row row=b>b<!--M_*14 #text/0--></div><!--M_*13 #div/0--><div class=col x=1 row="[object Object]"></div><!--M_*15 #div/0--><div class=row row=c>c<!--M_*18 #text/0--></div><!--M_*17 #div/0--><div class=row row=d>d<!--M_*20 #text/0--></div><!--M_*19 #div/0--><div class=col outside row="[object Object]"></div><!--M_*21 #div/0--><div class=row row=-1>Outside</div><!--M_*23 #div/0--><script>WALKER_RUNTIME("M")("_");M._.r=[_=>(_.q=[0,2,{item:_.c={style:{color:"red"},content:_._["__tests__/template.marko_1_renderer"](_.a={}),*[(_.b=[,_.d={style:{color:"blue"},content:_._["__tests__/template.marko_2_renderer"](_.a)},_.e={style:{color:"green"},content:_._["__tests__/template.marko_2_renderer"](_.a)}],Symbol.iterator)](){yield*_.b}}},1,{item:_.d},1,{item:_.e},1,{col:_.i={x:0,row:_.g={row:"a",content:_._["__tests__/template.marko_3_renderer"](_.a),*[(_.f=[,_.l={row:"b",content:_._["__tests__/template.marko_3_renderer"](_.a)}],Symbol.iterator)](){yield*_.f}},*[(_.h=[,_.m={x:1,row:_.k={row:"c",content:_._["__tests__/template.marko_3_renderer"](_.a),*[(_.j=[,_.n={row:"d",content:_._["__tests__/template.marko_3_renderer"](_.a)}],Symbol.iterator)](){yield*_.j}}},_.o={outside:!0,row:_.p={row:-1,content:_._["__tests__/template.marko_4_renderer"](_.a),*[Symbol.iterator](){yield this}}}],Symbol.iterator)](){yield*_.h}}},1,{row:_.g},{row:"a"},{row:_.l},{row:"b"},{col:_.m},1,{row:_.k},{row:"c"},{row:_.n},{row:"d"},{col:_.o},1,{row:_.p}],_.b[0]=_.c,_.f[0]=_.g,_.h[0]=_.i,_.j[0]=_.k,_.q),"__tests__/tags/hello/index.marko_1_item",3,5,7,"__tests__/tags/hello/index.marko_3_row",11,13,"__tests__/tags/hello/index.marko_2_col",9,"__tests__/tags/hello/index.marko_3_row",17,19,"__tests__/tags/hello/index.marko_2_col",15,"__tests__/tags/hello/index.marko_3_row",23,"__tests__/tags/hello/index.marko_2_col",21];M._.w()</script>
```
# Render End
@ -40,54 +40,54 @@
row="a"
>
a
<!--M_*11 #text/0-->
<!--M_*12 #text/0-->
</div>
<!--M_*10 #div/0-->
<!--M_*11 #div/0-->
<div
class="row"
row="b"
>
b
<!--M_*13 #text/0-->
<!--M_*14 #text/0-->
</div>
<!--M_*12 #div/0-->
<!--M_*13 #div/0-->
<div
class="col"
row="[object Object]"
x="1"
/>
<!--M_*14 #div/0-->
<!--M_*15 #div/0-->
<div
class="row"
row="c"
>
c
<!--M_*16 #text/0-->
<!--M_*18 #text/0-->
</div>
<!--M_*15 #div/0-->
<!--M_*17 #div/0-->
<div
class="row"
row="d"
>
d
<!--M_*18 #text/0-->
<!--M_*20 #text/0-->
</div>
<!--M_*17 #div/0-->
<!--M_*19 #div/0-->
<div
class="col"
outside=""
row="[object Object]"
/>
<!--M_*19 #div/0-->
<!--M_*21 #div/0-->
<div
class="row"
row="-1"
>
Outside
</div>
<!--M_*20 #div/0-->
<!--M_*23 #div/0-->
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.q=[0,2,{item:_.c={style:{color:"red"},content:_._["__tests__/template.marko_1_renderer"](_.a={}),*[(_.b=[,_.d={style:{color:"blue"},content:_._["__tests__/template.marko_2_renderer"](_.a)},_.e={style:{color:"green"},content:_._["__tests__/template.marko_2_renderer"](_.a)}],Symbol.iterator)](){yield*_.b}}},1,{item:_.d},1,{item:_.e},1,{col:_.i={x:0,row:_.g={row:"a",content:_._["__tests__/template.marko_3_renderer"](_.a),*[(_.f=[,_.l={row:"b",content:_._["__tests__/template.marko_3_renderer"](_.a)}],Symbol.iterator)](){yield*_.f}},*[(_.h=[,_.m={x:1,row:_.k={row:"c",content:_._["__tests__/template.marko_3_renderer"](_.a),*[(_.j=[,_.n={row:"d",content:_._["__tests__/template.marko_3_renderer"](_.a)}],Symbol.iterator)](){yield*_.j}}},_.o={outside:!0,row:_.p={row:-1,content:_._["__tests__/template.marko_4_renderer"](_.a),*[Symbol.iterator](){yield this}}}],Symbol.iterator)](){yield*_.h}}},{row:_.g},{row:"a"},{row:_.l},{row:"b"},{col:_.m},{row:_.k},{row:"c"},{row:_.n},{row:"d"},{col:_.o},{row:_.p}],_.b[0]=_.c,_.f[0]=_.g,_.h[0]=_.i,_.j[0]=_.k,_.q),"__tests__/tags/hello/index.marko_1_item",3,5,7,"__tests__/tags/hello/index.marko_3_row",10,12,"__tests__/tags/hello/index.marko_2_col",9,"__tests__/tags/hello/index.marko_3_row",15,17,"__tests__/tags/hello/index.marko_2_col",14,"__tests__/tags/hello/index.marko_3_row",20,"__tests__/tags/hello/index.marko_2_col",19];M._.w()
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.q=[0,2,{item:_.c={style:{color:"red"},content:_._["__tests__/template.marko_1_renderer"](_.a={}),*[(_.b=[,_.d={style:{color:"blue"},content:_._["__tests__/template.marko_2_renderer"](_.a)},_.e={style:{color:"green"},content:_._["__tests__/template.marko_2_renderer"](_.a)}],Symbol.iterator)](){yield*_.b}}},1,{item:_.d},1,{item:_.e},1,{col:_.i={x:0,row:_.g={row:"a",content:_._["__tests__/template.marko_3_renderer"](_.a),*[(_.f=[,_.l={row:"b",content:_._["__tests__/template.marko_3_renderer"](_.a)}],Symbol.iterator)](){yield*_.f}},*[(_.h=[,_.m={x:1,row:_.k={row:"c",content:_._["__tests__/template.marko_3_renderer"](_.a),*[(_.j=[,_.n={row:"d",content:_._["__tests__/template.marko_3_renderer"](_.a)}],Symbol.iterator)](){yield*_.j}}},_.o={outside:!0,row:_.p={row:-1,content:_._["__tests__/template.marko_4_renderer"](_.a),*[Symbol.iterator](){yield this}}}],Symbol.iterator)](){yield*_.h}}},1,{row:_.g},{row:"a"},{row:_.l},{row:"b"},{col:_.m},1,{row:_.k},{row:"c"},{row:_.n},{row:"d"},{col:_.o},1,{row:_.p}],_.b[0]=_.c,_.f[0]=_.g,_.h[0]=_.i,_.j[0]=_.k,_.q),"__tests__/tags/hello/index.marko_1_item",3,5,7,"__tests__/tags/hello/index.marko_3_row",11,13,"__tests__/tags/hello/index.marko_2_col",9,"__tests__/tags/hello/index.marko_3_row",17,19,"__tests__/tags/hello/index.marko_2_col",15,"__tests__/tags/hello/index.marko_3_row",23,"__tests__/tags/hello/index.marko_2_col",21];M._.w()
</script>
</body>
</html>

View File

@ -0,0 +1,17 @@
{
"vars": {
"props": {
"$_$": "t",
"$init": "o",
"$$className_effect": "m",
"$$className": "r",
"$$count$define$content": "n",
"$$setup$define$content": "e",
"$$expr_count_MyThing": "a",
"$$count_closure": "i",
"$$count_effect": "s",
"$$count": "c",
"$sideEffect": "d"
}
}
}

View File

@ -0,0 +1,28 @@
# Render
```html
<button>
0 3
</button>
```
# Render
```js
container.querySelector("button").click();
```
```html
<button>
1 3
</button>
```
# Render
```js
container.querySelector("button").click();
```
```html
<button>
2 3
</button>
```

View File

@ -0,0 +1,41 @@
# Render
```html
<button>
0 3
</button>
```
# Mutations
```
INSERT button
```
# Render
```js
container.querySelector("button").click();
```
```html
<button>
1 3
</button>
```
# Mutations
```
UPDATE button/#text0 "0" => "1"
```
# Render
```js
container.querySelector("button").click();
```
```html
<button>
2 3
</button>
```
# Mutations
```
UPDATE button/#text0 "1" => "2"
```

View File

@ -0,0 +1,24 @@
// size: 327 (min) 203 (brotli)
let sideEffect = 3;
const $count$define$content = _$.dynamicClosureRead(1, ($scope, count) =>
_$.data($scope[0], count),
);
_$.registerContent("a0", "<!> <!>", "%c%", ($scope) => {
(_$.data($scope[1], sideEffect++), $count$define$content($scope));
});
const $expr_count_MyThing = _$.intersection(3, ($scope) => {
const { 1: count, 2: MyThing } = $scope;
_$.insertContent($scope, 0, MyThing);
}),
$count_closure = _$.dynamicClosure($count$define$content),
$count_effect = _$.effect("a1", ($scope, { 1: count }) =>
_$.on($scope[0], "click", function () {
$count($scope, count + 1);
}),
),
$count = _$.state(1, ($scope) => {
($expr_count_MyThing($scope),
$count_closure($scope),
$count_effect($scope));
});
init();

View File

@ -0,0 +1,37 @@
export const $template = "<button></button>";
export const $walks = /* get, over(1) */" b";
let sideEffect = 3;
import * as _$ from "@marko/runtime-tags/debug/dom";
const $setup$define$content = $scope => {
debugger;
_$.data($scope["#text/1"], sideEffect++);
$count$define$content($scope);
};
const $count$define$content = /* @__PURE__ */_$.dynamicClosureRead("count", ($scope, count) => _$.data($scope["#text/0"], count));
const $define_content = _$.registerContent("__tests__/template.marko_1_renderer", "<!> <!>", /* replace, over(2), replace */"%c%", $setup$define$content);
const $expr_count_MyThing = /* @__PURE__ */_$.intersection(3, $scope => {
const {
count,
MyThing
} = $scope;
_$.insertContent($scope, "#button/0", (count, MyThing));
});
const $count_closure = /* @__PURE__ */_$.dynamicClosure($count$define$content);
const $count_effect = _$.effect("__tests__/template.marko_0_count", ($scope, {
count
}) => _$.on($scope["#button/0"], "click", function () {
$count($scope, count + 1), count;
}));
const $count = /* @__PURE__ */_$.state("count/1", $scope => {
$expr_count_MyThing($scope);
$count_closure($scope);
$count_effect($scope);
});
const $MyThing = /* @__PURE__ */_$.value("MyThing", $expr_count_MyThing);
export function $setup($scope) {
$count($scope, 0);
$MyThing($scope, {
content: $define_content($scope)
});
}
export default /* @__PURE__ */_$.createTemplate("__tests__/template.marko", $template, $walks, $setup);

View File

@ -0,0 +1,32 @@
let sideEffect = 3;
import * as _$ from "@marko/runtime-tags/debug/html";
export default _$.createTemplate("__tests__/template.marko", input => {
const $scope0_id = _$.nextScopeId();
const $count_closures = new Set();
let count = 0;
const MyThing = {
content: _$.registerContent("__tests__/template.marko_1_renderer", () => {
const $scope1_id = _$.nextScopeId();
debugger;
_$.write(`${_$.escapeXML(count)}${_$.markResumeNode($scope1_id, "#text/0")} ${_$.escapeXML(sideEffect++)}`);
_$.writeSubscribe($count_closures, _$.writeScope($scope1_id, {
_: _$.ensureScopeWithId($scope0_id),
"ClosureSignalIndex:count": 0
}, "__tests__/template.marko", "5:1"));
_$.resumeClosestBranch($scope1_id);
}, $scope0_id)
};
_$.write("<button>");
_$.writeContent("#button/0", $scope0_id, (count, MyThing));
_$.write(`</button>${_$.markResumeNode($scope0_id, "#button/0")}`);
_$.writeEffect($scope0_id, "__tests__/template.marko_0_count");
_$.writeScope($scope0_id, {
count,
MyThing,
"ClosureScopes:count": $count_closures
}, "__tests__/template.marko", 0, {
count: "3:5",
MyThing: "5:8"
});
_$.resumeClosestBranch($scope0_id);
});

View File

@ -0,0 +1,28 @@
# Render
```html
<button>
0 3
</button>
```
# Render
```js
container.querySelector("button").click();
```
```html
<button>
1 3
</button>
```
# Render
```js
container.querySelector("button").click();
```
```html
<button>
2 3
</button>
```

View File

@ -0,0 +1,70 @@
# Render
```html
<html>
<head />
<body>
<button>
0
<!--M_*2 #text/0-->
3
</button>
<!--M_*1 #button/0-->
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.d=[0,_.a={"ConditionalScope:#button/0":_.b={"ClosureSignalIndex:count":0},"ConditionalRenderer:#button/0":"__tests__/template.marko_1_renderer",count:0,MyThing:_.c={},"ClosureScopes:count":_.e=new Set},_.b],_.b._=_.a,_.c.content=_._["__tests__/template.marko_1_renderer"](_.a),(_.e).add(_.b),_.d),"__tests__/template.marko_0_count",1];M._.w()
</script>
</body>
</html>
```
# Render
```js
container.querySelector("button").click();
```
```html
<html>
<head />
<body>
<button>
1
<!--M_*2 #text/0-->
3
</button>
<!--M_*1 #button/0-->
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.d=[0,_.a={"ConditionalScope:#button/0":_.b={"ClosureSignalIndex:count":0},"ConditionalRenderer:#button/0":"__tests__/template.marko_1_renderer",count:0,MyThing:_.c={},"ClosureScopes:count":_.e=new Set},_.b],_.b._=_.a,_.c.content=_._["__tests__/template.marko_1_renderer"](_.a),(_.e).add(_.b),_.d),"__tests__/template.marko_0_count",1];M._.w()
</script>
</body>
</html>
```
# Mutations
```
UPDATE html/body/button/#text0 "0" => "1"
```
# Render
```js
container.querySelector("button").click();
```
```html
<html>
<head />
<body>
<button>
2
<!--M_*2 #text/0-->
3
</button>
<!--M_*1 #button/0-->
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.d=[0,_.a={"ConditionalScope:#button/0":_.b={"ClosureSignalIndex:count":0},"ConditionalRenderer:#button/0":"__tests__/template.marko_1_renderer",count:0,MyThing:_.c={},"ClosureScopes:count":_.e=new Set},_.b],_.b._=_.a,_.c.content=_._["__tests__/template.marko_1_renderer"](_.a),(_.e).add(_.b),_.d),"__tests__/template.marko_0_count",1];M._.w()
</script>
</body>
</html>
```
# Mutations
```
UPDATE html/body/button/#text0 "1" => "2"
```

View File

@ -0,0 +1,6 @@
# Render End
```html
<button>
0 3
</button>
```

View File

@ -0,0 +1,36 @@
# Write
```html
<button>0<!--M_*2 #text/0--> 3</button><!--M_*1 #button/0--><script>WALKER_RUNTIME("M")("_");M._.r=[_=>(_.d=[0,_.a={"ConditionalScope:#button/0":_.b={"ClosureSignalIndex:count":0},"ConditionalRenderer:#button/0":"__tests__/template.marko_1_renderer",count:0,MyThing:_.c={},"ClosureScopes:count":_.e=new Set},_.b],_.b._=_.a,_.c.content=_._["__tests__/template.marko_1_renderer"](_.a),(_.e).add(_.b),_.d),"__tests__/template.marko_0_count",1];M._.w()</script>
```
# Render End
```html
<html>
<head />
<body>
<button>
0
<!--M_*2 #text/0-->
3
</button>
<!--M_*1 #button/0-->
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.d=[0,_.a={"ConditionalScope:#button/0":_.b={"ClosureSignalIndex:count":0},"ConditionalRenderer:#button/0":"__tests__/template.marko_1_renderer",count:0,MyThing:_.c={},"ClosureScopes:count":_.e=new Set},_.b],_.b._=_.a,_.c.content=_._["__tests__/template.marko_1_renderer"](_.a),(_.e).add(_.b),_.d),"__tests__/template.marko_0_count",1];M._.w()
</script>
</body>
</html>
```
# Mutations
```
INSERT html
INSERT html/head
INSERT html/body
INSERT html/body/button
INSERT html/body/button/#text0
INSERT html/body/button/#comment
INSERT html/body/button/#text1
INSERT html/body/#comment
INSERT html/body/script
INSERT html/body/script/#text
```

View File

@ -0,0 +1,9 @@
static let sideEffect = 3
let/count=0
define/MyThing
debug
-- ${count} ${sideEffect++}
button onClick() { count++ } content=(count, MyThing)

View File

@ -0,0 +1,5 @@
export const steps = [{}, click, click];
function click(container: Element) {
container.querySelector("button")!.click();
}

View File

@ -0,0 +1,10 @@
{
"vars": {
"props": {
"$_$": "t",
"$init": "o",
"$$className_effect": "m",
"$$className": "r"
}
}
}

View File

@ -0,0 +1,24 @@
# Render
```html
<div>
Hello
</div>
<button
foo="1"
>
Hello
</button>
<span>
Overridden
</span>
<output />
<strong>
Custom content
</strong>
<p>
Hello
</p>
<em>
Custom content
</em>
```

View File

@ -0,0 +1,29 @@
# Render
```html
<div>
Hello
</div>
<button
foo="1"
>
Hello
</button>
<span>
Overridden
</span>
<output />
<strong>
Custom content
</strong>
<p>
Hello
</p>
<em>
Custom content
</em>
```
# Mutations
```
INSERT div, button, span, output, strong, p, em
```

View File

@ -0,0 +1,50 @@
export const $template = "<div></div><button></button><span>Overridden</span><output></output><strong></strong><p></p><em></em>";
export const $walks = /* get, over(1), get, over(1), get, over(1), get, over(1), get, over(1), get, over(1), get, over(1) */" b b b b b b b";
import * as _$ from "@marko/runtime-tags/debug/dom";
const $define_content = _$.registerContent("__tests__/tags/my-div.marko_1_renderer", "Custom content");
const $expr_input_CustomContent_content_effect = _$.effect("__tests__/tags/my-div.marko_0_input_CustomContent_content", $scope => _$.attrsEvents($scope, "#p/5"));
const $expr_input_CustomContent_content = /* @__PURE__ */_$.intersection(11, $scope => {
const {
input,
CustomContent_content
} = $scope;
_$.attrsAndContent($scope, "#p/5", {
content: CustomContent_content,
...input
});
$expr_input_CustomContent_content_effect($scope);
});
const $input_effect = _$.effect("__tests__/tags/my-div.marko_0_input", $scope => {
_$.attrsEvents($scope, "#div/0");
_$.attrsEvents($scope, "#button/1");
_$.attrsEvents($scope, "#span/2");
_$.attrsEvents($scope, "#output/3");
_$.attrsEvents($scope, "#strong/4");
});
export const $input = /* @__PURE__ */_$.value("input", ($scope, input) => {
_$.attrsAndContent($scope, "#div/0", input);
_$.attrsAndContent($scope, "#button/1", {
foo: 1,
...input
});
_$.attrs($scope, "#span/2", input);
_$.attrs($scope, "#output/3", input);
_$.attrs($scope, "#strong/4", input);
$expr_input_CustomContent_content($scope);
$input_effect($scope);
});
const $CustomContent = /* @__PURE__ */_$.value("CustomContent", ($scope, CustomContent) => {
_$.insertContent($scope, "#em/6", CustomContent);
$CustomContent_content($scope, CustomContent?.content);
});
export function $setup($scope) {
_$.insertContent($scope, "#output/3", undefined);
$CustomContent($scope, {
content: $define_content($scope)
});
}
const $CustomContent_content = /* @__PURE__ */_$.value("CustomContent_content", ($scope, CustomContent_content) => {
_$.insertContent($scope, "#strong/4", CustomContent_content);
$expr_input_CustomContent_content($scope);
});
export default /* @__PURE__ */_$.createTemplate("__tests__/tags/my-div.marko", $template, $walks, $setup, $input);

View File

@ -0,0 +1,12 @@
// size: 229 (min) 114 (brotli)
(_$.registerContent("a0", "Custom content"),
_$.effect("a1", ($scope) => _$.attrsEvents($scope, 5)),
_$.effect("a2", ($scope) => {
(_$.attrsEvents($scope, 0),
_$.attrsEvents($scope, 1),
_$.attrsEvents($scope, 2),
_$.attrsEvents($scope, 3),
_$.attrsEvents($scope, 4));
}),
_$.registerContent("b0", "Hello"),
init());

View File

@ -0,0 +1,12 @@
export const $template = _myDiv_template;
export const $walks = /* beginChild, _myDiv_walks, endChild */`/${_myDiv_walks}&`;
import { $setup as _myDiv, $input as _myDiv_input, $template as _myDiv_template, $walks as _myDiv_walks } from "./tags/my-div.marko";
import * as _$ from "@marko/runtime-tags/debug/dom";
const $mydiv_content = _$.registerContent("__tests__/template.marko_1_renderer", "Hello");
export function $setup($scope) {
_myDiv($scope["#childScope/0"]);
_myDiv_input($scope["#childScope/0"], {
content: $mydiv_content($scope)
});
}
export default /* @__PURE__ */_$.createTemplate("__tests__/template.marko", $template, $walks, $setup);

View File

@ -0,0 +1,39 @@
import * as _$ from "@marko/runtime-tags/debug/html";
export default _$.createTemplate("__tests__/tags/my-div.marko", input => {
const $scope0_id = _$.nextScopeId();
_$.write("<div");
_$.writeAttrsAndContent(input, "#div/0", $scope0_id, "div");
_$.write(`</div>${_$.markResumeNode($scope0_id, "#div/0")}<button`);
_$.writeAttrsAndContent({
foo: 1,
...input
}, "#button/1", $scope0_id, "button");
_$.write(`</button>${_$.markResumeNode($scope0_id, "#button/1")}<span${_$.attrs(input, "#span/2", $scope0_id, "span")}>Overridden</span>${_$.markResumeNode($scope0_id, "#span/2")}<output${_$.attrs(input, "#output/3", $scope0_id, "output")}>`);
_$.writeContent("#output/3", $scope0_id, undefined);
_$.write(`</output>${_$.markResumeNode($scope0_id, "#output/3")}`);
const CustomContent = {
content: _$.registerContent("__tests__/tags/my-div.marko_1_renderer", () => {
const $scope1_id = _$.nextScopeId();
_$.write("Custom content");
}, $scope0_id)
};
_$.write(`<strong${_$.attrs(input, "#strong/4", $scope0_id, "strong")}>`);
_$.writeContent("#strong/4", $scope0_id, CustomContent.content);
_$.write(`</strong>${_$.markResumeNode($scope0_id, "#strong/4")}<p`);
_$.writeAttrsAndContent({
content: CustomContent.content,
...input
}, "#p/5", $scope0_id, "p");
_$.write(`</p>${_$.markResumeNode($scope0_id, "#p/5")}<em>`);
_$.writeContent("#em/6", $scope0_id, CustomContent, 0);
_$.write("</em>");
_$.writeEffect($scope0_id, "__tests__/tags/my-div.marko_0_input_CustomContent_content");
_$.writeEffect($scope0_id, "__tests__/tags/my-div.marko_0_input");
_$.writeScope($scope0_id, {
input,
CustomContent_content: CustomContent?.content
}, "__tests__/tags/my-div.marko", 0, {
input: 0,
CustomContent_content: ["CustomContent.content", "10:8"]
});
});

View File

@ -0,0 +1,11 @@
import * as _$ from "@marko/runtime-tags/debug/html";
import _myDiv from "./tags/my-div.marko";
export default _$.createTemplate("__tests__/template.marko", input => {
const $scope0_id = _$.nextScopeId();
_myDiv({
content: _$.registerContent("__tests__/template.marko_1_renderer", () => {
const $scope1_id = _$.nextScopeId();
_$.write("Hello");
}, $scope0_id)
});
});

View File

@ -0,0 +1,24 @@
# Render
```html
<div>
Hello
</div>
<button
foo="1"
>
Hello
</button>
<span>
Overridden
</span>
<output />
<strong>
Custom content
</strong>
<p>
Hello
</p>
<em>
Custom content
</em>
```

View File

@ -0,0 +1,38 @@
# Render
```html
<html>
<head />
<body>
<div>
Hello
</div>
<!--M_*2 #div/0-->
<button
foo="1"
>
Hello
</button>
<!--M_*2 #button/1-->
<span>
Overridden
</span>
<!--M_*2 #span/2-->
<output />
<!--M_*2 #output/3-->
<strong>
Custom content
</strong>
<!--M_*2 #strong/4-->
<p>
Hello
</p>
<!--M_*2 #p/5-->
<em>
Custom content
</em>
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.g=[0,1,_.b={"ConditionalScope:#div/0":_.c={},"ConditionalRenderer:#div/0":"__tests__/template.marko_1_renderer","ConditionalScope:#button/1":_.d={},"ConditionalRenderer:#button/1":"__tests__/template.marko_1_renderer","ConditionalScope:#strong/4":_.e={},"ConditionalRenderer:#strong/4":"__tests__/tags/my-div.marko_1_renderer","ConditionalScope:#p/5":_.f={},"ConditionalRenderer:#p/5":"__tests__/template.marko_1_renderer",input:{content:_._["__tests__/template.marko_1_renderer"](_.a={})}},_.c,_.d,1,_.e,_.f],_.b.CustomContent_content=_._["__tests__/tags/my-div.marko_1_renderer"](_.b),_.g),"__tests__/tags/my-div.marko_0_input_CustomContent_content",2,"__tests__/tags/my-div.marko_0_input",2];M._.w()
</script>
</body>
</html>
```

View File

@ -0,0 +1,24 @@
# Render End
```html
<div>
Hello
</div>
<button
foo="1"
>
Hello
</button>
<span>
Overridden
</span>
<output />
<strong>
Custom content
</strong>
<p>
Hello
</p>
<em>
Custom content
</em>
```

View File

@ -0,0 +1,71 @@
# Write
```html
<div>Hello</div><!--M_*2 #div/0--><button foo=1>Hello</button><!--M_*2 #button/1--><span>Overridden</span><!--M_*2 #span/2--><output></output><!--M_*2 #output/3--><strong>Custom content</strong><!--M_*2 #strong/4--><p>Hello</p><!--M_*2 #p/5--><em>Custom content</em><script>WALKER_RUNTIME("M")("_");M._.r=[_=>(_.g=[0,1,_.b={"ConditionalScope:#div/0":_.c={},"ConditionalRenderer:#div/0":"__tests__/template.marko_1_renderer","ConditionalScope:#button/1":_.d={},"ConditionalRenderer:#button/1":"__tests__/template.marko_1_renderer","ConditionalScope:#strong/4":_.e={},"ConditionalRenderer:#strong/4":"__tests__/tags/my-div.marko_1_renderer","ConditionalScope:#p/5":_.f={},"ConditionalRenderer:#p/5":"__tests__/template.marko_1_renderer",input:{content:_._["__tests__/template.marko_1_renderer"](_.a={})}},_.c,_.d,1,_.e,_.f],_.b.CustomContent_content=_._["__tests__/tags/my-div.marko_1_renderer"](_.b),_.g),"__tests__/tags/my-div.marko_0_input_CustomContent_content",2,"__tests__/tags/my-div.marko_0_input",2];M._.w()</script>
```
# Render End
```html
<html>
<head />
<body>
<div>
Hello
</div>
<!--M_*2 #div/0-->
<button
foo="1"
>
Hello
</button>
<!--M_*2 #button/1-->
<span>
Overridden
</span>
<!--M_*2 #span/2-->
<output />
<!--M_*2 #output/3-->
<strong>
Custom content
</strong>
<!--M_*2 #strong/4-->
<p>
Hello
</p>
<!--M_*2 #p/5-->
<em>
Custom content
</em>
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.g=[0,1,_.b={"ConditionalScope:#div/0":_.c={},"ConditionalRenderer:#div/0":"__tests__/template.marko_1_renderer","ConditionalScope:#button/1":_.d={},"ConditionalRenderer:#button/1":"__tests__/template.marko_1_renderer","ConditionalScope:#strong/4":_.e={},"ConditionalRenderer:#strong/4":"__tests__/tags/my-div.marko_1_renderer","ConditionalScope:#p/5":_.f={},"ConditionalRenderer:#p/5":"__tests__/template.marko_1_renderer",input:{content:_._["__tests__/template.marko_1_renderer"](_.a={})}},_.c,_.d,1,_.e,_.f],_.b.CustomContent_content=_._["__tests__/tags/my-div.marko_1_renderer"](_.b),_.g),"__tests__/tags/my-div.marko_0_input_CustomContent_content",2,"__tests__/tags/my-div.marko_0_input",2];M._.w()
</script>
</body>
</html>
```
# Mutations
```
INSERT html
INSERT html/head
INSERT html/body
INSERT html/body/div
INSERT html/body/div/#text
INSERT html/body/#comment0
INSERT html/body/button
INSERT html/body/button/#text
INSERT html/body/#comment1
INSERT html/body/span
INSERT html/body/span/#text
INSERT html/body/#comment2
INSERT html/body/output
INSERT html/body/#comment3
INSERT html/body/strong
INSERT html/body/strong/#text
INSERT html/body/#comment4
INSERT html/body/p
INSERT html/body/p/#text
INSERT html/body/#comment5
INSERT html/body/em
INSERT html/body/em/#text
INSERT html/body/script
INSERT html/body/script/#text
```

View File

@ -0,0 +1,17 @@
div ...input
button foo=1 ...input
span ...input
-- Overridden
output ...input content=undefined
define/CustomContent
-- Custom content
strong ...input content=CustomContent.content
p content=CustomContent.content ...input
em content=CustomContent

View File

@ -0,0 +1,2 @@
my-div
-- Hello

View File

@ -7,7 +7,7 @@ const $expr_input_value_a = /* @__PURE__ */_$.intersection(7, $scope => {
input_value,
a
} = $scope;
_$.attrs($scope, "#div/1", {
_$.attrsAndContent($scope, "#div/1", {
a: a,
...input_value
});
@ -25,8 +25,8 @@ const $input_value_effect = _$.effect("__tests__/template.marko_0_input_value",
_$.attrsEvents($scope, "#div/2");
});
export const $input_value = /* @__PURE__ */_$.value("input_value", ($scope, input_value) => {
_$.attrs($scope, "#div/0", input_value);
_$.partialAttrs($scope, "#div/2", input_value, {
_$.attrsAndContent($scope, "#div/0", input_value);
_$.partialAttrsAndContent($scope, "#div/2", input_value, {
a: 1
});
$expr_input_value_a($scope);

View File

@ -2,12 +2,18 @@ import * as _$ from "@marko/runtime-tags/debug/html";
export default _$.createTemplate("__tests__/template.marko", input => {
const $scope0_id = _$.nextScopeId();
let a = 0;
_$.write(`<div${_$.attrs(input.value, "#div/0", $scope0_id, "div")}></div>${_$.markResumeNode($scope0_id, "#div/0")}<div${_$.attrs({
_$.write("<div");
_$.writeAttrsAndContent(input.value, "#div/0", $scope0_id, "div");
_$.write(`</div>${_$.markResumeNode($scope0_id, "#div/0")}<div`);
_$.writeAttrsAndContent({
a: a,
...input.value
}, "#div/1", $scope0_id, "div")}></div>${_$.markResumeNode($scope0_id, "#div/1")}<div${_$.attr("a", a)}${_$.partialAttrs(input.value, {
}, "#div/1", $scope0_id, "div");
_$.write(`</div>${_$.markResumeNode($scope0_id, "#div/1")}<div${_$.attr("a", a)}`);
_$.writePartialAttrsAndContent(input.value, {
a: 1
}, "#div/2", $scope0_id, "div")}></div>${_$.markResumeNode($scope0_id, "#div/2")}`);
}, "#div/2", $scope0_id, "div");
_$.write(`</div>${_$.markResumeNode($scope0_id, "#div/2")}`);
_$.writeEffect($scope0_id, "__tests__/template.marko_0_input_value_a");
_$.writeEffect($scope0_id, "__tests__/template.marko_0_input_value");
_$.writeScope($scope0_id, {

View File

@ -28,14 +28,17 @@ export {
export {
attr,
attrs,
attrsAndContent,
attrsEvents,
classAttr,
classItem,
classItems,
data,
html,
insertContent,
lifecycle,
partialAttrs,
partialAttrsAndContent,
props,
styleAttr,
styleItem,

View File

@ -2,6 +2,7 @@ import {
classValue,
getEventHandlerName,
isEventHandler,
normalizeDynamicRenderer,
styleValue,
} from "../common/helpers";
import {
@ -11,6 +12,7 @@ import {
type Scope,
} from "../common/types";
import { getAbortSignal } from "./abort-signal";
import { setConditionalRenderer } from "./control-flow";
import {
controllable_detailsOrDialog_open,
controllable_detailsOrDialog_open_effect,
@ -26,6 +28,8 @@ import {
} from "./controllable";
import { on } from "./event";
import { parseHTML } from "./parse-html";
import { createAndSetupBranch, type Renderer } from "./renderer";
import { subscribeToScopeSet } from "./signals";
export function attr(element: Element, name: string, value: unknown) {
setAttribute(element, name, normalizeAttrValue(value));
@ -111,6 +115,15 @@ export function attrs(
attrsInternal(scope, nodeAccessor, nextAttrs);
}
export function attrsAndContent(
scope: Scope,
nodeAccessor: Accessor,
nextAttrs: Record<string, unknown>,
) {
attrs(scope, nodeAccessor, nextAttrs);
insertContent(scope, nodeAccessor, nextAttrs?.content);
}
function hasAttrAlias(
element: Element,
attr: string,
@ -146,6 +159,16 @@ export function partialAttrs(
attrsInternal(scope, nodeAccessor, partial);
}
export function partialAttrsAndContent(
scope: Scope,
nodeAccessor: Accessor,
nextAttrs: Record<string, unknown>,
skip: Record<string, 1>,
) {
partialAttrs(scope, nodeAccessor, nextAttrs, skip);
insertContent(scope, nodeAccessor, nextAttrs?.content);
}
function attrsInternal(
scope: Scope,
nodeAccessor: Accessor,
@ -232,8 +255,9 @@ function attrsInternal(
case "style":
styleAttr(el, value);
break;
case "content":
case "content": {
break;
}
default: {
if (isEventHandler(name)) {
(events ||= scope[AccessorPrefix.EventAttributes + nodeAccessor] =
@ -246,6 +270,25 @@ function attrsInternal(
}
}
export function insertContent(
scope: Scope,
nodeAccessor: Accessor,
value: unknown,
) {
const content = normalizeClientRender(value);
const rendererAccessor = AccessorPrefix.ConditionalRenderer + nodeAccessor;
if (scope[rendererAccessor] !== (scope[rendererAccessor] = content?.___id)) {
setConditionalRenderer(scope, nodeAccessor, content, createAndSetupBranch);
if (content?.___accessor) {
subscribeToScopeSet(
content.___owner!,
content.___accessor,
scope[AccessorPrefix.ConditionalScope + nodeAccessor],
);
}
}
}
export function attrsEvents(scope: Scope, nodeAccessor: Accessor) {
const el = scope[nodeAccessor] as Element;
const events = scope[AccessorPrefix.EventAttributes + nodeAccessor] as Record<
@ -298,6 +341,19 @@ export function html(scope: Scope, value: unknown, accessor: Accessor) {
removeChildNodes(firstChild, lastChild);
}
export function normalizeClientRender(value: any) {
const renderer = normalizeDynamicRenderer<Renderer>(value);
if (renderer) {
if ((renderer as Renderer).___id) {
return renderer as Renderer;
} else if (MARKO_DEBUG) {
throw new Error(
`Invalid \`content\` attribute. Received ${typeof value}`,
);
}
}
}
export function props(scope: Scope, nodeIndex: number, index: number) {
const nextProps = scope[index] as Record<string, unknown>;
const prevProps = scope[index + "-"] as Record<string, unknown> | undefined;

View File

@ -12,6 +12,8 @@ export {
optionValueAttr,
partialAttrs,
styleAttr,
writeAttrsAndContent,
writePartialAttrsAndContent,
} from "./html/attrs";
export { compat } from "./html/compat";
export { escapeScript, escapeStyle, escapeXML, toString } from "./html/content";
@ -41,6 +43,7 @@ export {
setTagVar,
tryContent,
write,
writeContent,
writeEffect,
writeExistingScope,
writeScope,

View File

@ -7,7 +7,13 @@ import {
} from "../common/helpers";
import { type Accessor, AccessorPrefix, ControlledType } from "../common/types";
import { escapeTextAreaValue } from "./content";
import { getContext, withContext, writeScope } from "./writer";
import {
getContext,
withContext,
write,
writeContent,
writeScope,
} from "./writer";
export function classAttr(value: unknown) {
return stringAttr("class", classValue(value));
@ -253,6 +259,17 @@ export function attrs(
return result;
}
export function writeAttrsAndContent(
data: Record<string, unknown>,
nodeAccessor: Accessor,
scopeId: number,
tagName: string,
serializeReason?: 1 | 0,
) {
write(`${attrs(data, nodeAccessor, scopeId, tagName)}>`);
writeContent(nodeAccessor, scopeId, data?.content, serializeReason);
}
export function partialAttrs(
data: Record<string, unknown>,
skip: Record<string, 1>,
@ -268,6 +285,18 @@ export function partialAttrs(
return attrs(partial, nodeAccessor, scopeId, tagName);
}
export function writePartialAttrsAndContent(
data: Record<string, unknown>,
skip: Record<string, 1>,
nodeAccessor: Accessor,
scopeId: number,
tagName: string,
serializeReason?: 1 | 0,
) {
write(`${partialAttrs(data, skip, nodeAccessor, scopeId, tagName)}>`);
writeContent(nodeAccessor, scopeId, data?.content, serializeReason);
}
function writeControlledScope(
type: ControlledType,
scopeId: number,

View File

@ -55,6 +55,8 @@ export let dynamicTag = (
const input = ((inputIsArgs
? (inputOrArgs as unknown[])[0]
: inputOrArgs) || {}) as Record<string, unknown>;
const renderContent =
content || normalizeDynamicRenderer<ServerRenderer>(input.content);
nextScopeId();
write(`<${renderer}${attrs(input, accessor, scopeId, renderer)}>`);
@ -74,7 +76,12 @@ export let dynamicTag = (
input.valueChange,
),
);
} else if (content) {
} else if (renderContent) {
if (typeof renderContent !== "function") {
throw new Error(
`Body content is not supported for the \`<${renderer}>\` tag.`,
);
}
if (
renderer === "select" &&
("value" in input || "valueChange" in input)
@ -84,10 +91,10 @@ export let dynamicTag = (
accessor,
input.value,
input.valueChange,
content,
renderContent,
);
} else {
content();
renderContent();
}
}
};
@ -99,7 +106,9 @@ export let dynamicTag = (
}
write(`</${renderer}>`);
} else if (MARKO_DEBUG && content) {
throw new Error(`Body content is not supported for a "${renderer}" tag.`);
throw new Error(
`Body content is not supported for the \`<${renderer}>\` tag.`,
);
}
if (shouldResume) {

View File

@ -67,6 +67,52 @@ export function writeEffect(scopeId: number, registryId: string) {
$chunk.writeEffect(scopeId, registryId);
}
export function writeContent(
nodeAccessor: Accessor,
scopeId: number,
content: unknown,
serializeReason?: 1 | 0,
) {
const shouldResume = serializeReason !== 0;
const render = normalizeServerRender(content);
const branchId = peekNextScopeId();
if (render) {
if (shouldResume) {
withBranchId(branchId, render);
} else {
render();
}
}
const rendered = peekNextScopeId() !== branchId;
if (rendered) {
if (shouldResume) {
writeScope(scopeId, {
[AccessorPrefix.ConditionalScope + nodeAccessor]: writeScope(
branchId,
{},
),
[AccessorPrefix.ConditionalRenderer + nodeAccessor]: render?.___id,
});
}
} else {
nextScopeId();
}
}
export function normalizeServerRender(value: unknown) {
const renderer = normalizeDynamicRenderer<ServerRenderer>(value);
if (renderer) {
if (typeof renderer === "function") {
return renderer;
} else if (MARKO_DEBUG) {
throw new Error(
`Invalid \`content\` attribute. Received ${typeof value}`,
);
}
}
}
const kPendingContexts = Symbol("Pending Contexts");
export function withContext<T>(key: PropertyKey, value: unknown, cb: () => T) {
const ctx = ($chunk.context ||= { [kPendingContexts]: 0 } as any);

View File

@ -58,10 +58,12 @@ import { type TemplateVisitor, translateByTarget } from "../../util/visitors";
import * as walks from "../../util/walks";
import * as writer from "../../util/writer";
import { scopeIdentifier } from "../program";
import { getSerializeGuard } from "../program/html";
export const kNativeTagBinding = Symbol("native tag binding");
export const kSkipEndTag = Symbol("skip native tag mark");
const kGetterId = Symbol("node getter id");
const kTagContentAttr = Symbol("tag could have dynamic content attribute");
const htmlSelectArgs = new WeakMap<
t.MarkoTag,
@ -76,6 +78,7 @@ declare module "@marko/compiler/dist/types" {
[kNativeTagBinding]?: Binding;
[kSkipEndTag]?: true;
[kGetterId]?: string;
[kTagContentAttr]?: true;
}
}
@ -389,17 +392,22 @@ export default {
}
}
const isOpenOnly = !!(tagDef && tagDef.parseOptions?.openTagOnly);
const hasChildren = !!tag.node.body.body.length;
if (spreadExpression) {
addHTMLEffectCall(tagSection, tagExtra.referencedBindings);
if (skipExpression) {
write`${callRuntime("partialAttrs", spreadExpression, skipExpression, visitAccessor, getScopeIdIdentifier(tagSection), tag.node.name)}`;
} else {
write`${callRuntime("attrs", spreadExpression, visitAccessor, getScopeIdIdentifier(tagSection), tag.node.name)}`;
if (isOpenOnly || hasChildren || usedAttrs.staticContentAttr) {
if (skipExpression) {
write`${callRuntime("partialAttrs", spreadExpression, skipExpression, visitAccessor, getScopeIdIdentifier(tagSection), tag.node.name)}`;
} else {
write`${callRuntime("attrs", spreadExpression, visitAccessor, getScopeIdIdentifier(tagSection), tag.node.name)}`;
}
}
}
if (tagDef && tagDef.parseOptions?.openTagOnly) {
if (isOpenOnly) {
switch (tagDef.htmlType) {
case "svg":
case "math":
@ -410,7 +418,57 @@ export default {
break;
}
} else {
write`>`;
if (usedAttrs.staticContentAttr) {
write`>`;
tagExtra[kTagContentAttr] = true;
(tag.node.body.body as t.Statement[]) = [
t.expressionStatement(
callRuntime(
"writeContent",
visitAccessor,
getScopeIdIdentifier(tagSection),
usedAttrs.staticContentAttr.value,
getSerializeGuard(
nodeBinding &&
getBindingSerializeReason(tagSection, nodeBinding),
true,
),
),
),
];
} else if (spreadExpression && !hasChildren) {
const serializeReason = getSerializeGuard(
nodeBinding && getBindingSerializeReason(tagSection, nodeBinding),
true,
);
tagExtra[kTagContentAttr] = true;
(tag.node.body.body as t.Statement[]) = [
skipExpression
? t.expressionStatement(
callRuntime(
"writePartialAttrsAndContent",
spreadExpression,
skipExpression,
visitAccessor,
getScopeIdIdentifier(tagSection),
tag.node.name,
serializeReason,
),
)
: t.expressionStatement(
callRuntime(
"writeAttrsAndContent",
spreadExpression,
visitAccessor,
getScopeIdIdentifier(tagSection),
tag.node.name,
serializeReason,
),
),
];
} else {
write`>`;
}
}
// TODO: this is broken for DOM (and select in ssr) and so is currently disabled and always becomes a dynamic tag.
@ -434,6 +492,10 @@ export default {
const tagName = getTagName(tag);
const tagSection = getSection(tag);
if (tagExtra[kTagContentAttr]) {
writer.flushBefore(tag);
}
if (tagExtra.tagNameNullable) {
writer.flushInto(tag);
}
@ -570,6 +632,9 @@ export default {
const { staticAttrs, staticControllable, skipExpression } = usedAttrs;
const { spreadExpression } = usedAttrs;
const isOpenOnly = !!(tagDef && tagDef.parseOptions?.openTagOnly);
const hasChildren = !!tag.node.body.body.length;
if (staticControllable) {
const { helper, attrs } = staticControllable;
const firstAttr = attrs.find(Boolean)!;
@ -706,6 +771,11 @@ export default {
}
if (spreadExpression) {
const canHaveAttrContent = !(
isOpenOnly ||
hasChildren ||
usedAttrs.staticContentAttr
);
if (skipExpression) {
addStatement(
"render",
@ -713,7 +783,9 @@ export default {
tagExtra.referencedBindings,
t.expressionStatement(
callRuntime(
"partialAttrs",
canHaveAttrContent
? "partialAttrsAndContent"
: "partialAttrs",
scopeIdentifier,
visitAccessor,
spreadExpression,
@ -728,7 +800,7 @@ export default {
tagExtra.referencedBindings,
t.expressionStatement(
callRuntime(
"attrs",
canHaveAttrContent ? "attrsAndContent" : "attrs",
scopeIdentifier,
visitAccessor,
spreadExpression,
@ -748,7 +820,24 @@ export default {
);
}
if (tagDef && tagDef.parseOptions?.openTagOnly) {
if (usedAttrs.staticContentAttr) {
const contentAttrValue = usedAttrs.staticContentAttr.value;
addStatement(
"render",
tagSection,
contentAttrValue.extra?.referencedBindings,
t.expressionStatement(
callRuntime(
"insertContent",
scopeIdentifier,
visitAccessor,
contentAttrValue,
),
),
);
}
if (isOpenOnly) {
switch (tagDef.htmlType) {
case "svg":
case "math":
@ -872,6 +961,8 @@ function getUsedAttrs(tagName: string, tag: t.MarkoTag) {
let spreadProps: undefined | t.ObjectExpression["properties"];
let skipProps: undefined | t.ObjectExpression["properties"];
let staticControllable: RelatedControllable;
let staticContentAttr: undefined | t.MarkoAttribute;
for (let i = attributes.length; i--; ) {
const attr = attributes[i];
const { value } = attr;
@ -891,10 +982,15 @@ function getUsedAttrs(tagName: string, tag: t.MarkoTag) {
}
}
spreadProps.push(t.spreadElement(value));
} else if (!seen[attr.name]) {
} else if (
!seen[attr.name] ||
!(attr.name === "content" && tag.body.body.length)
) {
seen[attr.name] = attr;
if (spreadProps) {
spreadProps.push(toObjectProperty(attr.name, attr.value));
} else if (attr.name === "content") {
staticContentAttr = attr;
} else {
maybeStaticAttrs.add(attr);
}
@ -938,15 +1034,16 @@ function getUsedAttrs(tagName: string, tag: t.MarkoTag) {
(skipProps ||= []).push(toObjectProperty(name, t.numericLiteral(1)));
}
if (skipProps) {
skipExpression = t.objectExpression(skipProps);
}
spreadExpression = propsToExpression(spreadProps);
}
if (skipProps) {
skipExpression = t.objectExpression(skipProps);
}
return {
staticAttrs,
staticContentAttr,
staticControllable,
spreadExpression,
skipExpression,

View File

@ -4346,7 +4346,10 @@ declare global {
* Provide body content for the tag as a Marko.Body.
* @see Marko.Body
*/
content?: Marko.Body<[], void>;
content?:
| AttrMissing
| Marko.Body<[], void>
| Marko.Template<Record<any, never>, void>;
/**
* data-* global attributes form a class of attributes called custom data attributes, that allow proprietary