mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-02 10:10:42 +08:00
728e02cab7
#### PR Dependency Tree * **PR #14452** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved null-safety, dependency tracking, upload validation, and error logging for more reliable uploads, clipboard, calendar linking, telemetry, PDF/theme printing, and preview/zoom behavior. * Tightened handling of all-day calendar events (missing date now reported). * **Deprecations** * Removed deprecated RadioButton and RadioButtonGroup; use RadioGroup. * **Chores** * Unified and upgraded linting/config, reorganized imports, and standardized binary handling for more consistent builds and tooling. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
146 lines
3.9 KiB
TypeScript
146 lines
3.9 KiB
TypeScript
import type { Doc } from 'yjs';
|
|
import { Array as YArray, Map as YMap } from 'yjs';
|
|
|
|
import { diffKeyedRecords, type KeyedRecord } from './diff';
|
|
import { formatValue, toPlain } from './plain';
|
|
|
|
type RootDocMetaExtract = {
|
|
recordsById: Map<string, KeyedRecord>;
|
|
duplicateIds: string[];
|
|
};
|
|
|
|
export function extractRootDocPagesMeta(rootDoc: Doc): RootDocMetaExtract {
|
|
const recordsById = new Map<string, KeyedRecord>();
|
|
const duplicateIds: string[] = [];
|
|
|
|
const meta = rootDoc.getMap('meta');
|
|
const pages = meta.get('pages');
|
|
const entries =
|
|
pages instanceof YArray
|
|
? pages.toArray()
|
|
: Array.isArray(pages)
|
|
? pages
|
|
: null;
|
|
if (!entries) {
|
|
return { recordsById, duplicateIds };
|
|
}
|
|
|
|
for (const entry of entries) {
|
|
let id: string | null = null;
|
|
if (entry instanceof YMap) {
|
|
const idRaw = entry.get('id');
|
|
id =
|
|
typeof idRaw === 'string'
|
|
? idRaw
|
|
: typeof idRaw?.toString === 'function'
|
|
? idRaw.toString()
|
|
: null;
|
|
} else if (entry && typeof entry === 'object' && !Array.isArray(entry)) {
|
|
const record = entry as Record<string, unknown>;
|
|
id =
|
|
typeof record.id === 'string'
|
|
? record.id
|
|
: (record.id?.toString?.() ?? null);
|
|
}
|
|
|
|
if (!id) {
|
|
continue;
|
|
}
|
|
|
|
if (recordsById.has(id)) {
|
|
duplicateIds.push(id);
|
|
}
|
|
|
|
const metaPlain = toPlain(entry) as unknown;
|
|
if (
|
|
metaPlain &&
|
|
typeof metaPlain === 'object' &&
|
|
!Array.isArray(metaPlain)
|
|
) {
|
|
recordsById.set(id, metaPlain as KeyedRecord);
|
|
}
|
|
}
|
|
|
|
return { recordsById, duplicateIds };
|
|
}
|
|
|
|
function docLabel(id: string, meta: KeyedRecord) {
|
|
const title = meta.title;
|
|
if (typeof title === 'string' && title.trim()) {
|
|
return `${id} "${title}"`;
|
|
}
|
|
return id;
|
|
}
|
|
|
|
export function printRootDocPairDiff(opts: {
|
|
fromLabel: string;
|
|
toLabel: string;
|
|
fromMeta: RootDocMetaExtract;
|
|
toMeta: RootDocMetaExtract;
|
|
}) {
|
|
const diff = diffKeyedRecords(
|
|
opts.fromMeta.recordsById,
|
|
opts.toMeta.recordsById
|
|
);
|
|
|
|
console.log(`\n=== ${opts.fromLabel} -> ${opts.toLabel} ===`);
|
|
console.log(
|
|
`Docs: ${opts.fromMeta.recordsById.size} -> ${opts.toMeta.recordsById.size} (+${diff.added.length} / -${diff.removed.length} / ~${diff.changed.length})`
|
|
);
|
|
|
|
if (opts.fromMeta.duplicateIds.length) {
|
|
console.log(
|
|
`! Warning: duplicate page ids in FROM: ${Array.from(new Set(opts.fromMeta.duplicateIds)).sort().join(', ')}`
|
|
);
|
|
}
|
|
if (opts.toMeta.duplicateIds.length) {
|
|
console.log(
|
|
`! Warning: duplicate page ids in TO: ${Array.from(new Set(opts.toMeta.duplicateIds)).sort().join(', ')}`
|
|
);
|
|
}
|
|
|
|
if (diff.added.length) {
|
|
console.log(`\n+ Added (${diff.added.length})`);
|
|
for (const { id, record } of diff.added) {
|
|
console.log(` + ${docLabel(id, record)}`);
|
|
}
|
|
}
|
|
|
|
if (diff.removed.length) {
|
|
console.log(`\n- Removed (${diff.removed.length})`);
|
|
for (const { id, record } of diff.removed) {
|
|
console.log(` - ${docLabel(id, record)}`);
|
|
}
|
|
}
|
|
|
|
if (diff.changed.length) {
|
|
console.log(`\n~ Changed (${diff.changed.length})`);
|
|
for (const change of diff.changed) {
|
|
const fromTitle = change.fromRecord.title;
|
|
const toTitle = change.toRecord.title;
|
|
|
|
let header = ` ~ ${change.id}`;
|
|
if (
|
|
typeof fromTitle === 'string' &&
|
|
typeof toTitle === 'string' &&
|
|
fromTitle !== toTitle
|
|
) {
|
|
header += ` "${fromTitle}" -> "${toTitle}"`;
|
|
} else if (typeof toTitle === 'string' && toTitle.trim()) {
|
|
header += ` "${toTitle}"`;
|
|
}
|
|
console.log(header);
|
|
|
|
for (const field of change.fields) {
|
|
console.log(
|
|
` - ${field.key}: ${formatValue(field.key, field.from)} -> ${formatValue(field.key, field.to)}`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!diff.added.length && !diff.removed.length && !diff.changed.length) {
|
|
console.log('\n(no changes)');
|
|
}
|
|
}
|