Comark (Components in Markdown) parser: syntax, AST, Vue/React/Svelte/Angular renderers, plugins, and LLM streaming with auto-close.
57
67%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./skills/comark/SKILL.mdA high-performance markdown parser with Comark (Components in Markdown) support, built on markdown-it, offering both string-based and streaming APIs.
Comark extends standard markdown with a powerful component system while maintaining full compatibility with CommonMark and GitHub Flavored Markdown. It provides:
comarknpm install comark or pnpm add comarkcomark@comark/vue@comark/react@comark/svelte@comark/angular@comark/html@comark/ansi@comark/nuxtimport { parseMarkdown } from 'comark'
const content = `---
title: Hello World
---
# Hello World
This is **markdown** with :icon component.
::alert{type="info"}
Important message
::
`
const result = await parseMarkdown(content)
console.log(result.nodes) // Markdown AST
console.log(result.frontmatter) // { title: 'Hello World' }
console.log(result.meta) // Additional metadata<template>
<Markdown :value="content" />
</template>
<script setup lang="ts">
import { Markdown } from '@comark/vue'
const content = `# Hello World`
</script>import { Markdown } from '@comark/react'
export default function App() {
return <Markdown value={content} />
}<script lang="ts">
import { Markdown } from '@comark/svelte'
const content = `# Hello World`
</script>
<Markdown value={content} />import { Component } from '@angular/core'
import { Markdown } from '@comark/angular'
@Component({
selector: 'app-root',
standalone: true,
imports: [Markdown],
template: `<comark-markdown [value]="content" />`,
})
export class AppComponent {
content = `# Hello World`
}This guide is organized into focused sections covering different aspects of the package:
Learn how to write Comark documents with complete syntax reference:
::component), inline components (:component), properties, slots, nesting{...} syntax[x] and [ ] syntax→ Read Full Markdown Syntax Guide
Complete guide for parsing and working with MarkdownDocument:
parseMarkdown() function with options (autoUnwrap, autoClose)parseMarkdown() with Shiki syntax highlightingMarkdownDocument with compact array-based nodesrenderHtmlFromDocument via @comark/html) or markdown (renderMarkdown via comark/render)→ Read Full Parsing & Document Model Guide
Comprehensive guide for rendering in Vue applications:
Markdown component setupcomponentsManifest for lazy-loaded components#slot-name syntax__node and parsed properties→ Read Full Vue Rendering Guide
Comprehensive guide for rendering in React applications:
Markdown component setupcomponentsManifest for lazy-loaded componentsclass → className, etc.)__node→ Read Full React Rendering Guide
Comprehensive guide for rendering in Svelte 5 applications:
Markdown component setup with $statecomponentsManifest for lazy-loaded components$stateMarkdownAsync with <svelte:boundary>Prose prefix for overriding native HTML elements→ Read Full Svelte Rendering Guide
Comprehensive guide for rendering in Angular 17+ applications:
Markdown standalone component setupProse{PascalTag}, PascalTag, tag priority order<ng-content select="[slot=name]">:binding resolution with ambient data inputdefineMarkdownComponent and defineMarkdownDocumentComponent→ Read Full Angular Rendering Guide
Guide for integrating Comark in AI agent and LLM streaming workflows:
Comark extends markdown with custom components while preserving readability:
<!-- Block Component -->
::alert{type="warning" .important}
This is a **warning** message with markdown support.
::
<!-- Inline Component -->
Check out this :icon-star{.text-yellow} component.
<!-- Component with Slots -->
::card
#header
## Title
#content
Main content
#footer
Footer
::Lightweight array-based structure for efficient processing:
interface MarkdownDocument {
nodes: [
["h1", { "id": "hello" }, "Hello"],
["p", {}, "Text with ", ["strong", {}, "bold"], " word"],
["alert", { "type": "info" }, "Message"]
],
frontmatter: {},
meta: {}
}import { parseMarkdown } from 'comark'
import { renderHtmlFromDocument } from '@comark/html'
import shiki from '@comark/html/plugins/shiki'
async function processMarkdownFile(filePath: string) {
const content = await readFile(filePath, 'utf-8')
const doc = await parseMarkdown(content, {
plugins: [
shiki({
themes: { light: 'github-dark', dark: 'github-dark' },
}),
],
})
return {
html: await renderHtmlFromDocument(doc),
frontmatter: doc.frontmatter,
toc: doc.meta.toc
}
}import { useState } from 'react'
import { Markdown } from '@comark/react'
export default function Editor() {
const [content, setContent] = useState('# Hello')
return (
<div className="split-editor">
<textarea value={content} onChange={e => setContent(e.target.value)} />
<Markdown value={content} />
</div>
)
}import { readFile } from 'node:fs/promises'
import { parseMarkdown } from 'comark'
async function processMultipleFiles(files: string[]) {
const results = await Promise.all(
files.map(async (file) => {
const content = await readFile(file, 'utf-8')
return await parseMarkdown(content)
})
)
results.forEach((result, i) => {
console.log(`File ${files[i]}:`)
console.log(` - ${result.nodes.length} nodes`)
})
}<template>
<article class="prose">
<Markdown :value="markdownContent" :components="docComponents" />
</article>
</template>
<script setup lang="ts">
import { Markdown } from '@comark/vue'
import { docComponents } from './components'
</script>comark)// Asynchronous parsing
parseMarkdown(source: string, options?: ParserOptions): Promise<MarkdownDocument>
// Auto-close unclosed syntax
autoCloseMarkdown(source: string): string@comark/html)// Render markdown to HTML string (parse + render in one step)
renderHtml(markdown: string, options?: ParserOptions & RendererOptions): Promise<string>
// Render a pre-parsed document to HTML
renderHtmlFromDocument(document: MarkdownDocument, options?: RendererOptions): Promise<string>
// Create a reusable render function with shared parser instance
createHtmlRenderer(options?: ParserOptions & RendererOptions): (markdown: string) => Promise<string>@comark/vue)<Markdown :value="markdownString" :components="customComponents" />@comark/react)<Markdown value={markdownString} components={customComponents} />@comark/svelte)<Markdown value={markdownString} components={customComponents} />@comark/angular)<comark-markdown [value]="markdownString" [components]="customComponents" />Full TypeScript definitions included:
import type {
MarkdownDocument,
Node,
ParserOptions,
} from 'comark'┌─────────────────────────────────────────┐
│ Markdown Input (String) │
└────────────────┬────────────────────────┘
│
┌────────▼────────┐
│ Auto-close │ (Optional)
│ Unclosed │
│ Syntax │
└────────┬────────┘
│
┌────────▼────────┐
│ Parse │
│ Frontmatter │ (YAML)
└────────┬────────┘
│
┌────────▼────────┐
│ MarkdownIt │
│ + Plugins │ (Comark, Tasks)
└────────┬────────┘
│
┌────────▼────────┐
│ Token │
│ Processing │
└────────┬────────┘
│
┌────────▼────────┐
│ Comark │
│ AST │
└────────┬────────┘
│
┌────────▼────────┐
│ Auto-unwrap │ (Optional)
└────────┬────────┘
│
┌────────▼────────┐
│ Generate TOC │
└────────┬────────┘
│
┌────────▼────────┐
│ MarkdownDocument │
│ (nodes + data │
│ + meta) │
└────────┬────────┘
│
┌───────────┬──────┴──────┬───────────┐
▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Vue │ │ React │ │ Svelte │ │ Angular │
│ Renderer│ │ Renderer│ │ Renderer│ │ Renderer│
└─────────┘ └─────────┘ └─────────┘ └─────────┘See the test specifications for examples of all supported syntax features.
Run tests:
pnpm testRun specific test:
pnpm test -- tests/parse.test.tsComark is a comprehensive solution for parsing and rendering markdown with component support. It excels at:
MarkdownDocument model with compact nodesChoose Comark when you need:
Next Steps:
bc438e5
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.