Skip to content

Commit

Permalink
Render literals like vanilla js template strings
Browse files Browse the repository at this point in the history
fixes developit#40
and developit#37

inspired by developit#41

The only place we don't have parity right now is arrays (because that's
how children are passed) and bigint (because I'm not gonna do dependency
wrangling rn)
  • Loading branch information
odinhb committed Mar 8, 2024
1 parent 3fc484b commit 8a669e1
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 3 deletions.
10 changes: 7 additions & 3 deletions src/stringjsx.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,9 @@ function render(tagName, attributes) {

const children = extractChildren(arguments);
let result = '';
const isFragment = tagName !== null && tagName !== undefined;

if (tagName) { // null is passed when rendering a fragment
if (isFragment) {
result += '<';

result += tagName;
Expand All @@ -104,7 +105,10 @@ function render(tagName, attributes) {
} else while(children.length) {
const child = children.shift();

if (!child) continue;
if (child === undefined || child === null) {
result += child;
continue;
}

if (isCollection(child)) {
for (let i = child.length - 1; i >= 0; i--) {
Expand All @@ -116,7 +120,7 @@ function render(tagName, attributes) {
}
}

if (tagName) result += `</${tagName}>`;
if (isFragment) result += `</${tagName}>`;
}

// Read about the fun world of javascript strings
Expand Down
105 changes: 105 additions & 0 deletions test/stringjsx.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,14 @@ describe('stringjsx', () => {
);
});

it('also supports fragments w/ undefined', () => {
expect(
h(h.Fragment, null, <p>foo</p>, <em>bar</em>, <div class="qqqqqq">baz</div>).toString()
).to.equal(
'<p>foo</p><em>bar</em><div class="qqqqqq">baz</div>'
);
});

// regression test for https://github.com/developit/vhtml/issues/34
it('does not allow cache-based html injection anymore', () => {
const injectable = '<h1>test</h1>';
Expand Down Expand Up @@ -302,4 +310,101 @@ describe('stringjsx', () => {
'<line class="second" y2="-38"></line></g></svg>'
)
});

describe('literal rendering', () => {
it('renders the empty string', () => {
expect(
<div>{''}</div>.toString()
).to.equal('<div></div>')
});

it('renders blank strings', () => {
expect(
<div>{' '} and also {'\n\n\n \t\t\t'}</div>.toString()
).to.equal('<div> and also \n\n\n \t\t\t</div>')
});

it('renders a goofy string', () => {
expect(
<div>{'haha'}</div>.toString()
).to.equal('<div>haha</div>')
});

it('renders numbers', () => {
expect(
<div>
{63452}
<span>num: {12385}</span>
<p>{-882}, {942}</p>
</div>.toString()
).to.equal('<div>63452<span>num: 12385</span><p>-882, 942</p></div>')
});

it('renders infinities', () => {
// impressive
expect(
<div>
{Infinity}+{-Infinity}
</div>.toString()
).to.equal('<div>Infinity+-Infinity</div>')
});

it('renders a "very big" number', () => {
expect(
<div>{5463454363452342352665745632523423423}</div>.toString()
).to.equal('<div>5.463454363452342e+36</div>')
});

// TODO: hmm maybe isn't supported by any node tooling yet?
// it('renders a bigint', () => {
// expect(
// <div>{5463454363452342352665745632523423423n}</div>.toString()
// ).to.equal('<div>5463454363452342352665745632523423423</div>')
// });

// regression test for https://github.com/developit/vhtml/issues/40
it('renders zero', () => {
expect(
<div>{0} elephants carrying {0} trees</div>.toString()
).to.equal('<div>0 elephants carrying 0 trees</div>')
});

it('renders booleans', () => {
expect(
<div>
<p>{true} love</p>
<th>{false} promises</th>
</div>.toString()
).to.equal('<div><p>true love</p><th>false promises</th></div>')
});

it('renders undefined', () => {
expect(<div>{undefined} behaviour</div>.toString())
.to.equal('<div>undefined behaviour</div>')
});

it('renders null', () => {
expect(<div>{null} and void</div>.toString())
.to.equal('<div>null and void</div>')
});

it('"renders" an object', () => {
expect(<div>object? {{}} object</div>.toString())
.to.equal('<div>object? [object Object] object</div>')
});

it('renders an array', () => {
expect(<div>little bit of {['a', 'b']}</div>.toString())
.to.equal('<div>little bit of ab</div>')
});

it('renders toString', () => {
const instrument = {
toString: function() { return 'ukulele' },
}

expect(<div>instrument: {instrument}</div>.toString())
.to.equal('<div>instrument: ukulele</div>')
});
});
});

0 comments on commit 8a669e1

Please sign in to comment.