@antmjs/rapper
TypeScript icon, indicating that this package has built-in type declarations

2.3.28 • Public • Published

Rapper 是什么?

注:可以使用@antmjs/api 代替

Rapper 是 TypeScript 的最佳拍档,它可以帮你生成具有类型定义的请求方案。

  • 无需自行书写请求代码,把 HTTP 接口当做函数调用
  • 请求参数/返回数据类型化,静态校验、自动补全快到飞起

@antmjs/rapper 是什么?

基于 Rapper 开发,使配置更灵活,同时增加本地类型同步远程文档重要功能

  • ++++
  • 本地接口类型上传到 rapper 远程文档,本地编码驱动远程文档
  • 自定义请求函数模板,满足不同编程规范

快速开始

  1. package.json scripts 中 添加 { "rap" : "npx rapper"}

  2. 配置 antm.config.js

{
  rapper: {
    // 拉取接口地址
    apiUrl?: string;
    /** rap 前端地址,默认是 http://rap2.taobao.org */
    rapUrl?: string;
    // 生成的文件目录地址
    rapperPath?: string;
    // rap登录cookie
    tokenCookie?: string;
    // rap项目id
    repositoryId?: number;
  }
}
  1. 开始写你的 ts 接口类型, 然后执行 npm run rap

rapper 名称对应 接口 ts 类型介绍

ts 接口类型需要配合 rapper 使用

  • 暂时不支持 url 带 path 参数

    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 中含义

  • 1 [request] 请求参数定义;
  • 2 [age?: string] 入参定义字段名称,必选,类型;
  • 3 [response] 返回数据定义;
  • 4 [jsDoc 描述: 数组演示] 字段简介
  • 5 [jsDoc 关键字:@value #cname] 字段初始值
  • 6 [jsDoc 关键字:@rule 123] 字段生成规则

注意 jsDoc 关键字的值中【@】符号由于转义问题需要替换成【#】或者【\@】或者【/@】

命令函入参会和 config 合并(命令行优先级更高)

  • --u 上传
  • --d 下载
  • --m xx 指定 moduleId,不传默认提交更改的模块

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(
      {
        url,
        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,
  };
    ```

Package Sidebar

Install

npm i @antmjs/rapper

Weekly Downloads

16

Version

2.3.28

License

MIT

Unpacked Size

146 kB

Total Files

19

Last publish

Collaborators

  • zuolung
  • hisanshao