chore: fix type inference with different ways to define functions

Signed-off-by: benjdlambert <ben@blam.sh>
This commit is contained in:
benjdlambert
2025-03-19 08:41:50 +01:00
parent 497d47aafa
commit d48525c9f8
13 changed files with 108 additions and 159 deletions
+1 -1
View File
@@ -529,7 +529,7 @@ export interface RouterOptions {
// (undocumented)
additionalTemplateFilters?:
| Record<string, TemplateFilter_2>
| CreatedTemplateFilter[];
| CreatedTemplateFilter<any, any>[];
// (undocumented)
additionalTemplateGlobals?:
| Record<string, TemplateGlobal_2>
@@ -82,7 +82,7 @@ export const scaffolderPlugin = createBackendPlugin({
},
});
const additionalTemplateFilters: CreatedTemplateFilter[] = [];
const additionalTemplateFilters: CreatedTemplateFilter<any, any>[] = [];
const additionalTemplateGlobals: CreatedTemplateGlobal[] = [];
env.registerExtensionPoint(scaffolderTemplatingExtensionPoint, {
@@ -46,5 +46,5 @@ export const createParseRepoUrl = (integrations: ScmIntegrations) =>
.describe('`RepoSpec`'),
),
examples,
filter: (url: string) => parseRepoUrl(url, integrations),
filter: url => parseRepoUrl(url, integrations),
});
@@ -30,7 +30,7 @@ export const createProjectSlug = (integrations: ScmIntegrations) =>
z.string(),
),
examples,
filter: (repoUrl: string) => {
filter: repoUrl => {
const { owner, repo } = parseRepoUrl(repoUrl, integrations);
return `${owner}/${repo}`;
},
@@ -179,7 +179,7 @@ export interface RouterOptions {
taskBroker?: TaskBroker;
additionalTemplateFilters?:
| Record<string, TemplateFilter>
| CreatedTemplateFilter[];
| CreatedTemplateFilter<any, any>[];
additionalTemplateGlobals?:
| Record<string, TemplateGlobal>
| CreatedTemplateGlobal[];
@@ -64,7 +64,7 @@ describe('templating utilities', () => {
z.string().describe('separator').optional(),
)
.returns(z.string()),
filter: (input: string, times: number, separator?: string) =>
filter: (input, times, separator) =>
Array(times)
.fill(input)
.join(separator ?? ''),
@@ -149,7 +149,7 @@ describe('templating utilities', () => {
id: 'respond',
schema: z =>
z.function().args(z.string().describe('prompt')).returns(z.string()),
fn: (prompt: string) =>
fn: prompt =>
prompt === 'knock knock' ? "who's there?" : "nobody's home",
}),
];
@@ -22,7 +22,7 @@ import {
CreatedTemplateGlobal,
CreatedTemplateGlobalFunction,
CreatedTemplateGlobalValue,
TemplateGlobalFunctionSchema,
ZodFunctionSchema,
} from '@backstage/plugin-scaffolder-node/alpha';
import { JsonValue } from '@backstage/types';
import { Schema } from 'jsonschema';
@@ -63,8 +63,12 @@ type ExportFilterSchema = {
* Converts a Zod function schema to JSON schema
*/
function convertZodFunctionToJsonSchema(
t: ReturnType<TemplateGlobalFunctionSchema<any, any>>,
t: ReturnType<ZodFunctionSchema<any, any>>,
): ExportFunctionSchema {
if (!('parameters' in t) || !('returnType' in t)) {
throw new Error('Invalid Zod function schema');
}
const args = (t.parameters().items as ZodType[]).map(
zt => zodToJsonSchema(zt) as Schema,
);
@@ -142,7 +146,9 @@ export function extractFilterMetadata(
if (filter.schema) {
metadata.schema = convertToFilterSchema(
convertZodFunctionToJsonSchema(filter.schema(z)),
convertZodFunctionToJsonSchema(
filter.schema(z) as z.ZodFunction<any, any>,
),
);
}
@@ -167,10 +173,7 @@ export function extractFilterMetadata(
*/
function isGlobalFunction(
global: CreatedTemplateGlobal,
): global is CreatedTemplateGlobalFunction<
TemplateGlobalFunctionSchema<any, any> | undefined,
any
> {
): global is CreatedTemplateGlobalFunction<any, any> {
return 'fn' in global;
}
+40 -68
View File
@@ -29,56 +29,31 @@ export type AutocompleteHandler = ({
// @alpha (undocumented)
export type CreatedTemplateFilter<
TSchema extends
| TemplateFilterSchema<any, any>
| undefined
| unknown = unknown,
TFilterSchema extends TSchema extends TemplateFilterSchema<any, any>
? z.infer<ReturnType<TSchema>>
: TSchema extends unknown
? unknown
: TemplateFilter = TSchema extends TemplateFilterSchema<any, any>
? z.infer<ReturnType<TSchema>>
: TSchema extends unknown
? unknown
: TemplateFilter,
TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]],
TReturnType extends z.ZodTypeAny,
> = {
id: string;
description?: string;
examples?: TemplateFilterExample[];
schema?: TSchema;
filter: TFilterSchema;
schema?: ZodFunctionSchema<TFunctionArgs, TReturnType>;
filter: (...args: z.infer<z.ZodTuple<TFunctionArgs>>) => z.infer<TReturnType>;
};
// @alpha (undocumented)
export type CreatedTemplateGlobal =
| CreatedTemplateGlobalValue
| CreatedTemplateGlobalFunction<unknown, unknown>;
| CreatedTemplateGlobalFunction<any, any>;
// @alpha (undocumented)
export type CreatedTemplateGlobalFunction<
TSchema extends
| TemplateGlobalFunctionSchema<any, any>
| undefined
| unknown = unknown,
TFilterSchema extends TSchema extends TemplateGlobalFunctionSchema<any, any>
? z.infer<ReturnType<TSchema>>
: TSchema extends unknown
? unknown
: Exclude<
TemplateGlobal,
JsonValue
> = TSchema extends TemplateGlobalFunctionSchema<any, any>
? z.infer<ReturnType<TSchema>>
: TSchema extends unknown
? unknown
: Exclude<TemplateGlobal, JsonValue>,
TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]],
TReturnType extends z.ZodTypeAny,
> = {
id: string;
description?: string;
examples?: TemplateGlobalFunctionExample[];
schema?: TSchema;
fn: TFilterSchema;
schema?: ZodFunctionSchema<TFunctionArgs, TReturnType>;
fn: (...args: z.infer<z.ZodTuple<TFunctionArgs>>) => z.infer<TReturnType>;
};
// @alpha (undocumented)
@@ -90,23 +65,27 @@ export type CreatedTemplateGlobalValue<T extends JsonValue = JsonValue> = {
// @alpha
export const createTemplateFilter: <
TSchema extends TemplateFilterSchema<any, any> | undefined,
TFilterSchema extends TSchema extends TemplateFilterSchema<any, any>
? z.infer<ReturnType<TSchema>>
: (arg: JsonValue, ...rest: JsonValue[]) => JsonValue | undefined,
>(
filter: CreatedTemplateFilter<TSchema, TFilterSchema>,
) => CreatedTemplateFilter<TSchema, TFilterSchema>;
TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]],
TReturnType extends z.ZodTypeAny,
>(options: {
id: string;
description?: string;
examples?: TemplateFilterExample[];
schema?: ZodFunctionSchema<TFunctionArgs, TReturnType>;
filter: (...args: z.infer<z.ZodTuple<TFunctionArgs>>) => z.infer<TReturnType>;
}) => CreatedTemplateFilter<TFunctionArgs, TReturnType>;
// @alpha
export const createTemplateGlobalFunction: <
TSchema extends TemplateGlobalFunctionSchema<any, any> | undefined,
TFilterSchema extends TSchema extends TemplateGlobalFunctionSchema<any, any>
? z.infer<ReturnType<TSchema>>
: (...args: JsonValue[]) => JsonValue | undefined,
>(
fn: CreatedTemplateGlobalFunction<TSchema, TFilterSchema>,
) => CreatedTemplateGlobalFunction<TSchema, TFilterSchema>;
TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]],
TReturnType extends z.ZodTypeAny,
>(options: {
id: string;
description?: string;
examples?: TemplateGlobalFunctionExample[];
schema?: ZodFunctionSchema<TFunctionArgs, TReturnType>;
fn: (...args: z.infer<z.ZodTuple<TFunctionArgs>>) => z.infer<TReturnType>;
}) => CreatedTemplateGlobalFunction<TFunctionArgs, TReturnType>;
// @alpha
export const createTemplateGlobalValue: (
@@ -158,7 +137,7 @@ export interface ScaffolderTemplatingExtensionPoint {
addTemplateFilters(
filters:
| Record<string, TemplateFilter_2>
| CreatedTemplateFilter<unknown, unknown>[],
| CreatedTemplateFilter<any, any>[],
): void;
// (undocumented)
addTemplateGlobals(
@@ -196,16 +175,6 @@ export type TemplateFilterExample = {
notes?: string;
};
// @alpha (undocumented)
export type TemplateFilterSchema<
Args extends z.ZodTuple<
| [z.ZodType<JsonValue>]
| [z.ZodType<JsonValue>, ...(z.ZodType<JsonValue> | z.ZodUnknown)[]],
z.ZodType<JsonValue> | z.ZodUnknown | null
>,
Result extends z.ZodType<JsonValue> | z.ZodUndefined,
> = (zod: typeof z) => z.ZodFunction<Args, Result>;
// @public (undocumented)
export type TemplateGlobal =
| ((...args: JsonValue[]) => JsonValue | undefined)
@@ -218,15 +187,6 @@ export type TemplateGlobalFunctionExample = {
notes?: string;
};
// @alpha (undocumented)
export type TemplateGlobalFunctionSchema<
Args extends z.ZodTuple<
[] | [z.ZodType<JsonValue>, ...(z.ZodType<JsonValue> | z.ZodUnknown)[]],
z.ZodType<JsonValue> | z.ZodUnknown | null
>,
Result extends z.ZodType<JsonValue> | z.ZodUndefined,
> = (zod: typeof z) => z.ZodFunction<Args, Result>;
// @alpha
export interface WorkspaceProvider {
// (undocumented)
@@ -246,5 +206,17 @@ export interface WorkspaceProvider {
}): Promise<void>;
}
// @alpha
export type ZodFunctionSchema<
TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]],
TReturnType extends z.ZodTypeAny,
> = (
zod: typeof z,
) =>
| z.ZodFunction<z.ZodTuple<TFunctionArgs, null>, TReturnType>
| z.ZodType<
(...args: z.infer<z.ZodTuple<TFunctionArgs>>) => z.infer<TReturnType>
>;
// (No @packageDocumentation comment for this package)
```
@@ -14,8 +14,11 @@
* limitations under the License.
*/
import { JsonValue } from '@backstage/types';
import { CreatedTemplateFilter, TemplateFilterSchema } from './types';
import {
CreatedTemplateFilter,
TemplateFilterExample,
ZodFunctionSchema,
} from './types';
import { z } from 'zod';
/**
@@ -23,10 +26,12 @@ import { z } from 'zod';
* @alpha
*/
export const createTemplateFilter = <
TSchema extends TemplateFilterSchema<any, any> | undefined,
TFilterSchema extends TSchema extends TemplateFilterSchema<any, any>
? z.infer<ReturnType<TSchema>>
: (arg: JsonValue, ...rest: JsonValue[]) => JsonValue | undefined,
>(
filter: CreatedTemplateFilter<TSchema, TFilterSchema>,
): CreatedTemplateFilter<TSchema, TFilterSchema> => filter;
TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]],
TReturnType extends z.ZodTypeAny,
>(options: {
id: string;
description?: string;
examples?: TemplateFilterExample[];
schema?: ZodFunctionSchema<TFunctionArgs, TReturnType>;
filter: (...args: z.infer<z.ZodTuple<TFunctionArgs>>) => z.infer<TReturnType>;
}): CreatedTemplateFilter<TFunctionArgs, TReturnType> => options;
@@ -14,21 +14,9 @@
* limitations under the License.
*/
import { z } from 'zod';
import { TemplateFilter } from '../../types';
import { JsonValue } from '@backstage/types';
export type { TemplateFilter } from '../../types';
/** @alpha */
export type TemplateFilterSchema<
Args extends z.ZodTuple<
| [z.ZodType<JsonValue>]
| [z.ZodType<JsonValue>, ...(z.ZodType<JsonValue> | z.ZodUnknown)[]],
z.ZodType<JsonValue> | z.ZodUnknown | null
>,
Result extends z.ZodType<JsonValue> | z.ZodUndefined,
> = (zod: typeof z) => z.ZodFunction<Args, Result>;
/** @alpha */
export type TemplateFilterExample = {
description?: string;
@@ -36,25 +24,29 @@ export type TemplateFilterExample = {
notes?: string;
};
/**
* Type for template filter schema functions that supports both Zod function definition methods:
* @alpha
*/
export type ZodFunctionSchema<
TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]],
TReturnType extends z.ZodTypeAny,
> = (
zod: typeof z,
) =>
| z.ZodFunction<z.ZodTuple<TFunctionArgs, null>, TReturnType>
| z.ZodType<
(...args: z.infer<z.ZodTuple<TFunctionArgs>>) => z.infer<TReturnType>
>;
/** @alpha */
export type CreatedTemplateFilter<
TSchema extends
| TemplateFilterSchema<any, any>
| undefined
| unknown = unknown,
TFilterSchema extends TSchema extends TemplateFilterSchema<any, any>
? z.infer<ReturnType<TSchema>>
: TSchema extends unknown
? unknown
: TemplateFilter = TSchema extends TemplateFilterSchema<any, any>
? z.infer<ReturnType<TSchema>>
: TSchema extends unknown
? unknown
: TemplateFilter,
TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]],
TReturnType extends z.ZodTypeAny,
> = {
id: string;
description?: string;
examples?: TemplateFilterExample[];
schema?: TSchema;
filter: TFilterSchema;
schema?: ZodFunctionSchema<TFunctionArgs, TReturnType>;
filter: (...args: z.infer<z.ZodTuple<TFunctionArgs>>) => z.infer<TReturnType>;
};
@@ -18,9 +18,9 @@ import { z } from 'zod';
import {
CreatedTemplateGlobalFunction,
CreatedTemplateGlobalValue,
TemplateGlobalFunctionSchema,
TemplateGlobalFunctionExample,
} from './types';
import { JsonValue } from '@backstage/types';
import { ZodFunctionSchema } from '../filters';
/**
* This function is used to create new template global values in type-safe manner.
@@ -39,10 +39,12 @@ export const createTemplateGlobalValue = (
* @alpha
*/
export const createTemplateGlobalFunction = <
TSchema extends TemplateGlobalFunctionSchema<any, any> | undefined,
TFilterSchema extends TSchema extends TemplateGlobalFunctionSchema<any, any>
? z.infer<ReturnType<TSchema>>
: (...args: JsonValue[]) => JsonValue | undefined,
>(
fn: CreatedTemplateGlobalFunction<TSchema, TFilterSchema>,
): CreatedTemplateGlobalFunction<TSchema, TFilterSchema> => fn;
TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]],
TReturnType extends z.ZodTypeAny,
>(options: {
id: string;
description?: string;
examples?: TemplateGlobalFunctionExample[];
schema?: ZodFunctionSchema<TFunctionArgs, TReturnType>;
fn: (...args: z.infer<z.ZodTuple<TFunctionArgs>>) => z.infer<TReturnType>;
}): CreatedTemplateGlobalFunction<TFunctionArgs, TReturnType> => options;
@@ -15,7 +15,7 @@
*/
import { JsonValue } from '@backstage/types';
import { z } from 'zod';
import { TemplateGlobal } from '../../types';
import { ZodFunctionSchema } from '../filters/types';
export type { TemplateGlobal } from '../../types';
@@ -26,15 +26,6 @@ export type CreatedTemplateGlobalValue<T extends JsonValue = JsonValue> = {
description?: string;
};
/** @alpha */
export type TemplateGlobalFunctionSchema<
Args extends z.ZodTuple<
[] | [z.ZodType<JsonValue>, ...(z.ZodType<JsonValue> | z.ZodUnknown)[]],
z.ZodType<JsonValue> | z.ZodUnknown | null
>,
Result extends z.ZodType<JsonValue> | z.ZodUndefined,
> = (zod: typeof z) => z.ZodFunction<Args, Result>;
/** @alpha */
export type TemplateGlobalFunctionExample = {
description?: string;
@@ -44,31 +35,17 @@ export type TemplateGlobalFunctionExample = {
/** @alpha */
export type CreatedTemplateGlobalFunction<
TSchema extends
| TemplateGlobalFunctionSchema<any, any>
| undefined
| unknown = unknown,
TFilterSchema extends TSchema extends TemplateGlobalFunctionSchema<any, any>
? z.infer<ReturnType<TSchema>>
: TSchema extends unknown
? unknown
: Exclude<
TemplateGlobal,
JsonValue
> = TSchema extends TemplateGlobalFunctionSchema<any, any>
? z.infer<ReturnType<TSchema>>
: TSchema extends unknown
? unknown
: Exclude<TemplateGlobal, JsonValue>,
TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]],
TReturnType extends z.ZodTypeAny,
> = {
id: string;
description?: string;
examples?: TemplateGlobalFunctionExample[];
schema?: TSchema;
fn: TFilterSchema;
schema?: ZodFunctionSchema<TFunctionArgs, TReturnType>;
fn: (...args: z.infer<z.ZodTuple<TFunctionArgs>>) => z.infer<TReturnType>;
};
/** @alpha */
export type CreatedTemplateGlobal =
| CreatedTemplateGlobalValue
| CreatedTemplateGlobalFunction<unknown, unknown>;
| CreatedTemplateGlobalFunction<any, any>;
+1 -3
View File
@@ -73,9 +73,7 @@ export const scaffolderTaskBrokerExtensionPoint =
*/
export interface ScaffolderTemplatingExtensionPoint {
addTemplateFilters(
filters:
| Record<string, TemplateFilter>
| CreatedTemplateFilter<unknown, unknown>[],
filters: Record<string, TemplateFilter> | CreatedTemplateFilter<any, any>[],
): void;
addTemplateGlobals(