@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.
- package/LICENSE +21 -21
- package/assets/client/k6/request-builder.js +4 -0
- package/assets/client/k6/request-builder.ts +4 -0
- package/assets/stubs/easy-network-stub/easy-network-stub.utils.ts +2 -6
- package/package.json +2 -2
- package/src/mod.ts +0 -7
- package/src/src/assets.ts +0 -9
- package/src/src/ast/_index.ts +0 -54
- package/src/src/ast/common.ts +0 -1
- package/src/src/ast/index.ts +0 -1
- package/src/src/ast/node.ts +0 -10
- package/src/src/ast/nodes/argument.ts +0 -40
- package/src/src/ast/nodes/array-type.ts +0 -49
- package/src/src/ast/nodes/arrow-function.ts +0 -91
- package/src/src/ast/nodes/call.ts +0 -55
- package/src/src/ast/nodes/class.ts +0 -133
- package/src/src/ast/nodes/constructor-parameter.ts +0 -70
- package/src/src/ast/nodes/constructor.ts +0 -77
- package/src/src/ast/nodes/decorator.ts +0 -76
- package/src/src/ast/nodes/doc-tag.ts +0 -291
- package/src/src/ast/nodes/doc.ts +0 -102
- package/src/src/ast/nodes/enum-value.ts +0 -72
- package/src/src/ast/nodes/enum.ts +0 -77
- package/src/src/ast/nodes/export.ts +0 -54
- package/src/src/ast/nodes/function-type.ts +0 -60
- package/src/src/ast/nodes/function.ts +0 -107
- package/src/src/ast/nodes/generic-parameter.ts +0 -71
- package/src/src/ast/nodes/indexer.ts +0 -60
- package/src/src/ast/nodes/interface.ts +0 -117
- package/src/src/ast/nodes/intersection-type.ts +0 -67
- package/src/src/ast/nodes/lookup-type.ts +0 -53
- package/src/src/ast/nodes/method.ts +0 -138
- package/src/src/ast/nodes/object-type.ts +0 -52
- package/src/src/ast/nodes/object.ts +0 -48
- package/src/src/ast/nodes/parameter.ts +0 -85
- package/src/src/ast/nodes/property-accessor.ts +0 -173
- package/src/src/ast/nodes/property.ts +0 -192
- package/src/src/ast/nodes/reference.ts +0 -194
- package/src/src/ast/nodes/string.ts +0 -49
- package/src/src/ast/nodes/tuple.ts +0 -53
- package/src/src/ast/nodes/type-alias.ts +0 -75
- package/src/src/ast/nodes/typeof.ts +0 -42
- package/src/src/ast/nodes/types.ts +0 -40
- package/src/src/ast/nodes/union-type.ts +0 -62
- package/src/src/ast/nodes/variable.ts +0 -73
- package/src/src/ast/references/angular.ts +0 -24
- package/src/src/ast/references/easy-network-stub.ts +0 -21
- package/src/src/ast/references/index.ts +0 -5
- package/src/src/ast/references/k6.ts +0 -8
- package/src/src/ast/references/rxjs.ts +0 -7
- package/src/src/ast/references/typescript.ts +0 -35
- package/src/src/ast/utils/get-type-script-builder-options.ts +0 -19
- package/src/src/ast/utils/to-ts-node.ts +0 -27
- package/src/src/ast/utils/write-ts-generic-parameters.ts +0 -25
- package/src/src/ast/utils/write-ts-members.ts +0 -28
- package/src/src/ast/utils/write-ts-nodes.ts +0 -35
- package/src/src/ast/utils/write-ts-parameters.ts +0 -25
- package/src/src/common-results.ts +0 -26
- package/src/src/config.ts +0 -89
- package/src/src/file-builder.ts +0 -137
- package/src/src/generators/file-generator.ts +0 -15
- package/src/src/generators/index.ts +0 -6
- package/src/src/generators/models/index.ts +0 -3
- package/src/src/generators/models/model-generator.ts +0 -481
- package/src/src/generators/models/models-generator.ts +0 -108
- package/src/src/generators/models/models.ts +0 -121
- package/src/src/generators/services/angular-services/angular-service-generator.ts +0 -414
- package/src/src/generators/services/angular-services/angular-services-generator.ts +0 -295
- package/src/src/generators/services/angular-services/index.ts +0 -3
- package/src/src/generators/services/angular-services/models.ts +0 -277
- package/src/src/generators/services/angular-services/refs.ts +0 -54
- package/src/src/generators/services/easy-network-stub/easy-network-stub-generator.ts +0 -250
- package/src/src/generators/services/easy-network-stub/easy-network-stubs-generator.ts +0 -211
- package/src/src/generators/services/easy-network-stub/index.ts +0 -3
- package/src/src/generators/services/easy-network-stub/models.ts +0 -124
- package/src/src/generators/services/easy-network-stub/refs.ts +0 -45
- package/src/src/generators/services/fetch-clients/fetch-client-generator.ts +0 -285
- package/src/src/generators/services/fetch-clients/fetch-clients-generator.ts +0 -163
- package/src/src/generators/services/fetch-clients/index.ts +0 -3
- package/src/src/generators/services/fetch-clients/models.ts +0 -130
- package/src/src/generators/services/fetch-clients/refs.ts +0 -21
- package/src/src/generators/services/k6-clients/index.ts +0 -3
- package/src/src/generators/services/k6-clients/k6-client-generator.ts +0 -474
- package/src/src/generators/services/k6-clients/k6-clients-generator.ts +0 -171
- package/src/src/generators/services/k6-clients/models.ts +0 -247
- package/src/src/generators/services/k6-clients/refs.ts +0 -16
- package/src/src/import-collection.ts +0 -236
- package/src/src/utils.ts +0 -72
|
@@ -1,481 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
type ApiSchema,
|
|
5
|
-
type AppendValue,
|
|
6
|
-
type AppendValueGroup,
|
|
7
|
-
appendValueGroup,
|
|
8
|
-
type ArrayLikeApiSchema,
|
|
9
|
-
type CombinedLikeApiSchema,
|
|
10
|
-
DEFAULT_IGNORED_SCHEMA_PROPERTIES,
|
|
11
|
-
getSchemaReference,
|
|
12
|
-
getSourceDisplayName,
|
|
13
|
-
type MaybePromise,
|
|
14
|
-
notNullish,
|
|
15
|
-
type Nullable,
|
|
16
|
-
type ObjectLikeApiSchema,
|
|
17
|
-
resolveAnyOfAndAllOf,
|
|
18
|
-
type StringLikeApiSchema,
|
|
19
|
-
toCasing,
|
|
20
|
-
} from '@goast/core';
|
|
21
|
-
|
|
22
|
-
import { ts } from '../../ast/index.js';
|
|
23
|
-
import type { TypeScriptComponentOutputKind } from '../../common-results.js';
|
|
24
|
-
import { TypeScriptFileBuilder } from '../../file-builder.js';
|
|
25
|
-
import { TypeScriptFileGenerator } from '../file-generator.js';
|
|
26
|
-
import type { TypeScriptModelGeneratorContext, TypeScriptModelGeneratorOutput } from './models.js';
|
|
27
|
-
|
|
28
|
-
type Context = TypeScriptModelGeneratorContext;
|
|
29
|
-
type Output = TypeScriptModelGeneratorOutput;
|
|
30
|
-
type Builder = TypeScriptFileBuilder;
|
|
31
|
-
|
|
32
|
-
export interface TypeScriptModelGenerator<TOutput extends Output = Output> {
|
|
33
|
-
generate(ctx: Context): MaybePromise<TOutput>;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export class DefaultTypeScriptModelGenerator extends TypeScriptFileGenerator<Context, Output>
|
|
37
|
-
implements TypeScriptModelGenerator {
|
|
38
|
-
public generate(ctx: Context): MaybePromise<Output> {
|
|
39
|
-
if (this.shouldGenerateTypeDeclaration(ctx, ctx.schema)) {
|
|
40
|
-
const name = this.getDeclarationTypeName(ctx, ctx.schema);
|
|
41
|
-
const filePath = this.getFilePath(ctx, ctx.schema);
|
|
42
|
-
|
|
43
|
-
const fileContent = this.getFileContent(ctx);
|
|
44
|
-
TypeScriptFileBuilder.generate({
|
|
45
|
-
logName: `model ${getSourceDisplayName(ctx.data, ctx.schema)} [${name}]`,
|
|
46
|
-
filePath,
|
|
47
|
-
options: ctx.config,
|
|
48
|
-
generator: (b) => b.append(fileContent),
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const exports = fileContent.values.filter(
|
|
52
|
-
(x): x is AppendValue<Builder> & { name: string; export: true } =>
|
|
53
|
-
typeof x === 'object' && x !== null && 'export' in x && x.export === true && 'name' in x,
|
|
54
|
-
);
|
|
55
|
-
const node = exports.find((x) => x.name === name);
|
|
56
|
-
return {
|
|
57
|
-
component: name,
|
|
58
|
-
filePath,
|
|
59
|
-
imports: [
|
|
60
|
-
{
|
|
61
|
-
kind: 'file',
|
|
62
|
-
name,
|
|
63
|
-
modulePath: filePath,
|
|
64
|
-
type: node instanceof ts.Interface || node instanceof ts.TypeAlias ? 'type-import' : 'import',
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
additionalExports: exports
|
|
68
|
-
.filter((x) => x.name !== name)
|
|
69
|
-
.map(
|
|
70
|
-
(x) => ({
|
|
71
|
-
name: x.name,
|
|
72
|
-
type: x instanceof ts.TypeAlias || x instanceof ts.Interface ? 'type-export' : 'export',
|
|
73
|
-
} as const),
|
|
74
|
-
),
|
|
75
|
-
kind: this.getNodeKind(node),
|
|
76
|
-
};
|
|
77
|
-
} else {
|
|
78
|
-
const builder = new TypeScriptFileBuilder(undefined, ctx.config);
|
|
79
|
-
builder.append(this.getType(ctx, ctx.schema));
|
|
80
|
-
const imports = builder.imports.imports;
|
|
81
|
-
builder.imports.clear();
|
|
82
|
-
return { component: builder.toString(false), imports };
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
protected getNodeKind(node: unknown): TypeScriptComponentOutputKind | undefined {
|
|
87
|
-
if (node instanceof ts.Interface) return 'interface';
|
|
88
|
-
if (node instanceof ts.TypeAlias) return 'type';
|
|
89
|
-
if (node instanceof ts.Enum) return 'enum';
|
|
90
|
-
if (node instanceof ts.Class) return 'class';
|
|
91
|
-
return undefined;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
protected getFileContent(ctx: Context): AppendValueGroup<Builder> {
|
|
95
|
-
const content = appendValueGroup<Builder>([], '\n');
|
|
96
|
-
const interfaceSchema = this.resolveInterfaceSchema(ctx);
|
|
97
|
-
if (interfaceSchema) {
|
|
98
|
-
content.values.push(this.getInterface(ctx, interfaceSchema));
|
|
99
|
-
} else if (
|
|
100
|
-
ctx.config.enumGeneration !== 'union' &&
|
|
101
|
-
ctx.schema.kind === 'string' &&
|
|
102
|
-
ctx.schema.enum !== undefined &&
|
|
103
|
-
ctx.schema.enum.length > 0
|
|
104
|
-
) {
|
|
105
|
-
content.values.push(this.getEnum(ctx));
|
|
106
|
-
} else if (ctx.schema.discriminator && Object.keys(ctx.schema.discriminator.mapping).length > 0) {
|
|
107
|
-
content.values.push(
|
|
108
|
-
ts.typeAlias(
|
|
109
|
-
this.getDiscriminatorTypeName(ctx, ctx.schema),
|
|
110
|
-
ts.unionType(Object.keys(ctx.schema.discriminator.mapping).map((x) => ts.string(x))),
|
|
111
|
-
),
|
|
112
|
-
ts.typeAlias(
|
|
113
|
-
this.getBaseTypeName(ctx, ctx.schema),
|
|
114
|
-
this.getType(ctx, ctx.schema, { skipSchemas: true }) ?? this.getAnyType(ctx),
|
|
115
|
-
{ export: true },
|
|
116
|
-
),
|
|
117
|
-
this.getTypeAlias(ctx, ctx.schema),
|
|
118
|
-
);
|
|
119
|
-
} else {
|
|
120
|
-
content.values.push(this.getTypeAlias(ctx, ctx.schema));
|
|
121
|
-
if (ctx.schema.enum) {
|
|
122
|
-
content.values.push(this.getEnumValuesVariable(ctx, ctx.schema));
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
return content;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
protected getEnum(ctx: Context): ts.Enum<Builder> {
|
|
129
|
-
return ts.enum(this.getDeclarationTypeName(ctx, ctx.schema), {
|
|
130
|
-
doc: ts.doc({
|
|
131
|
-
description: ctx.schema.description,
|
|
132
|
-
tags: [ctx.schema.deprecated ? ts.docTag('deprecated') : null],
|
|
133
|
-
}),
|
|
134
|
-
export: true,
|
|
135
|
-
members: (ctx.schema.enum?.map((x) => String(x)) ?? []).map((x) =>
|
|
136
|
-
ts.enumValue(toCasing(x, ctx.config.enumValueNameCasing), { value: ts.string(x) })
|
|
137
|
-
),
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
protected getInterface(ctx: Context, schema: ObjectLikeApiSchema): ts.Interface<Builder> {
|
|
142
|
-
return ts.interface(this.getDeclarationTypeName(ctx, ctx.schema), {
|
|
143
|
-
export: true,
|
|
144
|
-
doc: ts.doc({
|
|
145
|
-
description: schema.description,
|
|
146
|
-
tags: [ctx.schema.deprecated ? ts.docTag('deprecated') : null],
|
|
147
|
-
}),
|
|
148
|
-
members: [...this.getProperties(ctx, schema), this.getIndexer(ctx, schema)],
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
protected getTypeAlias(ctx: Context, schema: ApiSchema): ts.TypeAlias<Builder> {
|
|
153
|
-
const hasDiscriminator = schema.discriminator && Object.keys(schema.discriminator.mapping).length > 0;
|
|
154
|
-
const result = ts.typeAlias<Builder>(
|
|
155
|
-
this.getDeclarationTypeName(ctx, schema),
|
|
156
|
-
(hasDiscriminator ? this.getDiscriminatorType(ctx, schema) : this.getType(ctx, schema, { skipSchemas: true })) ??
|
|
157
|
-
this.getAnyType(ctx),
|
|
158
|
-
{
|
|
159
|
-
export: true,
|
|
160
|
-
doc: ts.doc({
|
|
161
|
-
description: schema.description,
|
|
162
|
-
tags: [ctx.schema.deprecated ? ts.docTag('deprecated') : null],
|
|
163
|
-
}),
|
|
164
|
-
},
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
if (hasDiscriminator) {
|
|
168
|
-
const propertyValue = this.getDiscriminatorTypeName(ctx, ctx.schema);
|
|
169
|
-
result.generics.push(
|
|
170
|
-
ts.genericParameter(this.getDiscriminatorGenericParamName(ctx, schema), {
|
|
171
|
-
constraint: propertyValue,
|
|
172
|
-
default: propertyValue,
|
|
173
|
-
}),
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const inheritedSchemas = this.getInheritedSchemas(ctx, schema);
|
|
178
|
-
if (inheritedSchemas.length > 0) {
|
|
179
|
-
const fixedProperties = inheritedSchemas.reduce((p, c) => {
|
|
180
|
-
const mappingValues = Object.entries(c.discriminator.mapping)
|
|
181
|
-
.filter(([_, value]) => value.id === schema.id)
|
|
182
|
-
.map(([key]) => ts.string(key));
|
|
183
|
-
if (c.discriminator.propertyName in p) {
|
|
184
|
-
p[c.discriminator.propertyName].types.push(...mappingValues);
|
|
185
|
-
} else {
|
|
186
|
-
p[c.discriminator.propertyName] = ts.unionType(mappingValues);
|
|
187
|
-
}
|
|
188
|
-
return p;
|
|
189
|
-
}, {} as Record<string, ts.UnionType<Builder>>);
|
|
190
|
-
result.type = ts.intersectionType([
|
|
191
|
-
ts.refs.omit([result.type, ts.unionType(Object.keys(fixedProperties).map((x) => ts.string(x)))]),
|
|
192
|
-
ts.objectType({
|
|
193
|
-
members: Object.entries(fixedProperties).map(([key, value]) =>
|
|
194
|
-
ts.property(key, { type: value, readonly: ctx.config.immutableTypes })
|
|
195
|
-
),
|
|
196
|
-
}),
|
|
197
|
-
]);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return result;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
protected getEnumValuesVariable(ctx: Context, schema: ApiSchema): ts.Variable<Builder> {
|
|
204
|
-
const enumTypeName = this.getDeclarationTypeName(ctx, schema);
|
|
205
|
-
const values = schema.enum?.map((x) => ts.toNode(x)) ?? [];
|
|
206
|
-
return ts.variable(toCasing(`${enumTypeName}-Values`, ctx.config.constantNameCasing), {
|
|
207
|
-
doc: ts.doc({
|
|
208
|
-
description: `All possible values of the enum \`${enumTypeName}\`.`,
|
|
209
|
-
}),
|
|
210
|
-
export: true,
|
|
211
|
-
readonly: true,
|
|
212
|
-
value: ts.tuple(values, { asConst: true }),
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
protected getIndexer(ctx: Context, schema: ObjectLikeApiSchema): ts.Indexer<Builder> | null {
|
|
217
|
-
return schema.additionalProperties
|
|
218
|
-
? ts.indexer(
|
|
219
|
-
ts.refs.string(),
|
|
220
|
-
(schema.additionalProperties === true ? null : this.getType(ctx, schema.additionalProperties)) ??
|
|
221
|
-
this.getAnyType(ctx),
|
|
222
|
-
{ readonly: ctx.config.immutableTypes },
|
|
223
|
-
)
|
|
224
|
-
: null;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
protected getProperties(ctx: Context, schema: ObjectLikeApiSchema): ts.Property<Builder>[] {
|
|
228
|
-
return Array.from(schema.properties.values()).map((property) => {
|
|
229
|
-
return ts.property(property.name, {
|
|
230
|
-
doc: ts.doc({
|
|
231
|
-
description: property.schema.description,
|
|
232
|
-
tags: [property.schema.deprecated ? ts.docTag('deprecated') : null],
|
|
233
|
-
}),
|
|
234
|
-
readonly: ctx.config.immutableTypes,
|
|
235
|
-
optional: !schema.required.has(property.name),
|
|
236
|
-
type: ts.unionType([this.getType(ctx, property.schema), property.schema.nullable ? 'null' : null]),
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
protected getType(
|
|
242
|
-
ctx: Context,
|
|
243
|
-
schema: Nullable<ApiSchema>,
|
|
244
|
-
options?: { skipSchemas?: boolean; useBaseType?: boolean },
|
|
245
|
-
): ts.Type<Builder> | null {
|
|
246
|
-
if (!schema) return this.getAnyType(ctx);
|
|
247
|
-
|
|
248
|
-
schema = getSchemaReference(schema, DEFAULT_IGNORED_SCHEMA_PROPERTIES);
|
|
249
|
-
|
|
250
|
-
if (options?.useBaseType && ctx.schema.inheritedSchemas.some((x) => x.id === schema.id)) {
|
|
251
|
-
return ts.reference(this.getBaseTypeName(ctx, schema), this.getFilePath(ctx, schema), {
|
|
252
|
-
importType: 'type-import',
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (!options?.skipSchemas && this.shouldGenerateTypeDeclaration(ctx, schema)) {
|
|
257
|
-
if (schema.id === ctx.schema.id) {
|
|
258
|
-
return null;
|
|
259
|
-
}
|
|
260
|
-
return ts.reference(this.getDeclarationTypeName(ctx, schema), this.getFilePath(ctx, schema), {
|
|
261
|
-
importType: 'type-import',
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
if (schema.enum) {
|
|
266
|
-
return ts.unionType(schema.enum.map((x) => ts.toNode(x)));
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
switch (schema.kind) {
|
|
270
|
-
case 'boolean':
|
|
271
|
-
return 'boolean';
|
|
272
|
-
case 'integer':
|
|
273
|
-
case 'number':
|
|
274
|
-
return 'number';
|
|
275
|
-
case 'string':
|
|
276
|
-
return this.getStringType(ctx, schema);
|
|
277
|
-
case 'null':
|
|
278
|
-
return 'null';
|
|
279
|
-
case 'unknown':
|
|
280
|
-
return this.getAnyType(ctx);
|
|
281
|
-
case 'array':
|
|
282
|
-
return this.getArrayType(ctx, schema);
|
|
283
|
-
case 'object':
|
|
284
|
-
return this.getObjectType(ctx, schema);
|
|
285
|
-
case 'combined':
|
|
286
|
-
return this.getCombinedType(ctx, schema);
|
|
287
|
-
case 'multi-type':
|
|
288
|
-
return this.getMultiType(ctx, schema);
|
|
289
|
-
case 'oneOf':
|
|
290
|
-
return this.getOneOfType(ctx, schema);
|
|
291
|
-
default:
|
|
292
|
-
return this.getAnyType(ctx);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
protected getStringType(ctx: Context, schema: StringLikeApiSchema): ts.Type<Builder> {
|
|
297
|
-
if (schema.format === 'binary') {
|
|
298
|
-
return ctx.config.binarySchemaType();
|
|
299
|
-
}
|
|
300
|
-
return 'string';
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
protected getArrayType(ctx: Context, schema: ArrayLikeApiSchema): ts.Type<Builder> {
|
|
304
|
-
return ts.arrayType(this.getType(ctx, schema.items) ?? this.getAnyType(ctx), {
|
|
305
|
-
readonly: ctx.config.immutableTypes,
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
protected getObjectType(ctx: Context, schema: ObjectLikeApiSchema): ts.Type<Builder> {
|
|
310
|
-
const parts = [
|
|
311
|
-
schema.properties.size > 0 ? ts.objectType({ members: this.getProperties(ctx, schema) }) : null,
|
|
312
|
-
schema.additionalProperties ? ts.objectType({ members: [this.getIndexer(ctx, schema)] }) : null,
|
|
313
|
-
schema.allOf.length > 0 || schema.anyOf.length > 0 ? this.getCombinedType(ctx, schema) : null,
|
|
314
|
-
].filter(notNullish);
|
|
315
|
-
if (parts.length === 0) {
|
|
316
|
-
parts.push(
|
|
317
|
-
ts.objectType({
|
|
318
|
-
members: [ts.indexer(ts.refs.string(), ts.refs.never(), { readonly: ctx.config.immutableTypes })],
|
|
319
|
-
}),
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
return ts.intersectionType(parts);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
protected getDiscriminatorType(ctx: Context, schema: ApiSchema): ts.Type<Builder> {
|
|
326
|
-
if (schema.discriminator && Object.keys(schema.discriminator.mapping).length > 0) {
|
|
327
|
-
const discriminator = schema.discriminator;
|
|
328
|
-
return ts.intersectionType([
|
|
329
|
-
this.getBaseTypeName(ctx, schema as ApiSchema),
|
|
330
|
-
ts.lookupType(
|
|
331
|
-
ts.objectType({
|
|
332
|
-
members: Object.entries(discriminator.mapping).map(([key, value]) =>
|
|
333
|
-
ts.property(key, {
|
|
334
|
-
type: ts.intersectionType([
|
|
335
|
-
ts.objectType({
|
|
336
|
-
members: [
|
|
337
|
-
ts.property(discriminator.propertyName, {
|
|
338
|
-
type: ts.string(key),
|
|
339
|
-
readonly: ctx.config.immutableTypes,
|
|
340
|
-
}),
|
|
341
|
-
],
|
|
342
|
-
}),
|
|
343
|
-
this.getType(ctx, value),
|
|
344
|
-
]),
|
|
345
|
-
})
|
|
346
|
-
),
|
|
347
|
-
}),
|
|
348
|
-
this.getDiscriminatorGenericParamName(ctx, schema as ApiSchema),
|
|
349
|
-
),
|
|
350
|
-
]);
|
|
351
|
-
} else {
|
|
352
|
-
return ts.refs.unknown();
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
protected getCombinedType(ctx: Context, schema: CombinedLikeApiSchema): ts.Type<Builder> {
|
|
357
|
-
if (schema.allOf.length === 0 && schema.anyOf.length === 0) {
|
|
358
|
-
return this.getAnyType(ctx);
|
|
359
|
-
}
|
|
360
|
-
const useBaseType = schema.id === ctx.schema.id;
|
|
361
|
-
return ts.intersectionType([
|
|
362
|
-
...schema.allOf.map((x) => this.getType(ctx, x, { useBaseType })),
|
|
363
|
-
...schema.anyOf.map((x) => ts.reference('Partial', null, { generics: [this.getType(ctx, x, { useBaseType })] })),
|
|
364
|
-
]);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
protected getOneOfType(ctx: Context, schema: ApiSchema<'oneOf'>): ts.Type<Builder> {
|
|
368
|
-
if (schema.oneOf.length === 0) {
|
|
369
|
-
return this.getAnyType(ctx);
|
|
370
|
-
}
|
|
371
|
-
return ts.unionType(schema.oneOf.map((x) => this.getType(ctx, x)));
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
protected getMultiType(ctx: Context, schema: ApiSchema<'multi-type'>): ts.Type<Builder> {
|
|
375
|
-
if (schema.type.length === 0) {
|
|
376
|
-
return this.getAnyType(ctx);
|
|
377
|
-
}
|
|
378
|
-
return ts.unionType(
|
|
379
|
-
schema.type.map((x) => {
|
|
380
|
-
switch (x) {
|
|
381
|
-
case 'string':
|
|
382
|
-
return this.getStringType(ctx, schema);
|
|
383
|
-
case 'number':
|
|
384
|
-
case 'integer':
|
|
385
|
-
return 'number';
|
|
386
|
-
case 'boolean':
|
|
387
|
-
return 'boolean';
|
|
388
|
-
case 'null':
|
|
389
|
-
return 'null';
|
|
390
|
-
case 'array':
|
|
391
|
-
return this.getArrayType(ctx, schema);
|
|
392
|
-
case 'object':
|
|
393
|
-
return this.getObjectType(ctx, schema);
|
|
394
|
-
default:
|
|
395
|
-
return 'never';
|
|
396
|
-
}
|
|
397
|
-
}),
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
protected shouldGenerateTypeDeclaration(ctx: Context, schema: ApiSchema): boolean {
|
|
402
|
-
// All named schemas should have its own type declaration
|
|
403
|
-
if (!schema.isNameGenerated) {
|
|
404
|
-
return true;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// All enum types should have its own type declaration
|
|
408
|
-
if (schema.enum !== undefined && schema.enum.length > 0) {
|
|
409
|
-
return true;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// All primitive types already exist and do not need its own type declaration
|
|
413
|
-
if (
|
|
414
|
-
schema.kind !== 'array' &&
|
|
415
|
-
schema.kind !== 'combined' &&
|
|
416
|
-
schema.kind !== 'multi-type' &&
|
|
417
|
-
schema.kind !== 'object' &&
|
|
418
|
-
schema.kind !== 'oneOf'
|
|
419
|
-
) {
|
|
420
|
-
return false;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// Nullable by oneOf schemas do not need their own type declaration
|
|
424
|
-
if (schema.kind === 'oneOf' && schema.oneOf?.length === 2 && schema.oneOf.some((x) => x.kind === 'null')) {
|
|
425
|
-
return false;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// Dynamically generated schemas do not have its own type declaration
|
|
429
|
-
if (!ctx.data.schemas.some((x) => x.id === schema.id)) {
|
|
430
|
-
return false;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// Check if "real" schema
|
|
434
|
-
if (getSchemaReference(ctx.schema, DEFAULT_IGNORED_SCHEMA_PROPERTIES) !== ctx.schema) {
|
|
435
|
-
return false;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// For all other types, check if the user has enabled inline unnamed schemas
|
|
439
|
-
return !ctx.config.inlineUnnamedSchemas;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
protected resolveInterfaceSchema(ctx: Context): ApiSchema<'object'> | undefined {
|
|
443
|
-
if (
|
|
444
|
-
ctx.config.typeDeclaration === 'prefer-interface' &&
|
|
445
|
-
(ctx.schema.kind === 'object' || ctx.schema.kind === 'combined')
|
|
446
|
-
) {
|
|
447
|
-
return resolveAnyOfAndAllOf(ctx.schema, true);
|
|
448
|
-
}
|
|
449
|
-
return undefined;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
protected getDeclarationTypeName(ctx: Context, schema: ApiSchema): string {
|
|
453
|
-
return toCasing(schema.name, ctx.config.typeNameCasing);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
protected getDiscriminatorGenericParamName(ctx: Context, schema: ApiSchema): string {
|
|
457
|
-
return toCasing(schema.discriminator?.propertyName, ctx.config.genericParamNameCasing);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
protected getDiscriminatorTypeName(ctx: Context, schema: ApiSchema): string {
|
|
461
|
-
return toCasing(schema.name + '_Discriminator', ctx.config.typeNameCasing);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
protected getBaseTypeName(ctx: Context, schema: ApiSchema): string {
|
|
465
|
-
return toCasing(schema.name, ctx.config.discriminatorBaseTypeCasing);
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
protected getInheritedSchemas(ctx: Context, schema: ApiSchema): ApiSchema['inheritedSchemas'] {
|
|
469
|
-
return schema.inheritedSchemas
|
|
470
|
-
.filter((schema) => this.shouldGenerateTypeDeclaration(ctx, schema) && !schema.isNameGenerated)
|
|
471
|
-
.filter((item, index, self) => self.indexOf(item) === index);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
protected getFilePath(ctx: Context, schema: ApiSchema): string {
|
|
475
|
-
return resolve(
|
|
476
|
-
ctx.config.outputDir,
|
|
477
|
-
ctx.config.modelsDir,
|
|
478
|
-
`${toCasing(schema.name, ctx.config.modelFileNameCasing ?? ctx.config.fileNameCasing)}.ts`,
|
|
479
|
-
);
|
|
480
|
-
}
|
|
481
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
type ApiSchema,
|
|
5
|
-
type AppendValueGroup,
|
|
6
|
-
appendValueGroup,
|
|
7
|
-
Factory,
|
|
8
|
-
type MaybePromise,
|
|
9
|
-
type OpenApiGeneratorContext,
|
|
10
|
-
OpenApiSchemasGenerationProviderBase,
|
|
11
|
-
} from '@goast/core';
|
|
12
|
-
|
|
13
|
-
import { ts } from '../../ast/index.js';
|
|
14
|
-
import { TypeScriptFileBuilder } from '../../file-builder.js';
|
|
15
|
-
import { DefaultTypeScriptModelGenerator, type TypeScriptModelGenerator } from './model-generator.js';
|
|
16
|
-
import {
|
|
17
|
-
defaultTypeScriptModelsGeneratorConfig,
|
|
18
|
-
type TypeScriptModelGeneratorOutput,
|
|
19
|
-
type TypeScriptModelsGeneratorConfig,
|
|
20
|
-
type TypeScriptModelsGeneratorContext,
|
|
21
|
-
type TypeScriptModelsGeneratorInput,
|
|
22
|
-
type TypeScriptModelsGeneratorOutput,
|
|
23
|
-
} from './models.js';
|
|
24
|
-
|
|
25
|
-
type Input = TypeScriptModelsGeneratorInput;
|
|
26
|
-
type Output = TypeScriptModelsGeneratorOutput;
|
|
27
|
-
type Config = TypeScriptModelsGeneratorConfig;
|
|
28
|
-
type SchemaOutput = TypeScriptModelGeneratorOutput;
|
|
29
|
-
type Context = TypeScriptModelsGeneratorContext;
|
|
30
|
-
|
|
31
|
-
export class TypeScriptModelsGenerator extends OpenApiSchemasGenerationProviderBase<
|
|
32
|
-
Input,
|
|
33
|
-
Output,
|
|
34
|
-
Config,
|
|
35
|
-
SchemaOutput,
|
|
36
|
-
Context
|
|
37
|
-
> {
|
|
38
|
-
private readonly _modelGeneratorFactory: Factory<TypeScriptModelGenerator, []>;
|
|
39
|
-
|
|
40
|
-
constructor(modelGeneratorFactory?: Factory<TypeScriptModelGenerator, []>) {
|
|
41
|
-
super();
|
|
42
|
-
this._modelGeneratorFactory = modelGeneratorFactory ?? Factory.fromValue(new DefaultTypeScriptModelGenerator());
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
protected override initResult(): Output {
|
|
46
|
-
return {
|
|
47
|
-
typescript: {
|
|
48
|
-
models: {},
|
|
49
|
-
indexFiles: { models: undefined },
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
protected override buildContext(
|
|
55
|
-
context: OpenApiGeneratorContext<TypeScriptModelsGeneratorInput>,
|
|
56
|
-
config?: Partial<Config> | undefined,
|
|
57
|
-
): Context {
|
|
58
|
-
return this.getProviderContext(context, config, defaultTypeScriptModelsGeneratorConfig);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
protected override generateAdditionalFiles(ctx: TypeScriptModelsGeneratorContext): MaybePromise<void> {
|
|
62
|
-
ctx.output.typescript.indexFiles.models = this.generateIndexFile(ctx);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
protected override generateSchema(ctx: Context, schema: ApiSchema): MaybePromise<SchemaOutput> {
|
|
66
|
-
const modelGenerator = this._modelGeneratorFactory.create();
|
|
67
|
-
return modelGenerator.generate({
|
|
68
|
-
...ctx,
|
|
69
|
-
schema,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
protected override addSchemaResult(ctx: Context, schema: ApiSchema, result: SchemaOutput): void {
|
|
74
|
-
ctx.output.typescript.models[schema.id] = result;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
protected generateIndexFile(ctx: Context): string | null {
|
|
78
|
-
const filePath = this.getIndexFilePath(ctx);
|
|
79
|
-
TypeScriptFileBuilder.tryGenerate({
|
|
80
|
-
logName: 'model index file',
|
|
81
|
-
filePath,
|
|
82
|
-
options: ctx.config,
|
|
83
|
-
generator: (b) => b.append(this.getIndexFileContent(ctx)),
|
|
84
|
-
});
|
|
85
|
-
return filePath;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
protected getIndexFilePath(ctx: Context): string | null {
|
|
89
|
-
return ctx.config.modelsIndexFile ? resolve(ctx.config.outputDir, ctx.config.modelsIndexFile) : null;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
protected getIndexFileContent(ctx: Context): AppendValueGroup<TypeScriptFileBuilder> {
|
|
93
|
-
return appendValueGroup(
|
|
94
|
-
Object.values(ctx.output.typescript.models).flatMap((x) => {
|
|
95
|
-
const { filePath } = x;
|
|
96
|
-
if (!filePath) return [];
|
|
97
|
-
return [
|
|
98
|
-
ts.export(x.component, filePath, {
|
|
99
|
-
kind: x.kind === 'type' || x.kind === 'interface' ? 'type-export' : 'export',
|
|
100
|
-
}),
|
|
101
|
-
...(x.additionalExports?.map((e) =>
|
|
102
|
-
typeof e === 'string' ? ts.export(e, filePath) : ts.export(e.name, filePath, { kind: e.type })
|
|
103
|
-
) ?? []),
|
|
104
|
-
];
|
|
105
|
-
}),
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ApiSchema,
|
|
3
|
-
DefaultGenerationProviderConfig,
|
|
4
|
-
ExtendedStringCasing,
|
|
5
|
-
Nullable,
|
|
6
|
-
OpenApiSchemasGenerationProviderContext,
|
|
7
|
-
} from '@goast/core';
|
|
8
|
-
|
|
9
|
-
import { ts } from '../../ast/index.js';
|
|
10
|
-
import type { TypeScriptComponentOutput } from '../../common-results.js';
|
|
11
|
-
import { defaultTypeScriptGeneratorConfig, type TypeScriptGeneratorConfig } from '../../config.js';
|
|
12
|
-
import type { TypeScriptFileBuilder } from '../../file-builder.js';
|
|
13
|
-
|
|
14
|
-
export type TypeScriptModelGeneratorConfig = TypeScriptGeneratorConfig & {
|
|
15
|
-
/**
|
|
16
|
-
* Determines how to generate enums.
|
|
17
|
-
* - 'union': Generate enums as union types.
|
|
18
|
-
* - 'prefer-enum': Generate enums as enums if possible, otherwise as union types.
|
|
19
|
-
* @default 'union'
|
|
20
|
-
*/
|
|
21
|
-
enumGeneration: 'union' | 'prefer-enum';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Whether to generate immutable types.
|
|
25
|
-
* @default false
|
|
26
|
-
*/
|
|
27
|
-
immutableTypes: boolean;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Whether to inline unnamed schemas. If false, unnamed schemas will be generated as separate types.
|
|
31
|
-
* @default true
|
|
32
|
-
*/
|
|
33
|
-
inlineUnnamedSchemas: boolean;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* The directory where the models should be saved. The path is relative to the output directory.
|
|
37
|
-
* @default 'models'
|
|
38
|
-
*/
|
|
39
|
-
modelsDir: string;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* The casing of the model file names. If nullish, the `fileNameCasing` is used.
|
|
43
|
-
* @default undefined
|
|
44
|
-
*/
|
|
45
|
-
modelFileNameCasing: Nullable<ExtendedStringCasing>;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Determines how to declare types.
|
|
49
|
-
* - 'type': Always declare types as `type`.
|
|
50
|
-
* - 'prefer-interface': Prefer `interface` over `type` if possible.
|
|
51
|
-
* @default 'type'
|
|
52
|
-
*/
|
|
53
|
-
typeDeclaration: 'type' | 'prefer-interface';
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* The casing to use for the base type of discriminator schemas.
|
|
57
|
-
* @default `_<SchemaName>Base`
|
|
58
|
-
*/
|
|
59
|
-
discriminatorBaseTypeCasing: ExtendedStringCasing;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* The type to use for binary schemas.
|
|
63
|
-
* @default `ts.refs.blob`
|
|
64
|
-
*/
|
|
65
|
-
binarySchemaType: () => ts.Type<TypeScriptFileBuilder>;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export type TypeScriptModelsGeneratorConfig = TypeScriptModelGeneratorConfig & {
|
|
69
|
-
/**
|
|
70
|
-
* The path to the index file where all models should be exported. If nullish, no index file will be generated.
|
|
71
|
-
* @default 'models.ts'
|
|
72
|
-
*/
|
|
73
|
-
modelsIndexFile: Nullable<string>;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
export const defaultTypeScriptModelGeneratorConfig: DefaultGenerationProviderConfig<TypeScriptModelGeneratorConfig> = {
|
|
77
|
-
...defaultTypeScriptGeneratorConfig,
|
|
78
|
-
|
|
79
|
-
enumGeneration: 'union',
|
|
80
|
-
immutableTypes: false,
|
|
81
|
-
inlineUnnamedSchemas: true,
|
|
82
|
-
modelsDir: 'models',
|
|
83
|
-
modelFileNameCasing: undefined,
|
|
84
|
-
typeDeclaration: 'type',
|
|
85
|
-
discriminatorBaseTypeCasing: { casing: 'pascal', prefix: '_', suffix: 'Base' },
|
|
86
|
-
binarySchemaType: ts.refs.blob,
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
export const defaultTypeScriptModelsGeneratorConfig: DefaultGenerationProviderConfig<TypeScriptModelsGeneratorConfig> =
|
|
90
|
-
{
|
|
91
|
-
...defaultTypeScriptModelGeneratorConfig,
|
|
92
|
-
|
|
93
|
-
modelsIndexFile: 'models.ts',
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
// deno-lint-ignore ban-types
|
|
97
|
-
export type TypeScriptModelsGeneratorInput = {};
|
|
98
|
-
|
|
99
|
-
export type TypeScriptModelsGeneratorOutput = {
|
|
100
|
-
typescript: {
|
|
101
|
-
models: {
|
|
102
|
-
[schemaId: string]: TypeScriptModelGeneratorOutput;
|
|
103
|
-
};
|
|
104
|
-
indexFiles: {
|
|
105
|
-
models: Nullable<string>;
|
|
106
|
-
};
|
|
107
|
-
};
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
export type TypeScriptModelGeneratorOutput = TypeScriptComponentOutput;
|
|
111
|
-
|
|
112
|
-
export type TypeScriptModelsGeneratorContext = OpenApiSchemasGenerationProviderContext<
|
|
113
|
-
TypeScriptModelsGeneratorInput,
|
|
114
|
-
TypeScriptModelsGeneratorOutput,
|
|
115
|
-
TypeScriptModelsGeneratorConfig,
|
|
116
|
-
TypeScriptModelGeneratorOutput
|
|
117
|
-
>;
|
|
118
|
-
|
|
119
|
-
export type TypeScriptModelGeneratorContext = TypeScriptModelsGeneratorContext & {
|
|
120
|
-
schema: ApiSchema;
|
|
121
|
-
};
|