chore: CRM-NEW baseline
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
'use strict';
|
||||
|
||||
// 极简 Markdown → HTML(只覆盖 LLM 常用:粗体、链接、列表、段落、行内代码)。
|
||||
// LibreDesk 的 live chat 消息按 HTML 渲染,直接发 Markdown 会显示成 ** 和 [text](url)。
|
||||
function escapeHtml(text) {
|
||||
return String(text || '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
}
|
||||
|
||||
function inline(text) {
|
||||
const links = [];
|
||||
let out = text.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, (_, label, url) => {
|
||||
links.push(`<a href="${url}" target="_blank" rel="noopener noreferrer">${label}</a>`);
|
||||
return `\u0000L${links.length - 1}\u0000`;
|
||||
});
|
||||
out = out.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
||||
out = out.replace(/`([^`]+)`/g, '<code>$1</code>');
|
||||
// 裸 URL 自动转链接(占位符里还没有 http,避免重复处理 href)
|
||||
out = out.replace(/(https?:\/\/[^\s<]+)/g, '<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>');
|
||||
out = out.replace(/\u0000L(\d+)\u0000/g, (_, i) => links[Number(i)] || '');
|
||||
return out;
|
||||
}
|
||||
|
||||
function markdownToHtml(markdown) {
|
||||
const escaped = escapeHtml(markdown);
|
||||
const lines = escaped.split(/\r?\n/);
|
||||
const html = [];
|
||||
let paragraph = [];
|
||||
let list = null; // 'ul' | 'ol'
|
||||
|
||||
const flushParagraph = () => {
|
||||
if (!paragraph.length) return;
|
||||
html.push(`<p>${paragraph.map(inline).join('<br>')}</p>`);
|
||||
paragraph = [];
|
||||
};
|
||||
const closeList = () => {
|
||||
if (!list) return;
|
||||
html.push(`</${list}>`);
|
||||
list = null;
|
||||
};
|
||||
|
||||
for (const rawLine of lines) {
|
||||
const line = rawLine.trim();
|
||||
if (!line) {
|
||||
flushParagraph();
|
||||
closeList();
|
||||
continue;
|
||||
}
|
||||
const bullet = /^[-*]\s+(.*)$/.exec(line);
|
||||
const numbered = /^\d+[.)]\s+(.*)$/.exec(line);
|
||||
if (bullet || numbered) {
|
||||
flushParagraph();
|
||||
const kind = bullet ? 'ul' : 'ol';
|
||||
if (list !== kind) {
|
||||
closeList();
|
||||
list = kind;
|
||||
html.push(`<${kind}>`);
|
||||
}
|
||||
html.push(`<li>${inline((bullet || numbered)[1])}</li>`);
|
||||
continue;
|
||||
}
|
||||
closeList();
|
||||
const heading = /^#{1,3}\s+(.*)$/.exec(line);
|
||||
if (heading) {
|
||||
flushParagraph();
|
||||
html.push(`<p><strong>${inline(heading[1])}</strong></p>`);
|
||||
continue;
|
||||
}
|
||||
paragraph.push(line);
|
||||
}
|
||||
flushParagraph();
|
||||
closeList();
|
||||
return html.join('');
|
||||
}
|
||||
|
||||
module.exports = { markdownToHtml, escapeHtml };
|
||||
Reference in New Issue
Block a user