From f6aa11291e9e4d4b67d690037c8bcc1455db6203 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Wed, 8 Nov 2023 00:05:36 +0100 Subject: [PATCH] frontend-plugin-api: add missing implementations Signed-off-by: Vincenzo Scamporlino --- packages/frontend-plugin-api/api-report.md | 133 ++++-------------- .../src/apis/system/ApiRef.test.ts | 50 ------- .../src/apis/system/ApiRef.ts | 54 +------ .../src/apis/system/helpers.ts | 18 +++ .../src/apis/system/index.ts | 2 + .../src/apis/system/types.ts | 78 ++-------- .../src/apis/system/useApi.tsx | 18 +++ 7 files changed, 82 insertions(+), 271 deletions(-) delete mode 100644 packages/frontend-plugin-api/src/apis/system/ApiRef.test.ts create mode 100644 packages/frontend-plugin-api/src/apis/system/helpers.ts create mode 100644 packages/frontend-plugin-api/src/apis/system/useApi.tsx diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 4388414095..951922447d 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -8,11 +8,15 @@ import { AlertApi } from '../../../../core-plugin-api'; import { alertApiRef } from '../../../../core-plugin-api'; import { AlertMessage } from '../../../../core-plugin-api'; +import { AnyApiFactory } from '../../../../core-plugin-api'; import { AnyApiFactory as AnyApiFactory_2 } from '@backstage/core-plugin-api'; +import { AnyApiRef } from '../../../../core-plugin-api'; import { AnyApiRef as AnyApiRef_2 } from '@backstage/core-plugin-api'; -import { ApiFactory as ApiFactory_2 } from '@backstage/core-plugin-api'; -import { ApiHolder as ApiHolder_2 } from '@backstage/core-plugin-api'; +import { ApiFactory } from '../../../../core-plugin-api'; +import { ApiHolder } from '../../../../core-plugin-api'; +import { ApiRef } from '../../../../core-plugin-api'; import { ApiRef as ApiRef_2 } from '@backstage/core-plugin-api'; +import { ApiRefConfig } from '../../../../core-plugin-api'; import { AppTheme } from '../../../../core-plugin-api'; import { AppTheme as AppTheme_2 } from '@backstage/core-plugin-api'; import { AppThemeApi } from '../../../../core-plugin-api'; @@ -28,6 +32,8 @@ import { bitbucketServerAuthApiRef } from '../../../../core-plugin-api'; import { ComponentType } from 'react'; import { ConfigApi } from '../../../../core-plugin-api'; import { configApiRef } from '../../../../core-plugin-api'; +import { createApiFactory } from '../../../../core-plugin-api'; +import { createApiRef } from '../../../../core-plugin-api'; import { DiscoveryApi } from '../../../../core-plugin-api'; import { discoveryApiRef } from '../../../../core-plugin-api'; import { ErrorApi } from '../../../../core-plugin-api'; @@ -62,7 +68,6 @@ import { OpenIdConnectApi } from '../../../../core-plugin-api'; import { PendingOAuthRequest } from '../../../../core-plugin-api'; import { ProfileInfo } from '../../../../core-plugin-api'; import { ProfileInfoApi } from '../../../../core-plugin-api'; -import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; import { ReactNode } from 'react'; import { SessionApi } from '../../../../core-plugin-api'; @@ -70,6 +75,10 @@ import { SessionState } from '../../../../core-plugin-api'; import { StorageApi } from '../../../../core-plugin-api'; import { storageApiRef } from '../../../../core-plugin-api'; import { StorageValueSnapshot } from '../../../../core-plugin-api'; +import { TypesToApiRefs } from '../../../../core-plugin-api'; +import { useApi } from '../../../../core-plugin-api'; +import { useApiHolder } from '../../../../core-plugin-api'; +import { withApis } from '../../../../core-plugin-api'; import { z } from 'zod'; import { ZodSchema } from 'zod'; import { ZodTypeDef } from 'zod'; @@ -80,17 +89,9 @@ export { alertApiRef }; export { AlertMessage }; -// @public -export type AnyApiFactory = ApiFactory< - unknown, - unknown, - { - [key in string]: unknown; - } ->; +export { AnyApiFactory }; -// @public -export type AnyApiRef = ApiRef; +export { AnyApiRef }; // @public (undocumented) export type AnyExtensionDataMap = { @@ -130,95 +131,13 @@ export type AnyRoutes = { [name in string]: RouteRef; }; -// @public -export type ApiFactory< - Api, - Impl extends Api, - Deps extends { - [name in string]: unknown; - }, -> = { - api: ApiRef; - deps: TypesToApiRefs; - factory(deps: Deps): Impl; -}; +export { ApiFactory }; -// @public (undocumented) -export type ApiFactoryHolder = { - get(api: ApiRef): - | ApiFactory< - T, - T, - { - [key in string]: unknown; - } - > - | undefined; -}; +export { ApiHolder }; -// @public -export class ApiFactoryRegistry implements ApiFactoryHolder { - // (undocumented) - get(api: ApiRef_2): - | ApiFactory_2< - T, - T, - { - [x: string]: unknown; - } - > - | undefined; - // (undocumented) - getAllApis(): Set; - register< - Api, - Impl extends Api, - Deps extends { - [name in string]: unknown; - }, - >(scope: ApiFactoryScope, factory: ApiFactory_2): boolean; -} +export { ApiRef }; -// @public -export type ApiFactoryScope = 'default' | 'app' | 'static'; - -// @public -export type ApiHolder = { - get(api: ApiRef): T | undefined; -}; - -// @public -export const ApiProvider: ( - props: PropsWithChildren, -) => React_2.JSX.Element; - -// @public -export type ApiProviderProps = { - apis: ApiHolder_2; - children: ReactNode; -}; - -// @public -export type ApiRef = { - id: string; - T: T; -}; - -// @public -export type ApiRefConfig = { - id: string; -}; - -// @public -export class ApiResolver implements ApiHolder_2 { - constructor(factories: ApiFactoryHolder); - // (undocumented) - get(ref: ApiRef_2): T | undefined; - static validateFactories( - factories: ApiFactoryHolder, - apis: Iterable, - ): void; -} +export { ApiRefConfig }; // @public export interface AppNode { @@ -371,8 +290,9 @@ export function createApiExtension< }, ): Extension; -// @public -export function createApiRef(config: ApiRefConfig): ApiRef; +export { createApiFactory }; + +export { createApiRef }; // @public (undocumented) export function createExtension< @@ -820,10 +740,11 @@ export interface SubRouteRef< readonly T: TParams; } -// @public -export type TypesToApiRefs = { - [key in keyof T]: ApiRef; -}; +export { TypesToApiRefs }; + +export { useApi }; + +export { useApiHolder }; // @public export function useRouteRef< @@ -842,4 +763,6 @@ export function useRouteRef( export function useRouteRefParams( _routeRef: RouteRef | SubRouteRef, ): Params; + +export { withApis }; ``` diff --git a/packages/frontend-plugin-api/src/apis/system/ApiRef.test.ts b/packages/frontend-plugin-api/src/apis/system/ApiRef.test.ts deleted file mode 100644 index dab872236f..0000000000 --- a/packages/frontend-plugin-api/src/apis/system/ApiRef.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2020 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. - */ - -import { createApiRef } from './ApiRef'; - -describe('ApiRef', () => { - it('should be created', () => { - const ref = createApiRef({ id: 'abc' }); - expect(ref.id).toBe('abc'); - expect(String(ref)).toBe('apiRef{abc}'); - expect(() => ref.T).toThrow('tried to read ApiRef.T of apiRef{abc}'); - }); - - it('should reject invalid ids', () => { - for (const id of ['a', 'abc', 'ab-c', 'a.b.c', 'a-b.c', 'abc.a-b-c.abc3']) { - expect(createApiRef({ id }).id).toBe(id); - } - - for (const id of [ - '123', - 'ab-3', - 'ab_c', - '.', - '2ac', - 'ab.3a', - '.abc', - 'abc.', - 'ab..s', - '', - '_', - ]) { - expect(() => createApiRef({ id }).id).toThrow( - `API id must only contain period separated lowercase alphanum tokens with dashes, got '${id}'`, - ); - } - }); -}); diff --git a/packages/frontend-plugin-api/src/apis/system/ApiRef.ts b/packages/frontend-plugin-api/src/apis/system/ApiRef.ts index adedff9f73..c60bb5f111 100644 --- a/packages/frontend-plugin-api/src/apis/system/ApiRef.ts +++ b/packages/frontend-plugin-api/src/apis/system/ApiRef.ts @@ -14,51 +14,9 @@ * limitations under the License. */ -import type { ApiRef } from './types'; - -/** - * API reference configuration - holds an ID of the referenced API. - * - * @public - */ -export type ApiRefConfig = { - id: string; -}; - -class ApiRefImpl implements ApiRef { - constructor(private readonly config: ApiRefConfig) { - const valid = config.id - .split('.') - .flatMap(part => part.split('-')) - .every(part => part.match(/^[a-z][a-z0-9]*$/)); - if (!valid) { - throw new Error( - `API id must only contain period separated lowercase alphanum tokens with dashes, got '${config.id}'`, - ); - } - } - - get id(): string { - return this.config.id; - } - - // Utility for getting type of an api, using `typeof apiRef.T` - get T(): T { - throw new Error(`tried to read ApiRef.T of ${this}`); - } - - toString() { - return `apiRef{${this.config.id}}`; - } -} - -/** - * Creates a reference to an API. - * - * @param config - The descriptor of the API to reference. - * @returns An API reference. - * @public - */ -export function createApiRef(config: ApiRefConfig): ApiRef { - return new ApiRefImpl(config); -} +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +export { + type ApiRef, + type ApiRefConfig, + createApiRef, +} from '../../../../core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/system/helpers.ts b/packages/frontend-plugin-api/src/apis/system/helpers.ts new file mode 100644 index 0000000000..53dbcfb4e3 --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/system/helpers.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +export { createApiFactory } from '../../../../core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/system/index.ts b/packages/frontend-plugin-api/src/apis/system/index.ts index 6aad24daa9..b1bd3ac2b3 100644 --- a/packages/frontend-plugin-api/src/apis/system/index.ts +++ b/packages/frontend-plugin-api/src/apis/system/index.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +export { useApi, useApiHolder, withApis } from './useApi'; export { createApiRef } from './ApiRef'; export type { ApiRefConfig } from './ApiRef'; export * from './types'; +export * from './helpers'; diff --git a/packages/frontend-plugin-api/src/apis/system/types.ts b/packages/frontend-plugin-api/src/apis/system/types.ts index 730493c079..d56674625e 100644 --- a/packages/frontend-plugin-api/src/apis/system/types.ts +++ b/packages/frontend-plugin-api/src/apis/system/types.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * 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. @@ -14,70 +14,12 @@ * limitations under the License. */ -/** - * API reference. - * - * @public - */ -export type ApiRef = { - id: string; - T: T; -}; - -/** - * Catch-all {@link ApiRef} type. - * - * @public - */ -export type AnyApiRef = ApiRef; - -/** - * Wraps a type with API properties into a type holding their respective {@link ApiRef}s. - * - * @public - */ -export type TypesToApiRefs = { [key in keyof T]: ApiRef }; - -/** - * Provides lookup of APIs through their {@link ApiRef}s. - * - * @public - */ -export type ApiHolder = { - get(api: ApiRef): T | undefined; -}; - -/** - * Describes type returning API implementations. - * - * @public - */ -export type ApiFactory< - Api, - Impl extends Api, - Deps extends { [name in string]: unknown }, -> = { - api: ApiRef; - deps: TypesToApiRefs; - factory(deps: Deps): Impl; -}; - -/** - * Catch-all {@link ApiFactory} type. - * - * @public - */ -export type AnyApiFactory = ApiFactory< - unknown, - unknown, - { [key in string]: unknown } ->; - -/** - * @public - */ -export type ApiFactoryHolder = { - get( - api: ApiRef, - ): ApiFactory | undefined; -}; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +export type { + ApiRef, + AnyApiRef, + TypesToApiRefs, + ApiHolder, + ApiFactory, + AnyApiFactory, +} from '../../../../core-plugin-api'; diff --git a/packages/frontend-plugin-api/src/apis/system/useApi.tsx b/packages/frontend-plugin-api/src/apis/system/useApi.tsx new file mode 100644 index 0000000000..bb0f816cfc --- /dev/null +++ b/packages/frontend-plugin-api/src/apis/system/useApi.tsx @@ -0,0 +1,18 @@ +/* + * 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. + */ + +// eslint-disable-next-line @backstage/no-relative-monorepo-imports +export { useApiHolder, useApi, withApis } from '../../../../core-plugin-api';