backend-plugin-api: refactor to flatten internal backend feature loader
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -14,7 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createServiceFactory, createServiceRef } from './types';
|
||||
import {
|
||||
InternalServiceFactory,
|
||||
createServiceFactory,
|
||||
createServiceRef,
|
||||
} from './types';
|
||||
|
||||
const ref = createServiceRef<string>({ id: 'x' });
|
||||
const rootDep = createServiceRef<number>({ id: 'y', scope: 'root' });
|
||||
@@ -36,6 +40,10 @@ describe('createServiceFactory', () => {
|
||||
},
|
||||
});
|
||||
expect(metaFactory).toEqual(expect.any(Function));
|
||||
expect(metaFactory().$$type).toBe('@backstage/BackendFeature');
|
||||
expect((metaFactory() as InternalServiceFactory).featureType).toBe(
|
||||
'service',
|
||||
);
|
||||
expect(metaFactory().service).toBe(ref);
|
||||
|
||||
// @ts-expect-error
|
||||
|
||||
@@ -78,6 +78,7 @@ export interface InternalServiceFactory<
|
||||
TScope extends 'plugin' | 'root' = 'plugin' | 'root',
|
||||
> extends ServiceFactory<TService, TScope> {
|
||||
version: 'v1';
|
||||
featureType: 'service';
|
||||
initialization?: 'always' | 'lazy';
|
||||
deps: { [key in string]: ServiceRef<unknown> };
|
||||
createRootContext?(deps: { [key in string]: unknown }): Promise<unknown>;
|
||||
@@ -307,6 +308,7 @@ export function createServiceFactory<
|
||||
return {
|
||||
$$type: '@backstage/BackendFeature',
|
||||
version: 'v1',
|
||||
featureType: 'service',
|
||||
service: c.service,
|
||||
initialization: c.initialization,
|
||||
deps: c.deps,
|
||||
@@ -322,6 +324,7 @@ export function createServiceFactory<
|
||||
return {
|
||||
$$type: '@backstage/BackendFeature',
|
||||
version: 'v1',
|
||||
featureType: 'service',
|
||||
service: c.service,
|
||||
initialization: c.initialization,
|
||||
...('createRootContext' in c
|
||||
|
||||
@@ -15,33 +15,25 @@
|
||||
*/
|
||||
|
||||
import { coreServices, createServiceFactory } from '../services';
|
||||
import { InternalServiceFactory } from '../services/system/types';
|
||||
import { BackendFeature } from '../types';
|
||||
import { createBackendFeatureLoader } from './createBackendFeatureLoader';
|
||||
import { createBackendPlugin } from './createBackendPlugin';
|
||||
import {
|
||||
InternalBackendFeature,
|
||||
InternalBackendFeatureLoaderRegistration,
|
||||
} from './types';
|
||||
import { InternalBackendFeatureLoader } from './types';
|
||||
|
||||
describe('createBackendFeatureLoader', () => {
|
||||
it('should create an empty feature loader', () => {
|
||||
const result = createBackendFeatureLoader({
|
||||
deps: {},
|
||||
loader: () => [],
|
||||
});
|
||||
}) as InternalBackendFeatureLoader;
|
||||
|
||||
const plugin = result as unknown as InternalBackendFeature;
|
||||
expect(plugin.$$type).toEqual('@backstage/BackendFeature');
|
||||
expect(plugin.version).toEqual('v1');
|
||||
expect(plugin.getRegistrations).toEqual(expect.any(Function));
|
||||
expect(plugin.getRegistrations()).toEqual([
|
||||
{
|
||||
type: 'loader',
|
||||
description: expect.stringMatching(/^created at '.*'$/),
|
||||
deps: expect.any(Object),
|
||||
loader: expect.any(Function),
|
||||
},
|
||||
]);
|
||||
expect(result.$$type).toEqual('@backstage/BackendFeature');
|
||||
expect(result.version).toEqual('v1');
|
||||
expect(result.featureType).toEqual('loader');
|
||||
expect(result.deps).toEqual({});
|
||||
expect(result.loader).toEqual(expect.any(Function));
|
||||
expect(result.description).toMatch(/^created at '.*'$/);
|
||||
});
|
||||
|
||||
it('should create a feature loader that loads a few features', async () => {
|
||||
@@ -69,29 +61,21 @@ describe('createBackendFeatureLoader', () => {
|
||||
}),
|
||||
];
|
||||
},
|
||||
}) as InternalBackendFeature;
|
||||
}) as InternalBackendFeatureLoader;
|
||||
|
||||
expect(result.$$type).toEqual('@backstage/BackendFeature');
|
||||
expect(result.version).toEqual('v1');
|
||||
expect(result.getRegistrations).toEqual(expect.any(Function));
|
||||
expect(result.featureType).toEqual('loader');
|
||||
|
||||
const registrations = result.getRegistrations();
|
||||
expect(registrations).toEqual([
|
||||
{
|
||||
type: 'loader',
|
||||
description: expect.stringMatching(/^created at '.*'$/),
|
||||
deps: expect.any(Object),
|
||||
loader: expect.any(Function),
|
||||
},
|
||||
]);
|
||||
|
||||
const results = await (registrations[0] as any).loader({ config: {} });
|
||||
const results = await result.loader({ config: {} });
|
||||
expect(results.length).toBe(3);
|
||||
const [pluginX, serviceFactory, pluginY] = results;
|
||||
expect(pluginX.$$type).toBe('@backstage/BackendFeature');
|
||||
expect(serviceFactory.$$type).toBe('@backstage/BackendFeature');
|
||||
expect(pluginY.$$type).toBe('@backstage/BackendFeature');
|
||||
expect(serviceFactory.service.id).toBe(coreServices.pluginMetadata.id);
|
||||
expect((serviceFactory as InternalServiceFactory).service.id).toBe(
|
||||
coreServices.pluginMetadata.id,
|
||||
);
|
||||
});
|
||||
|
||||
it('should support multiple output formats', async () => {
|
||||
@@ -99,10 +83,8 @@ describe('createBackendFeatureLoader', () => {
|
||||
const dynamicFeature = Promise.resolve({ default: feature });
|
||||
|
||||
async function extractResult(f: BackendFeature) {
|
||||
const internal = f as InternalBackendFeature;
|
||||
const reg =
|
||||
internal.getRegistrations()[0] as InternalBackendFeatureLoaderRegistration;
|
||||
return reg.loader({});
|
||||
const internal = f as InternalBackendFeatureLoader;
|
||||
return internal.loader({});
|
||||
}
|
||||
|
||||
await expect(
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import { ServiceRef } from '../services';
|
||||
import { BackendFeature } from '../types';
|
||||
import { InternalBackendFeature } from './types';
|
||||
import { InternalBackendFeatureLoader } from './types';
|
||||
|
||||
/**
|
||||
* @public
|
||||
@@ -43,31 +43,25 @@ export interface CreateBackendFeatureLoaderOptions<
|
||||
export function createBackendFeatureLoader<
|
||||
TDeps extends { [name in string]: unknown },
|
||||
>(options: CreateBackendFeatureLoaderOptions<TDeps>): BackendFeature {
|
||||
const registrations = [
|
||||
{
|
||||
type: 'loader',
|
||||
description: `created at '${new Date().toISOString()}'`,
|
||||
deps: options.deps,
|
||||
async loader(deps: TDeps) {
|
||||
const it = await options.loader(deps);
|
||||
const result = new Array<BackendFeature>();
|
||||
for await (const item of it) {
|
||||
if ('$$type' in item && item.$$type === '@backstage/BackendFeature') {
|
||||
result.push(item);
|
||||
} else if ('default' in item) {
|
||||
result.push(item.default);
|
||||
} else {
|
||||
throw new Error(`Invalid item "${item}"`);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return {
|
||||
$$type: '@backstage/BackendFeature',
|
||||
version: 'v1',
|
||||
getRegistrations: () => registrations,
|
||||
} as InternalBackendFeature;
|
||||
featureType: 'loader',
|
||||
description: `created at '${new Date().toISOString()}'`,
|
||||
deps: options.deps,
|
||||
async loader(deps: TDeps) {
|
||||
const it = await options.loader(deps);
|
||||
const result = new Array<BackendFeature>();
|
||||
for await (const item of it) {
|
||||
if ('$$type' in item && item.$$type === '@backstage/BackendFeature') {
|
||||
result.push(item);
|
||||
} else if ('default' in item) {
|
||||
result.push(item.default);
|
||||
} else {
|
||||
throw new Error(`Invalid item "${item}"`);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
} as InternalBackendFeatureLoader;
|
||||
}
|
||||
|
||||
@@ -75,10 +75,9 @@ export interface BackendModuleRegistrationPoints {
|
||||
/** @internal */
|
||||
export interface InternalBackendFeature extends BackendFeature {
|
||||
version: 'v1';
|
||||
featureType: 'registrations';
|
||||
getRegistrations(): Array<
|
||||
| InternalBackendPluginRegistration
|
||||
| InternalBackendModuleRegistration
|
||||
| InternalBackendFeatureLoaderRegistration
|
||||
InternalBackendPluginRegistration | InternalBackendModuleRegistration
|
||||
>;
|
||||
}
|
||||
|
||||
@@ -108,8 +107,9 @@ export interface InternalBackendModuleRegistration {
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface InternalBackendFeatureLoaderRegistration {
|
||||
type: 'loader';
|
||||
export interface InternalBackendFeatureLoader extends BackendFeature {
|
||||
version: 'v1';
|
||||
featureType: 'loader';
|
||||
description: string;
|
||||
deps: Record<string, ServiceRef<unknown>>;
|
||||
loader(deps: Record<string, unknown>): Promise<BackendFeature[]>;
|
||||
|
||||
Reference in New Issue
Block a user