diff --git a/examples/workflow-glsp/src/direct-task-editing/di.config.ts b/examples/workflow-glsp/src/direct-task-editing/di.config.ts index 855b48f7..df8e8238 100644 --- a/examples/workflow-glsp/src/direct-task-editing/di.config.ts +++ b/examples/workflow-glsp/src/direct-task-editing/di.config.ts @@ -16,6 +16,9 @@ import { bindAsService, FeatureModule, TYPES } from '@eclipse-glsp/client'; import { TaskEditor } from './direct-task-editor'; -export const directTaskEditor = new FeatureModule((bind, _unbind, _isBound) => { - bindAsService(bind, TYPES.IUIExtension, TaskEditor); -}); +export const directTaskEditor = new FeatureModule( + (bind, _unbind, _isBound) => { + bindAsService(bind, TYPES.IUIExtension, TaskEditor); + }, + { featureId: Symbol('directTaskEditor') } +); diff --git a/examples/workflow-glsp/src/workflow-diagram-module.ts b/examples/workflow-glsp/src/workflow-diagram-module.ts index 3c0942ef..c73a4362 100644 --- a/examples/workflow-glsp/src/workflow-diagram-module.ts +++ b/examples/workflow-glsp/src/workflow-diagram-module.ts @@ -99,11 +99,11 @@ export function createWorkflowDiagramContainer(...containerConfiguration: Contai export function initializeWorkflowDiagramContainer(container: Container, ...containerConfiguration: ContainerConfiguration): Container { return initializeDiagramContainer( container, + ...containerConfiguration, directTaskEditor, helperLineModule, gridModule, debugModule, - workflowDiagramModule, - ...containerConfiguration + workflowDiagramModule ); } diff --git a/packages/client/src/base/default.module.ts b/packages/client/src/base/default.module.ts index c4a47d13..f6351b62 100644 --- a/packages/client/src/base/default.module.ts +++ b/packages/client/src/base/default.module.ts @@ -62,76 +62,83 @@ import { GViewRegistry } from './view/view-registry'; * The default module provides all of GLSP's base functionality and services. * It builds on top of sprotty's default module {@link `sprottyDefaultModule`}. */ -export const defaultModule = new FeatureModule((bind, unbind, isBound, rebind, ...rest) => { - // load bindings from sprotty's default module to avoid code duplication - sprottyDefaultModule.registry(bind, unbind, isBound, rebind, ...rest); - const context = { bind, unbind, isBound, rebind }; - - bindLazyInjector(context); - - bind(EditorContextService).toSelf().inSingletonScope(); - bind(TYPES.IDiagramStartup).toService(EditorContextService); - bind(TYPES.IEditorContextServiceProvider).toProvider(ctx => async () => ctx.container.get(EditorContextService)); - - configureActionHandler(context, SetEditModeAction.KIND, EditorContextService); - configureActionHandler(context, SetDirtyStateAction.KIND, EditorContextService); - - bind(FocusTracker).toSelf().inSingletonScope(); - configureActionHandler(context, FocusStateChangedAction.KIND, FocusTracker); - - // Model update initialization ------------------------------------ - bind(TYPES.IFeedbackActionDispatcher).to(FeedbackActionDispatcher).inSingletonScope(); - configureCommand(context, FeedbackAwareUpdateModelCommand); - rebind(SetModelCommand).to(FeedbackAwareSetModelCommand); - - bind(GLSPMouseTool).toSelf().inSingletonScope(); - bindOrRebind(context, MouseTool).toService(GLSPMouseTool); - bind(TYPES.IDiagramStartup).toService(GLSPMouseTool); - bind(GLSPMousePositionTracker).toSelf().inSingletonScope(); - bindOrRebind(context, MousePositionTracker).toService(GLSPMousePositionTracker); - bind(GLSPKeyTool).toSelf().inSingletonScope(); - bindOrRebind(context, KeyTool).toService(GLSPKeyTool); - bind(TYPES.IDiagramStartup).toService(GLSPKeyTool); - - bindAsService(context, TYPES.MouseListener, SelectionClearingMouseListener); - bindOrRebind(context, TYPES.ICommandStack).to(GLSPCommandStack).inSingletonScope(); - bind(GLSPActionDispatcher).toSelf().inSingletonScope(); - bindOrRebind(context, TYPES.IActionDispatcher).toService(GLSPActionDispatcher); - - bindOrRebind(context, ActionHandlerRegistry).to(GLSPActionHandlerRegistry).inSingletonScope(); - - bindAsService(context, TYPES.ModelSource, GLSPModelSource); - bind(DiagramLoader).toSelf().inSingletonScope(); - bind(ModelInitializationConstraint).to(DefaultModelInitializationConstraint).inSingletonScope(); - - // support re-registration of model elements and views - bindOrRebind(context, TYPES.SModelRegistry).to(GModelRegistry).inSingletonScope(); - bindOrRebind(context, TYPES.ViewRegistry).to(GViewRegistry).inSingletonScope(); - - bind(SelectionService).toSelf().inSingletonScope(); - bind(TYPES.IGModelRootListener).toService(SelectionService); - bind(TYPES.IDiagramStartup).toService(SelectionService); - - // Feedback Support ------------------------------------ - // Generic re-usable feedback modifying css classes - configureCommand(context, ModifyCssFeedbackCommand); - // We support using sprotty's MoveCommand as client-side visual feedback - configureCommand(context, MoveCommand); - - bindAsService(context, TYPES.IVNodePostprocessor, LocationPostprocessor); - bind(TYPES.HiddenVNodePostprocessor).toService(LocationPostprocessor); - - // Tool manager initialization ------------------------------------ - bind(TYPES.IToolManager).to(ToolManager).inSingletonScope(); - bind(TYPES.IDiagramStartup).toService(TYPES.IToolManager); - bind(TYPES.IEditModeListener).toService(TYPES.IToolManager); - bind(DefaultToolsEnablingKeyListener).toSelf().inSingletonScope(); - bind(TYPES.KeyListener).toService(DefaultToolsEnablingKeyListener); - bind(ToolManagerActionHandler).toSelf().inSingletonScope(); - configureActionHandler(context, EnableDefaultToolsAction.KIND, ToolManagerActionHandler); - configureActionHandler(context, EnableToolsAction.KIND, ToolManagerActionHandler); - - bind(GLSPUIExtensionRegistry).toSelf().inSingletonScope(); - bindOrRebind(context, TYPES.UIExtensionRegistry).toService(GLSPUIExtensionRegistry); - bind(TYPES.IDiagramStartup).toService(GLSPUIExtensionRegistry); -}); +export const defaultModule = new FeatureModule( + (bind, unbind, isBound, rebind, ...rest) => { + // load bindings from sprotty's default module to avoid code duplication + sprottyDefaultModule.registry(bind, unbind, isBound, rebind, ...rest); + const context = { bind, unbind, isBound, rebind }; + + bindLazyInjector(context); + + bind(EditorContextService).toSelf().inSingletonScope(); + bind(TYPES.IDiagramStartup).toService(EditorContextService); + bind(TYPES.IEditorContextServiceProvider).toProvider( + ctx => async () => ctx.container.get(EditorContextService) + ); + + configureActionHandler(context, SetEditModeAction.KIND, EditorContextService); + configureActionHandler(context, SetDirtyStateAction.KIND, EditorContextService); + + bind(FocusTracker).toSelf().inSingletonScope(); + configureActionHandler(context, FocusStateChangedAction.KIND, FocusTracker); + + // Model update initialization ------------------------------------ + bind(TYPES.IFeedbackActionDispatcher).to(FeedbackActionDispatcher).inSingletonScope(); + configureCommand(context, FeedbackAwareUpdateModelCommand); + rebind(SetModelCommand).to(FeedbackAwareSetModelCommand); + + bind(GLSPMouseTool).toSelf().inSingletonScope(); + bindOrRebind(context, MouseTool).toService(GLSPMouseTool); + bind(TYPES.IDiagramStartup).toService(GLSPMouseTool); + bind(GLSPMousePositionTracker).toSelf().inSingletonScope(); + bindOrRebind(context, MousePositionTracker).toService(GLSPMousePositionTracker); + bind(GLSPKeyTool).toSelf().inSingletonScope(); + bindOrRebind(context, KeyTool).toService(GLSPKeyTool); + bind(TYPES.IDiagramStartup).toService(GLSPKeyTool); + + bindAsService(context, TYPES.MouseListener, SelectionClearingMouseListener); + bindOrRebind(context, TYPES.ICommandStack).to(GLSPCommandStack).inSingletonScope(); + bind(GLSPActionDispatcher).toSelf().inSingletonScope(); + bindOrRebind(context, TYPES.IActionDispatcher).toService(GLSPActionDispatcher); + + bindOrRebind(context, ActionHandlerRegistry).to(GLSPActionHandlerRegistry).inSingletonScope(); + + bindAsService(context, TYPES.ModelSource, GLSPModelSource); + bind(DiagramLoader).toSelf().inSingletonScope(); + bind(ModelInitializationConstraint).to(DefaultModelInitializationConstraint).inSingletonScope(); + + // support re-registration of model elements and views + bindOrRebind(context, TYPES.SModelRegistry).to(GModelRegistry).inSingletonScope(); + bindOrRebind(context, TYPES.ViewRegistry).to(GViewRegistry).inSingletonScope(); + + bind(SelectionService).toSelf().inSingletonScope(); + bind(TYPES.IGModelRootListener).toService(SelectionService); + bind(TYPES.IDiagramStartup).toService(SelectionService); + + // Feedback Support ------------------------------------ + // Generic re-usable feedback modifying css classes + configureCommand(context, ModifyCssFeedbackCommand); + // We support using sprotty's MoveCommand as client-side visual feedback + configureCommand(context, MoveCommand); + + bindAsService(context, TYPES.IVNodePostprocessor, LocationPostprocessor); + bind(TYPES.HiddenVNodePostprocessor).toService(LocationPostprocessor); + + // Tool manager initialization ------------------------------------ + bind(TYPES.IToolManager).to(ToolManager).inSingletonScope(); + bind(TYPES.IDiagramStartup).toService(TYPES.IToolManager); + bind(TYPES.IEditModeListener).toService(TYPES.IToolManager); + bind(DefaultToolsEnablingKeyListener).toSelf().inSingletonScope(); + bind(TYPES.KeyListener).toService(DefaultToolsEnablingKeyListener); + bind(ToolManagerActionHandler).toSelf().inSingletonScope(); + configureActionHandler(context, EnableDefaultToolsAction.KIND, ToolManagerActionHandler); + configureActionHandler(context, EnableToolsAction.KIND, ToolManagerActionHandler); + + bind(GLSPUIExtensionRegistry).toSelf().inSingletonScope(); + bindOrRebind(context, TYPES.UIExtensionRegistry).toService(GLSPUIExtensionRegistry); + bind(TYPES.IDiagramStartup).toService(GLSPUIExtensionRegistry); + }, + { + featureId: Symbol('default') + } +); diff --git a/packages/client/src/features/accessibility/accessibility-module.ts b/packages/client/src/features/accessibility/accessibility-module.ts index 1a5b68da..5665ce83 100644 --- a/packages/client/src/features/accessibility/accessibility-module.ts +++ b/packages/client/src/features/accessibility/accessibility-module.ts @@ -15,30 +15,35 @@ ********************************************************************************/ import { FeatureModule } from '@eclipse-glsp/sprotty'; +import { configureElementNavigationTool } from './element-navigation/element-navigation-module'; +import { configureFocusTrackerTool } from './focus-tracker/focus-tracker-module'; import { configureShortcutHelpTool } from './key-shortcut/di.config'; +import { configureKeyboardControlTools } from './keyboard-pointer/keyboard-pointer-module'; +import { configureKeyboardToolPaletteTool } from './keyboard-tool-palette/keyboard-tool-palette-module'; import { configureMoveZoom } from './move-zoom/move-zoom-module'; import { configureResizeTools } from './resize-key-tool/resize-key-module'; import { configureSearchPaletteModule } from './search/search-palette-module'; -import { configureViewKeyTools } from './view-key-tools/view-key-tools-module'; -import { configureKeyboardToolPaletteTool } from './keyboard-tool-palette/keyboard-tool-palette-module'; -import { configureKeyboardControlTools } from './keyboard-pointer/keyboard-pointer-module'; -import { configureElementNavigationTool } from './element-navigation/element-navigation-module'; -import { configureFocusTrackerTool } from './focus-tracker/focus-tracker-module'; import { configureToastTool } from './toast/toast-module'; +import { configureViewKeyTools } from './view-key-tools/view-key-tools-module'; /** * Enables the accessibility tools for a keyboard-only-usage */ -export const accessibilityModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - configureResizeTools(context); - configureViewKeyTools(context); - configureMoveZoom(context); - configureSearchPaletteModule(context); - configureShortcutHelpTool(context); - configureKeyboardToolPaletteTool(context); - configureKeyboardControlTools(context); - configureElementNavigationTool(context); - configureFocusTrackerTool(context); - configureToastTool(context); -}); +export const accessibilityModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + configureResizeTools(context); + configureViewKeyTools(context); + configureMoveZoom(context); + configureSearchPaletteModule(context); + configureShortcutHelpTool(context); + configureKeyboardToolPaletteTool(context); + configureKeyboardControlTools(context); + configureElementNavigationTool(context); + configureFocusTrackerTool(context); + configureToastTool(context); + }, + { + featureId: Symbol('accessibility') + } +); diff --git a/packages/client/src/features/accessibility/keyboard-pointer/keyboard-pointer-module.ts b/packages/client/src/features/accessibility/keyboard-pointer/keyboard-pointer-module.ts index 6d09dffc..decbe60e 100644 --- a/packages/client/src/features/accessibility/keyboard-pointer/keyboard-pointer-module.ts +++ b/packages/client/src/features/accessibility/keyboard-pointer/keyboard-pointer-module.ts @@ -14,32 +14,35 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ import { + BindingContext, + FeatureModule, TYPES, - bindAsService, - configureActionHandler, + TriggerEdgeCreationAction, TriggerNodeCreationAction, - FeatureModule, - BindingContext, - TriggerEdgeCreationAction + bindAsService, + configureActionHandler } from '@eclipse-glsp/sprotty'; -import { GlobalKeyListenerTool } from '../global-keylistener-tool'; -import { KeyboardPointer } from './keyboard-pointer'; -import { KeyboardGrid } from '../keyboard-grid/keyboard-grid'; -import { SetKeyboardPointerRenderPositionAction } from './actions'; +import { SetEdgeTargetSelectionAction } from '../edge-autocomplete/action'; import { EdgeAutocompletePalette } from '../edge-autocomplete/edge-autocomplete-palette'; import { EdgeAutocompletePaletteTool } from '../edge-autocomplete/edge-autocomplete-tool'; -import { SetEdgeTargetSelectionAction } from '../edge-autocomplete/action'; +import { GlobalKeyListenerTool } from '../global-keylistener-tool'; +import { EnableKeyboardGridAction, KeyboardGridCellSelectedAction } from '../keyboard-grid/action'; +import { KeyboardGrid } from '../keyboard-grid/keyboard-grid'; import { GridSearchPalette } from '../keyboard-grid/keyboard-grid-search-palette'; import { KeyboardNodeGrid } from '../keyboard-grid/keyboard-node-grid'; -import { EnableKeyboardGridAction, KeyboardGridCellSelectedAction } from '../keyboard-grid/action'; +import { SetKeyboardPointerRenderPositionAction } from './actions'; +import { KeyboardPointer } from './keyboard-pointer'; /** * Handles the pointer used via grid to position new elements. */ -export const keyboardControlModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - configureKeyboardControlTools(context); -}); +export const keyboardControlModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + configureKeyboardControlTools(context); + }, + { featureId: Symbol('keyboardControl') } +); export function configureKeyboardControlTools(context: BindingContext): void { bindAsService(context, TYPES.IDefaultTool, GlobalKeyListenerTool); diff --git a/packages/client/src/features/accessibility/keyboard-tool-palette/keyboard-tool-palette-module.ts b/packages/client/src/features/accessibility/keyboard-tool-palette/keyboard-tool-palette-module.ts index 9f26fb09..b9477a90 100644 --- a/packages/client/src/features/accessibility/keyboard-tool-palette/keyboard-tool-palette-module.ts +++ b/packages/client/src/features/accessibility/keyboard-tool-palette/keyboard-tool-palette-module.ts @@ -29,10 +29,13 @@ import { EnableToolPaletteAction } from '../../tool-palette/tool-palette'; import { FocusDomAction } from '../actions'; import { KeyboardToolPalette } from './keyboard-tool-palette'; -export const keyboardToolPaletteModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - configureKeyboardToolPaletteTool(context); -}); +export const keyboardToolPaletteModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + configureKeyboardToolPaletteTool(context); + }, + { featureId: Symbol('keyboardToolPalette') } +); export function configureKeyboardToolPaletteTool(context: BindingContext): void { bindAsService(context, TYPES.IUIExtension, KeyboardToolPalette); diff --git a/packages/client/src/features/accessibility/move-zoom/move-zoom-module.ts b/packages/client/src/features/accessibility/move-zoom/move-zoom-module.ts index c9ff29a8..d8b8eb8a 100644 --- a/packages/client/src/features/accessibility/move-zoom/move-zoom-module.ts +++ b/packages/client/src/features/accessibility/move-zoom/move-zoom-module.ts @@ -21,10 +21,13 @@ import { ZoomElementAction, ZoomElementHandler, ZoomViewportAction, ZoomViewport /** * Handles move and zoom actions. */ -export const moveZoomModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - configureMoveZoom(context); -}); +export const moveZoomModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + configureMoveZoom(context); + }, + { featureId: Symbol('moveZoom') } +); export function configureMoveZoom(context: BindingContext): void { context.bind(MoveViewportHandler).toSelf().inSingletonScope(); diff --git a/packages/client/src/features/accessibility/resize-key-tool/resize-key-module.ts b/packages/client/src/features/accessibility/resize-key-tool/resize-key-module.ts index 41e3c6b5..7a29779f 100644 --- a/packages/client/src/features/accessibility/resize-key-tool/resize-key-module.ts +++ b/packages/client/src/features/accessibility/resize-key-tool/resize-key-module.ts @@ -21,10 +21,13 @@ import { ResizeKeyTool } from './resize-key-tool'; /** * Handles resize actions. */ -export const resizeKeyModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - configureResizeTools(context); -}); +export const resizeKeyModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + configureResizeTools(context); + }, + { featureId: Symbol('resizeKey') } +); export function configureResizeTools(context: BindingContext): void { context.bind(ResizeElementHandler).toSelf().inSingletonScope(); diff --git a/packages/client/src/features/accessibility/search/search-palette-module.ts b/packages/client/src/features/accessibility/search/search-palette-module.ts index 371d2b0d..c2bf03a3 100644 --- a/packages/client/src/features/accessibility/search/search-palette-module.ts +++ b/packages/client/src/features/accessibility/search/search-palette-module.ts @@ -18,10 +18,13 @@ import { bindAsService, BindingContext, FeatureModule, TYPES } from '@eclipse-gl import { SearchAutocompletePalette } from './search-palette'; import { SearchAutocompletePaletteTool } from './search-tool'; -export const searchPaletteModule = new FeatureModule((bind, _unbind, isBound, rebind) => { - const context = { bind, isBound, rebind }; - configureSearchPaletteModule(context); -}); +export const searchPaletteModule = new FeatureModule( + (bind, _unbind, isBound, rebind) => { + const context = { bind, isBound, rebind }; + configureSearchPaletteModule(context); + }, + { featureId: Symbol('searchPalette') } +); export function configureSearchPaletteModule(context: Pick): void { bindAsService(context, TYPES.IUIExtension, SearchAutocompletePalette); diff --git a/packages/client/src/features/accessibility/view-key-tools/view-key-tools-module.ts b/packages/client/src/features/accessibility/view-key-tools/view-key-tools-module.ts index f9811ab0..85f616d7 100644 --- a/packages/client/src/features/accessibility/view-key-tools/view-key-tools-module.ts +++ b/packages/client/src/features/accessibility/view-key-tools/view-key-tools-module.ts @@ -15,15 +15,20 @@ ********************************************************************************/ import { bindAsService, BindingContext, configureActionHandler, FeatureModule, TYPES } from '@eclipse-glsp/sprotty'; +import { KeyboardGridCellSelectedAction, KeyboardGridKeyboardEventAction } from '../keyboard-grid/action'; import { DeselectKeyTool } from './deselect-key-tool'; import { MovementKeyTool } from './movement-key-tool'; import { ZoomKeyTool } from './zoom-key-tool'; -import { KeyboardGridCellSelectedAction, KeyboardGridKeyboardEventAction } from '../keyboard-grid/action'; -export const viewKeyToolsModule = new FeatureModule((bind, _unbind, isBound, rebind) => { - const context = { bind, isBound, rebind }; - configureViewKeyTools(context); -}); +export const viewKeyToolsModule = new FeatureModule( + (bind, _unbind, isBound, rebind) => { + const context = { bind, isBound, rebind }; + configureViewKeyTools(context); + }, + { + featureId: Symbol('viewKeyTools') + } +); export function configureViewKeyTools(context: Pick): void { bindAsService(context, TYPES.IDefaultTool, MovementKeyTool); diff --git a/packages/client/src/features/bounds/bounds-module.ts b/packages/client/src/features/bounds/bounds-module.ts index 0cd98911..d686ab89 100644 --- a/packages/client/src/features/bounds/bounds-module.ts +++ b/packages/client/src/features/bounds/bounds-module.ts @@ -35,24 +35,27 @@ import { LocalComputedBoundsCommand } from './local-bounds'; import { SetBoundsFeedbackCommand } from './set-bounds-feedback-command'; import { VBoxLayouterExt } from './vbox-layout'; -export const boundsModule = new FeatureModule((bind, _unbind, isBound, _rebind) => { - const context = { bind, isBound }; - configureCommand(context, SetBoundsCommand); - configureCommand(context, RequestBoundsCommand); - bind(HiddenBoundsUpdater).toSelf().inSingletonScope(); - bindAsService(context, TYPES.HiddenVNodePostprocessor, GLSPHiddenBoundsUpdater); +export const boundsModule = new FeatureModule( + (bind, _unbind, isBound, _rebind) => { + const context = { bind, isBound }; + configureCommand(context, SetBoundsCommand); + configureCommand(context, RequestBoundsCommand); + bind(HiddenBoundsUpdater).toSelf().inSingletonScope(); + bindAsService(context, TYPES.HiddenVNodePostprocessor, GLSPHiddenBoundsUpdater); - configureCommand(context, LocalComputedBoundsCommand); - configureCommand(context, SetBoundsFeedbackCommand); + configureCommand(context, LocalComputedBoundsCommand); + configureCommand(context, SetBoundsFeedbackCommand); - bind(TYPES.Layouter).to(LayouterExt).inSingletonScope(); - bind(TYPES.LayoutRegistry).to(LayoutRegistry).inSingletonScope(); + bind(TYPES.Layouter).to(LayouterExt).inSingletonScope(); + bind(TYPES.LayoutRegistry).to(LayoutRegistry).inSingletonScope(); - configureLayout(context, VBoxLayouter.KIND, VBoxLayouterExt); - configureLayout(context, HBoxLayouter.KIND, HBoxLayouterExt); - configureLayout(context, FreeFormLayouter.KIND, FreeFormLayouter); + configureLayout(context, VBoxLayouter.KIND, VBoxLayouterExt); + configureLayout(context, HBoxLayouter.KIND, HBoxLayouterExt); + configureLayout(context, FreeFormLayouter.KIND, FreeFormLayouter); - // backwards compatibility - // eslint-disable-next-line deprecation/deprecation - bind(PositionSnapper).toSelf(); -}); + // backwards compatibility + // eslint-disable-next-line deprecation/deprecation + bind(PositionSnapper).toSelf(); + }, + { featureId: Symbol('bounds') } +); diff --git a/packages/client/src/features/command-palette/command-palette-module.ts b/packages/client/src/features/command-palette/command-palette-module.ts index 3bbecd84..61f42281 100644 --- a/packages/client/src/features/command-palette/command-palette-module.ts +++ b/packages/client/src/features/command-palette/command-palette-module.ts @@ -19,9 +19,12 @@ import { GlspCommandPalette } from './command-palette'; import { CommandPaletteTool } from './command-palette-tool'; import { ServerCommandPaletteActionProvider } from './server-command-palette-provider'; -export const commandPaletteModule = new FeatureModule(bind => { - bindAsService(bind, TYPES.IUIExtension, GlspCommandPalette); - bind(TYPES.ICommandPaletteActionProviderRegistry).to(CommandPaletteActionProviderRegistry).inSingletonScope(); - bindAsService(bind, TYPES.ICommandPaletteActionProvider, ServerCommandPaletteActionProvider); - bindAsService(bind, TYPES.IDefaultTool, CommandPaletteTool); -}); +export const commandPaletteModule = new FeatureModule( + bind => { + bindAsService(bind, TYPES.IUIExtension, GlspCommandPalette); + bind(TYPES.ICommandPaletteActionProviderRegistry).to(CommandPaletteActionProviderRegistry).inSingletonScope(); + bindAsService(bind, TYPES.ICommandPaletteActionProvider, ServerCommandPaletteActionProvider); + bindAsService(bind, TYPES.IDefaultTool, CommandPaletteTool); + }, + { featureId: Symbol('commandPalette') } +); diff --git a/packages/client/src/features/context-menu/context-menu-module.ts b/packages/client/src/features/context-menu/context-menu-module.ts index 1ae7c371..46c69993 100644 --- a/packages/client/src/features/context-menu/context-menu-module.ts +++ b/packages/client/src/features/context-menu/context-menu-module.ts @@ -17,17 +17,20 @@ import { ContextMenuProviderRegistry, FeatureModule, IContextMenuService, TYPES, import { GLSPContextMenuMouseListener } from './glsp-context-menu-mouse-listener'; import { ServerContextMenuItemProvider } from './server-context-menu-provider'; -export const contextMenuModule = new FeatureModule(bind => { - bind(TYPES.IContextMenuServiceProvider).toProvider(ctx => async () => { - if (ctx.container.isBound(TYPES.IContextMenuService)) { - return ctx.container.get(TYPES.IContextMenuService); - } - console.warn("'TYPES.IContextMenuService' is not bound. Use no-op implementation instead"); - // eslint-disable-next-line @typescript-eslint/no-empty-function - return { show: () => {} }; - }); +export const contextMenuModule = new FeatureModule( + bind => { + bind(TYPES.IContextMenuServiceProvider).toProvider(ctx => async () => { + if (ctx.container.isBound(TYPES.IContextMenuService)) { + return ctx.container.get(TYPES.IContextMenuService); + } + console.warn("'TYPES.IContextMenuService' is not bound. Use no-op implementation instead"); + // eslint-disable-next-line @typescript-eslint/no-empty-function + return { show: () => {} }; + }); - bindAsService(bind, TYPES.MouseListener, GLSPContextMenuMouseListener); - bind(TYPES.IContextMenuProviderRegistry).to(ContextMenuProviderRegistry); - bindAsService(bind, TYPES.IContextMenuItemProvider, ServerContextMenuItemProvider); -}); + bindAsService(bind, TYPES.MouseListener, GLSPContextMenuMouseListener); + bind(TYPES.IContextMenuProviderRegistry).to(ContextMenuProviderRegistry); + bindAsService(bind, TYPES.IContextMenuItemProvider, ServerContextMenuItemProvider); + }, + { featureId: Symbol('contextMenu') } +); diff --git a/packages/client/src/features/copy-paste/copy-paste-modules.ts b/packages/client/src/features/copy-paste/copy-paste-modules.ts index 435a1506..1bb8d4f8 100644 --- a/packages/client/src/features/copy-paste/copy-paste-modules.ts +++ b/packages/client/src/features/copy-paste/copy-paste-modules.ts @@ -17,10 +17,13 @@ import { bindAsService, FeatureModule, TYPES } from '@eclipse-glsp/sprotty'; import { LocalClipboardService, ServerCopyPasteHandler } from './copy-paste-handler'; import { CopyPasteStartup } from './copy-paste-standalone'; -export const copyPasteModule = new FeatureModule((bind, _unbind, isBound) => { - bind(TYPES.ICopyPasteHandler).to(ServerCopyPasteHandler); - bind(TYPES.IAsyncClipboardService).to(LocalClipboardService).inSingletonScope(); -}); +export const copyPasteModule = new FeatureModule( + (bind, _unbind, isBound) => { + bind(TYPES.ICopyPasteHandler).to(ServerCopyPasteHandler); + bind(TYPES.IAsyncClipboardService).to(LocalClipboardService).inSingletonScope(); + }, + { featureId: Symbol('copyPaste') } +); /** * Feature module that is intended for the standalone deployment of GLSP (i.e. plain webapp) @@ -31,5 +34,8 @@ export const standaloneCopyPasteModule = new FeatureModule( (bind, _unbind, isBound) => { bindAsService(bind, TYPES.IDiagramStartup, CopyPasteStartup); }, - { requires: copyPasteModule } + { + featureId: Symbol('standaloneCopyPaste'), + requires: copyPasteModule + } ); diff --git a/packages/client/src/features/debug/debug-module.ts b/packages/client/src/features/debug/debug-module.ts index 0b633e75..5b2bdde5 100644 --- a/packages/client/src/features/debug/debug-module.ts +++ b/packages/client/src/features/debug/debug-module.ts @@ -20,13 +20,16 @@ import { DebugBoundsDecorator } from './debug-bounds-decorator'; import { DebugManager } from './debug-manager'; import { EnableDebugModeAction, EnableDebugModeCommand } from './debug-model'; -export const debugModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; +export const debugModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; - configureCommand(context, EnableDebugModeCommand); + configureCommand(context, EnableDebugModeCommand); - bind(DebugManager).toSelf().inSingletonScope(); - configureActionHandler(context, EnableDebugModeAction.KIND, DebugManager); + bind(DebugManager).toSelf().inSingletonScope(); + configureActionHandler(context, EnableDebugModeAction.KIND, DebugManager); - bindAsService(context, TYPES.IVNodePostprocessor, DebugBoundsDecorator); -}); + bindAsService(context, TYPES.IVNodePostprocessor, DebugBoundsDecorator); + }, + { featureId: Symbol('debug') } +); diff --git a/packages/client/src/features/decoration/decoration-module.ts b/packages/client/src/features/decoration/decoration-module.ts index c4865bd1..ad0fd8ed 100644 --- a/packages/client/src/features/decoration/decoration-module.ts +++ b/packages/client/src/features/decoration/decoration-module.ts @@ -17,6 +17,9 @@ import { FeatureModule, TYPES, bindAsService } from '@eclipse-glsp/sprotty'; import '../../../css/decoration.css'; import { GlspDecorationPlacer } from './decoration-placer'; -export const decorationModule = new FeatureModule(bind => { - bindAsService(bind, TYPES.IVNodePostprocessor, GlspDecorationPlacer); -}); +export const decorationModule = new FeatureModule( + bind => { + bindAsService(bind, TYPES.IVNodePostprocessor, GlspDecorationPlacer); + }, + { featureId: Symbol('decoration') } +); diff --git a/packages/client/src/features/element-template/element-template-module.ts b/packages/client/src/features/element-template/element-template-module.ts index 30082318..7325b7fc 100644 --- a/packages/client/src/features/element-template/element-template-module.ts +++ b/packages/client/src/features/element-template/element-template-module.ts @@ -17,8 +17,11 @@ import { FeatureModule, configureCommand } from '@eclipse-glsp/sprotty'; import { AddTemplateElementsFeedbackCommand } from './add-template-element'; import { RemoveTemplateElementsFeedbackCommand } from './remove-template-element'; -export const elementTemplateModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - configureCommand(context, AddTemplateElementsFeedbackCommand); - configureCommand(context, RemoveTemplateElementsFeedbackCommand); -}); +export const elementTemplateModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + configureCommand(context, AddTemplateElementsFeedbackCommand); + configureCommand(context, RemoveTemplateElementsFeedbackCommand); + }, + { featureId: Symbol('elementTemplate') } +); diff --git a/packages/client/src/features/export/export-modules.ts b/packages/client/src/features/export/export-modules.ts index 43bac9d4..e0c04e8c 100644 --- a/packages/client/src/features/export/export-modules.ts +++ b/packages/client/src/features/export/export-modules.ts @@ -46,5 +46,5 @@ export const standaloneExportModule = new FeatureModule( bind(ExportSvgActionHandler).toSelf().inSingletonScope(); configureActionHandler(context, ExportSvgAction.KIND, ExportSvgActionHandler); }, - { requires: exportModule } + { featureId: Symbol('standaloneExport'), requires: exportModule } ); diff --git a/packages/client/src/features/grid/grid-module.ts b/packages/client/src/features/grid/grid-module.ts index becda00c..1b20830a 100644 --- a/packages/client/src/features/grid/grid-module.ts +++ b/packages/client/src/features/grid/grid-module.ts @@ -20,15 +20,18 @@ import { GridManager } from './grid-manager'; import { ShowGridAction, ShowGridCommand } from './grid-model'; import { GridSnapper } from './grid-snapper'; -export const gridModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; +export const gridModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; - bind(TYPES.Grid).toConstantValue({ x: 10, y: 10 }); + bind(TYPES.Grid).toConstantValue({ x: 10, y: 10 }); - configureCommand(context, ShowGridCommand); + configureCommand(context, ShowGridCommand); - bind(GridManager).toSelf().inSingletonScope(); - configureActionHandler(context, ShowGridAction.KIND, GridManager); + bind(GridManager).toSelf().inSingletonScope(); + configureActionHandler(context, ShowGridAction.KIND, GridManager); - bind(TYPES.ISnapper).to(GridSnapper); -}); + bind(TYPES.ISnapper).to(GridSnapper); + }, + { featureId: Symbol('grid') } +); diff --git a/packages/client/src/features/helper-lines/helper-line-module.ts b/packages/client/src/features/helper-lines/helper-line-module.ts index 03436c9a..200dc169 100644 --- a/packages/client/src/features/helper-lines/helper-line-module.ts +++ b/packages/client/src/features/helper-lines/helper-line-module.ts @@ -31,17 +31,20 @@ import { HelperLineManager } from './helper-line-manager-default'; import { HELPER_LINE, HelperLine, SELECTION_BOUNDS, SelectionBounds } from './model'; import { HelperLineView, SelectionBoundsView } from './view'; -export const helperLineModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - configureModelElement(context, HELPER_LINE, HelperLine, HelperLineView); - configureModelElement(context, SELECTION_BOUNDS, SelectionBounds, SelectionBoundsView); - configureCommand(context, DrawHelperLinesFeedbackCommand); - configureCommand(context, RemoveHelperLinesFeedbackCommand); +export const helperLineModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + configureModelElement(context, HELPER_LINE, HelperLine, HelperLineView); + configureModelElement(context, SELECTION_BOUNDS, SelectionBounds, SelectionBoundsView); + configureCommand(context, DrawHelperLinesFeedbackCommand); + configureCommand(context, RemoveHelperLinesFeedbackCommand); - bindAsService(bind, TYPES.IHelperLineManager, HelperLineManager); - configureActionHandler(context, SetBoundsAction.KIND, TYPES.IHelperLineManager); - configureActionHandler(context, SetBoundsFeedbackAction.KIND, TYPES.IHelperLineManager); - configureActionHandler(context, MoveAction.KIND, TYPES.IHelperLineManager); - configureActionHandler(context, MoveInitializedEventAction.KIND, TYPES.IHelperLineManager); - configureActionHandler(context, MoveFinishedEventAction.KIND, TYPES.IHelperLineManager); -}); + bindAsService(bind, TYPES.IHelperLineManager, HelperLineManager); + configureActionHandler(context, SetBoundsAction.KIND, TYPES.IHelperLineManager); + configureActionHandler(context, SetBoundsFeedbackAction.KIND, TYPES.IHelperLineManager); + configureActionHandler(context, MoveAction.KIND, TYPES.IHelperLineManager); + configureActionHandler(context, MoveInitializedEventAction.KIND, TYPES.IHelperLineManager); + configureActionHandler(context, MoveFinishedEventAction.KIND, TYPES.IHelperLineManager); + }, + { featureId: Symbol('helperLine') } +); diff --git a/packages/client/src/features/hints/type-hints-module.ts b/packages/client/src/features/hints/type-hints-module.ts index 0da5be71..970b2b7d 100644 --- a/packages/client/src/features/hints/type-hints-module.ts +++ b/packages/client/src/features/hints/type-hints-module.ts @@ -16,10 +16,13 @@ import { FeatureModule, SetTypeHintsAction, TYPES, bindAsService, configureActionHandler, configureCommand } from '@eclipse-glsp/sprotty'; import { ApplyTypeHintsCommand, TypeHintProvider } from './type-hint-provider'; -export const typeHintsModule = new FeatureModule((bind, unbind, isBound) => { - const context = { bind, unbind, isBound }; - bindAsService(context, TYPES.ITypeHintProvider, TypeHintProvider); - bind(TYPES.IDiagramStartup).toService(TypeHintProvider); - configureActionHandler(context, SetTypeHintsAction.KIND, TypeHintProvider); - configureCommand(context, ApplyTypeHintsCommand); -}); +export const typeHintsModule = new FeatureModule( + (bind, unbind, isBound) => { + const context = { bind, unbind, isBound }; + bindAsService(context, TYPES.ITypeHintProvider, TypeHintProvider); + bind(TYPES.IDiagramStartup).toService(TypeHintProvider); + configureActionHandler(context, SetTypeHintsAction.KIND, TypeHintProvider); + configureCommand(context, ApplyTypeHintsCommand); + }, + { featureId: Symbol('typeHints') } +); diff --git a/packages/client/src/features/hover/hover-module.ts b/packages/client/src/features/hover/hover-module.ts index 454141e1..360f4faa 100644 --- a/packages/client/src/features/hover/hover-module.ts +++ b/packages/client/src/features/hover/hover-module.ts @@ -35,30 +35,33 @@ import { FocusStateChangedAction } from '../../base/focus/focus-state-change-act import { EnableDefaultToolsAction, EnableToolsAction } from '../../base/tool-manager/tool'; import { GlspHoverMouseListener } from './hover'; -export const hoverModule = new FeatureModule((bind, _unbind, isBound) => { - const context = { bind, isBound }; - bindAsService(context, TYPES.PopupVNodePostprocessor, PopupPositionUpdater); - bindAsService(context, TYPES.MouseListener, GlspHoverMouseListener); - bindAsService(context, TYPES.PopupMouseListener, PopupHoverMouseListener); - bindAsService(context, TYPES.KeyListener, HoverKeyListener); +export const hoverModule = new FeatureModule( + (bind, _unbind, isBound) => { + const context = { bind, isBound }; + bindAsService(context, TYPES.PopupVNodePostprocessor, PopupPositionUpdater); + bindAsService(context, TYPES.MouseListener, GlspHoverMouseListener); + bindAsService(context, TYPES.PopupMouseListener, PopupHoverMouseListener); + bindAsService(context, TYPES.KeyListener, HoverKeyListener); - bind(TYPES.HoverState).toConstantValue({ - mouseOverTimer: undefined, - mouseOutTimer: undefined, - popupOpen: false, - previousPopupElement: undefined - }); - bind(ClosePopupActionHandler).toSelf().inSingletonScope(); + bind(TYPES.HoverState).toConstantValue({ + mouseOverTimer: undefined, + mouseOutTimer: undefined, + popupOpen: false, + previousPopupElement: undefined + }); + bind(ClosePopupActionHandler).toSelf().inSingletonScope(); - configureCommand(context, HoverFeedbackCommand); - configureCommand(context, SetPopupModelCommand); - configureActionHandler(context, SetPopupModelCommand.KIND, ClosePopupActionHandler); - configureActionHandler(context, FitToScreenCommand.KIND, ClosePopupActionHandler); - configureActionHandler(context, CenterCommand.KIND, ClosePopupActionHandler); - configureActionHandler(context, SetViewportCommand.KIND, ClosePopupActionHandler); - configureActionHandler(context, MoveCommand.KIND, ClosePopupActionHandler); - configureActionHandler(context, FocusStateChangedAction.KIND, ClosePopupActionHandler); - configureActionHandler(context, EnableToolsAction.KIND, GlspHoverMouseListener); - configureActionHandler(context, EnableDefaultToolsAction.KIND, GlspHoverMouseListener); - configureActionHandler(context, FocusStateChangedAction.KIND, GlspHoverMouseListener); -}); + configureCommand(context, HoverFeedbackCommand); + configureCommand(context, SetPopupModelCommand); + configureActionHandler(context, SetPopupModelCommand.KIND, ClosePopupActionHandler); + configureActionHandler(context, FitToScreenCommand.KIND, ClosePopupActionHandler); + configureActionHandler(context, CenterCommand.KIND, ClosePopupActionHandler); + configureActionHandler(context, SetViewportCommand.KIND, ClosePopupActionHandler); + configureActionHandler(context, MoveCommand.KIND, ClosePopupActionHandler); + configureActionHandler(context, FocusStateChangedAction.KIND, ClosePopupActionHandler); + configureActionHandler(context, EnableToolsAction.KIND, GlspHoverMouseListener); + configureActionHandler(context, EnableDefaultToolsAction.KIND, GlspHoverMouseListener); + configureActionHandler(context, FocusStateChangedAction.KIND, GlspHoverMouseListener); + }, + { featureId: Symbol('hover') } +); diff --git a/packages/client/src/features/label-edit-ui/label-edit-ui-module.ts b/packages/client/src/features/label-edit-ui/label-edit-ui-module.ts index 3b204b1d..0a4a3844 100644 --- a/packages/client/src/features/label-edit-ui/label-edit-ui-module.ts +++ b/packages/client/src/features/label-edit-ui/label-edit-ui-module.ts @@ -16,9 +16,12 @@ import { EditLabelAction, EditLabelActionHandler, FeatureModule, TYPES, configureActionHandler } from '@eclipse-glsp/sprotty'; import { GlspEditLabelUI } from './label-edit-ui'; -export const labelEditUiModule = new FeatureModule((bind, unbind, isBound, rebind, ...rest) => { - const context = { bind, unbind, isBound, rebind }; - configureActionHandler(context, EditLabelAction.KIND, EditLabelActionHandler); - bind(GlspEditLabelUI).toSelf().inSingletonScope(); - bind(TYPES.IUIExtension).toService(GlspEditLabelUI); -}); +export const labelEditUiModule = new FeatureModule( + (bind, unbind, isBound, rebind, ...rest) => { + const context = { bind, unbind, isBound, rebind }; + configureActionHandler(context, EditLabelAction.KIND, EditLabelActionHandler); + bind(GlspEditLabelUI).toSelf().inSingletonScope(); + bind(TYPES.IUIExtension).toService(GlspEditLabelUI); + }, + { featureId: Symbol('labelEditUi') } +); diff --git a/packages/client/src/features/label-edit/label-edit-module.ts b/packages/client/src/features/label-edit/label-edit-module.ts index 2e2ed1a3..90460abf 100644 --- a/packages/client/src/features/label-edit/label-edit-module.ts +++ b/packages/client/src/features/label-edit/label-edit-module.ts @@ -17,9 +17,12 @@ import { ApplyLabelEditCommand, FeatureModule, TYPES, bindAsService, configureCo import { DirectLabelEditTool } from './edit-label-tool'; import { BalloonLabelValidationDecorator, ServerEditLabelValidator } from './edit-label-validator'; -export const labelEditModule = new FeatureModule((bind, _unbind, isBound, _rebind) => { - bind(TYPES.IEditLabelValidator).to(ServerEditLabelValidator); - bind(TYPES.IEditLabelValidationDecorator).to(BalloonLabelValidationDecorator); - bindAsService(bind, TYPES.IDefaultTool, DirectLabelEditTool); - configureCommand({ bind, isBound }, ApplyLabelEditCommand); -}); +export const labelEditModule = new FeatureModule( + (bind, _unbind, isBound, _rebind) => { + bind(TYPES.IEditLabelValidator).to(ServerEditLabelValidator); + bind(TYPES.IEditLabelValidationDecorator).to(BalloonLabelValidationDecorator); + bindAsService(bind, TYPES.IDefaultTool, DirectLabelEditTool); + configureCommand({ bind, isBound }, ApplyLabelEditCommand); + }, + { featureId: Symbol('labelEdit') } +); diff --git a/packages/client/src/features/layout/layout-module.ts b/packages/client/src/features/layout/layout-module.ts index a05828d9..8b7df50d 100644 --- a/packages/client/src/features/layout/layout-module.ts +++ b/packages/client/src/features/layout/layout-module.ts @@ -21,8 +21,11 @@ import { ResizeElementsActionHandler } from './layout-elements-action'; -export const layoutModule = new FeatureModule((bind, _unbind, isBound) => { - const context = { bind, isBound }; - configureActionHandler(context, ResizeElementsAction.KIND, ResizeElementsActionHandler); - configureActionHandler(context, AlignElementsAction.KIND, AlignElementsActionHandler); -}); +export const layoutModule = new FeatureModule( + (bind, _unbind, isBound) => { + const context = { bind, isBound }; + configureActionHandler(context, ResizeElementsAction.KIND, ResizeElementsActionHandler); + configureActionHandler(context, AlignElementsAction.KIND, AlignElementsActionHandler); + }, + { featureId: Symbol('layout') } +); diff --git a/packages/client/src/features/navigation/navigation-module.ts b/packages/client/src/features/navigation/navigation-module.ts index 36d10244..40fe7bfd 100644 --- a/packages/client/src/features/navigation/navigation-module.ts +++ b/packages/client/src/features/navigation/navigation-module.ts @@ -17,11 +17,14 @@ import { FeatureModule, NavigateToExternalTargetAction, NavigateToTargetAction, import { NavigateAction, NavigationActionHandler, ProcessNavigationArgumentsAction } from './navigation-action-handler'; import { NavigationTargetResolver } from './navigation-target-resolver'; -export const navigationModule = new FeatureModule((bind, _unbind, isBound) => { - bind(NavigationTargetResolver).toSelf().inSingletonScope(); - bind(NavigationActionHandler).toSelf().inSingletonScope(); - configureActionHandler({ bind, isBound }, NavigateAction.KIND, NavigationActionHandler); - configureActionHandler({ bind, isBound }, NavigateToTargetAction.KIND, NavigationActionHandler); - configureActionHandler({ bind, isBound }, ProcessNavigationArgumentsAction.KIND, NavigationActionHandler); - configureActionHandler({ bind, isBound }, NavigateToExternalTargetAction.KIND, NavigationActionHandler); -}); +export const navigationModule = new FeatureModule( + (bind, _unbind, isBound) => { + bind(NavigationTargetResolver).toSelf().inSingletonScope(); + bind(NavigationActionHandler).toSelf().inSingletonScope(); + configureActionHandler({ bind, isBound }, NavigateAction.KIND, NavigationActionHandler); + configureActionHandler({ bind, isBound }, NavigateToTargetAction.KIND, NavigationActionHandler); + configureActionHandler({ bind, isBound }, ProcessNavigationArgumentsAction.KIND, NavigationActionHandler); + configureActionHandler({ bind, isBound }, NavigateToExternalTargetAction.KIND, NavigationActionHandler); + }, + { featureId: Symbol('navigation') } +); diff --git a/packages/client/src/features/routing/routing-module.ts b/packages/client/src/features/routing/routing-module.ts index a31e4e73..79851783 100644 --- a/packages/client/src/features/routing/routing-module.ts +++ b/packages/client/src/features/routing/routing-module.ts @@ -33,25 +33,28 @@ import { } from '@eclipse-glsp/sprotty'; import { GLSPBezierEdgeRouter, GLSPManhattanEdgeRouter, GLSPPolylineEdgeRouter } from './edge-router'; -export const routingModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - bind(EdgeRouterRegistry).toSelf().inSingletonScope(); - bind(AnchorComputerRegistry).toSelf().inSingletonScope(); +export const routingModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + bind(EdgeRouterRegistry).toSelf().inSingletonScope(); + bind(AnchorComputerRegistry).toSelf().inSingletonScope(); - bindAsService(context, TYPES.IEdgeRouter, GLSPManhattanEdgeRouter); - bindAsService(context, TYPES.IAnchorComputer, ManhattanEllipticAnchor); - bindAsService(context, TYPES.IAnchorComputer, ManhattanRectangularAnchor); - bindAsService(context, TYPES.IAnchorComputer, ManhattanDiamondAnchor); + bindAsService(context, TYPES.IEdgeRouter, GLSPManhattanEdgeRouter); + bindAsService(context, TYPES.IAnchorComputer, ManhattanEllipticAnchor); + bindAsService(context, TYPES.IAnchorComputer, ManhattanRectangularAnchor); + bindAsService(context, TYPES.IAnchorComputer, ManhattanDiamondAnchor); - bindAsService(context, TYPES.IEdgeRouter, GLSPPolylineEdgeRouter); - bindAsService(context, TYPES.IAnchorComputer, EllipseAnchor); - bindAsService(context, TYPES.IAnchorComputer, RectangleAnchor); - bindAsService(context, TYPES.IAnchorComputer, DiamondAnchor); + bindAsService(context, TYPES.IEdgeRouter, GLSPPolylineEdgeRouter); + bindAsService(context, TYPES.IAnchorComputer, EllipseAnchor); + bindAsService(context, TYPES.IAnchorComputer, RectangleAnchor); + bindAsService(context, TYPES.IAnchorComputer, DiamondAnchor); - bindAsService(context, TYPES.IEdgeRouter, GLSPBezierEdgeRouter); - bindAsService(context, TYPES.IAnchorComputer, BezierEllipseAnchor); - bindAsService(context, TYPES.IAnchorComputer, BezierRectangleAnchor); - bindAsService(context, TYPES.IAnchorComputer, BezierDiamondAnchor); + bindAsService(context, TYPES.IEdgeRouter, GLSPBezierEdgeRouter); + bindAsService(context, TYPES.IAnchorComputer, BezierEllipseAnchor); + bindAsService(context, TYPES.IAnchorComputer, BezierRectangleAnchor); + bindAsService(context, TYPES.IAnchorComputer, BezierDiamondAnchor); - configureCommand({ bind, isBound }, AddRemoveBezierSegmentCommand); -}); + configureCommand({ bind, isBound }, AddRemoveBezierSegmentCommand); + }, + { featureId: Symbol('routing') } +); diff --git a/packages/client/src/features/save/save-module.ts b/packages/client/src/features/save/save-module.ts index c030660e..5a97c2d9 100644 --- a/packages/client/src/features/save/save-module.ts +++ b/packages/client/src/features/save/save-module.ts @@ -21,6 +21,9 @@ import { SaveModelKeyboardListener } from './save-keylistener'; * When integrated into an application frame (e.g Theia/VS Code) this module is typically omitted and/or replaced * with an application native module. */ -export const saveModule = new FeatureModule(bind => { - bindAsService(bind, TYPES.KeyListener, SaveModelKeyboardListener); -}); +export const saveModule = new FeatureModule( + bind => { + bindAsService(bind, TYPES.KeyListener, SaveModelKeyboardListener); + }, + { featureId: Symbol('save') } +); diff --git a/packages/client/src/features/select/select-module.ts b/packages/client/src/features/select/select-module.ts index ef578807..6bf147d4 100644 --- a/packages/client/src/features/select/select-module.ts +++ b/packages/client/src/features/select/select-module.ts @@ -18,13 +18,16 @@ import { SelectAllCommand, SelectCommand } from '../../base/selection-service'; import { SelectFeedbackCommand } from './select-feedback-command'; import { RankedSelectMouseListener } from './select-mouse-listener'; -export const selectModule = new FeatureModule((bind, _unbind, isBound) => { - const context = { bind, isBound }; - configureCommand(context, SelectCommand); - configureCommand(context, SelectAllCommand); - configureCommand(context, SelectFeedbackCommand); - bindAsService(context, TYPES.MouseListener, RankedSelectMouseListener); -}); +export const selectModule = new FeatureModule( + (bind, _unbind, isBound) => { + const context = { bind, isBound }; + configureCommand(context, SelectCommand); + configureCommand(context, SelectAllCommand); + configureCommand(context, SelectFeedbackCommand); + bindAsService(context, TYPES.MouseListener, RankedSelectMouseListener); + }, + { featureId: Symbol('select') } +); /** * Feature module that is intended for the standalone deployment of GLSP (i.e. plain webapp) @@ -35,5 +38,5 @@ export const standaloneSelectModule = new FeatureModule( bind => { bindAsService(bind, TYPES.KeyListener, SelectKeyboardListener); }, - { requires: selectModule } + { featureId: Symbol('standaloneSelect'), requires: selectModule } ); diff --git a/packages/client/src/features/source-model-watcher/source-model-watcher-module.ts b/packages/client/src/features/source-model-watcher/source-model-watcher-module.ts index 747cae26..212cbf44 100644 --- a/packages/client/src/features/source-model-watcher/source-model-watcher-module.ts +++ b/packages/client/src/features/source-model-watcher/source-model-watcher-module.ts @@ -16,6 +16,9 @@ import { FeatureModule, SourceModelChangedAction, configureActionHandler } from '@eclipse-glsp/sprotty'; import { SourceModelChangedActionHandler } from './source-model-changed-action-handler'; -export const sourceModelWatcherModule = new FeatureModule((bind, _unbind, isBound) => { - configureActionHandler({ bind, isBound }, SourceModelChangedAction.KIND, SourceModelChangedActionHandler); -}); +export const sourceModelWatcherModule = new FeatureModule( + (bind, _unbind, isBound) => { + configureActionHandler({ bind, isBound }, SourceModelChangedAction.KIND, SourceModelChangedActionHandler); + }, + { featureId: Symbol('sourceModelWatcher') } +); diff --git a/packages/client/src/features/status/status-module.ts b/packages/client/src/features/status/status-module.ts index f9ee3418..3ec9672f 100644 --- a/packages/client/src/features/status/status-module.ts +++ b/packages/client/src/features/status/status-module.ts @@ -18,9 +18,12 @@ import { FeatureModule, StatusAction, TYPES, bindAsService, configureActionHandl import '../../../css/status-overlay.css'; import { StatusOverlay } from './status-overlay'; -export const statusModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - bindAsService(context, TYPES.IUIExtension, StatusOverlay); - bind(TYPES.IDiagramStartup).toService(StatusOverlay); - configureActionHandler(context, StatusAction.KIND, StatusOverlay); -}); +export const statusModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + bindAsService(context, TYPES.IUIExtension, StatusOverlay); + bind(TYPES.IDiagramStartup).toService(StatusOverlay); + configureActionHandler(context, StatusAction.KIND, StatusOverlay); + }, + { featureId: Symbol('status') } +); diff --git a/packages/client/src/features/svg-metadata/svg-metadata-module.ts b/packages/client/src/features/svg-metadata/svg-metadata-module.ts index 2d282053..cbab06aa 100644 --- a/packages/client/src/features/svg-metadata/svg-metadata-module.ts +++ b/packages/client/src/features/svg-metadata/svg-metadata-module.ts @@ -17,7 +17,10 @@ import { FeatureModule, TYPES } from '@eclipse-glsp/sprotty'; import { MetadataPlacer } from './metadata-placer'; -export const svgMetadataModule = new FeatureModule(bind => { - bind(MetadataPlacer).toSelf().inSingletonScope(); - bind(TYPES.IVNodePostprocessor).toService(MetadataPlacer); -}); +export const svgMetadataModule = new FeatureModule( + bind => { + bind(MetadataPlacer).toSelf().inSingletonScope(); + bind(TYPES.IVNodePostprocessor).toService(MetadataPlacer); + }, + { featureId: Symbol('svgMetadata') } +); diff --git a/packages/client/src/features/tool-palette/tool-palette-module.ts b/packages/client/src/features/tool-palette/tool-palette-module.ts index a8a4f4b1..f7dbf863 100644 --- a/packages/client/src/features/tool-palette/tool-palette-module.ts +++ b/packages/client/src/features/tool-palette/tool-palette-module.ts @@ -18,10 +18,13 @@ import '../../../css/tool-palette.css'; import { EnableDefaultToolsAction } from '../../base/tool-manager/tool'; import { ToolPalette } from './tool-palette'; -export const toolPaletteModule = new FeatureModule((bind, _unbind, isBound, _rebind) => { - bindAsService(bind, TYPES.IUIExtension, ToolPalette); - bind(TYPES.IDiagramStartup).toService(ToolPalette); - configureActionHandler({ bind, isBound }, EnableDefaultToolsAction.KIND, ToolPalette); - configureActionHandler({ bind, isBound }, UpdateModelAction.KIND, ToolPalette); - configureActionHandler({ bind, isBound }, SetModelAction.KIND, ToolPalette); -}); +export const toolPaletteModule = new FeatureModule( + (bind, _unbind, isBound, _rebind) => { + bindAsService(bind, TYPES.IUIExtension, ToolPalette); + bind(TYPES.IDiagramStartup).toService(ToolPalette); + configureActionHandler({ bind, isBound }, EnableDefaultToolsAction.KIND, ToolPalette); + configureActionHandler({ bind, isBound }, UpdateModelAction.KIND, ToolPalette); + configureActionHandler({ bind, isBound }, SetModelAction.KIND, ToolPalette); + }, + { featureId: Symbol('toolPalette') } +); diff --git a/packages/client/src/features/tools/change-bounds/change-bounds-tool-module.ts b/packages/client/src/features/tools/change-bounds/change-bounds-tool-module.ts index e20655c6..9ca32eb0 100644 --- a/packages/client/src/features/tools/change-bounds/change-bounds-tool-module.ts +++ b/packages/client/src/features/tools/change-bounds/change-bounds-tool-module.ts @@ -21,11 +21,14 @@ import { ChangeBoundsTool } from './change-bounds-tool'; import { HideChangeBoundsToolResizeFeedbackCommand, ShowChangeBoundsToolResizeFeedbackCommand } from './change-bounds-tool-feedback'; import { SResizeHandleView } from './view'; -export const changeBoundsToolModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - bind(ChangeBoundsManager).toSelf().inSingletonScope(); - bindAsService(context, TYPES.IDefaultTool, ChangeBoundsTool); - configureCommand(context, ShowChangeBoundsToolResizeFeedbackCommand); - configureCommand(context, HideChangeBoundsToolResizeFeedbackCommand); - configureView(context, SResizeHandle.TYPE, SResizeHandleView); -}); +export const changeBoundsToolModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + bind(ChangeBoundsManager).toSelf().inSingletonScope(); + bindAsService(context, TYPES.IDefaultTool, ChangeBoundsTool); + configureCommand(context, ShowChangeBoundsToolResizeFeedbackCommand); + configureCommand(context, HideChangeBoundsToolResizeFeedbackCommand); + configureView(context, SResizeHandle.TYPE, SResizeHandleView); + }, + { featureId: Symbol('changeBoundsTool') } +); diff --git a/packages/client/src/features/tools/deletion/deletion-tool-module.ts b/packages/client/src/features/tools/deletion/deletion-tool-module.ts index 15811484..444a5cb5 100644 --- a/packages/client/src/features/tools/deletion/deletion-tool-module.ts +++ b/packages/client/src/features/tools/deletion/deletion-tool-module.ts @@ -16,8 +16,11 @@ import { FeatureModule, TYPES, bindAsService } from '@eclipse-glsp/sprotty'; import { DelKeyDeleteTool, MouseDeleteTool } from './delete-tool'; -export const deletionToolModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - bindAsService(context, TYPES.IDefaultTool, DelKeyDeleteTool); - bindAsService(context, TYPES.ITool, MouseDeleteTool); -}); +export const deletionToolModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + bindAsService(context, TYPES.IDefaultTool, DelKeyDeleteTool); + bindAsService(context, TYPES.ITool, MouseDeleteTool); + }, + { featureId: Symbol('deletionTool') } +); diff --git a/packages/client/src/features/tools/edge-creation/edege-creation-module.ts b/packages/client/src/features/tools/edge-creation/edege-creation-module.ts index 78d2ee5a..dd605a70 100644 --- a/packages/client/src/features/tools/edge-creation/edege-creation-module.ts +++ b/packages/client/src/features/tools/edge-creation/edege-creation-module.ts @@ -17,9 +17,12 @@ import { FeatureModule, TYPES, TriggerEdgeCreationAction, bindAsService, configu import { configureDanglingFeedbackEdge } from './dangling-edge-feedback'; import { EdgeCreationTool } from './edge-creation-tool'; -export const edgeCreationToolModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - bindAsService(context, TYPES.ITool, EdgeCreationTool); - configureActionHandler(context, TriggerEdgeCreationAction.KIND, EdgeCreationTool); - configureDanglingFeedbackEdge(context); -}); +export const edgeCreationToolModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + bindAsService(context, TYPES.ITool, EdgeCreationTool); + configureActionHandler(context, TriggerEdgeCreationAction.KIND, EdgeCreationTool); + configureDanglingFeedbackEdge(context); + }, + { featureId: Symbol('edgeCreationTool') } +); diff --git a/packages/client/src/features/tools/edge-edit/edge-edit-module.ts b/packages/client/src/features/tools/edge-edit/edge-edit-module.ts index f7c77527..42aa7a2d 100644 --- a/packages/client/src/features/tools/edge-edit/edge-edit-module.ts +++ b/packages/client/src/features/tools/edge-edit/edge-edit-module.ts @@ -23,16 +23,19 @@ import { SwitchRoutingModeCommand } from './edge-edit-tool-feedback'; -export const edgeEditToolModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - bindAsService(context, TYPES.IDefaultTool, EdgeEditTool); +export const edgeEditToolModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + bindAsService(context, TYPES.IDefaultTool, EdgeEditTool); - // reconnect edge tool feedback - configureCommand(context, ShowEdgeReconnectHandlesFeedbackCommand); - configureCommand(context, HideEdgeReconnectHandlesFeedbackCommand); - configureCommand(context, DrawFeedbackEdgeSourceCommand); - configureCommand(context, SwitchRoutingModeCommand); + // reconnect edge tool feedback + configureCommand(context, ShowEdgeReconnectHandlesFeedbackCommand); + configureCommand(context, HideEdgeReconnectHandlesFeedbackCommand); + configureCommand(context, DrawFeedbackEdgeSourceCommand); + configureCommand(context, SwitchRoutingModeCommand); - // dangling edge feedback - configureDanglingFeedbackEdge(context); -}); + // dangling edge feedback + configureDanglingFeedbackEdge(context); + }, + { featureId: Symbol('edgeEditTool') } +); diff --git a/packages/client/src/features/tools/marquee-selection/marquee-selection-module.ts b/packages/client/src/features/tools/marquee-selection/marquee-selection-module.ts index 6a7998b6..43a4a2b3 100644 --- a/packages/client/src/features/tools/marquee-selection/marquee-selection-module.ts +++ b/packages/client/src/features/tools/marquee-selection/marquee-selection-module.ts @@ -20,13 +20,16 @@ import { DrawMarqueeCommand, MARQUEE, RemoveMarqueeCommand } from './marquee-too import { MarqueeNode } from './model'; import { MarqueeView } from './view'; -export const marqueeSelectionToolModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - bindAsService(context, TYPES.IDefaultTool, MarqueeTool); - bindAsService(context, TYPES.ITool, MarqueeMouseTool); +export const marqueeSelectionToolModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + bindAsService(context, TYPES.IDefaultTool, MarqueeTool); + bindAsService(context, TYPES.ITool, MarqueeMouseTool); - configureCommand(context, DrawMarqueeCommand); - configureCommand(context, RemoveMarqueeCommand); + configureCommand(context, DrawMarqueeCommand); + configureCommand(context, RemoveMarqueeCommand); - configureModelElement(context, MARQUEE, MarqueeNode, MarqueeView); -}); + configureModelElement(context, MARQUEE, MarqueeNode, MarqueeView); + }, + { featureId: Symbol('marqueeSelectionTool') } +); diff --git a/packages/client/src/features/tools/node-creation/node-creation-module.ts b/packages/client/src/features/tools/node-creation/node-creation-module.ts index 6d17ad52..d26e9454 100644 --- a/packages/client/src/features/tools/node-creation/node-creation-module.ts +++ b/packages/client/src/features/tools/node-creation/node-creation-module.ts @@ -35,5 +35,8 @@ export const nodeCreationToolModule = new FeatureModule( configureActionHandler(context, TriggerNodeCreationAction.KIND, NodeCreationTool); configureModelElement(context, InsertIndicator.TYPE, InsertIndicator, InsertIndicatorView); }, - { requires: elementTemplateModule } + { + featureId: Symbol('nodeCreationTool'), + requires: elementTemplateModule + } ); diff --git a/packages/client/src/features/tools/tool-focus-loss-module.ts b/packages/client/src/features/tools/tool-focus-loss-module.ts index 1f740a54..e83a7812 100644 --- a/packages/client/src/features/tools/tool-focus-loss-module.ts +++ b/packages/client/src/features/tools/tool-focus-loss-module.ts @@ -13,8 +13,8 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { injectable } from 'inversify'; import { Action, FeatureModule, IActionHandler, ICommand, configureActionHandler } from '@eclipse-glsp/sprotty'; +import { injectable } from 'inversify'; import { FocusStateChangedAction } from '../../base/focus/focus-state-change-action'; import { EnableDefaultToolsAction } from '../../base/tool-manager/tool'; @@ -34,6 +34,9 @@ export class EnableDefaultToolsOnFocusLossHandler implements IActionHandler { /** * Enables the default tools in the tool manager if the diagram looses focus. */ -export const toolFocusLossModule = new FeatureModule((bind, _unbind, isBound) => { - configureActionHandler({ bind, isBound }, FocusStateChangedAction.KIND, EnableDefaultToolsOnFocusLossHandler); -}); +export const toolFocusLossModule = new FeatureModule( + (bind, _unbind, isBound) => { + configureActionHandler({ bind, isBound }, FocusStateChangedAction.KIND, EnableDefaultToolsOnFocusLossHandler); + }, + { featureId: Symbol('toolFocusLoss ') } +); diff --git a/packages/client/src/features/validation/validation-modules.ts b/packages/client/src/features/validation/validation-modules.ts index 3f785608..6dacf574 100644 --- a/packages/client/src/features/validation/validation-modules.ts +++ b/packages/client/src/features/validation/validation-modules.ts @@ -25,19 +25,25 @@ import { } from './marker-navigator'; import { ApplyMarkersCommand, DeleteMarkersCommand, SetMarkersActionHandler, ValidationFeedbackEmitter } from './validate'; -export const validationModule = new FeatureModule((bind, _unbind, isBound) => { - const context = { bind, isBound }; - configureActionHandler(context, SetMarkersAction.KIND, SetMarkersActionHandler); - configureCommand(context, ApplyMarkersCommand); - configureCommand(context, DeleteMarkersCommand); - bind(ValidationFeedbackEmitter).toSelf().inSingletonScope(); -}); +export const validationModule = new FeatureModule( + (bind, _unbind, isBound) => { + const context = { bind, isBound }; + configureActionHandler(context, SetMarkersAction.KIND, SetMarkersActionHandler); + configureCommand(context, ApplyMarkersCommand); + configureCommand(context, DeleteMarkersCommand); + bind(ValidationFeedbackEmitter).toSelf().inSingletonScope(); + }, + { featureId: Symbol('validation') } +); -export const markerNavigatorModule = new FeatureModule((bind, _unbind, isBound) => { - bind(GModelElementComparator).to(LeftToRightTopToBottomComparator).inSingletonScope(); - bind(MarkerNavigator).toSelf().inSingletonScope(); - configureActionHandler({ bind, isBound }, NavigateToMarkerAction.KIND, NavigateToMarkerActionHandler); -}); +export const markerNavigatorModule = new FeatureModule( + (bind, _unbind, isBound) => { + bind(GModelElementComparator).to(LeftToRightTopToBottomComparator).inSingletonScope(); + bind(MarkerNavigator).toSelf().inSingletonScope(); + configureActionHandler({ bind, isBound }, NavigateToMarkerAction.KIND, NavigateToMarkerActionHandler); + }, + { featureId: Symbol('markerNavigator') } +); /** * Feature module that is intended for the standalone deployment of GLSP (i.e. plain webapp) @@ -49,5 +55,5 @@ export const standaloneMarkerNavigatorModule = new FeatureModule( bindAsService(bind, TYPES.IContextMenuProvider, MarkerNavigatorContextMenuItemProvider); bindAsService(bind, TYPES.KeyListener, MarkerNavigatorKeyListener); }, - { requires: markerNavigatorModule } + { featureId: Symbol('standaloneMarkerNavigator'), requires: markerNavigatorModule } ); diff --git a/packages/client/src/features/viewport/viewport-modules.ts b/packages/client/src/features/viewport/viewport-modules.ts index e2ea6733..7c86c7c0 100644 --- a/packages/client/src/features/viewport/viewport-modules.ts +++ b/packages/client/src/features/viewport/viewport-modules.ts @@ -33,25 +33,28 @@ import { OriginViewportCommand } from './origin-viewport'; import { RepositionCommand } from './reposition'; import { RestoreViewportHandler } from './viewport-handler'; -export const viewportModule = new FeatureModule((bind, _unbind, isBound) => { - const context = { bind, isBound }; - configureCommand(context, CenterCommand); - configureCommand(context, FitToScreenCommand); - configureCommand(context, GetViewportCommand); - configureCommand(context, SetViewportCommand); - configureCommand(context, RepositionCommand); - configureCommand(context, OriginViewportCommand); +export const viewportModule = new FeatureModule( + (bind, _unbind, isBound) => { + const context = { bind, isBound }; + configureCommand(context, CenterCommand); + configureCommand(context, FitToScreenCommand); + configureCommand(context, GetViewportCommand); + configureCommand(context, SetViewportCommand); + configureCommand(context, RepositionCommand); + configureCommand(context, OriginViewportCommand); - bindAsService(context, TYPES.MouseListener, ZoomMouseListener); - bindAsService(context, TYPES.MouseListener, GLSPScrollMouseListener); + bindAsService(context, TYPES.MouseListener, ZoomMouseListener); + bindAsService(context, TYPES.MouseListener, GLSPScrollMouseListener); - configureActionHandler(context, EnableToolsAction.KIND, GLSPScrollMouseListener); - configureActionHandler(context, EnableDefaultToolsAction.KIND, GLSPScrollMouseListener); + configureActionHandler(context, EnableToolsAction.KIND, GLSPScrollMouseListener); + configureActionHandler(context, EnableDefaultToolsAction.KIND, GLSPScrollMouseListener); - bindAsService(context, TYPES.IDiagramStartup, RestoreViewportHandler); - configureActionHandler(context, EnableDefaultToolsAction.KIND, RestoreViewportHandler); - configureActionHandler(context, FocusDomAction.KIND, RestoreViewportHandler); -}); + bindAsService(context, TYPES.IDiagramStartup, RestoreViewportHandler); + configureActionHandler(context, EnableDefaultToolsAction.KIND, RestoreViewportHandler); + configureActionHandler(context, FocusDomAction.KIND, RestoreViewportHandler); + }, + { featureId: Symbol('viewport') } +); /** * Feature module that is intended for the standalone deployment of GLSP (i.e. plain webapp) @@ -63,5 +66,5 @@ export const standaloneViewportModule = new FeatureModule( const context = { bind, isBound }; bindAsService(context, TYPES.KeyListener, CenterKeyboardListener); }, - { requires: viewportModule } + { featureId: Symbol('standaloneViewport'), requires: viewportModule } ); diff --git a/packages/client/src/standalone-modules.ts b/packages/client/src/standalone-modules.ts index cbbb8746..2c2a467a 100644 --- a/packages/client/src/standalone-modules.ts +++ b/packages/client/src/standalone-modules.ts @@ -42,15 +42,18 @@ import { undoRedoModule } from './features/undo-redo/undo-redo-module'; import { standaloneMarkerNavigatorModule } from './features/validation/validation-modules'; import { standaloneViewportModule } from './features/viewport/viewport-modules'; -export const standaloneDefaultModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - bind(FallbackActionHandler).toSelf().inSingletonScope(); - configureActionHandler(context, MessageAction.KIND, FallbackActionHandler); - configureActionHandler(context, StartProgressAction.KIND, FallbackActionHandler); - configureActionHandler(context, UpdateProgressAction.KIND, FallbackActionHandler); - configureActionHandler(context, EndProgressAction.KIND, FallbackActionHandler); - bindAsService(context, TYPES.KeyListener, LayoutKeyListener); -}); +export const standaloneDefaultModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + bind(FallbackActionHandler).toSelf().inSingletonScope(); + configureActionHandler(context, MessageAction.KIND, FallbackActionHandler); + configureActionHandler(context, StartProgressAction.KIND, FallbackActionHandler); + configureActionHandler(context, UpdateProgressAction.KIND, FallbackActionHandler); + configureActionHandler(context, EndProgressAction.KIND, FallbackActionHandler); + bindAsService(context, TYPES.KeyListener, LayoutKeyListener); + }, + { featureId: Symbol('standaloneDefault') } +); /** * A fallback action handler for actions sent by features that are currently not supported by diff --git a/packages/client/src/views/base-view-module.ts b/packages/client/src/views/base-view-module.ts index 3e198cf2..647fccc9 100644 --- a/packages/client/src/views/base-view-module.ts +++ b/packages/client/src/views/base-view-module.ts @@ -53,10 +53,13 @@ import { GGraphView } from './ggraph-view'; import { GIssueMarkerView } from './issue-marker-view'; import { RoundedCornerNodeView } from './rounded-corner-view'; -export const baseViewModule = new FeatureModule((bind, unbind, isBound, rebind) => { - const context = { bind, unbind, isBound, rebind }; - configureDefaultModelElements(context); -}); +export const baseViewModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + configureDefaultModelElements(context); + }, + { featureId: Symbol('baseView') } +); export function configureDefaultModelElements(context: Pick): void { // HTML elements diff --git a/packages/glsp-sprotty/package.json b/packages/glsp-sprotty/package.json index c2733bda..11035931 100644 --- a/packages/glsp-sprotty/package.json +++ b/packages/glsp-sprotty/package.json @@ -33,7 +33,7 @@ "watch": "tsc -w" }, "dependencies": { - "@eclipse-glsp/protocol": "^2.2.0-next", + "@eclipse-glsp/protocol": "2.2.0-next", "autocompleter": "^9.1.0", "snabbdom": "^3.5.1", "sprotty": "1.0.0", diff --git a/packages/glsp-sprotty/src/feature-modules.ts b/packages/glsp-sprotty/src/feature-modules.ts index aed1524b..169ec808 100644 --- a/packages/glsp-sprotty/src/feature-modules.ts +++ b/packages/glsp-sprotty/src/feature-modules.ts @@ -28,16 +28,16 @@ import sprottyUpdateModule from 'sprotty/lib/features/update/di.config'; import sprottyZorderModule from 'sprotty/lib/features/zorder/di.config'; import sprottyModelSourceModule from 'sprotty/lib/model-source/di.config'; -export const buttonModule = new FeatureModule(sprottyButtonModule.registry); -export const edgeEditModule = new FeatureModule(sprottyEdgeEditModule.registry); -export const edgeIntersectionModule = new FeatureModule(sprottyEdgeIntersectionModule.registry); -export const edgeLayoutModule = new FeatureModule(sprottyEdgeLayoutModule.registry); -export const expandModule = new FeatureModule(sprottyExpandModule.registry); -export const fadeModule = new FeatureModule(sprottyFadeModule.registry); -export const modelSourceModule = new FeatureModule(sprottyModelSourceModule.registry); -export const moveModule = new FeatureModule(sprottyMoveModule.registry); -export const openModule = new FeatureModule(sprottyOpenModule.registry); -export const updateModule = new FeatureModule(sprottyUpdateModule.registry); -export const zorderModule = new FeatureModule(sprottyZorderModule.registry); +export const buttonModule = new FeatureModule(sprottyButtonModule.registry, { featureId: Symbol('button') }); +export const edgeEditModule = new FeatureModule(sprottyEdgeEditModule.registry, { featureId: Symbol('edgeEdit') }); +export const edgeIntersectionModule = new FeatureModule(sprottyEdgeIntersectionModule.registry, { featureId: Symbol('edgeIntersection') }); +export const edgeLayoutModule = new FeatureModule(sprottyEdgeLayoutModule.registry, { featureId: Symbol('edgeLayout') }); +export const expandModule = new FeatureModule(sprottyExpandModule.registry, { featureId: Symbol('expand') }); +export const fadeModule = new FeatureModule(sprottyFadeModule.registry, { featureId: Symbol('fade') }); +export const modelSourceModule = new FeatureModule(sprottyModelSourceModule.registry, { featureId: Symbol('modelSource') }); +export const moveModule = new FeatureModule(sprottyMoveModule.registry, { featureId: Symbol('move') }); +export const openModule = new FeatureModule(sprottyOpenModule.registry, { featureId: Symbol('open') }); +export const updateModule = new FeatureModule(sprottyUpdateModule.registry, { featureId: Symbol('update') }); +export const zorderModule = new FeatureModule(sprottyZorderModule.registry, { featureId: Symbol('zorder') }); export { sprottyDefaultModule }; diff --git a/packages/protocol/src/di/container-configuration.spec.ts b/packages/protocol/src/di/container-configuration.spec.ts index 178b72c1..586c9dd8 100644 --- a/packages/protocol/src/di/container-configuration.spec.ts +++ b/packages/protocol/src/di/container-configuration.spec.ts @@ -15,53 +15,56 @@ ********************************************************************************/ import { expect } from 'chai'; import { Container } from 'inversify'; -import * as sinon from 'sinon'; -import { initializeContainer } from './container-configuration'; +import { resolveContainerConfiguration } from './container-configuration'; import { FeatureModule } from './feature-module'; -const sandbox = sinon.createSandbox(); -const container = new Container(); -const loadSpy = sandbox.spy(container, 'load'); -container.snapshot(); +const moduleA = new FeatureModule(() => {}, { featureId: Symbol('moduleA') }); +const moduleB = new FeatureModule(() => {}, { featureId: Symbol('moduleB') }); +const moduleC = new FeatureModule(() => {}, { featureId: Symbol('moduleC'), requires: [moduleA, moduleB] }); -const moduleA = new FeatureModule(() => {}); -const moduleB = new FeatureModule(() => {}); -const moduleC = new FeatureModule(() => {}); +FeatureModule.DEBUG_LOG_ENABLED = true; +const container = new Container(); +container.load(moduleC); describe('Container configuration', () => { - describe('initializeContainer', () => { - beforeEach(() => { - sandbox.reset(); - container.restore(); - container.snapshot(); - }); - it('should load the given container modules', () => { - initializeContainer(container, moduleA, moduleB, moduleC); - expect(loadSpy.calledOnce).to.equal(true); - expect(loadSpy.firstCall.args).to.deep.equal([moduleA, moduleB, moduleC]); + describe('resolveContainerConfiguration', () => { + it('should resolve the given container modules in incoming order', () => { + const result = resolveContainerConfiguration(moduleA, moduleB, moduleC); + expect(result).to.deep.equal([moduleA, moduleB, moduleC]); }); - it('should load the same container module only once', () => { - initializeContainer(container, moduleA, moduleA); - expect(loadSpy.calledOnce).to.equal(true); - expect(loadSpy.firstCall.args).to.deep.equal([moduleA]); + it('should resolve the same container module only once', () => { + const result = resolveContainerConfiguration(moduleA, moduleA); + expect(result).to.deep.equal([moduleA]); }); - it('should load the given container modules and add configurations', () => { - initializeContainer(container, moduleA, { add: [moduleB, moduleC] }); - expect(loadSpy.calledOnce).to.equal(true); - expect(loadSpy.firstCall.args).to.deep.equal([moduleA, moduleB, moduleC]); + it('should resolve the given container modules and add configurations', () => { + const result = resolveContainerConfiguration(moduleA, { add: [moduleB, moduleC] }); + expect(result).to.deep.equal([moduleA, moduleB, moduleC]); }); - it('should load the given container modules/add configurations and not load modules from remove configurations', () => { - initializeContainer(container, moduleA, { + it('should resolve the given container modules/add configurations and not load modules from remove configurations', () => { + const result = resolveContainerConfiguration(moduleA, { add: [moduleB, moduleC], remove: moduleA }); - expect(loadSpy.calledOnce).to.equal(true); - expect(loadSpy.firstCall.args).to.deep.equal([moduleB, moduleC]); + expect(result).to.deep.equal([moduleB, moduleC]); + }); + it('should resolve a module from a remove configuration if it is re-added with a subsequent add configuration', () => { + const result = resolveContainerConfiguration(moduleA, { remove: moduleA }, moduleA); + expect(result).to.deep.equal([moduleA]); + }); + it('should resolve a module from a replace configuration instead of a prior added module with the same feature id', () => { + const replaceModule = new FeatureModule(() => {}, { featureId: moduleA.featureId }); + const result = resolveContainerConfiguration(moduleA, moduleB, { replace: replaceModule }); + expect(result).to.deep.equal([replaceModule, moduleB]); + }); + // eslint-disable-next-line max-len + it('should still resolve a module from a replace configuration if there is no prior added module with the same featureId to replace', () => { + const replaceModule = new FeatureModule(() => {}, { featureId: Symbol('replaceModule') }); + const result = resolveContainerConfiguration(moduleA, moduleB, { replace: replaceModule }); + expect(result).to.deep.equal([moduleA, moduleB, replaceModule]); }); - it('should load a module from a remove configuration if it is added later again', () => { - initializeContainer(container, moduleA, { remove: moduleA }, moduleA); - expect(loadSpy.calledOnce).to.equal(true); - expect(loadSpy.firstCall.args).to.deep.equal([moduleA]); + it('should throw an error for a configuration that resolves to multiple feature modules with the same featureId', () => { + const duplicateModule = new FeatureModule(() => {}, { featureId: moduleA.featureId }); + expect(() => resolveContainerConfiguration(moduleA, duplicateModule)).to.throw(); }); }); }); diff --git a/packages/protocol/src/di/container-configuration.ts b/packages/protocol/src/di/container-configuration.ts index 230af51c..70f525d9 100644 --- a/packages/protocol/src/di/container-configuration.ts +++ b/packages/protocol/src/di/container-configuration.ts @@ -17,6 +17,7 @@ import { Container, ContainerModule } from 'inversify'; import { MaybeArray, asArray, distinctAdd, remove } from '../utils/array-util'; import { hasFunctionProp, hasNumberProp } from '../utils/type-util'; +import { FeatureModule } from './feature-module'; /** * Initializes a container with the given {@link ContainerConfiguration}. The container configuration @@ -36,8 +37,10 @@ export function initializeContainer(container: Container, ...containerConfigurat /** * Processes the given container configurations and returns the corresponding set of {@link ContainerModule}s. * Container configurations are processed in the order they are passed. If a module is configured to be removed - * it can be added again in a later configuration. - * @param containerConfigurations The container configurations to resolves + * it can be added again in a later configuration. This also means in case of `replace` configurations that affect the same feature id + * the last configuration wins. + * @param containerConfigurations The container configurations to resolve + * @throws An error if featureModule ids are not unique in the resolved module array * @returns an Array of resolved container modules */ export function resolveContainerConfiguration(...containerConfigurations: ContainerConfiguration): ContainerModule[] { @@ -52,8 +55,35 @@ export function resolveContainerConfiguration(...containerConfigurations: Contai if (config.add) { distinctAdd(modules, ...asArray(config.add)); } + if (config.replace) { + asArray(config.replace).forEach(replace => { + const existingIndex = modules.findIndex(m => m instanceof FeatureModule && m.featureId === replace.featureId); + if (existingIndex >= 0) { + modules[existingIndex] = replace; + } else { + distinctAdd(modules, replace); + } + }); + } + } + }); + + // Check for duplicate feature ids in resolved modules + const featureIds = new Set(); + const duplicates: FeatureModule[] = []; + modules.forEach(module => { + if (module instanceof FeatureModule) { + if (featureIds.has(module.featureId)) { + duplicates.push(module); + } else { + featureIds.add(module.featureId); + } } }); + if (duplicates.length > 0) { + const culprits = duplicates.map(m => m.featureId).join(', '); + throw new Error(`Could not resolve container configuration. Non-unique feature ids found in container configuration: ${culprits}`); + } return modules; } /** @@ -76,8 +106,15 @@ export type ContainerConfiguration = Array; /** Set of modules that should be loaded into the container */ remove?: MaybeArray; + /** + * Set of feature modules that should be loaded into the container and + * replace potential already configured modules with the same feature id. + * When resolving the replacement module will be added at the index of the module it replaces. + * If there is no module to replace, the replacement module will be added to the end of the list (i.e. behaves like `add`). + */ + replace?: MaybeArray; } diff --git a/packages/protocol/src/di/feature-module.spec.ts b/packages/protocol/src/di/feature-module.spec.ts index 0c562ea2..8210fc1b 100644 --- a/packages/protocol/src/di/feature-module.spec.ts +++ b/packages/protocol/src/di/feature-module.spec.ts @@ -70,6 +70,11 @@ describe('FeatureModule', () => { expect(container.isBound(moduleWithUnmetRequirements.featureId)).to.be.false; expect(container.isBound('Foo')).to.be.false; }); + it('Should throw an error if a feature module with the same featureId is already loaded', () => { + const loadedModule = new FeatureModule(() => {}, { featureId: moduleA.featureId }); + container.load(loadedModule); + expect(() => container.load(moduleA)).to.throw(); + }); }); describe('Multiple required modules', () => { it('Should load feature module with loaded required modules', () => { diff --git a/packages/protocol/src/di/feature-module.ts b/packages/protocol/src/di/feature-module.ts index 233cb2f0..a326b722 100644 --- a/packages/protocol/src/di/feature-module.ts +++ b/packages/protocol/src/di/feature-module.ts @@ -31,6 +31,7 @@ export interface FeatureModuleOptions { */ featureId?: symbol; } + /** * A `FeatureModule` is a specialized {@link ContainerModule} that can declare dependencies to other {@link FeatureModule}. * A feature module will only be loaded into a container if all of its required modules haven been loaded before. T @@ -39,6 +40,11 @@ export interface FeatureModuleOptions { */ export class FeatureModule extends ContainerModule { + /** + * Global flag to enable/disable additional debug log output when loading feature modules + * Default is `false`. + */ + public static DEBUG_LOG_ENABLED = false; readonly featureId: symbol; readonly requires?: MaybeArray; @@ -47,6 +53,7 @@ export class FeatureModule extends ContainerModule { super((bind, unbind, isBound, ...rest) => { if (this.configure(bind, isBound)) { registry(bind, unbind, isBound, ...rest); + this.debugLog(`Loading of feature module with id '${this.featureId.toString()}' completed`); } }); this.featureId = options.featureId ?? this.createFeatureId(); @@ -65,20 +72,45 @@ export class FeatureModule extends ContainerModule { * @returns `true` if all requirements are met and the module is loaded. `false` otherwise */ configure(bind: interfaces.Bind, isBound: interfaces.IsBound): boolean { + this.debugLog(`Trying to load feature module with id '${this.featureId.toString()}'`); + if (this.isLoaded({ isBound })) { + const message = `Could not load feature module. Another module with id '${this.featureId.toString()}' is already loaded`; + this.debugLog(message); + throw new Error(message); + } if (this.checkRequirements(isBound)) { + this.debugLog(`Requirements are met, continue loading of feature module with id '${this.featureId.toString()}'`); bind(this.featureId).toConstantValue(this.featureId); return true; } return false; } + protected debugLog(message?: any, ...optionalParams: any[]): void { + if (FeatureModule.DEBUG_LOG_ENABLED) { + console.log(message, ...optionalParams); + } + } + /** * Checks if all required {@link FeatureModule}s are already loaded/bound in the container. * @param isBound The `isBound` property of the module callback. Used to check the required modules. * @returns `true` if all requirements are met, `false` otherwise */ protected checkRequirements(isBound: interfaces.IsBound): boolean { - return this.requires ? asArray(this.requires).every(module => isBound(module.featureId)) : true; + const requires = asArray(this.requires ?? []); + if (requires.length === 0) { + return true; + } + const missing = requires.filter(module => !module.isLoaded({ isBound })); + if (missing.length > 0) { + this.debugLog( + // eslint-disable-next-line max-len + `Could not load feature module. Required modules are not loaded. Feature ids: ${missing.map(m => m.featureId.toString()).join(', ')}` + ); + return false; + } + return true; } isLoaded(context: Pick): boolean {