Skip to content

Commit

Permalink
refactor: migrate plain text adapter to extension (#8831)
Browse files Browse the repository at this point in the history
[BS-1855](https://linear.app/affine-design/issue/BS-1855/migrate-plain-text-adapter)

- [x] Migrate PlainTextAdapter to extension
- [x] Handle inline delta: reference, link, inline code
- [x] Add unit test
  • Loading branch information
donteatfriedrice committed Dec 3, 2024
1 parent 441c677 commit 6e0bc08
Show file tree
Hide file tree
Showing 23 changed files with 1,032 additions and 39 deletions.
2 changes: 2 additions & 0 deletions packages/affine/block-list/src/adapters/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './markdown.js';
export * from './plain-text.js';
28 changes: 28 additions & 0 deletions packages/affine/block-list/src/adapters/plain-text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { DeltaInsert } from '@blocksuite/inline';

import { ListBlockSchema } from '@blocksuite/affine-model';
import {
BlockPlainTextAdapterExtension,
type BlockPlainTextAdapterMatcher,
} from '@blocksuite/affine-shared/adapters';

export const listBlockPlainTextAdapterMatcher: BlockPlainTextAdapterMatcher = {
flavour: ListBlockSchema.model.flavour,
toMatch: () => false,
fromMatch: o => o.node.flavour === ListBlockSchema.model.flavour,
toBlockSnapshot: {},
fromBlockSnapshot: {
enter: (o, context) => {
const text = (o.node.props.text ?? { delta: [] }) as {
delta: DeltaInsert[];
};
const { deltaConverter } = context;
const buffer = deltaConverter.deltaToAST(text.delta).join('');
context.textBuffer.content += buffer;
context.textBuffer.content += '\n';
},
},
};

export const ListBlockPlainTextAdapterExtension =
BlockPlainTextAdapterExtension(listBlockPlainTextAdapterMatcher);
2 changes: 1 addition & 1 deletion packages/affine/block-list/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './adapters/markdown.js';
export * from './adapters/index.js';
export * from './list-block.js';
export * from './list-service.js';
export * from './list-spec.js';
2 changes: 2 additions & 0 deletions packages/affine/block-paragraph/src/adapters/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './markdown.js';
export * from './plain-text.js';
29 changes: 29 additions & 0 deletions packages/affine/block-paragraph/src/adapters/plain-text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { DeltaInsert } from '@blocksuite/inline';

import { ParagraphBlockSchema } from '@blocksuite/affine-model';
import {
BlockPlainTextAdapterExtension,
type BlockPlainTextAdapterMatcher,
} from '@blocksuite/affine-shared/adapters';

export const paragraphBlockPlainTextAdapterMatcher: BlockPlainTextAdapterMatcher =
{
flavour: ParagraphBlockSchema.model.flavour,
toMatch: () => false,
fromMatch: o => o.node.flavour === ParagraphBlockSchema.model.flavour,
toBlockSnapshot: {},
fromBlockSnapshot: {
enter: (o, context) => {
const text = (o.node.props.text ?? { delta: [] }) as {
delta: DeltaInsert[];
};
const { deltaConverter } = context;
const buffer = deltaConverter.deltaToAST(text.delta).join('');
context.textBuffer.content += buffer;
context.textBuffer.content += '\n';
},
},
};

export const ParagraphBlockPlainTextAdapterExtension =
BlockPlainTextAdapterExtension(paragraphBlockPlainTextAdapterMatcher);
2 changes: 1 addition & 1 deletion packages/affine/block-paragraph/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './adapters/markdown.js';
export * from './adapters/index.js';
export * from './paragraph-block.js';
export * from './paragraph-service.js';
export * from './paragraph-spec.js';
11 changes: 11 additions & 0 deletions packages/affine/shared/src/adapters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,22 @@ export {
type MarkdownASTToDeltaMatcher,
MarkdownASTToDeltaMatcherIdentifier,
} from './markdown/index.js';
export * from './plain-text/index.js';
export {
BlockPlainTextAdapterExtension,
type BlockPlainTextAdapterMatcher,
BlockPlainTextAdapterMatcherIdentifier,
type InlineDeltaToPlainTextAdapterMatcher,
InlineDeltaToPlainTextAdapterMatcherIdentifier,
type PlainText,
PlainTextDeltaConverter,
} from './plain-text/index.js';
export {
type AdapterContext,
type BlockAdapterMatcher,
DeltaASTConverter,
isBlockSnapshotNode,
type TextBuffer,
} from './type.js';
export {
createText,
Expand Down
29 changes: 29 additions & 0 deletions packages/affine/shared/src/adapters/plain-text/block-adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { ExtensionType } from '@blocksuite/block-std';

import {
createIdentifier,
type ServiceIdentifier,
} from '@blocksuite/global/di';

import type { BlockAdapterMatcher } from '../type.js';

export type BlockPlainTextAdapterMatcher = BlockAdapterMatcher;

export const BlockPlainTextAdapterMatcherIdentifier =
createIdentifier<BlockPlainTextAdapterMatcher>(
'BlockPlainTextAdapterMatcher'
);

export function BlockPlainTextAdapterExtension(
matcher: BlockPlainTextAdapterMatcher
): ExtensionType & {
identifier: ServiceIdentifier<BlockPlainTextAdapterMatcher>;
} {
const identifier = BlockPlainTextAdapterMatcherIdentifier(matcher.flavour);
return {
setup: di => {
di.addImpl(identifier, () => matcher);
},
identifier,
};
}
63 changes: 63 additions & 0 deletions packages/affine/shared/src/adapters/plain-text/delta-converter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { DeltaInsert } from '@blocksuite/inline';

import { createIdentifier } from '@blocksuite/global/di';

import type { AffineTextAttributes } from '../../types/index.js';

import {
type ASTToDeltaMatcher,
DeltaASTConverter,
type InlineDeltaMatcher,
type TextBuffer,
} from '../type.js';

export type InlineDeltaToPlainTextAdapterMatcher =
InlineDeltaMatcher<TextBuffer>;

export const InlineDeltaToPlainTextAdapterMatcherIdentifier =
createIdentifier<InlineDeltaToPlainTextAdapterMatcher>(
'InlineDeltaToPlainTextAdapterMatcher'
);

export type PlainTextASTToDeltaMatcher = ASTToDeltaMatcher<string>;

export class PlainTextDeltaConverter extends DeltaASTConverter<
AffineTextAttributes,
string
> {
constructor(
readonly configs: Map<string, string>,
readonly inlineDeltaMatchers: InlineDeltaToPlainTextAdapterMatcher[],
readonly plainTextASTToDeltaMatchers: PlainTextASTToDeltaMatcher[]
) {
super();
}

astToDelta(ast: string) {
const context = {
configs: this.configs,
toDelta: (ast: string) => this.astToDelta(ast),
};
for (const matcher of this.plainTextASTToDeltaMatchers) {
if (matcher.match(ast)) {
return matcher.toDelta(ast, context);
}
}
return [];
}

deltaToAST(deltas: DeltaInsert<AffineTextAttributes>[]): string[] {
return deltas.map(delta => {
const context = {
configs: this.configs,
current: { content: delta.insert },
};
for (const matcher of this.inlineDeltaMatchers) {
if (matcher.match(delta)) {
context.current = matcher.toAST(delta, context);
}
}
return context.current.content;
});
}
}
3 changes: 3 additions & 0 deletions packages/affine/shared/src/adapters/plain-text/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './block-adapter.js';
export * from './delta-converter.js';
export * from './type.js';
1 change: 1 addition & 0 deletions packages/affine/shared/src/adapters/plain-text/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type PlainText = string;
15 changes: 10 additions & 5 deletions packages/affine/shared/src/adapters/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,21 @@ import type { AffineTextAttributes } from '../types/index.js';
export const isBlockSnapshotNode = (node: unknown): node is BlockSnapshot =>
BlockSnapshotSchema.safeParse(node).success;

export type TextBuffer = {
content: string;
};

export type AdapterContext<
ONode extends object,
TNode extends object,
TConverter extends DeltaASTConverter,
TNode extends object = never,
TConverter extends DeltaASTConverter = DeltaASTConverter,
> = {
walker: ASTWalker<ONode, TNode>;
walkerContext: ASTWalkerContext<TNode>;
configs: Map<string, string>;
job: Job;
deltaConverter: TConverter;
textBuffer: TextBuffer;
assets?: AssetsManager;
updateAssetIds?: (assetsId: string) => void;
};
Expand All @@ -37,8 +42,8 @@ export type AdapterContext<
* @template TConverter - The converter used for handling delta format conversions
*/
export type BlockAdapterMatcher<
TNode extends object,
TConverter extends DeltaASTConverter,
TNode extends object = never,
TConverter extends DeltaASTConverter = DeltaASTConverter,
> = {
/** The block flavour identifier */
flavour: string;
Expand Down Expand Up @@ -126,7 +131,7 @@ export abstract class DeltaASTConverter<
): AST[];
}

export type InlineDeltaMatcher<TNode extends object> = {
export type InlineDeltaMatcher<TNode extends object = never> = {
name: keyof AffineTextAttributes | string;
match: (delta: DeltaInsert<AffineTextAttributes>) => boolean;
toAST: (
Expand Down
Loading

0 comments on commit 6e0bc08

Please sign in to comment.