diff --git a/blocksuite/affine/block-embed/src/embed-synced-doc-block/adapters/extension.ts b/blocksuite/affine/block-embed/src/embed-synced-doc-block/adapters/extension.ts index 76a25436c..6b85f9959 100644 --- a/blocksuite/affine/block-embed/src/embed-synced-doc-block/adapters/extension.ts +++ b/blocksuite/affine/block-embed/src/embed-synced-doc-block/adapters/extension.ts @@ -1,11 +1,11 @@ import type { ExtensionType } from '@blocksuite/block-std'; import { EmbedSyncedDocBlockHtmlAdapterExtension } from './html.js'; -import { EmbedSyncedDocBlockMarkdownAdapterExtension } from './markdown.js'; +import { EmbedSyncedDocMarkdownAdapterExtension } from './markdown.js'; import { EmbedSyncedDocBlockPlainTextAdapterExtension } from './plain-text.js'; export const EmbedSyncedDocBlockAdapterExtensions: ExtensionType[] = [ EmbedSyncedDocBlockHtmlAdapterExtension, - EmbedSyncedDocBlockMarkdownAdapterExtension, + EmbedSyncedDocMarkdownAdapterExtension, EmbedSyncedDocBlockPlainTextAdapterExtension, ]; diff --git a/blocksuite/affine/block-embed/src/embed-synced-doc-block/adapters/markdown.ts b/blocksuite/affine/block-embed/src/embed-synced-doc-block/adapters/markdown.ts index b0dadd136..4cea3df2d 100644 --- a/blocksuite/affine/block-embed/src/embed-synced-doc-block/adapters/markdown.ts +++ b/blocksuite/affine/block-embed/src/embed-synced-doc-block/adapters/markdown.ts @@ -60,5 +60,5 @@ export const embedSyncedDocBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatc }, }; -export const EmbedSyncedDocBlockMarkdownAdapterExtension = +export const EmbedSyncedDocMarkdownAdapterExtension = BlockMarkdownAdapterExtension(embedSyncedDocBlockMarkdownAdapterMatcher); diff --git a/blocksuite/affine/shared/package.json b/blocksuite/affine/shared/package.json index eb4cd9a0e..0509bff19 100644 --- a/blocksuite/affine/shared/package.json +++ b/blocksuite/affine/shared/package.json @@ -28,9 +28,21 @@ "lit": "^3.2.0", "lodash.clonedeep": "^4.5.0", "lodash.mergewith": "^4.6.2", + "mdast-util-gfm-autolink-literal": "^2.0.1", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "micromark-extension-gfm-autolink-literal": "^2.1.0", + "micromark-extension-gfm-strikethrough": "^2.1.0", + "micromark-extension-gfm-table": "^2.1.0", + "micromark-extension-gfm-task-list-item": "^2.1.0", + "micromark-util-combine-extensions": "^2.0.0", "minimatch": "^10.0.1", "rehype-parse": "^9.0.0", "rehype-stringify": "^10.0.0", + "remark-math": "^6.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", "unified": "^11.0.5", "zod": "^3.23.8" }, diff --git a/blocksuite/affine/shared/src/adapters/index.ts b/blocksuite/affine/shared/src/adapters/index.ts index 709dfc3d1..dbaa18415 100644 --- a/blocksuite/affine/shared/src/adapters/index.ts +++ b/blocksuite/affine/shared/src/adapters/index.ts @@ -20,11 +20,16 @@ export { BlockMarkdownAdapterExtension, type BlockMarkdownAdapterMatcher, BlockMarkdownAdapterMatcherIdentifier, + InlineDeltaToMarkdownAdapterExtension, type InlineDeltaToMarkdownAdapterMatcher, InlineDeltaToMarkdownAdapterMatcherIdentifier, isMarkdownAST, type Markdown, + MarkdownAdapter, + MarkdownAdapterFactoryExtension, + MarkdownAdapterFactoryIdentifier, type MarkdownAST, + MarkdownASTToDeltaExtension, type MarkdownASTToDeltaMatcher, MarkdownASTToDeltaMatcherIdentifier, MarkdownDeltaConverter, diff --git a/blocksuite/blocks/src/_common/adapters/markdown/gfm.ts b/blocksuite/affine/shared/src/adapters/markdown/gfm.ts similarity index 96% rename from blocksuite/blocks/src/_common/adapters/markdown/gfm.ts rename to blocksuite/affine/shared/src/adapters/markdown/gfm.ts index da11510f8..833384120 100644 --- a/blocksuite/blocks/src/_common/adapters/markdown/gfm.ts +++ b/blocksuite/affine/shared/src/adapters/markdown/gfm.ts @@ -52,7 +52,7 @@ function gfmToMarkdown() { } export function remarkGfm(this: Processor) { - // eslint-disable-next-line @typescript-eslint/no-this-alias + // oxlint-disable-next-line typescript/no-this-alias const self = this; const data = self.data(); diff --git a/blocksuite/affine/shared/src/adapters/markdown/index.ts b/blocksuite/affine/shared/src/adapters/markdown/index.ts index e45efaf7c..31a591041 100644 --- a/blocksuite/affine/shared/src/adapters/markdown/index.ts +++ b/blocksuite/affine/shared/src/adapters/markdown/index.ts @@ -1,3 +1,4 @@ export * from './block-adapter.js'; export * from './delta-converter.js'; +export * from './markdown.js'; export * from './type.js'; diff --git a/blocksuite/blocks/src/_common/adapters/markdown/markdown.ts b/blocksuite/affine/shared/src/adapters/markdown/markdown.ts similarity index 92% rename from blocksuite/blocks/src/_common/adapters/markdown/markdown.ts rename to blocksuite/affine/shared/src/adapters/markdown/markdown.ts index 67e93d5d2..ab149e968 100644 --- a/blocksuite/blocks/src/_common/adapters/markdown/markdown.ts +++ b/blocksuite/affine/shared/src/adapters/markdown/markdown.ts @@ -1,14 +1,6 @@ import { DefaultTheme, NoteDisplayMode } from '@blocksuite/affine-model'; -import { - type AdapterContext, - AdapterFactoryIdentifier, - type BlockMarkdownAdapterMatcher, - BlockMarkdownAdapterMatcherIdentifier, - type Markdown, - type MarkdownAST, - MarkdownDeltaConverter, -} from '@blocksuite/affine-shared/adapters'; import type { ExtensionType } from '@blocksuite/block-std'; +import type { ServiceProvider } from '@blocksuite/global/di'; import { type AssetsManager, ASTWalker, @@ -34,10 +26,18 @@ import remarkParse from 'remark-parse'; import remarkStringify from 'remark-stringify'; import { unified } from 'unified'; -import { defaultBlockMarkdownAdapterMatchers } from './block-matcher.js'; -import { inlineDeltaToMarkdownAdapterMatchers } from './delta-converter/inline-delta.js'; -import { markdownInlineToDeltaMatchers } from './delta-converter/markdown-inline.js'; -import { remarkGfm } from './gfm.js'; +import { type AdapterContext, AdapterFactoryIdentifier } from '../types'; +import { + type BlockMarkdownAdapterMatcher, + BlockMarkdownAdapterMatcherIdentifier, +} from './block-adapter'; +import { + InlineDeltaToMarkdownAdapterMatcherIdentifier, + MarkdownASTToDeltaMatcherIdentifier, + MarkdownDeltaConverter, +} from './delta-converter'; +import { remarkGfm } from './gfm'; +import type { Markdown, MarkdownAST } from './type'; type MarkdownToSliceSnapshotPayload = { file: Markdown; @@ -164,11 +164,20 @@ export class MarkdownAdapter extends BaseAdapter { deltaConverter: MarkdownDeltaConverter; - constructor( - job: Job, - readonly blockMatchers: BlockMarkdownAdapterMatcher[] = defaultBlockMarkdownAdapterMatchers - ) { + readonly blockMatchers: BlockMarkdownAdapterMatcher[]; + + constructor(job: Job, provider: ServiceProvider) { super(job); + const blockMatchers = Array.from( + provider.getAll(BlockMarkdownAdapterMatcherIdentifier).values() + ); + const inlineDeltaToMarkdownAdapterMatchers = Array.from( + provider.getAll(InlineDeltaToMarkdownAdapterMatcherIdentifier).values() + ); + const markdownInlineToDeltaMatchers = Array.from( + provider.getAll(MarkdownASTToDeltaMatcherIdentifier).values() + ); + this.blockMatchers = blockMatchers; this.deltaConverter = new MarkdownDeltaConverter( job.adapterConfigs, inlineDeltaToMarkdownAdapterMatchers, @@ -440,13 +449,7 @@ export const MarkdownAdapterFactoryIdentifier = export const MarkdownAdapterFactoryExtension: ExtensionType = { setup: di => { di.addImpl(MarkdownAdapterFactoryIdentifier, provider => ({ - get: (job: Job) => - new MarkdownAdapter( - job, - Array.from( - provider.getAll(BlockMarkdownAdapterMatcherIdentifier).values() - ) - ), + get: (job: Job) => new MarkdownAdapter(job, provider), })); }, }; diff --git a/blocksuite/blocks/src/__tests__/adapters/markdown.unit.spec.ts b/blocksuite/blocks/src/__tests__/adapters/markdown.unit.spec.ts index 733e02a6a..17d07f8d7 100644 --- a/blocksuite/blocks/src/__tests__/adapters/markdown.unit.spec.ts +++ b/blocksuite/blocks/src/__tests__/adapters/markdown.unit.spec.ts @@ -1,4 +1,6 @@ import { DefaultTheme, NoteDisplayMode } from '@blocksuite/affine-model'; +import { MarkdownAdapter } from '@blocksuite/affine-shared/adapters'; +import { Container } from '@blocksuite/global/di'; import type { BlockSnapshot, DocSnapshot, @@ -8,11 +10,24 @@ import type { import { AssetsManager, MemoryBlobCRUD } from '@blocksuite/store'; import { describe, expect, test } from 'vitest'; -import { MarkdownAdapter } from '../../_common/adapters/markdown/index.js'; +import { inlineDeltaToMarkdownAdapterMatchers } from '../../_common/adapters/markdown/delta-converter/inline-delta.js'; +import { markdownInlineToDeltaMatchers } from '../../_common/adapters/markdown/delta-converter/markdown-inline.js'; +import { defaultBlockMarkdownAdapterMatchers } from '../../_common/adapters/markdown/index.js'; import { nanoidReplacement } from '../../_common/test-utils/test-utils.js'; import { embedSyncedDocMiddleware } from '../../_common/transformers/middlewares.js'; import { createJob } from '../utils/create-job.js'; +const container = new Container(); +[ + ...markdownInlineToDeltaMatchers, + ...defaultBlockMarkdownAdapterMatchers, + ...inlineDeltaToMarkdownAdapterMatchers, +].forEach(ext => { + ext.setup(container); +}); + +const provider = container.provider(); + describe('snapshot to markdown', () => { test('code', async () => { const blockSnapshot: BlockSnapshot = { @@ -71,7 +86,7 @@ describe('snapshot to markdown', () => { const markdown = '```python\nimport this\n```\n'; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -270,7 +285,7 @@ describe('snapshot to markdown', () => { hhh `; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -418,7 +433,7 @@ hhh * eee `; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -567,7 +582,7 @@ hhh * [ ] eee `; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -710,7 +725,7 @@ hhh 2. ddd `; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -874,7 +889,7 @@ hhh 2. eee `; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -946,7 +961,7 @@ hhh }; const markdown = 'aaa `bbb` ccc\n'; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -1018,7 +1033,7 @@ hhh }; const markdown = 'inline $E=mc^2$ latex\n'; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -1074,7 +1089,7 @@ hhh const markdown = '$$\nE=mc^2\n$$\n'; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -1146,7 +1161,7 @@ hhh }; const markdown = 'aaa [bbb](https://affine.pro/) ccc\n'; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -1215,7 +1230,7 @@ hhh }; const markdown = 'aaa https://affine.pro/ \n'; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -1288,7 +1303,7 @@ hhh const markdown = 'aaa**bbb**ccc\n'; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -1361,7 +1376,7 @@ hhh const markdown = 'aaa*bbb*ccc\n'; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -1437,7 +1452,7 @@ hhh const markdown = '![](assets/YXXTjRmLlNyiOUnHb8nAIvUP6V7PAXhwW9F5_tc2LGs=.blob "aaa")\n\n'; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const blobCRUD = new MemoryBlobCRUD(); await blobCRUD.set( 'YXXTjRmLlNyiOUnHb8nAIvUP6V7PAXhwW9F5_tc2LGs=', @@ -1670,7 +1685,7 @@ hhh | Task 1 | TODO | 2023-12-15 | 1 | 65 | test1,test2 | [test2](https://google.com) | https://google.com | true | | Task 2 | In Progress | 2023-12-20 | | | | test1 | | | `; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -1920,7 +1935,7 @@ hhh adapterConfigs.set('title:deadbeef', 'test'); adapterConfigs.set('docLinkBaseUrl', 'https://example.com'); }; - const mdAdapter = new MarkdownAdapter(createJob([middleware])); + const mdAdapter = new MarkdownAdapter(createJob([middleware]), provider); const target = await mdAdapter.fromBlockSnapshot({ snapshot: blockSnapshot, }); @@ -2327,7 +2342,7 @@ World! await job.snapshotToDoc(syncedDocSnapshot); await job.snapshotToDoc(docSnapShot); - const mdAdapter = new MarkdownAdapter(job); + const mdAdapter = new MarkdownAdapter(job, provider); const target = await mdAdapter.fromDocSnapshot({ snapshot: docSnapShot, }); @@ -2371,7 +2386,7 @@ describe('markdown to snapshot', () => { ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -2420,7 +2435,7 @@ describe('markdown to snapshot', () => { pageId: '', }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({ file: markdown, workspaceId: '', @@ -2471,7 +2486,7 @@ describe('markdown to snapshot', () => { pageId: '', }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({ file: markdown, workspaceId: '', @@ -2522,7 +2537,7 @@ describe('markdown to snapshot', () => { pageId: '', }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({ file: markdown, workspaceId: '', @@ -2700,7 +2715,7 @@ hhh ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -2836,7 +2851,7 @@ hhh ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -2972,7 +2987,7 @@ hhh ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -3081,7 +3096,7 @@ bbb ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -3131,7 +3146,7 @@ bbb ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -3186,7 +3201,7 @@ bbb pageId: '', }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({ file: markdown, workspaceId: '', @@ -3238,7 +3253,7 @@ bbb ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -3288,7 +3303,7 @@ bbb ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -3339,7 +3354,7 @@ bbb ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -3390,7 +3405,7 @@ bbb ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -3511,7 +3526,7 @@ bbb ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -3553,7 +3568,7 @@ bbb ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -3603,7 +3618,7 @@ bbb ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -3637,7 +3652,7 @@ bbb ], }; - const mdAdapter = new MarkdownAdapter(createJob()); + const mdAdapter = new MarkdownAdapter(createJob(), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); @@ -3835,7 +3850,7 @@ hhh const middleware: JobMiddleware = ({ adapterConfigs }) => { adapterConfigs.set('docLinkBaseUrl', 'https://example.com'); }; - const mdAdapter = new MarkdownAdapter(createJob([middleware])); + const mdAdapter = new MarkdownAdapter(createJob([middleware]), provider); const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ file: markdown, }); diff --git a/blocksuite/blocks/src/__tests__/surface/mindmap-preview.unit.spec.ts b/blocksuite/blocks/src/__tests__/surface/mindmap-preview.unit.spec.ts index cc1252784..27af835a2 100644 --- a/blocksuite/blocks/src/__tests__/surface/mindmap-preview.unit.spec.ts +++ b/blocksuite/blocks/src/__tests__/surface/mindmap-preview.unit.spec.ts @@ -1,8 +1,22 @@ +import { Container } from '@blocksuite/global/di'; import { DocCollection, Schema } from '@blocksuite/store'; import { describe, expect, test } from 'vitest'; +import { defaultBlockMarkdownAdapterMatchers } from '../../_common/adapters/index.js'; +import { inlineDeltaToMarkdownAdapterMatchers } from '../../_common/adapters/markdown/delta-converter/inline-delta.js'; +import { markdownInlineToDeltaMatchers } from '../../_common/adapters/markdown/delta-converter/markdown-inline.js'; import { markdownToMindmap } from '../../surface-block/mini-mindmap/mindmap-preview.js'; +const container = new Container(); +[ + ...markdownInlineToDeltaMatchers, + ...defaultBlockMarkdownAdapterMatchers, + ...inlineDeltaToMarkdownAdapterMatchers, +].forEach(ext => { + ext.setup(container); +}); +const provider = container.provider(); + describe('markdownToMindmap: convert markdown list to a mind map tree', () => { test('basic case', () => { const markdown = ` @@ -15,7 +29,7 @@ describe('markdownToMindmap: convert markdown list to a mind map tree', () => { const collection = new DocCollection({ schema: new Schema() }); collection.meta.initialize(); const doc = collection.createDoc(); - const nodes = markdownToMindmap(markdown, doc); + const nodes = markdownToMindmap(markdown, doc, provider); expect(nodes).toEqual({ text: 'Text A', @@ -53,7 +67,7 @@ describe('markdownToMindmap: convert markdown list to a mind map tree', () => { const collection = new DocCollection({ schema: new Schema() }); collection.meta.initialize(); const doc = collection.createDoc(); - const nodes = markdownToMindmap(markdown, doc); + const nodes = markdownToMindmap(markdown, doc, provider); expect(nodes).toEqual({ text: 'Text A', @@ -85,7 +99,7 @@ describe('markdownToMindmap: convert markdown list to a mind map tree', () => { const collection = new DocCollection({ schema: new Schema() }); collection.meta.initialize(); const doc = collection.createDoc(); - const nodes = markdownToMindmap(markdown, doc); + const nodes = markdownToMindmap(markdown, doc, provider); expect(nodes).toEqual(null); }); diff --git a/blocksuite/blocks/src/_common/adapters/extension.ts b/blocksuite/blocks/src/_common/adapters/extension.ts index 6e5ea4e2d..d0ec8c843 100644 --- a/blocksuite/blocks/src/_common/adapters/extension.ts +++ b/blocksuite/blocks/src/_common/adapters/extension.ts @@ -2,6 +2,7 @@ import { AttachmentAdapterFactoryExtension, HtmlAdapterFactoryExtension, ImageAdapterFactoryExtension, + MarkdownAdapterFactoryExtension, NotionHtmlAdapterFactoryExtension, NotionTextAdapterFactoryExtension, PlainTextAdapterFactoryExtension, @@ -10,7 +11,8 @@ import type { ExtensionType } from '@blocksuite/block-std'; import { htmlInlineToDeltaMatchers } from './html/delta-converter/html-inline.js'; import { inlineDeltaToHtmlAdapterMatchers } from './html/delta-converter/inline-delta.js'; -import { MarkdownAdapterFactoryExtension } from './markdown/markdown.js'; +import { inlineDeltaToMarkdownAdapterMatchers } from './markdown/delta-converter/inline-delta.js'; +import { markdownInlineToDeltaMatchers } from './markdown/delta-converter/markdown-inline.js'; import { MixTextAdapterFactoryExtension } from './mix-text.js'; import { notionHtmlInlineToDeltaMatchers } from './notion-html/delta-converter/html-inline.js'; import { inlineDeltaToPlainTextAdapterMatchers } from './plain-text/delta-converter/inline-delta.js'; @@ -20,6 +22,8 @@ export const AdapterFactoryExtensions: ExtensionType[] = [ ...inlineDeltaToHtmlAdapterMatchers, ...notionHtmlInlineToDeltaMatchers, ...inlineDeltaToPlainTextAdapterMatchers, + ...markdownInlineToDeltaMatchers, + ...inlineDeltaToMarkdownAdapterMatchers, AttachmentAdapterFactoryExtension, ImageAdapterFactoryExtension, MarkdownAdapterFactoryExtension, diff --git a/blocksuite/blocks/src/_common/adapters/markdown/block-matcher.ts b/blocksuite/blocks/src/_common/adapters/markdown/block-matcher.ts index 57a3b0014..f398be7e1 100644 --- a/blocksuite/blocks/src/_common/adapters/markdown/block-matcher.ts +++ b/blocksuite/blocks/src/_common/adapters/markdown/block-matcher.ts @@ -1,36 +1,36 @@ -import { bookmarkBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-bookmark'; -import { codeBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-code'; -import { databaseBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-database'; -import { dividerBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-divider'; +import { BookmarkBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-bookmark'; +import { CodeBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-code'; +import { DatabaseBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-database'; +import { DividerBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-divider'; import { - embedFigmaBlockMarkdownAdapterMatcher, - embedGithubBlockMarkdownAdapterMatcher, - embedLinkedDocBlockMarkdownAdapterMatcher, - embedLoomBlockMarkdownAdapterMatcher, - embedSyncedDocBlockMarkdownAdapterMatcher, - embedYoutubeBlockMarkdownAdapterMatcher, + EmbedFigmaMarkdownAdapterExtension, + EmbedGithubMarkdownAdapterExtension, + EmbedLinkedDocMarkdownAdapterExtension, + EmbedLoomMarkdownAdapterExtension, + EmbedSyncedDocMarkdownAdapterExtension, + EmbedYoutubeMarkdownAdapterExtension, } from '@blocksuite/affine-block-embed'; -import { imageBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-image'; -import { latexBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-latex'; -import { listBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-list'; -import { paragraphBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-paragraph'; +import { ImageBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-image'; +import { LatexBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-latex'; +import { ListBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-list'; +import { ParagraphBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-paragraph'; -import { rootBlockMarkdownAdapterMatcher } from '../../../root-block/adapters/markdown.js'; +import { RootBlockMarkdownAdapterExtension } from '../../../root-block/adapters/markdown.js'; export const defaultBlockMarkdownAdapterMatchers = [ - embedFigmaBlockMarkdownAdapterMatcher, - embedGithubBlockMarkdownAdapterMatcher, - embedLinkedDocBlockMarkdownAdapterMatcher, - embedLoomBlockMarkdownAdapterMatcher, - embedSyncedDocBlockMarkdownAdapterMatcher, - embedYoutubeBlockMarkdownAdapterMatcher, - listBlockMarkdownAdapterMatcher, - paragraphBlockMarkdownAdapterMatcher, - bookmarkBlockMarkdownAdapterMatcher, - codeBlockMarkdownAdapterMatcher, - databaseBlockMarkdownAdapterMatcher, - dividerBlockMarkdownAdapterMatcher, - imageBlockMarkdownAdapterMatcher, - latexBlockMarkdownAdapterMatcher, - rootBlockMarkdownAdapterMatcher, + EmbedFigmaMarkdownAdapterExtension, + EmbedGithubMarkdownAdapterExtension, + EmbedLinkedDocMarkdownAdapterExtension, + EmbedLoomMarkdownAdapterExtension, + EmbedSyncedDocMarkdownAdapterExtension, + EmbedYoutubeMarkdownAdapterExtension, + ListBlockMarkdownAdapterExtension, + ParagraphBlockMarkdownAdapterExtension, + BookmarkBlockMarkdownAdapterExtension, + CodeBlockMarkdownAdapterExtension, + DatabaseBlockMarkdownAdapterExtension, + DividerBlockMarkdownAdapterExtension, + ImageBlockMarkdownAdapterExtension, + LatexBlockMarkdownAdapterExtension, + RootBlockMarkdownAdapterExtension, ]; diff --git a/blocksuite/blocks/src/_common/adapters/markdown/delta-converter/inline-delta.ts b/blocksuite/blocks/src/_common/adapters/markdown/delta-converter/inline-delta.ts index a1b9461d1..56142492a 100644 --- a/blocksuite/blocks/src/_common/adapters/markdown/delta-converter/inline-delta.ts +++ b/blocksuite/blocks/src/_common/adapters/markdown/delta-converter/inline-delta.ts @@ -1,9 +1,12 @@ import { generateDocUrl } from '@blocksuite/affine-block-embed'; -import type { InlineDeltaToMarkdownAdapterMatcher } from '@blocksuite/affine-shared/adapters'; +import { InlineDeltaToMarkdownAdapterExtension } from '@blocksuite/affine-shared/adapters'; import type { PhrasingContent } from 'mdast'; +import type RemarkMath from 'remark-math'; -export const boldDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = - { +declare type _GLOBAL_ = typeof RemarkMath; + +export const boldDeltaToMarkdownAdapterMatcher = + InlineDeltaToMarkdownAdapterExtension({ name: 'bold', match: delta => !!delta.attributes?.bold, toAST: (_, context) => { @@ -13,10 +16,10 @@ export const boldDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatc children: [currentMdast], }; }, - }; + }); -export const italicDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = - { +export const italicDeltaToMarkdownAdapterMatcher = + InlineDeltaToMarkdownAdapterExtension({ name: 'italic', match: delta => !!delta.attributes?.italic, toAST: (_, context) => { @@ -26,10 +29,10 @@ export const italicDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMa children: [currentMdast], }; }, - }; + }); -export const strikeDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = - { +export const strikeDeltaToMarkdownAdapterMatcher = + InlineDeltaToMarkdownAdapterExtension({ name: 'strike', match: delta => !!delta.attributes?.strike, toAST: (_, context) => { @@ -39,20 +42,20 @@ export const strikeDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMa children: [currentMdast], }; }, - }; + }); -export const inlineCodeDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = - { +export const inlineCodeDeltaToMarkdownAdapterMatcher = + InlineDeltaToMarkdownAdapterExtension({ name: 'inlineCode', match: delta => !!delta.attributes?.code, toAST: delta => ({ type: 'inlineCode', value: delta.insert, }), - }; + }); -export const referenceDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = - { +export const referenceDeltaToMarkdownAdapterMatcher = + InlineDeltaToMarkdownAdapterExtension({ name: 'reference', match: delta => !!delta.attributes?.reference, toAST: (delta, context) => { @@ -86,10 +89,10 @@ export const referenceDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapte return mdast; }, - }; + }); -export const linkDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = - { +export const linkDeltaToMarkdownAdapterMatcher = + InlineDeltaToMarkdownAdapterExtension({ name: 'link', match: delta => !!delta.attributes?.link, toAST: (delta, context) => { @@ -120,10 +123,10 @@ export const linkDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatc } return mdast; }, - }; + }); -export const latexDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = - { +export const latexDeltaToMarkdownAdapterMatcher = + InlineDeltaToMarkdownAdapterExtension({ name: 'inlineLatex', match: delta => !!delta.attributes?.latex, toAST: delta => { @@ -139,15 +142,14 @@ export const latexDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMat } return mdast; }, - }; + }); -export const inlineDeltaToMarkdownAdapterMatchers: InlineDeltaToMarkdownAdapterMatcher[] = - [ - referenceDeltaToMarkdownAdapterMatcher, - linkDeltaToMarkdownAdapterMatcher, - inlineCodeDeltaToMarkdownAdapterMatcher, - boldDeltaToMarkdownAdapterMatcher, - italicDeltaToMarkdownAdapterMatcher, - strikeDeltaToMarkdownAdapterMatcher, - latexDeltaToMarkdownAdapterMatcher, - ]; +export const inlineDeltaToMarkdownAdapterMatchers = [ + referenceDeltaToMarkdownAdapterMatcher, + linkDeltaToMarkdownAdapterMatcher, + inlineCodeDeltaToMarkdownAdapterMatcher, + boldDeltaToMarkdownAdapterMatcher, + italicDeltaToMarkdownAdapterMatcher, + strikeDeltaToMarkdownAdapterMatcher, + latexDeltaToMarkdownAdapterMatcher, +]; diff --git a/blocksuite/blocks/src/_common/adapters/markdown/delta-converter/markdown-inline.ts b/blocksuite/blocks/src/_common/adapters/markdown/delta-converter/markdown-inline.ts index 672a40b3d..17382604c 100644 --- a/blocksuite/blocks/src/_common/adapters/markdown/delta-converter/markdown-inline.ts +++ b/blocksuite/blocks/src/_common/adapters/markdown/delta-converter/markdown-inline.ts @@ -1,6 +1,6 @@ -import type { MarkdownASTToDeltaMatcher } from '@blocksuite/affine-shared/adapters'; +import { MarkdownASTToDeltaExtension } from '@blocksuite/affine-shared/adapters'; -export const markdownTextToDeltaMatcher: MarkdownASTToDeltaMatcher = { +export const markdownTextToDeltaMatcher = MarkdownASTToDeltaExtension({ name: 'text', match: ast => ast.type === 'text', toDelta: ast => { @@ -9,9 +9,9 @@ export const markdownTextToDeltaMatcher: MarkdownASTToDeltaMatcher = { } return [{ insert: ast.value }]; }, -}; +}); -export const markdownInlineCodeToDeltaMatcher: MarkdownASTToDeltaMatcher = { +export const markdownInlineCodeToDeltaMatcher = MarkdownASTToDeltaExtension({ name: 'inlineCode', match: ast => ast.type === 'inlineCode', toDelta: ast => { @@ -20,9 +20,9 @@ export const markdownInlineCodeToDeltaMatcher: MarkdownASTToDeltaMatcher = { } return [{ insert: ast.value, attributes: { code: true } }]; }, -}; +}); -export const markdownStrongToDeltaMatcher: MarkdownASTToDeltaMatcher = { +export const markdownStrongToDeltaMatcher = MarkdownASTToDeltaExtension({ name: 'strong', match: ast => ast.type === 'strong', toDelta: (ast, context) => { @@ -36,9 +36,9 @@ export const markdownStrongToDeltaMatcher: MarkdownASTToDeltaMatcher = { }) ); }, -}; +}); -export const markdownEmphasisToDeltaMatcher: MarkdownASTToDeltaMatcher = { +export const markdownEmphasisToDeltaMatcher = MarkdownASTToDeltaExtension({ name: 'emphasis', match: ast => ast.type === 'emphasis', toDelta: (ast, context) => { @@ -52,9 +52,9 @@ export const markdownEmphasisToDeltaMatcher: MarkdownASTToDeltaMatcher = { }) ); }, -}; +}); -export const markdownDeleteToDeltaMatcher: MarkdownASTToDeltaMatcher = { +export const markdownDeleteToDeltaMatcher = MarkdownASTToDeltaExtension({ name: 'delete', match: ast => ast.type === 'delete', toDelta: (ast, context) => { @@ -68,9 +68,9 @@ export const markdownDeleteToDeltaMatcher: MarkdownASTToDeltaMatcher = { }) ); }, -}; +}); -export const markdownLinkToDeltaMatcher: MarkdownASTToDeltaMatcher = { +export const markdownLinkToDeltaMatcher = MarkdownASTToDeltaExtension({ name: 'link', match: ast => ast.type === 'link', toDelta: (ast, context) => { @@ -119,15 +119,15 @@ export const markdownLinkToDeltaMatcher: MarkdownASTToDeltaMatcher = { }) ); }, -}; +}); -export const markdownListToDeltaMatcher: MarkdownASTToDeltaMatcher = { +export const markdownListToDeltaMatcher = MarkdownASTToDeltaExtension({ name: 'list', match: ast => ast.type === 'list', toDelta: () => [], -}; +}); -export const markdownInlineMathToDeltaMatcher: MarkdownASTToDeltaMatcher = { +export const markdownInlineMathToDeltaMatcher = MarkdownASTToDeltaExtension({ name: 'inlineMath', match: ast => ast.type === 'inlineMath', toDelta: ast => { @@ -136,9 +136,9 @@ export const markdownInlineMathToDeltaMatcher: MarkdownASTToDeltaMatcher = { } return [{ insert: ' ', attributes: { latex: ast.value } }]; }, -}; +}); -export const markdownInlineToDeltaMatchers: MarkdownASTToDeltaMatcher[] = [ +export const markdownInlineToDeltaMatchers = [ markdownTextToDeltaMatcher, markdownInlineCodeToDeltaMatcher, markdownStrongToDeltaMatcher, diff --git a/blocksuite/blocks/src/_common/adapters/markdown/index.ts b/blocksuite/blocks/src/_common/adapters/markdown/index.ts index ec387f385..bd8c0e4c7 100644 --- a/blocksuite/blocks/src/_common/adapters/markdown/index.ts +++ b/blocksuite/blocks/src/_common/adapters/markdown/index.ts @@ -1,6 +1,3 @@ export { defaultBlockMarkdownAdapterMatchers } from './block-matcher.js'; -export { - MarkdownAdapter, - MarkdownAdapterFactoryExtension, - MarkdownAdapterFactoryIdentifier, -} from './markdown.js'; +export { inlineDeltaToMarkdownAdapterMatchers } from './delta-converter/inline-delta.js'; +export { markdownInlineToDeltaMatchers } from './delta-converter/markdown-inline.js'; diff --git a/blocksuite/blocks/src/_common/adapters/mix-text.ts b/blocksuite/blocks/src/_common/adapters/mix-text.ts index 392b1b2c9..f4a9f7ed1 100644 --- a/blocksuite/blocks/src/_common/adapters/mix-text.ts +++ b/blocksuite/blocks/src/_common/adapters/mix-text.ts @@ -1,6 +1,10 @@ import { DefaultTheme, NoteDisplayMode } from '@blocksuite/affine-model'; -import { AdapterFactoryIdentifier } from '@blocksuite/affine-shared/adapters'; +import { + AdapterFactoryIdentifier, + MarkdownAdapter, +} from '@blocksuite/affine-shared/adapters'; import type { ExtensionType } from '@blocksuite/block-std'; +import type { ServiceProvider } from '@blocksuite/global/di'; import type { DeltaInsert } from '@blocksuite/inline'; import { type AssetsManager, @@ -22,8 +26,6 @@ import { type ToDocSnapshotPayload, } from '@blocksuite/store'; -import { MarkdownAdapter } from './markdown/index.js'; - export type MixText = string; type MixTextToSliceSnapshotPayload = { @@ -37,9 +39,9 @@ type MixTextToSliceSnapshotPayload = { export class MixTextAdapter extends BaseAdapter { private readonly _markdownAdapter: MarkdownAdapter; - constructor(job: Job) { + constructor(job: Job, provider: ServiceProvider) { super(job); - this._markdownAdapter = new MarkdownAdapter(job); + this._markdownAdapter = new MarkdownAdapter(job, provider); } private _splitDeltas(deltas: DeltaInsert[]): DeltaInsert[][] { @@ -353,8 +355,8 @@ export const MixTextAdapterFactoryIdentifier = export const MixTextAdapterFactoryExtension: ExtensionType = { setup: di => { - di.addImpl(MixTextAdapterFactoryIdentifier, () => ({ - get: (job: Job) => new MixTextAdapter(job), + di.addImpl(MixTextAdapterFactoryIdentifier, provider => ({ + get: (job: Job) => new MixTextAdapter(job, provider), })); }, }; diff --git a/blocksuite/blocks/src/_common/transformers/markdown.ts b/blocksuite/blocks/src/_common/transformers/markdown.ts index 3b7b6b61c..a304f9126 100644 --- a/blocksuite/blocks/src/_common/transformers/markdown.ts +++ b/blocksuite/blocks/src/_common/transformers/markdown.ts @@ -1,9 +1,13 @@ +import { MarkdownAdapter } from '@blocksuite/affine-shared/adapters'; +import { Container } from '@blocksuite/global/di'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { assertExists, sha } from '@blocksuite/global/utils'; import type { Doc, DocCollection } from '@blocksuite/store'; import { extMimeMap, Job } from '@blocksuite/store'; -import { MarkdownAdapter } from '../adapters/markdown/index.js'; +import { defaultBlockMarkdownAdapterMatchers } from '../adapters/index.js'; +import { inlineDeltaToMarkdownAdapterMatchers } from '../adapters/markdown/delta-converter/inline-delta.js'; +import { markdownInlineToDeltaMatchers } from '../adapters/markdown/delta-converter/markdown-inline.js'; import { defaultImageProxyMiddleware, docLinkBaseURLMiddleware, @@ -12,6 +16,17 @@ import { } from './middlewares.js'; import { createAssetsArchive, download, Unzip } from './utils.js'; +const container = new Container(); +[ + ...markdownInlineToDeltaMatchers, + ...defaultBlockMarkdownAdapterMatchers, + ...inlineDeltaToMarkdownAdapterMatchers, +].forEach(ext => { + ext.setup(container); +}); + +const provider = container.provider(); + type ImportMarkdownToBlockOptions = { doc: Doc; markdown: string; @@ -41,7 +56,7 @@ async function exportDoc(doc: Doc) { }); const snapshot = job.docToSnapshot(doc); - const adapter = new MarkdownAdapter(job); + const adapter = new MarkdownAdapter(job, provider); if (!snapshot) { return; } @@ -89,7 +104,7 @@ async function importMarkdownToBlock({ collection: doc.collection, middlewares: [defaultImageProxyMiddleware, docLinkBaseURLMiddleware], }); - const adapter = new MarkdownAdapter(job); + const adapter = new MarkdownAdapter(job, provider); const snapshot = await adapter.toSliceSnapshot({ file: markdown, assets: job.assetsManager, @@ -129,7 +144,7 @@ async function importMarkdownToDoc({ docLinkBaseURLMiddleware, ], }); - const mdAdapter = new MarkdownAdapter(job); + const mdAdapter = new MarkdownAdapter(job, provider); const page = await mdAdapter.toDoc({ file: markdown, assets: job.assetsManager, @@ -195,7 +210,7 @@ async function importMarkdownZip({ for (const [key, value] of pendingPathBlobIdMap.entries()) { pathBlobIdMap.set(key, value); } - const mdAdapter = new MarkdownAdapter(job); + const mdAdapter = new MarkdownAdapter(job, provider); const markdown = await blob.text(); const doc = await mdAdapter.toDoc({ file: markdown, diff --git a/blocksuite/blocks/src/index.ts b/blocksuite/blocks/src/index.ts index 60f3ed3ce..eae7c2c2c 100644 --- a/blocksuite/blocks/src/index.ts +++ b/blocksuite/blocks/src/index.ts @@ -7,6 +7,7 @@ import { splitElements } from './root-block/edgeless/utils/clipboard-utils.js'; import { isCanvasElement } from './root-block/edgeless/utils/query.js'; export * from './_common/adapters/index.js'; +export * from './_common/adapters/markdown'; export { type NavigatorMode } from './_common/edgeless/frame/consts.js'; export { ExportManager, @@ -108,6 +109,9 @@ export { ImageAdapter, ImageAdapterFactoryExtension, ImageAdapterFactoryIdentifier, + MarkdownAdapter, + MarkdownAdapterFactoryExtension, + MarkdownAdapterFactoryIdentifier, NotionTextAdapter, NotionTextAdapterFactoryExtension, NotionTextAdapterFactoryIdentifier, diff --git a/blocksuite/blocks/src/surface-block/mini-mindmap/mindmap-preview.ts b/blocksuite/blocks/src/surface-block/mini-mindmap/mindmap-preview.ts index 957a5428a..28d5d9450 100644 --- a/blocksuite/blocks/src/surface-block/mini-mindmap/mindmap-preview.ts +++ b/blocksuite/blocks/src/surface-block/mini-mindmap/mindmap-preview.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import type { SurfaceBlockModel } from '@blocksuite/affine-block-surface'; import { MindmapStyleFour, @@ -10,7 +9,9 @@ import { type MindmapElementModel, MindmapStyle, } from '@blocksuite/affine-model'; +import { MarkdownAdapter } from '@blocksuite/affine-shared/adapters'; import { BlockStdScope, type EditorHost } from '@blocksuite/block-std'; +import type { ServiceProvider } from '@blocksuite/global/di'; import { WithDisposable } from '@blocksuite/global/utils'; import { type Doc, @@ -24,8 +25,8 @@ import { css, html, LitElement, nothing } from 'lit'; import { property, query } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; import { styleMap } from 'lit/directives/style-map.js'; +import type { Root } from 'mdast'; -import { MarkdownAdapter } from '../../_common/adapters/markdown/index.js'; import { MiniMindmapSchema, MiniMindmapSpecs } from './spec.js'; const mindmapStyles = [ @@ -140,7 +141,7 @@ export class MiniMindmapPreview extends WithDisposable(LitElement) { } private _toMindmapNode(answer: string, doc: Doc) { - return markdownToMindmap(answer, doc); + return markdownToMindmap(answer, doc, this.host.std.provider); } override connectedCallback(): void { @@ -240,11 +241,15 @@ type Node = { children: Node[]; }; -export const markdownToMindmap = (answer: string, doc: Doc) => { +export const markdownToMindmap = ( + answer: string, + doc: Doc, + provider: ServiceProvider +) => { let result: Node | null = null; const job = new Job({ collection: doc.collection }); - const markdown = new MarkdownAdapter(job); - const ast = markdown['_markdownToAst'](answer); + const markdown = new MarkdownAdapter(job, provider); + const ast: Root = markdown['_markdownToAst'](answer); const traverse = ( markdownNode: Unpacked<(typeof ast)['children']>, firstLevel = false diff --git a/packages/frontend/apps/ios/src/app.tsx b/packages/frontend/apps/ios/src/app.tsx index ea170ea9c..c39125e7d 100644 --- a/packages/frontend/apps/ios/src/app.tsx +++ b/packages/frontend/apps/ios/src/app.tsx @@ -30,10 +30,14 @@ import { } from '@affine/core/modules/workspace-engine'; import { I18n } from '@affine/i18n'; import { + defaultBlockMarkdownAdapterMatchers, docLinkBaseURLMiddleware, + inlineDeltaToMarkdownAdapterMatchers, MarkdownAdapter, + markdownInlineToDeltaMatchers, titleMiddleware, } from '@blocksuite/affine/blocks'; +import { Container } from '@blocksuite/affine/global/di'; import { Job } from '@blocksuite/affine/store'; import { App as CapacitorApp } from '@capacitor/app'; import { Browser } from '@capacitor/browser'; @@ -175,7 +179,17 @@ const frameworkProvider = framework.provider(); }); const snapshot = job.docToSnapshot(blockSuiteDoc); - const adapter = new MarkdownAdapter(job); + const container = new Container(); + [ + ...markdownInlineToDeltaMatchers, + ...defaultBlockMarkdownAdapterMatchers, + ...inlineDeltaToMarkdownAdapterMatchers, + ].forEach(ext => { + ext.setup(container); + }); + const provider = container.provider(); + + const adapter = new MarkdownAdapter(job, provider); if (!snapshot) { return; } diff --git a/packages/frontend/core/src/blocksuite/presets/_common/components/text-renderer.ts b/packages/frontend/core/src/blocksuite/presets/_common/components/text-renderer.ts index 6c5c798be..7a03d6b9b 100644 --- a/packages/frontend/core/src/blocksuite/presets/_common/components/text-renderer.ts +++ b/packages/frontend/core/src/blocksuite/presets/_common/components/text-renderer.ts @@ -10,10 +10,14 @@ import type { } from '@blocksuite/affine/blocks'; import { CodeBlockComponent, + defaultBlockMarkdownAdapterMatchers, DividerBlockComponent, + inlineDeltaToMarkdownAdapterMatchers, ListBlockComponent, + markdownInlineToDeltaMatchers, ParagraphBlockComponent, } from '@blocksuite/affine/blocks'; +import { Container, type ServiceProvider } from '@blocksuite/affine/global/di'; import { WithDisposable } from '@blocksuite/affine/global/utils'; import { BlockViewType, @@ -192,8 +196,28 @@ export class TextRenderer extends WithDisposable(ShadowlessElement) { const latestAnswer = this._answers.pop(); this._answers = []; const schema = this.schema ?? this.host?.std.doc.collection.schema; + let provider: ServiceProvider; + if (this.host) { + provider = this.host.std.provider; + } else { + const container = new Container(); + [ + ...markdownInlineToDeltaMatchers, + ...defaultBlockMarkdownAdapterMatchers, + ...inlineDeltaToMarkdownAdapterMatchers, + ].forEach(ext => { + ext.setup(container); + }); + + provider = container.provider(); + } if (latestAnswer && schema) { - markDownToDoc(schema, latestAnswer, this.options.additionalMiddlewares) + markDownToDoc( + provider, + schema, + latestAnswer, + this.options.additionalMiddlewares + ) .then(doc => { this.disposeDoc(); this._doc = doc.blockCollection.getDoc({ diff --git a/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts b/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts index a38af3c06..5414cfbcd 100644 --- a/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts +++ b/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts @@ -12,6 +12,7 @@ import { PlainTextAdapter, titleMiddleware, } from '@blocksuite/affine/blocks'; +import type { ServiceProvider } from '@blocksuite/affine/global/di'; import type { JobMiddleware, Schema } from '@blocksuite/affine/store'; import { DocCollection, Job } from '@blocksuite/affine/store'; import { assertExists } from '@blocksuite/global/utils'; @@ -87,7 +88,7 @@ export async function getContentFromSlice( processTextInSnapshot(snapshot, host); const adapter = type === 'markdown' - ? new MarkdownAdapter(job) + ? new MarkdownAdapter(job, host.std.provider) : new PlainTextAdapter(job, host.std.provider); const content = await adapter.fromSliceSnapshot({ snapshot, @@ -122,7 +123,7 @@ export const markdownToSnapshot = async ( collection: host.std.doc.collection, middlewares: [defaultImageProxyMiddleware, pasteMiddleware(host.std)], }); - const markdownAdapter = new MixTextAdapter(job); + const markdownAdapter = new MixTextAdapter(job, host.std.provider); const { blockVersions, workspaceVersion, pageVersion } = host.std.doc.collection.meta; if (!blockVersions || !workspaceVersion || !pageVersion) @@ -188,6 +189,7 @@ export async function replaceFromMarkdown( } export async function markDownToDoc( + provider: ServiceProvider, schema: Schema, answer: string, additionalMiddlewares?: JobMiddleware[] @@ -205,7 +207,7 @@ export async function markDownToDoc( collection, middlewares, }); - const mdAdapter = new MarkdownAdapter(job); + const mdAdapter = new MarkdownAdapter(job, provider); const doc = await mdAdapter.toDoc({ file: answer, assets: job.assetsManager, diff --git a/packages/frontend/core/src/blocksuite/presets/ai/messages/mindmap.ts b/packages/frontend/core/src/blocksuite/presets/ai/messages/mindmap.ts index 526d01650..e6693fc71 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/messages/mindmap.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/messages/mindmap.ts @@ -64,7 +64,7 @@ export const createMindmapExecuteRenderer: ( } ctx.set({ - node: markdownToMindmap(answer, host.doc), + node: markdownToMindmap(answer, host.doc, host.std.provider), }); handler(host, ctx); diff --git a/packages/frontend/core/src/blocksuite/presets/ai/utils/editor-actions.ts b/packages/frontend/core/src/blocksuite/presets/ai/utils/editor-actions.ts index 811cbca06..1a7811607 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/utils/editor-actions.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/utils/editor-actions.ts @@ -143,7 +143,11 @@ export const copyTextAnswer = async (panel: AffineAIPanelWidget) => { }; export const copyText = async (host: EditorHost, text: string) => { - const previewDoc = await markDownToDoc(host.std.doc.schema, text); + const previewDoc = await markDownToDoc( + host.std.provider, + host.std.doc.schema, + text + ); const models = previewDoc .getBlocksByFlavour('affine:note') .map(b => b.model) diff --git a/packages/frontend/core/src/modules/docs-search/worker/in-worker.ts b/packages/frontend/core/src/modules/docs-search/worker/in-worker.ts index ceb33c408..739bfdca4 100644 --- a/packages/frontend/core/src/modules/docs-search/worker/in-worker.ts +++ b/packages/frontend/core/src/modules/docs-search/worker/in-worker.ts @@ -5,7 +5,13 @@ import type { EmbedBlockModel, ImageBlockModel, } from '@blocksuite/affine/blocks'; -import { MarkdownAdapter } from '@blocksuite/affine/blocks'; +import { + defaultBlockMarkdownAdapterMatchers, + inlineDeltaToMarkdownAdapterMatchers, + MarkdownAdapter, + markdownInlineToDeltaMatchers, +} from '@blocksuite/affine/blocks'; +import { Container } from '@blocksuite/affine/global/di'; import { createYProxy, DocCollection, @@ -174,11 +180,22 @@ function generateMarkdownPreviewBuilder( adapterConfigs.set('docLinkBaseUrl', baseUrl); }; + const container = new Container(); + [ + ...markdownInlineToDeltaMatchers, + ...defaultBlockMarkdownAdapterMatchers, + ...inlineDeltaToMarkdownAdapterMatchers, + ].forEach(ext => { + ext.setup(container); + }); + + const provider = container.provider(); const markdownAdapter = new MarkdownAdapter( new Job({ collection: markdownPreviewDocCollection, middlewares: [docLinkBaseURLMiddleware, titleMiddleware], - }) + }), + provider ); const markdownPreviewCache = new WeakMap(); diff --git a/yarn.lock b/yarn.lock index 6aa54caca..64d70bff8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3677,9 +3677,21 @@ __metadata: lit: "npm:^3.2.0" lodash.clonedeep: "npm:^4.5.0" lodash.mergewith: "npm:^4.6.2" + mdast-util-gfm-autolink-literal: "npm:^2.0.1" + mdast-util-gfm-strikethrough: "npm:^2.0.0" + mdast-util-gfm-table: "npm:^2.0.0" + mdast-util-gfm-task-list-item: "npm:^2.0.0" + micromark-extension-gfm-autolink-literal: "npm:^2.1.0" + micromark-extension-gfm-strikethrough: "npm:^2.1.0" + micromark-extension-gfm-table: "npm:^2.1.0" + micromark-extension-gfm-task-list-item: "npm:^2.1.0" + micromark-util-combine-extensions: "npm:^2.0.0" minimatch: "npm:^10.0.1" rehype-parse: "npm:^9.0.0" rehype-stringify: "npm:^10.0.0" + remark-math: "npm:^6.0.0" + remark-parse: "npm:^11.0.0" + remark-stringify: "npm:^11.0.0" unified: "npm:^11.0.5" zod: "npm:^3.23.8" languageName: unknown