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

@@ -162,10 +162,6 @@ export class TestDoc implements Doc {
return this._ready;
}
get schema() {
return this.workspace.schema;
}
get spaceDoc() {
return this._ySpaceDoc;
}
@@ -189,13 +185,6 @@ export class TestDoc implements Doc {
return (readonly?.toString() as 'true' | 'false') ?? 'false';
}
private _handleVersion() {
// Initialization from empty yDoc, indicating that the document is new.
if (!this.workspace.meta.hasVersion) {
this.workspace.meta.writeVersion(this.workspace);
}
}
private _handleYBlockAdd(id: string) {
this.slots.yBlockUpdated.emit({ type: 'add', id });
}
@@ -306,7 +295,6 @@ export class TestDoc implements Doc {
const doc = new Store({
doc: this,
schema: this.workspace.schema,
readonly,
query,
provider,
@@ -327,10 +315,6 @@ export class TestDoc implements Doc {
this._ySpaceDoc.load();
if ((this.workspace.meta.docs?.length ?? 0) <= 1) {
this._handleVersion();
}
this._initYBlocks();
this._yBlocks.forEach((_, id) => {

View File

@@ -4,20 +4,13 @@ import type * as Y from 'yjs';
import type {
DocMeta,
DocsPropertiesMeta,
Workspace,
WorkspaceMeta,
} from '../model/index.js';
import { createYProxy } from '../reactive/proxy.js';
const COLLECTION_VERSION = 2;
const PAGE_VERSION = 2;
type DocCollectionMetaState = {
pages?: unknown[];
properties?: DocsPropertiesMeta;
workspaceVersion?: number;
pageVersion?: number;
blockVersions?: Record<string, number>;
name?: string;
avatar?: string;
};
@@ -68,10 +61,6 @@ export class TestMeta implements WorkspaceMeta {
return this._proxy.avatar;
}
get blockVersions() {
return this._proxy.blockVersions;
}
get docMetas() {
if (!this._proxy.pages) {
return [] as DocMeta[];
@@ -83,21 +72,10 @@ export class TestMeta implements WorkspaceMeta {
return this._proxy.pages;
}
get hasVersion() {
if (!this.blockVersions || !this.pageVersion || !this.workspaceVersion) {
return false;
}
return Object.keys(this.blockVersions).length > 0;
}
get name() {
return this._proxy.name;
}
get pageVersion() {
return this._proxy.pageVersion;
}
get properties(): DocsPropertiesMeta {
const meta = this._proxy.properties;
if (!meta) {
@@ -110,10 +88,6 @@ export class TestMeta implements WorkspaceMeta {
return meta;
}
get workspaceVersion() {
return this._proxy.workspaceVersion;
}
get yDocs() {
return this._yMap.get('pages') as unknown as Y.Array<unknown>;
}
@@ -232,33 +206,4 @@ export class TestMeta implements WorkspaceMeta {
this._proxy.properties = meta;
this.docMetaUpdated.emit();
}
/**
* @internal Only for doc initialization
*/
writeVersion(collection: Workspace) {
const { blockVersions, pageVersion, workspaceVersion } = this._proxy;
if (!workspaceVersion) {
this._proxy.workspaceVersion = COLLECTION_VERSION;
} else {
console.error('Workspace version is already set');
}
if (!pageVersion) {
this._proxy.pageVersion = PAGE_VERSION;
} else {
console.error('Doc version is already set');
}
if (!blockVersions) {
const _versions: Record<string, number> = {};
collection.schema.flavourSchemaMap.forEach((schema, flavour) => {
_versions[flavour] = schema.version;
});
this._proxy.blockVersions = _versions;
} else {
console.error('Block versions is already set');
}
}
}

View File

@@ -21,14 +21,12 @@ import type {
Workspace,
WorkspaceMeta,
} from '../model/index.js';
import type { Schema } from '../schema/index.js';
import { type IdGenerator, nanoid } from '../utils/id-generator.js';
import { AwarenessStore } from '../yjs/index.js';
import { TestDoc } from './test-doc.js';
import { TestMeta } from './test-meta.js';
export type DocCollectionOptions = {
schema: Schema;
id?: string;
idGenerator?: IdGenerator;
docSources?: {
@@ -47,8 +45,6 @@ export type DocCollectionOptions = {
* Do not use this in production
*/
export class TestWorkspace implements Workspace {
protected readonly _schema: Schema;
storeExtensions: ExtensionType[] = [];
readonly awarenessStore: AwarenessStore;
@@ -79,13 +75,8 @@ export class TestWorkspace implements Workspace {
return this.blockCollections;
}
get schema() {
return this._schema;
}
constructor({
id,
schema,
idGenerator,
awarenessSources = [],
docSources = {
@@ -94,9 +85,7 @@ export class TestWorkspace implements Workspace {
blobSources = {
main: new MemoryBlobSource(),
},
}: DocCollectionOptions) {
this._schema = schema;
}: DocCollectionOptions = {}) {
this.id = id || '';
this.doc = new Y.Doc({ guid: id });
this.awarenessStore = new AwarenessStore(new Awareness(this.doc));
@@ -165,7 +154,12 @@ export class TestWorkspace implements Workspace {
* will be created in the doc simultaneously.
*/
createDoc(options: CreateBlocksOptions = {}) {
const { id: docId = this.idGenerator(), query, readonly } = options;
const {
id: docId = this.idGenerator(),
query,
readonly,
extensions,
} = options;
if (this._hasDoc(docId)) {
throw new BlockSuiteError(
ErrorCode.DocCollectionError,
@@ -184,6 +178,7 @@ export class TestWorkspace implements Workspace {
id: docId,
query,
readonly,
extensions,
}) as Store;
}