forked from loafle/openapi-generator-original
[typescript-angular] Fix inner enum reference in multi-map property type (#22748)
* [typescript-angular] Fix inner enum reference in multi-map property type Fixes #22747 * [typescript] Fix inner enum reference in multi-map property type Fixes #20877, #22747 * test for the double-prefixed enum names This proves that following comment is not relevant: https://github.com/OpenAPITools/openapi-generator/pull/22748#discussion_r2769863543 * Implement review comment about the trailing `>` This implements comment https://github.com/OpenAPITools/openapi-generator/pull/22748#discussion_r2769863549 * fix @type for generic interfaces in TypeScript clients Type annotation in a comment should match the actual field type.
This commit is contained in:
@@ -17,39 +17,65 @@
|
||||
|
||||
package org.openapitools.codegen.languages;
|
||||
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.media.Schema;
|
||||
import io.swagger.v3.oas.models.parameters.Parameter;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.openapitools.codegen.*;
|
||||
import org.openapitools.codegen.CodegenConstants.ENUM_PROPERTY_NAMING_TYPE;
|
||||
import org.openapitools.codegen.CodegenConstants.MODEL_PROPERTY_NAMING_TYPE;
|
||||
import org.openapitools.codegen.CodegenConstants.PARAM_NAMING_TYPE;
|
||||
import org.openapitools.codegen.meta.features.*;
|
||||
import org.openapitools.codegen.model.ModelMap;
|
||||
import org.openapitools.codegen.model.ModelsMap;
|
||||
import org.openapitools.codegen.utils.ModelUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import static org.openapitools.codegen.languages.AbstractTypeScriptClientCodegen.ParameterExpander.ParamStyle.form;
|
||||
import static org.openapitools.codegen.languages.AbstractTypeScriptClientCodegen.ParameterExpander.ParamStyle.simple;
|
||||
import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
|
||||
import static org.openapitools.codegen.utils.StringUtils.camelize;
|
||||
import static org.openapitools.codegen.utils.StringUtils.underscore;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.openapitools.codegen.languages.AbstractTypeScriptClientCodegen.ParameterExpander.ParamStyle.form;
|
||||
import static org.openapitools.codegen.languages.AbstractTypeScriptClientCodegen.ParameterExpander.ParamStyle.simple;
|
||||
import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
|
||||
import static org.openapitools.codegen.utils.StringUtils.camelize;
|
||||
import static org.openapitools.codegen.utils.StringUtils.underscore;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.openapitools.codegen.CliOption;
|
||||
import org.openapitools.codegen.CodegenConfig;
|
||||
import org.openapitools.codegen.CodegenConstants;
|
||||
import org.openapitools.codegen.CodegenConstants.ENUM_PROPERTY_NAMING_TYPE;
|
||||
import org.openapitools.codegen.CodegenConstants.MODEL_PROPERTY_NAMING_TYPE;
|
||||
import org.openapitools.codegen.CodegenConstants.PARAM_NAMING_TYPE;
|
||||
import org.openapitools.codegen.CodegenModel;
|
||||
import org.openapitools.codegen.CodegenOperation;
|
||||
import org.openapitools.codegen.CodegenParameter;
|
||||
import org.openapitools.codegen.CodegenProperty;
|
||||
import org.openapitools.codegen.CodegenType;
|
||||
import org.openapitools.codegen.DefaultCodegen;
|
||||
import org.openapitools.codegen.GeneratorLanguage;
|
||||
import org.openapitools.codegen.meta.features.ClientModificationFeature;
|
||||
import org.openapitools.codegen.meta.features.DocumentationFeature;
|
||||
import org.openapitools.codegen.meta.features.GlobalFeature;
|
||||
import org.openapitools.codegen.meta.features.SchemaSupportFeature;
|
||||
import org.openapitools.codegen.meta.features.SecurityFeature;
|
||||
import org.openapitools.codegen.meta.features.WireFormatFeature;
|
||||
import org.openapitools.codegen.model.ModelMap;
|
||||
import org.openapitools.codegen.model.ModelsMap;
|
||||
import org.openapitools.codegen.utils.ModelUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.media.Schema;
|
||||
import io.swagger.v3.oas.models.parameters.Parameter;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
|
||||
@@ -1023,6 +1049,85 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to fix the inner enum naming issue for maps/arrays of enums.
|
||||
* <p>
|
||||
* The parent implementation uses toEnumName(baseItem) which produces a generic name
|
||||
* like "InnerEnum" based on the inner item's name. This override first calculates
|
||||
* the correct property.enumName, then uses it in the datatypeWithEnum replacement.
|
||||
* </p>
|
||||
*
|
||||
* @param property Codegen property
|
||||
*/
|
||||
@Override
|
||||
protected void updateDataTypeWithEnumForArray(CodegenProperty property) {
|
||||
CodegenProperty baseItem = property.items;
|
||||
while (baseItem != null && (Boolean.TRUE.equals(baseItem.isMap)
|
||||
|| Boolean.TRUE.equals(baseItem.isArray))) {
|
||||
baseItem = baseItem.items;
|
||||
}
|
||||
|
||||
if (baseItem != null) {
|
||||
// First, set the property's enumName using the property itself (not the inner item)
|
||||
// This ensures the correct enum name (e.g., "OptionsEnum") is used
|
||||
// instead of the generic inner item name (e.g., "InnerEnum")
|
||||
property.enumName = toEnumName(property);
|
||||
|
||||
// Now use property.enumName for datatypeWithEnum
|
||||
property.datatypeWithEnum = property.datatypeWithEnum.replace(baseItem.baseType, property.enumName);
|
||||
|
||||
// set default value for variable with inner enum
|
||||
if (property.defaultValue != null) {
|
||||
property.defaultValue = property.defaultValue.replace(baseItem.baseType, property.enumName);
|
||||
}
|
||||
|
||||
updateCodegenPropertyEnum(property);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to fix the inner enum naming issue for map properties.
|
||||
* <p>
|
||||
* The parent implementation uses {@code toEnumName(baseItem)} which produces "InnerEnum"
|
||||
* for properties whose inner item has a generic name like "inner". We instead
|
||||
* calculate the enumName from the property itself first, then use it in the replacement.
|
||||
* </p>
|
||||
*
|
||||
* @param property Codegen property
|
||||
*/
|
||||
@Override
|
||||
protected void updateDataTypeWithEnumForMap(CodegenProperty property) {
|
||||
CodegenProperty baseItem = property.items;
|
||||
while (baseItem != null && (Boolean.TRUE.equals(baseItem.isMap)
|
||||
|| Boolean.TRUE.equals(baseItem.isArray))) {
|
||||
baseItem = baseItem.items;
|
||||
}
|
||||
|
||||
if (baseItem != null) {
|
||||
// First, set the property's enumName using the property itself (not the inner item)
|
||||
property.enumName = toEnumName(property);
|
||||
|
||||
// Replace only the LAST occurrence of baseType with enumName.
|
||||
// In map types, the value type appears last (after the key type),
|
||||
// so this approach is template-agnostic.
|
||||
String datatypeWithEnum = property.datatypeWithEnum;
|
||||
int lastIndex = datatypeWithEnum.lastIndexOf(baseItem.baseType);
|
||||
if (lastIndex >= 0) {
|
||||
property.datatypeWithEnum = datatypeWithEnum.substring(0, lastIndex)
|
||||
+ property.enumName
|
||||
+ datatypeWithEnum.substring(lastIndex + baseItem.baseType.length());
|
||||
}
|
||||
LOGGER.info("Updated datatypeWithEnum for map property '{}': {}", property.name, property.datatypeWithEnum);
|
||||
|
||||
// set default value for variable with inner enum
|
||||
if (property.defaultValue != null) {
|
||||
property.defaultValue = property.defaultValue.replace(baseItem.baseType, property.enumName);
|
||||
}
|
||||
|
||||
updateCodegenPropertyEnum(property);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelsMap postProcessModels(ModelsMap objs) {
|
||||
// process enum in models
|
||||
@@ -1030,15 +1135,18 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
|
||||
for (ModelMap mo : models) {
|
||||
CodegenModel cm = mo.getModel();
|
||||
cm.imports = new TreeSet<>(cm.imports);
|
||||
|
||||
// name enum with model name, e.g. StatusEnum => Pet.StatusEnum
|
||||
// This applies to both direct enum properties (isEnum) and properties containing
|
||||
// inner enums (isInnerEnum) like maps or arrays of enums.
|
||||
for (CodegenProperty var : cm.vars) {
|
||||
if (Boolean.TRUE.equals(var.isEnum)) {
|
||||
if (Boolean.TRUE.equals(var.isEnum) || Boolean.TRUE.equals(var.isInnerEnum)) {
|
||||
var.datatypeWithEnum = var.datatypeWithEnum.replace(var.enumName, cm.classname + classEnumSeparator + var.enumName);
|
||||
}
|
||||
}
|
||||
if (cm.parent != null) {
|
||||
for (CodegenProperty var : cm.allVars) {
|
||||
if (Boolean.TRUE.equals(var.isEnum)) {
|
||||
if (Boolean.TRUE.equals(var.isEnum) || Boolean.TRUE.equals(var.isInnerEnum)) {
|
||||
var.datatypeWithEnum = var.datatypeWithEnum
|
||||
.replace(var.enumName, cm.classname + classEnumSeparator + var.enumName);
|
||||
}
|
||||
|
||||
@@ -383,6 +383,7 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
|
||||
|
||||
@Override
|
||||
public ModelsMap postProcessModels(ModelsMap objs) {
|
||||
// postProcessModelsEnum applies inner enum fixes via the parent class override
|
||||
List<ModelMap> models = postProcessModelsEnum(objs).getModels();
|
||||
|
||||
// process enum and custom properties in models
|
||||
@@ -800,7 +801,8 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
|
||||
for (CodegenProperty cpVar : cm.allVars) {
|
||||
ExtendedCodegenProperty var = (ExtendedCodegenProperty) cpVar;
|
||||
|
||||
if (Boolean.TRUE.equals(var.isEnum)) {
|
||||
// Handle both direct enum properties and inner enums (maps/arrays of enums)
|
||||
if (Boolean.TRUE.equals(var.isEnum) || Boolean.TRUE.equals(var.isInnerEnum)) {
|
||||
var.datatypeWithEnum = var.datatypeWithEnum
|
||||
.replace(var.enumName, cm.classname + var.enumName);
|
||||
}
|
||||
@@ -845,7 +847,9 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
|
||||
|
||||
private boolean processCodegenProperty(ExtendedCodegenProperty var, String parentClassName, Object xEntityId) {
|
||||
// name enum with model name, e.g. StatusEnum => PetStatusEnum
|
||||
if (Boolean.TRUE.equals(var.isEnum)) {
|
||||
// This applies to both direct enum properties (isEnum) and properties containing
|
||||
// inner enums (isInnerEnum) like maps or arrays of enums.
|
||||
if (Boolean.TRUE.equals(var.isEnum) || Boolean.TRUE.equals(var.isInnerEnum)) {
|
||||
// behaviour for enum names is specific for Typescript Fetch, not using namespaces
|
||||
var.datatypeWithEnum = var.datatypeWithEnum.replace(var.enumName, parentClassName + var.enumName);
|
||||
|
||||
@@ -1525,11 +1529,11 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
|
||||
public Set<CodegenProperty> oneOfPrimitives = new HashSet<>();
|
||||
@Getter @Setter
|
||||
public CodegenDiscriminator.MappedModel selfReferencingDiscriminatorMapping;
|
||||
|
||||
|
||||
public boolean isEntity; // Is a model containing an "id" property marked as isUniqueId
|
||||
public String returnPassthrough;
|
||||
public boolean hasReturnPassthroughVoid;
|
||||
|
||||
|
||||
public boolean hasSelfReferencingDiscriminatorMapping(){
|
||||
return selfReferencingDiscriminatorMapping != null;
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ export interface {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{
|
||||
{{#vars}}
|
||||
/**
|
||||
* {{#lambda.indented_star_4}}{{{unescapedDescription}}}{{/lambda.indented_star_4}}
|
||||
* @type {{=<% %>=}}{<%&datatype%>}<%={{ }}=%>
|
||||
* @type {{=<% %>=}}{<%&datatypeWithEnum%>}<%={{ }}=%>
|
||||
* @memberof {{classname}}
|
||||
{{#deprecated}}
|
||||
* @deprecated
|
||||
{{/deprecated}}
|
||||
*/
|
||||
{{#isReadOnly}}readonly {{/isReadOnly}}{{name}}{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{#isNullable}} | null{{/isNullable}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{#isNullable}} | null{{/isNullable}}{{/isEnum}};
|
||||
{{#isReadOnly}}readonly {{/isReadOnly}}{{name}}{{^required}}?{{/required}}: {{{datatypeWithEnum}}}{{#isNullable}} | null{{/isNullable}};
|
||||
{{/vars}}
|
||||
}{{#hasEnums}}
|
||||
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
package org.openapitools.codegen.typescript;
|
||||
|
||||
import static org.openapitools.codegen.typescript.TypeScriptGroups.TYPESCRIPT;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openapitools.codegen.ClientOptInput;
|
||||
@@ -12,18 +26,6 @@ import org.openapitools.codegen.languages.TypeScriptFetchClientCodegen;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.openapitools.codegen.typescript.TypeScriptGroups.TYPESCRIPT;
|
||||
|
||||
@Test(groups = {TYPESCRIPT})
|
||||
public class SharedTypeScriptTest {
|
||||
|
||||
@@ -67,6 +69,24 @@ public class SharedTypeScriptTest {
|
||||
Assert.assertEquals(StringUtils.countMatches(apiFileContent, "import { GetCustomer200Response }"), 1);
|
||||
}
|
||||
|
||||
private Path findModelDefinitionFile(Path root, Pattern modelPattern) throws IOException {
|
||||
try (Stream<Path> paths = Files.walk(root)) {
|
||||
return paths
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(path -> path.toString().endsWith(".ts"))
|
||||
.filter(path -> {
|
||||
try {
|
||||
String content = Files.readString(path);
|
||||
return modelPattern.matcher(content).find();
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IOException("Unable to locate model definition in " + root));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oldImportsStillPresentTest() throws IOException {
|
||||
Path output = Files.createTempDirectory("test");
|
||||
@@ -184,4 +204,110 @@ public class SharedTypeScriptTest {
|
||||
TestUtils.assertFileNotContains(axiosApiFile.toPath(), "AxiosPromise<UserSummary>");
|
||||
}
|
||||
|
||||
@Test(description = "Issue #20877, #22747 - Maps/arrays of inner enums should use correct enum name")
|
||||
public void givenMapWithArrayOfEnumsThenCorrectEnumNameIsUsed() throws Exception {
|
||||
// This tests the fix for the issue where maps with array of enums generated
|
||||
// "InnerEnum" type reference instead of the correct qualified enum name.
|
||||
// The fix is in AbstractTypeScriptClientCodegen and applies to all TypeScript generators.
|
||||
final String specPath = "src/test/resources/3_0/issue_19393_map_of_inner_enum.yaml";
|
||||
|
||||
List<String> generators = Arrays.asList(
|
||||
"typescript",
|
||||
"typescript-angular",
|
||||
"typescript-axios",
|
||||
"typescript-aurelia",
|
||||
"typescript-fetch",
|
||||
"typescript-inversify",
|
||||
"typescript-jquery",
|
||||
"typescript-nestjs",
|
||||
"typescript-nestjs-server",
|
||||
"typescript-node",
|
||||
"typescript-redux-query",
|
||||
"typescript-rxjs"
|
||||
);
|
||||
|
||||
// Patterns for EmployeeWithMultiMapOfEnum (map of array of enums)
|
||||
Pattern multiMapModelDefinition = Pattern.compile("\\b(interface|type|class)\\s+EmployeeWithMultiMapOfEnum\\b");
|
||||
Pattern multiMapNamespacedEnumRef = Pattern.compile("projectRoles[^\\n]*ProjectRolesEnum");
|
||||
Pattern multiMapFlatEnumRef = Pattern.compile("projectRoles[^\\n]*EmployeeWithMultiMapOfEnumProjectRolesEnum");
|
||||
|
||||
// Patterns for EmployeeWithMapOfEnum (simple map of enums)
|
||||
Pattern simpleMapModelDefinition = Pattern.compile("\\b(interface|type|class)\\s+EmployeeWithMapOfEnum\\b");
|
||||
Pattern simpleMapNamespacedEnumRef = Pattern.compile("projectRole[^s][^\\n]*ProjectRoleEnum");
|
||||
Pattern simpleMapFlatEnumRef = Pattern.compile("projectRole[^s][^\\n]*EmployeeWithMapOfEnumProjectRoleEnum");
|
||||
|
||||
for (String generatorName : generators) {
|
||||
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
|
||||
output.deleteOnExit();
|
||||
|
||||
CodegenConfigurator configurator = new CodegenConfigurator()
|
||||
.setGeneratorName(generatorName)
|
||||
.setInputSpec(specPath)
|
||||
.setOutputDir(output.getAbsolutePath());
|
||||
|
||||
Generator generator = new DefaultGenerator();
|
||||
generator.opts(configurator.toClientOptInput()).generate();
|
||||
|
||||
// Test EmployeeWithMultiMapOfEnum (map of array of enums)
|
||||
Path multiMapModelFile = findModelDefinitionFile(output.toPath(), multiMapModelDefinition);
|
||||
String multiMapFileContents = Files.readString(multiMapModelFile);
|
||||
|
||||
Assert.assertFalse(multiMapFileContents.contains("InnerEnum"),
|
||||
generatorName + ": Should not contain 'InnerEnum' reference in " + multiMapModelFile);
|
||||
|
||||
boolean hasMultiMapEnumRef = multiMapNamespacedEnumRef.matcher(multiMapFileContents).find()
|
||||
|| multiMapFlatEnumRef.matcher(multiMapFileContents).find();
|
||||
Assert.assertTrue(hasMultiMapEnumRef,
|
||||
generatorName + ": Expected enum reference not found in " + multiMapModelFile);
|
||||
|
||||
// Test EmployeeWithMapOfEnum (simple map of enums)
|
||||
Path simpleMapModelFile = findModelDefinitionFile(output.toPath(), simpleMapModelDefinition);
|
||||
String simpleMapFileContents = Files.readString(simpleMapModelFile);
|
||||
|
||||
Assert.assertFalse(simpleMapFileContents.contains("InnerEnum"),
|
||||
generatorName + ": Should not contain 'InnerEnum' reference in " + simpleMapModelFile);
|
||||
|
||||
boolean hasSimpleMapEnumRef = simpleMapNamespacedEnumRef.matcher(simpleMapFileContents).find()
|
||||
|| simpleMapFlatEnumRef.matcher(simpleMapFileContents).find();
|
||||
Assert.assertTrue(hasSimpleMapEnumRef,
|
||||
generatorName + ": Expected enum reference for simple map not found in " + simpleMapModelFile);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(description = "Issue #22748 - Inner enums should not be double-prefixed when model has parent")
|
||||
public void givenChildModelWithInheritedInnerEnumThenEnumNameIsNotDoublePrefixed() throws Exception {
|
||||
// This tests that when a child model inherits from a parent that has an inner enum property,
|
||||
// the enum name is not double-prefixed (e.g., Employee.Employee.ProjectRolesEnum instead of
|
||||
// Employee.ProjectRolesEnum).
|
||||
//
|
||||
// We use typescript-angular because it sets supportsMultipleInheritance=true,
|
||||
// which means cm.parent will be set for child models using allOf.
|
||||
// typescript-fetch does NOT support inheritance, so cm.parent is always null there.
|
||||
final String specPath = "src/test/resources/3_0/issue_22748_inherited_inner_enum.yaml";
|
||||
|
||||
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
|
||||
output.deleteOnExit();
|
||||
|
||||
CodegenConfigurator configurator = new CodegenConfigurator()
|
||||
.setGeneratorName("typescript-angular")
|
||||
.setInputSpec(specPath)
|
||||
.setOutputDir(output.getAbsolutePath());
|
||||
|
||||
Generator generator = new DefaultGenerator();
|
||||
generator.opts(configurator.toClientOptInput()).generate();
|
||||
|
||||
// Find the Employee model file (the child model)
|
||||
Pattern modelDefinition = Pattern.compile("\\b(interface|type|class)\\s+Employee\\b");
|
||||
Path modelFile = findModelDefinitionFile(output.toPath(), modelDefinition);
|
||||
String fileContents = Files.readString(modelFile);
|
||||
|
||||
// Should NOT contain double-prefixed enum name (typescript-angular uses "." separator)
|
||||
Assert.assertFalse(fileContents.contains("Employee.Employee.ProjectRolesEnum"),
|
||||
"typescript-angular: Should not contain double-prefixed 'Employee.Employee.ProjectRolesEnum' in " + modelFile);
|
||||
|
||||
// Should contain correctly prefixed enum name (single prefix with "." separator)
|
||||
Assert.assertTrue(fileContents.contains("Employee.ProjectRolesEnum"),
|
||||
"typescript-angular: Should contain 'Employee.ProjectRolesEnum' in " + modelFile);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
version: 1.0.0
|
||||
title: OpenAPI Test API - Inherited Inner Enum
|
||||
description: Test case for inner enum in child model with inheritance
|
||||
license:
|
||||
name: Apache-2.0
|
||||
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
|
||||
paths:
|
||||
/employees:
|
||||
get:
|
||||
operationId: getEmployees
|
||||
responses:
|
||||
'200':
|
||||
description: List of employees
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Employee'
|
||||
components:
|
||||
schemas:
|
||||
# Parent model with discriminator - this is needed for cm.parent to be set
|
||||
BaseEmployee:
|
||||
type: object
|
||||
discriminator:
|
||||
propertyName: employeeType
|
||||
properties:
|
||||
employeeType:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
# Child model that has its OWN inner enum property (map of array of enums)
|
||||
# This tests that when cm.parent != null, the child's own properties
|
||||
# don't get double-prefixed (first in cm.vars loop, then in cm.allVars loop)
|
||||
Employee:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/BaseEmployee'
|
||||
- type: object
|
||||
properties:
|
||||
employeeId:
|
||||
type: integer
|
||||
projectRoles:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
enum:
|
||||
- DEVELOPER
|
||||
- TESTER
|
||||
- OWNER
|
||||
@@ -329,7 +329,7 @@ export type MammalAnyofTypeEnum = typeof MammalAnyofTypeEnum[keyof typeof Mammal
|
||||
|
||||
export interface MapTest {
|
||||
'map_map_of_string'?: { [key: string]: { [key: string]: string; }; };
|
||||
'map_of_enum_string'?: { [key: string]: string; };
|
||||
'map_of_enum_string'?: { [key: string]: MapTestMapOfEnumStringEnum; };
|
||||
'direct_map'?: { [key: string]: boolean; };
|
||||
'indirect_map'?: { [key: string]: boolean; };
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ export type Mammal = { className: 'whale' } & Whale | { className: 'zebra' } & Z
|
||||
|
||||
export interface MapTest {
|
||||
'map_map_of_string'?: { [key: string]: { [key: string]: string; }; };
|
||||
'map_of_enum_string'?: { [key: string]: string; };
|
||||
'map_of_enum_string'?: { [key: string]: MapTestMapOfEnumStringEnum; };
|
||||
'direct_map'?: { [key: string]: boolean; };
|
||||
'indirect_map'?: { [key: string]: boolean; };
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@ import { mapValues } from '../runtime';
|
||||
export interface EnumArrays {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @type {EnumArraysJustSymbolEnum}
|
||||
* @memberof EnumArrays
|
||||
*/
|
||||
justSymbol?: EnumArraysJustSymbolEnum;
|
||||
/**
|
||||
*
|
||||
* @type {Array<string>}
|
||||
* @type {Array<EnumArraysArrayEnumEnum>}
|
||||
* @memberof EnumArrays
|
||||
*/
|
||||
arrayEnum?: Array<EnumArraysArrayEnumEnum>;
|
||||
|
||||
@@ -50,25 +50,25 @@ import {
|
||||
export interface EnumTest {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @type {EnumTestEnumStringEnum}
|
||||
* @memberof EnumTest
|
||||
*/
|
||||
enumString?: EnumTestEnumStringEnum;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @type {EnumTestEnumStringRequiredEnum}
|
||||
* @memberof EnumTest
|
||||
*/
|
||||
enumStringRequired: EnumTestEnumStringRequiredEnum;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @type {EnumTestEnumIntegerEnum}
|
||||
* @memberof EnumTest
|
||||
*/
|
||||
enumInteger?: EnumTestEnumIntegerEnum;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @type {EnumTestEnumNumberEnum}
|
||||
* @memberof EnumTest
|
||||
*/
|
||||
enumNumber?: EnumTestEnumNumberEnum;
|
||||
|
||||
@@ -27,10 +27,10 @@ export interface MapTest {
|
||||
mapMapOfString?: { [key: string]: { [key: string]: string; }; };
|
||||
/**
|
||||
*
|
||||
* @type {{ [key: string]: string; }}
|
||||
* @type {{ [key: string]: MapTestMapOfEnumStringEnum; }}
|
||||
* @memberof MapTest
|
||||
*/
|
||||
mapOfEnumString?: { [key: string]: string; };
|
||||
mapOfEnumString?: { [key: string]: MapTestMapOfEnumStringEnum; };
|
||||
/**
|
||||
*
|
||||
* @type {{ [key: string]: boolean; }}
|
||||
|
||||
@@ -45,7 +45,7 @@ export interface Order {
|
||||
shipDate?: Date;
|
||||
/**
|
||||
* Order Status
|
||||
* @type {string}
|
||||
* @type {OrderStatusEnum}
|
||||
* @memberof Order
|
||||
*/
|
||||
status?: OrderStatusEnum;
|
||||
|
||||
@@ -22,7 +22,7 @@ import { type ChildWithNullable, ChildWithNullableFromJSONTyped, ChildWithNullab
|
||||
export interface ParentWithNullable {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @type {ParentWithNullableTypeEnum}
|
||||
* @memberof ParentWithNullable
|
||||
*/
|
||||
type?: ParentWithNullableTypeEnum;
|
||||
|
||||
@@ -66,7 +66,7 @@ export interface Pet {
|
||||
tags?: Array<Tag>;
|
||||
/**
|
||||
* pet status in the store
|
||||
* @type {string}
|
||||
* @type {PetStatusEnum}
|
||||
* @memberof Pet
|
||||
*/
|
||||
status?: PetStatusEnum;
|
||||
|
||||
@@ -45,7 +45,7 @@ export interface Order {
|
||||
shipDate?: Date;
|
||||
/**
|
||||
* Order Status
|
||||
* @type {string}
|
||||
* @type {OrderStatusEnum}
|
||||
* @memberof Order
|
||||
*/
|
||||
status?: OrderStatusEnum;
|
||||
|
||||
@@ -66,7 +66,7 @@ export interface Pet {
|
||||
tags?: Array<Tag>;
|
||||
/**
|
||||
* pet status in the store
|
||||
* @type {string}
|
||||
* @type {PetStatusEnum}
|
||||
* @memberof Pet
|
||||
*/
|
||||
status?: PetStatusEnum;
|
||||
|
||||
@@ -21,25 +21,25 @@ import { mapValues } from '../runtime';
|
||||
export interface FakeEnumRequestGetInline200Response {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @type {FakeEnumRequestGetInline200ResponseStringEnumEnum}
|
||||
* @memberof FakeEnumRequestGetInline200Response
|
||||
*/
|
||||
stringEnum?: FakeEnumRequestGetInline200ResponseStringEnumEnum;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @type {FakeEnumRequestGetInline200ResponseNullableStringEnumEnum}
|
||||
* @memberof FakeEnumRequestGetInline200Response
|
||||
*/
|
||||
nullableStringEnum?: FakeEnumRequestGetInline200ResponseNullableStringEnumEnum;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @type {FakeEnumRequestGetInline200ResponseNumberEnumEnum}
|
||||
* @memberof FakeEnumRequestGetInline200Response
|
||||
*/
|
||||
numberEnum?: FakeEnumRequestGetInline200ResponseNumberEnumEnum;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @type {FakeEnumRequestGetInline200ResponseNullableNumberEnumEnum}
|
||||
* @memberof FakeEnumRequestGetInline200Response
|
||||
*/
|
||||
nullableNumberEnum?: FakeEnumRequestGetInline200ResponseNullableNumberEnumEnum;
|
||||
|
||||
@@ -45,7 +45,7 @@ export interface Order {
|
||||
shipDate?: Date;
|
||||
/**
|
||||
* Order Status
|
||||
* @type {string}
|
||||
* @type {OrderStatusEnum}
|
||||
* @memberof Order
|
||||
*/
|
||||
status?: OrderStatusEnum;
|
||||
|
||||
@@ -66,7 +66,7 @@ export interface Pet {
|
||||
tags?: Array<Tag>;
|
||||
/**
|
||||
* pet status in the store
|
||||
* @type {string}
|
||||
* @type {PetStatusEnum}
|
||||
* @memberof Pet
|
||||
*/
|
||||
status?: PetStatusEnum;
|
||||
|
||||
@@ -45,7 +45,7 @@ export interface Order {
|
||||
shipDate?: Date;
|
||||
/**
|
||||
* Order Status
|
||||
* @type {string}
|
||||
* @type {OrderStatusEnum}
|
||||
* @memberof Order
|
||||
*/
|
||||
status?: OrderStatusEnum;
|
||||
|
||||
@@ -66,7 +66,7 @@ export interface Pet {
|
||||
tags?: Array<Tag>;
|
||||
/**
|
||||
* pet status in the store
|
||||
* @type {string}
|
||||
* @type {PetStatusEnum}
|
||||
* @memberof Pet
|
||||
*/
|
||||
status?: PetStatusEnum;
|
||||
|
||||
@@ -21,7 +21,7 @@ import { mapValues } from '../runtime';
|
||||
export interface OptionOne {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @type {OptionOneDiscriminatorFieldEnum}
|
||||
* @memberof OptionOne
|
||||
*/
|
||||
discriminatorField: OptionOneDiscriminatorFieldEnum;
|
||||
|
||||
@@ -21,7 +21,7 @@ import { mapValues } from '../runtime';
|
||||
export interface OptionTwo {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @type {OptionTwoDiscriminatorFieldEnum}
|
||||
* @memberof OptionTwo
|
||||
*/
|
||||
discriminatorField: OptionTwoDiscriminatorFieldEnum;
|
||||
|
||||
@@ -45,7 +45,7 @@ export interface Order {
|
||||
shipDate?: Date;
|
||||
/**
|
||||
* Order Status
|
||||
* @type {string}
|
||||
* @type {OrderStatusEnum}
|
||||
* @memberof Order
|
||||
*/
|
||||
status?: OrderStatusEnum;
|
||||
|
||||
@@ -66,7 +66,7 @@ export interface Pet {
|
||||
tags?: Array<Tag>;
|
||||
/**
|
||||
* pet status in the store
|
||||
* @type {string}
|
||||
* @type {PetStatusEnum}
|
||||
* @memberof Pet
|
||||
*/
|
||||
status?: PetStatusEnum;
|
||||
|
||||
@@ -45,7 +45,7 @@ export interface Order {
|
||||
shipDate?: Date;
|
||||
/**
|
||||
* Order Status
|
||||
* @type {string}
|
||||
* @type {OrderStatusEnum}
|
||||
* @memberof Order
|
||||
*/
|
||||
status?: OrderStatusEnum;
|
||||
|
||||
@@ -164,7 +164,7 @@ export interface Pet {
|
||||
optionalTags?: Array<Tag>;
|
||||
/**
|
||||
* pet status in the store
|
||||
* @type {string}
|
||||
* @type {PetStatusEnum}
|
||||
* @memberof Pet
|
||||
*/
|
||||
status: PetStatusEnum;
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
export interface ResponseMeta {
|
||||
/**
|
||||
* Code returned by the function
|
||||
* @type {string}
|
||||
* @type {ResponseMetaCodeEnum}
|
||||
* @memberof ResponseMeta
|
||||
*/
|
||||
code: ResponseMetaCodeEnum;
|
||||
|
||||
@@ -21,13 +21,13 @@ import { mapValues } from '../runtime';
|
||||
export interface EnumArrays {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @type {EnumArraysJustSymbolEnum}
|
||||
* @memberof EnumArrays
|
||||
*/
|
||||
justSymbol?: EnumArraysJustSymbolEnum;
|
||||
/**
|
||||
*
|
||||
* @type {Array<string>}
|
||||
* @type {Array<EnumArraysArrayEnumEnum>}
|
||||
* @memberof EnumArrays
|
||||
*/
|
||||
arrayEnum?: Array<EnumArraysArrayEnumEnum>;
|
||||
|
||||
@@ -50,25 +50,25 @@ import {
|
||||
export interface EnumTest {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @type {EnumTestEnumStringEnum}
|
||||
* @memberof EnumTest
|
||||
*/
|
||||
enumString?: EnumTestEnumStringEnum;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @type {EnumTestEnumStringRequiredEnum}
|
||||
* @memberof EnumTest
|
||||
*/
|
||||
enumStringRequired: EnumTestEnumStringRequiredEnum;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @type {EnumTestEnumIntegerEnum}
|
||||
* @memberof EnumTest
|
||||
*/
|
||||
enumInteger?: EnumTestEnumIntegerEnum;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @type {EnumTestEnumNumberEnum}
|
||||
* @memberof EnumTest
|
||||
*/
|
||||
enumNumber?: EnumTestEnumNumberEnum;
|
||||
|
||||
@@ -27,10 +27,10 @@ export interface MapTest {
|
||||
mapMapOfString?: { [key: string]: { [key: string]: string; }; };
|
||||
/**
|
||||
*
|
||||
* @type {{ [key: string]: string; }}
|
||||
* @type {{ [key: string]: MapTestMapOfEnumStringEnum; }}
|
||||
* @memberof MapTest
|
||||
*/
|
||||
mapOfEnumString?: { [key: string]: string; };
|
||||
mapOfEnumString?: { [key: string]: MapTestMapOfEnumStringEnum; };
|
||||
/**
|
||||
*
|
||||
* @type {{ [key: string]: boolean; }}
|
||||
|
||||
@@ -45,7 +45,7 @@ export interface Order {
|
||||
shipDate?: Date;
|
||||
/**
|
||||
* Order Status
|
||||
* @type {string}
|
||||
* @type {OrderStatusEnum}
|
||||
* @memberof Order
|
||||
*/
|
||||
status?: OrderStatusEnum;
|
||||
|
||||
@@ -66,7 +66,7 @@ export interface Pet {
|
||||
tags?: Array<Tag>;
|
||||
/**
|
||||
* pet status in the store
|
||||
* @type {string}
|
||||
* @type {PetStatusEnum}
|
||||
* @memberof Pet
|
||||
*/
|
||||
status?: PetStatusEnum;
|
||||
|
||||
@@ -46,7 +46,7 @@ export interface Order {
|
||||
shipDate?: Date;
|
||||
/**
|
||||
* Order Status
|
||||
* @type {string}
|
||||
* @type {OrderStatusEnum}
|
||||
* @memberof Order
|
||||
*/
|
||||
status?: OrderStatusEnum;
|
||||
|
||||
@@ -66,7 +66,7 @@ export interface Pet {
|
||||
tags?: Array<Tag>;
|
||||
/**
|
||||
* pet status in the store
|
||||
* @type {string}
|
||||
* @type {PetStatusEnum}
|
||||
* @memberof Pet
|
||||
* @deprecated
|
||||
*/
|
||||
|
||||
@@ -45,7 +45,7 @@ export interface Order {
|
||||
shipDate?: Date;
|
||||
/**
|
||||
* Order Status
|
||||
* @type {string}
|
||||
* @type {OrderStatusEnum}
|
||||
* @memberof Order
|
||||
*/
|
||||
status?: OrderStatusEnum;
|
||||
|
||||
@@ -66,7 +66,7 @@ export interface Pet {
|
||||
tags?: Array<Tag>;
|
||||
/**
|
||||
* pet status in the store
|
||||
* @type {string}
|
||||
* @type {PetStatusEnum}
|
||||
* @memberof Pet
|
||||
*/
|
||||
status?: PetStatusEnum;
|
||||
|
||||
@@ -45,7 +45,7 @@ export interface Order {
|
||||
shipDate?: Date;
|
||||
/**
|
||||
* Order Status
|
||||
* @type {string}
|
||||
* @type {OrderStatusEnum}
|
||||
* @memberof Order
|
||||
*/
|
||||
status?: OrderStatusEnum;
|
||||
|
||||
@@ -66,7 +66,7 @@ export interface Pet {
|
||||
tags?: Array<Tag>;
|
||||
/**
|
||||
* pet status in the store
|
||||
* @type {string}
|
||||
* @type {PetStatusEnum}
|
||||
* @memberof Pet
|
||||
*/
|
||||
status?: PetStatusEnum;
|
||||
|
||||
@@ -21,25 +21,25 @@ import { mapValues } from '../runtime';
|
||||
export interface FakeEnumRequestGetInline200Response {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @type {FakeEnumRequestGetInline200ResponseStringEnumEnum}
|
||||
* @memberof FakeEnumRequestGetInline200Response
|
||||
*/
|
||||
stringEnum?: FakeEnumRequestGetInline200ResponseStringEnumEnum;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @type {FakeEnumRequestGetInline200ResponseNullableStringEnumEnum}
|
||||
* @memberof FakeEnumRequestGetInline200Response
|
||||
*/
|
||||
nullableStringEnum?: FakeEnumRequestGetInline200ResponseNullableStringEnumEnum;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @type {FakeEnumRequestGetInline200ResponseNumberEnumEnum}
|
||||
* @memberof FakeEnumRequestGetInline200Response
|
||||
*/
|
||||
numberEnum?: FakeEnumRequestGetInline200ResponseNumberEnumEnum;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @type {FakeEnumRequestGetInline200ResponseNullableNumberEnumEnum}
|
||||
* @memberof FakeEnumRequestGetInline200Response
|
||||
*/
|
||||
nullableNumberEnum?: FakeEnumRequestGetInline200ResponseNullableNumberEnumEnum;
|
||||
|
||||
@@ -76,7 +76,7 @@ export interface Order {
|
||||
shipDate?: string;
|
||||
/**
|
||||
* Order Status
|
||||
* @type {string}
|
||||
* @type {OrderStatusEnum}
|
||||
* @memberof Order
|
||||
*/
|
||||
status?: OrderStatusEnum;
|
||||
@@ -137,7 +137,7 @@ export interface Pet {
|
||||
tags?: Array<Tag>;
|
||||
/**
|
||||
* pet status in the store
|
||||
* @type {string}
|
||||
* @type {PetStatusEnum}
|
||||
* @memberof Pet
|
||||
*/
|
||||
status?: PetStatusEnum;
|
||||
|
||||
@@ -14,7 +14,7 @@ import { HttpFile } from '../http/http';
|
||||
|
||||
export class MapTest {
|
||||
'mapMapOfString'?: { [key: string]: { [key: string]: string; }; };
|
||||
'mapOfEnumString'?: { [key: string]: string; };
|
||||
'mapOfEnumString'?: { [key: string]: MapTestMapOfEnumStringEnum; };
|
||||
'directMap'?: { [key: string]: boolean; };
|
||||
'indirectMap'?: { [key: string]: boolean; };
|
||||
|
||||
@@ -32,7 +32,7 @@ export class MapTest {
|
||||
{
|
||||
"name": "mapOfEnumString",
|
||||
"baseName": "map_of_enum_string",
|
||||
"type": "{ [key: string]: string; }",
|
||||
"type": "{ [key: string]: MapTestMapOfEnumStringEnum; }",
|
||||
"format": ""
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user