diff --git a/.github/workflows/samples-typescript-nestjs-server.yaml b/.github/workflows/samples-typescript-nestjs-server.yaml
new file mode 100644
index 000000000000..375f230ff75b
--- /dev/null
+++ b/.github/workflows/samples-typescript-nestjs-server.yaml
@@ -0,0 +1,35 @@
+name: TypeScript NestJS Server
+
+on:
+ pull_request:
+ paths:
+ - samples/server/petstore/typescript-nestjs-server/**
+ - .github/workflows/samples-typescript-nestjs-server.yaml
+jobs:
+ build:
+ name: Test TypeScript NestJS Server
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sample:
+ # clients
+ - samples/server/petstore/typescript-nestjs-server
+ node-version:
+ - 20
+ - 22
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node-version }}
+
+ - name: Install
+ working-directory: ${{ matrix.sample }}
+ run: |
+ npm i
+
+ - name: Test
+ working-directory: ${{ matrix.sample }}
+ run: npm run test
diff --git a/CI/circle_parallel.sh b/CI/circle_parallel.sh
index f10d419eca04..6ab5ed3927c0 100755
--- a/CI/circle_parallel.sh
+++ b/CI/circle_parallel.sh
@@ -115,6 +115,7 @@ elif [ "$NODE_INDEX" = "3" ]; then
(cd samples/client/petstore/javascript-flowtyped && mvn integration-test)
(cd samples/client/petstore/javascript-es6 && mvn integration-test)
(cd samples/client/petstore/javascript-promise-es6 && mvn integration-test)
+ (cd samples/server/petstore/typescript-nestjs-server && mvn integration-test)
else
echo "Running node $NODE_INDEX ..."
diff --git a/bin/configs/typescript-nestjs-server.yaml b/bin/configs/typescript-nestjs-server.yaml
new file mode 100644
index 000000000000..97d228fa6461
--- /dev/null
+++ b/bin/configs/typescript-nestjs-server.yaml
@@ -0,0 +1,4 @@
+generatorName: typescript-nestjs-server
+outputDir: samples/server/petstore/typescript-nestjs-server/builds/default
+inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
+templateDir: modules/openapi-generator/src/main/resources/typescript-nestjs-server
diff --git a/docs/generators.md b/docs/generators.md
index 753014a50b94..009bb56b4bcd 100644
--- a/docs/generators.md
+++ b/docs/generators.md
@@ -152,6 +152,7 @@ The following generators are available:
* [scala-play-server](generators/scala-play-server.md)
* [scalatra](generators/scalatra.md)
* [spring](generators/spring.md)
+* [typescript-nestjs-server (beta)](generators/typescript-nestjs-server.md)
## DOCUMENTATION generators
diff --git a/docs/generators/typescript-nestjs-server.md b/docs/generators/typescript-nestjs-server.md
new file mode 100644
index 000000000000..3f15cd815bfe
--- /dev/null
+++ b/docs/generators/typescript-nestjs-server.md
@@ -0,0 +1,305 @@
+---
+title: Documentation for the typescript-nestjs-server Generator
+---
+
+## METADATA
+
+| Property | Value | Notes |
+| -------- | ----- | ----- |
+| generator name | typescript-nestjs-server | pass this to the generate command after -g |
+| generator stability | BETA | |
+| generator type | SERVER | |
+| generator language | Typescript | |
+| generator default templating engine | mustache | |
+| helpTxt | Generates a TypeScript NestJS server stub. | |
+
+## CONFIG OPTIONS
+These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
+
+| Option | Description | Values | Default |
+| ------ | ----------- | ------ | ------- |
+|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
+|apiFileSuffix|The suffix of the file of the generated API class (api<suffix>.ts).| |.api|
+|apiSuffix|The suffix of the generated API class| |Api|
+|disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|
- **false**
- The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.
- **true**
- Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.
|true|
+|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
+|enumNameSuffix|Suffix that will be appended to all enum names.| |Enum|
+|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |PascalCase|
+|enumPropertyNamingReplaceSpecialChar|Set to true to replace '-' and '+' symbols with 'minus_' and 'plus_' in enum of type string| |false|
+|enumUnknownDefaultCase|If the server adds new enum cases, that are unknown by an old spec/client, the client will fail to parse the network response.With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the server sends an enum case that is not known by the client/spec, they can safely fallback to this case.|- **false**
- No changes to the enum's are made, this is the default option.
- **true**
- With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the enum case sent by the server is not known by the client/spec, can safely be decoded to this case.
|false|
+|fileNaming|Naming convention for the output files: 'camelCase', 'kebab-case'.| |kebab-case|
+|legacyDiscriminatorBehavior|Set to false for generators with better support for discriminators. (Python, Java, Go, PowerShell, C# have this enabled by default).|- **true**
- The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.
- **false**
- The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.
|true|
+|licenseName|The name of the license| |Unlicense|
+|modelFileSuffix|The suffix of the file of the generated model (model<suffix>.ts).| |null|
+|modelPropertyNaming|Naming convention for the property: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name. Only change it if you provide your own run-time code for (de-)serialization of models| |original|
+|modelSuffix|The suffix of the generated model.| |null|
+|nestVersion|The version of Nestjs. (At least 10.0.0)| |10.0.0|
+|npmName|The name under which you want to publish generated npm package. Required to generate a full package| |null|
+|npmRepository|Use this property to set an url your private npmRepo in the package.json| |null|
+|npmVersion|The version of your npm package. If not provided, using the version from the OpenAPI specification file.| |1.0.0|
+|nullSafeAdditionalProps|Set to make additional properties types declare that their indexer may return undefined| |false|
+|paramNaming|Naming convention for parameters: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name| |camelCase|
+|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
+|rxjsVersion|The version of RxJS compatible with Angular (see ngVersion option).| |null|
+|snapshot|When setting this property to true, the version will be suffixed with -SNAPSHOT.yyyyMMddHHmm| |false|
+|sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |true|
+|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
+|stringEnums|Generate string enums instead of objects for enum values.| |false|
+|supportsES6|Generate code that conforms to ES6.| |false|
+|taggedUnions|Use discriminators to create tagged unions instead of extending interfaces.| |false|
+|tsVersion|The version of typescript compatible with Angular (see ngVersion option).| |null|
+|useSingleRequestParameter|Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter.| |false|
+
+## IMPORT MAPPING
+
+| Type/Alias | Imports |
+| ---------- | ------- |
+
+
+## INSTANTIATION TYPES
+
+| Type/Alias | Instantiated By |
+| ---------- | --------------- |
+|array|Array|
+
+
+## LANGUAGE PRIMITIVES
+
+
+- Array
+- Awaited
+- Blob
+- Boolean
+- Capitalize
+- ConstructorParameters
+- Date
+- Double
+- Error
+- Exclude
+- Extract
+- File
+- Float
+- InstanceType
+- Integer
+- Long
+- Lowercase
+- Map
+- NoInfer
+- NonNullable
+- Object
+- Omit
+- OmitThisParameter
+- Parameters
+- Partial
+- Pick
+- Readonly
+- ReadonlyArray
+- Record
+- Required
+- ReturnType
+- Set
+- String
+- ThisParameterType
+- ThisType
+- Uncapitalize
+- Uppercase
+- any
+- boolean
+- number
+- object
+- string
+
+
+## RESERVED WORDS
+
+
+- abstract
+- await
+- boolean
+- break
+- byte
+- case
+- catch
+- char
+- class
+- const
+- continue
+- debugger
+- default
+- delete
+- do
+- double
+- else
+- enum
+- export
+- extends
+- false
+- final
+- finally
+- float
+- for
+- formParams
+- from
+- function
+- goto
+- headerParams
+- headers
+- if
+- implements
+- import
+- in
+- instanceof
+- int
+- interface
+- let
+- long
+- native
+- new
+- null
+- package
+- private
+- protected
+- public
+- queryParameters
+- requestOptions
+- return
+- short
+- static
+- super
+- switch
+- synchronized
+- this
+- throw
+- transient
+- true
+- try
+- typeof
+- useFormData
+- var
+- varLocalDeferred
+- varLocalPath
+- void
+- volatile
+- while
+- with
+- yield
+
+
+## FEATURE SET
+
+
+### Client Modification Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|BasePath|✓|ToolingExtension
+|Authorizations|✗|ToolingExtension
+|UserAgent|✗|ToolingExtension
+|MockServer|✗|ToolingExtension
+
+### Data Type Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Custom|✗|OAS2,OAS3
+|Int32|✓|OAS2,OAS3
+|Int64|✓|OAS2,OAS3
+|Float|✓|OAS2,OAS3
+|Double|✓|OAS2,OAS3
+|Decimal|✓|ToolingExtension
+|String|✓|OAS2,OAS3
+|Byte|✓|OAS2,OAS3
+|Binary|✓|OAS2,OAS3
+|Boolean|✓|OAS2,OAS3
+|Date|✓|OAS2,OAS3
+|DateTime|✓|OAS2,OAS3
+|Password|✓|OAS2,OAS3
+|File|✓|OAS2
+|Uuid|✗|
+|Array|✓|OAS2,OAS3
+|Null|✗|OAS3
+|AnyType|✗|OAS2,OAS3
+|Object|✓|OAS2,OAS3
+|Maps|✓|ToolingExtension
+|CollectionFormat|✓|OAS2
+|CollectionFormatMulti|✓|OAS2
+|Enum|✓|OAS2,OAS3
+|ArrayOfEnum|✓|ToolingExtension
+|ArrayOfModel|✓|ToolingExtension
+|ArrayOfCollectionOfPrimitives|✓|ToolingExtension
+|ArrayOfCollectionOfModel|✓|ToolingExtension
+|ArrayOfCollectionOfEnum|✓|ToolingExtension
+|MapOfEnum|✓|ToolingExtension
+|MapOfModel|✓|ToolingExtension
+|MapOfCollectionOfPrimitives|✓|ToolingExtension
+|MapOfCollectionOfModel|✓|ToolingExtension
+|MapOfCollectionOfEnum|✓|ToolingExtension
+
+### Documentation Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Readme|✓|ToolingExtension
+|Model|✓|ToolingExtension
+|Api|✓|ToolingExtension
+
+### Global Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Host|✓|OAS2,OAS3
+|BasePath|✓|OAS2,OAS3
+|Info|✓|OAS2,OAS3
+|Schemes|✗|OAS2,OAS3
+|PartialSchemes|✓|OAS2,OAS3
+|Consumes|✓|OAS2
+|Produces|✓|OAS2
+|ExternalDocumentation|✓|OAS2,OAS3
+|Examples|✓|OAS2,OAS3
+|XMLStructureDefinitions|✗|OAS2,OAS3
+|MultiServer|✗|OAS3
+|ParameterizedServer|✗|OAS3
+|ParameterStyling|✗|OAS3
+|Callbacks|✗|OAS3
+|LinkObjects|✗|OAS3
+
+### Parameter Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Path|✓|OAS2,OAS3
+|Query|✓|OAS2,OAS3
+|Header|✓|OAS2,OAS3
+|Body|✓|OAS2
+|FormUnencoded|✓|OAS2
+|FormMultipart|✓|OAS2
+|Cookie|✓|OAS3
+
+### Schema Support Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|Simple|✓|OAS2,OAS3
+|Composite|✗|OAS2,OAS3
+|Polymorphism|✗|OAS2,OAS3
+|Union|✗|OAS3
+|allOf|✗|OAS2,OAS3
+|anyOf|✗|OAS3
+|oneOf|✓|OAS3
+|not|✗|OAS3
+
+### Security Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|BasicAuth|✓|OAS2,OAS3
+|ApiKey|✓|OAS2,OAS3
+|OpenIDConnect|✗|OAS3
+|BearerToken|✗|OAS3
+|OAuth2_Implicit|✓|OAS2,OAS3
+|OAuth2_Password|✗|OAS2,OAS3
+|OAuth2_ClientCredentials|✗|OAS2,OAS3
+|OAuth2_AuthorizationCode|✗|OAS2,OAS3
+|SignatureAuth|✗|OAS3
+|AWSV4Signature|✗|ToolingExtension
+
+### Wire Format Feature
+| Name | Supported | Defined By |
+| ---- | --------- | ---------- |
+|JSON|✓|OAS2,OAS3
+|XML|✓|OAS2,OAS3
+|PROTOBUF|✗|ToolingExtension
+|Custom|✗|OAS2,OAS3
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptNestjsServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptNestjsServerCodegen.java
new file mode 100644
index 000000000000..46c8b20a74b4
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptNestjsServerCodegen.java
@@ -0,0 +1,591 @@
+/*
+ * Copyright 2024 OpenAPI-Generator Contributors (https://openapi-generator.tech)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openapitools.codegen.languages;
+
+import io.swagger.v3.oas.models.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+import org.openapitools.codegen.*;
+import org.openapitools.codegen.meta.GeneratorMetadata;
+import org.openapitools.codegen.meta.Stability;
+import org.openapitools.codegen.meta.features.*;
+import org.openapitools.codegen.model.ModelMap;
+import org.openapitools.codegen.model.ModelsMap;
+import org.openapitools.codegen.model.OperationMap;
+import org.openapitools.codegen.model.OperationsMap;
+import org.openapitools.codegen.utils.ModelUtils;
+import org.openapitools.codegen.utils.SemVer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.*;
+
+import static org.apache.commons.lang3.StringUtils.capitalize;
+import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
+import static org.openapitools.codegen.utils.StringUtils.*;
+
+public class TypeScriptNestjsServerCodegen extends AbstractTypeScriptClientCodegen {
+ private final Logger LOGGER = LoggerFactory.getLogger(TypeScriptNestjsServerCodegen.class);
+
+ private static String CLASS_NAME_SUFFIX_PATTERN = "^[a-zA-Z0-9]*$";
+ private static String FILE_NAME_SUFFIX_PATTERN = "^[a-zA-Z0-9.-]*$";
+
+ public static final String NPM_REPOSITORY = "npmRepository";
+ public static final String TAGGED_UNIONS = "taggedUnions";
+ public static final String NEST_VERSION = "nestVersion";
+ public static final String API_SUFFIX = "apiSuffix";
+ public static final String API_FILE_SUFFIX = "apiFileSuffix";
+ public static final String MODEL_SUFFIX = "modelSuffix";
+ public static final String MODEL_FILE_SUFFIX = "modelFileSuffix";
+ public static final String FILE_NAMING = "fileNaming";
+ public static final String STRING_ENUMS = "stringEnums";
+ public static final String STRING_ENUMS_DESC = "Generate string enums instead of objects for enum values.";
+ public static final String USE_SINGLE_REQUEST_PARAMETER = "useSingleRequestParameter";
+ public static final String NODE_VERSION = "nodeVersion";
+ public static final String TS_VERSION = "tsVersion";
+ public static final String RXJS_VERSION = "rxjsVersion";
+
+ protected String nestVersion = "10.0.0";
+ @Getter
+ @Setter
+ protected String npmRepository = null;
+ protected String apiSuffix = "Api";
+ protected String apiFileSuffix = ".api";
+ protected String modelSuffix = "";
+ protected String modelFileSuffix = "";
+ protected String fileNaming = "kebab-case";
+ @Getter
+ protected Boolean stringEnums = false;
+
+ private boolean taggedUnions = false;
+
+ private String nodeVersion = "22.17.0";
+ private String rxJsVersion = "7.8.1";
+ private String tsVersion = "5.7.3";
+
+ public TypeScriptNestjsServerCodegen() {
+ super();
+
+ this.outputFolder = "generated-code/typescript-nestjs-server";
+
+ supportsMultipleInheritance = true;
+
+ modifyFeatureSet(features -> features
+ .schemaSupportFeatures(EnumSet.of(
+ SchemaSupportFeature.Simple,
+ SchemaSupportFeature.oneOf
+ ))
+ );
+
+ generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
+ .stability(Stability.BETA)
+ .build();
+
+ embeddedTemplateDir = templateDir = "typescript-nestjs-server";
+ modelTemplateFiles.put("model.mustache", ".ts");
+ apiTemplateFiles.put("controller.mustache", ".ts");
+ apiTemplateFiles.put("api.mustache", ".ts");
+ languageSpecificPrimitives.add("Blob");
+ typeMapping.put("file", "Blob");
+ apiPackage = "api";
+ modelPackage = "models";
+
+ reservedWords.addAll(Arrays.asList("from", "headers"));
+
+ this.cliOptions.add(new CliOption(NPM_REPOSITORY,
+ "Use this property to set an url your private npmRepo in the package.json"));
+ this.cliOptions.add(CliOption.newBoolean(TAGGED_UNIONS,
+ "Use discriminators to create tagged unions instead of extending interfaces.",
+ this.taggedUnions));
+ this.cliOptions.add(new CliOption(NEST_VERSION, "The version of Nestjs. (At least 10.0.0)").defaultValue(this.nestVersion));
+ this.cliOptions.add(new CliOption(API_SUFFIX, "The suffix of the generated API class").defaultValue(this.apiSuffix));
+ this.cliOptions.add(new CliOption(API_FILE_SUFFIX, "The suffix of the file of the generated API class (api.ts).").defaultValue(this.apiFileSuffix));
+ this.cliOptions.add(new CliOption(MODEL_SUFFIX, "The suffix of the generated model."));
+ this.cliOptions.add(new CliOption(MODEL_FILE_SUFFIX, "The suffix of the file of the generated model (model.ts)."));
+ this.cliOptions.add(new CliOption(FILE_NAMING, "Naming convention for the output files: 'camelCase', 'kebab-case'.").defaultValue(this.fileNaming));
+ this.cliOptions.add(new CliOption(STRING_ENUMS, STRING_ENUMS_DESC).defaultValue(String.valueOf(this.stringEnums)));
+ this.cliOptions.add(new CliOption(USE_SINGLE_REQUEST_PARAMETER, "Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter.").defaultValue(Boolean.FALSE.toString()));
+ this.cliOptions.add(new CliOption(TS_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)."));
+ }
+
+ @Override
+ protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Schema schema) {
+ codegenModel.additionalPropertiesType = getTypeDeclaration(ModelUtils.getAdditionalProperties(schema));
+ addImport(codegenModel, codegenModel.additionalPropertiesType);
+ }
+
+ @Override
+ public CodegenType getTag() {
+ return CodegenType.SERVER;
+ }
+
+ @Override
+ public String getName() {
+ return "typescript-nestjs-server";
+ }
+
+ @Override
+ public String getHelp() {
+ return "Generates a TypeScript NestJS server stub.";
+ }
+
+ @Override
+ public void processOpts() {
+ super.processOpts();
+ supportingFiles.add(new SupportingFile("module.mustache", "", "index.ts"));
+ supportingFiles.add(
+ new SupportingFile("models.mustache", modelPackage().replace('.', File.separatorChar), "index.ts"));
+ supportingFiles
+ .add(new SupportingFile("apis.mustache", apiPackage().replace('.', File.separatorChar), "index.ts"));
+ supportingFiles.add(new SupportingFile("api-implementations.mustache", "", "api-implementations.ts"));
+ supportingFiles.add(new SupportingFile("api.module.mustache", "", "api.module.ts"));
+ supportingFiles.add(new SupportingFile("controllers.mustache", "controllers", "index.ts"));
+ supportingFiles.add(new SupportingFile("gitignore", "", ".gitignore"));
+ supportingFiles.add(new SupportingFile("README.md", "", "README.md"));
+ supportingFiles.add(new SupportingFile("tsconfig.mustache", "", "tsconfig.json"));
+
+ // determine Nestjs version
+ SemVer nestVersion;
+ if (additionalProperties.containsKey(NEST_VERSION)) {
+ nestVersion = new SemVer(additionalProperties.get(NEST_VERSION).toString());
+ } else {
+ nestVersion = new SemVer(this.nestVersion);
+ LOGGER.info("generating code for Nestjs {} ...", nestVersion);
+ LOGGER.info(" (you can select the nestjs version by setting the additionalProperty nestVersion)");
+ }
+
+ additionalProperties.put(NEST_VERSION, nestVersion);
+
+ if (additionalProperties.containsKey(NPM_NAME)) {
+ if(!additionalProperties.containsKey(NPM_VERSION)) {
+ additionalProperties.put(NPM_VERSION, "0.0.0");
+ }
+
+ if (additionalProperties.containsKey(TS_VERSION)) {
+ tsVersion = additionalProperties.get(TS_VERSION).toString();
+ } else {
+ additionalProperties.put(TS_VERSION, tsVersion);
+ }
+
+ if (additionalProperties.containsKey(RXJS_VERSION)) {
+ rxJsVersion = additionalProperties.get(RXJS_VERSION).toString();
+ } else {
+ additionalProperties.put(RXJS_VERSION, rxJsVersion);
+ }
+
+ if (additionalProperties.containsKey(NODE_VERSION)) {
+ nodeVersion = additionalProperties.get(NODE_VERSION).toString();
+ } else {
+ additionalProperties.put(NODE_VERSION, nodeVersion);
+ }
+
+ addNpmPackageGeneration();
+ }
+
+ if (additionalProperties.containsKey(STRING_ENUMS)) {
+ setStringEnums(Boolean.parseBoolean(additionalProperties.get(STRING_ENUMS).toString()));
+ additionalProperties.put("stringEnums", getStringEnums());
+ if (getStringEnums()) {
+ enumSuffix = "";
+ classEnumSeparator = "";
+ }
+ }
+
+ if (additionalProperties.containsKey(TAGGED_UNIONS)) {
+ taggedUnions = Boolean.parseBoolean(additionalProperties.get(TAGGED_UNIONS).toString());
+ }
+
+
+ if (additionalProperties.containsKey(API_SUFFIX)) {
+ apiSuffix = additionalProperties.get(API_SUFFIX).toString();
+ validateClassSuffixArgument("Service", apiSuffix);
+ }
+ if (additionalProperties.containsKey(API_FILE_SUFFIX)) {
+ apiFileSuffix = additionalProperties.get(API_FILE_SUFFIX).toString();
+ validateFileSuffixArgument("Service", apiFileSuffix);
+ }
+ if (additionalProperties.containsKey(MODEL_SUFFIX)) {
+ modelSuffix = additionalProperties.get(MODEL_SUFFIX).toString();
+ validateClassSuffixArgument("Model", modelSuffix);
+ }
+ if (additionalProperties.containsKey(MODEL_FILE_SUFFIX)) {
+ modelFileSuffix = additionalProperties.get(MODEL_FILE_SUFFIX).toString();
+ validateFileSuffixArgument("Model", modelFileSuffix);
+ }
+ if (additionalProperties.containsKey(FILE_NAMING)) {
+ this.setFileNaming(additionalProperties.get(FILE_NAMING).toString());
+ }
+ }
+
+ private void addNpmPackageGeneration() {
+ supportingFiles.add(new SupportingFile("package.mustache", "", "package.json"));
+ supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
+ }
+
+ public void setStringEnums(boolean value) {
+ this.stringEnums = value;
+ }
+
+ @Override
+ public boolean isDataTypeFile(final String dataType) {
+ return "Blob".equals(dataType);
+ }
+
+ @Override
+ public String getTypeDeclaration(Schema p) {
+ if (ModelUtils.isFileSchema(p)) {
+ return "Blob";
+ } else {
+ return super.getTypeDeclaration(p);
+ }
+ }
+
+ @Override
+ public String getSchemaType(Schema p) {
+ String openAPIType = super.getSchemaType(p);
+ if (isLanguagePrimitive(openAPIType) || isLanguageGenericType(openAPIType)) {
+ return openAPIType;
+ }
+ applyLocalTypeMapping(openAPIType);
+ return openAPIType;
+ }
+
+ private String applyLocalTypeMapping(String type) {
+ if (typeMapping.containsKey(type)) {
+ type = typeMapping.get(type);
+ }
+ return type;
+ }
+
+ private boolean isLanguagePrimitive(String type) {
+ return languageSpecificPrimitives.contains(type);
+ }
+
+ private boolean isLanguageGenericType(String type) {
+ for (String genericType : languageGenericTypes) {
+ if (type.startsWith(genericType + "<")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isRecordType(String type) {
+ return type.contains("[key:") || type.startsWith("Record<");
+ }
+
+ @Override
+ public void postProcessParameter(CodegenParameter parameter) {
+ super.postProcessParameter(parameter);
+ parameter.dataType = applyLocalTypeMapping(parameter.dataType);
+ }
+
+ @Override
+ public OperationsMap postProcessOperationsWithModels(OperationsMap operations, List allModels) {
+ OperationMap objectMap = operations.getOperations();
+ List operationList = objectMap.getOperation();
+
+ for (CodegenOperation operation : operationList) {
+ operation.path = operation.path.replaceAll("\\{([^}]+)}", ":$1");
+ operation.httpMethod = camelize(operation.httpMethod.toLowerCase(Locale.ROOT));
+
+ List params = operation.allParams;
+ if (params != null && params.isEmpty()) {
+ operation.allParams = null;
+ }
+ List responses = operation.responses;
+ if (responses != null) {
+ for (CodegenResponse resp : responses) {
+ if ("0".equals(resp.code)) {
+ resp.code = "default";
+ }
+ }
+ }
+ if (operation.examples != null && !operation.examples.isEmpty()) {
+ // Leave application/json* items only
+ for (Iterator