diff --git a/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api.ts b/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api.ts new file mode 100644 index 0000000000..8552cb5ec8 --- /dev/null +++ b/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api.ts @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +import type { Injectable } from "@ogre-tools/injectable"; + +import { getLegacyGlobalDiForExtensionApi } from "./legacy-global-di-for-extension-api"; + +type TentativeTuple = T extends object ? [T] : [undefined?]; + +type FactoryType = < + TInjectable extends Injectable, + TInstantiationParameter, + TInstance extends (...args: unknown[]) => any, + TFunction extends (...args: unknown[]) => any = Awaited< + ReturnType + >, +>( + injectableKey: TInjectable, + ...instantiationParameter: TentativeTuple +) => (...args: Parameters) => ReturnType; + +export const asLegacyGlobalFunctionForExtensionApi: FactoryType = + (injectableKey, ...instantiationParameter) => + (...args) => { + const injected = getLegacyGlobalDiForExtensionApi().inject( + injectableKey, + ...instantiationParameter, + ); + + return injected(...args); + }; diff --git a/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api.ts b/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api.ts new file mode 100644 index 0000000000..9c95472258 --- /dev/null +++ b/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api.ts @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +import type { Injectable } from "@ogre-tools/injectable"; +import { getLegacyGlobalDiForExtensionApi } from "./legacy-global-di-for-extension-api"; + +type TentativeTuple = T extends object ? [T] : [undefined?]; + +export const asLegacyGlobalObjectForExtensionApi = < + TInjectable extends Injectable, + TInstantiationParameter, +>( + injectableKey: TInjectable, + ...instantiationParameter: TentativeTuple + ) => + new Proxy( + {}, + { + get(target, propertyName) { + if (propertyName === "$$typeof") { + return undefined; + } + + const instance: any = getLegacyGlobalDiForExtensionApi().inject( + injectableKey, + ...instantiationParameter, + ); + + const propertyValue = instance[propertyName]; + + if (typeof propertyValue === "function") { + return function (...args: any[]) { + return propertyValue.apply(instance, args); + }; + } + + return propertyValue; + }, + }, + ) as ReturnType; diff --git a/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-singleton-for-extension-api.ts b/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-singleton-for-extension-api.ts new file mode 100644 index 0000000000..a470c6914b --- /dev/null +++ b/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-singleton-for-extension-api.ts @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +import type { Injectable } from "@ogre-tools/injectable"; +import { getLegacyGlobalDiForExtensionApi } from "./legacy-global-di-for-extension-api"; + +type TentativeTuple = T extends object ? [T] : [undefined?]; + +export const asLegacyGlobalSingletonForExtensionApi = < + TClass extends abstract new (...args: any[]) => any, + TInjectable extends Injectable, + TInstantiationParameter, +>( + Class: TClass, + injectableKey: TInjectable, + ...instantiationParameter: TentativeTuple + ) => + new Proxy(Class, { + construct: () => { + throw new Error("A legacy singleton class must be created by createInstance()"); + }, + + get: (target: any, propertyName) => { + if (propertyName === "getInstance" || propertyName === "createInstance") { + return () => + getLegacyGlobalDiForExtensionApi().inject( + injectableKey, + ...instantiationParameter, + ); + } + + if (propertyName === "resetInstance") { + return () => getLegacyGlobalDiForExtensionApi().purge(injectableKey); + } + + return target[propertyName]; + }, + }) as InstanceType & { + getInstance: () => InstanceType; + createInstance: () => InstanceType; + resetInstance: () => void; + }; diff --git a/src/extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api.ts b/src/extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api.ts new file mode 100644 index 0000000000..0d9bc728a5 --- /dev/null +++ b/src/extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api.ts @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +import type { DependencyInjectionContainer } from "@ogre-tools/injectable"; + +let legacyGlobalDi: DependencyInjectionContainer; + +export const setLegacyGlobalDiForExtensionApi = (di: DependencyInjectionContainer) => { + legacyGlobalDi = di; +}; + +export const getLegacyGlobalDiForExtensionApi = () => legacyGlobalDi; diff --git a/src/extensions/renderer-api/components.ts b/src/extensions/renderer-api/components.ts index 7173b592b3..ad31884330 100644 --- a/src/extensions/renderer-api/components.ts +++ b/src/extensions/renderer-api/components.ts @@ -19,6 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +import commandOverlayInjectable from "../../renderer/components/command-palette/command-overlay.injectable"; +import { asLegacyGlobalObjectForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; + // layouts export * from "../../renderer/components/layout/main-layout"; export * from "../../renderer/components/layout/setting-layout"; @@ -36,7 +39,7 @@ export * from "../../renderer/components/switch"; export * from "../../renderer/components/input/input"; // command-overlay -export { CommandOverlay } from "../../renderer/components/command-palette"; +export const CommandOverlay = asLegacyGlobalObjectForExtensionApi(commandOverlayInjectable); // other components export * from "../../renderer/components/icon"; diff --git a/src/renderer/getDi.tsx b/src/renderer/getDi.tsx index 4c4359fe74..e9126d62a9 100644 --- a/src/renderer/getDi.tsx +++ b/src/renderer/getDi.tsx @@ -20,14 +20,20 @@ */ import { createContainer } from "@ogre-tools/injectable"; +import { setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; -export const getDi = () => - createContainer( +export function getDi() { + const di = createContainer( getRequireContextForRendererCode, - getRequireContextForCommonCode, getRequireContextForCommonExtensionCode, + getRequireContextForCommonCode, ); + setLegacyGlobalDiForExtensionApi(di); + + return di; +} + const getRequireContextForRendererCode = () => require.context("./", true, /\.injectable\.(ts|tsx)$/);