@goast/typescript 0.7.6 → 0.8.0-beta.2

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