yapi-ts-builder
Version:
基于 yapi-to-typescript 实现的 YApi 接口定义生成工具
651 lines (650 loc) • 19.1 kB
TypeScript
/// <reference types="node" />
import { AsyncOrSync, LiteralUnion, OmitStrict, OneOrMore } from 'vtils/types';
import { JSONSchema4, JSONSchema4TypeName } from 'json-schema';
import { ParsedPath } from 'path';
export interface ChangeCase {
/**
* @example
* changeCase.camelCase('test string') // => 'testString'
*/
camelCase: (value: string) => string;
/**
* @example
* changeCase.constantCase('test string') // => 'TEST_STRING'
*/
constantCase: (value: string) => string;
/**
* @example
* changeCase.dotCase('test string') // => 'test.string'
*/
dotCase: (value: string) => string;
/**
* @example
* changeCase.headerCase('test string') // => 'Test-String'
*/
headerCase: (value: string) => string;
/**
* @example
* changeCase.lowerCase('TEST STRING') // => 'test string'
*/
lowerCase: (value: string) => string;
/**
* @example
* changeCase.lowerCaseFirst('TEST') // => 'tEST'
*/
lowerCaseFirst: (value: string) => string;
/**
* @example
* changeCase.paramCase('test string') // => 'test-string'
*/
paramCase: (value: string) => string;
/**
* @example
* changeCase.pascalCase('test string') // => 'TestString'
*/
pascalCase: (value: string) => string;
/**
* @example
* changeCase.pathCase('test string') // => 'test/string'
*/
pathCase: (value: string) => string;
/**
* @example
* changeCase.sentenceCase('testString') // => 'Test string'
*/
sentenceCase: (value: string) => string;
/**
* @example
* changeCase.snakeCase('test string') // => 'test_string'
*/
snakeCase: (value: string) => string;
/**
* @example
* changeCase.swapCase('Test String') // => 'tEST sTRING'
*/
swapCase: (value: string) => string;
/**
* @example
* changeCase.titleCase('a simple test') // => 'A Simple Test'
*/
titleCase: (value: string) => string;
/**
* @example
* changeCase.upperCase('test string') // => 'TEST STRING'
*/
upperCase: (value: string) => string;
/**
* @example
* changeCase.upperCaseFirst('test') // => 'Test'
*/
upperCaseFirst: (value: string) => string;
}
/** 请求方式 */
export declare enum Method {
GET = "GET",
POST = "POST",
PUT = "PUT",
DELETE = "DELETE",
HEAD = "HEAD",
OPTIONS = "OPTIONS",
PATCH = "PATCH"
}
/** 是否必需 */
export declare enum Required {
/** 不必需 */
false = "0",
/** 必需 */
true = "1"
}
/** 请求数据类型 */
export declare enum RequestBodyType {
/** 查询字符串 */
query = "query",
/** 表单 */
form = "form",
/** JSON */
json = "json",
/** 纯文本 */
text = "text",
/** 文件 */
file = "file",
/** 原始数据 */
raw = "raw",
/** 无请求数据 */
none = "none"
}
/** 请求路径参数类型 */
export declare enum RequestParamType {
/** 字符串 */
string = "string",
/** 数字 */
number = "number"
}
/** 请求查询参数类型 */
export declare enum RequestQueryType {
/** 字符串 */
string = "string",
/** 数字 */
number = "number"
}
/** 请求表单条目类型 */
export declare enum RequestFormItemType {
/** 纯文本 */
text = "text",
/** 文件 */
file = "file"
}
/** 返回数据类型 */
export declare enum ResponseBodyType {
/** JSON */
json = "json",
/** 纯文本 */
text = "text",
/** XML */
xml = "xml",
/** 原始数据 */
raw = "raw"
}
/** 查询字符串数组格式化方式 */
export declare enum QueryStringArrayFormat {
/** 示例: `a[]=b&a[]=c` */
'brackets' = "brackets",
/** 示例: `a[0]=b&a[1]=c` */
'indices' = "indices",
/** 示例: `a=b&a=c` */
'repeat' = "repeat",
/** 示例: `a=b,c` */
'comma' = "comma",
/** 示例: `a=["b","c"]` */
'json' = "json"
}
/** 接口定义 */
export interface Interface {
/** 接口 ID */
_id: number;
/** 所属分类信息(由 YTT 自行实现) */
_category: OmitStrict<Category, 'list'>;
/** 所属项目信息(由 YTT 自行实现) */
_project: Project;
/** 接口在 YApi 上的地址(由 YTT 自行实现) */
_url: string;
/** 接口名称 */
title: string;
/** 状态 */
status: LiteralUnion<'done' | 'undone', string>;
/** 接口备注 */
markdown: string;
/** 请求路径 */
path: string;
/** 请求方式,HEAD、OPTIONS 处理与 GET 相似,其余处理与 POST 相似 */
method: Method;
/** 所属项目 id */
project_id: number;
/** 所属分类 id */
catid: number;
/** 标签列表 */
tag: string[];
/** 请求头 */
req_headers: Array<{
/** 名称 */
name: string;
/** 值 */
value: string;
/** 备注 */
desc: string;
/** 示例 */
example: string;
/** 是否必需 */
required: Required;
}>;
/** 路径参数 */
req_params: Array<{
/** 名称 */
name: string;
/** 备注 */
desc: string;
/** 示例 */
example: string;
/** 类型(YApi-X) */
type?: RequestParamType;
}>;
/** 仅 GET:请求串 */
req_query: Array<{
/** 名称 */
name: string;
/** 备注 */
desc: string;
/** 示例 */
example: string;
/** 是否必需 */
required: Required;
/** 类型(YApi-X) */
type?: RequestQueryType;
}>;
/** 仅 POST:请求内容类型。为 text, file, raw 时不必特殊处理。 */
req_body_type: RequestBodyType;
/** `req_body_type = json` 时是否为 json schema */
req_body_is_json_schema: boolean;
/** `req_body_type = form` 时的请求内容 */
req_body_form: Array<{
/** 名称 */
name: string;
/** 类型 */
type: RequestFormItemType;
/** 备注 */
desc: string;
/** 示例 */
example: string;
/** 是否必需 */
required: Required;
}>;
/** `req_body_type = json` 时的请求内容 */
req_body_other: string;
/** 返回数据类型 */
res_body_type: ResponseBodyType;
/** `res_body_type = json` 时是否为 json schema */
res_body_is_json_schema: boolean;
/** 返回数据 */
res_body: string;
/** 创建时间(unix时间戳) */
add_time: number;
/** 更新时间(unix时间戳) */
up_time: number;
/** 创建人 ID */
uid: number;
[key: string]: any;
}
/** 扩展接口定义 */
export interface ExtendedInterface extends Interface {
parsedPath: ParsedPath;
}
/** 接口列表 */
export type InterfaceList = Interface[];
/** 分类信息 */
export interface Category {
/** ID */
_id: number;
/** 分类在 YApi 上的地址(由 YTT 自行实现) */
_url: string;
/** 分类名称 */
name: string;
/** 分类备注 */
desc: string;
/** 分类接口列表 */
list: InterfaceList;
/** 创建时间(unix时间戳) */
add_time: number;
/** 更新时间(unix时间戳) */
up_time: number;
}
/** 分类列表,对应数据导出的 json 内容 */
export type CategoryList = Category[];
/** 项目信息 */
export interface Project {
/** ID */
_id: number;
/** 项目在 YApi 上的地址(由 YTT 自行实现) */
_url: string;
/** 名称 */
name: string;
/** 描述 */
desc: string;
/** 基本路径 */
basepath: string;
/** 标签 */
tag: string[];
/** 环境配置 */
env: Array<{
/** 环境名称 */
name: string;
/** 环境域名 */
domain: string;
}>;
}
/** 支持生成 JSON Schema 的相关配置 */
export interface JsonSchemaConfig {
/**
* 是否开启该项功能。
*/
enabled: boolean;
/**
* 是否生成请求数据的 JSON Schema。
*
* @default true
*/
requestData?: boolean;
/**
* 是否生成返回数据的 JSON Schema。
*
* @default true
*/
responseData?: boolean;
}
/** 支持生成注释的相关配置 */
export interface CommentConfig {
/**
* 是否开启该项功能。
*
* @default true
*/
enabled?: boolean;
/**
* 是否有标题。
*
* @default true
*/
title?: boolean;
/**
* 是否有分类名称。
*
* @default true
*/
category?: boolean;
/**
* 是否有标签。
*
* @default true
*/
tag?: boolean;
/**
* 是否有请求头。
*
* @default true
*/
requestHeader?: boolean;
/**
* 是否有更新时间。
*
* @default true
*/
updateTime?: boolean;
/**
* 是否为标题、分类名称添加链接。
*
* @default true
*/
link?: boolean;
/**
* 额外的注释标签。生成的内容形如:`@{name} {value}`。
*/
extraTags?: (interfaceInfo: ExtendedInterface) => Array<{
/**
* 标签名。
*/
name: string;
/**
* 标签值。
*/
value: string;
/**
* 标签位置,即将新标签插在标签列表的开头还是末尾。
*
* @default 'end'
*/
position?: 'start' | 'end';
}>;
}
/**
* 共享的配置。
*/
export interface SharedConfig {
/**
* 要生成的目标代码类型。
* 默认为 `typescript`,若设为 `javascript`,会将生成的 `.ts` 文件转换为 `.js` + `.d.ts` 文件并删除原 `.ts` 文件。
*
* @default 'typescript'
*/
target?: 'typescript';
/**
* 是否只生成接口请求内容和返回内容的 TypeSript 类型,是则请求文件和请求函数都不会生成。
*
* @default false
*/
typesOnly?: boolean;
/**
* 测试环境名称。
*
* **用于获取测试环境域名。**
*
* 获取方式:打开项目 --> `设置` --> `环境配置` --> 点开或新增测试环境 --> 复制测试环境名称。
*
* @example 'dev'
*/
devEnvName?: string;
/**
* 生产环境名称。
*
* **用于获取生产环境域名。**
*
* 获取方式:打开项目 --> `设置` --> `环境配置` --> 点开或新增生产环境 --> 复制生产环境名称。
*
* @example 'prod'
*/
prodEnvName?: string;
/**
* 输出文件路径。
*
* 可以是 `相对路径` 或 `绝对路径`。
*
* @example 'src/api/index.ts'
*/
outputFilePath?: string | ((interfaceInfo: Interface, changeCase: ChangeCase) => string);
/**
* 如果接口响应的结果是 `JSON` 对象,
* 且我们想要的数据在该对象下,
* 那我们就可将 `dataKey` 设为我们想要的数据对应的键。
*
* 比如该对象为 `{ code: 0, msg: '成功', data: 100 }`,
* 我们想要的数据为 `100`,
* 则我们可将 `dataKey` 设为 `data`。
*
* @example 'data'
*/
dataKey?: OneOrMore<string>;
/**
* 支持生成 JSON Schema 的相关配置。
*/
jsonSchema?: JsonSchemaConfig;
/**
* 支持生成注释的相关配置。
*/
comment?: CommentConfig;
/**
* 将自定义类型转为 JSONSchema 类型的映射表,自定义类型名称大小写不敏感。
*/
customTypeMapping?: Record<string, JSONSchema4TypeName>;
/**
* 如何格式化查询字符串中的数组值。
*
* @default QueryStringArrayFormat.brackets
*/
queryStringArrayFormat?: QueryStringArrayFormat;
/**
* 设置传给请求函数的参数中的 extraInfo 的值。
*
* @param interfaceInfo 接口信息
* @param changeCase 常用的大小写转换函数集合对象
* @returns 返回要赋给 extraInfo 的值
*/
setRequestFunctionExtraInfo?(interfaceInfo: Interface, changeCase: ChangeCase): Record<string, any>;
/**
* 预处理接口信息,返回新的接口信息。可返回 false 排除当前接口。
*
* 譬如你想对接口的 `path` 进行某些处理或者想排除某些接口,就可使用该方法。
*
* @param interfaceInfo 接口信息
* @param changeCase 常用的大小写转换函数集合对象
* @param syntheticalConfig 作用到当前接口的最终配置
* @example
*
* ```js
* interfaceInfo => {
* interfaceInfo.path = interfaceInfo.path.replace('v1', 'v2')
* return interfaceInfo
* }
* ```
*/
preproccessInterface?(interfaceInfo: Interface, changeCase: ChangeCase, syntheticalConfig: SyntheticalConfig): Interface | false;
/**
* 获取请求数据类型的名称。
*
* @default changeCase.pascalCase(`${requestFunctionName}Request`)
* @param interfaceInfo 接口信息
* @param changeCase 常用的大小写转换函数集合对象
* @returns 请求数据类型的名称
*/
getRequestDataTypeName?(interfaceInfo: ExtendedInterface, changeCase: ChangeCase): string;
/**
* 获取响应数据类型的名称。
*
* @default changeCase.pascalCase(`${requestFunctionName}Response`)
* @param interfaceInfo 接口信息
* @param changeCase 常用的大小写转换函数集合对象
* @returns 响应数据类型的名称
*/
getResponseDataTypeName?(interfaceInfo: ExtendedInterface, changeCase: ChangeCase): string;
}
/**
* 分类的配置。
*/
export interface CategoryConfig extends SharedConfig {
/**
* 分类 ID,可以设置多个。设为 `0` 时表示全部分类。
*
* 如果需要获取全部分类,同时排除指定分类,可以这样:`[0, -20, -21]`,分类 ID 前面的负号表示排除。
*
* 获取方式:打开项目 --> 点开分类 --> 复制浏览器地址栏 `/api/cat_` 后面的数字。
*
* @example 20
*/
id: number | number[];
}
/**
* 项目的配置。
*/
export interface ProjectConfig extends SharedConfig {
/**
* 项目的唯一标识。支持多个项目。
*
* 获取方式:打开项目 --> `设置` --> `token配置` --> 复制 token。
*
* @example 'e02a47122259d0c1973a9ff81cabb30685d64abc72f39edaa1ac6b6a792a647d'
*/
token: string | string[];
/**
* 分类列表。
*/
categories: CategoryConfig[];
}
/**
* 服务器的配置。
*/
export interface ServerConfig extends SharedConfig {
/**
* 服务地址。若服务类型为 `yapi`,此处填其首页地址
*
* @example 'http://yapi.foo.bar'
*/
serverUrl: string;
/**
* 服务类型。
*
* @default 'yapi'
*/
serverType?: 'yapi';
/**
* 项目列表。
*/
projects: ProjectConfig[];
}
/** 混合的配置。 */
export type SyntheticalConfig = Partial<ServerConfig & ServerConfig['projects'][0] & ServerConfig['projects'][0]['categories'][0] & {
mockUrl: string;
devUrl: string;
prodUrl: string;
}>;
/** 配置。 */
export type Config = ServerConfig | ServerConfig[];
/**
* 请求配置。
*/
export interface RequestConfig<MockUrl extends string = string, DevUrl extends string = string, ProdUrl extends string = string, Path extends string = string, DataKey extends OneOrMore<string> | undefined = OneOrMore<string> | undefined, ParamName extends string = string, QueryName extends string = string, RequestDataOptional extends boolean = boolean> {
/** 接口 Mock 地址,结尾无 `/` */
mockUrl: MockUrl;
/** 接口测试环境地址,结尾无 `/` */
devUrl: DevUrl;
/** 接口生产环境地址,结尾无 `/` */
prodUrl: ProdUrl;
/** 接口路径,以 `/` 开头 */
path: Path;
/** 请求方法 */
method: Method;
/** 请求头,除了 Content-Type 的所有头 */
requestHeaders: Record<string, string>;
/** 请求数据类型 */
requestBodyType: RequestBodyType;
/** 返回数据类型 */
responseBodyType: ResponseBodyType;
/** 数据所在键 */
dataKey: DataKey;
/** 路径参数的名称列表 */
paramNames: ParamName[];
/** 查询参数的名称列表 */
queryNames: QueryName[];
/** 请求数据是否可选 */
requestDataOptional: RequestDataOptional;
/** 请求数据的 JSON Schema (仅开启了 JSON Schema 生成时生效) */
requestDataJsonSchema: JSONSchema4;
/** 返回数据的 JSON Schema (仅开启了 JSON Schema 生成时生效) */
responseDataJsonSchema: JSONSchema4;
/** 请求函数名称 */
requestFunctionName: string;
/** 如何格式化查询字符串中的数组值 */
queryStringArrayFormat: QueryStringArrayFormat;
/** 额外信息 */
extraInfo: Record<string, any>;
}
/**
* 请求参数。
*/
export interface RequestFunctionParams extends RequestConfig {
/** 原始数据 */
rawData: Record<string, any>;
/** 请求数据,不含文件数据 */
data: Record<string, any>;
/** 是否有文件数据 */
hasFileData: boolean;
/** 请求文件数据 */
fileData: Record<string, any>;
/** 所有请求数据,包括 data、fileData */
allData: Record<string, any>;
/** 获取全部请求数据(包含文件)的 FormData 实例 */
getFormData: () => FormData;
}
/** 请求函数的额外参数 */
export type RequestFunctionRestArgs<T extends Function> = T extends (payload: any, ...args: infer R) => any ? R : never;
/** 属性定义 */
export interface PropDefinition {
/** 属性名称 */
name: string;
/** 是否必需 */
required: boolean;
/** 类型 */
type: JSONSchema4['type'];
/** 注释 */
comment: string;
}
/** 属性定义列表 */
export type PropDefinitions = PropDefinition[];
/** 命令行钩子 */
export interface CliHooks {
/** 生成成功时触发 */
success?: () => AsyncOrSync<void>;
/** 生成失败时触发 */
fail?: () => AsyncOrSync<void>;
/** 生成完毕时触发(无论成功、失败) */
complete?: () => AsyncOrSync<void>;
}
export type ConfigWithHooks = Config & {
hooks?: CliHooks;
};