0
0
mirror of https://github.com/honojs/hono.git synced 2024-12-01 10:51:01 +00:00
hono/src/middleware/jsx/index.ts

78 lines
2.0 KiB
TypeScript
Raw Normal View History

2022-06-07 10:03:42 +00:00
import type { Context } from '../../context'
import type { Next } from '../../hono'
import { escape } from '../../utils/html'
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace h.JSX {
interface IntrinsicElements {
[tagName: string]: Record<string, any>
2022-06-07 10:03:42 +00:00
}
}
}
export const jsx = () => {
return async (c: Context, next: Next) => {
c.render = (content: string) => {
const output = `<!doctype html>${content.toString()}`
return c.html(output)
}
await next()
}
}
type EscapedString = string & { isEscaped: true }
export const h = (
tag: string | Function,
props: Record<string, any>,
...children: (string | EscapedString)[]
): EscapedString => {
if (typeof tag === 'function') {
return tag.call(null, { ...props, children: children.length <= 1 ? children[0] : children })
2022-06-07 10:03:42 +00:00
}
let result = `<${tag}`
2022-06-07 10:03:42 +00:00
const propsKeys = Object.keys(props || {})
for (let i = 0, len = propsKeys.length; i < len; i++) {
const v = props[propsKeys[i]]
if (propsKeys[i] === 'dangerouslySetInnerHTML') {
if (children.length > 0) {
throw 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
}
const escapedString = new String(v.__html) as EscapedString
escapedString.isEscaped = true
children = [escapedString]
continue
}
else if (v === null || v === undefined) {
continue
}
result += ` ${propsKeys[i]}="${escape(v.toString())}"`
2022-06-07 10:03:42 +00:00
}
result += '>'
const flattenChildren = children.flat(Infinity)
for (let i = 0, len = flattenChildren.length; i < len; i++) {
const child = flattenChildren[i]
if (typeof child === 'boolean' || child === null || child === undefined) {
continue
} else if (typeof child === 'object' && (child as any).isEscaped) {
result += child
} else {
result += escape(child.toString())
}
}
result += `</${tag}>`
const escapedString = new String(result) as EscapedString
escapedString.isEscaped = true
2022-06-07 10:03:42 +00:00
return escapedString
2022-06-07 10:03:42 +00:00
}