Files
bDS/src/renderer/utils/markdownEscape.ts
2026-02-17 06:55:16 +00:00

74 lines
2.3 KiB
TypeScript

/**
* Markdown escape utilities for Milkdown editor
*
* Handles unescaping of special characters that Milkdown/remark escapes
* but should be preserved in macro syntax.
*/
/**
* Unescape special characters in macro syntax that Milkdown escapes.
*
* Milkdown/remark-stringify escapes:
* - Brackets [ and ] to prevent unwanted link syntax
* - Underscores _ to prevent unwanted emphasis
*
* For macros like [[photo_gallery]], we want to preserve the original syntax.
*
* Strategy:
* 1. First unescape all brackets (they're always safe to unescape)
* 2. Then unescape underscores only inside [[...]] macro syntax
*
* @param markdown - The markdown string with escaped characters
* @returns The markdown with macro syntax unescaped
*/
export function unescapeMacroSyntax(markdown: string): string {
if (!markdown) return markdown;
// Step 1: Unescape all brackets \[ and \] back to [ and ]
let result = markdown.replace(/\\\[/g, '[').replace(/\\\]/g, ']');
// Step 2: Unescape underscores only inside macro brackets [[...]]
// Match [[...]] patterns and unescape underscores within them
result = result.replace(/\[\[([^\]]*)\]\]/g, (_match, content) => {
// Unescape underscores within the macro content
const unescapedContent = content.replace(/\\_/g, '_');
return `[[${unescapedContent}]]`;
});
return result;
}
const unorderedListItemPattern = /^[-+*]\s/;
const orderedListItemPattern = /^\d+\.\s/;
function getListLineType(line: string): 'ordered' | 'unordered' | null {
if (unorderedListItemPattern.test(line)) return 'unordered';
if (orderedListItemPattern.test(line)) return 'ordered';
return null;
}
export function normalizeMilkdownMarkdown(markdown: string): string {
const unescaped = unescapeMacroSyntax(markdown);
const lines = unescaped.split('\n');
const normalized: string[] = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const previousListType = i > 0 ? getListLineType(lines[i - 1]) : null;
const nextListType = i < lines.length - 1 ? getListLineType(lines[i + 1]) : null;
if (line === '' && previousListType !== null && previousListType === nextListType) {
continue;
}
if (line === '>') {
normalized.push('> ');
continue;
}
normalized.push(line);
}
return normalized.join('\n');
}