backend-plugin-api: fix for plugins and modules depending on multion services

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-08-07 12:48:09 +02:00
parent 61e4df970c
commit ddde5fe772
9 changed files with 187 additions and 24 deletions
@@ -14,7 +14,9 @@
* limitations under the License.
*/
import { createServiceRef } from '../services';
import { createBackendModule } from './createBackendModule';
import { createExtensionPoint } from './createExtensionPoint';
import { InternalBackendRegistrations } from './types';
describe('createBackendModule', () => {
@@ -54,4 +56,35 @@ describe('createBackendModule', () => {
// @ts-expect-error
expect(module({ a: 'a' })).toBeDefined();
});
it('should be able to depend on all types of dependencies', () => {
const extensionPoint = createExtensionPoint<string>({ id: 'point' });
const singleServiceRef = createServiceRef<string>({ id: 'single' });
const multiServiceRef = createServiceRef<string>({
id: 'multi',
multiton: true,
});
const plugin = createBackendModule({
pluginId: 'x',
moduleId: 'y',
register(r) {
r.registerInit({
deps: {
point: extensionPoint,
single: singleServiceRef,
multi: multiServiceRef,
},
async init({ point, single, multi }) {
const a: string = point;
const b: string = single;
const c: string[] = multi;
expect([a, b, c]).toBe('unused');
},
});
},
});
expect(plugin.$$type).toEqual('@backstage/BackendFeature');
});
});
@@ -14,7 +14,9 @@
* limitations under the License.
*/
import { createServiceRef } from '../services';
import { createBackendPlugin } from './createBackendPlugin';
import { createExtensionPoint } from './createExtensionPoint';
import { InternalBackendRegistrations } from './types';
describe('createBackendPlugin', () => {
@@ -52,4 +54,50 @@ describe('createBackendPlugin', () => {
// @ts-expect-error
expect(plugin({ a: 'a' })).toBeDefined();
});
it('should be able to depend on all compatible dependencies', () => {
const singleServiceRef = createServiceRef<string>({ id: 'single' });
const multiServiceRef = createServiceRef<string>({
id: 'multi',
multiton: true,
});
const plugin = createBackendPlugin({
pluginId: 'x',
register(r) {
r.registerInit({
deps: {
single: singleServiceRef,
multi: multiServiceRef,
},
async init({ single, multi }) {
const a: string = single;
const b: string[] = multi;
expect([a, b]).toBe('unused');
},
});
},
});
expect(plugin.$$type).toEqual('@backstage/BackendFeature');
});
it('should not be able to depend on extension points', () => {
const extensionPoint = createExtensionPoint<string>({ id: 'point' });
const plugin = createBackendPlugin({
pluginId: 'x',
register(r) {
r.registerInit({
deps: {
// @ts-expect-error
point: extensionPoint,
},
async init() {},
});
},
});
expect(plugin.$$type).toEqual('@backstage/BackendFeature');
});
});
+25 -10
View File
@@ -36,6 +36,17 @@ export type ExtensionPoint<T> = {
$$type: '@backstage/ExtensionPoint';
};
/** @ignore */
type DepsToInstances<
TDeps extends {
[key in string]: ServiceRef<unknown> | ExtensionPoint<unknown>;
},
> = {
[key in keyof TDeps]: TDeps[key] extends ServiceRef<unknown, any, 'multiton'>
? Array<TDeps[key]['T']>
: TDeps[key]['T'];
};
/**
* The callbacks passed to the `register` method of a backend plugin.
*
@@ -46,11 +57,13 @@ export interface BackendPluginRegistrationPoints {
ref: ExtensionPoint<TExtensionPoint>,
impl: TExtensionPoint,
): void;
registerInit<Deps extends { [name in string]: unknown }>(options: {
deps: {
[name in keyof Deps]: ServiceRef<Deps[name]>;
};
init(deps: Deps): Promise<void>;
registerInit<
TDeps extends {
[name in string]: ServiceRef<unknown>;
},
>(options: {
deps: TDeps;
init(deps: DepsToInstances<TDeps>): Promise<void>;
}): void;
}
@@ -64,11 +77,13 @@ export interface BackendModuleRegistrationPoints {
ref: ExtensionPoint<TExtensionPoint>,
impl: TExtensionPoint,
): void;
registerInit<Deps extends { [name in string]: unknown }>(options: {
deps: {
[name in keyof Deps]: ServiceRef<Deps[name]> | ExtensionPoint<Deps[name]>;
};
init(deps: Deps): Promise<void>;
registerInit<
TDeps extends {
[name in string]: ServiceRef<unknown> | ExtensionPoint<unknown>;
},
>(options: {
deps: TDeps;
init(deps: DepsToInstances<TDeps>): Promise<void>;
}): void;
}