@eclipse-glsp/layout-elk 2.6.0 → 2.7.0-next.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,27 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2022-2026 STMicroelectronics and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+ import { BindingTarget, GLSPModule } from '@eclipse-glsp/server';
1
17
  import { LayoutOptions } from 'elkjs/lib/elk.bundled';
2
- import { ContainerModule } from 'inversify';
18
+ import { ContainerModule, interfaces } from 'inversify';
3
19
  import { ElementFilter } from './element-filter';
20
+ import { ElkFactory, GlspElkLayoutEngine } from './glsp-elk-layout-engine';
4
21
  import { LayoutConfigurator } from './layout-configurator';
5
22
  type Constructor<T> = new (...args: any[]) => T;
6
23
  /**
7
- * Configuration options for the {@link configureELKLayoutModule} function.
24
+ * Configuration options for the {@link ElkLayoutModule} (and the legacy {@link configureELKLayoutModule} factory).
8
25
  */
9
26
  export interface ElkModuleOptions {
10
27
  /**
@@ -33,20 +50,33 @@ export interface ElkModuleOptions {
33
50
  isWebWorker?: boolean;
34
51
  }
35
52
  /**
36
- * Utility method to create a DI module that provides all necessary bindings to use the {@link GlspElkLayoutEngine} in a node GLSP server
37
- * implementation. A set of configuration options is provided to enable easy customization. In most cases at least
38
- * the custom {@link layoutConfigurator} binding should be provided (in addition to the required `algorithms' property) via these options.
53
+ * DI module that provides the bindings needed to use the {@link GlspElkLayoutEngine} in a node GLSP server.
39
54
  *
40
- * The constructed module is not intended for standalone use cases and only works in combination with a GLSPDiagramModule.
55
+ * Subclass and override the `bindXxx()` hooks to customize individual bindings e.g. to swap the
56
+ * layout configurator or element filter without re-implementing the whole module. The module is
57
+ * only meaningful in combination with a `GLSPDiagramModule`.
41
58
  *
42
- * * The following bindings are provided:
43
- * - {@link ILayoutConfigurator}
44
- * - {@link IElementFilter}
45
- * - {@link LayoutEngine}
59
+ * Bindings provided:
60
+ * - {@link ElementFilter}
61
+ * - {@link LayoutConfigurator}
46
62
  * - {@link ElkFactory}
47
- *
48
- * @param options The configuration options
49
- * @returns A DI module that can be loaded as additional module when configuring a diagram module for a GLSP server.
63
+ * - {@link GlspElkLayoutEngine} + {@link LayoutEngine} (toService)
64
+ * - Fallback bindings for {@link Logger} and {@link LoggerFactory} if absent.
65
+ */
66
+ export declare class ElkLayoutModule extends GLSPModule {
67
+ protected readonly options: ElkModuleOptions;
68
+ constructor(options: ElkModuleOptions);
69
+ protected configure(bind: interfaces.Bind, unbind: interfaces.Unbind, isBound: interfaces.IsBound, rebind: interfaces.Rebind): void;
70
+ protected bindElementFilter(): BindingTarget<ElementFilter>;
71
+ protected bindLayoutConfigurator(): BindingTarget<LayoutConfigurator>;
72
+ protected bindElkFactory(): BindingTarget<ElkFactory>;
73
+ protected bindGlspElkLayoutEngine(): BindingTarget<GlspElkLayoutEngine>;
74
+ /** Provide fallbacks so the module works standalone in tests/specs that don't preconfigure logging. */
75
+ protected bindLoggerFallbacks(bind: interfaces.Bind, isBound: interfaces.IsBound): void;
76
+ }
77
+ /**
78
+ * Utility wrapper around {@link ElkLayoutModule} for the common case where no override is needed.
79
+ * Prefer subclassing {@link ElkLayoutModule} when individual bindings need to be customized.
50
80
  */
51
81
  export declare function configureELKLayoutModule(options: ElkModuleOptions): ContainerModule;
52
82
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"di.config.d.ts","sourceRoot":"","sources":["../src/di.config.ts"],"names":[],"mappings":"AAgBA,OAAuB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAwB,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEvE,OAAO,EAA8B,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEvF,KAAK,WAAW,CAAC,CAAC,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B;;OAEG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,aAAa,CAAC;IACrC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,CAAC;IACrD;;;OAGG;IACH,aAAa,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IAC3C;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAoDnF"}
1
+ {"version":3,"file":"di.config.d.ts","sourceRoot":"","sources":["../src/di.config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;kFAckF;AAClF,OAAO,EACH,aAAa,EACb,UAAU,EAOb,MAAM,sBAAsB,CAAC;AAC9B,OAAuB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,eAAe,EAAc,UAAU,EAAE,MAAM,WAAW,CAAC;AACpE,OAAO,EAAwB,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAA8B,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEvF,KAAK,WAAW,CAAC,CAAC,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B;;OAEG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,aAAa,CAAC;IACrC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,CAAC;IACrD;;;OAGG;IACH,aAAa,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IAC3C;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;;;GAaG;AACH,qBACa,eAAgB,SAAQ,UAAU;IAC/B,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,gBAAgB;gBAAzB,OAAO,EAAE,gBAAgB;IAIxD,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,GAAG,IAAI;IAUnI,SAAS,CAAC,iBAAiB,IAAI,aAAa,CAAC,aAAa,CAAC;IAI3D,SAAS,CAAC,sBAAsB,IAAI,aAAa,CAAC,kBAAkB,CAAC;IAOrE,SAAS,CAAC,cAAc,IAAI,aAAa,CAAC,UAAU,CAAC;IAarD,SAAS,CAAC,uBAAuB,IAAI,aAAa,CAAC,mBAAmB,CAAC;IAYvE,uGAAuG;IACvG,SAAS,CAAC,mBAAmB,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,GAAG,IAAI;CAY1F;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAEnF"}
package/lib/di.config.js CHANGED
@@ -1,8 +1,18 @@
1
1
  "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ElkLayoutModule = void 0;
3
13
  exports.configureELKLayoutModule = configureELKLayoutModule;
4
14
  /********************************************************************************
5
- * Copyright (c) 2022-2025 STMicroelectronics and others.
15
+ * Copyright (c) 2022-2026 STMicroelectronics and others.
6
16
  *
7
17
  * This program and the accompanying materials are made available under the
8
18
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -23,57 +33,67 @@ const element_filter_1 = require("./element-filter");
23
33
  const glsp_elk_layout_engine_1 = require("./glsp-elk-layout-engine");
24
34
  const layout_configurator_1 = require("./layout-configurator");
25
35
  /**
26
- * Utility method to create a DI module that provides all necessary bindings to use the {@link GlspElkLayoutEngine} in a node GLSP server
27
- * implementation. A set of configuration options is provided to enable easy customization. In most cases at least
28
- * the custom {@link layoutConfigurator} binding should be provided (in addition to the required `algorithms' property) via these options.
36
+ * DI module that provides the bindings needed to use the {@link GlspElkLayoutEngine} in a node GLSP server.
29
37
  *
30
- * The constructed module is not intended for standalone use cases and only works in combination with a GLSPDiagramModule.
38
+ * Subclass and override the `bindXxx()` hooks to customize individual bindings e.g. to swap the
39
+ * layout configurator or element filter without re-implementing the whole module. The module is
40
+ * only meaningful in combination with a `GLSPDiagramModule`.
31
41
  *
32
- * * The following bindings are provided:
33
- * - {@link ILayoutConfigurator}
34
- * - {@link IElementFilter}
35
- * - {@link LayoutEngine}
42
+ * Bindings provided:
43
+ * - {@link ElementFilter}
44
+ * - {@link LayoutConfigurator}
36
45
  * - {@link ElkFactory}
37
- *
38
- * @param options The configuration options
39
- * @returns A DI module that can be loaded as additional module when configuring a diagram module for a GLSP server.
46
+ * - {@link GlspElkLayoutEngine} + {@link LayoutEngine} (toService)
47
+ * - Fallback bindings for {@link Logger} and {@link LoggerFactory} if absent.
40
48
  */
41
- function configureELKLayoutModule(options) {
42
- return new inversify_1.ContainerModule((bind, unbind, isBound, rebind) => {
43
- if (options.elementFilter) {
44
- bind(element_filter_1.ElementFilter).to(options.elementFilter).inSingletonScope();
45
- }
46
- else {
47
- bind(element_filter_1.ElementFilter).to(element_filter_1.DefaultElementFilter).inSingletonScope();
48
- }
49
- if (options.layoutConfigurator) {
50
- bind(layout_configurator_1.LayoutConfigurator).to(options.layoutConfigurator);
51
- }
52
- else {
53
- bind(layout_configurator_1.LayoutConfigurator)
54
- .toDynamicValue(context => new layout_configurator_1.FallbackLayoutConfigurator(options.algorithms, options.defaultLayoutOptions))
55
- .inSingletonScope();
49
+ let ElkLayoutModule = class ElkLayoutModule extends server_1.GLSPModule {
50
+ constructor(options) {
51
+ super();
52
+ this.options = options;
53
+ }
54
+ configure(bind, unbind, isBound, rebind) {
55
+ const context = { bind, unbind, isBound, rebind };
56
+ (0, server_1.applyBindingTarget)(context, element_filter_1.ElementFilter, this.bindElementFilter()).inSingletonScope();
57
+ (0, server_1.applyBindingTarget)(context, layout_configurator_1.LayoutConfigurator, this.bindLayoutConfigurator()).inSingletonScope();
58
+ (0, server_1.applyBindingTarget)(context, glsp_elk_layout_engine_1.ElkFactory, this.bindElkFactory());
59
+ (0, server_1.applyBindingTarget)(context, glsp_elk_layout_engine_1.GlspElkLayoutEngine, this.bindGlspElkLayoutEngine()).inSingletonScope();
60
+ bind(server_1.LayoutEngine).toService(glsp_elk_layout_engine_1.GlspElkLayoutEngine);
61
+ this.bindLoggerFallbacks(bind, isBound);
62
+ }
63
+ bindElementFilter() {
64
+ var _a;
65
+ return (_a = this.options.elementFilter) !== null && _a !== void 0 ? _a : element_filter_1.DefaultElementFilter;
66
+ }
67
+ bindLayoutConfigurator() {
68
+ if (this.options.layoutConfigurator) {
69
+ return this.options.layoutConfigurator;
56
70
  }
57
- const elkFactory = () => new elk_bundled_1.default({
58
- algorithms: options.algorithms,
59
- defaultLayoutOptions: options.defaultLayoutOptions,
60
- // The node implementation relied on elkjs' `FakeWorker` to set the `workerFactory`.
61
- // However, since the required file is dynamically loaded and not available in a web-worker context,
62
- // it needs to be mocked manually.
63
- workerFactory: options.isWebWorker ? () => ({ postMessage: () => { } }) : undefined
71
+ return { dynamicValue: () => new layout_configurator_1.FallbackLayoutConfigurator(this.options.algorithms, this.options.defaultLayoutOptions) };
72
+ }
73
+ bindElkFactory() {
74
+ const { algorithms, defaultLayoutOptions, isWebWorker } = this.options;
75
+ const factory = () => new elk_bundled_1.default({
76
+ algorithms,
77
+ defaultLayoutOptions,
78
+ // The node implementation relies on elkjs' `FakeWorker` to set the `workerFactory`. The required file is
79
+ // dynamically loaded and not available in a web-worker context, so it has to be mocked manually there.
80
+ workerFactory: isWebWorker ? () => ({ postMessage: () => { } }) : undefined
64
81
  });
65
- bind(glsp_elk_layout_engine_1.ElkFactory).toConstantValue(elkFactory);
66
- bind(glsp_elk_layout_engine_1.GlspElkLayoutEngine)
67
- .toDynamicValue(context => {
68
- const container = context.container;
69
- const factory = container.get(glsp_elk_layout_engine_1.ElkFactory);
70
- const filter = container.get(element_filter_1.ElementFilter);
71
- const configurator = container.get(layout_configurator_1.LayoutConfigurator);
72
- const modelState = container.get(server_1.ModelState);
73
- return new glsp_elk_layout_engine_1.GlspElkLayoutEngine(factory, filter, configurator, modelState);
74
- })
75
- .inSingletonScope();
76
- bind(server_1.LayoutEngine).toService(glsp_elk_layout_engine_1.GlspElkLayoutEngine);
82
+ return { constantValue: factory };
83
+ }
84
+ bindGlspElkLayoutEngine() {
85
+ return {
86
+ dynamicValue: ctx => {
87
+ const factory = ctx.container.get(glsp_elk_layout_engine_1.ElkFactory);
88
+ const filter = ctx.container.get(element_filter_1.ElementFilter);
89
+ const configurator = ctx.container.get(layout_configurator_1.LayoutConfigurator);
90
+ const modelState = ctx.container.get(server_1.ModelState);
91
+ return new glsp_elk_layout_engine_1.GlspElkLayoutEngine(factory, filter, configurator, modelState);
92
+ }
93
+ };
94
+ }
95
+ /** Provide fallbacks so the module works standalone in tests/specs that don't preconfigure logging. */
96
+ bindLoggerFallbacks(bind, isBound) {
77
97
  if (!isBound(server_1.Logger)) {
78
98
  bind(server_1.Logger).to(server_1.NullLogger).inSingletonScope();
79
99
  }
@@ -84,6 +104,18 @@ function configureELKLayoutModule(options) {
84
104
  return logger;
85
105
  });
86
106
  }
87
- });
107
+ }
108
+ };
109
+ exports.ElkLayoutModule = ElkLayoutModule;
110
+ exports.ElkLayoutModule = ElkLayoutModule = __decorate([
111
+ (0, inversify_1.injectable)(),
112
+ __metadata("design:paramtypes", [Object])
113
+ ], ElkLayoutModule);
114
+ /**
115
+ * Utility wrapper around {@link ElkLayoutModule} for the common case where no override is needed.
116
+ * Prefer subclassing {@link ElkLayoutModule} when individual bindings need to be customized.
117
+ */
118
+ function configureELKLayoutModule(options) {
119
+ return new ElkLayoutModule(options);
88
120
  }
89
121
  //# sourceMappingURL=di.config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"di.config.js","sourceRoot":"","sources":["../src/di.config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"di.config.js","sourceRoot":"","sources":["../src/di.config.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eclipse-glsp/layout-elk",
3
- "version": "2.6.0",
3
+ "version": "2.7.0-next.11+ea5b153",
4
4
  "description": "Integration of ELK graph layout algorithms in GLSP Node Server",
5
5
  "keywords": [
6
6
  "eclipse",
@@ -42,14 +42,14 @@
42
42
  "build": "tsc -b",
43
43
  "clean": "rimraf lib *.tsbuildinfo coverage .nyc_output",
44
44
  "generate:index": "glsp generateIndex src -f -s",
45
- "lint": "eslint --ext .ts,.tsx ./src",
45
+ "lint": "eslint ./src",
46
46
  "test": "mocha --config ../../.mocharc \"./src/**/*.spec.?(ts|tsx)\"",
47
47
  "test:ci": "yarn test --reporter mocha-ctrf-json-reporter",
48
48
  "test:coverage": "nyc yarn test",
49
49
  "watch": "tsc -w"
50
50
  },
51
51
  "dependencies": {
52
- "@eclipse-glsp/server": "2.6.0",
52
+ "@eclipse-glsp/server": "2.7.0-next.11+ea5b153",
53
53
  "elkjs": "^0.10.1"
54
54
  },
55
55
  "peerDependencies": {
@@ -58,5 +58,5 @@
58
58
  "publishConfig": {
59
59
  "access": "public"
60
60
  },
61
- "gitHead": "88356089bae7527c2df6c5331f75504495fe2aa4"
61
+ "gitHead": "ea5b15366a194a2cca2522f3b2011b03c9c85e6e"
62
62
  }
package/src/di.config.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2022-2025 STMicroelectronics and others.
2
+ * Copyright (c) 2022-2026 STMicroelectronics and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -13,9 +13,18 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
- import { LayoutEngine, Logger, LoggerFactory, ModelState, NullLogger } from '@eclipse-glsp/server';
16
+ import {
17
+ BindingTarget,
18
+ GLSPModule,
19
+ LayoutEngine,
20
+ Logger,
21
+ LoggerFactory,
22
+ ModelState,
23
+ NullLogger,
24
+ applyBindingTarget
25
+ } from '@eclipse-glsp/server';
17
26
  import ElkConstructor, { LayoutOptions } from 'elkjs/lib/elk.bundled';
18
- import { ContainerModule } from 'inversify';
27
+ import { ContainerModule, injectable, interfaces } from 'inversify';
19
28
  import { DefaultElementFilter, ElementFilter } from './element-filter';
20
29
  import { ElkFactory, GlspElkLayoutEngine } from './glsp-elk-layout-engine';
21
30
  import { FallbackLayoutConfigurator, LayoutConfigurator } from './layout-configurator';
@@ -23,7 +32,7 @@ import { FallbackLayoutConfigurator, LayoutConfigurator } from './layout-configu
23
32
  type Constructor<T> = new (...args: any[]) => T;
24
33
 
25
34
  /**
26
- * Configuration options for the {@link configureELKLayoutModule} function.
35
+ * Configuration options for the {@link ElkLayoutModule} (and the legacy {@link configureELKLayoutModule} factory).
27
36
  */
28
37
  export interface ElkModuleOptions {
29
38
  /**
@@ -53,65 +62,76 @@ export interface ElkModuleOptions {
53
62
  }
54
63
 
55
64
  /**
56
- * Utility method to create a DI module that provides all necessary bindings to use the {@link GlspElkLayoutEngine} in a node GLSP server
57
- * implementation. A set of configuration options is provided to enable easy customization. In most cases at least
58
- * the custom {@link layoutConfigurator} binding should be provided (in addition to the required `algorithms' property) via these options.
65
+ * DI module that provides the bindings needed to use the {@link GlspElkLayoutEngine} in a node GLSP server.
59
66
  *
60
- * The constructed module is not intended for standalone use cases and only works in combination with a GLSPDiagramModule.
67
+ * Subclass and override the `bindXxx()` hooks to customize individual bindings e.g. to swap the
68
+ * layout configurator or element filter without re-implementing the whole module. The module is
69
+ * only meaningful in combination with a `GLSPDiagramModule`.
61
70
  *
62
- * * The following bindings are provided:
63
- * - {@link ILayoutConfigurator}
64
- * - {@link IElementFilter}
65
- * - {@link LayoutEngine}
71
+ * Bindings provided:
72
+ * - {@link ElementFilter}
73
+ * - {@link LayoutConfigurator}
66
74
  * - {@link ElkFactory}
67
- *
68
- * @param options The configuration options
69
- * @returns A DI module that can be loaded as additional module when configuring a diagram module for a GLSP server.
75
+ * - {@link GlspElkLayoutEngine} + {@link LayoutEngine} (toService)
76
+ * - Fallback bindings for {@link Logger} and {@link LoggerFactory} if absent.
70
77
  */
71
- export function configureELKLayoutModule(options: ElkModuleOptions): ContainerModule {
72
- return new ContainerModule((bind, unbind, isBound, rebind) => {
73
- if (options.elementFilter) {
74
- bind(ElementFilter).to(options.elementFilter).inSingletonScope();
75
- } else {
76
- bind(ElementFilter).to(DefaultElementFilter).inSingletonScope();
77
- }
78
+ @injectable()
79
+ export class ElkLayoutModule extends GLSPModule {
80
+ constructor(protected readonly options: ElkModuleOptions) {
81
+ super();
82
+ }
78
83
 
79
- if (options.layoutConfigurator) {
80
- bind(LayoutConfigurator).to(options.layoutConfigurator);
81
- } else {
82
- bind(LayoutConfigurator)
83
- .toDynamicValue(context => new FallbackLayoutConfigurator(options.algorithms, options.defaultLayoutOptions))
84
- .inSingletonScope();
84
+ protected configure(bind: interfaces.Bind, unbind: interfaces.Unbind, isBound: interfaces.IsBound, rebind: interfaces.Rebind): void {
85
+ const context = { bind, unbind, isBound, rebind };
86
+ applyBindingTarget(context, ElementFilter, this.bindElementFilter()).inSingletonScope();
87
+ applyBindingTarget(context, LayoutConfigurator, this.bindLayoutConfigurator()).inSingletonScope();
88
+ applyBindingTarget(context, ElkFactory, this.bindElkFactory());
89
+ applyBindingTarget(context, GlspElkLayoutEngine, this.bindGlspElkLayoutEngine()).inSingletonScope();
90
+ bind(LayoutEngine).toService(GlspElkLayoutEngine);
91
+ this.bindLoggerFallbacks(bind, isBound);
92
+ }
93
+
94
+ protected bindElementFilter(): BindingTarget<ElementFilter> {
95
+ return this.options.elementFilter ?? DefaultElementFilter;
96
+ }
97
+
98
+ protected bindLayoutConfigurator(): BindingTarget<LayoutConfigurator> {
99
+ if (this.options.layoutConfigurator) {
100
+ return this.options.layoutConfigurator;
85
101
  }
102
+ return { dynamicValue: () => new FallbackLayoutConfigurator(this.options.algorithms, this.options.defaultLayoutOptions) };
103
+ }
86
104
 
87
- const elkFactory: ElkFactory = () =>
105
+ protected bindElkFactory(): BindingTarget<ElkFactory> {
106
+ const { algorithms, defaultLayoutOptions, isWebWorker } = this.options;
107
+ const factory: ElkFactory = () =>
88
108
  new ElkConstructor({
89
- algorithms: options.algorithms,
90
- defaultLayoutOptions: options.defaultLayoutOptions,
91
- // The node implementation relied on elkjs' `FakeWorker` to set the `workerFactory`.
92
- // However, since the required file is dynamically loaded and not available in a web-worker context,
93
- // it needs to be mocked manually.
94
- workerFactory: options.isWebWorker ? () => ({ postMessage: () => {} }) as unknown as Worker : undefined
109
+ algorithms,
110
+ defaultLayoutOptions,
111
+ // The node implementation relies on elkjs' `FakeWorker` to set the `workerFactory`. The required file is
112
+ // dynamically loaded and not available in a web-worker context, so it has to be mocked manually there.
113
+ workerFactory: isWebWorker ? () => ({ postMessage: () => {} }) as unknown as Worker : undefined
95
114
  });
115
+ return { constantValue: factory };
116
+ }
96
117
 
97
- bind(ElkFactory).toConstantValue(elkFactory);
98
-
99
- bind(GlspElkLayoutEngine)
100
- .toDynamicValue(context => {
101
- const container = context.container;
102
- const factory = container.get<ElkFactory>(ElkFactory);
103
- const filter = container.get<ElementFilter>(ElementFilter);
104
- const configurator = container.get<LayoutConfigurator>(LayoutConfigurator);
105
- const modelState = container.get<ModelState>(ModelState);
118
+ protected bindGlspElkLayoutEngine(): BindingTarget<GlspElkLayoutEngine> {
119
+ return {
120
+ dynamicValue: ctx => {
121
+ const factory = ctx.container.get<ElkFactory>(ElkFactory);
122
+ const filter = ctx.container.get<ElementFilter>(ElementFilter);
123
+ const configurator = ctx.container.get<LayoutConfigurator>(LayoutConfigurator);
124
+ const modelState = ctx.container.get<ModelState>(ModelState);
106
125
  return new GlspElkLayoutEngine(factory, filter, configurator, modelState);
107
- })
108
- .inSingletonScope();
109
- bind(LayoutEngine).toService(GlspElkLayoutEngine);
126
+ }
127
+ };
128
+ }
110
129
 
130
+ /** Provide fallbacks so the module works standalone in tests/specs that don't preconfigure logging. */
131
+ protected bindLoggerFallbacks(bind: interfaces.Bind, isBound: interfaces.IsBound): void {
111
132
  if (!isBound(Logger)) {
112
133
  bind(Logger).to(NullLogger).inSingletonScope();
113
134
  }
114
-
115
135
  if (!isBound(LoggerFactory)) {
116
136
  bind(LoggerFactory).toFactory(dynamicContext => (caller: string) => {
117
137
  const logger = dynamicContext.container.get(Logger);
@@ -119,5 +139,13 @@ export function configureELKLayoutModule(options: ElkModuleOptions): ContainerMo
119
139
  return logger;
120
140
  });
121
141
  }
122
- });
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Utility wrapper around {@link ElkLayoutModule} for the common case where no override is needed.
147
+ * Prefer subclassing {@link ElkLayoutModule} when individual bindings need to be customized.
148
+ */
149
+ export function configureELKLayoutModule(options: ElkModuleOptions): ContainerModule {
150
+ return new ElkLayoutModule(options);
123
151
  }