From 67ff04267442543ba4ad3b744d85d1689c7ef80c Mon Sep 17 00:00:00 2001 From: Johannes Odland Date: Sun, 22 Oct 2023 11:05:12 +0200 Subject: [PATCH] Switch to WeakMap and String objects to avoid memory leak. Fixes #20 and #34. --- src/vhtml.js | 9 +++++---- test/vhtml.js | 52 +++++++++++++++++++++++++++------------------------ 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/vhtml.js b/src/vhtml.js index 0e03f69..837e924 100644 --- a/src/vhtml.js +++ b/src/vhtml.js @@ -9,7 +9,7 @@ let DOMAttributeNames = { htmlFor: 'for' }; -let sanitized = {}; +let sanitized = new WeakMap(); /** Hyperscript reviver that constructs a sanitized HTML string. */ export default function h(name, attrs) { @@ -47,7 +47,7 @@ export default function h(name, attrs) { for (let i=child.length; i--; ) stack.push(child[i]); } else { - s += sanitized[child]===true ? child : esc(child); + s += sanitized.has(child) ? child : esc(child); } } } @@ -55,6 +55,7 @@ export default function h(name, attrs) { s += name ? `` : ''; } - sanitized[s] = true; - return s; + let res = new String(s); + sanitized.set(res, true); + return res; } diff --git a/test/vhtml.js b/test/vhtml.js index f88ddf2..83d8706 100644 --- a/test/vhtml.js +++ b/test/vhtml.js @@ -3,10 +3,14 @@ import { expect } from 'chai'; /** @jsx h */ /*global describe,it*/ +function valueOf(str) { + return str.valueOf(); +} + describe('vhtml', () => { it('should stringify html', () => { let items = ['one', 'two', 'three']; - expect( + expect(valueOf(

Hi!

Here is a list of {items.length} items:

@@ -16,46 +20,46 @@ describe('vhtml', () => { )) }
- ).to.equal( + )).to.equal( `

Hi!

Here is a list of 3 items:

` ); }); it('should sanitize children', () => { - expect( + expect(valueOf(
{ `blocked` } allowed
- ).to.equal( + )).to.equal( `
<strong>blocked</strong>allowed
` ); }); it('should sanitize attributes', () => { - expect( + expect(valueOf(
"'`} /> - ).to.equal( + )).to.equal( `
` ); }); it('should not sanitize the "dangerouslySetInnerHTML" attribute, and directly set its `__html` property as innerHTML', () => { - expect( + expect(valueOf(
Injected HTML" }} /> - ).to.equal( + )).to.equal( `
Injected HTML
` ); }); it('should flatten children', () => { - expect( + expect(valueOf(
{[['a','b']]} d {['e',['f'],[['g']]]}
- ).to.equal( + )).to.equal( `
abdefg
` ); }); @@ -70,7 +74,7 @@ describe('vhtml', () => { ); - expect( + expect(valueOf(

Hi!

    @@ -81,7 +85,7 @@ describe('vhtml', () => { )) }
- ).to.equal( + )).to.equal( `

Hi!

  • one

    This is item one!
  • two

    This is item two!
` ); }); @@ -95,7 +99,7 @@ describe('vhtml', () => { ); - expect( + expect(valueOf(

Hi!

    @@ -106,7 +110,7 @@ describe('vhtml', () => { )) }
- ).to.equal( + )).to.equal( `

Hi!

` ); }); @@ -121,7 +125,7 @@ describe('vhtml', () => { ); - expect( + expect(valueOf(

Hi!

    @@ -132,13 +136,13 @@ describe('vhtml', () => { )) }
- ).to.equal( + )).to.equal( `

Hi!

  • This is item one!
  • This is item two!
` ); }); it('should support empty (void) tags', () => { - expect( + expect(valueOf(
@@ -161,31 +165,31 @@ describe('vhtml', () => {

- ).to.equal( + )).to.equal( `


` ); }); it('should handle special prop names', () => { - expect( + expect(valueOf(
- ).to.equal( + )).to.equal( '
' ); }); it('should support string fragments', () => { - expect( + expect(valueOf( h(null, null, "foo", "bar", "baz") - ).to.equal( + )).to.equal( 'foobarbaz' ); }); it('should support element fragments', () => { - expect( + expect(valueOf( h(null, null,

foo

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

foo

bar
baz
' ); });