refactor(editor): extensionalize notion html adapter (#9318)

Part of [BS-2212](https://linear.app/affine-design/issue/BS-2212/adapter-extension化修复)
This commit is contained in:
donteatfriedrice
2024-12-26 03:22:09 +00:00
parent 3064f21454
commit 3996f96368
16 changed files with 158 additions and 125 deletions

View File

@@ -2,12 +2,12 @@ import type { ExtensionType } from '@blocksuite/block-std';
import { EmbedFigmaBlockHtmlAdapterExtension } from './html.js'; import { EmbedFigmaBlockHtmlAdapterExtension } from './html.js';
import { EmbedFigmaMarkdownAdapterExtension } from './markdown.js'; import { EmbedFigmaMarkdownAdapterExtension } from './markdown.js';
import { EmbedFigmaNotionHtmlAdapterExtension } from './notion-html.js'; import { EmbedFigmaBlockNotionHtmlAdapterExtension } from './notion-html.js';
import { EmbedFigmaBlockPlainTextAdapterExtension } from './plain-text.js'; import { EmbedFigmaBlockPlainTextAdapterExtension } from './plain-text.js';
export const EmbedFigmaBlockAdapterExtensions: ExtensionType[] = [ export const EmbedFigmaBlockAdapterExtensions: ExtensionType[] = [
EmbedFigmaBlockHtmlAdapterExtension, EmbedFigmaBlockHtmlAdapterExtension,
EmbedFigmaMarkdownAdapterExtension, EmbedFigmaMarkdownAdapterExtension,
EmbedFigmaBlockPlainTextAdapterExtension, EmbedFigmaBlockPlainTextAdapterExtension,
EmbedFigmaNotionHtmlAdapterExtension, EmbedFigmaBlockNotionHtmlAdapterExtension,
]; ];

View File

@@ -10,5 +10,5 @@ export const embedFigmaBlockNotionHtmlAdapterMatcher =
figmaUrlRegex figmaUrlRegex
); );
export const EmbedFigmaNotionHtmlAdapterExtension = export const EmbedFigmaBlockNotionHtmlAdapterExtension =
BlockNotionHtmlAdapterExtension(embedFigmaBlockNotionHtmlAdapterMatcher); BlockNotionHtmlAdapterExtension(embedFigmaBlockNotionHtmlAdapterMatcher);

View File

@@ -2,12 +2,12 @@ import type { ExtensionType } from '@blocksuite/block-std';
import { EmbedGithubBlockHtmlAdapterExtension } from './html.js'; import { EmbedGithubBlockHtmlAdapterExtension } from './html.js';
import { EmbedGithubMarkdownAdapterExtension } from './markdown.js'; import { EmbedGithubMarkdownAdapterExtension } from './markdown.js';
import { EmbedGithubNotionHtmlAdapterExtension } from './notion-html.js'; import { EmbedGithubBlockNotionHtmlAdapterExtension } from './notion-html.js';
import { EmbedGithubBlockPlainTextAdapterExtension } from './plain-text.js'; import { EmbedGithubBlockPlainTextAdapterExtension } from './plain-text.js';
export const EmbedGithubBlockAdapterExtensions: ExtensionType[] = [ export const EmbedGithubBlockAdapterExtensions: ExtensionType[] = [
EmbedGithubBlockHtmlAdapterExtension, EmbedGithubBlockHtmlAdapterExtension,
EmbedGithubMarkdownAdapterExtension, EmbedGithubMarkdownAdapterExtension,
EmbedGithubBlockPlainTextAdapterExtension, EmbedGithubBlockPlainTextAdapterExtension,
EmbedGithubNotionHtmlAdapterExtension, EmbedGithubBlockNotionHtmlAdapterExtension,
]; ];

View File

@@ -10,5 +10,5 @@ export const embedGithubBlockNotionHtmlAdapterMatcher =
githubUrlRegex githubUrlRegex
); );
export const EmbedGithubNotionHtmlAdapterExtension = export const EmbedGithubBlockNotionHtmlAdapterExtension =
BlockNotionHtmlAdapterExtension(embedGithubBlockNotionHtmlAdapterMatcher); BlockNotionHtmlAdapterExtension(embedGithubBlockNotionHtmlAdapterMatcher);

View File

@@ -2,12 +2,12 @@ import type { ExtensionType } from '@blocksuite/block-std';
import { EmbedLoomBlockHtmlAdapterExtension } from './html.js'; import { EmbedLoomBlockHtmlAdapterExtension } from './html.js';
import { EmbedLoomMarkdownAdapterExtension } from './markdown.js'; import { EmbedLoomMarkdownAdapterExtension } from './markdown.js';
import { EmbedLoomNotionHtmlAdapterExtension } from './notion-html.js'; import { EmbedLoomBlockNotionHtmlAdapterExtension } from './notion-html.js';
import { EmbedLoomBlockPlainTextAdapterExtension } from './plain-text.js'; import { EmbedLoomBlockPlainTextAdapterExtension } from './plain-text.js';
export const EmbedLoomBlockAdapterExtensions: ExtensionType[] = [ export const EmbedLoomBlockAdapterExtensions: ExtensionType[] = [
EmbedLoomBlockHtmlAdapterExtension, EmbedLoomBlockHtmlAdapterExtension,
EmbedLoomMarkdownAdapterExtension, EmbedLoomMarkdownAdapterExtension,
EmbedLoomBlockPlainTextAdapterExtension, EmbedLoomBlockPlainTextAdapterExtension,
EmbedLoomNotionHtmlAdapterExtension, EmbedLoomBlockNotionHtmlAdapterExtension,
]; ];

View File

@@ -10,5 +10,5 @@ export const embedLoomBlockNotionHtmlAdapterMatcher =
loomUrlRegex loomUrlRegex
); );
export const EmbedLoomNotionHtmlAdapterExtension = export const EmbedLoomBlockNotionHtmlAdapterExtension =
BlockNotionHtmlAdapterExtension(embedLoomBlockNotionHtmlAdapterMatcher); BlockNotionHtmlAdapterExtension(embedLoomBlockNotionHtmlAdapterMatcher);

View File

@@ -2,12 +2,12 @@ import type { ExtensionType } from '@blocksuite/block-std';
import { EmbedYoutubeBlockHtmlAdapterExtension } from './html.js'; import { EmbedYoutubeBlockHtmlAdapterExtension } from './html.js';
import { EmbedYoutubeMarkdownAdapterExtension } from './markdown.js'; import { EmbedYoutubeMarkdownAdapterExtension } from './markdown.js';
import { EmbedYoutubeNotionHtmlAdapterExtension } from './notion-html.js'; import { EmbedYoutubeBlockNotionHtmlAdapterExtension } from './notion-html.js';
import { EmbedYoutubeBlockPlainTextAdapterExtension } from './plain-text.js'; import { EmbedYoutubeBlockPlainTextAdapterExtension } from './plain-text.js';
export const EmbedYoutubeBlockAdapterExtensions: ExtensionType[] = [ export const EmbedYoutubeBlockAdapterExtensions: ExtensionType[] = [
EmbedYoutubeBlockHtmlAdapterExtension, EmbedYoutubeBlockHtmlAdapterExtension,
EmbedYoutubeMarkdownAdapterExtension, EmbedYoutubeMarkdownAdapterExtension,
EmbedYoutubeBlockPlainTextAdapterExtension, EmbedYoutubeBlockPlainTextAdapterExtension,
EmbedYoutubeNotionHtmlAdapterExtension, EmbedYoutubeBlockNotionHtmlAdapterExtension,
]; ];

View File

@@ -10,5 +10,5 @@ export const embedYoutubeBlockNotionHtmlAdapterMatcher =
youtubeUrlRegex youtubeUrlRegex
); );
export const EmbedYoutubeNotionHtmlAdapterExtension = export const EmbedYoutubeBlockNotionHtmlAdapterExtension =
BlockNotionHtmlAdapterExtension(embedYoutubeBlockNotionHtmlAdapterMatcher); BlockNotionHtmlAdapterExtension(embedYoutubeBlockNotionHtmlAdapterMatcher);

View File

@@ -30,6 +30,7 @@ export {
BlockNotionHtmlAdapterMatcherIdentifier, BlockNotionHtmlAdapterMatcherIdentifier,
type InlineDeltaToNotionHtmlAdapterMatcher, type InlineDeltaToNotionHtmlAdapterMatcher,
type NotionHtml, type NotionHtml,
NotionHtmlASTToDeltaExtension,
type NotionHtmlASTToDeltaMatcher, type NotionHtmlASTToDeltaMatcher,
NotionHtmlASTToDeltaMatcherIdentifier, NotionHtmlASTToDeltaMatcherIdentifier,
NotionHtmlDeltaConverter, NotionHtmlDeltaConverter,

View File

@@ -2,6 +2,7 @@ import {
DEFAULT_NOTE_BACKGROUND_COLOR, DEFAULT_NOTE_BACKGROUND_COLOR,
NoteDisplayMode, NoteDisplayMode,
} from '@blocksuite/affine-model'; } from '@blocksuite/affine-model';
import { Container } from '@blocksuite/global/di';
import { import {
AssetsManager, AssetsManager,
type BlockSnapshot, type BlockSnapshot,
@@ -9,10 +10,22 @@ import {
} from '@blocksuite/store'; } from '@blocksuite/store';
import { describe, expect, test } from 'vitest'; import { describe, expect, test } from 'vitest';
import { defaultBlockNotionHtmlAdapterMatchers } from '../../_common/adapters/notion-html/block-matcher.js';
import { notionHtmlInlineToDeltaMatchers } from '../../_common/adapters/notion-html/delta-converter/html-inline.js';
import { NotionHtmlAdapter } from '../../_common/adapters/notion-html/notion-html.js'; import { NotionHtmlAdapter } from '../../_common/adapters/notion-html/notion-html.js';
import { nanoidReplacement } from '../../_common/test-utils/test-utils.js'; import { nanoidReplacement } from '../../_common/test-utils/test-utils.js';
import { createJob } from '../utils/create-job.js'; import { createJob } from '../utils/create-job.js';
const container = new Container();
[
...notionHtmlInlineToDeltaMatchers,
...defaultBlockNotionHtmlAdapterMatchers,
].forEach(ext => {
ext.setup(container);
});
const provider = container.provider();
describe('notion html to snapshot', () => { describe('notion html to snapshot', () => {
test('code', async () => { test('code', async () => {
const html = `<div class="page-body"> const html = `<div class="page-body">
@@ -56,7 +69,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -179,7 +192,7 @@ describe('notion html to snapshot', () => {
}, },
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -259,7 +272,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -776,7 +789,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -914,7 +927,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -1018,7 +1031,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -1069,7 +1082,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -1139,7 +1152,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -1187,7 +1200,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -1225,7 +1238,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
assets: new AssetsManager({ blob: new MemoryBlobCRUD() }), assets: new AssetsManager({ blob: new MemoryBlobCRUD() }),
@@ -1277,7 +1290,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -1319,7 +1332,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const blobCRUD = new MemoryBlobCRUD(); const blobCRUD = new MemoryBlobCRUD();
const key = await blobCRUD.set(new File([], 'README.pdf')); const key = await blobCRUD.set(new File([], 'README.pdf'));
const assestsManager = new AssetsManager({ blob: blobCRUD }); const assestsManager = new AssetsManager({ blob: blobCRUD });
@@ -1683,7 +1696,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -1872,7 +1885,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -1912,7 +1925,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -1967,7 +1980,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });
@@ -2052,7 +2065,7 @@ describe('notion html to snapshot', () => {
], ],
}; };
const adapter = new NotionHtmlAdapter(createJob()); const adapter = new NotionHtmlAdapter(createJob(), provider);
const rawBlockSnapshot = await adapter.toBlockSnapshot({ const rawBlockSnapshot = await adapter.toBlockSnapshot({
file: html, file: html,
}); });

View File

@@ -7,6 +7,7 @@ import { HtmlAdapterFactoryExtension } from './html/html.js';
import { ImageAdapterFactoryExtension } from './image.js'; import { ImageAdapterFactoryExtension } from './image.js';
import { MarkdownAdapterFactoryExtension } from './markdown/markdown.js'; import { MarkdownAdapterFactoryExtension } from './markdown/markdown.js';
import { MixTextAdapterFactoryExtension } from './mix-text.js'; import { MixTextAdapterFactoryExtension } from './mix-text.js';
import { notionHtmlInlineToDeltaMatchers } from './notion-html/delta-converter/html-inline.js';
import { NotionHtmlAdapterFactoryExtension } from './notion-html/notion-html.js'; import { NotionHtmlAdapterFactoryExtension } from './notion-html/notion-html.js';
import { NotionTextAdapterFactoryExtension } from './notion-text.js'; import { NotionTextAdapterFactoryExtension } from './notion-text.js';
import { PlainTextAdapterFactoryExtension } from './plain-text/plain-text.js'; import { PlainTextAdapterFactoryExtension } from './plain-text/plain-text.js';
@@ -14,6 +15,7 @@ import { PlainTextAdapterFactoryExtension } from './plain-text/plain-text.js';
export const AdapterFactoryExtensions: ExtensionType[] = [ export const AdapterFactoryExtensions: ExtensionType[] = [
...htmlInlineToDeltaMatchers, ...htmlInlineToDeltaMatchers,
...inlineDeltaToHtmlAdapterMatchers, ...inlineDeltaToHtmlAdapterMatchers,
...notionHtmlInlineToDeltaMatchers,
AttachmentAdapterFactoryExtension, AttachmentAdapterFactoryExtension,
ImageAdapterFactoryExtension, ImageAdapterFactoryExtension,
MarkdownAdapterFactoryExtension, MarkdownAdapterFactoryExtension,

View File

@@ -1,36 +1,35 @@
import { attachmentBlockNotionHtmlAdapterMatcher } from '@blocksuite/affine-block-attachment'; import { AttachmentBlockNotionHtmlAdapterExtension } from '@blocksuite/affine-block-attachment';
import { bookmarkBlockNotionHtmlAdapterMatcher } from '@blocksuite/affine-block-bookmark'; import { BookmarkBlockNotionHtmlAdapterExtension } from '@blocksuite/affine-block-bookmark';
import { import {
embedFigmaBlockNotionHtmlAdapterMatcher, EmbedFigmaBlockNotionHtmlAdapterExtension,
embedGithubBlockNotionHtmlAdapterMatcher, EmbedGithubBlockNotionHtmlAdapterExtension,
embedLoomBlockNotionHtmlAdapterMatcher, EmbedLoomBlockNotionHtmlAdapterExtension,
embedYoutubeBlockNotionHtmlAdapterMatcher, EmbedYoutubeBlockNotionHtmlAdapterExtension,
} from '@blocksuite/affine-block-embed'; } from '@blocksuite/affine-block-embed';
import { imageBlockNotionHtmlAdapterMatcher } from '@blocksuite/affine-block-image'; import { ImageBlockNotionHtmlAdapterExtension } from '@blocksuite/affine-block-image';
import { listBlockNotionHtmlAdapterMatcher } from '@blocksuite/affine-block-list'; import { ListBlockNotionHtmlAdapterExtension } from '@blocksuite/affine-block-list';
import { paragraphBlockNotionHtmlAdapterMatcher } from '@blocksuite/affine-block-paragraph'; import { ParagraphBlockNotionHtmlAdapterExtension } from '@blocksuite/affine-block-paragraph';
import type { BlockNotionHtmlAdapterMatcher } from '@blocksuite/affine-shared/adapters'; import type { ExtensionType } from '@blocksuite/block-std';
import { codeBlockNotionHtmlAdapterMatcher } from '../../../code-block/adapters/notion-html.js'; import { CodeBlockNotionHtmlAdapterExtension } from '../../../code-block/adapters/notion-html.js';
import { databaseBlockNotionHtmlAdapterMatcher } from '../../../database-block/adapters/notion-html.js'; import { DatabaseBlockNotionHtmlAdapterExtension } from '../../../database-block/adapters/notion-html.js';
import { dividerBlockNotionHtmlAdapterMatcher } from '../../../divider-block/adapters/notion-html.js'; import { DividerBlockNotionHtmlAdapterExtension } from '../../../divider-block/adapters/notion-html.js';
import { latexBlockNotionHtmlAdapterMatcher } from '../../../latex-block/adapters/notion-html.js'; import { LatexBlockNotionHtmlAdapterExtension } from '../../../latex-block/adapters/notion-html.js';
import { rootBlockNotionHtmlAdapterMatcher } from '../../../root-block/adapters/notion-html.js'; import { RootBlockNotionHtmlAdapterExtension } from '../../../root-block/adapters/notion-html.js';
export const defaultBlockNotionHtmlAdapterMatchers: BlockNotionHtmlAdapterMatcher[] = export const defaultBlockNotionHtmlAdapterMatchers: ExtensionType[] = [
[ ListBlockNotionHtmlAdapterExtension,
listBlockNotionHtmlAdapterMatcher, ParagraphBlockNotionHtmlAdapterExtension,
paragraphBlockNotionHtmlAdapterMatcher, CodeBlockNotionHtmlAdapterExtension,
codeBlockNotionHtmlAdapterMatcher, DividerBlockNotionHtmlAdapterExtension,
dividerBlockNotionHtmlAdapterMatcher, ImageBlockNotionHtmlAdapterExtension,
imageBlockNotionHtmlAdapterMatcher, RootBlockNotionHtmlAdapterExtension,
rootBlockNotionHtmlAdapterMatcher, BookmarkBlockNotionHtmlAdapterExtension,
bookmarkBlockNotionHtmlAdapterMatcher, DatabaseBlockNotionHtmlAdapterExtension,
databaseBlockNotionHtmlAdapterMatcher, LatexBlockNotionHtmlAdapterExtension,
latexBlockNotionHtmlAdapterMatcher, EmbedYoutubeBlockNotionHtmlAdapterExtension,
embedYoutubeBlockNotionHtmlAdapterMatcher, EmbedFigmaBlockNotionHtmlAdapterExtension,
embedFigmaBlockNotionHtmlAdapterMatcher, EmbedGithubBlockNotionHtmlAdapterExtension,
embedGithubBlockNotionHtmlAdapterMatcher, EmbedLoomBlockNotionHtmlAdapterExtension,
embedLoomBlockNotionHtmlAdapterMatcher, AttachmentBlockNotionHtmlAdapterExtension,
attachmentBlockNotionHtmlAdapterMatcher, ];
];

View File

@@ -1,8 +1,9 @@
import { import {
HastUtils, HastUtils,
type HtmlAST, type HtmlAST,
type NotionHtmlASTToDeltaMatcher, NotionHtmlASTToDeltaExtension,
} from '@blocksuite/affine-shared/adapters'; } from '@blocksuite/affine-shared/adapters';
import type { ExtensionType } from '@blocksuite/block-std';
import { collapseWhiteSpace } from 'collapse-white-space'; import { collapseWhiteSpace } from 'collapse-white-space';
import type { Element, Text } from 'hast'; import type { Element, Text } from 'hast';
@@ -21,7 +22,7 @@ const italicElementTags = new Set(['i', 'em']);
const NotionInlineEquationToken = 'notion-text-equation-token'; const NotionInlineEquationToken = 'notion-text-equation-token';
const NotionUnderlineStyleToken = 'border-bottom:0.05em solid'; const NotionUnderlineStyleToken = 'border-bottom:0.05em solid';
export const notionHtmlTextToDeltaMatcher: NotionHtmlASTToDeltaMatcher = { export const notionHtmlTextToDeltaMatcher = NotionHtmlASTToDeltaExtension({
name: 'text', name: 'text',
match: ast => isText(ast), match: ast => isText(ast),
toDelta: (ast, context) => { toDelta: (ast, context) => {
@@ -45,10 +46,10 @@ export const notionHtmlTextToDeltaMatcher: NotionHtmlASTToDeltaMatcher = {
} }
return []; return [];
}, },
}; });
export const notionHtmlSpanElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher = export const notionHtmlSpanElementToDeltaMatcher =
{ NotionHtmlASTToDeltaExtension({
name: 'span-element', name: 'span-element',
match: ast => isElement(ast) && ast.tagName === 'span', match: ast => isElement(ast) && ast.tagName === 'span',
toDelta: (ast, context) => { toDelta: (ast, context) => {
@@ -82,18 +83,18 @@ export const notionHtmlSpanElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher =
return ast.children.flatMap(child => toDelta(child, options)); return ast.children.flatMap(child => toDelta(child, options));
}, },
}; });
export const notionHtmlListToDeltaMatcher: NotionHtmlASTToDeltaMatcher = { export const notionHtmlListToDeltaMatcher = NotionHtmlASTToDeltaExtension({
name: 'list-element', name: 'list-element',
match: ast => isElement(ast) && listElementTags.has(ast.tagName), match: ast => isElement(ast) && listElementTags.has(ast.tagName),
toDelta: () => { toDelta: () => {
return []; return [];
}, },
}; });
export const notionHtmlStrongElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher = export const notionHtmlStrongElementToDeltaMatcher =
{ NotionHtmlASTToDeltaExtension({
name: 'strong-element', name: 'strong-element',
match: ast => isElement(ast) && strongElementTags.has(ast.tagName), match: ast => isElement(ast) && strongElementTags.has(ast.tagName),
toDelta: (ast, context) => { toDelta: (ast, context) => {
@@ -109,10 +110,10 @@ export const notionHtmlStrongElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher
}) })
); );
}, },
}; });
export const notionHtmlItalicElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher = export const notionHtmlItalicElementToDeltaMatcher =
{ NotionHtmlASTToDeltaExtension({
name: 'italic-element', name: 'italic-element',
match: ast => isElement(ast) && italicElementTags.has(ast.tagName), match: ast => isElement(ast) && italicElementTags.has(ast.tagName),
toDelta: (ast, context) => { toDelta: (ast, context) => {
@@ -127,9 +128,10 @@ export const notionHtmlItalicElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher
}) })
); );
}, },
}; });
export const notionHtmlCodeElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher =
{ export const notionHtmlCodeElementToDeltaMatcher =
NotionHtmlASTToDeltaExtension({
name: 'code-element', name: 'code-element',
match: ast => isElement(ast) && ast.tagName === 'code', match: ast => isElement(ast) && ast.tagName === 'code',
toDelta: (ast, context) => { toDelta: (ast, context) => {
@@ -144,27 +146,29 @@ export const notionHtmlCodeElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher =
}) })
); );
}, },
}; });
export const notionHtmlDelElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher = { export const notionHtmlDelElementToDeltaMatcher = NotionHtmlASTToDeltaExtension(
name: 'del-element',
match: ast => isElement(ast) && ast.tagName === 'del',
toDelta: (ast, context) => {
if (!isElement(ast)) {
return [];
}
const { toDelta, options } = context;
return ast.children.flatMap(child =>
toDelta(child, options).map(delta => {
delta.attributes = { ...delta.attributes, strike: true };
return delta;
})
);
},
};
export const notionHtmlUnderlineElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher =
{ {
name: 'del-element',
match: ast => isElement(ast) && ast.tagName === 'del',
toDelta: (ast, context) => {
if (!isElement(ast)) {
return [];
}
const { toDelta, options } = context;
return ast.children.flatMap(child =>
toDelta(child, options).map(delta => {
delta.attributes = { ...delta.attributes, strike: true };
return delta;
})
);
},
}
);
export const notionHtmlUnderlineElementToDeltaMatcher =
NotionHtmlASTToDeltaExtension({
name: 'underline-element', name: 'underline-element',
match: ast => isElement(ast) && ast.tagName === 'u', match: ast => isElement(ast) && ast.tagName === 'u',
toDelta: (ast, context) => { toDelta: (ast, context) => {
@@ -179,10 +183,10 @@ export const notionHtmlUnderlineElementToDeltaMatcher: NotionHtmlASTToDeltaMatch
}) })
); );
}, },
}; });
export const notionHtmlLinkElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher = export const notionHtmlLinkElementToDeltaMatcher =
{ NotionHtmlASTToDeltaExtension({
name: 'link-element', name: 'link-element',
match: ast => isElement(ast) && ast.tagName === 'a', match: ast => isElement(ast) && ast.tagName === 'a',
toDelta: (ast, context) => { toDelta: (ast, context) => {
@@ -222,10 +226,10 @@ export const notionHtmlLinkElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher =
}) })
); );
}, },
}; });
export const notionHtmlMarkElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher = export const notionHtmlMarkElementToDeltaMatcher =
{ NotionHtmlASTToDeltaExtension({
name: 'mark-element', name: 'mark-element',
match: ast => isElement(ast) && ast.tagName === 'mark', match: ast => isElement(ast) && ast.tagName === 'mark',
toDelta: (ast, context) => { toDelta: (ast, context) => {
@@ -240,9 +244,9 @@ export const notionHtmlMarkElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher =
}) })
); );
}, },
}; });
export const notionHtmlLiElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher = { export const notionHtmlLiElementToDeltaMatcher = NotionHtmlASTToDeltaExtension({
name: 'li-element', name: 'li-element',
match: ast => match: ast =>
isElement(ast) && isElement(ast) &&
@@ -260,26 +264,26 @@ export const notionHtmlLiElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher = {
.slice(checkBoxIndex + 2) .slice(checkBoxIndex + 2)
.flatMap(child => toDelta(child, options)); .flatMap(child => toDelta(child, options));
}, },
}; });
export const notionHtmlBrElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher = { export const notionHtmlBrElementToDeltaMatcher = NotionHtmlASTToDeltaExtension({
name: 'br-element', name: 'br-element',
match: ast => isElement(ast) && ast.tagName === 'br', match: ast => isElement(ast) && ast.tagName === 'br',
toDelta: () => { toDelta: () => {
return [{ insert: '\n' }]; return [{ insert: '\n' }];
}, },
}; });
export const notionHtmlStyleElementToDeltaMatcher: NotionHtmlASTToDeltaMatcher = export const notionHtmlStyleElementToDeltaMatcher =
{ NotionHtmlASTToDeltaExtension({
name: 'style-element', name: 'style-element',
match: ast => isElement(ast) && ast.tagName === 'style', match: ast => isElement(ast) && ast.tagName === 'style',
toDelta: () => { toDelta: () => {
return []; return [];
}, },
}; });
export const notionHtmlInlineToDeltaMatchers: NotionHtmlASTToDeltaMatcher[] = [ export const notionHtmlInlineToDeltaMatchers: ExtensionType[] = [
notionHtmlTextToDeltaMatcher, notionHtmlTextToDeltaMatcher,
notionHtmlSpanElementToDeltaMatcher, notionHtmlSpanElementToDeltaMatcher,
notionHtmlStrongElementToDeltaMatcher, notionHtmlStrongElementToDeltaMatcher,

View File

@@ -9,9 +9,11 @@ import {
HastUtils, HastUtils,
type HtmlAST, type HtmlAST,
type NotionHtml, type NotionHtml,
NotionHtmlASTToDeltaMatcherIdentifier,
NotionHtmlDeltaConverter, NotionHtmlDeltaConverter,
} from '@blocksuite/affine-shared/adapters'; } 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 { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { import {
type AssetsManager, type AssetsManager,
@@ -33,8 +35,6 @@ import rehypeParse from 'rehype-parse';
import { unified } from 'unified'; import { unified } from 'unified';
import { AdapterFactoryIdentifier } from '../type.js'; import { AdapterFactoryIdentifier } from '../type.js';
import { defaultBlockNotionHtmlAdapterMatchers } from './block-matcher.js';
import { notionHtmlInlineToDeltaMatchers } from './delta-converter/html-inline.js';
type NotionHtmlToSliceSnapshotPayload = { type NotionHtmlToSliceSnapshotPayload = {
file: NotionHtml; file: NotionHtml;
@@ -112,11 +112,17 @@ export class NotionHtmlAdapter extends BaseAdapter<NotionHtml> {
deltaConverter: NotionHtmlDeltaConverter; deltaConverter: NotionHtmlDeltaConverter;
constructor( readonly blockMatchers: BlockNotionHtmlAdapterMatcher[];
job: Job,
readonly blockMatchers: BlockNotionHtmlAdapterMatcher[] = defaultBlockNotionHtmlAdapterMatchers constructor(job: Job, provider: ServiceProvider) {
) {
super(job); super(job);
const blockMatchers = Array.from(
provider.getAll(BlockNotionHtmlAdapterMatcherIdentifier).values()
);
const notionHtmlInlineToDeltaMatchers = Array.from(
provider.getAll(NotionHtmlASTToDeltaMatcherIdentifier).values()
);
this.blockMatchers = blockMatchers;
this.deltaConverter = new NotionHtmlDeltaConverter( this.deltaConverter = new NotionHtmlDeltaConverter(
job.adapterConfigs, job.adapterConfigs,
[], [],
@@ -287,13 +293,7 @@ export const NotionHtmlAdapterFactoryIdentifier =
export const NotionHtmlAdapterFactoryExtension: ExtensionType = { export const NotionHtmlAdapterFactoryExtension: ExtensionType = {
setup: di => { setup: di => {
di.addImpl(NotionHtmlAdapterFactoryIdentifier, provider => ({ di.addImpl(NotionHtmlAdapterFactoryIdentifier, provider => ({
get: (job: Job) => get: (job: Job) => new NotionHtmlAdapter(job, provider),
new NotionHtmlAdapter(
job,
Array.from(
provider.getAll(BlockNotionHtmlAdapterMatcherIdentifier).values()
)
),
})); }));
}, },
}; };

View File

@@ -1,6 +1,9 @@
import { Container } from '@blocksuite/global/di';
import { sha } from '@blocksuite/global/utils'; import { sha } from '@blocksuite/global/utils';
import { type DocCollection, extMimeMap, Job } from '@blocksuite/store'; import { type DocCollection, extMimeMap, Job } from '@blocksuite/store';
import { defaultBlockNotionHtmlAdapterMatchers } from '../adapters/notion-html/block-matcher.js';
import { notionHtmlInlineToDeltaMatchers } from '../adapters/notion-html/delta-converter/html-inline.js';
import { NotionHtmlAdapter } from '../adapters/notion-html/notion-html.js'; import { NotionHtmlAdapter } from '../adapters/notion-html/notion-html.js';
import { defaultImageProxyMiddleware } from './middlewares.js'; import { defaultImageProxyMiddleware } from './middlewares.js';
import { Unzip } from './utils.js'; import { Unzip } from './utils.js';
@@ -10,6 +13,16 @@ type ImportNotionZipOptions = {
imported: Blob; imported: Blob;
}; };
const container = new Container();
[
...notionHtmlInlineToDeltaMatchers,
...defaultBlockNotionHtmlAdapterMatchers,
].forEach(ext => {
ext.setup(container);
});
const provider = container.provider();
/** /**
* Imports a Notion zip file into the BlockSuite collection. * Imports a Notion zip file into the BlockSuite collection.
* *
@@ -109,7 +122,7 @@ async function importNotionZip({
collection: collection, collection: collection,
middlewares: [defaultImageProxyMiddleware], middlewares: [defaultImageProxyMiddleware],
}); });
const htmlAdapter = new NotionHtmlAdapter(job); const htmlAdapter = new NotionHtmlAdapter(job, provider);
const assets = job.assetsManager.getAssets(); const assets = job.assetsManager.getAssets();
const pathBlobIdMap = job.assetsManager.getPathBlobIdMap(); const pathBlobIdMap = job.assetsManager.getPathBlobIdMap();
for (const [key, value] of pendingAssets.entries()) { for (const [key, value] of pendingAssets.entries()) {

View File

@@ -12,6 +12,7 @@
{ "path": "./blocksuite/affine/block-embed" }, { "path": "./blocksuite/affine/block-embed" },
{ "path": "./blocksuite/affine/block-image" }, { "path": "./blocksuite/affine/block-image" },
{ "path": "./blocksuite/affine/block-list" }, { "path": "./blocksuite/affine/block-list" },
{ "path": "./blocksuite/affine/block-note" },
{ "path": "./blocksuite/affine/block-paragraph" }, { "path": "./blocksuite/affine/block-paragraph" },
{ "path": "./blocksuite/affine/block-surface" }, { "path": "./blocksuite/affine/block-surface" },
{ "path": "./blocksuite/affine/components" }, { "path": "./blocksuite/affine/components" },