Make createBackendPlugin and createBackendModule return BackendFeature instead of () => BackendFeature

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2024-06-07 16:30:25 +02:00
parent 647bfe011a
commit 78a0b086d2
125 changed files with 482 additions and 357 deletions
+8 -2
View File
@@ -63,6 +63,12 @@ export interface BackendFeature {
$$type: '@backstage/BackendFeature';
}
// @public @deprecated (undocumented)
export interface BackendFeatureCompat extends BackendFeature {
// @deprecated (undocumented)
(): this;
}
// @public @deprecated (undocumented)
export type BackendModuleConfig = CreateBackendModuleOptions;
@@ -208,7 +214,7 @@ export namespace coreServices {
// @public
export function createBackendModule(
options: CreateBackendModuleOptions,
): () => BackendFeature;
): BackendFeatureCompat;
// @public
export interface CreateBackendModuleOptions {
@@ -221,7 +227,7 @@ export interface CreateBackendModuleOptions {
// @public
export function createBackendPlugin(
options: CreateBackendPluginOptions,
): () => BackendFeature;
): BackendFeatureCompat;
// @public
export interface CreateBackendPluginOptions {
+1 -1
View File
@@ -21,6 +21,6 @@
*/
export * from './services';
export type { BackendFeature } from './types';
export type { BackendFeature, BackendFeatureCompat } from './types';
export * from './paths';
export * from './wiring';
+11
View File
@@ -27,3 +27,14 @@ export interface BackendFeature {
// NOTE: This type is opaque in order to simplify future API evolution.
$$type: '@backstage/BackendFeature';
}
/**
* @public
* @deprecated This type exists only as a helper for old code that relied on `createBackendFeature` and `createBackendPlugin` to return `() => BackendFeature` instead of `BackendFeature`. You should remove the `()` parentheses at the end of your usages. This type will be removed in a future release.
*/
export interface BackendFeatureCompat extends BackendFeature {
/**
* @deprecated You do not need to use this call signature; use the type directly instead by removing the `()` parentheses at the end. This call signature will be removed in a future release.
*/
(): this;
}
@@ -33,19 +33,25 @@ describe('createExtensionPoint', () => {
describe('createBackendPlugin', () => {
it('should create a BackendPlugin', () => {
const plugin = createBackendPlugin({
const result = createBackendPlugin({
pluginId: 'x',
register(r) {
r.registerInit({ deps: {}, async init() {} });
},
});
expect(plugin).toBeDefined();
expect(plugin()).toEqual({
$$type: '@backstage/BackendFeature',
version: 'v1',
getRegistrations: expect.any(Function),
});
expect((plugin() as InternalBackendFeature).getRegistrations()).toEqual([
// legacy form
const legacy = result() as unknown as InternalBackendFeature;
expect(legacy.$$type).toEqual('@backstage/BackendFeature');
expect(legacy.version).toEqual('v1');
expect(legacy.getRegistrations).toEqual(expect.any(Function));
// new form
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: 'plugin',
pluginId: 'x',
@@ -56,6 +62,7 @@ describe('createBackendPlugin', () => {
},
},
]);
// @ts-expect-error
expect(plugin({ a: 'a' })).toBeDefined();
});
@@ -63,21 +70,26 @@ describe('createBackendPlugin', () => {
describe('createBackendModule', () => {
it('should create a BackendModule', () => {
const mod = createBackendModule({
const result = createBackendModule({
pluginId: 'x',
moduleId: 'y',
register(r) {
r.registerInit({ deps: {}, async init() {} });
},
});
expect(mod).toBeDefined();
expect(mod()).toBeDefined();
expect(mod()).toEqual({
$$type: '@backstage/BackendFeature',
version: 'v1',
getRegistrations: expect.any(Function),
});
expect((mod() as InternalBackendFeature).getRegistrations()).toEqual([
// legacy form
const legacy = result() as unknown as InternalBackendFeature;
expect(legacy.$$type).toEqual('@backstage/BackendFeature');
expect(legacy.version).toEqual('v1');
expect(legacy.getRegistrations).toEqual(expect.any(Function));
// new form
const module = result as unknown as InternalBackendFeature;
expect(module.$$type).toEqual('@backstage/BackendFeature');
expect(module.version).toEqual('v1');
expect(module.getRegistrations).toEqual(expect.any(Function));
expect(module.getRegistrations()).toEqual([
{
type: 'module',
pluginId: 'x',
@@ -89,7 +101,8 @@ describe('createBackendModule', () => {
},
},
]);
// @ts-expect-error
expect(mod({ a: 'a' })).toBeDefined();
expect(module({ a: 'a' })).toBeDefined();
});
});
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { BackendFeature, BackendFeatureFactory } from '../types';
import { BackendFeatureCompat } from '../types';
import {
BackendModuleRegistrationPoints,
BackendPluginRegistrationPoints,
@@ -90,63 +90,57 @@ export interface CreateBackendPluginOptions {
*/
export function createBackendPlugin(
options: CreateBackendPluginOptions,
): () => BackendFeature {
const factory: BackendFeatureFactory = () => {
let registrations: InternalBackendPluginRegistration[];
): BackendFeatureCompat {
function getRegistrations() {
const extensionPoints: InternalBackendPluginRegistration['extensionPoints'] =
[];
let init: InternalBackendPluginRegistration['init'] | undefined = undefined;
return {
$$type: '@backstage/BackendFeature',
version: 'v1',
getRegistrations() {
if (registrations) {
return registrations;
options.register({
registerExtensionPoint(ext, impl) {
if (init) {
throw new Error('registerExtensionPoint called after registerInit');
}
const extensionPoints: InternalBackendPluginRegistration['extensionPoints'] =
[];
let init: InternalBackendPluginRegistration['init'] | undefined =
undefined;
options.register({
registerExtensionPoint(ext, impl) {
if (init) {
throw new Error(
'registerExtensionPoint called after registerInit',
);
}
extensionPoints.push([ext, impl]);
},
registerInit(regInit) {
if (init) {
throw new Error('registerInit must only be called once');
}
init = {
deps: regInit.deps,
func: regInit.init,
};
},
});
if (!init) {
throw new Error(
`registerInit was not called by register in ${options.pluginId}`,
);
}
registrations = [
{
type: 'plugin',
pluginId: options.pluginId,
extensionPoints,
init,
},
];
return registrations;
extensionPoints.push([ext, impl]);
},
};
};
factory.$$type = '@backstage/BackendFeatureFactory';
registerInit(regInit) {
if (init) {
throw new Error('registerInit must only be called once');
}
init = {
deps: regInit.deps,
func: regInit.init,
};
},
});
return factory;
if (!init) {
throw new Error(
`registerInit was not called by register in ${options.pluginId}`,
);
}
return [
{
type: 'plugin',
pluginId: options.pluginId,
extensionPoints,
init,
},
];
}
function backendFeatureCompatWrapper() {
return backendFeatureCompatWrapper;
}
Object.assign(backendFeatureCompatWrapper, {
$$type: '@backstage/BackendFeature' as const,
version: 'v1',
getRegistrations,
});
return backendFeatureCompatWrapper as BackendFeatureCompat;
}
/**
@@ -180,62 +174,56 @@ export interface CreateBackendModuleOptions {
*/
export function createBackendModule(
options: CreateBackendModuleOptions,
): () => BackendFeature {
const factory: BackendFeatureFactory = () => {
let registrations: InternalBackendModuleRegistration[];
): BackendFeatureCompat {
function getRegistrations() {
const extensionPoints: InternalBackendPluginRegistration['extensionPoints'] =
[];
let init: InternalBackendModuleRegistration['init'] | undefined = undefined;
return {
$$type: '@backstage/BackendFeature',
version: 'v1',
getRegistrations() {
if (registrations) {
return registrations;
options.register({
registerExtensionPoint(ext, impl) {
if (init) {
throw new Error('registerExtensionPoint called after registerInit');
}
const extensionPoints: InternalBackendPluginRegistration['extensionPoints'] =
[];
let init: InternalBackendModuleRegistration['init'] | undefined =
undefined;
options.register({
registerExtensionPoint(ext, impl) {
if (init) {
throw new Error(
'registerExtensionPoint called after registerInit',
);
}
extensionPoints.push([ext, impl]);
},
registerInit(regInit) {
if (init) {
throw new Error('registerInit must only be called once');
}
init = {
deps: regInit.deps,
func: regInit.init,
};
},
});
if (!init) {
throw new Error(
`registerInit was not called by register in ${options.moduleId} module for ${options.pluginId}`,
);
}
registrations = [
{
type: 'module',
pluginId: options.pluginId,
moduleId: options.moduleId,
extensionPoints,
init,
},
];
return registrations;
extensionPoints.push([ext, impl]);
},
};
};
factory.$$type = '@backstage/BackendFeatureFactory';
registerInit(regInit) {
if (init) {
throw new Error('registerInit must only be called once');
}
init = {
deps: regInit.deps,
func: regInit.init,
};
},
});
return factory;
if (!init) {
throw new Error(
`registerInit was not called by register in ${options.moduleId} module for ${options.pluginId}`,
);
}
return [
{
type: 'module',
pluginId: options.pluginId,
moduleId: options.moduleId,
extensionPoints,
init,
},
];
}
function backendFeatureCompatWrapper() {
return backendFeatureCompatWrapper;
}
Object.assign(backendFeatureCompatWrapper, {
$$type: '@backstage/BackendFeature' as const,
version: 'v1',
getRegistrations,
});
return backendFeatureCompatWrapper as BackendFeatureCompat;
}