feat(editor): schema extension (#10447)

1. **Major Architectural Change: Schema Management**
   - Moved from `workspace.schema` to `store.schema` throughout the codebase
   - Removed schema property from Workspace and Doc interfaces
   - Added `BlockSchemaExtension` pattern across multiple block types

2. **Block Schema Extensions Added**
   - Added new `BlockSchemaExtension` to numerous block types including:
     - DataView, Surface, Attachment, Bookmark, Code
     - Database, Divider, EdgelessText, Embed blocks (Figma, Github, HTML, etc.)
     - Frame, Image, Latex, List, Note, Paragraph
     - Root, Surface Reference, Table blocks

3. **Import/Export System Updates**
   - Updated import functions to accept `schema` parameter:
     - `importHTMLToDoc`
     - `importHTMLZip`
     - `importMarkdownToDoc`
     - `importMarkdownZip`
     - `importNotionZip`
   - Modified export functions to use new schema pattern

4. **Test Infrastructure Updates**
   - Updated test files to use new schema extensions
   - Modified test document creation to include schema extensions
   - Removed direct schema registration in favor of extensions

5. **Service Layer Changes**
   - Updated various services to use `getAFFiNEWorkspaceSchema()`
   - Modified transformer initialization to use document schema
   - Updated collection initialization patterns

6. **Version Management**
   - Removed version-related properties and methods from:
     - `WorkspaceMetaImpl`
     - `TestMeta`
     - `DocImpl`
   - Removed `blockVersions` and `workspaceVersion/pageVersion`

7. **Store and Extension Updates**
   - Added new store extensions and adapters
   - Updated store initialization patterns
   - Added new schema-related functionality in store extension

This PR represents a significant architectural shift in how schemas are managed, moving from a workspace-centric to a store-centric approach, while introducing a more extensible block schema system through `BlockSchemaExtension`. The changes touch multiple layers of the application including core functionality, services, testing infrastructure, and import/export capabilities.
This commit is contained in:
Saul-Mirone
2025-02-26 11:31:28 +00:00
parent 2732b96d00
commit ce87dcf58e
95 changed files with 655 additions and 490 deletions

View File

@@ -5,7 +5,10 @@ import type {
WORKSPACE_DIALOG_SCHEMA,
} from '@affine/core/modules/dialogs';
import { UrlService } from '@affine/core/modules/url';
import { WorkspaceService } from '@affine/core/modules/workspace';
import {
getAFFiNEWorkspaceSchema,
WorkspaceService,
} from '@affine/core/modules/workspace';
import { DebugLogger } from '@affine/debug';
import { useI18n } from '@affine/i18n';
import track from '@affine/track';
@@ -141,6 +144,7 @@ const importConfigs: Record<ImportType, ImportConfig> = {
const fileName = file.name.split('.').slice(0, -1).join('.');
const docId = await MarkdownTransformer.importMarkdownToDoc({
collection: docCollection,
schema: getAFFiNEWorkspaceSchema(),
markdown: text,
fileName,
});
@@ -159,6 +163,7 @@ const importConfigs: Record<ImportType, ImportConfig> = {
}
const docIds = await MarkdownTransformer.importMarkdownZip({
collection: docCollection,
schema: getAFFiNEWorkspaceSchema(),
imported: file,
});
return {
@@ -178,6 +183,7 @@ const importConfigs: Record<ImportType, ImportConfig> = {
const fileName = file.name.split('.').slice(0, -1).join('.');
const docId = await HtmlTransformer.importHTMLToDoc({
collection: docCollection,
schema: getAFFiNEWorkspaceSchema(),
html: text,
fileName,
});
@@ -197,6 +203,7 @@ const importConfigs: Record<ImportType, ImportConfig> = {
const { entryId, pageIds, isWorkspaceFile } =
await NotionHtmlTransformer.importNotionZip({
collection: docCollection,
schema: getAFFiNEWorkspaceSchema(),
imported: file,
});
return {
@@ -212,7 +219,13 @@ const importConfigs: Record<ImportType, ImportConfig> = {
if (Array.isArray(file)) {
throw new Error('Expected a single zip file for snapshot import');
}
const docIds = (await ZipTransformer.importDocs(docCollection, file))
const docIds = (
await ZipTransformer.importDocs(
docCollection,
getAFFiNEWorkspaceSchema(),
file
)
)
.filter(doc => doc !== undefined)
.map(doc => doc.id);

View File

@@ -1,7 +1,7 @@
import { getAFFiNEWorkspaceSchema } from '@affine/core/modules/workspace';
import { WorkspaceImpl } from '@affine/core/modules/workspace/impls/workspace';
import { AffineSchemas } from '@blocksuite/affine/blocks';
import type { DocSnapshot, Store } from '@blocksuite/affine/store';
import { Schema, Transformer } from '@blocksuite/affine/store';
import { Transformer } from '@blocksuite/affine/store';
const getCollection = (() => {
let collection: WorkspaceImpl | null = null;
@@ -9,9 +9,7 @@ const getCollection = (() => {
if (collection) {
return collection;
}
const schema = new Schema();
schema.register(AffineSchemas);
collection = new WorkspaceImpl({ schema });
collection = new WorkspaceImpl({});
collection.meta.initialize();
return collection;
};
@@ -86,7 +84,7 @@ async function initDoc(name: DocName) {
const snapshot = (await loaders[name]()) as DocSnapshot;
const collection = await getCollection();
const transformer = new Transformer({
schema: collection.schema,
schema: getAFFiNEWorkspaceSchema(),
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc({ id }),

View File

@@ -10,6 +10,7 @@ import { DndService } from '@affine/core/modules/dnd/services';
import { GlobalContextService } from '@affine/core/modules/global-context';
import { OpenInAppGuard } from '@affine/core/modules/open-in-app';
import {
getAFFiNEWorkspaceSchema,
type Workspace,
type WorkspaceMetadata,
WorkspacesService,
@@ -279,6 +280,7 @@ const WorkspacePage = ({ meta }: { meta: WorkspaceMetadata }) => {
window.exportWorkspaceSnapshot = async (docs?: string[]) => {
await ZipTransformer.exportDocs(
workspace.docCollection,
getAFFiNEWorkspaceSchema(),
Array.from(workspace.docCollection.docs.values())
.filter(doc => (docs ? docs.includes(doc.id) : true))
.map(doc => doc.getStore())
@@ -294,6 +296,7 @@ const WorkspacePage = ({ meta }: { meta: WorkspaceMetadata }) => {
const blob = new Blob([file], { type: 'application/zip' });
const newDocs = await ZipTransformer.importDocs(
workspace.docCollection,
getAFFiNEWorkspaceSchema(),
blob
);
console.log(