feat: enhance Milkdown editor and file system functionality
- Normalize line endings in Markdown export for DOCX files. - Improve selection serialization to Markdown with better handling of empty documents. - Add a new `updateFile` function to the file system for updating file properties. - Introduce video transcoding capabilities using FFmpeg, supporting various video formats. - Update AGENTS.md for clearer plugin structure and responsibilities. - Add scoped styles for TreeNodeItem component to improve UI consistency. - Implement cross-origin isolation headers in Vite configuration for enhanced security. - Remove obsolete test_cross.py file.
This commit is contained in:
+47
-14
@@ -5,6 +5,17 @@ export const DOC_CONTEXT_LIMIT = 32 * 1024
|
||||
const IMAGE_MD_RE = /!\[[^\]]*]\([^)]+\)/g
|
||||
const IMAGE_HTML_RE = /<img\b[^>]*>/gi
|
||||
const HEADER_SEPARATOR = '\n---\n'
|
||||
const FENCED_DOC_BLOCK_RE = /(^|\n)(`{3,})llm-file[^\n]*\n([\s\S]*?)\n\2(?=\n|$)/g
|
||||
const LEGACY_DOC_BLOCK_RE = /<doc_type="[^"]+"\s+doc_name="[^"]+"\s+upload_time="[^"]+"(?:\s+collapsed="[^"]+")?>[\s\S]*?<\/doc_end>/g
|
||||
|
||||
function normalizeMarkdownText(markdown = '') {
|
||||
return String(markdown || '').replace(/\r\n?/g, '\n')
|
||||
}
|
||||
|
||||
function clipDocContext(content = '', limit = 0) {
|
||||
if (!limit || content.length <= limit) return content
|
||||
return `${content.slice(0, limit)}...`
|
||||
}
|
||||
|
||||
export function normalizeDocType(value = '') {
|
||||
const lower = String(value || '').trim().toLowerCase()
|
||||
@@ -54,12 +65,9 @@ export function isSupportedDocFile(file) {
|
||||
}
|
||||
|
||||
export function sanitizeDocContent(markdown = '') {
|
||||
return String(markdown || '')
|
||||
.replace(/\r\n?/g, '\n')
|
||||
return normalizeMarkdownText(markdown)
|
||||
.replace(IMAGE_MD_RE, '')
|
||||
.replace(IMAGE_HTML_RE, '')
|
||||
.replace(/\n{3,}/g, '\n\n')
|
||||
.trim()
|
||||
}
|
||||
|
||||
function quoteMeta(value = '') {
|
||||
@@ -102,7 +110,7 @@ export function buildDocBlockValue(attrs = {}) {
|
||||
}
|
||||
|
||||
export function parseDocBlockValue(raw = '') {
|
||||
const normalized = String(raw || '').replace(/\r\n?/g, '\n')
|
||||
const normalized = normalizeMarkdownText(raw)
|
||||
const separatorIndex = normalized.indexOf(HEADER_SEPARATOR)
|
||||
const headerText = separatorIndex >= 0 ? normalized.slice(0, separatorIndex) : ''
|
||||
const bodyText = separatorIndex >= 0 ? normalized.slice(separatorIndex + HEADER_SEPARATOR.length) : normalized
|
||||
@@ -150,7 +158,8 @@ export function buildLegacyDocBlock(attrs = {}) {
|
||||
}
|
||||
|
||||
export function parseLegacyDocBlock(raw = '') {
|
||||
const match = String(raw || '').match(/^<doc_type="([^"]+)"\s+doc_name="([^"]+)"\s+upload_time="([^"]+)"(?:\s+collapsed="([^"]+)")?>\n?([\s\S]*?)\n?<\/doc_end>$/)
|
||||
const normalized = normalizeMarkdownText(raw)
|
||||
const match = normalized.match(/^<doc_type="([^"]+)"\s+doc_name="([^"]+)"\s+upload_time="([^"]+)"(?:\s+collapsed="([^"]+)")?>\n?([\s\S]*?)\n?<\/doc_end>$/)
|
||||
if (!match) return null
|
||||
return {
|
||||
docType: normalizeDocType(match[1]),
|
||||
@@ -161,33 +170,57 @@ export function parseLegacyDocBlock(raw = '') {
|
||||
}
|
||||
}
|
||||
|
||||
export function extractDocBlockContextFromMarkdown(markdown = '', contentLimit = 0) {
|
||||
const normalized = normalizeMarkdownText(markdown)
|
||||
const contexts = []
|
||||
const appendContext = (attrs) => {
|
||||
if (!attrs) return
|
||||
const rawContent = String(attrs.content || '')
|
||||
if (!rawContent.trim()) return
|
||||
contexts.push(buildDocContextFence({
|
||||
docType: attrs.docType,
|
||||
content: clipDocContext(rawContent, contentLimit),
|
||||
}))
|
||||
}
|
||||
|
||||
normalized.replace(FENCED_DOC_BLOCK_RE, (_full, _prefix, _fence, value) => {
|
||||
appendContext(parseDocBlockValue(value))
|
||||
return _full
|
||||
})
|
||||
|
||||
normalized.replace(LEGACY_DOC_BLOCK_RE, (full) => {
|
||||
appendContext(parseLegacyDocBlock(full))
|
||||
return full
|
||||
})
|
||||
|
||||
return contexts.join('\n\n')
|
||||
}
|
||||
|
||||
export function transformDocBlockMarkdownForClipboard(markdown = '') {
|
||||
const pattern = /(^|\n)(`{3,})llm-file[^\n]*\n([\s\S]*?)\n\2(?=\n|$)/g
|
||||
const replacedFence = String(markdown || '').replace(pattern, (full, prefix, _fence, value) => {
|
||||
const normalized = normalizeMarkdownText(markdown)
|
||||
const replacedFence = normalized.replace(FENCED_DOC_BLOCK_RE, (full, prefix, _fence, value) => {
|
||||
const attrs = parseDocBlockValue(value)
|
||||
return `${prefix}${buildDocContextFence(attrs)}`
|
||||
})
|
||||
return replacedFence.replace(/<doc_type="[^"]+"\s+doc_name="[^"]+"\s+upload_time="[^"]+"(?:\s+collapsed="[^"]+")?>[\s\S]*?<\/doc_end>/g, (full) => {
|
||||
return replacedFence.replace(LEGACY_DOC_BLOCK_RE, (full) => {
|
||||
const attrs = parseLegacyDocBlock(full)
|
||||
return attrs ? buildDocContextFence(attrs) : full
|
||||
})
|
||||
}
|
||||
|
||||
export function stripDocBlockMarkdown(markdown = '') {
|
||||
const pattern = /(^|\n)(`{3,})llm-file[^\n]*\n[\s\S]*?\n\2(?=\n|$)/g
|
||||
return String(markdown || '').replace(pattern, '$1').replace(/\n{3,}/g, '\n\n').trim()
|
||||
return normalizeMarkdownText(markdown).replace(FENCED_DOC_BLOCK_RE, '$1')
|
||||
}
|
||||
|
||||
export function transformLegacyDocBlocksForExport(markdown = '') {
|
||||
return String(markdown || '').replace(/<doc_type="[^"]+"\s+doc_name="[^"]+"\s+upload_time="[^"]+"(?:\s+collapsed="[^"]+")?>[\s\S]*?<\/doc_end>/g, (full) => {
|
||||
return normalizeMarkdownText(markdown).replace(LEGACY_DOC_BLOCK_RE, (full) => {
|
||||
const attrs = parseLegacyDocBlock(full)
|
||||
return attrs ? buildDocBlockMarkdown(attrs) : full
|
||||
})
|
||||
}
|
||||
|
||||
export function transformSpecialDocBlocksToLegacy(markdown = '') {
|
||||
const pattern = /(^|\n)(`{3,})llm-file[^\n]*\n([\s\S]*?)\n\2(?=\n|$)/g
|
||||
return String(markdown || '').replace(pattern, (full, prefix, _fence, value) => {
|
||||
return normalizeMarkdownText(markdown).replace(FENCED_DOC_BLOCK_RE, (full, prefix, _fence, value) => {
|
||||
const attrs = parseDocBlockValue(value)
|
||||
return `${prefix}${buildLegacyDocBlock(attrs)}`
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user