@bitstack/ng-query-codegen-openapi 0.0.30 → 0.0.31-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/lib/bin/cli.mjs +78 -60
- package/lib/bin/cli.mjs.map +1 -1
- package/lib/index.d.mts +4 -13
- package/lib/index.d.ts +4 -13
- package/lib/index.js +351 -290
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +351 -290
- 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 -40
- 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);
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
// src/generators/index-generator.ts
|
|
859
|
-
init_cjs_shims();
|
|
860
|
-
function generateIndexFile(groupKey, options) {
|
|
861
|
-
const { groupKey: optionsGroupKey } = options;
|
|
862
|
-
return `export * from './types';
|
|
863
|
-
export * from './api.service';
|
|
864
|
-
export * from './query.service';
|
|
865
|
-
`;
|
|
913
|
+
return getTypeFromSchema(param.schema, schemaTypeMap);
|
|
866
914
|
}
|
|
867
915
|
|
|
868
|
-
// src/
|
|
916
|
+
// src/generators/rtk-query-generator.ts
|
|
869
917
|
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,38 +997,15 @@ ${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
|
|
970
|
-
init_cjs_shims();
|
|
971
|
-
|
|
972
|
-
// src/generators/api-service-generator.ts
|
|
1000
|
+
// src/generators/rtk-enhance-endpoints-generator.ts
|
|
973
1001
|
init_cjs_shims();
|
|
974
|
-
function
|
|
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 */
|
|
978
1006
|
// [Warning] Generated automatically - do not edit manually
|
|
979
1007
|
|
|
980
|
-
import { ${httpClient.
|
|
1008
|
+
import { ${httpClient.importReturnTypeName} } from '${httpClient.file}';
|
|
981
1009
|
import { Injectable, inject } from '@angular/core';
|
|
982
1010
|
import { Observable } from 'rxjs';
|
|
983
1011
|
import { ${apiConfiguration.importName} } from '${apiConfiguration.file}';
|
|
@@ -990,11 +1018,12 @@ import {${endpointInfos.map((info) => ` ${info.argTypeName}, ${info.responseType
|
|
|
990
1018
|
})
|
|
991
1019
|
export class ${apiServiceClassName} {
|
|
992
1020
|
private config = inject(${apiConfiguration.importName});
|
|
993
|
-
private http = inject(${httpClient.
|
|
1021
|
+
private http = inject(${httpClient.importReturnTypeName});
|
|
994
1022
|
|
|
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,21 +1034,18 @@ ${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
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
options2.push(`headers: { 'Content-Type': 'application/json', ...args.fetchOptions?.headers }`);
|
|
1015
|
-
}
|
|
1016
|
-
if (hasQueryParams && hasArgs) {
|
|
1017
|
-
options2.push(generateQueryParams(info.queryParams));
|
|
1039
|
+
let paramsSection = "";
|
|
1040
|
+
if (info.queryParams && info.queryParams.length > 0) {
|
|
1041
|
+
const paramsLines = info.queryParams.map((param) => `${param.name}: args.variables.${param.name},`).join("\n");
|
|
1042
|
+
paramsSection = `params: {${paramsLines}},`;
|
|
1018
1043
|
}
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1044
|
+
return `{
|
|
1045
|
+
...args.fetchOptions,
|
|
1046
|
+
headers: { 'Content-Type': '${info.contentType}', ...args.fetchOptions?.headers },
|
|
1047
|
+
${paramsSection}${info.hasRequestBody ? `body: args.variables.body,` : ""}
|
|
1048
|
+
}`;
|
|
1023
1049
|
};
|
|
1024
1050
|
return `
|
|
1025
1051
|
/**
|
|
@@ -1035,32 +1061,6 @@ ${endpointInfos.map((info) => {
|
|
|
1035
1061
|
}
|
|
1036
1062
|
`;
|
|
1037
1063
|
}
|
|
1038
|
-
function generateQueryParams(queryParams) {
|
|
1039
|
-
const paramEntries = queryParams.map(
|
|
1040
|
-
(param) => `${param.name}: args.variables.${param.name}`
|
|
1041
|
-
).join(", ");
|
|
1042
|
-
return `params: withoutUndefined({ ${paramEntries} })`;
|
|
1043
|
-
}
|
|
1044
|
-
|
|
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
1064
|
|
|
1065
1065
|
// src/services/api-code-generator.ts
|
|
1066
1066
|
var ApiCodeGenerator = class {
|
|
@@ -1068,36 +1068,41 @@ var ApiCodeGenerator = class {
|
|
|
1068
1068
|
this.parserService = parserService;
|
|
1069
1069
|
this.options = options;
|
|
1070
1070
|
this.infoExtractor = new EndpointInfoExtractor(options);
|
|
1071
|
-
this.queryGenerator = new QueryCodeGenerator(options);
|
|
1072
|
-
this.apiServiceGenerator = new ApiServiceGenerator(options);
|
|
1073
1071
|
}
|
|
1074
1072
|
infoExtractor;
|
|
1075
|
-
queryGenerator;
|
|
1076
|
-
apiServiceGenerator;
|
|
1077
1073
|
/**
|
|
1078
|
-
* 生成完整的
|
|
1074
|
+
* 生成完整的 RTK Query 程式碼
|
|
1079
1075
|
*/
|
|
1080
1076
|
async generate() {
|
|
1081
1077
|
const operationDefinitions = this.parserService.getOperationDefinitions(this.options.filterEndpoints);
|
|
1082
1078
|
const endpointInfos = this.infoExtractor.extractEndpointInfos(operationDefinitions);
|
|
1079
|
+
return this.generateRtkQueryCode(endpointInfos);
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* 生成 RTK Query 代碼
|
|
1083
|
+
*/
|
|
1084
|
+
generateRtkQueryCode(endpointInfos) {
|
|
1083
1085
|
const typesContent = this.generateTypes(endpointInfos);
|
|
1084
|
-
const
|
|
1085
|
-
const
|
|
1086
|
+
const rtkQueryContent = generateRtkQueryFile(endpointInfos, this.options);
|
|
1087
|
+
const enhanceEndpointsContent = generateRtkEnhanceEndpointsFile(endpointInfos, this.options);
|
|
1086
1088
|
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
1089
|
const operationNames = endpointInfos.map((info) => info.operationName);
|
|
1090
|
+
const allTags = /* @__PURE__ */ new Set();
|
|
1091
|
+
endpointInfos.forEach((info) => {
|
|
1092
|
+
if (info.tags && Array.isArray(info.tags)) {
|
|
1093
|
+
info.tags.forEach((tag) => allTags.add(tag));
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1093
1096
|
return {
|
|
1094
1097
|
operationNames,
|
|
1098
|
+
tags: Array.from(allTags),
|
|
1095
1099
|
files: {
|
|
1096
1100
|
types: typesContent,
|
|
1097
|
-
|
|
1098
|
-
|
|
1101
|
+
queryService: rtkQueryContent,
|
|
1102
|
+
// RTK Query 檔案
|
|
1099
1103
|
index: indexContent,
|
|
1100
|
-
|
|
1104
|
+
enhanceEndpoints: enhanceEndpointsContent
|
|
1105
|
+
// 新增的 enhance endpoints 檔案
|
|
1101
1106
|
}
|
|
1102
1107
|
};
|
|
1103
1108
|
}
|
|
@@ -1113,43 +1118,35 @@ var ApiCodeGenerator = class {
|
|
|
1113
1118
|
}
|
|
1114
1119
|
};
|
|
1115
1120
|
const apiGen = this.parserService.getApiGenerator();
|
|
1116
|
-
const schemaInterfaces = apiGen.aliases.reduce(
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1121
|
+
const schemaInterfaces = apiGen.aliases.reduce(
|
|
1122
|
+
(curr, alias) => {
|
|
1123
|
+
if (import_typescript2.default.isInterfaceDeclaration(alias) || import_typescript2.default.isTypeAliasDeclaration(alias)) {
|
|
1124
|
+
const name = alias.name.text;
|
|
1125
|
+
return {
|
|
1126
|
+
...curr,
|
|
1127
|
+
[name]: alias
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
return curr;
|
|
1131
|
+
},
|
|
1132
|
+
{}
|
|
1133
|
+
);
|
|
1126
1134
|
const operationDefinitions = this.parserService.getOperationDefinitions(this.options.filterEndpoints);
|
|
1127
1135
|
return generateTypesFile(endpointInfos, generatorOptions, schemaInterfaces, operationDefinitions);
|
|
1128
1136
|
}
|
|
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
1137
|
/**
|
|
1142
1138
|
* 生成 Index 檔案內容
|
|
1143
1139
|
*/
|
|
1144
1140
|
generateIndex() {
|
|
1145
|
-
const
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1141
|
+
const groupKey = this.options.groupKey || "";
|
|
1142
|
+
const exportName = groupKey ? `${groupKey.charAt(0).toLowerCase() + groupKey.slice(1)}Api` : "api";
|
|
1143
|
+
return `/* eslint-disable */
|
|
1144
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1145
|
+
|
|
1146
|
+
export { default as ${exportName} } from "./enhanceEndpoints";
|
|
1147
|
+
export * from "./query.generated";
|
|
1148
|
+
export * from "./types";
|
|
1149
|
+
`;
|
|
1153
1150
|
}
|
|
1154
1151
|
// /**
|
|
1155
1152
|
// * 獲取已解析的 parser service(供外部使用)
|
|
@@ -1166,6 +1163,46 @@ var ApiCodeGenerator = class {
|
|
|
1166
1163
|
// }
|
|
1167
1164
|
};
|
|
1168
1165
|
|
|
1166
|
+
// src/generators/utils-generator.ts
|
|
1167
|
+
init_cjs_shims();
|
|
1168
|
+
function generateUtilsFile() {
|
|
1169
|
+
return `/* eslint-disable */
|
|
1170
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* Clear undefined in object
|
|
1174
|
+
*/
|
|
1175
|
+
export function withoutUndefined(obj?: Record<string, any>) {
|
|
1176
|
+
if(typeof obj === 'undefined') return;
|
|
1177
|
+
return Object.fromEntries(
|
|
1178
|
+
Object.entries(obj).filter(([_, v]) => v !== undefined && v !== null)
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
`;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// src/generators/tag-types-generator.ts
|
|
1186
|
+
init_cjs_shims();
|
|
1187
|
+
function generateTagTypesFile(tags) {
|
|
1188
|
+
if (tags.length === 0) {
|
|
1189
|
+
return `/* eslint-disable */
|
|
1190
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1191
|
+
|
|
1192
|
+
export enum ECacheTagTypes {
|
|
1193
|
+
}
|
|
1194
|
+
`;
|
|
1195
|
+
}
|
|
1196
|
+
const enumEntries = tags.sort().map((tag) => ` ${tag} = '${tag}',`).join("\n");
|
|
1197
|
+
return `/* eslint-disable */
|
|
1198
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1199
|
+
|
|
1200
|
+
export enum ECacheTagTypes {
|
|
1201
|
+
${enumEntries}
|
|
1202
|
+
}
|
|
1203
|
+
`;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1169
1206
|
// src/services/unified-code-generator.ts
|
|
1170
1207
|
var UnifiedCodeGenerator = class {
|
|
1171
1208
|
_options;
|
|
@@ -1176,17 +1213,18 @@ var UnifiedCodeGenerator = class {
|
|
|
1176
1213
|
openApiDoc = null;
|
|
1177
1214
|
parserService = null;
|
|
1178
1215
|
schemaInterfaces = {};
|
|
1179
|
-
allEndpointCacheKeys = [];
|
|
1180
1216
|
actualSchemaFile = "";
|
|
1181
1217
|
// 生成內容存儲
|
|
1182
1218
|
generatedContent = {
|
|
1183
1219
|
groups: [],
|
|
1184
|
-
cacheKeys: null,
|
|
1185
1220
|
commonTypes: "",
|
|
1186
1221
|
componentSchema: "",
|
|
1187
1222
|
doNotModify: "",
|
|
1188
|
-
utils: ""
|
|
1223
|
+
utils: "",
|
|
1224
|
+
tagTypes: ""
|
|
1189
1225
|
};
|
|
1226
|
+
// 收集所有 tags
|
|
1227
|
+
allTags = /* @__PURE__ */ new Set();
|
|
1190
1228
|
constructor(options) {
|
|
1191
1229
|
this._options = options;
|
|
1192
1230
|
}
|
|
@@ -1196,11 +1234,11 @@ var UnifiedCodeGenerator = class {
|
|
|
1196
1234
|
async generateAll() {
|
|
1197
1235
|
await this.prepare();
|
|
1198
1236
|
await this.generateApi();
|
|
1199
|
-
this.generateCacheKeysContent();
|
|
1200
1237
|
this.generateCommonTypesContent();
|
|
1201
1238
|
this.generateSchemaContent();
|
|
1202
1239
|
this.generateUtilsContent();
|
|
1203
1240
|
this.generateDoNotModifyContent();
|
|
1241
|
+
this.generateTagTypesContent();
|
|
1204
1242
|
return await this.release();
|
|
1205
1243
|
}
|
|
1206
1244
|
/**
|
|
@@ -1253,18 +1291,15 @@ var UnifiedCodeGenerator = class {
|
|
|
1253
1291
|
outputPath: groupInfo.outputPath,
|
|
1254
1292
|
content: groupContent
|
|
1255
1293
|
});
|
|
1294
|
+
if (groupContent.tags && Array.isArray(groupContent.tags)) {
|
|
1295
|
+
groupContent.tags.forEach((tag) => this.allTags.add(tag));
|
|
1296
|
+
}
|
|
1256
1297
|
}
|
|
1257
1298
|
} catch (error) {
|
|
1258
1299
|
throw new Error(`\u7FA4\u7D44 ${groupInfo.groupKey} \u751F\u6210\u5931\u6557: ${error}`);
|
|
1259
1300
|
}
|
|
1260
1301
|
}
|
|
1261
1302
|
}
|
|
1262
|
-
/**
|
|
1263
|
-
* 生成 cache keys
|
|
1264
|
-
*/
|
|
1265
|
-
async generateCacheKeysContent() {
|
|
1266
|
-
this.generatedContent.cacheKeys = generateCacheKeysFile(this.allEndpointCacheKeys);
|
|
1267
|
-
}
|
|
1268
1303
|
/**
|
|
1269
1304
|
* 生成 common types
|
|
1270
1305
|
*/
|
|
@@ -1289,6 +1324,13 @@ var UnifiedCodeGenerator = class {
|
|
|
1289
1324
|
async generateUtilsContent() {
|
|
1290
1325
|
this.generatedContent.utils = generateUtilsFile();
|
|
1291
1326
|
}
|
|
1327
|
+
/**
|
|
1328
|
+
* 生成 Tag Types
|
|
1329
|
+
*/
|
|
1330
|
+
async generateTagTypesContent() {
|
|
1331
|
+
const tagsArray = Array.from(this.allTags);
|
|
1332
|
+
this.generatedContent.tagTypes = generateTagTypesFile(tagsArray);
|
|
1333
|
+
}
|
|
1292
1334
|
/**
|
|
1293
1335
|
* 發佈階段:統一寫入所有檔案
|
|
1294
1336
|
*/
|
|
@@ -1305,8 +1347,8 @@ var UnifiedCodeGenerator = class {
|
|
|
1305
1347
|
groupOutputDir,
|
|
1306
1348
|
{
|
|
1307
1349
|
types: group.content.files.types,
|
|
1308
|
-
apiService: group.content.files.apiService,
|
|
1309
1350
|
queryService: group.content.files.queryService,
|
|
1351
|
+
enhanceEndpoints: group.content.files.enhanceEndpoints,
|
|
1310
1352
|
index: group.content.files.index
|
|
1311
1353
|
}
|
|
1312
1354
|
);
|
|
@@ -1318,11 +1360,10 @@ var UnifiedCodeGenerator = class {
|
|
|
1318
1360
|
}
|
|
1319
1361
|
}
|
|
1320
1362
|
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.
|
|
1363
|
+
if (this.generatedContent.commonTypes || this.generatedContent.doNotModify || this.generatedContent.utils) {
|
|
1322
1364
|
const sharedResults = await this.fileWriterService.writeSharedFiles(
|
|
1323
1365
|
outputDir,
|
|
1324
1366
|
{
|
|
1325
|
-
cacheKeys: this.generatedContent.cacheKeys || void 0,
|
|
1326
1367
|
commonTypes: this.generatedContent.commonTypes || void 0,
|
|
1327
1368
|
doNotModify: this.generatedContent.doNotModify || void 0,
|
|
1328
1369
|
utils: this.generatedContent.utils || void 0
|
|
@@ -1330,6 +1371,13 @@ var UnifiedCodeGenerator = class {
|
|
|
1330
1371
|
);
|
|
1331
1372
|
results.push(...sharedResults);
|
|
1332
1373
|
}
|
|
1374
|
+
if (this.generatedContent.tagTypes) {
|
|
1375
|
+
const tagTypesResult = await this.fileWriterService.writeFile(
|
|
1376
|
+
import_node_path4.default.join(outputDir, "tagTypes.ts"),
|
|
1377
|
+
this.generatedContent.tagTypes
|
|
1378
|
+
);
|
|
1379
|
+
results.push(tagTypesResult);
|
|
1380
|
+
}
|
|
1333
1381
|
if (this.generatedContent.componentSchema) {
|
|
1334
1382
|
const schemaResults = await this.fileWriterService.writeSchemaFile(
|
|
1335
1383
|
outputDir,
|
|
@@ -1337,6 +1385,12 @@ var UnifiedCodeGenerator = class {
|
|
|
1337
1385
|
);
|
|
1338
1386
|
results.push(...schemaResults);
|
|
1339
1387
|
}
|
|
1388
|
+
const mainIndexContent = this.generateMainIndex(generatedGroups);
|
|
1389
|
+
const mainIndexResult = await this.fileWriterService.writeFile(
|
|
1390
|
+
import_node_path4.default.join(outputDir, "index.ts"),
|
|
1391
|
+
mainIndexContent
|
|
1392
|
+
);
|
|
1393
|
+
results.push(mainIndexResult);
|
|
1340
1394
|
} catch (error) {
|
|
1341
1395
|
errors.push(error);
|
|
1342
1396
|
}
|
|
@@ -1366,12 +1420,19 @@ var UnifiedCodeGenerator = class {
|
|
|
1366
1420
|
}
|
|
1367
1421
|
const apiGenerator = new ApiCodeGenerator(this.parserService, groupOptions);
|
|
1368
1422
|
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
1423
|
return result;
|
|
1374
1424
|
}
|
|
1425
|
+
/**
|
|
1426
|
+
* 生成主 index.ts 檔案
|
|
1427
|
+
*/
|
|
1428
|
+
generateMainIndex(generatedGroups) {
|
|
1429
|
+
const exports2 = generatedGroups.map((groupKey) => `export * from "./${groupKey}";`).join("\n");
|
|
1430
|
+
return `/* eslint-disable */
|
|
1431
|
+
// [Warning] Generated automatically - do not edit manually
|
|
1432
|
+
|
|
1433
|
+
${exports2}
|
|
1434
|
+
`;
|
|
1435
|
+
}
|
|
1375
1436
|
};
|
|
1376
1437
|
|
|
1377
1438
|
// src/index.ts
|