From 9d26491e9b5859135826e35bd1250bdd563af58d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Habarta?= Date: Wed, 24 May 2017 16:41:44 +0200 Subject: [PATCH] String enums, refactored enum model --- .../typescript/generator/DeprecationText.java | 11 ++++ .../typescript/generator/EnumMapping.java | 2 +- .../typescript/generator/Settings.java | 10 ++- .../generator/compiler/EnumKind.java | 8 +-- .../generator/compiler/EnumMemberModel.java | 20 ++++-- .../generator/compiler/ModelCompiler.java | 64 ++++++++++++------- .../typescript/generator/emitter/Emitter.java | 25 ++++---- .../generator/emitter/TsEnumModel.java | 23 ++++--- .../typescript/generator/emitter/TsModel.java | 47 ++++++++++---- .../generator/ext/EnumConstantsExtension.java | 9 +-- .../generator/ext/NonConstEnumsExtension.java | 9 +-- .../generator/parser/EnumModel.java | 21 +++--- .../generator/parser/Jackson2Parser.java | 13 ++-- .../typescript/generator/parser/Javadoc.java | 16 ++--- .../typescript/generator/parser/Model.java | 8 +-- .../generator/parser/ModelParser.java | 8 +-- .../typescript/generator/util/Utils.java | 6 ++ .../typescript/generator/EnumTest.java | 21 +++++- .../typescript/generator/JavadocTest.java | 2 +- .../generator/ModulesAndNamespacesTest.java | 2 + .../typescript/generator/NumberEnumTest.java | 20 +++++- .../generator/gradle/GenerateTask.java | 2 + .../generator/maven/GenerateMojo.java | 11 +++- 23 files changed, 235 insertions(+), 123 deletions(-) create mode 100644 typescript-generator-core/src/main/java/cz/habarta/typescript/generator/DeprecationText.java diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/DeprecationText.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/DeprecationText.java new file mode 100644 index 000000000..d93133f89 --- /dev/null +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/DeprecationText.java @@ -0,0 +1,11 @@ + +package cz.habarta.typescript.generator; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + + +@Retention(RetentionPolicy.RUNTIME) +public @interface DeprecationText { + String value(); +} diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/EnumMapping.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/EnumMapping.java index 6cc850f12..bbd85aba5 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/EnumMapping.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/EnumMapping.java @@ -3,5 +3,5 @@ public enum EnumMapping { - asUnion, asInlineUnion, asNumberBasedEnum + asUnion, asInlineUnion, asEnum, asNumberBasedEnum } diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java index 92877bef0..aab4d680d 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java @@ -41,6 +41,7 @@ public class Settings { public Map customTypeMappings = new LinkedHashMap<>(); public DateMapping mapDate; // default is DateMapping.asDate public EnumMapping mapEnum; // default is EnumMapping.asUnion + public boolean nonConstEnums = false; public ClassMapping mapClasses; // default is ClassMapping.asInterfaces public boolean disableTaggedUnions = false; public boolean ignoreSwaggerAnnotations = false; @@ -64,7 +65,7 @@ public class Settings { public String npmName = null; public String npmVersion = null; public Map npmPackageDependencies = new LinkedHashMap<>(); - public String typescriptVersion = "2.2.2"; + public String typescriptVersion = "^2.4"; public boolean displaySerializerWarning = true; public boolean disableJackson2ModuleDiscovery = false; public ClassLoader classLoader = null; @@ -141,6 +142,10 @@ public void validate() { } for (EmitterExtension extension : extensions) { final String extensionName = extension.getClass().getSimpleName(); + final DeprecationText deprecation = extension.getClass().getAnnotation(DeprecationText.class); + if (deprecation != null) { + System.out.println(String.format("Warning: Extension '%s' is deprecated: %s", extensionName, deprecation.value())); + } final EmitterExtensionFeatures features = extension.getFeatures(); if (features.generatesRuntimeCode && outputFileType != TypeScriptFileType.implementationFile) { throw new RuntimeException(String.format("Extension '%s' generates runtime code but 'outputFileType' parameter is not set to 'implementationFile'.", extensionName)); @@ -170,6 +175,9 @@ public void validate() { defaultStringEnumsOverriddenByExtension = true; } } + if (nonConstEnums && outputFileType != TypeScriptFileType.implementationFile) { + throw new RuntimeException("Non-const enums can only be used in implementation files but 'outputFileType' parameter is not set to 'implementationFile'."); + } if (mapClasses == ClassMapping.asClasses && outputFileType != TypeScriptFileType.implementationFile) { throw new RuntimeException("'mapClasses' parameter is set to 'asClasses' which generates runtime code but 'outputFileType' parameter is not set to 'implementationFile'."); } diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/EnumKind.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/EnumKind.java index 5552bed2a..f29d571b0 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/EnumKind.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/EnumKind.java @@ -2,12 +2,8 @@ package cz.habarta.typescript.generator.compiler; -public final class EnumKind { +public enum EnumKind { - public static final EnumKind StringBased = new EnumKind<>(); - public static final EnumKind NumberBased = new EnumKind<>(); - - private EnumKind() { - } + StringBased, NumberBased } diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/EnumMemberModel.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/EnumMemberModel.java index 43ace2074..6ebcaba7f 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/EnumMemberModel.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/EnumMemberModel.java @@ -4,13 +4,21 @@ import java.util.List; -public class EnumMemberModel { +public class EnumMemberModel { private final String propertyName; - private final T enumValue; + private final Object/*String|Number*/ enumValue; private final List comments; - public EnumMemberModel(String propertyName, T enumValue, List comments) { + public EnumMemberModel(String propertyName, String enumValue, List comments) { + this(propertyName, (Object)enumValue, comments); + } + + public EnumMemberModel(String propertyName, Number enumValue, List comments) { + this(propertyName, (Object)enumValue, comments); + } + + private EnumMemberModel(String propertyName, Object enumValue, List comments) { this.propertyName = propertyName; this.enumValue = enumValue; this.comments = comments; @@ -20,7 +28,7 @@ public String getPropertyName() { return propertyName; } - public T getEnumValue() { + public Object getEnumValue() { return enumValue; } @@ -28,8 +36,8 @@ public List getComments() { return comments; } - public EnumMemberModel withComments(List comments) { - return new EnumMemberModel<>(propertyName, enumValue, comments); + public EnumMemberModel withComments(List comments) { + return new EnumMemberModel(propertyName, enumValue, comments); } } diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/ModelCompiler.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/ModelCompiler.java index ee77e0cf4..34f6c00cd 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/ModelCompiler.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/ModelCompiler.java @@ -76,6 +76,9 @@ public TsModel javaToTypeScript(Model model) { if (settings.mapEnum == EnumMapping.asInlineUnion) { tsModel = inlineEnums(tsModel, symbolTable); } + if (settings.mapEnum == EnumMapping.asNumberBasedEnum) { + tsModel = transformEnumsToNumberBasedEnum(tsModel); + } } // tagged unions @@ -89,7 +92,7 @@ public TsModel javaToTypeScript(Model model) { public TsType javaToTypeScript(Type type) { final BeanModel beanModel = new BeanModel(Object.class, Object.class, null, null, null, Collections.emptyList(), Collections.singletonList(new PropertyModel("property", type, false, null, null, null)), null); - final Model model = new Model(Collections.singletonList(beanModel), Collections.>emptyList(), null); + final Model model = new Model(Collections.singletonList(beanModel), Collections.emptyList(), null); final TsModel tsModel = javaToTypeScript(model); return tsModel.getBeans().get(0).getProperties().get(0).getTsType(); } @@ -100,11 +103,16 @@ private TsModel processModel(SymbolTable symbolTable, Model model) { for (BeanModel bean : model.getBeans()) { beans.add(processBean(symbolTable, model, children, bean)); } - final List> enums = new ArrayList<>(); - for (EnumModel enumModel : model.getEnums()) { - enums.add(processEnum(symbolTable, enumModel)); + final List enums = new ArrayList<>(); + final List stringEnums = new ArrayList<>(); + for (EnumModel enumModel : model.getEnums()) { + final TsEnumModel tsEnumModel = processEnum(symbolTable, enumModel); + enums.add(tsEnumModel); + if (tsEnumModel.getKind() == EnumKind.StringBased) { + stringEnums.add(tsEnumModel); + } } - return new TsModel().setBeans(beans).setEnums(enums); + return new TsModel().withBeans(beans).withEnums(enums).withOriginalStringEnums(stringEnums); } private Map> createChildrenMap(Model model) { @@ -205,7 +213,7 @@ private TsPropertyModel processProperty(SymbolTable symbolTable, BeanModel bean, return new TsPropertyModel(prefix + property.getName() + suffix, tsType, settings.declarePropertiesAsReadOnly, property.getComments()); } - private TsEnumModel processEnum(SymbolTable symbolTable, EnumModel enumModel) { + private TsEnumModel processEnum(SymbolTable symbolTable, EnumModel enumModel) { final Symbol beanIdentifier = symbolTable.getSymbol(enumModel.getOrigin()); return TsEnumModel.fromEnumModel(beanIdentifier, enumModel); } @@ -244,7 +252,7 @@ private TsModel removeInheritedProperties(SymbolTable symbolTable, TsModel tsMod } beans.add(bean.withProperties(properties)); } - return tsModel.setBeans(beans); + return tsModel.withBeans(beans); } private TsModel addImplementedProperties(SymbolTable symbolTable, TsModel tsModel) { @@ -273,7 +281,7 @@ private TsModel addImplementedProperties(SymbolTable symbolTable, TsModel tsMode beans.add(bean); } } - return tsModel.setBeans(beans); + return tsModel.withBeans(beans); } private static Map getInheritedProperties(SymbolTable symbolTable, TsModel tsModel, List parents) { @@ -544,20 +552,21 @@ public TsType transform(TsType type) { } }); - return model.setTypeAliases(new ArrayList<>(typeAliases)); + return model.withTypeAliases(new ArrayList<>(typeAliases)); } private TsModel transformEnumsToUnions(TsModel tsModel) { + final List stringEnums = tsModel.getEnums(EnumKind.StringBased); final LinkedHashSet typeAliases = new LinkedHashSet<>(tsModel.getTypeAliases()); - for (TsEnumModel enumModel : tsModel.getEnums(EnumKind.StringBased)) { + for (TsEnumModel enumModel : stringEnums) { final List values = new ArrayList<>(); - for (EnumMemberModel member : enumModel.getMembers()) { - values.add(new TsType.StringLiteralType(member.getEnumValue())); + for (EnumMemberModel member : enumModel.getMembers()) { + values.add(new TsType.StringLiteralType((String) member.getEnumValue())); } final TsType union = new TsType.UnionType(values); typeAliases.add(new TsAliasModel(enumModel.getOrigin(), enumModel.getName(), null, union, enumModel.getComments())); } - return tsModel.setTypeAliases(new ArrayList<>(typeAliases)); + return tsModel.withoutEnums(stringEnums).withTypeAliases(new ArrayList<>(typeAliases)); } private TsModel inlineEnums(final TsModel tsModel, final SymbolTable symbolTable) { @@ -575,9 +584,20 @@ public TsType transform(TsType tsType) { return tsType; } }); - final ArrayList aliases = new ArrayList<>(tsModel.getTypeAliases()); - aliases.removeAll(inlinedAliases); - return newTsModel.setTypeAliases(aliases); + return newTsModel.withoutTypeAliases(new ArrayList<>(inlinedAliases)); + } + + private TsModel transformEnumsToNumberBasedEnum(TsModel tsModel) { + final List stringEnums = tsModel.getEnums(EnumKind.StringBased); + final LinkedHashSet enums = new LinkedHashSet<>(); + for (TsEnumModel enumModel : stringEnums) { + final List members = new ArrayList<>(); + for (EnumMemberModel member : enumModel.getMembers()) { + members.add(new EnumMemberModel(member.getPropertyName(), (Number) null, member.getComments())); + } + enums.add(enumModel.withMembers(members)); + } + return tsModel.withoutEnums(stringEnums).withEnums(new ArrayList<>(enums)); } private TsModel createAndUseTaggedUnions(final SymbolTable symbolTable, TsModel tsModel) { @@ -612,13 +632,13 @@ public TsType transform(TsType tsType) { return tsType; } }); - return model.setTypeAliases(new ArrayList<>(typeAliases)); + return model.withTypeAliases(new ArrayList<>(typeAliases)); } private TsModel sortDeclarations(SymbolTable symbolTable, TsModel tsModel) { final List beans = tsModel.getBeans(); final List aliases = tsModel.getTypeAliases(); - final List> enums = tsModel.getEnums(); + final List enums = tsModel.getEnums(); if (settings.sortDeclarations) { for (TsBeanModel bean : beans) { Collections.sort(bean.getProperties()); @@ -634,9 +654,9 @@ private TsModel sortDeclarations(SymbolTable symbolTable, TsModel tsModel) { addOrderedClass(symbolTable, tsModel, bean, orderedBeans); } return tsModel - .setBeans(new ArrayList<>(orderedBeans)) - .setTypeAliases(aliases) - .setEnums(enums); + .withBeans(new ArrayList<>(orderedBeans)) + .withTypeAliases(aliases) + .withEnums(enums); } private static void addOrderedClass(SymbolTable symbolTable, TsModel tsModel, TsBeanModel bean, LinkedHashSet orderedBeans) { @@ -671,7 +691,7 @@ private static TsModel transformBeanPropertyTypes(TsModel tsModel, TsType.Transf } newBeans.add(bean.withProperties(newProperties).withMethods(newMethods)); } - return tsModel.setBeans(newBeans); + return tsModel.withBeans(newBeans); } private static Class getOriginClass(SymbolTable symbolTable, TsType type) { diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/Emitter.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/Emitter.java index cbeee6d2c..ad3776a8f 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/Emitter.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/Emitter.java @@ -2,7 +2,6 @@ package cz.habarta.typescript.generator.emitter; import cz.habarta.typescript.generator.*; -import cz.habarta.typescript.generator.compiler.EnumKind; import cz.habarta.typescript.generator.compiler.EnumMemberModel; import cz.habarta.typescript.generator.util.Utils; import java.io.*; @@ -105,7 +104,7 @@ private void emitElements(TsModel model, boolean exportKeyword, boolean declareK exportKeyword = exportKeyword || forceExportKeyword; emitBeans(model, exportKeyword, declareKeyword); emitTypeAliases(model, exportKeyword, declareKeyword); - emitNumberEnums(model, exportKeyword, declareKeyword); + emitLiteralEnums(model, exportKeyword, declareKeyword); emitHelpers(model); for (EmitterExtension emitterExtension : settings.extensions) { writeNewLine(); @@ -127,11 +126,8 @@ private void emitTypeAliases(TsModel model, boolean exportKeyword, boolean decla } } - private void emitNumberEnums(TsModel model, boolean exportKeyword, boolean declareKeyword) { - final ArrayList> enums = settings.mapEnum == EnumMapping.asNumberBasedEnum && !settings.areDefaultStringEnumsOverriddenByExtension() - ? new ArrayList<>(model.getEnums()) - : new ArrayList>(model.getEnums(EnumKind.NumberBased)); - for (TsEnumModel enumModel : enums) { + private void emitLiteralEnums(TsModel model, boolean exportKeyword, boolean declareKeyword) { + for (TsEnumModel enumModel : model.getEnums()) { emitFullyQualifiedDeclaration(enumModel, exportKeyword, declareKeyword); } } @@ -157,7 +153,7 @@ private void emitDeclaration(TsDeclarationModel declaration, boolean exportKeywo } else if (declaration instanceof TsAliasModel) { emitTypeAlias((TsAliasModel) declaration, exportKeyword); } else if (declaration instanceof TsEnumModel) { - emitNumberEnum((TsEnumModel) declaration, exportKeyword, declareKeyword); + emitLiteralEnum((TsEnumModel) declaration, exportKeyword, declareKeyword); } else { throw new RuntimeException("Unknown declaration type: " + declaration.getClass().getName()); } @@ -266,15 +262,18 @@ private void emitTypeAlias(TsAliasModel alias, boolean exportKeyword) { writeIndentedLine(exportKeyword, "type " + alias.getName().getSimpleName() + genericParameters + " = " + alias.getDefinition().format(settings) + ";"); } - private void emitNumberEnum(TsEnumModel enumModel, boolean exportKeyword, boolean declareKeyword) { + private void emitLiteralEnum(TsEnumModel enumModel, boolean exportKeyword, boolean declareKeyword) { writeNewLine(); emitComments(enumModel.getComments()); - writeIndentedLine(exportKeyword, (declareKeyword ? "declare " : "") + "const enum " + enumModel.getName().getSimpleName() + " {"); + final String declareText = declareKeyword ? "declare " : ""; + final String constText = settings.nonConstEnums ? "" : "const "; + writeIndentedLine(exportKeyword, declareText + constText + "enum " + enumModel.getName().getSimpleName() + " {"); indent++; - for (EnumMemberModel member : enumModel.getMembers()) { + for (EnumMemberModel member : enumModel.getMembers()) { emitComments(member.getComments()); - final String initializer = enumModel.getKind() == EnumKind.NumberBased - ? " = " + member.getEnumValue() + final Object value = member.getEnumValue(); + final String initializer = value != null + ? " = " + (value instanceof String ? quote((String) value, settings) : String.valueOf(value)) : ""; writeIndentedLine(member.getPropertyName() + initializer + ","); } diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/TsEnumModel.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/TsEnumModel.java index 52b52e6da..ad8faa61a 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/TsEnumModel.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/TsEnumModel.java @@ -8,28 +8,31 @@ import java.util.List; -// T extends String | Number -public class TsEnumModel extends TsDeclarationModel { - - private final EnumKind kind; - private final List> members; +public class TsEnumModel extends TsDeclarationModel { - public TsEnumModel(Class origin, Symbol name, EnumKind kind, List> members, List comments) { + private final EnumKind kind; + private final List members; + + public TsEnumModel(Class origin, Symbol name, EnumKind kind, List members, List comments) { super(origin, null, name, comments); this.kind = kind; this.members = members; } - public static TsEnumModel fromEnumModel(Symbol name, EnumModel enumModel) { - return new TsEnumModel<>(enumModel.getOrigin(), name, enumModel.getKind(), enumModel.getMembers(), enumModel.getComments()); + public static TsEnumModel fromEnumModel(Symbol name, EnumModel enumModel) { + return new TsEnumModel(enumModel.getOrigin(), name, enumModel.getKind(), enumModel.getMembers(), enumModel.getComments()); } - public EnumKind getKind() { + public EnumKind getKind() { return kind; } - public List> getMembers() { + public List getMembers() { return members; } + public TsEnumModel withMembers(List members) { + return new TsEnumModel(origin, name, kind, members, comments); + } + } diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/TsModel.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/TsModel.java index 0df6a66d0..6e0aaa5d8 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/TsModel.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/TsModel.java @@ -2,26 +2,29 @@ package cz.habarta.typescript.generator.emitter; import cz.habarta.typescript.generator.compiler.EnumKind; +import cz.habarta.typescript.generator.util.Utils; import java.util.*; public class TsModel { private final List beans; - private final List> enums; + private final List enums; + private final List originalStringEnums; private final List typeAliases; private final List helpers; public TsModel() { - this (new ArrayList(), new ArrayList>(), new ArrayList(), new ArrayList()); + this (new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList()); } - public TsModel(List beans, List> enums, List typeAliases, List helpers) { + public TsModel(List beans, List enums, List originalStringEnums, List typeAliases, List helpers) { if (beans == null) throw new NullPointerException(); if (enums == null) throw new NullPointerException(); if (typeAliases == null) throw new NullPointerException(); this.beans = beans; this.enums = enums; + this.originalStringEnums = originalStringEnums; this.typeAliases = typeAliases; this.helpers = helpers; } @@ -41,27 +44,39 @@ public TsBeanModel getBean(Class origin) { return null; } - public TsModel setBeans(List beans) { - return new TsModel(beans, enums, typeAliases, helpers); + public TsModel withBeans(List beans) { + return new TsModel(beans, enums, originalStringEnums, typeAliases, helpers); } - public List> getEnums() { + public List getEnums() { return enums; } @SuppressWarnings("unchecked") - public List> getEnums(EnumKind enumKind) { - final List> result = new ArrayList<>(); - for (TsEnumModel enumModel : enums) { + public List getEnums(EnumKind enumKind) { + final List result = new ArrayList<>(); + for (TsEnumModel enumModel : enums) { if (enumModel.getKind() == enumKind) { - result.add((TsEnumModel) enumModel); + result.add(enumModel); } } return result; } - public TsModel setEnums(List> enums) { - return new TsModel(beans, enums, typeAliases, helpers); + public TsModel withEnums(List enums) { + return new TsModel(beans, enums, originalStringEnums, typeAliases, helpers); + } + + public TsModel withoutEnums(List enums) { + return new TsModel(beans, Utils.removeAll(this.enums, enums), originalStringEnums, typeAliases, helpers); + } + + public List getOriginalStringEnums() { + return originalStringEnums; + } + + public TsModel withOriginalStringEnums(List originalStringEnums) { + return new TsModel(beans, enums, originalStringEnums, typeAliases, helpers); } public List getTypeAliases() { @@ -79,8 +94,12 @@ public TsAliasModel getTypeAlias(Class origin) { return null; } - public TsModel setTypeAliases(List typeAliases) { - return new TsModel(beans, enums, typeAliases, helpers); + public TsModel withTypeAliases(List typeAliases) { + return new TsModel(beans, enums, originalStringEnums, typeAliases, helpers); + } + + public TsModel withoutTypeAliases(List typeAliases) { + return new TsModel(beans, enums, originalStringEnums, Utils.removeAll(this.typeAliases, typeAliases), helpers); } public List getHelpers() { diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/EnumConstantsExtension.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/EnumConstantsExtension.java index 2e334154e..ce7f5f81d 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/EnumConstantsExtension.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/EnumConstantsExtension.java @@ -2,7 +2,6 @@ package cz.habarta.typescript.generator.ext; import cz.habarta.typescript.generator.Settings; -import cz.habarta.typescript.generator.compiler.EnumKind; import cz.habarta.typescript.generator.compiler.EnumMemberModel; import cz.habarta.typescript.generator.emitter.EmitterExtension; import cz.habarta.typescript.generator.emitter.EmitterExtensionFeatures; @@ -10,8 +9,10 @@ import cz.habarta.typescript.generator.emitter.TsModel; import java.util.Collections; import java.util.List; +import cz.habarta.typescript.generator.DeprecationText; +@DeprecationText("Consider using configuration parameter 'mapEnum' with value 'asEnum'") public class EnumConstantsExtension extends EmitterExtension { @Override @@ -24,12 +25,12 @@ public EmitterExtensionFeatures getFeatures() { @Override public void emitElements(Writer writer, Settings settings, boolean exportKeyword, TsModel model) { String exportString = exportKeyword ? "export " : ""; - List> enums = model.getEnums(EnumKind.StringBased); + List enums = model.getOriginalStringEnums(); Collections.sort(enums); - for (TsEnumModel tsEnum : enums) { + for (TsEnumModel tsEnum : enums) { writer.writeIndentedLine(""); writer.writeIndentedLine(exportString + "const " + tsEnum.getName().getSimpleName() + " = {"); - for (EnumMemberModel member : tsEnum.getMembers()) { + for (EnumMemberModel member : tsEnum.getMembers()) { writer.writeIndentedLine(settings.indentString + member.getPropertyName() + ": " + "<" + tsEnum.getName().getSimpleName() + ">\"" + member.getEnumValue() + "\","); } writer.writeIndentedLine("}"); diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/NonConstEnumsExtension.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/NonConstEnumsExtension.java index 682194b54..03ff9a71e 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/NonConstEnumsExtension.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/NonConstEnumsExtension.java @@ -2,7 +2,6 @@ package cz.habarta.typescript.generator.ext; import cz.habarta.typescript.generator.Settings; -import cz.habarta.typescript.generator.compiler.EnumKind; import cz.habarta.typescript.generator.compiler.EnumMemberModel; import cz.habarta.typescript.generator.emitter.EmitterExtension; import cz.habarta.typescript.generator.emitter.EmitterExtensionFeatures; @@ -10,8 +9,10 @@ import cz.habarta.typescript.generator.emitter.TsModel; import java.util.Collections; import java.util.List; +import cz.habarta.typescript.generator.DeprecationText; +@DeprecationText("Consider using parameter 'mapEnum' with value 'asEnum' and parameter 'nonConstEnums' with 'true'") public class NonConstEnumsExtension extends EmitterExtension { @Override @@ -25,12 +26,12 @@ public EmitterExtensionFeatures getFeatures() { @Override public void emitElements(Writer writer, Settings settings, boolean exportKeyword, TsModel model) { String exportString = exportKeyword ? "export " : ""; - List> enums = model.getEnums(EnumKind.StringBased); + List enums = model.getOriginalStringEnums(); Collections.sort(enums); - for (TsEnumModel tsEnum : enums) { + for (TsEnumModel tsEnum : enums) { writer.writeIndentedLine(""); writer.writeIndentedLine(exportString + "enum " + tsEnum.getName().getSimpleName() + " {"); - for (EnumMemberModel member : tsEnum.getMembers()) { + for (EnumMemberModel member : tsEnum.getMembers()) { writer.writeIndentedLine(settings.indentString + member.getPropertyName() + ","); } writer.writeIndentedLine("}"); diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/EnumModel.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/EnumModel.java index 1b5651054..3209e391b 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/EnumModel.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/EnumModel.java @@ -6,33 +6,32 @@ import java.util.*; -// T extends String | Number -public class EnumModel extends DeclarationModel { +public class EnumModel extends DeclarationModel { - private final EnumKind kind; - private final List> members; + private final EnumKind kind; + private final List members; - public EnumModel(Class origin, EnumKind kind, List> members, List comments) { + public EnumModel(Class origin, EnumKind kind, List members, List comments) { super (origin, comments); this.kind = kind; this.members = members; } - public EnumKind getKind() { + public EnumKind getKind() { return kind; } - public List> getMembers() { + public List getMembers() { return members; } - public EnumModel withMembers(List> members) { - return new EnumModel<>(origin, kind, members, comments); + public EnumModel withMembers(List members) { + return new EnumModel(origin, kind, members, comments); } @Override - public EnumModel withComments(List comments) { - return new EnumModel<>(origin, kind, members, comments); + public EnumModel withComments(List comments) { + return new EnumModel(origin, kind, members, comments); } } diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Jackson2Parser.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Jackson2Parser.java index 182031189..29fa18d52 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Jackson2Parser.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Jackson2Parser.java @@ -273,8 +273,7 @@ private DeclarationModel parseEnumOrObjectEnum(SourceType> sourceClass) jsonFormat.shape() == JsonFormat.Shape.NUMBER_FLOAT || jsonFormat.shape() == JsonFormat.Shape.NUMBER_INT); - final List> stringMembers = new ArrayList<>(); - final List> numberMembers = new ArrayList<>(); + final List enumMembers = new ArrayList<>(); if (sourceClass.type.isEnum()) { final Class enumClass = (Class) sourceClass.type; @@ -293,10 +292,10 @@ private DeclarationModel parseEnumOrObjectEnum(SourceType> sourceClass) if (field.isEnumConstant()) { if (isNumberBased) { final Number value = getNumberEnumValue(field, valueMethod, index++); - numberMembers.add(new EnumMemberModel<>(field.getName(), value, null)); + enumMembers.add(new EnumMemberModel(field.getName(), value, null)); } else { final String value = getStringEnumValue(field, valueMethod); - stringMembers.add(new EnumMemberModel<>(field.getName(), value, null)); + enumMembers.add(new EnumMemberModel(field.getName(), value, null)); } } } @@ -306,11 +305,7 @@ private DeclarationModel parseEnumOrObjectEnum(SourceType> sourceClass) } } - if (isNumberBased) { - return new EnumModel<>(sourceClass.type, EnumKind.NumberBased, numberMembers, null); - } else { - return new EnumModel<>(sourceClass.type, EnumKind.StringBased, stringMembers, null); - } + return new EnumModel(sourceClass.type, isNumberBased ? EnumKind.NumberBased : EnumKind.StringBased, enumMembers, null); } private Number getNumberEnumValue(Field field, Method valueMethod, int index) throws Exception { diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Javadoc.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Javadoc.java index 6c2b86593..5376838c6 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Javadoc.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Javadoc.java @@ -41,13 +41,13 @@ private static List loadJavadocXmlFiles(List javadocXmlFiles) { public Model enrichModel(Model model) { final List dBeans = new ArrayList<>(); - final List> dEnums = new ArrayList<>(); + final List dEnums = new ArrayList<>(); for (BeanModel bean : model.getBeans()) { final BeanModel dBean = enrichBean(bean); dBeans.add(dBean); } - for (EnumModel enumModel : model.getEnums()) { - final EnumModel dEnumModel = enrichEnum(enumModel); + for (EnumModel enumModel : model.getEnums()) { + final EnumModel dEnumModel = enrichEnum(enumModel); dEnums.add(dEnumModel); } return new Model(dBeans, dEnums, model.getJaxrsApplication()); @@ -96,11 +96,11 @@ private PropertyModel enrichProperty(PropertyModel property, List dFields return property.withComments(getComments(propertyComment, tags)); } - private EnumModel enrichEnum(EnumModel enumModel) { + private EnumModel enrichEnum(EnumModel enumModel) { final Enum dEnum = findJavadocEnum(enumModel.getOrigin(), dRoots); - final List> enrichedMembers = new ArrayList<>(); - for (EnumMemberModel member : enumModel.getMembers()) { - final EnumMemberModel enrichedMember = enrichEnumMember(member, dEnum); + final List enrichedMembers = new ArrayList<>(); + for (EnumMemberModel member : enumModel.getMembers()) { + final EnumMemberModel enrichedMember = enrichEnumMember(member, dEnum); enrichedMembers.add(enrichedMember); } final String enumComment = dEnum != null ? dEnum.getComment() : null; @@ -108,7 +108,7 @@ private EnumModel enrichEnum(EnumModel enumModel) { return enumModel.withMembers(enrichedMembers).withComments(Utils.concat(getComments(enumComment, tags), enumModel.getComments())); } - private EnumMemberModel enrichEnumMember(EnumMemberModel enumMember, Enum dEnum) { + private EnumMemberModel enrichEnumMember(EnumMemberModel enumMember, Enum dEnum) { final EnumConstant dConstant = findJavadocEnumConstant(enumMember.getPropertyName(), dEnum); final List tags = dConstant != null ? dConstant.getTag(): null; final String memberComment = dConstant != null ? dConstant.getComment() : null; diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Model.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Model.java index 259f82e37..721184ab4 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Model.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Model.java @@ -7,10 +7,10 @@ public class Model { private final List beans; - private final List> enums; + private final List enums; private final JaxrsApplicationModel jaxrsApplication; - public Model(List beans, List> enums, JaxrsApplicationModel jaxrsApplication) { + public Model(List beans, List enums, JaxrsApplicationModel jaxrsApplication) { if (beans == null) throw new NullPointerException(); if (enums == null) throw new NullPointerException(); this.beans = beans; @@ -31,7 +31,7 @@ public BeanModel getBean(Class beanClass) { return null; } - public List> getEnums() { + public List getEnums() { return enums; } @@ -49,7 +49,7 @@ public String toString() { sb.append(bean); sb.append(String.format("%n")); } - for (EnumModel enumModel : enums) { + for (EnumModel enumModel : enums) { sb.append(" "); sb.append(enumModel); sb.append(String.format("%n")); diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/ModelParser.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/ModelParser.java index 42abb382a..06ab469d5 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/ModelParser.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/ModelParser.java @@ -39,7 +39,7 @@ private Model parseQueue() { final JaxrsApplicationParser jaxrsApplicationParser = new JaxrsApplicationParser(settings); final Collection parsedTypes = new ArrayList<>(); // do not use hashcodes, we can only count on `equals` since we use custom `ParameterizedType`s final List beans = new ArrayList<>(); - final List> enums = new ArrayList<>(); + final List enums = new ArrayList<>(); SourceType sourceType; while ((sourceType = typeQueue.poll()) != null) { if (parsedTypes.contains(sourceType.type)) { @@ -80,15 +80,15 @@ private Model parseQueue() { protected abstract DeclarationModel parseClass(SourceType> sourceClass); protected static DeclarationModel parseEnum(SourceType> sourceClass) { - final List> values = new ArrayList<>(); + final List values = new ArrayList<>(); if (sourceClass.type.isEnum()) { @SuppressWarnings("unchecked") final Class> enumClass = (Class>) sourceClass.type; for (Enum enumConstant : enumClass.getEnumConstants()) { - values.add(new EnumMemberModel<>(enumConstant.name(), enumConstant.name(), null)); + values.add(new EnumMemberModel(enumConstant.name(), enumConstant.name(), null)); } } - return new EnumModel<>(sourceClass.type, EnumKind.StringBased, values, null); + return new EnumModel(sourceClass.type, EnumKind.StringBased, values, null); } protected void addBeanToQueue(SourceType sourceType) { diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/util/Utils.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/util/Utils.java index c9120fd26..820076d52 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/util/Utils.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/util/Utils.java @@ -165,6 +165,12 @@ public static List removeNulls(List list) { return result; } + public static List removeAll(List list, List toBeRemoved) { + final ArrayList result = new ArrayList<>(list); + result.removeAll(toBeRemoved); + return result; + } + public static List readLines(InputStream stream) { return splitMultiline(readString(stream), false); } diff --git a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/EnumTest.java b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/EnumTest.java index 800213eb0..6391124a7 100644 --- a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/EnumTest.java +++ b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/EnumTest.java @@ -75,6 +75,26 @@ public void testEnumAsNumberBasedEnum() { assertEquals(expected, output); } + @Test + public void testEnumAsEnum() { + final Settings settings = TestUtils.settings(); + settings.mapEnum = EnumMapping.asEnum; + final String output = new TypeScriptGenerator(settings).generateTypeScript(Input.from(AClass.class)); + final String expected = ( + "interface AClass {\n" + + " direction: Direction;\n" + + "}\n" + + "\n" + + "declare const enum Direction {\n" + + " North = 'North',\n" + + " East = 'East',\n" + + " South = 'South',\n" + + " West = 'West',\n" + + "}" + ).replace("'", "\""); + assertEquals(expected.trim(), output.trim()); + } + @Test public void testEnumWithJsonPropertyAnnotations() { final Settings settings = TestUtils.settings(); @@ -120,7 +140,6 @@ public void testExcludeObjectEnum() { public void testObjectEnum() { final Settings settings = TestUtils.settings(); final String output = new TypeScriptGenerator(settings).generateTypeScript(Input.from(StatusType.class)); - System.out.println(output); final String expected = "" + "interface StatusType {\n" + " code: number;\n" + diff --git a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/JavadocTest.java b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/JavadocTest.java index 1ab93cf78..3a93b599b 100644 --- a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/JavadocTest.java +++ b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/JavadocTest.java @@ -29,7 +29,7 @@ public void testJavadoc() { Assert.assertEquals("Documentation for documentedField.", property1.getComments().get(0)); final PropertyModel property2 = bean.getProperties().get(1); Assert.assertEquals("Documentation for documentedEnumField.", property2.getComments().get(0)); - final EnumModel enumModel = model.getEnums().get(0); + final EnumModel enumModel = model.getEnums().get(0); Assert.assertEquals("Documentation for DummyEnum.", enumModel.getComments().get(0)); } { diff --git a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/ModulesAndNamespacesTest.java b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/ModulesAndNamespacesTest.java index 773d3175c..5735d2878 100644 --- a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/ModulesAndNamespacesTest.java +++ b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/ModulesAndNamespacesTest.java @@ -36,6 +36,7 @@ public void files(File outputDir, boolean mapPackages) { private static void file(String prefix, String module, String namespace, boolean mapPackagesToNamespaces, TypeScriptOutputKind outputKind, TypeScriptFileType outputFileType, File output) { final Settings settings = new Settings(); settings.jsonLibrary = JsonLibrary.jackson2; + settings.mapEnum = EnumMapping.asEnum; settings.addTypeNamePrefix = prefix; settings.module = module; settings.namespace = namespace; @@ -43,6 +44,7 @@ private static void file(String prefix, String module, String namespace, boolean settings.outputKind = outputKind; settings.outputFileType = outputFileType; if (outputFileType == TypeScriptFileType.implementationFile) { + settings.nonConstEnums = true; settings.mapClasses = ClassMapping.asClasses; } if (outputFileType == TypeScriptFileType.implementationFile && !mapPackagesToNamespaces) { diff --git a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/NumberEnumTest.java b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/NumberEnumTest.java index ec07b40d6..84a6d6554 100644 --- a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/NumberEnumTest.java +++ b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/NumberEnumTest.java @@ -21,11 +21,11 @@ public void testParser() { final ModelParser parser = new TypeScriptGenerator(settings).getModelParser(); final Model model = parser.parseModel(SomeCode.class); Assert.assertEquals(1, model.getEnums().size()); - final EnumModel enumModel = model.getEnums().get(0); + final EnumModel enumModel = model.getEnums().get(0); Assert.assertEquals(EnumKind.NumberBased, enumModel.getKind()); Assert.assertEquals(2, enumModel.getMembers().size()); - Assert.assertEquals(10, enumModel.getMembers().get(0).getEnumValue()); - Assert.assertEquals(11, enumModel.getMembers().get(1).getEnumValue()); + Assert.assertEquals(10, ((Number)enumModel.getMembers().get(0).getEnumValue()).intValue()); + Assert.assertEquals(11, ((Number)enumModel.getMembers().get(1).getEnumValue()).intValue()); } @Test @@ -40,6 +40,20 @@ public void test() { output.trim()); } + @Test + public void testNonConstEnum() { + final Settings settings = TestUtils.settings(); + settings.outputFileType = TypeScriptFileType.implementationFile; + settings.nonConstEnums = true; + final String output = new TypeScriptGenerator(settings).generateTypeScript(Input.from(SomeCode.class)); + Assert.assertEquals( + "enum SomeCode {\n" + + " VALUE0 = 10,\n" + + " VALUE1 = 11,\n" + + "}", + output.trim()); + } + @Test public void testJavadoc() { final Settings settings = TestUtils.settings(); diff --git a/typescript-generator-gradle-plugin/src/main/java/cz/habarta/typescript/generator/gradle/GenerateTask.java b/typescript-generator-gradle-plugin/src/main/java/cz/habarta/typescript/generator/gradle/GenerateTask.java index 3eae2ce86..241dbf852 100644 --- a/typescript-generator-gradle-plugin/src/main/java/cz/habarta/typescript/generator/gradle/GenerateTask.java +++ b/typescript-generator-gradle-plugin/src/main/java/cz/habarta/typescript/generator/gradle/GenerateTask.java @@ -40,6 +40,7 @@ public class GenerateTask extends DefaultTask { public List customTypeMappings; public DateMapping mapDate; public EnumMapping mapEnum; + public boolean nonConstEnums; public ClassMapping mapClasses; public boolean disableTaggedUnions; public boolean ignoreSwaggerAnnotations; @@ -111,6 +112,7 @@ public void generate() throws Exception { settings.customTypeMappings = Settings.convertToMap(customTypeMappings); settings.mapDate = mapDate; settings.mapEnum = mapEnum; + settings.nonConstEnums = nonConstEnums; settings.mapClasses = mapClasses; settings.disableTaggedUnions = disableTaggedUnions; settings.ignoreSwaggerAnnotations = ignoreSwaggerAnnotations; diff --git a/typescript-generator-maven-plugin/src/main/java/cz/habarta/typescript/generator/maven/GenerateMojo.java b/typescript-generator-maven-plugin/src/main/java/cz/habarta/typescript/generator/maven/GenerateMojo.java index 0aad8ddcf..0f0811248 100644 --- a/typescript-generator-maven-plugin/src/main/java/cz/habarta/typescript/generator/maven/GenerateMojo.java +++ b/typescript-generator-maven-plugin/src/main/java/cz/habarta/typescript/generator/maven/GenerateMojo.java @@ -220,15 +220,23 @@ public class GenerateMojo extends AbstractMojo { /** * Specifies how enums will be mapped. - * Supported values are 'asUnion', 'asInlineUnion', 'asNumberBasedEnum'. + * Supported values are 'asUnion', 'asInlineUnion', 'asEnum', 'asNumberBasedEnum'. * Default value is 'asUnion'. * Value 'asUnion' creates type alias to union of string enum values. * Value 'asInlineUnion' creates union of enum values on places where the enum is used. + * Value 'asEnum' creates string enum. Requires TypeScript 2.4. * Value 'asNumberBasedEnum' creates enum of named number values. */ @Parameter private EnumMapping mapEnum; + /** + * If true generated enums will not have const keyword. + * This can be used only in implementation files. + */ + @Parameter + private boolean nonConstEnums; + /** * Specifies whether classes will be mapped to classes or interfaces. * Supported values are 'asInterfaces', 'asClasses'. @@ -444,6 +452,7 @@ public void execute() { settings.customTypeMappings = Settings.convertToMap(customTypeMappings); settings.mapDate = mapDate; settings.mapEnum = mapEnum; + settings.nonConstEnums = nonConstEnums; settings.mapClasses = mapClasses; settings.disableTaggedUnions = disableTaggedUnions; settings.ignoreSwaggerAnnotations = ignoreSwaggerAnnotations;