From d22f1316c50da7ea5d767fd23d9c6acf9be9ba07 Mon Sep 17 00:00:00 2001 From: blam Date: Wed, 24 Jul 2024 11:25:11 +0200 Subject: [PATCH] chore: getting somewhere with portable schemas and zod types Signed-off-by: blam --- .../src/wiring/createExtension.ts | 25 ++-- .../src/wiring/createExtensionBlueprint.ts | 120 ++++++++---------- plugins/catalog-graph/api-report-alpha.md | 67 +--------- 3 files changed, 75 insertions(+), 137 deletions(-) diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts index 61223ca8e8..6fa3a50634 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtension.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts @@ -15,7 +15,7 @@ */ import { AppNode } from '../apis'; -import { PortableSchema } from '../schema'; +import { PortableSchema, createSchemaFromZod } from '../schema'; import { Expand } from '../types'; import { ExtensionDataRef } from './createExtensionDataRef'; import { ExtensionInput } from './createExtensionInput'; @@ -106,10 +106,7 @@ export interface CreateExtensionOptions< } /** @public */ -export interface ExtensionDefinition< - TConfig, - TConfigSchema = never /* TODO -> refactor */, -> { +export interface ExtensionDefinition { $$type: '@backstage/ExtensionDefinition'; readonly kind?: string; readonly namespace?: string; @@ -117,9 +114,6 @@ export interface ExtensionDefinition< readonly attachTo: { id: string; input: string }; readonly disabled: boolean; readonly configSchema?: PortableSchema; - readonly config?: { - schema: TConfigSchema; - }; } /** @internal */ @@ -162,6 +156,18 @@ export function createExtension< >( options: CreateExtensionOptions, ): ExtensionDefinition { + // TODO: resovle configSchema from either configSchema or config.schema + const newConfigSchema = options.config?.schema; + const configSchema = newConfigSchema + ? createSchemaFromZod(innerZ => + innerZ.object( + Object.fromEntries( + Object.entries(newConfigSchema).map(([k, v]) => [k, v(innerZ)]), + ), + ), + ) + : options.configSchema; + return { $$type: '@backstage/ExtensionDefinition', version: 'v1', @@ -172,8 +178,7 @@ export function createExtension< disabled: options.disabled ?? false, inputs: options.inputs ?? {}, output: options.output, - configSchema: options.configSchema, - config: options.config, + configSchema, factory({ inputs, ...rest }) { // TODO: Simplify this, but TS wouldn't infer the input type for some reason return options.factory({ diff --git a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts index 9cd5689a95..c54131622f 100644 --- a/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts +++ b/packages/frontend-plugin-api/src/wiring/createExtensionBlueprint.ts @@ -33,7 +33,7 @@ export interface CreateExtensionBlueprintOptions< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key: string]: z.ZodTypeAny }, + TConfigSchema extends { [key in string]: z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap, > { kind: string; @@ -51,9 +51,9 @@ export interface CreateExtensionBlueprintOptions< params: TParams, context: { node: AppNode; - config: Expand<{ + config: { [key in keyof TConfigSchema]: z.infer; - }>; + }; inputs: Expand>; }, ): Expand>; @@ -68,7 +68,7 @@ export interface ExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key: string]: z.ZodTypeAny }, + TConfig extends { [key in string]: unknown }, TDataRefs extends AnyExtensionDataMap, > { dataRefs: TDataRefs; @@ -79,7 +79,7 @@ export interface ExtensionBlueprint< * You must either pass `params` directly, or define a `factory` that can * optionally call the original factory with the same params. */ - make( + make( args: { namespace?: string; name?: string; @@ -100,23 +100,17 @@ export interface ExtensionBlueprint< originalFactory: ( params: TParams, context?: { - config?: Expand<{ - [key in keyof TConfigSchema]: z.infer; - }>; + config?: TConfig; inputs?: Expand>; }, ) => Expand>, context: { node: AppNode; - config: Expand< - { - [key in keyof TExtensionConfigSchema]: z.infer< - TExtensionConfigSchema[key] - >; - } & { - [key in keyof TConfigSchema]: z.infer; - } - >; + config: { + [key in keyof TExtensionConfigSchema]: z.infer< + TExtensionConfigSchema[key] + >; + } & TConfig; inputs: Expand>; }, ): Expand>; @@ -130,8 +124,7 @@ export interface ExtensionBlueprint< [key in keyof TExtensionConfigSchema]: z.infer< TExtensionConfigSchema[key] >; - }, - TExtensionConfigSchema + } & TConfig >; } @@ -142,7 +135,7 @@ class ExtensionBlueprintImpl< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key: string]: z.ZodTypeAny }, + TConfigSchema extends { [key in string]: z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap, > { constructor( @@ -160,7 +153,7 @@ class ExtensionBlueprintImpl< dataRefs: TDataRefs; public make< - TExtensionConfigSchema extends { [key: string]: z.ZodTypeAny }, + TExtensionConfigSchema extends { [key in string]: z.ZodTypeAny }, >(args: { namespace?: string; name?: string; @@ -171,45 +164,53 @@ class ExtensionBlueprintImpl< params?: TParams; config?: { schema: { - [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; + [key in keyof TExtensionConfigSchema]: ( + zImpl: typeof z, + ) => TExtensionConfigSchema[key]; }; }; factory?( originalFactory: ( params: TParams, context?: { - config?: Expand<{ + config?: { [key in keyof TConfigSchema]: z.infer; - }>; + }; inputs?: Expand>; }, ) => Expand>, context: { node: AppNode; - config: Expand< - { - [key in keyof TExtensionConfigSchema]: z.infer< - TExtensionConfigSchema[key] - >; - } & { - [key in keyof TConfigSchema]: z.infer; - } - >; + config: { + [key in keyof TExtensionConfigSchema]: z.infer< + TExtensionConfigSchema[key] + >; + } & { + [key in keyof TConfigSchema]: z.infer; + }; inputs: Expand>; }, ): Expand>; }): ExtensionDefinition< - Expand< - { - [key in keyof TExtensionConfigSchema]: z.infer< - TExtensionConfigSchema[key] - >; - } & { - [key in keyof TConfigSchema]: z.infer; - } - >, - Expand + { + [key in keyof TExtensionConfigSchema]: z.infer< + TExtensionConfigSchema[key] + >; + } & { + [key in keyof TConfigSchema]: z.infer; + } > { + const schema = { + ...this.options.config?.schema, + ...args.config, + } as { + [key in keyof TConfigSchema]: (zImpl: typeof z) => TConfigSchema[key]; + } & { + [key in keyof TExtensionConfigSchema]: ( + zImpl: typeof z, + ) => TExtensionConfigSchema[key]; + }; + return createExtension({ kind: this.options.kind, namespace: args.namespace ?? this.options.namespace, @@ -218,31 +219,16 @@ class ExtensionBlueprintImpl< disabled: args.disabled ?? this.options.disabled, inputs: args.inputs ?? this.options.inputs, output: args.output ?? this.options.output, - config: { - schema: { - ...this.options.config?.schema, - ...args.config, - } as Expand< - { - [key in keyof TConfigSchema]: ( - zImpl: typeof z, - ) => TConfigSchema[key]; - } & { - [key in keyof TExtensionConfigSchema]: ( - zImpl: typeof z, - ) => TExtensionConfigSchema[key]; - } - >, - }, + config: Object.keys(schema).length === 0 ? undefined : { schema }, factory: ({ node, config, inputs }) => { if (args.factory) { return args.factory( ( innerParams: TParams, innerContext?: { - config?: Expand<{ + config?: { [key in keyof TConfigSchema]: z.infer; - }>; + }; inputs?: Expand>; }, ) => @@ -280,7 +266,7 @@ export function createExtensionBlueprint< TParams, TInputs extends AnyExtensionInputMap, TOutput extends AnyExtensionDataMap, - TConfigSchema extends { [key: string]: z.ZodTypeAny }, + TConfigSchema extends { [key in string]: z.ZodTypeAny }, TDataRefs extends AnyExtensionDataMap = never, >( options: CreateExtensionBlueprintOptions< @@ -290,6 +276,12 @@ export function createExtensionBlueprint< TConfigSchema, TDataRefs >, -): ExtensionBlueprint { - return new ExtensionBlueprintImpl(options) as any; +): ExtensionBlueprint< + TParams, + TInputs, + TOutput, + { [key in keyof TConfigSchema]: z.infer }, + TDataRefs +> { + return new ExtensionBlueprintImpl(options); } diff --git a/plugins/catalog-graph/api-report-alpha.md b/plugins/catalog-graph/api-report-alpha.md index afd03965ae..59a387adf0 100644 --- a/plugins/catalog-graph/api-report-alpha.md +++ b/plugins/catalog-graph/api-report-alpha.md @@ -6,72 +6,17 @@ import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; -import { objectUtil } from 'zod'; import { RouteRef } from '@backstage/frontend-plugin-api'; -import { ZodArray } from 'zod'; -import { ZodBoolean } from 'zod'; -import { ZodEnum } from 'zod'; -import { ZodNativeEnum } from 'zod'; -import { ZodNumber } from 'zod'; -import { ZodOptional } from 'zod'; -import { ZodString } from 'zod'; -import { ZodTuple } from 'zod'; // Warning: (ae-missing-release-tag) "CatalogGraphEntityCard" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const CatalogGraphEntityCard: ExtensionDefinition< { - filter?: string | undefined; - height?: number | undefined; - curve?: 'curveStepBefore' | 'curveMonotoneX' | undefined; - direction?: Direction | undefined; - title?: string | undefined; - zoom?: 'disabled' | 'enabled' | 'enable-on-click' | undefined; - relations?: string[] | undefined; - maxDepth?: number | undefined; - kinds?: string[] | undefined; - unidirectional?: boolean | undefined; - mergeRelations?: boolean | undefined; - relationPairs?: [string, string][] | undefined; - }, - objectUtil.extendShape< - objectUtil.extendShape< - { - filter: ZodOptional; - }, - { - title: ZodOptional; - height: ZodOptional; - } - >, - { - kinds: ZodOptional>; - relations: ZodOptional>; - maxDepth: ZodOptional; - unidirectional: ZodOptional; - mergeRelations: ZodOptional; - direction: ZodOptional>; - relationPairs: ZodOptional< - ZodArray, 'many'> - >; - zoom: ZodOptional>; - curve: ZodOptional>; - } - >, - { - filter?: string | undefined; - height?: number | undefined; - curve?: 'curveStepBefore' | 'curveMonotoneX' | undefined; - direction?: Direction | undefined; - title?: string | undefined; - zoom?: 'disabled' | 'enabled' | 'enable-on-click' | undefined; - relations?: string[] | undefined; - maxDepth?: number | undefined; - kinds?: string[] | undefined; - unidirectional?: boolean | undefined; - mergeRelations?: boolean | undefined; - relationPairs?: [string, string][] | undefined; + title: string | undefined; + height: number | undefined; + } & { + filter: string | undefined; } >; @@ -93,9 +38,5 @@ const _default: BackstagePlugin< >; export default _default; -// Warnings were encountered during analysis: -// -// src/alpha.d.ts:6:5 - (ae-forgotten-export) The symbol "Direction" needs to be exported by the entry point alpha.d.ts - // (No @packageDocumentation comment for this package) ```