Skip to content

Commit 0995e59

Browse files
[typescript] COPY: Add optional erasable syntax configuration to Typescript generator. (#21560)
* Add optional erasable syntax configuration. * Changes from generation clean-up. --------- Co-authored-by: Brendan Burns <5751682+brendandburns@users.noreply.github.com>
1 parent 473343f commit 0995e59

File tree

63 files changed

+246
-160
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+246
-160
lines changed

docs/generators/typescript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
4242
|sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |true|
4343
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
4444
|supportsES6|Generate code that conforms to ES6.| |false|
45+
|useErasableSyntax|Use erasable syntax for the generated code. This is a temporary feature and will be removed in the future.| |false|
4546
|useInversify|Enable this to generate decorators and service identifiers for the InversifyJS inversion of control container. If you set 'deno' as 'platform', the generator will process this value as 'disable'.| |false|
4647
|useObjectParameters|Use aggregate parameter objects as function arguments for api operations instead of passing each parameter as a separate function argument.| |false|
4748
|useRxJS|Enable this to internally use rxjs observables. If disabled, a stub is used instead. This is required for the 'angular' framework.| |false|

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptClientCodegen.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ public class TypeScriptClientCodegen extends AbstractTypeScriptClientCodegen imp
7878
private static final String USE_OBJECT_PARAMS_SWITCH = "useObjectParameters";
7979
private static final String USE_OBJECT_PARAMS_DESC = "Use aggregate parameter objects as function arguments for api operations instead of passing each parameter as a separate function argument.";
8080

81+
public static final String USE_ERASABLE_SYNTAX = "useErasableSyntax";
82+
public static final String USE_ERASABLE_SYNTAX_DESC = "Use erasable syntax for the generated code. This is a temporary feature and will be removed in the future.";
83+
8184
private final Map<String, String> frameworkToHttpLibMap;
8285

8386
// NPM Options
@@ -122,6 +125,7 @@ public TypeScriptClientCodegen() {
122125
cliOptions.add(new CliOption(TypeScriptClientCodegen.USE_OBJECT_PARAMS_SWITCH, TypeScriptClientCodegen.USE_OBJECT_PARAMS_DESC).defaultValue("false"));
123126
cliOptions.add(new CliOption(TypeScriptClientCodegen.USE_INVERSIFY_SWITCH, TypeScriptClientCodegen.USE_INVERSIFY_SWITCH_DESC).defaultValue("false"));
124127
cliOptions.add(new CliOption(TypeScriptClientCodegen.IMPORT_FILE_EXTENSION_SWITCH, TypeScriptClientCodegen.IMPORT_FILE_EXTENSION_SWITCH_DESC));
128+
cliOptions.add(new CliOption(TypeScriptClientCodegen.USE_ERASABLE_SYNTAX, TypeScriptClientCodegen.USE_ERASABLE_SYNTAX_DESC).defaultValue("false"));
125129

126130
CliOption frameworkOption = new CliOption(TypeScriptClientCodegen.FRAMEWORK_SWITCH, TypeScriptClientCodegen.FRAMEWORK_SWITCH_DESC);
127131
for (String option : TypeScriptClientCodegen.FRAMEWORKS) {

modules/openapi-generator/src/main/resources/typescript-rxjs/servers.mustache

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,20 @@
55
*
66
*/
77
export class ServerConfiguration<T extends { [key: string]: string }> {
8+
{{^useErasableSyntax}}
89
public constructor(private url: string, private variableConfiguration: T, private description: string) {}
10+
{{/useErasableSyntax}}
11+
{{#useErasableSyntax}}
12+
private url: string;
13+
private variableConfiguration: T;
14+
private description: string;
15+
16+
public constructor(url: string, variableConfiguration: T, description: string) {
17+
this.url = url;
18+
this.variableConfiguration = variableConfiguration;
19+
this.description = description;
20+
}
21+
{{/useErasableSyntax}}
922

1023
/**
1124
* Sets the value of the variables of this server.
@@ -25,15 +38,15 @@ export class ServerConfiguration<T extends { [key: string]: string }> {
2538
}
2639

2740
/**
28-
* Constructions the URL this server using the url with variables
29-
* replaced with their respective values
41+
* Constructs the URL for this server using the url with variables
42+
* replaced with their respective values.
3043
*/
3144
public getUrl(): string {
3245
let replacedUrl = this.url;
3346
for (const key in this.variableConfiguration) {
3447
if (this.variableConfiguration.hasOwnProperty(key)) {
35-
const re = new RegExp("{" + key + "}","g");
36-
replacedUrl = replacedUrl.replace(re, this.variableConfiguration[key]);
48+
const re = new RegExp("{" + key + "}", "g");
49+
replacedUrl = replacedUrl.replace(re, this.variableConfiguration[key]);
3750
}
3851
}
3952
return replacedUrl;

modules/openapi-generator/src/main/resources/typescript/api/baseapi.mustache

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,16 @@ export const COLLECTION_FORMATS = {
2626
{{/useInversify}}
2727
export class BaseAPIRequestFactory {
2828
29+
{{^useErasableSyntax}}
2930
constructor({{#useInversify}}@inject(AbstractConfiguration) {{/useInversify}}protected configuration: Configuration) {
3031
}
32+
{{/useErasableSyntax}}
33+
{{#useErasableSyntax}}
34+
protected configuration: Configuration;
35+
constructor({{#useInversify}}@inject(AbstractConfiguration) {{/useInversify}} config: Configuration) {
36+
this.configuration = config;
37+
}
38+
{{/useErasableSyntax}}
3139
};
3240

3341
/**
@@ -38,7 +46,20 @@ export class BaseAPIRequestFactory {
3846
*/
3947
export class RequiredError extends Error {
4048
override name: "RequiredError" = "RequiredError";
49+
{{#useErasableSyntax}}
50+
public api: string;
51+
public method: string;
52+
public field: string;
53+
constructor(api: string, method: string, field: string) {
54+
super("Required parameter " + field + " was null or undefined when calling " + api + "." + method + ".");
55+
this.api = api;
56+
this.method = method;
57+
this.field = field;
58+
}
59+
{{/useErasableSyntax}}
60+
{{^useErasableSyntax}}
4161
constructor(public api: string, public method: string, public field: string) {
4262
super("Required parameter " + field + " was null or undefined when calling " + api + "." + method + ".");
4363
}
64+
{{/useErasableSyntax}}
4465
}

modules/openapi-generator/src/main/resources/typescript/api/exception.mustache

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,22 @@
88
*
99
*/
1010
export class ApiException<T> extends Error {
11+
{{#useErasableSyntax}}
12+
public code: number;
13+
public body: T;
14+
public headers: { [key: string]: string; };
15+
public constructor(code: number, message: string, body: T, headers: { [key: string]: string; }) {
16+
super("HTTP-Code: " + code + "\nMessage: " + message + "\nBody: " + JSON.stringify(body) + "\nHeaders: " +
17+
JSON.stringify(headers));
18+
this.code = code;
19+
this.body = body;
20+
this.headers = headers;
21+
}
22+
{{/useErasableSyntax}}
23+
{{^useErasableSyntax}}
1124
public constructor(public code: number, message: string, public body: T, public headers: { [key: string]: string; }) {
1225
super("HTTP-Code: " + code + "\nMessage: " + message + "\nBody: " + JSON.stringify(body) + "\nHeaders: " +
13-
JSON.stringify(headers))
26+
JSON.stringify(headers));
1427
}
15-
}
28+
{{/useErasableSyntax}}
29+
}

modules/openapi-generator/src/main/resources/typescript/api/middleware.mustache

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,15 @@ export interface Middleware {
2626
}
2727

2828
export class PromiseMiddlewareWrapper implements Middleware {
29-
30-
public constructor(private middleware: PromiseMiddleware) {
31-
29+
{{#useErasableSyntax}}
30+
private middleware: PromiseMiddleware;
31+
public constructor(middleware: PromiseMiddleware) {
32+
this.middleware = middleware;
3233
}
34+
{{/useErasableSyntax}}
35+
{{^useErasableSyntax}}
36+
public constructor(private middleware: PromiseMiddleware) {}
37+
{{/useErasableSyntax}}
3338

3439
pre(context: RequestContext): Observable<RequestContext> {
3540
return from(this.middleware.pre(context));
@@ -38,7 +43,6 @@ export class PromiseMiddlewareWrapper implements Middleware {
3843
post(context: ResponseContext): Observable<ResponseContext> {
3944
return from(this.middleware.post(context));
4045
}
41-
4246
}
4347

4448
/**

modules/openapi-generator/src/main/resources/typescript/auth/auth.mustache

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,28 @@ export interface TokenProvider {
4040
{{/useInversify}}
4141
export class {{#lambda.pascalcase}}{{name}}{{/lambda.pascalcase}}Authentication implements SecurityAuthentication {
4242
{{#isApiKey}}
43+
{{^useErasableSyntax}}
4344
/**
4445
* Configures this api key authentication with the necessary properties
4546
*
4647
* @param apiKey: The api key to be used for every request
4748
*/
4849
public constructor({{#useInversify}}@inject(AuthApiKey) @named("{{name}}") {{/useInversify}}private apiKey: string) {}
50+
{{/useErasableSyntax}}
51+
{{#useErasableSyntax}}
52+
private apiKey: string;
53+
/**
54+
* Configures this api key authentication with the necessary properties
55+
*
56+
* @param apiKey: The api key to be used for every request
57+
*/
58+
public constructor({{#useInversify}}@inject(AuthApiKey) @named("{{name}}") {{/useInversify}}apiKey: string) {
59+
this.apiKey = apiKey;
60+
}
61+
{{/useErasableSyntax}}
4962
{{/isApiKey}}
5063
{{#isBasicBasic}}
64+
{{^useErasableSyntax}}
5165
/**
5266
* Configures the http authentication with the required details.
5367
*
@@ -58,22 +72,66 @@ export class {{#lambda.pascalcase}}{{name}}{{/lambda.pascalcase}}Authentication
5872
{{#useInversify}}@inject(AuthUsername) @named("{{name}}") {{/useInversify}}private username: string,
5973
{{#useInversify}}@inject(AuthPassword) @named("{{name}}") {{/useInversify}}private password: string
6074
) {}
75+
{{/useErasableSyntax}}
76+
{{#useErasableSyntax}}
77+
private username: string;
78+
private password: string;
79+
/**
80+
* Configures the http authentication with the required details.
81+
*
82+
* @param username username for http basic authentication
83+
* @param password password for http basic authentication
84+
*/
85+
public constructor(
86+
{{#useInversify}}@inject(AuthUsername) @named("{{name}}") {{/useInversify}}username: string,
87+
{{#useInversify}}@inject(AuthPassword) @named("{{name}}") {{/useInversify}}password: string
88+
) {
89+
this.username = username;
90+
this.password = password;
91+
}
92+
{{/useErasableSyntax}}
6193
{{/isBasicBasic}}
6294
{{#isBasicBearer}}
95+
{{^useErasableSyntax}}
6396
/**
6497
* Configures the http authentication with the required details.
6598
*
6699
* @param tokenProvider service that can provide the up-to-date token when needed
67100
*/
68101
public constructor({{#useInversify}}@inject(AbstractTokenProvider) @named("{{name}}") {{/useInversify}}private tokenProvider: TokenProvider) {}
102+
{{/useErasableSyntax}}
103+
{{#useErasableSyntax}}
104+
private tokenProvider: TokenProvider;
105+
/**
106+
* Configures the http authentication with the required details.
107+
*
108+
* @param tokenProvider service that can provide the up-to-date token when needed
109+
*/
110+
public constructor({{#useInversify}}@inject(AbstractTokenProvider) @named("{{name}}") {{/useInversify}}tokenProvider: TokenProvider) {
111+
this.tokenProvider = tokenProvider;
112+
}
113+
{{/useErasableSyntax}}
69114
{{/isBasicBearer}}
70115
{{#isOAuth}}
116+
{{^useErasableSyntax}}
71117
/**
72118
* Configures OAuth2 with the necessary properties
73119
*
74120
* @param accessToken: The access token to be used for every request
75121
*/
76122
public constructor(private accessToken: string) {}
123+
{{/useErasableSyntax}}
124+
{{#useErasableSyntax}}
125+
private accessToken: string;
126+
/**
127+
* Configures OAuth2 with the necessary properties
128+
*
129+
* @param accessToken: The access token to be used for every request
130+
*/
131+
public constructor(accessToken: string) {
132+
this.accessToken = accessToken;
133+
}
134+
{{/useErasableSyntax}}
77135
{{/isOAuth}}
78136

79137
public getName(): string {
@@ -98,7 +156,6 @@ export class {{#lambda.pascalcase}}{{name}}{{/lambda.pascalcase}}Authentication
98156
}
99157

100158
{{/authMethods}}
101-
102159
export type AuthMethods = {
103160
{{^useInversify}}
104161
"default"?: SecurityAuthentication,

modules/openapi-generator/src/main/resources/typescript/http/http.mustache

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,22 @@ export * from './jquery{{importFileExtension}}';
2626
/**
2727
* Represents an HTTP method.
2828
*/
29+
{{#useErasableSyntax}}
30+
export const HttpMethod = {
31+
GET: "GET",
32+
HEAD: "HEAD",
33+
POST: "POST",
34+
PUT: "PUT",
35+
DELETE: "DELETE",
36+
CONNECT: "CONNECT",
37+
OPTIONS: "OPTIONS",
38+
TRACE: "TRACE",
39+
PATCH: "PATCH"
40+
} as const;
41+
42+
export type HttpMethod = typeof HttpMethod[keyof typeof HttpMethod];
43+
{{/useErasableSyntax}}
44+
{{^useErasableSyntax}}
2945
export enum HttpMethod {
3046
GET = "GET",
3147
HEAD = "HEAD",
@@ -37,6 +53,7 @@ export enum HttpMethod {
3753
TRACE = "TRACE",
3854
PATCH = "PATCH"
3955
}
56+
{{/useErasableSyntax}}
4057

4158
/**
4259
* Represents an HTTP file which will be transferred from or to a server.

modules/openapi-generator/src/main/resources/typescript/rxjsStub.mustache

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
export class Observable<T> {
2+
{{#useErasableSyntax}}
3+
private promise: Promise<T>;
4+
constructor(promise: Promise<T>) {
5+
this.promise = promise;
6+
}
7+
{{/useErasableSyntax}}
8+
{{^useErasableSyntax}}
29
constructor(private promise: Promise<T>) {}
10+
{{/useErasableSyntax}}
311

412
toPromise() {
513
return this.promise;

modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/TypeScriptClientCodegenTest.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.testng.annotations.Test;
1515

1616
import java.io.File;
17+
import java.io.IOException;
1718
import java.nio.file.Files;
1819
import java.nio.file.Path;
1920
import java.nio.file.Paths;
@@ -238,7 +239,6 @@ public void testDeprecatedOperation() throws Exception {
238239

239240
String content = Files.readString(file);
240241
assertEquals(1, TestUtils.countOccurrences(content, "@deprecated"));
241-
242242
}
243243

244244
@Test
@@ -265,6 +265,33 @@ public void testDeprecatedParameter() throws Exception {
265265

266266
String content = Files.readString(file);
267267
assertEquals(1, TestUtils.countOccurrences(content, "@deprecated"));
268+
}
269+
270+
@Test(description = "Verify useErasableSyntax config parameter generates erasable code")
271+
public void testUseErasableSyntaxConfig() throws IOException {
272+
boolean[] options = {true, false};
273+
for (boolean useErasableSyntax : options) {
274+
final File output = Files.createTempDirectory("typescriptnodeclient_").toFile();
275+
output.deleteOnExit();
276+
277+
final CodegenConfigurator configurator = new CodegenConfigurator()
278+
.setGeneratorName("typescript")
279+
.setInputSpec("src/test/resources/3_0/composed-schemas.yaml")
280+
.addAdditionalProperty("useErasableSyntax", useErasableSyntax)
281+
.setOutputDir(output.getAbsolutePath().replace("\\", "/"));
268282

283+
final ClientOptInput clientOptInput = configurator.toClientOptInput();
284+
final DefaultGenerator generator = new DefaultGenerator();
285+
final List<File> files = generator.opts(clientOptInput).generate();
286+
files.forEach(File::deleteOnExit);
287+
288+
Path serverConfigurationPath = Paths.get(output + "/apis/baseapi.ts");
289+
TestUtils.assertFileExists(serverConfigurationPath);
290+
if (useErasableSyntax) {
291+
TestUtils.assertFileContains(serverConfigurationPath, "this.configuration = config;"); // Check for erasable syntax
292+
} else {
293+
TestUtils.assertFileNotContains(serverConfigurationPath, "this.configuration = config;"); // Check for non-erasable syntax
294+
}
295+
}
269296
}
270297
}

0 commit comments

Comments
 (0)