From 245120f323c2127174eb6fed72460b7ecb54747a Mon Sep 17 00:00:00 2001 From: Jason Miller Date: Sat, 12 Mar 2016 20:44:45 -0500 Subject: [PATCH 01/18] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dd09fd0..250230a 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ > Need to use HTML strings (angular?) but want to use JSX? vhtml's got your back. +[**JSFiddle Demo**](https://jsfiddle.net/developit/9q0vyskg/) --- From 09224c5ea73bde87664f7580866ceba313d0fc38 Mon Sep 17 00:00:00 2001 From: Jason Miller Date: Tue, 31 May 2016 09:59:26 -0400 Subject: [PATCH 02/18] Add a note about Preact --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 250230a..7f47597 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ ### **Render JSX/Hyperscript to HTML strings, without VDOM** > Need to use HTML strings (angular?) but want to use JSX? vhtml's got your back. +> +> Building components? do yourself a favor and use [Preact](https://github.com/developit/preact) [**JSFiddle Demo**](https://jsfiddle.net/developit/9q0vyskg/) From 24a3fdf2b3a43d406d607098a20e3c500a4c2ee6 Mon Sep 17 00:00:00 2001 From: Jason Miller Date: Thu, 27 Oct 2016 17:56:38 -0400 Subject: [PATCH 03/18] Clean up the repo and build a bit. --- .eslintignore | 1 - .eslintrc | 3 +-- .npmignore | 1 - package.json | 24 +++++++++++++----------- rollup.config.js | 14 ++++++-------- 5 files changed, 20 insertions(+), 23 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .npmignore diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index dd44972..0000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -*.md diff --git a/.eslintrc b/.eslintrc index 3a94731..06a5fd3 100644 --- a/.eslintrc +++ b/.eslintrc @@ -32,7 +32,7 @@ "no-implied-eval": 2, "no-new-func": 2, "guard-for-in": 2, - "eqeqeq": 1, + "eqeqeq": 0, "no-else-return": 2, "no-redeclare": 2, "no-dupe-keys": 2, @@ -44,7 +44,6 @@ "no-shadow-restricted-names": 2, "handle-callback-err": 0, "no-lonely-if": 2, - "keyword-spacing": 2, "constructor-super": 2, "no-this-before-super": 2, "no-dupe-class-members": 2, diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 4c2095a..0000000 --- a/.npmignore +++ /dev/null @@ -1 +0,0 @@ -.eslintrc diff --git a/package.json b/package.json index f716f83..f2205e8 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,8 @@ }, "babel": { "presets": [ - "es2015-minimal", - "stage-0", - "react" + "es2015", + "stage-0" ], "plugins": [ "transform-object-rest-spread", @@ -31,6 +30,10 @@ ] ] }, + "files": [ + "src", + "dist" + ], "keywords": [ "hyperscript", "html", @@ -49,23 +52,22 @@ "homepage": "https://github.com/developit/vhtml", "devDependencies": { "babel-core": "^6.6.4", - "babel-eslint": "^5.0.0", + "babel-eslint": "^7.0.0", "babel-plugin-transform-object-rest-spread": "^6.6.4", "babel-plugin-transform-react-jsx": "^6.6.5", - "babel-preset-es2015-minimal": "^1.1.0", - "babel-preset-es2015-minimal-rollup": "^1.1.0", - "babel-preset-react": "^6.5.0", + "babel-preset-es2015": "^6.9.0", "babel-preset-stage-0": "^6.5.0", "babel-register": "^6.7.2", "chai": "^3.5.0", - "eslint": "~2.2.0", + "eslint": "^3.1.0", "gzip-size-cli": "^1.0.0", "mkdirp": "^0.5.1", - "mocha": "^2.4.5", - "npm-run-all": "^1.5.1", + "mocha": "^3.1.2", + "npm-run-all": "^2.3.0", "pretty-bytes-cli": "^1.0.0", - "rollup": "^0.25.4", + "rollup": "^0.36.3", "rollup-plugin-babel": "^2.4.0", + "rollup-plugin-es3": "^1.0.3", "uglify-js": "^2.6.2" } } diff --git a/rollup.config.js b/rollup.config.js index 0de39c9..3a7799d 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,28 +1,26 @@ import path from 'path'; import fs from 'fs'; import babel from 'rollup-plugin-babel'; +import es3 from 'rollup-plugin-es3'; let pkg = JSON.parse(fs.readFileSync('./package.json')); -let external = Object.keys(pkg.peerDependencies || {}).concat(Object.keys(pkg.dependencies || {})); export default { entry: pkg['jsnext:main'], dest: pkg.main, sourceMap: path.resolve(pkg.main), moduleName: pkg.amdName, + exports: 'default', format: 'umd', - external, plugins: [ babel({ babelrc: false, comments: false, - exclude: 'node_modules/**', presets: [ - 'es2015-minimal-rollup' + ['es2015', { loose:true, modules:false }] ].concat(pkg.babel.presets.slice(1)), - plugins: require('babel-preset-es2015-minimal-rollup').plugins.concat([ - ['transform-react-jsx', { pragma:'h' }] - ]) - }) + plugins: pkg.babel.plugins + }), + es3() ] }; From f46e76220e2ca8e0a00fee0bdc837f546dacca52 Mon Sep 17 00:00:00 2001 From: Jason Miller Date: Thu, 27 Oct 2016 20:31:44 -0400 Subject: [PATCH 04/18] =?UTF-8?q?Add=20support=20for=20infinitely=20nested?= =?UTF-8?q?=20Arrays=20of=20children,=20while=20improving=20performance=20?= =?UTF-8?q?and=20decreasing=20library=20size=20=F0=9F=8E=88=20/cc=20@NekR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/vhtml.js | 27 +++++++++++++++++---------- test/vhtml.js | 12 ++++++++++++ 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/vhtml.js b/src/vhtml.js index a63a134..f641ece 100644 --- a/src/vhtml.js +++ b/src/vhtml.js @@ -2,24 +2,31 @@ let esc = str => String(str).replace(/[&<>"']/g, s=>`&${map[s]};`); let map = {'&':'amp','<':'lt','>':'gt','"':'quot',"'":'apos'}; -// sanitize text children and filter out falsey values -let child = s => truthy(s) ? (sanitized[s]===true ? s : esc(s)) : ''; - -// check that a value is not false, undefined or null -let truthy = v => v!==false && v!=null; - let sanitized = {}; /** Hyperscript reviver that constructs a sanitized HTML string. */ -export default function h(name, attrs, ...children) { +export default function h(name, attrs) { let s = `<${name}`; if (attrs) for (let i in attrs) { - if (attrs.hasOwnProperty(i) && truthy(attrs[i])) { + if (attrs[i]!==false && attrs[i]!=null) { s += ` ${esc(i)}="${esc(attrs[i])}"`; } } - s += `>${[].concat(...children).map(child).join('')}`; - sanitized[s] = true; + s += '>'; + let stack=[]; + for (let i=arguments.length; i-- > 2; ) stack.push(arguments[i]); + while (stack.length) { + let child = stack.pop(); + if (child) { + if (child.pop) { + for (let i=child.length; i--; ) stack.push(child[i]); + } + else { + s += sanitized[child]===true ? child : esc(child); + } + } + } + sanitized[s += ``] = true; return s; } diff --git a/test/vhtml.js b/test/vhtml.js index 51550df..46c4745 100644 --- a/test/vhtml.js +++ b/test/vhtml.js @@ -39,4 +39,16 @@ describe('vhtml', () => { `
` ); }); + + it('should flatten children', () => { + expect( +
+ {[['a','b']]} + d + {['e',['f'],[['g']]]} +
+ ).to.equal( + `
abdefg
` + ); + }); }); From c5a465c220d11ede9878ec27c72641f48886fbb9 Mon Sep 17 00:00:00 2001 From: Jason Miller Date: Thu, 27 Oct 2016 20:32:13 -0400 Subject: [PATCH 05/18] 1.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f2205e8..4dcf235 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vhtml", "amdName": "vhtml", - "version": "1.0.0", + "version": "1.1.0", "description": "Hyperscript reviver that constructs a sanitized HTML string.", "main": "dist/vhtml.js", "minified:main": "dist/vhtml.min.js", From 13d82941bcda3cfd308e8a8dc831df92b136843b Mon Sep 17 00:00:00 2001 From: Jason Miller Date: Thu, 3 Nov 2016 20:39:39 -0400 Subject: [PATCH 06/18] Add support for sortof components! Fixes #1 --- src/vhtml.js | 28 ++++++++++++++-------------- test/vhtml.js | 26 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/vhtml.js b/src/vhtml.js index f641ece..10962fe 100644 --- a/src/vhtml.js +++ b/src/vhtml.js @@ -6,6 +6,18 @@ let sanitized = {}; /** Hyperscript reviver that constructs a sanitized HTML string. */ export default function h(name, attrs) { + let stack=[]; + for (let i=arguments.length; i-- > 2; ) { + stack.push(arguments[i]); + } + + // Sortof component support! + if (typeof name==='function') { + attrs.children = stack.reverse(); + return name(attrs); + // return name(attrs, stack.reverse()); + } + let s = `<${name}`; if (attrs) for (let i in attrs) { if (attrs[i]!==false && attrs[i]!=null) { @@ -13,8 +25,7 @@ export default function h(name, attrs) { } } s += '>'; - let stack=[]; - for (let i=arguments.length; i-- > 2; ) stack.push(arguments[i]); + while (stack.length) { let child = stack.pop(); if (child) { @@ -26,18 +37,7 @@ export default function h(name, attrs) { } } } + sanitized[s += ``] = true; return s; } - - - -// for fun: -/* -export default const h = (tag, attrs, ...kids) => ( - `<${tag}${h.attrs(attrs)}>${[].concat(...kids).join('')}` -); -h.attrs = a => Object.keys(a || {}).reduce( (s,i) => `${s} ${h.esc(i)}="${h.esc(a[i]+'')}"`, ''); -h.esc = str => str.replace(/[&<>"']/g, s=>`&${h.map[s]};`); -h.map = {'&':'amp','<':'lt','>':'gt','"':'quot',"'":'apos'}; -*/ diff --git a/test/vhtml.js b/test/vhtml.js index 46c4745..0ab297c 100644 --- a/test/vhtml.js +++ b/test/vhtml.js @@ -51,4 +51,30 @@ describe('vhtml', () => { `
abdefg
` ); }); + + it('should support sortof components', () => { + let items = ['one', 'two']; + + const Item = ({ item, index, children }) => ( +
  • +

    {item}

    + {children} +
  • + ); + + expect( +
    +

    Hi!

    +
      + { items.map( (item, index) => ( + + This is item {item}! + + )) } +
    +
    + ).to.equal( + `

    Hi!

    • one

      This is item one!
    • two

      This is item two!
    ` + ); + }); }); From 7007386376ff1888b020503ccd45b5a0a93c70c3 Mon Sep 17 00:00:00 2001 From: Jason Miller Date: Thu, 3 Nov 2016 20:49:49 -0400 Subject: [PATCH 07/18] Add sortof components example to the readme --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/README.md b/README.md index 7f47597..1c41422 100644 --- a/README.md +++ b/README.md @@ -48,3 +48,56 @@ document.body.innerHTML = ( ); ``` + + +### New: "Sortof" Components! + +`vhtml` intentionally does not transform JSX to a Virtual DOM, instead serializing it directly to HTML. +However, it's still possible to make use of basic Pure Functional Components as a sort of "template partial". + +When `vhtml` is given a Function as the JSX tag name, it will invoke that function and pass it `{ children, ...props }`. +This is the same signature as a Pure Functional Component in react/preact, except `children` is an Array of already-serialized HTML strings. + +This actually means it's possible to build compositional template modifiers with these simple Components, or even higher-order components. + +Here's a more complex version of the previous example that uses a component to encapsulate iteration items: + +```js +let items = ['one', 'two']; + +const Item = ({ item, index, children }) => ( +
  • +

    {item}

    + {children} +
  • +); + +console.log( +
    +

    Hi!

    +
      + { items.map( (item, index) => ( + + This is item {item}! + + )) } +
    +
    +); +``` + +The above outputs the following HTML: + +```html +
    +

    Hi!

    +
      +
    • +

      one

      This is item one! +
    • +
    • +

      two

      This is item two! +
    • +
    +
    +``` From cc51b7180c6b2487e8c372496b98f4dc7c45bd03 Mon Sep 17 00:00:00 2001 From: Jason Miller Date: Thu, 3 Nov 2016 20:50:24 -0400 Subject: [PATCH 08/18] 2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4dcf235..b9b826d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vhtml", "amdName": "vhtml", - "version": "1.1.0", + "version": "2.0.0", "description": "Hyperscript reviver that constructs a sanitized HTML string.", "main": "dist/vhtml.js", "minified:main": "dist/vhtml.min.js", From 5be05af5011b515f352b7eb47046b04bd31a1dbd Mon Sep 17 00:00:00 2001 From: keyserfaty Date: Fri, 4 Nov 2016 18:03:12 -0300 Subject: [PATCH 09/18] fix bug when adding empty components --- src/vhtml.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vhtml.js b/src/vhtml.js index 10962fe..c62689e 100644 --- a/src/vhtml.js +++ b/src/vhtml.js @@ -13,7 +13,7 @@ export default function h(name, attrs) { // Sortof component support! if (typeof name==='function') { - attrs.children = stack.reverse(); + if (attrs) attrs.children = stack.reverse(); return name(attrs); // return name(attrs, stack.reverse()); } From f7489d917af350823e5fb0dfa057e9cfffb0cc91 Mon Sep 17 00:00:00 2001 From: Arthur Stolyar Date: Tue, 13 Dec 2016 00:35:11 +0300 Subject: [PATCH 10/18] Support empty (void) tags (#3) * Support empty tags * Improve test for empty (void) tags * Rename test for empty (void) tags * Inline empty-tags module in the project * Add forgotten empty-tags file * Simplify sanitization mapping --- src/empty-tags.js | 18 ++++++++++++++++++ src/vhtml.js | 29 +++++++++++++++++++---------- test/vhtml.js | 29 +++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 src/empty-tags.js diff --git a/src/empty-tags.js b/src/empty-tags.js new file mode 100644 index 0000000..6f91e68 --- /dev/null +++ b/src/empty-tags.js @@ -0,0 +1,18 @@ +export default [ + 'area', + 'base', + 'br', + 'col', + 'command', + 'embed', + 'hr', + 'img', + 'input', + 'keygen', + 'link', + 'meta', + 'param', + 'source', + 'track', + 'wbr' +]; \ No newline at end of file diff --git a/src/vhtml.js b/src/vhtml.js index c62689e..d719228 100644 --- a/src/vhtml.js +++ b/src/vhtml.js @@ -1,3 +1,5 @@ +import emptyTags from './empty-tags'; + // escape an attribute let esc = str => String(str).replace(/[&<>"']/g, s=>`&${map[s]};`); let map = {'&':'amp','<':'lt','>':'gt','"':'quot',"'":'apos'}; @@ -24,20 +26,27 @@ export default function h(name, attrs) { s += ` ${esc(i)}="${esc(attrs[i])}"`; } } - s += '>'; - while (stack.length) { - let child = stack.pop(); - if (child) { - if (child.pop) { - for (let i=child.length; i--; ) stack.push(child[i]); - } - else { - s += sanitized[child]===true ? child : esc(child); + if (emptyTags.indexOf(name) === -1) { + s += '>'; + + while (stack.length) { + let child = stack.pop(); + if (child) { + if (child.pop) { + for (let i=child.length; i--; ) stack.push(child[i]); + } + else { + s += sanitized[child]===true ? child : esc(child); + } } } + + s += ``; + } else { + s += '>'; } - sanitized[s += ``] = true; + sanitized[s] = true; return s; } diff --git a/test/vhtml.js b/test/vhtml.js index 0ab297c..4b6adc2 100644 --- a/test/vhtml.js +++ b/test/vhtml.js @@ -77,4 +77,33 @@ describe('vhtml', () => { `

    Hi!

    • one

      This is item one!
    • two

      This is item two!
    ` ); }); + + it('should support empty (void) tags', () => { + expect( +
    + + +
    + + + +
    + + + + + + + + + + {/* Not void elements */} +
    + +

    +

    + ).to.equal( + `


    ` + ); + }); }); From 539b9b893260d8e27b7b3ad4fc56021e1e91b091 Mon Sep 17 00:00:00 2001 From: Arthur Stolyar Date: Tue, 13 Dec 2016 02:32:19 +0300 Subject: [PATCH 11/18] Fix softof components use children without args (#4) --- src/vhtml.js | 2 +- test/vhtml.js | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/vhtml.js b/src/vhtml.js index d719228..7f36540 100644 --- a/src/vhtml.js +++ b/src/vhtml.js @@ -15,7 +15,7 @@ export default function h(name, attrs) { // Sortof component support! if (typeof name==='function') { - if (attrs) attrs.children = stack.reverse(); + (attrs || (attrs = {})).children = stack.reverse(); return name(attrs); // return name(attrs, stack.reverse()); } diff --git a/test/vhtml.js b/test/vhtml.js index 4b6adc2..3ca4a31 100644 --- a/test/vhtml.js +++ b/test/vhtml.js @@ -78,6 +78,57 @@ describe('vhtml', () => { ); }); + it('should support sortof components without args', () => { + let items = ['one', 'two']; + + const Item = () => ( +
  • +

    +
  • + ); + + expect( +
    +

    Hi!

    +
      + { items.map( (item, index) => ( + + This is item {item}! + + )) } +
    +
    + ).to.equal( + `

    Hi!

    ` + ); + }); + + it('should support sortof components without args but with children', () => { + let items = ['one', 'two']; + + const Item = ({ children }) => ( +
  • +

    + {children} +
  • + ); + + expect( +
    +

    Hi!

    +
      + { items.map( (item, index) => ( + + This is item {item}! + + )) } +
    +
    + ).to.equal( + `

    Hi!

    • This is item one!
    • This is item two!
    ` + ); + }); + it('should support empty (void) tags', () => { expect(
    From 4b4fd10dd666bf4461838fafcc724bed77e9b536 Mon Sep 17 00:00:00 2001 From: Jason Miller Date: Sun, 18 Dec 2016 20:27:36 -0500 Subject: [PATCH 12/18] 2.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b9b826d..33c90aa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vhtml", "amdName": "vhtml", - "version": "2.0.0", + "version": "2.1.0", "description": "Hyperscript reviver that constructs a sanitized HTML string.", "main": "dist/vhtml.js", "minified:main": "dist/vhtml.min.js", From 8767d1778ba86827c483d64a740b4818a8372d1d Mon Sep 17 00:00:00 2001 From: Nathan Cahill Date: Sat, 29 Apr 2017 16:49:25 -0700 Subject: [PATCH 13/18] support classname (#5) --- src/vhtml.js | 2 +- test/vhtml.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vhtml.js b/src/vhtml.js index 7f36540..837da4f 100644 --- a/src/vhtml.js +++ b/src/vhtml.js @@ -23,7 +23,7 @@ export default function h(name, attrs) { let s = `<${name}`; if (attrs) for (let i in attrs) { if (attrs[i]!==false && attrs[i]!=null) { - s += ` ${esc(i)}="${esc(attrs[i])}"`; + s += ` ${i === 'className' ? 'class' : esc(i)}="${esc(attrs[i])}"`; } } diff --git a/test/vhtml.js b/test/vhtml.js index 3ca4a31..382fa53 100644 --- a/test/vhtml.js +++ b/test/vhtml.js @@ -157,4 +157,12 @@ describe('vhtml', () => { `


    ` ); }); + + it('should handle className as class', () => { + expect( +
    + ).to.equal( + '
    ' + ); + }); }); From a111d561839f0a48cd1fdd9744b24190cef7a582 Mon Sep 17 00:00:00 2001 From: Nathan Cahill Date: Sun, 30 Apr 2017 14:13:08 -0700 Subject: [PATCH 14/18] support the other special prop (#7) --- src/vhtml.js | 6 +++++- test/vhtml.js | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/vhtml.js b/src/vhtml.js index 837da4f..d42d9c9 100644 --- a/src/vhtml.js +++ b/src/vhtml.js @@ -3,6 +3,10 @@ import emptyTags from './empty-tags'; // escape an attribute let esc = str => String(str).replace(/[&<>"']/g, s=>`&${map[s]};`); let map = {'&':'amp','<':'lt','>':'gt','"':'quot',"'":'apos'}; +let DOMAttributeNames = { + className: 'class', + htmlFor: 'for' +}; let sanitized = {}; @@ -23,7 +27,7 @@ export default function h(name, attrs) { let s = `<${name}`; if (attrs) for (let i in attrs) { if (attrs[i]!==false && attrs[i]!=null) { - s += ` ${i === 'className' ? 'class' : esc(i)}="${esc(attrs[i])}"`; + s += ` ${DOMAttributeNames[i] ? DOMAttributeNames[i] : esc(i)}="${esc(attrs[i])}"`; } } diff --git a/test/vhtml.js b/test/vhtml.js index 382fa53..606d762 100644 --- a/test/vhtml.js +++ b/test/vhtml.js @@ -158,11 +158,11 @@ describe('vhtml', () => { ); }); - it('should handle className as class', () => { + it('should handle special prop names', () => { expect( -
    +
    ).to.equal( - '
    ' + '
    ' ); }); }); From 714c9e0a6fd8ff7968d239e875a1f8b3c71a10eb Mon Sep 17 00:00:00 2001 From: Peter Lenahan Date: Thu, 23 May 2019 08:37:55 -0400 Subject: [PATCH 15/18] Address vhtml#11: Add ability to directly set innerHTML of a component using the `dangerouslySetInnerHTML` attribute. (#12) * Address vhtml#11: Add ability to directly set innerHTML of a component using the `dangerouslySetInnerHTML` attribute. * Remove check for valid `__html` property of `dangerouslySetInnerHTML * Hoist line that is always executed out of conditional block Saves 4 bytes. * Hoist declaration of `s` to avoid extra `let` statement. Saves 3 bytes. * Hoist default assignment of `attrs` to the top of `h`. This allows us to assume that `attrs` is a plain object, and remove multiple guards. Saves 6B. --- src/vhtml.js | 21 +++++++++++---------- test/vhtml.js | 8 ++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/vhtml.js b/src/vhtml.js index d42d9c9..8576bc3 100644 --- a/src/vhtml.js +++ b/src/vhtml.js @@ -3,6 +3,7 @@ import emptyTags from './empty-tags'; // escape an attribute let esc = str => String(str).replace(/[&<>"']/g, s=>`&${map[s]};`); let map = {'&':'amp','<':'lt','>':'gt','"':'quot',"'":'apos'}; +let setInnerHTMLAttr = 'dangerouslySetInnerHTML'; let DOMAttributeNames = { className: 'class', htmlFor: 'for' @@ -12,29 +13,31 @@ let sanitized = {}; /** Hyperscript reviver that constructs a sanitized HTML string. */ export default function h(name, attrs) { - let stack=[]; + let stack=[], s = `<${name}`; + attrs = attrs || {}; for (let i=arguments.length; i-- > 2; ) { stack.push(arguments[i]); } // Sortof component support! if (typeof name==='function') { - (attrs || (attrs = {})).children = stack.reverse(); + attrs.children = stack.reverse(); return name(attrs); // return name(attrs, stack.reverse()); } - let s = `<${name}`; - if (attrs) for (let i in attrs) { - if (attrs[i]!==false && attrs[i]!=null) { + for (let i in attrs) { + if (attrs[i]!==false && attrs[i]!=null && i !== setInnerHTMLAttr) { s += ` ${DOMAttributeNames[i] ? DOMAttributeNames[i] : esc(i)}="${esc(attrs[i])}"`; } } + s += '>'; if (emptyTags.indexOf(name) === -1) { - s += '>'; - - while (stack.length) { + if (attrs[setInnerHTMLAttr]) { + s += attrs[setInnerHTMLAttr].__html; + } + else while (stack.length) { let child = stack.pop(); if (child) { if (child.pop) { @@ -47,8 +50,6 @@ export default function h(name, attrs) { } s += ``; - } else { - s += '>'; } sanitized[s] = true; diff --git a/test/vhtml.js b/test/vhtml.js index 606d762..8fef98e 100644 --- a/test/vhtml.js +++ b/test/vhtml.js @@ -40,6 +40,14 @@ describe('vhtml', () => { ); }); + it('should not sanitize the "dangerouslySetInnerHTML" attribute, and directly set its `__html` property as innerHTML', () => { + expect( +
    Injected HTML" }} /> + ).to.equal( + `
    Injected HTML
    ` + ); + }); + it('should flatten children', () => { expect(
    From 8a0ae24ae616758db5034a40a33fff1c0a924fe6 Mon Sep 17 00:00:00 2001 From: Michael Stillwell Date: Thu, 23 May 2019 14:05:17 +0100 Subject: [PATCH 16/18] Support fragments via h(null, null, ...args) (#16) * Test on latest LTS node * Adds support for fragments * Bump Travis node versions * Back out of unnecessary change * Update .travis.yml * Update vhtml.js * Size optimization (-3b) --- .travis.yml | 4 ++-- src/vhtml.js | 15 +++++++++------ test/vhtml.js | 17 +++++++++++++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8524235..965fe2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,3 @@ language: node_js -node_js: - - 4 +node_js: node +cache: npm diff --git a/src/vhtml.js b/src/vhtml.js index 8576bc3..0e03f69 100644 --- a/src/vhtml.js +++ b/src/vhtml.js @@ -13,7 +13,7 @@ let sanitized = {}; /** Hyperscript reviver that constructs a sanitized HTML string. */ export default function h(name, attrs) { - let stack=[], s = `<${name}`; + let stack=[], s = ''; attrs = attrs || {}; for (let i=arguments.length; i-- > 2; ) { stack.push(arguments[i]); @@ -26,12 +26,15 @@ export default function h(name, attrs) { // return name(attrs, stack.reverse()); } - for (let i in attrs) { - if (attrs[i]!==false && attrs[i]!=null && i !== setInnerHTMLAttr) { - s += ` ${DOMAttributeNames[i] ? DOMAttributeNames[i] : esc(i)}="${esc(attrs[i])}"`; + if (name) { + s += '<' + name; + if (attrs) for (let i in attrs) { + if (attrs[i]!==false && attrs[i]!=null && i !== setInnerHTMLAttr) { + s += ` ${DOMAttributeNames[i] ? DOMAttributeNames[i] : esc(i)}="${esc(attrs[i])}"`; + } } + s += '>'; } - s += '>'; if (emptyTags.indexOf(name) === -1) { if (attrs[setInnerHTMLAttr]) { @@ -49,7 +52,7 @@ export default function h(name, attrs) { } } - s += ``; + s += name ? `` : ''; } sanitized[s] = true; diff --git a/test/vhtml.js b/test/vhtml.js index 8fef98e..f88ddf2 100644 --- a/test/vhtml.js +++ b/test/vhtml.js @@ -173,4 +173,21 @@ describe('vhtml', () => { '
    ' ); }); + + it('should support string fragments', () => { + expect( + h(null, null, "foo", "bar", "baz") + ).to.equal( + 'foobarbaz' + ); + }); + + it('should support element fragments', () => { + expect( + h(null, null,

    foo

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

    foo

    bar
    baz
    ' + ); + }); + }); From e0c23d4481ac247814789dcb3f3b1d9568d091df Mon Sep 17 00:00:00 2001 From: Jason Miller Date: Tue, 3 Dec 2019 19:49:24 -0500 Subject: [PATCH 17/18] ignore package lock --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 72e9b45..9df4e9f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /dist /node_modules /npm-debug.log +package-lock.json .DS_Store From 96fe21e63a983d7a8f52d8c51a0c994490313abc Mon Sep 17 00:00:00 2001 From: Jason Miller Date: Tue, 3 Dec 2019 19:50:12 -0500 Subject: [PATCH 18/18] 2.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 33c90aa..6e3d2ff 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vhtml", "amdName": "vhtml", - "version": "2.1.0", + "version": "2.2.0", "description": "Hyperscript reviver that constructs a sanitized HTML string.", "main": "dist/vhtml.js", "minified:main": "dist/vhtml.min.js", pFad - Phonifier reborn

    Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

    Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


    Alternative Proxies:

    Alternative Proxy

    pFad Proxy

    pFad v3 Proxy

    pFad v4 Proxy