fix(hololake): ship dynamic persona routes and coherent workspace
This commit is contained in:
parent
5105ec5e32
commit
787ba2ad3f
21 changed files with 1111 additions and 326 deletions
64
product-source/guanghu-knowledge-base/src/markdown.ts
Normal file
64
product-source/guanghu-knowledge-base/src/markdown.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import { marked, Renderer } from 'marked';
|
||||
|
||||
const WIKI_LINK = /\[\[([^\]|\n]+?)(?:\|([^\]\n]+?))?\]\]/g;
|
||||
const UNSAFE_SCHEME = /^(?:javascript|data|vbscript):/i;
|
||||
|
||||
export function normalizeImportedMarkup(source: string): string {
|
||||
return source.replace(/<aside>\s*([\s\S]*?)\s*<\/aside>/giu, (_match, rawBody: string) => {
|
||||
const body = rawBody.trim().split('\n').map(line => `> ${line}`).join('\n');
|
||||
return `\n\n${body}\n\n`;
|
||||
});
|
||||
}
|
||||
|
||||
export function expandWikiLinks(source: string): string {
|
||||
return source.replace(WIKI_LINK, (_match, rawTarget: string, rawLabel?: string) => {
|
||||
const target = rawTarget.trim();
|
||||
const label = (rawLabel || rawTarget).trim();
|
||||
const encoded = encodeURIComponent(target).replace(/%2F/gi, '/');
|
||||
return `[${label}](hololake://knowledge/${encoded} "${target.replace(/"/g, '"')}")`;
|
||||
});
|
||||
}
|
||||
|
||||
function escapeHtml(value: string): string {
|
||||
return value
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function safeHref(href: string | null): string {
|
||||
const value = (href || '').trim();
|
||||
return UNSAFE_SCHEME.test(value) ? '#' : value;
|
||||
}
|
||||
|
||||
const renderer = new Renderer();
|
||||
const renderBaseTable = renderer.table.bind(renderer);
|
||||
renderer.html = ({ text }) => /^<br\s*\/?\s*>$/iu.test(text.trim())
|
||||
? '<br>'
|
||||
: `<pre class="kb-raw-html"><code>${escapeHtml(text)}</code></pre>`;
|
||||
renderer.link = ({ href, title, tokens }) => {
|
||||
const label = renderer.parser.parseInline(tokens);
|
||||
const safe = escapeHtml(safeHref(href));
|
||||
const titleAttr = title ? ` title="${escapeHtml(title)}"` : '';
|
||||
const wiki = safe.startsWith('hololake://knowledge/');
|
||||
return `<a href="${safe}"${titleAttr}${wiki ? ' data-hololake-wiki="true"' : ''}>${label}</a>`;
|
||||
};
|
||||
renderer.image = ({ href, title, text }) => {
|
||||
const safe = safeHref(href);
|
||||
if (!safe || safe === '#') return `<span class="kb-image-blocked">图片地址已拦截</span>`;
|
||||
const titleAttr = title ? ` title="${escapeHtml(title)}"` : '';
|
||||
return `<img src="${escapeHtml(safe)}" alt="${escapeHtml(text)}"${titleAttr} loading="lazy">`;
|
||||
};
|
||||
renderer.table = token => `<div class="kb-table-scroll">${renderBaseTable(token)}</div>`;
|
||||
|
||||
marked.setOptions({ gfm: true, breaks: false });
|
||||
|
||||
export function renderKnowledgeMarkdown(source: string): string {
|
||||
try {
|
||||
return marked.parse(expandWikiLinks(normalizeImportedMarkup(source)), { async: false, renderer }) as string;
|
||||
} catch {
|
||||
return '<p class="kb-render-error">此页面暂时无法渲染,请切换到编辑模式检查原文。</p>';
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue