diff --git a/src/stringify.js b/src/stringify.js new file mode 100644 index 0000000..9c2e149 --- /dev/null +++ b/src/stringify.js @@ -0,0 +1,50 @@ +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 = {}; + +export default function stringify(name, attrs, stack) { + // Sortof component support! + if (typeof name==='function') { + attrs.children = stack.reverse(); + return String(name(attrs)); + } + + let s = `<${name}`; + if (attrs) for (let i in attrs) { + if (attrs[i]!==false && attrs[i]!=null) { + s += ` ${DOMAttributeNames[i] ? DOMAttributeNames[i] : esc(i)}="${esc(attrs[i])}"`; + } + } + + 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 { + let resolved = String(child); + s += sanitized[resolved]===true ? resolved : esc(resolved); + } + } + } + + s += ``; + } else { + s += '>'; + } + + sanitized[s] = true; + return s; +} diff --git a/src/vhtml.js b/src/vhtml.js index d42d9c9..a7e2afc 100644 --- a/src/vhtml.js +++ b/src/vhtml.js @@ -1,14 +1,4 @@ -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 = {}; +import stringify from './stringify'; /** Hyperscript reviver that constructs a sanitized HTML string. */ export default function h(name, attrs) { @@ -17,40 +7,5 @@ export default function h(name, attrs) { stack.push(arguments[i]); } - // Sortof component support! - if (typeof name==='function') { - (attrs || (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) { - s += ` ${DOMAttributeNames[i] ? DOMAttributeNames[i] : esc(i)}="${esc(attrs[i])}"`; - } - } - - 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; - return s; + return stringify(name, attrs || {}, stack); }