Custom

Plugin API

Type-safe API for creating Comark plugins with pre/post lifecycle hooks.

The comark/parse module exports defineComarkPlugin — a typed factory wrapper for building plugins that extend the parser.

defineComarkPlugin(factory)

Wraps a plugin factory function to provide type safety for both options and the returned plugin.

Parameters:

  • factory - A function (options?: O) => ComarkPlugin where O is an optional options type. When the plugin is instantiated, options receives the values passed by the caller. See ComarkPlugin for the full shape of the returned object.

Returns: A typed plugin factory (options?: O) => ComarkPlugin

Example:

import { defineComarkPlugin } from 'comark/parse'

export default defineComarkPlugin(() => ({
  name: 'my-plugin',
  pre(state) {},
  post(state) {},
}))

With typed options:

import { defineComarkPlugin } from 'comark/parse'

interface MyOptions {
  prefix?: string
}

export default defineComarkPlugin((options: MyOptions = {}) => ({
  name: 'my-plugin',
  post(state) {
    // options.prefix is typed
  },
}))

Lifecycle

Plugins hook into two phases of the parsing pipeline:

Markdown string


┌──────────┐
│   pre()  │  ← Modify raw markdown before parsing
└──────────┘


  Parse & Build ComarkTree


┌──────────┐
│  post()  │  ← Transform the AST after parsing
└──────────┘


  ComarkTree

pre(state)

Called before markdown is tokenized. Use it to transform the raw markdown string.

import { defineComarkPlugin } from 'comark/parse'

export default defineComarkPlugin(() => ({
  name: 'strip-comments',
  pre(state) {
    state.markdown = state.markdown.replace(/<!--[\s\S]*?-->/g, '')
  },
}))

ComarkParsePreState:

FieldTypeDescription
markdownstringThe raw markdown — modify to change parser input
optionsParseOptionsThe parser configuration

post(state)

Called after the AST is built. Use it to traverse nodes or populate meta with extracted data.

import { defineComarkPlugin } from 'comark/parse'
import { visit } from 'comark/utils'

export default defineComarkPlugin(() => ({
  name: 'word-count',
  post(state) {
    let count = 0
    visit(state.tree,
      (node) => typeof node === 'string',
      (node) => { count += (node as string).split(/\s+/).filter(Boolean).length }
    )
    state.tree.meta.wordCount = count
  },
}))

ComarkParsePostState:

FieldTypeDescription
markdownstringThe original markdown input
treeComarkTreeThe parsed AST — modify to transform output
optionsParseOptionsThe parser configuration
tokensunknown[]The raw markdown-it tokens
To traverse and transform tree nodes, see the AST API page for the visit() utility.

ComarkPlugin

PropertyTypeDescription
namestringA unique identifier for the plugin
markdownItPluginsMarkdownItPlugin[]markdown-it plugins to register on the parser — see Markdown-it Plugins
pre(state: ComarkParsePreState) => voidHook called before parsing
post(state: ComarkParsePostState) => voidHook called after the AST is built

Usage

Pass plugins to parse() or the <Comark> component:

import { parse } from 'comark'
import myPlugin from './my-plugin'

const tree = await parse(content, {
  plugins: [myPlugin()]
})