frontend-plugin-api: add the ability for extension data refs to encapsulate values

Co-authored-by: blam <ben@blam.sh>
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-07-26 11:59:04 +02:00
parent 2bae52597d
commit 733cc4f85a
2 changed files with 58 additions and 26 deletions
@@ -14,7 +14,10 @@
* limitations under the License.
*/
import { createExtensionDataRef } from './createExtensionDataRef';
import {
ExtensionDataValue,
createExtensionDataRef,
} from './createExtensionDataRef';
describe('createExtensionDataRef', () => {
it('can be created and read', () => {
@@ -34,4 +37,18 @@ describe('createExtensionDataRef', () => {
expect(refOptional.id).toBe('foo');
expect(String(refOptional)).toBe('ExtensionDataRef{id=foo,optional=true}');
});
it('can be used to encapsulate a value', () => {
const ref = createExtensionDataRef<string>().with({ id: 'foo' });
const val: ExtensionDataValue<string, 'foo'> = ref('hello');
expect(val).toEqual({
$$type: '@backstage/ExtensionDataValue',
id: 'foo',
value: 'hello',
});
// @ts-expect-error
ref(3);
// @ts-expect-error
ref();
});
});
@@ -14,29 +14,37 @@
* limitations under the License.
*/
/** @public */
export type ExtensionDataValue<TData, TId extends string> = {
readonly $$type: '@backstage/ExtensionDataValue';
readonly id: TId;
readonly value: TData;
};
/** @public */
export type ExtensionDataRef<
TData,
TId extends string = string,
TConfig extends { optional?: true } = {},
> = {
id: TId;
T: TData;
config: TConfig;
$$type: '@backstage/ExtensionDataRef';
readonly $$type: '@backstage/ExtensionDataRef';
readonly id: TId;
readonly T: TData;
readonly config: TConfig;
};
/** @public */
export interface ConfigurableExtensionDataRef<
TId extends string,
TData,
TId extends string,
TConfig extends { optional?: true } = {},
> extends ExtensionDataRef<TData, TId, TConfig> {
optional(): ConfigurableExtensionDataRef<
TId,
TData,
TId,
TData & { optional: true }
>;
(t: TData): ExtensionDataValue<TData, TId>;
}
/**
@@ -45,36 +53,43 @@ export interface ConfigurableExtensionDataRef<
*/
export function createExtensionDataRef<TData>(
id: string,
): ConfigurableExtensionDataRef<string, TData>;
): ConfigurableExtensionDataRef<TData, string>;
/** @public */
export function createExtensionDataRef<TData>(): {
with<TId extends string>(options: {
id: TId;
}): ConfigurableExtensionDataRef<TId, TData>;
}): ConfigurableExtensionDataRef<TData, TId>;
};
export function createExtensionDataRef<TData>(id?: string):
| ConfigurableExtensionDataRef<string, TData>
| ConfigurableExtensionDataRef<TData, string>
| {
with<TId extends string>(options: {
id: TId;
}): ConfigurableExtensionDataRef<TId, TData>;
}): ConfigurableExtensionDataRef<TData, TId>;
} {
const createRef = <TId extends string>(refId: TId) =>
({
id: refId,
$$type: '@backstage/ExtensionDataRef',
config: {},
optional() {
return {
...this,
config: { ...this.config, optional: true },
};
},
toString() {
const optional = Boolean(this.config.optional);
return `ExtensionDataRef{id=${refId},optional=${optional}}`;
},
} as ConfigurableExtensionDataRef<TId, TData, { optional?: true }>);
Object.assign(
(value: TData): ExtensionDataValue<TData, TId> => ({
$$type: '@backstage/ExtensionDataValue',
id: refId,
value,
}),
{
id: refId,
$$type: '@backstage/ExtensionDataRef',
config: {},
optional() {
return {
...this,
config: { ...this.config, optional: true },
};
},
toString() {
const optional = Boolean(this.config.optional);
return `ExtensionDataRef{id=${refId},optional=${optional}}`;
},
} as ConfigurableExtensionDataRef<TData, TId, { optional?: true }>,
);
if (id) {
return createRef(id);
}