From a045006a02e77ba02716e10b69538cfbd77188e2 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 15 Feb 2023 09:04:11 -0500 Subject: [PATCH] Simplify extension dependency injection - Has better typing - Removes use of unnusual unique symbol Signed-off-by: Sebastian Malton --- .../create-extension-instance.token.ts | 17 ------- .../extension-loader.injectable.ts | 2 - .../extension-loader/extension-loader.ts | 32 +++++--------- .../lens-extension-set-dependencies.ts | 33 -------------- .../core/src/extensions/lens-extension.ts | 40 ++++++++--------- .../src/extensions/lens-main-extension.ts | 44 ++++++++++++++++--- .../src/extensions/lens-renderer-extension.ts | 37 +++++++++++----- .../create-extension-instance.injectable.ts | 37 ---------------- .../create-extension-instance.injectable.ts | 43 ------------------ 9 files changed, 96 insertions(+), 189 deletions(-) delete mode 100644 packages/core/src/extensions/extension-loader/create-extension-instance.token.ts delete mode 100644 packages/core/src/extensions/lens-extension-set-dependencies.ts delete mode 100644 packages/core/src/main/extension-loader/create-extension-instance.injectable.ts delete mode 100644 packages/core/src/renderer/extension-loader/create-extension-instance.injectable.ts diff --git a/packages/core/src/extensions/extension-loader/create-extension-instance.token.ts b/packages/core/src/extensions/extension-loader/create-extension-instance.token.ts deleted file mode 100644 index e68e26b63c..0000000000 --- a/packages/core/src/extensions/extension-loader/create-extension-instance.token.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { getInjectionToken } from "@ogre-tools/injectable"; -import type { BundledInstalledExtension, ExternalInstalledExtension } from "../extension-discovery/extension-discovery"; -import type { BundledLensExtensionContructor, LensExtension, LensExtensionConstructor } from "../lens-extension"; - -export interface CreateExtensionInstance { - (ExtensionClass: LensExtensionConstructor, extension: ExternalInstalledExtension): LensExtension; - (ExtensionClass: BundledLensExtensionContructor, extension: BundledInstalledExtension): LensExtension; -} - -export const createExtensionInstanceInjectionToken = getInjectionToken({ - id: "create-extension-instance-token", -}); diff --git a/packages/core/src/extensions/extension-loader/extension-loader.injectable.ts b/packages/core/src/extensions/extension-loader/extension-loader.injectable.ts index 67f8434043..139300f750 100644 --- a/packages/core/src/extensions/extension-loader/extension-loader.injectable.ts +++ b/packages/core/src/extensions/extension-loader/extension-loader.injectable.ts @@ -5,7 +5,6 @@ import { getInjectable } from "@ogre-tools/injectable"; import { ExtensionLoader } from "./extension-loader"; import updateExtensionsStateInjectable from "./update-extensions-state/update-extensions-state.injectable"; -import { createExtensionInstanceInjectionToken } from "./create-extension-instance.token"; import extensionInstancesInjectable from "./extension-instances.injectable"; import type { LensExtension } from "../lens-extension"; import extensionInjectable from "./extension/extension.injectable"; @@ -20,7 +19,6 @@ const extensionLoaderInjectable = getInjectable({ instantiate: (di) => new ExtensionLoader({ updateExtensionsState: di.inject(updateExtensionsStateInjectable), - createExtensionInstance: di.inject(createExtensionInstanceInjectionToken), extensionInstances: di.inject(extensionInstancesInjectable), getExtension: (instance: LensExtension) => di.inject(extensionInjectable, instance), bundledExtensions: di.injectMany(bundledExtensionInjectionToken), diff --git a/packages/core/src/extensions/extension-loader/extension-loader.ts b/packages/core/src/extensions/extension-loader/extension-loader.ts index f65ce58ea0..7fd3779fe9 100644 --- a/packages/core/src/extensions/extension-loader/extension-loader.ts +++ b/packages/core/src/extensions/extension-loader/extension-loader.ts @@ -9,14 +9,13 @@ import type { ObservableMap } from "mobx"; import { runInAction, action, computed, observable, reaction, when } from "mobx"; import { broadcastMessage, ipcMainOn, ipcRendererOn, ipcMainHandle } from "../../common/ipc"; import { isDefined, iter, toJS } from "../../common/utils"; -import type { ExternalInstalledExtension, InstalledExtension } from "../extension-discovery/extension-discovery"; +import type { BundledInstalledExtension, ExternalInstalledExtension, InstalledExtension } from "../extension-discovery/extension-discovery"; import type { LensExtension, LensExtensionConstructor, LensExtensionId } from "../lens-extension"; import type { LensExtensionState } from "../extensions-store/extensions-store"; import { extensionLoaderFromMainChannel, extensionLoaderFromRendererChannel } from "../../common/ipc/extension-handling"; import { requestExtensionLoaderInitialState } from "../../renderer/ipc"; import assert from "assert"; import { EventEmitter } from "../../common/event-emitter"; -import type { CreateExtensionInstance } from "./create-extension-instance.token"; import type { Extension } from "./extension/extension.injectable"; import type { Logger } from "../../common/logger"; import type { JoinPaths } from "../../common/path/join-paths.injectable"; @@ -31,7 +30,6 @@ interface Dependencies { readonly logger: Logger; readonly extensionEntryPointName: "main" | "renderer"; updateExtensionsState: (extensionsState: Record) => void; - createExtensionInstance: CreateExtensionInstance; getExtension: (instance: LensExtension) => Extension; joinPaths: JoinPaths; getDirnameOfPath: GetDirnameOfPath; @@ -239,7 +237,7 @@ export class ExtensionLoader { return null; } - const installedExtension: InstalledExtension = { + const installedExtension: BundledInstalledExtension = { absolutePath: "irrelevant", id: extension.manifest.name, isBundled: true, @@ -248,10 +246,7 @@ export class ExtensionLoader { manifest: extension.manifest, manifestPath: "irrelevant", }; - const instance = this.dependencies.createExtensionInstance( - LensExtensionClass, - installedExtension, - ); + const instance = new LensExtensionClass(installedExtension); this.dependencies.extensionInstances.set(extension.manifest.name, instance); @@ -310,35 +305,32 @@ export class ExtensionLoader { return [...installedExtensions.entries()] .filter((entry): entry is [string, ExternalInstalledExtension] => !entry[1].isBundled) - .map(([extId, extension]) => { - const alreadyInit = this.dependencies.extensionInstances.has(extId) || this.nonInstancesByName.has(extension.manifest.name); + .map(([extId, installedExtension]) => { + const alreadyInit = this.dependencies.extensionInstances.has(extId) || this.nonInstancesByName.has(installedExtension.manifest.name); - if (extension.isCompatible && extension.isEnabled && !alreadyInit) { + if (installedExtension.isCompatible && installedExtension.isEnabled && !alreadyInit) { try { - const LensExtensionClass = this.requireExtension(extension); + const LensExtensionClass = this.requireExtension(installedExtension); if (!LensExtensionClass) { - this.nonInstancesByName.add(extension.manifest.name); + this.nonInstancesByName.add(installedExtension.manifest.name); return null; } - const instance = this.dependencies.createExtensionInstance( - LensExtensionClass, - extension, - ); + const instance = new LensExtensionClass(installedExtension); this.dependencies.extensionInstances.set(extId, instance); return { instance, - installedExtension: extension, + installedExtension, activated: instance.activate(), } as ExtensionBeingActivated; } catch (err) { - this.dependencies.logger.error(`${logModule}: error loading extension`, { ext: extension, err }); + this.dependencies.logger.error(`${logModule}: error loading extension`, { ext: installedExtension, err }); } - } else if (!extension.isEnabled && alreadyInit) { + } else if (!installedExtension.isEnabled && alreadyInit) { this.removeInstance(extId); } diff --git a/packages/core/src/extensions/lens-extension-set-dependencies.ts b/packages/core/src/extensions/lens-extension-set-dependencies.ts deleted file mode 100644 index 7b7c62597a..0000000000 --- a/packages/core/src/extensions/lens-extension-set-dependencies.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { IComputedValue } from "mobx"; -import type { CatalogCategoryRegistry } from "../common/catalog"; -import type { NavigateToRoute } from "../common/front-end-routing/navigate-to-route-injection-token"; -import type { Route } from "../common/front-end-routing/front-end-route-injection-token"; -import type { CatalogEntityRegistry as MainCatalogEntityRegistry } from "../main/catalog"; -import type { CatalogEntityRegistry as RendererCatalogEntityRegistry } from "../renderer/api/catalog/entity/registry"; -import type { GetExtensionPageParameters } from "../renderer/routes/get-extension-page-parameters.injectable"; -import type { FileSystemProvisionerStore } from "./extension-loader/file-system-provisioner-store/file-system-provisioner-store"; -import type { NavigateForExtension } from "../main/start-main-application/lens-window/navigate-for-extension.injectable"; -import type { Logger } from "../common/logger"; - -export interface LensExtensionDependencies { - readonly fileSystemProvisionerStore: FileSystemProvisionerStore; - readonly logger: Logger; -} - -export interface LensMainExtensionDependencies extends LensExtensionDependencies { - readonly entityRegistry: MainCatalogEntityRegistry; - readonly navigate: NavigateForExtension; -} - -export interface LensRendererExtensionDependencies extends LensExtensionDependencies { - navigateToRoute: NavigateToRoute; - getExtensionPageParameters: GetExtensionPageParameters; - readonly routes: IComputedValue[]>; - readonly entityRegistry: RendererCatalogEntityRegistry; - readonly categoryRegistry: CatalogCategoryRegistry; -} diff --git a/packages/core/src/extensions/lens-extension.ts b/packages/core/src/extensions/lens-extension.ts index f6227a0d2e..d93f4a23e7 100644 --- a/packages/core/src/extensions/lens-extension.ts +++ b/packages/core/src/extensions/lens-extension.ts @@ -6,9 +6,10 @@ import type { BundledInstalledExtension, ExternalInstalledExtension, InstalledExtension } from "./extension-discovery/extension-discovery"; import { action, computed, makeObservable, observable } from "mobx"; import { disposer } from "../common/utils"; -import type { LensExtensionDependencies } from "./lens-extension-set-dependencies"; import type { ProtocolHandlerRegistration } from "../common/protocol-handler/registration"; import type { PackageJson } from "type-fest"; +import type { FileSystemProvisionerStore } from "./extension-loader/file-system-provisioner-store/file-system-provisioner-store"; +import type { Logger } from "../common/logger"; export type LensExtensionId = string; // path to manifest (package.json) export type LensExtensionConstructor = new (ext: ExternalInstalledExtension) => LensExtension; @@ -20,6 +21,11 @@ export interface BundledLensExtensionManifest extends PackageJson { publishConfig?: Partial>; } +export interface LensExtensionDependencies { + readonly fileSystemProvisionerStore: FileSystemProvisionerStore; + readonly logger: Logger; +} + export interface LensExtensionManifest extends BundledLensExtensionManifest { main?: string; // path to %ext/dist/main.js renderer?: string; // path to %ext/dist/renderer.js @@ -37,15 +43,9 @@ export interface LensExtensionManifest extends BundledLensExtensionManifest { storeName?: string; } -export const lensExtensionDependencies = Symbol("lens-extension-dependencies"); export const Disposers = Symbol("disposers"); -export class LensExtension< - /** - * @ignore - */ - Dependencies extends LensExtensionDependencies = LensExtensionDependencies, -> { +export class LensExtension { readonly id: LensExtensionId; readonly manifest: LensExtensionManifest; readonly manifestPath: string; @@ -55,6 +55,11 @@ export class LensExtension< return sanitizeExtensionName(this.name); } + /** + * @ignore + */ + protected readonly dependencies: LensExtensionDependencies; + protocolHandlers: ProtocolHandlerRegistration[] = []; @observable private _isEnabled = false; @@ -68,12 +73,12 @@ export class LensExtension< */ [Disposers] = disposer(); - constructor({ id, manifest, manifestPath, isBundled }: InstalledExtension) { - // id is the name of the manifest + constructor(deps: LensExtensionDependencies, { id, manifest, manifestPath, isBundled }: InstalledExtension) { + this.dependencies = deps; this.id = id; this.manifest = manifest as LensExtensionManifest; this.manifestPath = manifestPath; - this.isBundled = !!isBundled; + this.isBundled = isBundled; makeObservable(this); } @@ -94,11 +99,6 @@ export class LensExtension< return this.manifest.storeName || this.name; } - /** - * @ignore - */ - readonly [lensExtensionDependencies]!: Dependencies; - /** * getExtensionFileFolder returns the path to an already created folder. This * folder is for the sole use of this extension. @@ -108,7 +108,7 @@ export class LensExtension< */ async getExtensionFileFolder(): Promise { // storeName is read from the manifest and has a fallback to the manifest name, which equals id - return this[lensExtensionDependencies].fileSystemProvisionerStore.requestDirectory(this.storeName); + return this.dependencies.fileSystemProvisionerStore.requestDirectory(this.storeName); } @action @@ -118,7 +118,7 @@ export class LensExtension< } this._isEnabled = true; - this[lensExtensionDependencies].logger.info(`[EXTENSION]: enabled ${this.name}@${this.version}`); + this.dependencies.logger.info(`[EXTENSION]: enabled ${this.name}@${this.version}`); } @action @@ -132,9 +132,9 @@ export class LensExtension< try { await this.onDeactivate(); this[Disposers](); - this[lensExtensionDependencies].logger.info(`[EXTENSION]: disabled ${this.name}@${this.version}`); + this.dependencies.logger.info(`[EXTENSION]: disabled ${this.name}@${this.version}`); } catch (error) { - this[lensExtensionDependencies].logger.error(`[EXTENSION]: disabling ${this.name}@${this.version} threw an error: ${error}`); + this.dependencies.logger.error(`[EXTENSION]: disabling ${this.name}@${this.version} threw an error: ${error}`); } } diff --git a/packages/core/src/extensions/lens-main-extension.ts b/packages/core/src/extensions/lens-main-extension.ts index 9f7096f722..3675f61629 100644 --- a/packages/core/src/extensions/lens-main-extension.ts +++ b/packages/core/src/extensions/lens-main-extension.ts @@ -3,19 +3,49 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { LensExtension, lensExtensionDependencies } from "./lens-extension"; +import type { LensExtensionDependencies } from "./lens-extension"; +import { LensExtension } from "./lens-extension"; import type { CatalogEntity } from "../common/catalog"; import type { IComputedValue, IObservableArray } from "mobx"; import { isObservableArray } from "mobx"; import type { MenuRegistration } from "../features/application-menu/main/menu-registration"; import type { TrayMenuRegistration } from "../main/tray/tray-menu-registration"; import type { ShellEnvModifier } from "../main/shell-session/shell-env-modifier/shell-env-modifier-registration"; -import type { LensMainExtensionDependencies } from "./lens-extension-set-dependencies"; +import { Environments, getEnvironmentSpecificLegacyGlobalDiForExtensionApi } from "./as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; +import type { InstalledExtension } from "./common-api"; +import type { CatalogEntityRegistry } from "../main/catalog"; +import type { NavigateForExtension } from "../main/start-main-application/lens-window/navigate-for-extension.injectable"; +import catalogEntityRegistryInjectable from "../main/catalog/entity-registry.injectable"; +import fileSystemProvisionerStoreInjectable from "./extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable"; +import loggerInjectable from "../common/logger.injectable"; +import navigateForExtensionInjectable from "../main/start-main-application/lens-window/navigate-for-extension.injectable"; -export class LensMainExtension extends LensExtension { +interface LensMainExtensionDependencies extends LensExtensionDependencies { + readonly entityRegistry: CatalogEntityRegistry; + readonly navigate: NavigateForExtension; +} + +export class LensMainExtension extends LensExtension { appMenus: MenuRegistration[] | IComputedValue = []; trayMenus: TrayMenuRegistration[] | IComputedValue = []; + /** + * @ignore + */ + declare readonly dependencies: LensMainExtensionDependencies; + + constructor(extension: InstalledExtension) { + const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi(Environments.main); + const deps: LensMainExtensionDependencies = { + entityRegistry: di.inject(catalogEntityRegistryInjectable), + fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable), + logger: di.inject(loggerInjectable), + navigate: di.inject(navigateForExtensionInjectable), + }; + + super(deps, extension); + } + /** * implement this to modify the shell environment that Lens terminals are opened with. The ShellEnvModifier type has the signature * @@ -32,18 +62,18 @@ export class LensMainExtension extends LensExtension, frameId?: number) { - await this[lensExtensionDependencies].navigate(this.id, pageId, params, frameId); + await this.dependencies.navigate(this.id, pageId, params, frameId); } addCatalogSource(id: string, source: IObservableArray | IComputedValue) { if (isObservableArray(source)) { - this[lensExtensionDependencies].entityRegistry.addObservableSource(`${this.name}:${id}`, source); + this.dependencies.entityRegistry.addObservableSource(`${this.name}:${id}`, source); } else { - this[lensExtensionDependencies].entityRegistry.addComputedSource(`${this.name}:${id}`, source); + this.dependencies.entityRegistry.addComputedSource(`${this.name}:${id}`, source); } } removeCatalogSource(id: string) { - this[lensExtensionDependencies].entityRegistry.removeSource(`${this.name}:${id}`); + this.dependencies.entityRegistry.removeSource(`${this.name}:${id}`); } } diff --git a/packages/core/src/extensions/lens-renderer-extension.ts b/packages/core/src/extensions/lens-renderer-extension.ts index aa00fd8ba3..0b56c12e41 100644 --- a/packages/core/src/extensions/lens-renderer-extension.ts +++ b/packages/core/src/extensions/lens-renderer-extension.ts @@ -3,10 +3,11 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { Disposers, LensExtension, lensExtensionDependencies } from "./lens-extension"; -import type { CatalogEntity, CategoryFilter } from "../common/catalog"; +import type { LensExtensionDependencies } from "./lens-extension"; +import { Disposers, LensExtension } from "./lens-extension"; +import type { CatalogEntity, CategoryFilter, CatalogCategoryRegistry } from "../common/catalog"; import type { Disposer } from "../common/utils"; -import type { EntityFilter } from "../renderer/api/catalog/entity/registry"; +import type { EntityFilter, CatalogEntityRegistry } from "../renderer/api/catalog/entity/registry"; import type { TopBarRegistration } from "../renderer/components/layout/top-bar/top-bar-registration"; import type { KubernetesCluster } from "../common/catalog-entities"; import type { WelcomeMenuRegistration } from "../renderer/components/+welcome/welcome-menu-items/welcome-menu-registration"; @@ -22,7 +23,6 @@ import type { KubeObjectStatusRegistration } from "../renderer/components/kube-o import { fromPairs, map, matches, toPairs } from "lodash/fp"; import { pipeline } from "@ogre-tools/fp"; import { getExtensionRoutePath } from "../renderer/routes/for-extension"; -import type { LensRendererExtensionDependencies } from "./lens-extension-set-dependencies"; import type { KubeObjectHandlerRegistration } from "../renderer/kube-object/handler"; import type { AppPreferenceTabRegistration } from "../features/preferences/renderer/compliance-for-legacy-extension-api/app-preference-tab-registration"; import type { KubeObjectDetailRegistration } from "../renderer/components/kube-object-details/kube-object-detail-registration"; @@ -31,8 +31,20 @@ import type { EntitySettingRegistration } from "../renderer/components/+entity-s import type { CatalogEntityDetailRegistration } from "../renderer/components/+catalog/entity-details/token"; import type { PageRegistration } from "../renderer/routes/page-registration"; import type { ClusterPageMenuRegistration } from "../renderer/components/layout/cluster-page-menu"; +import type { IComputedValue } from "mobx"; +import type { NavigateToRoute } from "../common/front-end-routing/navigate-to-route-injection-token"; +import type { Route } from "../common/front-end-routing/front-end-route-injection-token"; +import type { GetExtensionPageParameters } from "../renderer/routes/get-extension-page-parameters.injectable"; -export class LensRendererExtension extends LensExtension { +interface LensRendererExtensionDependencies extends LensExtensionDependencies { + navigateToRoute: NavigateToRoute; + getExtensionPageParameters: GetExtensionPageParameters; + readonly routes: IComputedValue[]>; + readonly entityRegistry: CatalogEntityRegistry; + readonly categoryRegistry: CatalogCategoryRegistry; +} + +export class LensRendererExtension extends LensExtension { globalPages: PageRegistration[] = []; clusterPages: PageRegistration[] = []; clusterPageMenus: ClusterPageMenuRegistration[] = []; @@ -54,8 +66,13 @@ export class LensRendererExtension extends LensExtension registration.id === (pageId || undefined)); @@ -70,7 +87,7 @@ export class LensRendererExtension extends LensExtension { - const deps: LensMainExtensionDependencies = { - fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable), - entityRegistry: di.inject(catalogEntityRegistryInjectable), - navigate: di.inject(navigateForExtensionInjectable), - logger: di.inject(loggerInjectable), - }; - - return (ExtensionClass, extension) => { - const instance = new ExtensionClass(extension as any) as LensMainExtension; - - (instance as Writable)[lensExtensionDependencies] = deps; - - return instance; - }; - }, - injectionToken: createExtensionInstanceInjectionToken, -}); - -export default createExtensionInstanceInjectable; diff --git a/packages/core/src/renderer/extension-loader/create-extension-instance.injectable.ts b/packages/core/src/renderer/extension-loader/create-extension-instance.injectable.ts deleted file mode 100644 index 0e53983ec6..0000000000 --- a/packages/core/src/renderer/extension-loader/create-extension-instance.injectable.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import type { Writable } from "type-fest"; -import catalogCategoryRegistryInjectable from "../../common/catalog/category-registry.injectable"; -import loggerInjectable from "../../common/logger.injectable"; -import { createExtensionInstanceInjectionToken } from "../../extensions/extension-loader/create-extension-instance.token"; -import fileSystemProvisionerStoreInjectable from "../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable"; -import { lensExtensionDependencies } from "../../extensions/lens-extension"; -import type { LensRendererExtensionDependencies } from "../../extensions/lens-extension-set-dependencies"; -import type { LensRendererExtension } from "../../extensions/lens-renderer-extension"; -import catalogEntityRegistryInjectable from "../api/catalog/entity/registry.injectable"; -import getExtensionPageParametersInjectable from "../routes/get-extension-page-parameters.injectable"; -import navigateToRouteInjectable from "../routes/navigate-to-route.injectable"; -import routesInjectable from "../routes/routes.injectable"; - -const createExtensionInstanceInjectable = getInjectable({ - id: "create-extension-instance", - instantiate: (di) => { - const deps: LensRendererExtensionDependencies = { - categoryRegistry: di.inject(catalogCategoryRegistryInjectable), - entityRegistry: di.inject(catalogEntityRegistryInjectable), - fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable), - getExtensionPageParameters: di.inject(getExtensionPageParametersInjectable), - navigateToRoute: di.inject(navigateToRouteInjectable), - routes: di.inject(routesInjectable), - logger: di.inject(loggerInjectable), - }; - - return (ExtensionClass, extension) => { - const instance = new ExtensionClass(extension as any) as LensRendererExtension; - - (instance as Writable)[lensExtensionDependencies] = deps; - - return instance; - }; - }, - injectionToken: createExtensionInstanceInjectionToken, -}); - -export default createExtensionInstanceInjectable;