Skip to content

Commit 1fd308e

Browse files
🎯 feat: Add customRenderTemplateData hook for fine-grained file generation control (#511)
* feat: added customGenFileFromTemplateList hook functionality * refactor: customGenFileFromTemplateList -> customRenderTemplateData * refactor: customGenFileFromTemplateList.spec -> customRenderTemplateData.spec * refactor: replace string constants with TypescriptFileType to enhance type safety * chore: update changelog * refactor: remove customGenFileFromTemplateList test * chore: revert 测试空的 schema 引用.snap --------- Co-authored-by: 故城 <[email protected]>
1 parent f2eab67 commit 1fd308e

19 files changed

+20401
-3
lines changed

.changeset/common-corners-walk.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openapi-ts-request': minor
3+
---
4+
5+
feat: Added customRenderTemplateData hook functionality #512

README-en_US.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ openapi -i ./spec.json -o ./apis
265265
| customType | ({<br>schemaObject: SchemaObject \| ReferenceObject,<br>namespace: string,<br>originGetType:(schemaObject: SchemaObject \| ReferenceObject, namespace: string, schemas?: ComponentsObject['schemas']) => string,<br>schemas?: ComponentsObject['schemas'],<br>}) => string | custom type <br> _returning a non-string will use the default method to get the type_ |
266266
| customFileNames | (<br>operationObject: OperationObject,<br>apiPath: string,<br>apiMethod: string,<br>) => string[] | custom generate request client controller file name, can return multiple: generate multiple files. <br> _if the return value is empty, the default getFileNames is used_ |
267267
| customTemplates | {<br>[TypescriptFileType.serviceController]?: <T, U>(item: T, context: U) => string;<br>} | custom template, details see source code |
268+
| customRenderTemplateData | {<br>[TypescriptFileType]?: (list: any[], context: {fileName: string, params: Record<string, unknown>}) => any[]<br>} | custom list parameter processing during file generation, provides fine-grained control for different file types |
268269

269270
## Apifox-Config
270271

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ openapi --i ./spec.json --o ./apis
267267
| customType | ({<br>schemaObject: SchemaObject \| ReferenceObject,<br>namespace: string,<br>originGetType:(schemaObject: SchemaObject \| ReferenceObject, namespace: string, schemas?: ComponentsObject['schemas']) => string,<br>schemas?: ComponentsObject['schemas'],<br>}) => string | 自定义类型 <br> _返回非字符串将使用默认方法获取type_ |
268268
| customFileNames | (<br>operationObject: OperationObject,<br>apiPath: string,<br>apiMethod: string,<br>) => string[] | 自定义生成的请求客户端文件名称,可以返回多个文件名称的数组(表示生成多个文件). <br> _返回为空,则使用默认的方法获取_ |
269269
| customTemplates | {<br>[TypescriptFileType.serviceController]?: <T, U>(item: T, context: U) => string;<br>} | 自定义模板,详情请看源码 |
270+
| customRenderTemplateData | {<br>[TypescriptFileType]?: (list: any[], context: {fileName: string, params: Record<string, unknown>}) => any[]<br>} | 自定义文件生成时的 list 参数处理,支持对不同文件类型进行精细化控制 |
270271

271272
## Apifox-Config
272273

src/generator/serviceGenarator.ts

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ import {
101101
// resolveFunctionName,
102102
resolveRefs,
103103
resolveTypeName,
104-
// stripDot,
105104
} from './util';
106105

107106
export default class ServiceGenerator {
@@ -865,6 +864,101 @@ export default class ServiceGenerator {
865864
): boolean {
866865
try {
867866
const template = this.getTemplate(type);
867+
868+
// 应用 customRenderTemplateData hook (如果存在)
869+
let processedParams = { ...params };
870+
const customListHooks = this.config.hook?.customRenderTemplateData;
871+
872+
if (customListHooks && params.list) {
873+
try {
874+
const context = {
875+
fileName,
876+
params: processedParams,
877+
};
878+
879+
let processedList = params.list;
880+
881+
// 根据不同的文件类型调用相应的 hook 函数
882+
switch (type) {
883+
case TypescriptFileType.serviceController:
884+
if (customListHooks.serviceController) {
885+
processedList = customListHooks.serviceController(
886+
params.list as APIDataType[],
887+
context
888+
);
889+
}
890+
break;
891+
case TypescriptFileType.reactQuery:
892+
if (customListHooks.reactQuery) {
893+
processedList = customListHooks.reactQuery(
894+
params.list as APIDataType[],
895+
context
896+
);
897+
}
898+
break;
899+
case TypescriptFileType.interface:
900+
if (customListHooks.interface) {
901+
processedList = customListHooks.interface(
902+
params.list as ITypeItem[],
903+
context
904+
);
905+
}
906+
break;
907+
case TypescriptFileType.displayEnumLabel:
908+
if (customListHooks.displayEnumLabel) {
909+
processedList = customListHooks.displayEnumLabel(
910+
params.list as ITypeItem[],
911+
context
912+
);
913+
}
914+
break;
915+
case TypescriptFileType.displayTypeLabel:
916+
if (customListHooks.displayTypeLabel) {
917+
processedList = customListHooks.displayTypeLabel(
918+
params.list as ITypeItem[],
919+
context
920+
);
921+
}
922+
break;
923+
case TypescriptFileType.schema:
924+
if (customListHooks.schema) {
925+
processedList = customListHooks.schema(
926+
params.list as ISchemaItem[],
927+
context
928+
);
929+
}
930+
break;
931+
case TypescriptFileType.serviceIndex:
932+
if (customListHooks.serviceIndex) {
933+
processedList = customListHooks.serviceIndex(
934+
params.list as ControllerType[],
935+
context
936+
);
937+
}
938+
break;
939+
}
940+
941+
if (processedList !== params.list) {
942+
processedParams = {
943+
...processedParams,
944+
list: processedList,
945+
};
946+
this.log(
947+
`customRenderTemplateData hook applied for ${type}: ${fileName}`
948+
);
949+
}
950+
} catch (error) {
951+
console.error(
952+
`[GenSDK] customRenderTemplateData hook error for ${type}:`,
953+
error
954+
);
955+
this.log(
956+
`customRenderTemplateData hook failed for ${type}, using original list`
957+
);
958+
// 发生错误时使用原始参数继续执行
959+
}
960+
}
961+
868962
// 设置输出不转义
869963
const env = nunjucks.configure({
870964
autoescape: false,
@@ -874,7 +968,7 @@ export default class ServiceGenerator {
874968
const destPath = join(this.config.serversPath, fileName);
875969
const destCode = nunjucks.renderString(template, {
876970
disableTypeCheck: false,
877-
...params,
971+
...processedParams,
878972
});
879973
let mergerProps: MergeOption = {} as MergeOption;
880974

src/index.ts

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import { PriorityRule, ReactQueryMode } from './config';
44
import type { TypescriptFileType } from './generator/config';
55
import { mockGenerator } from './generator/mockGenarator';
66
import ServiceGenerator from './generator/serviceGenarator';
7-
import type { APIDataType, ITypeItem } from './generator/type';
7+
import type {
8+
APIDataType,
9+
ControllerType,
10+
ISchemaItem,
11+
ITypeItem,
12+
} from './generator/type';
813
import type {
914
ComponentsObject,
1015
IPriorityRule,
@@ -265,6 +270,82 @@ export type GenerateServiceProps = {
265270
config: U
266271
) => ITypeItem[];
267272
};
273+
/**
274+
* 自定义 genFileFromTemplate 的 list 参数 hook
275+
* 可以在模板渲染前对 list 参数进行自定义处理
276+
*/
277+
customRenderTemplateData?: {
278+
/**
279+
* 自定义 serviceController 文件的 list 参数
280+
*/
281+
[TypescriptFileType.serviceController]?: (
282+
list: APIDataType[],
283+
context: {
284+
fileName: string;
285+
params: Record<string, unknown>;
286+
}
287+
) => APIDataType[];
288+
/**
289+
* 自定义 interface 文件的 list 参数
290+
*/
291+
[TypescriptFileType.interface]?: (
292+
list: ITypeItem[],
293+
context: {
294+
fileName: string;
295+
params: Record<string, unknown>;
296+
}
297+
) => ITypeItem[];
298+
/**
299+
* 自定义 displayEnumLabel 文件的 list 参数
300+
*/
301+
[TypescriptFileType.displayEnumLabel]?: (
302+
list: ITypeItem[],
303+
context: {
304+
fileName: string;
305+
params: Record<string, unknown>;
306+
}
307+
) => ITypeItem[];
308+
/**
309+
* 自定义 displayTypeLabel 文件的 list 参数
310+
*/
311+
[TypescriptFileType.displayTypeLabel]?: (
312+
list: ITypeItem[],
313+
context: {
314+
fileName: string;
315+
params: Record<string, unknown>;
316+
}
317+
) => ITypeItem[];
318+
/**
319+
* 自定义 schema 文件的 list 参数
320+
*/
321+
[TypescriptFileType.schema]?: (
322+
list: ISchemaItem[],
323+
context: {
324+
fileName: string;
325+
params: Record<string, unknown>;
326+
}
327+
) => ISchemaItem[];
328+
/**
329+
* 自定义 serviceIndex 文件的 list 参数
330+
*/
331+
[TypescriptFileType.serviceIndex]?: (
332+
list: ControllerType[],
333+
context: {
334+
fileName: string;
335+
params: Record<string, unknown>;
336+
}
337+
) => ControllerType[];
338+
/**
339+
* 自定义 reactQuery 文件的 list 参数
340+
*/
341+
[TypescriptFileType.reactQuery]?: (
342+
list: APIDataType[],
343+
context: {
344+
fileName: string;
345+
params: Record<string, unknown>;
346+
}
347+
) => APIDataType[];
348+
};
268349
};
269350
};
270351

0 commit comments

Comments
 (0)