frontend-plugin-api: add missing implementations

Signed-off-by: Vincenzo Scamporlino <vincenzos@spotify.com>
This commit is contained in:
Vincenzo Scamporlino
2023-11-08 00:05:36 +01:00
committed by Patrik Oldsberg
parent b0716b55d3
commit f6aa11291e
7 changed files with 82 additions and 271 deletions
+28 -105
View File
@@ -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<unknown>;
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<Api>;
deps: TypesToApiRefs<Deps>;
factory(deps: Deps): Impl;
};
export { ApiFactory };
// @public (undocumented)
export type ApiFactoryHolder = {
get<T>(api: ApiRef<T>):
| ApiFactory<
T,
T,
{
[key in string]: unknown;
}
>
| undefined;
};
export { ApiHolder };
// @public
export class ApiFactoryRegistry implements ApiFactoryHolder {
// (undocumented)
get<T>(api: ApiRef_2<T>):
| ApiFactory_2<
T,
T,
{
[x: string]: unknown;
}
>
| undefined;
// (undocumented)
getAllApis(): Set<AnyApiRef_2>;
register<
Api,
Impl extends Api,
Deps extends {
[name in string]: unknown;
},
>(scope: ApiFactoryScope, factory: ApiFactory_2<Api, Impl, Deps>): boolean;
}
export { ApiRef };
// @public
export type ApiFactoryScope = 'default' | 'app' | 'static';
// @public
export type ApiHolder = {
get<T>(api: ApiRef<T>): T | undefined;
};
// @public
export const ApiProvider: (
props: PropsWithChildren<ApiProviderProps>,
) => React_2.JSX.Element;
// @public
export type ApiProviderProps = {
apis: ApiHolder_2;
children: ReactNode;
};
// @public
export type ApiRef<T> = {
id: string;
T: T;
};
// @public
export type ApiRefConfig = {
id: string;
};
// @public
export class ApiResolver implements ApiHolder_2 {
constructor(factories: ApiFactoryHolder);
// (undocumented)
get<T>(ref: ApiRef_2<T>): T | undefined;
static validateFactories(
factories: ApiFactoryHolder,
apis: Iterable<AnyApiRef_2>,
): void;
}
export { ApiRefConfig };
// @public
export interface AppNode {
@@ -371,8 +290,9 @@ export function createApiExtension<
},
): Extension<TConfig>;
// @public
export function createApiRef<T>(config: ApiRefConfig): ApiRef<T>;
export { createApiFactory };
export { createApiRef };
// @public (undocumented)
export function createExtension<
@@ -820,10 +740,11 @@ export interface SubRouteRef<
readonly T: TParams;
}
// @public
export type TypesToApiRefs<T> = {
[key in keyof T]: ApiRef<T[key]>;
};
export { TypesToApiRefs };
export { useApi };
export { useApiHolder };
// @public
export function useRouteRef<
@@ -842,4 +763,6 @@ export function useRouteRef<TParams extends AnyRouteRefParams>(
export function useRouteRefParams<Params extends AnyRouteRefParams>(
_routeRef: RouteRef<Params> | SubRouteRef<Params>,
): Params;
export { withApis };
```
@@ -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}'`,
);
}
});
});
@@ -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<T> implements ApiRef<T> {
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<T>(config: ApiRefConfig): ApiRef<T> {
return new ApiRefImpl<T>(config);
}
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
export {
type ApiRef,
type ApiRefConfig,
createApiRef,
} from '../../../../core-plugin-api';
@@ -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';
@@ -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';
@@ -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<T> = {
id: string;
T: T;
};
/**
* Catch-all {@link ApiRef} type.
*
* @public
*/
export type AnyApiRef = ApiRef<unknown>;
/**
* Wraps a type with API properties into a type holding their respective {@link ApiRef}s.
*
* @public
*/
export type TypesToApiRefs<T> = { [key in keyof T]: ApiRef<T[key]> };
/**
* Provides lookup of APIs through their {@link ApiRef}s.
*
* @public
*/
export type ApiHolder = {
get<T>(api: ApiRef<T>): T | undefined;
};
/**
* Describes type returning API implementations.
*
* @public
*/
export type ApiFactory<
Api,
Impl extends Api,
Deps extends { [name in string]: unknown },
> = {
api: ApiRef<Api>;
deps: TypesToApiRefs<Deps>;
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<T>(
api: ApiRef<T>,
): ApiFactory<T, T, { [key in string]: unknown }> | undefined;
};
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
export type {
ApiRef,
AnyApiRef,
TypesToApiRefs,
ApiHolder,
ApiFactory,
AnyApiFactory,
} from '../../../../core-plugin-api';
@@ -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';