frontend-plugin-api: wrap resolved extension inputs in an object

Co-authored-by: Camila Belo <camilaibs@gmail.com>
Co-authored-by: Vincenzo Scamporlino <vincenzos@spotify.com>
Co-authored-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Philipp Hugenroth <philipph@spotify.com>
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2023-11-26 10:48:12 +01:00
parent 0e1a53db1b
commit 8f5d6c1fbf
29 changed files with 166 additions and 111 deletions
+30 -29
View File
@@ -382,7 +382,7 @@ export function createApiExtension<
api: AnyApiRef;
factory: (options: {
config: TConfig;
inputs: Expand<ExtensionInputValues<TInputs>>;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => AnyApiFactory;
}
| {
@@ -413,13 +413,13 @@ export function createComponentExtension<
| {
lazy: (values: {
config: TConfig;
inputs: Expand<ExtensionInputValues<TInputs>>;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => Promise<TRef['T']>;
}
| {
sync: (values: {
config: TConfig;
inputs: Expand<ExtensionInputValues<TInputs>>;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => TRef['T'];
};
}): ExtensionDefinition<TConfig>;
@@ -475,7 +475,7 @@ export interface CreateExtensionOptions<
factory(options: {
node: AppNode;
config: TConfig;
inputs: Expand<ExtensionInputValues<TInputs>>;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}): Expand<ExtensionDataValues<TOutput>>;
// (undocumented)
inputs?: TInputs;
@@ -556,7 +556,7 @@ export function createPageExtension<
routeRef?: RouteRef;
loader: (options: {
config: TConfig;
inputs: Expand<ExtensionInputValues<TInputs>>;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => Promise<JSX.Element>;
},
): ExtensionDefinition<TConfig>;
@@ -610,7 +610,7 @@ export function createSignInPageExtension<
inputs?: TInputs;
loader: (options: {
config: TConfig;
inputs: Expand<ExtensionInputValues<TInputs>>;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => Promise<ComponentType<SignInPageProps>>;
}): ExtensionDefinition<TConfig>;
@@ -657,10 +657,7 @@ export interface Extension<TConfig> {
factory(options: {
node: AppNode;
config: TConfig;
inputs: Record<
string,
undefined | Record<string, unknown> | Array<Record<string, unknown>>
>;
inputs: ResolvedExtensionInputs<any>;
}): ExtensionDataValues<any>;
// (undocumented)
id: string;
@@ -730,10 +727,7 @@ export interface ExtensionDefinition<TConfig> {
factory(options: {
node: AppNode;
config: TConfig;
inputs: Record<
string,
undefined | Record<string, unknown> | Array<Record<string, unknown>>
>;
inputs: ResolvedExtensionInputs<any>;
}): ExtensionDataValues<any>;
// (undocumented)
inputs: AnyExtensionInputMap;
@@ -763,21 +757,6 @@ export interface ExtensionInput<
extensionData: TExtensionData;
}
// @public
export type ExtensionInputValues<
TInputs extends {
[name in string]: ExtensionInput<any, any>;
},
> = {
[InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton']
? Array<Expand<ExtensionDataValues<TInputs[InputName]['extensionData']>>>
: false extends TInputs[InputName]['config']['optional']
? Expand<ExtensionDataValues<TInputs[InputName]['extensionData']>>
: Expand<
ExtensionDataValues<TInputs[InputName]['extensionData']> | undefined
>;
};
// @public (undocumented)
export interface ExtensionOverrides {
// (undocumented)
@@ -906,6 +885,28 @@ export { ProfileInfo };
export { ProfileInfoApi };
// @public
export type ResolvedExtensionInput<TExtensionData extends AnyExtensionDataMap> =
{
extensionId: string;
output: ExtensionDataValues<TExtensionData>;
};
// @public
export type ResolvedExtensionInputs<
TInputs extends {
[name in string]: ExtensionInput<any, any>;
},
> = {
[InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton']
? Array<Expand<ResolvedExtensionInput<TInputs[InputName]['extensionData']>>>
: false extends TInputs[InputName]['config']['optional']
? Expand<ResolvedExtensionInput<TInputs[InputName]['extensionData']>>
: Expand<
ResolvedExtensionInput<TInputs[InputName]['extensionData']> | undefined
>;
};
// @public
export type RouteFunc<TParams extends AnyRouteRefParams> = (
...[params]: TParams extends undefined
@@ -17,7 +17,7 @@
import { AnyApiFactory, AnyApiRef } from '@backstage/core-plugin-api';
import { PortableSchema } from '../schema';
import {
ExtensionInputValues,
ResolvedExtensionInputs,
createExtension,
coreExtensionData,
} from '../wiring';
@@ -34,7 +34,7 @@ export function createApiExtension<
api: AnyApiRef;
factory: (options: {
config: TConfig;
inputs: Expand<ExtensionInputValues<TInputs>>;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => AnyApiFactory;
}
| {
@@ -17,7 +17,7 @@
import React, { lazy } from 'react';
import {
AnyExtensionInputMap,
ExtensionInputValues,
ResolvedExtensionInputs,
coreExtensionData,
createExtension,
} from '../wiring';
@@ -40,13 +40,13 @@ export function createComponentExtension<
| {
lazy: (values: {
config: TConfig;
inputs: Expand<ExtensionInputValues<TInputs>>;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => Promise<TRef['T']>;
}
| {
sync: (values: {
config: TConfig;
inputs: Expand<ExtensionInputValues<TInputs>>;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => TRef['T'];
};
}) {
@@ -20,7 +20,7 @@ import { createSchemaFromZod, PortableSchema } from '../schema';
import {
coreExtensionData,
createExtension,
ExtensionInputValues,
ResolvedExtensionInputs,
AnyExtensionInputMap,
} from '../wiring';
import { RouteRef } from '../routing';
@@ -52,7 +52,7 @@ export function createPageExtension<
routeRef?: RouteRef;
loader: (options: {
config: TConfig;
inputs: Expand<ExtensionInputValues<TInputs>>;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => Promise<JSX.Element>;
},
): ExtensionDefinition<TConfig> {
@@ -19,7 +19,7 @@ import { ExtensionBoundary } from '../components';
import { PortableSchema } from '../schema';
import {
createExtension,
ExtensionInputValues,
ResolvedExtensionInputs,
AnyExtensionInputMap,
createExtensionDataRef,
ExtensionDefinition,
@@ -47,7 +47,7 @@ export function createSignInPageExtension<
inputs?: TInputs;
loader: (options: {
config: TConfig;
inputs: Expand<ExtensionInputValues<TInputs>>;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => Promise<ComponentType<SignInPageProps>>;
}): ExtensionDefinition<TConfig> {
return createExtension({
@@ -251,34 +251,34 @@ describe('createExtension', () => {
foo: stringData,
},
factory({ inputs }) {
const a1: string = inputs.mixed?.[0].required;
const a1: string = inputs.mixed?.[0].output.required;
// @ts-expect-error
const a2: number = inputs.mixed?.[0].required;
const a2: number = inputs.mixed?.[0].output.required;
// @ts-expect-error
const a3: any = inputs.mixed?.[0].nonExistent;
const a3: any = inputs.mixed?.[0].output.nonExistent;
unused(a1, a2, a3);
const b1: string | undefined = inputs.mixed?.[0].optional;
const b1: string | undefined = inputs.mixed?.[0].output.optional;
// @ts-expect-error
const b2: string = inputs.mixed?.[0].optional;
const b2: string = inputs.mixed?.[0].output.optional;
// @ts-expect-error
const b3: number = inputs.mixed?.[0].optional;
const b3: number = inputs.mixed?.[0].output.optional;
// @ts-expect-error
const b4: number | undefined = inputs.mixed?.[0].optional;
const b4: number | undefined = inputs.mixed?.[0].output.optional;
unused(b1, b2, b3, b4);
const c1: string = inputs.onlyRequired?.[0].required;
const c1: string = inputs.onlyRequired?.[0].output.required;
// @ts-expect-error
const c2: number = inputs.onlyRequired?.[0].required;
const c2: number = inputs.onlyRequired?.[0].output.required;
unused(c1, c2);
const d1: string | undefined = inputs.onlyOptional?.[0].optional;
const d1: string | undefined = inputs.onlyOptional?.[0].output.optional;
// @ts-expect-error
const d2: string = inputs.onlyOptional?.[0].optional;
const d2: string = inputs.onlyOptional?.[0].output.optional;
// @ts-expect-error
const d3: number = inputs.onlyOptional?.[0].optional;
const d3: number = inputs.onlyOptional?.[0].output.optional;
// @ts-expect-error
const d4: number | undefined = inputs.onlyOptional?.[0].optional;
const d4: number | undefined = inputs.onlyOptional?.[0].output.optional;
unused(d1, d2, d3, d4);
return {
@@ -52,18 +52,28 @@ export type ExtensionDataValues<TExtensionData extends AnyExtensionDataMap> = {
};
/**
* Converts an extension input map into the matching concrete input values type.
* Convert a single extension input into a matching resolved input.
* @public
*/
export type ExtensionInputValues<
export type ResolvedExtensionInput<TExtensionData extends AnyExtensionDataMap> =
{
extensionId: string;
output: ExtensionDataValues<TExtensionData>;
};
/**
* Converts an extension input map into a matching collection of resolved inputs.
* @public
*/
export type ResolvedExtensionInputs<
TInputs extends { [name in string]: ExtensionInput<any, any> },
> = {
[InputName in keyof TInputs]: false extends TInputs[InputName]['config']['singleton']
? Array<Expand<ExtensionDataValues<TInputs[InputName]['extensionData']>>>
? Array<Expand<ResolvedExtensionInput<TInputs[InputName]['extensionData']>>>
: false extends TInputs[InputName]['config']['optional']
? Expand<ExtensionDataValues<TInputs[InputName]['extensionData']>>
? Expand<ResolvedExtensionInput<TInputs[InputName]['extensionData']>>
: Expand<
ExtensionDataValues<TInputs[InputName]['extensionData']> | undefined
ResolvedExtensionInput<TInputs[InputName]['extensionData']> | undefined
>;
};
@@ -84,7 +94,7 @@ export interface CreateExtensionOptions<
factory(options: {
node: AppNode;
config: TConfig;
inputs: Expand<ExtensionInputValues<TInputs>>;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}): Expand<ExtensionDataValues<TOutput>>;
}
@@ -102,10 +112,7 @@ export interface ExtensionDefinition<TConfig> {
factory(options: {
node: AppNode;
config: TConfig;
inputs: Record<
string,
undefined | Record<string, unknown> | Array<Record<string, unknown>>
>;
inputs: ResolvedExtensionInputs<any>;
}): ExtensionDataValues<any>;
}
@@ -121,10 +128,7 @@ export interface Extension<TConfig> {
factory(options: {
node: AppNode;
config: TConfig;
inputs: Record<
string,
undefined | Record<string, unknown> | Array<Record<string, unknown>>
>;
inputs: ResolvedExtensionInputs<any>;
}): ExtensionDataValues<any>;
}
@@ -149,7 +153,7 @@ export function createExtension<
factory({ inputs, ...rest }) {
// TODO: Simplify this, but TS wouldn't infer the input type for some reason
return options.factory({
inputs: inputs as Expand<ExtensionInputValues<TInputs>>,
inputs: inputs as Expand<ResolvedExtensionInputs<TInputs>>,
...rest,
});
},
@@ -65,7 +65,9 @@ const Extension3 = createExtension({
name: nameExtensionDataRef,
},
factory({ inputs }) {
return { name: `extension-3:${inputs.addons.map(n => n.name).join('-')}` };
return {
name: `extension-3:${inputs.addons.map(n => n.output.name).join('-')}`,
};
},
});
@@ -111,7 +113,7 @@ const outputExtension = createExtension({
factory({ inputs }) {
return {
element: React.createElement('span', {}, [
`Names: ${inputs.names.map(n => n.name).join(', ')}`,
`Names: ${inputs.names.map(n => n.output.name).join(', ')}`,
]),
};
},
@@ -25,7 +25,8 @@ export {
type ExtensionDefinition,
type CreateExtensionOptions,
type ExtensionDataValues,
type ExtensionInputValues,
type ResolvedExtensionInput,
type ResolvedExtensionInputs,
type AnyExtensionInputMap,
type AnyExtensionDataMap,
} from './createExtension';