模板自定义
@scx/api-tool 使用 Handlebars 模板引擎生成代码,支持完全自定义模板以适应不同的项目需求。
模板系统概述
默认模板结构
src/templates/
├── types.ts # TypeScript 类型定义模板
├── request.ts # HTTP 请求函数模板
├── interface.ts # API 接口定义模板
└── config.ts # 配置文件模板模板引擎
使用 Handlebars 作为模板引擎,支持:
- 变量替换:
{\{variable\}} - 条件渲染:
{\{#if condition\}}...{\{/if\}} - 循环遍历:
{\{#each items\}}...{\{/each\}} - 自定义助手函数
- 模板继承:
{\{> partial\}}
基础模板定制
1. 使用自定义模板目录
在配置中指定模板目录:
typescript
export default defineConfig([
{
// ... 其他配置
templateDir: './my-templates', // 自定义模板目录
},
]);2. 覆盖特定模板
只覆盖需要的模板文件:
my-templates/
├── types.ts # 覆盖默认的类型模板
└── request.ts # 覆盖默认的请求模板模板数据结构
可用变量
每个模板文件都会接收以下数据:
typescript
interface TemplateData {
// 项目配置
config: {
outputDir: string;
target: 'typescript' | 'javascript';
indentSize: number;
};
// 接口信息
interfaces: InterfaceInfo[];
// 类型定义
types: TypeInfo[];
// 当前分类信息(如果在分类模板中)
category?: CategoryInfo;
// 工具函数
utils: {
changeCase: ChangeCaseUtils;
formatString: FormatUtils;
};
}接口信息结构
typescript
interface InterfaceInfo {
id: string;
name: string;
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
path: string;
summary: string;
description?: string;
parameters: ParameterInfo[];
requestBody?: RequestBodyInfo;
responses: ResponseInfo[];
tags: string[];
}类型信息结构
typescript
interface TypeInfo {
name: string;
description?: string;
properties: PropertyInfo[];
required?: string[];
enum?: any[];
}模板示例
1. 简化的类型模板
2. 带 JSDoc 的请求模板
3. React Hooks 模板
自定义助手函数
1. 创建助手函数
typescript
// src/template-helpers.ts
import type { HelperOptions } from 'handlebars';
export const registerHelpers = (Handlebars: typeof import('handlebars')) => {
// 类型转换助手
Handlebars.registerHelper('tsType', (swaggerType: string) => {
const typeMap: Record<string, string> = {
string: 'string',
integer: 'number',
number: 'number',
boolean: 'boolean',
array: 'Array<any>',
object: 'Record<string, any>',
};
return typeMap[swaggerType] || 'any';
});
// 路径转参数名助手
Handlebars.registerHelper('pathToParams', (path: string) => {
return path
.split('/')
.filter((segment) => segment.startsWith(':'))
.map((segment) => segment.slice(1))
.join(', ');
});
// 条件判断助手
Handlebars.registerHelper('eq', (a: any, b: any) => {
return a === b;
});
// 格式化请求头助手
Handlebars.registerHelper('formatHeaders', (headers: Record<string, string>) => {
return Object.entries(headers)
.map(([key, value]) => `'${key}': '${value}'`)
.join(',\n ');
});
};2. 注册助手函数
typescript
// 在生成代码前注册助手
import { registerHelpers } from './template-helpers';
const Handlebars = require('handlebars');
registerHelpers(Handlebars);高级模板技巧
1. 模板继承
创建基础模板:
2. 条件模板生成
根据配置生成不同内容:
3. 多格式输出
同时生成 TypeScript 和 JavaScript:
实用模板示例
1. 生成 Fetch API 版本
2. 生成 Axios 客户端
模板测试
1. 单元测试
typescript
// test/templates.test.ts
import { generateCode } from '../src/generator';
describe('Template Generation', () => {
test('generates correct TypeScript types', async () => {
const mockData = {
types: [{ name: 'User', properties: [{ name: 'id', type: 'number' }] }],
};
const result = await generateCode('types.ts', mockData);
expect(result).toContain('export interface User');
});
});2. 快照测试
typescript
// test/templates.snapshot.test.ts
import { generateCode } from '../src/generator';
test('type template snapshot', async () => {
const result = await generateCode('types.ts', mockData);
expect(result).toMatchSnapshot();
});最佳实践
1. 模板组织
my-templates/
├── base/ # 基础模板
│ ├── types.hbs
│ └── request.hbs
├── frameworks/ # 框架特定模板
│ ├── react/
│ ├── vue/
│ └── angular/
└── utils/ # 工具函数模板
├── validation.hbs
└── helpers.hbs2. 版本兼容
3. 错误处理
4. 性能优化
- 缓存编译后的模板
- 避免深层嵌套循环
- 合理使用条件判断
- 复用公共模板片段