mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
feat(editor): support user provided role and role schema (#10939)
Let me analyze the key changes in this diff: 1. **Role System Changes**: - Changed from a fixed enum of roles (`root`, `hub`, `content`) to a more flexible string-based system - Removed strict role hierarchy validation rules (hub/content/root relationships) - Added support for role-based matching using `@` prefix (e.g., `@root`, `@content`) 2. **Schema Validation Updates**: - Added new `_matchFlavourOrRole` method to handle both flavour and role-based matching - Updated `_validateParent` to consider both roles and flavours when validating parent-child relationships - Simplified `_validateRole` by removing specific role hierarchy constraints 3. **Block Schema Changes**: - Updated parent/children references in various block schemas to use the new `@` prefix notation - Changed parent definitions from `['affine:page']` to `['@root']` in several blocks - Updated children definitions to use role-based references (e.g., `['@content']`) 4. **Test Updates**: - Added new test cases for role-based schema validation - Introduced new test block schemas (`TestRoleBlockSchema`, `TestParagraphBlockSchema`) to verify role-based functionality This appears to be a significant architectural change that makes the block schema system more flexible by: 1. Moving away from hardcoded role hierarchies 2. Introducing a more dynamic role-based relationship system 3. Supporting both flavour-based and role-based parent-child relationships 4. Using the `@` prefix convention to distinguish role references from flavour references The changes make the system more extensible while maintaining backward compatibility with existing flavour-based relationships.
This commit is contained in:
@@ -59,7 +59,7 @@ export class Schema {
|
||||
if (!parentFlavour) {
|
||||
throw new SchemaValidateError(
|
||||
schema.model.flavour,
|
||||
'Hub/Content must have parent.'
|
||||
'None root block must have parent.'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -86,33 +86,84 @@ export class Schema {
|
||||
);
|
||||
}
|
||||
|
||||
private _matchFlavourOrRole(
|
||||
childValue: string,
|
||||
parentValue: string,
|
||||
childRole: string,
|
||||
parentRole: string
|
||||
): boolean {
|
||||
// Check if either value starts with '@' indicating it's a role
|
||||
const isChildRole = childValue.startsWith('@');
|
||||
const isParentRole = parentValue.startsWith('@');
|
||||
|
||||
// If both are roles, do exact match
|
||||
if (isChildRole && isParentRole) {
|
||||
return childValue === parentValue;
|
||||
}
|
||||
// If child is role, compare with parent's actual role
|
||||
if (isChildRole) {
|
||||
return childValue === `@${parentRole}`;
|
||||
}
|
||||
// If parent is role, compare with child's actual role
|
||||
if (isParentRole) {
|
||||
return parentValue === `@${childRole}`;
|
||||
}
|
||||
// If neither is role, use flavour matching
|
||||
return this._matchFlavour(childValue, parentValue);
|
||||
}
|
||||
|
||||
private _validateParent(
|
||||
child: BlockSchemaType,
|
||||
parent: BlockSchemaType
|
||||
): boolean {
|
||||
const _childFlavour = child.model.flavour;
|
||||
const _parentFlavour = parent.model.flavour;
|
||||
const _childRole = child.model.role;
|
||||
const _parentRole = parent.model.role;
|
||||
|
||||
const childValidFlavours = child.model.parent || ['*'];
|
||||
const parentValidFlavours = parent.model.children || ['*'];
|
||||
const childValidFlavourOrRole = child.model.parent || ['*'];
|
||||
const parentValidFlavourOrRole = parent.model.children || ['*'];
|
||||
|
||||
return parentValidFlavours.some(parentValidFlavour => {
|
||||
return childValidFlavours.some(childValidFlavour => {
|
||||
if (parentValidFlavour === '*' && childValidFlavour === '*') {
|
||||
return parentValidFlavourOrRole.some(parentValidFlavourOrRole => {
|
||||
return childValidFlavourOrRole.some(childValidFlavourOrRole => {
|
||||
if (
|
||||
parentValidFlavourOrRole === '*' &&
|
||||
childValidFlavourOrRole === '*'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parentValidFlavour === '*') {
|
||||
return this._matchFlavour(childValidFlavour, _parentFlavour);
|
||||
if (parentValidFlavourOrRole === '*') {
|
||||
return this._matchFlavourOrRole(
|
||||
childValidFlavourOrRole,
|
||||
_parentFlavour,
|
||||
_childRole,
|
||||
_parentRole
|
||||
);
|
||||
}
|
||||
|
||||
if (childValidFlavour === '*') {
|
||||
return this._matchFlavour(_childFlavour, parentValidFlavour);
|
||||
if (childValidFlavourOrRole === '*') {
|
||||
return this._matchFlavourOrRole(
|
||||
_childFlavour,
|
||||
parentValidFlavourOrRole,
|
||||
_childRole,
|
||||
_parentRole
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
this._matchFlavour(_childFlavour, parentValidFlavour) &&
|
||||
this._matchFlavour(childValidFlavour, _parentFlavour)
|
||||
this._matchFlavourOrRole(
|
||||
_childFlavour,
|
||||
parentValidFlavourOrRole,
|
||||
_childRole,
|
||||
_parentRole
|
||||
) &&
|
||||
this._matchFlavourOrRole(
|
||||
childValidFlavourOrRole,
|
||||
_parentFlavour,
|
||||
_childRole,
|
||||
_parentRole
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -120,7 +171,6 @@ export class Schema {
|
||||
|
||||
private _validateRole(child: BlockSchemaType, parent: BlockSchemaType) {
|
||||
const childRole = child.model.role;
|
||||
const parentRole = parent.model.role;
|
||||
const childFlavour = child.model.flavour;
|
||||
const parentFlavour = parent.model.flavour;
|
||||
|
||||
@@ -130,20 +180,6 @@ export class Schema {
|
||||
`Root block cannot have parent: ${parentFlavour}.`
|
||||
);
|
||||
}
|
||||
|
||||
if (childRole === 'hub' && parentRole === 'content') {
|
||||
throw new SchemaValidateError(
|
||||
childFlavour,
|
||||
`Hub block cannot be child of content block: ${parentFlavour}.`
|
||||
);
|
||||
}
|
||||
|
||||
if (childRole === 'content' && parentRole === 'root') {
|
||||
throw new SchemaValidateError(
|
||||
childFlavour,
|
||||
`Content block can only be child of hub block or itself. But get: ${parentFlavour}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
isValid(child: string, parent: string) {
|
||||
|
||||
Reference in New Issue
Block a user