refactor(editor): extract markdown adapter (#9443)

This commit is contained in:
Saul-Mirone
2024-12-31 04:13:02 +00:00
parent adf14d11d5
commit 09427e846e
25 changed files with 333 additions and 181 deletions

View File

@@ -1,11 +1,11 @@
import type { ExtensionType } from '@blocksuite/block-std'; import type { ExtensionType } from '@blocksuite/block-std';
import { EmbedSyncedDocBlockHtmlAdapterExtension } from './html.js'; import { EmbedSyncedDocBlockHtmlAdapterExtension } from './html.js';
import { EmbedSyncedDocBlockMarkdownAdapterExtension } from './markdown.js'; import { EmbedSyncedDocMarkdownAdapterExtension } from './markdown.js';
import { EmbedSyncedDocBlockPlainTextAdapterExtension } from './plain-text.js'; import { EmbedSyncedDocBlockPlainTextAdapterExtension } from './plain-text.js';
export const EmbedSyncedDocBlockAdapterExtensions: ExtensionType[] = [ export const EmbedSyncedDocBlockAdapterExtensions: ExtensionType[] = [
EmbedSyncedDocBlockHtmlAdapterExtension, EmbedSyncedDocBlockHtmlAdapterExtension,
EmbedSyncedDocBlockMarkdownAdapterExtension, EmbedSyncedDocMarkdownAdapterExtension,
EmbedSyncedDocBlockPlainTextAdapterExtension, EmbedSyncedDocBlockPlainTextAdapterExtension,
]; ];

View File

@@ -60,5 +60,5 @@ export const embedSyncedDocBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatc
}, },
}; };
export const EmbedSyncedDocBlockMarkdownAdapterExtension = export const EmbedSyncedDocMarkdownAdapterExtension =
BlockMarkdownAdapterExtension(embedSyncedDocBlockMarkdownAdapterMatcher); BlockMarkdownAdapterExtension(embedSyncedDocBlockMarkdownAdapterMatcher);

View File

@@ -28,9 +28,21 @@
"lit": "^3.2.0", "lit": "^3.2.0",
"lodash.clonedeep": "^4.5.0", "lodash.clonedeep": "^4.5.0",
"lodash.mergewith": "^4.6.2", "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", "minimatch": "^10.0.1",
"rehype-parse": "^9.0.0", "rehype-parse": "^9.0.0",
"rehype-stringify": "^10.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", "unified": "^11.0.5",
"zod": "^3.23.8" "zod": "^3.23.8"
}, },

View File

@@ -20,11 +20,16 @@ export {
BlockMarkdownAdapterExtension, BlockMarkdownAdapterExtension,
type BlockMarkdownAdapterMatcher, type BlockMarkdownAdapterMatcher,
BlockMarkdownAdapterMatcherIdentifier, BlockMarkdownAdapterMatcherIdentifier,
InlineDeltaToMarkdownAdapterExtension,
type InlineDeltaToMarkdownAdapterMatcher, type InlineDeltaToMarkdownAdapterMatcher,
InlineDeltaToMarkdownAdapterMatcherIdentifier, InlineDeltaToMarkdownAdapterMatcherIdentifier,
isMarkdownAST, isMarkdownAST,
type Markdown, type Markdown,
MarkdownAdapter,
MarkdownAdapterFactoryExtension,
MarkdownAdapterFactoryIdentifier,
type MarkdownAST, type MarkdownAST,
MarkdownASTToDeltaExtension,
type MarkdownASTToDeltaMatcher, type MarkdownASTToDeltaMatcher,
MarkdownASTToDeltaMatcherIdentifier, MarkdownASTToDeltaMatcherIdentifier,
MarkdownDeltaConverter, MarkdownDeltaConverter,

View File

@@ -52,7 +52,7 @@ function gfmToMarkdown() {
} }
export function remarkGfm(this: Processor) { 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 self = this;
const data = self.data(); const data = self.data();

View File

@@ -1,3 +1,4 @@
export * from './block-adapter.js'; export * from './block-adapter.js';
export * from './delta-converter.js'; export * from './delta-converter.js';
export * from './markdown.js';
export * from './type.js'; export * from './type.js';

View File

@@ -1,14 +1,6 @@
import { DefaultTheme, NoteDisplayMode } from '@blocksuite/affine-model'; 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 { ExtensionType } from '@blocksuite/block-std';
import type { ServiceProvider } from '@blocksuite/global/di';
import { import {
type AssetsManager, type AssetsManager,
ASTWalker, ASTWalker,
@@ -34,10 +26,18 @@ import remarkParse from 'remark-parse';
import remarkStringify from 'remark-stringify'; import remarkStringify from 'remark-stringify';
import { unified } from 'unified'; import { unified } from 'unified';
import { defaultBlockMarkdownAdapterMatchers } from './block-matcher.js'; import { type AdapterContext, AdapterFactoryIdentifier } from '../types';
import { inlineDeltaToMarkdownAdapterMatchers } from './delta-converter/inline-delta.js'; import {
import { markdownInlineToDeltaMatchers } from './delta-converter/markdown-inline.js'; type BlockMarkdownAdapterMatcher,
import { remarkGfm } from './gfm.js'; BlockMarkdownAdapterMatcherIdentifier,
} from './block-adapter';
import {
InlineDeltaToMarkdownAdapterMatcherIdentifier,
MarkdownASTToDeltaMatcherIdentifier,
MarkdownDeltaConverter,
} from './delta-converter';
import { remarkGfm } from './gfm';
import type { Markdown, MarkdownAST } from './type';
type MarkdownToSliceSnapshotPayload = { type MarkdownToSliceSnapshotPayload = {
file: Markdown; file: Markdown;
@@ -164,11 +164,20 @@ export class MarkdownAdapter extends BaseAdapter<Markdown> {
deltaConverter: MarkdownDeltaConverter; deltaConverter: MarkdownDeltaConverter;
constructor( readonly blockMatchers: BlockMarkdownAdapterMatcher[];
job: Job,
readonly blockMatchers: BlockMarkdownAdapterMatcher[] = defaultBlockMarkdownAdapterMatchers constructor(job: Job, provider: ServiceProvider) {
) {
super(job); 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( this.deltaConverter = new MarkdownDeltaConverter(
job.adapterConfigs, job.adapterConfigs,
inlineDeltaToMarkdownAdapterMatchers, inlineDeltaToMarkdownAdapterMatchers,
@@ -440,13 +449,7 @@ export const MarkdownAdapterFactoryIdentifier =
export const MarkdownAdapterFactoryExtension: ExtensionType = { export const MarkdownAdapterFactoryExtension: ExtensionType = {
setup: di => { setup: di => {
di.addImpl(MarkdownAdapterFactoryIdentifier, provider => ({ di.addImpl(MarkdownAdapterFactoryIdentifier, provider => ({
get: (job: Job) => get: (job: Job) => new MarkdownAdapter(job, provider),
new MarkdownAdapter(
job,
Array.from(
provider.getAll(BlockMarkdownAdapterMatcherIdentifier).values()
)
),
})); }));
}, },
}; };

View File

@@ -1,4 +1,6 @@
import { DefaultTheme, NoteDisplayMode } from '@blocksuite/affine-model'; import { DefaultTheme, NoteDisplayMode } from '@blocksuite/affine-model';
import { MarkdownAdapter } from '@blocksuite/affine-shared/adapters';
import { Container } from '@blocksuite/global/di';
import type { import type {
BlockSnapshot, BlockSnapshot,
DocSnapshot, DocSnapshot,
@@ -8,11 +10,24 @@ import type {
import { AssetsManager, MemoryBlobCRUD } from '@blocksuite/store'; import { AssetsManager, MemoryBlobCRUD } from '@blocksuite/store';
import { describe, expect, test } from 'vitest'; 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 { nanoidReplacement } from '../../_common/test-utils/test-utils.js';
import { embedSyncedDocMiddleware } from '../../_common/transformers/middlewares.js'; import { embedSyncedDocMiddleware } from '../../_common/transformers/middlewares.js';
import { createJob } from '../utils/create-job.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', () => { describe('snapshot to markdown', () => {
test('code', async () => { test('code', async () => {
const blockSnapshot: BlockSnapshot = { const blockSnapshot: BlockSnapshot = {
@@ -71,7 +86,7 @@ describe('snapshot to markdown', () => {
const markdown = '```python\nimport this\n```\n'; const markdown = '```python\nimport this\n```\n';
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -270,7 +285,7 @@ describe('snapshot to markdown', () => {
hhh hhh
`; `;
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -418,7 +433,7 @@ hhh
* eee * eee
`; `;
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -567,7 +582,7 @@ hhh
* [ ] eee * [ ] eee
`; `;
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -710,7 +725,7 @@ hhh
2. ddd 2. ddd
`; `;
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -874,7 +889,7 @@ hhh
2. eee 2. eee
`; `;
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -946,7 +961,7 @@ hhh
}; };
const markdown = 'aaa `bbb` ccc\n'; const markdown = 'aaa `bbb` ccc\n';
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -1018,7 +1033,7 @@ hhh
}; };
const markdown = 'inline $E=mc^2$ latex\n'; const markdown = 'inline $E=mc^2$ latex\n';
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -1074,7 +1089,7 @@ hhh
const markdown = '$$\nE=mc^2\n$$\n'; const markdown = '$$\nE=mc^2\n$$\n';
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -1146,7 +1161,7 @@ hhh
}; };
const markdown = 'aaa [bbb](https://affine.pro/) ccc\n'; 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({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -1215,7 +1230,7 @@ hhh
}; };
const markdown = 'aaa https://affine.pro/ \n'; const markdown = 'aaa https://affine.pro/ \n';
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -1288,7 +1303,7 @@ hhh
const markdown = 'aaa**bbb**ccc\n'; const markdown = 'aaa**bbb**ccc\n';
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -1361,7 +1376,7 @@ hhh
const markdown = 'aaa*bbb*ccc\n'; const markdown = 'aaa*bbb*ccc\n';
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -1437,7 +1452,7 @@ hhh
const markdown = const markdown =
'![](assets/YXXTjRmLlNyiOUnHb8nAIvUP6V7PAXhwW9F5_tc2LGs=.blob "aaa")\n\n'; '![](assets/YXXTjRmLlNyiOUnHb8nAIvUP6V7PAXhwW9F5_tc2LGs=.blob "aaa")\n\n';
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const blobCRUD = new MemoryBlobCRUD(); const blobCRUD = new MemoryBlobCRUD();
await blobCRUD.set( await blobCRUD.set(
'YXXTjRmLlNyiOUnHb8nAIvUP6V7PAXhwW9F5_tc2LGs=', '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 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 | | | | Task 2 | In Progress | 2023-12-20 | | | | test1 | | |
`; `;
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -1920,7 +1935,7 @@ hhh
adapterConfigs.set('title:deadbeef', 'test'); adapterConfigs.set('title:deadbeef', 'test');
adapterConfigs.set('docLinkBaseUrl', 'https://example.com'); adapterConfigs.set('docLinkBaseUrl', 'https://example.com');
}; };
const mdAdapter = new MarkdownAdapter(createJob([middleware])); const mdAdapter = new MarkdownAdapter(createJob([middleware]), provider);
const target = await mdAdapter.fromBlockSnapshot({ const target = await mdAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -2327,7 +2342,7 @@ World!
await job.snapshotToDoc(syncedDocSnapshot); await job.snapshotToDoc(syncedDocSnapshot);
await job.snapshotToDoc(docSnapShot); await job.snapshotToDoc(docSnapShot);
const mdAdapter = new MarkdownAdapter(job); const mdAdapter = new MarkdownAdapter(job, provider);
const target = await mdAdapter.fromDocSnapshot({ const target = await mdAdapter.fromDocSnapshot({
snapshot: docSnapShot, 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({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -2420,7 +2435,7 @@ describe('markdown to snapshot', () => {
pageId: '', pageId: '',
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({ const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({
file: markdown, file: markdown,
workspaceId: '', workspaceId: '',
@@ -2471,7 +2486,7 @@ describe('markdown to snapshot', () => {
pageId: '', pageId: '',
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({ const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({
file: markdown, file: markdown,
workspaceId: '', workspaceId: '',
@@ -2522,7 +2537,7 @@ describe('markdown to snapshot', () => {
pageId: '', pageId: '',
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({ const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({
file: markdown, file: markdown,
workspaceId: '', workspaceId: '',
@@ -2700,7 +2715,7 @@ hhh
], ],
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -2836,7 +2851,7 @@ hhh
], ],
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -2972,7 +2987,7 @@ hhh
], ],
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -3081,7 +3096,7 @@ bbb
], ],
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -3131,7 +3146,7 @@ bbb
], ],
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -3186,7 +3201,7 @@ bbb
pageId: '', pageId: '',
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({ const rawSliceSnapshot = await mdAdapter.toSliceSnapshot({
file: markdown, file: markdown,
workspaceId: '', workspaceId: '',
@@ -3238,7 +3253,7 @@ bbb
], ],
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -3288,7 +3303,7 @@ bbb
], ],
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -3339,7 +3354,7 @@ bbb
], ],
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -3390,7 +3405,7 @@ bbb
], ],
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -3511,7 +3526,7 @@ bbb
], ],
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -3553,7 +3568,7 @@ bbb
], ],
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -3603,7 +3618,7 @@ bbb
], ],
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -3637,7 +3652,7 @@ bbb
], ],
}; };
const mdAdapter = new MarkdownAdapter(createJob()); const mdAdapter = new MarkdownAdapter(createJob(), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });
@@ -3835,7 +3850,7 @@ hhh
const middleware: JobMiddleware = ({ adapterConfigs }) => { const middleware: JobMiddleware = ({ adapterConfigs }) => {
adapterConfigs.set('docLinkBaseUrl', 'https://example.com'); adapterConfigs.set('docLinkBaseUrl', 'https://example.com');
}; };
const mdAdapter = new MarkdownAdapter(createJob([middleware])); const mdAdapter = new MarkdownAdapter(createJob([middleware]), provider);
const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({ const rawBlockSnapshot = await mdAdapter.toBlockSnapshot({
file: markdown, file: markdown,
}); });

View File

@@ -1,8 +1,22 @@
import { Container } from '@blocksuite/global/di';
import { DocCollection, Schema } from '@blocksuite/store'; import { DocCollection, Schema } from '@blocksuite/store';
import { describe, expect, test } from 'vitest'; 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'; 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', () => { describe('markdownToMindmap: convert markdown list to a mind map tree', () => {
test('basic case', () => { test('basic case', () => {
const markdown = ` const markdown = `
@@ -15,7 +29,7 @@ describe('markdownToMindmap: convert markdown list to a mind map tree', () => {
const collection = new DocCollection({ schema: new Schema() }); const collection = new DocCollection({ schema: new Schema() });
collection.meta.initialize(); collection.meta.initialize();
const doc = collection.createDoc(); const doc = collection.createDoc();
const nodes = markdownToMindmap(markdown, doc); const nodes = markdownToMindmap(markdown, doc, provider);
expect(nodes).toEqual({ expect(nodes).toEqual({
text: 'Text A', text: 'Text A',
@@ -53,7 +67,7 @@ describe('markdownToMindmap: convert markdown list to a mind map tree', () => {
const collection = new DocCollection({ schema: new Schema() }); const collection = new DocCollection({ schema: new Schema() });
collection.meta.initialize(); collection.meta.initialize();
const doc = collection.createDoc(); const doc = collection.createDoc();
const nodes = markdownToMindmap(markdown, doc); const nodes = markdownToMindmap(markdown, doc, provider);
expect(nodes).toEqual({ expect(nodes).toEqual({
text: 'Text A', text: 'Text A',
@@ -85,7 +99,7 @@ describe('markdownToMindmap: convert markdown list to a mind map tree', () => {
const collection = new DocCollection({ schema: new Schema() }); const collection = new DocCollection({ schema: new Schema() });
collection.meta.initialize(); collection.meta.initialize();
const doc = collection.createDoc(); const doc = collection.createDoc();
const nodes = markdownToMindmap(markdown, doc); const nodes = markdownToMindmap(markdown, doc, provider);
expect(nodes).toEqual(null); expect(nodes).toEqual(null);
}); });

View File

@@ -2,6 +2,7 @@ import {
AttachmentAdapterFactoryExtension, AttachmentAdapterFactoryExtension,
HtmlAdapterFactoryExtension, HtmlAdapterFactoryExtension,
ImageAdapterFactoryExtension, ImageAdapterFactoryExtension,
MarkdownAdapterFactoryExtension,
NotionHtmlAdapterFactoryExtension, NotionHtmlAdapterFactoryExtension,
NotionTextAdapterFactoryExtension, NotionTextAdapterFactoryExtension,
PlainTextAdapterFactoryExtension, PlainTextAdapterFactoryExtension,
@@ -10,7 +11,8 @@ import type { ExtensionType } from '@blocksuite/block-std';
import { htmlInlineToDeltaMatchers } from './html/delta-converter/html-inline.js'; import { htmlInlineToDeltaMatchers } from './html/delta-converter/html-inline.js';
import { inlineDeltaToHtmlAdapterMatchers } from './html/delta-converter/inline-delta.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 { MixTextAdapterFactoryExtension } from './mix-text.js';
import { notionHtmlInlineToDeltaMatchers } from './notion-html/delta-converter/html-inline.js'; import { notionHtmlInlineToDeltaMatchers } from './notion-html/delta-converter/html-inline.js';
import { inlineDeltaToPlainTextAdapterMatchers } from './plain-text/delta-converter/inline-delta.js'; import { inlineDeltaToPlainTextAdapterMatchers } from './plain-text/delta-converter/inline-delta.js';
@@ -20,6 +22,8 @@ export const AdapterFactoryExtensions: ExtensionType[] = [
...inlineDeltaToHtmlAdapterMatchers, ...inlineDeltaToHtmlAdapterMatchers,
...notionHtmlInlineToDeltaMatchers, ...notionHtmlInlineToDeltaMatchers,
...inlineDeltaToPlainTextAdapterMatchers, ...inlineDeltaToPlainTextAdapterMatchers,
...markdownInlineToDeltaMatchers,
...inlineDeltaToMarkdownAdapterMatchers,
AttachmentAdapterFactoryExtension, AttachmentAdapterFactoryExtension,
ImageAdapterFactoryExtension, ImageAdapterFactoryExtension,
MarkdownAdapterFactoryExtension, MarkdownAdapterFactoryExtension,

View File

@@ -1,36 +1,36 @@
import { bookmarkBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-bookmark'; import { BookmarkBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-bookmark';
import { codeBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-code'; import { CodeBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-code';
import { databaseBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-database'; import { DatabaseBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-database';
import { dividerBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-divider'; import { DividerBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-divider';
import { import {
embedFigmaBlockMarkdownAdapterMatcher, EmbedFigmaMarkdownAdapterExtension,
embedGithubBlockMarkdownAdapterMatcher, EmbedGithubMarkdownAdapterExtension,
embedLinkedDocBlockMarkdownAdapterMatcher, EmbedLinkedDocMarkdownAdapterExtension,
embedLoomBlockMarkdownAdapterMatcher, EmbedLoomMarkdownAdapterExtension,
embedSyncedDocBlockMarkdownAdapterMatcher, EmbedSyncedDocMarkdownAdapterExtension,
embedYoutubeBlockMarkdownAdapterMatcher, EmbedYoutubeMarkdownAdapterExtension,
} from '@blocksuite/affine-block-embed'; } from '@blocksuite/affine-block-embed';
import { imageBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-image'; import { ImageBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-image';
import { latexBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-latex'; import { LatexBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-latex';
import { listBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-list'; import { ListBlockMarkdownAdapterExtension } from '@blocksuite/affine-block-list';
import { paragraphBlockMarkdownAdapterMatcher } from '@blocksuite/affine-block-paragraph'; 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 = [ export const defaultBlockMarkdownAdapterMatchers = [
embedFigmaBlockMarkdownAdapterMatcher, EmbedFigmaMarkdownAdapterExtension,
embedGithubBlockMarkdownAdapterMatcher, EmbedGithubMarkdownAdapterExtension,
embedLinkedDocBlockMarkdownAdapterMatcher, EmbedLinkedDocMarkdownAdapterExtension,
embedLoomBlockMarkdownAdapterMatcher, EmbedLoomMarkdownAdapterExtension,
embedSyncedDocBlockMarkdownAdapterMatcher, EmbedSyncedDocMarkdownAdapterExtension,
embedYoutubeBlockMarkdownAdapterMatcher, EmbedYoutubeMarkdownAdapterExtension,
listBlockMarkdownAdapterMatcher, ListBlockMarkdownAdapterExtension,
paragraphBlockMarkdownAdapterMatcher, ParagraphBlockMarkdownAdapterExtension,
bookmarkBlockMarkdownAdapterMatcher, BookmarkBlockMarkdownAdapterExtension,
codeBlockMarkdownAdapterMatcher, CodeBlockMarkdownAdapterExtension,
databaseBlockMarkdownAdapterMatcher, DatabaseBlockMarkdownAdapterExtension,
dividerBlockMarkdownAdapterMatcher, DividerBlockMarkdownAdapterExtension,
imageBlockMarkdownAdapterMatcher, ImageBlockMarkdownAdapterExtension,
latexBlockMarkdownAdapterMatcher, LatexBlockMarkdownAdapterExtension,
rootBlockMarkdownAdapterMatcher, RootBlockMarkdownAdapterExtension,
]; ];

View File

@@ -1,9 +1,12 @@
import { generateDocUrl } from '@blocksuite/affine-block-embed'; 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 { PhrasingContent } from 'mdast';
import type RemarkMath from 'remark-math';
export const boldDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = declare type _GLOBAL_ = typeof RemarkMath;
{
export const boldDeltaToMarkdownAdapterMatcher =
InlineDeltaToMarkdownAdapterExtension({
name: 'bold', name: 'bold',
match: delta => !!delta.attributes?.bold, match: delta => !!delta.attributes?.bold,
toAST: (_, context) => { toAST: (_, context) => {
@@ -13,10 +16,10 @@ export const boldDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatc
children: [currentMdast], children: [currentMdast],
}; };
}, },
}; });
export const italicDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = export const italicDeltaToMarkdownAdapterMatcher =
{ InlineDeltaToMarkdownAdapterExtension({
name: 'italic', name: 'italic',
match: delta => !!delta.attributes?.italic, match: delta => !!delta.attributes?.italic,
toAST: (_, context) => { toAST: (_, context) => {
@@ -26,10 +29,10 @@ export const italicDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMa
children: [currentMdast], children: [currentMdast],
}; };
}, },
}; });
export const strikeDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = export const strikeDeltaToMarkdownAdapterMatcher =
{ InlineDeltaToMarkdownAdapterExtension({
name: 'strike', name: 'strike',
match: delta => !!delta.attributes?.strike, match: delta => !!delta.attributes?.strike,
toAST: (_, context) => { toAST: (_, context) => {
@@ -39,20 +42,20 @@ export const strikeDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMa
children: [currentMdast], children: [currentMdast],
}; };
}, },
}; });
export const inlineCodeDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = export const inlineCodeDeltaToMarkdownAdapterMatcher =
{ InlineDeltaToMarkdownAdapterExtension({
name: 'inlineCode', name: 'inlineCode',
match: delta => !!delta.attributes?.code, match: delta => !!delta.attributes?.code,
toAST: delta => ({ toAST: delta => ({
type: 'inlineCode', type: 'inlineCode',
value: delta.insert, value: delta.insert,
}), }),
}; });
export const referenceDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = export const referenceDeltaToMarkdownAdapterMatcher =
{ InlineDeltaToMarkdownAdapterExtension({
name: 'reference', name: 'reference',
match: delta => !!delta.attributes?.reference, match: delta => !!delta.attributes?.reference,
toAST: (delta, context) => { toAST: (delta, context) => {
@@ -86,10 +89,10 @@ export const referenceDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapte
return mdast; return mdast;
}, },
}; });
export const linkDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = export const linkDeltaToMarkdownAdapterMatcher =
{ InlineDeltaToMarkdownAdapterExtension({
name: 'link', name: 'link',
match: delta => !!delta.attributes?.link, match: delta => !!delta.attributes?.link,
toAST: (delta, context) => { toAST: (delta, context) => {
@@ -120,10 +123,10 @@ export const linkDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatc
} }
return mdast; return mdast;
}, },
}; });
export const latexDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMatcher = export const latexDeltaToMarkdownAdapterMatcher =
{ InlineDeltaToMarkdownAdapterExtension({
name: 'inlineLatex', name: 'inlineLatex',
match: delta => !!delta.attributes?.latex, match: delta => !!delta.attributes?.latex,
toAST: delta => { toAST: delta => {
@@ -139,10 +142,9 @@ export const latexDeltaToMarkdownAdapterMatcher: InlineDeltaToMarkdownAdapterMat
} }
return mdast; return mdast;
}, },
}; });
export const inlineDeltaToMarkdownAdapterMatchers: InlineDeltaToMarkdownAdapterMatcher[] = export const inlineDeltaToMarkdownAdapterMatchers = [
[
referenceDeltaToMarkdownAdapterMatcher, referenceDeltaToMarkdownAdapterMatcher,
linkDeltaToMarkdownAdapterMatcher, linkDeltaToMarkdownAdapterMatcher,
inlineCodeDeltaToMarkdownAdapterMatcher, inlineCodeDeltaToMarkdownAdapterMatcher,

View File

@@ -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', name: 'text',
match: ast => ast.type === 'text', match: ast => ast.type === 'text',
toDelta: ast => { toDelta: ast => {
@@ -9,9 +9,9 @@ export const markdownTextToDeltaMatcher: MarkdownASTToDeltaMatcher = {
} }
return [{ insert: ast.value }]; return [{ insert: ast.value }];
}, },
}; });
export const markdownInlineCodeToDeltaMatcher: MarkdownASTToDeltaMatcher = { export const markdownInlineCodeToDeltaMatcher = MarkdownASTToDeltaExtension({
name: 'inlineCode', name: 'inlineCode',
match: ast => ast.type === 'inlineCode', match: ast => ast.type === 'inlineCode',
toDelta: ast => { toDelta: ast => {
@@ -20,9 +20,9 @@ export const markdownInlineCodeToDeltaMatcher: MarkdownASTToDeltaMatcher = {
} }
return [{ insert: ast.value, attributes: { code: true } }]; return [{ insert: ast.value, attributes: { code: true } }];
}, },
}; });
export const markdownStrongToDeltaMatcher: MarkdownASTToDeltaMatcher = { export const markdownStrongToDeltaMatcher = MarkdownASTToDeltaExtension({
name: 'strong', name: 'strong',
match: ast => ast.type === 'strong', match: ast => ast.type === 'strong',
toDelta: (ast, context) => { toDelta: (ast, context) => {
@@ -36,9 +36,9 @@ export const markdownStrongToDeltaMatcher: MarkdownASTToDeltaMatcher = {
}) })
); );
}, },
}; });
export const markdownEmphasisToDeltaMatcher: MarkdownASTToDeltaMatcher = { export const markdownEmphasisToDeltaMatcher = MarkdownASTToDeltaExtension({
name: 'emphasis', name: 'emphasis',
match: ast => ast.type === 'emphasis', match: ast => ast.type === 'emphasis',
toDelta: (ast, context) => { toDelta: (ast, context) => {
@@ -52,9 +52,9 @@ export const markdownEmphasisToDeltaMatcher: MarkdownASTToDeltaMatcher = {
}) })
); );
}, },
}; });
export const markdownDeleteToDeltaMatcher: MarkdownASTToDeltaMatcher = { export const markdownDeleteToDeltaMatcher = MarkdownASTToDeltaExtension({
name: 'delete', name: 'delete',
match: ast => ast.type === 'delete', match: ast => ast.type === 'delete',
toDelta: (ast, context) => { toDelta: (ast, context) => {
@@ -68,9 +68,9 @@ export const markdownDeleteToDeltaMatcher: MarkdownASTToDeltaMatcher = {
}) })
); );
}, },
}; });
export const markdownLinkToDeltaMatcher: MarkdownASTToDeltaMatcher = { export const markdownLinkToDeltaMatcher = MarkdownASTToDeltaExtension({
name: 'link', name: 'link',
match: ast => ast.type === 'link', match: ast => ast.type === 'link',
toDelta: (ast, context) => { toDelta: (ast, context) => {
@@ -119,15 +119,15 @@ export const markdownLinkToDeltaMatcher: MarkdownASTToDeltaMatcher = {
}) })
); );
}, },
}; });
export const markdownListToDeltaMatcher: MarkdownASTToDeltaMatcher = { export const markdownListToDeltaMatcher = MarkdownASTToDeltaExtension({
name: 'list', name: 'list',
match: ast => ast.type === 'list', match: ast => ast.type === 'list',
toDelta: () => [], toDelta: () => [],
}; });
export const markdownInlineMathToDeltaMatcher: MarkdownASTToDeltaMatcher = { export const markdownInlineMathToDeltaMatcher = MarkdownASTToDeltaExtension({
name: 'inlineMath', name: 'inlineMath',
match: ast => ast.type === 'inlineMath', match: ast => ast.type === 'inlineMath',
toDelta: ast => { toDelta: ast => {
@@ -136,9 +136,9 @@ export const markdownInlineMathToDeltaMatcher: MarkdownASTToDeltaMatcher = {
} }
return [{ insert: ' ', attributes: { latex: ast.value } }]; return [{ insert: ' ', attributes: { latex: ast.value } }];
}, },
}; });
export const markdownInlineToDeltaMatchers: MarkdownASTToDeltaMatcher[] = [ export const markdownInlineToDeltaMatchers = [
markdownTextToDeltaMatcher, markdownTextToDeltaMatcher,
markdownInlineCodeToDeltaMatcher, markdownInlineCodeToDeltaMatcher,
markdownStrongToDeltaMatcher, markdownStrongToDeltaMatcher,

View File

@@ -1,6 +1,3 @@
export { defaultBlockMarkdownAdapterMatchers } from './block-matcher.js'; export { defaultBlockMarkdownAdapterMatchers } from './block-matcher.js';
export { export { inlineDeltaToMarkdownAdapterMatchers } from './delta-converter/inline-delta.js';
MarkdownAdapter, export { markdownInlineToDeltaMatchers } from './delta-converter/markdown-inline.js';
MarkdownAdapterFactoryExtension,
MarkdownAdapterFactoryIdentifier,
} from './markdown.js';

View File

@@ -1,6 +1,10 @@
import { DefaultTheme, NoteDisplayMode } from '@blocksuite/affine-model'; 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 { ExtensionType } from '@blocksuite/block-std';
import type { ServiceProvider } from '@blocksuite/global/di';
import type { DeltaInsert } from '@blocksuite/inline'; import type { DeltaInsert } from '@blocksuite/inline';
import { import {
type AssetsManager, type AssetsManager,
@@ -22,8 +26,6 @@ import {
type ToDocSnapshotPayload, type ToDocSnapshotPayload,
} from '@blocksuite/store'; } from '@blocksuite/store';
import { MarkdownAdapter } from './markdown/index.js';
export type MixText = string; export type MixText = string;
type MixTextToSliceSnapshotPayload = { type MixTextToSliceSnapshotPayload = {
@@ -37,9 +39,9 @@ type MixTextToSliceSnapshotPayload = {
export class MixTextAdapter extends BaseAdapter<MixText> { export class MixTextAdapter extends BaseAdapter<MixText> {
private readonly _markdownAdapter: MarkdownAdapter; private readonly _markdownAdapter: MarkdownAdapter;
constructor(job: Job) { constructor(job: Job, provider: ServiceProvider) {
super(job); super(job);
this._markdownAdapter = new MarkdownAdapter(job); this._markdownAdapter = new MarkdownAdapter(job, provider);
} }
private _splitDeltas(deltas: DeltaInsert[]): DeltaInsert[][] { private _splitDeltas(deltas: DeltaInsert[]): DeltaInsert[][] {
@@ -353,8 +355,8 @@ export const MixTextAdapterFactoryIdentifier =
export const MixTextAdapterFactoryExtension: ExtensionType = { export const MixTextAdapterFactoryExtension: ExtensionType = {
setup: di => { setup: di => {
di.addImpl(MixTextAdapterFactoryIdentifier, () => ({ di.addImpl(MixTextAdapterFactoryIdentifier, provider => ({
get: (job: Job) => new MixTextAdapter(job), get: (job: Job) => new MixTextAdapter(job, provider),
})); }));
}, },
}; };

View File

@@ -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 { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { assertExists, sha } from '@blocksuite/global/utils'; import { assertExists, sha } from '@blocksuite/global/utils';
import type { Doc, DocCollection } from '@blocksuite/store'; import type { Doc, DocCollection } from '@blocksuite/store';
import { extMimeMap, Job } 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 { import {
defaultImageProxyMiddleware, defaultImageProxyMiddleware,
docLinkBaseURLMiddleware, docLinkBaseURLMiddleware,
@@ -12,6 +16,17 @@ import {
} from './middlewares.js'; } from './middlewares.js';
import { createAssetsArchive, download, Unzip } from './utils.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 = { type ImportMarkdownToBlockOptions = {
doc: Doc; doc: Doc;
markdown: string; markdown: string;
@@ -41,7 +56,7 @@ async function exportDoc(doc: Doc) {
}); });
const snapshot = job.docToSnapshot(doc); const snapshot = job.docToSnapshot(doc);
const adapter = new MarkdownAdapter(job); const adapter = new MarkdownAdapter(job, provider);
if (!snapshot) { if (!snapshot) {
return; return;
} }
@@ -89,7 +104,7 @@ async function importMarkdownToBlock({
collection: doc.collection, collection: doc.collection,
middlewares: [defaultImageProxyMiddleware, docLinkBaseURLMiddleware], middlewares: [defaultImageProxyMiddleware, docLinkBaseURLMiddleware],
}); });
const adapter = new MarkdownAdapter(job); const adapter = new MarkdownAdapter(job, provider);
const snapshot = await adapter.toSliceSnapshot({ const snapshot = await adapter.toSliceSnapshot({
file: markdown, file: markdown,
assets: job.assetsManager, assets: job.assetsManager,
@@ -129,7 +144,7 @@ async function importMarkdownToDoc({
docLinkBaseURLMiddleware, docLinkBaseURLMiddleware,
], ],
}); });
const mdAdapter = new MarkdownAdapter(job); const mdAdapter = new MarkdownAdapter(job, provider);
const page = await mdAdapter.toDoc({ const page = await mdAdapter.toDoc({
file: markdown, file: markdown,
assets: job.assetsManager, assets: job.assetsManager,
@@ -195,7 +210,7 @@ async function importMarkdownZip({
for (const [key, value] of pendingPathBlobIdMap.entries()) { for (const [key, value] of pendingPathBlobIdMap.entries()) {
pathBlobIdMap.set(key, value); pathBlobIdMap.set(key, value);
} }
const mdAdapter = new MarkdownAdapter(job); const mdAdapter = new MarkdownAdapter(job, provider);
const markdown = await blob.text(); const markdown = await blob.text();
const doc = await mdAdapter.toDoc({ const doc = await mdAdapter.toDoc({
file: markdown, file: markdown,

View File

@@ -7,6 +7,7 @@ import { splitElements } from './root-block/edgeless/utils/clipboard-utils.js';
import { isCanvasElement } from './root-block/edgeless/utils/query.js'; import { isCanvasElement } from './root-block/edgeless/utils/query.js';
export * from './_common/adapters/index.js'; export * from './_common/adapters/index.js';
export * from './_common/adapters/markdown';
export { type NavigatorMode } from './_common/edgeless/frame/consts.js'; export { type NavigatorMode } from './_common/edgeless/frame/consts.js';
export { export {
ExportManager, ExportManager,
@@ -108,6 +109,9 @@ export {
ImageAdapter, ImageAdapter,
ImageAdapterFactoryExtension, ImageAdapterFactoryExtension,
ImageAdapterFactoryIdentifier, ImageAdapterFactoryIdentifier,
MarkdownAdapter,
MarkdownAdapterFactoryExtension,
MarkdownAdapterFactoryIdentifier,
NotionTextAdapter, NotionTextAdapter,
NotionTextAdapterFactoryExtension, NotionTextAdapterFactoryExtension,
NotionTextAdapterFactoryIdentifier, NotionTextAdapterFactoryIdentifier,

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import type { SurfaceBlockModel } from '@blocksuite/affine-block-surface'; import type { SurfaceBlockModel } from '@blocksuite/affine-block-surface';
import { import {
MindmapStyleFour, MindmapStyleFour,
@@ -10,7 +9,9 @@ import {
type MindmapElementModel, type MindmapElementModel,
MindmapStyle, MindmapStyle,
} from '@blocksuite/affine-model'; } from '@blocksuite/affine-model';
import { MarkdownAdapter } from '@blocksuite/affine-shared/adapters';
import { BlockStdScope, type EditorHost } from '@blocksuite/block-std'; import { BlockStdScope, type EditorHost } from '@blocksuite/block-std';
import type { ServiceProvider } from '@blocksuite/global/di';
import { WithDisposable } from '@blocksuite/global/utils'; import { WithDisposable } from '@blocksuite/global/utils';
import { import {
type Doc, type Doc,
@@ -24,8 +25,8 @@ import { css, html, LitElement, nothing } from 'lit';
import { property, query } from 'lit/decorators.js'; import { property, query } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js'; import { repeat } from 'lit/directives/repeat.js';
import { styleMap } from 'lit/directives/style-map.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'; import { MiniMindmapSchema, MiniMindmapSpecs } from './spec.js';
const mindmapStyles = [ const mindmapStyles = [
@@ -140,7 +141,7 @@ export class MiniMindmapPreview extends WithDisposable(LitElement) {
} }
private _toMindmapNode(answer: string, doc: Doc) { private _toMindmapNode(answer: string, doc: Doc) {
return markdownToMindmap(answer, doc); return markdownToMindmap(answer, doc, this.host.std.provider);
} }
override connectedCallback(): void { override connectedCallback(): void {
@@ -240,11 +241,15 @@ type Node = {
children: Node[]; children: Node[];
}; };
export const markdownToMindmap = (answer: string, doc: Doc) => { export const markdownToMindmap = (
answer: string,
doc: Doc,
provider: ServiceProvider
) => {
let result: Node | null = null; let result: Node | null = null;
const job = new Job({ collection: doc.collection }); const job = new Job({ collection: doc.collection });
const markdown = new MarkdownAdapter(job); const markdown = new MarkdownAdapter(job, provider);
const ast = markdown['_markdownToAst'](answer); const ast: Root = markdown['_markdownToAst'](answer);
const traverse = ( const traverse = (
markdownNode: Unpacked<(typeof ast)['children']>, markdownNode: Unpacked<(typeof ast)['children']>,
firstLevel = false firstLevel = false

View File

@@ -30,10 +30,14 @@ import {
} from '@affine/core/modules/workspace-engine'; } from '@affine/core/modules/workspace-engine';
import { I18n } from '@affine/i18n'; import { I18n } from '@affine/i18n';
import { import {
defaultBlockMarkdownAdapterMatchers,
docLinkBaseURLMiddleware, docLinkBaseURLMiddleware,
inlineDeltaToMarkdownAdapterMatchers,
MarkdownAdapter, MarkdownAdapter,
markdownInlineToDeltaMatchers,
titleMiddleware, titleMiddleware,
} from '@blocksuite/affine/blocks'; } from '@blocksuite/affine/blocks';
import { Container } from '@blocksuite/affine/global/di';
import { Job } from '@blocksuite/affine/store'; import { Job } from '@blocksuite/affine/store';
import { App as CapacitorApp } from '@capacitor/app'; import { App as CapacitorApp } from '@capacitor/app';
import { Browser } from '@capacitor/browser'; import { Browser } from '@capacitor/browser';
@@ -175,7 +179,17 @@ const frameworkProvider = framework.provider();
}); });
const snapshot = job.docToSnapshot(blockSuiteDoc); 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) { if (!snapshot) {
return; return;
} }

View File

@@ -10,10 +10,14 @@ import type {
} from '@blocksuite/affine/blocks'; } from '@blocksuite/affine/blocks';
import { import {
CodeBlockComponent, CodeBlockComponent,
defaultBlockMarkdownAdapterMatchers,
DividerBlockComponent, DividerBlockComponent,
inlineDeltaToMarkdownAdapterMatchers,
ListBlockComponent, ListBlockComponent,
markdownInlineToDeltaMatchers,
ParagraphBlockComponent, ParagraphBlockComponent,
} from '@blocksuite/affine/blocks'; } from '@blocksuite/affine/blocks';
import { Container, type ServiceProvider } from '@blocksuite/affine/global/di';
import { WithDisposable } from '@blocksuite/affine/global/utils'; import { WithDisposable } from '@blocksuite/affine/global/utils';
import { import {
BlockViewType, BlockViewType,
@@ -192,8 +196,28 @@ export class TextRenderer extends WithDisposable(ShadowlessElement) {
const latestAnswer = this._answers.pop(); const latestAnswer = this._answers.pop();
this._answers = []; this._answers = [];
const schema = this.schema ?? this.host?.std.doc.collection.schema; 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) { if (latestAnswer && schema) {
markDownToDoc(schema, latestAnswer, this.options.additionalMiddlewares) markDownToDoc(
provider,
schema,
latestAnswer,
this.options.additionalMiddlewares
)
.then(doc => { .then(doc => {
this.disposeDoc(); this.disposeDoc();
this._doc = doc.blockCollection.getDoc({ this._doc = doc.blockCollection.getDoc({

View File

@@ -12,6 +12,7 @@ import {
PlainTextAdapter, PlainTextAdapter,
titleMiddleware, titleMiddleware,
} from '@blocksuite/affine/blocks'; } from '@blocksuite/affine/blocks';
import type { ServiceProvider } from '@blocksuite/affine/global/di';
import type { JobMiddleware, Schema } from '@blocksuite/affine/store'; import type { JobMiddleware, Schema } from '@blocksuite/affine/store';
import { DocCollection, Job } from '@blocksuite/affine/store'; import { DocCollection, Job } from '@blocksuite/affine/store';
import { assertExists } from '@blocksuite/global/utils'; import { assertExists } from '@blocksuite/global/utils';
@@ -87,7 +88,7 @@ export async function getContentFromSlice(
processTextInSnapshot(snapshot, host); processTextInSnapshot(snapshot, host);
const adapter = const adapter =
type === 'markdown' type === 'markdown'
? new MarkdownAdapter(job) ? new MarkdownAdapter(job, host.std.provider)
: new PlainTextAdapter(job, host.std.provider); : new PlainTextAdapter(job, host.std.provider);
const content = await adapter.fromSliceSnapshot({ const content = await adapter.fromSliceSnapshot({
snapshot, snapshot,
@@ -122,7 +123,7 @@ export const markdownToSnapshot = async (
collection: host.std.doc.collection, collection: host.std.doc.collection,
middlewares: [defaultImageProxyMiddleware, pasteMiddleware(host.std)], middlewares: [defaultImageProxyMiddleware, pasteMiddleware(host.std)],
}); });
const markdownAdapter = new MixTextAdapter(job); const markdownAdapter = new MixTextAdapter(job, host.std.provider);
const { blockVersions, workspaceVersion, pageVersion } = const { blockVersions, workspaceVersion, pageVersion } =
host.std.doc.collection.meta; host.std.doc.collection.meta;
if (!blockVersions || !workspaceVersion || !pageVersion) if (!blockVersions || !workspaceVersion || !pageVersion)
@@ -188,6 +189,7 @@ export async function replaceFromMarkdown(
} }
export async function markDownToDoc( export async function markDownToDoc(
provider: ServiceProvider,
schema: Schema, schema: Schema,
answer: string, answer: string,
additionalMiddlewares?: JobMiddleware[] additionalMiddlewares?: JobMiddleware[]
@@ -205,7 +207,7 @@ export async function markDownToDoc(
collection, collection,
middlewares, middlewares,
}); });
const mdAdapter = new MarkdownAdapter(job); const mdAdapter = new MarkdownAdapter(job, provider);
const doc = await mdAdapter.toDoc({ const doc = await mdAdapter.toDoc({
file: answer, file: answer,
assets: job.assetsManager, assets: job.assetsManager,

View File

@@ -64,7 +64,7 @@ export const createMindmapExecuteRenderer: (
} }
ctx.set({ ctx.set({
node: markdownToMindmap(answer, host.doc), node: markdownToMindmap(answer, host.doc, host.std.provider),
}); });
handler(host, ctx); handler(host, ctx);

View File

@@ -143,7 +143,11 @@ export const copyTextAnswer = async (panel: AffineAIPanelWidget) => {
}; };
export const copyText = async (host: EditorHost, text: string) => { 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 const models = previewDoc
.getBlocksByFlavour('affine:note') .getBlocksByFlavour('affine:note')
.map(b => b.model) .map(b => b.model)

View File

@@ -5,7 +5,13 @@ import type {
EmbedBlockModel, EmbedBlockModel,
ImageBlockModel, ImageBlockModel,
} from '@blocksuite/affine/blocks'; } 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 { import {
createYProxy, createYProxy,
DocCollection, DocCollection,
@@ -174,11 +180,22 @@ function generateMarkdownPreviewBuilder(
adapterConfigs.set('docLinkBaseUrl', baseUrl); adapterConfigs.set('docLinkBaseUrl', baseUrl);
}; };
const container = new Container();
[
...markdownInlineToDeltaMatchers,
...defaultBlockMarkdownAdapterMatchers,
...inlineDeltaToMarkdownAdapterMatchers,
].forEach(ext => {
ext.setup(container);
});
const provider = container.provider();
const markdownAdapter = new MarkdownAdapter( const markdownAdapter = new MarkdownAdapter(
new Job({ new Job({
collection: markdownPreviewDocCollection, collection: markdownPreviewDocCollection,
middlewares: [docLinkBaseURLMiddleware, titleMiddleware], middlewares: [docLinkBaseURLMiddleware, titleMiddleware],
}) }),
provider
); );
const markdownPreviewCache = new WeakMap<BlockDocumentInfo, string | null>(); const markdownPreviewCache = new WeakMap<BlockDocumentInfo, string | null>();

View File

@@ -3677,9 +3677,21 @@ __metadata:
lit: "npm:^3.2.0" lit: "npm:^3.2.0"
lodash.clonedeep: "npm:^4.5.0" lodash.clonedeep: "npm:^4.5.0"
lodash.mergewith: "npm:^4.6.2" 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" minimatch: "npm:^10.0.1"
rehype-parse: "npm:^9.0.0" rehype-parse: "npm:^9.0.0"
rehype-stringify: "npm:^10.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" unified: "npm:^11.0.5"
zod: "npm:^3.23.8" zod: "npm:^3.23.8"
languageName: unknown languageName: unknown