@goast/typescript 0.5.3 → 0.6.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/LICENSE +21 -21
  2. package/esm/src/file-builder.d.ts.map +1 -1
  3. package/esm/src/file-builder.js +2 -5
  4. package/esm/src/generators/models/model-generator.d.ts.map +1 -1
  5. package/esm/src/generators/models/model-generator.js +6 -2
  6. package/esm/src/generators/services/k6-clients/k6-client-generator.d.ts.map +1 -1
  7. package/esm/src/generators/services/k6-clients/k6-client-generator.js +2 -1
  8. package/package.json +3 -3
  9. package/script/src/file-builder.d.ts.map +1 -1
  10. package/script/src/file-builder.js +1 -5
  11. package/script/src/generators/models/model-generator.d.ts.map +1 -1
  12. package/script/src/generators/models/model-generator.js +5 -1
  13. package/script/src/generators/services/k6-clients/k6-client-generator.d.ts.map +1 -1
  14. package/script/src/generators/services/k6-clients/k6-client-generator.js +2 -1
  15. package/src/mod.ts +0 -7
  16. package/src/src/assets.ts +0 -9
  17. package/src/src/ast/_index.ts +0 -54
  18. package/src/src/ast/common.ts +0 -1
  19. package/src/src/ast/index.ts +0 -1
  20. package/src/src/ast/node.ts +0 -10
  21. package/src/src/ast/nodes/argument.ts +0 -40
  22. package/src/src/ast/nodes/array-type.ts +0 -49
  23. package/src/src/ast/nodes/arrow-function.ts +0 -91
  24. package/src/src/ast/nodes/call.ts +0 -55
  25. package/src/src/ast/nodes/class.ts +0 -133
  26. package/src/src/ast/nodes/constructor-parameter.ts +0 -70
  27. package/src/src/ast/nodes/constructor.ts +0 -77
  28. package/src/src/ast/nodes/decorator.ts +0 -76
  29. package/src/src/ast/nodes/doc-tag.ts +0 -291
  30. package/src/src/ast/nodes/doc.ts +0 -102
  31. package/src/src/ast/nodes/enum-value.ts +0 -72
  32. package/src/src/ast/nodes/enum.ts +0 -77
  33. package/src/src/ast/nodes/export.ts +0 -54
  34. package/src/src/ast/nodes/function-type.ts +0 -60
  35. package/src/src/ast/nodes/function.ts +0 -107
  36. package/src/src/ast/nodes/generic-parameter.ts +0 -71
  37. package/src/src/ast/nodes/indexer.ts +0 -60
  38. package/src/src/ast/nodes/interface.ts +0 -117
  39. package/src/src/ast/nodes/intersection-type.ts +0 -67
  40. package/src/src/ast/nodes/lookup-type.ts +0 -53
  41. package/src/src/ast/nodes/method.ts +0 -138
  42. package/src/src/ast/nodes/object-type.ts +0 -52
  43. package/src/src/ast/nodes/object.ts +0 -48
  44. package/src/src/ast/nodes/parameter.ts +0 -85
  45. package/src/src/ast/nodes/property-accessor.ts +0 -173
  46. package/src/src/ast/nodes/property.ts +0 -192
  47. package/src/src/ast/nodes/reference.ts +0 -194
  48. package/src/src/ast/nodes/string.ts +0 -49
  49. package/src/src/ast/nodes/tuple.ts +0 -53
  50. package/src/src/ast/nodes/type-alias.ts +0 -75
  51. package/src/src/ast/nodes/typeof.ts +0 -42
  52. package/src/src/ast/nodes/types.ts +0 -40
  53. package/src/src/ast/nodes/union-type.ts +0 -62
  54. package/src/src/ast/nodes/variable.ts +0 -73
  55. package/src/src/ast/references/angular.ts +0 -24
  56. package/src/src/ast/references/easy-network-stub.ts +0 -21
  57. package/src/src/ast/references/index.ts +0 -5
  58. package/src/src/ast/references/k6.ts +0 -8
  59. package/src/src/ast/references/rxjs.ts +0 -7
  60. package/src/src/ast/references/typescript.ts +0 -35
  61. package/src/src/ast/utils/get-type-script-builder-options.ts +0 -19
  62. package/src/src/ast/utils/to-ts-node.ts +0 -27
  63. package/src/src/ast/utils/write-ts-generic-parameters.ts +0 -25
  64. package/src/src/ast/utils/write-ts-members.ts +0 -28
  65. package/src/src/ast/utils/write-ts-nodes.ts +0 -35
  66. package/src/src/ast/utils/write-ts-parameters.ts +0 -25
  67. package/src/src/common-results.ts +0 -26
  68. package/src/src/config.ts +0 -89
  69. package/src/src/file-builder.ts +0 -136
  70. package/src/src/generators/file-generator.ts +0 -15
  71. package/src/src/generators/index.ts +0 -6
  72. package/src/src/generators/models/index.ts +0 -3
  73. package/src/src/generators/models/model-generator.ts +0 -469
  74. package/src/src/generators/models/models-generator.ts +0 -108
  75. package/src/src/generators/models/models.ts +0 -121
  76. package/src/src/generators/services/angular-services/angular-service-generator.ts +0 -406
  77. package/src/src/generators/services/angular-services/angular-services-generator.ts +0 -295
  78. package/src/src/generators/services/angular-services/index.ts +0 -3
  79. package/src/src/generators/services/angular-services/models.ts +0 -277
  80. package/src/src/generators/services/angular-services/refs.ts +0 -54
  81. package/src/src/generators/services/easy-network-stub/easy-network-stub-generator.ts +0 -242
  82. package/src/src/generators/services/easy-network-stub/easy-network-stubs-generator.ts +0 -211
  83. package/src/src/generators/services/easy-network-stub/index.ts +0 -3
  84. package/src/src/generators/services/easy-network-stub/models.ts +0 -124
  85. package/src/src/generators/services/easy-network-stub/refs.ts +0 -45
  86. package/src/src/generators/services/fetch-clients/fetch-client-generator.ts +0 -275
  87. package/src/src/generators/services/fetch-clients/fetch-clients-generator.ts +0 -163
  88. package/src/src/generators/services/fetch-clients/index.ts +0 -3
  89. package/src/src/generators/services/fetch-clients/models.ts +0 -130
  90. package/src/src/generators/services/fetch-clients/refs.ts +0 -21
  91. package/src/src/generators/services/k6-clients/index.ts +0 -3
  92. package/src/src/generators/services/k6-clients/k6-client-generator.ts +0 -465
  93. package/src/src/generators/services/k6-clients/k6-clients-generator.ts +0 -171
  94. package/src/src/generators/services/k6-clients/models.ts +0 -247
  95. package/src/src/generators/services/k6-clients/refs.ts +0 -16
  96. package/src/src/import-collection.ts +0 -236
  97. package/src/src/utils.ts +0 -72
@@ -1,406 +0,0 @@
1
- import { resolve } from 'node:path';
2
-
3
- import {
4
- type ApiEndpoint,
5
- type ApiResponse,
6
- type ApiSchema,
7
- type AppendValueGroup,
8
- appendValueGroup,
9
- builderTemplate as s,
10
- type MaybePromise,
11
- type Nullable,
12
- toCasing,
13
- } from '@goast/core';
14
-
15
- import { ts } from '../../../ast/index.js';
16
- import type { TypeScriptExportOutput } from '../../../common-results.js';
17
- import { TypeScriptFileBuilder } from '../../../file-builder.js';
18
- import { TypeScriptFileGenerator } from '../../file-generator.js';
19
- import type { TypeScriptAngularServiceGeneratorContext, TypeScriptAngularServiceGeneratorOutput } from './models.js';
20
-
21
- type Context = TypeScriptAngularServiceGeneratorContext;
22
- type Output = TypeScriptAngularServiceGeneratorOutput;
23
- type Builder = TypeScriptFileBuilder;
24
-
25
- export interface TypeScriptAngularServiceGenerator<TOutput extends Output = Output> {
26
- generate(ctx: Context): MaybePromise<TOutput>;
27
- }
28
-
29
- export class DefaultTypeScriptAngularServiceGenerator extends TypeScriptFileGenerator<Context, Output>
30
- implements TypeScriptAngularServiceGenerator {
31
- public generate(ctx: Context): MaybePromise<Output> {
32
- const responseModels = this.generateResponseModels(ctx);
33
-
34
- const filePath = this.getServiceFilePath(ctx);
35
- const name = this.getServiceClassName(ctx);
36
-
37
- TypeScriptFileBuilder.generate({
38
- logName: `service ${name}`,
39
- filePath,
40
- options: ctx.config,
41
- generator: (b) => b.append(this.getServiceFileContent(ctx)),
42
- });
43
-
44
- return {
45
- filePath,
46
- component: name,
47
- responseModels,
48
- };
49
- }
50
-
51
- // #region Response Model
52
- protected generateResponseModels(ctx: Context): Record<string, TypeScriptExportOutput> {
53
- const result: Record<string, TypeScriptExportOutput> = {};
54
- const filePath = this.getResponseModelFilePath(ctx);
55
- const builder = new TypeScriptFileBuilder(filePath, ctx.config);
56
-
57
- for (const endpoint of ctx.service.endpoints) {
58
- const name = this.getResponseModelName(ctx, endpoint);
59
- builder.appendLine(this.getResponseModelFileContent(ctx, endpoint));
60
- result[endpoint.id] = { component: name, filePath };
61
- }
62
-
63
- builder.writeToFile();
64
- return result;
65
- }
66
-
67
- protected getResponseModelFileContent(ctx: Context, endpoint: ApiEndpoint): AppendValueGroup<Builder> {
68
- const result = appendValueGroup<Builder>([]);
69
- const statusCodes = this.getEndpointStatusCodes(ctx, endpoint);
70
- let statusCodeType: ts.Reference<Builder>;
71
-
72
- const statusCodesTypeName = toCasing(`${endpoint.name}_StatusCodes`, ctx.config.typeNameCasing);
73
- result.values.push(ts.typeAlias(statusCodesTypeName, ts.unionType(Object.keys(statusCodes))));
74
- if (ctx.config.strictResponseTypes) {
75
- statusCodeType = ts.reference(statusCodesTypeName);
76
- } else {
77
- statusCodeType = ctx.refs.httpStatusCode();
78
- }
79
-
80
- result.values.push(
81
- ts.typeAlias(
82
- this.getResponseModelName(ctx, endpoint),
83
- ts.intersectionType([
84
- ts.unionType([
85
- ...Object.entries(statusCodes).map(([key, value]) => {
86
- const isSuccess = key.startsWith('2');
87
- return ts.intersectionType<Builder>([
88
- isSuccess
89
- ? ts.refs.angular.httpResponse([value.type])
90
- : ts.refs.omit([ts.refs.angular.httpErrorResponse(), ts.string('error')]),
91
- ts.objectType({
92
- members: [
93
- isSuccess ? null : ts.property('error', { type: ts.unionType([value.type, ts.refs.null_()]) }),
94
- ts.property('status', { type: key }),
95
- ts.property('ok', { type: isSuccess ? 'true' : 'false' }),
96
- ],
97
- }),
98
- ]);
99
- }),
100
- !ctx.config.strictResponseTypes
101
- ? ts.intersectionType([
102
- ts.refs.angular.httpResponse([this.getAnyType(ctx)]),
103
- ts.objectType({
104
- members: [
105
- ts.property('status', {
106
- type: ts.refs.exclude([ctx.refs.httpStatusCode(), ts.reference(statusCodesTypeName)]),
107
- }),
108
- ],
109
- }),
110
- ])
111
- : null,
112
- ]),
113
- ts.objectType({ members: [ts.property('status', { type: 'TStatus' })] }),
114
- ]),
115
- {
116
- doc: ts.doc({
117
- description: `Response model for operation ${this.getEndpointMethodName(ctx, endpoint)}`,
118
- tags: [endpoint.deprecated ? ts.docTag('deprecated') : null],
119
- }),
120
- export: true,
121
- generics: [
122
- ts.genericParameter('TStatus', {
123
- constraint: statusCodeType,
124
- default: statusCodeType,
125
- }),
126
- ],
127
- },
128
- ),
129
- );
130
-
131
- return result;
132
- }
133
-
134
- protected getEndpointStatusCodes(
135
- ctx: Context,
136
- endpoint: ApiEndpoint,
137
- ): Record<number, { parser: 'text' | 'json'; type: ts.Type<Builder> }> {
138
- return Object.fromEntries([
139
- ...Object.entries(ctx.config.defaultStatusCodeResponseTypes).map(([key, value]) => [
140
- key,
141
- {
142
- parser: value?.parser ?? 'text',
143
- type: typeof value?.type === 'function'
144
- ? this.getSchemaType(ctx, value.type(ctx.data.schemas))
145
- : value ?? this.getAnyType(ctx),
146
- },
147
- ]),
148
- ...endpoint.responses
149
- .filter((x) => x.statusCode)
150
- .map((x) => [
151
- x.statusCode,
152
- {
153
- parser: this.contentTypeToResponseType(x.contentOptions[0]?.type),
154
- type: this.getSchemaType(ctx, x.contentOptions[0]?.schema, this.getAnyType(ctx)),
155
- },
156
- ]),
157
- ]);
158
- }
159
- // #endregion
160
-
161
- protected getServiceFileContent(ctx: Context): AppendValueGroup<Builder> {
162
- const code = appendValueGroup<Builder>([], '\n');
163
- for (const endpoint of ctx.service.endpoints) {
164
- if (endpoint.parameters.length > 0 || endpoint.requestBody !== undefined) {
165
- code.values.push(this.getEndpointParamsType(ctx, endpoint));
166
- }
167
- }
168
- code.values.push(this.getClass(ctx));
169
- return code;
170
- }
171
-
172
- protected getEndpointParamsType(ctx: Context, endpoint: ApiEndpoint): ts.TypeAlias<Builder> {
173
- const type = ts.objectType<Builder>();
174
-
175
- for (const parameter of endpoint.parameters) {
176
- const schema = parameter.schema;
177
- type.members.push(
178
- ts.property(toCasing(parameter.name, ctx.config.propertyNameCasing), {
179
- doc: ts.doc({
180
- description: parameter.description,
181
- tags: [parameter.deprecated ? ts.docTag('deprecated') : null],
182
- }),
183
- type: schema ? (b) => b.appendModelUsage(ctx.input.typescript.models[schema.id]) : this.getAnyType(ctx),
184
- optional: !parameter.required,
185
- }),
186
- );
187
- }
188
-
189
- if (endpoint.requestBody !== undefined) {
190
- const body = endpoint.requestBody;
191
- const schema = body.content[0].schema;
192
- type.members.push(
193
- ts.property('body', {
194
- doc: ts.doc({ description: body.description }),
195
- type: schema ? (b) => b.appendModelUsage(ctx.input.typescript.models[schema.id]) : this.getAnyType(ctx),
196
- optional: !body.required,
197
- }),
198
- );
199
- }
200
-
201
- return ts.typeAlias(this.getEndpointParamsTypeName(ctx, endpoint), type, {
202
- doc: ts.doc({ description: `Parameters for operation ${this.getEndpointMethodName(ctx, endpoint)}` }),
203
- });
204
- }
205
-
206
- protected getClass(ctx: Context): ts.Class<Builder> {
207
- return ts.class<Builder>(this.getServiceClassName(ctx), {
208
- doc: ts.doc({
209
- description: ctx.service.description,
210
- tags: [
211
- ctx.service.endpoints.length === 0 || ctx.service.endpoints.some((x) => !x.deprecated)
212
- ? null
213
- : ts.docTag('deprecated'),
214
- ],
215
- }),
216
- decorators: [
217
- ts.decorator(
218
- ts.refs.angular.injectable(),
219
- ctx.config.provideKind === 'root' ? [ts.toNode({ providedIn: 'root' })] : [],
220
- ),
221
- ],
222
- export: true,
223
- extends: ctx.refs.apiBaseService(),
224
- members: [
225
- ...ctx.service.endpoints.map((e) =>
226
- ts.property(this.getEndpointPathPropertyName(ctx, e), {
227
- accessModifier: 'private',
228
- static: true,
229
- readonly: true,
230
- value: ts.string(e.path),
231
- })
232
- ),
233
- ...ctx.service.endpoints.map((e) => this.getEndpointMethod(ctx, e)),
234
- ],
235
- });
236
- }
237
-
238
- protected getEndpointMethod(ctx: Context, endpoint: ApiEndpoint): ts.Method<Builder> {
239
- const hasParams = this.hasEndpointParams(ctx, endpoint);
240
- const paramsOptional = !endpoint.parameters.some((p) => p.required) && !endpoint.requestBody?.required;
241
- const responseModelType = ts.reference(
242
- this.getResponseModelName(ctx, endpoint),
243
- this.getResponseModelFilePath(ctx),
244
- {
245
- importType: 'type-import',
246
- },
247
- );
248
- const returnType = ctx.refs.abortablePromise([responseModelType]);
249
- const accept = this.getEndpointSuccessResponseType(ctx, endpoint);
250
- const responseType = this.contentTypeToResponseType(accept);
251
- return ts.method<Builder>(this.getEndpointMethodName(ctx, endpoint), {
252
- accessModifier: 'public',
253
- parameters: [
254
- hasParams
255
- ? ts.parameter('params', {
256
- optional: paramsOptional,
257
- type: ts.reference(this.getEndpointParamsTypeName(ctx, endpoint)),
258
- })
259
- : null,
260
- ts.parameter('context', { optional: true, type: ts.refs.angular.httpContext() }),
261
- ],
262
- doc: ts.doc({
263
- description: endpoint.description,
264
- tags: [endpoint.deprecated ? ts.docTag('deprecated') : null],
265
- }),
266
- returnType,
267
- body: appendValueGroup(
268
- [
269
- s`const rb = new ${ctx.refs.requestBuilder()}(this.rootUrl, ${
270
- this.getServiceClassName(
271
- ctx,
272
- )
273
- }.${this.getEndpointPathPropertyName(ctx, endpoint)}, '${endpoint.method}');`,
274
- hasParams
275
- ? (b) =>
276
- b.appendIf(paramsOptional, 'if (params) ').parenthesizeIf(
277
- paramsOptional,
278
- '{}',
279
- appendValueGroup(
280
- [
281
- ...endpoint.parameters
282
- .filter((p) => p.target === 'path' || p.target === 'query' || p.target === 'header')
283
- .map((p) => {
284
- const options = ts.object({
285
- members: [
286
- p.style !== undefined ? ts.property('style', { value: ts.string(p.style) }) : null,
287
- p.explode !== undefined ? ts.property('explode', { value: ts.toNode(p.explode) }) : null,
288
- ],
289
- });
290
- return s<Builder>`rb.${p.target}(${ts.string(p.name)}, params.${
291
- toCasing(
292
- p.name,
293
- ctx.config.propertyNameCasing,
294
- )
295
- }, ${options});`;
296
- }),
297
- endpoint.requestBody
298
- ? s`rb.body(params.body, ${ts.string(this.getEndpointRequestContentType(ctx, endpoint))});`
299
- : null,
300
- ],
301
- '\n',
302
- ),
303
- { multiline: true },
304
- )
305
- : null,
306
- '',
307
- s`return ${ctx.refs.waitForResponse([responseModelType])}(${s.indent`
308
- this.http.request(rb.build({${s.indent`
309
- responseType: ${ts.string(responseType)},
310
- accept: ${ts.string(accept)},
311
- context,`}
312
- })),
313
- {${s.indent`
314
- errorResponseTypes: ${
315
- ts.object({
316
- members: [
317
- ...Object.entries(this.getEndpointStatusCodes(ctx, endpoint))
318
- .filter(([key]) => !key.startsWith('2'))
319
- .map(([key, value]) => {
320
- return ts.property(key, { value: ts.string(value.parser) });
321
- }),
322
- ],
323
- })
324
- }`}
325
- }`}
326
- )`,
327
- ],
328
- '\n',
329
- ),
330
- });
331
- }
332
-
333
- protected getEndpointRequestContentType(ctx: Context, endpoint: ApiEndpoint): string {
334
- return ctx.config.defaultRequestContentType ?? endpoint?.requestBody?.content[0].type ?? 'application/json';
335
- }
336
-
337
- protected getEndpointSuccessResponseType(ctx: Context, endpoint: ApiEndpoint): string {
338
- const response = this.getEndpointSuccessResponse(ctx, endpoint);
339
- if (!response) return '*/*';
340
-
341
- if (!ctx.config.defaultSuccessResponseContentType) return response.contentOptions[0]?.type ?? '*/*';
342
-
343
- return (
344
- response.contentOptions.find((x) => x.type === ctx.config.defaultSuccessResponseContentType)?.type ??
345
- response.contentOptions[0]?.type ??
346
- '*/*'
347
- );
348
- }
349
-
350
- protected getEndpointSuccessResponse(_ctx: Context, endpoint: ApiEndpoint): ApiResponse | undefined {
351
- return (
352
- endpoint.responses.find((x) => x.statusCode && x.statusCode >= 200 && x.statusCode < 300) ??
353
- endpoint.responses.find((x) => x.statusCode === undefined)
354
- );
355
- }
356
-
357
- protected getServiceClassName(ctx: Context): string {
358
- return toCasing(ctx.service.name + '_Service', ctx.config.typeNameCasing);
359
- }
360
-
361
- protected getResponseModelName(ctx: Context, endpoint: ApiEndpoint): string {
362
- return toCasing(`${this.getEndpointMethodName(ctx, endpoint)}ApiResponse`, ctx.config.typeNameCasing);
363
- }
364
-
365
- protected getEndpointParamsTypeName(ctx: Context, endpoint: ApiEndpoint): string {
366
- return toCasing(this.getEndpointMethodName(ctx, endpoint) + '_Params', ctx.config.typeNameCasing);
367
- }
368
-
369
- protected getEndpointPathPropertyName(ctx: Context, endpoint: ApiEndpoint): string {
370
- return toCasing(this.getEndpointMethodName(ctx, endpoint) + '_Path', ctx.config.constantNameCasing);
371
- }
372
-
373
- protected getEndpointMethodName(ctx: Context, endpoint: ApiEndpoint): string {
374
- return toCasing(endpoint.name, ctx.config.functionNameCasing);
375
- }
376
-
377
- protected getServiceFilePath(ctx: Context): string {
378
- return resolve(
379
- ctx.config.outputDir,
380
- ctx.config.servicesDir,
381
- `${toCasing(ctx.service.name, ctx.config.serviceFileNameCasing ?? ctx.config.fileNameCasing)}.ts`,
382
- );
383
- }
384
-
385
- protected getResponseModelFilePath(ctx: Context): string {
386
- return resolve(
387
- ctx.config.outputDir,
388
- ctx.config.responseModelsDir,
389
- `${toCasing(ctx.service.name, ctx.config.responseModelFileNameCasing ?? ctx.config.fileNameCasing)}.ts`,
390
- );
391
- }
392
-
393
- protected hasEndpointParams(_ctx: Context, endpoint: ApiEndpoint): boolean {
394
- return endpoint.parameters.length > 0 || endpoint.requestBody !== undefined;
395
- }
396
-
397
- protected getSchemaType(ctx: Context, schema: ApiSchema | undefined, fallback?: ts.Type<Builder>): ts.Type<Builder> {
398
- const output = schema && ctx.input.typescript.models[schema.id];
399
- if (!output) return fallback ?? this.getAnyType(ctx);
400
- return (b) => b.appendModelUsage(output);
401
- }
402
-
403
- private contentTypeToResponseType(contentType: Nullable<string>): 'text' | 'json' {
404
- return contentType?.includes('json') ? 'json' : 'text';
405
- }
406
- }
@@ -1,295 +0,0 @@
1
- import { resolve } from 'node:path';
2
-
3
-
4
- import fs from 'fs-extra';
5
-
6
- import {
7
- type ApiService,
8
- type AppendValueGroup,
9
- appendValueGroup,
10
- Factory,
11
- type MaybePromise,
12
- type OpenApiGeneratorContext,
13
- OpenApiServicesGenerationProviderBase,
14
- toCasing,
15
- } from '@goast/core';
16
-
17
- import { copyAssetFile } from '../../../assets.js';
18
- import { ts } from '../../../ast/index.js';
19
- import { TypeScriptFileBuilder } from '../../../file-builder.js';
20
- import { modifyString } from '../../../utils.js';
21
- import {
22
- DefaultTypeScriptAngularServiceGenerator,
23
- type TypeScriptAngularServiceGenerator,
24
- } from './angular-service-generator.js';
25
- import {
26
- defaultTypeScriptAngularServicesGeneratorConfig,
27
- type TypeScriptAngularServiceGeneratorOutput,
28
- type TypeScriptAngularServicesGeneratorConfig,
29
- type TypeScriptAngularServicesGeneratorContext,
30
- type TypeScriptAngularServicesGeneratorInput,
31
- type TypeScriptAngularServicesGeneratorOutput,
32
- } from './models.js';
33
- import { getReferenceFactories } from './refs.js';
34
-
35
- type Input = TypeScriptAngularServicesGeneratorInput;
36
- type Output = TypeScriptAngularServicesGeneratorOutput;
37
- type Config = TypeScriptAngularServicesGeneratorConfig;
38
- type ServiceOutput = TypeScriptAngularServiceGeneratorOutput;
39
- type Context = TypeScriptAngularServicesGeneratorContext;
40
-
41
- export class TypeScriptAngularServicesGenerator extends OpenApiServicesGenerationProviderBase<
42
- Input,
43
- Output,
44
- Config,
45
- ServiceOutput,
46
- Context
47
- > {
48
- private readonly _clientGeneratorFactory: Factory<TypeScriptAngularServiceGenerator, []>;
49
-
50
- constructor(clientGeneratorFactory?: Factory<TypeScriptAngularServiceGenerator, []>) {
51
- super();
52
- this._clientGeneratorFactory = clientGeneratorFactory ??
53
- Factory.fromValue(new DefaultTypeScriptAngularServiceGenerator());
54
- }
55
-
56
- protected override initResult(): Output {
57
- return {
58
- typescript: {
59
- services: {},
60
- indexFiles: { services: undefined, responseModels: undefined },
61
- },
62
- };
63
- }
64
-
65
- protected override buildContext(
66
- context: OpenApiGeneratorContext<Input>,
67
- config?: Partial<Config> | undefined,
68
- ): Context {
69
- const providerContext = this.getProviderContext(context, config, defaultTypeScriptAngularServicesGeneratorConfig);
70
- return Object.assign(providerContext, {
71
- refs: getReferenceFactories(providerContext.config),
72
- });
73
- }
74
-
75
- protected override async generateAdditionalFiles(ctx: TypeScriptAngularServicesGeneratorContext): Promise<void> {
76
- await this.generateUtilsFiles(ctx);
77
- ctx.output.typescript.indexFiles = this.generateIndexFiles(ctx);
78
- }
79
-
80
- protected override generateService(ctx: Context, service: ApiService): MaybePromise<ServiceOutput> {
81
- const clientGenerator = this._clientGeneratorFactory.create();
82
- return clientGenerator.generate({
83
- ...ctx,
84
- service,
85
- });
86
- }
87
-
88
- protected override addServiceResult(ctx: Context, service: ApiService, result: ServiceOutput): void {
89
- ctx.output.typescript.services[service.id] = result;
90
- }
91
-
92
- // #region Utils
93
- protected async generateUtilsFiles(ctx: Context): Promise<void> {
94
- const targetDir = resolve(ctx.config.outputDir, ctx.config.utilsDir);
95
- await fs.ensureDir(targetDir);
96
-
97
- await copyAssetFile('client/angular/request-builder.ts', targetDir, 'Request Builder');
98
- await copyAssetFile('client/angular/angular-service.utils.ts', targetDir, 'Angular Service Utils');
99
-
100
- TypeScriptFileBuilder.generate({
101
- logName: 'api configuration',
102
- filePath: resolve(targetDir, 'api-configuration.ts'),
103
- options: ctx.config,
104
- generator: (b) => b.append(this.getApiConfigurationFileContent(ctx)),
105
- });
106
-
107
- TypeScriptFileBuilder.generate({
108
- logName: 'api base service',
109
- filePath: resolve(targetDir, 'api-base-service.ts'),
110
- options: ctx.config,
111
- generator: (b) => b.append(this.getApiBaseServiceFileContent(ctx)),
112
- });
113
-
114
- if (!ctx.config.strictResponseTypes) {
115
- TypeScriptFileBuilder.generate({
116
- logName: 'http status codes',
117
- filePath: resolve(targetDir, 'http-status-code.ts'),
118
- options: ctx.config,
119
- generator: (b) => b.append(this.getHttpStatusCodeFileContent(ctx)),
120
- });
121
- }
122
-
123
- if (ctx.config.provideKind === 'provide-fn') {
124
- TypeScriptFileBuilder.generate({
125
- logName: 'providers',
126
- filePath: resolve(targetDir, 'provide.ts'),
127
- options: ctx.config,
128
- generator: (b) => b.append(this.getProvideFnFileContent(ctx)),
129
- });
130
- }
131
- }
132
-
133
- protected getApiConfigurationFileContent(ctx: Context): AppendValueGroup<TypeScriptFileBuilder> {
134
- return appendValueGroup(
135
- [
136
- ts.class(toCasing(`${ctx.config.domainName ?? ''}ApiConfiguration`, ctx.config.typeNameCasing), {
137
- doc: ts.doc({ description: `${ctx.config.domainName ?? 'Global'} API Configuration.` }),
138
- decorators: [
139
- ts.decorator(ts.refs.angular.injectable(), [
140
- ctx.config.provideKind === 'root' ? ts.toNode({ providedIn: 'root' }) : null,
141
- ]),
142
- ],
143
- export: true,
144
- members: [
145
- ts.property('rootUrl', {
146
- accessModifier: 'public',
147
- type: ts.refs.string(),
148
- value: ts.string(this.getRootUrl(ctx)),
149
- }),
150
- ],
151
- }),
152
- ],
153
- '\n',
154
- );
155
- }
156
-
157
- protected getApiBaseServiceFileContent(ctx: Context): AppendValueGroup<TypeScriptFileBuilder> {
158
- return appendValueGroup(
159
- [
160
- ts.class('ApiBaseService', {
161
- doc: ts.doc({ description: 'Base class for API services.' }),
162
- export: true,
163
- abstract: true,
164
- members: [
165
- ts.property('config', {
166
- accessModifier: 'protected',
167
- value: (b) => b.append(ts.refs.angular.inject(), '(', ctx.refs.apiConfiguration(), ')'),
168
- }),
169
- ts.property('http', {
170
- accessModifier: 'protected',
171
- value: (b) => b.append(ts.refs.angular.inject(), '(', ts.refs.angular.httpClient(), ')'),
172
- }),
173
- ts.property('_rootUrl', { accessModifier: 'private', type: ts.refs.string(), value: ts.string('') }),
174
- ts.property('rootUrl', {
175
- doc: ts.doc({
176
- description:
177
- `Gets or sets the root URL for API operations provided by this service.\nFalls back to \`${ctx.refs.apiConfiguration.refName}.rootUrl\` if not set in this service.`,
178
- }),
179
- accessModifier: 'public',
180
- type: ts.refs.string(),
181
- get: ts.property.getter({ body: 'return this._rootUrl || this.config.rootUrl;' }),
182
- set: ts.property.setter({ body: 'this._rootUrl = value;' }),
183
- }),
184
- ],
185
- }),
186
- ],
187
- '\n',
188
- );
189
- }
190
-
191
- protected getHttpStatusCodeFileContent(ctx: Context): AppendValueGroup<TypeScriptFileBuilder> {
192
- return appendValueGroup(
193
- [
194
- ts.typeAlias('HttpStatusCode', ts.unionType(ctx.config.possibleStatusCodes), {
195
- doc: ts.doc({ description: 'The possible status codes that any API endpoint can return.' }),
196
- export: true,
197
- }),
198
- ],
199
- '\n',
200
- );
201
- }
202
-
203
- protected getProvideFnFileContent(ctx: Context): AppendValueGroup<TypeScriptFileBuilder> {
204
- return appendValueGroup(
205
- [
206
- ts.function(toCasing(`provide_${ctx.config.domainName ?? ''}_Api`, ctx.config.functionNameCasing), {
207
- doc: ts.doc({
208
- description: 'Provides all the API services' +
209
- (ctx.config.domainName ? ` for ${ctx.config.domainName}` : '') + '.',
210
- }),
211
- export: true,
212
- parameters: [ts.parameter('config', { type: ctx.refs.apiConfiguration(), optional: true })],
213
- returnType: ts.refs.angular.provider(),
214
- body: appendValueGroup([
215
- 'return ',
216
- ts.tuple([
217
- (b) =>
218
- b.append(
219
- 'config ? { provide: ',
220
- ctx.refs.apiConfiguration(),
221
- ', useValue: config } : ',
222
- ctx.refs.apiConfiguration(),
223
- ),
224
- ...Object.values(ctx.output.typescript.services).map((x) => ts.reference(x.component, x.filePath)),
225
- ]),
226
- ';',
227
- ]),
228
- }),
229
- ],
230
- '\n',
231
- );
232
- }
233
-
234
- protected getRootUrl(ctx: Context): string {
235
- return modifyString<[]>(
236
- (ctx.data.services[0].$src ?? ctx.data.services[0].endpoints[0]?.$src)?.document.servers?.[0]?.url ?? '/',
237
- ctx.config.rootUrl,
238
- );
239
- }
240
- // #endregion
241
-
242
- // #region Index
243
- protected generateIndexFiles(ctx: Context): Output['typescript']['indexFiles'] {
244
- const servicesIndexFilePath = this.getServicesIndexFilePath(ctx);
245
- const responseModelsIndexFilePath = this.getResponseModelsIndexFilePath(ctx);
246
-
247
- TypeScriptFileBuilder.tryGenerate({
248
- logName: 'services index file',
249
- filePath: servicesIndexFilePath,
250
- options: ctx.config,
251
- generator: (b) => b.append(this.getServicesIndexFileContent(ctx)),
252
- });
253
-
254
- TypeScriptFileBuilder.tryGenerate({
255
- logName: 'response models index file',
256
- filePath: responseModelsIndexFilePath,
257
- options: ctx.config,
258
- generator: (b) => b.append(this.getResponseModelsIndexFileContent(ctx)),
259
- });
260
-
261
- return {
262
- services: servicesIndexFilePath,
263
- responseModels: responseModelsIndexFilePath,
264
- };
265
- }
266
-
267
- protected getServicesIndexFileContent(ctx: Context): AppendValueGroup<TypeScriptFileBuilder> {
268
- return appendValueGroup([
269
- ts.export(ctx.refs.apiConfiguration.refName, ctx.refs.apiConfiguration.moduleNameOrfilePath),
270
- ctx.config.provideKind === 'provide-fn'
271
- ? ts.export(ctx.refs.provide.refName, ctx.refs.provide.moduleNameOrfilePath)
272
- : null,
273
- ...Object.values(ctx.output.typescript.services).map((x) => ts.export(x.component, x.filePath)),
274
- ]);
275
- }
276
-
277
- protected getResponseModelsIndexFileContent(ctx: Context): AppendValueGroup<TypeScriptFileBuilder> {
278
- return appendValueGroup(
279
- Object.values(ctx.output.typescript.services)
280
- .flatMap((x) => Object.values(x.responseModels))
281
- .map((x) => ts.export(x.component, x.filePath, { kind: 'type-export' })),
282
- );
283
- }
284
-
285
- protected getServicesIndexFilePath(ctx: Context): string | null {
286
- return ctx.config.servicesIndexFile ? resolve(ctx.config.outputDir, ctx.config.servicesIndexFile) : null;
287
- }
288
-
289
- protected getResponseModelsIndexFilePath(ctx: Context): string | null {
290
- return ctx.config.responseModelsIndexFile
291
- ? resolve(ctx.config.outputDir, ctx.config.responseModelsIndexFile)
292
- : null;
293
- }
294
- // #endregion
295
- }
@@ -1,3 +0,0 @@
1
- export * from './angular-service-generator.js';
2
- export * from './angular-services-generator.js';
3
- export * from './models.js';