Skip to content

Commit

Permalink
fix: nested states inside tag tag
Browse files Browse the repository at this point in the history
  • Loading branch information
DylanPiercey committed Mar 22, 2022
1 parent a0a4d05 commit 497a87d
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<ul>
<li>
<input
type="checkbox"
/>
Nested 1
</li>
<li>
<input
type="checkbox"
/>
Nested 2
<ul>
<li>
<input
type="checkbox"
/>
Nested 3
</li>
</ul>
</li>
</ul>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<ul>
<li>
<input
type="checkbox"
/>
Nested 1
</li>
<li>
<input
type="checkbox"
/>
Nested 2
<ul>
<li>
<input
type="checkbox"
/>
Nested 3
</li>
</ul>
</li>
</ul>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<ul>
<li>
<input
checked=""
type="checkbox"
/>
Nested 1
</li>
<li>
<input
type="checkbox"
/>
Nested 2
<ul>
<li>
<input
type="checkbox"
/>
Nested 3
</li>
</ul>
</li>
</ul>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<ul>
<li>
<input
checked=""
type="checkbox"
/>
Nested 1
</li>
<li>
<input
checked=""
type="checkbox"
/>
Nested 2
<ul>
<li>
<input
type="checkbox"
/>
Nested 3
</li>
</ul>
</li>
</ul>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<ul>
<li>
<input
checked=""
type="checkbox"
/>
Nested 1
</li>
<li>
<input
checked=""
type="checkbox"
/>
Nested 2
<ul>
<li>
<input
checked=""
type="checkbox"
/>
Nested 3
</li>
</ul>
</li>
</ul>
21 changes: 21 additions & 0 deletions src/__tests__/fixtures/tag/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,27 @@ import fixture from "../../fixture";

describe("<tag> basic", fixture("./templates/basic.marko"));

describe(
"<tag> with state",
fixture("./templates/with-state.marko", [
{
items: [
{ label: "Nested 1" },
{ label: "Nested 2", items: [{ label: "Nested 3" }] },
],
},
async ({ screen, fireEvent }) => {
await fireEvent.click(screen.getAllByRole("checkbox")[0]);
},
async ({ screen, fireEvent }) => {
await fireEvent.click(screen.getAllByRole("checkbox")[1]);
},
async ({ screen, fireEvent }) => {
await fireEvent.click(screen.getAllByRole("checkbox")[2]);
},
])
);

describe("<tag> error args", fixture("./templates/error-args.marko"));

describe("<tag> error attrs", fixture("./templates/error-attrs.marko"));
Expand Down
23 changes: 23 additions & 0 deletions src/__tests__/fixtures/tag/templates/with-state.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<attrs/{ items }/>

<tag/item|{ label, items }|>
<let/isChecked = false/>
<li>
<input type="checkbox" checked:=isChecked>
${label}

<if=items>
<ul>
<for|value| of=items>
<item ...value />
</for>
</ul>
</if>
</li>
</tag>

<ul>
<for|value| of=items>
<item ...value />
</for>
</ul>
61 changes: 36 additions & 25 deletions src/components/tag/translate.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,43 @@
import { types as t } from "@marko/compiler";
import assertNoAssignments from "../../util/assert-no-assignments";
const IDENTIFIERS = new WeakMap<t.NodePath<t.MarkoTag>, t.Identifier>();

export = function transform(tag: t.NodePath<t.MarkoTag>) {
const tagVar = tag.node.var! as t.Identifier;
const body = tag.node.body;
const errorMessage = tag.node.attributes.length
? "does not support attributes"
: !tagVar
? "requires a tag variable"
: !t.isIdentifier(tagVar)
? "cannot have a destructured tag variable"
: tag.node.arguments
? "does not support arguments"
: !body.body.length
? "requires body content"
: undefined;
export = {
enter(tag: t.NodePath<t.MarkoTag>) {
const tagVar = tag.node.var! as t.Identifier;
const body = tag.node.body;
const errorMessage = tag.node.attributes.length
? "does not support attributes"
: !tagVar
? "requires a tag variable"
: !t.isIdentifier(tagVar)
? "cannot have a destructured tag variable"
: tag.node.arguments
? "does not support arguments"
: !body.body.length
? "requires body content"
: undefined;

if (errorMessage) {
throw tag.get("name").buildCodeFrameError(`The <tag> tag ${errorMessage}.`);
}
if (errorMessage) {
throw tag
.get("name")
.buildCodeFrameError(`The <tag> tag ${errorMessage}.`);
}

assertNoAssignments(tag.get("var") as t.NodePath<t.PatternLike>);
assertNoAssignments(tag.get("var") as t.NodePath<t.PatternLike>);

tag.replaceWith(
t.functionDeclaration(
tagVar,
[t.identifier("out"), ...body.params],
t.blockStatement(body.body)
)
);
// We must clear the var to avoid the default translator complaining
// but we store it in a weakmap so we can read on exit.
IDENTIFIERS.set(tag, tagVar);
tag.node.var = null;
},
exit(tag: t.NodePath<t.MarkoTag>) {
tag.replaceWith(
t.functionDeclaration(
IDENTIFIERS.get(tag)!,
[t.identifier("out"), ...tag.node.body.params],
t.blockStatement(tag.node.body.body)
)
);
},
};

0 comments on commit 497a87d

Please sign in to comment.