refactor(editor): extensionalize plain text adapter (#9330)

This commit is contained in:
donteatfriedrice
2024-12-26 07:27:07 +00:00
parent 45acdbda04
commit cadb9211a6
27 changed files with 226 additions and 120 deletions

View File

@@ -2,17 +2,20 @@ import {
EdgelessSurfaceBlockMarkdownAdapterExtension, EdgelessSurfaceBlockMarkdownAdapterExtension,
SurfaceBlockMarkdownAdapterExtension, SurfaceBlockMarkdownAdapterExtension,
} from './markdown/markdown.js'; } from './markdown/markdown.js';
import { elementToPlainTextAdapterMatchers } from './plain-text/element-adapter/elements/index.js';
import { import {
EdgelessSurfaceBlockPlainTextAdapterExtension, EdgelessSurfaceBlockPlainTextAdapterExtension,
SurfaceBlockPlainTextAdapterExtension, SurfaceBlockPlainTextAdapterExtension,
} from './plain-text/plain-text.js'; } from './plain-text/plain-text.js';
export const SurfaceBlockAdapterExtensions = [ export const SurfaceBlockAdapterExtensions = [
...elementToPlainTextAdapterMatchers,
SurfaceBlockPlainTextAdapterExtension, SurfaceBlockPlainTextAdapterExtension,
SurfaceBlockMarkdownAdapterExtension, SurfaceBlockMarkdownAdapterExtension,
]; ];
export const EdgelessSurfaceBlockAdapterExtensions = [ export const EdgelessSurfaceBlockAdapterExtensions = [
...elementToPlainTextAdapterMatchers,
EdgelessSurfaceBlockPlainTextAdapterExtension, EdgelessSurfaceBlockPlainTextAdapterExtension,
EdgelessSurfaceBlockMarkdownAdapterExtension, EdgelessSurfaceBlockMarkdownAdapterExtension,
]; ];

View File

@@ -0,0 +1,4 @@
export {
EdgelessSurfaceBlockAdapterExtensions,
SurfaceBlockAdapterExtensions,
} from './extension.js';

View File

@@ -1,11 +1,11 @@
import type { ElementModelToPlainTextAdapterMatcher } from '../type.js'; import { ElementToPlainTextAdapterExtension } from '../type.js';
export const brushToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatcher = export const brushToPlainTextAdapterMatcher =
{ ElementToPlainTextAdapterExtension({
name: 'brush', name: 'brush',
match: elementModel => elementModel.type === 'brush', match: elementModel => elementModel.type === 'brush',
toAST: () => { toAST: () => {
const content = `Brush Stroke`; const content = `Brush Stroke`;
return { content }; return { content };
}, },
}; });

View File

@@ -1,8 +1,8 @@
import { getConnectorText } from '../../../utils/text.js'; import { getConnectorText } from '../../../utils/text.js';
import type { ElementModelToPlainTextAdapterMatcher } from '../type.js'; import { ElementToPlainTextAdapterExtension } from '../type.js';
export const connectorToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatcher = export const connectorToPlainTextAdapterMatcher =
{ ElementToPlainTextAdapterExtension({
name: 'connector', name: 'connector',
match: elementModel => elementModel.type === 'connector', match: elementModel => elementModel.type === 'connector',
toAST: elementModel => { toAST: elementModel => {
@@ -10,4 +10,4 @@ export const connectorToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterM
const content = `Connector, with text label "${text}"`; const content = `Connector, with text label "${text}"`;
return { content }; return { content };
}, },
}; });

View File

@@ -1,8 +1,8 @@
import { getGroupTitle } from '../../../utils/text.js'; import { getGroupTitle } from '../../../utils/text.js';
import type { ElementModelToPlainTextAdapterMatcher } from '../type.js'; import { ElementToPlainTextAdapterExtension } from '../type.js';
export const groupToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatcher = export const groupToPlainTextAdapterMatcher =
{ ElementToPlainTextAdapterExtension({
name: 'group', name: 'group',
match: elementModel => elementModel.type === 'group', match: elementModel => elementModel.type === 'group',
toAST: elementModel => { toAST: elementModel => {
@@ -10,4 +10,4 @@ export const groupToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatch
const content = `Group, with title "${title}"`; const content = `Group, with title "${title}"`;
return { content }; return { content };
}, },
}; });

View File

@@ -5,7 +5,7 @@ import { mindmapToPlainTextAdapterMatcher } from './mindmap.js';
import { shapeToPlainTextAdapterMatcher } from './shape.js'; import { shapeToPlainTextAdapterMatcher } from './shape.js';
import { textToPlainTextAdapterMatcher } from './text.js'; import { textToPlainTextAdapterMatcher } from './text.js';
export const elementModelToPlainTextAdapterMatchers = [ export const elementToPlainTextAdapterMatchers = [
groupToPlainTextAdapterMatcher, groupToPlainTextAdapterMatcher,
shapeToPlainTextAdapterMatcher, shapeToPlainTextAdapterMatcher,
connectorToPlainTextAdapterMatcher, connectorToPlainTextAdapterMatcher,

View File

@@ -1,12 +1,12 @@
import { getMindMapTreeText } from '../../../utils/text.js'; import { getMindMapTreeText } from '../../../utils/text.js';
import type { ElementModelToPlainTextAdapterMatcher } from '../type.js'; import { ElementToPlainTextAdapterExtension } from '../type.js';
export const mindmapToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatcher = export const mindmapToPlainTextAdapterMatcher =
{ ElementToPlainTextAdapterExtension({
name: 'mindmap', name: 'mindmap',
match: elementModel => elementModel.type === 'mindmap', match: elementModel => elementModel.type === 'mindmap',
toAST: (elementModel, context) => { toAST: (elementModel, context) => {
const mindMapContent = getMindMapTreeText(elementModel, context.elements); const mindMapContent = getMindMapTreeText(elementModel, context.elements);
return { content: mindMapContent }; return { content: mindMapContent };
}, },
}; });

View File

@@ -1,9 +1,9 @@
import type { MindMapTreeNode } from '../../../types/mindmap.js'; import type { MindMapTreeNode } from '../../../types/mindmap.js';
import { getShapeText, getShapeType } from '../../../utils/text.js'; import { getShapeText, getShapeType } from '../../../utils/text.js';
import type { ElementModelToPlainTextAdapterMatcher } from '../type.js'; import { ElementToPlainTextAdapterExtension } from '../type.js';
export const shapeToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatcher = export const shapeToPlainTextAdapterMatcher =
{ ElementToPlainTextAdapterExtension({
name: 'shape', name: 'shape',
match: elementModel => elementModel.type === 'shape', match: elementModel => elementModel.type === 'shape',
toAST: (elementModel, context) => { toAST: (elementModel, context) => {
@@ -31,4 +31,4 @@ export const shapeToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatch
content = `${shapeType}, with text label "${text}"`; content = `${shapeType}, with text label "${text}"`;
return { content }; return { content };
}, },
}; });

View File

@@ -1,7 +1,7 @@
import { getTextElementText } from '../../../utils/text.js'; import { getTextElementText } from '../../../utils/text.js';
import type { ElementModelToPlainTextAdapterMatcher } from '../type.js'; import { ElementToPlainTextAdapterExtension } from '../type.js';
export const textToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatcher = export const textToPlainTextAdapterMatcher = ElementToPlainTextAdapterExtension(
{ {
name: 'text', name: 'text',
match: elementModel => elementModel.type === 'text', match: elementModel => elementModel.type === 'text',
@@ -9,4 +9,5 @@ export const textToPlainTextAdapterMatcher: ElementModelToPlainTextAdapterMatche
const content = getTextElementText(elementModel); const content = getTextElementText(elementModel);
return { content }; return { content };
}, },
}; }
);

View File

@@ -4,15 +4,14 @@ import {
ElementModelAdapter, ElementModelAdapter,
type ElementModelAdapterContext, type ElementModelAdapterContext,
} from '../../type.js'; } from '../../type.js';
import { elementModelToPlainTextAdapterMatchers } from './elements/index.js'; import type { ElementToPlainTextAdapterMatcher } from './type.js';
import type { ElementModelToPlainTextAdapterMatcher } from './type.js';
export class PlainTextElementModelAdapter extends ElementModelAdapter< export class PlainTextElementModelAdapter extends ElementModelAdapter<
string, string,
TextBuffer TextBuffer
> { > {
constructor( constructor(
readonly elementModelMatchers: ElementModelToPlainTextAdapterMatcher[] = elementModelToPlainTextAdapterMatchers readonly elementModelMatchers: ElementToPlainTextAdapterMatcher[]
) { ) {
super(); super();
} }

View File

@@ -1,6 +1,29 @@
import type { TextBuffer } from '@blocksuite/affine-shared/adapters'; import type { TextBuffer } from '@blocksuite/affine-shared/adapters';
import type { ExtensionType } from '@blocksuite/block-std';
import {
createIdentifier,
type ServiceIdentifier,
} from '@blocksuite/global/di';
import type { ElementModelMatcher } from '../../type.js'; import type { ElementModelMatcher } from '../../type.js';
export type ElementModelToPlainTextAdapterMatcher = export type ElementToPlainTextAdapterMatcher = ElementModelMatcher<TextBuffer>;
ElementModelMatcher<TextBuffer>;
export const ElementToPlainTextAdapterMatcherIdentifier =
createIdentifier<ElementToPlainTextAdapterMatcher>(
'elementToPlainTextAdapterMatcher'
);
export function ElementToPlainTextAdapterExtension(
matcher: ElementToPlainTextAdapterMatcher
): ExtensionType & {
identifier: ServiceIdentifier<ElementToPlainTextAdapterMatcher>;
} {
const identifier = ElementToPlainTextAdapterMatcherIdentifier(matcher.name);
return {
setup: di => {
di.addImpl(identifier, () => matcher);
},
identifier,
};
}

View File

@@ -5,6 +5,7 @@ import {
import { getMindMapNodeMap } from '../utils/mindmap.js'; import { getMindMapNodeMap } from '../utils/mindmap.js';
import { PlainTextElementModelAdapter } from './element-adapter/index.js'; import { PlainTextElementModelAdapter } from './element-adapter/index.js';
import { ElementToPlainTextAdapterMatcherIdentifier } from './element-adapter/type.js';
export const surfaceBlockPlainTextAdapterMatcher: BlockPlainTextAdapterMatcher = export const surfaceBlockPlainTextAdapterMatcher: BlockPlainTextAdapterMatcher =
{ {
@@ -30,8 +31,18 @@ export const edgelessSurfaceBlockPlainTextAdapterMatcher: BlockPlainTextAdapterM
toBlockSnapshot: {}, toBlockSnapshot: {},
fromBlockSnapshot: { fromBlockSnapshot: {
enter: (o, context) => { enter: (o, context) => {
const { walkerContext } = context; const { walkerContext, provider } = context;
const plainTextElementModelAdapter = new PlainTextElementModelAdapter(); if (!provider) {
context.walkerContext.skipAllChildren();
return;
}
const elementModelMatchers = Array.from(
provider.getAll(ElementToPlainTextAdapterMatcherIdentifier).values()
);
const plainTextElementModelAdapter = new PlainTextElementModelAdapter(
elementModelMatchers
);
if ('elements' in o.node.props) { if ('elements' in o.node.props) {
const elements = o.node.props.elements as Record< const elements = o.node.props.elements as Record<
string, string,

View File

@@ -44,6 +44,10 @@ import {
isSameFontFamily, isSameFontFamily,
wrapFontFamily, wrapFontFamily,
} from './utils/font.js'; } from './utils/font.js';
export {
EdgelessSurfaceBlockAdapterExtensions,
SurfaceBlockAdapterExtensions,
} from './adapters/index.js';
export type { SurfaceContext } from './surface-block.js'; export type { SurfaceContext } from './surface-block.js';
export { SurfaceBlockComponent } from './surface-block.js'; export { SurfaceBlockComponent } from './surface-block.js';
export { SurfaceBlockModel, SurfaceBlockSchema } from './surface-model.js'; export { SurfaceBlockModel, SurfaceBlockSchema } from './surface-model.js';

View File

@@ -42,9 +42,13 @@ export {
BlockPlainTextAdapterExtension, BlockPlainTextAdapterExtension,
type BlockPlainTextAdapterMatcher, type BlockPlainTextAdapterMatcher,
BlockPlainTextAdapterMatcherIdentifier, BlockPlainTextAdapterMatcherIdentifier,
InlineDeltaToPlainTextAdapterExtension,
type InlineDeltaToPlainTextAdapterMatcher, type InlineDeltaToPlainTextAdapterMatcher,
InlineDeltaToPlainTextAdapterMatcherIdentifier, InlineDeltaToPlainTextAdapterMatcherIdentifier,
type PlainText, type PlainText,
PlainTextAdapter,
PlainTextAdapterFactoryExtension,
PlainTextAdapterFactoryIdentifier,
PlainTextDeltaConverter, PlainTextDeltaConverter,
} from './plain-text'; } from './plain-text';
export { export {

View File

@@ -1,4 +1,8 @@
import { createIdentifier } from '@blocksuite/global/di'; import type { ExtensionType } from '@blocksuite/block-std';
import {
createIdentifier,
type ServiceIdentifier,
} from '@blocksuite/global/di';
import type { DeltaInsert } from '@blocksuite/inline'; import type { DeltaInsert } from '@blocksuite/inline';
import type { AffineTextAttributes } from '../../types/index.js'; import type { AffineTextAttributes } from '../../types/index.js';
@@ -17,6 +21,22 @@ export const InlineDeltaToPlainTextAdapterMatcherIdentifier =
'InlineDeltaToPlainTextAdapterMatcher' 'InlineDeltaToPlainTextAdapterMatcher'
); );
export function InlineDeltaToPlainTextAdapterExtension(
matcher: InlineDeltaToPlainTextAdapterMatcher
): ExtensionType & {
identifier: ServiceIdentifier<InlineDeltaToPlainTextAdapterMatcher>;
} {
const identifier = InlineDeltaToPlainTextAdapterMatcherIdentifier(
matcher.name
);
return {
setup: di => {
di.addImpl(identifier, () => matcher);
},
identifier,
};
}
export type PlainTextASTToDeltaMatcher = ASTToDeltaMatcher<string>; export type PlainTextASTToDeltaMatcher = ASTToDeltaMatcher<string>;
export class PlainTextDeltaConverter extends DeltaASTConverter< export class PlainTextDeltaConverter extends DeltaASTConverter<

View File

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

View File

@@ -2,16 +2,8 @@ import {
DEFAULT_NOTE_BACKGROUND_COLOR, DEFAULT_NOTE_BACKGROUND_COLOR,
NoteDisplayMode, NoteDisplayMode,
} from '@blocksuite/affine-model'; } from '@blocksuite/affine-model';
import {
type AdapterContext,
AdapterFactoryIdentifier,
type BlockPlainTextAdapterMatcher,
BlockPlainTextAdapterMatcherIdentifier,
type PlainText,
PlainTextDeltaConverter,
type TextBuffer,
} 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,
@@ -32,8 +24,21 @@ import {
type ToDocSnapshotPayload, type ToDocSnapshotPayload,
} from '@blocksuite/store'; } from '@blocksuite/store';
import { defaultBlockPlainTextAdapterMatchers } from './block-matcher.js'; import {
import { inlineDeltaToPlainTextAdapterMatchers } from './delta-converter/inline-delta.js'; type AdapterContext,
AdapterFactoryIdentifier,
type TextBuffer,
} from '../types';
import {
type BlockPlainTextAdapterMatcher,
BlockPlainTextAdapterMatcherIdentifier,
} from './block-adapter';
import {
InlineDeltaToPlainTextAdapterMatcherIdentifier,
PlainTextDeltaConverter,
} from './delta-converter';
export type PlainText = string;
type PlainTextToSliceSnapshotPayload = { type PlainTextToSliceSnapshotPayload = {
file: PlainText; file: PlainText;
@@ -46,11 +51,20 @@ type PlainTextToSliceSnapshotPayload = {
export class PlainTextAdapter extends BaseAdapter<PlainText> { export class PlainTextAdapter extends BaseAdapter<PlainText> {
deltaConverter: PlainTextDeltaConverter; deltaConverter: PlainTextDeltaConverter;
readonly blockMatchers: BlockPlainTextAdapterMatcher[];
constructor( constructor(
job: Job, job: Job,
readonly blockMatchers: BlockPlainTextAdapterMatcher[] = defaultBlockPlainTextAdapterMatchers readonly provider: ServiceProvider
) { ) {
super(job); super(job);
const blockMatchers = Array.from(
provider.getAll(BlockPlainTextAdapterMatcherIdentifier).values()
);
const inlineDeltaToPlainTextAdapterMatchers = Array.from(
provider.getAll(InlineDeltaToPlainTextAdapterMatcherIdentifier).values()
);
this.blockMatchers = blockMatchers;
this.deltaConverter = new PlainTextDeltaConverter( this.deltaConverter = new PlainTextDeltaConverter(
job.adapterConfigs, job.adapterConfigs,
inlineDeltaToPlainTextAdapterMatchers, inlineDeltaToPlainTextAdapterMatchers,
@@ -78,6 +92,7 @@ export class PlainTextAdapter extends BaseAdapter<PlainText> {
configs: this.configs, configs: this.configs,
job: this.job, job: this.job,
deltaConverter: this.deltaConverter, deltaConverter: this.deltaConverter,
provider: this.provider,
textBuffer, textBuffer,
}; };
await matcher.fromBlockSnapshot.enter?.(o, adapterContext); await matcher.fromBlockSnapshot.enter?.(o, adapterContext);
@@ -93,6 +108,7 @@ export class PlainTextAdapter extends BaseAdapter<PlainText> {
configs: this.configs, configs: this.configs,
job: this.job, job: this.job,
deltaConverter: this.deltaConverter, deltaConverter: this.deltaConverter,
provider: this.provider,
textBuffer, textBuffer,
}; };
await matcher.fromBlockSnapshot.leave?.(o, adapterContext); await matcher.fromBlockSnapshot.leave?.(o, adapterContext);
@@ -309,13 +325,7 @@ export const PlainTextAdapterFactoryIdentifier =
export const PlainTextAdapterFactoryExtension: ExtensionType = { export const PlainTextAdapterFactoryExtension: ExtensionType = {
setup: di => { setup: di => {
di.addImpl(PlainTextAdapterFactoryIdentifier, provider => ({ di.addImpl(PlainTextAdapterFactoryIdentifier, provider => ({
get: (job: Job) => get: (job: Job) => new PlainTextAdapter(job, provider),
new PlainTextAdapter(
job,
Array.from(
provider.getAll(BlockPlainTextAdapterMatcherIdentifier).values()
)
),
})); }));
}, },
}; };

View File

@@ -1 +0,0 @@
export type PlainText = string;

View File

@@ -1,4 +1,4 @@
import { createIdentifier } from '@blocksuite/global/di'; import { createIdentifier, type ServiceProvider } from '@blocksuite/global/di';
import type { BaseTextAttributes, DeltaInsert } from '@blocksuite/inline'; import type { BaseTextAttributes, DeltaInsert } from '@blocksuite/inline';
import { import {
type AssetsManager, type AssetsManager,
@@ -38,6 +38,7 @@ export type AdapterContext<
job: Job; job: Job;
deltaConverter: TConverter; deltaConverter: TConverter;
textBuffer: TextBuffer; textBuffer: TextBuffer;
provider?: ServiceProvider;
assets?: AssetsManager; assets?: AssetsManager;
pageMap?: Map<string, string>; pageMap?: Map<string, string>;
updateAssetIds?: (assetsId: string) => void; updateAssetIds?: (assetsId: string) => void;

View File

@@ -2,6 +2,8 @@ import {
DEFAULT_NOTE_BACKGROUND_COLOR, DEFAULT_NOTE_BACKGROUND_COLOR,
NoteDisplayMode, NoteDisplayMode,
} from '@blocksuite/affine-model'; } from '@blocksuite/affine-model';
import { PlainTextAdapter } from '@blocksuite/affine-shared/adapters';
import { Container } from '@blocksuite/global/di';
import type { import type {
BlockSnapshot, BlockSnapshot,
DocSnapshot, DocSnapshot,
@@ -9,10 +11,20 @@ import type {
} from '@blocksuite/store'; } from '@blocksuite/store';
import { describe, expect, test } from 'vitest'; import { describe, expect, test } from 'vitest';
import { PlainTextAdapter } from '../../_common/adapters/plain-text/plain-text.js'; import { defaultBlockPlainTextAdapterMatchers } from '../../_common/adapters/plain-text/block-matcher.js';
import { inlineDeltaToPlainTextAdapterMatchers } from '../../_common/adapters/plain-text/delta-converter/inline-delta.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();
[
...defaultBlockPlainTextAdapterMatchers,
...inlineDeltaToPlainTextAdapterMatchers,
].forEach(ext => {
ext.setup(container);
});
const provider = container.provider();
describe('snapshot to plain text', () => { describe('snapshot to plain text', () => {
test('paragraph', async () => { test('paragraph', async () => {
const blockSnapshot: BlockSnapshot = { const blockSnapshot: BlockSnapshot = {
@@ -157,7 +169,7 @@ describe('snapshot to plain text', () => {
}; };
const plainText = 'aaabbbccc\nddd\neee\nfff\nggg\n'; const plainText = 'aaabbbccc\nddd\neee\nfff\nggg\n';
const plainTextAdapter = new PlainTextAdapter(createJob()); const plainTextAdapter = new PlainTextAdapter(createJob(), provider);
const target = await plainTextAdapter.fromBlockSnapshot({ const target = await plainTextAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -316,7 +328,7 @@ describe('snapshot to plain text', () => {
const plainText = 'aaa\nbbb\nccc\nddd\neee\n'; const plainText = 'aaa\nbbb\nccc\nddd\neee\n';
const plainTextAdapter = new PlainTextAdapter(createJob()); const plainTextAdapter = new PlainTextAdapter(createJob(), provider);
const target = await plainTextAdapter.fromBlockSnapshot({ const target = await plainTextAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -386,7 +398,7 @@ describe('snapshot to plain text', () => {
}; };
const plainText = 'aaa\n---\n'; const plainText = 'aaa\n---\n';
const plainTextAdapter = new PlainTextAdapter(createJob()); const plainTextAdapter = new PlainTextAdapter(createJob(), provider);
const target = await plainTextAdapter.fromBlockSnapshot({ const target = await plainTextAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -449,7 +461,7 @@ describe('snapshot to plain text', () => {
}; };
const plainText = 'import this\n'; const plainText = 'import this\n';
const plainTextAdapter = new PlainTextAdapter(createJob()); const plainTextAdapter = new PlainTextAdapter(createJob(), provider);
const target = await plainTextAdapter.fromBlockSnapshot({ const target = await plainTextAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -568,7 +580,10 @@ describe('snapshot to plain text', () => {
adapterConfigs.set('title:deadbeef', 'test'); adapterConfigs.set('title:deadbeef', 'test');
adapterConfigs.set('docLinkBaseUrl', 'https://example.com'); adapterConfigs.set('docLinkBaseUrl', 'https://example.com');
}; };
const plainTextAdapter = new PlainTextAdapter(createJob([middleware])); const plainTextAdapter = new PlainTextAdapter(
createJob([middleware]),
provider
);
const plainText = const plainText =
'aaa: https://affine.pro/\ntest: https://example.com/deadbeef?mode=page&blockIds=abc%2C123&elementIds=def%2C456&databaseId=deadbeef&databaseRowId=123\nE=mc^2\n'; 'aaa: https://affine.pro/\ntest: https://example.com/deadbeef?mode=page&blockIds=abc%2C123&elementIds=def%2C456&databaseId=deadbeef&databaseRowId=123\nE=mc^2\n';
@@ -670,7 +685,7 @@ describe('snapshot to plain text', () => {
], ],
}; };
const plainTextAdapter = new PlainTextAdapter(createJob()); const plainTextAdapter = new PlainTextAdapter(createJob(), provider);
const target = await plainTextAdapter.fromBlockSnapshot({ const target = await plainTextAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -750,7 +765,10 @@ describe('snapshot to plain text', () => {
}; };
const plainText = const plainText =
'test: https://example.com/4T5ObMgEIMII-4Bexyta1?mode=page&blockIds=abc%2C123&elementIds=def%2C456&databaseId=deadbeef&databaseRowId=123\n'; 'test: https://example.com/4T5ObMgEIMII-4Bexyta1?mode=page&blockIds=abc%2C123&elementIds=def%2C456&databaseId=deadbeef&databaseRowId=123\n';
const plainTextAdapter = new PlainTextAdapter(createJob([middleware])); const plainTextAdapter = new PlainTextAdapter(
createJob([middleware]),
provider
);
const target = await plainTextAdapter.fromBlockSnapshot({ const target = await plainTextAdapter.fromBlockSnapshot({
snapshot: blockSnapShot, snapshot: blockSnapShot,
}); });
@@ -1146,7 +1164,7 @@ describe('snapshot to plain text', () => {
await job.snapshotToDoc(syncedDocSnapshot); await job.snapshotToDoc(syncedDocSnapshot);
await job.snapshotToDoc(docSnapShot); await job.snapshotToDoc(docSnapShot);
const mdAdapter = new PlainTextAdapter(job); const mdAdapter = new PlainTextAdapter(job, provider);
const target = await mdAdapter.fromDocSnapshot({ const target = await mdAdapter.fromDocSnapshot({
snapshot: docSnapShot, snapshot: docSnapShot,
}); });
@@ -1180,7 +1198,7 @@ describe('snapshot to plain text', () => {
}; };
const plainText = 'LaTex, with value: E=mc^2\n'; const plainText = 'LaTex, with value: E=mc^2\n';
const plainTextAdapter = new PlainTextAdapter(createJob()); const plainTextAdapter = new PlainTextAdapter(createJob(), provider);
const target = await plainTextAdapter.fromBlockSnapshot({ const target = await plainTextAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });
@@ -1405,7 +1423,7 @@ describe('snapshot to plain text', () => {
| 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 plainTextAdapter = new PlainTextAdapter(createJob()); const plainTextAdapter = new PlainTextAdapter(createJob(), provider);
const target = await plainTextAdapter.fromBlockSnapshot({ const target = await plainTextAdapter.fromBlockSnapshot({
snapshot: blockSnapshot, snapshot: blockSnapshot,
}); });

View File

@@ -1,4 +1,7 @@
import { HtmlAdapterFactoryExtension } from '@blocksuite/affine-shared/adapters'; import {
HtmlAdapterFactoryExtension,
PlainTextAdapterFactoryExtension,
} from '@blocksuite/affine-shared/adapters';
import type { ExtensionType } from '@blocksuite/block-std'; import type { ExtensionType } from '@blocksuite/block-std';
import { AttachmentAdapterFactoryExtension } from './attachment.js'; import { AttachmentAdapterFactoryExtension } from './attachment.js';
@@ -10,12 +13,13 @@ 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 { 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 { inlineDeltaToPlainTextAdapterMatchers } from './plain-text/delta-converter/inline-delta.js';
export const AdapterFactoryExtensions: ExtensionType[] = [ export const AdapterFactoryExtensions: ExtensionType[] = [
...htmlInlineToDeltaMatchers, ...htmlInlineToDeltaMatchers,
...inlineDeltaToHtmlAdapterMatchers, ...inlineDeltaToHtmlAdapterMatchers,
...notionHtmlInlineToDeltaMatchers, ...notionHtmlInlineToDeltaMatchers,
...inlineDeltaToPlainTextAdapterMatchers,
AttachmentAdapterFactoryExtension, AttachmentAdapterFactoryExtension,
ImageAdapterFactoryExtension, ImageAdapterFactoryExtension,
MarkdownAdapterFactoryExtension, MarkdownAdapterFactoryExtension,

View File

@@ -5,4 +5,3 @@ export * from './markdown/index.js';
export * from './mix-text.js'; export * from './mix-text.js';
export * from './notion-html/index.js'; export * from './notion-html/index.js';
export * from './notion-text.js'; export * from './notion-text.js';
export * from './plain-text/plain-text.js';

View File

@@ -1,34 +1,33 @@
import { bookmarkBlockPlainTextAdapterMatcher } from '@blocksuite/affine-block-bookmark'; import { BookmarkBlockPlainTextAdapterExtension } from '@blocksuite/affine-block-bookmark';
import { import {
embedFigmaBlockPlainTextAdapterMatcher, EmbedFigmaBlockPlainTextAdapterExtension,
embedGithubBlockPlainTextAdapterMatcher, EmbedGithubBlockPlainTextAdapterExtension,
embedLinkedDocBlockPlainTextAdapterMatcher, EmbedLinkedDocBlockPlainTextAdapterExtension,
embedLoomBlockPlainTextAdapterMatcher, EmbedLoomBlockPlainTextAdapterExtension,
embedSyncedDocBlockPlainTextAdapterMatcher, EmbedSyncedDocBlockPlainTextAdapterExtension,
embedYoutubeBlockPlainTextAdapterMatcher, EmbedYoutubeBlockPlainTextAdapterExtension,
} from '@blocksuite/affine-block-embed'; } from '@blocksuite/affine-block-embed';
import { latexBlockPlainTextAdapterMatcher } from '@blocksuite/affine-block-latex'; import { LatexBlockPlainTextAdapterExtension } from '@blocksuite/affine-block-latex';
import { listBlockPlainTextAdapterMatcher } from '@blocksuite/affine-block-list'; import { ListBlockPlainTextAdapterExtension } from '@blocksuite/affine-block-list';
import { paragraphBlockPlainTextAdapterMatcher } from '@blocksuite/affine-block-paragraph'; import { ParagraphBlockPlainTextAdapterExtension } from '@blocksuite/affine-block-paragraph';
import type { BlockPlainTextAdapterMatcher } from '@blocksuite/affine-shared/adapters'; import type { ExtensionType } from '@blocksuite/block-std';
import { codeBlockPlainTextAdapterMatcher } from '../../../code-block/adapters/plain-text.js'; import { CodeBlockPlainTextAdapterExtension } from '../../../code-block/adapters/plain-text.js';
import { databaseBlockPlainTextAdapterMatcher } from '../../../database-block/adapters/plain-text.js'; import { DatabaseBlockPlainTextAdapterExtension } from '../../../database-block/adapters/plain-text.js';
import { dividerBlockPlainTextAdapterMatcher } from '../../../divider-block/adapters/plain-text.js'; import { DividerBlockPlainTextAdapterExtension } from '../../../divider-block/adapters/plain-text.js';
export const defaultBlockPlainTextAdapterMatchers: BlockPlainTextAdapterMatcher[] = export const defaultBlockPlainTextAdapterMatchers: ExtensionType[] = [
[ ParagraphBlockPlainTextAdapterExtension,
paragraphBlockPlainTextAdapterMatcher, ListBlockPlainTextAdapterExtension,
listBlockPlainTextAdapterMatcher, DividerBlockPlainTextAdapterExtension,
dividerBlockPlainTextAdapterMatcher, CodeBlockPlainTextAdapterExtension,
codeBlockPlainTextAdapterMatcher, BookmarkBlockPlainTextAdapterExtension,
bookmarkBlockPlainTextAdapterMatcher, EmbedFigmaBlockPlainTextAdapterExtension,
embedFigmaBlockPlainTextAdapterMatcher, EmbedGithubBlockPlainTextAdapterExtension,
embedGithubBlockPlainTextAdapterMatcher, EmbedLoomBlockPlainTextAdapterExtension,
embedLoomBlockPlainTextAdapterMatcher, EmbedYoutubeBlockPlainTextAdapterExtension,
embedYoutubeBlockPlainTextAdapterMatcher, EmbedLinkedDocBlockPlainTextAdapterExtension,
embedLinkedDocBlockPlainTextAdapterMatcher, EmbedSyncedDocBlockPlainTextAdapterExtension,
embedSyncedDocBlockPlainTextAdapterMatcher, LatexBlockPlainTextAdapterExtension,
latexBlockPlainTextAdapterMatcher, DatabaseBlockPlainTextAdapterExtension,
databaseBlockPlainTextAdapterMatcher, ];
];

View File

@@ -1,11 +1,12 @@
import { generateDocUrl } from '@blocksuite/affine-block-embed'; import { generateDocUrl } from '@blocksuite/affine-block-embed';
import type { import {
InlineDeltaToPlainTextAdapterMatcher, InlineDeltaToPlainTextAdapterExtension,
TextBuffer, type TextBuffer,
} from '@blocksuite/affine-shared/adapters'; } from '@blocksuite/affine-shared/adapters';
import type { ExtensionType } from '@blocksuite/block-std';
export const referenceDeltaMarkdownAdapterMatch: InlineDeltaToPlainTextAdapterMatcher = export const referenceDeltaMarkdownAdapterMatch =
{ InlineDeltaToPlainTextAdapterExtension({
name: 'reference', name: 'reference',
match: delta => !!delta.attributes?.reference, match: delta => !!delta.attributes?.reference,
toAST: (delta, context) => { toAST: (delta, context) => {
@@ -30,10 +31,10 @@ export const referenceDeltaMarkdownAdapterMatch: InlineDeltaToPlainTextAdapterMa
content, content,
}; };
}, },
}; });
export const linkDeltaMarkdownAdapterMatch: InlineDeltaToPlainTextAdapterMatcher = export const linkDeltaMarkdownAdapterMatch =
{ InlineDeltaToPlainTextAdapterExtension({
name: 'link', name: 'link',
match: delta => !!delta.attributes?.link, match: delta => !!delta.attributes?.link,
toAST: delta => { toAST: delta => {
@@ -51,10 +52,10 @@ export const linkDeltaMarkdownAdapterMatch: InlineDeltaToPlainTextAdapterMatcher
content, content,
}; };
}, },
}; });
export const latexDeltaMarkdownAdapterMatch: InlineDeltaToPlainTextAdapterMatcher = export const latexDeltaMarkdownAdapterMatch =
{ InlineDeltaToPlainTextAdapterExtension({
name: 'inlineLatex', name: 'inlineLatex',
match: delta => !!delta.attributes?.latex, match: delta => !!delta.attributes?.latex,
toAST: delta => { toAST: delta => {
@@ -68,11 +69,10 @@ export const latexDeltaMarkdownAdapterMatch: InlineDeltaToPlainTextAdapterMatche
content: delta.attributes?.latex, content: delta.attributes?.latex,
}; };
}, },
}; });
export const inlineDeltaToPlainTextAdapterMatchers: InlineDeltaToPlainTextAdapterMatcher[] = export const inlineDeltaToPlainTextAdapterMatchers: ExtensionType[] = [
[ referenceDeltaMarkdownAdapterMatch,
referenceDeltaMarkdownAdapterMatch, linkDeltaMarkdownAdapterMatch,
linkDeltaMarkdownAdapterMatch, latexDeltaMarkdownAdapterMatch,
latexDeltaMarkdownAdapterMatch, ];
];

View File

@@ -1,4 +1,7 @@
import { HtmlAdapter } from '@blocksuite/affine-shared/adapters'; import {
HtmlAdapter,
PlainTextAdapter,
} from '@blocksuite/affine-shared/adapters';
import { import {
type BlockComponent, type BlockComponent,
Clipboard, Clipboard,
@@ -6,7 +9,6 @@ import {
} from '@blocksuite/block-std'; } from '@blocksuite/block-std';
import { assertExists, DisposableGroup } from '@blocksuite/global/utils'; import { assertExists, DisposableGroup } from '@blocksuite/global/utils';
import { PlainTextAdapter } from '../../_common/adapters/index.js';
import { pasteMiddleware } from '../../root-block/clipboard/middlewares/index.js'; import { pasteMiddleware } from '../../root-block/clipboard/middlewares/index.js';
export class CodeClipboardController { export class CodeClipboardController {

View File

@@ -103,6 +103,9 @@ export {
HtmlAdapter, HtmlAdapter,
HtmlAdapterFactoryExtension, HtmlAdapterFactoryExtension,
HtmlAdapterFactoryIdentifier, HtmlAdapterFactoryIdentifier,
PlainTextAdapter,
PlainTextAdapterFactoryExtension,
PlainTextAdapterFactoryIdentifier,
} from '@blocksuite/affine-shared/adapters'; } from '@blocksuite/affine-shared/adapters';
export * from '@blocksuite/affine-shared/services'; export * from '@blocksuite/affine-shared/services';
export { scrollbarStyle } from '@blocksuite/affine-shared/styles'; export { scrollbarStyle } from '@blocksuite/affine-shared/styles';

View File

@@ -86,7 +86,9 @@ export async function getContentFromSlice(
} }
processTextInSnapshot(snapshot, host); processTextInSnapshot(snapshot, host);
const adapter = const adapter =
type === 'markdown' ? new MarkdownAdapter(job) : new PlainTextAdapter(job); type === 'markdown'
? new MarkdownAdapter(job)
: new PlainTextAdapter(job, host.std.provider);
const content = await adapter.fromSliceSnapshot({ const content = await adapter.fromSliceSnapshot({
snapshot, snapshot,
assets: job.assetsManager, assets: job.assetsManager,
@@ -104,7 +106,7 @@ export async function getPlainTextFromSlice(host: EditorHost, slice: Slice) {
return ''; return '';
} }
processTextInSnapshot(snapshot, host); processTextInSnapshot(snapshot, host);
const plainTextAdapter = new PlainTextAdapter(job); const plainTextAdapter = new PlainTextAdapter(job, host.std.provider);
const plainText = await plainTextAdapter.fromSliceSnapshot({ const plainText = await plainTextAdapter.fromSliceSnapshot({
snapshot, snapshot,
assets: job.assetsManager, assets: job.assetsManager,