@bitstack/ng-query-codegen-openapi 0.0.30 → 0.0.31-alpha.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/README.md +8 -1
- package/lib/bin/cli.mjs +70 -57
- package/lib/bin/cli.mjs.map +1 -1
- package/lib/index.d.mts +4 -18
- package/lib/index.d.ts +4 -18
- package/lib/index.js +343 -275
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +343 -275
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/bin/utils.ts +74 -3
- package/src/generators/common-types-generator.ts +6 -2
- package/src/generators/component-schema-generator.ts +40 -7
- package/src/generators/do-not-modify-generator.ts +2 -2
- package/src/generators/rtk-enhance-endpoints-generator.ts +113 -0
- package/src/generators/{query-service-generator.ts → rtk-query-generator.ts} +45 -33
- package/src/generators/tag-types-generator.ts +30 -0
- package/src/generators/types-generator.ts +216 -112
- package/src/generators/utils-generator.ts +2 -4
- package/src/index.ts +6 -3
- package/src/services/api-code-generator.ts +62 -74
- package/src/services/endpoint-info-extractor.ts +66 -14
- package/src/services/file-writer-service.ts +27 -23
- package/src/services/openapi-parser-service.ts +10 -2
- package/src/services/unified-code-generator.ts +55 -26
- package/src/types.ts +19 -45
- package/src/generators/api-service-generator.ts +0 -112
- package/src/generators/cache-keys-generator.ts +0 -43
- package/src/generators/index-generator.ts +0 -11
- package/src/services/api-service-generator.ts +0 -24
- package/src/services/query-code-generator.ts +0 -24
package/lib/index.mjs
CHANGED
|
@@ -311,6 +311,13 @@ var FileWriterService = class {
|
|
|
311
311
|
async writeFile(filePath, content) {
|
|
312
312
|
try {
|
|
313
313
|
const resolvedPath = path3.resolve(process.cwd(), filePath);
|
|
314
|
+
const fileName = path3.basename(resolvedPath);
|
|
315
|
+
if (fileName === "enhanceEndpoints.ts" && fs3.existsSync(resolvedPath)) {
|
|
316
|
+
return {
|
|
317
|
+
path: resolvedPath,
|
|
318
|
+
success: true
|
|
319
|
+
};
|
|
320
|
+
}
|
|
314
321
|
await ensureDirectoryExists(resolvedPath);
|
|
315
322
|
fs3.writeFileSync(resolvedPath, content);
|
|
316
323
|
return {
|
|
@@ -338,7 +345,7 @@ var FileWriterService = class {
|
|
|
338
345
|
return results;
|
|
339
346
|
}
|
|
340
347
|
/**
|
|
341
|
-
*
|
|
348
|
+
* 為群組寫入 RTK Query 檔案結構
|
|
342
349
|
* @param groupOutputDir - 群組輸出目錄
|
|
343
350
|
* @param files - 檔案內容
|
|
344
351
|
*/
|
|
@@ -347,11 +354,11 @@ var FileWriterService = class {
|
|
|
347
354
|
if (files.types) {
|
|
348
355
|
filesToWrite[path3.join(groupOutputDir, "types.ts")] = files.types;
|
|
349
356
|
}
|
|
350
|
-
if (files.apiService) {
|
|
351
|
-
filesToWrite[path3.join(groupOutputDir, "api.service.ts")] = files.apiService;
|
|
352
|
-
}
|
|
353
357
|
if (files.queryService) {
|
|
354
|
-
filesToWrite[path3.join(groupOutputDir, "query.
|
|
358
|
+
filesToWrite[path3.join(groupOutputDir, "query.generated.ts")] = files.queryService;
|
|
359
|
+
}
|
|
360
|
+
if (files.enhanceEndpoints) {
|
|
361
|
+
filesToWrite[path3.join(groupOutputDir, "enhanceEndpoints.ts")] = files.enhanceEndpoints;
|
|
355
362
|
}
|
|
356
363
|
if (files.index) {
|
|
357
364
|
filesToWrite[path3.join(groupOutputDir, "index.ts")] = files.index;
|
|
@@ -368,9 +375,6 @@ var FileWriterService = class {
|
|
|
368
375
|
if (sharedFiles.commonTypes) {
|
|
369
376
|
filesToWrite[path3.join(outputDir, "common-types.ts")] = sharedFiles.commonTypes;
|
|
370
377
|
}
|
|
371
|
-
if (sharedFiles.cacheKeys) {
|
|
372
|
-
filesToWrite[path3.join(outputDir, "cache-keys.ts")] = sharedFiles.cacheKeys;
|
|
373
|
-
}
|
|
374
378
|
if (sharedFiles.doNotModify) {
|
|
375
379
|
filesToWrite[path3.join(outputDir, "DO_NOT_MODIFY.md")] = sharedFiles.doNotModify;
|
|
376
380
|
}
|
|
@@ -399,7 +403,6 @@ var OpenApiParserService = class {
|
|
|
399
403
|
this.v3Doc = v3Doc;
|
|
400
404
|
this.apiGen = new ApiGenerator(v3Doc, {
|
|
401
405
|
unionUndefined: options.unionUndefined,
|
|
402
|
-
useEnumType: options.useEnumType,
|
|
403
406
|
mergeReadWriteOnly: options.mergeReadWriteOnly
|
|
404
407
|
});
|
|
405
408
|
}
|
|
@@ -409,6 +412,12 @@ var OpenApiParserService = class {
|
|
|
409
412
|
*/
|
|
410
413
|
initialize() {
|
|
411
414
|
if (this.apiGen.spec.components?.schemas) {
|
|
415
|
+
Object.keys(this.apiGen.spec.components.schemas).forEach((schemaName) => {
|
|
416
|
+
const schema = this.apiGen.spec.components.schemas[schemaName];
|
|
417
|
+
if (schema && typeof schema === "object" && "title" in schema) {
|
|
418
|
+
delete schema.title;
|
|
419
|
+
}
|
|
420
|
+
});
|
|
412
421
|
this.apiGen.preprocessComponents(this.apiGen.spec.components.schemas);
|
|
413
422
|
Object.keys(this.apiGen.spec.components.schemas).forEach((schemaName) => {
|
|
414
423
|
try {
|
|
@@ -447,64 +456,6 @@ var OpenApiParserService = class {
|
|
|
447
456
|
}
|
|
448
457
|
};
|
|
449
458
|
|
|
450
|
-
// src/generators/cache-keys-generator.ts
|
|
451
|
-
init_esm_shims();
|
|
452
|
-
|
|
453
|
-
// src/generators/utils-generator.ts
|
|
454
|
-
init_esm_shims();
|
|
455
|
-
function generateUtilsFile() {
|
|
456
|
-
return `/* eslint-disable */
|
|
457
|
-
// [Warning] Generated automatically - do not edit manually
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* Clear undefined in object
|
|
461
|
-
*/
|
|
462
|
-
export function withoutUndefined(obj?: Record<string, any>) {
|
|
463
|
-
if(typeof obj === 'undefined') return;
|
|
464
|
-
return Object.fromEntries(
|
|
465
|
-
Object.entries(obj).filter(([_, v]) => v !== undefined && v !== null)
|
|
466
|
-
);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
`;
|
|
470
|
-
}
|
|
471
|
-
function toCamelCase(str) {
|
|
472
|
-
return str.toLowerCase().replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// src/generators/cache-keys-generator.ts
|
|
476
|
-
function generateCacheKeysFile(allEndpointInfos) {
|
|
477
|
-
const groupedKeys = allEndpointInfos.reduce((acc, info) => {
|
|
478
|
-
if (!acc[info.groupKey]) {
|
|
479
|
-
acc[info.groupKey] = [];
|
|
480
|
-
}
|
|
481
|
-
acc[info.groupKey].push({
|
|
482
|
-
operationName: info.operationName,
|
|
483
|
-
queryKeyName: info.queryKeyName
|
|
484
|
-
});
|
|
485
|
-
return acc;
|
|
486
|
-
}, {});
|
|
487
|
-
const enumEntries = Object.entries(groupedKeys).map(([groupKey, keys]) => {
|
|
488
|
-
const groupComment = ` // ${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)} related cache keys`;
|
|
489
|
-
const keyEntries = keys.map(
|
|
490
|
-
(key) => ` ${key.queryKeyName} = '${toCamelCase(key.queryKeyName)}',`
|
|
491
|
-
).join("\n");
|
|
492
|
-
return `${groupComment}
|
|
493
|
-
${keyEntries}`;
|
|
494
|
-
}).join("\n\n");
|
|
495
|
-
return `// [Warning] Generated automatically - do not edit manually
|
|
496
|
-
|
|
497
|
-
/**
|
|
498
|
-
* Cache keys enum for all API queries
|
|
499
|
-
*/
|
|
500
|
-
export enum ECacheKeys {
|
|
501
|
-
${enumEntries}
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
export default ECacheKeys;
|
|
505
|
-
`;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
459
|
// src/generators/common-types-generator.ts
|
|
509
460
|
init_esm_shims();
|
|
510
461
|
function generateCommonTypesFile() {
|
|
@@ -525,11 +476,15 @@ export interface QueryConfig {
|
|
|
525
476
|
keepUnusedDataFor?: number,
|
|
526
477
|
}
|
|
527
478
|
|
|
479
|
+
export interface IRequestConfig extends RequestOptions { {
|
|
480
|
+
timeout?: number;
|
|
481
|
+
}
|
|
482
|
+
|
|
528
483
|
export type IRestFulEndpointsQueryReturn<TVariables> = TVariables extends void ?
|
|
529
|
-
void | {fetchOptions?:
|
|
484
|
+
void | {fetchOptions?: IRequestConfig;}:
|
|
530
485
|
{
|
|
531
486
|
variables: TVariables;
|
|
532
|
-
fetchOptions?:
|
|
487
|
+
fetchOptions?: IRequestConfig;
|
|
533
488
|
config?: QueryConfig;
|
|
534
489
|
};
|
|
535
490
|
`;
|
|
@@ -538,6 +493,19 @@ export type IRestFulEndpointsQueryReturn<TVariables> = TVariables extends void ?
|
|
|
538
493
|
// src/generators/component-schema-generator.ts
|
|
539
494
|
init_esm_shims();
|
|
540
495
|
import ts from "typescript";
|
|
496
|
+
function toPascalCase(name) {
|
|
497
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
498
|
+
}
|
|
499
|
+
function renameIdentifier(node, oldName, newName) {
|
|
500
|
+
return ts.transform(node, [
|
|
501
|
+
(context) => (rootNode) => ts.visitNode(rootNode, function visit(node2) {
|
|
502
|
+
if (ts.isIdentifier(node2) && node2.text === oldName) {
|
|
503
|
+
return ts.factory.createIdentifier(newName);
|
|
504
|
+
}
|
|
505
|
+
return ts.visitEachChild(node2, visit, context);
|
|
506
|
+
})
|
|
507
|
+
]).transformed[0];
|
|
508
|
+
}
|
|
541
509
|
function generateComponentSchemaFile(interfaces) {
|
|
542
510
|
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
543
511
|
const resultFile = ts.createSourceFile(
|
|
@@ -547,10 +515,19 @@ function generateComponentSchemaFile(interfaces) {
|
|
|
547
515
|
false,
|
|
548
516
|
ts.ScriptKind.TS
|
|
549
517
|
);
|
|
518
|
+
const renamedInterfaces = [];
|
|
519
|
+
const typeNameMapping = {};
|
|
520
|
+
Object.entries(interfaces).forEach(([originalName, node]) => {
|
|
521
|
+
const pascalCaseName = toPascalCase(originalName);
|
|
522
|
+
typeNameMapping[originalName] = pascalCaseName;
|
|
523
|
+
const renamedNode = renameIdentifier(node, originalName, pascalCaseName);
|
|
524
|
+
const printed = printer.printNode(ts.EmitHint.Unspecified, renamedNode, resultFile);
|
|
525
|
+
renamedInterfaces.push(printed);
|
|
526
|
+
});
|
|
550
527
|
return `/* eslint-disable */
|
|
551
|
-
// [Warning] Generated automatically - do not edit manually
|
|
552
|
-
|
|
553
|
-
${
|
|
528
|
+
// [Warning] Generated automatically - do not edit manually
|
|
529
|
+
|
|
530
|
+
${renamedInterfaces.join("\n")}
|
|
554
531
|
`;
|
|
555
532
|
}
|
|
556
533
|
|
|
@@ -606,7 +583,13 @@ var EndpointInfoExtractor = class {
|
|
|
606
583
|
*/
|
|
607
584
|
extractSingleEndpointInfo(operationDefinition) {
|
|
608
585
|
const { verb, path: path5, operation } = operationDefinition;
|
|
609
|
-
const {
|
|
586
|
+
const {
|
|
587
|
+
operationNameSuffix = "",
|
|
588
|
+
argSuffix = "Req",
|
|
589
|
+
responseSuffix = "Res",
|
|
590
|
+
queryMatch,
|
|
591
|
+
endpointOverrides
|
|
592
|
+
} = this.options;
|
|
610
593
|
const operationName = getOperationName({ verb, path: path5 });
|
|
611
594
|
const finalOperationName = operationNameSuffix ? capitalize(operationName + operationNameSuffix) : operationName;
|
|
612
595
|
const argTypeName = capitalize(operationName + operationNameSuffix + argSuffix);
|
|
@@ -614,7 +597,9 @@ var EndpointInfoExtractor = class {
|
|
|
614
597
|
const isQuery2 = isQuery(verb, path5, getOverrides(operationDefinition, endpointOverrides), queryMatch);
|
|
615
598
|
const queryKeyName = `${operationName.replace(/([A-Z])/g, "_$1").toUpperCase()}`;
|
|
616
599
|
const summary = operation.summary || `${verb.toUpperCase()} ${path5}`;
|
|
617
|
-
const { queryParams, pathParams, isVoidArg } = this.extractParameters(operationDefinition);
|
|
600
|
+
const { queryParams, pathParams, isVoidArg, hasRequestBody } = this.extractParameters(operationDefinition);
|
|
601
|
+
const contentType = this.extractContentType(operation);
|
|
602
|
+
const tags = Array.isArray(operation.tags) ? operation.tags : [];
|
|
618
603
|
return {
|
|
619
604
|
operationName: finalOperationName,
|
|
620
605
|
argTypeName,
|
|
@@ -626,7 +611,10 @@ var EndpointInfoExtractor = class {
|
|
|
626
611
|
queryParams,
|
|
627
612
|
pathParams,
|
|
628
613
|
isVoidArg,
|
|
629
|
-
summary
|
|
614
|
+
summary,
|
|
615
|
+
contentType,
|
|
616
|
+
hasRequestBody,
|
|
617
|
+
tags
|
|
630
618
|
};
|
|
631
619
|
}
|
|
632
620
|
/**
|
|
@@ -636,15 +624,21 @@ var EndpointInfoExtractor = class {
|
|
|
636
624
|
extractParameters(operationDefinition) {
|
|
637
625
|
const { operation, pathItem } = operationDefinition;
|
|
638
626
|
const operationParameters = this.resolveArray(operation.parameters);
|
|
639
|
-
const pathItemParameters = this.resolveArray(pathItem.parameters).filter(
|
|
640
|
-
|
|
627
|
+
const pathItemParameters = this.resolveArray(pathItem.parameters).filter(
|
|
628
|
+
(pp) => !operationParameters.some((op) => op.name === pp.name && op.in === pp.in)
|
|
629
|
+
);
|
|
630
|
+
const allParameters = supportDeepObjects([...pathItemParameters, ...operationParameters]).filter(
|
|
631
|
+
(param) => param.in !== "header"
|
|
632
|
+
);
|
|
641
633
|
const queryParams = allParameters.filter((param) => param.in === "query");
|
|
642
634
|
const pathParams = allParameters.filter((param) => param.in === "path");
|
|
635
|
+
const hasRequestBody = !!operation.requestBody;
|
|
643
636
|
const isVoidArg = queryParams.length === 0 && pathParams.length === 0 && !operation.requestBody;
|
|
644
637
|
return {
|
|
645
638
|
queryParams,
|
|
646
639
|
pathParams,
|
|
647
|
-
isVoidArg
|
|
640
|
+
isVoidArg,
|
|
641
|
+
hasRequestBody
|
|
648
642
|
};
|
|
649
643
|
}
|
|
650
644
|
/**
|
|
@@ -654,11 +648,46 @@ var EndpointInfoExtractor = class {
|
|
|
654
648
|
if (!parameters) return [];
|
|
655
649
|
return Array.isArray(parameters) ? parameters : [parameters];
|
|
656
650
|
}
|
|
651
|
+
/**
|
|
652
|
+
* 提取操作的 content type
|
|
653
|
+
* @param operation - 操作對象
|
|
654
|
+
*/
|
|
655
|
+
extractContentType(operation) {
|
|
656
|
+
if (!operation.requestBody) {
|
|
657
|
+
return "application/json";
|
|
658
|
+
}
|
|
659
|
+
const content = operation.requestBody.content;
|
|
660
|
+
if (!content || typeof content !== "object") {
|
|
661
|
+
return "application/json";
|
|
662
|
+
}
|
|
663
|
+
const contentTypes = Object.keys(content);
|
|
664
|
+
if (contentTypes.length === 0) {
|
|
665
|
+
return "application/json";
|
|
666
|
+
}
|
|
667
|
+
return contentTypes[0];
|
|
668
|
+
}
|
|
657
669
|
};
|
|
658
670
|
|
|
659
671
|
// src/generators/types-generator.ts
|
|
660
672
|
init_esm_shims();
|
|
673
|
+
var toPascalCase2 = (name) => {
|
|
674
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
675
|
+
};
|
|
661
676
|
function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationDefinitions) {
|
|
677
|
+
const schemaTypeMap = {};
|
|
678
|
+
if (schemaInterfaces) {
|
|
679
|
+
Object.keys(schemaInterfaces).forEach((actualTypeName) => {
|
|
680
|
+
schemaTypeMap[actualTypeName] = actualTypeName;
|
|
681
|
+
if (actualTypeName.endsWith("Vo")) {
|
|
682
|
+
const openApiName = actualTypeName.slice(0, -2) + "VO";
|
|
683
|
+
schemaTypeMap[openApiName] = actualTypeName;
|
|
684
|
+
}
|
|
685
|
+
if (actualTypeName.endsWith("Dto")) {
|
|
686
|
+
const openApiName = actualTypeName.slice(0, -3) + "DTO";
|
|
687
|
+
schemaTypeMap[openApiName] = actualTypeName;
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
}
|
|
662
691
|
let importStatement = `/* eslint-disable */
|
|
663
692
|
// [Warning] Generated automatically - do not edit manually
|
|
664
693
|
|
|
@@ -675,35 +704,19 @@ function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationD
|
|
|
675
704
|
const reqTypeName = endpoint.argTypeName;
|
|
676
705
|
const resTypeName = endpoint.responseTypeName;
|
|
677
706
|
if (reqTypeName) {
|
|
678
|
-
const requestTypeContent = generateRequestTypeContent(endpoint, operationDefinitions);
|
|
679
|
-
if (requestTypeContent.trim() === ""
|
|
680
|
-
endpointTypes.push(
|
|
681
|
-
`export type ${reqTypeName} = void;`,
|
|
682
|
-
``
|
|
683
|
-
);
|
|
707
|
+
const requestTypeContent = generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap);
|
|
708
|
+
if (requestTypeContent.trim() === "") {
|
|
709
|
+
endpointTypes.push(`export type ${reqTypeName} = void;`, ``);
|
|
684
710
|
} else {
|
|
685
|
-
endpointTypes.push(
|
|
686
|
-
`export type ${reqTypeName} = {`,
|
|
687
|
-
requestTypeContent,
|
|
688
|
-
`};`,
|
|
689
|
-
``
|
|
690
|
-
);
|
|
711
|
+
endpointTypes.push(`export type ${reqTypeName} = {`, requestTypeContent, `};`, ``);
|
|
691
712
|
}
|
|
692
713
|
}
|
|
693
714
|
if (resTypeName) {
|
|
694
|
-
const responseTypeContent = generateResponseTypeContent(endpoint, operationDefinitions);
|
|
695
|
-
if (responseTypeContent.trim() === ""
|
|
696
|
-
endpointTypes.push(
|
|
697
|
-
`export type ${resTypeName} = void;`,
|
|
698
|
-
``
|
|
699
|
-
);
|
|
715
|
+
const responseTypeContent = generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap);
|
|
716
|
+
if (responseTypeContent.trim() === "") {
|
|
717
|
+
endpointTypes.push(`export type ${resTypeName} = void;`, ``);
|
|
700
718
|
} else {
|
|
701
|
-
endpointTypes.push(
|
|
702
|
-
`export type ${resTypeName} = {`,
|
|
703
|
-
responseTypeContent,
|
|
704
|
-
`};`,
|
|
705
|
-
``
|
|
706
|
-
);
|
|
719
|
+
endpointTypes.push(`export type ${resTypeName} = {`, responseTypeContent, `};`, ``);
|
|
707
720
|
}
|
|
708
721
|
}
|
|
709
722
|
});
|
|
@@ -711,27 +724,23 @@ function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationD
|
|
|
711
724
|
typeDefinitions.push(endpointTypes.join("\n"));
|
|
712
725
|
}
|
|
713
726
|
if (typeDefinitions.length === 0) {
|
|
714
|
-
typeDefinitions.push(
|
|
715
|
-
`// \u6B64\u6A94\u6848\u7528\u65BC\u5B9A\u7FA9 API \u76F8\u95DC\u7684\u985E\u578B`,
|
|
716
|
-
`// \u985E\u578B\u5B9A\u7FA9\u6703\u6839\u64DA OpenAPI Schema \u81EA\u52D5\u751F\u6210`,
|
|
717
|
-
``
|
|
718
|
-
);
|
|
727
|
+
typeDefinitions.push(`// \u6B64\u6A94\u6848\u7528\u65BC\u5B9A\u7FA9 API \u76F8\u95DC\u7684\u985E\u578B`, `// \u985E\u578B\u5B9A\u7FA9\u6703\u6839\u64DA OpenAPI Schema \u81EA\u52D5\u751F\u6210`, ``);
|
|
719
728
|
}
|
|
720
729
|
return importStatement + typeDefinitions.join("\n\n");
|
|
721
730
|
}
|
|
722
|
-
function generateRequestTypeContent(endpoint, operationDefinitions) {
|
|
731
|
+
function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}) {
|
|
723
732
|
const properties = [];
|
|
724
733
|
if (endpoint.queryParams && endpoint.queryParams.length > 0) {
|
|
725
734
|
endpoint.queryParams.forEach((param) => {
|
|
726
735
|
const optional = param.required ? "" : "?";
|
|
727
|
-
const paramType = getTypeFromParameter(param);
|
|
736
|
+
const paramType = getTypeFromParameter(param, schemaTypeMap);
|
|
728
737
|
properties.push(` ${param.name}${optional}: ${paramType};`);
|
|
729
738
|
});
|
|
730
739
|
}
|
|
731
740
|
if (endpoint.pathParams && endpoint.pathParams.length > 0) {
|
|
732
741
|
endpoint.pathParams.forEach((param) => {
|
|
733
742
|
const optional = param.required ? "" : "?";
|
|
734
|
-
const paramType = getTypeFromParameter(param);
|
|
743
|
+
const paramType = getTypeFromParameter(param, schemaTypeMap);
|
|
735
744
|
properties.push(` ${param.name}${optional}: ${paramType};`);
|
|
736
745
|
});
|
|
737
746
|
}
|
|
@@ -742,16 +751,22 @@ function generateRequestTypeContent(endpoint, operationDefinitions) {
|
|
|
742
751
|
if (operationDef?.operation?.requestBody) {
|
|
743
752
|
const requestBody = operationDef.operation.requestBody;
|
|
744
753
|
const content = requestBody.content;
|
|
745
|
-
const jsonContent = content["application/json"];
|
|
754
|
+
const jsonContent = content["application/json"] || content["*/*"];
|
|
746
755
|
const formContent = content["multipart/form-data"] || content["application/x-www-form-urlencoded"];
|
|
747
756
|
if (jsonContent?.schema) {
|
|
748
|
-
const bodyType = getTypeFromSchema(jsonContent.schema);
|
|
757
|
+
const bodyType = getTypeFromSchema(jsonContent.schema, schemaTypeMap, 1);
|
|
749
758
|
properties.push(` body: ${bodyType};`);
|
|
750
759
|
} else if (formContent?.schema) {
|
|
751
|
-
const bodyType = getTypeFromSchema(formContent.schema);
|
|
760
|
+
const bodyType = getTypeFromSchema(formContent.schema, schemaTypeMap, 1);
|
|
752
761
|
properties.push(` body: ${bodyType};`);
|
|
753
762
|
} else {
|
|
754
|
-
|
|
763
|
+
const firstContent = Object.values(content)[0];
|
|
764
|
+
if (firstContent?.schema) {
|
|
765
|
+
const bodyType = getTypeFromSchema(firstContent.schema, schemaTypeMap, 1);
|
|
766
|
+
properties.push(` body: ${bodyType};`);
|
|
767
|
+
} else {
|
|
768
|
+
properties.push(` body?: any; // Request body from OpenAPI`);
|
|
769
|
+
}
|
|
755
770
|
}
|
|
756
771
|
}
|
|
757
772
|
if (properties.length === 0) {
|
|
@@ -759,7 +774,7 @@ function generateRequestTypeContent(endpoint, operationDefinitions) {
|
|
|
759
774
|
}
|
|
760
775
|
return properties.join("\n");
|
|
761
776
|
}
|
|
762
|
-
function generateResponseTypeContent(endpoint, operationDefinitions) {
|
|
777
|
+
function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}) {
|
|
763
778
|
const properties = [];
|
|
764
779
|
const operationDef = operationDefinitions?.find((op) => {
|
|
765
780
|
return op.operation?.operationId === endpoint.operationName || op.operation?.operationId === endpoint.operationName.toLowerCase() || // 也嘗試匹配 verb + path 組合
|
|
@@ -768,9 +783,9 @@ function generateResponseTypeContent(endpoint, operationDefinitions) {
|
|
|
768
783
|
if (operationDef?.operation?.responses) {
|
|
769
784
|
const successResponse = operationDef.operation.responses["200"] || operationDef.operation.responses["201"];
|
|
770
785
|
if (successResponse?.content) {
|
|
771
|
-
const jsonContent = successResponse.content["application/json"];
|
|
786
|
+
const jsonContent = successResponse.content["application/json"] || successResponse.content["*/*"] || Object.values(successResponse.content)[0];
|
|
772
787
|
if (jsonContent?.schema) {
|
|
773
|
-
const responseProps = parseSchemaProperties(jsonContent.schema);
|
|
788
|
+
const responseProps = parseSchemaProperties(jsonContent.schema, schemaTypeMap);
|
|
774
789
|
properties.push(...responseProps);
|
|
775
790
|
} else {
|
|
776
791
|
properties.push(` // Success response from OpenAPI`);
|
|
@@ -783,83 +798,114 @@ function generateResponseTypeContent(endpoint, operationDefinitions) {
|
|
|
783
798
|
}
|
|
784
799
|
return properties.join("\n");
|
|
785
800
|
}
|
|
786
|
-
function parseSchemaProperties(schema) {
|
|
801
|
+
function parseSchemaProperties(schema, schemaTypeMap = {}) {
|
|
787
802
|
const properties = [];
|
|
788
803
|
if (schema.type === "object" && schema.properties) {
|
|
789
804
|
const required = schema.required || [];
|
|
790
805
|
Object.entries(schema.properties).forEach(([propName, propSchema]) => {
|
|
791
806
|
const isRequired = required.includes(propName);
|
|
792
807
|
const optional = isRequired ? "" : "?";
|
|
793
|
-
const propType = getTypeFromSchema(propSchema);
|
|
794
|
-
const
|
|
795
|
-
|
|
808
|
+
const propType = getTypeFromSchema(propSchema, schemaTypeMap, 1);
|
|
809
|
+
const needsQuotes = /[^a-zA-Z0-9_$]/.test(propName);
|
|
810
|
+
const quotedPropName = needsQuotes ? `"${propName}"` : propName;
|
|
811
|
+
if (propSchema.description) {
|
|
812
|
+
properties.push(` /** ${propSchema.description} */`);
|
|
813
|
+
}
|
|
814
|
+
properties.push(` ${quotedPropName}${optional}: ${propType};`);
|
|
796
815
|
});
|
|
797
816
|
}
|
|
798
817
|
return properties;
|
|
799
818
|
}
|
|
800
|
-
function getTypeFromSchema(schema) {
|
|
819
|
+
function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
801
820
|
if (!schema) return "any";
|
|
802
821
|
if (schema.$ref) {
|
|
803
822
|
const refPath = schema.$ref;
|
|
804
823
|
if (refPath.startsWith("#/components/schemas/")) {
|
|
805
|
-
const
|
|
806
|
-
|
|
824
|
+
const originalTypeName = refPath.replace("#/components/schemas/", "");
|
|
825
|
+
const actualTypeName = schemaTypeMap[originalTypeName] || originalTypeName;
|
|
826
|
+
const pascalCaseTypeName = toPascalCase2(actualTypeName);
|
|
827
|
+
const baseType2 = `Schema.${pascalCaseTypeName}`;
|
|
828
|
+
return schema.nullable ? `${baseType2} | null` : baseType2;
|
|
807
829
|
}
|
|
808
830
|
}
|
|
831
|
+
let baseType;
|
|
809
832
|
switch (schema.type) {
|
|
810
833
|
case "string":
|
|
811
834
|
if (schema.enum) {
|
|
812
|
-
|
|
835
|
+
baseType = schema.enum.map((val) => `"${val}"`).join(" | ");
|
|
836
|
+
} else if (schema.format === "binary") {
|
|
837
|
+
baseType = "Blob";
|
|
838
|
+
} else {
|
|
839
|
+
baseType = "string";
|
|
813
840
|
}
|
|
814
|
-
|
|
841
|
+
break;
|
|
815
842
|
case "number":
|
|
816
843
|
case "integer":
|
|
817
|
-
|
|
844
|
+
baseType = "number";
|
|
845
|
+
break;
|
|
818
846
|
case "boolean":
|
|
819
|
-
|
|
847
|
+
baseType = "boolean";
|
|
848
|
+
break;
|
|
820
849
|
case "array":
|
|
821
|
-
const itemType = schema.items ? getTypeFromSchema(schema.items) : "any";
|
|
822
|
-
|
|
850
|
+
const itemType = schema.items ? getTypeFromSchema(schema.items, schemaTypeMap, indentLevel) : "any";
|
|
851
|
+
const needsParentheses = itemType.includes("|");
|
|
852
|
+
baseType = needsParentheses ? `(${itemType})[]` : `${itemType}[]`;
|
|
853
|
+
break;
|
|
823
854
|
case "object":
|
|
824
855
|
if (schema.properties) {
|
|
825
|
-
const
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
856
|
+
const entries = Object.entries(schema.properties);
|
|
857
|
+
if (entries.length === 0) {
|
|
858
|
+
if (schema.additionalProperties) {
|
|
859
|
+
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel);
|
|
860
|
+
baseType = `Record<string, ${valueType}>`;
|
|
861
|
+
} else {
|
|
862
|
+
baseType = "{}";
|
|
863
|
+
}
|
|
864
|
+
} else {
|
|
865
|
+
const nextIndent = " ".repeat(indentLevel + 1);
|
|
866
|
+
const currentIndent = " ".repeat(indentLevel);
|
|
867
|
+
const props = [];
|
|
868
|
+
entries.forEach(([key, propSchema]) => {
|
|
869
|
+
const required = schema.required || [];
|
|
870
|
+
const optional = required.includes(key) ? "" : "?";
|
|
871
|
+
const type = getTypeFromSchema(propSchema, schemaTypeMap, indentLevel + 1);
|
|
872
|
+
const needsQuotes = /[^a-zA-Z0-9_$]/.test(key);
|
|
873
|
+
const quotedKey = needsQuotes ? `"${key}"` : key;
|
|
874
|
+
if (propSchema.description) {
|
|
875
|
+
props.push(`${nextIndent}/** ${propSchema.description} */`);
|
|
876
|
+
}
|
|
877
|
+
props.push(`${nextIndent}${quotedKey}${optional}: ${type};`);
|
|
878
|
+
});
|
|
879
|
+
baseType = `{
|
|
880
|
+
${props.join("\n")}
|
|
881
|
+
${currentIndent}}`;
|
|
882
|
+
}
|
|
883
|
+
} else if (schema.additionalProperties) {
|
|
884
|
+
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel);
|
|
885
|
+
baseType = `Record<string, ${valueType}>`;
|
|
886
|
+
} else {
|
|
887
|
+
baseType = "any";
|
|
832
888
|
}
|
|
833
|
-
|
|
889
|
+
break;
|
|
834
890
|
default:
|
|
835
|
-
|
|
891
|
+
baseType = "any";
|
|
892
|
+
break;
|
|
836
893
|
}
|
|
894
|
+
return schema.nullable ? `${baseType} | null` : baseType;
|
|
837
895
|
}
|
|
838
|
-
function getTypeFromParameter(param) {
|
|
896
|
+
function getTypeFromParameter(param, schemaTypeMap = {}) {
|
|
839
897
|
if (!param.schema) return "any";
|
|
840
|
-
return getTypeFromSchema(param.schema);
|
|
898
|
+
return getTypeFromSchema(param.schema, schemaTypeMap);
|
|
841
899
|
}
|
|
842
900
|
|
|
843
|
-
// src/generators/
|
|
901
|
+
// src/generators/rtk-query-generator.ts
|
|
844
902
|
init_esm_shims();
|
|
845
|
-
function
|
|
846
|
-
const { groupKey: optionsGroupKey } = options;
|
|
847
|
-
return `export * from './types';
|
|
848
|
-
export * from './api.service';
|
|
849
|
-
export * from './query.service';
|
|
850
|
-
`;
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
// src/services/query-code-generator.ts
|
|
854
|
-
init_esm_shims();
|
|
855
|
-
|
|
856
|
-
// src/generators/query-service-generator.ts
|
|
857
|
-
init_esm_shims();
|
|
858
|
-
function generateQueryServiceFile(endpointInfos, options) {
|
|
903
|
+
function generateRtkQueryFile(endpointInfos, options) {
|
|
859
904
|
const { groupKey, refetchOnMountOrArgChange = 60 } = options;
|
|
860
905
|
const queryServiceName = groupKey ? `${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)}QueryService` : "QueryService";
|
|
861
906
|
const apiServiceName = groupKey ? `${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)}ApiService` : "ApiService";
|
|
862
|
-
const queryMethods = endpointInfos.filter((info) => info.isQuery).map(
|
|
907
|
+
const queryMethods = endpointInfos.filter((info) => info.isQuery).map(
|
|
908
|
+
(info) => `
|
|
863
909
|
/**
|
|
864
910
|
* ${info.summary}
|
|
865
911
|
*/
|
|
@@ -872,8 +918,10 @@ function generateQueryServiceFile(endpointInfos, options) {
|
|
|
872
918
|
fetchOptions: args?.fetchOptions,
|
|
873
919
|
config: args?.config,
|
|
874
920
|
})${info.argTypeName !== "VoidApiArg" ? "(args)" : "()"};
|
|
875
|
-
}`
|
|
876
|
-
|
|
921
|
+
}`
|
|
922
|
+
).join("");
|
|
923
|
+
const mutationMethods = endpointInfos.filter((info) => !info.isQuery).map(
|
|
924
|
+
(info) => `
|
|
877
925
|
/**
|
|
878
926
|
* ${info.summary}
|
|
879
927
|
*/
|
|
@@ -887,8 +935,10 @@ function generateQueryServiceFile(endpointInfos, options) {
|
|
|
887
935
|
return this.apiService.${info.operationName}(${info.argTypeName !== "VoidApiArg" ? "args" : ""});
|
|
888
936
|
},
|
|
889
937
|
});
|
|
890
|
-
}`
|
|
891
|
-
|
|
938
|
+
}`
|
|
939
|
+
).join("");
|
|
940
|
+
const lazyQueryMethods = endpointInfos.filter((info) => info.isQuery).map(
|
|
941
|
+
(info) => `
|
|
892
942
|
/**
|
|
893
943
|
* ${info.summary}
|
|
894
944
|
*/
|
|
@@ -907,7 +957,8 @@ function generateQueryServiceFile(endpointInfos, options) {
|
|
|
907
957
|
return this.apiService.${info.operationName}(${info.argTypeName !== "VoidApiArg" ? "args" : ""});
|
|
908
958
|
}
|
|
909
959
|
};
|
|
910
|
-
}`
|
|
960
|
+
}`
|
|
961
|
+
).join("");
|
|
911
962
|
return `/* eslint-disable */
|
|
912
963
|
// [Warning] Generated automatically - do not edit manually
|
|
913
964
|
|
|
@@ -931,32 +982,9 @@ ${queryMethods}${mutationMethods}${lazyQueryMethods}
|
|
|
931
982
|
`;
|
|
932
983
|
}
|
|
933
984
|
|
|
934
|
-
// src/
|
|
935
|
-
var QueryCodeGenerator = class {
|
|
936
|
-
constructor(options) {
|
|
937
|
-
this.options = options;
|
|
938
|
-
}
|
|
939
|
-
/**
|
|
940
|
-
* 生成 Query Service 檔案內容
|
|
941
|
-
*/
|
|
942
|
-
generateQueryService(endpointInfos) {
|
|
943
|
-
const generatorOptions = {
|
|
944
|
-
...this.options,
|
|
945
|
-
apiConfiguration: this.options.apiConfiguration || {
|
|
946
|
-
file: "@/store/webapi",
|
|
947
|
-
importName: "WebApiConfiguration"
|
|
948
|
-
}
|
|
949
|
-
};
|
|
950
|
-
return generateQueryServiceFile(endpointInfos, generatorOptions);
|
|
951
|
-
}
|
|
952
|
-
};
|
|
953
|
-
|
|
954
|
-
// src/services/api-service-generator.ts
|
|
985
|
+
// src/generators/rtk-enhance-endpoints-generator.ts
|
|
955
986
|
init_esm_shims();
|
|
956
|
-
|
|
957
|
-
// src/generators/api-service-generator.ts
|
|
958
|
-
init_esm_shims();
|
|
959
|
-
function generateApiServiceFile(endpointInfos, options) {
|
|
987
|
+
function generateRtkEnhanceEndpointsFile(endpointInfos, options) {
|
|
960
988
|
const { apiConfiguration, httpClient, groupKey } = options;
|
|
961
989
|
const apiServiceClassName = groupKey ? `${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)}ApiService` : "ApiService";
|
|
962
990
|
return `/* eslint-disable */
|
|
@@ -980,6 +1008,7 @@ export class ${apiServiceClassName} {
|
|
|
980
1008
|
${endpointInfos.map((info) => {
|
|
981
1009
|
const isGet = info.verb.toUpperCase() === "GET";
|
|
982
1010
|
const hasArgs = info.argTypeName !== "VoidApiArg";
|
|
1011
|
+
const hasRequestBody = info.hasRequestBody;
|
|
983
1012
|
const generateUrlTemplate = (path5) => {
|
|
984
1013
|
const hasPathParams = path5.includes("{");
|
|
985
1014
|
if (hasPathParams && hasArgs) {
|
|
@@ -990,18 +1019,16 @@ ${endpointInfos.map((info) => {
|
|
|
990
1019
|
}
|
|
991
1020
|
};
|
|
992
1021
|
const hasQueryParams = info.queryParams.length > 0;
|
|
993
|
-
const hasBody = !isGet && hasArgs
|
|
1022
|
+
const hasBody = !isGet && hasArgs;
|
|
994
1023
|
const generateRequestOptions = () => {
|
|
995
|
-
const options2 = [
|
|
996
|
-
|
|
997
|
-
];
|
|
998
|
-
if (hasBody || !isGet) {
|
|
1024
|
+
const options2 = ["...args.fetchOptions"];
|
|
1025
|
+
if (hasRequestBody || !isGet) {
|
|
999
1026
|
options2.push(`headers: { 'Content-Type': 'application/json', ...args.fetchOptions?.headers }`);
|
|
1000
1027
|
}
|
|
1001
1028
|
if (hasQueryParams && hasArgs) {
|
|
1002
1029
|
options2.push(generateQueryParams(info.queryParams));
|
|
1003
1030
|
}
|
|
1004
|
-
if (
|
|
1031
|
+
if (hasRequestBody) {
|
|
1005
1032
|
options2.push("body: args.variables.body");
|
|
1006
1033
|
}
|
|
1007
1034
|
return options2.length > 0 ? `{ ${options2.join(", ")} }` : "{}";
|
|
@@ -1027,62 +1054,47 @@ function generateQueryParams(queryParams) {
|
|
|
1027
1054
|
return `params: withoutUndefined({ ${paramEntries} })`;
|
|
1028
1055
|
}
|
|
1029
1056
|
|
|
1030
|
-
// src/services/api-service-generator.ts
|
|
1031
|
-
var ApiServiceGenerator = class {
|
|
1032
|
-
constructor(options) {
|
|
1033
|
-
this.options = options;
|
|
1034
|
-
}
|
|
1035
|
-
/**
|
|
1036
|
-
* 生成 API Service 檔案內容
|
|
1037
|
-
*/
|
|
1038
|
-
generateApiService(endpointInfos) {
|
|
1039
|
-
const generatorOptions = {
|
|
1040
|
-
...this.options,
|
|
1041
|
-
apiConfiguration: this.options.apiConfiguration || {
|
|
1042
|
-
file: "@/store/webapi",
|
|
1043
|
-
importName: "WebApiConfiguration"
|
|
1044
|
-
}
|
|
1045
|
-
};
|
|
1046
|
-
return generateApiServiceFile(endpointInfos, generatorOptions);
|
|
1047
|
-
}
|
|
1048
|
-
};
|
|
1049
|
-
|
|
1050
1057
|
// src/services/api-code-generator.ts
|
|
1051
1058
|
var ApiCodeGenerator = class {
|
|
1052
1059
|
constructor(parserService, options) {
|
|
1053
1060
|
this.parserService = parserService;
|
|
1054
1061
|
this.options = options;
|
|
1055
1062
|
this.infoExtractor = new EndpointInfoExtractor(options);
|
|
1056
|
-
this.queryGenerator = new QueryCodeGenerator(options);
|
|
1057
|
-
this.apiServiceGenerator = new ApiServiceGenerator(options);
|
|
1058
1063
|
}
|
|
1059
1064
|
infoExtractor;
|
|
1060
|
-
queryGenerator;
|
|
1061
|
-
apiServiceGenerator;
|
|
1062
1065
|
/**
|
|
1063
|
-
* 生成完整的
|
|
1066
|
+
* 生成完整的 RTK Query 程式碼
|
|
1064
1067
|
*/
|
|
1065
1068
|
async generate() {
|
|
1066
1069
|
const operationDefinitions = this.parserService.getOperationDefinitions(this.options.filterEndpoints);
|
|
1067
1070
|
const endpointInfos = this.infoExtractor.extractEndpointInfos(operationDefinitions);
|
|
1071
|
+
return this.generateRtkQueryCode(endpointInfos);
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* 生成 RTK Query 代碼
|
|
1075
|
+
*/
|
|
1076
|
+
generateRtkQueryCode(endpointInfos) {
|
|
1068
1077
|
const typesContent = this.generateTypes(endpointInfos);
|
|
1069
|
-
const
|
|
1070
|
-
const
|
|
1078
|
+
const rtkQueryContent = generateRtkQueryFile(endpointInfos, this.options);
|
|
1079
|
+
const enhanceEndpointsContent = generateRtkEnhanceEndpointsFile(endpointInfos, this.options);
|
|
1071
1080
|
const indexContent = this.generateIndex();
|
|
1072
|
-
const allEndpointCacheKeys = endpointInfos.filter((info) => info.isQuery).map((info) => ({
|
|
1073
|
-
operationName: info.operationName,
|
|
1074
|
-
queryKeyName: info.queryKeyName,
|
|
1075
|
-
groupKey: this.options.groupKey || "_common"
|
|
1076
|
-
}));
|
|
1077
1081
|
const operationNames = endpointInfos.map((info) => info.operationName);
|
|
1082
|
+
const allTags = /* @__PURE__ */ new Set();
|
|
1083
|
+
endpointInfos.forEach((info) => {
|
|
1084
|
+
if (info.tags && Array.isArray(info.tags)) {
|
|
1085
|
+
info.tags.forEach((tag) => allTags.add(tag));
|
|
1086
|
+
}
|
|
1087
|
+
});
|
|
1078
1088
|
return {
|
|
1079
1089
|
operationNames,
|
|
1090
|
+
tags: Array.from(allTags),
|
|
1080
1091
|
files: {
|
|
1081
1092
|
types: typesContent,
|
|
1082
|
-
|
|
1083
|
-
|
|
1093
|
+
queryService: rtkQueryContent,
|
|
1094
|
+
// RTK Query 檔案
|
|
1084
1095
|
index: indexContent,
|
|
1085
|
-
|
|
1096
|
+
enhanceEndpoints: enhanceEndpointsContent
|
|
1097
|
+
// 新增的 enhance endpoints 檔案
|
|
1086
1098
|
}
|
|
1087
1099
|
};
|
|
1088
1100
|
}
|
|
@@ -1098,43 +1110,35 @@ var ApiCodeGenerator = class {
|
|
|
1098
1110
|
}
|
|
1099
1111
|
};
|
|
1100
1112
|
const apiGen = this.parserService.getApiGenerator();
|
|
1101
|
-
const schemaInterfaces = apiGen.aliases.reduce(
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1113
|
+
const schemaInterfaces = apiGen.aliases.reduce(
|
|
1114
|
+
(curr, alias) => {
|
|
1115
|
+
if (ts2.isInterfaceDeclaration(alias) || ts2.isTypeAliasDeclaration(alias)) {
|
|
1116
|
+
const name = alias.name.text;
|
|
1117
|
+
return {
|
|
1118
|
+
...curr,
|
|
1119
|
+
[name]: alias
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
return curr;
|
|
1123
|
+
},
|
|
1124
|
+
{}
|
|
1125
|
+
);
|
|
1111
1126
|
const operationDefinitions = this.parserService.getOperationDefinitions(this.options.filterEndpoints);
|
|
1112
1127
|
return generateTypesFile(endpointInfos, generatorOptions, schemaInterfaces, operationDefinitions);
|
|
1113
1128
|
}
|
|
1114
|
-
/**
|
|
1115
|
-
* 生成 API Service 檔案內容
|
|
1116
|
-
*/
|
|
1117
|
-
generateApiService(endpointInfos) {
|
|
1118
|
-
return this.apiServiceGenerator.generateApiService(endpointInfos);
|
|
1119
|
-
}
|
|
1120
|
-
/**
|
|
1121
|
-
* 生成 Query Service 檔案內容
|
|
1122
|
-
*/
|
|
1123
|
-
generateQueryService(endpointInfos) {
|
|
1124
|
-
return this.queryGenerator.generateQueryService(endpointInfos);
|
|
1125
|
-
}
|
|
1126
1129
|
/**
|
|
1127
1130
|
* 生成 Index 檔案內容
|
|
1128
1131
|
*/
|
|
1129
1132
|
generateIndex() {
|
|
1130
|
-
const
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1133
|
+
const groupKey = this.options.groupKey || "";
|
|
1134
|
+
const exportName = groupKey ? `${groupKey.charAt(0).toLowerCase() + groupKey.slice(1)}Api` : "api";
|
|
1135
|
+
return `/* eslint-disable */
|
|
1136
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1137
|
+
|
|
1138
|
+
export { default as ${exportName} } from "./enhanceEndpoints";
|
|
1139
|
+
export * from "./query.generated";
|
|
1140
|
+
export * from "./types";
|
|
1141
|
+
`;
|
|
1138
1142
|
}
|
|
1139
1143
|
// /**
|
|
1140
1144
|
// * 獲取已解析的 parser service(供外部使用)
|
|
@@ -1151,6 +1155,46 @@ var ApiCodeGenerator = class {
|
|
|
1151
1155
|
// }
|
|
1152
1156
|
};
|
|
1153
1157
|
|
|
1158
|
+
// src/generators/utils-generator.ts
|
|
1159
|
+
init_esm_shims();
|
|
1160
|
+
function generateUtilsFile() {
|
|
1161
|
+
return `/* eslint-disable */
|
|
1162
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1163
|
+
|
|
1164
|
+
/**
|
|
1165
|
+
* Clear undefined in object
|
|
1166
|
+
*/
|
|
1167
|
+
export function withoutUndefined(obj?: Record<string, any>) {
|
|
1168
|
+
if(typeof obj === 'undefined') return;
|
|
1169
|
+
return Object.fromEntries(
|
|
1170
|
+
Object.entries(obj).filter(([_, v]) => v !== undefined && v !== null)
|
|
1171
|
+
);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
`;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
// src/generators/tag-types-generator.ts
|
|
1178
|
+
init_esm_shims();
|
|
1179
|
+
function generateTagTypesFile(tags) {
|
|
1180
|
+
if (tags.length === 0) {
|
|
1181
|
+
return `/* eslint-disable */
|
|
1182
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1183
|
+
|
|
1184
|
+
export enum ECacheTagTypes {
|
|
1185
|
+
}
|
|
1186
|
+
`;
|
|
1187
|
+
}
|
|
1188
|
+
const enumEntries = tags.sort().map((tag) => ` ${tag} = '${tag}',`).join("\n");
|
|
1189
|
+
return `/* eslint-disable */
|
|
1190
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1191
|
+
|
|
1192
|
+
export enum ECacheTagTypes {
|
|
1193
|
+
${enumEntries}
|
|
1194
|
+
}
|
|
1195
|
+
`;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1154
1198
|
// src/services/unified-code-generator.ts
|
|
1155
1199
|
var UnifiedCodeGenerator = class {
|
|
1156
1200
|
_options;
|
|
@@ -1161,17 +1205,18 @@ var UnifiedCodeGenerator = class {
|
|
|
1161
1205
|
openApiDoc = null;
|
|
1162
1206
|
parserService = null;
|
|
1163
1207
|
schemaInterfaces = {};
|
|
1164
|
-
allEndpointCacheKeys = [];
|
|
1165
1208
|
actualSchemaFile = "";
|
|
1166
1209
|
// 生成內容存儲
|
|
1167
1210
|
generatedContent = {
|
|
1168
1211
|
groups: [],
|
|
1169
|
-
cacheKeys: null,
|
|
1170
1212
|
commonTypes: "",
|
|
1171
1213
|
componentSchema: "",
|
|
1172
1214
|
doNotModify: "",
|
|
1173
|
-
utils: ""
|
|
1215
|
+
utils: "",
|
|
1216
|
+
tagTypes: ""
|
|
1174
1217
|
};
|
|
1218
|
+
// 收集所有 tags
|
|
1219
|
+
allTags = /* @__PURE__ */ new Set();
|
|
1175
1220
|
constructor(options) {
|
|
1176
1221
|
this._options = options;
|
|
1177
1222
|
}
|
|
@@ -1181,11 +1226,11 @@ var UnifiedCodeGenerator = class {
|
|
|
1181
1226
|
async generateAll() {
|
|
1182
1227
|
await this.prepare();
|
|
1183
1228
|
await this.generateApi();
|
|
1184
|
-
this.generateCacheKeysContent();
|
|
1185
1229
|
this.generateCommonTypesContent();
|
|
1186
1230
|
this.generateSchemaContent();
|
|
1187
1231
|
this.generateUtilsContent();
|
|
1188
1232
|
this.generateDoNotModifyContent();
|
|
1233
|
+
this.generateTagTypesContent();
|
|
1189
1234
|
return await this.release();
|
|
1190
1235
|
}
|
|
1191
1236
|
/**
|
|
@@ -1238,18 +1283,15 @@ var UnifiedCodeGenerator = class {
|
|
|
1238
1283
|
outputPath: groupInfo.outputPath,
|
|
1239
1284
|
content: groupContent
|
|
1240
1285
|
});
|
|
1286
|
+
if (groupContent.tags && Array.isArray(groupContent.tags)) {
|
|
1287
|
+
groupContent.tags.forEach((tag) => this.allTags.add(tag));
|
|
1288
|
+
}
|
|
1241
1289
|
}
|
|
1242
1290
|
} catch (error) {
|
|
1243
1291
|
throw new Error(`\u7FA4\u7D44 ${groupInfo.groupKey} \u751F\u6210\u5931\u6557: ${error}`);
|
|
1244
1292
|
}
|
|
1245
1293
|
}
|
|
1246
1294
|
}
|
|
1247
|
-
/**
|
|
1248
|
-
* 生成 cache keys
|
|
1249
|
-
*/
|
|
1250
|
-
async generateCacheKeysContent() {
|
|
1251
|
-
this.generatedContent.cacheKeys = generateCacheKeysFile(this.allEndpointCacheKeys);
|
|
1252
|
-
}
|
|
1253
1295
|
/**
|
|
1254
1296
|
* 生成 common types
|
|
1255
1297
|
*/
|
|
@@ -1274,6 +1316,13 @@ var UnifiedCodeGenerator = class {
|
|
|
1274
1316
|
async generateUtilsContent() {
|
|
1275
1317
|
this.generatedContent.utils = generateUtilsFile();
|
|
1276
1318
|
}
|
|
1319
|
+
/**
|
|
1320
|
+
* 生成 Tag Types
|
|
1321
|
+
*/
|
|
1322
|
+
async generateTagTypesContent() {
|
|
1323
|
+
const tagsArray = Array.from(this.allTags);
|
|
1324
|
+
this.generatedContent.tagTypes = generateTagTypesFile(tagsArray);
|
|
1325
|
+
}
|
|
1277
1326
|
/**
|
|
1278
1327
|
* 發佈階段:統一寫入所有檔案
|
|
1279
1328
|
*/
|
|
@@ -1290,8 +1339,8 @@ var UnifiedCodeGenerator = class {
|
|
|
1290
1339
|
groupOutputDir,
|
|
1291
1340
|
{
|
|
1292
1341
|
types: group.content.files.types,
|
|
1293
|
-
apiService: group.content.files.apiService,
|
|
1294
1342
|
queryService: group.content.files.queryService,
|
|
1343
|
+
enhanceEndpoints: group.content.files.enhanceEndpoints,
|
|
1295
1344
|
index: group.content.files.index
|
|
1296
1345
|
}
|
|
1297
1346
|
);
|
|
@@ -1303,11 +1352,10 @@ var UnifiedCodeGenerator = class {
|
|
|
1303
1352
|
}
|
|
1304
1353
|
}
|
|
1305
1354
|
const outputDir = this.generatedContent.groups[0] ? path4.dirname(path4.dirname(this.generatedContent.groups[0].outputPath)) : "./generated";
|
|
1306
|
-
if (this.generatedContent.
|
|
1355
|
+
if (this.generatedContent.commonTypes || this.generatedContent.doNotModify || this.generatedContent.utils) {
|
|
1307
1356
|
const sharedResults = await this.fileWriterService.writeSharedFiles(
|
|
1308
1357
|
outputDir,
|
|
1309
1358
|
{
|
|
1310
|
-
cacheKeys: this.generatedContent.cacheKeys || void 0,
|
|
1311
1359
|
commonTypes: this.generatedContent.commonTypes || void 0,
|
|
1312
1360
|
doNotModify: this.generatedContent.doNotModify || void 0,
|
|
1313
1361
|
utils: this.generatedContent.utils || void 0
|
|
@@ -1315,6 +1363,13 @@ var UnifiedCodeGenerator = class {
|
|
|
1315
1363
|
);
|
|
1316
1364
|
results.push(...sharedResults);
|
|
1317
1365
|
}
|
|
1366
|
+
if (this.generatedContent.tagTypes) {
|
|
1367
|
+
const tagTypesResult = await this.fileWriterService.writeFile(
|
|
1368
|
+
path4.join(outputDir, "tagTypes.ts"),
|
|
1369
|
+
this.generatedContent.tagTypes
|
|
1370
|
+
);
|
|
1371
|
+
results.push(tagTypesResult);
|
|
1372
|
+
}
|
|
1318
1373
|
if (this.generatedContent.componentSchema) {
|
|
1319
1374
|
const schemaResults = await this.fileWriterService.writeSchemaFile(
|
|
1320
1375
|
outputDir,
|
|
@@ -1322,6 +1377,12 @@ var UnifiedCodeGenerator = class {
|
|
|
1322
1377
|
);
|
|
1323
1378
|
results.push(...schemaResults);
|
|
1324
1379
|
}
|
|
1380
|
+
const mainIndexContent = this.generateMainIndex(generatedGroups);
|
|
1381
|
+
const mainIndexResult = await this.fileWriterService.writeFile(
|
|
1382
|
+
path4.join(outputDir, "index.ts"),
|
|
1383
|
+
mainIndexContent
|
|
1384
|
+
);
|
|
1385
|
+
results.push(mainIndexResult);
|
|
1325
1386
|
} catch (error) {
|
|
1326
1387
|
errors.push(error);
|
|
1327
1388
|
}
|
|
@@ -1351,12 +1412,19 @@ var UnifiedCodeGenerator = class {
|
|
|
1351
1412
|
}
|
|
1352
1413
|
const apiGenerator = new ApiCodeGenerator(this.parserService, groupOptions);
|
|
1353
1414
|
const result = await apiGenerator.generate();
|
|
1354
|
-
if (result.files && "allEndpointCacheKeys" in result.files) {
|
|
1355
|
-
const cacheKeys = result.files.allEndpointCacheKeys;
|
|
1356
|
-
this.allEndpointCacheKeys.push(...cacheKeys);
|
|
1357
|
-
}
|
|
1358
1415
|
return result;
|
|
1359
1416
|
}
|
|
1417
|
+
/**
|
|
1418
|
+
* 生成主 index.ts 檔案
|
|
1419
|
+
*/
|
|
1420
|
+
generateMainIndex(generatedGroups) {
|
|
1421
|
+
const exports = generatedGroups.map((groupKey) => `export * from "./${groupKey}";`).join("\n");
|
|
1422
|
+
return `/* eslint-disable */
|
|
1423
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1424
|
+
|
|
1425
|
+
${exports}
|
|
1426
|
+
`;
|
|
1427
|
+
}
|
|
1360
1428
|
};
|
|
1361
1429
|
|
|
1362
1430
|
// src/index.ts
|