[TypeScript] fix array enum (#3538)

* better enum support for typescript angular2

* fix enum property for TS

* fix non-array enum datatype for TS

* update build name for TS fetch petstore client

* restore TS fetch enum naming

* [TS fetch]add test cases, fix enum integer naming
This commit is contained in:
wing328 2016-08-09 10:49:26 +08:00 committed by GitHub
parent 529f45c337
commit c4835ea52e
31 changed files with 219 additions and 108 deletions

View File

@ -3,14 +3,17 @@ package io.swagger.codegen.languages;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.util.List;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.TreeSet;
import io.swagger.codegen.CliOption;
import io.swagger.codegen.CodegenConfig;
import io.swagger.codegen.CodegenConstants;
import io.swagger.codegen.CodegenModel;
import io.swagger.codegen.CodegenProperty;
import io.swagger.codegen.CodegenType;
import io.swagger.codegen.DefaultCodegen;
@ -257,7 +260,7 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
@Override
public String toEnumValue(String value, String datatype) {
if ("int".equals(datatype) || "double".equals(datatype) || "float".equals(datatype)) {
if ("number".equals(datatype)) {
return value;
} else {
return "\'" + escapeText(value) + "\'";
@ -271,9 +274,15 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
@Override
public String toEnumVarName(String name, String datatype) {
// for symbol, e.g. $, #
if (getSymbolName(name) != null) {
return camelize(getSymbolName(name));
}
// number
if ("int".equals(datatype) || "double".equals(datatype) || "float".equals(datatype)) {
String varName = new String(name);
if ("number".equals(datatype)) {
String varName = "NUMBER_" + name;
varName = varName.replaceAll("-", "MINUS_");
varName = varName.replaceAll("\\+", "PLUS_");
varName = varName.replaceAll("\\.", "_DOT_");
@ -310,7 +319,20 @@ public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegen imp
@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
// process enum in models
return postProcessModelsEnum(objs);
List<Object> models = (List<Object>) postProcessModelsEnum(objs).get("models");
for (Object _mo : models) {
Map<String, Object> mo = (Map<String, Object>) _mo;
CodegenModel cm = (CodegenModel) mo.get("model");
cm.imports = new TreeSet(cm.imports);
for (CodegenProperty var : cm.vars) {
// name enum with model name, e.g. StatuEnum => Pet.StatusEnum
if (Boolean.TRUE.equals(var.isEnum)) {
var.datatypeWithEnum = var.datatypeWithEnum.replace(var.enumName, cm.classname + "." + var.enumName);
}
}
}
return objs;
}
public void setSupportsES6(Boolean value) {

View File

@ -1,9 +1,14 @@
package io.swagger.codegen.languages;
import io.swagger.codegen.CliOption;
import io.swagger.codegen.CodegenModel;
import io.swagger.codegen.CodegenProperty;
import io.swagger.codegen.SupportingFile;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodegen {
@ -72,4 +77,24 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege
this.npmVersion = npmVersion;
}
@Override
public Map<String, Object> postProcessModels(Map<String, Object> objs) {
// process enum in models
List<Object> models = (List<Object>) postProcessModelsEnum(objs).get("models");
for (Object _mo : models) {
Map<String, Object> mo = (Map<String, Object>) _mo;
CodegenModel cm = (CodegenModel) mo.get("model");
cm.imports = new TreeSet(cm.imports);
for (CodegenProperty var : cm.vars) {
// name enum with model name, e.g. StatuEnum => PetStatusEnum
if (Boolean.TRUE.equals(var.isEnum)) {
var.datatypeWithEnum = var.datatypeWithEnum.replace(var.enumName, cm.classname + var.enumName);
var.enumName = cm.classname + var.enumName;
}
}
}
return objs;
}
}

View File

@ -41,14 +41,14 @@ export interface {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{
* {{{description}}}
*/
{{/description}}
"{{name}}"{{^required}}?{{/required}}: {{#isEnum}}{{classname}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}};
"{{name}}"{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}};
{{/vars}}
}
{{#hasEnums}}
{{#vars}}
{{#isEnum}}
export type {{classname}}{{datatypeWithEnum}} = {{#allowableValues}}{{#values}}"{{.}}"{{^-last}} | {{/-last}}{{/values}}{{/allowableValues}};
export type {{{enumName}}} = {{#allowableValues}}{{#values}}"{{{.}}}"{{^-last}} | {{/-last}}{{/values}}{{/allowableValues}};
{{/isEnum}}
{{/vars}}
{{/hasEnums}}

View File

@ -13,13 +13,13 @@ namespace {{package}} {
{{/description}}
export interface {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{
{{#vars}}
{{#description}}
/**
* {{{description}}}
*/
{{/description}}
"{{name}}"{{^required}}?{{/required}}: {{#isEnum}}{{classname}}.{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}};
"{{name}}"{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}};
{{/vars}}
}
@ -27,9 +27,12 @@ namespace {{package}} {
export namespace {{classname}} {
{{#vars}}
{{#isEnum}}
export enum {{datatypeWithEnum}} { {{#allowableValues}}{{#values}}
{{.}} = <any> '{{.}}'{{^-last}},{{/-last}}{{/values}}{{/allowableValues}}
export enum {{enumName}} {
{{#allowableValues}}
{{#enumVars}}
{{{name}}} = <any> {{{value}}}{{^-last}},{{/-last}}
{{/enumVars}}
{{/allowableValues}}
}
{{/isEnum}}
{{/vars}}

View File

@ -10,24 +10,30 @@ import * as models from './models';
*/
{{/description}}
export interface {{classname}} {{#parent}}extends models.{{{parent}}} {{/parent}}{
{{#additionalPropertiesType}}[key: string]: {{{additionalPropertiesType}}}{{#hasVars}} | any{{/hasVars}};{{/additionalPropertiesType}}
{{#vars}}
{{#additionalPropertiesType}}
[key: string]: {{{additionalPropertiesType}}}{{#hasVars}} | any{{/hasVars}};
{{/additionalPropertiesType}}
{{#vars}}
{{#description}}
/**
* {{{description}}}
*/
{{/description}}
{{name}}?: {{#isEnum}}{{classname}}.{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}};
{{name}}?: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}};
{{/vars}}
}
{{#hasEnums}}
export namespace {{classname}} {
{{#vars}}
{{#isEnum}}
export enum {{datatypeWithEnum}} { {{#allowableValues}}{{#values}}
{{.}} = <any> '{{.}}',{{/values}}{{/allowableValues}}
export enum {{enumName}} {
{{#allowableValues}}
{{#enumVars}}
{{{name}}} = <any> {{{value}}}{{^-last}},{{/-last}}
{{/enumVars}}
{{/allowableValues}}
}
{{/isEnum}}
{{/vars}}

View File

@ -27,7 +27,7 @@ export class {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{
* {{{description}}}
*/
{{/description}}
'{{name}}': {{#isEnum}}{{classname}}.{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}};
'{{name}}': {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}};
{{/vars}}
}
@ -35,7 +35,7 @@ export class {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{
export namespace {{classname}} {
{{#vars}}
{{#isEnum}}
export enum {{datatypeWithEnum}} {
export enum {{enumName}} {
{{#allowableValues}}
{{#enumVars}}
{{name}} = <any> {{{value}}}{{^-last}},{{/-last}}

View File

@ -12,11 +12,17 @@ import io.swagger.codegen.languages.TypeScriptFetchClientCodegen;
import io.swagger.models.ArrayModel;
import io.swagger.models.Model;
import io.swagger.models.ModelImpl;
import io.swagger.models.properties.Property;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.DateTimeProperty;
import io.swagger.models.properties.LongProperty;
import io.swagger.models.properties.RefProperty;
import io.swagger.models.properties.StringProperty;
import io.swagger.models.Swagger;
import io.swagger.parser.SwaggerParser;
import java.util.HashMap;
import java.util.Arrays;
@SuppressWarnings("static-method")
public class TypeScriptFetchModelTest {
@ -180,4 +186,69 @@ public class TypeScriptFetchModelTest {
Assert.assertEquals(cm.imports.size(), 1);
Assert.assertEquals(Sets.intersection(cm.imports, Sets.newHashSet("Children")).size(), 1);
}
@Test(description = "test enum array model")
public void enumArrayMdoelTest() {
final Swagger model = new SwaggerParser().read("src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml");
final DefaultCodegen codegen = new TypeScriptFetchClientCodegen();
final Model definition = model.getDefinitions().get("EnumArrays");
Property property = definition.getProperties().get("array_enum");
CodegenProperty prope = codegen.fromProperty("array_enum", property);
codegen.updateCodegenPropertyEnum(prope);
Assert.assertEquals(prope.datatypeWithEnum, "Array<ArrayEnumEnum>");
Assert.assertEquals(prope.enumName, "ArrayEnumEnum");
Assert.assertTrue(prope.isEnum);
Assert.assertEquals(prope.allowableValues.get("values"), Arrays.asList("fish", "crab"));
HashMap<String, String> fish= new HashMap<String, String>();
fish.put("name", "Fish");
fish.put("value", "'fish'");
HashMap<String, String> crab= new HashMap<String, String>();
crab.put("name", "Crab");
crab.put("value", "'crab'");
Assert.assertEquals(prope.allowableValues.get("enumVars"), Arrays.asList(fish, crab));
// assert inner items
Assert.assertEquals(prope.datatypeWithEnum, "Array<ArrayEnumEnum>");
Assert.assertEquals(prope.enumName, "ArrayEnumEnum");
Assert.assertTrue(prope.items.isEnum);
Assert.assertEquals(prope.items.allowableValues.get("values"), Arrays.asList("fish", "crab"));
Assert.assertEquals(prope.items.allowableValues.get("enumVars"), Arrays.asList(fish, crab));
//IMPORTANT: these are not final enum values, which may be further updated
//by postProcessModels
}
@Test(description = "test enum model for values (numeric, string, etc)")
public void enumMdoelValueTest() {
final Swagger model = new SwaggerParser().read("src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml");
final DefaultCodegen codegen = new TypeScriptFetchClientCodegen();
final Model definition = model.getDefinitions().get("Enum_Test");
Property property = definition.getProperties().get("enum_integer");
CodegenProperty prope = codegen.fromProperty("enum_integer", property);
codegen.updateCodegenPropertyEnum(prope);
Assert.assertEquals(prope.datatypeWithEnum, "EnumIntegerEnum");
Assert.assertEquals(prope.enumName, "EnumIntegerEnum");
Assert.assertTrue(prope.isEnum);
Assert.assertNull(prope.isContainer);
Assert.assertNull(prope.items);
Assert.assertEquals(prope.allowableValues.get("values"), Arrays.asList(1, -1));
HashMap<String, String> one = new HashMap<String, String>();
one.put("name", "NUMBER_1");
one.put("value", "1");
HashMap<String, String> minusOne = new HashMap<String, String>();
minusOne.put("name", "NUMBER_MINUS_1");
minusOne.put("value", "-1");
Assert.assertEquals(prope.allowableValues.get("enumVars"), Arrays.asList(one, minusOne));
//IMPORTANT: these are not final enum values, which may be further updated
//by postProcessModels
}
}

View File

@ -28,10 +28,10 @@ namespace API.Client {
'use strict';
export interface Category {
"id"?: number;
"name"?: string;
}
}

View File

@ -28,7 +28,6 @@ namespace API.Client {
'use strict';
export interface Order {
"id"?: number;
"petId"?: number;
@ -43,14 +42,14 @@ namespace API.Client {
"status"?: Order.StatusEnum;
"complete"?: boolean;
}
export namespace Order {
export enum StatusEnum {
placed = <any> 'placed',
approved = <any> 'approved',
delivered = <any> 'delivered'
export enum StatusEnum {
Placed = <any> 'placed',
Approved = <any> 'approved',
Delivered = <any> 'delivered'
}
}
}

View File

@ -28,7 +28,6 @@ namespace API.Client {
'use strict';
export interface Pet {
"id"?: number;
"category"?: Category;
@ -43,14 +42,14 @@ namespace API.Client {
* pet status in the store
*/
"status"?: Pet.StatusEnum;
}
export namespace Pet {
export enum StatusEnum {
available = <any> 'available',
pending = <any> 'pending',
sold = <any> 'sold'
export enum StatusEnum {
Available = <any> 'available',
Pending = <any> 'pending',
Sold = <any> 'sold'
}
}
}

View File

@ -87,9 +87,9 @@ namespace API.Client {
let queryParameters: any = {};
let headerParams: any = this.extendObj({}, this.defaultHeaders);
// verify required parameter 'petId' is set
if (!petId) {
throw new Error('Missing required parameter petId when calling deletePet');
// verify required parameter 'petId' is not null or undefined
if (petId === null || petId === undefined) {
throw new Error('Required parameter petId was null or undefined when calling deletePet.');
}
headerParams['api_key'] = apiKey;
@ -174,9 +174,9 @@ namespace API.Client {
let queryParameters: any = {};
let headerParams: any = this.extendObj({}, this.defaultHeaders);
// verify required parameter 'petId' is set
if (!petId) {
throw new Error('Missing required parameter petId when calling getPetById');
// verify required parameter 'petId' is not null or undefined
if (petId === null || petId === undefined) {
throw new Error('Required parameter petId was null or undefined when calling getPetById.');
}
let httpRequestParams: any = {
method: 'GET',
@ -232,9 +232,9 @@ namespace API.Client {
let headerParams: any = this.extendObj({}, this.defaultHeaders);
let formParams: any = {};
// verify required parameter 'petId' is set
if (!petId) {
throw new Error('Missing required parameter petId when calling updatePetWithForm');
// verify required parameter 'petId' is not null or undefined
if (petId === null || petId === undefined) {
throw new Error('Required parameter petId was null or undefined when calling updatePetWithForm.');
}
headerParams['Content-Type'] = 'application/x-www-form-urlencoded';
@ -272,9 +272,9 @@ namespace API.Client {
let headerParams: any = this.extendObj({}, this.defaultHeaders);
let formParams: any = {};
// verify required parameter 'petId' is set
if (!petId) {
throw new Error('Missing required parameter petId when calling uploadFile');
// verify required parameter 'petId' is not null or undefined
if (petId === null || petId === undefined) {
throw new Error('Required parameter petId was null or undefined when calling uploadFile.');
}
headerParams['Content-Type'] = 'application/x-www-form-urlencoded';

View File

@ -61,9 +61,9 @@ namespace API.Client {
let queryParameters: any = {};
let headerParams: any = this.extendObj({}, this.defaultHeaders);
// verify required parameter 'orderId' is set
if (!orderId) {
throw new Error('Missing required parameter orderId when calling deleteOrder');
// verify required parameter 'orderId' is not null or undefined
if (orderId === null || orderId === undefined) {
throw new Error('Required parameter orderId was null or undefined when calling deleteOrder.');
}
let httpRequestParams: any = {
method: 'DELETE',
@ -113,9 +113,9 @@ namespace API.Client {
let queryParameters: any = {};
let headerParams: any = this.extendObj({}, this.defaultHeaders);
// verify required parameter 'orderId' is set
if (!orderId) {
throw new Error('Missing required parameter orderId when calling getOrderById');
// verify required parameter 'orderId' is not null or undefined
if (orderId === null || orderId === undefined) {
throw new Error('Required parameter orderId was null or undefined when calling getOrderById.');
}
let httpRequestParams: any = {
method: 'GET',

View File

@ -28,10 +28,10 @@ namespace API.Client {
'use strict';
export interface Tag {
"id"?: number;
"name"?: string;
}
}

View File

@ -28,7 +28,6 @@ namespace API.Client {
'use strict';
export interface User {
"id"?: number;
"username"?: string;
@ -47,6 +46,7 @@ namespace API.Client {
* User Status
*/
"userStatus"?: number;
}
}

View File

@ -136,9 +136,9 @@ namespace API.Client {
let queryParameters: any = {};
let headerParams: any = this.extendObj({}, this.defaultHeaders);
// verify required parameter 'username' is set
if (!username) {
throw new Error('Missing required parameter username when calling deleteUser');
// verify required parameter 'username' is not null or undefined
if (username === null || username === undefined) {
throw new Error('Required parameter username was null or undefined when calling deleteUser.');
}
let httpRequestParams: any = {
method: 'DELETE',
@ -165,9 +165,9 @@ namespace API.Client {
let queryParameters: any = {};
let headerParams: any = this.extendObj({}, this.defaultHeaders);
// verify required parameter 'username' is set
if (!username) {
throw new Error('Missing required parameter username when calling getUserByName');
// verify required parameter 'username' is not null or undefined
if (username === null || username === undefined) {
throw new Error('Required parameter username was null or undefined when calling getUserByName.');
}
let httpRequestParams: any = {
method: 'GET',
@ -251,9 +251,9 @@ namespace API.Client {
let queryParameters: any = {};
let headerParams: any = this.extendObj({}, this.defaultHeaders);
// verify required parameter 'username' is set
if (!username) {
throw new Error('Missing required parameter username when calling updateUser');
// verify required parameter 'username' is not null or undefined
if (username === null || username === undefined) {
throw new Error('Required parameter username was null or undefined when calling updateUser.');
}
let httpRequestParams: any = {
method: 'PUT',

View File

@ -26,9 +26,8 @@
import * as models from './models';
export interface Category {
id?: number;
name?: string;
}

View File

@ -26,8 +26,6 @@
import * as models from './models';
export interface Order {
id?: number;
petId?: number;
@ -42,12 +40,12 @@ export interface Order {
status?: Order.StatusEnum;
complete?: boolean;
}
export namespace Order {
export enum StatusEnum {
placed = <any> 'placed',
approved = <any> 'approved',
delivered = <any> 'delivered',
export enum StatusEnum {
Placed = <any> 'placed',
Approved = <any> 'approved',
Delivered = <any> 'delivered'
}
}

View File

@ -26,8 +26,6 @@
import * as models from './models';
export interface Pet {
id?: number;
category?: models.Category;
@ -42,12 +40,12 @@ export interface Pet {
* pet status in the store
*/
status?: Pet.StatusEnum;
}
export namespace Pet {
export enum StatusEnum {
available = <any> 'available',
pending = <any> 'pending',
sold = <any> 'sold',
export enum StatusEnum {
Available = <any> 'available',
Pending = <any> 'pending',
Sold = <any> 'sold'
}
}

View File

@ -26,9 +26,8 @@
import * as models from './models';
export interface Tag {
id?: number;
name?: string;
}

View File

@ -26,8 +26,6 @@
import * as models from './models';
export interface User {
id?: number;
username?: string;
@ -46,4 +44,5 @@ export interface User {
* User Status
*/
userStatus?: number;
}

View File

@ -1,4 +1,4 @@
## @swagger/angular2-typescript-petstore@0.0.1-SNAPSHOT.201607211723
## @swagger/angular2-typescript-petstore@0.0.1-SNAPSHOT.201608052320
### Building
@ -19,7 +19,7 @@ navigate to the folder of your consuming project and run one of next commando's.
_published:_
```
npm install @swagger/angular2-typescript-petstore@0.0.1-SNAPSHOT.201607211723 --save
npm install @swagger/angular2-typescript-petstore@0.0.1-SNAPSHOT.201608052320 --save
```
_unPublished (not recommended):_

View File

@ -26,9 +26,8 @@
import * as models from './models';
export interface Category {
id?: number;
name?: string;
}

View File

@ -26,8 +26,6 @@
import * as models from './models';
export interface Order {
id?: number;
petId?: number;
@ -42,12 +40,12 @@ export interface Order {
status?: Order.StatusEnum;
complete?: boolean;
}
export namespace Order {
export enum StatusEnum {
placed = <any> 'placed',
approved = <any> 'approved',
delivered = <any> 'delivered',
export enum StatusEnum {
Placed = <any> 'placed',
Approved = <any> 'approved',
Delivered = <any> 'delivered'
}
}

View File

@ -26,8 +26,6 @@
import * as models from './models';
export interface Pet {
id?: number;
category?: models.Category;
@ -42,12 +40,12 @@ export interface Pet {
* pet status in the store
*/
status?: Pet.StatusEnum;
}
export namespace Pet {
export enum StatusEnum {
available = <any> 'available',
pending = <any> 'pending',
sold = <any> 'sold',
export enum StatusEnum {
Available = <any> 'available',
Pending = <any> 'pending',
Sold = <any> 'sold'
}
}

View File

@ -26,9 +26,8 @@
import * as models from './models';
export interface Tag {
id?: number;
name?: string;
}

View File

@ -26,8 +26,6 @@
import * as models from './models';
export interface User {
id?: number;
username?: string;
@ -46,4 +44,5 @@ export interface User {
* User Status
*/
userStatus?: number;
}

View File

@ -1,6 +1,6 @@
{
"name": "@swagger/angular2-typescript-petstore",
"version": "0.0.1-SNAPSHOT.201607211723",
"version": "0.0.1-SNAPSHOT.201608052320",
"description": "swagger client for @swagger/angular2-typescript-petstore",
"author": "Swagger Codegen Contributors",
"keywords": [

View File

@ -4,7 +4,7 @@
<artifactId>TypeScriptAngularBuildPestoreClientTests</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>TS Angular Build Petstore Client</name>
<name>TS Fetch Default Petstore Client</name>
<build>
<plugins>
<plugin>

View File

@ -4,7 +4,7 @@
<artifactId>TypeScriptAngularBuildES6PestoreClientTests</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>TS Angular Build ES6 Petstore Client</name>
<name>TS Fetch ES6 Petstore Client</name>
<build>
<plugins>
<plugin>

View File

@ -4,7 +4,7 @@
<artifactId>TypeScriptAngularBuildWithNPMVersionPestoreClientTests</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>TS Angular Build With NPM Version Petstore Client</name>
<name>TS Fetch Petstore Client (with npm)</name>
<build>
<plugins>
<plugin>

View File

@ -4,7 +4,7 @@
<artifactId>TypeScriptFetchPestoreClientTests</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>TS Fetch default Petstore Client</name>
<name>TS Fetch Petstore Test Client</name>
<build>
<plugins>
<plugin>