@goast/typescript 0.5.3 → 0.6.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 (109) 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 +8 -3
  6. package/esm/src/generators/services/angular-services/angular-service-generator.d.ts.map +1 -1
  7. package/esm/src/generators/services/angular-services/angular-service-generator.js +7 -2
  8. package/esm/src/generators/services/easy-network-stub/easy-network-stub-generator.d.ts.map +1 -1
  9. package/esm/src/generators/services/easy-network-stub/easy-network-stub-generator.js +7 -2
  10. package/esm/src/generators/services/fetch-clients/fetch-client-generator.d.ts.map +1 -1
  11. package/esm/src/generators/services/fetch-clients/fetch-client-generator.js +7 -2
  12. package/esm/src/generators/services/k6-clients/k6-client-generator.d.ts.map +1 -1
  13. package/esm/src/generators/services/k6-clients/k6-client-generator.js +9 -3
  14. package/package.json +3 -3
  15. package/script/src/file-builder.d.ts.map +1 -1
  16. package/script/src/file-builder.js +1 -5
  17. package/script/src/generators/models/model-generator.d.ts.map +1 -1
  18. package/script/src/generators/models/model-generator.js +7 -2
  19. package/script/src/generators/services/angular-services/angular-service-generator.d.ts.map +1 -1
  20. package/script/src/generators/services/angular-services/angular-service-generator.js +6 -1
  21. package/script/src/generators/services/easy-network-stub/easy-network-stub-generator.d.ts.map +1 -1
  22. package/script/src/generators/services/easy-network-stub/easy-network-stub-generator.js +6 -1
  23. package/script/src/generators/services/fetch-clients/fetch-client-generator.d.ts.map +1 -1
  24. package/script/src/generators/services/fetch-clients/fetch-client-generator.js +6 -1
  25. package/script/src/generators/services/k6-clients/k6-client-generator.d.ts.map +1 -1
  26. package/script/src/generators/services/k6-clients/k6-client-generator.js +8 -2
  27. package/src/mod.ts +0 -7
  28. package/src/src/assets.ts +0 -9
  29. package/src/src/ast/_index.ts +0 -54
  30. package/src/src/ast/common.ts +0 -1
  31. package/src/src/ast/index.ts +0 -1
  32. package/src/src/ast/node.ts +0 -10
  33. package/src/src/ast/nodes/argument.ts +0 -40
  34. package/src/src/ast/nodes/array-type.ts +0 -49
  35. package/src/src/ast/nodes/arrow-function.ts +0 -91
  36. package/src/src/ast/nodes/call.ts +0 -55
  37. package/src/src/ast/nodes/class.ts +0 -133
  38. package/src/src/ast/nodes/constructor-parameter.ts +0 -70
  39. package/src/src/ast/nodes/constructor.ts +0 -77
  40. package/src/src/ast/nodes/decorator.ts +0 -76
  41. package/src/src/ast/nodes/doc-tag.ts +0 -291
  42. package/src/src/ast/nodes/doc.ts +0 -102
  43. package/src/src/ast/nodes/enum-value.ts +0 -72
  44. package/src/src/ast/nodes/enum.ts +0 -77
  45. package/src/src/ast/nodes/export.ts +0 -54
  46. package/src/src/ast/nodes/function-type.ts +0 -60
  47. package/src/src/ast/nodes/function.ts +0 -107
  48. package/src/src/ast/nodes/generic-parameter.ts +0 -71
  49. package/src/src/ast/nodes/indexer.ts +0 -60
  50. package/src/src/ast/nodes/interface.ts +0 -117
  51. package/src/src/ast/nodes/intersection-type.ts +0 -67
  52. package/src/src/ast/nodes/lookup-type.ts +0 -53
  53. package/src/src/ast/nodes/method.ts +0 -138
  54. package/src/src/ast/nodes/object-type.ts +0 -52
  55. package/src/src/ast/nodes/object.ts +0 -48
  56. package/src/src/ast/nodes/parameter.ts +0 -85
  57. package/src/src/ast/nodes/property-accessor.ts +0 -173
  58. package/src/src/ast/nodes/property.ts +0 -192
  59. package/src/src/ast/nodes/reference.ts +0 -194
  60. package/src/src/ast/nodes/string.ts +0 -49
  61. package/src/src/ast/nodes/tuple.ts +0 -53
  62. package/src/src/ast/nodes/type-alias.ts +0 -75
  63. package/src/src/ast/nodes/typeof.ts +0 -42
  64. package/src/src/ast/nodes/types.ts +0 -40
  65. package/src/src/ast/nodes/union-type.ts +0 -62
  66. package/src/src/ast/nodes/variable.ts +0 -73
  67. package/src/src/ast/references/angular.ts +0 -24
  68. package/src/src/ast/references/easy-network-stub.ts +0 -21
  69. package/src/src/ast/references/index.ts +0 -5
  70. package/src/src/ast/references/k6.ts +0 -8
  71. package/src/src/ast/references/rxjs.ts +0 -7
  72. package/src/src/ast/references/typescript.ts +0 -35
  73. package/src/src/ast/utils/get-type-script-builder-options.ts +0 -19
  74. package/src/src/ast/utils/to-ts-node.ts +0 -27
  75. package/src/src/ast/utils/write-ts-generic-parameters.ts +0 -25
  76. package/src/src/ast/utils/write-ts-members.ts +0 -28
  77. package/src/src/ast/utils/write-ts-nodes.ts +0 -35
  78. package/src/src/ast/utils/write-ts-parameters.ts +0 -25
  79. package/src/src/common-results.ts +0 -26
  80. package/src/src/config.ts +0 -89
  81. package/src/src/file-builder.ts +0 -136
  82. package/src/src/generators/file-generator.ts +0 -15
  83. package/src/src/generators/index.ts +0 -6
  84. package/src/src/generators/models/index.ts +0 -3
  85. package/src/src/generators/models/model-generator.ts +0 -469
  86. package/src/src/generators/models/models-generator.ts +0 -108
  87. package/src/src/generators/models/models.ts +0 -121
  88. package/src/src/generators/services/angular-services/angular-service-generator.ts +0 -406
  89. package/src/src/generators/services/angular-services/angular-services-generator.ts +0 -295
  90. package/src/src/generators/services/angular-services/index.ts +0 -3
  91. package/src/src/generators/services/angular-services/models.ts +0 -277
  92. package/src/src/generators/services/angular-services/refs.ts +0 -54
  93. package/src/src/generators/services/easy-network-stub/easy-network-stub-generator.ts +0 -242
  94. package/src/src/generators/services/easy-network-stub/easy-network-stubs-generator.ts +0 -211
  95. package/src/src/generators/services/easy-network-stub/index.ts +0 -3
  96. package/src/src/generators/services/easy-network-stub/models.ts +0 -124
  97. package/src/src/generators/services/easy-network-stub/refs.ts +0 -45
  98. package/src/src/generators/services/fetch-clients/fetch-client-generator.ts +0 -275
  99. package/src/src/generators/services/fetch-clients/fetch-clients-generator.ts +0 -163
  100. package/src/src/generators/services/fetch-clients/index.ts +0 -3
  101. package/src/src/generators/services/fetch-clients/models.ts +0 -130
  102. package/src/src/generators/services/fetch-clients/refs.ts +0 -21
  103. package/src/src/generators/services/k6-clients/index.ts +0 -3
  104. package/src/src/generators/services/k6-clients/k6-client-generator.ts +0 -465
  105. package/src/src/generators/services/k6-clients/k6-clients-generator.ts +0 -171
  106. package/src/src/generators/services/k6-clients/models.ts +0 -247
  107. package/src/src/generators/services/k6-clients/refs.ts +0 -16
  108. package/src/src/import-collection.ts +0 -236
  109. package/src/src/utils.ts +0 -72
@@ -1,211 +0,0 @@
1
- import { resolve } from 'node:path';
2
-
3
-
4
- import fs from 'fs-extra';
5
-
6
- import {
7
- adjustCasing,
8
- type ApiService,
9
- type AppendValueGroup,
10
- appendValueGroup,
11
- builderTemplate as s,
12
- Factory,
13
- type MaybePromise,
14
- type OpenApiGeneratorContext,
15
- OpenApiServicesGenerationProviderBase,
16
- toCasing,
17
- } from '@goast/core';
18
-
19
- import { copyAssetFile } from '../../../assets.js';
20
- import { ts } from '../../../ast/index.js';
21
- import type { TypeScriptExportOutput } from '../../../common-results.js';
22
- import { TypeScriptFileBuilder } from '../../../file-builder.js';
23
- import {
24
- DefaultTypeScriptEasyNetworkStubGenerator,
25
- type TypeScriptEasyNetworkStubGenerator,
26
- } from './easy-network-stub-generator.js';
27
- import {
28
- defaultTypeScriptEasyNetworkStubsGeneratorConfig,
29
- type TypeScriptEasyNetworkStubGeneratorOutput,
30
- type TypeScriptEasyNetworkStubsGeneratorConfig,
31
- type TypeScriptEasyNetworkStubsGeneratorContext,
32
- type TypeScriptEasyNetworkStubsGeneratorInput,
33
- type TypeScriptEasyNetworkStubsGeneratorOutput,
34
- } from './models.js';
35
- import { getReferenceFactories } from './refs.js';
36
-
37
- type Input = TypeScriptEasyNetworkStubsGeneratorInput;
38
- type Output = TypeScriptEasyNetworkStubsGeneratorOutput;
39
- type Config = TypeScriptEasyNetworkStubsGeneratorConfig;
40
- type ServiceOutput = TypeScriptEasyNetworkStubGeneratorOutput;
41
- type Context = TypeScriptEasyNetworkStubsGeneratorContext;
42
-
43
- export class TypeScriptEasyNetworkStubsGenerator extends OpenApiServicesGenerationProviderBase<
44
- Input,
45
- Output,
46
- Config,
47
- ServiceOutput,
48
- Context
49
- > {
50
- private readonly _generatorFactory: Factory<TypeScriptEasyNetworkStubGenerator, []>;
51
-
52
- constructor(generatorFactory?: Factory<TypeScriptEasyNetworkStubGenerator, []>) {
53
- super();
54
- this._generatorFactory = generatorFactory ?? Factory.fromValue(new DefaultTypeScriptEasyNetworkStubGenerator());
55
- }
56
-
57
- protected override initResult(): Output {
58
- return {
59
- typescript: {
60
- stubs: {},
61
- indexFiles: { stubs: undefined },
62
- },
63
- };
64
- }
65
-
66
- protected override buildContext(
67
- context: OpenApiGeneratorContext<Input>,
68
- config?: Partial<Config> | undefined,
69
- ): Context {
70
- const providerContext = this.getProviderContext(context, config, defaultTypeScriptEasyNetworkStubsGeneratorConfig);
71
- return Object.assign(providerContext, {
72
- refs: getReferenceFactories(providerContext.config),
73
- });
74
- }
75
-
76
- protected override async generateAdditionalFiles(ctx: TypeScriptEasyNetworkStubsGeneratorContext): Promise<void> {
77
- await this.generateUtilsFiles(ctx);
78
- ctx.output.typescript.indexFiles = this.generateIndexFiles(ctx);
79
- }
80
-
81
- protected override generateService(ctx: Context, service: ApiService): MaybePromise<TypeScriptExportOutput> {
82
- const clientGenerator = this._generatorFactory.create();
83
- return clientGenerator.generate({
84
- ...ctx,
85
- service,
86
- });
87
- }
88
-
89
- protected override addServiceResult(ctx: Context, service: ApiService, result: TypeScriptExportOutput): void {
90
- ctx.output.typescript.stubs[service.id] = result;
91
- }
92
-
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('stubs/easy-network-stub/easy-network-stub.utils.ts', targetDir, 'easy-network-stub utils');
98
- }
99
-
100
- protected generateIndexFiles(ctx: Context): Output['typescript']['indexFiles'] {
101
- const stubsIndexFilePath = this.getStubsIndexFilePath(ctx);
102
-
103
- TypeScriptFileBuilder.tryGenerate({
104
- logName: 'stubs index file',
105
- filePath: stubsIndexFilePath,
106
- options: ctx.config,
107
- generator: (b) => b.append(this.getStubsIndexFileContent(ctx)),
108
- });
109
-
110
- return {
111
- stubs: stubsIndexFilePath,
112
- };
113
- }
114
-
115
- protected getStubsIndexFileContent(ctx: Context): AppendValueGroup<TypeScriptFileBuilder> {
116
- return appendValueGroup(
117
- [
118
- appendValueGroup(Object.values(ctx.output.typescript.stubs).map((x) => ts.export(x.component, x.filePath))),
119
- this.getStubsClass(ctx),
120
- ],
121
- '\n',
122
- );
123
- }
124
-
125
- protected getStubsClass(ctx: Context): ts.Class<TypeScriptFileBuilder> {
126
- const fieldCasing = adjustCasing(ctx.config.propertyNameCasing, { prefix: '_' });
127
- const serviceNames = Object.fromEntries(ctx.data.services.map((x) => [x.id, x.name]));
128
- return ts.class(this.getStubsClassName(ctx), {
129
- export: true,
130
- members: [
131
- ts.property('_stubWrapper', {
132
- accessModifier: 'private',
133
- readonly: true,
134
- type: ctx.refs.easyNetworkStubWrapper(),
135
- }),
136
- ...Object.entries(ctx.output.typescript.stubs).map(([id, x]) =>
137
- ts.property<TypeScriptFileBuilder>(toCasing(serviceNames[id], fieldCasing), {
138
- accessModifier: 'private',
139
- optional: true,
140
- type: ctx.refs.easyNetworkStubGroup([ts.reference(x.component, x.filePath), 'this']),
141
- })
142
- ),
143
- ts.constructor({
144
- parameters: [
145
- ts.constructorParameter('stub', { type: ts.refs.easyNetworkStub.easyNetworkStub() }),
146
- ts.constructorParameter('options', {
147
- type: ts.refs.partial([ctx.refs.easyNetworkStubWrapperOptions()]),
148
- optional: true,
149
- }),
150
- ],
151
- body: appendValueGroup(
152
- [s`this._stubWrapper = new ${ctx.refs.easyNetworkStubWrapper()}(stub, options);`],
153
- '\n',
154
- ),
155
- }),
156
- ts.property('requests', {
157
- accessModifier: 'public',
158
- type: ts.arrayType(ctx.refs.stubRequestItem(), { readonly: true }),
159
- get: ts.property.getter({
160
- body: appendValueGroup(['return this._stubWrapper.requests;'], '\n'),
161
- }),
162
- }),
163
- ...Object.entries(ctx.output.typescript.stubs).map(([id, x]) =>
164
- ts.property<TypeScriptFileBuilder>(toCasing(serviceNames[id], ctx.config.propertyNameCasing), {
165
- accessModifier: 'public',
166
- type: ctx.refs.easyNetworkStubGroup([ts.reference(x.component, x.filePath), 'this']),
167
- get: ts.property.getter({
168
- body: appendValueGroup(
169
- [
170
- s`return this.${
171
- toCasing(
172
- serviceNames[id],
173
- fieldCasing,
174
- )
175
- } ??= ${ctx.refs.createEasyNetworkStubGroup.infer()}(this, this._stubWrapper, ${
176
- ts.reference(
177
- x.component,
178
- x.filePath,
179
- )
180
- });`,
181
- ],
182
- '\n',
183
- ),
184
- }),
185
- })
186
- ),
187
- ts.method('resetStubs', {
188
- accessModifier: 'public',
189
- returnType: 'this',
190
- body: appendValueGroup(
191
- [
192
- ...Object.keys(ctx.output.typescript.stubs).map((id) =>
193
- `this.${toCasing(serviceNames[id], fieldCasing)}?.reset();`
194
- ),
195
- 'return this;',
196
- ],
197
- '\n',
198
- ),
199
- }),
200
- ],
201
- });
202
- }
203
-
204
- protected getStubsIndexFilePath(ctx: Context): string | null {
205
- return ctx.config.stubsIndexFile ? resolve(ctx.config.outputDir, ctx.config.stubsIndexFile) : null;
206
- }
207
-
208
- protected getStubsClassName(ctx: Context): string {
209
- return toCasing(`${ctx.config.domainName ?? ''}_ApiStubs`, ctx.config.typeNameCasing);
210
- }
211
- }
@@ -1,3 +0,0 @@
1
- export * from './easy-network-stub-generator.js';
2
- export * from './easy-network-stubs-generator.js';
3
- export * from './models.js';
@@ -1,124 +0,0 @@
1
- import type {
2
- ApiSchema,
3
- ApiService,
4
- DefaultGenerationProviderConfig,
5
- ExtendedStringCasing,
6
- Nullable,
7
- OpenApiServicesGenerationProviderContext,
8
- } from '@goast/core';
9
-
10
- import { ts } from '../../../ast/index.js';
11
- import type { TypeScriptExportOutput } from '../../../common-results.js';
12
- import { defaultTypeScriptGeneratorConfig, type TypeScriptGeneratorConfig } from '../../../config.js';
13
- import type { TypeScriptFileBuilder } from '../../../file-builder.js';
14
- import type { TypeScriptModelGeneratorOutput } from '../../models/index.js';
15
- import type { getReferenceFactories } from './refs.js';
16
-
17
- export type TypeScriptEasyNetworkStubsGeneratorConfig = TypeScriptGeneratorConfig & {
18
- /**
19
- * The domain name of the API. Used as a prefix for exported components (e.g. `ApiStubs`).
20
- * @default undefined
21
- */
22
- domainName: Nullable<string>;
23
-
24
- /**
25
- * The default response types for status codes that are not defined in the OpenAPI specification.
26
- * @example
27
- * {
28
- * 400: schemas =>
29
- * schemas.find(s => s.name === 'BadRequestResponse')
30
- * ?? throwExp('BadRequestResponse not found'),
31
- * 404: 'never',
32
- * 500: ts.refs.any(),
33
- * }
34
- * @default
35
- * {
36
- * 401: ts.refs.never(),
37
- * 403: ts.refs.never(),
38
- * 500: ts.refs.never(),
39
- * }
40
- */
41
- defaultStatusCodeResponseTypes: Record<
42
- number,
43
- // deno-lint-ignore ban-types
44
- Exclude<ts.Type<TypeScriptFileBuilder>, Function> | ((schemas: readonly ApiSchema[]) => ApiSchema)
45
- >;
46
-
47
- /**
48
- * The directory where the stubs should be saved. The path is relative to the output directory.
49
- * @default 'stubs'
50
- */
51
- stubsDir: string;
52
-
53
- /**
54
- * The casing of the stub file names. If nullish, the `fileNameCasing` is used.
55
- * @default { casing: 'kebab', suffix: '.stubs' }
56
- */
57
- stubFileNameCasing: Nullable<ExtendedStringCasing>;
58
-
59
- /**
60
- * The index file where all stubs should be exported. The path is relative to the output directory. If nullish, no index file will be generated.
61
- * @default 'stubs.ts'
62
- */
63
- stubsIndexFile: Nullable<string>;
64
-
65
- /**
66
- * The directory where the utilies should be saved. The path is relative to the output directory.
67
- * @default 'utils'
68
- */
69
- utilsDir: string;
70
- };
71
-
72
- export const defaultTypeScriptEasyNetworkStubsGeneratorConfig: DefaultGenerationProviderConfig<
73
- TypeScriptEasyNetworkStubsGeneratorConfig
74
- > = {
75
- ...defaultTypeScriptGeneratorConfig,
76
-
77
- domainName: undefined,
78
- defaultStatusCodeResponseTypes: {
79
- 401: ts.refs.never(),
80
- 403: ts.refs.never(),
81
- 500: ts.refs.never(),
82
- },
83
-
84
- stubsDir: 'stubs',
85
- stubFileNameCasing: { casing: 'kebab', suffix: '.stubs' },
86
- stubsIndexFile: 'stubs.ts',
87
- utilsDir: 'utils',
88
- };
89
-
90
- export type TypeScriptEasyNetworkStubsGeneratorInput = {
91
- typescript: {
92
- models: {
93
- [schemaId: string]: TypeScriptModelGeneratorOutput;
94
- };
95
- };
96
- };
97
-
98
- export type TypeScriptEasyNetworkStubsGeneratorOutput = {
99
- typescript: {
100
- stubs: {
101
- [serviceId: string]: TypeScriptEasyNetworkStubGeneratorOutput;
102
- };
103
- indexFiles: {
104
- stubs: Nullable<string>;
105
- };
106
- };
107
- };
108
-
109
- export type TypeScriptEasyNetworkStubGeneratorOutput = TypeScriptExportOutput;
110
-
111
- export type TypeScriptEasyNetworkStubsGeneratorContext =
112
- & OpenApiServicesGenerationProviderContext<
113
- TypeScriptEasyNetworkStubsGeneratorInput,
114
- TypeScriptEasyNetworkStubsGeneratorOutput,
115
- TypeScriptEasyNetworkStubsGeneratorConfig,
116
- TypeScriptEasyNetworkStubGeneratorOutput
117
- >
118
- & {
119
- refs: ReturnType<typeof getReferenceFactories>;
120
- };
121
-
122
- export type TypeScriptEasyNetworkStubGeneratorContext = TypeScriptEasyNetworkStubsGeneratorContext & {
123
- readonly service: ApiService;
124
- };
@@ -1,45 +0,0 @@
1
- import { join, resolve } from 'node:path';
2
-
3
- import { ts } from '../../../ast/index.js';
4
- import type { TypeScriptEasyNetworkStubsGeneratorConfig } from './models.js';
5
-
6
- // See packages/typescript/assets/stubs/easy-network-stub for reference
7
- export function getReferenceFactories(options: TypeScriptEasyNetworkStubsGeneratorConfig): {
8
- easyNetworkStubWrapperOptions: ts.ModuleReferenceFactory;
9
- stubRequestItem: ts.ModuleReferenceFactory;
10
- stubRequestInfo: ts.GenericModuleReferenceFactory<2>;
11
- strictRouteResponseCallback: ts.GenericModuleReferenceFactory<3>;
12
- getStubResponder: ts.GenericModuleReferenceFactory<1>;
13
- easyNetworkStubWrapper: ts.ModuleReferenceFactory;
14
- easyNetworkStubBase: ts.ModuleReferenceFactory;
15
- easyNetworkStubGroup: ts.GenericModuleReferenceFactory<2>;
16
- createEasyNetworkStubGroup: ts.GenericModuleReferenceFactory<2>;
17
- } {
18
- const utilsDirPath = resolve(options.outputDir, options.utilsDir);
19
- const easyNetworkStubUtilsPath = join(utilsDirPath, 'easy-network-stub.utils.ts');
20
-
21
- return {
22
- // easy-network-stub.utils.ts
23
- easyNetworkStubWrapperOptions: ts.reference.factory('EasyNetworkStubWrapperOptions', easyNetworkStubUtilsPath, {
24
- importType: 'type-import',
25
- }),
26
- stubRequestItem: ts.reference.factory('StubRequestItem', easyNetworkStubUtilsPath, { importType: 'type-import' }),
27
- stubRequestInfo: ts.reference.genericFactory<2>('StubRequestInfo', easyNetworkStubUtilsPath, {
28
- importType: 'type-import',
29
- }),
30
- strictRouteResponseCallback: ts.reference.genericFactory<3>(
31
- 'StrictRouteResponseCallback',
32
- easyNetworkStubUtilsPath,
33
- {
34
- importType: 'type-import',
35
- },
36
- ),
37
- getStubResponder: ts.reference.genericFactory<1>('getStubResponder', easyNetworkStubUtilsPath),
38
- easyNetworkStubWrapper: ts.reference.factory('EasyNetworkStubWrapper', easyNetworkStubUtilsPath),
39
- easyNetworkStubBase: ts.reference.factory('EasyNetworkStubBase', easyNetworkStubUtilsPath),
40
- easyNetworkStubGroup: ts.reference.genericFactory<2>('EasyNetworkStubGroup', easyNetworkStubUtilsPath, {
41
- importType: 'type-import',
42
- }),
43
- createEasyNetworkStubGroup: ts.reference.genericFactory<2>('createEasyNetworkStubGroup', easyNetworkStubUtilsPath),
44
- };
45
- }
@@ -1,275 +0,0 @@
1
- import { resolve } from 'node:path';
2
-
3
- import {
4
- type ApiEndpoint,
5
- type ApiSchema,
6
- type AppendValueGroup,
7
- appendValueGroup,
8
- builderTemplate as s,
9
- type MaybePromise,
10
- toCasing,
11
- } from '@goast/core';
12
-
13
- import { ts } from '../../../ast/index.js';
14
- import { TypeScriptFileBuilder } from '../../../file-builder.js';
15
- import { TypeScriptFileGenerator } from '../../file-generator.js';
16
- import type { TypeScriptFetchClientGeneratorContext, TypeScriptFetchClientGeneratorOutput } from './models.js';
17
-
18
- type Context = TypeScriptFetchClientGeneratorContext;
19
- type Output = TypeScriptFetchClientGeneratorOutput;
20
- type Builder = TypeScriptFileBuilder;
21
-
22
- export interface TypeScriptFetchClientGenerator<TOutput extends Output = Output> {
23
- generate(ctx: Context): MaybePromise<TOutput>;
24
- }
25
-
26
- export class DefaultTypeScriptFetchClientGenerator extends TypeScriptFileGenerator<Context, Output>
27
- implements TypeScriptFetchClientGenerator {
28
- public generate(ctx: Context): MaybePromise<Output> {
29
- const result: Output = {};
30
-
31
- if (this.shouldGenerateInterface(ctx)) {
32
- const filePath = this.getInterfaceFilePath(ctx);
33
- const name = this.getInterfaceName(ctx);
34
-
35
- TypeScriptFileBuilder.generate({
36
- logName: `interface ${name}`,
37
- filePath,
38
- options: ctx.config,
39
- generator: (b) => b.append(this.getInterfaceFileContent(ctx)),
40
- });
41
-
42
- result.clientInterface = { filePath, component: name };
43
- }
44
-
45
- if (this.shouldGenerateClass(ctx)) {
46
- const filePath = this.getClassFilePath(ctx);
47
- const name = this.getClassName(ctx);
48
-
49
- TypeScriptFileBuilder.generate({
50
- logName: `class ${name}`,
51
- filePath,
52
- options: ctx.config,
53
- generator: (b) => b.append(this.getClassFileContent(ctx)),
54
- });
55
-
56
- result.client = { filePath, component: name };
57
- }
58
-
59
- return result;
60
- }
61
-
62
- // #region Interface
63
- protected getInterfaceFileContent(ctx: Context): AppendValueGroup<Builder> {
64
- return appendValueGroup([this.getInterface(ctx)], '\n');
65
- }
66
-
67
- protected getInterface(ctx: Context): ts.Interface<Builder> {
68
- return ts.interface(this.getInterfaceName(ctx), {
69
- doc: ts.doc({
70
- description: ctx.service.description,
71
- tags: [
72
- ctx.service.endpoints.length === 0 || ctx.service.endpoints.some((x) => !x.deprecated)
73
- ? null
74
- : ts.docTag('deprecated'),
75
- ],
76
- }),
77
- export: true,
78
- members: ctx.service.endpoints.map((endpoint) => this.getInterfaceEndpointMethod(ctx, endpoint)),
79
- });
80
- }
81
-
82
- protected getInterfaceEndpointMethod(ctx: Context, endpoint: ApiEndpoint): ts.Method<Builder> {
83
- const params = endpoint.parameters.filter((x) =>
84
- x.target === 'path' || x.target === 'query' || x.target === 'header'
85
- );
86
- const bodySchema = endpoint.requestBody?.content[0]?.schema;
87
- const responseSchema = this.getResponseSchema(ctx, endpoint);
88
- return ts.method(toCasing(endpoint.name, ctx.config.functionNameCasing), {
89
- doc: ts.doc({ description: endpoint.description, tags: [endpoint.deprecated ? ts.docTag('deprecated') : null] }),
90
- parameters: [
91
- params.length > 0
92
- ? ts.parameter('params', {
93
- description: 'Parameters for the endpoint.',
94
- type: ts.objectType({
95
- members: params.map((x) =>
96
- ts.property(toCasing(x.name, ctx.config.propertyNameCasing), {
97
- doc: ts.doc({ tags: [x.deprecated ? ts.docTag('deprecated') : null] }),
98
- type: this.getSchemaType(ctx, x.schema),
99
- optional: !x.required,
100
- })
101
- ),
102
- }),
103
- })
104
- : null,
105
- bodySchema &&
106
- ts.parameter('body', {
107
- description: 'Body for the endpoint.',
108
- type: this.getSchemaType(ctx, bodySchema),
109
- }),
110
- ],
111
- returnType: ts.refs.promise([ctx.refs.typedResponse([this.getSchemaType(ctx, responseSchema, ts.refs.void_())])]),
112
- });
113
- }
114
- // #endregion
115
-
116
- // #region Class
117
- protected getClassFileContent(ctx: Context): AppendValueGroup<Builder> {
118
- return appendValueGroup([this.getDefaultOptionsConstant(ctx), this.getClass(ctx)], '\n');
119
- }
120
-
121
- protected getDefaultOptionsConstant(ctx: Context): ts.Variable<Builder> {
122
- const baseUrl = ctx.service.endpoints.map((x) => x.$src?.document.servers?.find((x) => x.url)?.url).find((x) =>
123
- !!x
124
- );
125
- return ts.variable(this.getDefaultOptionsConstantName(ctx), {
126
- export: true,
127
- readonly: true,
128
- type: ctx.refs.fetchClientOptions(),
129
- value: ts.object({
130
- members: [baseUrl && ts.property('baseUrl', { value: ts.string(baseUrl) })],
131
- }),
132
- });
133
- }
134
-
135
- protected getClass(ctx: Context): ts.Class<Builder> {
136
- return ts.class(this.getClassName(ctx), {
137
- doc: ts.doc({
138
- description: ctx.service.description,
139
- tags: [
140
- ctx.service.endpoints.length === 0 || ctx.service.endpoints.some((x) => !x.deprecated)
141
- ? null
142
- : ts.docTag('deprecated'),
143
- ],
144
- }),
145
- export: true,
146
- implements: this.shouldGenerateInterface(ctx)
147
- ? [ts.reference(this.getInterfaceName(ctx), this.getInterfaceFilePath(ctx))]
148
- : undefined,
149
- members: [
150
- ts.property('options', {
151
- doc: ts.doc({ description: 'Options for the fetch client.' }),
152
- accessModifier: 'public',
153
- type: ctx.refs.fetchClientOptions(),
154
- }),
155
- ts.constructor({
156
- parameters: [
157
- ts.constructorParameter('options', {
158
- type: ts.refs.partial([ctx.refs.fetchClientOptions()]),
159
- optional: true,
160
- }),
161
- ],
162
- body: appendValueGroup(
163
- [s`this.options = { ...${this.getDefaultOptionsConstantName(ctx)}, ...options };`],
164
- '\n',
165
- ),
166
- }),
167
- ...ctx.service.endpoints.map((endpoint) => this.getServiceMethod(ctx, endpoint)),
168
- ],
169
- });
170
- }
171
-
172
- protected getServiceMethod(ctx: Context, endpoint: ApiEndpoint): ts.Method<Builder> {
173
- const method = this.getInterfaceEndpointMethod(ctx, endpoint);
174
- method.accessModifier = 'public';
175
- method.body = appendValueGroup(
176
- [
177
- s`const url = new ${ctx.refs.urlBuilder()}(this.options.baseUrl)${s.indent`
178
- .withPath(${ts.string(endpoint.path)})${(b) =>
179
- b.forEach(endpoint.parameters, (b, p) => {
180
- switch (p.target) {
181
- case 'path':
182
- b.append(
183
- s<Builder>`\n.withPathParam(${ts.string(p.name)}, params.${
184
- toCasing(p.name, ctx.config.paramNameCasing)
185
- })`,
186
- );
187
- break;
188
- case 'query':
189
- b.append(
190
- s<Builder>`\n.withQueryParam(${ts.string(p.name)}, params.${
191
- toCasing(p.name, ctx.config.paramNameCasing)
192
- })`,
193
- );
194
- break;
195
- }
196
- })}
197
- .build();`}`,
198
- 'const headers = { ...this.options.headers };',
199
- ...endpoint.parameters.filter((x) => x.target === 'header').map((p) =>
200
- s<Builder>`if (params && params.${toCasing(p.name, ctx.config.paramNameCasing)} !== undefined) {${s.indent`
201
- headers[${ts.string(p.name)}] = String(params.${toCasing(p.name, ctx.config.paramNameCasing)});`}
202
- }`
203
- ),
204
- s`const response = (this.options.fetch ?? fetch)(url, ${
205
- ts.object({
206
- members: [
207
- ts.property('method', { value: ts.string(toCasing(endpoint.method, 'all-upper')) }),
208
- ts.property('headers', { value: 'headers' }),
209
- endpoint.requestBody?.content[0]?.schema ? ts.property('body', { value: 'JSON.stringify(body)' }) : null,
210
- ],
211
- })
212
- });`,
213
- s`Object.defineProperty(response, 'isVoidResponse', { value: ${
214
- this.getResponseSchema(ctx, endpoint) ? 'false' : 'true'
215
- } });`,
216
- s`return response as unknown as ${method.returnType ?? 'unknown'};`,
217
- ],
218
- '\n',
219
- );
220
- return method;
221
- }
222
- // #endregion
223
-
224
- protected getSchemaType(ctx: Context, schema: ApiSchema | undefined, fallback?: ts.Type<Builder>): ts.Type<Builder> {
225
- const output = schema && ctx.input.typescript.models[schema.id];
226
- if (!output) return fallback ?? this.getAnyType(ctx);
227
- return (b) => b.appendModelUsage(output);
228
- }
229
-
230
- protected shouldGenerateInterface(ctx: Context): boolean {
231
- return ctx.config.clientFileKind === 'interface' || ctx.config.clientFileKind === 'class-and-interface';
232
- }
233
-
234
- protected shouldGenerateClass(ctx: Context): boolean {
235
- return ctx.config.clientFileKind === 'class' || ctx.config.clientFileKind === 'class-and-interface';
236
- }
237
-
238
- protected getInterfaceName(ctx: Context): string {
239
- return toCasing(ctx.service.name, ctx.config.clientInterfaceNameCasing ?? ctx.config.typeNameCasing);
240
- }
241
-
242
- protected getClassName(ctx: Context): string {
243
- return toCasing(ctx.service.name, ctx.config.clientNameCasing ?? ctx.config.typeNameCasing);
244
- }
245
-
246
- protected getDefaultOptionsConstantName(ctx: Context): string {
247
- return toCasing(this.getClassName(ctx) + '-default-options', ctx.config.constantNameCasing);
248
- }
249
-
250
- protected getInterfaceFilePath(ctx: Context): string {
251
- return resolve(
252
- ctx.config.outputDir,
253
- ctx.config.clientInterfaceDir ?? ctx.config.clientDir,
254
- `${toCasing(ctx.service.name, ctx.config.clientInterfaceFileNameCasing ?? ctx.config.fileNameCasing)}.ts`,
255
- );
256
- }
257
-
258
- protected getClassFilePath(ctx: Context): string {
259
- return resolve(
260
- ctx.config.outputDir,
261
- ctx.config.clientDir,
262
- `${toCasing(ctx.service.name, ctx.config.clientFileNameCasing ?? ctx.config.fileNameCasing)}.ts`,
263
- );
264
- }
265
-
266
- protected getUtilPath(ctx: Context, fileName: string): string {
267
- return resolve(ctx.config.outputDir, ctx.config.utilsDir, fileName);
268
- }
269
-
270
- private getResponseSchema(_ctx: Context, endpoint: ApiEndpoint) {
271
- const successResponse = endpoint.responses.find((x) => x.statusCode === 200) ??
272
- endpoint.responses.find((x) => x.statusCode && x.statusCode > 200 && x.statusCode < 300);
273
- return successResponse?.contentOptions?.find((x) => x.schema !== undefined)?.schema;
274
- }
275
- }