@goast/typescript 0.6.0-beta.2 → 0.6.0
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.
- package/LICENSE +21 -21
- package/esm/src/generators/models/model-generator.d.ts.map +1 -1
- package/esm/src/generators/models/model-generator.js +0 -1
- package/package.json +2 -2
- package/script/src/generators/models/model-generator.d.ts.map +1 -1
- package/script/src/generators/models/model-generator.js +0 -1
- package/src/mod.ts +7 -0
- package/src/src/assets.ts +9 -0
- package/src/src/ast/_index.ts +54 -0
- package/src/src/ast/common.ts +1 -0
- package/src/src/ast/index.ts +1 -0
- package/src/src/ast/node.ts +10 -0
- package/src/src/ast/nodes/argument.ts +40 -0
- package/src/src/ast/nodes/array-type.ts +49 -0
- package/src/src/ast/nodes/arrow-function.ts +91 -0
- package/src/src/ast/nodes/call.ts +55 -0
- package/src/src/ast/nodes/class.ts +133 -0
- package/src/src/ast/nodes/constructor-parameter.ts +70 -0
- package/src/src/ast/nodes/constructor.ts +77 -0
- package/src/src/ast/nodes/decorator.ts +76 -0
- package/src/src/ast/nodes/doc-tag.ts +291 -0
- package/src/src/ast/nodes/doc.ts +102 -0
- package/src/src/ast/nodes/enum-value.ts +72 -0
- package/src/src/ast/nodes/enum.ts +77 -0
- package/src/src/ast/nodes/export.ts +54 -0
- package/src/src/ast/nodes/function-type.ts +60 -0
- package/src/src/ast/nodes/function.ts +107 -0
- package/src/src/ast/nodes/generic-parameter.ts +71 -0
- package/src/src/ast/nodes/indexer.ts +60 -0
- package/src/src/ast/nodes/interface.ts +117 -0
- package/src/src/ast/nodes/intersection-type.ts +67 -0
- package/src/src/ast/nodes/lookup-type.ts +53 -0
- package/src/src/ast/nodes/method.ts +138 -0
- package/src/src/ast/nodes/object-type.ts +52 -0
- package/src/src/ast/nodes/object.ts +48 -0
- package/src/src/ast/nodes/parameter.ts +85 -0
- package/src/src/ast/nodes/property-accessor.ts +173 -0
- package/src/src/ast/nodes/property.ts +192 -0
- package/src/src/ast/nodes/reference.ts +194 -0
- package/src/src/ast/nodes/string.ts +49 -0
- package/src/src/ast/nodes/tuple.ts +53 -0
- package/src/src/ast/nodes/type-alias.ts +75 -0
- package/src/src/ast/nodes/typeof.ts +42 -0
- package/src/src/ast/nodes/types.ts +40 -0
- package/src/src/ast/nodes/union-type.ts +62 -0
- package/src/src/ast/nodes/variable.ts +73 -0
- package/src/src/ast/references/angular.ts +24 -0
- package/src/src/ast/references/easy-network-stub.ts +21 -0
- package/src/src/ast/references/index.ts +5 -0
- package/src/src/ast/references/k6.ts +8 -0
- package/src/src/ast/references/rxjs.ts +7 -0
- package/src/src/ast/references/typescript.ts +35 -0
- package/src/src/ast/utils/get-type-script-builder-options.ts +19 -0
- package/src/src/ast/utils/to-ts-node.ts +27 -0
- package/src/src/ast/utils/write-ts-generic-parameters.ts +25 -0
- package/src/src/ast/utils/write-ts-members.ts +28 -0
- package/src/src/ast/utils/write-ts-nodes.ts +35 -0
- package/src/src/ast/utils/write-ts-parameters.ts +25 -0
- package/src/src/common-results.ts +26 -0
- package/src/src/config.ts +89 -0
- package/src/src/file-builder.ts +137 -0
- package/src/src/generators/file-generator.ts +15 -0
- package/src/src/generators/index.ts +6 -0
- package/src/src/generators/models/index.ts +3 -0
- package/src/src/generators/models/model-generator.ts +476 -0
- package/src/src/generators/models/models-generator.ts +108 -0
- package/src/src/generators/models/models.ts +121 -0
- package/src/src/generators/services/angular-services/angular-service-generator.ts +414 -0
- package/src/src/generators/services/angular-services/angular-services-generator.ts +295 -0
- package/src/src/generators/services/angular-services/index.ts +3 -0
- package/src/src/generators/services/angular-services/models.ts +277 -0
- package/src/src/generators/services/angular-services/refs.ts +54 -0
- package/src/src/generators/services/easy-network-stub/easy-network-stub-generator.ts +250 -0
- package/src/src/generators/services/easy-network-stub/easy-network-stubs-generator.ts +211 -0
- package/src/src/generators/services/easy-network-stub/index.ts +3 -0
- package/src/src/generators/services/easy-network-stub/models.ts +124 -0
- package/src/src/generators/services/easy-network-stub/refs.ts +45 -0
- package/src/src/generators/services/fetch-clients/fetch-client-generator.ts +285 -0
- package/src/src/generators/services/fetch-clients/fetch-clients-generator.ts +163 -0
- package/src/src/generators/services/fetch-clients/index.ts +3 -0
- package/src/src/generators/services/fetch-clients/models.ts +130 -0
- package/src/src/generators/services/fetch-clients/refs.ts +21 -0
- package/src/src/generators/services/k6-clients/index.ts +3 -0
- package/src/src/generators/services/k6-clients/k6-client-generator.ts +474 -0
- package/src/src/generators/services/k6-clients/k6-clients-generator.ts +171 -0
- package/src/src/generators/services/k6-clients/models.ts +247 -0
- package/src/src/generators/services/k6-clients/refs.ts +16 -0
- package/src/src/import-collection.ts +236 -0
- package/src/src/utils.ts +72 -0
|
@@ -0,0 +1,295 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ApiEndpoint,
|
|
3
|
+
ApiSchema,
|
|
4
|
+
ApiService,
|
|
5
|
+
DefaultGenerationProviderConfig,
|
|
6
|
+
ExtendedStringCasing,
|
|
7
|
+
Nullable,
|
|
8
|
+
OpenApiServicesGenerationProviderContext,
|
|
9
|
+
} from '@goast/core';
|
|
10
|
+
|
|
11
|
+
import type { ts } from '../../../ast/index.js';
|
|
12
|
+
import type { TypeScriptExportOutput } from '../../../common-results.js';
|
|
13
|
+
import { defaultTypeScriptGeneratorConfig, type TypeScriptGeneratorConfig } from '../../../config.js';
|
|
14
|
+
import type { TypeScriptFileBuilder } from '../../../file-builder.js';
|
|
15
|
+
import type { TypeScriptModelGeneratorOutput } from '../../models/index.js';
|
|
16
|
+
import type { getReferenceFactories } from './refs.js';
|
|
17
|
+
|
|
18
|
+
export type TypeScriptAngularServicesGeneratorConfig = TypeScriptGeneratorConfig & {
|
|
19
|
+
/**
|
|
20
|
+
* How the services should be provided in the Angular application.
|
|
21
|
+
* - `root` - provides all the services using `Injectable({ providedIn: 'root' })`
|
|
22
|
+
* - `provide-fn` - generates a function `provideApiClients` that provides the services
|
|
23
|
+
* @default 'root'
|
|
24
|
+
*/
|
|
25
|
+
provideKind: 'root' | 'provide-fn';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The domain name of the API. Used as a prefix for exported components (e.g. `ApiConfiguration`).
|
|
29
|
+
* @default undefined
|
|
30
|
+
*/
|
|
31
|
+
domainName: Nullable<string>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Whether to use strict response types for the services.
|
|
35
|
+
* If enabled only the status codes are included that are defined in the OpenAPI specification or the `defaultStatusCodeResponseTypes` option.
|
|
36
|
+
* @default true
|
|
37
|
+
*/
|
|
38
|
+
strictResponseTypes: boolean;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The default response types for status codes that are not defined in the OpenAPI specification.
|
|
42
|
+
* @example
|
|
43
|
+
* {
|
|
44
|
+
* 400: {
|
|
45
|
+
* parser: 'json',
|
|
46
|
+
* type: schemas =>
|
|
47
|
+
* schemas.find(s => s.name === 'BadRequestResponse')
|
|
48
|
+
* ?? throwExp('BadRequestResponse not found'),
|
|
49
|
+
* },
|
|
50
|
+
* 404: null,
|
|
51
|
+
* 500: {
|
|
52
|
+
* parser: 'json',
|
|
53
|
+
* type: ts.refs.any(),
|
|
54
|
+
* },
|
|
55
|
+
* }
|
|
56
|
+
* @default
|
|
57
|
+
* {
|
|
58
|
+
* 401: null,
|
|
59
|
+
* 403: null,
|
|
60
|
+
* 500: null,
|
|
61
|
+
* }
|
|
62
|
+
*/
|
|
63
|
+
defaultStatusCodeResponseTypes: Record<
|
|
64
|
+
number,
|
|
65
|
+
{
|
|
66
|
+
parser: 'text' | 'json';
|
|
67
|
+
// deno-lint-ignore ban-types
|
|
68
|
+
type: Exclude<ts.Type<TypeScriptFileBuilder>, Function> | ((schemas: readonly ApiSchema[]) => ApiSchema);
|
|
69
|
+
} | null
|
|
70
|
+
>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The default content type which is used for the request. If not defined the first one defined in the OpenApi specification is used.
|
|
74
|
+
* @default undefined
|
|
75
|
+
*/
|
|
76
|
+
defaultRequestContentType: Nullable<string>;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The default content type which is used for the success response. If not defined the first one defined in the OpenApi specification is used.
|
|
80
|
+
* @default undefined
|
|
81
|
+
*/
|
|
82
|
+
defaultSuccessResponseContentType: Nullable<string>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The possible status codes that any API endpoint can return.
|
|
86
|
+
* This is only used when `strictResponseTypes` is set to `false`.
|
|
87
|
+
* @default
|
|
88
|
+
* [100, 101, 102, 103, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451, 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511]
|
|
89
|
+
*/
|
|
90
|
+
possibleStatusCodes: number[];
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Explicitly set the root URL of the API. If `undefined`, the root URL is taken from the first `server` in the OpenAPI specification.
|
|
94
|
+
* @default undefined
|
|
95
|
+
*/
|
|
96
|
+
rootUrl: Nullable<string | RegExp | ((rootUrl: string) => string)>;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Modifier that is applied to the path of each endpoint.
|
|
100
|
+
* @default undefined
|
|
101
|
+
*/
|
|
102
|
+
pathModifier: Nullable<RegExp | ((path: string, endpoint: ApiEndpoint) => string)>;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The directory where the services should be saved. The path is relative to the output directory.
|
|
106
|
+
* @default 'services'
|
|
107
|
+
*/
|
|
108
|
+
servicesDir: string;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The casing of the file names for the services. If nullish, the `fileNameCasing` is used.
|
|
112
|
+
* @default { casing: 'kebab', suffix: '.service' }
|
|
113
|
+
*/
|
|
114
|
+
serviceFileNameCasing: Nullable<ExtendedStringCasing>;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The path to the index file where all services should be exported. The path is relative to the output directory. If nullish, no index file will be generated.
|
|
118
|
+
* @default 'services.ts'
|
|
119
|
+
*/
|
|
120
|
+
servicesIndexFile: Nullable<string>;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The directory where the response models should be saved. The path is relative to the output directory.
|
|
124
|
+
* @default 'models/responses'
|
|
125
|
+
*/
|
|
126
|
+
responseModelsDir: string;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The casing of the file names for the response models. If nullish, the `fileNameCasing` is used.
|
|
130
|
+
* @default { casing: 'kebab', suffix: '-responses.model' }
|
|
131
|
+
*/
|
|
132
|
+
responseModelFileNameCasing: Nullable<ExtendedStringCasing>;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The path to the index file where all response models should be exported. The path is relative to the output directory. If nullish, no index file will be generated.
|
|
136
|
+
* @default 'responses.ts'
|
|
137
|
+
*/
|
|
138
|
+
responseModelsIndexFile: Nullable<string>;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* The directory where the utilies should be saved. The path is relative to the output directory.
|
|
142
|
+
* @default 'utils'
|
|
143
|
+
*/
|
|
144
|
+
utilsDir: string;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const defaultTypeScriptAngularServicesGeneratorConfig: DefaultGenerationProviderConfig<
|
|
148
|
+
TypeScriptAngularServicesGeneratorConfig
|
|
149
|
+
> = {
|
|
150
|
+
...defaultTypeScriptGeneratorConfig,
|
|
151
|
+
|
|
152
|
+
provideKind: 'provide-fn',
|
|
153
|
+
domainName: undefined,
|
|
154
|
+
strictResponseTypes: true,
|
|
155
|
+
defaultStatusCodeResponseTypes: {
|
|
156
|
+
401: null,
|
|
157
|
+
403: null,
|
|
158
|
+
500: null,
|
|
159
|
+
},
|
|
160
|
+
defaultRequestContentType: undefined,
|
|
161
|
+
defaultSuccessResponseContentType: undefined,
|
|
162
|
+
possibleStatusCodes: [
|
|
163
|
+
100,
|
|
164
|
+
101,
|
|
165
|
+
102,
|
|
166
|
+
103,
|
|
167
|
+
200,
|
|
168
|
+
201,
|
|
169
|
+
202,
|
|
170
|
+
203,
|
|
171
|
+
204,
|
|
172
|
+
205,
|
|
173
|
+
206,
|
|
174
|
+
207,
|
|
175
|
+
208,
|
|
176
|
+
226,
|
|
177
|
+
300,
|
|
178
|
+
301,
|
|
179
|
+
302,
|
|
180
|
+
303,
|
|
181
|
+
304,
|
|
182
|
+
305,
|
|
183
|
+
306,
|
|
184
|
+
307,
|
|
185
|
+
308,
|
|
186
|
+
400,
|
|
187
|
+
401,
|
|
188
|
+
402,
|
|
189
|
+
403,
|
|
190
|
+
404,
|
|
191
|
+
405,
|
|
192
|
+
406,
|
|
193
|
+
407,
|
|
194
|
+
408,
|
|
195
|
+
409,
|
|
196
|
+
410,
|
|
197
|
+
411,
|
|
198
|
+
412,
|
|
199
|
+
413,
|
|
200
|
+
414,
|
|
201
|
+
415,
|
|
202
|
+
416,
|
|
203
|
+
417,
|
|
204
|
+
421,
|
|
205
|
+
422,
|
|
206
|
+
423,
|
|
207
|
+
424,
|
|
208
|
+
425,
|
|
209
|
+
426,
|
|
210
|
+
428,
|
|
211
|
+
429,
|
|
212
|
+
431,
|
|
213
|
+
451,
|
|
214
|
+
500,
|
|
215
|
+
501,
|
|
216
|
+
502,
|
|
217
|
+
503,
|
|
218
|
+
504,
|
|
219
|
+
505,
|
|
220
|
+
506,
|
|
221
|
+
507,
|
|
222
|
+
508,
|
|
223
|
+
510,
|
|
224
|
+
511,
|
|
225
|
+
],
|
|
226
|
+
rootUrl: undefined,
|
|
227
|
+
pathModifier: undefined,
|
|
228
|
+
|
|
229
|
+
servicesDir: 'services',
|
|
230
|
+
serviceFileNameCasing: { casing: 'kebab', suffix: '.service' },
|
|
231
|
+
servicesIndexFile: 'services.ts',
|
|
232
|
+
responseModelsDir: 'models/responses',
|
|
233
|
+
responseModelFileNameCasing: { casing: 'kebab', suffix: '-responses.model' },
|
|
234
|
+
responseModelsIndexFile: 'responses.ts',
|
|
235
|
+
utilsDir: 'utils',
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
export type TypeScriptAngularServicesGeneratorInput = {
|
|
239
|
+
typescript: {
|
|
240
|
+
models: {
|
|
241
|
+
[schemaId: string]: TypeScriptModelGeneratorOutput;
|
|
242
|
+
};
|
|
243
|
+
};
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
export type TypeScriptAngularServicesGeneratorOutput = {
|
|
247
|
+
typescript: {
|
|
248
|
+
services: {
|
|
249
|
+
[serviceId: string]: TypeScriptAngularServiceGeneratorOutput;
|
|
250
|
+
};
|
|
251
|
+
indexFiles: {
|
|
252
|
+
services: Nullable<string>;
|
|
253
|
+
responseModels: Nullable<string>;
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
export type TypeScriptAngularServiceGeneratorOutput = TypeScriptExportOutput & {
|
|
259
|
+
responseModels: {
|
|
260
|
+
[operationId: string]: TypeScriptExportOutput;
|
|
261
|
+
};
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
export type TypeScriptAngularServicesGeneratorContext =
|
|
265
|
+
& OpenApiServicesGenerationProviderContext<
|
|
266
|
+
TypeScriptAngularServicesGeneratorInput,
|
|
267
|
+
TypeScriptAngularServicesGeneratorOutput,
|
|
268
|
+
TypeScriptAngularServicesGeneratorConfig,
|
|
269
|
+
TypeScriptAngularServiceGeneratorOutput
|
|
270
|
+
>
|
|
271
|
+
& {
|
|
272
|
+
refs: ReturnType<typeof getReferenceFactories>;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
export type TypeScriptAngularServiceGeneratorContext = TypeScriptAngularServicesGeneratorContext & {
|
|
276
|
+
readonly service: ApiService;
|
|
277
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { join, resolve } from 'node:path';
|
|
2
|
+
|
|
3
|
+
import { toCasing } from '@goast/core';
|
|
4
|
+
|
|
5
|
+
import { ts } from '../../../ast/index.js';
|
|
6
|
+
|
|
7
|
+
import type { TypeScriptAngularServicesGeneratorConfig } from './models.js';
|
|
8
|
+
|
|
9
|
+
// See packages/typescript/assets/client/angular for reference
|
|
10
|
+
export function getReferenceFactories(options: TypeScriptAngularServicesGeneratorConfig): {
|
|
11
|
+
abortablePromise: ts.GenericModuleReferenceFactory<1>;
|
|
12
|
+
waitForResponse: ts.GenericModuleReferenceFactory<1>;
|
|
13
|
+
requestBuilder: ts.ModuleReferenceFactory;
|
|
14
|
+
apiConfiguration: ts.ModuleReferenceFactory;
|
|
15
|
+
apiBaseService: ts.ModuleReferenceFactory;
|
|
16
|
+
httpStatusCode: ts.ModuleReferenceFactory;
|
|
17
|
+
provide: ts.ModuleReferenceFactory;
|
|
18
|
+
} {
|
|
19
|
+
const utilsDirPath = resolve(options.outputDir, options.utilsDir);
|
|
20
|
+
return {
|
|
21
|
+
// angular-service.utils.ts
|
|
22
|
+
abortablePromise: ts.reference.genericFactory<1>(
|
|
23
|
+
'AbortablePromise',
|
|
24
|
+
join(utilsDirPath, 'angular-service.utils.ts'),
|
|
25
|
+
{
|
|
26
|
+
importType: 'type-import',
|
|
27
|
+
},
|
|
28
|
+
),
|
|
29
|
+
waitForResponse: ts.reference.genericFactory<1>('waitForResponse', join(utilsDirPath, 'angular-service.utils.ts')),
|
|
30
|
+
|
|
31
|
+
// request-builder.ts
|
|
32
|
+
requestBuilder: ts.reference.factory('RequestBuilder', join(utilsDirPath, 'request-builder.ts')),
|
|
33
|
+
|
|
34
|
+
// api-configuration.ts - generated in angular-services-generator.ts
|
|
35
|
+
apiConfiguration: ts.reference.factory(
|
|
36
|
+
toCasing(`${options.domainName ?? ''}ApiConfiguration`, options.typeNameCasing),
|
|
37
|
+
join(utilsDirPath, 'api-configuration.ts'),
|
|
38
|
+
),
|
|
39
|
+
|
|
40
|
+
// api-base-service.ts - generated in angular-service-generator.ts
|
|
41
|
+
apiBaseService: ts.reference.factory('ApiBaseService', join(utilsDirPath, 'api-base-service.ts')),
|
|
42
|
+
|
|
43
|
+
// http-status-code.ts - generated in angular-services-generator.ts
|
|
44
|
+
httpStatusCode: ts.reference.factory('HttpStatusCode', join(utilsDirPath, 'http-status-code.ts'), {
|
|
45
|
+
importType: 'type-import',
|
|
46
|
+
}),
|
|
47
|
+
|
|
48
|
+
// provide.ts - generated in angular-services-generator.ts
|
|
49
|
+
provide: ts.reference.factory(
|
|
50
|
+
toCasing(`provide_${options.domainName ?? ''}_Api`, options.functionNameCasing),
|
|
51
|
+
join(utilsDirPath, 'provide.ts'),
|
|
52
|
+
),
|
|
53
|
+
};
|
|
54
|
+
}
|