frontend-plugin-api: refactor createDataContainer -> createExtensionDataContainer
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -19,12 +19,14 @@ import { PortableSchema, createSchemaFromZod } from '../schema';
|
||||
import { Expand } from '../types';
|
||||
import {
|
||||
ResolveInputValueOverrides,
|
||||
createDataContainer,
|
||||
resolveInputOverrides,
|
||||
} from './createExtensionBlueprint';
|
||||
import {
|
||||
ExtensionDataContainer,
|
||||
createExtensionDataContainer,
|
||||
} from './createExtensionDataContainer';
|
||||
import {
|
||||
AnyExtensionDataRef,
|
||||
ExtensionDataRef,
|
||||
ExtensionDataValue,
|
||||
} from './createExtensionDataRef';
|
||||
import { ExtensionInput, LegacyExtensionInput } from './createExtensionInput';
|
||||
@@ -68,28 +70,6 @@ export type ExtensionDataValues<TExtensionData extends AnyExtensionDataMap> = {
|
||||
: never]?: TExtensionData[DataName]['T'];
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export type ExtensionDataContainer<UExtensionData extends AnyExtensionDataRef> =
|
||||
Iterable<
|
||||
UExtensionData extends ExtensionDataRef<
|
||||
infer IData,
|
||||
infer IId,
|
||||
infer IConfig
|
||||
>
|
||||
? IConfig['optional'] extends true
|
||||
? never
|
||||
: ExtensionDataValue<IData, IId>
|
||||
: never
|
||||
> & {
|
||||
get<TId extends UExtensionData['id']>(
|
||||
ref: ExtensionDataRef<any, TId, any>,
|
||||
): UExtensionData extends ExtensionDataRef<infer IData, TId, infer IConfig>
|
||||
? IConfig['optional'] extends true
|
||||
? IData | undefined
|
||||
: IData
|
||||
: never;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a single extension input into a matching resolved input.
|
||||
* @public
|
||||
@@ -669,7 +649,7 @@ export function createExtension<
|
||||
};
|
||||
inputs?: ResolveInputValueOverrides<TInputs>;
|
||||
}): ExtensionDataContainer<UOutput> => {
|
||||
return createDataContainer<UOutput>(
|
||||
return createExtensionDataContainer<UOutput>(
|
||||
newOptions.factory({
|
||||
node,
|
||||
config: innerContext?.config ?? config,
|
||||
|
||||
@@ -16,10 +16,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import { coreExtensionData } from './coreExtensionData';
|
||||
import {
|
||||
createDataContainer,
|
||||
createExtensionBlueprint,
|
||||
} from './createExtensionBlueprint';
|
||||
import { createExtensionBlueprint } from './createExtensionBlueprint';
|
||||
import { createExtensionTester } from '@backstage/frontend-test-utils';
|
||||
import {
|
||||
ExtensionDataValue,
|
||||
@@ -31,6 +28,7 @@ import {
|
||||
ExtensionDefinition,
|
||||
toInternalExtensionDefinition,
|
||||
} from './createExtension';
|
||||
import { createExtensionDataContainer } from './createExtensionDataContainer';
|
||||
|
||||
function unused(..._any: any[]) {}
|
||||
|
||||
@@ -376,7 +374,7 @@ describe('createExtensionBlueprint', () => {
|
||||
});
|
||||
|
||||
const mockInput = (node: string, ...data: ExtensionDataValue<any, any>[]) =>
|
||||
Object.assign(createDataContainer(data), {
|
||||
Object.assign(createExtensionDataContainer(data), {
|
||||
node,
|
||||
});
|
||||
const mockParentInputs = {
|
||||
|
||||
@@ -18,7 +18,6 @@ import { AppNode } from '../apis';
|
||||
import { Expand } from '../types';
|
||||
import {
|
||||
CreateExtensionOptions,
|
||||
ExtensionDataContainer,
|
||||
ExtensionDefinition,
|
||||
ResolvedExtensionInput,
|
||||
ResolvedExtensionInputs,
|
||||
@@ -29,10 +28,13 @@ import { z } from 'zod';
|
||||
import { ExtensionInput } from './createExtensionInput';
|
||||
import {
|
||||
AnyExtensionDataRef,
|
||||
ExtensionDataRef,
|
||||
ExtensionDataRefToValue,
|
||||
ExtensionDataValue,
|
||||
} from './createExtensionDataRef';
|
||||
import {
|
||||
ExtensionDataContainer,
|
||||
createExtensionDataContainer,
|
||||
} from './createExtensionDataContainer';
|
||||
|
||||
/**
|
||||
* @public
|
||||
@@ -252,51 +254,6 @@ export interface ExtensionBlueprint<
|
||||
>;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function createDataContainer<UData extends AnyExtensionDataRef>(
|
||||
values: Iterable<
|
||||
UData extends ExtensionDataRef<infer IData, infer IId>
|
||||
? 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(
|
||||
`extension data '${output.id}' was provided but 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 extension data value(s) '${remainingRefs
|
||||
.map(ref => ref.id)
|
||||
.join(', ')}'`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
get(ref) {
|
||||
return container.get(ref.id)?.value;
|
||||
},
|
||||
[Symbol.iterator]() {
|
||||
return container.values();
|
||||
},
|
||||
} as ExtensionDataContainer<UData>;
|
||||
}
|
||||
|
||||
function expectArray<T>(value: T | T[]): T[] {
|
||||
return value as T[];
|
||||
}
|
||||
@@ -333,7 +290,7 @@ export function resolveInputOverrides(
|
||||
if (declaredInput.config.singleton) {
|
||||
const originalInput = expectItem(inputs[name]);
|
||||
if (providedData) {
|
||||
const providedContainer = createDataContainer(
|
||||
const providedContainer = createExtensionDataContainer(
|
||||
providedData as Iterable<ExtensionDataValue<any, any>>,
|
||||
declaredInput.extensionData,
|
||||
);
|
||||
@@ -362,7 +319,7 @@ export function resolveInputOverrides(
|
||||
);
|
||||
}
|
||||
newInputs[name] = providedData.map((data, i) => {
|
||||
const providedContainer = createDataContainer(
|
||||
const providedContainer = createExtensionDataContainer(
|
||||
data as Iterable<ExtensionDataValue<any, any>>,
|
||||
declaredInput.extensionData,
|
||||
);
|
||||
@@ -506,7 +463,7 @@ class ExtensionBlueprintImpl<
|
||||
inputs?: ResolveInputValueOverrides;
|
||||
},
|
||||
): ExtensionDataContainer<UOutput> => {
|
||||
return createDataContainer<UOutput>(
|
||||
return createExtensionDataContainer<UOutput>(
|
||||
this.options.factory(innerParams, {
|
||||
node,
|
||||
config: innerContext?.config ?? config,
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
AnyExtensionDataRef,
|
||||
ExtensionDataRef,
|
||||
ExtensionDataValue,
|
||||
} from './createExtensionDataRef';
|
||||
|
||||
/** @public */
|
||||
export type ExtensionDataContainer<UExtensionData extends AnyExtensionDataRef> =
|
||||
Iterable<
|
||||
UExtensionData extends ExtensionDataRef<
|
||||
infer IData,
|
||||
infer IId,
|
||||
infer IConfig
|
||||
>
|
||||
? IConfig['optional'] extends true
|
||||
? never
|
||||
: ExtensionDataValue<IData, IId>
|
||||
: never
|
||||
> & {
|
||||
get<TId extends UExtensionData['id']>(
|
||||
ref: ExtensionDataRef<any, TId, any>,
|
||||
): UExtensionData extends ExtensionDataRef<infer IData, TId, infer IConfig>
|
||||
? IConfig['optional'] extends true
|
||||
? IData | undefined
|
||||
: IData
|
||||
: never;
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
export function createExtensionDataContainer<UData extends AnyExtensionDataRef>(
|
||||
values: Iterable<
|
||||
UData extends ExtensionDataRef<infer IData, infer IId>
|
||||
? 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(
|
||||
`extension data '${output.id}' was provided but 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 extension data value(s) '${remainingRefs
|
||||
.map(ref => ref.id)
|
||||
.join(', ')}'`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
get(ref) {
|
||||
return container.get(ref.id)?.value;
|
||||
},
|
||||
[Symbol.iterator]() {
|
||||
return container.values();
|
||||
},
|
||||
} as ExtensionDataContainer<UData>;
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
export { coreExtensionData } from './coreExtensionData';
|
||||
export {
|
||||
createExtension,
|
||||
type ExtensionDataContainer,
|
||||
type ExtensionDefinition,
|
||||
type CreateExtensionOptions,
|
||||
type ExtensionDataValues,
|
||||
@@ -32,6 +31,7 @@ export {
|
||||
type ExtensionInput,
|
||||
type LegacyExtensionInput,
|
||||
} from './createExtensionInput';
|
||||
export { type ExtensionDataContainer } from './createExtensionDataContainer';
|
||||
export {
|
||||
createExtensionDataRef,
|
||||
type AnyExtensionDataRef,
|
||||
|
||||
Reference in New Issue
Block a user