fix(editor): notion html adapter for embed link block (#9279)

[BS-1745](https://linear.app/affine-design/issue/BS-1745/[bug]-导入的notion-youtube-embed-错误)
This commit is contained in:
donteatfriedrice
2024-12-25 07:20:26 +00:00
parent 2cc7bdfc77
commit 62b930f336
14 changed files with 168 additions and 1 deletions
@@ -0,0 +1,89 @@
import {
type BlockNotionHtmlAdapterMatcher,
HastUtils,
} from '@blocksuite/affine-shared/adapters';
import { nanoid } from '@blocksuite/store';
export function createEmbedBlockNotionHtmlAdapterMatcher(
flavour: string,
urlRegex: RegExp,
{
toMatch = o => {
const isFigure =
HastUtils.isElement(o.node) && o.node.tagName === 'figure';
const embededFigureWrapper = HastUtils.querySelector(o.node, '.source');
if (!isFigure || !embededFigureWrapper) {
return false;
}
const embededURL = HastUtils.querySelector(embededFigureWrapper, 'a')
?.properties.href;
if (!embededURL || typeof embededURL !== 'string') {
return false;
}
// To avoid polynomial regular expression used on uncontrolled data
// https://codeql.github.com/codeql-query-help/javascript/js-polynomial-redos/
if (embededURL.length > 1000) {
return false;
}
return urlRegex.test(embededURL);
},
fromMatch = o => o.node.flavour === flavour,
toBlockSnapshot = {
enter: (o, context) => {
if (!HastUtils.isElement(o.node)) {
return;
}
const { assets, walkerContext } = context;
if (!assets) {
return;
}
const embededFigureWrapper = HastUtils.querySelector(o.node, '.source');
if (!embededFigureWrapper) {
return;
}
let embededURL = '';
const embedA = HastUtils.querySelector(embededFigureWrapper, 'a');
embededURL =
typeof embedA?.properties.href === 'string'
? embedA.properties.href
: '';
if (!embededURL) {
return;
}
walkerContext
.openNode(
{
type: 'block',
id: nanoid(),
flavour,
props: {
url: embededURL,
},
children: [],
},
'children'
)
.closeNode();
walkerContext.skipAllChildren();
},
},
fromBlockSnapshot = {},
}: {
toMatch?: BlockNotionHtmlAdapterMatcher['toMatch'];
fromMatch?: BlockNotionHtmlAdapterMatcher['fromMatch'];
toBlockSnapshot?: BlockNotionHtmlAdapterMatcher['toBlockSnapshot'];
fromBlockSnapshot?: BlockNotionHtmlAdapterMatcher['fromBlockSnapshot'];
} = Object.create(null)
): BlockNotionHtmlAdapterMatcher {
return {
flavour,
toMatch,
fromMatch,
toBlockSnapshot,
fromBlockSnapshot,
};
}
@@ -2,10 +2,12 @@ import type { ExtensionType } from '@blocksuite/block-std';
import { EmbedFigmaBlockHtmlAdapterExtension } from './html.js';
import { EmbedFigmaMarkdownAdapterExtension } from './markdown.js';
import { EmbedFigmaNotionHtmlAdapterExtension } from './notion-html.js';
import { EmbedFigmaBlockPlainTextAdapterExtension } from './plain-text.js';
export const EmbedFigmaBlockAdapterExtensions: ExtensionType[] = [
EmbedFigmaBlockHtmlAdapterExtension,
EmbedFigmaMarkdownAdapterExtension,
EmbedFigmaBlockPlainTextAdapterExtension,
EmbedFigmaNotionHtmlAdapterExtension,
];
@@ -1,3 +1,4 @@
export * from './html.js';
export * from './markdown.js';
export * from './notion-html.js';
export * from './plain-text.js';
@@ -0,0 +1,14 @@
import { EmbedFigmaBlockSchema } from '@blocksuite/affine-model';
import { BlockNotionHtmlAdapterExtension } from '@blocksuite/affine-shared/adapters';
import { createEmbedBlockNotionHtmlAdapterMatcher } from '../../common/adapters/notion-html.js';
import { figmaUrlRegex } from '../embed-figma-model.js';
export const embedFigmaBlockNotionHtmlAdapterMatcher =
createEmbedBlockNotionHtmlAdapterMatcher(
EmbedFigmaBlockSchema.model.flavour,
figmaUrlRegex
);
export const EmbedFigmaNotionHtmlAdapterExtension =
BlockNotionHtmlAdapterExtension(embedFigmaBlockNotionHtmlAdapterMatcher);
@@ -2,10 +2,12 @@ import type { ExtensionType } from '@blocksuite/block-std';
import { EmbedGithubBlockHtmlAdapterExtension } from './html.js';
import { EmbedGithubMarkdownAdapterExtension } from './markdown.js';
import { EmbedGithubNotionHtmlAdapterExtension } from './notion-html.js';
import { EmbedGithubBlockPlainTextAdapterExtension } from './plain-text.js';
export const EmbedGithubBlockAdapterExtensions: ExtensionType[] = [
EmbedGithubBlockHtmlAdapterExtension,
EmbedGithubMarkdownAdapterExtension,
EmbedGithubBlockPlainTextAdapterExtension,
EmbedGithubNotionHtmlAdapterExtension,
];
@@ -1,3 +1,4 @@
export * from './html.js';
export * from './markdown.js';
export * from './notion-html.js';
export * from './plain-text.js';
@@ -0,0 +1,14 @@
import { EmbedGithubBlockSchema } from '@blocksuite/affine-model';
import { BlockNotionHtmlAdapterExtension } from '@blocksuite/affine-shared/adapters';
import { createEmbedBlockNotionHtmlAdapterMatcher } from '../../common/adapters/notion-html.js';
import { githubUrlRegex } from '../embed-github-model.js';
export const embedGithubBlockNotionHtmlAdapterMatcher =
createEmbedBlockNotionHtmlAdapterMatcher(
EmbedGithubBlockSchema.model.flavour,
githubUrlRegex
);
export const EmbedGithubNotionHtmlAdapterExtension =
BlockNotionHtmlAdapterExtension(embedGithubBlockNotionHtmlAdapterMatcher);
@@ -2,10 +2,12 @@ import type { ExtensionType } from '@blocksuite/block-std';
import { EmbedLoomBlockHtmlAdapterExtension } from './html.js';
import { EmbedLoomMarkdownAdapterExtension } from './markdown.js';
import { EmbedLoomNotionHtmlAdapterExtension } from './notion-html.js';
import { EmbedLoomBlockPlainTextAdapterExtension } from './plain-text.js';
export const EmbedLoomBlockAdapterExtensions: ExtensionType[] = [
EmbedLoomBlockHtmlAdapterExtension,
EmbedLoomMarkdownAdapterExtension,
EmbedLoomBlockPlainTextAdapterExtension,
EmbedLoomNotionHtmlAdapterExtension,
];
@@ -1,3 +1,4 @@
export * from './html.js';
export * from './markdown.js';
export * from './notion-html.js';
export * from './plain-text.js';
@@ -0,0 +1,14 @@
import { EmbedLoomBlockSchema } from '@blocksuite/affine-model';
import { BlockNotionHtmlAdapterExtension } from '@blocksuite/affine-shared/adapters';
import { createEmbedBlockNotionHtmlAdapterMatcher } from '../../common/adapters/notion-html.js';
import { loomUrlRegex } from '../embed-loom-model.js';
export const embedLoomBlockNotionHtmlAdapterMatcher =
createEmbedBlockNotionHtmlAdapterMatcher(
EmbedLoomBlockSchema.model.flavour,
loomUrlRegex
);
export const EmbedLoomNotionHtmlAdapterExtension =
BlockNotionHtmlAdapterExtension(embedLoomBlockNotionHtmlAdapterMatcher);
@@ -2,10 +2,12 @@ import type { ExtensionType } from '@blocksuite/block-std';
import { EmbedYoutubeBlockHtmlAdapterExtension } from './html.js';
import { EmbedYoutubeMarkdownAdapterExtension } from './markdown.js';
import { EmbedYoutubeNotionHtmlAdapterExtension } from './notion-html.js';
import { EmbedYoutubeBlockPlainTextAdapterExtension } from './plain-text.js';
export const EmbedYoutubeBlockAdapterExtensions: ExtensionType[] = [
EmbedYoutubeBlockHtmlAdapterExtension,
EmbedYoutubeMarkdownAdapterExtension,
EmbedYoutubeBlockPlainTextAdapterExtension,
EmbedYoutubeNotionHtmlAdapterExtension,
];
@@ -1,3 +1,4 @@
export * from './html.js';
export * from './markdown.js';
export * from './notion-html.js';
export * from './plain-text.js';
@@ -0,0 +1,14 @@
import { EmbedYoutubeBlockSchema } from '@blocksuite/affine-model';
import { BlockNotionHtmlAdapterExtension } from '@blocksuite/affine-shared/adapters';
import { createEmbedBlockNotionHtmlAdapterMatcher } from '../../common/adapters/notion-html.js';
import { youtubeUrlRegex } from '../embed-youtube-model.js';
export const embedYoutubeBlockNotionHtmlAdapterMatcher =
createEmbedBlockNotionHtmlAdapterMatcher(
EmbedYoutubeBlockSchema.model.flavour,
youtubeUrlRegex
);
export const EmbedYoutubeNotionHtmlAdapterExtension =
BlockNotionHtmlAdapterExtension(embedYoutubeBlockNotionHtmlAdapterMatcher);
@@ -1,3 +1,9 @@
import {
embedFigmaBlockNotionHtmlAdapterMatcher,
embedGithubBlockNotionHtmlAdapterMatcher,
embedLoomBlockNotionHtmlAdapterMatcher,
embedYoutubeBlockNotionHtmlAdapterMatcher,
} from '@blocksuite/affine-block-embed';
import { listBlockNotionHtmlAdapterMatcher } from '@blocksuite/affine-block-list';
import { paragraphBlockNotionHtmlAdapterMatcher } from '@blocksuite/affine-block-paragraph';
import type { BlockNotionHtmlAdapterMatcher } from '@blocksuite/affine-shared/adapters';
@@ -21,6 +27,10 @@ export const defaultBlockNotionHtmlAdapterMatchers: BlockNotionHtmlAdapterMatche
rootBlockNotionHtmlAdapterMatcher,
bookmarkBlockNotionHtmlAdapterMatcher,
databaseBlockNotionHtmlAdapterMatcher,
attachmentBlockNotionHtmlAdapterMatcher,
latexBlockNotionHtmlAdapterMatcher,
embedYoutubeBlockNotionHtmlAdapterMatcher,
embedFigmaBlockNotionHtmlAdapterMatcher,
embedGithubBlockNotionHtmlAdapterMatcher,
embedLoomBlockNotionHtmlAdapterMatcher,
attachmentBlockNotionHtmlAdapterMatcher,
];