Serialize boolean attributes without a value (#422)

* Serialize boolean attributes without a value

Fixes #307

* Update the attrs test

* Adds a changeset

* Adds test that components receive booleans
This commit is contained in:
Matthew Phillips 2021-06-14 12:29:34 -04:00 committed by GitHub
parent 42dee7978d
commit 2d854092a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 41 additions and 4 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixes serialization of boolean attributes

View file

@ -1,4 +1,4 @@
export type HProps = Record<string, string> | null | undefined;
export type HProps = Record<string, string | boolean> | null | undefined;
export type HChild = string | undefined | (() => string);
export type AstroComponent = (props: HProps, ...children: Array<HChild>) => string;
export type HTag = string | AstroComponent;
@ -20,7 +20,8 @@ function* _h(tag: string, attrs: HProps, children: Array<HChild>) {
if (attrs) {
for (let [key, value] of Object.entries(attrs)) {
if (value === '') yield ` ${key}=""`;
else if (value == null) yield '';
else if (value == null || value === false) yield '';
else if (value === true) yield ` ${key}`;
else yield ` ${key}="${value}"`;
}
}

View file

@ -14,7 +14,7 @@ Attributes('Passes attributes to elements as expected', async ({ runtime }) => {
const $ = doc(result.contents);
const ids = ['false-str', 'true-str', 'false', 'true', 'empty', 'null', 'undefined'];
const specs = ['false', 'true', 'false', 'true', '', undefined, undefined];
const specs = ['false', 'true', undefined, '', '', undefined, undefined];
let i = 0;
for (const id of ids) {
@ -25,4 +25,15 @@ Attributes('Passes attributes to elements as expected', async ({ runtime }) => {
}
});
Attributes('Passes boolean attributes to components as expected', async ({ runtime }) => {
const result = await runtime.load('/component');
if (result.error) throw new Error(result.error);
const $ = doc(result.contents);
assert.equal($('#true').attr('attr'), 'attr-true');
assert.equal($('#true').attr('type'), 'boolean');
assert.equal($('#false').attr('attr'), 'attr-false');
assert.equal($('#false').attr('type'), 'boolean');
});
Attributes.run();

View file

@ -32,4 +32,12 @@ Basics('Does not set the HMR port when no dynamic component used', async ({ runt
assert.ok(!/HMR_WEBSOCKET_URL/.test(html), 'Does not set the websocket port');
});
Basics('Correctly serializes boolean attributes', async ({ runtime }) => {
const result = await runtime.load('/');
const html = result.contents;
const $ = doc(html);
assert.equal($('h1').attr('data-something'), '');
assert.equal($('h2').attr('not-data-ok'), '');
});
Basics.run();

View file

@ -0,0 +1,5 @@
import React from 'react';
export default function({ id, attr }) {
return <span id={id} attr={`attr-${attr}`} type={typeof attr}></span>
}

View file

@ -0,0 +1,6 @@
---
import Span from '../components/Span.jsx';
---
<Span id="true" attr={true} />
<Span id="false" attr={false} />

View file

@ -7,6 +7,7 @@ let title = 'My App'
<!-- Head Stuff -->
</head>
<body>
<h1>Hello world!</h1>
<h1 data-something>Hello world!</h1>
<h2 not-data-ok>Subtitle here</h2>
</body>
</html>