frontend-plugin-api: remove deprecated createSchemaFromZod
The helper is no longer used internally and has been replaced by the `configSchema` option with direct Standard Schema values. Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> Made-with: Cursor
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
---
|
||||
'@backstage/frontend-plugin-api': patch
|
||||
'@backstage/frontend-plugin-api': minor
|
||||
---
|
||||
|
||||
Refactored the internal `createSchemaFromZod` helper to use a schema-first generic pattern, replacing the `ZodSchema<TOutput, ZodTypeDef, TInput>` constraint with `TSchema extends ZodType`. This avoids "excessively deep" type inference errors when multiple Zod copies are resolved.
|
||||
**BREAKING**: Removed the deprecated `createSchemaFromZod` helper. Use the `configSchema` option with Standard Schema values instead, for example `configSchema: { title: z.string() }` using zod v3.25+ or v4.
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 { createSchemaFromZod } from './createSchemaFromZod';
|
||||
|
||||
describe('createSchemaFromZod', () => {
|
||||
it('should provide nice parse errors', () => {
|
||||
const { parse } = createSchemaFromZod(z =>
|
||||
z.object({
|
||||
foo: z.union([z.string(), z.number()]),
|
||||
derp: z.object({ bar: z.number() }),
|
||||
}),
|
||||
);
|
||||
|
||||
expect(() => {
|
||||
// @ts-expect-error
|
||||
return parse({ derp: { bar: 'derp' } });
|
||||
}).toThrow(
|
||||
`Missing required value at 'foo'; Expected number, received string at 'derp.bar'`,
|
||||
);
|
||||
expect(() => {
|
||||
// @ts-expect-error
|
||||
return parse(undefined);
|
||||
}).toThrow(`Missing required value`);
|
||||
expect(() => {
|
||||
// @ts-expect-error
|
||||
return parse('derp');
|
||||
}).toThrow(`Expected object, received string`);
|
||||
});
|
||||
});
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 { JsonObject } from '@backstage/types';
|
||||
import { z, type ZodIssue, type ZodType } from 'zod/v3';
|
||||
import zodToJsonSchema from 'zod-to-json-schema';
|
||||
import { PortableSchema } from './types';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated Use {@link createConfigSchema} instead.
|
||||
*/
|
||||
export function createSchemaFromZod<TSchema extends ZodType>(
|
||||
schemaCreator: (zImpl: typeof z) => TSchema,
|
||||
): PortableSchema<z.output<TSchema>, z.input<TSchema>> {
|
||||
const schema = schemaCreator(z);
|
||||
|
||||
let cached: PortableSchema['schema'] | undefined;
|
||||
|
||||
const result: PortableSchema<z.output<TSchema>, z.input<TSchema>> = {
|
||||
parse: input => {
|
||||
const parseResult = schema.safeParse(input);
|
||||
if (parseResult.success) {
|
||||
return parseResult.data;
|
||||
}
|
||||
throw new Error(parseResult.error.issues.map(formatIssue).join('; '));
|
||||
},
|
||||
schema: undefined as any,
|
||||
};
|
||||
|
||||
Object.defineProperty(result, 'schema', {
|
||||
get() {
|
||||
if (!cached) {
|
||||
const jsonSchema = zodToJsonSchema(schema) as JsonObject;
|
||||
cached = Object.assign(
|
||||
() => ({ schema: jsonSchema }),
|
||||
jsonSchema,
|
||||
) as PortableSchema['schema'];
|
||||
}
|
||||
return cached;
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function formatIssue(issue: ZodIssue): string {
|
||||
if (issue.code === 'invalid_union') {
|
||||
return formatIssue(issue.unionErrors[0].issues[0]);
|
||||
}
|
||||
let message = issue.message;
|
||||
if (message === 'Required') {
|
||||
message = `Missing required value`;
|
||||
}
|
||||
if (issue.path.length) {
|
||||
message += ` at '${issue.path.join('.')}'`;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
@@ -343,9 +343,9 @@ const _default: OverridableFrontendPlugin<
|
||||
icon: string | undefined;
|
||||
};
|
||||
configInput: {
|
||||
filter?: FilterPredicate | undefined;
|
||||
title?: string | undefined;
|
||||
path?: string | undefined;
|
||||
title?: string | undefined;
|
||||
filter?: FilterPredicate | undefined;
|
||||
group?: string | false | undefined;
|
||||
icon?: string | undefined;
|
||||
};
|
||||
@@ -413,9 +413,9 @@ const _default: OverridableFrontendPlugin<
|
||||
icon: string | undefined;
|
||||
};
|
||||
configInput: {
|
||||
filter?: FilterPredicate | undefined;
|
||||
title?: string | undefined;
|
||||
path?: string | undefined;
|
||||
title?: string | undefined;
|
||||
filter?: FilterPredicate | undefined;
|
||||
group?: string | false | undefined;
|
||||
icon?: string | undefined;
|
||||
};
|
||||
|
||||
@@ -334,9 +334,9 @@ export const EntityContentBlueprint: ExtensionBlueprint<{
|
||||
icon: string | undefined;
|
||||
};
|
||||
configInput: {
|
||||
filter?: FilterPredicate | undefined;
|
||||
title?: string | undefined;
|
||||
path?: string | undefined;
|
||||
title?: string | undefined;
|
||||
filter?: FilterPredicate | undefined;
|
||||
group?: string | false | undefined;
|
||||
icon?: string | undefined;
|
||||
};
|
||||
|
||||
@@ -808,9 +808,9 @@ const _default: OverridableFrontendPlugin<
|
||||
icon: string | undefined;
|
||||
};
|
||||
configInput: {
|
||||
filter?: FilterPredicate | undefined;
|
||||
title?: string | undefined;
|
||||
path?: string | undefined;
|
||||
title?: string | undefined;
|
||||
filter?: FilterPredicate | undefined;
|
||||
group?: string | false | undefined;
|
||||
icon?: string | undefined;
|
||||
};
|
||||
|
||||
@@ -101,9 +101,9 @@ const _default: OverridableFrontendPlugin<
|
||||
icon: string | undefined;
|
||||
};
|
||||
configInput: {
|
||||
filter?: FilterPredicate | undefined;
|
||||
title?: string | undefined;
|
||||
path?: string | undefined;
|
||||
title?: string | undefined;
|
||||
filter?: FilterPredicate | undefined;
|
||||
group?: string | false | undefined;
|
||||
icon?: string | undefined;
|
||||
};
|
||||
|
||||
@@ -132,9 +132,9 @@ const _default: OverridableFrontendPlugin<
|
||||
icon: string | undefined;
|
||||
};
|
||||
configInput: {
|
||||
filter?: FilterPredicate | undefined;
|
||||
title?: string | undefined;
|
||||
path?: string | undefined;
|
||||
title?: string | undefined;
|
||||
filter?: FilterPredicate | undefined;
|
||||
group?: string | false | undefined;
|
||||
icon?: string | undefined;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user