diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..346125f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,31 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Changed + +- Render nulls, undefined, zeroes and false correctly and more in line with how template strings do. + +### [3.0.0] - 2023-07-07 + +- This version marks the fork from [vhtml](https://www.npmjs.com/package/vhtml) + +### Added + +- Typescript support (no additional @types/ package is required) (thanks to [pastelmind](https://github.com/pastelmind) for his type definitions for vhtml, these are simply adapted from his by @odinhb) +- New way to skip sanitization by passing a string with `_stringjsx_sanitized = true` set. ([remziatay](https://github.com/remziatay) had the idea [here](https://github.com/developit/vhtml/issues/34#issuecomment-1460436783)) + +### Changed + +- Returns a `String` (object, not primitive) ([remziatay](https://github.com/remziatay) had the idea [here](https://github.com/developit/vhtml/issues/34#issuecomment-1460436783)) +- Rewrote the source code itself (@odinhb) + +### Fixed + +- Fix [injection possibility](https://github.com/developit/vhtml/issues/34) +- Fix [memory leak](https://github.com/developit/vhtml/issues/20) diff --git a/src/stringjsx.js b/src/stringjsx.js index 7ae48ed..b309671 100644 --- a/src/stringjsx.js +++ b/src/stringjsx.js @@ -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; @@ -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--) { @@ -116,7 +120,7 @@ function render(tagName, attributes) { } } - if (tagName) result += ``; + if (isFragment) result += ``; } // Read about the fun world of javascript strings diff --git a/test/stringjsx.js b/test/stringjsx.js index 33c5f44..3643089 100644 --- a/test/stringjsx.js +++ b/test/stringjsx.js @@ -269,6 +269,14 @@ describe('stringjsx', () => { ); }); + it('also supports fragments w/ undefined', () => { + expect( + h(h.Fragment, null,

foo

, bar,
baz
).toString() + ).to.equal( + '

foo

bar
baz
' + ); + }); + // regression test for https://github.com/developit/vhtml/issues/34 it('does not allow cache-based html injection anymore', () => { const injectable = '

test

'; @@ -302,4 +310,101 @@ describe('stringjsx', () => { '' ) }); + + describe('literal rendering', () => { + it('renders the empty string', () => { + expect( +
{''}
.toString() + ).to.equal('
') + }); + + it('renders blank strings', () => { + expect( +
{' '} and also {'\n\n\n \t\t\t'}
.toString() + ).to.equal('
and also \n\n\n \t\t\t
') + }); + + it('renders a goofy string', () => { + expect( +
{'haha'}
.toString() + ).to.equal('
haha
') + }); + + it('renders numbers', () => { + expect( +
+ {63452} + num: {12385} +

{-882}, {942}

+
.toString() + ).to.equal('
63452num: 12385

-882, 942

') + }); + + it('renders infinities', () => { + // impressive + expect( +
+ {Infinity}+{-Infinity} +
.toString() + ).to.equal('
Infinity+-Infinity
') + }); + + it('renders a "very big" number', () => { + expect( +
{5463454363452342352665745632523423423}
.toString() + ).to.equal('
5.463454363452342e+36
') + }); + + // TODO: hmm maybe isn't supported by any node tooling yet? + // it('renders a bigint', () => { + // expect( + //
{5463454363452342352665745632523423423n}
.toString() + // ).to.equal('
5463454363452342352665745632523423423
') + // }); + + // regression test for https://github.com/developit/vhtml/issues/40 + it('renders zero', () => { + expect( +
{0} elephants carrying {0} trees
.toString() + ).to.equal('
0 elephants carrying 0 trees
') + }); + + it('renders booleans', () => { + expect( +
+

{true} love

+ {false} promises +
.toString() + ).to.equal('

true love

false promises
') + }); + + it('renders undefined', () => { + expect(
{undefined} behaviour
.toString()) + .to.equal('
undefined behaviour
') + }); + + it('renders null', () => { + expect(
{null} and void
.toString()) + .to.equal('
null and void
') + }); + + it('"renders" an object', () => { + expect(
object? {{}} object
.toString()) + .to.equal('
object? [object Object] object
') + }); + + it('renders an array', () => { + expect(
little bit of {['a', 'b']}
.toString()) + .to.equal('
little bit of ab
') + }); + + it('renders toString', () => { + const instrument = { + toString: function() { return 'ukulele' }, + } + + expect(
instrument: {instrument}
.toString()) + .to.equal('
instrument: ukulele
') + }); + }); });