From 5a7b95edd7f8ed14f577d736cbb65b8ebc0f2b7e Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Thu, 5 Mar 2026 12:49:26 +0100 Subject: [PATCH 01/23] refactor: separate packages for vue, react and nuxt --- docs/app/components/ComarkDocs.ts | 11 +- .../app/components/ContentRenderer.global.vue | 3 +- .../components/landing/LandingGetStarted.vue | 2 +- docs/app/pages/play.vue | 8 +- docs/app/pages/stream.vue | 1 - docs/app/pages/test.vue | 1 - docs/nuxt.config.ts | 2 +- docs/package.json | 7 +- examples/3.plugins/vue-vite-cjk/package.json | 2 +- examples/3.plugins/vue-vite-cjk/src/App.vue | 2 +- examples/3.plugins/vue-vite-math/package.json | 2 +- examples/3.plugins/vue-vite-math/src/App.vue | 4 +- .../3.plugins/vue-vite-mermaid/package.json | 2 +- .../3.plugins/vue-vite-mermaid/src/App.vue | 4 +- package.json | 10 +- packages/comark-nuxt/.release-it.json | 33 + packages/comark-nuxt/build.config.mjs | 11 + packages/comark-nuxt/package.json | 33 + .../src/nuxt => comark-nuxt/src}/module.ts | 16 +- packages/comark-nuxt/tsconfig.json | 16 + packages/comark-react/.release-it.json | 33 + packages/comark-react/build.config.mjs | 11 + packages/comark-react/package.json | 30 + .../src}/components/Comark.tsx | 8 +- .../src}/components/ComarkRenderer.tsx | 8 +- .../src/react => comark-react/src}/index.ts | 8 +- packages/comark-react/src/utils/caret.ts | 51 ++ packages/comark-react/tsconfig.json | 17 + packages/comark-vue/.release-it.json | 33 + packages/comark-vue/build.config.mjs | 11 + packages/comark-vue/package.json | 31 + .../src}/components/Comark.ts | 8 +- .../src}/components/ComarkRenderer.ts | 11 +- .../src/vue => comark-vue/src}/index.ts | 2 +- packages/comark-vue/src/utils/caret.ts | 51 ++ packages/comark-vue/tsconfig.json | 16 + packages/comark/build.config.mjs | 13 - packages/comark/package.json | 26 +- packages/comark/test/index.test.ts | 2 +- .../.release-it.json | 6 +- .../{comark-cjk => plugin-cjk}/CHANGELOG.md | 0 .../build.config.mjs | 0 .../{comark-cjk => plugin-cjk}/package.json | 2 +- .../{comark-cjk => plugin-cjk}/src/index.ts | 0 .../test/index.test.ts | 2 +- .../{comark-cjk => plugin-cjk}/tsconfig.json | 0 .../vitest.config.ts | 0 .../{comark-math => plugin-math}/.gitignore | 0 .../.release-it.json | 6 +- .../{comark-math => plugin-math}/CHANGELOG.md | 0 .../{comark-math => plugin-math}/README.md | 0 .../build.config.mjs | 0 .../{comark-math => plugin-math}/package.json | 2 +- .../{comark-math => plugin-math}/src/index.ts | 2 +- .../src/react.tsx | 0 .../{comark-math => plugin-math}/src/vue.ts | 0 .../test/index.test.ts | 0 .../tsconfig.json | 0 .../vitest.config.ts | 0 .../.gitignore | 0 .../.release-it.json | 6 +- .../CHANGELOG.md | 0 .../README.md | 0 .../build.config.mjs | 0 .../package.json | 2 +- .../src/index.ts | 2 +- .../src/react.tsx | 0 .../src/vue.ts | 0 .../test/index.test.ts | 0 .../tsconfig.json | 0 .../vitest.config.ts | 0 pnpm-lock.yaml | 581 ++++++++++++++++-- 72 files changed, 1007 insertions(+), 144 deletions(-) create mode 100644 packages/comark-nuxt/.release-it.json create mode 100644 packages/comark-nuxt/build.config.mjs create mode 100644 packages/comark-nuxt/package.json rename packages/{comark/src/nuxt => comark-nuxt/src}/module.ts (84%) create mode 100644 packages/comark-nuxt/tsconfig.json create mode 100644 packages/comark-react/.release-it.json create mode 100644 packages/comark-react/build.config.mjs create mode 100644 packages/comark-react/package.json rename packages/{comark/src/react => comark-react/src}/components/Comark.tsx (94%) rename packages/{comark/src/react => comark-react/src}/components/ComarkRenderer.tsx (97%) rename packages/{comark/src/react => comark-react/src}/index.ts (89%) create mode 100644 packages/comark-react/src/utils/caret.ts create mode 100644 packages/comark-react/tsconfig.json create mode 100644 packages/comark-vue/.release-it.json create mode 100644 packages/comark-vue/build.config.mjs create mode 100644 packages/comark-vue/package.json rename packages/{comark/src/vue => comark-vue/src}/components/Comark.ts (95%) rename packages/{comark/src/vue => comark-vue/src}/components/ComarkRenderer.ts (96%) rename packages/{comark/src/vue => comark-vue/src}/index.ts (97%) create mode 100644 packages/comark-vue/src/utils/caret.ts create mode 100644 packages/comark-vue/tsconfig.json rename packages/{comark-cjk => plugin-cjk}/.release-it.json (81%) rename packages/{comark-cjk => plugin-cjk}/CHANGELOG.md (100%) rename packages/{comark-cjk => plugin-cjk}/build.config.mjs (100%) rename packages/{comark-cjk => plugin-cjk}/package.json (96%) rename packages/{comark-cjk => plugin-cjk}/src/index.ts (100%) rename packages/{comark-cjk => plugin-cjk}/test/index.test.ts (99%) rename packages/{comark-cjk => plugin-cjk}/tsconfig.json (100%) rename packages/{comark-cjk => plugin-cjk}/vitest.config.ts (100%) rename packages/{comark-math => plugin-math}/.gitignore (100%) rename packages/{comark-math => plugin-math}/.release-it.json (80%) rename packages/{comark-math => plugin-math}/CHANGELOG.md (100%) rename packages/{comark-math => plugin-math}/README.md (100%) rename packages/{comark-math => plugin-math}/build.config.mjs (100%) rename packages/{comark-math => plugin-math}/package.json (97%) rename packages/{comark-math => plugin-math}/src/index.ts (99%) rename packages/{comark-math => plugin-math}/src/react.tsx (100%) rename packages/{comark-math => plugin-math}/src/vue.ts (100%) rename packages/{comark-math => plugin-math}/test/index.test.ts (100%) rename packages/{comark-math => plugin-math}/tsconfig.json (100%) rename packages/{comark-math => plugin-math}/vitest.config.ts (100%) rename packages/{comark-mermaid => plugin-mermaid}/.gitignore (100%) rename packages/{comark-mermaid => plugin-mermaid}/.release-it.json (79%) rename packages/{comark-mermaid => plugin-mermaid}/CHANGELOG.md (100%) rename packages/{comark-mermaid => plugin-mermaid}/README.md (100%) rename packages/{comark-mermaid => plugin-mermaid}/build.config.mjs (100%) rename packages/{comark-mermaid => plugin-mermaid}/package.json (96%) rename packages/{comark-mermaid => plugin-mermaid}/src/index.ts (98%) rename packages/{comark-mermaid => plugin-mermaid}/src/react.tsx (100%) rename packages/{comark-mermaid => plugin-mermaid}/src/vue.ts (100%) rename packages/{comark-mermaid => plugin-mermaid}/test/index.test.ts (100%) rename packages/{comark-mermaid => plugin-mermaid}/tsconfig.json (100%) rename packages/{comark-mermaid => plugin-mermaid}/vitest.config.ts (100%) diff --git a/docs/app/components/ComarkDocs.ts b/docs/app/components/ComarkDocs.ts index 8e79e1f..dbb927e 100644 --- a/docs/app/components/ComarkDocs.ts +++ b/docs/app/components/ComarkDocs.ts @@ -1,9 +1,8 @@ -import { defineComarkComponent } from 'comark/vue' -import math from '@comark/math' -import mermaid from '@comark/mermaid' -import cjk from '@comark/cjk' -import { Math } from '@comark/math/vue' -import { Mermaid } from '@comark/mermaid/vue' +import math from '@comark/plugin-math' +import mermaid from '@comark/plugin-mermaid' +import cjk from '@comark/plugin-cjk' +import { Math } from '@comark/plugin-math/vue' +import { Mermaid } from '@comark/plugin-mermaid/vue' import ProsePre from './landing/ProsePre.vue' import highlight from 'comark/plugins/highlight' import githubLight from '@shikijs/themes/github-light' diff --git a/docs/app/components/ContentRenderer.global.vue b/docs/app/components/ContentRenderer.global.vue index d44f148..375705a 100644 --- a/docs/app/components/ContentRenderer.global.vue +++ b/docs/app/components/ContentRenderer.global.vue @@ -5,9 +5,8 @@ import type { AsyncComponentLoader, PropType } from 'vue' import htmlTags from '@nuxtjs/mdc/runtime/parser/utils/html-tags-list' import { globalComponents, localComponents } from '#content/components' import { useRuntimeConfig } from '#imports' -import { ComarkRenderer } from 'comark/vue' import alert from 'comark/plugins/alert' -import { Mermaid } from '@comark/mermaid/vue' +import { Mermaid } from '@comark/plugin-mermaid/vue' import type { ComarkTree, ComarkElement } from 'comark/ast' import type { MinimarkNode, MinimarkTree } from 'minimark' diff --git a/docs/app/components/landing/LandingGetStarted.vue b/docs/app/components/landing/LandingGetStarted.vue index c586827..a9b8499 100644 --- a/docs/app/components/landing/LandingGetStarted.vue +++ b/docs/app/components/landing/LandingGetStarted.vue @@ -11,7 +11,7 @@ const tabs = [ const codeSnippets = { vue: `\`\`\`vue [src/App.vue] @@ -77,7 +77,7 @@ Use the `options` prop to configure parser behavior: ```vue [App.vue] @@ -184,7 +184,7 @@ Render only content before ``: ```vue [ArticleSummary.vue] @@ -85,7 +85,7 @@ import emoji from 'comark/plugins/emoji' ``` ```tsx [React] -import { Comark } from 'comark/react' +import { Comark } from '@comark/react' import emoji from 'comark/plugins/emoji' {content} diff --git a/docs/content/5.api/3.reference.md b/docs/content/5.api/3.reference.md index 91a2ddd..5237f03 100644 --- a/docs/content/5.api/3.reference.md +++ b/docs/content/5.api/3.reference.md @@ -278,10 +278,10 @@ import { renderHTML, renderMarkdown } from 'comark/string' import type { RenderHTMLOptions, ComponentRenderFn, RenderHTMLContext } from 'comark/string' // Vue components -import { Comark, defineComarkComponent } from 'comark/vue' +import { Comark, defineComarkComponent } from '@comark/vue' // React components -import { Comark, defineComarkComponent } from 'comark/react' +import { Comark, defineComarkComponent } from '@comark/react' // Types import type { diff --git a/docs/content/6.integrations/1.nuxt.md b/docs/content/6.integrations/1.nuxt.md index e14a776..6406694 100644 --- a/docs/content/6.integrations/1.nuxt.md +++ b/docs/content/6.integrations/1.nuxt.md @@ -45,7 +45,7 @@ Add the module to your `nuxt.config.ts`: ```typescript [nuxt.config.ts] export default defineNuxtConfig({ - modules: ['comark/nuxt'] + modules: ['@comark/nuxt'] }) ``` @@ -250,7 +250,7 @@ bun add @nuxt/ui ```typescript [nuxt.config.ts] export default defineNuxtConfig({ - modules: ['comark/nuxt', '@nuxt/ui'] + modules: ['@comark/nuxt', '@nuxt/ui'] }) ``` @@ -294,7 +294,7 @@ This alert uses Nuxt UI styling! ```typescript [nuxt.config.ts] export default defineNuxtConfig({ - modules: ['comark/nuxt', '@nuxt/ui'], + modules: ['@comark/nuxt', '@nuxt/ui'], css: ['~/assets/css/main.css'] }) ``` @@ -338,7 +338,7 @@ const { data: content } = await useFetch('/api/article') ```typescript [nuxt.config.ts] export default defineNuxtConfig({ - modules: ['comark/nuxt'], + modules: ['@comark/nuxt'], nitro: { prerender: { routes: ['/blog', '/docs'] diff --git a/docs/content/index.md b/docs/content/index.md index 7fa359d..7a77187 100644 --- a/docs/content/index.md +++ b/docs/content/index.md @@ -50,7 +50,7 @@ Install with npm and start parsing markdown in seconds #vue ```vue [src/App.vue] @@ -68,7 +68,7 @@ const content = `# Hello World` ### React Rendering ```tsx -import { Comark } from 'comark/react' +import { Comark } from '@comark/react' export default function App() { return @@ -231,7 +231,7 @@ async function processMarkdownFile(filePath: string) { ```tsx import { useState } from 'react' -import { Comark } from 'comark/react' +import { Comark } from '@comark/react' export default function Editor() { const [content, setContent] = useState('# Hello') @@ -276,7 +276,7 @@ async function processMultipleFiles(files: string[]) { ``` diff --git a/skills/mdc/references/rendering-react.md b/skills/mdc/references/rendering-react.md index bad5920..2e1cbae 100644 --- a/skills/mdc/references/rendering-react.md +++ b/skills/mdc/references/rendering-react.md @@ -20,7 +20,7 @@ Complete guide for rendering Comark AST in React applications. Use the `Comark` component to render markdown: ```tsx -import { Comark } from 'comark/react' +import { Comark } from '@comark/react' const content = ` # Hello World @@ -44,7 +44,7 @@ export default function App() { Map custom React components to Comark elements: ```tsx -import { Comark } from 'comark/react' +import { Comark } from '@comark/react' import CustomHeading from './CustomHeading' import CustomAlert from './CustomAlert' import CustomCard from './CustomCard' @@ -150,7 +150,7 @@ export default function CustomAlert({ type = 'info', children }: AlertProps) { Load components dynamically using `componentsManifest`: ```tsx -import { Comark } from 'comark/react' +import { Comark } from '@comark/react' const componentMap = { 'alert': () => import('./Alert'), @@ -241,7 +241,7 @@ Use the `Comark` component with reactive state for streaming content: ```tsx import { useState, useEffect } from 'react' -import { Comark } from 'comark/react' +import { Comark } from '@comark/react' export default function StreamingContent() { const [content, setContent] = useState('') @@ -281,7 +281,7 @@ export default function StreamingContent() { The `Comark` component uses built-in prose styling automatically. You can override with custom components: ```tsx -import { Comark } from 'comark/react' +import { Comark } from '@comark/react' import CustomAlert from './CustomAlert' const components = { @@ -296,7 +296,7 @@ export default function App({ content }) { ### Tailwind CSS Prose ```tsx -import { Comark } from 'comark/react' +import { Comark } from '@comark/react' export default function App({ content }) { return ( diff --git a/skills/mdc/references/rendering-vue.md b/skills/mdc/references/rendering-vue.md index 91b1f42..92963d1 100644 --- a/skills/mdc/references/rendering-vue.md +++ b/skills/mdc/references/rendering-vue.md @@ -25,7 +25,7 @@ Use the `Comark` component to render markdown: ``` ### React +```bash +npm install @comark/react @comark/math +# or +pnpm add @comark/react @comark/math +``` + ```tsx import { Comark } from '@comark/react' -import cjk from '@comark/cjk' import math from '@comark/math' import { Math } from '@comark/math/react' function App() { const chatMessage = ... - return {chatMessage} + return {chatMessage} } ``` +### HTML (No Framework) +```bash +npm install comark +# or +pnpm add comark +``` + +```js +import { parse } from 'comark' +import { renderHTML } from 'comark/string' + +const chatMessage = ... + +const tree = await parse(chatMessage) +const html = renderHTML(tree) +``` + + ## License Made with ❤️ From b499ef69028ee1758d75f8ef959021aa65f5c59d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Chopin?= Date: Thu, 5 Mar 2026 16:45:43 +0100 Subject: [PATCH 06/23] Update 1.installation.md --- .../1.getting-started/1.installation.md | 85 +++++++++++-------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/docs/content/1.getting-started/1.installation.md b/docs/content/1.getting-started/1.installation.md index e428f28..cdd158a 100644 --- a/docs/content/1.getting-started/1.installation.md +++ b/docs/content/1.getting-started/1.installation.md @@ -16,42 +16,55 @@ links: ## Install Comark -::code-group -```bash [pnpm] -# Vue -pnpm add @comark/vue -# React -pnpm add @comark/react -# HTML -pnpm add comark -``` - -```bash [npm] -# Vue -npm install @comark/vue -# React -npm install @comark/react -# HTML -npm install comark -``` - -```bash [yarn] -# Vue -yarn add @comark/vue -# React -yarn add @comark/react -# HTML -yarn add comark -``` - -```bash [bun] -# Vue -bun add @comark/vue -# React -bun add @comark/react -# HTML -bun add comark -``` +::tabs{class="gap-0"} + ::tab-item{label="Vue" icon="i-logos-vue"} + ::code-group + ```bash [pnpm] + pnpm add @comark/vue + ``` + ```bash [npm] + npm install @comark/vue + ``` + ```bash [yarn] + yarn add @comark/vue + ``` + ```bash [bun] + bun add @comark/vue + ``` + :: + :: + ::tab-item{label="React" icon="i-logos-react"} + ::code-group + ```bash [pnpm] + pnpm add @comark/react + ``` + ```bash [npm] + npm install @comark/react + ``` + ```bash [yarn] + yarn add @comark/react + ``` + ```bash [bun] + bun add @comark/react + ``` + :: + :: + ::tab-item{label="HTML" icon="i-vscode-icons-file-type-html"} + ::code-group + ```bash [pnpm] + pnpm add comark + ``` + ```bash [npm] + npm install comark + ``` + ```bash [yarn] + yarn add comark + ``` + ```bash [bun] + bun add comark + ``` + :: + :: :: ## Quick Start From b706d6648788f8e13e5512df4c64648e04818f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Chopin?= Date: Thu, 5 Mar 2026 17:35:56 +0100 Subject: [PATCH 07/23] Update 1.installation.md --- .../1.getting-started/1.installation.md | 44 ++++++++----------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/docs/content/1.getting-started/1.installation.md b/docs/content/1.getting-started/1.installation.md index cdd158a..583e4fc 100644 --- a/docs/content/1.getting-started/1.installation.md +++ b/docs/content/1.getting-started/1.installation.md @@ -16,6 +16,8 @@ links: ## Install Comark +Add comark to your project with your package manager of choice depending on your framework. + ::tabs{class="gap-0"} ::tab-item{label="Vue" icon="i-logos-vue"} ::code-group @@ -73,10 +75,10 @@ Pick your framework and get rendering in seconds. ### Vue -::code-group ```vue [App.vue] ``` -```html [Output] -

Hello World

-

This is markdown with a custom component:

-
-

Welcome to Comark!

-
-``` -:: - -::callout{color="warning" icon="i-lucide-triangle-alert"} +::note When using async plugins (like syntax highlighting), wrap `` in a `` component. See [Vue Rendering](/rendering/vue) for details. :: +Learn more about [Vue Rendering](/rendering/vue). + + ### React -::code-group +Use the `components` prop to pass your custom components to the `` component. + ```tsx [App.tsx] import { Comark } from '@comark/react' +import Alert from './Alert.tsx' const content = `# Hello World -This is **markdown** with a custom component: +This is **markdown** with Comark components. ::alert{type="info"} -Welcome to Comark! +This is an alert! :: ` export default function App() { - return {content} + return {content} } ``` -```html [Output] -

Hello World

-

This is markdown with a custom component:

-
-

Welcome to Comark!

-
-``` -:: +Learn more about [React Rendering](/rendering/react). + ### HTML (No Framework) @@ -166,9 +160,7 @@ console.log(html) ``` :: -::callout{color="info" icon="i-lucide-info"} Use the `components` option in `renderHTML` to control how custom components are rendered to HTML. See [HTML Rendering](/rendering/html) for details. -:: ## Next Steps From 9bfbd8d39b99628f1dfd2102f8c6dd8201e145c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Chopin?= Date: Thu, 5 Mar 2026 18:07:15 +0100 Subject: [PATCH 08/23] chore: fix import --- examples/1.frameworks/nextjs/README.md | 2 +- examples/1.frameworks/nextjs/app/blog/[slug]/page.tsx | 2 +- examples/1.frameworks/nextjs/content/posts/hello-world.md | 2 +- .../1.frameworks/nextjs/content/posts/nextjs-integration.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/1.frameworks/nextjs/README.md b/examples/1.frameworks/nextjs/README.md index ba10a33..723721e 100644 --- a/examples/1.frameworks/nextjs/README.md +++ b/examples/1.frameworks/nextjs/README.md @@ -11,7 +11,7 @@ path: /examples/frameworks/nextjs ```tsx [app/blog/[slug]/page.tsx] import type { Metadata } from 'next' import Link from 'next/link' -import { ComarkRenderer } from 'comark/react/components/ComarkRenderer' +import { ComarkRenderer } from '@comark/react' import { getAllPosts, getPost } from '@/lib/posts' import Alert from '@/components/Alert' diff --git a/examples/1.frameworks/nextjs/app/blog/[slug]/page.tsx b/examples/1.frameworks/nextjs/app/blog/[slug]/page.tsx index 1c27402..6b3108d 100644 --- a/examples/1.frameworks/nextjs/app/blog/[slug]/page.tsx +++ b/examples/1.frameworks/nextjs/app/blog/[slug]/page.tsx @@ -1,6 +1,6 @@ import type { Metadata } from 'next' import Link from 'next/link' -import { ComarkRenderer } from 'comark/react/components/ComarkRenderer' +import { ComarkRenderer } from '@comark/react' import { getAllPosts, getPost } from '@/lib/posts' import Alert from '@/components/Alert' diff --git a/examples/1.frameworks/nextjs/content/posts/hello-world.md b/examples/1.frameworks/nextjs/content/posts/hello-world.md index aa64a4d..2c90f36 100644 --- a/examples/1.frameworks/nextjs/content/posts/hello-world.md +++ b/examples/1.frameworks/nextjs/content/posts/hello-world.md @@ -21,7 +21,7 @@ This alert is rendered using a custom Comark component — no client-side JavaSc ```ts import { parse } from 'comark' -import { ComarkRenderer } from 'comark/react/components/ComarkRenderer' +import { ComarkRenderer } from '@comark/react' const tree = await parse(markdown) // diff --git a/examples/1.frameworks/nextjs/content/posts/nextjs-integration.md b/examples/1.frameworks/nextjs/content/posts/nextjs-integration.md index ef105b3..f69f175 100644 --- a/examples/1.frameworks/nextjs/content/posts/nextjs-integration.md +++ b/examples/1.frameworks/nextjs/content/posts/nextjs-integration.md @@ -18,7 +18,7 @@ Instead of using the typical `gray-matter` + `remark` + `rehype` pipeline, we us ```ts import { parse } from 'comark' -import { ComarkRenderer } from 'comark/react/components/ComarkRenderer' +import { ComarkRenderer } from '@comark/react' import highlight from 'comark/plugins/highlight' import Alert from '@/components/Alert' From 7051a73673fbe3311f694d1d4558ca3f651ec2cc Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 9 Mar 2026 14:11:18 +0100 Subject: [PATCH 09/23] refactor: move plugins components to renderer packages --- docs/app/components/ComarkDocs.ts | 10 +- .../app/components/ContentRenderer.global.vue | 2 +- docs/app/components/Playground.vue | 2 +- docs/content/3.rendering/1.vue.md | 26 +- docs/content/3.rendering/2.react.md | 34 +- .../4.plugins/2.external/10.mermaid.md | 22 +- docs/content/4.plugins/2.external/11.math.md | 25 +- docs/content/4.plugins/2.external/12.cjk.md | 30 +- docs/package.json | 4 +- examples/3.plugins/vue-vite-cjk/package.json | 1 - examples/3.plugins/vue-vite-math/README.md | 3 +- examples/3.plugins/vue-vite-math/package.json | 3 +- examples/3.plugins/vue-vite-mermaid/README.md | 5 +- .../3.plugins/vue-vite-mermaid/package.json | 3 +- package.json | 7 +- packages/comark-nuxt/build.config.mjs | 11 - packages/comark-nuxt/package.json | 17 +- packages/comark-nuxt/tsconfig.build.json | 10 + packages/comark-react/build.config.mjs | 11 - packages/comark-react/package.json | 16 +- .../src/components/Math.tsx} | 0 .../src/components/Mermaid.tsx} | 2 +- packages/comark-react/src/plugins/math.ts | 4 + packages/comark-react/src/plugins/mermaid.ts | 4 + packages/comark-react/tsconfig.build.json | 10 + packages/comark-vue/build.config.mjs | 11 - packages/comark-vue/package.json | 16 +- .../src/components/Math.ts} | 0 .../src/components/Mermaid.ts} | 2 +- packages/comark-vue/src/env.d.ts | 3 + packages/comark-vue/src/plugins/math.ts | 4 + packages/comark-vue/src/plugins/mermaid.ts | 4 + packages/comark-vue/tsconfig.build.json | 10 + packages/comark/README.md | 14 +- packages/comark/build.config.mjs | 26 -- packages/comark/package.json | 35 +- .../index.ts => comark/src/plugins/math.ts} | 2 +- .../src/plugins/mermaid.ts} | 2 +- packages/comark/tsconfig.build.json | 16 + packages/plugin-cjk/.release-it.json | 33 -- packages/plugin-cjk/CHANGELOG.md | 33 -- packages/plugin-cjk/build.config.mjs | 11 - packages/plugin-cjk/package.json | 45 -- packages/plugin-cjk/src/index.ts | 9 - packages/plugin-cjk/test/index.test.ts | 248 ----------- packages/plugin-cjk/tsconfig.json | 16 - packages/plugin-cjk/vitest.config.ts | 7 - packages/plugin-math/.gitignore | 4 - packages/plugin-math/.release-it.json | 33 -- packages/plugin-math/CHANGELOG.md | 3 - packages/plugin-math/README.md | 295 ------------- packages/plugin-math/build.config.mjs | 11 - packages/plugin-math/package.json | 60 --- packages/plugin-math/test/index.test.ts | 184 -------- packages/plugin-math/tsconfig.json | 17 - packages/plugin-math/vitest.config.ts | 7 - packages/plugin-mermaid/.gitignore | 4 - packages/plugin-mermaid/.release-it.json | 33 -- packages/plugin-mermaid/CHANGELOG.md | 3 - packages/plugin-mermaid/README.md | 346 --------------- packages/plugin-mermaid/build.config.mjs | 11 - packages/plugin-mermaid/package.json | 60 --- packages/plugin-mermaid/test/index.test.ts | 339 --------------- packages/plugin-mermaid/tsconfig.json | 17 - packages/plugin-mermaid/vitest.config.ts | 7 - pnpm-lock.yaml | 398 +----------------- scripts/stub.mjs | 57 +++ scripts/sync-plugins.mjs | 56 +++ 68 files changed, 330 insertions(+), 2424 deletions(-) delete mode 100644 packages/comark-nuxt/build.config.mjs create mode 100644 packages/comark-nuxt/tsconfig.build.json delete mode 100644 packages/comark-react/build.config.mjs rename packages/{plugin-math/src/react.tsx => comark-react/src/components/Math.tsx} (100%) rename packages/{plugin-mermaid/src/react.tsx => comark-react/src/components/Mermaid.tsx} (97%) create mode 100644 packages/comark-react/src/plugins/math.ts create mode 100644 packages/comark-react/src/plugins/mermaid.ts create mode 100644 packages/comark-react/tsconfig.build.json delete mode 100644 packages/comark-vue/build.config.mjs rename packages/{plugin-math/src/vue.ts => comark-vue/src/components/Math.ts} (100%) rename packages/{plugin-mermaid/src/vue.ts => comark-vue/src/components/Mermaid.ts} (98%) create mode 100644 packages/comark-vue/src/env.d.ts create mode 100644 packages/comark-vue/src/plugins/math.ts create mode 100644 packages/comark-vue/src/plugins/mermaid.ts create mode 100644 packages/comark-vue/tsconfig.build.json delete mode 100644 packages/comark/build.config.mjs rename packages/{plugin-math/src/index.ts => comark/src/plugins/math.ts} (99%) rename packages/{plugin-mermaid/src/index.ts => comark/src/plugins/mermaid.ts} (98%) create mode 100644 packages/comark/tsconfig.build.json delete mode 100644 packages/plugin-cjk/.release-it.json delete mode 100644 packages/plugin-cjk/CHANGELOG.md delete mode 100644 packages/plugin-cjk/build.config.mjs delete mode 100644 packages/plugin-cjk/package.json delete mode 100644 packages/plugin-cjk/src/index.ts delete mode 100644 packages/plugin-cjk/test/index.test.ts delete mode 100644 packages/plugin-cjk/tsconfig.json delete mode 100644 packages/plugin-cjk/vitest.config.ts delete mode 100644 packages/plugin-math/.gitignore delete mode 100644 packages/plugin-math/.release-it.json delete mode 100644 packages/plugin-math/CHANGELOG.md delete mode 100644 packages/plugin-math/README.md delete mode 100644 packages/plugin-math/build.config.mjs delete mode 100644 packages/plugin-math/package.json delete mode 100644 packages/plugin-math/test/index.test.ts delete mode 100644 packages/plugin-math/tsconfig.json delete mode 100644 packages/plugin-math/vitest.config.ts delete mode 100644 packages/plugin-mermaid/.gitignore delete mode 100644 packages/plugin-mermaid/.release-it.json delete mode 100644 packages/plugin-mermaid/CHANGELOG.md delete mode 100644 packages/plugin-mermaid/README.md delete mode 100644 packages/plugin-mermaid/build.config.mjs delete mode 100644 packages/plugin-mermaid/package.json delete mode 100644 packages/plugin-mermaid/test/index.test.ts delete mode 100644 packages/plugin-mermaid/tsconfig.json delete mode 100644 packages/plugin-mermaid/vitest.config.ts create mode 100644 scripts/stub.mjs create mode 100644 scripts/sync-plugins.mjs diff --git a/docs/app/components/ComarkDocs.ts b/docs/app/components/ComarkDocs.ts index 27b25ef..cc0db3e 100644 --- a/docs/app/components/ComarkDocs.ts +++ b/docs/app/components/ComarkDocs.ts @@ -1,8 +1,7 @@ -import math from '@comark/plugin-math' -import mermaid from '@comark/plugin-mermaid' -import cjk from '@comark/plugin-cjk' -import { Math } from '@comark/plugin-math/vue' -import { Mermaid } from '@comark/plugin-mermaid/vue' +import math from '@comark/vue/plugins/math' +import mermaid from '@comark/vue/plugins/mermaid' +import { Math } from '@comark/vue/plugins/math' +import { Mermaid } from '@comark/vue/plugins/mermaid' import ProsePre from './landing/ProsePre.vue' import highlight from 'comark/plugins/highlight' import githubLight from '@shikijs/themes/github-light' @@ -14,7 +13,6 @@ export default defineComarkComponent({ plugins: [ math(), mermaid(), - cjk(), highlight({ themes: { light: githubLight, diff --git a/docs/app/components/ContentRenderer.global.vue b/docs/app/components/ContentRenderer.global.vue index de1fd26..85714db 100644 --- a/docs/app/components/ContentRenderer.global.vue +++ b/docs/app/components/ContentRenderer.global.vue @@ -6,7 +6,7 @@ import htmlTags from '@nuxtjs/mdc/runtime/parser/utils/html-tags-list' import { globalComponents, localComponents } from '#content/components' import { useRuntimeConfig } from '#imports' import alert from 'comark/plugins/alert' -import { Mermaid } from '@comark/plugin-mermaid/vue' +import { Mermaid } from '@comark/vue/plugins/mermaid' import type { ComarkTree, ComarkElement } from 'comark/ast' import type { MinimarkNode, MinimarkTree } from 'minimark' diff --git a/docs/app/components/Playground.vue b/docs/app/components/Playground.vue index 4cc8fe3..3f59d31 100644 --- a/docs/app/components/Playground.vue +++ b/docs/app/components/Playground.vue @@ -2,7 +2,7 @@ import { parse } from 'comark' import highlight from 'comark/plugins/highlight' import { renderMarkdown } from 'comark/string' -import { ComarkRenderer } from 'comark/vue' +import { ComarkRenderer } from '@comark/vue' import { Splitpanes, Pane } from 'splitpanes' import { defaultMarkdown } from '~/constants' import { watchDebounced } from '@vueuse/core' diff --git a/docs/content/3.rendering/1.vue.md b/docs/content/3.rendering/1.vue.md index 39afb7f..421cda0 100644 --- a/docs/content/3.rendering/1.vue.md +++ b/docs/content/3.rendering/1.vue.md @@ -223,8 +223,8 @@ export const MyComark = defineComarkComponent({ ```typescript [comark.ts] import { defineComarkComponent } from '@comark/vue' -import math from '@comark/math' -import mermaid from '@comark/mermaid' +import math from '@comark/vue/plugins/math' +import mermaid from '@comark/vue/plugins/mermaid' export const DocsComark = defineComarkComponent({ name: 'DocsComark', @@ -239,8 +239,8 @@ export const DocsComark = defineComarkComponent({ ```typescript [comark.ts] import { defineComarkComponent } from '@comark/vue' -import { Math } from '@comark/math/vue' -import { Mermaid } from '@comark/mermaid/vue' +import { Math } from '@comark/vue/plugins/math' +import { Mermaid } from '@comark/vue/plugins/mermaid' import CustomAlert from './components/CustomAlert.vue' import CustomCard from './components/CustomCard.vue' @@ -280,13 +280,13 @@ export const CodeComark = defineComarkComponent({ ```typescript [comark.ts] import { defineComarkComponent } from '@comark/vue' -import math from '@comark/math' -import mermaid from '@comark/mermaid' +import math from '@comark/vue/plugins/math' +import mermaid from '@comark/vue/plugins/mermaid' import highlight from 'comark/plugins/highlight' import githubLight from '@shikijs/themes/github-light' import githubDark from '@shikijs/themes/github-dark' -import { Math } from '@comark/math/vue' -import { Mermaid } from '@comark/mermaid/vue' +import { Math } from '@comark/vue/plugins/math' +import { Mermaid } from '@comark/vue/plugins/mermaid' import CustomAlert from './components/CustomAlert.vue' export const AppComark = defineComarkComponent({ @@ -402,14 +402,11 @@ import emoji from 'comark/plugins/emoji' ```typescript [comark.ts] import { defineComarkComponent } from '@comark/vue' -import math from '@comark/math' -import mermaid from '@comark/mermaid' -import cjk from '@comark/cjk' -import highlight from 'comark/plugins/highlight' +import math, { Math } from '@comark/vue/plugins/math' +import mermaid, { Mermaid } from '@comark/vue/plugins/mermaid' +import highlight from '@comark/vue/plugins/highlight' import githubLight from '@shikijs/themes/github-light' import githubDark from '@shikijs/themes/github-dark' -import { Math } from '@comark/math/vue' -import { Mermaid } from '@comark/mermaid/vue' import ProsePre from './components/ProsePre.vue' import ProseAlert from './components/ProseAlert.vue' @@ -419,7 +416,6 @@ export const DocsComark = defineComarkComponent({ plugins: [ math(), mermaid(), - cjk(), // Better CJK typography highlight({ themes: { light: githubLight, diff --git a/docs/content/3.rendering/2.react.md b/docs/content/3.rendering/2.react.md index d82dd21..494b12a 100644 --- a/docs/content/3.rendering/2.react.md +++ b/docs/content/3.rendering/2.react.md @@ -225,8 +225,8 @@ export const MyComark = defineComarkComponent({ ```tsx [comark.ts] import { defineComarkComponent } from '@comark/react' -import math from '@comark/math' -import mermaid from '@comark/mermaid' +import math from '@comark/react/plugins/math' +import mermaid from '@comark/react/plugins/mermaid' export const DocsComark = defineComarkComponent({ name: 'DocsComark', @@ -241,8 +241,8 @@ export const DocsComark = defineComarkComponent({ ```tsx [comark.ts] import { defineComarkComponent } from '@comark/react' -import { Math } from '@comark/math/react' -import { Mermaid } from '@comark/mermaid/react' +import { Math } from '@comark/react/plugins/math' +import { Mermaid } from '@comark/react/plugins/mermaid' import CustomAlert from './components/CustomAlert' import CustomCard from './components/CustomCard' @@ -282,13 +282,13 @@ export const CodeComark = defineComarkComponent({ ```tsx [comark.ts] import { defineComarkComponent } from '@comark/react' -import math from '@comark/math' -import mermaid from '@comark/mermaid' +import math from '@comark/react/plugins/math' +import mermaid from '@comark/react/plugins/mermaid' import highlight from 'comark/plugins/highlight' import githubLight from '@shikijs/themes/github-light' import githubDark from '@shikijs/themes/github-dark' -import { Math } from '@comark/math/react' -import { Mermaid } from '@comark/mermaid/react' +import { Math } from '@comark/react/plugins/math' +import { Mermaid } from '@comark/react/plugins/mermaid' import CustomAlert from './components/CustomAlert' export const AppComark = defineComarkComponent({ @@ -404,14 +404,11 @@ export default function Page() { ```tsx [comark.ts] import { defineComarkComponent } from '@comark/react' -import math from '@comark/math' -import mermaid from '@comark/mermaid' -import cjk from '@comark/cjk' -import highlight from 'comark/plugins/highlight' +import math, { Math } from '@comark/react/plugins/math' +import mermaid, { Mermaid } from '@comark/react/plugins/mermaid' +import highlight from '@comark/react/plugins/highlight' import githubLight from '@shikijs/themes/github-light' import githubDark from '@shikijs/themes/github-dark' -import { Math } from '@comark/math/react' -import { Mermaid } from '@comark/mermaid/react' import CodeBlock from './components/CodeBlock' import Alert from './components/Alert' @@ -421,7 +418,6 @@ export const DocsComark = defineComarkComponent({ plugins: [ math(), mermaid(), - cjk(), // Better CJK typography highlight({ themes: { light: githubLight, @@ -463,8 +459,8 @@ export default function DocPage() { 'use client' import { defineComarkComponent } from '@comark/react' -import math from '@comark/math' -import { Math } from '@comark/math/react' +import math from '@comark/react/plugins/math' +import { Math } from '@comark/react/plugins/math' export const DocsComark = defineComarkComponent({ name: 'DocsComark', @@ -489,12 +485,12 @@ Create different configurations for different contexts: ```tsx [comark/index.ts] import { defineComarkComponent } from '@comark/react' -import math from '@comark/math' +import math from '@comark/react/plugins/math' import highlight from 'comark/plugins/highlight' import githubLight from '@shikijs/themes/github-light' import githubDark from '@shikijs/themes/github-dark' import nord from '@shikijs/themes/nord' -import { Math } from '@comark/math/react' +import { Math } from '@comark/react/plugins/math' // For documentation pages export const DocsComark = defineComarkComponent({ diff --git a/docs/content/4.plugins/2.external/10.mermaid.md b/docs/content/4.plugins/2.external/10.mermaid.md index 3119452..54f63d6 100644 --- a/docs/content/4.plugins/2.external/10.mermaid.md +++ b/docs/content/4.plugins/2.external/10.mermaid.md @@ -18,25 +18,25 @@ links: variant: soft --- -The `@comark/mermaid` plugin enables rendering of [Mermaid](https://mermaid.js.org/) diagrams in your markdown content. Mermaid lets you create diagrams and visualizations using text and code. +The Mermaid plugin enables rendering of [Mermaid](https://mermaid.js.org/) diagrams in your markdown content. Mermaid lets you create diagrams and visualizations using text and code. -## Installation +The plugin is included in `@comark/vue` and `@comark/react`. You only need to install the `beautiful-mermaid` peer dependency: ::code-group ```bash [npm] -npm install @comark/mermaid +npm install beautiful-mermaid ``` ```bash [pnpm] -pnpm add @comark/mermaid +pnpm add beautiful-mermaid ``` ```bash [yarn] -yarn add @comark/mermaid +yarn add beautiful-mermaid ``` ```bash [bun] -bun add @comark/mermaid +bun add beautiful-mermaid ``` :: @@ -47,8 +47,8 @@ bun add @comark/mermaid ```vue @@ -45,15 +44,14 @@ const chatMessage = ... ### React ```bash -npm install @comark/react @comark/math +npm install @comark/react katex # or -pnpm add @comark/react @comark/math +pnpm add @comark/react katex ``` ```tsx import { Comark } from '@comark/react' -import math from '@comark/math' -import { Math } from '@comark/math/react' +import math, { Math } from '@comark/react/plugins/math' function App() { const chatMessage = ... diff --git a/packages/comark/build.config.mjs b/packages/comark/build.config.mjs deleted file mode 100644 index 250c7ca..0000000 --- a/packages/comark/build.config.mjs +++ /dev/null @@ -1,26 +0,0 @@ -import { defineBuildConfig } from 'obuild/config' - -export default defineBuildConfig({ - entries: [ - { - type: 'transform', - input: './src/plugins', - outDir: './dist/plugins', - }, - { - type: 'bundle', - input: [ - './src/index.ts', - './src/plugins/summary.ts', - './src/plugins/security.ts', - './src/ast/index.ts', - './src/string.ts', - ], - }, - { - type: 'transform', - input: './src/utils', - outDir: './dist/utils', - }, - ], -}) diff --git a/packages/comark/package.json b/packages/comark/package.json index d4b0e8d..4bb07eb 100644 --- a/packages/comark/package.json +++ b/packages/comark/package.json @@ -15,14 +15,14 @@ "react" ], "exports": { - ".": "./dist/index.mjs", - "./ast": "./dist/ast/index.mjs", - "./string": "./dist/string.mjs", - "./plugins/*": "./dist/plugins/*.mjs" + ".": "./dist/index.js", + "./ast": "./dist/ast/index.js", + "./string": "./dist/string.js", + "./plugins/*": "./dist/plugins/*.js" }, - "main": "./dist/index.mjs", - "module": "./dist/index.mjs", - "types": "./dist/index.d.mts", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", "files": [ "dist" ], @@ -30,24 +30,32 @@ "access": "public" }, "scripts": { - "build": "obuild", + "stub": "node ../../scripts/stub.mjs", + "build": "tsc -p tsconfig.build.json", + "dev": "tsc -p tsconfig.build.json --watch", "test": "vitest run", "benchmark": "node --import tsx benchmark.ts", - "prepack": "obuild", + "prepack": "tsc -p tsconfig.build.json", "release": "release-it", "release:dry": "release-it --dry-run" }, "peerDependencies": { - "shiki": "^3.22.0" + "shiki": "^3.22.0", + "beautiful-mermaid": "^1.1.3", + "katex": "^0.16.33" }, "peerDependenciesMeta": { "shiki": { "optional": true + }, + "beautiful-mermaid": { + "optional": true + }, + "katex": { + "optional": true } }, "devDependencies": { - "@comark/plugin-cjk": "workspace:*", - "@comark/markdown-it": "^0.3.1", "@shikijs/primitive": "^4.0.1", "@types/js-yaml": "^4.0.9", "github-slugger": "^2.0.0", @@ -55,11 +63,12 @@ "markdown-it": "^14.1.1", "minimark": "0.2.0", "mitata": "^1.0.34", - "obuild": "^0.4.31", "tsx": "^4.21.0", "vitest": "^4.0.18" }, "dependencies": { + "@comark/markdown-it": "^0.3.1", + "entities": "^4.5.0", "markdown-exit": "1.0.0-beta.9", "js-yaml": "^4.1.1" } diff --git a/packages/plugin-math/src/index.ts b/packages/comark/src/plugins/math.ts similarity index 99% rename from packages/plugin-math/src/index.ts rename to packages/comark/src/plugins/math.ts index 1aa477d..36bbec6 100644 --- a/packages/plugin-math/src/index.ts +++ b/packages/comark/src/plugins/math.ts @@ -312,7 +312,7 @@ function markdownItMath(md: MarkdownIt, config: MathConfig = {}) { * @example * ```ts * import { parse } from 'comark' - * import math from '@comark/plugin-math' + * import math from 'comark/plugins/math' * * const result = await parse('Inline $x^2$ and display $$E = mc^2$$', { * plugins: [math({ throwOnError: false })] diff --git a/packages/plugin-mermaid/src/index.ts b/packages/comark/src/plugins/mermaid.ts similarity index 98% rename from packages/plugin-mermaid/src/index.ts rename to packages/comark/src/plugins/mermaid.ts index b29224e..c6e4040 100644 --- a/packages/plugin-mermaid/src/index.ts +++ b/packages/comark/src/plugins/mermaid.ts @@ -198,7 +198,7 @@ export function searchProps(content: string, index = 0) { * @example * ```ts * import { parse } from 'comark' - * import { createMermaidPlugin } from '@comark/plugin-mermaid' + * import { createMermaidPlugin } from 'comark/plugins/mermaid' * * const mermaid = createMermaidPlugin({ theme: 'dark' }) * const result = await parse('```mermaid\ngraph TD; A-->B;\n```', { diff --git a/packages/comark/tsconfig.build.json b/packages/comark/tsconfig.build.json new file mode 100644 index 0000000..58e7a7a --- /dev/null +++ b/packages/comark/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "outDir": "./dist", + "declaration": true, + "paths": { + "comark": ["./src/index.ts"], + "comark/ast": ["./src/ast/index.ts"], + "comark/string": ["./src/string.ts"], + "comark/plugins/*": ["./src/plugins/*.ts"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/plugin-cjk/.release-it.json b/packages/plugin-cjk/.release-it.json deleted file mode 100644 index beee15b..0000000 --- a/packages/plugin-cjk/.release-it.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "git": { - "commitMessage": "chore(cjk): release v${version}", - "tagName": "@comark/plugin-cjk@${version}", - "tagAnnotation": "@comark/plugin-cjk v${version}", - "requireCleanWorkingDir": true - }, - "github": { - "release": true, - "releaseName": "@comark/plugin-cjk v${version}" - }, - "npm": { - "publish": true, - "publishPath": "." - }, - "plugins": { - "@release-it/conventional-changelog": { - "ignoreRecommendedBump": true, - "preset": { - "name": "conventionalcommits", - "types": [ - { "type": "feat", "section": "Features" }, - { "type": "fix", "section": "Bug Fixes" }, - { "type": "perf", "section": "Performance" } - ] - }, - "infile": "CHANGELOG.md" - } - }, - "hooks": { - "before:release": ["pnpm run build"] - } -} diff --git a/packages/plugin-cjk/CHANGELOG.md b/packages/plugin-cjk/CHANGELOG.md deleted file mode 100644 index 4004468..0000000 --- a/packages/plugin-cjk/CHANGELOG.md +++ /dev/null @@ -1,33 +0,0 @@ -# Changelog - -## 1.0.0 (2026-02-11) - -### Features - -* improve GFM syntax and React support ([30c0ae8](https://github.com/comarkdown/comark/commit/30c0ae81d6bf06cc49a847abcbcaba744dce9363)) -* `@comark/math` package ([3c7538e](https://github.com/comarkdown/comark/commit/3c7538e3bf0b7786103d19929f46e909d67ca1dd)) -* auto unwrap single child paragraphs ([69c5e0c](https://github.com/comarkdown/comark/commit/69c5e0c289a1c575fc67b3df6d7a5e6c0c024130)) -* codeblock meta data ([c1a2a57](https://github.com/comarkdown/comark/commit/c1a2a57754cfde4ccd6da60279774ded5fab291b)) -* headings id and mixed inline components ([20c1a00](https://github.com/comarkdown/comark/commit/20c1a003f2faf86eee270e759e179706cede57fd)) -* line-break ([1599057](https://github.com/comarkdown/comark/commit/1599057d0288edfbacd6599543813a6a97418c6c)) -* shiki code highlighting ([9b6df0c](https://github.com/comarkdown/comark/commit/9b6df0cd0a257b3131e80c616616a167fa74b18c)) -* streaming caret indicator ([8228120](https://github.com/comarkdown/comark/commit/82281202be096fe3ec2e44bb2c74fb79122d5f19)) -* use `yaml` package to parse frontmatter ([e592349](https://github.com/comarkdown/comark/commit/e592349f0e86e7a33f0c5f69408e6d5cb51aa6a3)) - -### Bug Fixes - -* auto-close markdown ([0f76bac](https://github.com/comarkdown/comark/commit/0f76bac15652fa95c57ce1465297cc4a7c5627b1)) -* **auto-close:** improve performance & partial issues ([2aadfc7](https://github.com/comarkdown/comark/commit/2aadfc75597498f68c845d6cf1441a03a78b72e0)) -* **auto-close:** trailing spaces ([8664088](https://github.com/comarkdown/comark/commit/86640888114f9104f81d2575abb6ea6891140fd2)) -* auto-unwrap issue with pargraphs, PascalCase components ([2b9defd](https://github.com/comarkdown/comark/commit/2b9defd2ee1245738df24aa444c06b950a60d11d)) -* detect code block language without space ([621d9ec](https://github.com/comarkdown/comark/commit/621d9ece0d740e0b550da7bb83ae843feef04abd)) -* drop stream components in React ([3702c17](https://github.com/comarkdown/comark/commit/3702c177793ab5d65fd7bd21355a4b7e0f3fb6aa)) -* expose `/vue/*` ([6455b2e](https://github.com/comarkdown/comark/commit/6455b2ec7830188aed2b9ce67767d745d5002b22)) -* lint and tests ([857e0e6](https://github.com/comarkdown/comark/commit/857e0e6c6f4b0304abb26574cb11a7ac7d4ae26c)) -* pre component styles ([31186b1](https://github.com/comarkdown/comark/commit/31186b1b461cf0474117e80bd970430ddc84d4cb)) -* prepack script ([ba3c847](https://github.com/comarkdown/comark/commit/ba3c847c34877aa898f206d59b540bdea6d565ec)) -* **shiki:** dual theme ([2176594](https://github.com/comarkdown/comark/commit/2176594417d72ca62a8f67689fdfa0cdb3d47bfd)) - -### Performance - -* optimize Vue Renderer ([5ee6927](https://github.com/comarkdown/comark/commit/5ee6927f2c2ba132f87770bfe25567ac6949e3ac)) diff --git a/packages/plugin-cjk/build.config.mjs b/packages/plugin-cjk/build.config.mjs deleted file mode 100644 index 83a54e6..0000000 --- a/packages/plugin-cjk/build.config.mjs +++ /dev/null @@ -1,11 +0,0 @@ -import { defineBuildConfig } from 'obuild/config' - -export default defineBuildConfig({ - entries: [ - { - type: 'bundle', - input: ['./src/index.ts'], - }, - ], - externals: ['comark'], -}) diff --git a/packages/plugin-cjk/package.json b/packages/plugin-cjk/package.json deleted file mode 100644 index 9503df2..0000000 --- a/packages/plugin-cjk/package.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "@comark/plugin-cjk", - "type": "module", - "version": "1.0.0", - "description": "CJK support for Comark", - "author": "", - "license": "MIT", - "repository": "comarkdown/comark", - "keywords": [ - "markdown", - "mdc", - "comark", - "parser", - "streaming", - "vue", - "react" - ], - "exports": { - ".": "./dist/index.mjs" - }, - "main": "./dist/index.mjs", - "module": "./dist/index.mjs", - "types": "./dist/index.d.mts", - "files": [ - "dist" - ], - "publishConfig": { - "access": "public" - }, - "scripts": { - "build": "obuild", - "test": "vitest run", - "prepack": "obuild", - "release": "release-it", - "release:dry": "release-it --dry-run" - }, - "dependencies": { - "markdown-it-cjk-friendly": "^2.0.2" - }, - "devDependencies": { - "comark": "workspace:*", - "obuild": "^0.4.31", - "vitest": "^4.0.18" - } -} diff --git a/packages/plugin-cjk/src/index.ts b/packages/plugin-cjk/src/index.ts deleted file mode 100644 index 1676742..0000000 --- a/packages/plugin-cjk/src/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import markdownItCjkFriendly from 'markdown-it-cjk-friendly' -import type { ComarkPlugin, MarkdownItPlugin } from 'comark' - -export default function comarkCjk(): ComarkPlugin { - return { - name: 'cjk', - markdownItPlugins: [markdownItCjkFriendly as unknown as MarkdownItPlugin], - } -} diff --git a/packages/plugin-cjk/test/index.test.ts b/packages/plugin-cjk/test/index.test.ts deleted file mode 100644 index 82960b6..0000000 --- a/packages/plugin-cjk/test/index.test.ts +++ /dev/null @@ -1,248 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { parse } from 'comark' -import comarkCjk from '../src/index' - -describe('@comark/plugin-cjk', () => { - describe('plugin export', () => { - it('should export a valid ComarkPlugin', async () => { - const cjk = comarkCjk() - expect(cjk).toBeDefined() - expect(cjk.markdownItPlugins).toBeDefined() - expect(Array.isArray(cjk.markdownItPlugins)).toBe(true) - expect(cjk.markdownItPlugins?.length).toBe(1) - }) - - it('should have markdownItPlugins as functions', async () => { - const cjk = comarkCjk() - for (const plugin of (cjk.markdownItPlugins || [])) { - expect(typeof plugin).toBe('function') - } - }) - }) - - describe('CJK text parsing', () => { - it('should parse Chinese text correctly', async () => { - const cjk = comarkCjk() - const result = await parse('这是一段中文文本。', { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - expect(result.nodes[0]).toEqual(['p', {}, '这是一段中文文本。']) - }) - - it('should parse Japanese text correctly', async () => { - const cjk = comarkCjk() - const result = await parse('これは日本語のテキストです。', { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - expect(result.nodes[0]).toEqual(['p', {}, 'これは日本語のテキストです。']) - }) - - it('should parse Korean text correctly', async () => { - const cjk = comarkCjk() - const result = await parse('이것은 한국어 텍스트입니다.', { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - expect(result.nodes[0]).toEqual(['p', {}, '이것은 한국어 텍스트입니다.']) - }) - - it('should handle mixed CJK and Latin text', async () => { - const cjk = comarkCjk() - const result = await parse('Hello 世界!', { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - expect(result.nodes[0]).toEqual(['p', {}, 'Hello 世界!']) - }) - - it('should handle CJK with markdown formatting', async () => { - const cjk = comarkCjk() - const result = await parse('**加粗文本** 和 *斜体文本*', { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const p = result.nodes[0] as any[] - expect(p[0]).toBe('p') - expect(p).toContainEqual(['strong', {}, '加粗文本']) - expect(p).toContainEqual(['em', {}, '斜体文本']) - }) - }) - - describe('CJK line breaking', () => { - it('should handle line breaks in CJK text without adding extra spaces', async () => { - const input = `这是第一行 -这是第二行` - const cjk = comarkCjk() - const result = await parse(input, { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const p = result.nodes[0] as any[] - expect(p[0]).toBe('p') - // CJK-friendly plugin should not add space between lines - const text = p.slice(2).join('') - expect(text).not.toContain(' 这是第二行') - }) - - it('should handle line breaks between CJK and Latin text appropriately', async () => { - const input = `Hello -世界` - const cjk = comarkCjk() - const result = await parse(input, { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - }) - - it('should handle soft line breaks in CJK text', async () => { - // CJK-friendly plugin handles soft line breaks appropriately - const input = `第一行 -第二行` - const cjk = comarkCjk() - const result = await parse(input, { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const p = result.nodes[0] as any[] - expect(p[0]).toBe('p') - // Text content should contain both lines - const textContent = p.slice(2).join('') - expect(textContent).toContain('第一行') - expect(textContent).toContain('第二行') - }) - }) - - describe('CJK with Comark components', () => { - it('should parse Comark component with CJK content', async () => { - const input = `::alert -这是一个警告消息。 -::` - const cjk = comarkCjk() - const result = await parse(input, { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const alert = result.nodes[0] as any[] - expect(alert[0]).toBe('alert') - }) - - it('should parse Comark component with CJK props', async () => { - const input = `::card{title="卡片标题"} -卡片内容 -::` - const cjk = comarkCjk() - const result = await parse(input, { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const card = result.nodes[0] as any[] - expect(card[0]).toBe('card') - expect(card[1].title).toBe('卡片标题') - }) - - it('should handle inline component with CJK', async () => { - const input = '这是一个 :badge[徽章] 组件。' - const cjk = comarkCjk() - const result = await parse(input, { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const p = result.nodes[0] as any[] - expect(p[0]).toBe('p') - expect(p.some(child => Array.isArray(child) && child[0] === 'badge')).toBe(true) - }) - }) - - describe('CJK headings', () => { - it('should parse CJK headings', async () => { - const cjk = comarkCjk() - const result = await parse('# 中文标题', { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const h1 = result.nodes[0] as any[] - expect(h1[0]).toBe('h1') - expect(h1[2]).toBe('中文标题') - }) - - it('should generate correct ID for CJK headings', async () => { - const cjk = comarkCjk() - const result = await parse('## 日本語の見出し', { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const h2 = result.nodes[0] as any[] - expect(h2[0]).toBe('h2') - expect(h2[1].id).toBeDefined() - }) - - it('should handle mixed language headings', async () => { - const cjk = comarkCjk() - const result = await parse('### Hello 你好 こんにちは', { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const h3 = result.nodes[0] as any[] - expect(h3[0]).toBe('h3') - }) - }) - - describe('CJK lists', () => { - it('should parse CJK unordered list', async () => { - const input = `- 第一项 -- 第二项 -- 第三项` - const cjk = comarkCjk() - const result = await parse(input, { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const ul = result.nodes[0] as any[] - expect(ul[0]).toBe('ul') - }) - - it('should parse CJK ordered list', async () => { - const input = `1. 第一步 -2. 第二步 -3. 第三步` - const cjk = comarkCjk() - const result = await parse(input, { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const ol = result.nodes[0] as any[] - expect(ol[0]).toBe('ol') - }) - }) - - describe('CJK code blocks', () => { - it('should preserve CJK in inline code', async () => { - const cjk = comarkCjk() - const result = await parse('使用 `代码` 标签', { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const p = result.nodes[0] as any[] - expect(p[0]).toBe('p') - expect(p.some(child => Array.isArray(child) && child[0] === 'code')).toBe(true) - }) - - it('should preserve CJK in code blocks', async () => { - const input = `\`\`\` -// 中文注释 -const msg = "你好世界" -\`\`\`` - const cjk = comarkCjk() - const result = await parse(input, { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const pre = result.nodes[0] as any[] - expect(pre[0]).toBe('pre') - }) - }) - - describe('CJK blockquotes', () => { - it('should parse CJK blockquote', async () => { - const input = `> 这是一段引用文本。 -> 来自某位名人。` - const cjk = comarkCjk() - const result = await parse(input, { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const blockquote = result.nodes[0] as any[] - expect(blockquote[0]).toBe('blockquote') - }) - }) - - describe('CJK tables', () => { - it('should parse CJK table', async () => { - const input = `| 名称 | 描述 | -|------|------| -| 项目A | 这是项目A | -| 项目B | 这是项目B |` - const cjk = comarkCjk() - const result = await parse(input, { plugins: [cjk] }) - expect(result.nodes).toHaveLength(1) - const table = result.nodes[0] as any[] - expect(table[0]).toBe('table') - }) - }) - - describe('comparison with and without plugin', () => { - it('should handle CJK text consistently', async () => { - const input = '中文文本 English text 日本語' - const cjk = comarkCjk() - const withPlugin = await parse(input, { plugins: [cjk] }) - const withoutPlugin = await parse(input) - // Both should produce valid output - expect(withPlugin.nodes).toHaveLength(1) - expect(withoutPlugin.nodes).toHaveLength(1) - }) - }) -}) diff --git a/packages/plugin-cjk/tsconfig.json b/packages/plugin-cjk/tsconfig.json deleted file mode 100644 index 5abae64..0000000 --- a/packages/plugin-cjk/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "es2024", - "lib": ["esnext", "DOM", "DOM.Iterable"], - "module": "esnext", - "moduleResolution": "bundler", - "strict": true, - "strictNullChecks": true, - "esModuleInterop": true, - "skipDefaultLibCheck": true, - "skipLibCheck": true, - "noEmit": true - }, - "include": ["src/**/*", "test/**/*"], - "exclude": ["node_modules", "dist"] -} diff --git a/packages/plugin-cjk/vitest.config.ts b/packages/plugin-cjk/vitest.config.ts deleted file mode 100644 index 3e42797..0000000 --- a/packages/plugin-cjk/vitest.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - test: { - include: ['test/**/*.test.ts'], - }, -}) diff --git a/packages/plugin-math/.gitignore b/packages/plugin-math/.gitignore deleted file mode 100644 index 7ac8ea1..0000000 --- a/packages/plugin-math/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.DS_Store -*.log diff --git a/packages/plugin-math/.release-it.json b/packages/plugin-math/.release-it.json deleted file mode 100644 index e38c1ac..0000000 --- a/packages/plugin-math/.release-it.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "git": { - "commitMessage": "chore(math): release v${version}", - "tagName": "@comark/plugin-math@${version}", - "tagAnnotation": "@comark/plugin-math v${version}", - "requireCleanWorkingDir": true - }, - "github": { - "release": true, - "releaseName": "@comark/plugin-math v${version}" - }, - "npm": { - "publish": true, - "publishPath": "." - }, - "plugins": { - "@release-it/conventional-changelog": { - "ignoreRecommendedBump": true, - "preset": { - "name": "conventionalcommits", - "types": [ - { "type": "feat", "section": "Features" }, - { "type": "fix", "section": "Bug Fixes" }, - { "type": "perf", "section": "Performance" } - ] - }, - "infile": "CHANGELOG.md" - } - }, - "hooks": { - "before:release": ["pnpm run build"] - } -} diff --git a/packages/plugin-math/CHANGELOG.md b/packages/plugin-math/CHANGELOG.md deleted file mode 100644 index f9bd7d0..0000000 --- a/packages/plugin-math/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -# Changelog - -## [1.0.0](https://github.com/comarkdown/comark/compare/@comark/cjk@1.0.0...@comark/cjk@1.0.0) (2026-02-11) diff --git a/packages/plugin-math/README.md b/packages/plugin-math/README.md deleted file mode 100644 index 6859493..0000000 --- a/packages/plugin-math/README.md +++ /dev/null @@ -1,295 +0,0 @@ -# @comark/math - -Math formula support for [comark](https://github.com/comarkdown/comark) using [KaTeX](https://katex.org/). - -## Features - -- ✅ Inline math with `$...$` syntax (tokenized at parse time) -- ✅ Display math with `$$...$$` syntax (tokenized at parse time) -- ✅ HTML output via KaTeX -- ✅ Full LaTeX math syntax support -- ✅ Vue and React components -- ✅ TypeScript support -- ✅ Automatic tokenization during parsing for optimal performance - -## Installation - -```bash -npm install @comark/math comark katex -# or -pnpm add @comark/math comark katex -# or -yarn add @comark/math comark katex -``` - -**Note:** KaTeX is a peer dependency. Make sure to install it and include its CSS. - -## Usage - -### Vue - -```vue - - - -``` - -**Important:** -- The `math` must be passed to parse and tokenize `$...$` and `$$...$$` expressions -- Include KaTeX CSS: `import 'katex/dist/katex.min.css'` in your app -- Comark component requires `` wrapper (it's async) - -### React - -```tsx -import { Comark } from '@comark/react' -import math from '@comark/math' -import { Math } from '@comark/math/react' - -const components = { - math: Math -} - -function App() { - const markdown = ` -# Math Examples - -Inline math: $E = mc^2$ - -Display math: -$$ -\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2} -$$ - ` - - return {markdown} -} -``` - -**Important:** -- The `math` must be passed to parse and tokenize `$...$` and `$$...$$` expressions -- Include KaTeX CSS import - -### Core Parsing API - -```typescript -import { parse } from 'comark' -import math from '@comark/math' - -const result = await parse('Inline $x^2$ and display $$E = mc^2$$', { - plugins: [math()] -}) - -// The AST will contain math nodes with LaTeX content -console.log(result.nodes) -``` - -## How It Works - -The plugin uses a two-stage approach: - -1. **Parse Time (markdown-it plugin):** - - Custom inline rules detect `$...$` and `$$...$$` syntax - - LaTeX expressions are tokenized and stored in the AST - - No rendering happens at this stage - -2. **Render Time (Vue/React components):** - - The `Math` component receives LaTeX content via props - - KaTeX renders the LaTeX to HTML on demand - - Component determines display mode based on CSS class - -This architecture provides optimal performance by separating parsing from rendering. - -## Syntax Support - -The package supports full LaTeX math syntax via KaTeX: - -### Inline vs Display Math - -```markdown -Inline math: $E = mc^2$ appears in the text flow - -Display math (on its own line): -$$ -\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2} -$$ - -Inline display (same line): Text $$E = mc^2$$ more text -``` - -### Basic Operations - -```markdown -$x + y - z$ -$a \times b \div c$ -$x^2 + y^2 = z^2$ -$x_1, x_2, \ldots, x_n$ -``` - -### Fractions and Roots - -```markdown -$\frac{a}{b}$ -$\sqrt{x}$ -$\sqrt[3]{x}$ -``` - -### Greek Letters - -```markdown -$\alpha, \beta, \gamma, \Delta, \Sigma$ -``` - -### Integrals and Sums - -```markdown -$$ -\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2} -$$ - -$$ -\sum_{i=1}^{n} i = \frac{n(n+1)}{2} -$$ -``` - -### Matrices - -```markdown -$$ -\begin{pmatrix} -a & b \\ -c & d -\end{pmatrix} -$$ -``` - -### Limits - -```markdown -$$ -\lim_{x \to \infty} f(x) -$$ -``` - -## Edge Cases - -### Dollar Signs in Text - -The plugin intelligently avoids matching dollar signs that aren't math: - -```markdown -Prices like $100 or $200 won't be parsed as math -``` - -The parser requires: -- At least one character between `$` delimiters -- Content that doesn't start with a digit -- Proper closing delimiter - -### Math in Headings, Lists, Blockquotes - -Math works everywhere: - -```markdown -# Formula $E = mc^2$ - -- Item with $x^2$ -- Another with $y^2$ - -> Quote with $\alpha + \beta$ -``` - -### Code Blocks and Inline Code - -Math is **not** parsed inside code: - -```markdown -Inline code: `$x^2$` stays as-is - -``` -Code block $x^2$ also stays as-is -``` -``` - -## Configuration - -### Math Component Props - -Both Vue and React `Math` components accept: - -- `content` (string, required): The LaTeX expression -- `class` (string, optional): CSS classes (determines inline vs display mode) - -The component automatically renders in display mode when the class contains "block", otherwise inline mode. - -## Troubleshooting - -### Math not rendering - -1. **Plugin not included**: Make sure to pass `plugins: [math()]` to the parse/Comark component -2. **KaTeX CSS not loaded**: Import `'katex/dist/katex.min.css'` in your app -3. **Component not registered**: Register the `Math` component in the components map - -### Math appearing as plain text - -If you see `$x^2$` in the output: -- The plugin might not be loaded -- Check that the plugin is in the `plugins` array - -### Invalid LaTeX errors - -KaTeX will show an error message for invalid LaTeX. Check your syntax: -- Escape backslashes in JavaScript strings: `\\frac` not `\frac` -- Use double backslashes in template strings - -## Performance - -The plugin is designed for performance: - -1. **Parse-time tokenization**: Math is identified during markdown parsing -2. **Lazy rendering**: KaTeX only renders when components mount -3. **No regex scanning at render time**: All pattern matching happens once during parse -4. **Minimal overhead**: LaTeX stored as plain text in AST until render - -## Development - -```bash -# Install dependencies -pnpm install - -# Build -pnpm build - -# Test -pnpm test - -# Run tests in watch mode -pnpm test -- --watch -``` - -## License - -MIT diff --git a/packages/plugin-math/build.config.mjs b/packages/plugin-math/build.config.mjs deleted file mode 100644 index 54e143f..0000000 --- a/packages/plugin-math/build.config.mjs +++ /dev/null @@ -1,11 +0,0 @@ -import { defineBuildConfig } from 'obuild/config' - -export default defineBuildConfig({ - entries: [ - { - type: 'bundle', - input: ['./src/index.ts', './src/vue.ts', './src/react.tsx'], - }, - ], - externals: ['vue', 'react'], -}) diff --git a/packages/plugin-math/package.json b/packages/plugin-math/package.json deleted file mode 100644 index 8fa336e..0000000 --- a/packages/plugin-math/package.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "@comark/plugin-math", - "type": "module", - "version": "1.0.0", - "description": "Math formula support for Comark using KaTeX", - "author": "", - "license": "MIT", - "repository": "comarkdown/comark", - "keywords": [ - "markdown", - "mdc", - "comark", - "math", - "latex", - "katex", - "vue", - "react" - ], - "exports": { - ".": "./dist/index.mjs", - "./vue": "./dist/vue.mjs", - "./react": "./dist/react.mjs" - }, - "main": "./dist/index.mjs", - "module": "./dist/index.mjs", - "types": "./dist/index.d.mts", - "files": [ - "dist" - ], - "publishConfig": { - "access": "public" - }, - "scripts": { - "build": "obuild", - "test": "vitest run", - "prepack": "obuild", - "release": "release-it", - "release:dry": "release-it --dry-run" - }, - "peerDependencies": { - "react": "^19.0.0", - "vue": "^3.5.0" - }, - "peerDependenciesMeta": { - "vue": { - "optional": true - }, - "react": { - "optional": true - } - }, - "dependencies": { - "katex": "^0.16.33" - }, - "devDependencies": { - "comark": "workspace:*", - "obuild": "^0.4.31", - "vitest": "^4.0.18" - } -} diff --git a/packages/plugin-math/test/index.test.ts b/packages/plugin-math/test/index.test.ts deleted file mode 100644 index 370729f..0000000 --- a/packages/plugin-math/test/index.test.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { parse } from 'comark' -import mathPlugin from '../src/index' - -const math = mathPlugin() - -describe('math', () => { - it('should create a plugin with default config', async () => { - const plugin = mathPlugin() - expect(plugin).toBeDefined() - expect(plugin.markdownItPlugins).toBeDefined() - expect(plugin.markdownItPlugins?.length).toBeGreaterThan(0) - }) - - it('should create a plugin with custom config', async () => { - const plugin = mathPlugin() - expect(plugin).toBeDefined() - }) -}) - -describe('markdown-it integration', () => { - it('should parse inline math', async () => { - const result = await parse('The formula $x^2$ is simple', { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('math') - expect(ast).toContain('math inline') - expect(ast).toContain('x^2') - }) - - it('should parse display math on single line', async () => { - const result = await parse('Display: $$E = mc^2$$', { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('math') - expect(ast).toContain('math inline') // Inline $$...$$ creates inline tokens with display mode - expect(ast).toContain('E = mc^2') - }) - - it('should parse multiline display math', async () => { - const markdown = `Formula: -$$ -x^2 + y^2 = z^2 -$$` - const result = await parse(markdown, { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('math') - expect(ast).toContain('math block') - expect(ast).toContain('x^2 + y^2 = z^2') - }) - - it('should parse multiple inline math expressions', async () => { - const result = await parse('Both $x^2$ and $y^2$ are squared', { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('x^2') - expect(ast).toContain('y^2') - expect((ast.match(/math inline/g) || []).length).toBeGreaterThanOrEqual(2) - }) - - it('should parse mixed inline and display math', async () => { - const markdown = `Inline $x^2$ and display: -$$ -E = mc^2 -$$` - const result = await parse(markdown, { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('math inline') - expect(ast).toContain('math block') - expect(ast).toContain('x^2') - expect(ast).toContain('E = mc^2') - }) - - it('should handle text without math', async () => { - const text = 'No math here' - const result = await parse(text, { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).not.toContain('"math"') // Check for the math tag, not the word - }) - - it('should not parse single dollar signs', async () => { - const text = 'Price is $100 or $200' - const result = await parse(text, { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('$100') - expect(ast).toContain('$200') - expect(ast).not.toContain('"math"') - }) - - it('should handle fractions in inline math', async () => { - const result = await parse('The ratio $\\frac{a}{b}$ is important', { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('math inline') - expect(ast).toContain('\\frac{a}{b}') - }) - - it('should handle complex display math', async () => { - const markdown = `$$ -\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2} -$$` - const result = await parse(markdown, { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('math block') - expect(ast).toContain('\\int') - expect(ast).toContain('\\frac') - }) -}) - -describe('complex math expressions', () => { - it('should handle quadratic formula', async () => { - const result = await parse('$x = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}$', { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('math') - expect(ast).toContain('\\frac') - expect(ast).toContain('\\sqrt') - }) - - it('should handle summations', async () => { - const result = await parse('$\\sum_{i=1}^{n} i = \\frac{n(n+1)}{2}$', { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('math') - expect(ast).toContain('\\sum') - }) - - it('should handle matrices', async () => { - const result = await parse('$$\\begin{pmatrix} a & b \\\\ c & d \\end{pmatrix}$$', { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('math') - expect(ast).toContain('pmatrix') - }) - - it('should handle limits', async () => { - const result = await parse('$\\lim_{x \\to \\infty} f(x)$', { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('math') - expect(ast).toContain('\\lim') - }) -}) - -describe('edge cases', () => { - it('should handle empty inline math', async () => { - const result = await parse('Empty $$', { plugins: [math] }) - expect(result.nodes).toBeDefined() - }) - - it('should handle math in headings', async () => { - const result = await parse('# Formula $E = mc^2$', { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('math inline') - expect(ast).toContain('E = mc^2') - }) - - it('should handle math in lists', async () => { - const markdown = `- Item with $x^2$ -- Another with $y^2$` - const result = await parse(markdown, { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('math inline') - expect(ast).toContain('x^2') - expect(ast).toContain('y^2') - }) - - it('should handle math in blockquotes', async () => { - const result = await parse('> Quote with $x^2$', { plugins: [math] }) - const ast = JSON.stringify(result) - expect(ast).toContain('math inline') - expect(ast).toContain('x^2') - }) - - it('should not parse math in code blocks', async () => { - const markdown = '```\n$x^2$\n```' - const result = await parse(markdown, { plugins: [math] }) - const ast = JSON.stringify(result) - // The $ should appear but not as a math token - expect(ast).toContain('$x^2$') - expect(ast).not.toContain('"math"') - }) - - it('should not parse math in inline code', async () => { - const result = await parse('Code `$x^2$` here', { plugins: [math] }) - const ast = JSON.stringify(result) - // Should contain the code element but not math - expect(ast).toContain('code') - expect(ast).toContain('$x^2$') - expect(ast).not.toContain('"math"') - }) -}) diff --git a/packages/plugin-math/tsconfig.json b/packages/plugin-math/tsconfig.json deleted file mode 100644 index 291ac64..0000000 --- a/packages/plugin-math/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "es2024", - "lib": ["esnext", "DOM", "DOM.Iterable"], - "module": "esnext", - "moduleResolution": "bundler", - "jsx": "react-jsx", - "strict": true, - "strictNullChecks": true, - "esModuleInterop": true, - "skipDefaultLibCheck": true, - "skipLibCheck": true, - "noEmit": true - }, - "include": ["src/**/*", "test/**/*"], - "exclude": ["node_modules", "dist"] -} diff --git a/packages/plugin-math/vitest.config.ts b/packages/plugin-math/vitest.config.ts deleted file mode 100644 index 3e42797..0000000 --- a/packages/plugin-math/vitest.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - test: { - include: ['test/**/*.test.ts'], - }, -}) diff --git a/packages/plugin-mermaid/.gitignore b/packages/plugin-mermaid/.gitignore deleted file mode 100644 index 7ac8ea1..0000000 --- a/packages/plugin-mermaid/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.DS_Store -*.log diff --git a/packages/plugin-mermaid/.release-it.json b/packages/plugin-mermaid/.release-it.json deleted file mode 100644 index dd65a60..0000000 --- a/packages/plugin-mermaid/.release-it.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "git": { - "commitMessage": "chore(mermaid): release v${version}", - "tagName": "@comark/plugin-mermaid@${version}", - "tagAnnotation": "@comark/plugin-mermaid v${version}", - "requireCleanWorkingDir": true - }, - "github": { - "release": true, - "releaseName": "@comark/plugin-mermaid v${version}" - }, - "npm": { - "publish": true, - "publishPath": "." - }, - "plugins": { - "@release-it/conventional-changelog": { - "ignoreRecommendedBump": true, - "preset": { - "name": "conventionalcommits", - "types": [ - { "type": "feat", "section": "Features" }, - { "type": "fix", "section": "Bug Fixes" }, - { "type": "perf", "section": "Performance" } - ] - }, - "infile": "CHANGELOG.md" - } - }, - "hooks": { - "before:release": ["pnpm run build"] - } -} diff --git a/packages/plugin-mermaid/CHANGELOG.md b/packages/plugin-mermaid/CHANGELOG.md deleted file mode 100644 index 6361e43..0000000 --- a/packages/plugin-mermaid/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. diff --git a/packages/plugin-mermaid/README.md b/packages/plugin-mermaid/README.md deleted file mode 100644 index 9a7ad25..0000000 --- a/packages/plugin-mermaid/README.md +++ /dev/null @@ -1,346 +0,0 @@ -# @comark/mermaid - -Mermaid diagram support for [comark](https://github.com/comarkdown/comark) using [Mermaid](https://mermaid.js.org/). - -## Features - -- ✅ Mermaid code blocks with ` ```mermaid ` syntax -- ✅ Automatic SVG rendering -- ✅ Full Mermaid diagram types support (flowcharts, sequence diagrams, Gantt charts, etc.) -- ✅ Vue and React components -- ✅ TypeScript support -- ✅ Error handling with visual feedback -- ✅ Customizable themes - -## Installation - -```bash -npm install @comark/mermaid comark mermaid -# or -pnpm add @comark/mermaid comark mermaid -# or -yarn add @comark/mermaid comark mermaid -``` - -**Note:** Mermaid is a peer dependency. Make sure to install it. - -## Usage - -### Vue - -```vue - - - -``` - -**Important:** -- The `mermaid` must be passed to identify and parse mermaid code blocks -- Comark component requires `` wrapper (it's async) - -### React - -```tsx -import { Comark } from '@comark/react' -import mermaid from '@comark/mermaid' -import { Mermaid } from '@comark/mermaid/react' - -const components = { - mermaid: Mermaid -} - -function App() { - const markdown = ` -# Diagram Example - -\`\`\`mermaid -graph TD - A[Start] --> B{Is it working?} - B -->|Yes| C[Great!] - B -->|No| D[Debug] - D --> A -\`\`\` - ` - - return {markdown} -} -``` - -**Important:** -- The `mermaid` must be passed to identify and parse mermaid code blocks - -### Core Parsing API - -```typescript -import { parse } from 'comark' -import mermaid from '@comark/mermaid' - -const result = await parse(` -\`\`\`mermaid -graph LR - A --> B -\`\`\` -`, { - plugins: [mermaid()] -}) - -// The AST will contain mermaid nodes with diagram code -console.log(result.nodes) -``` - -## How It Works - -The plugin uses a two-stage approach: - -1. **Parse Time (markdown-it plugin):** - - Identifies code blocks with `mermaid` language - - Stores the diagram code in the AST - - No rendering happens at this stage - -2. **Render Time (Vue/React components):** - - The `Mermaid` component receives diagram code via props - - Mermaid renders the diagram to SVG on demand - - Component displays error messages if rendering fails - -This architecture provides optimal performance by separating parsing from rendering. - -## Supported Diagram Types - -Mermaid supports many diagram types: - -### Flowcharts - -````markdown -```mermaid -graph TD - A[Start] --> B{Decision} - B -->|Yes| C[Action 1] - B -->|No| D[Action 2] -``` -```` - -### Sequence Diagrams - -````markdown -```mermaid -sequenceDiagram - participant Alice - participant Bob - Alice->>Bob: Hello Bob! - Bob->>Alice: Hello Alice! -``` -```` - -### Class Diagrams - -````markdown -```mermaid -classDiagram - Animal <|-- Duck - Animal <|-- Fish - Animal : +int age - Animal : +String gender - Animal: +isMammal() -``` -```` - -### State Diagrams - -````markdown -```mermaid -stateDiagram-v2 - [*] --> Still - Still --> [*] - Still --> Moving - Moving --> Still - Moving --> Crash - Crash --> [*] -``` -```` - -### Gantt Charts - -````markdown -```mermaid -gantt - title Project Timeline - dateFormat YYYY-MM-DD - section Planning - Task 1 :a1, 2024-01-01, 30d - Task 2 :after a1, 20d -``` -```` - -### Pie Charts - -````markdown -```mermaid -pie title Pets adopted by volunteers - "Dogs" : 386 - "Cats" : 85 - "Rats" : 15 -``` -```` - -### Git Graphs - -````markdown -```mermaid -gitGraph - commit - branch develop - checkout develop - commit - checkout main - merge develop -``` -```` - -### ER Diagrams - -````markdown -```mermaid -erDiagram - CUSTOMER ||--o{ ORDER : places - ORDER ||--|{ LINE-ITEM : contains - CUSTOMER }|..|{ DELIVERY-ADDRESS : uses -``` -```` - -### Journey Diagrams - -````markdown -```mermaid -journey - title My working day - section Go to work - Make tea: 5: Me - Go upstairs: 3: Me - section Work - Do work: 1: Me, Cat -``` -```` - -## Configuration - -### Theme Support - -You can configure the mermaid theme: - -```typescript -import { createMermaidPlugin } from '@comark/mermaid' - -const mermaid = createMermaidPlugin({ - theme: 'dark' // 'default' | 'dark' | 'forest' | 'neutral' -}) -``` - -### Advanced Configuration - -Pass custom mermaid options: - -```typescript -const mermaid = createMermaidPlugin({ - theme: 'dark', - options: { - fontFamily: 'Arial', - flowchart: { - curve: 'basis' - } - } -}) -``` - -### Mermaid Component Props - -Both Vue and React `Mermaid` components accept: - -- `content` (string, required): The Mermaid diagram code -- `class` (string, optional): CSS classes for styling - -## Troubleshooting - -### Diagrams not rendering - -1. **Plugin not included**: Make sure to pass `plugins: [mermaid()]` to the parse/Comark component -2. **Component not registered**: Register the `Mermaid` component in the components map -3. **Syntax errors**: Check the Mermaid syntax - the component will display error messages - -### Diagrams appearing as code blocks - -If you see the raw mermaid code in a code block: -- The plugin might not be loaded -- Check that the plugin is in the `plugins` array -- Ensure the code block uses `mermaid` as the language - -### Invalid syntax errors - -The component will show a visual error message for invalid Mermaid syntax: -- Check your diagram syntax at [Mermaid Live Editor](https://mermaid.live) -- Review the [Mermaid documentation](https://mermaid.js.org/intro/) - -### Performance issues - -For pages with many diagrams: -- Consider lazy loading diagrams -- Use code splitting for the mermaid dependency -- Mermaid diagrams are rendered client-side and can be CPU-intensive - -## Performance - -The plugin is designed for performance: - -1. **Parse-time identification**: Diagrams are identified during markdown parsing -2. **Lazy rendering**: Mermaid only renders when components mount -3. **No regex scanning at render time**: All pattern matching happens once during parse -4. **Minimal overhead**: Diagram code stored as plain text in AST until render - -## Development - -```bash -# Install dependencies -pnpm install - -# Build -pnpm build - -# Test -pnpm test - -# Run tests in watch mode -pnpm test -- --watch -``` - -## Resources - -- [Mermaid Documentation](https://mermaid.js.org/intro/) -- [Mermaid Live Editor](https://mermaid.live) - Test your diagrams -- [Mermaid Cheat Sheet](https://jojozhuang.github.io/tutorial/mermaid-cheat-sheet/) - -## License - -MIT diff --git a/packages/plugin-mermaid/build.config.mjs b/packages/plugin-mermaid/build.config.mjs deleted file mode 100644 index 54e143f..0000000 --- a/packages/plugin-mermaid/build.config.mjs +++ /dev/null @@ -1,11 +0,0 @@ -import { defineBuildConfig } from 'obuild/config' - -export default defineBuildConfig({ - entries: [ - { - type: 'bundle', - input: ['./src/index.ts', './src/vue.ts', './src/react.tsx'], - }, - ], - externals: ['vue', 'react'], -}) diff --git a/packages/plugin-mermaid/package.json b/packages/plugin-mermaid/package.json deleted file mode 100644 index 684d6d3..0000000 --- a/packages/plugin-mermaid/package.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "@comark/plugin-mermaid", - "type": "module", - "version": "1.0.0", - "description": "Mermaid diagram support for Comark", - "author": "", - "license": "MIT", - "repository": "comarkdown/comark", - "keywords": [ - "markdown", - "mdc", - "comark", - "mermaid", - "diagram", - "flowchart", - "vue", - "react" - ], - "exports": { - ".": "./dist/index.mjs", - "./vue": "./dist/vue.mjs", - "./react": "./dist/react.mjs" - }, - "main": "./dist/index.mjs", - "module": "./dist/index.mjs", - "types": "./dist/index.d.mts", - "files": [ - "dist" - ], - "publishConfig": { - "access": "public" - }, - "scripts": { - "build": "obuild", - "test": "vitest run", - "prepack": "obuild", - "release": "release-it", - "release:dry": "release-it --dry-run" - }, - "peerDependencies": { - "react": "^19.0.0", - "vue": "^3.5.0" - }, - "peerDependenciesMeta": { - "vue": { - "optional": true - }, - "react": { - "optional": true - } - }, - "dependencies": { - "beautiful-mermaid": "^1.1.3" - }, - "devDependencies": { - "comark": "workspace:*", - "obuild": "^0.4.31", - "vitest": "^4.0.18" - } -} diff --git a/packages/plugin-mermaid/test/index.test.ts b/packages/plugin-mermaid/test/index.test.ts deleted file mode 100644 index 2e0804f..0000000 --- a/packages/plugin-mermaid/test/index.test.ts +++ /dev/null @@ -1,339 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { parse } from 'comark' -import comarkMermaid from '../src/index' - -const mermaid = comarkMermaid() - -describe('comarkMermaid', () => { - it('should create a plugin with default config', async () => { - const plugin = comarkMermaid() - expect(plugin).toBeDefined() - expect(plugin.markdownItPlugins).toBeDefined() - expect(plugin.markdownItPlugins?.length).toBeGreaterThan(0) - }) - - it('should create a plugin with custom config', async () => { - const plugin = comarkMermaid({ theme: 'zinc-dark' }) - expect(plugin).toBeDefined() - expect(plugin.markdownItPlugins).toBeDefined() - }) - - it('should create a plugin with custom options', async () => { - const plugin = comarkMermaid({ theme: 'zinc-dark' }) - expect(plugin).toBeDefined() - }) -}) - -describe('markdown-it integration', () => { - it('should parse mermaid code block', async () => { - const markdown = `\`\`\`mermaid -graph TD - A --> B -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('graph TD') - }) - - it('should parse flowchart diagram', async () => { - const markdown = `\`\`\`mermaid -graph TD - A[Start] --> B{Is it working?} - B -->|Yes| C[Great!] - B -->|No| D[Debug] -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('graph TD') - expect(ast).toContain('Start') - }) - - it('should parse sequence diagram', async () => { - const markdown = `\`\`\`mermaid -sequenceDiagram - Alice->>Bob: Hello Bob! - Bob-->>Alice: Hello Alice! -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('sequenceDiagram') - expect(ast).toContain('Alice') - }) - - it('should parse class diagram', async () => { - const markdown = `\`\`\`mermaid -classDiagram - Animal <|-- Duck - Animal : +int age -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('classDiagram') - }) - - it('should parse state diagram', async () => { - const markdown = `\`\`\`mermaid -stateDiagram-v2 - [*] --> Still - Still --> Moving -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('stateDiagram') - }) - - it('should parse gantt chart', async () => { - const markdown = `\`\`\`mermaid -gantt - title Project Timeline - section Planning - Task 1 :a1, 2024-01-01, 30d -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('gantt') - }) - - it('should parse pie chart', async () => { - const markdown = `\`\`\`mermaid -pie title Pets - "Dogs" : 386 - "Cats" : 85 -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('pie') - }) - - it('should parse ER diagram', async () => { - const markdown = `\`\`\`mermaid -erDiagram - CUSTOMER ||--o{ ORDER : places -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('erDiagram') - }) - - it('should parse git graph', async () => { - const markdown = `\`\`\`mermaid -gitGraph - commit - branch develop - checkout develop -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('gitGraph') - }) - - it('should not parse non-mermaid code blocks', async () => { - const markdown = `\`\`\`javascript -const x = 1 -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).not.toContain('"mermaid"') - expect(ast).toContain('javascript') - }) - - it('should handle multiple mermaid blocks', async () => { - const markdown = `\`\`\`mermaid -graph TD - A --> B -\`\`\` - -Some text - -\`\`\`mermaid -sequenceDiagram - Alice->>Bob: Hi -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('graph TD') - expect(ast).toContain('sequenceDiagram') - }) - - it('should handle text without mermaid', async () => { - const text = 'No diagrams here' - const result = await parse(text, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).not.toContain('"mermaid"') - }) -}) - -describe('complex mermaid diagrams', () => { - it('should handle complex flowchart with styling', async () => { - const markdown = `\`\`\`mermaid -graph TB - A[Christmas] -->|Get money| B(Go shopping) - B --> C{Let me think} - C -->|One| D[Laptop] - C -->|Two| E[iPhone] - C -->|Three| F[Car] -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('Christmas') - }) - - it('should handle multiline sequence diagram', async () => { - const markdown = `\`\`\`mermaid -sequenceDiagram - participant User - participant App - participant API - User->>App: Request data - App->>API: Fetch data - API-->>App: Return data - App-->>User: Display data -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('participant') - }) - - it('should handle diagram with notes', async () => { - const markdown = `\`\`\`mermaid -sequenceDiagram - Alice->>John: Hello John - Note right of John: John thinks - John-->>Alice: Hi Alice -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('Note') - }) -}) - -describe('edge cases', () => { - it('should handle empty mermaid block', async () => { - const markdown = `\`\`\`mermaid -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - expect(result.nodes).toBeDefined() - }) - - it('should handle mermaid block with whitespace', async () => { - const markdown = `\`\`\`mermaid - -graph TD - A --> B - -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - }) - - it('should handle mermaid with markdown around it', async () => { - const markdown = `# Heading - -\`\`\`mermaid -graph TD - A --> B -\`\`\` - -Some text after` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('Heading') - }) - - it('should handle mermaid in lists', async () => { - const markdown = `- Item 1 - \`\`\`mermaid - graph TD - A --> B - \`\`\` -- Item 2` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - }) - - it('should not parse inline code as mermaid', async () => { - const result = await parse('Inline `mermaid` code', { plugins: [mermaid] }) - const p = result.nodes[0] as any[] - // Should have code element, not mermaid element - expect(p[0]).toBe('p') - expect(p.some(child => Array.isArray(child) && child[0] === 'code')).toBe(true) - expect(p.some(child => Array.isArray(child) && child[0] === 'mermaid')).toBe(false) - }) - - it('should preserve indentation in mermaid code', async () => { - const markdown = `\`\`\`mermaid -graph TD - A --> B - B --> C -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('A --> B') - }) -}) - -describe('integration with other markdown features', () => { - it('should work with headings and mermaid', async () => { - const markdown = `# Diagram - -\`\`\`mermaid -graph TD - A --> B -\`\`\` - -## Another Section` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('h1') - expect(ast).toContain('mermaid') - expect(ast).toContain('h2') - }) - - it('should work with blockquotes', async () => { - const markdown = `> Quote -> -> \`\`\`mermaid -> graph TD -> A --> B -> \`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('blockquote') - }) - - it('should work with other code blocks', async () => { - const markdown = `\`\`\`javascript -const x = 1 -\`\`\` - -\`\`\`mermaid -graph TD - A --> B -\`\`\` - -\`\`\`python -x = 1 -\`\`\`` - const result = await parse(markdown, { plugins: [mermaid] }) - const ast = JSON.stringify(result) - expect(ast).toContain('mermaid') - expect(ast).toContain('javascript') - expect(ast).toContain('python') - }) -}) diff --git a/packages/plugin-mermaid/tsconfig.json b/packages/plugin-mermaid/tsconfig.json deleted file mode 100644 index 291ac64..0000000 --- a/packages/plugin-mermaid/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "es2024", - "lib": ["esnext", "DOM", "DOM.Iterable"], - "module": "esnext", - "moduleResolution": "bundler", - "jsx": "react-jsx", - "strict": true, - "strictNullChecks": true, - "esModuleInterop": true, - "skipDefaultLibCheck": true, - "skipLibCheck": true, - "noEmit": true - }, - "include": ["src/**/*", "test/**/*"], - "exclude": ["node_modules", "dist"] -} diff --git a/packages/plugin-mermaid/vitest.config.ts b/packages/plugin-mermaid/vitest.config.ts deleted file mode 100644 index 3e42797..0000000 --- a/packages/plugin-mermaid/vitest.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - test: { - include: ['test/**/*.test.ts'], - }, -}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0907ed0..31b7dee 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -62,15 +62,9 @@ importers: '@comark/nuxt': specifier: workspace:* version: link:../packages/comark-nuxt - '@comark/plugin-cjk': - specifier: workspace:* - version: link:../packages/plugin-cjk - '@comark/plugin-math': - specifier: workspace:* - version: link:../packages/plugin-math - '@comark/plugin-mermaid': + '@comark/vue': specifier: workspace:* - version: link:../packages/plugin-mermaid + version: link:../packages/comark-vue '@monaco-editor/loader': specifier: ^1.7.0 version: 1.7.0 @@ -293,9 +287,6 @@ importers: examples/3.plugins/vue-vite-cjk: dependencies: - '@comark/plugin-cjk': - specifier: workspace:* - version: link:../../../packages/plugin-cjk comark: specifier: workspace:* version: link:../../../packages/comark @@ -349,12 +340,9 @@ importers: examples/3.plugins/vue-vite-math: dependencies: - '@comark/plugin-math': - specifier: workspace:* - version: link:../../../packages/plugin-math - comark: + '@comark/vue': specifier: workspace:* - version: link:../../../packages/comark + version: link:../../../packages/comark-vue katex: specifier: ^0.16.33 version: 0.16.33 @@ -377,15 +365,12 @@ importers: examples/3.plugins/vue-vite-mermaid: dependencies: - '@comark/plugin-mermaid': + '@comark/vue': specifier: workspace:* - version: link:../../../packages/plugin-mermaid + version: link:../../../packages/comark-vue '@tailwindcss/vite': specifier: ^4.2.1 version: 4.2.1(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) - comark: - specifier: workspace:* - version: link:../../../packages/comark vue: specifier: ^3.5.29 version: 3.5.29(typescript@5.9.3) @@ -411,9 +396,21 @@ importers: packages/comark: dependencies: + '@comark/markdown-it': + specifier: ^0.3.1 + version: 0.3.1(@types/markdown-it@14.1.2)(markdown-it@14.1.1) + beautiful-mermaid: + specifier: ^1.1.3 + version: 1.1.3 + entities: + specifier: ^4.5.0 + version: 4.5.0 js-yaml: specifier: ^4.1.1 version: 4.1.1 + katex: + specifier: ^0.16.33 + version: 0.16.33 markdown-exit: specifier: 1.0.0-beta.9 version: 1.0.0-beta.9 @@ -421,12 +418,6 @@ importers: specifier: ^3.22.0 version: 3.22.0 devDependencies: - '@comark/markdown-it': - specifier: ^0.3.1 - version: 0.3.1(@types/markdown-it@14.1.2)(markdown-it@14.1.1) - '@comark/plugin-cjk': - specifier: workspace:* - version: link:../plugin-cjk '@shikijs/primitive': specifier: ^4.0.1 version: 4.0.1 @@ -448,9 +439,6 @@ importers: mitata: specifier: ^1.0.34 version: 1.0.34 - obuild: - specifier: ^0.4.31 - version: 0.4.31(chokidar@5.0.0)(dotenv@17.2.3)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.1)(picomatch@4.0.3)(rollup@4.57.1)(typescript@5.9.3)(vue-tsc@3.2.5(typescript@5.9.3)) tsx: specifier: ^4.21.0 version: 4.21.0 @@ -472,10 +460,6 @@ importers: nuxt: specifier: ^3.0.0 version: 3.21.1(@parcel/watcher@2.5.6)(@types/node@25.3.3)(@vue/compiler-sfc@3.5.29)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(eslint@10.0.2(jiti@2.6.1))(ioredis@5.9.2)(lightningcss@1.31.1)(magicast@0.5.1)(meow@13.2.0)(optionator@0.9.4)(rolldown@1.0.0-rc.5)(rollup@4.57.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.5(typescript@5.9.3))(yaml@2.8.2) - devDependencies: - obuild: - specifier: ^0.4.31 - version: 0.4.31(chokidar@5.0.0)(dotenv@17.2.3)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.1)(picomatch@4.0.3)(rollup@4.57.1)(typescript@5.9.3)(vue-tsc@3.2.5(typescript@5.9.3)) packages/comark-react: dependencies: @@ -492,9 +476,6 @@ importers: '@types/react-dom': specifier: ^19.0.0 version: 19.2.3(@types/react@19.2.14) - obuild: - specifier: ^0.4.31 - version: 0.4.31(chokidar@5.0.0)(dotenv@17.2.3)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.1)(picomatch@4.0.3)(rollup@4.57.1)(typescript@5.9.3)(vue-tsc@3.2.5(typescript@5.9.3)) react: specifier: ^19.0.0 version: 19.2.4 @@ -514,9 +495,6 @@ importers: '@vue/server-renderer': specifier: ^3.5.0 version: 3.5.29(vue@3.5.29(typescript@5.9.3)) - obuild: - specifier: ^0.4.31 - version: 0.4.31(chokidar@5.0.0)(dotenv@17.2.3)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.1)(picomatch@4.0.3)(rollup@4.57.1)(typescript@5.9.3)(vue-tsc@3.2.5(typescript@5.9.3)) vitest: specifier: ^4.0.18 version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) @@ -524,66 +502,6 @@ importers: specifier: ^3.5.0 version: 3.5.29(typescript@5.9.3) - packages/plugin-cjk: - dependencies: - markdown-it-cjk-friendly: - specifier: ^2.0.2 - version: 2.0.2(@types/markdown-it@14.1.2)(markdown-it@14.1.1) - devDependencies: - comark: - specifier: workspace:* - version: link:../comark - obuild: - specifier: ^0.4.31 - version: 0.4.31(chokidar@5.0.0)(dotenv@17.2.3)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.1)(picomatch@4.0.3)(rollup@4.57.1)(typescript@5.9.3)(vue-tsc@3.2.5(typescript@5.9.3)) - vitest: - specifier: ^4.0.18 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - - packages/plugin-math: - dependencies: - katex: - specifier: ^0.16.33 - version: 0.16.33 - react: - specifier: ^19.0.0 - version: 19.2.4 - vue: - specifier: ^3.5.0 - version: 3.5.29(typescript@5.9.3) - devDependencies: - comark: - specifier: workspace:* - version: link:../comark - obuild: - specifier: ^0.4.31 - version: 0.4.31(chokidar@5.0.0)(dotenv@17.2.3)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.1)(picomatch@4.0.3)(rollup@4.57.1)(typescript@5.9.3)(vue-tsc@3.2.5(typescript@5.9.3)) - vitest: - specifier: ^4.0.18 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - - packages/plugin-mermaid: - dependencies: - beautiful-mermaid: - specifier: ^1.1.3 - version: 1.1.3 - react: - specifier: ^19.0.0 - version: 19.2.4 - vue: - specifier: ^3.5.0 - version: 3.5.29(typescript@5.9.3) - devDependencies: - comark: - specifier: workspace:* - version: link:../comark - obuild: - specifier: ^0.4.31 - version: 0.4.31(chokidar@5.0.0)(dotenv@17.2.3)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.1)(picomatch@4.0.3)(rollup@4.57.1)(typescript@5.9.3)(vue-tsc@3.2.5(typescript@5.9.3)) - vitest: - specifier: ^4.0.18 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - packages: '@ai-sdk/gateway@3.0.66': @@ -737,10 +655,6 @@ packages: resolution: {integrity: sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==} engines: {node: '>=6.9.0'} - '@babel/generator@8.0.0-rc.2': - resolution: {integrity: sha512-oCQ1IKPwkzCeJzAPb7Fv8rQ9k5+1sG8mf2uoHiMInPYvkRfrDJxbTIbH51U+jstlkghus0vAi3EBvkfvEsYNLQ==} - engines: {node: ^20.19.0 || >=22.12.0} - '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} @@ -795,18 +709,10 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@8.0.0-rc.2': - resolution: {integrity: sha512-noLx87RwlBEMrTzncWd/FvTxoJ9+ycHNg0n8yyYydIoDsLZuxknKgWRJUqcrVkNrJ74uGyhWQzQaS3q8xfGAhQ==} - engines: {node: ^20.19.0 || >=22.12.0} - '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@8.0.0-rc.2': - resolution: {integrity: sha512-xExUBkuXWJjVuIbO7z6q7/BA9bgfJDEhVL0ggrggLMbg0IzCUWGT1hZGE8qUH7Il7/RD/a6cZ3AAFrrlp1LF/A==} - engines: {node: ^20.19.0 || >=22.12.0} - '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} @@ -820,11 +726,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@8.0.0-rc.2': - resolution: {integrity: sha512-29AhEtcq4x8Dp3T72qvUMZHx0OMXCj4Jy/TEReQa+KWLln524Cj1fWb3QFi0l/xSpptQBR6y9RNEXuxpFvwiUQ==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - '@babel/plugin-syntax-jsx@7.28.6': resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} @@ -871,10 +772,6 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@babel/types@8.0.0-rc.2': - resolution: {integrity: sha512-91gAaWRznDwSX4E2tZ1YjBuIfnQVOFDCQ2r0Toby0gu4XEbyF623kXLMA8d4ZbCu+fINcrudkmEcwSUHgDDkNw==} - engines: {node: ^20.19.0 || >=22.12.0} - '@bomb.sh/tab@0.0.12': resolution: {integrity: sha512-dYRwg4MqfHR5/BcTy285XOGRhjQFmNpaJBZ0tl2oU+RY595MQ5ApTF6j3OvauPAooHL6cfoOZMySQrOQztT8RQ==} hasBin: true @@ -4205,9 +4102,6 @@ packages: '@types/js-yaml@4.0.9': resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} - '@types/jsesc@2.5.1': - resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} - '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -5058,10 +4952,6 @@ packages: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} - array-find-index@1.0.2: - resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} - engines: {node: '>=0.10.0'} - array-ify@1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} @@ -5076,10 +4966,6 @@ packages: resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} engines: {node: '>=20.19.0'} - ast-kit@3.0.0-beta.1: - resolution: {integrity: sha512-trmleAnZ2PxN/loHWVhhx1qeOHSRXq4TDsBBxq3GqeJitfk3+jTQ+v/C1km/KYq9M7wKqCewMh+/NAvVH7m+bw==} - engines: {node: '>=20.19.0'} - ast-types@0.13.4: resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} engines: {node: '>=4'} @@ -5184,9 +5070,6 @@ packages: birpc@2.9.0: resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} - birpc@4.0.0: - resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} - bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -5253,26 +5136,6 @@ packages: magicast: optional: true - c12@4.0.0-beta.3: - resolution: {integrity: sha512-15pHxeM4kKKnF1zPgvXq/ETPhf9DRLGg0Id3GAyQhQqYxt8WkUCbo0NipHjQUUNC5VPP8TQA32pGPDUZmAi/3g==} - peerDependencies: - chokidar: ^5 - dotenv: '*' - giget: '*' - jiti: '*' - magicast: '*' - peerDependenciesMeta: - chokidar: - optional: true - dotenv: - optional: true - giget: - optional: true - jiti: - optional: true - magicast: - optional: true - cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -5445,9 +5308,6 @@ packages: resolution: {integrity: sha512-aRDkn3uyIlCFfk5NUA+VdwMmMsh8JGhc4hapfV4yxymHGQ3BVskMQfoXGpCo5IoBuQ9tS5iiVKhCpTcB4pW4qw==} engines: {node: '>= 12.0.0'} - commenting@1.1.0: - resolution: {integrity: sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA==} - common-ancestor-path@1.0.1: resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} @@ -5822,15 +5682,6 @@ packages: resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} engines: {node: '>=4'} - dts-resolver@2.1.3: - resolution: {integrity: sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==} - engines: {node: '>=20.19.0'} - peerDependencies: - oxc-resolver: '>=11.0.0' - peerDependenciesMeta: - oxc-resolver: - optional: true - dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -6444,9 +6295,6 @@ packages: get-tsconfig@4.13.1: resolution: {integrity: sha512-EoY1N2xCn44xU6750Sx7OjOIT59FkmstNc3X6y5xpz7D5cBtZRe/3pSlTkDJgqsOk3WwZPkWfonhhUJfttQo3w==} - get-tsconfig@4.13.6: - resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} - get-uri@6.0.5: resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} engines: {node: '>= 14'} @@ -7177,16 +7025,6 @@ packages: markdown-exit@1.0.0-beta.9: resolution: {integrity: sha512-5tzrMKMF367amyBly131vm6eGuWRL2DjBqWaFmPzPbLyuxP0XOmyyyroOAIXuBAMF/3kZbbfqOxvW/SotqKqbQ==} - markdown-it-cjk-friendly@2.0.2: - resolution: {integrity: sha512-KXCl6sd129UqkAiRDb+NcAHrxC9xRa2WsGIsMMvtp2y1YlbeIaNYzArX2zfDoGhOjsyNMfJrGO7xGBss27YQSA==} - engines: {node: '>=18'} - peerDependencies: - '@types/markdown-it': '*' - markdown-it: '*' - peerDependenciesMeta: - '@types/markdown-it': - optional: true - markdown-it-math@5.2.1: resolution: {integrity: sha512-0YJczaqvBxgOt13oKj/4HYs/34Y9FsHiTktsIBaWYqrE+k1JxmMSTxCcTezTVul0YjmhmCBDehK65vWxjzRbdg==} peerDependencies: @@ -7458,9 +7296,6 @@ packages: mocked-exports@0.1.1: resolution: {integrity: sha512-aF7yRQr/Q0O2/4pIXm6PZ5G+jAd7QS4Yu8m+WEeEHGnbo+7mE36CbLSDQiXYV8bVL3NfmdeqPJct0tUlnjVSnA==} - moment@2.30.1: - resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} - motion-dom@12.30.1: resolution: {integrity: sha512-QXB+iFJRzZTqL+Am4a1CRoHdH+0Nq12wLdqQQZZsfHlp9AMt6PA098L/61oVZsDA+Ep3QSGudzpViyRrhYhGcQ==} @@ -7711,10 +7546,6 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - obuild@0.4.31: - resolution: {integrity: sha512-qv3wn5pQbcxXWH8gOzD4Gp36ssrgnbvraFoJuaI1ZjSVM4IHDQ2jBNYCtaDS8IHYHVh/kOf8Lu9JJHpAuPWmFg==} - hasBin: true - ofetch@1.5.1: resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} @@ -7839,10 +7670,6 @@ packages: package-manager-detector@1.6.0: resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} - package-name-regex@2.0.6: - resolution: {integrity: sha512-gFL35q7kbE/zBaPA3UKhp2vSzcPYx2ecbYuwv1ucE9Il6IIgBDweBlH8D68UFGZic2MkllKa2KHCfC1IQBQUYA==} - engines: {node: '>=12'} - pako@0.2.9: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} @@ -8508,36 +8335,11 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rolldown-plugin-dts@0.22.4: - resolution: {integrity: sha512-pueqTPyN1N6lWYivyDGad+j+GO3DT67pzpct8s8e6KGVIezvnrDjejuw1AXFeyDRas3xTq4Ja6Lj5R5/04C5GQ==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@ts-macro/tsc': ^0.3.6 - '@typescript/native-preview': '>=7.0.0-dev.20250601.1' - rolldown: ^1.0.0-rc.3 - typescript: ^5.0.0 || ^6.0.0-beta - vue-tsc: ~3.2.0 - peerDependenciesMeta: - '@ts-macro/tsc': - optional: true - '@typescript/native-preview': - optional: true - typescript: - optional: true - vue-tsc: - optional: true - rolldown@1.0.0-rc.5: resolution: {integrity: sha512-0AdalTs6hNTioaCYIkAa7+xsmHBfU5hCNclZnM/lp7lGGDuUOb6N4BVNtwiomybbencDjq/waKjTImqiGCs5sw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup-plugin-license@3.7.0: - resolution: {integrity: sha512-RvvOIF+GH3fBR3wffgc/vmjQn6qOn72WjppWVDp/v+CLpT0BbcRBdSkPeeIOL6U5XccdYgSIMjUyXgxlKEEFcw==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 - rollup-plugin-visualizer@6.0.5: resolution: {integrity: sha512-9+HlNgKCVbJDs8tVtjQ43US12eqaiHyyiLMdBwQ7vSZPiHMysGNo2E88TAp1si5wx8NAoYriI2A5kuKfIakmJg==} engines: {node: '>=18'} @@ -8792,9 +8594,6 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - spdx-compare@1.0.0: - resolution: {integrity: sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==} - spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} @@ -8807,18 +8606,9 @@ packages: spdx-expression-parse@4.0.0: resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} - spdx-expression-validate@2.0.0: - resolution: {integrity: sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg==} - spdx-license-ids@3.0.22: resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} - spdx-ranges@2.1.1: - resolution: {integrity: sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==} - - spdx-satisfies@5.0.1: - resolution: {integrity: sha512-Nwor6W6gzFp8XX4neaKQ7ChV4wmpSh2sSDemMFSzHxpTw460jxFYeOn+jq4ybnSSw/5sc3pjka9MQPouksQNpw==} - speakingurl@14.0.1: resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} engines: {node: '>=0.10.0'} @@ -10232,15 +10022,6 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/generator@8.0.0-rc.2': - dependencies: - '@babel/parser': 8.0.0-rc.2 - '@babel/types': 8.0.0-rc.2 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - '@types/jsesc': 2.5.1 - jsesc: 3.1.0 - '@babel/helper-annotate-as-pure@7.27.3': dependencies: '@babel/types': 7.29.0 @@ -10315,12 +10096,8 @@ snapshots: '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-string-parser@8.0.0-rc.2': {} - '@babel/helper-validator-identifier@7.28.5': {} - '@babel/helper-validator-identifier@8.0.0-rc.2': {} - '@babel/helper-validator-option@7.27.1': {} '@babel/helpers@7.28.6': @@ -10332,10 +10109,6 @@ snapshots: dependencies: '@babel/types': 7.29.0 - '@babel/parser@8.0.0-rc.2': - dependencies: - '@babel/types': 8.0.0-rc.2 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 @@ -10392,11 +10165,6 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@babel/types@8.0.0-rc.2': - dependencies: - '@babel/helper-string-parser': 8.0.0-rc.2 - '@babel/helper-validator-identifier': 8.0.0-rc.2 - '@bomb.sh/tab@0.0.12(cac@6.7.14)(citty@0.2.0)': optionalDependencies: cac: 6.7.14 @@ -12813,7 +12581,8 @@ snapshots: '@oxc-project/types@0.112.0': {} - '@oxc-project/types@0.114.0': {} + '@oxc-project/types@0.114.0': + optional: true '@oxc-project/types@0.95.0': {} @@ -13126,7 +12895,8 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.3': {} - '@rolldown/pluginutils@1.0.0-rc.5': {} + '@rolldown/pluginutils@1.0.0-rc.5': + optional: true '@rollup/plugin-alias@6.0.0(rollup@4.57.1)': optionalDependencies: @@ -14076,8 +13846,6 @@ snapshots: '@types/js-yaml@4.0.9': {} - '@types/jsesc@2.5.1': {} - '@types/json-schema@7.0.15': {} '@types/linkify-it@5.0.0': {} @@ -15052,8 +14820,6 @@ snapshots: aria-query@5.3.2: {} - array-find-index@1.0.2: {} - array-ify@1.0.0: {} array-iterate@2.0.1: {} @@ -15065,12 +14831,6 @@ snapshots: '@babel/parser': 7.29.0 pathe: 2.0.3 - ast-kit@3.0.0-beta.1: - dependencies: - '@babel/parser': 8.0.0-rc.2 - estree-walker: 3.0.3 - pathe: 2.0.3 - ast-types@0.13.4: dependencies: tslib: 2.8.1 @@ -15269,8 +15029,6 @@ snapshots: birpc@2.9.0: {} - birpc@4.0.0: {} - bl@4.1.0: dependencies: buffer: 5.7.1 @@ -15367,21 +15125,6 @@ snapshots: optionalDependencies: magicast: 0.5.1 - c12@4.0.0-beta.3(chokidar@5.0.0)(dotenv@17.2.3)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.1): - dependencies: - confbox: 0.2.4 - defu: 6.1.4 - exsolve: 1.0.8 - pathe: 2.0.3 - pkg-types: 2.3.0 - rc9: 3.0.0 - optionalDependencies: - chokidar: 5.0.0 - dotenv: 17.2.3 - giget: 3.1.2 - jiti: 2.6.1 - magicast: 0.5.1 - cac@6.7.14: {} call-bind-apply-helpers@1.0.2: @@ -15521,8 +15264,6 @@ snapshots: comment-parser@1.4.5: {} - commenting@1.1.0: {} - common-ancestor-path@1.0.1: {} commondir@1.0.1: {} @@ -15961,8 +15702,6 @@ snapshots: dset@3.1.4: {} - dts-resolver@2.1.3: {} - dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -16768,10 +16507,6 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - get-tsconfig@4.13.6: - dependencies: - resolve-pkg-maps: 1.0.0 - get-uri@6.0.5: dependencies: basic-ftp: 5.1.0 @@ -17601,13 +17336,6 @@ snapshots: punycode.js: 2.3.1 uc.micro: 2.1.0 - markdown-it-cjk-friendly@2.0.2(@types/markdown-it@14.1.2)(markdown-it@14.1.1): - dependencies: - get-east-asian-width: 1.4.0 - markdown-it: 14.1.1 - optionalDependencies: - '@types/markdown-it': 14.1.2 - markdown-it-math@5.2.1(temml@0.11.11): optionalDependencies: temml: 0.11.11 @@ -18032,8 +17760,6 @@ snapshots: mocked-exports@0.1.1: {} - moment@2.30.1: {} - motion-dom@12.30.1: dependencies: motion-utils: 12.29.2 @@ -18700,33 +18426,6 @@ snapshots: obug@2.1.1: {} - obuild@0.4.31(chokidar@5.0.0)(dotenv@17.2.3)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.1)(picomatch@4.0.3)(rollup@4.57.1)(typescript@5.9.3)(vue-tsc@3.2.5(typescript@5.9.3)): - dependencies: - c12: 4.0.0-beta.3(chokidar@5.0.0)(dotenv@17.2.3)(giget@3.1.2)(jiti@2.6.1)(magicast@0.5.1) - consola: 3.4.2 - defu: 6.1.4 - exsolve: 1.0.8 - magic-string: 0.30.21 - pathe: 2.0.3 - pretty-bytes: 7.1.0 - rolldown: 1.0.0-rc.5 - rolldown-plugin-dts: 0.22.4(rolldown@1.0.0-rc.5)(typescript@5.9.3)(vue-tsc@3.2.5(typescript@5.9.3)) - rollup-plugin-license: 3.7.0(picomatch@4.0.3)(rollup@4.57.1) - tinyglobby: 0.2.15 - transitivePeerDependencies: - - '@ts-macro/tsc' - - '@typescript/native-preview' - - chokidar - - dotenv - - giget - - jiti - - magicast - - oxc-resolver - - picomatch - - rollup - - typescript - - vue-tsc - ofetch@1.5.1: dependencies: destr: 2.0.5 @@ -18970,8 +18669,6 @@ snapshots: package-manager-detector@1.6.0: {} - package-name-regex@2.0.6: {} - pako@0.2.9: {} pako@1.0.11: {} @@ -19806,24 +19503,6 @@ snapshots: rfdc@1.4.1: {} - rolldown-plugin-dts@0.22.4(rolldown@1.0.0-rc.5)(typescript@5.9.3)(vue-tsc@3.2.5(typescript@5.9.3)): - dependencies: - '@babel/generator': 8.0.0-rc.2 - '@babel/helper-validator-identifier': 8.0.0-rc.2 - '@babel/parser': 8.0.0-rc.2 - '@babel/types': 8.0.0-rc.2 - ast-kit: 3.0.0-beta.1 - birpc: 4.0.0 - dts-resolver: 2.1.3 - get-tsconfig: 4.13.6 - obug: 2.1.1 - rolldown: 1.0.0-rc.5 - optionalDependencies: - typescript: 5.9.3 - vue-tsc: 3.2.5(typescript@5.9.3) - transitivePeerDependencies: - - oxc-resolver - rolldown@1.0.0-rc.5: dependencies: '@oxc-project/types': 0.114.0 @@ -19842,20 +19521,7 @@ snapshots: '@rolldown/binding-wasm32-wasi': 1.0.0-rc.5 '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.5 '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.5 - - rollup-plugin-license@3.7.0(picomatch@4.0.3)(rollup@4.57.1): - dependencies: - commenting: 1.1.0 - fdir: 6.5.0(picomatch@4.0.3) - lodash: 4.17.23 - magic-string: 0.30.21 - moment: 2.30.1 - package-name-regex: 2.0.6 - rollup: 4.57.1 - spdx-expression-validate: 2.0.0 - spdx-satisfies: 5.0.1 - transitivePeerDependencies: - - picomatch + optional: true rollup-plugin-visualizer@6.0.5(rolldown@1.0.0-rc.5)(rollup@4.57.1): dependencies: @@ -20232,12 +19898,6 @@ snapshots: space-separated-tokens@2.0.2: {} - spdx-compare@1.0.0: - dependencies: - array-find-index: 1.0.2 - spdx-expression-parse: 3.0.1 - spdx-ranges: 2.1.1 - spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 @@ -20255,20 +19915,8 @@ snapshots: spdx-exceptions: 2.5.0 spdx-license-ids: 3.0.22 - spdx-expression-validate@2.0.0: - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids@3.0.22: {} - spdx-ranges@2.1.1: {} - - spdx-satisfies@5.0.1: - dependencies: - spdx-compare: 1.0.0 - spdx-expression-parse: 3.0.1 - spdx-ranges: 2.1.1 - speakingurl@14.0.1: {} splitpanes@4.0.4(vue@3.5.29(typescript@5.9.3)): diff --git a/scripts/stub.mjs b/scripts/stub.mjs new file mode 100644 index 0000000..a32bc7a --- /dev/null +++ b/scripts/stub.mjs @@ -0,0 +1,57 @@ +#!/usr/bin/env node +// Creates development stub files in dist/ that re-export from src/ +// so bundlers (Vite, vitest) resolve TypeScript sources directly. +// Run from a package directory: node ../../scripts/stub.mjs + +import { readFileSync, writeFileSync, mkdirSync, readdirSync, statSync } from 'node:fs' +import { join, relative, dirname } from 'node:path' + +const cwd = process.cwd() +const srcDir = join(cwd, 'src') +const distDir = join(cwd, 'dist') +const pkgName = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf-8')).name + +function walkDir(dir) { + const files = [] + for (const entry of readdirSync(dir)) { + const full = join(dir, entry) + if (statSync(full).isDirectory()) { + files.push(...walkDir(full)) + } else if (/\.tsx?$/.test(entry) && !entry.endsWith('.d.ts')) { + files.push(full) + } + } + return files +} + +const srcFiles = walkDir(srcDir) + +for (const srcFile of srcFiles) { + const rel = relative(srcDir, srcFile) // e.g. 'index.ts', 'ast/index.ts' + const base = rel.replace(/\.tsx?$/, '') // e.g. 'index', 'ast/index' + const distJs = join(distDir, base + '.js') + const distDts = join(distDir, base + '.d.ts') + + mkdirSync(dirname(distJs), { recursive: true }) + + // Relative path from the stub file back to the source file + let srcRel = relative(dirname(distJs), srcFile).replace(/\\/g, '/') + if (!srcRel.startsWith('.')) srcRel = './' + srcRel + + const hasDefault = /\bexport\s+default\b/.test(readFileSync(srcFile, 'utf-8')) + + // JS stub: re-export from source (bundlers handle .ts imports) + writeFileSync(distJs, + `export * from '${srcRel}'\n` + + (hasDefault ? `export { default } from '${srcRel}'\n` : ''), + ) + + // .d.ts stub: TypeScript follows this to find types from source + const srcRelNoExt = srcRel.replace(/\.tsx?$/, '') + writeFileSync(distDts, + `export * from '${srcRelNoExt}'\n` + + (hasDefault ? `export { default } from '${srcRelNoExt}'\n` : ''), + ) +} + +console.log(`[stub] ${pkgName}: ${srcFiles.length} files`) diff --git a/scripts/sync-plugins.mjs b/scripts/sync-plugins.mjs new file mode 100644 index 0000000..7a59df9 --- /dev/null +++ b/scripts/sync-plugins.mjs @@ -0,0 +1,56 @@ +#!/usr/bin/env node +// Syncs missing plugin re-exports from comark into framework packages (comark-vue, comark-react). +// For each plugin in comark/dist/plugins/ not present in a framework package's dist/plugins/, +// creates a .js and .d.ts file that re-exports from 'comark/plugins/'. +// +// Run from repo root: node scripts/sync-plugins.mjs + +import { readFileSync, writeFileSync, mkdirSync, readdirSync, existsSync } from 'node:fs' +import { join, basename } from 'node:path' + +const root = new URL('..', import.meta.url).pathname.replace(/\/$/, '') +const packagesDir = join(root, 'packages') + +const comarkPluginsDir = join(packagesDir, 'comark', 'dist', 'plugins') + +// Framework packages to sync plugins into +const frameworkPackages = ['comark-vue', 'comark-react'] + +// Collect plugin names from comark/dist/plugins/ (by .js files) +const comarkPlugins = readdirSync(comarkPluginsDir) + .filter(f => f.endsWith('.js') && !f.endsWith('.mjs')) + .map(f => basename(f, '.js')) + +for (const pkg of frameworkPackages) { + const distPluginsDir = join(packagesDir, pkg, 'dist', 'plugins') + mkdirSync(distPluginsDir, { recursive: true }) + + // Determine which plugins already have a dist file + const existing = existsSync(distPluginsDir) + ? new Set( + readdirSync(distPluginsDir) + .filter(f => f.endsWith('.js') && !f.endsWith('.mjs')) + .map(f => basename(f, '.js')), + ) + : new Set() + + const missing = comarkPlugins.filter(name => !existing.has(name)) + + for (const name of missing) { + // Check if the comark plugin has a default export in its .d.ts + const dtsPath = join(comarkPluginsDir, `${name}.d.ts`) + const hasDefault = existsSync(dtsPath) && + /^export default /m.test(readFileSync(dtsPath, 'utf-8')) + + const reexport = `export * from 'comark/plugins/${name}';\n` + + (hasDefault ? `export { default } from 'comark/plugins/${name}';\n` : '') + + writeFileSync(join(distPluginsDir, `${name}.js`), reexport) + writeFileSync(join(distPluginsDir, `${name}.d.ts`), reexport) + console.log(`[sync-plugins] ${pkg}/dist/plugins/${name}: created`) + } + + if (missing.length === 0) { + console.log(`[sync-plugins] ${pkg}: all plugins already present`) + } +} From c87f342592345df2d8a5102c3b85371b28a293d2 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 9 Mar 2026 14:26:43 +0100 Subject: [PATCH 10/23] lint: fix --- docs/app/components/ComarkDocs.ts | 7 ++-- .../app/components/ContentRenderer.global.vue | 2 +- docs/app/components/og-image/OgImageDocs.vue | 24 +++++++++-- packages/comark-react/src/plugins/math.ts | 2 +- packages/comark-react/src/plugins/mermaid.ts | 2 +- packages/comark-vue/src/plugins/math.ts | 2 +- packages/comark-vue/src/plugins/mermaid.ts | 2 +- packages/comark/package.json | 9 ++-- packages/comark/test/index.test.ts | 4 +- pnpm-lock.yaml | 40 +++++++++++++----- scripts/stub.mjs | 15 +++---- scripts/sync-plugins.mjs | 42 +++++++++---------- 12 files changed, 92 insertions(+), 59 deletions(-) diff --git a/docs/app/components/ComarkDocs.ts b/docs/app/components/ComarkDocs.ts index cc0db3e..08ff7d8 100644 --- a/docs/app/components/ComarkDocs.ts +++ b/docs/app/components/ComarkDocs.ts @@ -1,7 +1,6 @@ -import math from '@comark/vue/plugins/math' -import mermaid from '@comark/vue/plugins/mermaid' -import { Math } from '@comark/vue/plugins/math' -import { Mermaid } from '@comark/vue/plugins/mermaid' +import { defineComarkComponent } from '@comark/vue' +import math, { Math } from '@comark/vue/plugins/math' +import mermaid, { Mermaid } from '@comark/vue/plugins/mermaid' import ProsePre from './landing/ProsePre.vue' import highlight from 'comark/plugins/highlight' import githubLight from '@shikijs/themes/github-light' diff --git a/docs/app/components/ContentRenderer.global.vue b/docs/app/components/ContentRenderer.global.vue index 85714db..bca1854 100644 --- a/docs/app/components/ContentRenderer.global.vue +++ b/docs/app/components/ContentRenderer.global.vue @@ -5,7 +5,7 @@ import type { AsyncComponentLoader, PropType } from 'vue' import htmlTags from '@nuxtjs/mdc/runtime/parser/utils/html-tags-list' import { globalComponents, localComponents } from '#content/components' import { useRuntimeConfig } from '#imports' -import alert from 'comark/plugins/alert' +import alert from '@comark/vue/plugins/alert' import { Mermaid } from '@comark/vue/plugins/mermaid' import type { ComarkTree, ComarkElement } from 'comark/ast' import type { MinimarkNode, MinimarkTree } from 'minimark' diff --git a/docs/app/components/og-image/OgImageDocs.vue b/docs/app/components/og-image/OgImageDocs.vue index ce74979..a5bc90b 100644 --- a/docs/app/components/og-image/OgImageDocs.vue +++ b/docs/app/components/og-image/OgImageDocs.vue @@ -23,9 +23,22 @@ function truncate(str: string, max: number) { style="width:200px;background:#eab308;padding:48px 0;" >
- - - + + +
@@ -41,7 +54,10 @@ function truncate(str: string, max: number) { style="position:absolute;inset:0;background-image:radial-gradient(circle, rgba(234,179,8,0.03) 1px, transparent 1px);background-size:28px 28px;" /> -
+
ComarkPlugin> = { - cjk, + cjk: () => ({ name: 'cjk', markdownItPlugins: [cjk as any] }), emoji, } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 31b7dee..5d44211 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -73,16 +73,16 @@ importers: version: 0.9.0 '@vercel/analytics': specifier: ^1.6.1 - version: 1.6.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) + version: 1.6.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) '@vercel/speed-insights': specifier: ^1.3.1 - version: 1.3.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) + version: 1.3.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) comark: specifier: workspace:* version: link:../packages/comark docus: specifier: latest - version: 5.4.4(dd5c3a1f396c19f5a6a808c3b94aca78) + version: 5.4.4(fd164cb6eab2bb659669583ce73808f6) markdown-it: specifier: ^14.1.1 version: 14.1.1 @@ -433,6 +433,9 @@ importers: markdown-it: specifier: ^14.1.1 version: 14.1.1 + markdown-it-cjk-friendly: + specifier: ^2.0.2 + version: 2.0.2(@types/markdown-it@14.1.2)(markdown-it@14.1.1) minimark: specifier: 0.2.0 version: 0.2.0 @@ -7025,6 +7028,16 @@ packages: markdown-exit@1.0.0-beta.9: resolution: {integrity: sha512-5tzrMKMF367amyBly131vm6eGuWRL2DjBqWaFmPzPbLyuxP0XOmyyyroOAIXuBAMF/3kZbbfqOxvW/SotqKqbQ==} + markdown-it-cjk-friendly@2.0.2: + resolution: {integrity: sha512-KXCl6sd129UqkAiRDb+NcAHrxC9xRa2WsGIsMMvtp2y1YlbeIaNYzArX2zfDoGhOjsyNMfJrGO7xGBss27YQSA==} + engines: {node: '>=18'} + peerDependencies: + '@types/markdown-it': '*' + markdown-it: '*' + peerDependenciesMeta: + '@types/markdown-it': + optional: true + markdown-it-math@5.2.1: resolution: {integrity: sha512-0YJczaqvBxgOt13oKj/4HYs/34Y9FsHiTktsIBaWYqrE+k1JxmMSTxCcTezTVul0YjmhmCBDehK65vWxjzRbdg==} peerDependencies: @@ -11783,7 +11796,7 @@ snapshots: rc9: 3.0.0 std-env: 3.10.0 - '@nuxt/ui@4.4.0(@nuxt/content@3.11.0(better-sqlite3@12.6.2)(magicast@0.5.1))(@tiptap/extensions@3.20.0(@tiptap/core@3.18.0(@tiptap/pm@3.18.0))(@tiptap/pm@3.18.0))(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.6.2))(embla-carousel@8.6.0)(focus-trap@7.8.0)(ioredis@5.9.2)(magicast@0.5.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))(yjs@13.6.29)(zod@4.3.6)': + '@nuxt/ui@4.4.0(@nuxt/content@3.11.0(better-sqlite3@12.6.2)(magicast@0.5.1))(@tiptap/extensions@3.20.0(@tiptap/core@3.18.0(@tiptap/pm@3.18.0))(@tiptap/pm@3.18.0))(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.6.2))(embla-carousel@8.6.0)(focus-trap@7.8.0)(ioredis@5.9.2)(magicast@0.5.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))(yjs@13.6.29)(zod@4.3.6)': dependencies: '@floating-ui/dom': 1.7.5 '@iconify/vue': 5.0.0(vue@3.5.29(typescript@5.9.3)) @@ -12169,7 +12182,7 @@ snapshots: typescript: 5.9.3 ufo: 1.6.3 unplugin: 2.3.11 - unplugin-vue-router: 0.16.2(@vue/compiler-sfc@3.5.27)(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) + unplugin-vue-router: 0.16.2(@vue/compiler-sfc@3.5.27)(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) unstorage: 1.17.4(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.2) vue-i18n: 11.2.8(vue@3.5.29(typescript@5.9.3)) vue-router: 4.6.4(vue@3.5.29(typescript@5.9.3)) @@ -14140,7 +14153,7 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vercel/analytics@1.6.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))': + '@vercel/analytics@1.6.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))': optionalDependencies: next: 15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) react: 19.2.4 @@ -14168,7 +14181,7 @@ snapshots: '@vercel/oidc@3.1.0': {} - '@vercel/speed-insights@1.3.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))': + '@vercel/speed-insights@1.3.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))': optionalDependencies: next: 15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) react: 19.2.4 @@ -15576,7 +15589,7 @@ snapshots: dlv@1.1.3: {} - docus@5.4.4(dd5c3a1f396c19f5a6a808c3b94aca78): + docus@5.4.4(fd164cb6eab2bb659669583ce73808f6): dependencies: '@iconify-json/lucide': 1.2.88 '@iconify-json/simple-icons': 1.2.69 @@ -15584,7 +15597,7 @@ snapshots: '@nuxt/content': 3.11.0(better-sqlite3@12.6.2)(magicast@0.5.1) '@nuxt/image': 2.0.0(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.2)(magicast@0.5.1) '@nuxt/kit': 4.3.0(magicast@0.5.1) - '@nuxt/ui': 4.4.0(@nuxt/content@3.11.0(better-sqlite3@12.6.2)(magicast@0.5.1))(@tiptap/extensions@3.20.0(@tiptap/core@3.18.0(@tiptap/pm@3.18.0))(@tiptap/pm@3.18.0))(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.6.2))(embla-carousel@8.6.0)(focus-trap@7.8.0)(ioredis@5.9.2)(magicast@0.5.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))(yjs@13.6.29)(zod@4.3.6) + '@nuxt/ui': 4.4.0(@nuxt/content@3.11.0(better-sqlite3@12.6.2)(magicast@0.5.1))(@tiptap/extensions@3.20.0(@tiptap/core@3.18.0(@tiptap/pm@3.18.0))(@tiptap/pm@3.18.0))(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.6.2))(embla-carousel@8.6.0)(focus-trap@7.8.0)(ioredis@5.9.2)(magicast@0.5.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))(yjs@13.6.29)(zod@4.3.6) '@nuxtjs/i18n': 10.2.1(@vue/compiler-dom@3.5.29)(db0@0.3.4(better-sqlite3@12.6.2))(eslint@10.0.2(jiti@2.6.1))(ioredis@5.9.2)(magicast@0.5.1)(rollup@4.57.1)(vue@3.5.29(typescript@5.9.3)) '@nuxtjs/mcp-toolkit': 0.6.2(hono@4.11.7)(magicast@0.5.1)(zod@4.3.6) '@nuxtjs/mdc': 0.20.0(magicast@0.5.1) @@ -17336,6 +17349,13 @@ snapshots: punycode.js: 2.3.1 uc.micro: 2.1.0 + markdown-it-cjk-friendly@2.0.2(@types/markdown-it@14.1.2)(markdown-it@14.1.1): + dependencies: + get-east-asian-width: 1.4.0 + markdown-it: 14.1.1 + optionalDependencies: + '@types/markdown-it': 14.1.2 + markdown-it-math@5.2.1(temml@0.11.11): optionalDependencies: temml: 0.11.11 @@ -20392,7 +20412,7 @@ snapshots: optionalDependencies: '@nuxt/kit': 4.3.1(magicast@0.5.1) - unplugin-vue-router@0.16.2(@vue/compiler-sfc@3.5.27)(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)): + unplugin-vue-router@0.16.2(@vue/compiler-sfc@3.5.27)(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)): dependencies: '@babel/generator': 7.29.0 '@vue-macros/common': 3.1.2(vue@3.5.29(typescript@5.9.3)) diff --git a/scripts/stub.mjs b/scripts/stub.mjs index a32bc7a..45ce9a3 100644 --- a/scripts/stub.mjs +++ b/scripts/stub.mjs @@ -17,7 +17,8 @@ function walkDir(dir) { const full = join(dir, entry) if (statSync(full).isDirectory()) { files.push(...walkDir(full)) - } else if (/\.tsx?$/.test(entry) && !entry.endsWith('.d.ts')) { + } + else if (/\.tsx?$/.test(entry) && !entry.endsWith('.d.ts')) { files.push(full) } } @@ -27,8 +28,8 @@ function walkDir(dir) { const srcFiles = walkDir(srcDir) for (const srcFile of srcFiles) { - const rel = relative(srcDir, srcFile) // e.g. 'index.ts', 'ast/index.ts' - const base = rel.replace(/\.tsx?$/, '') // e.g. 'index', 'ast/index' + const rel = relative(srcDir, srcFile) // e.g. 'index.ts', 'ast/index.ts' + const base = rel.replace(/\.tsx?$/, '') // e.g. 'index', 'ast/index' const distJs = join(distDir, base + '.js') const distDts = join(distDir, base + '.d.ts') @@ -42,15 +43,15 @@ for (const srcFile of srcFiles) { // JS stub: re-export from source (bundlers handle .ts imports) writeFileSync(distJs, - `export * from '${srcRel}'\n` + - (hasDefault ? `export { default } from '${srcRel}'\n` : ''), + `export * from '${srcRel}'\n` + + (hasDefault ? `export { default } from '${srcRel}'\n` : ''), ) // .d.ts stub: TypeScript follows this to find types from source const srcRelNoExt = srcRel.replace(/\.tsx?$/, '') writeFileSync(distDts, - `export * from '${srcRelNoExt}'\n` + - (hasDefault ? `export { default } from '${srcRelNoExt}'\n` : ''), + `export * from '${srcRelNoExt}'\n` + + (hasDefault ? `export { default } from '${srcRelNoExt}'\n` : ''), ) } diff --git a/scripts/sync-plugins.mjs b/scripts/sync-plugins.mjs index 7a59df9..d305b45 100644 --- a/scripts/sync-plugins.mjs +++ b/scripts/sync-plugins.mjs @@ -25,32 +25,28 @@ for (const pkg of frameworkPackages) { const distPluginsDir = join(packagesDir, pkg, 'dist', 'plugins') mkdirSync(distPluginsDir, { recursive: true }) - // Determine which plugins already have a dist file - const existing = existsSync(distPluginsDir) - ? new Set( - readdirSync(distPluginsDir) - .filter(f => f.endsWith('.js') && !f.endsWith('.mjs')) - .map(f => basename(f, '.js')), - ) - : new Set() - - const missing = comarkPlugins.filter(name => !existing.has(name)) - - for (const name of missing) { - // Check if the comark plugin has a default export in its .d.ts - const dtsPath = join(comarkPluginsDir, `${name}.d.ts`) - const hasDefault = existsSync(dtsPath) && - /^export default /m.test(readFileSync(dtsPath, 'utf-8')) - - const reexport = `export * from 'comark/plugins/${name}';\n` + - (hasDefault ? `export { default } from 'comark/plugins/${name}';\n` : '') + let created = 0 - writeFileSync(join(distPluginsDir, `${name}.js`), reexport) - writeFileSync(join(distPluginsDir, `${name}.d.ts`), reexport) - console.log(`[sync-plugins] ${pkg}/dist/plugins/${name}: created`) + for (const name of comarkPlugins) { + // Check if the comark plugin has a default export in its .d.ts + const comarkDtsPath = join(comarkPluginsDir, `${name}.d.ts`) + const hasDefault = existsSync(comarkDtsPath) + && /^export default /m.test(readFileSync(comarkDtsPath, 'utf-8')) + + const reexport = `export * from 'comark/plugins/${name}';\n` + + (hasDefault ? `export { default } from 'comark/plugins/${name}';\n` : '') + + for (const ext of ['.js', '.d.ts']) { + const dest = join(distPluginsDir, `${name}${ext}`) + if (!existsSync(dest)) { + writeFileSync(dest, reexport) + console.log(`[sync-plugins] ${pkg}/dist/plugins/${name}${ext}: created`) + created++ + } + } } - if (missing.length === 0) { + if (created === 0) { console.log(`[sync-plugins] ${pkg}: all plugins already present`) } } From 1cdb1cde8b80f66704e8c664e45ebea32aa270aa Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 9 Mar 2026 15:12:48 +0100 Subject: [PATCH 11/23] fix: stub --- scripts/stub.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/stub.mjs b/scripts/stub.mjs index 45ce9a3..28ac95b 100644 --- a/scripts/stub.mjs +++ b/scripts/stub.mjs @@ -39,7 +39,9 @@ for (const srcFile of srcFiles) { let srcRel = relative(dirname(distJs), srcFile).replace(/\\/g, '/') if (!srcRel.startsWith('.')) srcRel = './' + srcRel - const hasDefault = /\bexport\s+default\b/.test(readFileSync(srcFile, 'utf-8')) + const content = readFileSync(srcFile, 'utf-8') + const hasDefault = /\bexport\s+default\b/.test(content) + || /export\s*\{\s*default/.test(content) // JS stub: re-export from source (bundlers handle .ts imports) writeFileSync(distJs, From 05ba321384b0a8259a6393803cc6094497b3aca6 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 9 Mar 2026 15:40:39 +0100 Subject: [PATCH 12/23] up --- package.json | 2 +- scripts/sync-plugins.mjs | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 141c578..62eda43 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "stub": "pnpm --parallel --filter './packages/**' run stub && pnpm sync-plugins", "sync-plugins": "node scripts/sync-plugins.mjs", "dev:packages": "pnpm --parallel --filter './packages/**' run dev", - "build": "pnpm --filter './packages/**' run build", + "build": "pnpm --filter './packages/**' run build && pnpm sync-plugins", "test": "pnpm --filter 'comark' run test && pnpm --filter '@comark/*' run test", "test:spec": "cd packages/comark && pnpm vitest run test/index.test.ts -- -spec", "lint": "eslint .", diff --git a/scripts/sync-plugins.mjs b/scripts/sync-plugins.mjs index d305b45..3c574a1 100644 --- a/scripts/sync-plugins.mjs +++ b/scripts/sync-plugins.mjs @@ -23,6 +23,7 @@ const comarkPlugins = readdirSync(comarkPluginsDir) for (const pkg of frameworkPackages) { const distPluginsDir = join(packagesDir, pkg, 'dist', 'plugins') + const srcPluginsDir = join(packagesDir, pkg, 'src', 'plugins') mkdirSync(distPluginsDir, { recursive: true }) let created = 0 @@ -36,13 +37,13 @@ for (const pkg of frameworkPackages) { const reexport = `export * from 'comark/plugins/${name}';\n` + (hasDefault ? `export { default } from 'comark/plugins/${name}';\n` : '') + if (existsSync(join(srcPluginsDir, `${name}.ts`))) { + continue + } + for (const ext of ['.js', '.d.ts']) { - const dest = join(distPluginsDir, `${name}${ext}`) - if (!existsSync(dest)) { - writeFileSync(dest, reexport) - console.log(`[sync-plugins] ${pkg}/dist/plugins/${name}${ext}: created`) - created++ - } + writeFileSync(join(distPluginsDir, `${name}${ext}`), reexport) + created++ } } From 9f188a2dbd46044488cc6a5c7cbad645816b2a02 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 9 Mar 2026 15:57:15 +0100 Subject: [PATCH 13/23] chore: update build command --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 066bb0d..03be5c0 100644 --- a/docs/package.json +++ b/docs/package.json @@ -2,7 +2,7 @@ "name": "Comark", "scripts": { "dev": "nuxt dev --extends docus", - "build": "nuxt build --extends docus" + "build": " pnpm --filter '../' run build && nuxt build --extends docus" }, "dependencies": { "@comark/nuxt": "workspace:*", From 7e3cf038b76ff48a60fa8409a91ee6b0dbc5048a Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 9 Mar 2026 16:47:59 +0100 Subject: [PATCH 14/23] up --- packages/comark-svelte/vitest.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/comark-svelte/vitest.config.ts b/packages/comark-svelte/vitest.config.ts index 95d1243..685b1da 100644 --- a/packages/comark-svelte/vitest.config.ts +++ b/packages/comark-svelte/vitest.config.ts @@ -14,9 +14,9 @@ export default defineConfig({ test: { name: 'client', browser: { - enabled: true, + enabled: process.env.CI !== 'true', provider: playwright(), - instances: [{ browser: 'chromium' }], + instances: [{ browser: 'chromium', headless: true }], }, include: ['src/**/*.svelte.{test,spec}.{js,ts}'], }, From 2e0d031327889721a3df1c61d3b234bc761b1f26 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 9 Mar 2026 16:51:53 +0100 Subject: [PATCH 15/23] test: disable browser in ci --- packages/comark-svelte/vitest.config.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/comark-svelte/vitest.config.ts b/packages/comark-svelte/vitest.config.ts index 685b1da..ec224cd 100644 --- a/packages/comark-svelte/vitest.config.ts +++ b/packages/comark-svelte/vitest.config.ts @@ -2,6 +2,8 @@ import { defineConfig } from 'vitest/config' import { svelte } from '@sveltejs/vite-plugin-svelte' import { playwright } from '@vitest/browser-playwright' +const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true' + export default defineConfig({ plugins: [svelte()], optimizeDeps: { @@ -14,7 +16,7 @@ export default defineConfig({ test: { name: 'client', browser: { - enabled: process.env.CI !== 'true', + enabled: !isCI, provider: playwright(), instances: [{ browser: 'chromium', headless: true }], }, From de0ed879c9f62a7a2819007ab1147ba06b856676 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 9 Mar 2026 16:55:50 +0100 Subject: [PATCH 16/23] up --- packages/comark-svelte/vitest.config.ts | 28 +++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/packages/comark-svelte/vitest.config.ts b/packages/comark-svelte/vitest.config.ts index ec224cd..fbb1a1a 100644 --- a/packages/comark-svelte/vitest.config.ts +++ b/packages/comark-svelte/vitest.config.ts @@ -11,18 +11,20 @@ export default defineConfig({ }, test: { projects: [ - { - extends: './vitest.config.ts', - test: { - name: 'client', - browser: { - enabled: !isCI, - provider: playwright(), - instances: [{ browser: 'chromium', headless: true }], - }, - include: ['src/**/*.svelte.{test,spec}.{js,ts}'], - }, - }, + isCI + ? { + extends: './vitest.config.ts', + test: { + name: 'client', + browser: { + enabled: !isCI, + provider: playwright(), + instances: [{ browser: 'chromium', headless: true }], + }, + include: ['src/**/*.svelte.{test,spec}.{js,ts}'], + }, + } + : false, { extends: './vitest.config.ts', test: { @@ -32,6 +34,6 @@ export default defineConfig({ exclude: ['src/**/*.svelte.{test,spec}.{js,ts}'], }, }, - ], + ].filter(Boolean), }, }) From 1a4cddea3f2ae9f47128d0a458532662facf92cd Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 9 Mar 2026 16:58:42 +0100 Subject: [PATCH 17/23] test: update vitest cofnig --- packages/comark-svelte/vitest.config.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/comark-svelte/vitest.config.ts b/packages/comark-svelte/vitest.config.ts index fbb1a1a..7d37df6 100644 --- a/packages/comark-svelte/vitest.config.ts +++ b/packages/comark-svelte/vitest.config.ts @@ -12,7 +12,8 @@ export default defineConfig({ test: { projects: [ isCI - ? { + ? false + : { extends: './vitest.config.ts', test: { name: 'client', @@ -23,8 +24,7 @@ export default defineConfig({ }, include: ['src/**/*.svelte.{test,spec}.{js,ts}'], }, - } - : false, + }, { extends: './vitest.config.ts', test: { From a0e353154af42bacb2fb038cf25c77489de0cad2 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Mon, 9 Mar 2026 17:29:01 +0100 Subject: [PATCH 18/23] chore: update plugins structure --- AGENTS.md | 507 +++++++----------- docs/content/3.rendering/3.svelte.md | 8 +- .../4.plugins/2.external/10.mermaid.md | 2 +- docs/content/4.plugins/2.external/11.math.md | 2 +- packages/comark-svelte/package.json | 10 +- .../comark-svelte/src/plugin-math/index.ts | 3 - .../comark-svelte/src/plugin-mermaid/index.ts | 3 - packages/comark-svelte/src/plugins/math.ts | 3 + .../{plugin-math => plugins/math}/Math.svelte | 0 .../math}/index.svelte.test.ts | 6 +- .../math}/index.test.ts | 4 +- packages/comark-svelte/src/plugins/mermaid.ts | 3 + .../mermaid}/Mermaid.svelte | 2 +- .../mermaid}/index.svelte.test.ts | 6 +- .../mermaid}/index.test.ts | 4 +- packages/comark-svelte/vitest.config.ts | 2 +- scripts/sync-plugins.mjs | 2 +- 17 files changed, 228 insertions(+), 339 deletions(-) delete mode 100644 packages/comark-svelte/src/plugin-math/index.ts delete mode 100644 packages/comark-svelte/src/plugin-mermaid/index.ts create mode 100644 packages/comark-svelte/src/plugins/math.ts rename packages/comark-svelte/src/{plugin-math => plugins/math}/Math.svelte (100%) rename packages/comark-svelte/src/{plugin-math => plugins/math}/index.svelte.test.ts (95%) rename packages/comark-svelte/src/{plugin-math => plugins/math}/index.test.ts (96%) create mode 100644 packages/comark-svelte/src/plugins/mermaid.ts rename packages/comark-svelte/src/{plugin-mermaid => plugins/mermaid}/Mermaid.svelte (97%) rename packages/comark-svelte/src/{plugin-mermaid => plugins/mermaid}/index.svelte.test.ts (93%) rename packages/comark-svelte/src/{plugin-mermaid => plugins/mermaid}/index.test.ts (95%) diff --git a/AGENTS.md b/AGENTS.md index 9bfb2c7..2c790a6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -19,18 +19,17 @@ This is a **monorepo** containing multiple packages related to Comark (Component ``` / # Root workspace ├── packages/ # All publishable packages -│ ├── comark/ # Main Comark parser package -│ ├── comark-cjk/ # CJK support plugin (@comark/cjk) -│ ├── comark-math/ # Math formula support (@comark/math) -│ └── comark-svelte/ # Svelte renderer (@comark/svelte) +│ ├── comark/ # Main Comark parser + core plugins +│ ├── comark-vue/ # Vue renderer + plugins (@comark/vue) +│ ├── comark-react/ # React renderer + plugins (@comark/react) +│ ├── comark-svelte/ # Svelte renderer + plugins (@comark/svelte) +│ └── comark-nuxt/ # Nuxt module (@comark/nuxt) ├── examples/ # Example applications -│ ├── vue-vite/ # Vue + Vite + Tailwind CSS v4 -│ ├── react-vite/ # React 19 + Vite + Tailwind CSS v4 -│ ├── nuxt/ # Nuxt example -│ └── nuxt-ui/ # Nuxt UI example +│ ├── 1.vue-vite/ # Vue + Vite + Tailwind CSS v4 +│ ├── 2.react-vite/ # React 19 + Vite + Tailwind CSS v4 +│ └── 3.plugins/ # Plugin examples (vue-vite-math, vue-vite-mermaid) ├── docs/ # Documentation site (Docus-based) -├── playground/ # Development playground -├── skills/ # AI agent skills definitions +├── scripts/ # Build/sync scripts ├── pnpm-workspace.yaml # Workspace configuration ├── tsconfig.json # Root TypeScript config ├── eslint.config.mjs # ESLint configuration @@ -45,159 +44,115 @@ Located at `packages/comark/`: packages/comark/ ├── src/ │ ├── index.ts # Core parser: parse(), autoCloseMarkdown() -│ ├── string.ts # String rendering: renderHTML(tree, options?), renderMarkdown() +│ ├── string.ts # String rendering: renderHTML(), renderMarkdown() │ ├── types.ts # TypeScript interfaces (ParseOptions, etc.) │ ├── ast/ # Comark AST types and utilities │ │ ├── index.ts # Re-exports (comark/ast entry point) │ │ ├── types.ts # ComarkTree, ComarkNode, ComarkElement, ComarkText │ │ └── utils.ts # textContent(), visit() tree utilities -│ ├── internal/ # Internal implementation (not exported) -│ │ ├── front-matter.ts # YAML frontmatter parsing/rendering -│ │ ├── yaml.ts # YAML serialization utilities -│ │ ├── props-validation.ts # Component props validation -│ │ ├── parse/ # Parsing pipeline -│ │ │ ├── token-processor.ts # markdown-it token → Comark AST conversion -│ │ │ ├── auto-close.ts # Auto-close incomplete markdown/Comark -│ │ │ ├── auto-unwrap.ts # Remove unnecessary

wrappers -│ │ │ ├── table-of-contents.ts # TOC generation -│ │ │ ├── shiki-highlighter.ts # Syntax highlighting via Shiki -│ │ │ └── markdown-it-task-lists-mdc.ts # Task list plugin -│ │ └── stringify/ # AST → string rendering -│ │ ├── index.ts # Main stringify entry -│ │ ├── state.ts # Rendering state management -│ │ ├── types.ts # Stringify type definitions -│ │ ├── attributes.ts # Attribute serialization -│ │ ├── indent.ts # Indentation handling -│ │ └── handlers/ # Per-element render handlers (a, p, pre, heading, etc.) -│ ├── vue/ # Vue components -│ │ ├── index.ts # Vue entry point (comark/vue) -│ │ └── components/ -│ │ ├── Comark.ts # High-level markdown → render component -│ │ ├── ComarkRenderer.ts # Low-level AST → render component -│ │ ├── index.ts # Component re-exports -│ │ └── prose/ -│ │ └── ProsePre.vue # Code block prose component -│ ├── react/ # React components -│ │ ├── index.ts # React entry point (comark/react) -│ │ └── components/ -│ │ ├── Comark.tsx # High-level markdown → render component -│ │ ├── ComarkRenderer.tsx # Low-level AST → render component -│ │ ├── index.tsx # Component re-exports -│ │ └── prose/ -│ │ └── ProsePre.tsx # Code block prose component -│ └── utils/ -│ └── caret.ts # Caret/cursor utilities +│ ├── plugins/ # Built-in and optional plugins +│ │ ├── alert.ts # Alert/callout blocks +│ │ ├── emoji.ts # Emoji shortcodes +│ │ ├── highlight.ts # Syntax highlighting via Shiki (peer: shiki) +│ │ ├── math.ts # LaTeX math via KaTeX (peer: katex) +│ │ ├── mermaid.ts # Mermaid diagrams (peer: beautiful-mermaid) +│ │ ├── security.ts # XSS/security sanitization +│ │ ├── summary.ts # Summary extraction +│ │ ├── task-list.ts # GFM task lists +│ │ └── toc.ts # Table of contents +│ └── internal/ # Internal implementation (not exported) +│ ├── front-matter.ts +│ ├── parse/ # Parsing pipeline +│ └── stringify/ # AST → string rendering ├── test/ # Vitest test files -├── SPEC/ # Markdown spec test files (CommonMark, GFM, MDC) -├── package.json # Package manifest -├── tsconfig.json # TypeScript config -├── build.config.mjs # Build configuration (obuild) -└── vitest.config.ts # Test configuration +├── package.json +└── tsconfig.build.json ``` -## Package: @comark/cjk +### Peer dependencies -CJK (Chinese, Japanese, Korean) support plugin. Located at `packages/comark-cjk/`: +| Peer | Required by | +|------|-------------| +| `shiki` | `comark/plugins/highlight` | +| `katex` | `comark/plugins/math` | +| `beautiful-mermaid` | `comark/plugins/mermaid` | + +All are optional — only install what you use. + +## Package: @comark/vue + +Located at `packages/comark-vue/`. Vue 3 renderer with framework-specific plugin wrappers. ``` -packages/comark-cjk/ +packages/comark-vue/ ├── src/ -│ └── index.ts # Plugin export -├── test/ # Vitest test files (23 tests) -├── package.json # Package manifest -├── tsconfig.json # TypeScript config -├── build.config.mjs # Build configuration -└── vitest.config.ts # Test configuration +│ ├── index.ts # Entry point +│ ├── components/ +│ │ ├── Comark.ts # High-level markdown → render component +│ │ ├── ComarkRenderer.ts # Low-level AST → render component +│ │ ├── Math.ts # Math rendering component +│ │ └── Mermaid.ts # Mermaid rendering component +│ └── plugins/ +│ ├── math.ts # Re-exports comark/plugins/math + Math component +│ └── mermaid.ts # Re-exports comark/plugins/mermaid + Mermaid component +├── package.json +└── tsconfig.build.json +``` + +### Exports + +```json +{ + ".": "./dist/index.js", + "./plugins/*": "./dist/plugins/*.js" +} ``` ### Usage ```typescript -import { parse } from 'comark' -import cjk from '@comark/cjk' - -const result = await parse('中文内容 **加粗**', { plugins: [cjk()] }) +import { Comark, ComarkRenderer, defineComarkComponent } from '@comark/vue' +import math, { Math } from '@comark/vue/plugins/math' +import mermaid, { Mermaid } from '@comark/vue/plugins/mermaid' ``` -### Features - -- Improved line breaking between CJK and non-CJK characters -- Better handling of soft line breaks in CJK text -- Full support for CJK in all Comark features (headings, lists, components, etc.) +## Package: @comark/react -## Package: @comark/math - -Math formula support for Comark using KaTeX. Located at `packages/comark-math/`: +Located at `packages/comark-react/`. React renderer with framework-specific plugin wrappers. ``` -packages/comark-math/ +packages/comark-react/ ├── src/ -│ ├── index.ts # Core math utilities -│ ├── vue.ts # Vue component -│ └── react.tsx # React component -├── test/ # Vitest test files -├── package.json # Package manifest -├── tsconfig.json # TypeScript config -├── build.config.mjs # Build configuration -└── vitest.config.ts # Test configuration +│ ├── index.ts # Entry point +│ ├── components/ +│ │ ├── Comark.tsx # High-level markdown → render component +│ │ ├── ComarkRenderer.tsx # Low-level AST → render component +│ │ ├── Math.tsx # Math rendering component +│ │ └── Mermaid.tsx # Mermaid rendering component +│ └── plugins/ +│ ├── math.ts # Re-exports comark/plugins/math + Math component +│ └── mermaid.ts # Re-exports comark/plugins/mermaid + Mermaid component +├── package.json +└── tsconfig.build.json +``` + +### Exports + +```json +{ + ".": "./dist/index.js", + "./plugins/*": "./dist/plugins/*.js" +} ``` ### Usage -**Vue:** -```vue - - - -``` - -**React:** -```tsx -import { Comark } from '@comark/react' -import math from '@comark/math' -import { Math } from '@comark/math/react' - -const components = { math: Math } -const markdown = ` -Inline math: $E = mc^2$ - -Display math: -$$ -\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2} -$$ -` - -{markdown} +```typescript +import { Comark, ComarkRenderer, defineComarkComponent } from '@comark/react' +import math, { Math } from '@comark/react/plugins/math' +import mermaid, { Mermaid } from '@comark/react/plugins/mermaid' ``` -### Features - -- Inline math with `$...$` syntax (tokenized during parsing via markdown-it plugin) -- Display math with `$$...$$` syntax (tokenized during parsing via markdown-it plugin) -- Code blocks with `math` language -- HTML output via KaTeX with built-in styling -- Supports full LaTeX math syntax via KaTeX -- Vue and React components for easy integration -- Automatic tokenization at parse time (not render time) for performance - ## Package: @comark/svelte Svelte 5 renderer for Comark. Located at `packages/comark-svelte/`: @@ -210,16 +165,31 @@ packages/comark-svelte/ │ ├── Comark.svelte # High-level markdown → render ($state + $effect) │ ├── ComarkAsync.svelte # High-level markdown → render (experimental await) │ ├── ComarkRenderer.svelte # Low-level AST → render component -│ └── ComarkNode.svelte # Recursive AST node renderer +│ ├── ComarkNode.svelte # Recursive AST node renderer +│ ├── async/index.ts # Async export (@comark/svelte/async) +│ └── plugins/ +│ ├── math.ts # Re-exports comark/plugins/math +│ ├── Math.svelte # Math rendering component +│ ├── mermaid.ts # Re-exports comark/plugins/mermaid +│ └── Mermaid.svelte # Mermaid rendering component ├── svelte.config.js # Svelte config (experimental.async enabled) -├── vitest.config.ts # Dual test config (server + client browser) -├── tsconfig.json +├── vitest.config.ts # Dual test config (server + browser) └── package.json ``` +### Exports + +```json +{ + ".": { "svelte": "./dist/index.js" }, + "./async": { "svelte": "./dist/async/index.js" }, + "./plugins/*": { "svelte": "./dist/plugins/*.js" } +} +``` + ### Build -Uses `@sveltejs/package` (`svelte-package`) — the standard Svelte library packaging tool. Ships `.svelte` source files (compiled by consumer's bundler) with `.d.ts` type definitions generated via `svelte2tsx`. +Uses `@sveltejs/package` (`svelte-package`) — the standard Svelte library packaging tool. ### Testing @@ -229,18 +199,20 @@ Uses Vitest with two test projects: ### Usage -**Manual state (stable API)**: ```svelte - + + ``` **Experimental async** (requires `experimental.async` in Svelte config): ```svelte @@ -250,31 +222,43 @@ Uses Vitest with two test projects: ``` -## Package Exports +## Package Exports Reference ```typescript // Core parsing -import { parse, parse, autoCloseMarkdown } from 'comark' +import { parse, autoCloseMarkdown } from 'comark' // String rendering (HTML & Markdown) import { renderHTML, renderMarkdown } from 'comark/string' -import type { RenderHTMLOptions, ComponentRenderFn, RenderHTMLContext } from 'comark/string' // AST types and utilities import type { ComarkTree, ComarkNode, ComarkElement, ComarkText } from 'comark/ast' import { textContent, visit } from 'comark/ast' -// Vue components -import { Comark } from '@comark/vue' - -// React components -import { Comark } from 'comark/react' - -// Svelte components +// Core plugins (framework-agnostic) +import highlight from 'comark/plugins/highlight' +import math from 'comark/plugins/math' +import mermaid from 'comark/plugins/mermaid' +import cjk from 'comark/plugins/cjk' +import emoji from 'comark/plugins/emoji' +import toc from 'comark/plugins/toc' +import alert from 'comark/plugins/alert' + +// Vue — renderer + plugin wrappers (plugin fn + Vue component) +import { Comark, ComarkRenderer, defineComarkComponent } from '@comark/vue' +import math, { Math } from '@comark/vue/plugins/math' +import mermaid, { Mermaid } from '@comark/vue/plugins/mermaid' + +// React — renderer + plugin wrappers (plugin fn + React component) +import { Comark, ComarkRenderer, defineComarkComponent } from '@comark/react' +import math, { Math } from '@comark/react/plugins/math' +import mermaid, { Mermaid } from '@comark/react/plugins/mermaid' + +// Svelte — renderer + plugin wrappers (plugin fn + Svelte component) import { Comark, ComarkRenderer } from '@comark/svelte' import { ComarkAsync } from '@comark/svelte/async' // requires experimental.async -import { math, Math } from '@comark/svelte/plugin-math' -import { mermaid, Mermaid } from '@comark/svelte/plugin-mermaid' +import math, { Math } from '@comark/svelte/plugins/math' +import mermaid, { Mermaid } from '@comark/svelte/plugins/mermaid' ``` ## Coding Principles @@ -285,19 +269,6 @@ import { mermaid, Mermaid } from '@comark/svelte/plugin-mermaid' 2. **Linear time complexity** - Strive for O(n) operations, avoid nested loops that could be O(n²) or worse 3. **Minimize allocations** - Reuse arrays/objects, avoid creating unnecessary intermediate structures -Example from auto-close.ts: -```typescript -// Good: Single-pass character scan in O(n) -for (let i = 0; i < len; i++) { - const ch = line[i] - if (ch === '*') asteriskCount++ - // ... -} - -// Avoid: Regex that may have backtracking -const matches = line.match(/\*+/g) // Don't do this -``` - ### TypeScript Conventions 1. Use explicit types for function parameters and return values @@ -307,19 +278,17 @@ const matches = line.match(/\*+/g) // Don't do this ### Code Organization -1. Keep internal implementation in `packages/comark/src/internal/` (parsing in `internal/parse/`, stringification in `internal/stringify/`) +1. Keep internal implementation in `packages/comark/src/internal/` 2. AST types and utilities in `packages/comark/src/ast/` -3. Framework-specific code in `packages/comark/src/vue/`, `packages/comark/src/react/`, and `packages/comark-svelte/src/` -4. Export public APIs from entry points (`index.ts`, `ast/index.ts`) -5. Document exported functions with JSDoc including `@example` +3. Core plugins (parser-only) in `packages/comark/src/plugins/` +4. Framework renderers in separate packages (`comark-vue`, `comark-react`, `comark-svelte`) +5. Framework plugin wrappers (plugin fn + component) in `packages/comark-{framework}/src/plugins/` ## Testing Guidelines -Tests are in `packages/comark/test/` using Vitest: - ```bash -pnpm test # Run all package tests -cd packages/comark && pnpm test # Run comark tests +pnpm test # Run all package tests +cd packages/comark && pnpm test # Run comark tests cd packages/comark && pnpm vitest run test/auto-close.test.ts # Run specific test ``` @@ -335,10 +304,6 @@ describe('functionUnderTest', () => { const expected = 'expected output' expect(functionUnderTest(input)).toBe(expected) }) - - it('should handle edge case', () => { - // Test edge cases explicitly - }) }) ``` @@ -353,23 +318,19 @@ describe('functionUnderTest', () => { ### parse(source, options) -Synchronous parsing of Comark content: - ```typescript const result = await parse(markdownContent, { autoUnwrap: true, // Remove

wrappers from single-paragraph containers autoClose: true, // Auto-close incomplete syntax }) -result.nodes // ComarkNodes list -result.frontmatter // Frontmatter data object -result.meta // Additional metadata +result.nodes // ComarkNode[] +result.frontmatter // Record +result.meta // Record ``` ### autoCloseMarkdown(markdown) -Closes unclosed inline syntax and Comark components: - ```typescript autoCloseMarkdown('**bold text') // '**bold text**' autoCloseMarkdown('::alert\nContent') // '::alert\nContent\n::' @@ -377,20 +338,11 @@ autoCloseMarkdown('::alert\nContent') // '::alert\nContent\n::' ## Comark AST Format -The parser outputs Comark AST - a compact array-based format. Types are defined in `packages/comark/src/ast/types.ts`: - ```typescript type ComarkText = string - -type ComarkElementAttributes = { - [key: string]: unknown -} - type ComarkElement = [string, ComarkElementAttributes, ...ComarkNode[]] - type ComarkNode = ComarkElement | ComarkText - -export type ComarkTree = { +type ComarkTree = { nodes: ComarkNode[] frontmatter: Record meta: Record @@ -414,8 +366,6 @@ Example: ### Comark Component (High-level) -Accepts markdown string, handles parsing internally. - **Vue** (requires `` wrapper since Comark is async): ```vue @@ -430,36 +380,53 @@ Accepts markdown string, handles parsing internally. {content} ``` -**Svelte** (manual state — stable API, uses `$state` + `$effect`): +**Svelte** (stable, uses `$state` + `$effect`): ```svelte - - ``` **Svelte** (experimental async — requires `experimental.async` in Svelte config): ```svelte - - - {#snippet pending()} -

Loading...

- {/snippet} + {#snippet pending()}

Loading...

{/snippet} ``` +### defineComarkComponent (Vue & React) + +Creates a pre-configured Comark component with default plugins and components: + +```typescript +// Vue +import { defineComarkComponent } from '@comark/vue' +import math, { Math } from '@comark/vue/plugins/math' +import mermaid, { Mermaid } from '@comark/vue/plugins/mermaid' + +export const DocsComark = defineComarkComponent({ + name: 'DocsComark', + plugins: [math(), mermaid()], + components: { Math, Mermaid }, +}) + +// React +import { defineComarkComponent } from '@comark/react' +import math, { Math } from '@comark/react/plugins/math' + +export const DocsComark = defineComarkComponent({ + name: 'DocsComark', + plugins: [math()], + components: { Math }, +}) +``` + ## Common Tasks ### Adding a new utility function -1. Create file in `packages/comark/src/internal/` (or `src/ast/` for AST utilities) +1. Create file in `packages/comark/src/internal/` 2. Export from `packages/comark/src/index.ts` if public API 3. Add tests in `packages/comark/test/` 4. Document with JSDoc @@ -472,11 +439,21 @@ Accepts markdown string, handles parsing internally. ### Adding component features -1. Vue components in `packages/comark/src/vue/components/` -2. React components in `packages/comark/src/react/components/` +1. Vue components in `packages/comark-vue/src/components/` +2. React components in `packages/comark-react/src/components/` 3. Svelte components in `packages/comark-svelte/src/` 4. All three should have similar APIs for consistency +### Adding a new core plugin + +1. Create `packages/comark/src/plugins/{name}.ts` +2. Available as `comark/plugins/{name}` via the `"./plugins/*"` wildcard export +3. Add framework wrappers if it needs a render component: + - `packages/comark-vue/src/plugins/{name}.ts` (re-export plugin + Vue component) + - `packages/comark-react/src/plugins/{name}.ts` (re-export plugin + React component) + - `packages/comark-svelte/src/plugins/{name}.ts` (re-export plugin + Svelte component) +4. Run `node scripts/sync-plugins.mjs` to sync plain re-exports for plugins without components + ### Adding a new package 1. Create directory in `packages/` @@ -489,9 +466,6 @@ Accepts markdown string, handles parsing internally. Root workspace scripts: ```bash -pnpm dev # Alias for dev:vue -pnpm dev:vue # Run Vue example (Vite) -pnpm dev:react # Run React example (Vite) pnpm docs # Run documentation site pnpm build # Build all packages pnpm test # Run all package tests @@ -500,42 +474,17 @@ pnpm typecheck # Run TypeScript check pnpm verify # Run lint + test + typecheck ``` -Package-specific scripts (from `packages/comark/`): +Utility scripts: ```bash -pnpm build # Build the package (obuild) -pnpm test # Run package tests (vitest) -pnpm release # Release the package -pnpm release:dry # Dry run release +node scripts/stub.mjs # Generate stub dist files for local dev +node scripts/sync-plugins.mjs # Sync plugin re-exports to framework packages ``` ## Releasing Uses [release-it](https://github.com/release-it/release-it) with conventional changelog. -### Release all packages (synced versions) - -```bash -pnpm release # Interactive release -pnpm release:dry # Dry run to preview -``` - -This will: -1. Run `pnpm verify` (lint, test, typecheck) -2. Bump version in root and all packages -3. Generate/update CHANGELOG.md -4. Create git tag and GitHub release - -### Release individual package - -```bash -cd packages/comark -pnpm release # Release comark only - -cd packages/comark-cjk -pnpm release # Release @comark/cjk only -``` - ### Commit message format Follow [Conventional Commits](https://www.conventionalcommits.org/): @@ -549,41 +498,6 @@ docs: update README # No version bump chore: update dependencies # No version bump ``` -## Examples - -Interactive examples are in `examples/`: - -### Vue/Vite Example (`examples/vue-vite/`) - -```bash -pnpm dev:vue -``` - -Features: -- Editor mode with live preview -- Custom component registration (alert) -- Light/dark mode support via Tailwind CSS v4 -- Uses `` wrapper for async Comark component - -Key files: -- `examples/vue-vite/src/App.vue` - Main app with editor -- `examples/vue-vite/src/components/Alert.vue` - Custom alert component - -### React/Vite Example (`examples/react-vite/`) - -```bash -pnpm dev:react -``` - -Features: -- Same feature set as Vue example -- Uses React hooks (useState, useMemo) -- Custom component registration - -Key files: -- `examples/react-vite/src/App.tsx` - Main app -- `examples/react-vite/src/components/Alert.tsx` - Custom alert component - ## Documentation Maintenance **Important:** After completing any feature, bug fix, or significant change, update the relevant documentation: @@ -592,38 +506,17 @@ Key files: 1. **AGENTS.md** (this file) - Update architecture section if new files/modules added - - Update package exports if new public APIs - - Add new APIs to the Key APIs section - - Update common tasks if workflows change - -2. **Skills** (`skills/mdc/`) - - Update `SKILL.md` if syntax or usage changes - - Update reference files in `skills/mdc/references/` for: - - `markdown-syntax.md` - Comark changes - - `parsing-ast.md` - Parser API or AST format changes - - `rendering-vue.md` - Vue component changes - - `rendering-react.md` - React component changes - -3. **Documentation** (`docs/content/`) - - Update relevant docs pages: - - `1.getting-started/` - Installation or quick start changes - - `2.syntax/` - Comark changes - - `3.rendering/` - Vue/React renderer changes - - `4.api/` - API changes (parse, auto-close, reference) - -### When to Update - -- **New feature**: Update all three (AGENTS.md, skills, docs) -- **Bug fix**: Update docs if it changes expected behavior -- **API change**: Update AGENTS.md and docs API reference -- **Internal refactor**: Update AGENTS.md architecture if structure changes + - Update Package Exports Reference if new public APIs + - Update Common Tasks if workflows change + +2. **Documentation** (`docs/content/`) + - `1.getting-started/` — Installation or quick start changes + - `3.rendering/` — Vue/React/Svelte renderer changes + - `4.plugins/` — Plugin changes ### Documentation Checklist After each change, ask: - [ ] Does AGENTS.md reflect the current architecture? -- [ ] Are all public APIs documented in Key APIs? -- [ ] Do the skills references match current behavior? +- [ ] Are all public APIs documented in Package Exports Reference? - [ ] Are the docs pages accurate and up-to-date? - - diff --git a/docs/content/3.rendering/3.svelte.md b/docs/content/3.rendering/3.svelte.md index 3967f44..895c6f9 100644 --- a/docs/content/3.rendering/3.svelte.md +++ b/docs/content/3.rendering/3.svelte.md @@ -106,12 +106,12 @@ Use the `plugins` prop to add functionality like syntax highlighting, emoji supp ### With Math Plugin -The `@comark/svelte/plugin-math` subpath bundles the math plugin and a Svelte rendering component: +The `@comark/svelte/plugins/math` subpath bundles the math plugin and a Svelte rendering component: ```svelte [App.svelte] @@ -121,12 +121,12 @@ The `@comark/svelte/plugin-math` subpath bundles the math plugin and a Svelte re ### With Mermaid Plugin -The `@comark/svelte/plugin-mermaid` subpath provides Mermaid diagram support: +The `@comark/svelte/plugins/mermaid` subpath provides Mermaid diagram support: ```svelte [App.svelte] diff --git a/docs/content/4.plugins/2.external/10.mermaid.md b/docs/content/4.plugins/2.external/10.mermaid.md index 9690f29..2547120 100644 --- a/docs/content/4.plugins/2.external/10.mermaid.md +++ b/docs/content/4.plugins/2.external/10.mermaid.md @@ -97,7 +97,7 @@ function App() { ```svelte [App.svelte] + + +``` + +### With React + +```tsx +import { Comark } from '@comark/react' +import taskList from 'comark/plugins/task-list' + +function App() { + return ( + {markdown} + ) +} +``` + +## Syntax + +Use `[ ]` for unchecked and `[x]` (or `[X]`) for checked items inside a list: + +```mdc +- [x] Completed task +- [ ] Pending task +- [X] Also completed (case-insensitive) +``` + +Task lists also work in nested lists: + +```mdc +- [x] Parent task + - [x] Sub-task done + - [ ] Sub-task pending +- [ ] Another parent task +``` + +## CSS Classes + +The plugin adds CSS classes to help with styling: + +| Element | Class | +|---------|-------| +| `
    ` containing tasks | `contains-task-list` | +| `
  • ` with a checkbox | `task-list-item` | +| `` checkbox | `task-list-item-checkbox` | + +Example styles: + +```css +.task-list-item { + list-style: none; +} + +.task-list-item-checkbox { + margin-right: 0.5em; +} +``` + +## Related + +- [Parse API](/api/parse) - Main parsing API +- [Alerts](/plugins/core/alert) - GitHub-style alert blockquotes diff --git a/docs/content/4.plugins/2.external/.navigation.yml b/docs/content/4.plugins/2.external/.navigation.yml deleted file mode 100644 index ee38010..0000000 --- a/docs/content/4.plugins/2.external/.navigation.yml +++ /dev/null @@ -1 +0,0 @@ -title: External Plugins diff --git a/docs/content/4.plugins/2.external/12.cjk.md b/docs/content/4.plugins/2.external/12.cjk.md deleted file mode 100644 index f86404f..0000000 --- a/docs/content/4.plugins/2.external/12.cjk.md +++ /dev/null @@ -1,222 +0,0 @@ ---- -title: CJK Language Support -description: Plugin for proper handling of Chinese, Japanese, and Korean text in Comark. -navigation: - icon: i-lucide-languages - title: CJK Language -seo: - title: CJK Language Support Plugin -links: - - label: Parse API - icon: i-lucide-code - to: /api/parse - color: neutral - variant: soft - - label: Plugins Overview - icon: i-lucide-plug - to: /plugins - color: neutral - variant: soft ---- - -The CJK plugin provides optimized text handling for Chinese, Japanese, and Korean (CJK) languages. It handles line breaks correctly to prevent unwanted spaces between CJK characters. - -The plugin is included in `comark` — no separate installation needed. - -## Basic Usage - -### With Parse API - -```typescript [parse.ts] -import { parse } from 'comark' -import cjk from 'comark/plugins/cjk' - -const result = await parse('这是一段中文文本。', { - plugins: [cjk()] -}) -``` - -### With Vue - -```vue [App.vue] - - - -``` - -### With React - -```tsx [App.tsx] -import { Comark } from '@comark/react' -import cjk from 'comark/plugins/cjk' - -function App() { - const markdown = ` -# 日本語の見出し - -これは日本語のテキストです。 - ` - - return {markdown} -} -``` - -## Supported Languages - -### Chinese (中文) - -- Simplified Chinese (简体中文) -- Traditional Chinese (繁體中文) -- Proper punctuation handling: ,。!?「」『』 -- Chinese-specific typography - -**Example:** - -```mdc -# 中文标题 - -这是**加粗文本**,这是*斜体文本*。 - -- 列表项一 -- 列表项二 -- 列表项三 -``` - -### Japanese (日本語) - -- Hiragana (ひらがな) -- Katakana (カタカナ) -- Kanji (漢字) -- Proper punctuation handling: 、。!?「」『』 -- Mixed script support - -**Example:** - -```mdc -# 日本語の見出し - -これは**太字テキスト**です。これは*斜体テキスト*です。 - -1. 最初の項目 -2. 二番目の項目 -3. 三番目の項目 -``` - -### Korean (한국어) - -- Hangul characters -- Korean punctuation handling -- Proper spacing rules - -**Example:** - -```mdc -# 한국어 제목 - -이것은 **굵은 글씨**입니다。이것은 *기울임 글씨*입니다。 - -- 첫 번째 항목 -- 두 번째 항목 -- 세 번째 항목 -``` - -## Features - -### Line Breaking - -The plugin handles soft line breaks in CJK text correctly: - -```mdc -这是第一行 -这是第二行 -这是第三行 -``` - -Renders without extra spaces between lines. - -### Mixed Content - -Works seamlessly with mixed CJK and Latin text: - -```mdc -Hello 世界!こんにちは 안녕하세요! - -CJK文字とLatin文字를 함께 사용할 수 있습니다。 -``` - -### All Markdown Features - -The plugin supports all standard markdown features: - -#### Headings - -```mdc -# 一级标题 -## 二级标题 -### 三级标题 -``` - -#### Lists - -```mdc -- 无序列表项 -- 另一个项目 - -1. 有序列表项 -2. 第二项 -``` - -#### Tables - -```mdc -| 名称 | 描述 | -|------|------| -| 项目A | 这是项目A的描述 | -| 项目B | これはプロジェクトBです | -``` - -#### Blockquotes - -```mdc -> 这是一段引用文本。 -> 来自某位名人。 -``` - -#### Code Blocks - -````mdc -```javascript -// 中文注释 -const message = "你好世界" -console.log(message) -``` -```` - -#### Inline Code - -```mdc -使用 `代码` 标签在中文文本中。 -``` - -## Examples - -See the [CJK example](/examples#cjk-text-support) for a complete working implementation. - -## Related - -- [Parse API](/api/parse) - Main parsing API -- [Vue Rendering](/rendering/vue) - Using with Vue -- [React Rendering](/rendering/react) - Using with React diff --git a/docs/content/4.plugins/index.md b/docs/content/4.plugins/index.md index 206e295..8c518ad 100644 --- a/docs/content/4.plugins/index.md +++ b/docs/content/4.plugins/index.md @@ -4,11 +4,9 @@ description: Extend Comark with powerful plugins for syntax highlighting, emojis navigation: false --- -Comark's plugin system extends markdown functionality with specialized features. Plugins can add new syntax, transform content, or enhance rendering. +Comark's plugin system extends markdown functionality with specialized features. All plugins are part of the core `comark` package. -## Core Plugins - -Core plugins are built-in and part of the main `comark` package: +## Plugins ::card-group{cols="2"} ::card{icon="i-lucide-shield-check" title="Security" to="/plugins/core/security"} @@ -32,26 +30,20 @@ Core plugins are built-in and part of the main `comark` package: :: ::card{icon="i-lucide-bell" title="Alerts" to="/plugins/core/alert"} - Render GitHub-style alert blockquotes with icons and colors (built-in) + Render GitHub-style alert blockquotes with icons and colors :: -:: -## External Plugins - -External plugins are separate packages that extend Comark with specialized features: + ::card{icon="i-lucide-check-square" title="Task List" to="/plugins/core/task-list"} + Render interactive checkboxes from `[ ]` and `[x]` list syntax + :: -::card-group{cols="2"} - ::card{icon="i-simple-icons-mermaid" title="Mermaid" to="/plugins/external/mermaid"} + ::card{icon="i-simple-icons-mermaid" title="Mermaid" to="/plugins/core/mermaid"} Create diagrams and visualizations using Mermaid syntax in code blocks :: - ::card{icon="i-lucide-calculator" title="Math" to="/plugins/external/math"} + ::card{icon="i-lucide-calculator" title="Math" to="/plugins/core/math"} Render LaTeX math formulas using KaTeX with inline and display equations :: - - ::card{icon="i-lucide-languages" title="CJK Language" to="/plugins/external/cjk"} - Optimized text handling for Chinese, Japanese, and Korean languages - :: :: ## Use Plugins diff --git a/docs/content/index.md b/docs/content/index.md index 644400a..34fb09d 100644 --- a/docs/content/index.md +++ b/docs/content/index.md @@ -87,17 +87,6 @@ plugins: $$e^{i\pi} + 1 = 0$$ package: "@comark/math" - - id: cjk - name: CJK - icon: i-lucide-languages - description: Improved line breaking and spacing between CJK and Latin characters. - input: |- - # 你好世界 - - Comark支持**中文**、_日本語_、한국어等CJK文字。 - - 混合English和中文的排版效果更好。 - package: "@comark/cjk" - id: highlight name: Highlight icon: i-lucide-code @@ -136,7 +125,7 @@ plugins: Full API docs. package: comark -description: Extend Comark with plugins for math formulas, CJK text, syntax +description: Extend Comark with plugins for math formulas, syntax highlighting, and more. headline: Plugins linkLabel: Browse all plugins @@ -166,8 +155,6 @@ footerSections: to: /plugins/core/highlight - label: Math to: /plugins/external/math - - label: CJK - to: /plugins/external/cjk - label: Mermaid to: /plugins/external/mermaid - title: Community diff --git a/examples/3.plugins/vue-vite-cjk/README.md b/examples/3.plugins/vue-vite-cjk/README.md deleted file mode 100644 index 2bfd755..0000000 --- a/examples/3.plugins/vue-vite-cjk/README.md +++ /dev/null @@ -1,237 +0,0 @@ ---- -title: CJK Language Support -navigation.title: CJK languages -description: Example showing how to use Comark with Chinese, Japanese, and Korean text in Vue and Vite. -navigation.icon: i-lucide-languages -category: Plugins -path: /examples/plugins/vue-vite-cjk ---- - -::code-tree{defaultValue="src/App.vue" expandAll} - -```ts [src/main.ts] -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') -``` - -```vue [src/App.vue] - - - -``` - -```ts [vite.config.ts] -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' - -export default defineConfig({ - plugins: [vue()], -}) -``` - -```json [package.json] -{ - "name": "comark-vue-cjk-example", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vue-tsc && vite build", - "preview": "vite preview" - }, - "dependencies": { - "@comark/cjk": "latest", - "comark": "latest", - "vue": "^3.5.27" - }, - "devDependencies": { - "@vitejs/plugin-vue": "^6.0.4", - "typescript": "^5.9.3", - "vite": "^7.3.1", - "vue-tsc": "^3.2.4" - } -} -``` - -```html [index.html] - - - - - - Comark + CJK - Vue Example - - -
    - - - -``` - -```json [tsconfig.json] -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "skipLibCheck": true, - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "preserve", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src/**/*.ts", "src/**/*.vue"] -} -``` - -:: - -## Features - -This example demonstrates how to use Comark with CJK (Chinese, Japanese, Korean) text in Vue: - -- **CJK Plugin**: Optimized text handling for Chinese, Japanese, and Korean languages -- **Proper Line Breaking**: Handles line breaks in CJK text without adding unwanted spaces -- **Mixed Content**: Works seamlessly with mixed CJK and Latin text -- **All Markdown Features**: Full support for headings, lists, code, tables, and more in CJK - -## Usage - -1. Import the CJK plugin: - ```ts - import cjk from '@comark/cjk' - ``` - -2. Pass the plugin to Comark: - ```vue - - ``` - -3. Write markdown in any CJK language: - ```markdown - # 中文标题 - - 这是一段中文文本。 - - ## 日本語の見出し - - これは日本語のテキストです。 - - ### 한국어 제목 - - 이것은 한국어 텍스트입니다. - ``` - -## Why Use the CJK Plugin? - -Without the CJK plugin, markdown parsers often add unwanted spaces between lines of CJK text, which breaks proper text flow. The CJK plugin handles this correctly: - -**Without CJK plugin:** -``` -这是第一行 -这是第二行 -→ Renders as: "这是第一行 这是第二行" (unwanted space) -``` - -**With CJK plugin:** -``` -这是第一行 -这是第二行 -→ Renders as: "这是第一行这是第二行" (correct) -``` - -## Language-Specific Features - -### Chinese (中文) -- Simplified and Traditional Chinese support -- Proper punctuation handling (,。!?) -- Chinese-specific typography - -### Japanese (日本語) -- Hiragana, Katakana, and Kanji support -- Proper handling of Japanese punctuation (、。!?) -- Mixed script support (かな + 漢字 + ローマ字) - -### Korean (한국어) -- Hangul character support -- Korean punctuation handling -- Proper spacing rules for Korean text - -## Tips for CJK Content - -1. **Font Selection**: Use system fonts or web fonts that support CJK characters -2. **Line Height**: Increase line-height (1.7-2.0) for better readability -3. **Font Size**: Consider slightly larger font sizes for CJK text -4. **Mixed Content**: The plugin handles transitions between CJK and Latin text automatically diff --git a/examples/3.plugins/vue-vite-cjk/index.html b/examples/3.plugins/vue-vite-cjk/index.html deleted file mode 100644 index 7411bba..0000000 --- a/examples/3.plugins/vue-vite-cjk/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - Comark + CJK - Vue Example - - -
    - - - diff --git a/examples/3.plugins/vue-vite-cjk/package.json b/examples/3.plugins/vue-vite-cjk/package.json deleted file mode 100644 index 79766fd..0000000 --- a/examples/3.plugins/vue-vite-cjk/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "comark-vue-vite-cjk", - "type": "module", - "private": true, - "scripts": { - "dev": "vite", - "build": "vue-tsc && vite build", - "preview": "vite preview" - }, - "dependencies": { - "comark": "workspace:*", - "vue": "^3.5.29" - }, - "devDependencies": { - "@vitejs/plugin-vue": "^6.0.4", - "typescript": "^5.9.3", - "vite": "^7.3.1", - "vue-tsc": "^3.2.5" - } -} diff --git a/examples/3.plugins/vue-vite-cjk/src/App.vue b/examples/3.plugins/vue-vite-cjk/src/App.vue deleted file mode 100644 index 53280d9..0000000 --- a/examples/3.plugins/vue-vite-cjk/src/App.vue +++ /dev/null @@ -1,69 +0,0 @@ - - - diff --git a/examples/3.plugins/vue-vite-cjk/src/main.ts b/examples/3.plugins/vue-vite-cjk/src/main.ts deleted file mode 100644 index 01433bc..0000000 --- a/examples/3.plugins/vue-vite-cjk/src/main.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/examples/3.plugins/vue-vite-cjk/tsconfig.json b/examples/3.plugins/vue-vite-cjk/tsconfig.json deleted file mode 100644 index d078fc8..0000000 --- a/examples/3.plugins/vue-vite-cjk/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "skipLibCheck": true, - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "preserve", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src/**/*.ts", "src/**/*.vue"] -} diff --git a/examples/3.plugins/vue-vite-cjk/vite.config.ts b/examples/3.plugins/vue-vite-cjk/vite.config.ts deleted file mode 100644 index c40aa3c..0000000 --- a/examples/3.plugins/vue-vite-cjk/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' - -export default defineConfig({ - plugins: [vue()], -}) diff --git a/package.json b/package.json index 49eb20a..577c857 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "dev:vue": "pnpm --filter comark-vue-vite run dev", "dev:vue:mermaid": "pnpm --filter comark-vue-vite-mermaid run dev", "dev:vue:math": "pnpm --filter comark-vue-vite-math run dev", - "dev:vue:cjk": "pnpm --filter comark-vue-vite-cjk run dev", "dev:astro": "pnpm --filter comark-astro run dev", "dev:vitepress": "pnpm --filter comark-vitepress run dev", "dev:nuxt": "pnpm --filter comark-nuxt run dev", @@ -36,8 +35,8 @@ "lint": "eslint .", "typecheck": "tsc --noEmit", "verify": "pnpm run lint && pnpm run test && pnpm run typecheck", - "release": "pnpm --filter 'comark' run release && pnpm --filter '@comark/cjk' run release && pnpm --filter '@comark/math' run release", - "release:dry": "pnpm --filter 'comark' run release:dry && pnpm --filter '@comark/cjk' run release:dry && pnpm --filter '@comark/math' run release:dry", + "release": "pnpm --filter 'comark' run release && pnpm --filter '@comark/*' run release", + "release:dry": "pnpm --filter 'comark' run release:dry && pnpm --filter '@comark/*' run release:dry", "postinstall": "pnpm stub" }, "devDependencies": { diff --git a/packages/comark-react/src/index.ts b/packages/comark-react/src/index.ts index 95877ec..d4b5602 100644 --- a/packages/comark-react/src/index.ts +++ b/packages/comark-react/src/index.ts @@ -5,6 +5,7 @@ import type { ParseOptions } from 'comark' export { ComarkRenderer } from './components/ComarkRenderer' export { Comark } +export type * from 'comark' interface DefineComarkComponentOptions extends ParseOptions { name?: string diff --git a/packages/comark-svelte/.release-it.json b/packages/comark-svelte/.release-it.json new file mode 100644 index 0000000..c59f778 --- /dev/null +++ b/packages/comark-svelte/.release-it.json @@ -0,0 +1,33 @@ +{ + "git": { + "commitMessage": "chore(svelte): release v${version}", + "tagName": "@comark/svelte@${version}", + "tagAnnotation": "@comark/svelte v${version}", + "requireCleanWorkingDir": true + }, + "github": { + "release": true, + "releaseName": "@comark/svelte v${version}" + }, + "npm": { + "publish": true, + "publishPath": "." + }, + "plugins": { + "@release-it/conventional-changelog": { + "ignoreRecommendedBump": true, + "preset": { + "name": "conventionalcommits", + "types": [ + { "type": "feat", "section": "Features" }, + { "type": "fix", "section": "Bug Fixes" }, + { "type": "perf", "section": "Performance" } + ] + }, + "infile": "CHANGELOG.md" + } + }, + "hooks": { + "before:release": ["pnpm run build"] + } +} diff --git a/packages/comark-svelte/package.json b/packages/comark-svelte/package.json index ba5e7a8..4b3868d 100644 --- a/packages/comark-svelte/package.json +++ b/packages/comark-svelte/package.json @@ -43,13 +43,14 @@ "test": "vitest run", "check": "svelte-check --tsconfig ./tsconfig.json", "lint": "eslint src/", - "lint:fix": "eslint src/ --fix" + "lint:fix": "eslint src/ --fix", + "release": "release-it" }, "peerDependencies": { - "svelte": "^5.0.0", "beautiful-mermaid": "^1.1.3", "katex": "^0.16.33", - "shiki": "^3.22.0" + "shiki": "^3.22.0", + "svelte": "^5.0.0" }, "peerDependenciesMeta": { "shiki": { @@ -71,6 +72,7 @@ "@sveltejs/vite-plugin-svelte": "^6.2.4", "@vitest/browser": "^4.0.18", "@vitest/browser-playwright": "^4.0.18", + "release-it": "^19.2.4", "svelte": "^5.53.7", "svelte-check": "^4.2.1", "vitest": "^4.0.18", diff --git a/packages/comark-svelte/src/index.ts b/packages/comark-svelte/src/index.ts index d259ff5..96fecf7 100644 --- a/packages/comark-svelte/src/index.ts +++ b/packages/comark-svelte/src/index.ts @@ -6,3 +6,5 @@ export type { ComarkRendererProps, ComarkNodeProps, } from './types.js' + +export type * from 'comark' diff --git a/packages/comark-vue/src/index.ts b/packages/comark-vue/src/index.ts index 39555ec..f253d91 100644 --- a/packages/comark-vue/src/index.ts +++ b/packages/comark-vue/src/index.ts @@ -5,6 +5,7 @@ import type { ComponentManifest, ParseOptions } from 'comark' export { ComarkRenderer } from './components/ComarkRenderer' export { Comark } from './components/Comark' +export type * from 'comark' interface DefineComarkComponentOptions extends ParseOptions { name?: string diff --git a/packages/comark/SPEC/MDC/cjk.md b/packages/comark/SPEC/MDC/cjk.md deleted file mode 100644 index 5f53bbf..0000000 --- a/packages/comark/SPEC/MDC/cjk.md +++ /dev/null @@ -1,258 +0,0 @@ ---- -options: - plugins: - - cjk ---- - -## Input - -```md -# CJK Language Support - -Comark properly handles emphasis in Chinese, Japanese, and Korean text, even with ideographic punctuation. - -## Japanese - -Standard markdown breaks with ideographic punctuation: - -**この文は太字になります(This sentence will be bolded)。**この文が後に続いても大丈夫です。 - -*斜体のテキスト【補足情報】。*この文が後に続いても大丈夫です。 - -~~削除されたテキスト(古い情報)。~~この文は正しいです。 - -## Chinese - -Works seamlessly with Chinese punctuation: - -**重要提示(Important Notice):**请注意。 - -*这是斜体文字(带括号)。*这句子继续也没问题。 - -~~旧方法(已废弃)。~~这个句子是正确的。 - -## Korean - -Korean text with mixed punctuation: - -**한국어 구문(괄호 포함)**을 강조. - -*이 텍스트(괄호 포함)*는 기울임꼴입니다. - -~~이 텍스트(괄호 포함)~~를 삭제합니다. -``` - -## AST - -```json -{ - "frontmatter": {}, - "meta": {}, - "nodes": [ - [ - "h1", - { - "id": "cjk-language-support" - }, - "CJK Language Support" - ], - [ - "p", - {}, - "Comark properly handles emphasis in Chinese, Japanese, and Korean text, even with ideographic punctuation." - ], - [ - "h2", - { - "id": "japanese" - }, - "Japanese" - ], - [ - "p", - {}, - "Standard markdown breaks with ideographic punctuation:" - ], - [ - "p", - {}, - [ - "strong", - {}, - "この文は太字になります(This sentence will be bolded)。" - ], - "この文が後に続いても大丈夫です。" - ], - [ - "p", - {}, - [ - "em", - {}, - "斜体のテキスト【補足情報】。" - ], - "この文が後に続いても大丈夫です。" - ], - [ - "p", - {}, - [ - "del", - {}, - "削除されたテキスト(古い情報)。" - ], - "この文は正しいです。" - ], - [ - "h2", - { - "id": "chinese" - }, - "Chinese" - ], - [ - "p", - {}, - "Works seamlessly with Chinese punctuation:" - ], - [ - "p", - {}, - [ - "strong", - {}, - "重要提示(Important Notice):" - ], - "请注意。" - ], - [ - "p", - {}, - [ - "em", - {}, - "这是斜体文字(带括号)。" - ], - "这句子继续也没问题。" - ], - [ - "p", - {}, - [ - "del", - {}, - "旧方法(已废弃)。" - ], - "这个句子是正确的。" - ], - [ - "h2", - { - "id": "korean" - }, - "Korean" - ], - [ - "p", - {}, - "Korean text with mixed punctuation:" - ], - [ - "p", - {}, - [ - "strong", - {}, - "한국어 구문(괄호 포함)" - ], - "을 강조." - ], - [ - "p", - {}, - [ - "em", - {}, - "이 텍스트(괄호 포함)" - ], - "는 기울임꼴입니다." - ], - [ - "p", - {}, - [ - "del", - {}, - "이 텍스트(괄호 포함)" - ], - "를 삭제합니다." - ] - ] -} -``` - -## HTML - -```html -

    CJK Language Support

    -

    Comark properly handles emphasis in Chinese, Japanese, and Korean text, even with ideographic punctuation.

    -

    Japanese

    -

    Standard markdown breaks with ideographic punctuation:

    -

    この文は太字になります(This sentence will be bolded)。この文が後に続いても大丈夫です。

    -

    斜体のテキスト【補足情報】。この文が後に続いても大丈夫です。

    -

    - 削除されたテキスト(古い情報)。この文は正しいです。 -

    -

    Chinese

    -

    Works seamlessly with Chinese punctuation:

    -

    重要提示(Important Notice):请注意。

    -

    这是斜体文字(带括号)。这句子继续也没问题。

    -

    - 旧方法(已废弃)。这个句子是正确的。 -

    -

    Korean

    -

    Korean text with mixed punctuation:

    -

    한국어 구문(괄호 포함)을 강조.

    -

    이 텍스트(괄호 포함)는 기울임꼴입니다.

    -

    - 이 텍스트(괄호 포함)를 삭제합니다. -

    -``` - -## Markdown - -```md -# CJK Language Support - -Comark properly handles emphasis in Chinese, Japanese, and Korean text, even with ideographic punctuation. - -## Japanese - -Standard markdown breaks with ideographic punctuation: - -**この文は太字になります(This sentence will be bolded)。**この文が後に続いても大丈夫です。 - -*斜体のテキスト【補足情報】。*この文が後に続いても大丈夫です。 - -~~削除されたテキスト(古い情報)。~~この文は正しいです。 - -## Chinese - -Works seamlessly with Chinese punctuation: - -**重要提示(Important Notice):**请注意。 - -*这是斜体文字(带括号)。*这句子继续也没问题。 - -~~旧方法(已废弃)。~~这个句子是正确的。 - -## Korean - -Korean text with mixed punctuation: - -**한국어 구문(괄호 포함)**을 강조. - -*이 텍스트(괄호 포함)*는 기울임꼴입니다. - -~~이 텍스트(괄호 포함)~~를 삭제합니다. -``` diff --git a/packages/comark/package.json b/packages/comark/package.json index 1368e50..2c84237 100644 --- a/packages/comark/package.json +++ b/packages/comark/package.json @@ -61,7 +61,6 @@ "github-slugger": "^2.0.0", "hast-util-to-string": "^3.0.1", "markdown-it": "^14.1.1", - "markdown-it-cjk-friendly": "^2.0.2", "minimark": "0.2.0", "mitata": "^1.0.34", "tsx": "^4.21.0", diff --git a/packages/comark/src/index.ts b/packages/comark/src/index.ts index 5c17a05..ab0e457 100644 --- a/packages/comark/src/index.ts +++ b/packages/comark/src/index.ts @@ -1,5 +1,5 @@ -import type { ComarkParseFn, ComarkParsePostState, ParseOptions } from './types' -import MarkdownIt from 'markdown-exit' +import type { ComarkParseFn, ComarkParsePostState, MarkdownExitPlugin, ParseOptions } from './types' +import MarkdownExit from 'markdown-exit' import pluginMdc from '@comark/markdown-it' import taskList from './plugins/task-list' import alert from './plugins/alert' @@ -48,7 +48,7 @@ export function createParse(options: ParseOptions = {}): ComarkParseFn { plugins.unshift(taskList()) plugins.unshift(alert()) - const parser = new MarkdownIt({ + const parser = new MarkdownExit({ html: true, linkify: true, }) @@ -57,7 +57,7 @@ export function createParse(options: ParseOptions = {}): ComarkParseFn { for (const plugin of plugins) { for (const markdownItPlugin of (plugin.markdownItPlugins || [])) { - parser.use(markdownItPlugin) + parser.use(markdownItPlugin as unknown as MarkdownExitPlugin) } } diff --git a/packages/comark/src/types.ts b/packages/comark/src/types.ts index 1303046..05ac6c7 100644 --- a/packages/comark/src/types.ts +++ b/packages/comark/src/types.ts @@ -1,7 +1,9 @@ import type MarkdownExit from 'markdown-exit' +import type MarkdownIt from 'markdown-it' import type { ComarkTree } from './ast/types' -export type MarkdownItPlugin = (md: MarkdownExit) => void +export type MarkdownExitPlugin = (md: MarkdownExit) => void +export type MarkdownItPlugin = (md: MarkdownIt) => void export type ComarkParsePreState = { markdown: string diff --git a/packages/comark/test/index.test.ts b/packages/comark/test/index.test.ts index a9da491..6943f00 100644 --- a/packages/comark/test/index.test.ts +++ b/packages/comark/test/index.test.ts @@ -5,7 +5,6 @@ import { parseFrontmatter } from '../src/internal/front-matter' import { parse } from 'comark' import highlight from 'comark/plugins/highlight' import { renderHTML, renderMarkdown } from '../src/string' -import cjk from 'markdown-it-cjk-friendly' import type { HighlightOptions } from '../src/plugins/highlight' import emoji from '../src/plugins/emoji' import type { ComarkPlugin } from 'comark' @@ -16,10 +15,9 @@ import rustLanguage from '@shikijs/langs/rust' import goLanguage from '@shikijs/langs/go' import type { ParseOptions } from '../src/types' -type PluginName = 'cjk' | 'emoji' +type PluginName = 'emoji' const pluginRegistry: Record ComarkPlugin> = { - cjk: () => ({ name: 'cjk', markdownItPlugins: [cjk as any] }), emoji, } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 15b3f90..b5c0b15 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -76,16 +76,16 @@ importers: version: 0.9.0 '@vercel/analytics': specifier: ^1.6.1 - version: 1.6.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(svelte@5.53.7)(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) + version: 1.6.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(svelte@5.53.7)(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) '@vercel/speed-insights': specifier: ^1.3.1 - version: 1.3.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(svelte@5.53.7)(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) + version: 1.3.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(svelte@5.53.7)(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) comark: specifier: workspace:* version: link:../packages/comark docus: specifier: latest - version: 5.4.4(dd5c3a1f396c19f5a6a808c3b94aca78) + version: 5.4.4(fd164cb6eab2bb659669583ce73808f6) markdown-it: specifier: ^14.1.1 version: 14.1.1 @@ -319,28 +319,6 @@ importers: specifier: ^3.2.5 version: 3.2.5(typescript@5.9.3) - examples/3.plugins/vue-vite-cjk: - dependencies: - comark: - specifier: workspace:* - version: link:../../../packages/comark - vue: - specifier: ^3.5.29 - version: 3.5.29(typescript@5.9.3) - devDependencies: - '@vitejs/plugin-vue': - specifier: ^6.0.4 - version: 6.0.4(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.29(typescript@5.9.3)) - typescript: - specifier: ^5.9.3 - version: 5.9.3 - vite: - specifier: ^7.3.1 - version: 7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - vue-tsc: - specifier: ^3.2.5 - version: 3.2.5(typescript@5.9.3) - examples/3.plugins/vue-vite-highlight: dependencies: '@shikijs/langs': @@ -467,9 +445,6 @@ importers: markdown-it: specifier: ^14.1.1 version: 14.1.1 - markdown-it-cjk-friendly: - specifier: ^2.0.2 - version: 2.0.2(@types/markdown-it@14.1.2)(markdown-it@14.1.1) minimark: specifier: 0.2.0 version: 0.2.0 @@ -562,6 +537,9 @@ importers: '@vitest/browser-playwright': specifier: ^4.0.18 version: 4.0.18(playwright@1.58.2)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18) + release-it: + specifier: ^19.2.4 + version: 19.2.4(@types/node@25.3.3)(magicast@0.5.1) svelte: specifier: ^5.53.7 version: 5.53.7 @@ -7212,16 +7190,6 @@ packages: markdown-exit@1.0.0-beta.9: resolution: {integrity: sha512-5tzrMKMF367amyBly131vm6eGuWRL2DjBqWaFmPzPbLyuxP0XOmyyyroOAIXuBAMF/3kZbbfqOxvW/SotqKqbQ==} - markdown-it-cjk-friendly@2.0.2: - resolution: {integrity: sha512-KXCl6sd129UqkAiRDb+NcAHrxC9xRa2WsGIsMMvtp2y1YlbeIaNYzArX2zfDoGhOjsyNMfJrGO7xGBss27YQSA==} - engines: {node: '>=18'} - peerDependencies: - '@types/markdown-it': '*' - markdown-it: '*' - peerDependenciesMeta: - '@types/markdown-it': - optional: true - markdown-it-math@5.2.1: resolution: {integrity: sha512-0YJczaqvBxgOt13oKj/4HYs/34Y9FsHiTktsIBaWYqrE+k1JxmMSTxCcTezTVul0YjmhmCBDehK65vWxjzRbdg==} peerDependencies: @@ -12072,7 +12040,7 @@ snapshots: rc9: 3.0.0 std-env: 3.10.0 - '@nuxt/ui@4.4.0(@nuxt/content@3.11.0(better-sqlite3@12.6.2)(magicast@0.5.1))(@tiptap/extensions@3.20.0(@tiptap/core@3.18.0(@tiptap/pm@3.18.0))(@tiptap/pm@3.18.0))(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.6.2))(embla-carousel@8.6.0)(focus-trap@7.8.0)(ioredis@5.9.2)(magicast@0.5.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))(yjs@13.6.29)(zod@4.3.6)': + '@nuxt/ui@4.4.0(@nuxt/content@3.11.0(better-sqlite3@12.6.2)(magicast@0.5.1))(@tiptap/extensions@3.20.0(@tiptap/core@3.18.0(@tiptap/pm@3.18.0))(@tiptap/pm@3.18.0))(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.6.2))(embla-carousel@8.6.0)(focus-trap@7.8.0)(ioredis@5.9.2)(magicast@0.5.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))(yjs@13.6.29)(zod@4.3.6)': dependencies: '@floating-ui/dom': 1.7.5 '@iconify/vue': 5.0.0(vue@3.5.29(typescript@5.9.3)) @@ -12458,7 +12426,7 @@ snapshots: typescript: 5.9.3 ufo: 1.6.3 unplugin: 2.3.11 - unplugin-vue-router: 0.16.2(@vue/compiler-sfc@3.5.27)(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) + unplugin-vue-router: 0.16.2(@vue/compiler-sfc@3.5.27)(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) unstorage: 1.17.4(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.2) vue-i18n: 11.2.8(vue@3.5.29(typescript@5.9.3)) vue-router: 4.6.4(vue@3.5.29(typescript@5.9.3)) @@ -14463,7 +14431,7 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vercel/analytics@1.6.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(svelte@5.53.7)(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))': + '@vercel/analytics@1.6.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(svelte@5.53.7)(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))': optionalDependencies: next: 15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) react: 19.2.4 @@ -14492,7 +14460,7 @@ snapshots: '@vercel/oidc@3.1.0': {} - '@vercel/speed-insights@1.3.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(svelte@5.53.7)(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))': + '@vercel/speed-insights@1.3.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(svelte@5.53.7)(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))': optionalDependencies: next: 15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) react: 19.2.4 @@ -15933,7 +15901,7 @@ snapshots: dlv@1.1.3: {} - docus@5.4.4(dd5c3a1f396c19f5a6a808c3b94aca78): + docus@5.4.4(fd164cb6eab2bb659669583ce73808f6): dependencies: '@iconify-json/lucide': 1.2.88 '@iconify-json/simple-icons': 1.2.69 @@ -15941,7 +15909,7 @@ snapshots: '@nuxt/content': 3.11.0(better-sqlite3@12.6.2)(magicast@0.5.1) '@nuxt/image': 2.0.0(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.2)(magicast@0.5.1) '@nuxt/kit': 4.3.0(magicast@0.5.1) - '@nuxt/ui': 4.4.0(@nuxt/content@3.11.0(better-sqlite3@12.6.2)(magicast@0.5.1))(@tiptap/extensions@3.20.0(@tiptap/core@3.18.0(@tiptap/pm@3.18.0))(@tiptap/pm@3.18.0))(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.6.2))(embla-carousel@8.6.0)(focus-trap@7.8.0)(ioredis@5.9.2)(magicast@0.5.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))(yjs@13.6.29)(zod@4.3.6) + '@nuxt/ui': 4.4.0(@nuxt/content@3.11.0(better-sqlite3@12.6.2)(magicast@0.5.1))(@tiptap/extensions@3.20.0(@tiptap/core@3.18.0(@tiptap/pm@3.18.0))(@tiptap/pm@3.18.0))(@tiptap/y-tiptap@3.0.2(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29))(change-case@5.4.4)(db0@0.3.4(better-sqlite3@12.6.2))(embla-carousel@8.6.0)(focus-trap@7.8.0)(ioredis@5.9.2)(magicast@0.5.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))(yjs@13.6.29)(zod@4.3.6) '@nuxtjs/i18n': 10.2.1(@vue/compiler-dom@3.5.29)(db0@0.3.4(better-sqlite3@12.6.2))(eslint@10.0.2(jiti@2.6.1))(ioredis@5.9.2)(magicast@0.5.1)(rollup@4.57.1)(vue@3.5.29(typescript@5.9.3)) '@nuxtjs/mcp-toolkit': 0.6.2(hono@4.11.7)(magicast@0.5.1)(zod@4.3.6) '@nuxtjs/mdc': 0.20.0(magicast@0.5.1) @@ -17735,13 +17703,6 @@ snapshots: punycode.js: 2.3.1 uc.micro: 2.1.0 - markdown-it-cjk-friendly@2.0.2(@types/markdown-it@14.1.2)(markdown-it@14.1.1): - dependencies: - get-east-asian-width: 1.4.0 - markdown-it: 14.1.1 - optionalDependencies: - '@types/markdown-it': 14.1.2 - markdown-it-math@5.2.1(temml@0.11.11): optionalDependencies: temml: 0.11.11 @@ -20883,7 +20844,7 @@ snapshots: optionalDependencies: '@nuxt/kit': 4.3.1(magicast@0.5.1) - unplugin-vue-router@0.16.2(@vue/compiler-sfc@3.5.27)(vue-router@4.6.4(vue@3.5.28(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)): + unplugin-vue-router@0.16.2(@vue/compiler-sfc@3.5.27)(vue-router@4.6.4(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)): dependencies: '@babel/generator': 7.29.0 '@vue-macros/common': 3.1.2(vue@3.5.29(typescript@5.9.3)) diff --git a/scripts/sync-plugins.mjs b/scripts/sync-plugins.mjs index 6d6ba66..8159020 100644 --- a/scripts/sync-plugins.mjs +++ b/scripts/sync-plugins.mjs @@ -31,8 +31,12 @@ for (const pkg of frameworkPackages) { for (const name of comarkPlugins) { // Check if the comark plugin has a default export in its .d.ts const comarkDtsPath = join(comarkPluginsDir, `${name}.d.ts`) - const hasDefault = existsSync(comarkDtsPath) - && /^export default /m.test(readFileSync(comarkDtsPath, 'utf-8')) + let hasDefault = existsSync(comarkDtsPath) + if (hasDefault) { + const content = readFileSync(comarkDtsPath, 'utf-8') + hasDefault = /^export default /m.test(content) + || /export\s*\{\s*default/.test(content) + } const reexport = `export * from 'comark/plugins/${name}';\n` + (hasDefault ? `export { default } from 'comark/plugins/${name}';\n` : '') diff --git a/skills/mdc/SKILL.md b/skills/mdc/SKILL.md index 44201a0..067cdd9 100644 --- a/skills/mdc/SKILL.md +++ b/skills/mdc/SKILL.md @@ -358,7 +358,7 @@ import type { │ ┌────────▼────────┐ │ MarkdownIt │ - │ + Plugins │ (Comark, Tasks, CJK) + │ + Plugins │ (Comark, Tasks) └────────┬────────┘ │ ┌────────▼────────┐ From 5b1b5fcad84910c9d7d82c2d6ab288c58bb385ec Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Tue, 10 Mar 2026 13:11:15 +0100 Subject: [PATCH 20/23] fix: react components --- .../comark-react/src/components/Comark.tsx | 55 ++++++++--------- .../src/components/ComarkClient.tsx | 60 +++++++++++++++++++ packages/comark-react/src/index.ts | 1 + 3 files changed, 85 insertions(+), 31 deletions(-) create mode 100644 packages/comark-react/src/components/ComarkClient.tsx diff --git a/packages/comark-react/src/components/Comark.tsx b/packages/comark-react/src/components/Comark.tsx index 5bb6e06..fac3749 100644 --- a/packages/comark-react/src/components/Comark.tsx +++ b/packages/comark-react/src/components/Comark.tsx @@ -1,8 +1,8 @@ -import React, { useState, useEffect } from 'react' +import React from 'react' import { parse } from 'comark' -import type { ComarkTree } from 'comark/ast' import type { ParseOptions } from 'comark' import { ComarkRenderer } from './ComarkRenderer' +import { ComarkClient } from './ComarkClient' export interface ComarkProps { /** @@ -39,7 +39,8 @@ export interface ComarkProps { componentsManifest?: (name: string) => Promise<{ default: React.ComponentType }> /** - * Enable streaming mode with enhanced components (e.g., ShikiCodeBlock) + * Enable streaming mode — delegates to ComarkClient for client-side re-rendering + * when the markdown prop changes. Use this for LLM streaming output. */ streaming?: boolean @@ -58,8 +59,8 @@ export interface ComarkProps { /** * Comark component * - * High-level component that accepts markdown as a string prop, - * parses it, and renders it using ComarkRenderer. + * Async server component that parses markdown on the server and renders it. + * When `streaming` is true, delegates to ComarkClient for client-side re-rendering. * * @example * ```tsx @@ -86,7 +87,7 @@ export interface ComarkProps { * } * ``` */ -export const Comark: React.FC = ({ +export async function Comark({ children, markdown = '', options = {}, @@ -96,34 +97,26 @@ export const Comark: React.FC = ({ streaming = false, caret = false, className, -}) => { - const [parsed, setParsed] = useState(null) +}: ComarkProps) { + const source = children ? String(children) : markdown - // Parse the markdown content - useEffect(() => { - let isMounted = true - - // Use async parse for non-streaming mode (supports code highlighting, etc.) - parse(children ? String(children) : markdown, { - ...options, - plugins, - }).then((result) => { - if (isMounted) { - setParsed(result) - } - }).catch((error) => { - console.error('Failed to parse markdown:', error) - }) - - return () => { - isMounted = false - } - }, [markdown, children, plugins, streaming]) - - if (!parsed) { - return null + if (streaming) { + return ( + + ) } + const parsed = await parse(source, { ...options, plugins }) + return ( { + parsePromise: Promise +} + +function ComarkContent({ + parsePromise, + components: customComponents = {}, + componentsManifest, + streaming = false, + caret = false, + className, +}: ComarkContentProps) { + const parsed = use(parsePromise) + + return ( + + ) +} + +export function ComarkClient({ + children, + markdown = '', + options = {}, + plugins = [], + ...rest +}: ComarkProps) { + const content = children ? String(children) : markdown + + // Re-creates the promise only when content changes. + // Note: options/plugins should be stable references (defined outside render or memoized). + const parsePromise = useMemo( + () => parse(content, { ...options, plugins }), + [content], + ) + + // Keep showing the previous parsed result while a new parse is pending — + // prevents blank flashes during rapid streaming updates. + const deferredPromise = useDeferredValue(parsePromise) + + return ( + + + + ) +} diff --git a/packages/comark-react/src/index.ts b/packages/comark-react/src/index.ts index d4b5602..1d76569 100644 --- a/packages/comark-react/src/index.ts +++ b/packages/comark-react/src/index.ts @@ -4,6 +4,7 @@ import type { ComarkProps } from './components/Comark' import type { ParseOptions } from 'comark' export { ComarkRenderer } from './components/ComarkRenderer' +export { ComarkClient } from './components/ComarkClient' export { Comark } export type * from 'comark' From f85da8febb0dd1b91afc549b7f82183768dbe083 Mon Sep 17 00:00:00 2001 From: Farnabaz Date: Tue, 10 Mar 2026 13:21:22 +0100 Subject: [PATCH 21/23] up --- docs/content/3.rendering/1.vue.md | 8 ++++---- docs/content/3.rendering/2.react.md | 8 ++++---- docs/content/3.rendering/3.svelte.md | 2 +- examples/3.plugins/vue-vite-highlight/src/App.vue | 2 +- examples/3.plugins/vue-vite-math/src/App.vue | 3 +-- examples/3.plugins/vue-vite-mermaid/src/App.vue | 3 +-- packages/comark-react/src/index.ts | 5 ++--- 7 files changed, 14 insertions(+), 17 deletions(-) diff --git a/docs/content/3.rendering/1.vue.md b/docs/content/3.rendering/1.vue.md index 8ea7339..7f89031 100644 --- a/docs/content/3.rendering/1.vue.md +++ b/docs/content/3.rendering/1.vue.md @@ -103,7 +103,7 @@ Use the `plugins` prop to add functionality like syntax highlighting, emoji supp ```vue [App.vue]