mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
fix: regression with text only elements with no children and a spread
This commit is contained in:
parent
04902fad7d
commit
8cdeb6bb1d
5
.changeset/hip-dogs-listen.md
Normal file
5
.changeset/hip-dogs-listen.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@marko/runtime-tags": patch
|
||||
---
|
||||
|
||||
Fix regression with text only tags (textarea/title) with a spread and no body content.
|
||||
@ -0,0 +1,8 @@
|
||||
{
|
||||
"vars": {
|
||||
"props": {
|
||||
"$_": "r",
|
||||
"$init": "m"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
# Render `{"value":"foo"}`
|
||||
|
||||
```html
|
||||
<textarea>
|
||||
foo
|
||||
</textarea>
|
||||
```
|
||||
@ -0,0 +1,12 @@
|
||||
# Render `{"value":"foo"}`
|
||||
|
||||
```html
|
||||
<textarea>
|
||||
foo
|
||||
</textarea>
|
||||
```
|
||||
|
||||
# Mutations
|
||||
```
|
||||
INSERT textarea
|
||||
```
|
||||
@ -0,0 +1,2 @@
|
||||
// size: 46 (min) 50 (brotli)
|
||||
(_._script("a0", ($scope) => _._attrs_script($scope, "a")), init());
|
||||
@ -0,0 +1,10 @@
|
||||
export const $template = "<textarea></textarea>";
|
||||
export const $walks = /* get, over(1) */" b";
|
||||
export const $setup = () => {};
|
||||
import * as _ from "@marko/runtime-tags/debug/dom";
|
||||
const $input__script = _._script("__tests__/template.marko_0_input", $scope => _._attrs_script($scope, "#textarea/0"));
|
||||
export const $input = /* @__PURE__ */_._const("input", $scope => {
|
||||
_._attrs($scope, "#textarea/0", $scope.input);
|
||||
$input__script($scope);
|
||||
});
|
||||
export default /* @__PURE__ */_._template("__tests__/template.marko", $template, $walks, $setup, $input);
|
||||
@ -0,0 +1,12 @@
|
||||
import * as _ from "@marko/runtime-tags/debug/html";
|
||||
export default _._template("__tests__/template.marko", input => {
|
||||
const $scope0_id = _._scope_id();
|
||||
const $textarea_input = input;
|
||||
_._html(`<textarea${_._attrs($textarea_input, "#textarea/0", $scope0_id, "textarea")}>${_._attr_textarea_value($scope0_id, "#textarea/0", $textarea_input.value, $textarea_input.valueChange)}</textarea>${_._el_resume($scope0_id, "#textarea/0")}`);
|
||||
_._script($scope0_id, "__tests__/template.marko_0_input");
|
||||
_._scope($scope0_id, {
|
||||
input
|
||||
}, "__tests__/template.marko", 0, {
|
||||
input: 0
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,7 @@
|
||||
# Render `{"value":"foo"}`
|
||||
|
||||
```html
|
||||
<textarea>
|
||||
foo
|
||||
</textarea>
|
||||
```
|
||||
@ -0,0 +1,26 @@
|
||||
# Render `{"value":"foo"}`
|
||||
|
||||
```html
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
<textarea>
|
||||
foo
|
||||
</textarea>
|
||||
<!--M_*1 #textarea/0-->
|
||||
<script>
|
||||
WALKER_RUNTIME("M")("_");
|
||||
M._.r = [_ => (_.a = [0,
|
||||
{
|
||||
input:
|
||||
{
|
||||
value: "foo"
|
||||
}
|
||||
}]),
|
||||
"__tests__/template.marko_0_input 1"
|
||||
];
|
||||
M._.w()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
@ -0,0 +1,6 @@
|
||||
# Render End
|
||||
```html
|
||||
<textarea>
|
||||
foo
|
||||
</textarea>
|
||||
```
|
||||
@ -0,0 +1,42 @@
|
||||
# Write
|
||||
```html
|
||||
<textarea>foo</textarea><!--M_*1 #textarea/0--><script>WALKER_RUNTIME("M")("_");M._.r=[_=>(_.a=[0,{input:{value:"foo"}}]),"__tests__/template.marko_0_input 1"];M._.w()</script>
|
||||
```
|
||||
|
||||
# Render End
|
||||
```html
|
||||
<html>
|
||||
<head />
|
||||
<body>
|
||||
<textarea>
|
||||
foo
|
||||
</textarea>
|
||||
<!--M_*1 #textarea/0-->
|
||||
<script>
|
||||
WALKER_RUNTIME("M")("_");
|
||||
M._.r = [_ => (_.a = [0,
|
||||
{
|
||||
input:
|
||||
{
|
||||
value: "foo"
|
||||
}
|
||||
}]),
|
||||
"__tests__/template.marko_0_input 1"
|
||||
];
|
||||
M._.w()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
# Mutations
|
||||
```
|
||||
INSERT html
|
||||
INSERT html/head
|
||||
INSERT html/body
|
||||
INSERT html/body/textarea
|
||||
INSERT html/body/textarea/#text
|
||||
INSERT html/body/#comment
|
||||
INSERT html/body/script
|
||||
INSERT html/body/script/#text
|
||||
```
|
||||
@ -0,0 +1 @@
|
||||
<textarea ...input/>
|
||||
@ -0,0 +1 @@
|
||||
export const steps = [{ value: "foo" }];
|
||||
@ -89,7 +89,7 @@ export default {
|
||||
}
|
||||
|
||||
const tagName = getCanonicalTagName(tag);
|
||||
const textOnly = isTextOnlyNativeTag(tag);
|
||||
const isTextOnly = isTextOnlyNativeTag(tag);
|
||||
const seen: Record<string, t.MarkoAttribute> = {};
|
||||
const { attributes } = tag.node;
|
||||
let injectNonce = isInjectNonceTag(tagName);
|
||||
@ -146,7 +146,7 @@ export default {
|
||||
});
|
||||
|
||||
let textPlaceholders: undefined | t.Node[];
|
||||
if (textOnly) {
|
||||
if (isTextOnly) {
|
||||
for (const child of tag.node.body.body) {
|
||||
if (t.isMarkoPlaceholder(child)) {
|
||||
(textPlaceholders ||= []).push(child.value);
|
||||
@ -372,12 +372,13 @@ export default {
|
||||
}
|
||||
|
||||
const isOpenOnly = !!(tagDef && tagDef.parseOptions?.openTagOnly);
|
||||
const isTextOnly = isTextOnlyNativeTag(tag);
|
||||
const hasChildren = !!tag.node.body.body.length;
|
||||
|
||||
if (spreadExpression) {
|
||||
addHTMLEffectCall(tagSection, tagExtra.referencedBindings);
|
||||
|
||||
if (isOpenOnly || hasChildren || staticContentAttr) {
|
||||
if (isTextOnly || isOpenOnly || hasChildren || staticContentAttr) {
|
||||
if (skipExpression) {
|
||||
write`${callRuntime(
|
||||
"_attrs_partial",
|
||||
@ -409,59 +410,59 @@ export default {
|
||||
write`>`;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (staticContentAttr) {
|
||||
write`>`;
|
||||
tagExtra[kTagContentAttr] = true;
|
||||
(tag.node.body.body as t.Statement[]) = [
|
||||
t.expressionStatement(
|
||||
callRuntime(
|
||||
"_attr_content",
|
||||
visitAccessor,
|
||||
getScopeIdIdentifier(tagSection),
|
||||
staticContentAttr.value,
|
||||
getSerializeGuard(
|
||||
tagSection,
|
||||
nodeBinding && getSerializeReason(tagSection, nodeBinding),
|
||||
true,
|
||||
),
|
||||
} else if (isTextOnly) {
|
||||
write`>`;
|
||||
} else if (staticContentAttr) {
|
||||
write`>`;
|
||||
tagExtra[kTagContentAttr] = true;
|
||||
(tag.node.body.body as t.Statement[]) = [
|
||||
t.expressionStatement(
|
||||
callRuntime(
|
||||
"_attr_content",
|
||||
visitAccessor,
|
||||
getScopeIdIdentifier(tagSection),
|
||||
staticContentAttr.value,
|
||||
getSerializeGuard(
|
||||
tagSection,
|
||||
nodeBinding && getSerializeReason(tagSection, nodeBinding),
|
||||
true,
|
||||
),
|
||||
),
|
||||
];
|
||||
} else if (spreadExpression && !hasChildren) {
|
||||
const serializeReason = getSerializeGuard(
|
||||
tagSection,
|
||||
nodeBinding && getSerializeReason(tagSection, nodeBinding),
|
||||
true,
|
||||
);
|
||||
tagExtra[kTagContentAttr] = true;
|
||||
(tag.node.body.body as t.Statement[]) = [
|
||||
skipExpression
|
||||
? t.expressionStatement(
|
||||
callRuntime(
|
||||
"_attrs_partial_content",
|
||||
spreadExpression,
|
||||
skipExpression,
|
||||
visitAccessor,
|
||||
getScopeIdIdentifier(tagSection),
|
||||
t.stringLiteral(tagName),
|
||||
serializeReason,
|
||||
),
|
||||
)
|
||||
: t.expressionStatement(
|
||||
callRuntime(
|
||||
"_attrs_content",
|
||||
spreadExpression,
|
||||
visitAccessor,
|
||||
getScopeIdIdentifier(tagSection),
|
||||
t.stringLiteral(tagName),
|
||||
serializeReason,
|
||||
),
|
||||
),
|
||||
];
|
||||
} else if (spreadExpression && !hasChildren) {
|
||||
const serializeReason = getSerializeGuard(
|
||||
tagSection,
|
||||
nodeBinding && getSerializeReason(tagSection, nodeBinding),
|
||||
true,
|
||||
);
|
||||
tagExtra[kTagContentAttr] = true;
|
||||
(tag.node.body.body as t.Statement[]) = [
|
||||
skipExpression
|
||||
? t.expressionStatement(
|
||||
callRuntime(
|
||||
"_attrs_partial_content",
|
||||
spreadExpression,
|
||||
skipExpression,
|
||||
visitAccessor,
|
||||
getScopeIdIdentifier(tagSection),
|
||||
t.stringLiteral(tagName),
|
||||
serializeReason,
|
||||
),
|
||||
];
|
||||
} else {
|
||||
write`>`;
|
||||
}
|
||||
)
|
||||
: t.expressionStatement(
|
||||
callRuntime(
|
||||
"_attrs_content",
|
||||
spreadExpression,
|
||||
visitAccessor,
|
||||
getScopeIdIdentifier(tagSection),
|
||||
t.stringLiteral(tagName),
|
||||
serializeReason,
|
||||
),
|
||||
),
|
||||
];
|
||||
} else {
|
||||
write`>`;
|
||||
}
|
||||
|
||||
if (writeAtStartOfBody) {
|
||||
@ -471,8 +472,8 @@ export default {
|
||||
exit(tag) {
|
||||
const tagExtra = tag.node.extra!;
|
||||
const nodeBinding = tagExtra[kNativeTagBinding];
|
||||
const openTagOnly = getTagDef(tag)?.parseOptions?.openTagOnly;
|
||||
const textOnly = isTextOnlyNativeTag(tag);
|
||||
const isOpenOnly = getTagDef(tag)?.parseOptions?.openTagOnly;
|
||||
const isTextOnly = isTextOnlyNativeTag(tag);
|
||||
const selectArgs = htmlSelectArgs.get(tag.node);
|
||||
const tagName = getCanonicalTagName(tag);
|
||||
const tagSection = getSection(tag);
|
||||
@ -510,7 +511,7 @@ export default {
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (textOnly) {
|
||||
} else if (isTextOnly) {
|
||||
for (const child of tag.node.body.body) {
|
||||
if (t.isMarkoText(child)) {
|
||||
write`${child.value}`;
|
||||
@ -522,7 +523,7 @@ export default {
|
||||
tag.insertBefore(tag.node.body.body).forEach((child) => child.skip());
|
||||
}
|
||||
|
||||
if (!tagExtra[kSkipEndTag] && !openTagOnly && !selectArgs) {
|
||||
if (!tagExtra[kSkipEndTag] && !isOpenOnly && !selectArgs) {
|
||||
write`</${tagName}>`;
|
||||
}
|
||||
|
||||
@ -559,6 +560,7 @@ export default {
|
||||
injectNonce,
|
||||
} = getUsedAttrs(tagName, tag.node);
|
||||
const isOpenOnly = !!(tagDef && tagDef.parseOptions?.openTagOnly);
|
||||
const isTextOnly = isTextOnlyNativeTag(tag);
|
||||
const hasChildren = !!tag.node.body.body.length;
|
||||
|
||||
if (injectNonce) {
|
||||
@ -712,6 +714,7 @@ export default {
|
||||
|
||||
if (spreadExpression) {
|
||||
const canHaveAttrContent = !(
|
||||
isTextOnly ||
|
||||
isOpenOnly ||
|
||||
hasChildren ||
|
||||
staticContentAttr
|
||||
@ -796,13 +799,14 @@ export default {
|
||||
const tagExtra = tag.node.extra!;
|
||||
const nodeBinding = tagExtra[kNativeTagBinding];
|
||||
const openTagOnly = getTagDef(tag)?.parseOptions?.openTagOnly;
|
||||
const textOnly = isTextOnlyNativeTag(tag);
|
||||
const tagName = getCanonicalTagName(tag);
|
||||
|
||||
if (!openTagOnly) {
|
||||
if (textOnly) {
|
||||
const write = writer.writeTo(tag);
|
||||
if (tagName !== "textarea" && isTextOnlyNativeTag(tag)) {
|
||||
const textLiteral = bodyToTextLiteral(tag.node.body);
|
||||
if (t.isStringLiteral(textLiteral)) {
|
||||
writer.writeTo(tag)`${textLiteral}`;
|
||||
write`${textLiteral}`;
|
||||
} else {
|
||||
addStatement(
|
||||
"render",
|
||||
@ -823,7 +827,7 @@ export default {
|
||||
.forEach((child) => child.skip());
|
||||
}
|
||||
|
||||
writer.writeTo(tag)`</${getCanonicalTagName(tag)}>`;
|
||||
write`</${tagName}>`;
|
||||
}
|
||||
|
||||
walks.exit(tag);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user