@acrool/rtk-query-codegen-openapi 0.0.2 → 0.0.6
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/lib/index.d.mts +8 -4
- package/lib/index.d.ts +8 -4
- package/lib/index.js +442 -112
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +442 -112
- package/lib/index.mjs.map +1 -1
- package/package.json +11 -2
- package/src/generate.ts +327 -127
- package/src/generators/react-hooks.ts +2 -2
- package/src/index.ts +250 -9
- package/src/types.ts +9 -1
package/src/generate.ts
CHANGED
|
@@ -38,8 +38,8 @@ function defaultIsDataResponse(code: string, includeDefault: boolean) {
|
|
|
38
38
|
return !Number.isNaN(parsedCode) && parsedCode >= 200 && parsedCode < 300;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function getOperationName({ verb, path
|
|
42
|
-
return _getOperationName(verb, path,
|
|
41
|
+
function getOperationName({ verb, path }: Pick<OperationDefinition, 'verb' | 'path' >) {
|
|
42
|
+
return _getOperationName(verb, path, undefined);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
function getTags({ verb, pathItem }: Pick<OperationDefinition, 'verb' | 'pathItem'>): string[] {
|
|
@@ -128,49 +128,176 @@ export async function generateApi(
|
|
|
128
128
|
mergeReadWriteOnly,
|
|
129
129
|
});
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
const schemeTypeNames = new Set<string>();
|
|
132
|
+
|
|
133
|
+
function addSchemeTypeName(name: string) {
|
|
134
|
+
schemeTypeNames.add(name);
|
|
135
|
+
schemeTypeNames.add(camelCase(name));
|
|
136
|
+
schemeTypeNames.add(capitalize(camelCase(name)));
|
|
137
|
+
}
|
|
138
|
+
|
|
132
139
|
if (sharedTypesFile) {
|
|
140
|
+
const resultFile = ts.createSourceFile(
|
|
141
|
+
'sharedTypes.ts',
|
|
142
|
+
'',
|
|
143
|
+
ts.ScriptTarget.Latest,
|
|
144
|
+
/*setParentNodes*/ false,
|
|
145
|
+
ts.ScriptKind.TS
|
|
146
|
+
);
|
|
147
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
148
|
+
|
|
149
|
+
const allTypeDefinitions: ts.Statement[] = [];
|
|
150
|
+
const definedTypeNames = new Set<string>();
|
|
151
|
+
|
|
133
152
|
const components = v3Doc.components;
|
|
134
153
|
if (components) {
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
154
|
+
const componentDefinitions = Object.entries(components).map(([componentType, componentDefs]) => {
|
|
155
|
+
const typeEntries = Object.entries(componentDefs as Record<string, unknown>)
|
|
156
|
+
.map(([name, def]) => {
|
|
157
|
+
addSchemeTypeName(name);
|
|
158
|
+
const typeName = capitalize(camelCase(name));
|
|
159
|
+
definedTypeNames.add(typeName);
|
|
160
|
+
const typeNode = wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(def as OpenAPIV3.SchemaObject));
|
|
161
|
+
return factory.createTypeAliasDeclaration(
|
|
162
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
163
|
+
factory.createIdentifier(typeName),
|
|
164
|
+
undefined,
|
|
165
|
+
typeNode
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
return factory.createModuleDeclaration(
|
|
169
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
170
|
+
factory.createIdentifier('Scheme'),
|
|
171
|
+
factory.createModuleBlock(typeEntries),
|
|
172
|
+
ts.NodeFlags.Namespace
|
|
173
|
+
);
|
|
174
|
+
});
|
|
175
|
+
allTypeDefinitions.push(...componentDefinitions);
|
|
176
|
+
}
|
|
143
177
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
178
|
+
const enumEntries = [
|
|
179
|
+
...apiGen.enumAliases.filter(e => ts.isEnumDeclaration(e)),
|
|
180
|
+
...apiGen.enumAliases.filter(e => ts.isTypeAliasDeclaration(e)),
|
|
181
|
+
].map(enumDecl => {
|
|
182
|
+
if (ts.isEnumDeclaration(enumDecl)) {
|
|
183
|
+
return factory.createEnumDeclaration(
|
|
184
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
185
|
+
enumDecl.name,
|
|
186
|
+
enumDecl.members
|
|
187
|
+
);
|
|
188
|
+
} else if (ts.isTypeAliasDeclaration(enumDecl)) {
|
|
189
|
+
return factory.createTypeAliasDeclaration(
|
|
190
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
191
|
+
enumDecl.name,
|
|
192
|
+
enumDecl.typeParameters,
|
|
193
|
+
enumDecl.type
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
return enumDecl;
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const unionTypeEnums = apiGen.aliases
|
|
200
|
+
.filter(alias => {
|
|
201
|
+
if (ts.isTypeAliasDeclaration(alias) && alias.type) {
|
|
202
|
+
return ts.isUnionTypeNode(alias.type);
|
|
203
|
+
}
|
|
204
|
+
return false;
|
|
205
|
+
})
|
|
206
|
+
.map(alias => {
|
|
207
|
+
if (ts.isTypeAliasDeclaration(alias)) {
|
|
148
208
|
return factory.createTypeAliasDeclaration(
|
|
149
209
|
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
210
|
+
alias.name,
|
|
211
|
+
alias.typeParameters,
|
|
212
|
+
alias.type
|
|
153
213
|
);
|
|
154
|
-
}
|
|
214
|
+
}
|
|
215
|
+
return alias;
|
|
155
216
|
});
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
ts.
|
|
163
|
-
|
|
164
|
-
|
|
217
|
+
|
|
218
|
+
const allEnumEntries = [...enumEntries, ...unionTypeEnums];
|
|
219
|
+
|
|
220
|
+
if (allEnumEntries.length > 0) {
|
|
221
|
+
allTypeDefinitions.push(
|
|
222
|
+
factory.createModuleDeclaration(
|
|
223
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
224
|
+
factory.createIdentifier('Enum'),
|
|
225
|
+
factory.createModuleBlock(allEnumEntries),
|
|
226
|
+
ts.NodeFlags.Namespace
|
|
227
|
+
)
|
|
165
228
|
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (apiGen.aliases.length > 0) {
|
|
232
|
+
const aliasEntries = apiGen.aliases
|
|
233
|
+
.filter(alias => {
|
|
234
|
+
if (ts.isTypeAliasDeclaration(alias)) {
|
|
235
|
+
const isDefinedInComponents = definedTypeNames.has(alias.name.text);
|
|
236
|
+
const isUnionTypeEnum = ts.isUnionTypeNode(alias.type);
|
|
237
|
+
return !isDefinedInComponents && !isUnionTypeEnum;
|
|
238
|
+
}
|
|
239
|
+
return false;
|
|
240
|
+
})
|
|
241
|
+
.map(alias => {
|
|
242
|
+
if (ts.isTypeAliasDeclaration(alias)) {
|
|
243
|
+
return factory.createTypeAliasDeclaration(
|
|
244
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
245
|
+
alias.name,
|
|
246
|
+
alias.typeParameters,
|
|
247
|
+
alias.type
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
return alias;
|
|
251
|
+
});
|
|
166
252
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
253
|
+
if (aliasEntries.length > 0) {
|
|
254
|
+
const existingSchemeIndex = allTypeDefinitions.findIndex(def =>
|
|
255
|
+
ts.isModuleDeclaration(def) &&
|
|
256
|
+
ts.isIdentifier(def.name) &&
|
|
257
|
+
def.name.text === 'Scheme'
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
if (existingSchemeIndex >= 0) {
|
|
261
|
+
const existingScheme = allTypeDefinitions[existingSchemeIndex] as ts.ModuleDeclaration;
|
|
262
|
+
const mergedMembers = [...(existingScheme.body as ts.ModuleBlock).statements, ...aliasEntries];
|
|
263
|
+
allTypeDefinitions[existingSchemeIndex] = factory.createModuleDeclaration(
|
|
264
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
265
|
+
factory.createIdentifier('Scheme'),
|
|
266
|
+
factory.createModuleBlock(mergedMembers),
|
|
267
|
+
ts.NodeFlags.Namespace
|
|
268
|
+
);
|
|
269
|
+
} else {
|
|
270
|
+
allTypeDefinitions.push(
|
|
271
|
+
factory.createModuleDeclaration(
|
|
272
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
273
|
+
factory.createIdentifier('Scheme'),
|
|
274
|
+
factory.createModuleBlock(aliasEntries),
|
|
275
|
+
ts.NodeFlags.Namespace
|
|
276
|
+
)
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
170
280
|
}
|
|
281
|
+
|
|
282
|
+
const fs = await import('node:fs/promises');
|
|
283
|
+
const path = await import('node:path');
|
|
284
|
+
|
|
285
|
+
const sharedTypesDir = path.dirname(sharedTypesFile);
|
|
286
|
+
await fs.mkdir(sharedTypesDir, { recursive: true });
|
|
287
|
+
|
|
288
|
+
const output = printer.printNode(
|
|
289
|
+
ts.EmitHint.Unspecified,
|
|
290
|
+
factory.createSourceFile(
|
|
291
|
+
allTypeDefinitions,
|
|
292
|
+
factory.createToken(ts.SyntaxKind.EndOfFileToken),
|
|
293
|
+
ts.NodeFlags.None
|
|
294
|
+
),
|
|
295
|
+
resultFile
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
await fs.writeFile(sharedTypesFile, output, 'utf-8');
|
|
171
299
|
}
|
|
172
300
|
|
|
173
|
-
// temporary workaround for https://github.com/oazapfts/oazapfts/issues/491
|
|
174
301
|
if (apiGen.spec.components?.schemas) {
|
|
175
302
|
apiGen.preprocessComponents(apiGen.spec.components.schemas);
|
|
176
303
|
}
|
|
@@ -203,17 +330,18 @@ export async function generateApi(
|
|
|
203
330
|
apiFile = apiFile.replace(/\\/g, '/');
|
|
204
331
|
if (!apiFile.startsWith('.')) apiFile = `./${apiFile}`;
|
|
205
332
|
}
|
|
206
|
-
// 處理 sharedTypesFile 的路徑
|
|
207
|
-
if (sharedTypesFile && sharedTypesFile.startsWith('.')) {
|
|
208
|
-
sharedTypesFile = path.relative(path.dirname(outputFile), sharedTypesFile);
|
|
209
|
-
sharedTypesFile = sharedTypesFile.replace(/\\/g, '/');
|
|
210
|
-
if (!sharedTypesFile.startsWith('.')) sharedTypesFile = `./${sharedTypesFile}`;
|
|
211
|
-
}
|
|
212
333
|
}
|
|
213
334
|
apiFile = apiFile.replace(/\.[jt]sx?$/, '');
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
335
|
+
|
|
336
|
+
const sharedTypesImportPath = sharedTypesFile && outputFile
|
|
337
|
+
? (() => {
|
|
338
|
+
let rel = path.relative(path.dirname(outputFile), sharedTypesFile)
|
|
339
|
+
.replace(/\\/g, '/')
|
|
340
|
+
.replace(/\.[jt]sx?$/, '');
|
|
341
|
+
if (!rel.startsWith('.')) rel = './' + rel;
|
|
342
|
+
return rel;
|
|
343
|
+
})()
|
|
344
|
+
: './shared-types';
|
|
217
345
|
|
|
218
346
|
return printer.printNode(
|
|
219
347
|
ts.EmitHint.Unspecified,
|
|
@@ -222,16 +350,10 @@ export async function generateApi(
|
|
|
222
350
|
generateImportNode(apiFile, { [apiImport]: 'api' }),
|
|
223
351
|
generateImportNode('@acrool/react-fetcher', { IRestFulEndpointsQueryReturn: 'IRestFulEndpointsQueryReturn' }),
|
|
224
352
|
...(sharedTypesFile ? [
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
undefined,
|
|
230
|
-
factory.createNamespaceImport(factory.createIdentifier('SharedTypes'))
|
|
231
|
-
),
|
|
232
|
-
factory.createStringLiteral(sharedTypesFile),
|
|
233
|
-
undefined
|
|
234
|
-
)
|
|
353
|
+
generateImportNode(sharedTypesImportPath, {
|
|
354
|
+
Scheme: 'Scheme',
|
|
355
|
+
...(useEnumType ? { Enum: 'Enum' } : {})
|
|
356
|
+
})
|
|
235
357
|
] : []),
|
|
236
358
|
...(tag ? [generateTagTypes({ addTagTypes: extractAllTagTypes({ operationDefinitions }) })] : []),
|
|
237
359
|
generateCreateApiCall({
|
|
@@ -241,6 +363,7 @@ export async function generateApi(
|
|
|
241
363
|
generateEndpoint({
|
|
242
364
|
operationDefinition,
|
|
243
365
|
overrides: getOverrides(operationDefinition, endpointOverrides),
|
|
366
|
+
sharedTypesFile: !!sharedTypesFile,
|
|
244
367
|
})
|
|
245
368
|
),
|
|
246
369
|
true
|
|
@@ -285,9 +408,11 @@ export async function generateApi(
|
|
|
285
408
|
function generateEndpoint({
|
|
286
409
|
operationDefinition,
|
|
287
410
|
overrides,
|
|
411
|
+
sharedTypesFile,
|
|
288
412
|
}: {
|
|
289
413
|
operationDefinition: OperationDefinition;
|
|
290
414
|
overrides?: EndpointOverrides;
|
|
415
|
+
sharedTypesFile: boolean;
|
|
291
416
|
}) {
|
|
292
417
|
const {
|
|
293
418
|
verb,
|
|
@@ -296,73 +421,37 @@ export async function generateApi(
|
|
|
296
421
|
operation,
|
|
297
422
|
operation: { responses, requestBody },
|
|
298
423
|
} = operationDefinition;
|
|
299
|
-
const operationName = getOperationName({ verb, path
|
|
424
|
+
const operationName = getOperationName({ verb, path });
|
|
300
425
|
const tags = tag ? getTags({ verb, pathItem }) : [];
|
|
301
426
|
const isQuery = testIsQuery(verb, overrides);
|
|
302
427
|
|
|
303
428
|
const returnsJson = apiGen.getResponseType(responses) === 'json';
|
|
304
429
|
let ResponseType: ts.TypeNode = factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
|
|
305
|
-
|
|
306
|
-
function replaceReferences(schema: any): ts.TypeNode {
|
|
307
|
-
if (!schema) return factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
|
|
308
|
-
|
|
309
|
-
const refName = getReferenceName(schema);
|
|
310
|
-
if (refName && sharedTypesFile) {
|
|
311
|
-
return factory.createTypeReferenceNode(
|
|
312
|
-
factory.createQualifiedName(
|
|
313
|
-
factory.createIdentifier('SharedTypes'),
|
|
314
|
-
factory.createIdentifier(refName)
|
|
315
|
-
),
|
|
316
|
-
undefined
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (schema.type === 'object' && schema.properties) {
|
|
321
|
-
const members = Object.entries(schema.properties).map(([key, value]: [string, any]) => {
|
|
322
|
-
return factory.createPropertySignature(
|
|
323
|
-
undefined,
|
|
324
|
-
factory.createIdentifier(key),
|
|
325
|
-
schema.required?.includes(key) ? undefined : factory.createToken(ts.SyntaxKind.QuestionToken),
|
|
326
|
-
replaceReferences(value)
|
|
327
|
-
);
|
|
328
|
-
});
|
|
329
|
-
return factory.createTypeLiteralNode(members);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (schema.type === 'array' && schema.items) {
|
|
333
|
-
return factory.createArrayTypeNode(replaceReferences(schema.items));
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
return apiGen.getTypeFromSchema(schema);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
430
|
if (returnsJson) {
|
|
340
431
|
const returnTypes = Object.entries(responses || {})
|
|
341
432
|
.map(
|
|
342
|
-
([code, response]) =>
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
return [code, resolvedResponse, type] as const;
|
|
352
|
-
}
|
|
433
|
+
([code, response]) =>
|
|
434
|
+
[
|
|
435
|
+
code,
|
|
436
|
+
apiGen.resolve(response),
|
|
437
|
+
wrapWithSchemeIfComponent(
|
|
438
|
+
apiGen.getTypeFromResponse(response, 'readOnly') ||
|
|
439
|
+
factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword)
|
|
440
|
+
),
|
|
441
|
+
] as const
|
|
353
442
|
)
|
|
354
443
|
.filter(([status, response]) =>
|
|
355
444
|
isDataResponse(status, includeDefault, apiGen.resolve(response), responses || {})
|
|
356
445
|
)
|
|
357
446
|
.filter(([_1, _2, type]) => type !== keywordType.void)
|
|
358
|
-
.map(([code, response, type]) =>
|
|
359
|
-
ts.addSyntheticLeadingComment(
|
|
360
|
-
|
|
447
|
+
.map(([code, response, type]) => {
|
|
448
|
+
return ts.addSyntheticLeadingComment(
|
|
449
|
+
type,
|
|
361
450
|
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
362
451
|
`* status ${code} ${response.description} `,
|
|
363
452
|
false
|
|
364
|
-
)
|
|
365
|
-
);
|
|
453
|
+
);
|
|
454
|
+
});
|
|
366
455
|
if (returnTypes.length > 0) {
|
|
367
456
|
ResponseType = factory.createUnionTypeNode(returnTypes);
|
|
368
457
|
}
|
|
@@ -392,28 +481,36 @@ export async function generateApi(
|
|
|
392
481
|
const queryArg: QueryArgDefinitions = {};
|
|
393
482
|
function generateName(name: string, potentialPrefix: string) {
|
|
394
483
|
const isPureSnakeCase = /^[a-zA-Z][a-zA-Z0-9_]*$/.test(name);
|
|
395
|
-
// prefix with `query`, `path` or `body` if there are multiple paramters with the same name
|
|
396
484
|
const hasNamingConflict = allNames.filter((n) => n === name).length > 1;
|
|
397
485
|
if (hasNamingConflict) {
|
|
398
486
|
name = `${potentialPrefix}_${name}`;
|
|
399
487
|
}
|
|
400
|
-
// convert to camelCase if the name is pure snake_case and there are no naming conflicts
|
|
401
488
|
const camelCaseName = camelCase(name);
|
|
402
489
|
if (isPureSnakeCase && !allNames.includes(camelCaseName)) {
|
|
403
490
|
name = camelCaseName;
|
|
404
491
|
}
|
|
405
|
-
// if there are still any naming conflicts, prepend with underscore
|
|
406
492
|
while (name in queryArg) {
|
|
407
493
|
name = `_${name}`;
|
|
408
494
|
}
|
|
409
495
|
return name;
|
|
410
496
|
}
|
|
411
497
|
|
|
498
|
+
for (const param of parameters) {
|
|
499
|
+
const name = generateName(param.name, param.in);
|
|
500
|
+
queryArg[name] = {
|
|
501
|
+
origin: 'param',
|
|
502
|
+
name,
|
|
503
|
+
originalName: param.name,
|
|
504
|
+
type: wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(isReference(param) ? param : param.schema, undefined, 'writeOnly')),
|
|
505
|
+
required: param.required,
|
|
506
|
+
param,
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
|
|
412
510
|
if (requestBody) {
|
|
413
511
|
const body = apiGen.resolve(requestBody);
|
|
414
512
|
const schema = apiGen.getSchemaFromContent(body.content);
|
|
415
|
-
const type =
|
|
416
|
-
|
|
513
|
+
const type = wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(schema));
|
|
417
514
|
const schemaName = camelCase(
|
|
418
515
|
(type as any).name ||
|
|
419
516
|
getReferenceName(schema) ||
|
|
@@ -426,27 +523,12 @@ export async function generateApi(
|
|
|
426
523
|
origin: 'body',
|
|
427
524
|
name,
|
|
428
525
|
originalName: schemaName,
|
|
429
|
-
type,
|
|
526
|
+
type: wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(schema, undefined, 'writeOnly')),
|
|
430
527
|
required: true,
|
|
431
528
|
body,
|
|
432
529
|
};
|
|
433
530
|
}
|
|
434
531
|
|
|
435
|
-
for (const param of parameters) {
|
|
436
|
-
const name = generateName(param.name, param.in);
|
|
437
|
-
const paramSchema = isReference(param) ? param : param.schema;
|
|
438
|
-
const type = replaceReferences(paramSchema);
|
|
439
|
-
|
|
440
|
-
queryArg[name] = {
|
|
441
|
-
origin: 'param',
|
|
442
|
-
name,
|
|
443
|
-
originalName: param.name,
|
|
444
|
-
type,
|
|
445
|
-
required: param.required,
|
|
446
|
-
param,
|
|
447
|
-
};
|
|
448
|
-
}
|
|
449
|
-
|
|
450
532
|
const propertyName = (name: string | ts.PropertyName): ts.PropertyName => {
|
|
451
533
|
if (typeof name === 'string') {
|
|
452
534
|
return isValidIdentifier(name) ? factory.createIdentifier(name) : factory.createStringLiteral(name);
|
|
@@ -617,14 +699,132 @@ export async function generateApi(
|
|
|
617
699
|
);
|
|
618
700
|
}
|
|
619
701
|
|
|
620
|
-
// eslint-disable-next-line no-empty-pattern
|
|
621
702
|
function generateQueryEndpointProps({}: { operationDefinition: OperationDefinition }): ObjectPropertyDefinitions {
|
|
622
|
-
return {};
|
|
703
|
+
return {};
|
|
623
704
|
}
|
|
624
705
|
|
|
625
|
-
// eslint-disable-next-line no-empty-pattern
|
|
626
706
|
function generateMutationEndpointProps({}: { operationDefinition: OperationDefinition }): ObjectPropertyDefinitions {
|
|
627
|
-
return {};
|
|
707
|
+
return {};
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
function wrapWithSchemeIfComponent(typeNode: ts.TypeNode): ts.TypeNode {
|
|
711
|
+
if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName)) {
|
|
712
|
+
const typeName = typeNode.typeName.text;
|
|
713
|
+
|
|
714
|
+
// 檢查是否為 enum 類型(包括在 enumAliases 和 aliases 中的)
|
|
715
|
+
const isEnumType = useEnumType && (
|
|
716
|
+
apiGen.enumAliases.some(enumDecl => {
|
|
717
|
+
if (ts.isEnumDeclaration(enumDecl) || ts.isTypeAliasDeclaration(enumDecl)) {
|
|
718
|
+
return enumDecl.name.text === typeName;
|
|
719
|
+
}
|
|
720
|
+
return false;
|
|
721
|
+
}) ||
|
|
722
|
+
apiGen.aliases.some(alias => {
|
|
723
|
+
if (ts.isTypeAliasDeclaration(alias) && alias.type) {
|
|
724
|
+
// 檢查是否為 union type 的 enum
|
|
725
|
+
if (ts.isUnionTypeNode(alias.type)) {
|
|
726
|
+
return alias.name.text === typeName;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return false;
|
|
730
|
+
})
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
if (isEnumType) {
|
|
734
|
+
return factory.createTypeReferenceNode(
|
|
735
|
+
factory.createQualifiedName(
|
|
736
|
+
factory.createIdentifier('Enum'),
|
|
737
|
+
typeNode.typeName
|
|
738
|
+
),
|
|
739
|
+
typeNode.typeArguments?.map(wrapWithSchemeIfComponent)
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
if (schemeTypeNames.has(typeName)) {
|
|
744
|
+
return factory.createTypeReferenceNode(
|
|
745
|
+
factory.createQualifiedName(
|
|
746
|
+
factory.createIdentifier('Scheme'),
|
|
747
|
+
typeNode.typeName
|
|
748
|
+
),
|
|
749
|
+
typeNode.typeArguments?.map(wrapWithSchemeIfComponent)
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
if (typeNode.typeArguments) {
|
|
753
|
+
return factory.createTypeReferenceNode(
|
|
754
|
+
typeNode.typeName,
|
|
755
|
+
typeNode.typeArguments.map(wrapWithSchemeIfComponent)
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
if (ts.isArrayTypeNode(typeNode)) {
|
|
760
|
+
return factory.createArrayTypeNode(wrapWithSchemeIfComponent(typeNode.elementType));
|
|
761
|
+
}
|
|
762
|
+
if (ts.isUnionTypeNode(typeNode)) {
|
|
763
|
+
// 檢查是否為 enum 的 union type
|
|
764
|
+
const unionTypes = typeNode.types;
|
|
765
|
+
if (unionTypes.length > 0 && unionTypes.every(type =>
|
|
766
|
+
ts.isLiteralTypeNode(type) &&
|
|
767
|
+
(ts.isStringLiteral(type.literal) || ts.isNumericLiteral(type.literal))
|
|
768
|
+
)) {
|
|
769
|
+
// 這是一個 enum 的 union type,我們需要找到對應的 enum 類型
|
|
770
|
+
const enumValues = unionTypes.map(type => {
|
|
771
|
+
if (ts.isLiteralTypeNode(type)) {
|
|
772
|
+
if (ts.isStringLiteral(type.literal)) {
|
|
773
|
+
return type.literal.text;
|
|
774
|
+
} else if (ts.isNumericLiteral(type.literal)) {
|
|
775
|
+
return type.literal.text;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
return null;
|
|
779
|
+
}).filter(Boolean);
|
|
780
|
+
|
|
781
|
+
// 查找對應的 enum 類型
|
|
782
|
+
const matchingEnum = apiGen.aliases.find(alias => {
|
|
783
|
+
if (ts.isTypeAliasDeclaration(alias) && ts.isUnionTypeNode(alias.type)) {
|
|
784
|
+
const aliasValues = alias.type.types.map(type => {
|
|
785
|
+
if (ts.isLiteralTypeNode(type)) {
|
|
786
|
+
if (ts.isStringLiteral(type.literal)) {
|
|
787
|
+
return type.literal.text;
|
|
788
|
+
} else if (ts.isNumericLiteral(type.literal)) {
|
|
789
|
+
return type.literal.text;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return null;
|
|
793
|
+
}).filter(Boolean);
|
|
794
|
+
|
|
795
|
+
return aliasValues.length === enumValues.length &&
|
|
796
|
+
aliasValues.every(val => enumValues.includes(val));
|
|
797
|
+
}
|
|
798
|
+
return false;
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
// 對於所有的 enum 類型,直接使用字串型別,不轉換為 Enum
|
|
802
|
+
// 這樣可以避免自動命名造成的變更問題
|
|
803
|
+
if (matchingEnum && ts.isTypeAliasDeclaration(matchingEnum)) {
|
|
804
|
+
// 直接返回原始的 union type,不轉換為 Enum
|
|
805
|
+
return typeNode;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
return factory.createUnionTypeNode(typeNode.types.map(wrapWithSchemeIfComponent));
|
|
810
|
+
}
|
|
811
|
+
if (ts.isTypeLiteralNode(typeNode)) {
|
|
812
|
+
return factory.createTypeLiteralNode(
|
|
813
|
+
typeNode.members.map(member => {
|
|
814
|
+
if (ts.isPropertySignature(member) && member.type) {
|
|
815
|
+
return factory.updatePropertySignature(
|
|
816
|
+
member,
|
|
817
|
+
member.modifiers,
|
|
818
|
+
member.name,
|
|
819
|
+
member.questionToken,
|
|
820
|
+
wrapWithSchemeIfComponent(member.type)
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
return member;
|
|
824
|
+
})
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
return typeNode;
|
|
628
828
|
}
|
|
629
829
|
}
|
|
630
830
|
|
|
@@ -20,7 +20,7 @@ type CreateBindingParams = {
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
const createBinding = ({
|
|
23
|
-
operationDefinition: { verb, path
|
|
23
|
+
operationDefinition: { verb, path },
|
|
24
24
|
overrides,
|
|
25
25
|
isLazy = false,
|
|
26
26
|
}: CreateBindingParams) =>
|
|
@@ -28,7 +28,7 @@ const createBinding = ({
|
|
|
28
28
|
undefined,
|
|
29
29
|
undefined,
|
|
30
30
|
factory.createIdentifier(
|
|
31
|
-
`use${isLazy ? 'Lazy' : ''}${capitalize(getOperationName(verb, path,
|
|
31
|
+
`use${isLazy ? 'Lazy' : ''}${capitalize(getOperationName(verb, path, undefined))}${
|
|
32
32
|
isQuery(verb, overrides) ? 'Query' : 'Mutation'
|
|
33
33
|
}`
|
|
34
34
|
),
|