frontend-plugin-api: simply output mapping types + add inputs mapped types
Co-authored-by: Fredrik Adelöw <freben@gmail.com> Co-authored-by: Johan Haals <johan.haals@gmail.com> Co-authored-by: Philipp Hugenroth <philipph@spotify.com> Co-authored-by: Camila Belo <camilaibs@gmail.com> Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -19,6 +19,8 @@ import { createExtensionDataRef } from './createExtensionDataRef';
|
||||
|
||||
const stringData = createExtensionDataRef<string>('string');
|
||||
|
||||
function unused(..._any: any[]) {}
|
||||
|
||||
describe('createExtension', () => {
|
||||
it('should create an extension with a simple output', () => {
|
||||
const extension = createExtension({
|
||||
@@ -87,4 +89,68 @@ describe('createExtension', () => {
|
||||
});
|
||||
expect(extension.id).toBe('test');
|
||||
});
|
||||
|
||||
it('should create an extension with input', () => {
|
||||
const extension = createExtension({
|
||||
id: 'test',
|
||||
at: 'root',
|
||||
inputs: {
|
||||
mixed: {
|
||||
extensionData: {
|
||||
required: stringData,
|
||||
optional: stringData.optional(),
|
||||
},
|
||||
},
|
||||
onlyRequired: {
|
||||
extensionData: {
|
||||
required: stringData,
|
||||
},
|
||||
},
|
||||
onlyOptional: {
|
||||
extensionData: {
|
||||
optional: stringData.optional(),
|
||||
},
|
||||
},
|
||||
},
|
||||
output: {
|
||||
foo: stringData,
|
||||
},
|
||||
factory({ bind, inputs }) {
|
||||
const a1: string = inputs.mixed?.[0].required;
|
||||
// @ts-expect-error
|
||||
const a2: number = inputs.mixed?.[0].required;
|
||||
// @ts-expect-error
|
||||
const a3: any = inputs.mixed?.[0].nonExistent;
|
||||
unused(a1, a2, a3);
|
||||
|
||||
const b1: string | undefined = inputs.mixed?.[0].optional;
|
||||
// @ts-expect-error
|
||||
const b2: string = inputs.mixed?.[0].optional;
|
||||
// @ts-expect-error
|
||||
const b3: number = inputs.mixed?.[0].optional;
|
||||
// @ts-expect-error
|
||||
const b4: number | undefined = inputs.mixed?.[0].optional;
|
||||
unused(b1, b2, b3, b4);
|
||||
|
||||
const c1: string = inputs.onlyRequired?.[0].required;
|
||||
// @ts-expect-error
|
||||
const c2: number = inputs.onlyRequired?.[0].required;
|
||||
unused(c1, c2);
|
||||
|
||||
const d1: string | undefined = inputs.onlyOptional?.[0].optional;
|
||||
// @ts-expect-error
|
||||
const d2: string = inputs.onlyOptional?.[0].optional;
|
||||
// @ts-expect-error
|
||||
const d3: number = inputs.onlyOptional?.[0].optional;
|
||||
// @ts-expect-error
|
||||
const d4: number | undefined = inputs.onlyOptional?.[0].optional;
|
||||
unused(d1, d2, d3, d4);
|
||||
|
||||
bind({
|
||||
foo: 'bar',
|
||||
});
|
||||
},
|
||||
});
|
||||
expect(extension.id).toBe('test');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,32 +18,44 @@ import { PortableSchema } from '../schema';
|
||||
import { BackstagePlugin } from './createPlugin';
|
||||
import { AnyExtensionDataMap, Extension } from './types';
|
||||
|
||||
type OnlyRequiredKeys<TOutput extends AnyExtensionDataMap> = {
|
||||
[K in keyof TOutput]: TOutput[K]['config']['optional'] extends true
|
||||
? never
|
||||
: K;
|
||||
}[keyof TOutput];
|
||||
|
||||
type OnlyOptionalKeys<TOutput extends AnyExtensionDataMap> = {
|
||||
[K in keyof TOutput]: TOutput[K]['config']['optional'] extends false
|
||||
? never
|
||||
: K;
|
||||
}[keyof TOutput];
|
||||
/** @public */
|
||||
export type ExtensionDataInputValues<
|
||||
TInputs extends { [name in string]: { extensionData: AnyExtensionDataMap } },
|
||||
> = {
|
||||
[InputName in keyof TInputs]: Array<
|
||||
{
|
||||
[DataName in keyof TInputs[InputName]['extensionData'] as TInputs[InputName]['extensionData'][DataName]['config'] extends {
|
||||
optional: true;
|
||||
}
|
||||
? DataName
|
||||
: never]?: TInputs[InputName]['extensionData'][DataName]['T'];
|
||||
} & {
|
||||
[DataName in keyof TInputs[InputName]['extensionData'] as TInputs[InputName]['extensionData'][DataName]['config'] extends {
|
||||
optional: false;
|
||||
}
|
||||
? DataName
|
||||
: never]: TInputs[InputName]['extensionData'][DataName]['T'];
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export type ExtensionDataBind<TOutput extends AnyExtensionDataMap> = (
|
||||
outputs: {
|
||||
[K in OnlyRequiredKeys<TOutput>]: TOutput[K]['T'];
|
||||
export type ExtensionDataBind<TMap extends AnyExtensionDataMap> = (
|
||||
values: {
|
||||
[DataName in keyof TMap as TMap[DataName]['config'] extends {
|
||||
optional: false;
|
||||
}
|
||||
? DataName
|
||||
: never]: TMap[DataName]['T'];
|
||||
} & {
|
||||
[K in OnlyOptionalKeys<TOutput>]?: TOutput[K]['T'];
|
||||
[DataName in keyof TMap as TMap[DataName]['config'] extends {
|
||||
optional: true;
|
||||
}
|
||||
? DataName
|
||||
: never]?: TMap[DataName]['T'];
|
||||
},
|
||||
) => void;
|
||||
|
||||
/** @public */
|
||||
export type ExtensionDataValue<TData extends AnyExtensionDataMap> = {
|
||||
[K in keyof TData]: TData[K]['T'];
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface CreateExtensionOptions<
|
||||
TOutput extends AnyExtensionDataMap,
|
||||
@@ -60,11 +72,7 @@ export interface CreateExtensionOptions<
|
||||
source?: BackstagePlugin;
|
||||
bind: ExtensionDataBind<TOutput>;
|
||||
config: TConfig;
|
||||
inputs: {
|
||||
[pointName in keyof TInputs]: ExtensionDataValue<
|
||||
TInputs[pointName]['extensionData']
|
||||
>[];
|
||||
};
|
||||
inputs: ExtensionDataInputValues<TInputs>;
|
||||
}): void;
|
||||
}
|
||||
|
||||
@@ -86,11 +94,7 @@ export function createExtension<
|
||||
return options.factory({
|
||||
bind,
|
||||
config,
|
||||
inputs: inputs as {
|
||||
[pointName in keyof TInputs]: ExtensionDataValue<
|
||||
TInputs[pointName]['extensionData']
|
||||
>[];
|
||||
},
|
||||
inputs: inputs as ExtensionDataInputValues<TInputs>,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ export {
|
||||
createExtension,
|
||||
type CreateExtensionOptions,
|
||||
type ExtensionDataBind,
|
||||
type ExtensionDataValue,
|
||||
type ExtensionDataInputValues,
|
||||
} from './createExtension';
|
||||
export {
|
||||
createExtensionDataRef,
|
||||
|
||||
@@ -20,7 +20,9 @@ import { ExtensionDataRef } from './createExtensionDataRef';
|
||||
import { BackstagePlugin } from './createPlugin';
|
||||
|
||||
/** @public */
|
||||
export type AnyExtensionDataMap = Record<string, ExtensionDataRef<any, any>>;
|
||||
export type AnyExtensionDataMap = {
|
||||
[name in string]: ExtensionDataRef<any, any>;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface Extension<TConfig> {
|
||||
|
||||
Reference in New Issue
Block a user