diff --git a/blocksuite/affine/shared/src/adapters/html-adapter/block-adapter.ts b/blocksuite/affine/shared/src/adapters/html/block-adapter.ts
similarity index 100%
rename from blocksuite/affine/shared/src/adapters/html-adapter/block-adapter.ts
rename to blocksuite/affine/shared/src/adapters/html/block-adapter.ts
diff --git a/blocksuite/affine/shared/src/adapters/html-adapter/delta-converter.ts b/blocksuite/affine/shared/src/adapters/html/delta-converter.ts
similarity index 100%
rename from blocksuite/affine/shared/src/adapters/html-adapter/delta-converter.ts
rename to blocksuite/affine/shared/src/adapters/html/delta-converter.ts
diff --git a/blocksuite/affine/shared/src/adapters/html-adapter/index.ts b/blocksuite/affine/shared/src/adapters/html/index.ts
similarity index 100%
rename from blocksuite/affine/shared/src/adapters/html-adapter/index.ts
rename to blocksuite/affine/shared/src/adapters/html/index.ts
diff --git a/blocksuite/affine/shared/src/adapters/html-adapter/type.ts b/blocksuite/affine/shared/src/adapters/html/type.ts
similarity index 100%
rename from blocksuite/affine/shared/src/adapters/html-adapter/type.ts
rename to blocksuite/affine/shared/src/adapters/html/type.ts
diff --git a/blocksuite/affine/shared/src/adapters/index.ts b/blocksuite/affine/shared/src/adapters/index.ts
index fb261cd31a..ae19f8fcfe 100644
--- a/blocksuite/affine/shared/src/adapters/index.ts
+++ b/blocksuite/affine/shared/src/adapters/index.ts
@@ -3,12 +3,14 @@ export {
type BlockHtmlAdapterMatcher,
BlockHtmlAdapterMatcherIdentifier,
type Html,
+ HtmlASTToDeltaExtension,
type HtmlASTToDeltaMatcher,
HtmlASTToDeltaMatcherIdentifier,
HtmlDeltaConverter,
+ InlineDeltaToHtmlAdapterExtension,
type InlineDeltaToHtmlAdapterMatcher,
InlineDeltaToHtmlAdapterMatcherIdentifier,
-} from './html-adapter/index.js';
+} from './html/index.js';
export {
BlockMarkdownAdapterExtension,
type BlockMarkdownAdapterMatcher,
diff --git a/blocksuite/blocks/src/__tests__/adapters/html.unit.spec.ts b/blocksuite/blocks/src/__tests__/adapters/html.unit.spec.ts
index 2de1f80c00..bba8219d92 100644
--- a/blocksuite/blocks/src/__tests__/adapters/html.unit.spec.ts
+++ b/blocksuite/blocks/src/__tests__/adapters/html.unit.spec.ts
@@ -2,6 +2,7 @@ import {
DEFAULT_NOTE_BACKGROUND_COLOR,
NoteDisplayMode,
} from '@blocksuite/affine-model';
+import { Container } from '@blocksuite/global/di';
import type {
BlockSnapshot,
DocSnapshot,
@@ -10,11 +11,24 @@ import type {
import { AssetsManager, MemoryBlobCRUD } from '@blocksuite/store';
import { describe, expect, test } from 'vitest';
-import { HtmlAdapter } from '../../_common/adapters/html-adapter/html.js';
+import { defaultBlockHtmlAdapterMatchers } from '../../_common/adapters/html/block-matcher.js';
+import { htmlInlineToDeltaMatchers } from '../../_common/adapters/html/delta-converter/html-inline.js';
+import { inlineDeltaToHtmlAdapterMatchers } from '../../_common/adapters/html/delta-converter/inline-delta.js';
+import { HtmlAdapter } from '../../_common/adapters/html/html.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();
+[
+ ...htmlInlineToDeltaMatchers,
+ ...defaultBlockHtmlAdapterMatchers,
+ ...inlineDeltaToHtmlAdapterMatchers,
+].forEach(ext => {
+ ext.setup(container);
+});
+const provider = container.provider();
+
describe('snapshot to html', () => {
const template = (html: string, title?: string) => {
let htmlTemplate = `
@@ -126,7 +140,7 @@ describe('snapshot to html', () => {
`
import this
`
);
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const target = await htmlAdapter.fromBlockSnapshot({
snapshot: blockSnapshot,
});
@@ -192,7 +206,7 @@ describe('snapshot to html', () => {
`import this
`
);
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const target = await htmlAdapter.fromBlockSnapshot({
snapshot: blockSnapshot,
});
@@ -258,7 +272,7 @@ describe('snapshot to html', () => {
`import this
`
);
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const target = await htmlAdapter.fromBlockSnapshot({
snapshot: blockSnapshot,
});
@@ -444,7 +458,7 @@ describe('snapshot to html', () => {
``
);
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const target = await htmlAdapter.fromBlockSnapshot({
snapshot: blockSnapshot,
});
@@ -589,7 +603,7 @@ describe('snapshot to html', () => {
``
);
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const target = await htmlAdapter.fromBlockSnapshot({
snapshot: blockSnapshot,
});
@@ -694,7 +708,7 @@ describe('snapshot to html', () => {
``
);
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const target = await htmlAdapter.fromBlockSnapshot({
snapshot: blockSnapshot,
});
@@ -768,7 +782,7 @@ describe('snapshot to html', () => {
``
);
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const target = await htmlAdapter.fromBlockSnapshot({
snapshot: blockSnapshot,
});
@@ -842,7 +856,7 @@ describe('snapshot to html', () => {
``
);
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const target = await htmlAdapter.fromBlockSnapshot({
snapshot: blockSnapshot,
});
@@ -917,7 +931,7 @@ describe('snapshot to html', () => {
``
);
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const target = await htmlAdapter.fromBlockSnapshot({
snapshot: blockSnapshot,
});
@@ -992,7 +1006,7 @@ describe('snapshot to html', () => {
``
);
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const target = await htmlAdapter.fromBlockSnapshot({
snapshot: blockSnapshot,
});
@@ -1069,7 +1083,7 @@ describe('snapshot to html', () => {
`
`
);
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const blobManager = new MemoryBlobCRUD();
await blobManager.set(
'YXXTjRmLlNyiOUnHb8nAIvUP6V7PAXhwW9F5_tc2LGs=',
@@ -1171,7 +1185,7 @@ describe('snapshot to html', () => {
``
);
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const target = await htmlAdapter.fromBlockSnapshot({
snapshot: blockSnapshot,
});
@@ -1430,7 +1444,7 @@ describe('snapshot to html', () => {
const html = template(
'| Title | Status | Date | Number | Progress | MultiSelect | RichText | Link | Checkbox |
|---|
| Task 1 | TODO | 2023-12-15 | 1 | 65 | test1,test2 | test2 | https://google.com | true |
| Task 2 | In Progress | 2023-12-20 | | | | test1 | | |
'
);
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const target = await htmlAdapter.fromBlockSnapshot({
snapshot: blockSnapshot,
});
@@ -1510,7 +1524,7 @@ describe('snapshot to html', () => {
const html = template(
''
);
- const htmlAdapter = new HtmlAdapter(createJob([middleware]));
+ const htmlAdapter = new HtmlAdapter(createJob([middleware]), provider);
const target = await htmlAdapter.fromBlockSnapshot({
snapshot: blockSnapShot,
});
@@ -1896,7 +1910,7 @@ describe('snapshot to html', () => {
await job.snapshotToDoc(syncedDocSnapshot);
await job.snapshotToDoc(docSnapShot);
- const mdAdapter = new HtmlAdapter(job);
+ const mdAdapter = new HtmlAdapter(job, provider);
const target = await mdAdapter.fromDocSnapshot({
snapshot: docSnapShot,
});
@@ -1981,7 +1995,7 @@ describe('html to snapshot', () => {
],
};
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await htmlAdapter.toBlockSnapshot({
file: html,
});
@@ -2091,7 +2105,7 @@ describe('html to snapshot', () => {
],
};
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await htmlAdapter.toBlockSnapshot({
file: html,
});
@@ -2157,7 +2171,7 @@ describe('html to snapshot', () => {
],
};
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await htmlAdapter.toBlockSnapshot({
file: html,
});
@@ -2202,7 +2216,7 @@ describe('html to snapshot', () => {
],
};
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await htmlAdapter.toBlockSnapshot({
file: html,
});
@@ -2238,7 +2252,7 @@ describe('html to snapshot', () => {
],
};
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await htmlAdapter.toBlockSnapshot({
file: html,
});
@@ -2350,7 +2364,7 @@ describe('html to snapshot', () => {
],
};
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await htmlAdapter.toBlockSnapshot({
file: html,
});
@@ -2394,7 +2408,7 @@ describe('html to snapshot', () => {
],
};
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await htmlAdapter.toBlockSnapshot({
file: html,
});
@@ -2438,7 +2452,7 @@ describe('html to snapshot', () => {
],
};
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await htmlAdapter.toBlockSnapshot({
file: html,
});
@@ -2491,7 +2505,7 @@ describe('html to snapshot', () => {
],
};
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await htmlAdapter.toBlockSnapshot({
file: html,
});
@@ -2544,7 +2558,7 @@ describe('html to snapshot', () => {
],
};
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await htmlAdapter.toBlockSnapshot({
file: html,
});
@@ -2585,7 +2599,7 @@ describe('html to snapshot', () => {
],
};
- const htmlAdapter = new HtmlAdapter(createJob());
+ const htmlAdapter = new HtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await htmlAdapter.toBlockSnapshot({
file: html,
});
diff --git a/blocksuite/blocks/src/_common/adapters/extension.ts b/blocksuite/blocks/src/_common/adapters/extension.ts
index 228113d748..7135e10d22 100644
--- a/blocksuite/blocks/src/_common/adapters/extension.ts
+++ b/blocksuite/blocks/src/_common/adapters/extension.ts
@@ -1,7 +1,9 @@
import type { ExtensionType } from '@blocksuite/block-std';
import { AttachmentAdapterFactoryExtension } from './attachment.js';
-import { HtmlAdapterFactoryExtension } from './html-adapter/html.js';
+import { htmlInlineToDeltaMatchers } from './html/delta-converter/html-inline.js';
+import { inlineDeltaToHtmlAdapterMatchers } from './html/delta-converter/inline-delta.js';
+import { HtmlAdapterFactoryExtension } from './html/html.js';
import { ImageAdapterFactoryExtension } from './image.js';
import { MarkdownAdapterFactoryExtension } from './markdown/markdown.js';
import { MixTextAdapterFactoryExtension } from './mix-text.js';
@@ -10,6 +12,8 @@ import { NotionTextAdapterFactoryExtension } from './notion-text.js';
import { PlainTextAdapterFactoryExtension } from './plain-text/plain-text.js';
export const AdapterFactoryExtensions: ExtensionType[] = [
+ ...htmlInlineToDeltaMatchers,
+ ...inlineDeltaToHtmlAdapterMatchers,
AttachmentAdapterFactoryExtension,
ImageAdapterFactoryExtension,
MarkdownAdapterFactoryExtension,
diff --git a/blocksuite/blocks/src/_common/adapters/html-adapter/block-matcher.ts b/blocksuite/blocks/src/_common/adapters/html-adapter/block-matcher.ts
deleted file mode 100644
index 1fa564266b..0000000000
--- a/blocksuite/blocks/src/_common/adapters/html-adapter/block-matcher.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import {
- embedFigmaBlockHtmlAdapterMatcher,
- embedGithubBlockHtmlAdapterMatcher,
- embedLinkedDocBlockHtmlAdapterMatcher,
- embedLoomBlockHtmlAdapterMatcher,
- embedSyncedDocBlockHtmlAdapterMatcher,
- embedYoutubeBlockHtmlAdapterMatcher,
-} from '@blocksuite/affine-block-embed';
-import { listBlockHtmlAdapterMatcher } from '@blocksuite/affine-block-list';
-import { paragraphBlockHtmlAdapterMatcher } from '@blocksuite/affine-block-paragraph';
-
-import { bookmarkBlockHtmlAdapterMatcher } from '../../../bookmark-block/adapters/html.js';
-import { codeBlockHtmlAdapterMatcher } from '../../../code-block/adapters/html.js';
-import { databaseBlockHtmlAdapterMatcher } from '../../../database-block/adapters/html.js';
-import { dividerBlockHtmlAdapterMatcher } from '../../../divider-block/adapters/html.js';
-import { imageBlockHtmlAdapterMatcher } from '../../../image-block/adapters/html.js';
-import { rootBlockHtmlAdapterMatcher } from '../../../root-block/adapters/html.js';
-
-export const defaultBlockHtmlAdapterMatchers = [
- listBlockHtmlAdapterMatcher,
- paragraphBlockHtmlAdapterMatcher,
- codeBlockHtmlAdapterMatcher,
- dividerBlockHtmlAdapterMatcher,
- imageBlockHtmlAdapterMatcher,
- rootBlockHtmlAdapterMatcher,
- embedYoutubeBlockHtmlAdapterMatcher,
- embedFigmaBlockHtmlAdapterMatcher,
- embedLoomBlockHtmlAdapterMatcher,
- embedGithubBlockHtmlAdapterMatcher,
- bookmarkBlockHtmlAdapterMatcher,
- databaseBlockHtmlAdapterMatcher,
- embedLinkedDocBlockHtmlAdapterMatcher,
- embedSyncedDocBlockHtmlAdapterMatcher,
-];
diff --git a/blocksuite/blocks/src/_common/adapters/html/block-matcher.ts b/blocksuite/blocks/src/_common/adapters/html/block-matcher.ts
new file mode 100644
index 0000000000..6b13cd8694
--- /dev/null
+++ b/blocksuite/blocks/src/_common/adapters/html/block-matcher.ts
@@ -0,0 +1,34 @@
+import {
+ EmbedFigmaBlockHtmlAdapterExtension,
+ EmbedGithubBlockHtmlAdapterExtension,
+ EmbedLinkedDocHtmlAdapterExtension,
+ EmbedLoomBlockHtmlAdapterExtension,
+ EmbedSyncedDocBlockHtmlAdapterExtension,
+ EmbedYoutubeBlockHtmlAdapterExtension,
+} from '@blocksuite/affine-block-embed';
+import { ListBlockHtmlAdapterExtension } from '@blocksuite/affine-block-list';
+import { ParagraphBlockHtmlAdapterExtension } from '@blocksuite/affine-block-paragraph';
+
+import { BookmarkBlockHtmlAdapterExtension } from '../../../bookmark-block/adapters/html.js';
+import { CodeBlockHtmlAdapterExtension } from '../../../code-block/adapters/html.js';
+import { DatabaseBlockHtmlAdapterExtension } from '../../../database-block/adapters/html.js';
+import { DividerBlockHtmlAdapterExtension } from '../../../divider-block/adapters/html.js';
+import { ImageBlockHtmlAdapterExtension } from '../../../image-block/adapters/html.js';
+import { RootBlockHtmlAdapterExtension } from '../../../root-block/adapters/html.js';
+
+export const defaultBlockHtmlAdapterMatchers = [
+ ListBlockHtmlAdapterExtension,
+ ParagraphBlockHtmlAdapterExtension,
+ CodeBlockHtmlAdapterExtension,
+ DividerBlockHtmlAdapterExtension,
+ ImageBlockHtmlAdapterExtension,
+ RootBlockHtmlAdapterExtension,
+ EmbedYoutubeBlockHtmlAdapterExtension,
+ EmbedFigmaBlockHtmlAdapterExtension,
+ EmbedLoomBlockHtmlAdapterExtension,
+ EmbedGithubBlockHtmlAdapterExtension,
+ BookmarkBlockHtmlAdapterExtension,
+ DatabaseBlockHtmlAdapterExtension,
+ EmbedLinkedDocHtmlAdapterExtension,
+ EmbedSyncedDocBlockHtmlAdapterExtension,
+];
diff --git a/blocksuite/blocks/src/_common/adapters/html-adapter/delta-converter/html-inline.ts b/blocksuite/blocks/src/_common/adapters/html/delta-converter/html-inline.ts
similarity index 86%
rename from blocksuite/blocks/src/_common/adapters/html-adapter/delta-converter/html-inline.ts
rename to blocksuite/blocks/src/_common/adapters/html/delta-converter/html-inline.ts
index 7a0d910322..1a2704a9a6 100644
--- a/blocksuite/blocks/src/_common/adapters/html-adapter/delta-converter/html-inline.ts
+++ b/blocksuite/blocks/src/_common/adapters/html/delta-converter/html-inline.ts
@@ -1,6 +1,6 @@
-import type {
- HtmlAST,
- HtmlASTToDeltaMatcher,
+import {
+ type HtmlAST,
+ HtmlASTToDeltaExtension,
} from '@blocksuite/affine-shared/adapters';
import { collapseWhiteSpace } from 'collapse-white-space';
import type { Element } from 'hast';
@@ -14,7 +14,7 @@ const listElementTags = new Set(['ol', 'ul']);
const strongElementTags = new Set(['strong', 'b']);
const italicElementTags = new Set(['i', 'em']);
-export const htmlTextToDeltaMatcher: HtmlASTToDeltaMatcher = {
+export const htmlTextToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'text',
match: ast => ast.type === 'text',
toDelta: (ast, context) => {
@@ -33,9 +33,9 @@ export const htmlTextToDeltaMatcher: HtmlASTToDeltaMatcher = {
: collapseWhiteSpace(ast.value);
return value ? [{ insert: value }] : [];
},
-};
+});
-export const htmlTextLikeElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
+export const htmlTextLikeElementToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'text-like-element',
match: ast => isElement(ast) && textLikeElementTags.has(ast.tagName),
toDelta: (ast, context) => {
@@ -46,17 +46,17 @@ export const htmlTextLikeElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
context.toDelta(child, { trim: false })
);
},
-};
+});
-export const htmlListToDeltaMatcher: HtmlASTToDeltaMatcher = {
+export const htmlListToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'list-element',
match: ast => isElement(ast) && listElementTags.has(ast.tagName),
toDelta: () => {
return [];
},
-};
+});
-export const htmlStrongElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
+export const htmlStrongElementToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'strong-element',
match: ast => isElement(ast) && strongElementTags.has(ast.tagName),
toDelta: (ast, context) => {
@@ -70,9 +70,9 @@ export const htmlStrongElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
})
);
},
-};
+});
-export const htmlItalicElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
+export const htmlItalicElementToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'italic-element',
match: ast => isElement(ast) && italicElementTags.has(ast.tagName),
toDelta: (ast, context) => {
@@ -86,8 +86,9 @@ export const htmlItalicElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
})
);
},
-};
-export const htmlCodeElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
+});
+
+export const htmlCodeElementToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'code-element',
match: ast => isElement(ast) && ast.tagName === 'code',
toDelta: (ast, context) => {
@@ -101,9 +102,9 @@ export const htmlCodeElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
})
);
},
-};
+});
-export const htmlDelElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
+export const htmlDelElementToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'del-element',
match: ast => isElement(ast) && ast.tagName === 'del',
toDelta: (ast, context) => {
@@ -117,9 +118,9 @@ export const htmlDelElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
})
);
},
-};
+});
-export const htmlUnderlineElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
+export const htmlUnderlineElementToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'underline-element',
match: ast => isElement(ast) && ast.tagName === 'u',
toDelta: (ast, context) => {
@@ -133,9 +134,9 @@ export const htmlUnderlineElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
})
);
},
-};
+});
-export const htmlLinkElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
+export const htmlLinkElementToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'link-element',
match: ast => isElement(ast) && ast.tagName === 'a',
toDelta: (ast, context) => {
@@ -194,9 +195,9 @@ export const htmlLinkElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
})
);
},
-};
+});
-export const htmlMarkElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
+export const htmlMarkElementToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'mark-element',
match: ast => isElement(ast) && ast.tagName === 'mark',
toDelta: (ast, context) => {
@@ -210,17 +211,17 @@ export const htmlMarkElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
})
);
},
-};
+});
-export const htmlBrElementToDeltaMatcher: HtmlASTToDeltaMatcher = {
+export const htmlBrElementToDeltaMatcher = HtmlASTToDeltaExtension({
name: 'br-element',
match: ast => isElement(ast) && ast.tagName === 'br',
toDelta: () => {
return [{ insert: '\n' }];
},
-};
+});
-export const htmlInlineToDeltaMatchers: HtmlASTToDeltaMatcher[] = [
+export const htmlInlineToDeltaMatchers = [
htmlTextToDeltaMatcher,
htmlTextLikeElementToDeltaMatcher,
htmlStrongElementToDeltaMatcher,
diff --git a/blocksuite/blocks/src/_common/adapters/html-adapter/delta-converter/inline-delta.ts b/blocksuite/blocks/src/_common/adapters/html/delta-converter/inline-delta.ts
similarity index 68%
rename from blocksuite/blocks/src/_common/adapters/html-adapter/delta-converter/inline-delta.ts
rename to blocksuite/blocks/src/_common/adapters/html/delta-converter/inline-delta.ts
index 577e530211..d8b0501e97 100644
--- a/blocksuite/blocks/src/_common/adapters/html-adapter/delta-converter/inline-delta.ts
+++ b/blocksuite/blocks/src/_common/adapters/html/delta-converter/inline-delta.ts
@@ -1,10 +1,8 @@
import { generateDocUrl } from '@blocksuite/affine-block-embed';
-import type {
- InlineDeltaToHtmlAdapterMatcher,
- InlineHtmlAST,
-} from '@blocksuite/affine-shared/adapters';
+import type { InlineHtmlAST } from '@blocksuite/affine-shared/adapters';
+import { InlineDeltaToHtmlAdapterExtension } from '@blocksuite/affine-shared/adapters';
-export const boldDeltaToHtmlAdapterMatcher: InlineDeltaToHtmlAdapterMatcher = {
+export const boldDeltaToHtmlAdapterMatcher = InlineDeltaToHtmlAdapterExtension({
name: 'bold',
match: delta => !!delta.attributes?.bold,
toAST: (_, context) => {
@@ -15,10 +13,10 @@ export const boldDeltaToHtmlAdapterMatcher: InlineDeltaToHtmlAdapterMatcher = {
children: [context.current],
};
},
-};
+});
-export const italicDeltaToHtmlAdapterMatcher: InlineDeltaToHtmlAdapterMatcher =
- {
+export const italicDeltaToHtmlAdapterMatcher =
+ InlineDeltaToHtmlAdapterExtension({
name: 'italic',
match: delta => !!delta.attributes?.italic,
toAST: (_, context) => {
@@ -29,10 +27,10 @@ export const italicDeltaToHtmlAdapterMatcher: InlineDeltaToHtmlAdapterMatcher =
children: [context.current],
};
},
- };
+ });
-export const strikeDeltaToHtmlAdapterMatcher: InlineDeltaToHtmlAdapterMatcher =
- {
+export const strikeDeltaToHtmlAdapterMatcher =
+ InlineDeltaToHtmlAdapterExtension({
name: 'strike',
match: delta => !!delta.attributes?.strike,
toAST: (_, context) => {
@@ -43,10 +41,10 @@ export const strikeDeltaToHtmlAdapterMatcher: InlineDeltaToHtmlAdapterMatcher =
children: [context.current],
};
},
- };
+ });
-export const inlineCodeDeltaToMarkdownAdapterMatcher: InlineDeltaToHtmlAdapterMatcher =
- {
+export const inlineCodeDeltaToMarkdownAdapterMatcher =
+ InlineDeltaToHtmlAdapterExtension({
name: 'inlineCode',
match: delta => !!delta.attributes?.code,
toAST: (_, context) => {
@@ -57,10 +55,10 @@ export const inlineCodeDeltaToMarkdownAdapterMatcher: InlineDeltaToHtmlAdapterMa
children: [context.current],
};
},
- };
+ });
-export const underlineDeltaToHtmlAdapterMatcher: InlineDeltaToHtmlAdapterMatcher =
- {
+export const underlineDeltaToHtmlAdapterMatcher =
+ InlineDeltaToHtmlAdapterExtension({
name: 'underline',
match: delta => !!delta.attributes?.underline,
toAST: (_, context) => {
@@ -71,10 +69,10 @@ export const underlineDeltaToHtmlAdapterMatcher: InlineDeltaToHtmlAdapterMatcher
children: [context.current],
};
},
- };
+ });
-export const referenceDeltaToHtmlAdapterMatcher: InlineDeltaToHtmlAdapterMatcher =
- {
+export const referenceDeltaToHtmlAdapterMatcher =
+ InlineDeltaToHtmlAdapterExtension({
name: 'reference',
match: delta => !!delta.attributes?.reference,
toAST: (delta, context) => {
@@ -108,9 +106,9 @@ export const referenceDeltaToHtmlAdapterMatcher: InlineDeltaToHtmlAdapterMatcher
return hast;
},
- };
+ });
-export const linkDeltaToHtmlAdapterMatcher: InlineDeltaToHtmlAdapterMatcher = {
+export const linkDeltaToHtmlAdapterMatcher = InlineDeltaToHtmlAdapterExtension({
name: 'link',
match: delta => !!delta.attributes?.link,
toAST: (delta, _) => {
@@ -131,15 +129,14 @@ export const linkDeltaToHtmlAdapterMatcher: InlineDeltaToHtmlAdapterMatcher = {
children: [hast],
};
},
-};
+});
-export const inlineDeltaToHtmlAdapterMatchers: InlineDeltaToHtmlAdapterMatcher[] =
- [
- boldDeltaToHtmlAdapterMatcher,
- italicDeltaToHtmlAdapterMatcher,
- strikeDeltaToHtmlAdapterMatcher,
- underlineDeltaToHtmlAdapterMatcher,
- inlineCodeDeltaToMarkdownAdapterMatcher,
- referenceDeltaToHtmlAdapterMatcher,
- linkDeltaToHtmlAdapterMatcher,
- ];
+export const inlineDeltaToHtmlAdapterMatchers = [
+ boldDeltaToHtmlAdapterMatcher,
+ italicDeltaToHtmlAdapterMatcher,
+ strikeDeltaToHtmlAdapterMatcher,
+ underlineDeltaToHtmlAdapterMatcher,
+ inlineCodeDeltaToMarkdownAdapterMatcher,
+ referenceDeltaToHtmlAdapterMatcher,
+ linkDeltaToHtmlAdapterMatcher,
+];
diff --git a/blocksuite/blocks/src/_common/adapters/html-adapter/html.ts b/blocksuite/blocks/src/_common/adapters/html/html.ts
similarity index 93%
rename from blocksuite/blocks/src/_common/adapters/html-adapter/html.ts
rename to blocksuite/blocks/src/_common/adapters/html/html.ts
index 6c77f8054d..faf053f968 100644
--- a/blocksuite/blocks/src/_common/adapters/html-adapter/html.ts
+++ b/blocksuite/blocks/src/_common/adapters/html/html.ts
@@ -8,9 +8,12 @@ import {
BlockHtmlAdapterMatcherIdentifier,
HastUtils,
type HtmlAST,
+ HtmlASTToDeltaMatcherIdentifier,
HtmlDeltaConverter,
+ InlineDeltaToHtmlAdapterMatcherIdentifier,
} from '@blocksuite/affine-shared/adapters';
import type { ExtensionType } from '@blocksuite/block-std';
+import type { ServiceProvider } from '@blocksuite/global/di';
import {
type AssetsManager,
ASTWalker,
@@ -36,9 +39,6 @@ import rehypeStringify from 'rehype-stringify';
import { unified } from 'unified';
import { AdapterFactoryIdentifier } from '../type.js';
-import { defaultBlockHtmlAdapterMatchers } from './block-matcher.js';
-import { htmlInlineToDeltaMatchers } from './delta-converter/html-inline.js';
-import { inlineDeltaToHtmlAdapterMatchers } from './delta-converter/inline-delta.js';
export type Html = string;
@@ -170,11 +170,20 @@ export class HtmlAdapter extends BaseAdapter {
deltaConverter: HtmlDeltaConverter;
- constructor(
- job: Job,
- readonly blockMatchers: BlockHtmlAdapterMatcher[] = defaultBlockHtmlAdapterMatchers
- ) {
+ readonly blockMatchers: BlockHtmlAdapterMatcher[];
+
+ constructor(job: Job, provider: ServiceProvider) {
super(job);
+ const blockMatchers = Array.from(
+ provider.getAll(BlockHtmlAdapterMatcherIdentifier).values()
+ );
+ const inlineDeltaToHtmlAdapterMatchers = Array.from(
+ provider.getAll(InlineDeltaToHtmlAdapterMatcherIdentifier).values()
+ );
+ const htmlInlineToDeltaMatchers = Array.from(
+ provider.getAll(HtmlASTToDeltaMatcherIdentifier).values()
+ );
+ this.blockMatchers = blockMatchers;
this.deltaConverter = new HtmlDeltaConverter(
job.adapterConfigs,
inlineDeltaToHtmlAdapterMatchers,
@@ -373,13 +382,7 @@ export const HtmlAdapterFactoryIdentifier = AdapterFactoryIdentifier('Html');
export const HtmlAdapterFactoryExtension: ExtensionType = {
setup: di => {
di.addImpl(HtmlAdapterFactoryIdentifier, provider => ({
- get: (job: Job) =>
- new HtmlAdapter(
- job,
- Array.from(
- provider.getAll(BlockHtmlAdapterMatcherIdentifier).values()
- )
- ),
+ get: job => new HtmlAdapter(job, provider),
}));
},
};
diff --git a/blocksuite/blocks/src/_common/adapters/html-adapter/index.ts b/blocksuite/blocks/src/_common/adapters/html/index.ts
similarity index 100%
rename from blocksuite/blocks/src/_common/adapters/html-adapter/index.ts
rename to blocksuite/blocks/src/_common/adapters/html/index.ts
diff --git a/blocksuite/blocks/src/_common/adapters/index.ts b/blocksuite/blocks/src/_common/adapters/index.ts
index d6e8c7b240..6340949f3d 100644
--- a/blocksuite/blocks/src/_common/adapters/index.ts
+++ b/blocksuite/blocks/src/_common/adapters/index.ts
@@ -1,6 +1,6 @@
export * from './attachment.js';
export * from './extension.js';
-export * from './html-adapter/html.js';
+export * from './html/html.js';
export * from './image.js';
export * from './markdown/index.js';
export * from './mix-text.js';
diff --git a/blocksuite/blocks/src/_common/transformers/html.ts b/blocksuite/blocks/src/_common/transformers/html.ts
index e09d1c6116..c3d4be102b 100644
--- a/blocksuite/blocks/src/_common/transformers/html.ts
+++ b/blocksuite/blocks/src/_common/transformers/html.ts
@@ -1,8 +1,12 @@
+import { Container } from '@blocksuite/global/di';
import { sha } from '@blocksuite/global/utils';
import type { Doc, DocCollection } from '@blocksuite/store';
import { extMimeMap, Job } from '@blocksuite/store';
-import { HtmlAdapter } from '../adapters/html-adapter/html.js';
+import { defaultBlockHtmlAdapterMatchers } from '../adapters/html/block-matcher.js';
+import { htmlInlineToDeltaMatchers } from '../adapters/html/delta-converter/html-inline.js';
+import { inlineDeltaToHtmlAdapterMatchers } from '../adapters/html/delta-converter/inline-delta.js';
+import { HtmlAdapter } from '../adapters/html/html.js';
import {
defaultImageProxyMiddleware,
docLinkBaseURLMiddleware,
@@ -22,6 +26,17 @@ type ImportHTMLZipOptions = {
imported: Blob;
};
+const container = new Container();
+[
+ ...htmlInlineToDeltaMatchers,
+ ...defaultBlockHtmlAdapterMatchers,
+ ...inlineDeltaToHtmlAdapterMatchers,
+].forEach(ext => {
+ ext.setup(container);
+});
+
+const provider = container.provider();
+
/**
* Exports a doc to HTML format.
*
@@ -34,7 +49,7 @@ async function exportDoc(doc: Doc) {
middlewares: [docLinkBaseURLMiddleware, titleMiddleware],
});
const snapshot = job.docToSnapshot(doc);
- const adapter = new HtmlAdapter(job);
+ const adapter = new HtmlAdapter(job, provider);
if (!snapshot) {
return;
}
@@ -83,7 +98,7 @@ async function importHTMLToDoc({
docLinkBaseURLMiddleware,
],
});
- const htmlAdapter = new HtmlAdapter(job);
+ const htmlAdapter = new HtmlAdapter(job, provider);
const page = await htmlAdapter.toDoc({
file: html,
assets: job.assetsManager,
@@ -147,7 +162,7 @@ async function importHTMLZip({ collection, imported }: ImportHTMLZipOptions) {
for (const [key, value] of pendingPathBlobIdMap.entries()) {
pathBlobIdMap.set(key, value);
}
- const htmlAdapter = new HtmlAdapter(job);
+ const htmlAdapter = new HtmlAdapter(job, provider);
const html = await blob.text();
const doc = await htmlAdapter.toDoc({
file: html,
diff --git a/blocksuite/framework/block-std/src/clipboard/index.ts b/blocksuite/framework/block-std/src/clipboard/index.ts
index a1d8295e9b..fcb8888efb 100644
--- a/blocksuite/framework/block-std/src/clipboard/index.ts
+++ b/blocksuite/framework/block-std/src/clipboard/index.ts
@@ -1,3 +1,4 @@
+import type { ServiceProvider } from '@blocksuite/global/di';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import type {
BaseAdapter,
@@ -15,7 +16,9 @@ import { unified } from 'unified';
import { LifeCycleWatcher } from '../extension/index.js';
-type AdapterConstructor = new (job: Job) => T;
+type AdapterConstructor =
+ | { new (job: Job): T }
+ | (new (job: Job, provider: ServiceProvider) => T);
type AdapterMap = Map<
string,
@@ -131,7 +134,7 @@ export class Clipboard extends LifeCycleWatcher {
}
if (item) {
const job = this._getJob();
- const adapterInstance = new adapter(job);
+ const adapterInstance = new adapter(job, this.std.provider);
const payload = {
file: item,
assets: job.assetsManager,
@@ -274,7 +277,7 @@ export class Clipboard extends LifeCycleWatcher {
return;
}
const { adapter } = adapterItem;
- const adapterInstance = new adapter(job);
+ const adapterInstance = new adapter(job, this.std.provider);
const result = await adapterInstance.fromSlice(slice);
if (!result) {
return;