@goast/typescript 0.6.1 → 0.6.3-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 (88) hide show
  1. package/LICENSE +21 -21
  2. package/assets/client/k6/request-builder.js +4 -0
  3. package/assets/client/k6/request-builder.ts +4 -0
  4. package/assets/stubs/easy-network-stub/easy-network-stub.utils.ts +2 -6
  5. package/package.json +2 -2
  6. package/src/mod.ts +0 -7
  7. package/src/src/assets.ts +0 -9
  8. package/src/src/ast/_index.ts +0 -54
  9. package/src/src/ast/common.ts +0 -1
  10. package/src/src/ast/index.ts +0 -1
  11. package/src/src/ast/node.ts +0 -10
  12. package/src/src/ast/nodes/argument.ts +0 -40
  13. package/src/src/ast/nodes/array-type.ts +0 -49
  14. package/src/src/ast/nodes/arrow-function.ts +0 -91
  15. package/src/src/ast/nodes/call.ts +0 -55
  16. package/src/src/ast/nodes/class.ts +0 -133
  17. package/src/src/ast/nodes/constructor-parameter.ts +0 -70
  18. package/src/src/ast/nodes/constructor.ts +0 -77
  19. package/src/src/ast/nodes/decorator.ts +0 -76
  20. package/src/src/ast/nodes/doc-tag.ts +0 -291
  21. package/src/src/ast/nodes/doc.ts +0 -102
  22. package/src/src/ast/nodes/enum-value.ts +0 -72
  23. package/src/src/ast/nodes/enum.ts +0 -77
  24. package/src/src/ast/nodes/export.ts +0 -54
  25. package/src/src/ast/nodes/function-type.ts +0 -60
  26. package/src/src/ast/nodes/function.ts +0 -107
  27. package/src/src/ast/nodes/generic-parameter.ts +0 -71
  28. package/src/src/ast/nodes/indexer.ts +0 -60
  29. package/src/src/ast/nodes/interface.ts +0 -117
  30. package/src/src/ast/nodes/intersection-type.ts +0 -67
  31. package/src/src/ast/nodes/lookup-type.ts +0 -53
  32. package/src/src/ast/nodes/method.ts +0 -138
  33. package/src/src/ast/nodes/object-type.ts +0 -52
  34. package/src/src/ast/nodes/object.ts +0 -48
  35. package/src/src/ast/nodes/parameter.ts +0 -85
  36. package/src/src/ast/nodes/property-accessor.ts +0 -173
  37. package/src/src/ast/nodes/property.ts +0 -192
  38. package/src/src/ast/nodes/reference.ts +0 -194
  39. package/src/src/ast/nodes/string.ts +0 -49
  40. package/src/src/ast/nodes/tuple.ts +0 -53
  41. package/src/src/ast/nodes/type-alias.ts +0 -75
  42. package/src/src/ast/nodes/typeof.ts +0 -42
  43. package/src/src/ast/nodes/types.ts +0 -40
  44. package/src/src/ast/nodes/union-type.ts +0 -62
  45. package/src/src/ast/nodes/variable.ts +0 -73
  46. package/src/src/ast/references/angular.ts +0 -24
  47. package/src/src/ast/references/easy-network-stub.ts +0 -21
  48. package/src/src/ast/references/index.ts +0 -5
  49. package/src/src/ast/references/k6.ts +0 -8
  50. package/src/src/ast/references/rxjs.ts +0 -7
  51. package/src/src/ast/references/typescript.ts +0 -35
  52. package/src/src/ast/utils/get-type-script-builder-options.ts +0 -19
  53. package/src/src/ast/utils/to-ts-node.ts +0 -27
  54. package/src/src/ast/utils/write-ts-generic-parameters.ts +0 -25
  55. package/src/src/ast/utils/write-ts-members.ts +0 -28
  56. package/src/src/ast/utils/write-ts-nodes.ts +0 -35
  57. package/src/src/ast/utils/write-ts-parameters.ts +0 -25
  58. package/src/src/common-results.ts +0 -26
  59. package/src/src/config.ts +0 -89
  60. package/src/src/file-builder.ts +0 -137
  61. package/src/src/generators/file-generator.ts +0 -15
  62. package/src/src/generators/index.ts +0 -6
  63. package/src/src/generators/models/index.ts +0 -3
  64. package/src/src/generators/models/model-generator.ts +0 -481
  65. package/src/src/generators/models/models-generator.ts +0 -108
  66. package/src/src/generators/models/models.ts +0 -121
  67. package/src/src/generators/services/angular-services/angular-service-generator.ts +0 -414
  68. package/src/src/generators/services/angular-services/angular-services-generator.ts +0 -295
  69. package/src/src/generators/services/angular-services/index.ts +0 -3
  70. package/src/src/generators/services/angular-services/models.ts +0 -277
  71. package/src/src/generators/services/angular-services/refs.ts +0 -54
  72. package/src/src/generators/services/easy-network-stub/easy-network-stub-generator.ts +0 -250
  73. package/src/src/generators/services/easy-network-stub/easy-network-stubs-generator.ts +0 -211
  74. package/src/src/generators/services/easy-network-stub/index.ts +0 -3
  75. package/src/src/generators/services/easy-network-stub/models.ts +0 -124
  76. package/src/src/generators/services/easy-network-stub/refs.ts +0 -45
  77. package/src/src/generators/services/fetch-clients/fetch-client-generator.ts +0 -285
  78. package/src/src/generators/services/fetch-clients/fetch-clients-generator.ts +0 -163
  79. package/src/src/generators/services/fetch-clients/index.ts +0 -3
  80. package/src/src/generators/services/fetch-clients/models.ts +0 -130
  81. package/src/src/generators/services/fetch-clients/refs.ts +0 -21
  82. package/src/src/generators/services/k6-clients/index.ts +0 -3
  83. package/src/src/generators/services/k6-clients/k6-client-generator.ts +0 -474
  84. package/src/src/generators/services/k6-clients/k6-clients-generator.ts +0 -171
  85. package/src/src/generators/services/k6-clients/models.ts +0 -247
  86. package/src/src/generators/services/k6-clients/refs.ts +0 -16
  87. package/src/src/import-collection.ts +0 -236
  88. package/src/src/utils.ts +0 -72
@@ -1,474 +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
- getSourceDisplayName,
11
- type MaybePromise,
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 type { TypeScriptImportOptions } from '../../../import-collection.js';
19
- import { TypeScriptFileGenerator } from '../../file-generator.js';
20
- import type { TypeScriptK6ClientGeneratorContext, TypeScriptK6ClientGeneratorOutput } from './models.js';
21
-
22
- type Context = TypeScriptK6ClientGeneratorContext;
23
- type Output = TypeScriptK6ClientGeneratorOutput;
24
- type Builder = TypeScriptFileBuilder;
25
-
26
- export interface TypeScriptK6ClientGenerator<TOutput extends Output = Output> {
27
- generate(context: Context): MaybePromise<TOutput>;
28
- }
29
-
30
- export class DefaultTypeScriptK6ClientGenerator extends TypeScriptFileGenerator<Context, Output>
31
- implements TypeScriptK6ClientGenerator {
32
- public override generate(ctx: TypeScriptK6ClientGeneratorContext): MaybePromise<TypeScriptK6ClientGeneratorOutput> {
33
- const responseModels = this.generateResponseModels(ctx);
34
-
35
- const filePath = this.getFilePath(ctx);
36
- const name = this.getClassName(ctx);
37
-
38
- TypeScriptFileBuilder.generate({
39
- logName: `k6 client ${name}`,
40
- filePath,
41
- options: ctx.config,
42
- generator: (b) => {
43
- ctx.service.endpoints.forEach((endpoint) => {
44
- console.log(
45
- ` ${getSourceDisplayName(ctx.data, endpoint)} [${toCasing(endpoint.name, ctx.config.functionNameCasing)}]`,
46
- );
47
- });
48
- b.append(this.getClientFileContent(ctx));
49
- },
50
- });
51
-
52
- return {
53
- filePath,
54
- component: name,
55
- responseModels,
56
- };
57
- }
58
-
59
- // #region Response Model
60
- protected generateResponseModels(ctx: Context): Record<string, TypeScriptExportOutput> {
61
- const result: Record<string, TypeScriptExportOutput> = {};
62
- const filePath = this.getResponseModelFilePath(ctx);
63
- const builder = new TypeScriptFileBuilder(filePath, ctx.config);
64
-
65
- for (const endpoint of ctx.service.endpoints) {
66
- const name = this.getResponseModelName(ctx, endpoint);
67
- builder.appendLine(this.getResponseModelFileContent(ctx, endpoint));
68
- result[endpoint.id] = { component: name, filePath };
69
- }
70
-
71
- builder.writeToFile();
72
- return result;
73
- }
74
-
75
- protected getResponseModelFileContent(ctx: Context, endpoint: ApiEndpoint): AppendValueGroup<Builder> {
76
- const result = appendValueGroup<Builder>([]);
77
- const statusCodes = this.getEndpointStatusCodes(ctx, endpoint);
78
- let statusCodeType: ts.Reference<Builder>;
79
-
80
- const statusCodesTypeName = toCasing(`${endpoint.name}_StatusCodes`, ctx.config.typeNameCasing);
81
- result.values.push(ts.typeAlias(statusCodesTypeName, ts.unionType(Object.keys(statusCodes))));
82
- if (ctx.config.strictResponseTypes) {
83
- statusCodeType = ts.reference(statusCodesTypeName);
84
- } else {
85
- statusCodeType = ctx.refs.httpStatusCode();
86
- }
87
-
88
- result.values.push(
89
- ts.typeAlias(
90
- this.getResponseModelName(ctx, endpoint),
91
- ts.intersectionType([
92
- ts.unionType([
93
- ...Object.entries(statusCodes).map(([key, value]) => {
94
- return ts.intersectionType<Builder>([
95
- ts.refs.omit([ts.refs.k6.response(), ts.string('json')]),
96
- ts.objectType({
97
- members: [
98
- ts.property('status', { type: key }),
99
- ts.method('json', {
100
- returnType: value.type,
101
- }),
102
- ts.method('json', {
103
- parameters: [ts.parameter('selector', { type: ts.refs.string() })],
104
- returnType: ts.refs.k6.jsonValue(),
105
- }),
106
- ],
107
- }),
108
- ]);
109
- }),
110
- !ctx.config.strictResponseTypes
111
- ? ts.intersectionType([
112
- ts.refs.k6.response(),
113
- ts.objectType({
114
- members: [
115
- ts.property('status', {
116
- type: ts.refs.exclude([ctx.refs.httpStatusCode(), ts.reference(statusCodesTypeName)]),
117
- }),
118
- ],
119
- }),
120
- ])
121
- : null,
122
- ]),
123
- ts.objectType({ members: [ts.property('status', { type: 'TStatus' })] }),
124
- ]),
125
- {
126
- doc: ts.doc({
127
- description: `Response model for operation ${this.getEndpointMethodName(ctx, endpoint)}`,
128
- tags: [endpoint.deprecated ? ts.docTag('deprecated') : null],
129
- }),
130
- export: true,
131
- generics: [
132
- ts.genericParameter('TStatus', {
133
- constraint: statusCodeType,
134
- default: statusCodeType,
135
- }),
136
- ],
137
- },
138
- ),
139
- );
140
-
141
- return result;
142
- }
143
-
144
- protected getEndpointStatusCodes(ctx: Context, endpoint: ApiEndpoint): Record<number, { type: ts.Type<Builder> }> {
145
- return Object.fromEntries([
146
- ...Object.entries(ctx.config.defaultStatusCodeResponseTypes).map(([key, value]) => [
147
- key,
148
- {
149
- parser: value?.parser ?? 'text',
150
- type: typeof value?.type === 'function'
151
- ? this.getSchemaType(ctx, value.type(ctx.data.schemas))
152
- : value ?? ts.refs.never(),
153
- },
154
- ]),
155
- ...endpoint.responses
156
- .filter((x) => x.statusCode)
157
- .map((x) => [
158
- x.statusCode,
159
- {
160
- type: this.getSchemaType(ctx, x.contentOptions[0]?.schema, { fallback: ts.refs.never() }),
161
- },
162
- ]),
163
- ]);
164
- }
165
- // #endregion
166
-
167
- protected getClientFileContent(ctx: Context): AppendValueGroup<Builder> {
168
- const code = appendValueGroup<Builder>([], '\n');
169
- for (const endpoint of ctx.service.endpoints) {
170
- if (endpoint.parameters.length > 0 || endpoint.requestBody !== undefined) {
171
- code.values.push(this.getEndpointParamsType(ctx, endpoint));
172
- }
173
- }
174
- code.values.push(
175
- appendValueGroup<Builder>(
176
- ctx.service.endpoints.map((e) =>
177
- ts.variable(this.getEndpointPathPropertyName(ctx, e), {
178
- readonly: true,
179
- value: ts.string(e.path),
180
- })
181
- ),
182
- ),
183
- );
184
- code.values.push(this.getClass(ctx));
185
- return code;
186
- }
187
-
188
- protected getEndpointParamsType(ctx: Context, endpoint: ApiEndpoint): ts.Doc<Builder> | ts.TypeAlias<Builder> {
189
- const importOptions: TypeScriptImportOptions = ctx.config.language === 'javascript' ? { type: 'js-doc' } : {};
190
- const description = `Parameters for operation ${this.getEndpointMethodName(ctx, endpoint)}`;
191
- const typeName = this.getEndpointParamsTypeName(ctx, endpoint);
192
- const properties: { name: string; type: ts.Type<Builder>; description: string | undefined; required: boolean }[] =
193
- endpoint.parameters
194
- .map((parameter) => {
195
- const schema = parameter.schema;
196
- return {
197
- name: toCasing(parameter.name, ctx.config.propertyNameCasing),
198
- type: schema
199
- ? (b) => b.appendModelUsage(ctx.input.typescript.models[schema.id], importOptions)
200
- : this.getAnyType(ctx),
201
- description: (parameter.deprecated ? 'Deprecated: ' : '') + parameter.description,
202
- required: parameter.required,
203
- };
204
- });
205
-
206
- if (endpoint.requestBody !== undefined) {
207
- const body = endpoint.requestBody;
208
- const schema = body.content[0].schema;
209
- properties.push({
210
- name: 'body',
211
- type: schema
212
- ? (b) => b.appendModelUsage(ctx.input.typescript.models[schema.id], importOptions)
213
- : this.getAnyType(ctx),
214
- description: body.description,
215
- required: body.required,
216
- });
217
- }
218
-
219
- if (ctx.config.language === 'javascript') {
220
- return ts.doc<Builder>({
221
- description,
222
- tags: [
223
- ts.docTag('typedef', typeName),
224
- ...properties.map((p) =>
225
- ts.docTag<'property', Builder>('property', p.required ? p.name : `[${p.name}]`, {
226
- type: p.type,
227
- text: p.description,
228
- })
229
- ),
230
- ],
231
- });
232
- } else {
233
- return ts.typeAlias<Builder>(
234
- typeName,
235
- ts.objectType({
236
- members: properties.map((p) =>
237
- ts.property(p.name, {
238
- type: p.type,
239
- optional: !p.required,
240
- doc: p.description ? ts.doc({ description: p.description }) : undefined,
241
- })
242
- ),
243
- }),
244
- );
245
- }
246
- }
247
-
248
- protected getClass(ctx: Context): ts.Class<Builder> {
249
- const isJs = ctx.config.language === 'javascript';
250
- const rootUrlType = ts.refs.string();
251
- const paramType = ts.functionType({
252
- returnType: ts.refs.k6.params({ importType: isJs ? 'js-doc' : 'type-import' }),
253
- });
254
- return ts.class<Builder>(this.getClassName(ctx), {
255
- doc: ts.doc({
256
- description: ctx.service.description,
257
- tags: [
258
- isJs ? ts.docTag('property', 'rootUrl', 'The root URL for this client.', { type: ts.refs.string() }) : null,
259
- ctx.service.endpoints.length === 0 || ctx.service.endpoints.some((x) => !x.deprecated)
260
- ? null
261
- : ts.docTag('deprecated'),
262
- ],
263
- }),
264
- export: true,
265
- members: [
266
- ...(isJs ? [] : [
267
- ts.property('rootUrl', {
268
- type: rootUrlType,
269
- readonly: true,
270
- accessModifier: 'public',
271
- doc: ts.doc({ description: 'The root URL for this client.' }),
272
- }),
273
- ts.property('_defaultK6ParamsFactory', {
274
- type: paramType,
275
- optional: true,
276
- readonly: true,
277
- accessModifier: 'private',
278
- doc: ts.doc({ description: 'A factory function that returns the default K6 parameters.' }),
279
- }),
280
- ]),
281
- ts.constructor({
282
- doc: ts.doc({
283
- description: 'Creates a new instance of the client.',
284
- tags: [
285
- ts.docTag('param', 'rootUrl', 'The root URL for this client.', { type: isJs ? rootUrlType : undefined }),
286
- ts.docTag(
287
- 'param',
288
- '[defaultK6ParamsFactory]',
289
- 'A factory function that returns the default K6 parameters.',
290
- { type: isJs ? paramType : undefined },
291
- ),
292
- ],
293
- }),
294
- parameters: [
295
- ts.constructorParameter('rootUrl', { type: isJs ? undefined : rootUrlType }),
296
- ts.constructorParameter('defaultK6ParamsFactory', { type: isJs ? undefined : paramType, optional: true }),
297
- ],
298
- body: s`this.rootUrl = rootUrl;
299
- this._defaultK6ParamsFactory = defaultK6ParamsFactory;`,
300
- }),
301
- ...ctx.service.endpoints.map((e) => this.getEndpointMethod(ctx, e)),
302
- this.getGetK6ParamsMethod(ctx),
303
- ],
304
- });
305
- }
306
-
307
- protected getEndpointMethod(ctx: Context, endpoint: ApiEndpoint): ts.Method<Builder> {
308
- const isJs = ctx.config.language === 'javascript';
309
- const hasParams = this.hasEndpointParams(ctx, endpoint);
310
- const paramsOptional = !endpoint.parameters.some((p) => p.required) && !endpoint.requestBody?.required;
311
- const responseModelType = ts.reference(
312
- this.getResponseModelName(ctx, endpoint),
313
- this.getResponseModelFilePath(ctx),
314
- { importType: ctx.config.language === 'javascript' ? 'js-doc' : 'type-import' },
315
- );
316
- const returnType = responseModelType;
317
- const accept = this.getEndpointSuccessResponse(ctx, endpoint)?.contentOptions[0]?.type ?? '*/*';
318
- const paramsType = hasParams ? ts.reference(this.getEndpointParamsTypeName(ctx, endpoint)) : null;
319
- const returnTypeWithPromise = ctx.config.async ? ts.refs.promise([returnType]) : returnType;
320
-
321
- return ts.method<Builder>(this.getEndpointMethodName(ctx, endpoint), {
322
- async: ctx.config.async,
323
- parameters: [
324
- hasParams ? ts.parameter('params', { type: isJs ? null : paramsType }) : null,
325
- ts.parameter('k6Params', { type: isJs ? null : ts.refs.k6.params({ importType: 'type-import' }) }),
326
- ],
327
- returnType: isJs ? null : returnTypeWithPromise,
328
- doc: ts.doc({
329
- description: endpoint.description,
330
- tags: isJs
331
- ? [
332
- hasParams ? ts.docTag('param', paramsOptional ? '[params]' : 'params', { type: paramsType }) : null,
333
- ts.docTag('param', '[k6Params]', { type: ts.refs.k6.params({ importType: 'js-doc' }) }),
334
- ts.docTag('returns', { type: returnTypeWithPromise }),
335
- endpoint.deprecated ? ts.docTag('deprecated') : null,
336
- ]
337
- : [],
338
- }),
339
- accessModifier: isJs ? null : 'public',
340
- body: appendValueGroup(
341
- [
342
- s`const rb = new ${ctx.refs.requestBuilder()}(this.rootUrl, ${
343
- this.getEndpointPathPropertyName(ctx, endpoint)
344
- }, '${endpoint.method}');`,
345
- hasParams
346
- ? (b) =>
347
- b.appendIf(paramsOptional, 'if (params) ').parenthesizeIf(
348
- paramsOptional,
349
- '{}',
350
- appendValueGroup(
351
- [
352
- ...endpoint.parameters
353
- .filter((p) => p.target === 'path' || p.target === 'query' || p.target === 'header')
354
- .map((p) => {
355
- const options = ts.object({
356
- members: [
357
- p.style !== undefined ? ts.property('style', { value: ts.string(p.style) }) : null,
358
- p.explode !== undefined ? ts.property('explode', { value: ts.toNode(p.explode) }) : null,
359
- ],
360
- });
361
- return s<Builder>`rb.${p.target}(${ts.string(p.name)}, params.${
362
- toCasing(
363
- p.name,
364
- ctx.config.propertyNameCasing,
365
- )
366
- }, ${options});`;
367
- }),
368
- endpoint.requestBody
369
- ? s`rb.body(params.body, ${
370
- ts.string(endpoint.requestBody.content[0].type ?? 'application/json')
371
- });`
372
- : null,
373
- ],
374
- '\n',
375
- ),
376
- { multiline: true },
377
- )
378
- : null,
379
- '',
380
- ctx.config.language === 'javascript'
381
- ? s`return /** @type {${returnType}} */ (${s.indent`
382
- ${ctx.config.async ? 'await rb.buildAsync' : 'rb.build'}({${s.indent`
383
- accept: ${ts.string(accept)},
384
- params: this.getK6Params(k6Params),`}
385
- })`}
386
- );`
387
- : s`return (${s.indent`
388
- ${ctx.config.async ? 'await rb.buildAsync' : 'rb.build'}({${s.indent`
389
- accept: ${ts.string(accept)},
390
- params: this.getK6Params(k6Params),`}
391
- })`}
392
- ) as unknown as ${returnType};`,
393
- ],
394
- '\n',
395
- ),
396
- });
397
- }
398
-
399
- protected getGetK6ParamsMethod(ctx: Context): ts.Method<Builder> {
400
- const isJs = ctx.config.language === 'javascript';
401
- return ts.method('getK6Params', {
402
- accessModifier: isJs ? null : 'private',
403
- doc: isJs
404
- ? ts.doc({
405
- tags: [
406
- ts.docTag('private'),
407
- ts.docTag('param', '[k6Params]', { type: ts.refs.k6.params({ importType: 'js-doc' }) }),
408
- ],
409
- })
410
- : null,
411
- parameters: [ts.parameter('k6Params', { type: isJs ? null : ts.refs.k6.params({ importType: 'type-import' }) })],
412
- body: s`return Object.assign({}, this._defaultK6ParamsFactory ? this._defaultK6ParamsFactory() : {}, k6Params);`,
413
- });
414
- }
415
-
416
- protected getEndpointSuccessResponse(_ctx: Context, endpoint: ApiEndpoint): ApiResponse | undefined {
417
- return (
418
- endpoint.responses.find((x) => x.statusCode && x.statusCode >= 200 && x.statusCode < 300) ??
419
- endpoint.responses.find((x) => x.statusCode === undefined)
420
- );
421
- }
422
-
423
- protected getSchemaType(
424
- ctx: Context,
425
- schema: ApiSchema | undefined,
426
- options?: TypeScriptImportOptions & { fallback?: ts.Type<Builder> },
427
- ): ts.Type<Builder> {
428
- const output = schema && ctx.input.typescript.models[schema.id];
429
- if (!output) return options?.fallback ?? this.getAnyType(ctx);
430
- return (b) => b.appendModelUsage(output, options);
431
- }
432
-
433
- protected getClassName(ctx: Context): string {
434
- return toCasing(ctx.service.name, ctx.config.clientNameCasing ?? ctx.config.typeNameCasing);
435
- }
436
-
437
- protected getResponseModelName(ctx: Context, endpoint: ApiEndpoint): string {
438
- return toCasing(`${this.getEndpointMethodName(ctx, endpoint)}ApiResponse`, ctx.config.typeNameCasing);
439
- }
440
-
441
- protected getEndpointParamsTypeName(ctx: Context, endpoint: ApiEndpoint): string {
442
- return toCasing(this.getEndpointMethodName(ctx, endpoint) + '_Params', ctx.config.typeNameCasing);
443
- }
444
-
445
- protected getEndpointPathPropertyName(ctx: Context, endpoint: ApiEndpoint): string {
446
- return toCasing(this.getEndpointMethodName(ctx, endpoint) + '_Path', ctx.config.constantNameCasing);
447
- }
448
-
449
- protected getEndpointMethodName(ctx: Context, endpoint: ApiEndpoint): string {
450
- return toCasing(endpoint.name, ctx.config.functionNameCasing);
451
- }
452
-
453
- protected getFilePath(ctx: Context): string {
454
- return resolve(
455
- ctx.config.outputDir,
456
- ctx.config.clientDir,
457
- `${toCasing(ctx.service.name, ctx.config.clientFileNameCasing ?? ctx.config.fileNameCasing)}.${
458
- ctx.config.language === 'typescript' ? 'ts' : 'js'
459
- }`,
460
- );
461
- }
462
-
463
- protected getResponseModelFilePath(ctx: Context): string {
464
- return resolve(
465
- ctx.config.outputDir,
466
- ctx.config.responseModelsDir,
467
- `${toCasing(ctx.service.name, ctx.config.responseModelFileNameCasing ?? ctx.config.fileNameCasing)}.ts`,
468
- );
469
- }
470
-
471
- protected hasEndpointParams(_ctx: Context, endpoint: ApiEndpoint): boolean {
472
- return endpoint.parameters.length > 0 || endpoint.requestBody !== undefined;
473
- }
474
- }
@@ -1,171 +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
- } from '@goast/core';
15
-
16
- import { copyAssetFile } from '../../../assets.js';
17
- import { ts } from '../../../ast/index.js';
18
- import { TypeScriptFileBuilder } from '../../../file-builder.js';
19
- import { DefaultTypeScriptK6ClientGenerator, type TypeScriptK6ClientGenerator } from './k6-client-generator.js';
20
- import {
21
- defaultTypeScriptK6ClientsGeneratorConfig,
22
- type TypeScriptK6ClientGeneratorOutput,
23
- type TypeScriptK6ClientsGeneratorConfig,
24
- type TypeScriptK6ClientsGeneratorContext,
25
- type TypeScriptK6ClientsGeneratorInput,
26
- type TypeScriptK6ClientsGeneratorOutput,
27
- } from './models.js';
28
- import { getReferenceFactories } from './refs.js';
29
-
30
- type Input = TypeScriptK6ClientsGeneratorInput;
31
- type Output = TypeScriptK6ClientsGeneratorOutput;
32
- type Config = TypeScriptK6ClientsGeneratorConfig;
33
- type ServiceOutput = TypeScriptK6ClientGeneratorOutput;
34
- type Context = TypeScriptK6ClientsGeneratorContext;
35
-
36
- export class TypeScriptK6ClientsGenerator extends OpenApiServicesGenerationProviderBase<
37
- Input,
38
- Output,
39
- Config,
40
- ServiceOutput,
41
- Context
42
- > {
43
- private readonly _clientGeneratorFactory: Factory<TypeScriptK6ClientGenerator, []>;
44
-
45
- constructor(clientGeneratorFactory?: Factory<TypeScriptK6ClientGenerator, []>) {
46
- super();
47
- this._clientGeneratorFactory = clientGeneratorFactory ??
48
- Factory.fromValue(new DefaultTypeScriptK6ClientGenerator());
49
- }
50
-
51
- protected override initResult(): Output {
52
- return {
53
- typescript: {
54
- k6Clients: {},
55
- indexFiles: {
56
- k6Clients: undefined,
57
- k6ResponseModels: undefined,
58
- },
59
- },
60
- };
61
- }
62
-
63
- protected override buildContext(
64
- context: OpenApiGeneratorContext<Input>,
65
- config?: Partial<Config> | undefined,
66
- ): Context {
67
- const providerContext = this.getProviderContext(context, config, defaultTypeScriptK6ClientsGeneratorConfig);
68
- return Object.assign(providerContext, {
69
- refs: getReferenceFactories(providerContext.config),
70
- });
71
- }
72
-
73
- protected override async generateAdditionalFiles(ctx: TypeScriptK6ClientsGeneratorContext): Promise<void> {
74
- await this.generateUtilsFiles(ctx);
75
- ctx.output.typescript.indexFiles = this.generateIndexFiles(ctx);
76
- }
77
-
78
- protected override generateService(ctx: Context, service: ApiService): MaybePromise<ServiceOutput> {
79
- const clientGenerator = this._clientGeneratorFactory.create();
80
- return clientGenerator.generate({
81
- ...ctx,
82
- service,
83
- });
84
- }
85
-
86
- protected override addServiceResult(ctx: Context, service: ApiService, result: ServiceOutput): void {
87
- ctx.output.typescript.k6Clients[service.id] = result;
88
- }
89
-
90
- protected async generateUtilsFiles(ctx: Context): Promise<void> {
91
- const targetDir = resolve(ctx.config.outputDir, ctx.config.utilsDir);
92
- await fs.ensureDir(targetDir);
93
-
94
- const ext = ctx.config.language === 'javascript' ? '.js' : '.ts';
95
- await copyAssetFile(`client/k6/request-builder${ext}`, targetDir, 'Request Builder');
96
-
97
- if (!ctx.config.strictResponseTypes) {
98
- TypeScriptFileBuilder.generate({
99
- logName: 'http status codes',
100
- filePath: resolve(targetDir, 'http-status-code.ts'),
101
- options: ctx.config,
102
- generator: (b) => b.append(this.getHttpStatusCodeFileContent(ctx)),
103
- });
104
- }
105
- }
106
-
107
- protected getHttpStatusCodeFileContent(ctx: Context): AppendValueGroup<TypeScriptFileBuilder> {
108
- return appendValueGroup(
109
- [
110
- ts.typeAlias('HttpStatusCode', ts.unionType(ctx.config.possibleStatusCodes), {
111
- doc: ts.doc({ description: 'The possible status codes that any API endpoint can return.' }),
112
- export: true,
113
- }),
114
- ],
115
- '\n',
116
- );
117
- }
118
-
119
- protected generateIndexFiles(ctx: Context): Output['typescript']['indexFiles'] {
120
- const clientsIndexFilePath = this.getIndexFilePath(ctx);
121
- const responseModelsIndexFilePath = this.getResponseModelsIndexFilePath(ctx);
122
-
123
- TypeScriptFileBuilder.tryGenerate({
124
- logName: 'clients index file',
125
- filePath: clientsIndexFilePath,
126
- options: ctx.config,
127
- generator: (b) => b.append(this.getIndexFileContent(ctx)),
128
- });
129
-
130
- TypeScriptFileBuilder.tryGenerate({
131
- logName: 'response models index file',
132
- filePath: responseModelsIndexFilePath,
133
- options: ctx.config,
134
- generator: (b) => b.append(this.getResponseModelsIndexFileContent(ctx)),
135
- });
136
-
137
- return {
138
- k6Clients: clientsIndexFilePath,
139
- k6ResponseModels: responseModelsIndexFilePath,
140
- };
141
- }
142
-
143
- protected getIndexFilePath(ctx: Context): string | null {
144
- return ctx.config.clientsIndexFile
145
- ? resolve(
146
- ctx.config.outputDir,
147
- ctx.config.clientsIndexFile.replace(/\.[jt]s$/, ctx.config.language === 'javascript' ? '.js' : '.ts'),
148
- )
149
- : null;
150
- }
151
-
152
- protected getResponseModelsIndexFilePath(ctx: Context): string | null {
153
- return ctx.config.responseModelsIndexFile
154
- ? resolve(ctx.config.outputDir, ctx.config.responseModelsIndexFile)
155
- : null;
156
- }
157
-
158
- protected getIndexFileContent(ctx: Context): AppendValueGroup<TypeScriptFileBuilder> {
159
- return appendValueGroup(
160
- Object.values(ctx.output.typescript.k6Clients).map((x) => ts.export(x.component, x.filePath)),
161
- );
162
- }
163
-
164
- protected getResponseModelsIndexFileContent(ctx: Context): AppendValueGroup<TypeScriptFileBuilder> {
165
- return appendValueGroup(
166
- Object.values(ctx.output.typescript.k6Clients)
167
- .flatMap((x) => Object.values(x.responseModels))
168
- .map((x) => ts.export(x.component, x.filePath)),
169
- );
170
- }
171
- }