chore: steps to making outputs and factories look pretty

Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
blam
2024-08-05 17:35:13 +02:00
committed by Patrik Oldsberg
parent 34f1b2aeb1
commit 1533b959ef
3 changed files with 102 additions and 16 deletions
@@ -148,7 +148,9 @@ export interface LegacyCreateExtensionOptions<
/** @ignore */
export type VerifyExtensionFactoryOutput<
UDeclaredOutput extends AnyExtensionDataRef,
UFactoryOutput extends ExtensionDataValue<any, any>,
UFactoryOutput extends
| ExtensionDataValue<any, any>
| ExtensionDataContainer<any>,
> = (
UDeclaredOutput extends any
? UDeclaredOutput['config']['optional'] extends true
@@ -156,21 +158,29 @@ export type VerifyExtensionFactoryOutput<
: UDeclaredOutput['id']
: never
) extends infer IRequiredOutputIds
? [IRequiredOutputIds] extends [UFactoryOutput['id']]
? [UFactoryOutput['id']] extends [UDeclaredOutput['id']]
? {}
? (
UFactoryOutput extends ExtensionDataValue<any, any>
? UFactoryOutput['id']
: UFactoryOutput extends ExtensionDataContainer<infer IDataRefs>
? IDataRefs['id']
: never
) extends infer IFactoryOutputIds
? [IRequiredOutputIds] extends [IFactoryOutputIds]
? [IFactoryOutputIds] extends [UDeclaredOutput['id']]
? {}
: {
'Error: The extension factory has undeclared output(s)': Exclude<
IFactoryOutputIds,
UDeclaredOutput['id']
>;
}
: {
'Error: The extension factory has undeclared output(s)': Exclude<
UFactoryOutput['id'],
UDeclaredOutput['id']
'Error: The extension factory is missing the following output(s)': Exclude<
IRequiredOutputIds,
IFactoryOutputIds
>;
}
: {
'Error: The extension factory is missing the following output(s)': Exclude<
IRequiredOutputIds,
UFactoryOutput['id']
>;
}
: never
: never;
/** @public */
@@ -21,6 +21,7 @@ import { createExtensionTester } from '@backstage/frontend-test-utils';
import { createExtensionDataRef } from './createExtensionDataRef';
import { createExtensionInput } from './createExtensionInput';
import { RouteRef } from '../routing';
import { toInternalExtensionDefinition } from './createExtension';
function unused(..._any: any[]) {}
@@ -450,4 +451,79 @@ describe('createExtensionBlueprint', () => {
expect(true).toBe(true);
});
it('should replace the outputs when provided through make', () => {
const testDataRef1 = createExtensionDataRef<string>().with({ id: 'test1' });
const testDataRef2 = createExtensionDataRef<string>().with({ id: 'test2' });
const blueprint = createExtensionBlueprint({
kind: 'test-extension',
attachTo: { id: 'test', input: 'default' },
output: [testDataRef1],
factory() {
return [testDataRef1('foo')];
},
});
const ext = toInternalExtensionDefinition(
blueprint.make({
output: [testDataRef2],
factory(origFactory) {
const parent = origFactory({});
return [testDataRef2(`${parent.get(testDataRef1)}bar`)];
},
}),
);
expect(ext.output).toEqual([testDataRef2]);
});
it('should allow returning of the parent data container', () => {
const testDataRef1 = createExtensionDataRef<string>().with({ id: 'test1' });
const testDataRef2 = createExtensionDataRef<string>().with({ id: 'test2' });
const blueprint = createExtensionBlueprint({
kind: 'test-extension',
attachTo: { id: 'test', input: 'default' },
output: [testDataRef1],
factory() {
return [testDataRef1('foo')];
},
});
blueprint.make({
output: [testDataRef1, testDataRef2],
*factory(origFactory) {
yield origFactory({});
yield testDataRef2('bar');
},
});
expect(true).toBe(true);
// todo: test that the data is actually available
});
it('should not allow returning parent output if outputs are overridden', () => {
const testDataRef1 = createExtensionDataRef<string>().with({ id: 'test1' });
const testDataRef2 = createExtensionDataRef<string>().with({ id: 'test2' });
const blueprint = createExtensionBlueprint({
kind: 'test-extension',
attachTo: { id: 'test', input: 'default' },
output: [testDataRef1.optional()],
factory() {
return [testDataRef1('foo')];
},
});
blueprint.make({
output: [testDataRef2.optional()],
*factory(origFactory) {
// yield testDataRef1('bar');
yield testDataRef2('bar');
},
});
expect(true).toBe(true);
});
});
@@ -204,7 +204,7 @@ class ExtensionBlueprintImpl<
[key in string]: (zImpl: typeof z) => z.ZodType;
},
UFactoryOutput extends ExtensionDataValue<any, any>,
UExtraOutput extends AnyExtensionDataRef,
UNewOutput extends AnyExtensionDataRef,
TExtraInputs extends {
[inputName in string]: ExtensionInput<
AnyExtensionDataRef,
@@ -220,7 +220,7 @@ class ExtensionBlueprintImpl<
[KName in keyof TInputs]?: `Error: Input '${KName &
string}' is already defined in parent definition`;
};
output?: Array<UExtraOutput>;
output?: Array<UNewOutput>;
params?: TParams;
config?: {
schema: TExtensionConfigSchema;
@@ -296,7 +296,7 @@ class ExtensionBlueprintImpl<
attachTo: args.attachTo ?? this.options.attachTo,
disabled: args.disabled ?? this.options.disabled,
inputs: { ...args.inputs, ...this.options.inputs },
output: [...(args.output ?? []), ...this.options.output],
output: args.output ?? this.options.output,
config: Object.keys(schema).length === 0 ? undefined : { schema },
factory: ({ node, config, inputs }) => {
if (args.factory) {