Skip to content

Commit 10f0f72

Browse files
Merge pull request #132 from vojtechhabarta/mapPackagesToNamespaces
Mapping Java packages to TypeScript namespaces
2 parents 5d4adf5 + 5e48f6b commit 10f0f72

File tree

22 files changed

+323
-81
lines changed

22 files changed

+323
-81
lines changed

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public class Settings {
2424
public TypeScriptOutputKind outputKind = null;
2525
public String module = null;
2626
public String namespace = null;
27+
public boolean mapPackagesToNamespaces = false;
2728
public String umdNamespace = null;
2829
public JsonLibrary jsonLibrary = null;
2930
private Predicate<String> excludeFilter = null;
@@ -147,6 +148,9 @@ public void validate() {
147148
if (features.generatesModuleCode && outputKind != TypeScriptOutputKind.module) {
148149
throw new RuntimeException(String.format("Extension '%s' generates code as module but 'outputKind' parameter is not set to 'module'.", extensionName));
149150
}
151+
if (!features.worksWithPackagesMappedToNamespaces && mapPackagesToNamespaces) {
152+
throw new RuntimeException(String.format("Extension '%s' doesn't work with 'mapPackagesToNamespaces' parameter.", extensionName));
153+
}
150154
if (features.generatesJaxrsApplicationClient) {
151155
reportConfigurationChange(extensionName, "generateJaxrsApplicationClient", "true");
152156
generateJaxrsApplicationClient = true;

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/TsType.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public ReferenceType(Symbol symbol) {
8989

9090
@Override
9191
public String format(Settings settings) {
92-
return symbol.toString();
92+
return symbol.getFullName();
9393
}
9494

9595
}
@@ -109,7 +109,7 @@ public GenericReferenceType(Symbol symbol, List<TsType> typeArguments) {
109109

110110
@Override
111111
public String format(Settings settings) {
112-
return symbol + "<" + Utils.join(format(typeArguments, settings), ", ") + ">";
112+
return symbol.getFullName() + "<" + Utils.join(format(typeArguments, settings), ", ") + ">";
113113
}
114114
}
115115

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/Symbol.java

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,34 @@
44

55
public class Symbol {
66

7-
protected String name;
7+
private String namespace;
8+
private String simpleName;
89

9-
public Symbol(String name) {
10-
this.name = name;
10+
public Symbol(String temporaryName) {
11+
this.simpleName = temporaryName;
1112
}
1213

13-
@Override
14-
public String toString() {
15-
return name;
14+
public String getNamespace() {
15+
return namespace;
16+
}
17+
18+
public String getSimpleName() {
19+
return simpleName;
20+
}
21+
22+
public String getFullName() {
23+
return namespace != null ? namespace + "." + simpleName : simpleName;
24+
}
25+
26+
public void setFullName(String fullName) {
27+
final int index = fullName.lastIndexOf('.');
28+
if (index == -1) {
29+
namespace = null;
30+
simpleName = fullName;
31+
} else {
32+
namespace = fullName.substring(0, index);
33+
simpleName = fullName.substring(index + 1);
34+
}
1635
}
1736

1837
}

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/SymbolTable.java

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public Symbol addSuffixToSymbol(Symbol symbol, String suffix) {
6969
}
7070
}
7171
// syntheticSymbols
72-
return getSyntheticSymbol(symbol.name + suffix);
72+
return getSyntheticSymbol(symbol.getFullName() + suffix);
7373
}
7474

7575
public void resolveSymbolNames() {
@@ -79,12 +79,12 @@ public void resolveSymbolNames() {
7979
final String suffix = entry.getKey().getValue2();
8080
final Symbol symbol = entry.getValue();
8181
final String suffixString = suffix != null ? suffix : "";
82-
final String name = getMappedName(cls) + suffixString;
83-
symbol.name = name;
84-
if (!names.containsKey(name)) {
85-
names.put(name, new ArrayList<Class<?>>());
82+
final String fullName = getMappedFullName(cls) + suffixString;
83+
symbol.setFullName(fullName);
84+
if (!names.containsKey(fullName)) {
85+
names.put(fullName, new ArrayList<Class<?>>());
8686
}
87-
names.get(name).add(cls);
87+
names.get(fullName).add(cls);
8888
}
8989
reportConflicts(names);
9090
}
@@ -104,7 +104,7 @@ private static void reportConflicts(Map<String, List<Class<?>>> names) {
104104
}
105105
}
106106

107-
public String getMappedName(Class<?> cls) {
107+
public String getMappedFullName(Class<?> cls) {
108108
if (cls == null) {
109109
return null;
110110
}
@@ -123,20 +123,31 @@ public String getMappedName(Class<?> cls) {
123123
throw new RuntimeException("Evaluating 'customTypeNamingFunction' failed.", e);
124124
}
125125
}
126-
String name = cls.getSimpleName();
127-
if (settings.removeTypeNamePrefix != null && name.startsWith(settings.removeTypeNamePrefix)) {
128-
name = name.substring(settings.removeTypeNamePrefix.length(), name.length());
126+
String simpleName = cls.getSimpleName();
127+
if (settings.removeTypeNamePrefix != null && simpleName.startsWith(settings.removeTypeNamePrefix)) {
128+
simpleName = simpleName.substring(settings.removeTypeNamePrefix.length(), simpleName.length());
129129
}
130-
if (settings.removeTypeNameSuffix != null && name.endsWith(settings.removeTypeNameSuffix)) {
131-
name = name.substring(0, name.length() - settings.removeTypeNameSuffix.length());
130+
if (settings.removeTypeNameSuffix != null && simpleName.endsWith(settings.removeTypeNameSuffix)) {
131+
simpleName = simpleName.substring(0, simpleName.length() - settings.removeTypeNameSuffix.length());
132132
}
133133
if (settings.addTypeNamePrefix != null) {
134-
name = settings.addTypeNamePrefix + name;
134+
simpleName = settings.addTypeNamePrefix + simpleName;
135135
}
136136
if (settings.addTypeNameSuffix != null) {
137-
name = name + settings.addTypeNameSuffix;
137+
simpleName = simpleName + settings.addTypeNameSuffix;
138+
}
139+
140+
if (settings.mapPackagesToNamespaces) {
141+
final String classNameDotted = cls.getName().replace('$', '.');
142+
final int index = classNameDotted.lastIndexOf('.');
143+
if (index == -1) {
144+
return simpleName;
145+
} else {
146+
return classNameDotted.substring(0, index) + "." + simpleName;
147+
}
148+
} else {
149+
return simpleName;
138150
}
139-
return name;
140151
}
141152

142153
private static boolean isUndefined(Object variable) {

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/Emitter.java

Lines changed: 82 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -117,30 +117,75 @@ private void emitElements(TsModel model, boolean exportKeyword, boolean declareK
117117

118118
private void emitBeans(TsModel model, boolean exportKeyword) {
119119
for (TsBeanModel bean : model.getBeans()) {
120+
emitFullyQualifiedDeclaration(bean, exportKeyword, false);
121+
}
122+
}
123+
124+
private void emitTypeAliases(TsModel model, boolean exportKeyword) {
125+
for (TsAliasModel alias : model.getTypeAliases()) {
126+
emitFullyQualifiedDeclaration(alias, exportKeyword, false);
127+
}
128+
}
129+
130+
private void emitNumberEnums(TsModel model, boolean exportKeyword, boolean declareKeyword) {
131+
final ArrayList<TsEnumModel<?>> enums = settings.mapEnum == EnumMapping.asNumberBasedEnum && !settings.areDefaultStringEnumsOverriddenByExtension()
132+
? new ArrayList<>(model.getEnums())
133+
: new ArrayList<TsEnumModel<?>>(model.getEnums(EnumKind.NumberBased));
134+
for (TsEnumModel<?> enumModel : enums) {
135+
emitFullyQualifiedDeclaration(enumModel, exportKeyword, declareKeyword);
136+
}
137+
}
138+
139+
private void emitFullyQualifiedDeclaration(TsDeclarationModel declaration, boolean exportKeyword, boolean declareKeyword) {
140+
if (declaration.getName().getNamespace() != null) {
120141
writeNewLine();
121-
emitComments(bean.getComments());
122-
final String declarationType = bean.isClass() ? "class" : "interface";
123-
final String typeParameters = bean.getTypeParameters().isEmpty() ? "" : "<" + Utils.join(bean.getTypeParameters(), ", ")+ ">";
124-
final List<TsType> extendsList = bean.getExtendsList();
125-
final List<TsType> implementsList = bean.getImplementsList();
126-
final String extendsClause = extendsList.isEmpty() ? "" : " extends " + Utils.join(extendsList, ", ");
127-
final String implementsClause = implementsList.isEmpty() ? "" : " implements " + Utils.join(implementsList, ", ");
128-
writeIndentedLine(exportKeyword, declarationType + " " + bean.getName() + typeParameters + extendsClause + implementsClause + " {");
142+
writeIndentedLine(exportKeyword, "namespace " + declaration.getName().getNamespace() + " {");
129143
indent++;
130-
for (TsPropertyModel property : bean.getProperties()) {
131-
emitProperty(property);
132-
}
133-
if (bean.getConstructor() != null) {
134-
emitCallable(bean.getConstructor());
135-
}
136-
for (TsMethodModel method : bean.getMethods()) {
137-
emitCallable(method);
138-
}
144+
emitDeclaration(declaration, true, declareKeyword);
139145
indent--;
146+
writeNewLine();
140147
writeIndentedLine("}");
148+
} else {
149+
emitDeclaration(declaration, exportKeyword, declareKeyword);
141150
}
142151
}
143152

153+
private void emitDeclaration(TsDeclarationModel declaration, boolean exportKeyword, boolean declareKeyword) {
154+
if (declaration instanceof TsBeanModel) {
155+
emitBean((TsBeanModel) declaration, exportKeyword);
156+
} else if (declaration instanceof TsAliasModel) {
157+
emitTypeAlias((TsAliasModel) declaration, exportKeyword);
158+
} else if (declaration instanceof TsEnumModel) {
159+
emitNumberEnum((TsEnumModel) declaration, exportKeyword, declareKeyword);
160+
} else {
161+
throw new RuntimeException("Unknown declaration type: " + declaration.getClass().getName());
162+
}
163+
}
164+
165+
private void emitBean(TsBeanModel bean, boolean exportKeyword) {
166+
writeNewLine();
167+
emitComments(bean.getComments());
168+
final String declarationType = bean.isClass() ? "class" : "interface";
169+
final String typeParameters = bean.getTypeParameters().isEmpty() ? "" : "<" + Utils.join(bean.getTypeParameters(), ", ")+ ">";
170+
final List<TsType> extendsList = bean.getExtendsList();
171+
final List<TsType> implementsList = bean.getImplementsList();
172+
final String extendsClause = extendsList.isEmpty() ? "" : " extends " + Utils.join(extendsList, ", ");
173+
final String implementsClause = implementsList.isEmpty() ? "" : " implements " + Utils.join(implementsList, ", ");
174+
writeIndentedLine(exportKeyword, declarationType + " " + bean.getName().getSimpleName() + typeParameters + extendsClause + implementsClause + " {");
175+
indent++;
176+
for (TsPropertyModel property : bean.getProperties()) {
177+
emitProperty(property);
178+
}
179+
if (bean.getConstructor() != null) {
180+
emitCallable(bean.getConstructor());
181+
}
182+
for (TsMethodModel method : bean.getMethods()) {
183+
emitCallable(method);
184+
}
185+
indent--;
186+
writeIndentedLine("}");
187+
}
188+
144189
private void emitProperty(TsPropertyModel property) {
145190
emitComments(property.getComments());
146191
final TsType tsType = property.getTsType();
@@ -211,36 +256,29 @@ private void emitStatements(List<TsStatement> statements) {
211256
}
212257
}
213258

214-
private void emitTypeAliases(TsModel model, boolean exportKeyword) {
215-
for (TsAliasModel alias : model.getTypeAliases()) {
216-
writeNewLine();
217-
emitComments(alias.getComments());
218-
final String genericParameters = alias.getTypeParameters().isEmpty()
219-
? ""
220-
: "<" + Utils.join(alias.getTypeParameters(), ", ") + ">";
221-
writeIndentedLine(exportKeyword, "type " + alias.getName() + genericParameters + " = " + alias.getDefinition().format(settings) + ";");
222-
}
259+
private void emitTypeAlias(TsAliasModel alias, boolean exportKeyword) {
260+
writeNewLine();
261+
emitComments(alias.getComments());
262+
final String genericParameters = alias.getTypeParameters().isEmpty()
263+
? ""
264+
: "<" + Utils.join(alias.getTypeParameters(), ", ") + ">";
265+
writeIndentedLine(exportKeyword, "type " + alias.getName().getSimpleName() + genericParameters + " = " + alias.getDefinition().format(settings) + ";");
223266
}
224267

225-
private void emitNumberEnums(TsModel model, boolean exportKeyword, boolean declareKeyword) {
226-
final ArrayList<TsEnumModel<?>> enums = settings.mapEnum == EnumMapping.asNumberBasedEnum && !settings.areDefaultStringEnumsOverriddenByExtension()
227-
? new ArrayList<>(model.getEnums())
228-
: new ArrayList<TsEnumModel<?>>(model.getEnums(EnumKind.NumberBased));
229-
for (TsEnumModel<?> enumModel : enums) {
230-
writeNewLine();
231-
emitComments(enumModel.getComments());
232-
writeIndentedLine(exportKeyword, (declareKeyword ? "declare " : "") + "const enum " + enumModel.getName() + " {");
233-
indent++;
234-
for (EnumMemberModel<?> member : enumModel.getMembers()) {
235-
emitComments(member.getComments());
236-
final String initializer = enumModel.getKind() == EnumKind.NumberBased
237-
? " = " + member.getEnumValue()
238-
: "";
239-
writeIndentedLine(member.getPropertyName() + initializer + ",");
240-
}
241-
indent--;
242-
writeIndentedLine("}");
268+
private void emitNumberEnum(TsEnumModel<?> enumModel, boolean exportKeyword, boolean declareKeyword) {
269+
writeNewLine();
270+
emitComments(enumModel.getComments());
271+
writeIndentedLine(exportKeyword, (declareKeyword ? "declare " : "") + "const enum " + enumModel.getName().getSimpleName() + " {");
272+
indent++;
273+
for (EnumMemberModel<?> member : enumModel.getMembers()) {
274+
emitComments(member.getComments());
275+
final String initializer = enumModel.getKind() == EnumKind.NumberBased
276+
? " = " + member.getEnumValue()
277+
: "";
278+
writeIndentedLine(member.getPropertyName() + initializer + ",");
243279
}
280+
indent--;
281+
writeIndentedLine("}");
244282
}
245283

246284
private void emitHelpers(TsModel model) {

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/EmitterExtensionFeatures.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66

77
public class EmitterExtensionFeatures {
88

9+
// declared abilities
910
public boolean generatesRuntimeCode = false;
1011
public boolean generatesModuleCode = false;
12+
public boolean worksWithPackagesMappedToNamespaces = false;
13+
public boolean overridesStringEnums = false;
14+
15+
// overridden settings
1116
public boolean generatesJaxrsApplicationClient = false;
1217
public String restResponseType = null;
1318
public String restOptionsType = null;
1419
public Map<String, String> npmPackageDependencies = null;
15-
public boolean overridesStringEnums = false;
1620

1721
}

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/TsDeclarationModel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public int compareTo(TsDeclarationModel o) {
4141
if (categoryResult != 0) {
4242
return categoryResult;
4343
}
44-
final int nameResult = compare(this.name.toString(), o.name.toString());
44+
final int nameResult = compare(this.name.getFullName(), o.name.getFullName());
4545
if (nameResult != 0) {
4646
return nameResult;
4747
}

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/AxiosClientExtension.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public EmitterExtensionFeatures getFeatures() {
1818
final EmitterExtensionFeatures features = new EmitterExtensionFeatures();
1919
features.generatesRuntimeCode = true;
2020
features.generatesModuleCode = true;
21+
features.worksWithPackagesMappedToNamespaces = true;
2122
features.generatesJaxrsApplicationClient = true;
2223
features.restResponseType = "Promise<Axios.GenericAxiosResponse<R>>";
2324
features.restOptionsType = "<O>";
@@ -30,7 +31,7 @@ public void emitElements(Writer writer, Settings settings, boolean exportKeyword
3031
emitSharedPart(writer, settings);
3132
for (TsBeanModel bean : model.getBeans()) {
3233
if (bean.isJaxrsApplicationClientBean()) {
33-
final String clientName = bean.getName().toString();
34+
final String clientName = bean.getName().getSimpleName();
3435
emitClient(writer, settings, exportKeyword, clientName);
3536
}
3637
}

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/BeanPropertyPathExtension.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ private static TsBeanModel getBeanModelByType(TsModel model, TsType type) {
155155
}
156156

157157
private static String getBeanModelClassName(TsBeanModel bean) {
158-
return bean.getName().toString();
158+
return bean.getName().getSimpleName();
159159
}
160160

161161
private static void writeBeanProperty(
@@ -164,7 +164,7 @@ private static void writeBeanProperty(
164164
TsBeanModel fieldBeanModel = getBeanModelByType(model, property.getTsType());
165165
String fieldClassName = fieldBeanModel != null ? getBeanModelClassName(fieldBeanModel) : "";
166166
// if a class has a field of its own type, we get stackoverflow exception
167-
if (fieldClassName.equals(bean.getName().toString())) {
167+
if (fieldClassName.equals(bean.getName().getSimpleName())) {
168168
fieldClassName = "";
169169
}
170170
writer.writeIndentedLine(

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/EnumConstantsExtension.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ public void emitElements(Writer writer, Settings settings, boolean exportKeyword
2828
Collections.sort(enums);
2929
for (TsEnumModel<String> tsEnum : enums) {
3030
writer.writeIndentedLine("");
31-
writer.writeIndentedLine(exportString + "const " + tsEnum.getName() + " = {");
31+
writer.writeIndentedLine(exportString + "const " + tsEnum.getName().getSimpleName() + " = {");
3232
for (EnumMemberModel<String> member : tsEnum.getMembers()) {
33-
writer.writeIndentedLine(settings.indentString + member.getPropertyName() + ": " + "<" + tsEnum.getName() + ">\"" + member.getEnumValue() + "\",");
33+
writer.writeIndentedLine(settings.indentString + member.getPropertyName() + ": " + "<" + tsEnum.getName().getSimpleName() + ">\"" + member.getEnumValue() + "\",");
3434
}
3535
writer.writeIndentedLine("}");
3636
}

0 commit comments

Comments
 (0)