[typescript-node] Fixes generation when parent contains TypeScript primitive (#22401)

* fixes parents when schema has additional properties

* exclude primitive types from parent property
This commit is contained in:
Sergey Fetiskin
2025-12-08 22:26:42 +01:00
committed by GitHub
parent ce21b9e503
commit b86213bea3
3 changed files with 130 additions and 0 deletions

View File

@@ -184,6 +184,11 @@ public class TypeScriptNodeClientCodegen extends AbstractTypeScriptClientCodegen
for (ModelMap mo : entry.getModels()) {
CodegenModel cm = mo.getModel();
// Filter out primitive types from parent property
if (cm.parent != null && isPrimitiveType(cm.parent)) {
cm.parent = null;
}
// Add additional filename information for imports
mo.put("tsImports", toTsImports(cm, cm.imports));
}
@@ -289,6 +294,26 @@ public class TypeScriptNodeClientCodegen extends AbstractTypeScriptClientCodegen
return languageSpecificPrimitives.contains(type);
}
/**
* Check if a type is a primitive TypeScript type (string, boolean, number).
* This is used to filter out primitive types from the parent property.
*
* @param type the type to check
* @return true if the type is a primitive type
*/
private boolean isPrimitiveType(String type) {
if (type == null) {
return false;
}
// Check for primitive types (case-insensitive)
String lowerType = type.toLowerCase(Locale.ROOT);
return "string".equals(lowerType) ||
"boolean".equals(lowerType) ||
"number".equals(lowerType) ||
"any".equals(lowerType) ||
"array".equals(lowerType);
}
// Determines if the given type is a generic/templated type (ie. ArrayList<String>)
private boolean isLanguageGenericType(String type) {
for (String genericType : languageGenericTypes) {
@@ -323,6 +348,15 @@ public class TypeScriptNodeClientCodegen extends AbstractTypeScriptClientCodegen
return result;
}
@Override
protected void addParentFromContainer(CodegenModel model, Schema schema) {
super.addParentFromContainer(model, schema);
// Filter out primitive types from parent property
if (model.parent != null && isPrimitiveType(model.parent)) {
model.parent = null;
}
}
@Override
protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Schema schema) {
super.addAdditionPropertiesToCodeGenModel(codegenModel, schema);

View File

@@ -354,4 +354,35 @@ public class TypeScriptNodeModelTest {
Assert.assertEquals(cm.name, "ApiResponse");
Assert.assertEquals(cm.classFilename, mappedName);
}
@Test(description = "should exclude TypeScript primitive types from parent property")
public void modelShouldExcludePrimitiveTypesFromParentPropertyTest() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/model_with_additional_properties.yaml");
final DefaultCodegen codegen = new TypeScriptNodeClientCodegen();
codegen.setOpenAPI(openAPI);
// Check that all models with primitive additionalProperties don't have parent property set
for (String modelName : openAPI.getComponents().getSchemas().keySet()) {
final Schema schema = openAPI.getComponents().getSchemas().get(modelName);
final CodegenModel model = codegen.fromModel(modelName, schema);
Assert.assertNull(model.parent, "Model " + modelName + " should not have a parent property");
}
}
@Test(description = "should extend from parent")
public void shouldExtendFromParentTest() {
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/allOf.yaml");
final DefaultCodegen codegen = new TypeScriptNodeClientCodegen();
codegen.setOpenAPI(openAPI);
// Check that Child model extends Person
final Schema childSchema = openAPI.getComponents().getSchemas().get("Child");
final CodegenModel childModel = codegen.fromModel("Child", childSchema);
Assert.assertEquals(childModel.parent, "Person");
// Check that Adult model extends Person
final Schema adultSchema = openAPI.getComponents().getSchemas().get("Adult");
final CodegenModel adultModel = codegen.fromModel("Adult", adultSchema);
Assert.assertEquals(adultModel.parent, "Person");
}
}

View File

@@ -0,0 +1,65 @@
openapi: 3.0.0
info:
version: 1.0.0
title: OpenAPI Petstore
license:
name: Apache-2.0
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
paths:
/pet:
get:
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
components:
schemas:
Pet:
title: a Pet with string additionalProperties
type: object
properties:
id:
type: integer
format: int64
additionalProperties:
type: string
PetBoolean:
title: a Pet with boolean additionalProperties
type: object
properties:
id:
type: integer
format: int64
additionalProperties:
type: boolean
PetNumber:
title: a Pet with number additionalProperties
type: object
properties:
id:
type: integer
format: int64
additionalProperties:
type: number
PetAny:
title: a Pet with any additionalProperties
type: object
properties:
id:
type: integer
format: int64
additionalProperties: true
PetArray:
title: a Pet with array additionalProperties
type: object
properties:
id:
type: integer
format: int64
additionalProperties:
type: array
items:
type: string