mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-21 16:01:35 +08:00
Remove verbose logging and simplify YAML front matter handling
- Eliminate logger imports and debug statements throughout YAML front matter extension - Streamline markdown tokenizer to match YAML front matter with optional leading whitespace - Simplify parseMarkdown and renderMarkdown logic using helper methods - Remove custom YAML front matter plugin from markdown converter as it's now handled by TipTap extension
This commit is contained in:
parent
ef7e8a7201
commit
cfb9ee7df3
@ -1,11 +1,8 @@
|
||||
import { loggerService } from '@logger'
|
||||
import { mergeAttributes, Node } from '@tiptap/core'
|
||||
import { ReactNodeViewRenderer } from '@tiptap/react'
|
||||
|
||||
import YamlFrontMatterNodeView from '../components/YamlFrontMatterNodeView'
|
||||
|
||||
const logger = loggerService.withContext('YamlFrontMatterExtension')
|
||||
|
||||
declare module '@tiptap/core' {
|
||||
interface Commands<ReturnType> {
|
||||
yamlFrontMatter: {
|
||||
@ -24,30 +21,17 @@ export const YamlFrontMatter = Node.create({
|
||||
markdownTokenizer: {
|
||||
name: 'yamlFrontMatter',
|
||||
level: 'block',
|
||||
// Optimization: check if content starts with ---
|
||||
start(src: string) {
|
||||
logger.info('🔍 Tokenizer start() called', {
|
||||
srcLength: src.length,
|
||||
srcPrefix: src.substring(0, 60).replace(/\n/g, '\\n'),
|
||||
startsWithDashes: src.startsWith('---\n')
|
||||
})
|
||||
|
||||
const result = src.match(/^---\n/) ? 0 : -1
|
||||
logger.info('✅ Tokenizer start() result:', { result })
|
||||
start(src: string) {
|
||||
const result = src.match(/^\s*---\n/) ? 0 : -1
|
||||
return result
|
||||
},
|
||||
// Parse YAML front matter
|
||||
tokenize(src: string) {
|
||||
logger.info('🔍 Tokenizer tokenize() called', {
|
||||
srcLength: src.length,
|
||||
srcPrefix: src.substring(0, 120).replace(/\n/g, '\\n')
|
||||
})
|
||||
|
||||
// Match: ---\n...yaml content...\n---
|
||||
const match = /^---\n([\s\S]*?)\n---(?:\n|$)/.exec(src)
|
||||
|
||||
if (!match) {
|
||||
logger.warn('❌ Tokenizer tokenize() - NO MATCH FOUND')
|
||||
return undefined
|
||||
}
|
||||
|
||||
@ -56,74 +40,37 @@ export const YamlFrontMatter = Node.create({
|
||||
raw: match[0],
|
||||
text: match[1] // YAML content without delimiters
|
||||
}
|
||||
|
||||
logger.info('✅ Tokenizer tokenize() - MATCH FOUND', {
|
||||
rawLength: token.raw.length,
|
||||
textLength: token.text.length,
|
||||
textPreview: token.text.substring(0, 100).replace(/\n/g, '\\n')
|
||||
})
|
||||
|
||||
return token
|
||||
}
|
||||
},
|
||||
|
||||
// Parse markdown token to Tiptap JSON
|
||||
parseMarkdown(token, helpers) {
|
||||
logger.info('🔍 parseMarkdown() called', {
|
||||
tokenType: token.type,
|
||||
hasText: !!token.text,
|
||||
textLength: token.text?.length || 0,
|
||||
textPreview: token.text?.substring(0, 100).replace(/\n/g, '\\n'),
|
||||
hasTokens: !!token.tokens,
|
||||
tokensLength: token.tokens?.length || 0
|
||||
})
|
||||
|
||||
// Since this is an atom node, we don't need child content
|
||||
const result = {
|
||||
type: 'yamlFrontMatter', // Use explicit node name instead of this.name
|
||||
attrs: {
|
||||
const attrs = {
|
||||
content: token.text || ''
|
||||
}
|
||||
}
|
||||
|
||||
logger.info('✅ parseMarkdown() result', {
|
||||
type: result.type,
|
||||
contentLength: result.attrs.content.length
|
||||
})
|
||||
|
||||
return result
|
||||
return helpers.createNode('yamlFrontMatter', attrs)
|
||||
},
|
||||
|
||||
// Serialize Tiptap node to markdown
|
||||
renderMarkdown(node) {
|
||||
logger.info('🔍 renderMarkdown() called', {
|
||||
nodeType: node.type,
|
||||
hasContent: !!node.attrs?.content,
|
||||
contentLength: node.attrs?.content?.length || 0,
|
||||
contentPreview: node.attrs?.content?.substring(0, 100).replace(/\n/g, '\\n')
|
||||
})
|
||||
|
||||
const content = node.attrs?.content || ''
|
||||
if (!content.trim()) {
|
||||
logger.info('⚠️ renderMarkdown() - empty content, returning empty string')
|
||||
return ''
|
||||
}
|
||||
|
||||
const trimmedContent = content.trim()
|
||||
let result = ''
|
||||
|
||||
// Ensure proper format with closing ---
|
||||
if (trimmedContent.endsWith('---')) {
|
||||
result = trimmedContent + '\n\n'
|
||||
// Ensure proper format with opening and closing ---
|
||||
// The content is stored without the --- delimiters, so we need to add them back
|
||||
if (content.endsWith('---')) {
|
||||
// Content already has closing ---, just add opening
|
||||
result = '---\n' + content + '\n\n'
|
||||
} else {
|
||||
result = trimmedContent + '\n---\n\n'
|
||||
// Add both opening and closing ---
|
||||
result = '---\n' + content + '\n---\n\n'
|
||||
}
|
||||
|
||||
logger.info('✅ renderMarkdown() result', {
|
||||
resultLength: result.length,
|
||||
resultPreview: result.substring(0, 120).replace(/\n/g, '\\n')
|
||||
})
|
||||
|
||||
return result
|
||||
},
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { loggerService } from '@logger'
|
||||
import { MARKDOWN_SOURCE_LINE_ATTR } from '@renderer/components/RichEditor/constants'
|
||||
import he from 'he'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import TurndownService from 'turndown'
|
||||
|
||||
@ -58,141 +57,6 @@ defaultBlockRules.forEach((ruleName) => {
|
||||
}
|
||||
})
|
||||
|
||||
// Override the code_block and code_inline renderers to properly escape HTML entities
|
||||
md.renderer.rules.code_block = function (tokens, idx) {
|
||||
const token = tokens[idx]
|
||||
const langName = token.info ? ` class="language-${token.info.trim()}"` : ''
|
||||
const escapedContent = he.encode(token.content, { useNamedReferences: false })
|
||||
let html = `<pre><code${langName}>${escapedContent}</code></pre>`
|
||||
html = injectLineNumber(token, html)
|
||||
return html
|
||||
}
|
||||
|
||||
md.renderer.rules.code_inline = function (tokens, idx) {
|
||||
const token = tokens[idx]
|
||||
const escapedContent = he.encode(token.content, { useNamedReferences: false })
|
||||
return `<code>${escapedContent}</code>`
|
||||
}
|
||||
|
||||
md.renderer.rules.fence = function (tokens, idx) {
|
||||
const token = tokens[idx]
|
||||
const langName = token.info ? ` class="language-${token.info.trim()}"` : ''
|
||||
const escapedContent = he.encode(token.content, { useNamedReferences: false })
|
||||
let html = `<pre><code${langName}>${escapedContent}</code></pre>`
|
||||
html = injectLineNumber(token, html)
|
||||
return html
|
||||
}
|
||||
|
||||
interface TokenLike {
|
||||
content: string
|
||||
block?: boolean
|
||||
map?: [number, number]
|
||||
}
|
||||
|
||||
interface BlockStateLike {
|
||||
src: string
|
||||
bMarks: number[]
|
||||
eMarks: number[]
|
||||
tShift: number[]
|
||||
line: number
|
||||
parentType: string
|
||||
blkIndent: number
|
||||
push: (type: string, tag: string, nesting: number) => TokenLike
|
||||
}
|
||||
|
||||
interface InlineStateLike {
|
||||
src: string
|
||||
pos: number
|
||||
posMax: number
|
||||
push: (type: string, tag: string, nesting: number) => TokenLike & { content?: string }
|
||||
}
|
||||
|
||||
function yamlFrontMatterPlugin(md: MarkdownIt) {
|
||||
// Parser: recognize YAML front matter
|
||||
md.block.ruler.before(
|
||||
'table',
|
||||
'yaml_front_matter',
|
||||
(stateLike: unknown, startLine: number, endLine: number, silent: boolean): boolean => {
|
||||
const state = stateLike as BlockStateLike
|
||||
|
||||
// Only check at the very beginning of the document
|
||||
if (startLine !== 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
const startPos = state.bMarks[startLine] + state.tShift[startLine]
|
||||
const maxPos = state.eMarks[startLine]
|
||||
|
||||
// Must begin with --- at document start
|
||||
if (startPos + 3 > maxPos) return false
|
||||
if (
|
||||
state.src.charCodeAt(startPos) !== 0x2d /* - */ ||
|
||||
state.src.charCodeAt(startPos + 1) !== 0x2d /* - */ ||
|
||||
state.src.charCodeAt(startPos + 2) !== 0x2d /* - */
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
// If requested only to validate existence
|
||||
if (silent) return true
|
||||
|
||||
// Search for closing ---
|
||||
let nextLine = startLine + 1
|
||||
let found = false
|
||||
|
||||
for (nextLine = startLine + 1; nextLine < endLine; nextLine++) {
|
||||
const lineStart = state.bMarks[nextLine] + state.tShift[nextLine]
|
||||
const lineEnd = state.eMarks[nextLine]
|
||||
const line = state.src.slice(lineStart, lineEnd).trim()
|
||||
|
||||
if (line === '---') {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Extract YAML content between the --- delimiters, preserving original indentation
|
||||
const yamlLines: string[] = []
|
||||
for (let lineIdx = startLine + 1; lineIdx < nextLine; lineIdx++) {
|
||||
// Use the original line markers without shift to preserve indentation
|
||||
const lineStart = state.bMarks[lineIdx]
|
||||
const lineEnd = state.eMarks[lineIdx]
|
||||
yamlLines.push(state.src.slice(lineStart, lineEnd))
|
||||
}
|
||||
|
||||
// Also capture the closing --- line with its indentation
|
||||
const closingLineStart = state.bMarks[nextLine]
|
||||
const closingLineEnd = state.eMarks[nextLine]
|
||||
const closingLine = state.src.slice(closingLineStart, closingLineEnd)
|
||||
|
||||
const yamlContent = yamlLines.join('\n') + '\n' + closingLine
|
||||
|
||||
const token = state.push('yaml_front_matter', 'div', 0)
|
||||
token.block = true
|
||||
token.map = [startLine, nextLine + 1]
|
||||
token.content = yamlContent
|
||||
|
||||
state.line = nextLine + 1
|
||||
return true
|
||||
}
|
||||
)
|
||||
|
||||
// Renderer: output YAML front matter as special HTML element
|
||||
md.renderer.rules.yaml_front_matter = (tokens: Array<{ content?: string }>, idx: number): string => {
|
||||
const token = tokens[idx]
|
||||
const content = token?.content ?? ''
|
||||
let html = `<div data-type="yaml-front-matter" data-content="${he.encode(content)}">${content}</div>`
|
||||
html = injectLineNumber(token, html)
|
||||
return html
|
||||
}
|
||||
}
|
||||
|
||||
md.use(yamlFrontMatterPlugin)
|
||||
|
||||
// Initialize turndown service
|
||||
const turndownService = new TurndownService({
|
||||
headingStyle: 'atx', // Use # for headings
|
||||
@ -204,28 +68,6 @@ const turndownService = new TurndownService({
|
||||
strongDelimiter: '**' // Use ** for strong
|
||||
})
|
||||
|
||||
// Custom rule to preserve YAML front matter
|
||||
turndownService.addRule('yamlFrontMatter', {
|
||||
filter: (node: Element) => {
|
||||
return node.nodeName === 'DIV' && node.getAttribute?.('data-type') === 'yaml-front-matter'
|
||||
},
|
||||
replacement: (_content: string, node: Node) => {
|
||||
const element = node as Element
|
||||
const yamlContent = element.getAttribute?.('data-content') || ''
|
||||
const decodedContent = he.decode(yamlContent, {
|
||||
isAttributeValue: false,
|
||||
strict: false
|
||||
})
|
||||
// The decodedContent already includes the complete YAML with closing ---
|
||||
// We just need to add the opening --- if it's not there
|
||||
if (decodedContent.startsWith('---')) {
|
||||
return decodedContent
|
||||
} else {
|
||||
return `---\n${decodedContent}`
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Gets plain text preview from Markdown content
|
||||
* @param markdown - Markdown string
|
||||
|
||||
Loading…
Reference in New Issue
Block a user