diff --git a/modules/openapi-generator/pom.xml b/modules/openapi-generator/pom.xml
index 49d4b81d07aab..5e64320be74d9 100644
--- a/modules/openapi-generator/pom.xml
+++ b/modules/openapi-generator/pom.xml
@@ -459,6 +459,11 @@
lombok
${lombok.version}
+
+ org.yaml
+ snakeyaml
+ ${snakeyaml.version}
+
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptAngularClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptAngularClientCodegen.java
index 420225325f640..68a53f5aff884 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptAngularClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptAngularClientCodegen.java
@@ -19,6 +19,7 @@
import io.swagger.v3.oas.models.media.Schema;
import lombok.AccessLevel;
+import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.openapitools.codegen.*;
@@ -31,6 +32,7 @@
import org.openapitools.codegen.model.OperationsMap;
import org.openapitools.codegen.utils.ModelUtils;
import org.openapitools.codegen.utils.SemVer;
+import org.openapitools.codegen.utils.YamlConfigUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -76,6 +78,10 @@ public static enum PROVIDED_IN_LEVEL {none, root, any, platform}
public static final String STRING_ENUMS_DESC = "Generate string enums instead of objects for enum values.";
public static final String QUERY_PARAM_OBJECT_FORMAT = "queryParamObjectFormat";
public static final String USE_SQUARE_BRACKETS_IN_ARRAY_NAMES = "useSquareBracketsInArrayNames";
+ public static final String TYPESCRIPT_VERSION = "typescriptVersion";
+ public static final String RXJS_VERSION = "rxjsVersion";
+ public static final String NGPACKAGR_VERSION = "ngPackagrVersion ";
+ public static final String ZONEJS_VERSION = "zoneJsVersion";
protected String ngVersion = "19.0.0";
@Getter @Setter
@@ -144,6 +150,10 @@ public TypeScriptAngularClientCodegen() {
this.cliOptions.add(new CliOption(STRING_ENUMS, STRING_ENUMS_DESC).defaultValue(String.valueOf(this.stringEnums)));
this.cliOptions.add(new CliOption(QUERY_PARAM_OBJECT_FORMAT, "The format for query param objects: 'dot', 'json', 'key'.").defaultValue(this.queryParamObjectFormat.name()));
this.cliOptions.add(CliOption.newBoolean(USE_SQUARE_BRACKETS_IN_ARRAY_NAMES, "Setting this property to true will add brackets to array attribute names, e.g. my_values[].", false));
+ this.cliOptions.add(new CliOption(TYPESCRIPT_VERSION, "The version of typescript compatible with Angular (see ngVersion option)."));
+ this.cliOptions.add(new CliOption(RXJS_VERSION, "The version of RxJS compatible with Angular (see ngVersion option)."));
+ this.cliOptions.add(new CliOption(NGPACKAGR_VERSION, "The version of ng-packagr compatible with Angular (see ngVersion option)."));
+ this.cliOptions.add(new CliOption(ZONEJS_VERSION, "The version of zone.js compatible with Angular (see ngVersion option)."));
}
@Override
@@ -286,135 +296,53 @@ public void processOpts() {
}
+ @Data
+ static class AngularDependencies {
+ String tsVersion;
+ String rxjsVersion;
+ String ngPackagrVersion;
+ String zonejsVersion;
+ String tsickleVersion;
+ }
+
private void addNpmPackageGeneration(SemVer ngVersion) {
if (additionalProperties.containsKey(NPM_REPOSITORY)) {
this.setNpmRepository(additionalProperties.get(NPM_REPOSITORY).toString());
}
- // Set the typescript version compatible to the Angular version
- // based on https://angular.dev/reference/versions
- if (ngVersion.atLeast("19.0.0")) {
- additionalProperties.put("tsVersion", ">=5.5.0 <5.7.0");
- } else if (ngVersion.atLeast("18.1.0")) {
- additionalProperties.put("tsVersion", ">=5.4.0 <5.6.0");
- } else if (ngVersion.atLeast("18.0.0")) {
- additionalProperties.put("tsVersion", ">=5.4.0 <5.5.0");
- } else if (ngVersion.atLeast("17.0.0")) {
- additionalProperties.put("tsVersion", ">=4.9.3 <5.3.0");
- } else if (ngVersion.atLeast("16.1.0")) {
- additionalProperties.put("tsVersion", ">=4.9.3 <5.2.0");
- } else if (ngVersion.atLeast("16.0.0")) {
- additionalProperties.put("tsVersion", ">=4.9.3 <5.1.0");
- } else if (ngVersion.atLeast("15.0.0")) {
- additionalProperties.put("tsVersion", ">=4.8.2 <4.10.0");
- } else if (ngVersion.atLeast("14.0.0")) {
- additionalProperties.put("tsVersion", ">=4.6.0 <=4.8.0");
- } else if (ngVersion.atLeast("13.0.0")) {
- additionalProperties.put("tsVersion", ">=4.4.2 <4.5.0");
- } else if (ngVersion.atLeast("12.0.0")) {
- additionalProperties.put("tsVersion", ">=4.3.0 <4.4.0");
- } else if (ngVersion.atLeast("11.0.0")) {
- additionalProperties.put("tsVersion", ">=4.0.0 <4.1.0");
- } else if (ngVersion.atLeast("10.0.0")) {
- additionalProperties.put("tsVersion", ">=3.9.2 <4.0.0");
- } else if (ngVersion.atLeast("9.0.0")) {
- additionalProperties.put("tsVersion", ">=3.6.0 <3.8.0");
- } else {
- throw new IllegalArgumentException("Invalid ngVersion. Only Angular v9+ is supported.");
- }
-
- // Set the rxJS version compatible to the Angular version
- if (ngVersion.atLeast("19.0.0")) {
- additionalProperties.put("rxjsVersion", "7.4.0");
- } else if (ngVersion.atLeast("18.0.0")) {
- additionalProperties.put("rxjsVersion", "7.4.0");
- } else if (ngVersion.atLeast("17.0.0")) {
- additionalProperties.put("rxjsVersion", "7.4.0");
- } else if (ngVersion.atLeast("16.0.0")) {
- additionalProperties.put("rxjsVersion", "7.4.0");
- } else if (ngVersion.atLeast("15.0.0")) {
- additionalProperties.put("rxjsVersion", "7.5.5");
- } else if (ngVersion.atLeast("14.0.0")) {
- additionalProperties.put("rxjsVersion", "7.5.5");
- } else if (ngVersion.atLeast("13.0.0")) {
- additionalProperties.put("rxjsVersion", "7.4.0");
- } else if (ngVersion.atLeast("10.0.0")) {
- additionalProperties.put("rxjsVersion", "6.6.0");
- } else if (ngVersion.atLeast("9.0.0")) {
- additionalProperties.put("rxjsVersion", "6.5.3");
- }
+ Map angularDependenciesByVersion = YamlConfigUtils.loadAsMap("typescript-angular/angularDependenciesByVersion.yaml", AngularDependencies.class);
- supportingFiles.add(new SupportingFile("ng-package.mustache", getIndexDirectory(), "ng-package.json"));
+ AngularDependencies angularDependencies = angularDependenciesByVersion.entrySet().stream()
+ // we filter only config version above or equal the current one
+ .filter(versionMatrix -> ngVersion.atLeast(versionMatrix.getKey()))
+ // get can the latest version configured that match the current one
+ .max(Comparator.comparing(s -> new SemVer(s.getKey())))
+ .map(Map.Entry::getValue)
+ .orElseThrow(() -> new IllegalArgumentException("Invalid ngVersion. Only Angular v9+ is supported."));
- // Specific ng-packagr configuration
- if (ngVersion.atLeast("19.0.0")) {
- additionalProperties.put("ngPackagrVersion", "19.0.0");
- } else if (ngVersion.atLeast("18.1.0")) {
- additionalProperties.put("ngPackagrVersion", "18.1.0");
- // tsTickle is not required and there is no available version compatible with
- // versions of TypeScript compatible with Angular 18.
- } else if (ngVersion.atLeast("18.0.0")) {
- additionalProperties.put("ngPackagrVersion", "18.0.0");
- // tsTickle is not required and there is no available version compatible with
- // versions of TypeScript compatible with Angular 18.
- } else if (ngVersion.atLeast("17.0.0")) {
- additionalProperties.put("ngPackagrVersion", "17.0.3");
- // tsTickle is not required and there is no available version compatible with
- // versions of TypeScript compatible with Angular 17.
- } else if (ngVersion.atLeast("16.0.0")) {
- additionalProperties.put("ngPackagrVersion", "16.0.0");
- // tsTickle is not required and there is no available version compatible with
- // versions of TypeScript compatible with Angular 16.
- } else if (ngVersion.atLeast("15.0.0")) {
- additionalProperties.put("ngPackagrVersion", "15.0.2");
- // tsTickle is not required and there is no available version compatible with
- // versions of TypeScript compatible with Angular 15.
- } else if (ngVersion.atLeast("14.0.0")) {
- additionalProperties.put("ngPackagrVersion", "14.0.2");
- additionalProperties.put("tsickleVersion", "0.46.3");
- } else if (ngVersion.atLeast("13.0.0")) {
- additionalProperties.put("ngPackagrVersion", "13.0.3");
- additionalProperties.put("tsickleVersion", "0.43.0");
- } else if (ngVersion.atLeast("12.0.0")) {
- additionalProperties.put("ngPackagrVersion", "12.2.1");
- additionalProperties.put("tsickleVersion", "0.43.0");
- } else if (ngVersion.atLeast("11.0.0")) {
- additionalProperties.put("ngPackagrVersion", "11.0.2");
- additionalProperties.put("tsickleVersion", "0.39.1");
- } else if (ngVersion.atLeast("10.0.0")) {
- additionalProperties.put("ngPackagrVersion", "10.0.3");
- additionalProperties.put("tsickleVersion", "0.39.1");
- } else if (ngVersion.atLeast("9.0.0")) {
- additionalProperties.put("ngPackagrVersion", "9.0.1");
- additionalProperties.put("tsickleVersion", "0.38.0");
- }
-
- // set zone.js version
- // based on https://github.com/angular/angular/blob/main/packages/core/package.json
- if (ngVersion.atLeast("19.0.0")) {
- additionalProperties.put("zonejsVersion", "0.15.0");
- } else if (ngVersion.atLeast("18.0.0")) {
- additionalProperties.put("zonejsVersion", "0.14.7");
- } else if (ngVersion.atLeast("17.0.0")) {
- additionalProperties.put("zonejsVersion", "0.14.0");
- } else if (ngVersion.atLeast("16.0.0")) {
- additionalProperties.put("zonejsVersion", "0.13.0");
- } else if (ngVersion.atLeast("15.0.0")) {
- additionalProperties.put("zonejsVersion", "0.11.5");
- } else if (ngVersion.atLeast("14.0.0")) {
- additionalProperties.put("zonejsVersion", "0.11.5");
- } else if (ngVersion.atLeast("12.0.0")) {
- additionalProperties.put("zonejsVersion", "0.11.4");
- } else if (ngVersion.atLeast("11.0.0")) {
- additionalProperties.put("zonejsVersion", "0.11.3");
- } else if (ngVersion.atLeast("9.0.0")) {
- additionalProperties.put("zonejsVersion", "0.10.2");
- } else if (ngVersion.atLeast("8.0.0")) {
- additionalProperties.put("zonejsVersion", "0.9.1");
+ additionalProperties.put("tsVersion", additionalProperties.containsKey(TYPESCRIPT_VERSION)
+ ? additionalProperties.containsKey(TYPESCRIPT_VERSION)
+ : angularDependencies.getTsVersion());
+
+ additionalProperties.put("rxjsVersion", additionalProperties.containsKey(RXJS_VERSION)
+ ? additionalProperties.containsKey(RXJS_VERSION)
+ : angularDependencies.getRxjsVersion());
+
+ additionalProperties.put("ngPackagrVersion", additionalProperties.containsKey(NGPACKAGR_VERSION)
+ ? additionalProperties.containsKey(NGPACKAGR_VERSION)
+ : angularDependencies.getNgPackagrVersion());
+
+ additionalProperties.put("zonejsVersion", additionalProperties.containsKey(ZONEJS_VERSION)
+ ? additionalProperties.containsKey(ZONEJS_VERSION)
+ : angularDependencies.getZonejsVersion());
+
+ if (angularDependencies.getTsickleVersion() != null) {
+ additionalProperties.put("tsickleVersion", angularDependencies.getTsickleVersion());
}
//Files for building our lib
+ supportingFiles.add(new SupportingFile("ng-package.mustache", getIndexDirectory(), "ng-package.json"));
supportingFiles.add(new SupportingFile("package.mustache", getIndexDirectory(), "package.json"));
supportingFiles.add(new SupportingFile("tsconfig.mustache", getIndexDirectory(), "tsconfig.json"));
}
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/YamlConfigUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/YamlConfigUtils.java
new file mode 100644
index 0000000000000..eaa41f357c22f
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/YamlConfigUtils.java
@@ -0,0 +1,69 @@
+package org.openapitools.codegen.utils;
+
+import org.yaml.snakeyaml.LoaderOptions;
+import org.yaml.snakeyaml.TypeDescription;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.Tag;
+
+import java.io.InputStream;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class YamlConfigUtils {
+
+ /**
+ * Load yaml config file as map
+ *
+ * @param configFile yaml config file to load
+ * @param clazz class of object to map data
+ * @param type of config object to generate
+ * @return config object generated
+ */
+ public static Map loadAsMap(String configFile, Class clazz) {
+ LoaderOptions loaderOptions = new LoaderOptions();
+ loaderOptions.setAllowDuplicateKeys(false);
+
+ Yaml yaml = new Yaml(new MapConstructor(loaderOptions, clazz));
+ yaml.setBeanAccess(BeanAccess.FIELD);
+ InputStream inputStream = YamlConfigUtils.class
+ .getClassLoader()
+ .getResourceAsStream(configFile);
+
+ return yaml.load(inputStream);
+ }
+
+ private static class MapConstructor extends Constructor {
+ private final TypeDescription itemType;
+
+ public MapConstructor(LoaderOptions loaderOptions, Class clazz) {
+ super(loaderOptions);
+ this.rootTag = new Tag("root");
+ itemType = new TypeDescription(clazz);
+ this.addTypeDescription(itemType);
+ }
+
+ @Override
+ protected Object constructObject(Node node) {
+ if ("root".equals(node.getTag().getValue()) && node instanceof MappingNode) {
+ MappingNode mNode = (MappingNode) node;
+ return mNode.getValue().stream().collect(
+ Collectors.toMap(
+ t -> super.constructObject(t.getKeyNode()),
+ t -> {
+ Node child = t.getValueNode();
+ child.setType(itemType.getType());
+ return super.constructObject(child);
+ }
+ )
+ );
+
+ } else {
+ return super.constructObject(node);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/typescript-angular/angularDependenciesByVersion.yaml b/modules/openapi-generator/src/main/resources/typescript-angular/angularDependenciesByVersion.yaml
new file mode 100644
index 0000000000000..26c53f39f9f9c
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/typescript-angular/angularDependenciesByVersion.yaml
@@ -0,0 +1,74 @@
+# For future versions...
+# Get typescript and rxjs version here: https://angular.dev/reference/versions
+# Get zone.js version here: https://github.com/angular/angular/blob/main/packages/core/package.json
+19.0.0:
+ tsVersion: '>=5.5.0 <5.7.0'
+ rxjsVersion: 7.4.0
+ ngPackagrVersion: 19.0.0
+ zonejsVersion: 0.15.0
+18.1.0:
+ tsVersion: '>=5.4.0 <5.6.0'
+ rxjsVersion: 7.4.0
+ ngPackagrVersion: 18.1.0
+ zonejsVersion: 0.14.7
+18.0.0:
+ tsVersion: '>=5.4.0 <5.5.0'
+ rxjsVersion: 7.4.0
+ ngPackagrVersion: 18.0.0
+ zonejsVersion: 0.14.7
+17.0.0:
+ tsVersion: '>=4.9.3 <5.3.0'
+ rxjsVersion: 7.4.0
+ ngPackagrVersion: 17.0.3
+ zonejsVersion: 0.14.0
+16.1.0:
+ tsVersion: '>=4.9.3 <5.2.0'
+ rxjsVersion: 7.4.0
+ ngPackagrVersion: 16.0.0
+ zonejsVersion: 0.13.0
+16.0.0:
+ tsVersion: '>=4.9.3 <5.1.0'
+ rxjsVersion: 7.4.0
+ ngPackagrVersion: 16.0.0
+ zonejsVersion: 0.13.0
+15.0.0:
+ tsVersion: '>=4.8.2 <4.10.0'
+ rxjsVersion: 7.5.5
+ ngPackagrVersion: 15.0.2
+ zonejsVersion: 0.11.5
+14.0.0:
+ tsVersion: '>=4.6.0 <=4.8.0'
+ rxjsVersion: 7.5.5
+ ngPackagrVersion: 14.0.2
+ zonejsVersion: 0.11.5
+ tsickleVersion: 0.46.3
+13.0.0:
+ tsVersion: '>=4.4.2 <4.5.0'
+ rxjsVersion: 7.4.0
+ ngPackagrVersion: 13.0.3
+ zonejsVersion: 0.11.4
+ tsickleVersion: 0.43.0
+12.0.0:
+ tsVersion: '>=4.3.0 <4.4.0'
+ rxjsVersion: 6.6.0
+ ngPackagrVersion: 12.2.1
+ zonejsVersion: 0.11.4
+ tsickleVersion: 0.43.0
+11.0.0:
+ tsVersion: '>=4.0.0 <4.1.0'
+ rxjsVersion: 6.6.0
+ ngPackagrVersion: 11.0.2
+ zonejsVersion: 0.11.3
+ tsickleVersion: 0.39.1
+10.0.0:
+ tsVersion: '>=3.9.2 <4.0.0'
+ rxjsVersion: 6.6.0
+ ngPackagrVersion: 10.0.3
+ zonejsVersion: 0.10.2
+ tsickleVersion: 0.39.1
+9.0.0:
+ tsVersion: '>=3.6.0 <3.8.0'
+ rxjsVersion: 6.5.3
+ ngPackagrVersion: 9.0.1
+ zonejsVersion: 0.10.2
+ tsickleVersion: 0.39.1
\ No newline at end of file
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/YamlConfigUtilsTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/YamlConfigUtilsTest.java
new file mode 100644
index 0000000000000..e36eac81b80df
--- /dev/null
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/YamlConfigUtilsTest.java
@@ -0,0 +1,45 @@
+package org.openapitools.codegen.utils;
+
+import lombok.Data;
+import org.testng.annotations.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class YamlConfigUtilsTest {
+
+ @Test
+ public void testLoadConfigAsMap() {
+ Map yamlConfig = YamlConfigUtils.loadAsMap("yamlConfigMap.yaml", YamlConfig.class);
+ assertThat(yamlConfig.keySet()).containsOnly("firstItem", "secondItem");
+
+ YamlConfig firstItem = yamlConfig.get("firstItem");
+ assertThat(firstItem.getStringConfig()).isEqualTo("Hello");
+ assertThat(firstItem.getNumberConfig()).isEqualTo(42);
+ assertThat(firstItem.getObjectConfig().getAttribut()).isEqualTo("openapi");
+ assertThat(firstItem.getArrayConfig()).hasSize(2);
+ assertThat(firstItem.getArrayConfig().get(0)).isEqualTo("one");
+ assertThat(firstItem.getArrayConfig().get(1)).isEqualTo("two");
+
+ YamlConfig secondItem = yamlConfig.get("secondItem");
+ assertThat(secondItem.getStringConfig()).isEqualTo("World");
+ assertThat(secondItem.getNumberConfig()).isNull();
+ assertThat(secondItem.getObjectConfig()).isNull();
+ assertThat(secondItem.getArrayConfig()).isNull();
+ }
+
+ @Data
+ static class YamlConfig {
+ private String stringConfig;
+ private Integer numberConfig;
+ private ObjectConfig objectConfig;
+ private List arrayConfig;
+ }
+
+ @Data
+ static class ObjectConfig {
+ private String attribut;
+ }
+}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/test/resources/yamlConfigMap.yaml b/modules/openapi-generator/src/test/resources/yamlConfigMap.yaml
new file mode 100644
index 0000000000000..47309d1973217
--- /dev/null
+++ b/modules/openapi-generator/src/test/resources/yamlConfigMap.yaml
@@ -0,0 +1,10 @@
+firstItem:
+ stringConfig: 'Hello'
+ numberConfig: 42
+ objectConfig:
+ attribut: 'openapi'
+ arrayConfig:
+ - 'one'
+ - 'two'
+secondItem:
+ stringConfig: 'World'
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 7bdf939e375ea..65aa5564bca4b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1246,6 +1246,7 @@
1.4
4.6.1
1.7.36
+ 2.3
3.1.12.2
io.swagger.parser.v3
2.1.22