Skip to content
Content
Skill

/migrate-mdc-to-comark

Port a legacy MDC-based PR onto the new comark-based `main`. Use when a contributor's PR was opened against the old `@nuxtjs/mdc` API (any commit before `feat(mdc): comark migration #355`) and now needs to be rebased / merged with the current Nuxt Studio main branch, which uses

From plugin
nuxt-studio
7422 skills

Claude Code

$ npx -y skills add nuxt-content/nuxt-studio --skill migrate-mdc-to-comark --agent claude-code

SKILL.md

migrate-mdc-to-comark.SKILL.md
name: migrate-mdc-to-comark
description: Port a legacy MDC-based PR onto the new comark-based `main`. Use when a contributor's PR was opened against the old `@nuxtjs/mdc` API (any commit before `feat(mdc): comark migration #355`) and now needs to be rebased / merged with the current Nuxt Studio main branch, which uses `comark` everywhere.
allowed-tools: Read, Write, Edit, Glob, Grep, Bash

Migrating a Legacy MDC PR to Comark

Since commit `5464103e feat(mdc): comark migration (#355)` (merged 2026-05-13), Nuxt Studio's `main` branch no longer uses `@nuxtjs/mdc`. The entire conversion layer, document utilities, and TipTap bridges were rewritten on top of [`comark`](https://github.com/nuxt-content/comark).

Any PR opened against `main` **before** this commit will conflict on merge. Do **not** simply resolve the conflicts mechanically — most legacy API calls have semantic equivalents in comark that must be re-implemented.

This skill is the reverse of the previous "merge-main-on-comark" skill: the comark branch is now `main`, and legacy PRs need to be ported forward.

1. Identify whether the PR is legacy

Run these checks at the root of the PR branch:

# Legacy imports — any match means the PR predates the comark migration
grep -rE "from '@nuxtjs/mdc'|from 'remark-mdc'|from 'unist-util-visit'|from '@nuxt/content/runtime'" src/

# Legacy function names
grep -rE "generateDocumentFromContent|generateDocumentFromMarkdownContent|generateDocumentFromYAMLContent|generateDocumentFromJSONContent|generateContentFromDocument|generateContentFromMarkdownDocument|generateContentFromYAMLDocument|generateContentFromJSONDocument|mdcToTiptap|tiptapToMDC|compressTree|decompressTree|parseMarkdown|stringifyMarkdown|parseFrontMatter|stringifyFrontMatter|remarkEmojiPlugin" src/

# Legacy file references (these files were deleted on main)
ls src/app/src/utils/tiptap/mdcToTiptap.ts src/app/src/utils/tiptap/tiptapToMdc.ts 2>/dev/null

If anything matches, the PR is legacy.

2. Conceptual Mapping: Legacy MDC → Comark

Types

| Legacy (pre-#355) | Comark (current main) | |---|---| | `MDCRoot`, `MarkdownRoot` from `@nuxt/content` | `MarkdownDocument` from `comark` | | `MDCNode`, `MDCElement`, `MDCText`, `MDCComment` from `@nuxtjs/mdc` | `MarkdownNode`, `ElementNode`, `CommentNode` from `comark` | | MDC element: `{ type: 'element', tag: 'note', props: {…}, children: [...] }` | Tuple: `['note', attrs, ...children]` | | MDC text: `{ type: 'text', value: 'hello' }` | Plain string: `'hello'` | | MDC comment: `{ type: 'comment', value: 'txt' }` | Tuple: `[null, {}, 'txt']` |

Functions (document utilities)

Located in `src/module/src/runtime/utils/document/generate.ts`:

| Legacy | Comark | |---|---| | `generateDocumentFromContent(id, content, opts)` | `documentFromContent(id, content, opts)` | | `generateDocumentFromMarkdownContent(...)` | `documentFromMarkdownContent(...)` | | `generateDocumentFromYAMLContent(...)` | `documentFromYAMLContent(...)` | | `generateDocumentFromJSONContent(...)` | `documentFromJSONContent(...)` | | `generateContentFromDocument(doc)` | `contentFromDocument(doc)` | | `generateContentFromMarkdownDocument(doc)` | `contentFromMarkdownDocument(doc)` | | `generateContentFromYAMLDocument(doc)` | `contentFromYAMLDocument(doc)` | | `generateContentFromJSONDocument(doc)` | `contentFromJSONDocument(doc)` |

The shape `generate-X-from-Y` was reversed to `Y-from-X` for symmetry.

TipTap bridges

Located in `src/app/src/utils/tiptap/`:

| Legacy file (deleted on main) | Comark replacement | |---|---| | `mdcToTiptap.ts` | `comarkToTiptap.ts` | | `tiptapToMdc.ts` | `tiptapToComark.ts` | | `mdcToTiptap(body, frontmatterData, opts)` | `comarkToTiptap(tree, opts)` — options collapsed to a single object; frontmatter is part of the tree | | `tiptapToMDC(json, opts) → { body, data }` | `tiptapToComark(json, opts) → MarkdownDocument` — returns one tree with `frontmatter` embedded |

Parser / stringifier

| Legacy | Comark | |---|---| | `import { parseMarkdown } from '@nuxtjs/mdc/runtime/parser/index'` | `import { parseMarkdown } from 'comark'` | | `import { stringifyMarkdown } from '@nuxtjs/mdc/runtime'` | `import { renderMarkdown } from 'comark/render'` | | `parseFrontMatter` / `stringifyFrontMatter` from `remark-mdc` | `js-yaml` (`yaml.load` / `yaml.dump`) for pure YAML/JSON files; for Markdown, frontmatter is now embedded in `MarkdownDocument.frontmatter` | | `compressTree` / `decompressTree` from `@nuxt/content/runtime` | No longer used in app code — see §4 "Legacy bridge" | | `visit` from `unist-util-visit` | Walk the tuple tree manually using the helpers from `src/app/src/utils/comark.ts` |

Plugin / option shape

// Legacy
parseMarkdown(content, {
  contentHeading: …,
  highlight: { theme },
  remark: {
    plugins: {
      'emoji': { instance: remarkEmojiPlugin },
      'remark-mdc': { options: { autoUnwrap: true } },
    },
  },
})

// Comark
import { parseMarkdown } from 'comark'
import comarkEmoji from 'comark/plugins/emoji'
import shiki from 'comark/plugins/shiki'
import tocPlugin from 'comark/plugins/toc'

parseMarkdown(content, {
  autoClose: false,
  autoUnwrap: true,
  plugins: [
    comarkEmoji(),
    shiki({ themes: { default, dark, light } }),
    tocPlugin({ depth: 2, searchDepth: 2, title: '', links: [] }),
  ],
})

For rendering back to markdown:

// Legacy
const markdown = await stringifyMarkdown(body, data, {
  frontMatter: { options: { lineWidth: 0 } },
  plugins: { remarkMDC: { options: { autoUnwrap: true } } },
})

// Comark
const markdown = await renderMarkdown(tree, {
  blockAttributesStyle: 'frontmatter',
  components: { br: () => ':br' },
})

Dependencies (`package.json`)

Removed from runtime deps: `@nuxtjs/mdc`, `remark-mdc` (moved to devDeps), `unist-util-visit`.

Added: `comark` (pulled from `pkg.pr.new` while it stabilises). `js-yaml` is now used directly for YAML.

`minimark` is also a devDep only — do not import

Read more
@nuxt-content
Ships withnuxt-studio

Visual edition in production for your Nuxt Content website. Originally offered as a standalone premium platform, Studio has evolved into a free, open-source, and self-hostable Nuxt module. Enable your entire team to edit website content right in production.

Stars on GitHub

Momentum

stars in total
742
Star history of nuxt-content/nuxt-studio on GitHub, a chart by star-history.com

Other skills on nuxt-studio.

More skills from other plugins.

prompt-lookup

prompt-lookup

Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use…

@gh-f@gh-fInstall Skill
ppt-master

ppt-master

AI-driven presentation workflow for generating editable PPTX decks and slides, reconstructing page visuals, creating reusable…

@hugohe3@hugohe3Install Skill
morph-ppt

morph-ppt

Use this skill when the user wants a .pptx with smooth cross-slide animation — PowerPoint Morph transitions, Keynote-style…

officecli12d33k
@iofficeai@iofficeaiInstall Skill

Questions about migrate-mdc-to-comark.

Which coding agents can use migrate-mdc-to-comark?
migrate-mdc-to-comark installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.