@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
189 lines (177 loc) • 6.19 kB
JavaScript
function splitInlineCode(text) {
var segments = [];
var currentPos = 0;
// 匹配行内代码,支持多个反引号
var inlineCodeRegex = /(`+)([^`]*?)\1/g;
var match;
while ((match = inlineCodeRegex.exec(text)) !== null) {
// 添加代码前的普通文本
if (match.index > currentPos) {
segments.push({
content: text.slice(currentPos, match.index),
isCode: false
});
}
// 添加行内代码
segments.push({
content: match[0],
isCode: true
});
currentPos = match.index + match[0].length;
}
// 添加最后剩余的普通文本
if (currentPos < text.length) {
segments.push({
content: text.slice(currentPos),
isCode: false
});
}
return segments;
}
function applyEmphasisFixes(text) {
var result = text;
// Step 1: Remove trailing spaces inside emphasis markers
var removeInternalSpaces = [
// 处理 **bold** 格式(两个星号)- 只处理一个空格,确保内容不包含表格分隔符
{
pattern: /(\*\*)([^\n*|]+?)( )(\*\*)/g,
replacement: '$1$2$4'
},
// 处理 __bold__ 格式(两个下划线)- 只处理一个空格,确保内容不包含表格分隔符
{
pattern: /(__)([^\n_|]+?)( )(__)/g,
replacement: '$1$2$4'
},
// 处理 ~~strikethrough~~ 格式(删除线)- 只处理一个空格,确保内容不包含表格分隔符
{
pattern: /(~~)([^\n|~]+?)( )(~~)/g,
replacement: '$1$2$4'
},
// 处理单个 * 格式 - 只处理一个空格,使用更精确的边界匹配,确保内容不包含表格分隔符
{
pattern: /(^|[^\w*])(\*(?!\*))([^\n*|]+?)( )(\*(?!\*))/g,
replacement: '$1$2$3$5'
},
// 处理单个 _ 格式 - 只处理一个空格,使用更精确的边界匹配,确保内容不包含表格分隔符
{
pattern: /(^|\W)(_(?!_))([^\n_|]+?)( )(_(?!_))/g,
replacement: '$1$2$3$5'
}];
result = removeInternalSpaces.reduce(function (text, _ref) {
var pattern = _ref.pattern,
replacement = _ref.replacement;
return text.replace(pattern, replacement);
}, result);
// Step 2: Add space after closing emphasis markers when followed by symbols/punctuation/Chinese characters
// Define emphasis patterns
var emphasisPatterns = [
// ** (bold) - exclude table separators from content
{
markerChar: '*',
pattern: /(\*\*)([^\n*|]*?)(\*\*)(\S)/g
},
// __ (bold) - exclude table separators from content
{
markerChar: '_',
pattern: /(__)([^\n_|]*?)(__)(\S)/g
},
// * (italic) - need to avoid matching **, exclude table separators from content
{
markerChar: '*',
pattern: /(\*(?!\*))([^\n*|]*?)(\*(?!\*))(\S)/g
},
// _ (italic) - need to avoid matching __, exclude table separators from content
{
markerChar: '_',
pattern: /(_(?!_))([^\n_|]*?)(_(?!_))(\S)/g
},
// ~~ (strikethrough) - exclude table separators from content
{
markerChar: '~',
pattern: /(~~)([^\n|~]*?)(~~)(\S)/g
}];
// Apply space after closing markers for each emphasis type
for (var _i = 0, _emphasisPatterns = emphasisPatterns; _i < _emphasisPatterns.length; _i++) {
var pattern = _emphasisPatterns[_i].pattern;
result = result.replaceAll(pattern, function (match, start, content, end, nextChar) {
// Check if the content ends with a symbol/punctuation (like :, :, etc.)
var lastChar = content.slice(-1);
var isSymbolOrPunctuation = /[!"#$%&'()*+,./:;<=>?@[\\\]^_`{|}~、。《》【】!(),:;?{|}-]/.test(lastChar);
// Don't add space if next character is a table separator or other markdown structural characters
var isTableSeparator = nextChar === '|';
var isMarkdownStructural = /[()[\]{}]/.test(nextChar);
// If content ends with symbol/punctuation and next character is not whitespace, add space
// But skip if it's a table separator or markdown structural character
if (isSymbolOrPunctuation && nextChar && !/\s/.test(nextChar) && !isTableSeparator && !isMarkdownStructural) {
return start + content + end + ' ' + nextChar;
}
return match;
});
}
return result;
}
function splitMarkdownWithAllCodeTypes(text) {
var segments = [];
var lines = text.split('\n');
var currentSegment = '';
var isInCodeBlock = false;
var codeBlockType = null; // 'fenced' | 'indented'
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
// 检查围栏代码块的开始/结束
var fencedCodeMatch = line.match(/^(\s*)(```|~~~)/);
if (fencedCodeMatch && !isInCodeBlock) {
// 开始围栏代码块
if (currentSegment) {
segments.push({
content: currentSegment,
isCode: false
});
currentSegment = '';
}
isInCodeBlock = true;
codeBlockType = 'fenced';
currentSegment = line + (i < lines.length - 1 ? '\n' : '');
} else if (fencedCodeMatch && isInCodeBlock && codeBlockType === 'fenced') {
// 结束围栏代码块
currentSegment += line + (i < lines.length - 1 ? '\n' : '');
segments.push({
content: currentSegment,
isCode: true
});
currentSegment = '';
isInCodeBlock = false;
codeBlockType = null;
} else if (isInCodeBlock) {
// 在代码块内部
currentSegment += line + (i < lines.length - 1 ? '\n' : '');
} else {
// 普通行,但需要检查行内代码
currentSegment += line + (i < lines.length - 1 ? '\n' : '');
}
}
// 处理最后的片段
if (currentSegment) {
segments.push({
content: currentSegment,
isCode: isInCodeBlock
});
}
// 进一步处理行内代码
return segments.flatMap(function (segment) {
if (segment.isCode) {
return [segment];
}
return splitInlineCode(segment.content);
});
}
export function fixMarkdownEmphasisSpacing(text) {
// 更完善的代码块识别,包括缩进代码块
var segments = splitMarkdownWithAllCodeTypes(text);
return segments.map(function (segment) {
if (segment.isCode) {
return segment.content;
}
return applyEmphasisFixes(segment.content);
}).join('');
}