Rapper 是什么?
注:可以使用@antmjs/api 代替
Rapper 是 TypeScript 的最佳拍档,它可以帮你生成具有类型定义的请求方案。
@antmjs/rapper 是什么?
基于 Rapper 开发,使配置更灵活,同时增加本地类型同步远程文档重要功能
package.json scripts 中 添加 { "rap" : "npx rapper"}
配置 antm.config.js
rapper: { // 拉取接口地址 apiUrl ? : string ; /** rap 前端地址,默认是 http://rap2.taobao.org */ rapUrl ? : string ; // 生成的文件目录地址 rapperPath ? : string ; // rap登录cookie tokenCookie ? : string ; // rap项目id repositoryId ? : number ;rapper 名称对应 接口 ts 类型介绍
ts 接口类型需要配合 rapper 使用
rapper 接口字段名称对应
interface XY {
x: number
y: number
z: number
export type IUserInfo = {
request: {
// (1)
age?: string // (2)
response: {
// (3)
* @value true
success: boolean
data: {
* 数组演示 // (4)
* @rule 123 // (6)
array: {
* @value #cname // (5)
name: string
* 支持泛型以及接口引用
other: XY
}[]
以下是 rapper 中含义
注意 jsDoc 关键字的值中【@】符号由于转义问题需要替换成【#】或者【\@】或者【/@】
命令函入参会和 config 合并(命令行优先级更高)
rapper 配置 config 有三种方案
方案一(推荐)
通过 antm.config.js 配置 config
// <!-- antm.config.js文件 -->
const antmRapper = require('@antmjs/rapper')
// <!-- 使用antm 提供 defineConfig 会有类型提示 -->
export.default = antmRapper.defineConfig({
upload: { xx: xx }, // 本地上传 配置
通过 命令行参数执行 config 路径
$ npx rapper --config ./config/index.js
// <!-- ./config/index.js文件 -->
const antmRapper = require('@antmjs/rapper')
// <!-- antmRapper 提供 defineConfig 会有类型提示 -->
export.default = antmRapper.defineConfig({
upload: { xx: xx }, // 本地上传 配置
download: { xx: xx } // 远程下载 配置
通过 package.json 配置 antm.rapper
<!--package.json 文件 -->
'antm': {
'rapper': {
'upload': { xx: xx }, // 本地上传 配置
本地代码类型同步到远程 raper 文档
解析本地文件
fetch 方法追加注释 (接口 id 接口模块 id)
格式化 类型
调用 rapper 接口
增量更新实现每次更新会给文件头部 加一个 MD5 值
初始化会检查合法的文件(符合 formatFunc 结构的文件) MD5 值 对不住
去解析当前文件以及 依赖当前文件的文件
提交变更的模块接口(文件级检查),做不到方法级检查
config 接口类型interface IConfig {
// 下载配置
download: {
* @param params rap上填入接口的信息
* @returns
* reqTypeName: request类型名称;
* resTypeName: response类型名称;
* funcMain: 请求函数体;
requestFunc?: (params: {
funcDescription: string
repositoryId: number
moduleId: number
interfaceId: number
requestUrl: string
requestMethod: string
rapUrl: string
}) => {
reqTypeName: string
resTypeName: string
funcMain: string
* @param params rap 上填入的module信息
* @returns
* fileName: 模块的文件名称;
* moduleHeader: 模块头部的banner;
requestModule?: (params: {
repositoryId: number
moduleId: number
moduleRapUrl: string
moduleDescription: string
}) => {
fileName: string
moduleHeader: string
// 自定下载的module
moduleId?: number
rapper: {
// 拉取接口地址
apiUrl?: string
/** rap 前端地址,默认是 http://rap2.taobao.org */
rapUrl?: string
// 生成的文件目录地址
rapperPath?: string
// rap登录cookie
tokenCookie?: string
// rap项目id
repositoryId?: number
upload: {
// 模式 type 文件扫描入口是type(需要编译生成fetch)
// fetch 文件扫描入口是fetch请求函数(不需要编译)
mode?: 'type' | 'fetch'
// 需要解析的文件名称正则
fileRegex?: string
* @param params 函数信息
* @returns
* resTypeName: request 类型名称;
* reqTypeName: response 类型名称;
* reqUrl: 请求 url;
* reqMethod: 请求method;
* interfaceId: 接口id;
formatFunc?: (params: {
funcName: string
body: string
comment: string
// 三种函数 定义 会被选中到导出
funcType: 'CallExpression' | 'FunctionDeclaration' | 'ArrowFunction'
}) => {
resTypeName: string
reqTypeName: string
reqUrl: string
reqMethod: string
interfaceId: number
} | null
// 指定下载的 模块id
moduleId?: number
// webpack 别名
alias?: Record<string, string>
// 内部标识使用 不用管
__completion?: boolean
// 是不是上传
isUpload: boolean
export type IOptions = Partial<IConfig>
defaultConfig 会和传进来的 config 合并补全 const defaultOptions = {
download: {
//请求 function 模板
requestFunc(params) {
function getFnName(url: string): null | string {
const fnName = url.match(/\/([.a-z0-9_-]+)\/([a-z0-9_-]+$)/i);
if (fnName && fnName.length === 3) {
if (/^\d+\.\d+$/.test(fnName[1])) {
return fnName[2];
return fnName[1] + fnName[2].charAt(0).toUpperCase() + fnName[2].slice(1);
return null;
const fnName = getFnName(params.requestUrl);
if (!fnName) {
throw new TypeError('接口路径不对,请修改合规');
const camelCaseName = `${fnName.charAt(0).toUpperCase()}${fnName.slice(1)}`;
const reqTypeName = `IReq${camelCaseName}`;
const resTypeName = `IRes${camelCaseName}`;
return {
reqTypeName,
resTypeName,
funcMain: `
* 接口名:${params.funcDescription}
* Rap 地址: ${params.rapUrl}?id=${params.repositoryId}&mod=${params.moduleId}&itf=${params.interfaceId}
export const ${fnName} = createFetch<${reqTypeName}, ${resTypeName}>('${params.requestUrl}', '${params.requestMethod}')
//请求 函数共工头(用于引入函数
requestModule(params) {
return {
fileName: params.moduleDescription,
moduleHeader: `
/* eslint-disable */
/* tslint:disable */
// @ts-nocheck
import instance from '@/utils/request'
function createFetch<REQ extends Record<string, unknown>, RES extends {data: any}> (url: string, method: string) {
return <T extends boolean = false>(
data: REQ,
options?: {
proxy?: T
pageError?: boolean
): Promise<T extends true ? RES['data'] : RES> => {
return instance(
method,
data,
options
rapper: {
// 拉取接口地址
apiUrl:
'http://rap2api.taobao.org/repository/get?id=284428&token=TTDNJ7gvXgy9R-9axC-7_mbi4ZxEPlp6',
/** rap 前端地址,默认是 http://rap2.taobao.org */
rapUrl: 'http://rap2.taobao.org',
rapperPath: './src/actions',
tokenCookie:
'aliyungf_tc=f3a5915db08fc3b6de3ec5df0d0b3a5dc07c0b701e44cf4bf98a855799570bfe; koa.sid=2I353u8TTwtrHSdPXdJ9t8Mx5lTOeQFV; koa.sid.sig=D4vYLNcryQ8vcU4GkJJknTi_Fm8',
repositoryId: 284428,
upload: {
mode: 'type' as const,
// fileRegex 将尝试使用绝对文件路径检测测试文件
// (/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$
fileRegex: './src/actions/types/.*(js|jsx|ts|tsx)',
formatFunc(params) {
// createFetch<IReqGoodsQbf, IResGoodsQbf>('/c/api/1.0/approve/goods/qbf', 'GET')
// export const goodsQbf = createFetch<IGoodsQbf['request'], IGoodsQbf['response']>("/c/api/1.0/approve/goods/qbf", "GET");
const [_, reqTypeName, resTypeName, reqUrl, reqMethod] =
params.body.match(
/createFetch<([\w\[\]'"]+),\s+([\w\[\]'"]+)>\(['"]([\s\S]+)['"], ['"]([a-zA-Z]+)['"]\)/,
) || [];
if (!reqTypeName || !resTypeName) {
return null;
const matchInterfaceId = params.comment.match(/http:\/\/rap2\.tao[\s\S]+&itf=(\d+)/);
return {
resTypeName,
reqTypeName,
// 如果返回 null '' undefined 0 等 就会被认为是新的接口,会触发上rap操作
interfaceId: matchInterfaceId ? Number(matchInterfaceId[1]) : null,
reqUrl: reqUrl,
reqMethod: reqMethod,
// webpack 别名 alias 绝对路径
alias: {
'@': './src',
isUpload: true,