@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.js
CHANGED
|
@@ -326,6 +326,13 @@ var FileWriterService = class {
|
|
|
326
326
|
async writeFile(filePath, content) {
|
|
327
327
|
try {
|
|
328
328
|
const resolvedPath = import_node_path3.default.resolve(process.cwd(), filePath);
|
|
329
|
+
const fileName = import_node_path3.default.basename(resolvedPath);
|
|
330
|
+
if (fileName === "enhanceEndpoints.ts" && import_node_fs3.default.existsSync(resolvedPath)) {
|
|
331
|
+
return {
|
|
332
|
+
path: resolvedPath,
|
|
333
|
+
success: true
|
|
334
|
+
};
|
|
335
|
+
}
|
|
329
336
|
await ensureDirectoryExists(resolvedPath);
|
|
330
337
|
import_node_fs3.default.writeFileSync(resolvedPath, content);
|
|
331
338
|
return {
|
|
@@ -353,7 +360,7 @@ var FileWriterService = class {
|
|
|
353
360
|
return results;
|
|
354
361
|
}
|
|
355
362
|
/**
|
|
356
|
-
*
|
|
363
|
+
* 為群組寫入 RTK Query 檔案結構
|
|
357
364
|
* @param groupOutputDir - 群組輸出目錄
|
|
358
365
|
* @param files - 檔案內容
|
|
359
366
|
*/
|
|
@@ -362,11 +369,11 @@ var FileWriterService = class {
|
|
|
362
369
|
if (files.types) {
|
|
363
370
|
filesToWrite[import_node_path3.default.join(groupOutputDir, "types.ts")] = files.types;
|
|
364
371
|
}
|
|
365
|
-
if (files.apiService) {
|
|
366
|
-
filesToWrite[import_node_path3.default.join(groupOutputDir, "api.service.ts")] = files.apiService;
|
|
367
|
-
}
|
|
368
372
|
if (files.queryService) {
|
|
369
|
-
filesToWrite[import_node_path3.default.join(groupOutputDir, "query.
|
|
373
|
+
filesToWrite[import_node_path3.default.join(groupOutputDir, "query.generated.ts")] = files.queryService;
|
|
374
|
+
}
|
|
375
|
+
if (files.enhanceEndpoints) {
|
|
376
|
+
filesToWrite[import_node_path3.default.join(groupOutputDir, "enhanceEndpoints.ts")] = files.enhanceEndpoints;
|
|
370
377
|
}
|
|
371
378
|
if (files.index) {
|
|
372
379
|
filesToWrite[import_node_path3.default.join(groupOutputDir, "index.ts")] = files.index;
|
|
@@ -383,9 +390,6 @@ var FileWriterService = class {
|
|
|
383
390
|
if (sharedFiles.commonTypes) {
|
|
384
391
|
filesToWrite[import_node_path3.default.join(outputDir, "common-types.ts")] = sharedFiles.commonTypes;
|
|
385
392
|
}
|
|
386
|
-
if (sharedFiles.cacheKeys) {
|
|
387
|
-
filesToWrite[import_node_path3.default.join(outputDir, "cache-keys.ts")] = sharedFiles.cacheKeys;
|
|
388
|
-
}
|
|
389
393
|
if (sharedFiles.doNotModify) {
|
|
390
394
|
filesToWrite[import_node_path3.default.join(outputDir, "DO_NOT_MODIFY.md")] = sharedFiles.doNotModify;
|
|
391
395
|
}
|
|
@@ -414,7 +418,6 @@ var OpenApiParserService = class {
|
|
|
414
418
|
this.v3Doc = v3Doc;
|
|
415
419
|
this.apiGen = new import_generate2.default(v3Doc, {
|
|
416
420
|
unionUndefined: options.unionUndefined,
|
|
417
|
-
useEnumType: options.useEnumType,
|
|
418
421
|
mergeReadWriteOnly: options.mergeReadWriteOnly
|
|
419
422
|
});
|
|
420
423
|
}
|
|
@@ -424,6 +427,12 @@ var OpenApiParserService = class {
|
|
|
424
427
|
*/
|
|
425
428
|
initialize() {
|
|
426
429
|
if (this.apiGen.spec.components?.schemas) {
|
|
430
|
+
Object.keys(this.apiGen.spec.components.schemas).forEach((schemaName) => {
|
|
431
|
+
const schema = this.apiGen.spec.components.schemas[schemaName];
|
|
432
|
+
if (schema && typeof schema === "object" && "title" in schema) {
|
|
433
|
+
delete schema.title;
|
|
434
|
+
}
|
|
435
|
+
});
|
|
427
436
|
this.apiGen.preprocessComponents(this.apiGen.spec.components.schemas);
|
|
428
437
|
Object.keys(this.apiGen.spec.components.schemas).forEach((schemaName) => {
|
|
429
438
|
try {
|
|
@@ -462,64 +471,6 @@ var OpenApiParserService = class {
|
|
|
462
471
|
}
|
|
463
472
|
};
|
|
464
473
|
|
|
465
|
-
// src/generators/cache-keys-generator.ts
|
|
466
|
-
init_cjs_shims();
|
|
467
|
-
|
|
468
|
-
// src/generators/utils-generator.ts
|
|
469
|
-
init_cjs_shims();
|
|
470
|
-
function generateUtilsFile() {
|
|
471
|
-
return `/* eslint-disable */
|
|
472
|
-
// [Warning] Generated automatically - do not edit manually
|
|
473
|
-
|
|
474
|
-
/**
|
|
475
|
-
* Clear undefined in object
|
|
476
|
-
*/
|
|
477
|
-
export function withoutUndefined(obj?: Record<string, any>) {
|
|
478
|
-
if(typeof obj === 'undefined') return;
|
|
479
|
-
return Object.fromEntries(
|
|
480
|
-
Object.entries(obj).filter(([_, v]) => v !== undefined && v !== null)
|
|
481
|
-
);
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
`;
|
|
485
|
-
}
|
|
486
|
-
function toCamelCase(str) {
|
|
487
|
-
return str.toLowerCase().replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
// src/generators/cache-keys-generator.ts
|
|
491
|
-
function generateCacheKeysFile(allEndpointInfos) {
|
|
492
|
-
const groupedKeys = allEndpointInfos.reduce((acc, info) => {
|
|
493
|
-
if (!acc[info.groupKey]) {
|
|
494
|
-
acc[info.groupKey] = [];
|
|
495
|
-
}
|
|
496
|
-
acc[info.groupKey].push({
|
|
497
|
-
operationName: info.operationName,
|
|
498
|
-
queryKeyName: info.queryKeyName
|
|
499
|
-
});
|
|
500
|
-
return acc;
|
|
501
|
-
}, {});
|
|
502
|
-
const enumEntries = Object.entries(groupedKeys).map(([groupKey, keys]) => {
|
|
503
|
-
const groupComment = ` // ${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)} related cache keys`;
|
|
504
|
-
const keyEntries = keys.map(
|
|
505
|
-
(key) => ` ${key.queryKeyName} = '${toCamelCase(key.queryKeyName)}',`
|
|
506
|
-
).join("\n");
|
|
507
|
-
return `${groupComment}
|
|
508
|
-
${keyEntries}`;
|
|
509
|
-
}).join("\n\n");
|
|
510
|
-
return `// [Warning] Generated automatically - do not edit manually
|
|
511
|
-
|
|
512
|
-
/**
|
|
513
|
-
* Cache keys enum for all API queries
|
|
514
|
-
*/
|
|
515
|
-
export enum ECacheKeys {
|
|
516
|
-
${enumEntries}
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
export default ECacheKeys;
|
|
520
|
-
`;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
474
|
// src/generators/common-types-generator.ts
|
|
524
475
|
init_cjs_shims();
|
|
525
476
|
function generateCommonTypesFile() {
|
|
@@ -540,11 +491,15 @@ export interface QueryConfig {
|
|
|
540
491
|
keepUnusedDataFor?: number,
|
|
541
492
|
}
|
|
542
493
|
|
|
494
|
+
export interface IRequestConfig extends RequestOptions { {
|
|
495
|
+
timeout?: number;
|
|
496
|
+
}
|
|
497
|
+
|
|
543
498
|
export type IRestFulEndpointsQueryReturn<TVariables> = TVariables extends void ?
|
|
544
|
-
void | {fetchOptions?:
|
|
499
|
+
void | {fetchOptions?: IRequestConfig;}:
|
|
545
500
|
{
|
|
546
501
|
variables: TVariables;
|
|
547
|
-
fetchOptions?:
|
|
502
|
+
fetchOptions?: IRequestConfig;
|
|
548
503
|
config?: QueryConfig;
|
|
549
504
|
};
|
|
550
505
|
`;
|
|
@@ -553,6 +508,19 @@ export type IRestFulEndpointsQueryReturn<TVariables> = TVariables extends void ?
|
|
|
553
508
|
// src/generators/component-schema-generator.ts
|
|
554
509
|
init_cjs_shims();
|
|
555
510
|
var import_typescript = __toESM(require("typescript"));
|
|
511
|
+
function toPascalCase(name) {
|
|
512
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
513
|
+
}
|
|
514
|
+
function renameIdentifier(node, oldName, newName) {
|
|
515
|
+
return import_typescript.default.transform(node, [
|
|
516
|
+
(context) => (rootNode) => import_typescript.default.visitNode(rootNode, function visit(node2) {
|
|
517
|
+
if (import_typescript.default.isIdentifier(node2) && node2.text === oldName) {
|
|
518
|
+
return import_typescript.default.factory.createIdentifier(newName);
|
|
519
|
+
}
|
|
520
|
+
return import_typescript.default.visitEachChild(node2, visit, context);
|
|
521
|
+
})
|
|
522
|
+
]).transformed[0];
|
|
523
|
+
}
|
|
556
524
|
function generateComponentSchemaFile(interfaces) {
|
|
557
525
|
const printer = import_typescript.default.createPrinter({ newLine: import_typescript.default.NewLineKind.LineFeed });
|
|
558
526
|
const resultFile = import_typescript.default.createSourceFile(
|
|
@@ -562,10 +530,19 @@ function generateComponentSchemaFile(interfaces) {
|
|
|
562
530
|
false,
|
|
563
531
|
import_typescript.default.ScriptKind.TS
|
|
564
532
|
);
|
|
533
|
+
const renamedInterfaces = [];
|
|
534
|
+
const typeNameMapping = {};
|
|
535
|
+
Object.entries(interfaces).forEach(([originalName, node]) => {
|
|
536
|
+
const pascalCaseName = toPascalCase(originalName);
|
|
537
|
+
typeNameMapping[originalName] = pascalCaseName;
|
|
538
|
+
const renamedNode = renameIdentifier(node, originalName, pascalCaseName);
|
|
539
|
+
const printed = printer.printNode(import_typescript.default.EmitHint.Unspecified, renamedNode, resultFile);
|
|
540
|
+
renamedInterfaces.push(printed);
|
|
541
|
+
});
|
|
565
542
|
return `/* eslint-disable */
|
|
566
|
-
// [Warning] Generated automatically - do not edit manually
|
|
567
|
-
|
|
568
|
-
${
|
|
543
|
+
// [Warning] Generated automatically - do not edit manually
|
|
544
|
+
|
|
545
|
+
${renamedInterfaces.join("\n")}
|
|
569
546
|
`;
|
|
570
547
|
}
|
|
571
548
|
|
|
@@ -621,7 +598,13 @@ var EndpointInfoExtractor = class {
|
|
|
621
598
|
*/
|
|
622
599
|
extractSingleEndpointInfo(operationDefinition) {
|
|
623
600
|
const { verb, path: path5, operation } = operationDefinition;
|
|
624
|
-
const {
|
|
601
|
+
const {
|
|
602
|
+
operationNameSuffix = "",
|
|
603
|
+
argSuffix = "Req",
|
|
604
|
+
responseSuffix = "Res",
|
|
605
|
+
queryMatch,
|
|
606
|
+
endpointOverrides
|
|
607
|
+
} = this.options;
|
|
625
608
|
const operationName = getOperationName({ verb, path: path5 });
|
|
626
609
|
const finalOperationName = operationNameSuffix ? capitalize(operationName + operationNameSuffix) : operationName;
|
|
627
610
|
const argTypeName = capitalize(operationName + operationNameSuffix + argSuffix);
|
|
@@ -629,7 +612,9 @@ var EndpointInfoExtractor = class {
|
|
|
629
612
|
const isQuery2 = isQuery(verb, path5, getOverrides(operationDefinition, endpointOverrides), queryMatch);
|
|
630
613
|
const queryKeyName = `${operationName.replace(/([A-Z])/g, "_$1").toUpperCase()}`;
|
|
631
614
|
const summary = operation.summary || `${verb.toUpperCase()} ${path5}`;
|
|
632
|
-
const { queryParams, pathParams, isVoidArg } = this.extractParameters(operationDefinition);
|
|
615
|
+
const { queryParams, pathParams, isVoidArg, hasRequestBody } = this.extractParameters(operationDefinition);
|
|
616
|
+
const contentType = this.extractContentType(operation);
|
|
617
|
+
const tags = Array.isArray(operation.tags) ? operation.tags : [];
|
|
633
618
|
return {
|
|
634
619
|
operationName: finalOperationName,
|
|
635
620
|
argTypeName,
|
|
@@ -641,7 +626,10 @@ var EndpointInfoExtractor = class {
|
|
|
641
626
|
queryParams,
|
|
642
627
|
pathParams,
|
|
643
628
|
isVoidArg,
|
|
644
|
-
summary
|
|
629
|
+
summary,
|
|
630
|
+
contentType,
|
|
631
|
+
hasRequestBody,
|
|
632
|
+
tags
|
|
645
633
|
};
|
|
646
634
|
}
|
|
647
635
|
/**
|
|
@@ -651,15 +639,21 @@ var EndpointInfoExtractor = class {
|
|
|
651
639
|
extractParameters(operationDefinition) {
|
|
652
640
|
const { operation, pathItem } = operationDefinition;
|
|
653
641
|
const operationParameters = this.resolveArray(operation.parameters);
|
|
654
|
-
const pathItemParameters = this.resolveArray(pathItem.parameters).filter(
|
|
655
|
-
|
|
642
|
+
const pathItemParameters = this.resolveArray(pathItem.parameters).filter(
|
|
643
|
+
(pp) => !operationParameters.some((op) => op.name === pp.name && op.in === pp.in)
|
|
644
|
+
);
|
|
645
|
+
const allParameters = (0, import_generate3.supportDeepObjects)([...pathItemParameters, ...operationParameters]).filter(
|
|
646
|
+
(param) => param.in !== "header"
|
|
647
|
+
);
|
|
656
648
|
const queryParams = allParameters.filter((param) => param.in === "query");
|
|
657
649
|
const pathParams = allParameters.filter((param) => param.in === "path");
|
|
650
|
+
const hasRequestBody = !!operation.requestBody;
|
|
658
651
|
const isVoidArg = queryParams.length === 0 && pathParams.length === 0 && !operation.requestBody;
|
|
659
652
|
return {
|
|
660
653
|
queryParams,
|
|
661
654
|
pathParams,
|
|
662
|
-
isVoidArg
|
|
655
|
+
isVoidArg,
|
|
656
|
+
hasRequestBody
|
|
663
657
|
};
|
|
664
658
|
}
|
|
665
659
|
/**
|
|
@@ -669,11 +663,46 @@ var EndpointInfoExtractor = class {
|
|
|
669
663
|
if (!parameters) return [];
|
|
670
664
|
return Array.isArray(parameters) ? parameters : [parameters];
|
|
671
665
|
}
|
|
666
|
+
/**
|
|
667
|
+
* 提取操作的 content type
|
|
668
|
+
* @param operation - 操作對象
|
|
669
|
+
*/
|
|
670
|
+
extractContentType(operation) {
|
|
671
|
+
if (!operation.requestBody) {
|
|
672
|
+
return "application/json";
|
|
673
|
+
}
|
|
674
|
+
const content = operation.requestBody.content;
|
|
675
|
+
if (!content || typeof content !== "object") {
|
|
676
|
+
return "application/json";
|
|
677
|
+
}
|
|
678
|
+
const contentTypes = Object.keys(content);
|
|
679
|
+
if (contentTypes.length === 0) {
|
|
680
|
+
return "application/json";
|
|
681
|
+
}
|
|
682
|
+
return contentTypes[0];
|
|
683
|
+
}
|
|
672
684
|
};
|
|
673
685
|
|
|
674
686
|
// src/generators/types-generator.ts
|
|
675
687
|
init_cjs_shims();
|
|
688
|
+
var toPascalCase2 = (name) => {
|
|
689
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
690
|
+
};
|
|
676
691
|
function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationDefinitions) {
|
|
692
|
+
const schemaTypeMap = {};
|
|
693
|
+
if (schemaInterfaces) {
|
|
694
|
+
Object.keys(schemaInterfaces).forEach((actualTypeName) => {
|
|
695
|
+
schemaTypeMap[actualTypeName] = actualTypeName;
|
|
696
|
+
if (actualTypeName.endsWith("Vo")) {
|
|
697
|
+
const openApiName = actualTypeName.slice(0, -2) + "VO";
|
|
698
|
+
schemaTypeMap[openApiName] = actualTypeName;
|
|
699
|
+
}
|
|
700
|
+
if (actualTypeName.endsWith("Dto")) {
|
|
701
|
+
const openApiName = actualTypeName.slice(0, -3) + "DTO";
|
|
702
|
+
schemaTypeMap[openApiName] = actualTypeName;
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
}
|
|
677
706
|
let importStatement = `/* eslint-disable */
|
|
678
707
|
// [Warning] Generated automatically - do not edit manually
|
|
679
708
|
|
|
@@ -690,35 +719,19 @@ function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationD
|
|
|
690
719
|
const reqTypeName = endpoint.argTypeName;
|
|
691
720
|
const resTypeName = endpoint.responseTypeName;
|
|
692
721
|
if (reqTypeName) {
|
|
693
|
-
const requestTypeContent = generateRequestTypeContent(endpoint, operationDefinitions);
|
|
694
|
-
if (requestTypeContent.trim() === ""
|
|
695
|
-
endpointTypes.push(
|
|
696
|
-
`export type ${reqTypeName} = void;`,
|
|
697
|
-
``
|
|
698
|
-
);
|
|
722
|
+
const requestTypeContent = generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap);
|
|
723
|
+
if (requestTypeContent.trim() === "") {
|
|
724
|
+
endpointTypes.push(`export type ${reqTypeName} = void;`, ``);
|
|
699
725
|
} else {
|
|
700
|
-
endpointTypes.push(
|
|
701
|
-
`export type ${reqTypeName} = {`,
|
|
702
|
-
requestTypeContent,
|
|
703
|
-
`};`,
|
|
704
|
-
``
|
|
705
|
-
);
|
|
726
|
+
endpointTypes.push(`export type ${reqTypeName} = {`, requestTypeContent, `};`, ``);
|
|
706
727
|
}
|
|
707
728
|
}
|
|
708
729
|
if (resTypeName) {
|
|
709
|
-
const responseTypeContent = generateResponseTypeContent(endpoint, operationDefinitions);
|
|
710
|
-
if (responseTypeContent.trim() === ""
|
|
711
|
-
endpointTypes.push(
|
|
712
|
-
`export type ${resTypeName} = void;`,
|
|
713
|
-
``
|
|
714
|
-
);
|
|
730
|
+
const responseTypeContent = generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap);
|
|
731
|
+
if (responseTypeContent.trim() === "") {
|
|
732
|
+
endpointTypes.push(`export type ${resTypeName} = void;`, ``);
|
|
715
733
|
} else {
|
|
716
|
-
endpointTypes.push(
|
|
717
|
-
`export type ${resTypeName} = {`,
|
|
718
|
-
responseTypeContent,
|
|
719
|
-
`};`,
|
|
720
|
-
``
|
|
721
|
-
);
|
|
734
|
+
endpointTypes.push(`export type ${resTypeName} = {`, responseTypeContent, `};`, ``);
|
|
722
735
|
}
|
|
723
736
|
}
|
|
724
737
|
});
|
|
@@ -726,27 +739,23 @@ function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationD
|
|
|
726
739
|
typeDefinitions.push(endpointTypes.join("\n"));
|
|
727
740
|
}
|
|
728
741
|
if (typeDefinitions.length === 0) {
|
|
729
|
-
typeDefinitions.push(
|
|
730
|
-
`// \u6B64\u6A94\u6848\u7528\u65BC\u5B9A\u7FA9 API \u76F8\u95DC\u7684\u985E\u578B`,
|
|
731
|
-
`// \u985E\u578B\u5B9A\u7FA9\u6703\u6839\u64DA OpenAPI Schema \u81EA\u52D5\u751F\u6210`,
|
|
732
|
-
``
|
|
733
|
-
);
|
|
742
|
+
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`, ``);
|
|
734
743
|
}
|
|
735
744
|
return importStatement + typeDefinitions.join("\n\n");
|
|
736
745
|
}
|
|
737
|
-
function generateRequestTypeContent(endpoint, operationDefinitions) {
|
|
746
|
+
function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}) {
|
|
738
747
|
const properties = [];
|
|
739
748
|
if (endpoint.queryParams && endpoint.queryParams.length > 0) {
|
|
740
749
|
endpoint.queryParams.forEach((param) => {
|
|
741
750
|
const optional = param.required ? "" : "?";
|
|
742
|
-
const paramType = getTypeFromParameter(param);
|
|
751
|
+
const paramType = getTypeFromParameter(param, schemaTypeMap);
|
|
743
752
|
properties.push(` ${param.name}${optional}: ${paramType};`);
|
|
744
753
|
});
|
|
745
754
|
}
|
|
746
755
|
if (endpoint.pathParams && endpoint.pathParams.length > 0) {
|
|
747
756
|
endpoint.pathParams.forEach((param) => {
|
|
748
757
|
const optional = param.required ? "" : "?";
|
|
749
|
-
const paramType = getTypeFromParameter(param);
|
|
758
|
+
const paramType = getTypeFromParameter(param, schemaTypeMap);
|
|
750
759
|
properties.push(` ${param.name}${optional}: ${paramType};`);
|
|
751
760
|
});
|
|
752
761
|
}
|
|
@@ -757,16 +766,22 @@ function generateRequestTypeContent(endpoint, operationDefinitions) {
|
|
|
757
766
|
if (operationDef?.operation?.requestBody) {
|
|
758
767
|
const requestBody = operationDef.operation.requestBody;
|
|
759
768
|
const content = requestBody.content;
|
|
760
|
-
const jsonContent = content["application/json"];
|
|
769
|
+
const jsonContent = content["application/json"] || content["*/*"];
|
|
761
770
|
const formContent = content["multipart/form-data"] || content["application/x-www-form-urlencoded"];
|
|
762
771
|
if (jsonContent?.schema) {
|
|
763
|
-
const bodyType = getTypeFromSchema(jsonContent.schema);
|
|
772
|
+
const bodyType = getTypeFromSchema(jsonContent.schema, schemaTypeMap, 1);
|
|
764
773
|
properties.push(` body: ${bodyType};`);
|
|
765
774
|
} else if (formContent?.schema) {
|
|
766
|
-
const bodyType = getTypeFromSchema(formContent.schema);
|
|
775
|
+
const bodyType = getTypeFromSchema(formContent.schema, schemaTypeMap, 1);
|
|
767
776
|
properties.push(` body: ${bodyType};`);
|
|
768
777
|
} else {
|
|
769
|
-
|
|
778
|
+
const firstContent = Object.values(content)[0];
|
|
779
|
+
if (firstContent?.schema) {
|
|
780
|
+
const bodyType = getTypeFromSchema(firstContent.schema, schemaTypeMap, 1);
|
|
781
|
+
properties.push(` body: ${bodyType};`);
|
|
782
|
+
} else {
|
|
783
|
+
properties.push(` body?: any; // Request body from OpenAPI`);
|
|
784
|
+
}
|
|
770
785
|
}
|
|
771
786
|
}
|
|
772
787
|
if (properties.length === 0) {
|
|
@@ -774,7 +789,7 @@ function generateRequestTypeContent(endpoint, operationDefinitions) {
|
|
|
774
789
|
}
|
|
775
790
|
return properties.join("\n");
|
|
776
791
|
}
|
|
777
|
-
function generateResponseTypeContent(endpoint, operationDefinitions) {
|
|
792
|
+
function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}) {
|
|
778
793
|
const properties = [];
|
|
779
794
|
const operationDef = operationDefinitions?.find((op) => {
|
|
780
795
|
return op.operation?.operationId === endpoint.operationName || op.operation?.operationId === endpoint.operationName.toLowerCase() || // 也嘗試匹配 verb + path 組合
|
|
@@ -783,9 +798,9 @@ function generateResponseTypeContent(endpoint, operationDefinitions) {
|
|
|
783
798
|
if (operationDef?.operation?.responses) {
|
|
784
799
|
const successResponse = operationDef.operation.responses["200"] || operationDef.operation.responses["201"];
|
|
785
800
|
if (successResponse?.content) {
|
|
786
|
-
const jsonContent = successResponse.content["application/json"];
|
|
801
|
+
const jsonContent = successResponse.content["application/json"] || successResponse.content["*/*"] || Object.values(successResponse.content)[0];
|
|
787
802
|
if (jsonContent?.schema) {
|
|
788
|
-
const responseProps = parseSchemaProperties(jsonContent.schema);
|
|
803
|
+
const responseProps = parseSchemaProperties(jsonContent.schema, schemaTypeMap);
|
|
789
804
|
properties.push(...responseProps);
|
|
790
805
|
} else {
|
|
791
806
|
properties.push(` // Success response from OpenAPI`);
|
|
@@ -798,83 +813,114 @@ function generateResponseTypeContent(endpoint, operationDefinitions) {
|
|
|
798
813
|
}
|
|
799
814
|
return properties.join("\n");
|
|
800
815
|
}
|
|
801
|
-
function parseSchemaProperties(schema) {
|
|
816
|
+
function parseSchemaProperties(schema, schemaTypeMap = {}) {
|
|
802
817
|
const properties = [];
|
|
803
818
|
if (schema.type === "object" && schema.properties) {
|
|
804
819
|
const required = schema.required || [];
|
|
805
820
|
Object.entries(schema.properties).forEach(([propName, propSchema]) => {
|
|
806
821
|
const isRequired = required.includes(propName);
|
|
807
822
|
const optional = isRequired ? "" : "?";
|
|
808
|
-
const propType = getTypeFromSchema(propSchema);
|
|
809
|
-
const
|
|
810
|
-
|
|
823
|
+
const propType = getTypeFromSchema(propSchema, schemaTypeMap, 1);
|
|
824
|
+
const needsQuotes = /[^a-zA-Z0-9_$]/.test(propName);
|
|
825
|
+
const quotedPropName = needsQuotes ? `"${propName}"` : propName;
|
|
826
|
+
if (propSchema.description) {
|
|
827
|
+
properties.push(` /** ${propSchema.description} */`);
|
|
828
|
+
}
|
|
829
|
+
properties.push(` ${quotedPropName}${optional}: ${propType};`);
|
|
811
830
|
});
|
|
812
831
|
}
|
|
813
832
|
return properties;
|
|
814
833
|
}
|
|
815
|
-
function getTypeFromSchema(schema) {
|
|
834
|
+
function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
816
835
|
if (!schema) return "any";
|
|
817
836
|
if (schema.$ref) {
|
|
818
837
|
const refPath = schema.$ref;
|
|
819
838
|
if (refPath.startsWith("#/components/schemas/")) {
|
|
820
|
-
const
|
|
821
|
-
|
|
839
|
+
const originalTypeName = refPath.replace("#/components/schemas/", "");
|
|
840
|
+
const actualTypeName = schemaTypeMap[originalTypeName] || originalTypeName;
|
|
841
|
+
const pascalCaseTypeName = toPascalCase2(actualTypeName);
|
|
842
|
+
const baseType2 = `Schema.${pascalCaseTypeName}`;
|
|
843
|
+
return schema.nullable ? `${baseType2} | null` : baseType2;
|
|
822
844
|
}
|
|
823
845
|
}
|
|
846
|
+
let baseType;
|
|
824
847
|
switch (schema.type) {
|
|
825
848
|
case "string":
|
|
826
849
|
if (schema.enum) {
|
|
827
|
-
|
|
850
|
+
baseType = schema.enum.map((val) => `"${val}"`).join(" | ");
|
|
851
|
+
} else if (schema.format === "binary") {
|
|
852
|
+
baseType = "Blob";
|
|
853
|
+
} else {
|
|
854
|
+
baseType = "string";
|
|
828
855
|
}
|
|
829
|
-
|
|
856
|
+
break;
|
|
830
857
|
case "number":
|
|
831
858
|
case "integer":
|
|
832
|
-
|
|
859
|
+
baseType = "number";
|
|
860
|
+
break;
|
|
833
861
|
case "boolean":
|
|
834
|
-
|
|
862
|
+
baseType = "boolean";
|
|
863
|
+
break;
|
|
835
864
|
case "array":
|
|
836
|
-
const itemType = schema.items ? getTypeFromSchema(schema.items) : "any";
|
|
837
|
-
|
|
865
|
+
const itemType = schema.items ? getTypeFromSchema(schema.items, schemaTypeMap, indentLevel) : "any";
|
|
866
|
+
const needsParentheses = itemType.includes("|");
|
|
867
|
+
baseType = needsParentheses ? `(${itemType})[]` : `${itemType}[]`;
|
|
868
|
+
break;
|
|
838
869
|
case "object":
|
|
839
870
|
if (schema.properties) {
|
|
840
|
-
const
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
871
|
+
const entries = Object.entries(schema.properties);
|
|
872
|
+
if (entries.length === 0) {
|
|
873
|
+
if (schema.additionalProperties) {
|
|
874
|
+
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel);
|
|
875
|
+
baseType = `Record<string, ${valueType}>`;
|
|
876
|
+
} else {
|
|
877
|
+
baseType = "{}";
|
|
878
|
+
}
|
|
879
|
+
} else {
|
|
880
|
+
const nextIndent = " ".repeat(indentLevel + 1);
|
|
881
|
+
const currentIndent = " ".repeat(indentLevel);
|
|
882
|
+
const props = [];
|
|
883
|
+
entries.forEach(([key, propSchema]) => {
|
|
884
|
+
const required = schema.required || [];
|
|
885
|
+
const optional = required.includes(key) ? "" : "?";
|
|
886
|
+
const type = getTypeFromSchema(propSchema, schemaTypeMap, indentLevel + 1);
|
|
887
|
+
const needsQuotes = /[^a-zA-Z0-9_$]/.test(key);
|
|
888
|
+
const quotedKey = needsQuotes ? `"${key}"` : key;
|
|
889
|
+
if (propSchema.description) {
|
|
890
|
+
props.push(`${nextIndent}/** ${propSchema.description} */`);
|
|
891
|
+
}
|
|
892
|
+
props.push(`${nextIndent}${quotedKey}${optional}: ${type};`);
|
|
893
|
+
});
|
|
894
|
+
baseType = `{
|
|
895
|
+
${props.join("\n")}
|
|
896
|
+
${currentIndent}}`;
|
|
897
|
+
}
|
|
898
|
+
} else if (schema.additionalProperties) {
|
|
899
|
+
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel);
|
|
900
|
+
baseType = `Record<string, ${valueType}>`;
|
|
901
|
+
} else {
|
|
902
|
+
baseType = "any";
|
|
847
903
|
}
|
|
848
|
-
|
|
904
|
+
break;
|
|
849
905
|
default:
|
|
850
|
-
|
|
906
|
+
baseType = "any";
|
|
907
|
+
break;
|
|
851
908
|
}
|
|
909
|
+
return schema.nullable ? `${baseType} | null` : baseType;
|
|
852
910
|
}
|
|
853
|
-
function getTypeFromParameter(param) {
|
|
911
|
+
function getTypeFromParameter(param, schemaTypeMap = {}) {
|
|
854
912
|
if (!param.schema) return "any";
|
|
855
|
-
return getTypeFromSchema(param.schema);
|
|
913
|
+
return getTypeFromSchema(param.schema, schemaTypeMap);
|
|
856
914
|
}
|
|
857
915
|
|
|
858
|
-
// src/generators/
|
|
916
|
+
// src/generators/rtk-query-generator.ts
|
|
859
917
|
init_cjs_shims();
|
|
860
|
-
function
|
|
861
|
-
const { groupKey: optionsGroupKey } = options;
|
|
862
|
-
return `export * from './types';
|
|
863
|
-
export * from './api.service';
|
|
864
|
-
export * from './query.service';
|
|
865
|
-
`;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
// src/services/query-code-generator.ts
|
|
869
|
-
init_cjs_shims();
|
|
870
|
-
|
|
871
|
-
// src/generators/query-service-generator.ts
|
|
872
|
-
init_cjs_shims();
|
|
873
|
-
function generateQueryServiceFile(endpointInfos, options) {
|
|
918
|
+
function generateRtkQueryFile(endpointInfos, options) {
|
|
874
919
|
const { groupKey, refetchOnMountOrArgChange = 60 } = options;
|
|
875
920
|
const queryServiceName = groupKey ? `${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)}QueryService` : "QueryService";
|
|
876
921
|
const apiServiceName = groupKey ? `${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)}ApiService` : "ApiService";
|
|
877
|
-
const queryMethods = endpointInfos.filter((info) => info.isQuery).map(
|
|
922
|
+
const queryMethods = endpointInfos.filter((info) => info.isQuery).map(
|
|
923
|
+
(info) => `
|
|
878
924
|
/**
|
|
879
925
|
* ${info.summary}
|
|
880
926
|
*/
|
|
@@ -887,8 +933,10 @@ function generateQueryServiceFile(endpointInfos, options) {
|
|
|
887
933
|
fetchOptions: args?.fetchOptions,
|
|
888
934
|
config: args?.config,
|
|
889
935
|
})${info.argTypeName !== "VoidApiArg" ? "(args)" : "()"};
|
|
890
|
-
}`
|
|
891
|
-
|
|
936
|
+
}`
|
|
937
|
+
).join("");
|
|
938
|
+
const mutationMethods = endpointInfos.filter((info) => !info.isQuery).map(
|
|
939
|
+
(info) => `
|
|
892
940
|
/**
|
|
893
941
|
* ${info.summary}
|
|
894
942
|
*/
|
|
@@ -902,8 +950,10 @@ function generateQueryServiceFile(endpointInfos, options) {
|
|
|
902
950
|
return this.apiService.${info.operationName}(${info.argTypeName !== "VoidApiArg" ? "args" : ""});
|
|
903
951
|
},
|
|
904
952
|
});
|
|
905
|
-
}`
|
|
906
|
-
|
|
953
|
+
}`
|
|
954
|
+
).join("");
|
|
955
|
+
const lazyQueryMethods = endpointInfos.filter((info) => info.isQuery).map(
|
|
956
|
+
(info) => `
|
|
907
957
|
/**
|
|
908
958
|
* ${info.summary}
|
|
909
959
|
*/
|
|
@@ -922,7 +972,8 @@ function generateQueryServiceFile(endpointInfos, options) {
|
|
|
922
972
|
return this.apiService.${info.operationName}(${info.argTypeName !== "VoidApiArg" ? "args" : ""});
|
|
923
973
|
}
|
|
924
974
|
};
|
|
925
|
-
}`
|
|
975
|
+
}`
|
|
976
|
+
).join("");
|
|
926
977
|
return `/* eslint-disable */
|
|
927
978
|
// [Warning] Generated automatically - do not edit manually
|
|
928
979
|
|
|
@@ -946,32 +997,9 @@ ${queryMethods}${mutationMethods}${lazyQueryMethods}
|
|
|
946
997
|
`;
|
|
947
998
|
}
|
|
948
999
|
|
|
949
|
-
// src/
|
|
950
|
-
var QueryCodeGenerator = class {
|
|
951
|
-
constructor(options) {
|
|
952
|
-
this.options = options;
|
|
953
|
-
}
|
|
954
|
-
/**
|
|
955
|
-
* 生成 Query Service 檔案內容
|
|
956
|
-
*/
|
|
957
|
-
generateQueryService(endpointInfos) {
|
|
958
|
-
const generatorOptions = {
|
|
959
|
-
...this.options,
|
|
960
|
-
apiConfiguration: this.options.apiConfiguration || {
|
|
961
|
-
file: "@/store/webapi",
|
|
962
|
-
importName: "WebApiConfiguration"
|
|
963
|
-
}
|
|
964
|
-
};
|
|
965
|
-
return generateQueryServiceFile(endpointInfos, generatorOptions);
|
|
966
|
-
}
|
|
967
|
-
};
|
|
968
|
-
|
|
969
|
-
// src/services/api-service-generator.ts
|
|
1000
|
+
// src/generators/rtk-enhance-endpoints-generator.ts
|
|
970
1001
|
init_cjs_shims();
|
|
971
|
-
|
|
972
|
-
// src/generators/api-service-generator.ts
|
|
973
|
-
init_cjs_shims();
|
|
974
|
-
function generateApiServiceFile(endpointInfos, options) {
|
|
1002
|
+
function generateRtkEnhanceEndpointsFile(endpointInfos, options) {
|
|
975
1003
|
const { apiConfiguration, httpClient, groupKey } = options;
|
|
976
1004
|
const apiServiceClassName = groupKey ? `${groupKey.charAt(0).toUpperCase() + groupKey.slice(1)}ApiService` : "ApiService";
|
|
977
1005
|
return `/* eslint-disable */
|
|
@@ -995,6 +1023,7 @@ export class ${apiServiceClassName} {
|
|
|
995
1023
|
${endpointInfos.map((info) => {
|
|
996
1024
|
const isGet = info.verb.toUpperCase() === "GET";
|
|
997
1025
|
const hasArgs = info.argTypeName !== "VoidApiArg";
|
|
1026
|
+
const hasRequestBody = info.hasRequestBody;
|
|
998
1027
|
const generateUrlTemplate = (path5) => {
|
|
999
1028
|
const hasPathParams = path5.includes("{");
|
|
1000
1029
|
if (hasPathParams && hasArgs) {
|
|
@@ -1005,18 +1034,16 @@ ${endpointInfos.map((info) => {
|
|
|
1005
1034
|
}
|
|
1006
1035
|
};
|
|
1007
1036
|
const hasQueryParams = info.queryParams.length > 0;
|
|
1008
|
-
const hasBody = !isGet && hasArgs
|
|
1037
|
+
const hasBody = !isGet && hasArgs;
|
|
1009
1038
|
const generateRequestOptions = () => {
|
|
1010
|
-
const options2 = [
|
|
1011
|
-
|
|
1012
|
-
];
|
|
1013
|
-
if (hasBody || !isGet) {
|
|
1039
|
+
const options2 = ["...args.fetchOptions"];
|
|
1040
|
+
if (hasRequestBody || !isGet) {
|
|
1014
1041
|
options2.push(`headers: { 'Content-Type': 'application/json', ...args.fetchOptions?.headers }`);
|
|
1015
1042
|
}
|
|
1016
1043
|
if (hasQueryParams && hasArgs) {
|
|
1017
1044
|
options2.push(generateQueryParams(info.queryParams));
|
|
1018
1045
|
}
|
|
1019
|
-
if (
|
|
1046
|
+
if (hasRequestBody) {
|
|
1020
1047
|
options2.push("body: args.variables.body");
|
|
1021
1048
|
}
|
|
1022
1049
|
return options2.length > 0 ? `{ ${options2.join(", ")} }` : "{}";
|
|
@@ -1042,62 +1069,47 @@ function generateQueryParams(queryParams) {
|
|
|
1042
1069
|
return `params: withoutUndefined({ ${paramEntries} })`;
|
|
1043
1070
|
}
|
|
1044
1071
|
|
|
1045
|
-
// src/services/api-service-generator.ts
|
|
1046
|
-
var ApiServiceGenerator = class {
|
|
1047
|
-
constructor(options) {
|
|
1048
|
-
this.options = options;
|
|
1049
|
-
}
|
|
1050
|
-
/**
|
|
1051
|
-
* 生成 API Service 檔案內容
|
|
1052
|
-
*/
|
|
1053
|
-
generateApiService(endpointInfos) {
|
|
1054
|
-
const generatorOptions = {
|
|
1055
|
-
...this.options,
|
|
1056
|
-
apiConfiguration: this.options.apiConfiguration || {
|
|
1057
|
-
file: "@/store/webapi",
|
|
1058
|
-
importName: "WebApiConfiguration"
|
|
1059
|
-
}
|
|
1060
|
-
};
|
|
1061
|
-
return generateApiServiceFile(endpointInfos, generatorOptions);
|
|
1062
|
-
}
|
|
1063
|
-
};
|
|
1064
|
-
|
|
1065
1072
|
// src/services/api-code-generator.ts
|
|
1066
1073
|
var ApiCodeGenerator = class {
|
|
1067
1074
|
constructor(parserService, options) {
|
|
1068
1075
|
this.parserService = parserService;
|
|
1069
1076
|
this.options = options;
|
|
1070
1077
|
this.infoExtractor = new EndpointInfoExtractor(options);
|
|
1071
|
-
this.queryGenerator = new QueryCodeGenerator(options);
|
|
1072
|
-
this.apiServiceGenerator = new ApiServiceGenerator(options);
|
|
1073
1078
|
}
|
|
1074
1079
|
infoExtractor;
|
|
1075
|
-
queryGenerator;
|
|
1076
|
-
apiServiceGenerator;
|
|
1077
1080
|
/**
|
|
1078
|
-
* 生成完整的
|
|
1081
|
+
* 生成完整的 RTK Query 程式碼
|
|
1079
1082
|
*/
|
|
1080
1083
|
async generate() {
|
|
1081
1084
|
const operationDefinitions = this.parserService.getOperationDefinitions(this.options.filterEndpoints);
|
|
1082
1085
|
const endpointInfos = this.infoExtractor.extractEndpointInfos(operationDefinitions);
|
|
1086
|
+
return this.generateRtkQueryCode(endpointInfos);
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* 生成 RTK Query 代碼
|
|
1090
|
+
*/
|
|
1091
|
+
generateRtkQueryCode(endpointInfos) {
|
|
1083
1092
|
const typesContent = this.generateTypes(endpointInfos);
|
|
1084
|
-
const
|
|
1085
|
-
const
|
|
1093
|
+
const rtkQueryContent = generateRtkQueryFile(endpointInfos, this.options);
|
|
1094
|
+
const enhanceEndpointsContent = generateRtkEnhanceEndpointsFile(endpointInfos, this.options);
|
|
1086
1095
|
const indexContent = this.generateIndex();
|
|
1087
|
-
const allEndpointCacheKeys = endpointInfos.filter((info) => info.isQuery).map((info) => ({
|
|
1088
|
-
operationName: info.operationName,
|
|
1089
|
-
queryKeyName: info.queryKeyName,
|
|
1090
|
-
groupKey: this.options.groupKey || "_common"
|
|
1091
|
-
}));
|
|
1092
1096
|
const operationNames = endpointInfos.map((info) => info.operationName);
|
|
1097
|
+
const allTags = /* @__PURE__ */ new Set();
|
|
1098
|
+
endpointInfos.forEach((info) => {
|
|
1099
|
+
if (info.tags && Array.isArray(info.tags)) {
|
|
1100
|
+
info.tags.forEach((tag) => allTags.add(tag));
|
|
1101
|
+
}
|
|
1102
|
+
});
|
|
1093
1103
|
return {
|
|
1094
1104
|
operationNames,
|
|
1105
|
+
tags: Array.from(allTags),
|
|
1095
1106
|
files: {
|
|
1096
1107
|
types: typesContent,
|
|
1097
|
-
|
|
1098
|
-
|
|
1108
|
+
queryService: rtkQueryContent,
|
|
1109
|
+
// RTK Query 檔案
|
|
1099
1110
|
index: indexContent,
|
|
1100
|
-
|
|
1111
|
+
enhanceEndpoints: enhanceEndpointsContent
|
|
1112
|
+
// 新增的 enhance endpoints 檔案
|
|
1101
1113
|
}
|
|
1102
1114
|
};
|
|
1103
1115
|
}
|
|
@@ -1113,43 +1125,35 @@ var ApiCodeGenerator = class {
|
|
|
1113
1125
|
}
|
|
1114
1126
|
};
|
|
1115
1127
|
const apiGen = this.parserService.getApiGenerator();
|
|
1116
|
-
const schemaInterfaces = apiGen.aliases.reduce(
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1128
|
+
const schemaInterfaces = apiGen.aliases.reduce(
|
|
1129
|
+
(curr, alias) => {
|
|
1130
|
+
if (import_typescript2.default.isInterfaceDeclaration(alias) || import_typescript2.default.isTypeAliasDeclaration(alias)) {
|
|
1131
|
+
const name = alias.name.text;
|
|
1132
|
+
return {
|
|
1133
|
+
...curr,
|
|
1134
|
+
[name]: alias
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
return curr;
|
|
1138
|
+
},
|
|
1139
|
+
{}
|
|
1140
|
+
);
|
|
1126
1141
|
const operationDefinitions = this.parserService.getOperationDefinitions(this.options.filterEndpoints);
|
|
1127
1142
|
return generateTypesFile(endpointInfos, generatorOptions, schemaInterfaces, operationDefinitions);
|
|
1128
1143
|
}
|
|
1129
|
-
/**
|
|
1130
|
-
* 生成 API Service 檔案內容
|
|
1131
|
-
*/
|
|
1132
|
-
generateApiService(endpointInfos) {
|
|
1133
|
-
return this.apiServiceGenerator.generateApiService(endpointInfos);
|
|
1134
|
-
}
|
|
1135
|
-
/**
|
|
1136
|
-
* 生成 Query Service 檔案內容
|
|
1137
|
-
*/
|
|
1138
|
-
generateQueryService(endpointInfos) {
|
|
1139
|
-
return this.queryGenerator.generateQueryService(endpointInfos);
|
|
1140
|
-
}
|
|
1141
1144
|
/**
|
|
1142
1145
|
* 生成 Index 檔案內容
|
|
1143
1146
|
*/
|
|
1144
1147
|
generateIndex() {
|
|
1145
|
-
const
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1148
|
+
const groupKey = this.options.groupKey || "";
|
|
1149
|
+
const exportName = groupKey ? `${groupKey.charAt(0).toLowerCase() + groupKey.slice(1)}Api` : "api";
|
|
1150
|
+
return `/* eslint-disable */
|
|
1151
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1152
|
+
|
|
1153
|
+
export { default as ${exportName} } from "./enhanceEndpoints";
|
|
1154
|
+
export * from "./query.generated";
|
|
1155
|
+
export * from "./types";
|
|
1156
|
+
`;
|
|
1153
1157
|
}
|
|
1154
1158
|
// /**
|
|
1155
1159
|
// * 獲取已解析的 parser service(供外部使用)
|
|
@@ -1166,6 +1170,46 @@ var ApiCodeGenerator = class {
|
|
|
1166
1170
|
// }
|
|
1167
1171
|
};
|
|
1168
1172
|
|
|
1173
|
+
// src/generators/utils-generator.ts
|
|
1174
|
+
init_cjs_shims();
|
|
1175
|
+
function generateUtilsFile() {
|
|
1176
|
+
return `/* eslint-disable */
|
|
1177
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1178
|
+
|
|
1179
|
+
/**
|
|
1180
|
+
* Clear undefined in object
|
|
1181
|
+
*/
|
|
1182
|
+
export function withoutUndefined(obj?: Record<string, any>) {
|
|
1183
|
+
if(typeof obj === 'undefined') return;
|
|
1184
|
+
return Object.fromEntries(
|
|
1185
|
+
Object.entries(obj).filter(([_, v]) => v !== undefined && v !== null)
|
|
1186
|
+
);
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
`;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// src/generators/tag-types-generator.ts
|
|
1193
|
+
init_cjs_shims();
|
|
1194
|
+
function generateTagTypesFile(tags) {
|
|
1195
|
+
if (tags.length === 0) {
|
|
1196
|
+
return `/* eslint-disable */
|
|
1197
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1198
|
+
|
|
1199
|
+
export enum ECacheTagTypes {
|
|
1200
|
+
}
|
|
1201
|
+
`;
|
|
1202
|
+
}
|
|
1203
|
+
const enumEntries = tags.sort().map((tag) => ` ${tag} = '${tag}',`).join("\n");
|
|
1204
|
+
return `/* eslint-disable */
|
|
1205
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1206
|
+
|
|
1207
|
+
export enum ECacheTagTypes {
|
|
1208
|
+
${enumEntries}
|
|
1209
|
+
}
|
|
1210
|
+
`;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1169
1213
|
// src/services/unified-code-generator.ts
|
|
1170
1214
|
var UnifiedCodeGenerator = class {
|
|
1171
1215
|
_options;
|
|
@@ -1176,17 +1220,18 @@ var UnifiedCodeGenerator = class {
|
|
|
1176
1220
|
openApiDoc = null;
|
|
1177
1221
|
parserService = null;
|
|
1178
1222
|
schemaInterfaces = {};
|
|
1179
|
-
allEndpointCacheKeys = [];
|
|
1180
1223
|
actualSchemaFile = "";
|
|
1181
1224
|
// 生成內容存儲
|
|
1182
1225
|
generatedContent = {
|
|
1183
1226
|
groups: [],
|
|
1184
|
-
cacheKeys: null,
|
|
1185
1227
|
commonTypes: "",
|
|
1186
1228
|
componentSchema: "",
|
|
1187
1229
|
doNotModify: "",
|
|
1188
|
-
utils: ""
|
|
1230
|
+
utils: "",
|
|
1231
|
+
tagTypes: ""
|
|
1189
1232
|
};
|
|
1233
|
+
// 收集所有 tags
|
|
1234
|
+
allTags = /* @__PURE__ */ new Set();
|
|
1190
1235
|
constructor(options) {
|
|
1191
1236
|
this._options = options;
|
|
1192
1237
|
}
|
|
@@ -1196,11 +1241,11 @@ var UnifiedCodeGenerator = class {
|
|
|
1196
1241
|
async generateAll() {
|
|
1197
1242
|
await this.prepare();
|
|
1198
1243
|
await this.generateApi();
|
|
1199
|
-
this.generateCacheKeysContent();
|
|
1200
1244
|
this.generateCommonTypesContent();
|
|
1201
1245
|
this.generateSchemaContent();
|
|
1202
1246
|
this.generateUtilsContent();
|
|
1203
1247
|
this.generateDoNotModifyContent();
|
|
1248
|
+
this.generateTagTypesContent();
|
|
1204
1249
|
return await this.release();
|
|
1205
1250
|
}
|
|
1206
1251
|
/**
|
|
@@ -1253,18 +1298,15 @@ var UnifiedCodeGenerator = class {
|
|
|
1253
1298
|
outputPath: groupInfo.outputPath,
|
|
1254
1299
|
content: groupContent
|
|
1255
1300
|
});
|
|
1301
|
+
if (groupContent.tags && Array.isArray(groupContent.tags)) {
|
|
1302
|
+
groupContent.tags.forEach((tag) => this.allTags.add(tag));
|
|
1303
|
+
}
|
|
1256
1304
|
}
|
|
1257
1305
|
} catch (error) {
|
|
1258
1306
|
throw new Error(`\u7FA4\u7D44 ${groupInfo.groupKey} \u751F\u6210\u5931\u6557: ${error}`);
|
|
1259
1307
|
}
|
|
1260
1308
|
}
|
|
1261
1309
|
}
|
|
1262
|
-
/**
|
|
1263
|
-
* 生成 cache keys
|
|
1264
|
-
*/
|
|
1265
|
-
async generateCacheKeysContent() {
|
|
1266
|
-
this.generatedContent.cacheKeys = generateCacheKeysFile(this.allEndpointCacheKeys);
|
|
1267
|
-
}
|
|
1268
1310
|
/**
|
|
1269
1311
|
* 生成 common types
|
|
1270
1312
|
*/
|
|
@@ -1289,6 +1331,13 @@ var UnifiedCodeGenerator = class {
|
|
|
1289
1331
|
async generateUtilsContent() {
|
|
1290
1332
|
this.generatedContent.utils = generateUtilsFile();
|
|
1291
1333
|
}
|
|
1334
|
+
/**
|
|
1335
|
+
* 生成 Tag Types
|
|
1336
|
+
*/
|
|
1337
|
+
async generateTagTypesContent() {
|
|
1338
|
+
const tagsArray = Array.from(this.allTags);
|
|
1339
|
+
this.generatedContent.tagTypes = generateTagTypesFile(tagsArray);
|
|
1340
|
+
}
|
|
1292
1341
|
/**
|
|
1293
1342
|
* 發佈階段:統一寫入所有檔案
|
|
1294
1343
|
*/
|
|
@@ -1305,8 +1354,8 @@ var UnifiedCodeGenerator = class {
|
|
|
1305
1354
|
groupOutputDir,
|
|
1306
1355
|
{
|
|
1307
1356
|
types: group.content.files.types,
|
|
1308
|
-
apiService: group.content.files.apiService,
|
|
1309
1357
|
queryService: group.content.files.queryService,
|
|
1358
|
+
enhanceEndpoints: group.content.files.enhanceEndpoints,
|
|
1310
1359
|
index: group.content.files.index
|
|
1311
1360
|
}
|
|
1312
1361
|
);
|
|
@@ -1318,11 +1367,10 @@ var UnifiedCodeGenerator = class {
|
|
|
1318
1367
|
}
|
|
1319
1368
|
}
|
|
1320
1369
|
const outputDir = this.generatedContent.groups[0] ? import_node_path4.default.dirname(import_node_path4.default.dirname(this.generatedContent.groups[0].outputPath)) : "./generated";
|
|
1321
|
-
if (this.generatedContent.
|
|
1370
|
+
if (this.generatedContent.commonTypes || this.generatedContent.doNotModify || this.generatedContent.utils) {
|
|
1322
1371
|
const sharedResults = await this.fileWriterService.writeSharedFiles(
|
|
1323
1372
|
outputDir,
|
|
1324
1373
|
{
|
|
1325
|
-
cacheKeys: this.generatedContent.cacheKeys || void 0,
|
|
1326
1374
|
commonTypes: this.generatedContent.commonTypes || void 0,
|
|
1327
1375
|
doNotModify: this.generatedContent.doNotModify || void 0,
|
|
1328
1376
|
utils: this.generatedContent.utils || void 0
|
|
@@ -1330,6 +1378,13 @@ var UnifiedCodeGenerator = class {
|
|
|
1330
1378
|
);
|
|
1331
1379
|
results.push(...sharedResults);
|
|
1332
1380
|
}
|
|
1381
|
+
if (this.generatedContent.tagTypes) {
|
|
1382
|
+
const tagTypesResult = await this.fileWriterService.writeFile(
|
|
1383
|
+
import_node_path4.default.join(outputDir, "tagTypes.ts"),
|
|
1384
|
+
this.generatedContent.tagTypes
|
|
1385
|
+
);
|
|
1386
|
+
results.push(tagTypesResult);
|
|
1387
|
+
}
|
|
1333
1388
|
if (this.generatedContent.componentSchema) {
|
|
1334
1389
|
const schemaResults = await this.fileWriterService.writeSchemaFile(
|
|
1335
1390
|
outputDir,
|
|
@@ -1337,6 +1392,12 @@ var UnifiedCodeGenerator = class {
|
|
|
1337
1392
|
);
|
|
1338
1393
|
results.push(...schemaResults);
|
|
1339
1394
|
}
|
|
1395
|
+
const mainIndexContent = this.generateMainIndex(generatedGroups);
|
|
1396
|
+
const mainIndexResult = await this.fileWriterService.writeFile(
|
|
1397
|
+
import_node_path4.default.join(outputDir, "index.ts"),
|
|
1398
|
+
mainIndexContent
|
|
1399
|
+
);
|
|
1400
|
+
results.push(mainIndexResult);
|
|
1340
1401
|
} catch (error) {
|
|
1341
1402
|
errors.push(error);
|
|
1342
1403
|
}
|
|
@@ -1366,12 +1427,19 @@ var UnifiedCodeGenerator = class {
|
|
|
1366
1427
|
}
|
|
1367
1428
|
const apiGenerator = new ApiCodeGenerator(this.parserService, groupOptions);
|
|
1368
1429
|
const result = await apiGenerator.generate();
|
|
1369
|
-
if (result.files && "allEndpointCacheKeys" in result.files) {
|
|
1370
|
-
const cacheKeys = result.files.allEndpointCacheKeys;
|
|
1371
|
-
this.allEndpointCacheKeys.push(...cacheKeys);
|
|
1372
|
-
}
|
|
1373
1430
|
return result;
|
|
1374
1431
|
}
|
|
1432
|
+
/**
|
|
1433
|
+
* 生成主 index.ts 檔案
|
|
1434
|
+
*/
|
|
1435
|
+
generateMainIndex(generatedGroups) {
|
|
1436
|
+
const exports2 = generatedGroups.map((groupKey) => `export * from "./${groupKey}";`).join("\n");
|
|
1437
|
+
return `/* eslint-disable */
|
|
1438
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1439
|
+
|
|
1440
|
+
${exports2}
|
|
1441
|
+
`;
|
|
1442
|
+
}
|
|
1375
1443
|
};
|
|
1376
1444
|
|
|
1377
1445
|
// src/index.ts
|