const { DISPLAY_TYPES } = require('../constants.js')
const {
MENTION,
HTTP_LINK,
PEAR_LINK,
BOLD,
ITALIC,
CODE,
EMOJI,
CODE_BLOCK,
STRIKE_THROUGH
} = DISPLAY_TYPES
const map = {
[BOLD]: bold,
[ITALIC]: italic,
[STRIKE_THROUGH]: strike,
[CODE]: code,
[CODE_BLOCK]: codeBlock,
[EMOJI]: emoji,
[MENTION]: mention,
[PEAR_LINK]: link,
[HTTP_LINK]: link
}
module.exports = { segmentToHtml }
function segmentToHtml(text, segments, opts = {}) {
if (!segments) return escapeHTML(text) || ''
let html = ''
for (const { start, end, styles } of segments) {
let htmlSegment = escapeHTML(text.slice(start, end))
for (const display of styles) {
htmlSegment = map[display.type](htmlSegment, display, opts)
}
html += htmlSegment
}
return html.replace(/\n/g, '<br />')
}
function escapeHTML(str) {
if (!str) return ''
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
}
function bold(text) {
return `<b>${text}</b>`
}
function italic(text) {
return `<i>${text}</i>`
}
function strike(text) {
return `<s>${text}</s>`
}
function code(text) {
return `<code>${text}</code>`
}
function codeBlock(text) {
return `<pre>${text}</pre>`
}
function emoji(text, display, opts) {
const { urlRiv, url, emoji } = opts.getEmojiData(display.content) || {}
let children
if (urlRiv || url) {
const attributes = {
class: 'emoji-img',
src: urlRiv || url,
alt: `:${display.content}:`
}
children = `<img ${objToStr(attributes)} />`
} else {
children = text
}
const attributes = {
class: 'emoji',
data: {
shortcode: display.content,
emoji
}
}
return `<span ${objToStr(attributes)}>${children}</span>`
}
function mention(text, display) {
const [id, role] = display.content.split('/')
const attributes = {
class: 'mention',
data: {
type: 'mention',
id,
label: text.startsWith('@') ? text.slice(1) : text
}
}
if (role) {
attributes.data.role = role
}
return `<span ${objToStr(attributes)}>${text}</span>`
}
function link(text, display) {
return `<a href="${display.content}">${text}</a>`
}
function objToStr(attr) {
const { data, ...rest } = attr
const parts = Object.keys(rest).map((key) => `${key}="${rest[key]}"`)
if (data) {
Object.keys(data).forEach((key) => parts.push(`data-${key}="${data[key]}"`))
}
return parts.join(' ')
}