From 8c4743c88f0e9adc567118c5dafd05e9da0397cf Mon Sep 17 00:00:00 2001 From: gustaf <18744409+gurkodil@users.noreply.github.com> Date: Tue, 3 Mar 2026 21:58:19 +0100 Subject: [PATCH 1/2] fix(typescript-fetch): generate validationAttributes when withoutRuntimeChecks=true Previously, setting `validationAttributes=true` had no effect when `withoutRuntimeChecks=true` was set. This commit fixes that by adding the validation attributes to the `modelGenericInterfaces.mustache` template (that is used when withoutRuntimeChecks is enabled) - Moves validationAttributes logic to a partial template and includes it in the modelGenericInterfaces.mustache template - modelGeneric.mustache includes the modelGenericInterfaces.mustache partial and should work as before --- .../typescript-fetch/modelGeneric.mustache | 65 ------------------- .../modelGenericInterfaces.mustache | 2 +- .../validationAttributes.mustache | 65 +++++++++++++++++++ .../TypeScriptFetchClientCodegenTest.java | 14 ++++ 4 files changed, 80 insertions(+), 66 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/typescript-fetch/validationAttributes.mustache diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/modelGeneric.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/modelGeneric.mustache index 16f2f4336212..76de06732fd3 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/modelGeneric.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/modelGeneric.mustache @@ -194,68 +194,3 @@ export function {{classname}}ToJSONTyped(value?: {{#hasReadOnly}}Omit<{{classnam return value; {{/hasVars}} } -{{#validationAttributes}} - -export const {{classname}}PropertyValidationAttributesMap: { - [property: string]: { - maxLength?: number, - minLength?: number, - pattern?: string, - maximum?: number, - exclusiveMaximum?: boolean, - minimum?: number, - exclusiveMinimum?: boolean, - multipleOf?: number, - maxItems?: number, - minItems?: number, - uniqueItems?: boolean - } -} = { -{{#vars}} -{{#hasValidation}} - {{name}}: { - {{#maxLength}} - maxLength: {{maxLength}}, - {{/maxLength}} - {{#minLength}} - minLength: {{minLength}}, - {{/minLength}} - {{#pattern}} - pattern: '{{pattern}}', - {{/pattern}} - {{#maximum}} - maximum: {{maximum}}, - exclusiveMaximum: {{exclusiveMaximum}}, - {{/maximum}} - {{#minimum}} - minimum: {{minimum}}, - exclusiveMinimum: {{exclusiveMinimum}}, - {{/minimum}} - {{#multipleOf}} - multipleOf: {{multipleOf}}, - {{/multipleOf}} - {{#maxItems}} - maxItems: {{maxItems}}, - {{/maxItems}} - {{#minItems}} - minItems: {{minItems}}, - {{/minItems}} - {{#isArray}} - uniqueItems: {{uniqueItems}}, - {{/isArray}} - }, -{{/hasValidation}} -{{/vars}} -} -{{#isAdditionalPropertiesTrue}} - -export const {{classname}}AdditionalPropertiesValidationAttributes: { maxProperties?: number, minProperties?: number } = { - {{#maxProperties}} - maxProperties: {{maxProperties}}, - {{/maxProperties}} - {{#minProperties}} - minProperties: {{minProperties}}, - {{/minProperties}} -} -{{/isAdditionalPropertiesTrue}} -{{/validationAttributes}} diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/modelGenericInterfaces.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/modelGenericInterfaces.mustache index a1a115440821..b070bf9c07e0 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/modelGenericInterfaces.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/modelGenericInterfaces.mustache @@ -47,4 +47,4 @@ export const {{classname}}{{enumName}} = { } as const; export type {{classname}}{{enumName}} = typeof {{classname}}{{enumName}}[keyof typeof {{classname}}{{enumName}}]; {{/stringEnums}} -{{/isEnum}}{{/vars}}{{/hasEnums}} \ No newline at end of file +{{/isEnum}}{{/vars}}{{/hasEnums}}{{>validationAttributes}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/validationAttributes.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/validationAttributes.mustache new file mode 100644 index 000000000000..7ddff376299f --- /dev/null +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/validationAttributes.mustache @@ -0,0 +1,65 @@ +{{#validationAttributes}} + +export const {{classname}}PropertyValidationAttributesMap: { + [property: string]: { + maxLength?: number, + minLength?: number, + pattern?: string, + maximum?: number, + exclusiveMaximum?: boolean, + minimum?: number, + exclusiveMinimum?: boolean, + multipleOf?: number, + maxItems?: number, + minItems?: number, + uniqueItems?: boolean + } +} = { +{{#vars}} +{{#hasValidation}} + {{name}}: { + {{#maxLength}} + maxLength: {{maxLength}}, + {{/maxLength}} + {{#minLength}} + minLength: {{minLength}}, + {{/minLength}} + {{#pattern}} + pattern: '{{pattern}}', + {{/pattern}} + {{#maximum}} + maximum: {{maximum}}, + exclusiveMaximum: {{exclusiveMaximum}}, + {{/maximum}} + {{#minimum}} + minimum: {{minimum}}, + exclusiveMinimum: {{exclusiveMinimum}}, + {{/minimum}} + {{#multipleOf}} + multipleOf: {{multipleOf}}, + {{/multipleOf}} + {{#maxItems}} + maxItems: {{maxItems}}, + {{/maxItems}} + {{#minItems}} + minItems: {{minItems}}, + {{/minItems}} + {{#isArray}} + uniqueItems: {{uniqueItems}}, + {{/isArray}} + }, +{{/hasValidation}} +{{/vars}} +} +{{#isAdditionalPropertiesTrue}} + +export const {{classname}}AdditionalPropertiesValidationAttributes: { maxProperties?: number, minProperties?: number } = { + {{#maxProperties}} + maxProperties: {{maxProperties}}, + {{/maxProperties}} + {{#minProperties}} + minProperties: {{minProperties}}, + {{/minProperties}} +} +{{/isAdditionalPropertiesTrue}} +{{/validationAttributes}} \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java index 1608fe2750cf..da8324317640 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java @@ -444,6 +444,20 @@ public void testOneOfModelsImportNonPrimitiveTypes() throws IOException { TestUtils.assertFileContains(testResponse, "import type { OptionThree } from './OptionThree'"); } + @Test(description = "Verify validationAttributes works with withoutRuntimeChecks=true") + public void testValidationAttributesWithWithoutRuntimeChecks() throws IOException { + Map properties = new HashMap<>(); + properties.put(TypeScriptFetchClientCodegen.VALIDATION_ATTRIBUTES, true); + properties.put(TypeScriptFetchClientCodegen.WITHOUT_RUNTIME_CHECKS, true); + + File output = generate(properties, "src/test/resources/3_0/typescript-fetch/validation-attributes.yaml"); + + Path modelsIndex = Paths.get(output + "/models/index.ts"); + TestUtils.assertFileExists(modelsIndex); + TestUtils.assertFileContains(modelsIndex, "PetPropertyValidationAttributesMap"); + TestUtils.assertFileContains(modelsIndex, "[property: string]:"); + } + private static File generate( Map properties ) throws IOException { From 0bf54dddbe50f1c403eafd5bd84e04dff7fff599 Mon Sep 17 00:00:00 2001 From: gustaf <18744409+gurkodil@users.noreply.github.com> Date: Tue, 3 Mar 2026 23:02:57 +0100 Subject: [PATCH 2/2] update samples --- .../validation-attributes/models/Category.ts | 40 ++++++------- .../models/ModelApiResponse.ts | 34 +++++------ .../validation-attributes/models/Order.ts | 44 +++++++-------- .../validation-attributes/models/Pet.ts | 44 +++++++-------- .../validation-attributes/models/Tag.ts | 34 +++++------ .../validation-attributes/models/User.ts | 56 +++++++++---------- 6 files changed, 126 insertions(+), 126 deletions(-) diff --git a/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Category.ts b/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Category.ts index 32df5bbb27c5..7525b3690660 100644 --- a/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Category.ts +++ b/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Category.ts @@ -32,6 +32,26 @@ export interface Category { */ name?: string; } +export const CategoryPropertyValidationAttributesMap: { + [property: string]: { + maxLength?: number, + minLength?: number, + pattern?: string, + maximum?: number, + exclusiveMaximum?: boolean, + minimum?: number, + exclusiveMinimum?: boolean, + multipleOf?: number, + maxItems?: number, + minItems?: number, + uniqueItems?: boolean + } +} = { + name: { + pattern: '/^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$/', + }, +} + /** * Check if a given object implements the Category interface. @@ -71,23 +91,3 @@ export function CategoryToJSONTyped(value?: Category | null, ignoreDiscriminator }; } -export const CategoryPropertyValidationAttributesMap: { - [property: string]: { - maxLength?: number, - minLength?: number, - pattern?: string, - maximum?: number, - exclusiveMaximum?: boolean, - minimum?: number, - exclusiveMinimum?: boolean, - multipleOf?: number, - maxItems?: number, - minItems?: number, - uniqueItems?: boolean - } -} = { - name: { - pattern: '/^[a-zA-Z0-9]+[a-zA-Z0-9\\.\\-_]*[a-zA-Z0-9]+$/', - }, -} - diff --git a/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/ModelApiResponse.ts b/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/ModelApiResponse.ts index 7059aa7225ef..15f29f87c7b0 100644 --- a/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/ModelApiResponse.ts +++ b/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/ModelApiResponse.ts @@ -38,6 +38,23 @@ export interface ModelApiResponse { */ message?: string; } +export const ModelApiResponsePropertyValidationAttributesMap: { + [property: string]: { + maxLength?: number, + minLength?: number, + pattern?: string, + maximum?: number, + exclusiveMaximum?: boolean, + minimum?: number, + exclusiveMinimum?: boolean, + multipleOf?: number, + maxItems?: number, + minItems?: number, + uniqueItems?: boolean + } +} = { +} + /** * Check if a given object implements the ModelApiResponse interface. @@ -79,20 +96,3 @@ export function ModelApiResponseToJSONTyped(value?: ModelApiResponse | null, ign }; } -export const ModelApiResponsePropertyValidationAttributesMap: { - [property: string]: { - maxLength?: number, - minLength?: number, - pattern?: string, - maximum?: number, - exclusiveMaximum?: boolean, - minimum?: number, - exclusiveMinimum?: boolean, - multipleOf?: number, - maxItems?: number, - minItems?: number, - uniqueItems?: boolean - } -} = { -} - diff --git a/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Order.ts b/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Order.ts index d0d6bb018ae9..be720a30f163 100644 --- a/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Order.ts +++ b/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Order.ts @@ -69,6 +69,28 @@ export const OrderStatusEnum = { } as const; export type OrderStatusEnum = typeof OrderStatusEnum[keyof typeof OrderStatusEnum]; +export const OrderPropertyValidationAttributesMap: { + [property: string]: { + maxLength?: number, + minLength?: number, + pattern?: string, + maximum?: number, + exclusiveMaximum?: boolean, + minimum?: number, + exclusiveMinimum?: boolean, + multipleOf?: number, + maxItems?: number, + minItems?: number, + uniqueItems?: boolean + } +} = { +} + +export const OrderAdditionalPropertiesValidationAttributes: { maxProperties?: number, minProperties?: number } = { + maxProperties: 10, + minProperties: 2, +} + /** * Check if a given object implements the Order interface. @@ -118,25 +140,3 @@ export function OrderToJSONTyped(value?: Order | null, ignoreDiscriminator: bool }; } -export const OrderPropertyValidationAttributesMap: { - [property: string]: { - maxLength?: number, - minLength?: number, - pattern?: string, - maximum?: number, - exclusiveMaximum?: boolean, - minimum?: number, - exclusiveMinimum?: boolean, - multipleOf?: number, - maxItems?: number, - minItems?: number, - uniqueItems?: boolean - } -} = { -} - -export const OrderAdditionalPropertiesValidationAttributes: { maxProperties?: number, minProperties?: number } = { - maxProperties: 10, - minProperties: 2, -} - diff --git a/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Pet.ts b/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Pet.ts index ec7832cc4856..e0d6bd3fe721 100644 --- a/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Pet.ts +++ b/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Pet.ts @@ -84,6 +84,28 @@ export const PetStatusEnum = { } as const; export type PetStatusEnum = typeof PetStatusEnum[keyof typeof PetStatusEnum]; +export const PetPropertyValidationAttributesMap: { + [property: string]: { + maxLength?: number, + minLength?: number, + pattern?: string, + maximum?: number, + exclusiveMaximum?: boolean, + minimum?: number, + exclusiveMinimum?: boolean, + multipleOf?: number, + maxItems?: number, + minItems?: number, + uniqueItems?: boolean + } +} = { + photoUrls: { + maxItems: 8, + minItems: 1, + uniqueItems: true, + }, +} + /** * Check if a given object implements the Pet interface. @@ -133,25 +155,3 @@ export function PetToJSONTyped(value?: Pet | null, ignoreDiscriminator: boolean }; } -export const PetPropertyValidationAttributesMap: { - [property: string]: { - maxLength?: number, - minLength?: number, - pattern?: string, - maximum?: number, - exclusiveMaximum?: boolean, - minimum?: number, - exclusiveMinimum?: boolean, - multipleOf?: number, - maxItems?: number, - minItems?: number, - uniqueItems?: boolean - } -} = { - photoUrls: { - maxItems: 8, - minItems: 1, - uniqueItems: true, - }, -} - diff --git a/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Tag.ts b/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Tag.ts index a942cc99f5d5..46a305d26466 100644 --- a/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Tag.ts +++ b/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/Tag.ts @@ -32,6 +32,23 @@ export interface Tag { */ name?: string; } +export const TagPropertyValidationAttributesMap: { + [property: string]: { + maxLength?: number, + minLength?: number, + pattern?: string, + maximum?: number, + exclusiveMaximum?: boolean, + minimum?: number, + exclusiveMinimum?: boolean, + multipleOf?: number, + maxItems?: number, + minItems?: number, + uniqueItems?: boolean + } +} = { +} + /** * Check if a given object implements the Tag interface. @@ -71,20 +88,3 @@ export function TagToJSONTyped(value?: Tag | null, ignoreDiscriminator: boolean }; } -export const TagPropertyValidationAttributesMap: { - [property: string]: { - maxLength?: number, - minLength?: number, - pattern?: string, - maximum?: number, - exclusiveMaximum?: boolean, - minimum?: number, - exclusiveMinimum?: boolean, - multipleOf?: number, - maxItems?: number, - minItems?: number, - uniqueItems?: boolean - } -} = { -} - diff --git a/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/User.ts b/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/User.ts index 39a70be42fae..fd515e217965 100644 --- a/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/User.ts +++ b/samples/client/petstore/typescript-fetch/builds/validation-attributes/models/User.ts @@ -68,6 +68,34 @@ export interface User { */ userStatus?: number; } +export const UserPropertyValidationAttributesMap: { + [property: string]: { + maxLength?: number, + minLength?: number, + pattern?: string, + maximum?: number, + exclusiveMaximum?: boolean, + minimum?: number, + exclusiveMinimum?: boolean, + multipleOf?: number, + maxItems?: number, + minItems?: number, + uniqueItems?: boolean + } +} = { + password: { + maxLength: 256, + minLength: 8, + }, + userStatus: { + maximum: 100, + exclusiveMaximum: true, + minimum: 0, + exclusiveMinimum: true, + multipleOf: 10, + }, +} + /** * Check if a given object implements the User interface. @@ -119,31 +147,3 @@ export function UserToJSONTyped(value?: User | null, ignoreDiscriminator: boolea }; } -export const UserPropertyValidationAttributesMap: { - [property: string]: { - maxLength?: number, - minLength?: number, - pattern?: string, - maximum?: number, - exclusiveMaximum?: boolean, - minimum?: number, - exclusiveMinimum?: boolean, - multipleOf?: number, - maxItems?: number, - minItems?: number, - uniqueItems?: boolean - } -} = { - password: { - maxLength: 256, - minLength: 8, - }, - userStatus: { - maximum: 100, - exclusiveMaximum: true, - minimum: 0, - exclusiveMinimum: true, - multipleOf: 10, - }, -} -