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:
suyao 2025-10-29 07:54:56 +08:00
parent ef7e8a7201
commit cfb9ee7df3
No known key found for this signature in database
2 changed files with 12 additions and 223 deletions

View File

@ -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
},

View File

@ -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