feat(editor): replace spec provider with extension manager (#11861)

Closes: BS-3273
This commit is contained in:
Saul-Mirone
2025-04-22 07:40:41 +00:00
parent 8fdb00e0ab
commit 6d6504e2af
51 changed files with 623 additions and 177 deletions

View File

@@ -54,14 +54,17 @@ describe('multiple scopes', () => {
class ViewExt1 extends ViewExtensionProvider {
override name = 'ViewExt1';
override setup(context: ViewExtensionContext) {
super.setup(context);
constructor() {
super();
setup1();
}
override setup(context: ViewExtensionContext, option?: { foo: number }) {
super.setup(context, option);
if (context.scope === 'page') {
setup1();
context.register(Ext2);
}
if (context.scope === 'edgeless') {
setup2();
context.register(Ext3);
}
}
@@ -69,6 +72,11 @@ describe('multiple scopes', () => {
class ViewExt2 extends ViewExtensionProvider {
override name = 'ViewExt2';
constructor() {
super();
setup2();
}
override setup(context: ViewExtensionContext) {
super.setup(context);
if (context.scope === 'page') {
@@ -87,7 +95,7 @@ describe('multiple scopes', () => {
expect(edgelessExtensions).toEqual([Ext3, Ext5]);
});
it('should setup be cached', () => {
it('should cache provider instances', () => {
manager.get('page');
manager.get('edgeless');
expect(setup1).toHaveBeenCalledTimes(1);

View File

@@ -84,16 +84,17 @@ export class ExtensionManager<Scope extends string> {
/**
* Retrieves all extensions registered for a specific scope.
* If the scope hasn't been built yet, it triggers the build process.
* It triggers the build process.
*
* @param scope - The scope to retrieve extensions for
* @returns An array of extensions registered for the specified scope
* @throws {BlockSuiteError} If the scope is not found
*/
get(scope: Scope) {
if (!this._extensions.has(scope)) {
this._build(scope);
if (this._extensions.has(scope)) {
this._extensions.delete(scope);
}
this._build(scope);
const extensionSet = this._extensions.get(scope);
if (!extensionSet) {
throw new BlockSuiteError(
@@ -117,14 +118,19 @@ export class ExtensionManager<Scope extends string> {
provider: typeof BaseExtensionProvider<Scope, T>,
options: ((prev: T | undefined) => T | undefined) | T | undefined
) {
const prev = this._providerOptions.get(provider);
let config: T | undefined;
if (typeof options === 'function') {
const prev = this._providerOptions.get(provider);
config = (options as (prev: unknown) => T)(prev);
} else {
config = options;
}
if (prev === config) {
return;
}
if (config === undefined) {
this._providerOptions.delete(provider);
} else {