Pont 支持自定义 数据获取 、数据源预处理、代码生成器 等。JSON配置中其他配置请参考 pont-config.json 配置
在自定义前,需要了解 Pont 在运行时的执行流程。蓝色框表示自定义文件,绿色框表示被自定义的环节
指定 数据获取 路径(使用相对路径指定)。
注意:此文件目前只能使用 .ts
后缀,且路径字段不需要加 .ts
后缀
{
// ...
"fetchMethodPath": "./myFetchMethod",
}
#### 类型 ```javascript export default function (url: string): Promise ```
// ./myFetchMethod.ts
import axios from 'axios';
export default async function (url: string): Promise<string> {
const { data } = await axios.post('/api/login', {
username: 'my_name',
password: '123456'
});
return axios
.get(url, {
headers: {
Authorization: data.token
}
})
.then((res) => JSON.stringify(res.data));
}
指定 数据源预处理 路径(使用相对路径指定)。
Pont 将 Swagger.json 数据转换为内部标准数据源之后会尝试调用由transformPath
指定的转换程序,对数据进行一些处理。
{
// ...
"transformPath": "./pontTransfrom",
}
export default function transform(dataSource: StandardDataSource): StandardDataSource
pont-config.json 同级目录下新建一个 pontTransfrom.ts文件, export default 默认方法
// pontTransfrom.ts
import { StandardDataSource } from 'pont-engine';
// 根据 Mod.name进行过滤
export default function transform(data: StandardDataSource) {
if (data.name === 'fooapi') {
const filterMods = ['modName1', 'modName2', 'modName3'];
let { mods, baseClasses } = filterModsAndBaseClass(filterMods, data);
data.mods = mods;
data.baseClasses = baseClasses;
}
return data;
}
/**
* 过滤mod及所依赖的baseClass
* @param filterMods Mod.name数组
* @param data StandardDataSource
*/
function filterModsAndBaseClass(filterMods: string[], data: StandardDataSource) {
let mods = data.mods.filter((mod) => {
return filterMods.includes(mod.name);
});
// 获取所有typeName
let typeNames = JSON.stringify(mods).match(/"typeName":".+?"/g);
typeNames = Array.from(new Set(typeNames)) // 去重
// 取typeName的值
.map((item) => item.split(':')[1].replace(/\"/g, ''));
// 过滤baseClasses
let baseClasses = data.baseClasses.filter((cls) => typeNames.includes(cls.name));
return { mods, baseClasses };
}
指定 代码生成器 路径(使用相对路径指定)。
一旦指定,pont 将即刻生成一份默认的自定义代码生成器。自定义代码生成器是一份 ts 文件,通过覆盖默认的代码生成器,来自定义生成代码。默认的代码生成器包含两个类,一个负责管理目录结构,一个负责管理目录结构每个文件如何生成代码。自定义代码生成器通过继承这两个类(类型完美,可以查看提示和含义),覆盖对应的代码来达到自定义的目的。
{
// ...
"templatePath": "./pontTemplate",
}
类型
import { CodeGenerator, FileStructures as OriginFileStructures } from 'pont-engine';
// 代码生成器
export default class MyCodeGenerator extends CodeGenerator {}
// 文件结构生成
export class FileStructures extends OriginFileStructures {}
代码生成器
export class CodeGenerator {
usingMultipleOrigins = false;
dataSource: StandardDataSource;
hasContextBund = false;
constructor(public surrounding = Surrounding.typeScript, public outDir = '') {}
setDataSource(dataSource: StandardDataSource) {
this.dataSource = dataSource;
// 将basic-resource这种命名转化成合法命名
this.dataSource.name = _.camelCase(this.dataSource.name);
}
/** 获取某个基类的类型定义代码 */
getBaseClassInDeclaration(base: BaseClass): string
/**
* 获取所有基类的类型定义代码,一个 namespace
* surrounding, 优先级高于this.surrounding,用于生成api.d.ts时强制保留类型
*/
getBaseClassesInDeclaration(): string
/** 获取接口内容的类型定义代码 */
getInterfaceContentInDeclaration(inter: Interface): string
/** 获取接口内容的类型定义 */
private getInterfaceInDeclaration(inter: Interface): string
/** 获取模块的类型定义代码,一个 namespace ,一般不需要覆盖 */
getModsDeclaration(): string
/** 获取公共的类型定义代码 */
getCommonDeclaration(): string
/** 获取总的类型定义代码 */
getDeclaration(): string
/** 获取接口类和基类的总的 index 入口文件代码 */
getIndex(): string
/** 获取所有基类文件代码 */
getBaseClassesIndex(): string
/** 获取接口实现内容的代码 */
getInterfaceContent(inter: Interface): string
/** 获取单个模块的 index 入口文件 */
getModIndex(mod: Mod): string
/** 获取所有模块的 index 入口文件 */
getModsIndex(): string
/** 获取中间态数据结构 */
getDataSourceCallback(dataSource?: StandardDataSource): void
/** VSCode插件接口代码片段生成 */
codeSnippet(inter: Interface): string
}
文件结构生成
export interface FileStructure {
[filePath: string]: FileStructure | (() => string) | string;
}
export class FileStructures {
constructor(
private generators: CodeGenerator[],
private usingMultipleOrigins: boolean,
private surrounding = Surrounding.typeScript,
private baseDir = 'src/service',
private templateType = ''
) {}
/** 获取所有基类的类型定义代码, generator.hasContextBund 为true时覆盖 generator的同名方法 */
getBaseClassesInDeclaration(originCode: string, usingMultipleOrigins: boolean): string
/** 获取模块的类型定义代码, generator.hasContextBund 为true时覆盖 generator的同名方法 */
getModsDeclaration(originCode: string, usingMultipleOrigins: boolean): string
/** 获取多个数据源的文件结构 */
getMultipleOriginsFileStructures(): FileStructure
/** 获取单个数据源的文件结构 */
getOriginFileStructures(generator: CodeGenerator, usingMultipleOrigins = false): FileStructure
/** 获取总文件结构 */
getFileStructures(): FileStructure
/** 检测是否存在 fetch 模板文件 */
private checkHasTemplateFetch(): boolean
/** 多源下的数据名称 */
getMultipleOriginsDataSourceName(): string[]
/** 判断是否有多个不同输出地址 */
judgeHasMultipleFilesName(): boolean
/** 获取 index 内容 */
getDataSourcesTs(): string
/** 获取 api.d.ts 内容 */
getDataSourcesDeclarationTs(): string
/** 获取 api-lock.json 内容 */
getLockContent(): string
/** 用于scan扫描接口 */
getApiUseCases: (inter: Interface) => Array<string>
}
根据 pont-config.json 中配置的 templatePath 路径下新建一个 pontTemplate.ts文件, ,export default 一个 CodeGenerator 子类 MyGenerator 和 export 一个 FileStructures 子类 MyFileStructures , 根据自身需求覆盖 CodeGenerator 和 FileStructures 中的方法。
实例中的 Request 就是一个可用的 http 请求库, 可以替换为 axios、fetch 等可用的 http 请求封装。
// pontTemplate.ts
import { CodeGenerator, Interface, FileStructures as OriginFileStructures } from 'pont-engine';
export class FileStructures extends OriginFileStructures {}
export default class MyGenerator extends CodeGenerator {
getInterfaceContent(inter: Interface) {
const paramsCode = inter.getParamsCode();
const bodyParamsCode = inter.getBodyParamsCode();
const method = inter.method.toUpperCase();
let requestParams = bodyParamsCode ? `bodyParams = {}` : `params = {}`;
return `
/**
* @description ${inter.description}
*/
import { getUrl } from 'src/utils/getUrl';
import Request from 'src/utils/requests';
import * as defs from '../../baseClass';
export ${paramsCode}
export const init = ${inter.response.initialValue};
export async function request(${requestParams}) {
return Request({
url: getUrl("${inter.path}", ${bodyParamsCode ? 'bodyParams' : 'params'}, "${method}"),
${bodyParamsCode ? 'params: bodyParams' : 'params'},
method: '${inter.method}',
});
}
export function createFetchAction(types, stateKey) {
return (${bodyParamsCode ? `bodyParams = {}` : 'params = {}'}, meta?: any) => {
return {
types,
meta,
stateKey,
method: '${inter.method}',
url: getUrl("${inter.path}", ${bodyParamsCode ? 'bodyParams' : 'params'}, "${method}"),
${bodyParamsCode ? 'params: bodyParams,' : 'params,'}
init,
};
};
}
`;
}
}