From eaec9708d1790c856be9abb9129e134ff4660588 Mon Sep 17 00:00:00 2001 From: Mikhail Menshikov Date: Sun, 9 Jun 2024 01:09:02 +0500 Subject: [PATCH 1/4] chore(zod): typos --- packages/zod/src/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/zod/src/index.ts b/packages/zod/src/index.ts index 5d26950af..78e0b2107 100644 --- a/packages/zod/src/index.ts +++ b/packages/zod/src/index.ts @@ -70,7 +70,7 @@ const resolveZodType = (schemaTypeValue: SchemaObject['type']) => { let constsUniqueCounter: Record = {}; // https://github.com/colinhacks/zod#coercion-for-primitives -const COERCEABLE_TYPES = ['string', 'number', 'boolean', 'bigint', 'date']; +const COERCIBLE_TYPES = ['string', 'number', 'boolean', 'bigint', 'date']; export const generateZodValidationSchemaDefinition = ( schema: SchemaObject | undefined, @@ -299,7 +299,7 @@ export type ZodValidationSchemaDefinitionInput = { export const parseZodValidationSchemaDefinition = ( input: ZodValidationSchemaDefinitionInput, - contex: ContextSpecs, + context: ContextSpecs, coerceTypes: boolean | ZodCoerceType[] = false, preprocessResponse?: GeneratorMutator, ): { zod: string; consts: string } => { @@ -387,11 +387,11 @@ ${Object.entries(args) coerceTypes && (Array.isArray(coerceTypes) ? coerceTypes.includes(fn as ZodCoerceType) - : COERCEABLE_TYPES.includes(fn)); + : COERCIBLE_TYPES.includes(fn)); if ( (fn !== 'date' && shouldCoerceType) || - (fn === 'date' && shouldCoerceType && contex.output.override.useDates) + (fn === 'date' && shouldCoerceType && context.output.override.useDates) ) { return `.coerce.${fn}(${args})`; } From 695565fb043e05cc229774c694cfafd41d04f951 Mon Sep 17 00:00:00 2001 From: Mikhail Menshikov Date: Sun, 9 Jun 2024 01:09:02 +0500 Subject: [PATCH 2/4] refactor(zod): pull up definition type --- packages/zod/src/index.ts | 32 ++++++++++++++++---------------- packages/zod/src/zod.test.ts | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/zod/src/index.ts b/packages/zod/src/index.ts index 78e0b2107..3b55246a3 100644 --- a/packages/zod/src/index.ts +++ b/packages/zod/src/index.ts @@ -72,13 +72,18 @@ let constsUniqueCounter: Record = {}; // https://github.com/colinhacks/zod#coercion-for-primitives const COERCIBLE_TYPES = ['string', 'number', 'boolean', 'bigint', 'date']; +export type ZodValidationSchemaDefinition = { + functions: [string, any][]; + consts: string[]; +}; + export const generateZodValidationSchemaDefinition = ( schema: SchemaObject | undefined, context: ContextSpecs, _required: boolean | undefined, name: string, strict: boolean, -): { functions: [string, any][]; consts: string[] } => { +): ZodValidationSchemaDefinition => { if (!schema) return { functions: [], consts: [] }; const consts: string[] = []; @@ -292,13 +297,8 @@ export const generateZodValidationSchemaDefinition = ( return { functions, consts: uniq(consts) }; }; -export type ZodValidationSchemaDefinitionInput = { - functions: [string, any][]; - consts: string[]; -}; - export const parseZodValidationSchemaDefinition = ( - input: ZodValidationSchemaDefinitionInput, + input: ZodValidationSchemaDefinition, context: ContextSpecs, coerceTypes: boolean | ZodCoerceType[] = false, preprocessResponse?: GeneratorMutator, @@ -360,10 +360,10 @@ export const parseZodValidationSchemaDefinition = ( return `zod.object({ ${Object.entries(args) .map(([key, schema]) => { - const value = (schema as ZodValidationSchemaDefinitionInput).functions + const value = (schema as ZodValidationSchemaDefinition).functions .map(parseProperty) .join(''); - consts += (schema as ZodValidationSchemaDefinitionInput).consts.join('\n'); + consts += (schema as ZodValidationSchemaDefinition).consts.join('\n'); return ` "${key}": ${value.startsWith('.') ? 'zod' : ''}${value}`; }) .join(',\n')} @@ -461,7 +461,7 @@ const parseBodyAndResponse = ({ name: string; strict: boolean; }): { - input: ZodValidationSchemaDefinitionInput; + input: ZodValidationSchemaDefinition; isArray: boolean; } => { if (!data) { @@ -531,9 +531,9 @@ const parseParameters = ({ response: boolean; }; }): { - headers: ZodValidationSchemaDefinitionInput; - queryParams: ZodValidationSchemaDefinitionInput; - params: ZodValidationSchemaDefinitionInput; + headers: ZodValidationSchemaDefinition; + queryParams: ZodValidationSchemaDefinition; + params: ZodValidationSchemaDefinition; } => { if (!data) { return { @@ -609,7 +609,7 @@ const parseParameters = ({ >, ); - const headers: ZodValidationSchemaDefinitionInput = { + const headers: ZodValidationSchemaDefinition = { functions: [], consts: [], }; @@ -622,7 +622,7 @@ const parseParameters = ({ } } - const queryParams: ZodValidationSchemaDefinitionInput = { + const queryParams: ZodValidationSchemaDefinition = { functions: [], consts: [], }; @@ -635,7 +635,7 @@ const parseParameters = ({ } } - const params: ZodValidationSchemaDefinitionInput = { + const params: ZodValidationSchemaDefinition = { functions: [], consts: [], }; diff --git a/packages/zod/src/zod.test.ts b/packages/zod/src/zod.test.ts index 07b327110..49989cfbe 100644 --- a/packages/zod/src/zod.test.ts +++ b/packages/zod/src/zod.test.ts @@ -1,13 +1,13 @@ import { describe, expect, it } from 'vitest'; import { - type ZodValidationSchemaDefinitionInput, + type ZodValidationSchemaDefinition, parseZodValidationSchemaDefinition, generateZodValidationSchemaDefinition, } from '.'; import { SchemaObject } from 'openapi3-ts/oas30'; import { ContextSpecs } from '@orval/core'; -const queryParams: ZodValidationSchemaDefinitionInput = { +const queryParams: ZodValidationSchemaDefinition = { functions: [ [ 'object', From 6448cefa39e84fb0f8a42117c9b6028f31ff39ae Mon Sep 17 00:00:00 2001 From: Mikhail Menshikov Date: Sun, 9 Jun 2024 01:09:02 +0500 Subject: [PATCH 3/4] test(zod): add tests for additionalProperties keyword --- packages/zod/src/zod.test.ts | 109 +++++++++++++++++++++++++++++++++++ tests/configs/zod.config.ts | 9 +++ 2 files changed, 118 insertions(+) diff --git a/packages/zod/src/zod.test.ts b/packages/zod/src/zod.test.ts index 49989cfbe..13135eddf 100644 --- a/packages/zod/src/zod.test.ts +++ b/packages/zod/src/zod.test.ts @@ -42,6 +42,29 @@ const queryParams: ZodValidationSchemaDefinition = { consts: [], }; +const record: ZodValidationSchemaDefinition = { + functions: [ + [ + 'object', + { + queryParams: { + functions: [ + [ + 'additionalProperties', + { + functions: [['any', undefined]], + consts: [], + }, + ], + ], + consts: [], + }, + }, + ], + ], + consts: [], +}; + describe('parseZodValidationSchemaDefinition', () => { describe('with `override.coerceTypes = false` (default)', () => { it('does not emit coerced zod property schemas', () => { @@ -82,6 +105,24 @@ describe('parseZodValidationSchemaDefinition', () => { ); }); }); + + it('treats additionalProperties properly', () => { + const parseResult = parseZodValidationSchemaDefinition( + record, + { + output: { + override: { + useDates: false, + }, + }, + } as ContextSpecs, + false, + ); + + expect(parseResult.zod).toBe( + 'zod.object({\n "queryParams": zod.record(zod.string(), zod.any())\n})', + ); + }); }); const objectIntoObjectSchema: SchemaObject = { @@ -119,6 +160,20 @@ const deepRequiredSchema: SchemaObject = { }, }; +const additionalPropertiesSchema: SchemaObject = { + type: 'object', + properties: { + any: { + type: 'object', + additionalProperties: {}, + }, + true: { + type: 'object', + additionalProperties: true, + }, + }, +}; + describe('generateZodValidationSchemaDefinition`', () => { it('required', () => { const result = generateZodValidationSchemaDefinition( @@ -224,4 +279,58 @@ describe('generateZodValidationSchemaDefinition`', () => { consts: [], }); }); + + it('additionalProperties', () => { + const result = generateZodValidationSchemaDefinition( + additionalPropertiesSchema, + { + output: { + override: { + useDates: false, + }, + }, + } as ContextSpecs, + true, + 'strict', + true, + ); + + expect(result).toEqual({ + functions: [ + [ + 'object', + { + any: { + functions: [ + [ + 'additionalProperties', + { + functions: [['any', undefined]], + consts: [], + }, + ], + ['optional', undefined], + ], + consts: [], + }, + true: { + functions: [ + [ + 'additionalProperties', + { + functions: [['any', undefined]], + consts: [], + }, + ], + ['optional', undefined], + ], + consts: [], + }, + }, + ], + ['strict', undefined], + ], + consts: [], + }); + }); }); diff --git a/tests/configs/zod.config.ts b/tests/configs/zod.config.ts index ffce668af..2a4ea3a77 100644 --- a/tests/configs/zod.config.ts +++ b/tests/configs/zod.config.ts @@ -128,4 +128,13 @@ export default defineConfig({ target: '../specifications/circular.yaml', }, }, + additionalProperties: { + output: { + target: '../generated/zod', + client: 'zod', + }, + input: { + target: '../specifications/additional-properties.yaml', + }, + }, }); From b4692cc1d55392adb80a16a1fcd6ae91763ba516 Mon Sep 17 00:00:00 2001 From: Mikhail Menshikov Date: Sun, 9 Jun 2024 01:09:02 +0500 Subject: [PATCH 4/4] fix(zod): fix handling of additionalProperties in zod generator --- packages/zod/src/index.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/zod/src/index.ts b/packages/zod/src/index.ts index 3b55246a3..15b8fd4c0 100644 --- a/packages/zod/src/index.ts +++ b/packages/zod/src/index.ts @@ -229,15 +229,15 @@ export const generateZodValidationSchemaDefinition = ( if (schema.additionalProperties) { functions.push([ 'additionalProperties', - isBoolean(schema.additionalProperties) - ? schema.additionalProperties - : generateZodValidationSchemaDefinition( - schema.additionalProperties as SchemaObject, - context, - true, - name, - strict, - ), + generateZodValidationSchemaDefinition( + isBoolean(schema.additionalProperties) + ? {} + : (schema.additionalProperties as SchemaObject), + context, + true, + name, + strict, + ), ]); break;