feat: misc optimizations (#14257)

fix #13798
This commit is contained in:
DarkSky
2026-01-15 03:47:22 +08:00
committed by GitHub
parent 76e1721d70
commit ac7a95e708
6 changed files with 424 additions and 76 deletions

View File

@@ -2,7 +2,13 @@ import { readFileSync } from 'node:fs';
import path from 'node:path';
import { expect, test } from 'vitest';
import { applyUpdate, Array as YArray, Doc as YDoc, Map as YMap } from 'yjs';
import {
applyUpdate,
Array as YArray,
Doc as YDoc,
Map as YMap,
Text as YText,
} from 'yjs';
import {
parsePageDoc,
@@ -160,3 +166,79 @@ test('should parse page full doc work with ai editable', () => {
expect(result.md).toMatchSnapshot();
});
test('should index references from database rich-text cells', async () => {
const doc = new YDoc({
guid: 'db-doc',
});
const blocks = doc.getMap('blocks');
const pageTitle = new YText();
pageTitle.insert(0, 'Page');
const page = new YMap();
page.set('sys:id', 'page');
page.set('sys:flavour', 'affine:page');
page.set('sys:children', YArray.from(['note']));
page.set('prop:title', pageTitle);
blocks.set('page', page);
const note = new YMap();
note.set('sys:id', 'note');
note.set('sys:flavour', 'affine:note');
note.set('sys:children', YArray.from(['db']));
note.set('prop:displayMode', 'page');
blocks.set('note', note);
const dbTitle = new YText();
dbTitle.insert(0, 'Database');
const db = new YMap();
db.set('sys:id', 'db');
db.set('sys:flavour', 'affine:database');
db.set('sys:children', new YArray());
db.set('prop:title', dbTitle);
const columns = new YArray();
const column = new YMap();
column.set('id', 'col1');
column.set('name', 'Text');
column.set('type', 'rich-text');
column.set('data', new YMap());
columns.push([column]);
db.set('prop:columns', columns);
const cellText = new YText();
cellText.applyDelta([
{ insert: 'See ' },
{
insert: 'Target',
attributes: {
reference: {
pageId: 'target-doc',
params: { mode: 'page' },
},
},
},
]);
const cell = new YMap();
cell.set('columnId', 'col1');
cell.set('value', cellText);
const row = new YMap();
row.set('col1', cell);
const cells = new YMap();
cells.set('row1', row);
db.set('prop:cells', cells);
blocks.set('db', db);
const result = await readAllBlocksFromDoc({
ydoc: doc,
spaceId: 'test-space',
});
const dbBlock = result?.blocks.find(block => block.blockId === 'db');
expect(dbBlock?.refDocId).toEqual(['target-doc']);
expect(dbBlock?.ref).toEqual([
JSON.stringify({ docId: 'target-doc', mode: 'page' }),
]);
});

View File

@@ -18,7 +18,7 @@ import {
type TransformerMiddleware,
type YBlock,
} from '@blocksuite/affine/store';
import { uniq } from 'lodash-es';
import { uniqBy } from 'lodash-es';
import {
Array as YArray,
type Doc as YDoc,
@@ -58,6 +58,81 @@ const bookmarkFlavours = new Set([
'affine:embed-loom',
]);
const collectInlineReferences = (
deltas: DeltaInsert<AffineTextAttributes>[]
): { refDocId: string; ref: string }[] =>
uniqBy(
deltas
.flatMap(delta => {
if (
delta.attributes &&
delta.attributes.reference &&
delta.attributes.reference.pageId
) {
const { pageId: refDocId, params = {} } = delta.attributes.reference;
return {
refDocId,
ref: JSON.stringify({ docId: refDocId, ...params }),
};
}
return null;
})
.filter((ref): ref is { refDocId: string; ref: string } => ref !== null),
item => item.ref
);
const getTextDeltasFromCellValue = (
value: unknown
): DeltaInsert<AffineTextAttributes>[] | null => {
if (!value) {
return null;
}
if (value instanceof YText) {
return value.toDelta() as DeltaInsert<AffineTextAttributes>[];
}
if (typeof value === 'object' && value !== null) {
const maybeText = value as { yText?: unknown };
if (maybeText.yText instanceof YText) {
return maybeText.yText.toDelta() as DeltaInsert<AffineTextAttributes>[];
}
}
if (value instanceof YMap) {
const marker = value.get('$blocksuite:internal:text$');
const delta = value.get('delta');
if (marker) {
if (delta instanceof YArray) {
return delta
.toArray()
.map(entry => (entry instanceof YMap ? entry.toJSON() : entry)) as
| DeltaInsert<AffineTextAttributes>[]
| null;
}
if (Array.isArray(delta)) {
return delta as DeltaInsert<AffineTextAttributes>[];
}
}
}
if (
typeof value === 'object' &&
value !== null &&
'$blocksuite:internal:text$' in value
) {
const delta = (value as { delta?: unknown }).delta;
if (delta instanceof YArray) {
return delta.toArray() as DeltaInsert<AffineTextAttributes>[];
}
if (Array.isArray(delta)) {
return delta as DeltaInsert<AffineTextAttributes>[];
}
}
return null;
};
function generateMarkdownPreviewBuilder(
workspaceId: string,
blocks: BlockDocumentInfo[],
@@ -587,25 +662,7 @@ export async function readAllBlocksFromDoc({
}
const deltas: DeltaInsert<AffineTextAttributes>[] = text.toDelta();
const refs = uniq(
deltas
.flatMap(delta => {
if (
delta.attributes &&
delta.attributes.reference &&
delta.attributes.reference.pageId
) {
const { pageId: refDocId, params = {} } =
delta.attributes.reference;
return {
refDocId,
ref: JSON.stringify({ docId: refDocId, ...params }),
};
}
return null;
})
.filter(ref => !!ref)
);
const refs = collectInlineReferences(deltas);
const databaseName =
flavour === 'affine:paragraph' && parentFlavour === 'affine:database' // if block is a database row
@@ -741,6 +798,29 @@ export async function readAllBlocksFromDoc({
}
}
const databaseRefs: { refDocId: string; ref: string }[] = [];
const cellsObj = block.get('prop:cells');
if (cellsObj instanceof YMap) {
for (const row of cellsObj.values()) {
if (!(row instanceof YMap)) {
continue;
}
for (const cell of row.values()) {
if (!(cell instanceof YMap)) {
continue;
}
const deltas = getTextDeltasFromCellValue(cell.get('value'));
if (!deltas?.length) {
continue;
}
const refs = collectInlineReferences(deltas);
if (refs.length) {
databaseRefs.push(...refs);
}
}
}
}
blockDocuments.push({
...commonBlockProps,
content: texts,
@@ -748,6 +828,16 @@ export async function readAllBlocksFromDoc({
...commonBlockProps.additional,
databaseName: databaseTitle?.toString(),
},
...(databaseRefs.length
? databaseRefs.reduce<{ refDocId: string[]; ref: string[] }>(
(prev, curr) => {
prev.refDocId.push(curr.refDocId);
prev.ref.push(curr.ref);
return prev;
},
{ refDocId: [], ref: [] }
)
: {}),
});
} else if (flavour === 'affine:latex') {
blockDocuments.push({