diff --git a/.changeset/wicked-bottles-itch.md b/.changeset/wicked-bottles-itch.md new file mode 100644 index 0000000000..5c53d747a9 --- /dev/null +++ b/.changeset/wicked-bottles-itch.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-plugin-api': patch +--- + +Updates all `create*` methods to simplify their type definitions and ensure they all have configuration interfaces. diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index a829f6200c..2dcd0dccb4 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -111,28 +111,19 @@ export namespace coreServices { } // @public -export function createBackendModule< - TOptions extends object | undefined = undefined, ->( +export function createBackendModule( config: BackendModuleConfig, -): undefined extends TOptions - ? (options?: TOptions) => BackendFeature - : (options: TOptions) => BackendFeature; +): FactoryFunctionWithOptions; // @public (undocumented) -export function createBackendPlugin< - TOptions extends object | undefined = undefined, ->(config: { - id: string; - register(reg: BackendRegistrationPoints, options: TOptions): void; -}): undefined extends TOptions - ? (options?: TOptions) => BackendFeature - : (options: TOptions) => BackendFeature; +export function createBackendPlugin( + config: BackendPluginConfig, +): FactoryFunctionWithOptions; // @public (undocumented) -export function createExtensionPoint(options: { - id: string; -}): ExtensionPoint; +export function createExtensionPoint( + config: ExtensionPointConfig, +): ExtensionPoint; // @public (undocumented) export function createServiceFactory< @@ -142,37 +133,20 @@ export function createServiceFactory< TDeps extends { [name in string]: ServiceRef; }, - TOpts extends object | undefined = undefined, ->(config: { - service: ServiceRef; - deps: TDeps; - factory( - deps: ServiceRefsToInstances, - options: TOpts, - ): TScope extends 'root' - ? Promise - : Promise<(deps: ServiceRefsToInstances) => Promise>; -}): undefined extends TOpts - ? (options?: TOpts) => ServiceFactory - : (options: TOpts) => ServiceFactory; + TOpts extends MaybeOptions = undefined, +>( + config: ServiceFactoryConfig, +): FactoryFunctionWithOptions, TOpts>; -// @public (undocumented) -export function createServiceRef(options: { - id: string; - scope?: 'plugin'; - defaultFactory?: ( - service: ServiceRef, - ) => Promise | (() => ServiceFactory)>; -}): ServiceRef; +// @public +export function createServiceRef( + config: ServiceRefConfig, +): ServiceRef; -// @public (undocumented) -export function createServiceRef(options: { - id: string; - scope: 'root'; - defaultFactory?: ( - service: ServiceRef, - ) => Promise | (() => ServiceFactory)>; -}): ServiceRef; +// @public +export function createServiceRef( + config: ServiceRefConfig, +): ServiceRef; // @public export interface DatabaseService { @@ -196,6 +170,12 @@ export type ExtensionPoint = { $$ref: 'extension-point'; }; +// @public (undocumented) +export interface ExtensionPointConfig { + // (undocumented) + id: string; +} + // @public (undocumented) export interface HttpRouterService { // (undocumented) @@ -344,6 +324,29 @@ export type ServiceFactory = >; }; +// @public (undocumented) +export interface ServiceFactoryConfig< + TService, + TScope extends 'root' | 'plugin', + TImpl extends TService, + TDeps extends { + [name in string]: ServiceRef; + }, + TOpts extends MaybeOptions = undefined, +> { + // (undocumented) + deps: TDeps; + // (undocumented) + factory( + deps: ServiceRefsToInstances, + options: TOpts, + ): TScope extends 'root' + ? Promise + : Promise<(deps: ServiceRefsToInstances) => Promise>; + // (undocumented) + service: ServiceRef; +} + // @public export type ServiceRef< TService, @@ -356,6 +359,18 @@ export type ServiceRef< $$ref: 'service'; }; +// @public (undocumented) +export interface ServiceRefConfig { + // (undocumented) + defaultFactory?: ( + service: ServiceRef, + ) => Promise | (() => ServiceFactory)>; + // (undocumented) + id: string; + // (undocumented) + scope?: TScope; +} + // @public export interface TokenManagerService { authenticate(token: string): Promise; diff --git a/packages/backend-plugin-api/src/services/system/index.ts b/packages/backend-plugin-api/src/services/system/index.ts index 8c666af42e..d00c2da4bd 100644 --- a/packages/backend-plugin-api/src/services/system/index.ts +++ b/packages/backend-plugin-api/src/services/system/index.ts @@ -14,5 +14,11 @@ * limitations under the License. */ -export type { ServiceRef, TypesToServiceRef, ServiceFactory } from './types'; +export type { + ServiceRef, + ServiceRefConfig, + TypesToServiceRef, + ServiceFactory, + ServiceFactoryConfig, +} from './types'; export { createServiceRef, createServiceFactory } from './types'; diff --git a/packages/backend-plugin-api/src/services/system/types.ts b/packages/backend-plugin-api/src/services/system/types.ts index 2459dea918..7c3a9547b6 100644 --- a/packages/backend-plugin-api/src/services/system/types.ts +++ b/packages/backend-plugin-api/src/services/system/types.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { FactoryFunctionWithOptions, MaybeOptions } from '../../types'; + /** * TODO * @@ -70,48 +72,50 @@ export type ServiceFactory = }; /** @public */ -export function createServiceRef(options: { +export interface ServiceRefConfig { id: string; - scope?: 'plugin'; + scope?: TScope; defaultFactory?: ( - service: ServiceRef, - ) => Promise | (() => ServiceFactory)>; -}): ServiceRef; -/** @public */ -export function createServiceRef(options: { - id: string; - scope: 'root'; - defaultFactory?: ( - service: ServiceRef, - ) => Promise | (() => ServiceFactory)>; -}): ServiceRef; -export function createServiceRef(options: { - id: string; - scope?: 'plugin' | 'root'; - defaultFactory?: - | (( - service: ServiceRef, - ) => Promise | (() => ServiceFactory)>) - | (( - service: ServiceRef, - ) => Promise | (() => ServiceFactory)>); -}): ServiceRef { - const { id, scope = 'plugin', defaultFactory } = options; + service: ServiceRef, + ) => Promise | (() => ServiceFactory)>; +} + +/** + * Creates a new service definition. This overload is used to create plugin scoped services. + * + * @public + */ +export function createServiceRef( + config: ServiceRefConfig, +): ServiceRef; + +/** + * Creates a new service definition. This overload is used to create root scoped services. + * + * @public + */ +export function createServiceRef( + config: ServiceRefConfig, +): ServiceRef; +export function createServiceRef( + config: ServiceRefConfig, +): ServiceRef { + const { id, scope = 'plugin', defaultFactory } = config; return { id, scope, - get T(): T { + get T(): TService { throw new Error(`tried to read ServiceRef.T of ${this}`); }, toString() { - return `serviceRef{${options.id}}`; + return `serviceRef{${config.id}}`; }, $$ref: 'service', // TODO: declare __defaultFactory: defaultFactory, - } as ServiceRef & { + } as ServiceRef & { __defaultFactory?: ( - service: ServiceRef, - ) => Promise | (() => ServiceFactory)>; + service: ServiceRef, + ) => Promise | (() => ServiceFactory)>; }; } @@ -125,16 +129,14 @@ type ServiceRefsToInstances< }[keyof T]]: T[name] extends ServiceRef ? TImpl : never; }; -/** - * @public - */ -export function createServiceFactory< +/** @public */ +export interface ServiceFactoryConfig< TService, TScope extends 'root' | 'plugin', TImpl extends TService, TDeps extends { [name in string]: ServiceRef }, - TOpts extends object | undefined = undefined, ->(config: { + TOpts extends MaybeOptions = undefined, +> { service: ServiceRef; deps: TDeps; factory( @@ -143,9 +145,20 @@ export function createServiceFactory< ): TScope extends 'root' ? Promise : Promise<(deps: ServiceRefsToInstances) => Promise>; -}): undefined extends TOpts - ? (options?: TOpts) => ServiceFactory - : (options: TOpts) => ServiceFactory { +} + +/** + * @public + */ +export function createServiceFactory< + TService, + TScope extends 'root' | 'plugin', + TImpl extends TService, + TDeps extends { [name in string]: ServiceRef }, + TOpts extends MaybeOptions = undefined, +>( + config: ServiceFactoryConfig, +): FactoryFunctionWithOptions, TOpts> { return (options?: TOpts) => ({ scope: config.service.scope, diff --git a/packages/backend-plugin-api/src/types.ts b/packages/backend-plugin-api/src/types.ts new file mode 100644 index 0000000000..6da3bafe17 --- /dev/null +++ b/packages/backend-plugin-api/src/types.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Base type for options objects that aren't required. + * + * @ignore + */ +export type MaybeOptions = object | undefined; + +/** + * Helper type that makes the options argument optional if options are not required. + * + * @ignore + */ +export type FactoryFunctionWithOptions = + undefined extends TOptions + ? (options?: TOptions) => TResult + : (options: TOptions) => TResult; diff --git a/packages/backend-plugin-api/src/wiring/factories.ts b/packages/backend-plugin-api/src/wiring/factories.ts index 831e40f9f8..4c384840cd 100644 --- a/packages/backend-plugin-api/src/wiring/factories.ts +++ b/packages/backend-plugin-api/src/wiring/factories.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { FactoryFunctionWithOptions, MaybeOptions } from '../types'; import { BackendRegistrationPoints, BackendFeature, @@ -21,16 +22,21 @@ import { } from './types'; /** @public */ -export function createExtensionPoint(options: { +export interface ExtensionPointConfig { id: string; -}): ExtensionPoint { +} + +/** @public */ +export function createExtensionPoint( + config: ExtensionPointConfig, +): ExtensionPoint { return { - id: options.id, + id: config.id, get T(): T { throw new Error(`tried to read ExtensionPoint.T of ${this}`); }, toString() { - return `extensionPoint{${options.id}}`; + return `extensionPoint{${config.id}}`; }, $$ref: 'extension-point', // TODO: declare }; @@ -43,14 +49,9 @@ export interface BackendPluginConfig { } /** @public */ -export function createBackendPlugin< - TOptions extends object | undefined = undefined, ->(config: { - id: string; - register(reg: BackendRegistrationPoints, options: TOptions): void; -}): undefined extends TOptions - ? (options?: TOptions) => BackendFeature - : (options: TOptions) => BackendFeature { +export function createBackendPlugin( + config: BackendPluginConfig, +): FactoryFunctionWithOptions { return (options?: TOptions) => ({ id: config.id, register(register: BackendRegistrationPoints) { @@ -70,9 +71,11 @@ export interface BackendModuleConfig { } /** + * Creates a new backend module for a given plugin. + * * @public * - * Creates a new backend module for a given plugin. + * @remarks * * The `moduleId` should be equal to the module-specific prefix of the exported name, such * that the full name is `moduleId + PluginId + "Module"`. For example, a GitHub entity @@ -81,13 +84,9 @@ export interface BackendModuleConfig { * * The `pluginId` should exactly match the `id` of the plugin that the module extends. */ -export function createBackendModule< - TOptions extends object | undefined = undefined, ->( +export function createBackendModule( config: BackendModuleConfig, -): undefined extends TOptions - ? (options?: TOptions) => BackendFeature - : (options: TOptions) => BackendFeature { +): FactoryFunctionWithOptions { return (options?: TOptions) => ({ id: `${config.pluginId}.${config.moduleId}`, register(register: BackendRegistrationPoints) { diff --git a/packages/backend-plugin-api/src/wiring/index.ts b/packages/backend-plugin-api/src/wiring/index.ts index 8f85edb2eb..6d8de91080 100644 --- a/packages/backend-plugin-api/src/wiring/index.ts +++ b/packages/backend-plugin-api/src/wiring/index.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -export type { BackendModuleConfig, BackendPluginConfig } from './factories'; +export type { + BackendModuleConfig, + BackendPluginConfig, + ExtensionPointConfig, +} from './factories'; export { createBackendModule, createBackendPlugin,