Files
www/html.js
T
paul aacfd33c62
Deploy website / deploy (push) Failing after 28s
fmt and ci
2026-08-25 17:59:45 -04:00

46 lines
1.2 KiB
JavaScript

const voidElements = new Set([
'area',
'base',
'br',
'col',
'embed',
'hr',
'img',
'input',
'link',
'meta',
'source',
'track',
'wbr',
])
export const raw = (html) => ({ type: 'raw', html })
export const h = (tag, attributes = {}, children = []) => ({
type: 'element',
tag,
attributes,
children: Array.isArray(children) ? children : [children],
})
export const escapeHtml = (value) =>
String(value)
.replaceAll('&', '&')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.replaceAll('"', '&quot;')
.replaceAll("'", '&#39;')
export const render = (node) => {
if (node == null || node === false) return ''
if (Array.isArray(node)) return node.map(render).join('')
if (typeof node === 'string' || typeof node === 'number') return escapeHtml(node)
if (node.type === 'raw') return node.html
const attributes = Object.entries(node.attributes)
.filter(([, value]) => value !== false && value != null)
.map(([name, value]) => (value === true ? name : `${name}="${escapeHtml(value)}"`))
.join(' ')
const opening = attributes ? `<${node.tag} ${attributes}>` : `<${node.tag}>`
if (voidElements.has(node.tag)) return opening
return `${opening}${node.children.map(render).join('')}</${node.tag}>`
}