@portabletext/to-html
Version:
Render Portable Text to HTML
49 lines (40 loc) • 1.22 kB
text/typescript
const allowedProtocols = ['http', 'https', 'mailto', 'tel']
const charMap: Record<string, string> = {
'&': 'amp',
'<': 'lt',
'>': 'gt',
'"': 'quot',
"'": '#x27',
}
export function escapeHTML(str: string): string {
return str.replace(/[&<>"']/g, (s) => `&${charMap[s]};`)
}
export function uriLooksSafe(uri: string): boolean {
const url = (uri || '').trim()
const first = url.charAt(0)
// Allow hash-links, absolute paths and "same-protocol" (//foo.bar) URLs
if (first === '#' || first === '/') {
return true
}
// If the URL does not contain a `:`, allow it
const colonIndex = url.indexOf(':')
if (colonIndex === -1) {
return true
}
// If the protocol is in the allowed list, treat it as OK
const proto = url.slice(0, colonIndex).toLowerCase()
if (allowedProtocols.indexOf(proto) !== -1) {
return true
}
// If the URL is `site/search?query=author:espen`, allow it
const queryIndex = url.indexOf('?')
if (queryIndex !== -1 && colonIndex > queryIndex) {
return true
}
// If the URL is `site/search#my:encoded:data`, allow it
const hashIndex = url.indexOf('#')
if (hashIndex !== -1 && colonIndex > hashIndex) {
return true
}
return false
}