Skip to content

Commit 6ff205e

Browse files
Merge branch 'global-module-dependencies' into master
2 parents e4e63df + f2e9ad5 commit 6ff205e

File tree

5 files changed

+119
-16
lines changed

5 files changed

+119
-16
lines changed

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

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,24 @@ public LoadedModuleDependencies(Settings settings, List<ModuleDependency> depend
2424
final ObjectMapper objectMapper = Utils.getObjectMapper();
2525
final Map<String, ModuleDependency> importFromMap = new LinkedHashMap<>();
2626
final Map<String, ModuleDependency> importAsMap = new LinkedHashMap<>();
27+
final Map<String, ModuleDependency> globalTypeNames = new LinkedHashMap<>();
2728
for (ModuleDependency dependency : dependencies) {
2829
try {
2930
final Function<String, String> reportNullParameter = parameterName ->
3031
String.format("Missing required configuration parameter '%s' in module dependency: %s", parameterName, dependency);
31-
Objects.requireNonNull(dependency.importFrom, () -> reportNullParameter.apply("importFrom"));
32-
Objects.requireNonNull(dependency.importAs, () -> reportNullParameter.apply("importAs"));
32+
if (dependency.global) {
33+
if (dependency.importFrom != null) {
34+
throw new RuntimeException(String.format(
35+
"'importFrom' parameter is only applicable when 'global' is not set to 'true' (at module dependency %s).", dependency));
36+
}
37+
if (dependency.importAs != null) {
38+
throw new RuntimeException(String.format(
39+
"'importAs' parameter is only applicable when 'global' is not set to 'true' (at module dependency %s).", dependency));
40+
}
41+
} else {
42+
Objects.requireNonNull(dependency.importFrom, () -> reportNullParameter.apply("importFrom"));
43+
Objects.requireNonNull(dependency.importAs, () -> reportNullParameter.apply("importAs"));
44+
}
3345
Objects.requireNonNull(dependency.infoJson, () -> reportNullParameter.apply("infoJson"));
3446
if (settings.generateNpmPackageJson) {
3547
Objects.requireNonNull(dependency.npmPackageName, () -> reportNullParameter.apply("npmPackageName"));
@@ -46,27 +58,36 @@ public LoadedModuleDependencies(Settings settings, List<ModuleDependency> depend
4658
}
4759

4860
TypeScriptGenerator.getLogger().info(String.format(
49-
"Loading '%s' module info from: %s", dependency.importFrom, dependency.infoJson));
61+
"Loading %s module info from: %s", dependency.toShortString(), dependency.infoJson));
5062

51-
final ModuleDependency importFromConflict = importFromMap.put(dependency.importFrom, dependency);
52-
if (importFromConflict != null) {
53-
throw new RuntimeException(String.format("Duplicate module '%s'", dependency.importFrom));
54-
}
63+
if (!dependency.global) {
64+
final ModuleDependency importFromConflict = importFromMap.put(dependency.importFrom, dependency);
65+
if (importFromConflict != null) {
66+
throw new RuntimeException(String.format("Duplicate module '%s'", dependency.importFrom));
67+
}
5568

56-
final ModuleDependency importAsConflict = importAsMap.put(dependency.importAs, dependency);
57-
if (importAsConflict != null) {
58-
throw new RuntimeException(String.format("Import identifier '%s' already used for module '%s'", dependency.importAs, importAsConflict.importFrom));
69+
final ModuleDependency importAsConflict = importAsMap.put(dependency.importAs, dependency);
70+
if (importAsConflict != null) {
71+
throw new RuntimeException(String.format("Import identifier '%s' already used for module '%s'", dependency.importAs, importAsConflict.importFrom));
72+
}
5973
}
6074

6175
final InfoJson infoJson = objectMapper.readValue(dependency.infoJson, InfoJson.class);
6276
for (InfoJson.ClassInfo classInfo : infoJson.classes) {
6377
final Pair<ModuleDependency, String> presentMapping = classMappings.get(classInfo.javaClass);
6478
if (presentMapping != null) {
6579
TypeScriptGenerator.getLogger().warning(String.format(
66-
"Java class '%s' already present in module '%s'", classInfo.javaClass, presentMapping.getValue1().importFrom));
80+
"Java class '%s' already present in '%s'", classInfo.javaClass, presentMapping.getValue1().infoJson));
6781
} else {
6882
classMappings.put(classInfo.javaClass, Pair.of(dependency, classInfo.typeName));
6983
}
84+
final ModuleDependency presentTypeName = globalTypeNames.get(classInfo.typeName);
85+
if (presentTypeName != null) {
86+
throw new RuntimeException(String.format(
87+
"Duplicate TypeScript global name '%s', declared in '%s' and also '%s'", classInfo.typeName, presentTypeName.infoJson, dependency.infoJson));
88+
} else {
89+
globalTypeNames.put(classInfo.typeName, dependency);
90+
}
7091
}
7192
} catch (IOException e) {
7293
throw new RuntimeException(e);

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11

22
package cz.habarta.typescript.generator;
33

4+
import com.fasterxml.jackson.annotation.JsonInclude;
45
import cz.habarta.typescript.generator.util.Utils;
56
import java.io.File;
67

78

9+
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
810
public class ModuleDependency {
911

12+
public boolean global;
1013
public String importFrom;
1114
public String importAs;
1215
public File infoJson;
@@ -16,17 +19,30 @@ public class ModuleDependency {
1619
public ModuleDependency() {
1720
}
1821

19-
public ModuleDependency(String importFrom, String importAs, File infoJson, String npmPackageName, String npmVersionRange) {
22+
private ModuleDependency(boolean global, String importFrom, String importAs, File infoJson, String npmPackageName, String npmVersionRange) {
23+
this.global = global;
2024
this.importFrom = importFrom;
2125
this.importAs = importAs;
2226
this.infoJson = infoJson;
2327
this.npmPackageName = npmPackageName;
2428
this.npmVersionRange = npmVersionRange;
2529
}
2630

31+
public static ModuleDependency module(String importFrom, String importAs, File infoJson, String npmPackageName, String npmVersionRange) {
32+
return new ModuleDependency(false, importFrom, importAs, infoJson, npmPackageName, npmVersionRange);
33+
}
34+
35+
public static ModuleDependency global(File infoJson) {
36+
return new ModuleDependency(true, null, null, infoJson, null, null);
37+
}
38+
2739
@Override
2840
public String toString() {
2941
return Utils.objectToString(this);
3042
}
3143

44+
public String toShortString() {
45+
return global ? "global" : "'" + importFrom + "'";
46+
}
47+
3248
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,8 +441,8 @@ public void validate() {
441441
if (restOptionsType != null && !isGenerateRest()) {
442442
throw new RuntimeException("'restOptionsType' parameter can only be used when generating REST client or interface.");
443443
}
444-
if (generateInfoJson && outputKind != TypeScriptOutputKind.module) {
445-
throw new RuntimeException("'generateInfoJson' can only be used when generating proper module ('outputKind' parameter is 'module').");
444+
if (generateInfoJson && (outputKind != TypeScriptOutputKind.module && outputKind != TypeScriptOutputKind.global)) {
445+
throw new RuntimeException("'generateInfoJson' can only be used when 'outputKind' parameter is 'module' or 'global'.");
446446
}
447447
if (generateNpmPackageJson && outputKind != TypeScriptOutputKind.module) {
448448
throw new RuntimeException("'generateNpmPackageJson' can only be used when generating proper module ('outputKind' parameter is 'module').");

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ private void emitImports() {
7777
if (settings.moduleDependencies != null && !settings.moduleDependencies.isEmpty()) {
7878
writeNewLine();
7979
for (ModuleDependency dependency : settings.moduleDependencies) {
80-
writeIndentedLine("import * as " + dependency.importAs + " from " + quote(dependency.importFrom, settings) + ";");
80+
if (!dependency.global) {
81+
writeIndentedLine("import * as " + dependency.importAs + " from " + quote(dependency.importFrom, settings) + ";");
82+
}
8183
}
8284
}
8385
if (settings.importDeclarations != null && !settings.importDeclarations.isEmpty()) {

typescript-generator-core/src/test/java/cz/habarta/typescript/generator/ModuleDependenciesTest.java

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import java.util.Arrays;
88
import java.util.Collections;
99
import java.util.List;
10+
import java.util.stream.Collectors;
11+
import java.util.stream.Stream;
1012
import org.junit.Assert;
1113
import org.junit.Test;
1214

@@ -45,7 +47,7 @@ private void generateModuleB() {
4547
settings.npmName = "b";
4648
settings.npmVersion = "1.0.0";
4749
settings.moduleDependencies = Arrays.asList(
48-
new ModuleDependency("../a", "a", new File("target/test-module-dependencies/a/typescript-generator-info.json"), "a", "1.0.0")
50+
ModuleDependency.module("../a", "a", new File("target/test-module-dependencies/a/typescript-generator-info.json"), "a", "1.0.0")
4951
);
5052
new TypeScriptGenerator(settings).generateTypeScript(
5153
Input.from(B1.class, B2.class, C.class, D1.class, D2.class),
@@ -67,6 +69,68 @@ private void generateModuleB() {
6769
Assert.assertTrue(!output.contains("type Enum1 ="));
6870
}
6971

72+
@Test
73+
public void testGlobal() {
74+
generateGlobalA("global-a");
75+
generateGlobalB("global-b", "global-a");
76+
}
77+
78+
@Test(expected = RuntimeException.class)
79+
public void testGlobalWithConflict() {
80+
generateGlobalA("global-a1");
81+
generateGlobalA("global-a2");
82+
try {
83+
generateGlobalB("global-b-conflict", "global-a1", "global-a2");
84+
} catch (Exception e) {
85+
System.out.println("Exception (expected): " + e.getMessage());
86+
throw e;
87+
}
88+
}
89+
90+
private void generateGlobalA(String directory) {
91+
final Settings settings = TestUtils.settings();
92+
settings.outputKind = TypeScriptOutputKind.global;
93+
settings.customTypeNaming = Collections.singletonMap("cz.habarta.typescript.generator.ModuleDependenciesTest$A2", "NS.A2");
94+
settings.generateInfoJson = true;
95+
new TypeScriptGenerator(settings).generateTypeScript(
96+
Input.from(A1.class, A2.class, Enum1.class, ABase.class),
97+
Output.to(new File("target/test-module-dependencies/" + directory + "/global.d.ts")));
98+
final String output = TestUtils.readFile("target/test-module-dependencies/" + directory + "/global.d.ts");
99+
Assert.assertTrue(output.contains("interface A1 {"));
100+
Assert.assertTrue(output.contains("namespace NS {"));
101+
Assert.assertTrue(output.contains("interface A2 {"));
102+
Assert.assertTrue(output.contains("type Enum1 ="));
103+
}
104+
105+
private void generateGlobalB(String directory, String... dependencyDirectories) {
106+
final Settings settings = TestUtils.settings();
107+
settings.outputKind = TypeScriptOutputKind.global;
108+
settings.referencedFiles = Stream.of(dependencyDirectories)
109+
.map(depDir -> "../" + depDir + "/global.d.ts")
110+
.collect(Collectors.toList());
111+
settings.moduleDependencies = Stream.of(dependencyDirectories)
112+
.map(depDir -> ModuleDependency.global(new File("target/test-module-dependencies/" + depDir + "/typescript-generator-info.json")))
113+
.collect(Collectors.toList());
114+
new TypeScriptGenerator(settings).generateTypeScript(
115+
Input.from(B1.class, B2.class, C.class, D1.class, D2.class),
116+
Output.to(new File("target/test-module-dependencies/" + directory + "/global.d.ts")));
117+
final String output = TestUtils.readFile("target/test-module-dependencies/" + directory + "/global.d.ts");
118+
Assert.assertTrue(!output.contains("import"));
119+
Assert.assertTrue(output.contains("interface B1 extends A1 {"));
120+
Assert.assertTrue(output.contains("objectA: A1;"));
121+
Assert.assertTrue(output.contains("enum1: Enum1;"));
122+
Assert.assertTrue(output.contains("aBase: ABaseUnion<string>;"));
123+
Assert.assertTrue(output.contains("aBases: ABaseUnion<string>[];"));
124+
Assert.assertTrue(output.contains("interface B2 extends NS.A2 {"));
125+
Assert.assertTrue(output.contains("objectA: NS.A2;"));
126+
Assert.assertTrue(output.contains("interface D1 extends C<A1> {"));
127+
Assert.assertTrue(output.contains("interface D2 extends C<NS.A2> {"));
128+
Assert.assertTrue(!output.contains("interface A1 {"));
129+
Assert.assertTrue(!output.contains("namespace NS {"));
130+
Assert.assertTrue(!output.contains("interface A2 {"));
131+
Assert.assertTrue(!output.contains("type Enum1 ="));
132+
}
133+
70134
/// module "a"
71135

72136
private static class A1 {

0 commit comments

Comments
 (0)