diff --git a/packages/sprotty/src/base/model/smodel-factory.ts b/packages/sprotty/src/base/model/smodel-factory.ts index 1b591a06..19412a59 100644 --- a/packages/sprotty/src/base/model/smodel-factory.ts +++ b/packages/sprotty/src/base/model/smodel-factory.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2017-2018 TypeFox and others. + * Copyright (c) 2017-2024 TypeFox and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -34,13 +34,25 @@ export class SModelRegistry extends FactoryRegistry { defaultFeatures = []; if (defaultFeatures) { const featureSet = createFeatureSet(defaultFeatures, registration.features); - this.register(registration.type, () => { - const element = new registration.constr(); - element.features = featureSet; - return element; - }); + if (registration.isOverride) { + this.override(registration.type, () => { + const element = new registration.constr(); + element.features = featureSet; + return element; + }); + } else { + this.register(registration.type, () => { + const element = new registration.constr(); + element.features = featureSet; + return element; + }); + } } else { - this.register(registration.type, () => new registration.constr()); + if (registration.isOverride) { + this.override(registration.type, () => new registration.constr()); + } else { + this.register(registration.type, () => new registration.constr()); + } } }); } @@ -177,6 +189,7 @@ export interface SModelElementRegistration { type: string constr: SModelElementConstructor features?: CustomFeatures + isOverride?: boolean } export interface SModelElementConstructor { diff --git a/packages/sprotty/src/base/model/smodel-utils.ts b/packages/sprotty/src/base/model/smodel-utils.ts index f182ffed..57b7ea96 100644 --- a/packages/sprotty/src/base/model/smodel-utils.ts +++ b/packages/sprotty/src/base/model/smodel-utils.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2017-2018 TypeFox and others. + * Copyright (c) 2017-2024 TypeFox and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -24,9 +24,9 @@ import { SModelElementRegistration, CustomFeatures } from "./smodel-factory"; * Register a model element constructor for an element type. */ export function registerModelElement(context: { bind: interfaces.Bind, isBound: interfaces.IsBound }, - type: string, constr: new () => SModelElementImpl, features?: CustomFeatures): void { + type: string, constr: new () => SModelElementImpl, features?: CustomFeatures, isOverride?: boolean): void { context.bind(TYPES.SModelElementRegistration).toConstantValue({ - type, constr, features + type, constr, features, isOverride }); } diff --git a/packages/sprotty/src/base/views/view.tsx b/packages/sprotty/src/base/views/view.tsx index ac2ae94b..391a5688 100644 --- a/packages/sprotty/src/base/views/view.tsx +++ b/packages/sprotty/src/base/views/view.tsx @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2017-2018 TypeFox and others. + * Copyright (c) 2017-2024 TypeFox and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -86,6 +86,7 @@ export interface RenderingContext { export interface ViewRegistration { type: string factory: () => IView + isOverride?: boolean } export type ViewRegistrationFactory = () => ViewRegistration; @@ -101,8 +102,13 @@ export class ViewRegistry extends InstanceRegistry { constructor(@multiInject(TYPES.ViewRegistration) @optional() registrations: ViewRegistration[]) { super(); this.registerDefaults(); - registrations.forEach(registration => - this.register(registration.type, registration.factory()) + registrations.forEach(registration => { + if (registration.isOverride) { + this.override(registration.type, registration.factory()); + } else { + this.register(registration.type, registration.factory()); + } + } ); } @@ -125,12 +131,20 @@ export function configureModelElement(context: { bind: interfaces.Bind, isBound: registerModelElement(context, type, modelConstr, features); configureView(context, type, viewConstr); } +export function overrideModelElement(context: {bind: interfaces.Bind, isBound: interfaces.IsBound}, + type: string, modelConstr: new () => SModelElementImpl, viewConstr: interfaces.ServiceIdentifier, + features?: CustomFeatures): void { + registerModelElement(context, type, modelConstr, features, true); + configureView(context, type, viewConstr, true); +} + + /** * Utility function to register a view for a model element type. */ export function configureView(context: { bind: interfaces.Bind, isBound: interfaces.IsBound }, - type: string, constr: interfaces.ServiceIdentifier): void { + type: string, constr: interfaces.ServiceIdentifier, isOverride?: boolean): void { if (typeof constr === 'function') { if (!isInjectable(constr)) { throw new Error(`Views should be @injectable: ${constr.name}`); @@ -141,7 +155,8 @@ export function configureView(context: { bind: interfaces.Bind, isBound: interfa } context.bind(TYPES.ViewRegistration).toDynamicValue(ctx => ({ type, - factory: () => ctx.container.get(constr) + factory: () => ctx.container.get(constr), + isOverride })); } diff --git a/packages/sprotty/src/utils/registry.ts b/packages/sprotty/src/utils/registry.ts index 3d079b22..70c9fd4d 100644 --- a/packages/sprotty/src/utils/registry.ts +++ b/packages/sprotty/src/utils/registry.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2017-2018 TypeFox and others. + * Copyright (c) 2017-2024 TypeFox and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -60,7 +60,16 @@ export class FactoryRegistry { throw new Error('Key is undefined'); } if (this.hasKey(key)) { - throw new Error('Key is already registered: ' + key); + throw new Error(`Key is already registered: ${key}. Use \`overrideModelElement\` instead.`); + } + this.elements.set(key, factory); + } + + override(key: string, factory: (u: U) => T) { + if (key === undefined) { + throw new Error('Key is undefined'); + } else if (!this.hasKey(key)) { + throw new Error(`Key is not registered: ${key}. Use \`configureModelElement\` instead.`); } this.elements.set(key, factory); } @@ -99,7 +108,16 @@ export class InstanceRegistry { throw new Error('Key is undefined'); } if (this.hasKey(key)) { - throw new Error('Key is already registered: ' + key); + throw new Error(`Key is already registered: ${key}. Use \`overrideModelElement\` instead.`); + } + this.elements.set(key, instance); + } + + override(key: string, instance: T) { + if (key === undefined) { + throw new Error('Key is undefined'); + } else if (!this.hasKey(key)) { + throw new Error(`Key is not registered: ${key}. Use \`configureModelElement\` instead.`); } this.elements.set(key, instance); }