frontend-plugin-api: validate input override values

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-08-10 13:56:03 +02:00
parent c33f8df6eb
commit eab84be933
2 changed files with 50 additions and 5 deletions
@@ -443,17 +443,17 @@ describe('createExtensionBlueprint', () => {
}),
]);
// Not enough values provided, checked at runtime
// Mismatched input override length
expect(() =>
factoryOutput(
Blueprint.makeWithOverrides({
factory(origFactory) {
factory(origFactory, { inputs }) {
return origFactory(
{},
{
inputs: {
single: [],
multi: [],
...inputs,
multi: [[testDataRef1('multi1')]],
},
},
);
@@ -465,6 +465,28 @@ describe('createExtensionBlueprint', () => {
`"Invalid override provided for input 'multi', when overriding the input data the length must match the original input data"`,
);
// Required input not provided
expect(() =>
factoryOutput(
Blueprint.makeWithOverrides({
factory(origFactory, { inputs }) {
return origFactory(
{},
{
inputs: {
...inputs,
single: [testDataRef2('singleOpt')],
},
},
);
},
}),
mockParentInputs,
),
).toThrowErrorMatchingInlineSnapshot(
`"Missing required data values for 'test1'"`,
);
// Wrong value provided
expect(() =>
factoryOutput(
@@ -490,7 +512,7 @@ describe('createExtensionBlueprint', () => {
mockParentInputs,
),
).toThrowErrorMatchingInlineSnapshot(
`"Invalid override provided for input 'multi', when overriding the input data the length must match the original input data"`,
`"Invalid data value provided, 'test2' was not declared"`,
);
// Forwarding entire inputs object
@@ -259,13 +259,34 @@ export function createDataContainer<UData extends AnyExtensionDataRef>(
? ExtensionDataValue<IData, IId>
: never
>,
declaredRefs?: ExtensionDataRef<any, any, any>[],
): ExtensionDataContainer<UData> {
const container = new Map<string, ExtensionDataValue<any, any>>();
const verifyRefs =
declaredRefs && new Map(declaredRefs.map(ref => [ref.id, ref]));
for (const output of values) {
if (verifyRefs) {
if (!verifyRefs.delete(output.id)) {
throw new Error(
`Invalid data value provided, '${output.id}' was not declared`,
);
}
}
container.set(output.id, output);
}
const remainingRefs =
verifyRefs &&
Array.from(verifyRefs.values()).filter(ref => !ref.config.optional);
if (remainingRefs && remainingRefs.length > 0) {
throw new Error(
`Missing required data values for '${remainingRefs
.map(ref => ref.id)
.join(', ')}'`,
);
}
return {
get(ref) {
return container.get(ref.id)?.value;
@@ -436,6 +457,7 @@ class ExtensionBlueprintImpl<
if (providedData) {
const providedContainer = createDataContainer(
providedData as Iterable<ExtensionDataValue<any, any>>,
declaredInput.extensionData,
);
if (!originalInput) {
throw new Error(
@@ -467,6 +489,7 @@ class ExtensionBlueprintImpl<
newInputs[name] = providedData.map((data, i) => {
const providedContainer = createDataContainer(
data as Iterable<ExtensionDataValue<any, any>>,
declaredInput.extensionData,
);
return Object.assign(providedContainer, {
name: (originalInput[i] as ResolvedExtensionInput<any>)