-
-
Notifications
You must be signed in to change notification settings - Fork 7.7k
feature: [typescript-fetch] add model suffix support #24873
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| generatorName: typescript-fetch | ||
| outputDir: samples/client/petstore/typescript-fetch/builds/model-suffix | ||
| inputSpec: modules/openapi-generator/src/test/resources/3_0/typescript-fetch/oneOf.yaml | ||
| templateDir: modules/openapi-generator/src/main/resources/typescript-fetch | ||
| additionalProperties: | ||
| modelSuffix: Resource | ||
| npmName: '@openapitools/typescript-fetch-model-suffix' | ||
| npmVersion: 1.0.0 | ||
| snapshot: false |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,6 +58,8 @@ | |
| public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodegen { | ||
| private final Logger LOGGER = LoggerFactory.getLogger(TypeScriptFetchClientCodegen.class); | ||
|
|
||
| private static String CLASS_NAME_SUFFIX_PATTERN = "^[a-zA-Z0-9]*$"; | ||
|
|
||
| public static final String NPM_REPOSITORY = "npmRepository"; | ||
| public static final String WITH_INTERFACES = "withInterfaces"; | ||
| public static final String USE_SINGLE_REQUEST_PARAMETER = "useSingleRequestParameter"; | ||
|
|
@@ -71,6 +73,7 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege | |
| public static final String STRING_ENUMS_DESC = "Generate string enums instead of objects for enum values."; | ||
| public static final String IMPORT_FILE_EXTENSION_SWITCH = "importFileExtension"; | ||
| public static final String IMPORT_FILE_EXTENSION_SWITCH_DESC = "File extension to use with relative imports. Set it to '.js' or '.mjs' when using [ESM](https://nodejs.org/api/esm.html)."; | ||
| public static final String MODEL_SUFFIX = "modelSuffix"; | ||
| public static final String FILE_NAMING = "fileNaming"; | ||
| public static final String KEBAB_CASE = "kebab-case"; | ||
| public static final String CAMEL_CASE = "camelCase"; | ||
|
|
@@ -159,6 +162,7 @@ public TypeScriptFetchClientCodegen() { | |
| this.cliOptions.add(new CliOption(SAGAS_AND_RECORDS, "Setting this property to true will generate additional files for use with redux-saga and immutablejs.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); | ||
| this.cliOptions.add(new CliOption(STRING_ENUMS, STRING_ENUMS_DESC, SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); | ||
| this.cliOptions.add(new CliOption(IMPORT_FILE_EXTENSION_SWITCH, IMPORT_FILE_EXTENSION_SWITCH_DESC).defaultValue("")); | ||
| this.cliOptions.add(new CliOption(MODEL_SUFFIX, "The suffix of the generated model.")); | ||
| this.cliOptions.add(new CliOption(FILE_NAMING, "Naming convention for the output files: 'PascalCase', 'camelCase', 'kebab-case'.").defaultValue(this.fileNaming)); | ||
| this.cliOptions.add(new CliOption(USE_SQUARE_BRACKETS_IN_ARRAY_NAMES, "Setting this property to true will add brackets to array attribute names, e.g. my_values[].", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); | ||
| this.cliOptions.add(new CliOption(VALIDATION_ATTRIBUTES, "Setting this property to true will generate the validation attributes of model properties.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); | ||
|
|
@@ -230,6 +234,21 @@ public void setStringEnums(Boolean stringEnums) { | |
| this.stringEnums = stringEnums; | ||
| } | ||
|
|
||
| /** | ||
| * Validates that the given string value only contains alpha numeric characters. | ||
| * Throws an IllegalArgumentException, if the string contains any other characters. | ||
| * | ||
| * @param argument The name of the argument being validated. This is only used for displaying an error message. | ||
| * @param value The value that is being validated. | ||
| */ | ||
| private void validateClassSuffixArgument(String argument, String value) { | ||
| if (!value.matches(CLASS_NAME_SUFFIX_PATTERN)) { | ||
| throw new IllegalArgumentException( | ||
| String.format(Locale.ROOT, "%s class suffix only allows alphanumeric characters.", argument) | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Set the file naming type. | ||
| * | ||
|
|
@@ -335,6 +354,11 @@ public void processOpts() { | |
| additionalProperties.put("stringEnums", this.stringEnums); | ||
| } | ||
|
|
||
| if (additionalProperties.containsKey(MODEL_SUFFIX)) { | ||
| this.modelNameSuffix = additionalProperties.get(MODEL_SUFFIX).toString(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The new Prompt for AI agents |
||
| validateClassSuffixArgument("Model", modelNameSuffix); | ||
| } | ||
|
|
||
| if (additionalProperties.containsKey(FILE_NAMING)) { | ||
| this.setFileNaming(additionalProperties.get(FILE_NAMING).toString()); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,9 +6,6 @@ | |
| import io.swagger.v3.oas.models.media.MapSchema; | ||
| import io.swagger.v3.oas.models.media.Schema; | ||
| import io.swagger.v3.oas.models.media.StringSchema; | ||
| import java.util.Collections; | ||
| import java.util.Locale; | ||
| import java.util.stream.Stream; | ||
| import org.apache.commons.lang3.StringUtils; | ||
| import org.openapitools.codegen.*; | ||
| import org.openapitools.codegen.config.CodegenConfigurator; | ||
|
|
@@ -25,9 +22,8 @@ | |
| import java.nio.file.Files; | ||
| import java.nio.file.Path; | ||
| import java.nio.file.Paths; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.*; | ||
| import java.util.stream.Stream; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
|
|
||
|
|
@@ -561,6 +557,22 @@ public void containsESMTSConfigFileInCaseOfES6AndNPM() { | |
| assertThat(codegen.supportingFiles()).contains(new SupportingFile("tsconfig.esm.mustache", "", "tsconfig.esm.json")); | ||
| } | ||
|
|
||
| @Test(description = "Verify model suffix is added to model name and model filename") | ||
| public void testModelSuffixGeneration() throws IOException { | ||
| Map<String, Object> properties = new HashMap<>(); | ||
| properties.put(TypeScriptFetchClientCodegen.MODEL_SUFFIX, "Resource"); | ||
|
|
||
| File output = generate(properties, "src/test/resources/3_0/typescript-fetch/oneOf.yaml"); | ||
|
|
||
| Path modelWithSuffix = Paths.get(output + "/models/TestBResource.ts"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: The new suffix test only asserts the suffixed model files and their Prompt for AI agents |
||
| TestUtils.assertFileExists(modelWithSuffix); | ||
| TestUtils.assertFileContains(modelWithSuffix, "export interface TestBResource"); | ||
|
|
||
| Path discriminatorModelWithSuffix = Paths.get(output + "/models/TestDiscriminatorResponseResource.ts"); | ||
| TestUtils.assertFileExists(discriminatorModelWithSuffix); | ||
| TestUtils.assertFileContains(discriminatorModelWithSuffix, "export type TestDiscriminatorResponseResource"); | ||
| } | ||
|
|
||
| @Test(description = "Verify file name formatting from model name in PascalCase") | ||
| public void testModelFileNameInPascalCase() { | ||
| final TypeScriptFetchClientCodegen codegen = new TypeScriptFetchClientCodegen(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| wwwroot/*.js | ||
| node_modules | ||
| typings | ||
| dist |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| README.md |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # OpenAPI Generator Ignore | ||
| # Generated by openapi-generator https://github.com/openapitools/openapi-generator | ||
|
|
||
| # Use this file to prevent files from being overwritten by the generator. | ||
| # The patterns follow closely to .gitignore or .dockerignore. | ||
|
|
||
| # As an example, the C# client generator defines ApiClient.cs. | ||
| # You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: | ||
| #ApiClient.cs | ||
|
|
||
| # You can match any string of characters against a directory, file or extension with a single asterisk (*): | ||
| #foo/*/qux | ||
| # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux | ||
|
|
||
| # You can recursively match patterns against a directory, file or extension with a double asterisk (**): | ||
| #foo/**/qux | ||
| # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux | ||
|
|
||
| # You can also negate patterns with an exclamation (!). | ||
| # For example, you can ignore all files in a docs folder with the file extension .md: | ||
| #docs/*.md | ||
| # Then explicitly reverse the ignore rule for a single file: | ||
| #!docs/README.md |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| .gitignore | ||
| .npmignore | ||
| .openapi-generator-ignore | ||
| README.md | ||
| docs/DashedOptionOneResource.md | ||
| docs/DashedOptionTwoResource.md | ||
| docs/DefaultApi.md | ||
| docs/NumericSingletonEnumModelResource.md | ||
| docs/OptionOneResource.md | ||
| docs/OptionTwoResource.md | ||
| docs/SnakeOptionOneResource.md | ||
| docs/SnakeOptionTwoResource.md | ||
| docs/TestAResource.md | ||
| docs/TestArrayResponseResource.md | ||
| docs/TestBResource.md | ||
| docs/TestDashedDiscriminatorResponseResource.md | ||
| docs/TestDiscriminatorResponseResource.md | ||
| docs/TestResponseResource.md | ||
| docs/TestSnakeCaseDiscriminatorResponseResource.md | ||
| package.json | ||
| src/apis/DefaultApi.ts | ||
| src/apis/index.ts | ||
| src/index.ts | ||
| src/models/DashedOptionOneResource.ts | ||
| src/models/DashedOptionTwoResource.ts | ||
| src/models/NumericSingletonEnumModelResource.ts | ||
| src/models/OptionOneResource.ts | ||
| src/models/OptionTwoResource.ts | ||
| src/models/SnakeOptionOneResource.ts | ||
| src/models/SnakeOptionTwoResource.ts | ||
| src/models/TestAResource.ts | ||
| src/models/TestArrayResponseResource.ts | ||
| src/models/TestBResource.ts | ||
| src/models/TestDashedDiscriminatorResponseResource.ts | ||
| src/models/TestDiscriminatorResponseResource.ts | ||
| src/models/TestResponseResource.ts | ||
| src/models/TestSnakeCaseDiscriminatorResponseResource.ts | ||
| src/models/index.ts | ||
| src/runtime.ts | ||
| tsconfig.esm.json | ||
| tsconfig.json |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 7.26.0-SNAPSHOT |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| # @openapitools/typescript-fetch-model-suffix@1.0.0 | ||
|
|
||
| A TypeScript SDK client for the localhost API. | ||
|
|
||
| ## Usage | ||
|
|
||
| First, install the SDK from npm. | ||
|
|
||
| ```bash | ||
| npm install @openapitools/typescript-fetch-model-suffix --save | ||
| ``` | ||
|
|
||
| Next, try it out. | ||
|
|
||
|
|
||
| ```ts | ||
| import { | ||
| Configuration, | ||
| DefaultApi, | ||
| } from '@openapitools/typescript-fetch-model-suffix'; | ||
| import type { TestRequest } from '@openapitools/typescript-fetch-model-suffix'; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The README example imports Prompt for AI agents |
||
|
|
||
| async function example() { | ||
| console.log("🚀 Testing @openapitools/typescript-fetch-model-suffix SDK..."); | ||
| const api = new DefaultApi(); | ||
|
|
||
| try { | ||
| const data = await api.test(); | ||
| console.log(data); | ||
| } catch (error) { | ||
| console.error(error); | ||
| } | ||
| } | ||
|
|
||
| // Run the test | ||
| example().catch(console.error); | ||
| ``` | ||
|
|
||
|
|
||
| ## Documentation | ||
|
|
||
| ### API Endpoints | ||
|
|
||
| All URIs are relative to *http://localhost:3000* | ||
|
|
||
| | Class | Method | HTTP request | Description | ||
| | ----- | ------ | ------------ | ------------- | ||
| *DefaultApi* | [**test**](docs/DefaultApi.md#test) | **GET** /test | | ||
| *DefaultApi* | [**testArray**](docs/DefaultApi.md#testarray) | **GET** /test-array | | ||
| *DefaultApi* | [**testDashedDiscriminator**](docs/DefaultApi.md#testdasheddiscriminator) | **GET** /test-dashed-discriminator | | ||
| *DefaultApi* | [**testDiscriminator**](docs/DefaultApi.md#testdiscriminator) | **GET** /test-discriminator | | ||
| *DefaultApi* | [**testSnakeCaseDiscriminator**](docs/DefaultApi.md#testsnakecasediscriminator) | **GET** /test-snake-case-discriminator | | ||
|
|
||
|
|
||
| ### Models | ||
|
|
||
| - [DashedOptionOneResource](docs/DashedOptionOneResource.md) | ||
| - [DashedOptionTwoResource](docs/DashedOptionTwoResource.md) | ||
| - [NumericSingletonEnumModelResource](docs/NumericSingletonEnumModelResource.md) | ||
| - [OptionOneResource](docs/OptionOneResource.md) | ||
| - [OptionTwoResource](docs/OptionTwoResource.md) | ||
| - [SnakeOptionOneResource](docs/SnakeOptionOneResource.md) | ||
| - [SnakeOptionTwoResource](docs/SnakeOptionTwoResource.md) | ||
| - [TestAResource](docs/TestAResource.md) | ||
| - [TestArrayResponseResource](docs/TestArrayResponseResource.md) | ||
| - [TestBResource](docs/TestBResource.md) | ||
| - [TestDashedDiscriminatorResponseResource](docs/TestDashedDiscriminatorResponseResource.md) | ||
| - [TestDiscriminatorResponseResource](docs/TestDiscriminatorResponseResource.md) | ||
| - [TestResponseResource](docs/TestResponseResource.md) | ||
| - [TestSnakeCaseDiscriminatorResponseResource](docs/TestSnakeCaseDiscriminatorResponseResource.md) | ||
|
|
||
| ### Authorization | ||
|
|
||
| Endpoints do not require authorization. | ||
|
|
||
|
|
||
| ## About | ||
|
|
||
| This TypeScript SDK client supports the [Fetch API](https://fetch.spec.whatwg.org/) | ||
| and is automatically generated by the | ||
| [OpenAPI Generator](https://openapi-generator.tech) project: | ||
|
|
||
| - API version: `1.0.0` | ||
| - Package version: `1.0.0` | ||
| - Generator version: `7.26.0-SNAPSHOT` | ||
| - Build package: `org.openapitools.codegen.languages.TypeScriptFetchClientCodegen` | ||
|
|
||
| The generated npm module supports the following: | ||
|
|
||
| - Environments | ||
| * Node.js | ||
| * Webpack | ||
| * Browserify | ||
| - Language levels | ||
| * ES5 - you must have a Promises/A+ library installed | ||
| * ES6 | ||
| - Module systems | ||
| * CommonJS | ||
| * ES6 module system | ||
|
|
||
|
|
||
| ## Development | ||
|
|
||
| ### Building | ||
|
|
||
| To build the TypeScript source code, you need to have Node.js and npm installed. | ||
| After cloning the repository, navigate to the project directory and run: | ||
|
|
||
| ```bash | ||
| npm install | ||
| npm run build | ||
| ``` | ||
|
|
||
| ### Publishing | ||
|
|
||
| Once you've built the package, you can publish it to npm: | ||
|
|
||
| ```bash | ||
| npm publish | ||
| ``` | ||
|
|
||
| ## License | ||
|
|
||
| []() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
|
|
||
| # DashedOptionOneResource | ||
|
|
||
|
|
||
| ## Properties | ||
|
|
||
| Name | Type | ||
| ------------ | ------------- | ||
| `discriminatorField` | string | ||
| `someProperty` | string | ||
|
|
||
| ## Example | ||
|
|
||
| ```typescript | ||
| import type { DashedOptionOneResource } from '@openapitools/typescript-fetch-model-suffix' | ||
|
|
||
| // TODO: Update the object below with actual values | ||
| const example = { | ||
| "discriminatorField": null, | ||
| "someProperty": null, | ||
| } satisfies DashedOptionOneResource | ||
|
|
||
| console.log(example) | ||
|
|
||
| // Convert the instance to a JSON string | ||
| const exampleJSON: string = JSON.stringify(example) | ||
| console.log(exampleJSON) | ||
|
|
||
| // Parse the JSON string back to an object | ||
| const exampleParsed = JSON.parse(exampleJSON) as DashedOptionOneResource | ||
| console.log(exampleParsed) | ||
| ``` | ||
|
|
||
| [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
|
|
||
| # DashedOptionTwoResource | ||
|
|
||
|
|
||
| ## Properties | ||
|
|
||
| Name | Type | ||
| ------------ | ------------- | ||
| `discriminatorField` | string | ||
| `someProperty` | string | ||
|
|
||
| ## Example | ||
|
|
||
| ```typescript | ||
| import type { DashedOptionTwoResource } from '@openapitools/typescript-fetch-model-suffix' | ||
|
|
||
| // TODO: Update the object below with actual values | ||
| const example = { | ||
| "discriminatorField": null, | ||
| "someProperty": null, | ||
| } satisfies DashedOptionTwoResource | ||
|
|
||
| console.log(example) | ||
|
|
||
| // Convert the instance to a JSON string | ||
| const exampleJSON: string = JSON.stringify(example) | ||
| console.log(exampleJSON) | ||
|
|
||
| // Parse the JSON string back to an object | ||
| const exampleParsed = JSON.parse(exampleJSON) as DashedOptionTwoResource | ||
| console.log(exampleParsed) | ||
| ``` | ||
|
|
||
| [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) | ||
|
|
||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P3:
CLASS_NAME_SUFFIX_PATTERNis an immutable constant but is neitherstatic finalnorfinal, unlike the other compile-time constants in this class. Mark itprivate static final String.Prompt for AI agents