diff --git a/src/myzod/index.ts b/src/myzod/index.ts index a8e77496..eead0f19 100644 --- a/src/myzod/index.ts +++ b/src/myzod/index.ts @@ -5,6 +5,7 @@ import { GraphQLSchema, InputObjectTypeDefinitionNode, InputValueDefinitionNode, + Kind, NameNode, ObjectTypeDefinitionNode, TypeNode, @@ -234,7 +235,19 @@ const generateFieldTypeMyZodSchema = ( if (isListType(parentType)) { return `${gen}.nullable()`; } - const appliedDirectivesGen = applyDirectives(config, field, gen); + let appliedDirectivesGen = applyDirectives(config, field, gen); + + if (field.kind === Kind.INPUT_VALUE_DEFINITION) { + const { defaultValue } = field; + + if (defaultValue?.kind === Kind.INT || defaultValue?.kind === Kind.FLOAT || defaultValue?.kind === Kind.BOOLEAN) { + appliedDirectivesGen = `${appliedDirectivesGen}.default(${defaultValue.value})`; + } + if ((defaultValue?.kind === Kind.STRING) || (defaultValue?.kind === Kind.ENUM)) { + appliedDirectivesGen = `${appliedDirectivesGen}.default("${defaultValue.value}")`; + } + } + if (isNonNullType(parentType)) { if (visitor.shouldEmitAsNotAllowEmptyString(type.name.value)) { return `${gen}.min(1)`; diff --git a/src/yup/index.ts b/src/yup/index.ts index 171d47f4..aeea78a3 100644 --- a/src/yup/index.ts +++ b/src/yup/index.ts @@ -5,6 +5,7 @@ import { GraphQLSchema, InputObjectTypeDefinitionNode, InputValueDefinitionNode, + Kind, NameNode, ObjectTypeDefinitionNode, TypeNode, @@ -68,12 +69,7 @@ export class YupSchemaVisitor extends BaseSchemaVisitor { const appendArguments = argumentBlocks ? '\n' + argumentBlocks : ''; // Building schema for fields. - const shape = node.fields - ?.map(field => { - const fieldSchema = generateFieldYupSchema(this.config, visitor, field, 2); - return isNonNullType(field.type) ? fieldSchema : `${fieldSchema}.optional()`; - }) - .join(',\n'); + const shape = shapeFields(node.fields, this.config, visitor) switch (this.config.validationSchemaExportType) { case 'const': @@ -203,12 +199,7 @@ export class YupSchemaVisitor extends BaseSchemaVisitor { visitor: Visitor, name: string ) { - const shape = fields - ?.map(field => { - const fieldSchema = generateFieldYupSchema(this.config, visitor, field, 2); - return isNonNullType(field.type) ? fieldSchema : `${fieldSchema}.optional()`; - }) - .join(',\n'); + const shape = shapeFields(fields, this.config, visitor) switch (this.config.validationSchemaExportType) { case 'const': @@ -229,6 +220,30 @@ export class YupSchemaVisitor extends BaseSchemaVisitor { } } +const shapeFields = (fields: readonly (FieldDefinitionNode | InputValueDefinitionNode)[] | undefined, config: ValidationSchemaPluginConfig, visitor: Visitor) => { + return fields?.map(field => { + let fieldSchema = generateFieldYupSchema(config, visitor, field, 2); + + if (field.kind === Kind.INPUT_VALUE_DEFINITION) { + const { defaultValue } = field; + + if (defaultValue?.kind === Kind.INT || defaultValue?.kind === Kind.FLOAT || defaultValue?.kind === Kind.BOOLEAN) { + fieldSchema = `${fieldSchema}.default(${defaultValue.value})`; + } + if ((defaultValue?.kind === Kind.STRING) || (defaultValue?.kind === Kind.ENUM)) { + fieldSchema = `${fieldSchema}.default("${defaultValue.value}")`; + } + } + + if(isNonNullType(field.type)) { + return fieldSchema + } + + return `${fieldSchema}.optional()`; + }) + .join(',\n'); +} + const generateFieldYupSchema = ( config: ValidationSchemaPluginConfig, visitor: Visitor, diff --git a/src/zod/index.ts b/src/zod/index.ts index ef83ad1d..527aca02 100644 --- a/src/zod/index.ts +++ b/src/zod/index.ts @@ -5,6 +5,7 @@ import { GraphQLSchema, InputObjectTypeDefinitionNode, InputValueDefinitionNode, + Kind, NameNode, ObjectTypeDefinitionNode, TypeNode, @@ -129,16 +130,16 @@ export class ZodSchemaVisitor extends BaseSchemaVisitor { this.enumDeclarations.push( this.config.enumsAsTypes ? new DeclarationBlock({}) - .export() - .asKind('const') - .withName(`${enumname}Schema`) - .withContent(`z.enum([${node.values?.map(enumOption => `'${enumOption.name.value}'`).join(', ')}])`) - .string + .export() + .asKind('const') + .withName(`${enumname}Schema`) + .withContent(`z.enum([${node.values?.map(enumOption => `'${enumOption.name.value}'`).join(', ')}])`) + .string : new DeclarationBlock({}) - .export() - .asKind('const') - .withName(`${enumname}Schema`) - .withContent(`z.nativeEnum(${enumname})`).string + .export() + .asKind('const') + .withName(`${enumname}Schema`) + .withContent(`z.nativeEnum(${enumname})`).string ); }, }; @@ -247,7 +248,19 @@ const generateFieldTypeZodSchema = ( if (isListType(parentType)) { return `${gen}.nullable()`; } - const appliedDirectivesGen = applyDirectives(config, field, gen); + let appliedDirectivesGen = applyDirectives(config, field, gen); + + if (field.kind === Kind.INPUT_VALUE_DEFINITION) { + const { defaultValue } = field; + + if (defaultValue?.kind === Kind.INT || defaultValue?.kind === Kind.FLOAT || defaultValue?.kind === Kind.BOOLEAN) { + appliedDirectivesGen = `${appliedDirectivesGen}.default(${defaultValue.value})`; + } + if ((defaultValue?.kind === Kind.STRING) || (defaultValue?.kind === Kind.ENUM)) { + appliedDirectivesGen = `${appliedDirectivesGen}.default("${defaultValue.value}")`; + } + } + if (isNonNullType(parentType)) { if (visitor.shouldEmitAsNotAllowEmptyString(type.name.value)) { return `${appliedDirectivesGen}.min(1)`; diff --git a/tests/myzod.spec.ts b/tests/myzod.spec.ts index c0b91ecb..5242a383 100644 --- a/tests/myzod.spec.ts +++ b/tests/myzod.spec.ts @@ -991,4 +991,38 @@ describe('myzod', () => { }`; expect(result.content).toContain(wantContain); }); + + it('with default input values', async () => { + const schema = buildSchema(/* GraphQL */ ` + enum PageType { + PUBLIC + BASIC_AUTH + } + input PageInput { + pageType: PageType! = PUBLIC + greeting: String = "Hello" + score: Int = 100 + ratio: Float = 0.5 + isMember: Boolean = true + } + `); + const result = await plugin( + schema, + [], + { + schema: 'myzod', + importFrom: './types', + }, + {} + ); + + expect(result.content).toContain('export const PageTypeSchema = myzod.enum(PageType)'); + expect(result.content).toContain('export function PageInputSchema(): myzod.Type'); + + expect(result.content).toContain('pageType: PageTypeSchema.default("PUBLIC")'); + expect(result.content).toContain('greeting: myzod.string().default("Hello").optional().nullable()'); + expect(result.content).toContain('score: myzod.number().default(100).optional().nullable()'); + expect(result.content).toContain('ratio: myzod.number().default(0.5).optional().nullable()'); + expect(result.content).toContain('isMember: myzod.boolean().default(true).optional().nullable()'); + }); }); diff --git a/tests/yup.spec.ts b/tests/yup.spec.ts index 50316ad7..b4381ca1 100644 --- a/tests/yup.spec.ts +++ b/tests/yup.spec.ts @@ -905,4 +905,38 @@ describe('yup', () => { }`; expect(result.content).toContain(wantContain); }); + + it('with default input values', async () => { + const schema = buildSchema(/* GraphQL */ ` + enum PageType { + PUBLIC + BASIC_AUTH + } + input PageInput { + pageType: PageType! = PUBLIC + greeting: String = "Hello" + score: Int = 100 + ratio: Float = 0.5 + isMember: Boolean = true + } + `); + const result = await plugin( + schema, + [], + { + schema: 'yup', + importFrom: './types', + }, + {} + ); + + expect(result.content).toContain('export const PageTypeSchema = yup.string().oneOf([PageType.Public, PageType.BasicAuth]).defined()'); + expect(result.content).toContain('export function PageInputSchema(): yup.ObjectSchema'); + + expect(result.content).toContain('pageType: PageTypeSchema.nonNullable().default("PUBLIC")'); + expect(result.content).toContain('greeting: yup.string().defined().nullable().default("Hello").optional()'); + expect(result.content).toContain('score: yup.number().defined().nullable().default(100).optional()'); + expect(result.content).toContain('ratio: yup.number().defined().nullable().default(0.5).optional()'); + expect(result.content).toContain('isMember: yup.boolean().defined().nullable().default(true).optional()'); + }); }); diff --git a/tests/zod.spec.ts b/tests/zod.spec.ts index 76f3ecde..16d7324b 100644 --- a/tests/zod.spec.ts +++ b/tests/zod.spec.ts @@ -403,6 +403,40 @@ describe('zod', () => { expect(result.content).toContain('export function SayISchema(): z.ZodObject> {'); }); + it('with default input values', async () => { + const schema = buildSchema(/* GraphQL */ ` + enum PageType { + PUBLIC + BASIC_AUTH + } + input PageInput { + pageType: PageType! = PUBLIC + greeting: String = "Hello" + score: Int = 100 + ratio: Float = 0.5 + isMember: Boolean = true + } + `); + const result = await plugin( + schema, + [], + { + schema: 'zod', + importFrom: './types', + }, + {} + ); + + expect(result.content).toContain('export const PageTypeSchema = z.nativeEnum(PageType)'); + expect(result.content).toContain('export function PageInputSchema(): z.ZodObject>'); + + expect(result.content).toContain('pageType: PageTypeSchema.default("PUBLIC")'); + expect(result.content).toContain('greeting: z.string().default("Hello").nullish()'); + expect(result.content).toContain('score: z.number().default(100).nullish()'); + expect(result.content).toContain('ratio: z.number().default(0.5).nullish()'); + expect(result.content).toContain('isMember: z.boolean().default(true).nullish()'); + }); + describe('issues #19', () => { it('string field', async () => { const schema = buildSchema(/* GraphQL */ `