Correctly serialize falsey values at top-level of components (#834)
* Correctly serialize falsey values at top-level of components * Adding a changeset
This commit is contained in:
parent
0c729f248d
commit
164489fbb2
5 changed files with 61 additions and 16 deletions
5
.changeset/healthy-pants-rule.md
Normal file
5
.changeset/healthy-pants-rule.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix for `false` being rendered in conditionals
|
|
@ -5,6 +5,23 @@ export type HTag = string | AstroComponent;
|
||||||
|
|
||||||
const voidTags = new Set(['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
|
const voidTags = new Set(['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
|
||||||
|
|
||||||
|
function* _children(children: Array<HChild>) {
|
||||||
|
for (let child of children) {
|
||||||
|
// Special: If a child is a function, call it automatically.
|
||||||
|
// This lets you do {() => ...} without the extra boilerplate
|
||||||
|
// of wrapping it in a function and calling it.
|
||||||
|
if (typeof child === 'function') {
|
||||||
|
yield child();
|
||||||
|
} else if (typeof child === 'string') {
|
||||||
|
yield child;
|
||||||
|
} else if (!child && child !== 0) {
|
||||||
|
// do nothing, safe to ignore falsey values.
|
||||||
|
} else {
|
||||||
|
yield child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Generator for primary h() function */
|
/** Generator for primary h() function */
|
||||||
function* _h(tag: string, attrs: HProps, children: Array<HChild>) {
|
function* _h(tag: string, attrs: HProps, children: Array<HChild>) {
|
||||||
if (tag.toLowerCase() === '!doctype') {
|
if (tag.toLowerCase() === '!doctype') {
|
||||||
|
@ -32,20 +49,7 @@ function* _h(tag: string, attrs: HProps, children: Array<HChild>) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let child of children) {
|
yield * _children(children);
|
||||||
// Special: If a child is a function, call it automatically.
|
|
||||||
// This lets you do {() => ...} without the extra boilerplate
|
|
||||||
// of wrapping it in a function and calling it.
|
|
||||||
if (typeof child === 'function') {
|
|
||||||
yield child();
|
|
||||||
} else if (typeof child === 'string') {
|
|
||||||
yield child;
|
|
||||||
} else if (!child && child !== 0) {
|
|
||||||
// do nothing, safe to ignore falsey values.
|
|
||||||
} else {
|
|
||||||
yield child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
yield `</${tag}>`;
|
yield `</${tag}>`;
|
||||||
}
|
}
|
||||||
|
@ -62,6 +66,6 @@ export async function h(tag: HTag, attrs: HProps, ...pChildren: Array<Promise<HC
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fragment helper, similar to React.Fragment */
|
/** Fragment helper, similar to React.Fragment */
|
||||||
export function Fragment(_: HProps, ...children: Array<string>) {
|
export function Fragment(_: HProps, ...children: Array<HChild>) {
|
||||||
return children.join('');
|
return Array.from(_children(children)).join('');
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,12 @@ Expressions('Does not render falsy values using &&', async ({ runtime }) => {
|
||||||
assert.equal($('#false').length, 0, `Expected {false && <span id="false" />} not to render`);
|
assert.equal($('#false').length, 0, `Expected {false && <span id="false" />} not to render`);
|
||||||
assert.equal($('#null').length, 0, `Expected {null && <span id="null" />} not to render`);
|
assert.equal($('#null').length, 0, `Expected {null && <span id="null" />} not to render`);
|
||||||
assert.equal($('#undefined').length, 0, `Expected {undefined && <span id="undefined" />} not to render`);
|
assert.equal($('#undefined').length, 0, `Expected {undefined && <span id="undefined" />} not to render`);
|
||||||
|
|
||||||
|
// Inside of a component
|
||||||
|
assert.equal($('#frag-true').length, 1, `Expected {true && <span id="true" />} to render`);
|
||||||
|
assert.equal($('#frag-false').length, 0, `Expected {false && <span id="false" />} not to render`);
|
||||||
|
assert.equal($('#frag-null').length, 0, `Expected {null && <span id="null" />} not to render`);
|
||||||
|
assert.equal($('#frag-undefined').length, 0, `Expected {undefined && <span id="undefined" />} not to render`);
|
||||||
});
|
});
|
||||||
|
|
||||||
Expressions.run();
|
Expressions.run();
|
||||||
|
|
23
packages/astro/test/fixtures/astro-expr/src/components/falsy.astro
vendored
Normal file
23
packages/astro/test/fixtures/astro-expr/src/components/falsy.astro
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
const { items, emptyItems } = Astro.props;
|
||||||
|
|
||||||
|
const internal = [];
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- False -->
|
||||||
|
{false && (
|
||||||
|
<span id="frag-false" />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<!-- Null -->
|
||||||
|
{null && (
|
||||||
|
<span id="frag-null" />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<!-- True -->
|
||||||
|
{true && (
|
||||||
|
<span id="frag-true" />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<!-- Undefined -->
|
||||||
|
{false && (<span id="frag-undefined" />)}
|
|
@ -1,3 +1,6 @@
|
||||||
|
---
|
||||||
|
import Falsey from '../components/falsy.astro';
|
||||||
|
---
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>My site</title>
|
<title>My site</title>
|
||||||
|
@ -8,5 +11,9 @@
|
||||||
{undefined && <span id="undefined" />}
|
{undefined && <span id="undefined" />}
|
||||||
{true && <span id="true" />}
|
{true && <span id="true" />}
|
||||||
<span id="zero">{0 && "VALUE"}</span>
|
<span id="zero">{0 && "VALUE"}</span>
|
||||||
|
|
||||||
|
<section id="fragment-container">
|
||||||
|
<Falsey />
|
||||||
|
</section>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Add table
Reference in a new issue