2.3.27 • Published 2 months ago

@antmjs/rapper v2.3.27

Weekly downloads
-
License
MIT
Repository
github
Last release
2 months ago

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

注意 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,
  };
    ```
2.3.27

2 months ago

2.3.26

4 months ago

2.3.25

4 months ago

2.3.24

6 months ago

2.3.23

7 months ago

2.3.20

9 months ago

2.3.22

8 months ago

2.3.21

9 months ago

2.3.19

9 months ago

2.3.18

10 months ago

2.3.8

11 months ago

2.3.7

11 months ago

2.3.9

11 months ago

2.3.17

11 months ago

2.3.16

11 months ago

2.3.13

11 months ago

2.3.12

11 months ago

2.3.15

11 months ago

2.3.14

11 months ago

2.3.11

11 months ago

2.2.4

1 year ago

2.3.0

1 year ago

2.3.2

1 year ago

2.3.1

1 year ago

2.3.4

1 year ago

2.3.3

1 year ago

2.3.6

12 months ago

2.3.5

12 months ago

2.2.1

1 year ago

2.2.0

1 year ago

2.1.2

2 years ago

2.1.3

1 year ago

2.1.1

2 years ago

2.0.3

2 years ago

2.0.2

2 years ago

2.0.5

2 years ago

2.0.4

2 years ago

2.0.7

2 years ago

2.0.6

2 years ago

2.0.1

2 years ago

2.0.0

2 years ago

1.21.3

2 years ago

2.1.0

2 years ago

1.19.0

2 years ago

1.19.2

2 years ago

1.19.1

2 years ago

1.21.0

2 years ago

1.20.1

2 years ago

1.21.1

2 years ago

1.20.0

2 years ago

1.20.5

2 years ago

1.21.2

2 years ago

1.20.4

2 years ago

1.18.1

2 years ago

1.18.0

2 years ago

1.18.4

2 years ago

1.18.3

2 years ago

1.18.2

2 years ago

1.17.9

2 years ago

1.17.2

2 years ago

1.17.6

2 years ago

1.17.5

2 years ago

1.17.4

2 years ago

1.17.7

2 years ago

1.15.0

2 years ago

1.14.1

2 years ago

1.16.3

2 years ago

1.15.4

2 years ago

1.17.1

2 years ago

1.16.2

2 years ago

1.15.3

2 years ago

1.17.0

2 years ago

1.16.1

2 years ago

1.15.2

2 years ago

1.16.0

2 years ago

1.15.1

2 years ago

1.15.6

2 years ago

1.16.4

2 years ago

1.15.5

2 years ago

1.14.0

3 years ago

1.13.2

3 years ago