From 8fc3c7d21ca35ed26fa8d668edc7210e87953362 Mon Sep 17 00:00:00 2001 From: Jose Cisneros Date: Sat, 12 Oct 2024 06:17:59 -0700 Subject: [PATCH 1/3] feat: allows for passthrough of a default/fallback scalar type --- src/config.ts | 18 ++++++++++++++++++ src/myzod/index.ts | 5 +++++ src/valibot/index.ts | 5 +++++ src/yup/index.ts | 5 +++++ src/zod/index.ts | 5 +++++ tests/myzod.spec.ts | 35 +++++++++++++++++++++++++++++++++++ tests/valibot.spec.ts | 37 +++++++++++++++++++++++++++++++++++++ tests/yup.spec.ts | 35 +++++++++++++++++++++++++++++++++++ tests/zod.spec.ts | 35 +++++++++++++++++++++++++++++++++++ 9 files changed, 180 insertions(+) diff --git a/src/config.ts b/src/config.ts index 4e26153b..b4d03852 100644 --- a/src/config.ts +++ b/src/config.ts @@ -176,6 +176,24 @@ export interface ValidationSchemaPluginConfig extends TypeScriptPluginConfig { * ``` */ scalarSchemas?: ScalarSchemas + /** + * @description Fallback scalar type for undefined scalar types in the schema not found in `scalarSchemas`. + * + * @exampleMarkdown + * ```yml + * config: + * schema: yup + * defaultScalarSchema: yup.unknown() + * ``` + * + * @exampleMarkdown + * ```yml + * config: + * schema: zod + * defaultScalarSchema: z.unknown() + * ``` + */ + defaultScalarTypeSchema?: string /** * @description Generates validation schema with GraphQL type objects. * but excludes "Query", "Mutation", "Subscription" objects. diff --git a/src/myzod/index.ts b/src/myzod/index.ts index 8804a153..b6fb3804 100644 --- a/src/myzod/index.ts +++ b/src/myzod/index.ts @@ -374,6 +374,11 @@ function myzod4Scalar(config: ValidationSchemaPluginConfig, visitor: Visitor, sc case 'boolean': return `myzod.boolean()`; } + + if (config.defaultScalarTypeSchema) { + return config.defaultScalarTypeSchema; + } + console.warn('unhandled name:', scalarName); return anySchema; } diff --git a/src/valibot/index.ts b/src/valibot/index.ts index 71c4d09b..2215b073 100644 --- a/src/valibot/index.ts +++ b/src/valibot/index.ts @@ -294,6 +294,11 @@ function valibot4Scalar(config: ValidationSchemaPluginConfig, visitor: Visitor, case 'boolean': return `v.boolean()`; } + + if (config.defaultScalarTypeSchema) { + return config.defaultScalarTypeSchema; + } + console.warn('unhandled scalar name:', scalarName); return 'v.any()'; } diff --git a/src/yup/index.ts b/src/yup/index.ts index b1805d8a..65c5c889 100644 --- a/src/yup/index.ts +++ b/src/yup/index.ts @@ -396,6 +396,11 @@ function yup4Scalar(config: ValidationSchemaPluginConfig, visitor: Visitor, scal case 'boolean': return `yup.boolean().defined()`; } + + if (config.defaultScalarTypeSchema) { + return config.defaultScalarTypeSchema + } + console.warn('unhandled name:', scalarName); return `yup.mixed()`; } diff --git a/src/zod/index.ts b/src/zod/index.ts index b1164fb0..dbb9c850 100644 --- a/src/zod/index.ts +++ b/src/zod/index.ts @@ -390,6 +390,11 @@ function zod4Scalar(config: ValidationSchemaPluginConfig, visitor: Visitor, scal case 'boolean': return `z.boolean()`; } + + if (config.defaultScalarTypeSchema) { + return config.defaultScalarTypeSchema; + } + console.warn('unhandled scalar name:', scalarName); return anySchema; } diff --git a/tests/myzod.spec.ts b/tests/myzod.spec.ts index 0497476e..f60f87eb 100644 --- a/tests/myzod.spec.ts +++ b/tests/myzod.spec.ts @@ -467,6 +467,41 @@ describe('myzod', () => { " `) }); + + it('with defaultScalarTypeSchema', async () => { + const schema = buildSchema(/* GraphQL */ ` + input ScalarsInput { + date: Date! + email: Email + str: String! + } + scalar Date + scalar Email + `); + const result = await plugin( + schema, + [], + { + schema: 'myzod', + scalarSchemas: { + Email: 'myzod.string()', // generate the basic type. User can later extend it using `withPredicate(fn: (val: string) => boolean), errMsg?: string }` + }, + defaultScalarTypeSchema: 'myzod.string()', + }, + {}, + ); + expect(removedInitialEmitValue(result.content)).toMatchInlineSnapshot(` + " + export function ScalarsInputSchema(): myzod.Type { + return myzod.object({ + date: myzod.string(), + email: myzod.string().optional().nullable(), + str: myzod.string() + }) + } + " + `) + }); it('with typesPrefix', async () => { const schema = buildSchema(/* GraphQL */ ` input Say { diff --git a/tests/valibot.spec.ts b/tests/valibot.spec.ts index 61f5a535..3ee9fabd 100644 --- a/tests/valibot.spec.ts +++ b/tests/valibot.spec.ts @@ -338,6 +338,43 @@ describe('valibot', () => { " `) }); + + it('with defaultScalarTypeSchema', async () => { + const schema = buildSchema(/* GraphQL */ ` + input ScalarsInput { + date: Date! + email: Email + str: String! + } + scalar Date + scalar Email + `); + const result = await plugin( + schema, + [], + { + schema: 'valibot', + scalarSchemas: { + Email: 'v.string([v.email()])', + }, + defaultScalarTypeSchema: 'v.string()', + }, + {}, + ); + expect(result.content).toMatchInlineSnapshot(` + " + + export function ScalarsInputSchema(): v.GenericSchema { + return v.object({ + date: v.string(), + email: v.nullish(v.string([v.email()])), + str: v.string() + }) + } + " + `) + }); + it.todo('with typesPrefix') it.todo('with typesSuffix') it.todo('with default input values') diff --git a/tests/yup.spec.ts b/tests/yup.spec.ts index bad9c1f4..014386db 100644 --- a/tests/yup.spec.ts +++ b/tests/yup.spec.ts @@ -472,6 +472,41 @@ describe('yup', () => { `) }); + it('with defaultScalarTypeSchema', async () => { + const schema = buildSchema(/* GraphQL */ ` + input ScalarsInput { + date: Date! + email: Email + str: String! + } + scalar Date + scalar Email + `); + const result = await plugin( + schema, + [], + { + scalarSchemas: { + Email: 'yup.string().email()', + }, + defaultScalarTypeSchema: 'yup.string()', + }, + {}, + ); + expect(result.content).toMatchInlineSnapshot(` + " + + export function ScalarsInputSchema(): yup.ObjectSchema { + return yup.object({ + date: yup.string().nonNullable(), + email: yup.string().email().defined().nullable().optional(), + str: yup.string().defined().nonNullable() + }) + } + " + `) + }); + it('with typesPrefix', async () => { const schema = buildSchema(/* GraphQL */ ` input Say { diff --git a/tests/zod.spec.ts b/tests/zod.spec.ts index 28cbe369..ea7d0a23 100644 --- a/tests/zod.spec.ts +++ b/tests/zod.spec.ts @@ -464,6 +464,41 @@ describe('zod', () => { `) }); + it('with defaultScalarTypeSchema', async () => { + const schema = buildSchema(/* GraphQL */ ` + input ScalarsInput { + date: Date! + email: Email + str: String! + } + scalar Date + scalar Email + `); + const result = await plugin( + schema, + [], + { + schema: 'zod', + scalarSchemas: { + Email: 'z.string().email()', + }, + defaultScalarTypeSchema: 'z.string()', + }, + {}, + ); + expect(removedInitialEmitValue(result.content)).toMatchInlineSnapshot(` + " + export function ScalarsInputSchema(): z.ZodObject> { + return z.object({ + date: z.string(), + email: z.string().email().nullish(), + str: z.string() + }) + } + " + `) + }); + it('with typesPrefix', async () => { const schema = buildSchema(/* GraphQL */ ` input Say { From b1e7f30b9edcac8e9278c2be19f414e895519009 Mon Sep 17 00:00:00 2001 From: Jose Cisneros Date: Thu, 7 Nov 2024 07:55:29 -0800 Subject: [PATCH 2/3] chore(README): update README --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index fd6cdae6..cfc8e64b 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,24 @@ config: Email: z.string().email() ``` +### `defaultScalarTypeSchema` + +type: `string` + +#### yup schema +```yml +config: + schema: yup + defaultScalarSchema: yup.unknown() +``` + +#### zod schema +```yml +config: + schema: zod + defaultScalarSchema: z.unknown() +``` + ### `withObjectType` type: `boolean` default: `false` From 75a2f0920b3cc0520c5d39a3a31680cbe1c85975 Mon Sep 17 00:00:00 2001 From: Jose Cisneros Date: Thu, 7 Nov 2024 08:07:35 -0800 Subject: [PATCH 3/3] chore(README): add description to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index cfc8e64b..a28f820c 100644 --- a/README.md +++ b/README.md @@ -191,6 +191,8 @@ config: type: `string` +Fallback scalar type for undefined scalar types in the schema not found in `scalarSchemas`. + #### yup schema ```yml config: