Parse API
String Parsing
parse(source: string): ParseResult
Parses MDC content from a string and returns the complete parsed structure.
Parameters:
source- The markdown/MDC content as a string
Returns: ParseResult object containing:
body- The parsed MDC AST rootexcerpt?- Optional excerpt (content before<!-- more -->comment)data- Frontmatter data parsed from YAMLtoc?- Table of contents
Example:
import { parse } from 'mdc-syntax'
const content = `---
title: Hello World
description: A simple example
---
# Hello World
This is a **markdown** document with *MDC* components.
::alert{type="info"}
This is an alert component
::
`
const result = parse(content)
console.log(result.body) // MDC AST
console.log(result.data) // { title: 'Hello World', description: 'A simple example' }
console.log(result.toc) // Table of contents
Stream Parsing
parseStream(stream: Readable | ReadableStream<Uint8Array>): Promise<ParseResult>
Asynchronously parses MDC content from a Node.js Readable stream or Web ReadableStream. The function waits for the entire stream to complete before parsing.
Parameters:
stream- A Node.js Readable stream or Web ReadableStream containing MDC content
Returns: Promise resolving to ParseResult
Example with Node.js stream:
import { createReadStream } from 'node:fs'
import { parseStream } from 'mdc-syntax/stream'
const stream = createReadStream('content.md')
const result = await parseStream(stream)
console.log(result.body)
console.log(result.data)
console.log(result.toc)
Example with Web stream (Fetch API):
import { parseStream } from 'mdc-syntax/stream'
const response = await fetch('https://example.com/content.md')
const result = await parseStream(response.body!)
console.log(result.body)
parseStreamIncremental(stream: Readable | ReadableStream<Uint8Array>): AsyncGenerator<IncrementalParseResult>
Parses MDC content incrementally as chunks arrive from the stream. This is ideal for real-time UI updates during streaming.
Features:
- Yields results after each chunk is received
- Automatically applies auto-close to handle incomplete syntax
- Provides progress tracking through chunk information
- Final result includes complete TOC
Parameters:
stream- A Node.js Readable stream or Web ReadableStream
Yields: IncrementalParseResult for each chunk:
chunk- The chunk that was just processed (string)content- The accumulated content (string)body- Current state of the parsed MDC ASTdata- Frontmatter data (available once parsed)isComplete- Boolean indicating if stream is completeexcerpt?- Optional excerpttoc?- Table of contents (only in final result whenisComplete: true)
Example:
import { parseStreamIncremental } from 'mdc-syntax/stream'
const response = await fetch('https://example.com/article.md')
for await (const result of parseStreamIncremental(response.body!)) {
if (!result.isComplete) {
// Update UI as chunks arrive
console.log(`Received chunk: ${result.chunk.length} bytes`)
console.log(`Current elements: ${result.body.value.length}`)
renderPartialContent(result.body)
}
else {
// Final result with complete TOC
console.log('Stream complete!')
console.log('TOC:', result.toc)
renderFinalContent(result.body)
}
}
Example with progress tracking:
import { parseStreamIncremental } from 'mdc-syntax/stream'
let totalBytes = 0
let chunkCount = 0
for await (const result of parseStreamIncremental(stream)) {
if (!result.isComplete) {
totalBytes += result.chunk.length
chunkCount++
console.log(`Progress: ${chunkCount} chunks, ${totalBytes} bytes`)
console.log(`Parsed ${result.body.value.length} elements so far`)
}
}
Types
ParseResult
interface ParseResult {
body: MinimarkTree // The parsed MDC AST
excerpt?: MinimarkTree // Optional excerpt (content before <!-- more -->)
data: any // Frontmatter data
toc?: any // Table of contents
}
IncrementalParseResult
interface IncrementalParseResult {
chunk: string // The chunk just received
content: string // The accumulated content
body: MinimarkTree // Current parsed state
data: any // Frontmatter data (once available)
isComplete: boolean // Whether stream is finished
excerpt?: MinimarkTree // Optional excerpt
toc?: any // TOC (only in final result)
}
MinimarkTree
interface MinimarkTree {
type: 'minimark'
value: MinimarkNode[]
}
MinimarkNode
type MinimarkNode = MinimarkElement | MinimarkText | MinimarkComment
interface MinimarkElement {
type: 'element'
tag: string
props: Record<string, any>
children: MinimarkNode[]
}
interface MinimarkText {
type: 'text'
value: string
}
interface MinimarkComment {
type: 'comment'
value: string
}
Processing Multiple Files
import { createReadStream } from 'node:fs'
import { readdir } from 'node:fs/promises'
import { join } from 'node:path'
import { parseStream } from 'mdc-syntax/stream'
async function processMarkdownDirectory(dir: string) {
const files = await readdir(dir)
const mdFiles = files.filter(f => f.endsWith('.md'))
const results = await Promise.all(
mdFiles.map(async (file) => {
const stream = createReadStream(join(dir, file))
const result = await parseStream(stream)
return { file, result }
})
)
return results
}
// Usage
const results = await processMarkdownDirectory('./content')
console.log(`Processed ${results.length} files`)
Chunked Stream Processing
import { Readable } from 'node:stream'
import { parseStream } from 'mdc-syntax/stream'
// Create a stream from chunks
const chunks = [
'# Hello World\n\n',
'This is some content.\n\n',
'::alert{type="info"}\n',
'Important message\n',
'::\n'
]
const stream = Readable.from(chunks)
const result = await parseStream(stream)
console.log(result.body)
Frontmatter Parsing
The parse functions automatically extract and parse YAML frontmatter:
const content = `---
title: My Document
tags:
- javascript
- markdown
author:
name: John Doe
email: john@example.com
---
# Content here
`
const result = parse(content)
console.log(result.data)
// {
// title: 'My Document',
// tags: ['javascript', 'markdown'],
// author: { name: 'John Doe', email: 'john@example.com' }
// }
Table of Contents
The parse functions automatically generate a table of contents based on headings:
const content = `# Main Title
## Section 1
Some content here.
### Subsection 1.1
More content.
## Section 2
Final content.
`
const result = parse(content)
console.log(result.toc)
// {
// title: 'Main Title',
// depth: 2,
// searchDepth: 2,
// links: [
// { id: 'section-1', text: 'Section 1', depth: 2, children: [
// { id: 'subsection-11', text: 'Subsection 1.1', depth: 3 }
// ]},
// { id: 'section-2', text: 'Section 2', depth: 2 }
// ]
// }
Excerpt Extraction
Content before the <!-- more --> comment is automatically extracted as an excerpt:
const content = `# Article Title
This is the introduction paragraph that will be used as an excerpt.
<!-- more -->
This is the full article content that won't appear in the excerpt.
`
const result = parse(content)
console.log(result.excerpt)
// MinimarkTree with only the content before <!-- more -->
Error Handling
import { parseStream } from 'mdc-syntax/stream'
try {
const stream = createReadStream('content.md')
const result = await parseStream(stream)
console.log('Parsed successfully:', result.body)
}
catch (error) {
console.error('Parse error:', error)
}
Performance Tips
- Use streaming for large files: For files larger than 1MB, use
parseStreaminstead of reading the entire file into memory first. - Use incremental parsing for real-time updates: When you need to update the UI during streaming (e.g., AI-generated content), use
parseStreamIncremental. - Batch process multiple files: Use
Promise.all()to parse multiple files in parallel. - Cache parsed results: If parsing the same content multiple times, cache the
ParseResultto avoid redundant parsing.
// Good: Stream large files
const result = await parseStream(createReadStream('large-file.md'))
// Avoid: Loading entire large file into memory
const content = await readFile('large-file.md', 'utf-8') // Don't do this for large files
const result = parse(content)
See Also
- Auto-Close API - Handling incomplete syntax
- API Reference - Quick reference for all exports
- Vue Renderer - Rendering parsed content in Vue
- React Renderer - Rendering parsed content in React