# nswag-ts-vscode **Repository Path**: money-code/nswag-ts-vscode ## Basic Information - **Project Name**: nswag-ts-vscode - **Description**: 通过swagger.json 生成 typescript 接口调用代码 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-12-08 - **Last Updated**: 2026-04-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # nswag-ts [![Version](https://img.shields.io/badge/version-0.1.6-blue.svg)](https://marketplace.visualstudio.com/items?itemName=hezechang.nswag-ts) [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE.md) ## 📖 介绍 **nswag-ts** 是一个强大的 VS Code 扩展,能够根据 Swagger/OpenAPI 文档自动生成 TypeScript 客户端调用代码。它支持自定义模板、代码格式化、Mock 数据生成等功能,让前端开发更加高效。 ## ✨ 主要特性 - 🚀 **一键生成**:根据 Swagger 文档自动生成 TypeScript 接口代码 - 🎨 **模板定制**:支持自定义 EJS 模板,满足不同项目需求 - 📝 **代码格式化**:集成 Prettier,自动格式化生成的代码 - 🎭 **Mock 数据**:自动生成模拟数据,支持自定义格式化规则 - 🔧 **灵活配置**:支持多 API 配置,可自定义命名规则 - 📊 **进度显示**:实时显示代码生成进度,支持取消操作 - 📋 **日志记录**:详细的日志记录,便于调试和问题排查 - 🔌 **MCP 支持**:内置 MCP 服务,可在 VS Code Agent / Cursor 等对话中通过工具完成初始化与代码生成 ## 🛠️ 安装 1. 在 VS Code 中打开扩展面板 (`Ctrl+Shift+X` 或 `Cmd+Shift+X`) 2. 搜索 `nswag-ts` 3. 点击安装 或者直接从 [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=hezechang.nswag-ts) 安装。 ## 🚀 快速开始 ### 第一步:初始化模板 1. 在项目根目录右键 2. 选择 `nswag-ts.init 初始化模板` 3. 等待模板文件复制完成 这将自动创建 `nswag` 文件夹,包含配置文件和代码模板。 ### 第二步:配置 API 编辑项目根目录下的 `nswag.js` 文件: ```javascript module.exports = { Name: 'nswag-ts', Description: '根据swagger文档生成typescript客户端调用代码', Apis: [ { SwaggerUrl: 'https://your-api.com/swagger.json', // 接口文档地址(必填) ApiBase: 'https://your-api.com/api', // 接口根节点(必填) ApiName: 'UserService', // 接口名称(必填) OutPath: 'src/api', // 输出目录(可选,默认:src/api/{ApiName}) TplPath: 'nswag/template', // 模板路径(可选,默认:内部默认模板) Mock: true, // 是否启用模拟数据(可选,默认:false) Int64ToString: true // 是否将int64类型转换为string类型,避免导致前端精度丢失(可选,默认:true) } ], prettier: { parser: 'babel-ts', singleQuote: true, printWidth: 180, tabWidth: 2, semi: false, trailingComma: 'none' } } ``` ### 第三步:生成代码 1. 选中 `nswag.js` 配置文件 2. 右键选择 `nswag-ts.run 生成代码` 3. 等待代码生成完成 ## 🔌 MCP(AI 对话 / Agent 调用) 扩展内置 **Model Context Protocol (MCP)** 子进程(`dist/mcp-server.js`),将「初始化模板」「按 `nswag.js` 生成代码」暴露为工具,供支持 MCP 的 AI 客户端在对话中调用。 ### 使用前提 1. 已安装本扩展,且扩展能正常完成「快速开始」中的右键命令(用于确认环境与模板无误)。 2. 在所用编辑器中 **启用 MCP**,并在 **工具列表 / 工具选择器** 中允许 **nswag-ts** 相关工具(不同产品菜单位置略有差异)。 3. 使用 **支持工具调用的对话模式**(例如 VS Code 的 Copilot **Agent** 等);纯聊天模式可能不会触发 MCP。 ### VS Code - **推荐**使用 **VS Code 1.110 及以上**,以便使用官方的 `registerMcpServerDefinitionProvider`,由扩展向编辑器注册 MCP 定义。 - 若当前内核版本较低、不包含该 API,扩展会 **自动跳过** 该项注册(不影响右键菜单与命令;可改用 Cursor 的自动注册,或见下文「Cursor」中的手动 stdio 示例)。 - 安装扩展后,在 MCP 相关设置中找到 **nswag-ts**,按需启用;对话中说明意图并给出 **`nswag.js` 或项目根的绝对路径**,便于模型传入工具参数。 ### Cursor - 扩展激活时会尝试通过 **`vscode.cursor.mcp.registerServer`** 注册本扩展自带的 stdio MCP(一般无需再编辑 `mcp.json`,具体以当前 Cursor 版本为准)。 - 若列表中未出现,可在 Cursor 的 MCP 配置中 **手动添加 stdio**,示例如下(路径请改为你本机扩展安装目录): ```json { "mcpServers": { "nswag-ts": { "command": "node", "args": ["/绝对路径/到/扩展目录/dist/mcp-server.js"], "env": { "NSWAG_TS_EXTENSION_PATH": "/绝对路径/到/扩展目录" } } } } ``` 也可将 `command` 设为当前环境 Node 可执行文件路径,与扩展内注册方式一致。 ### 手动配置(通用方案) 当客户端未自动发现此 MCP 服务,或你想在其他支持 MCP 的客户端里复用时,可以手动配置一个 **stdio** 服务。 #### 1) 先找到扩展安装目录 扩展目录即 `package.json` 所在目录,通常类似: - macOS/Linux(VS Code):`<用户目录>/.vscode/extensions/hezechang.nswag-ts-vscode-0.1.6` - Windows(VS Code):`<用户目录>\\.vscode\\extensions\\hezechang.nswag-ts-vscode-0.1.6` 需要用到两个路径: - `mcp-server.js`:`<扩展目录>/dist/mcp-server.js` - `NSWAG_TS_EXTENSION_PATH`:`<扩展目录>` #### 2) 配置示例(通用 JSON) ```json { "mcpServers": { "nswag-ts": { "command": "node", "args": [ "<用户目录>/.vscode/extensions/hezechang.nswag-ts-vscode-0.1.6/dist/mcp-server.js" ], "env": { "NSWAG_TS_EXTENSION_PATH": "<用户目录>/.vscode/extensions/hezechang.nswag-ts-vscode-0.1.6" } } } } ``` > 如果你的客户端支持 `${workspaceFolder}` 等变量,可按其文档改写;否则建议直接写绝对路径。 #### 3) 快速验证 1. 重启客户端或刷新 MCP 服务列表。 2. 在 MCP/Tools 列表中确认出现 `nswag-ts`。 3. 在对话里尝试调用: - `nswag_ts_init`:`targetFolder` 传项目根绝对路径 - `nswag_ts_run`:`nswagJsPath` 传 `nswag.js` 绝对路径 ### MCP 工具一览 | 工具名 | 作用 | 参数 | | ------ | ---- | ---- | | `nswag_ts_run` | 读取 `nswag.js`(`module.exports`),按其中 `Apis` 拉取 Swagger/OpenAPI 并生成 TypeScript 客户端代码 | **`nswagJsPath`**:`nswag.js` 的 **绝对路径** | | `nswag_ts_init` | 将扩展内置 `nswag` 模板复制到目标项目下的 `nswag/` 目录 | **`targetFolder`**:项目根目录的 **绝对路径** | > 生成与复制均会 **写入磁盘**;部分客户端会对工具调用做确认提示。 ### 在提示词里怎么写 模型根据工具 **名称 / 描述** 与你的 **自然语言** 决定是否调用,可参考: - 「请根据 `/你的项目/nswag.js` 生成 TypeScript 接口代码」(倾向触发 `nswag_ts_run`)。 - 「请在 `/你的项目根目录` 初始化 nswag 模板」(倾向触发 `nswag_ts_init`)。 - 直接写出工具名与路径,例如:「调用 **nswag_ts_run**,`nswagJsPath` 为 `/xxx/nswag.js`」。 路径请务必使用 **绝对路径**,与工具参数约定一致。 ### 故障排除(MCP) - **工具未出现**:检查 MCP 总开关、本扩展是否已启用、是否需要 **Agent / 工具模式**。 - **`NSWAG_TS_EXTENSION_PATH` 未设置**:说明 MCP 进程不是由本扩展拉起;请用扩展自带的注册方式安装,或按上文手动配置 `env`。 - **内核版本与功能差异**:`package.json` 中 `engines.vscode` 声明为较低版本以便在 Cursor 等基于旧内核的分发上安装;VS Code 新特性(如官方 MCP 注册)以实际内核 API 为准。 ## ⚙️ 配置详解 ### API 配置参数 | 参数 | 类型 | 必填 | 默认值 | 说明 | | ---------------------- | -------- | ---- | ------------------- | -------------------------------------------- | | `SwaggerUrl` | string | ✅ | - | Swagger 文档地址 | | `ApiBase` | string | ✅ | - | API 基础地址 | | `ApiName` | string | ✅ | - | API 服务名称 | | `OutPath` | string | ❌ | `src/api/{ApiName}` | 代码输出目录 | | `TplPath` | string | ❌ | 内部默认模板 | 自定义模板路径 | | `Mock` | boolean | ❌ | `false` | 是否生成 Mock 数据 | | `Int64ToString` | boolean | ❌ | `true` | 是否将 int64 类型转换为 string,避免精度丢失 | | `FormatControllerName` | Function | ❌ | 接口名称+Api | 格式化模块/控制器名称 | | `FormatMethodName` | Function | ❌ | 小驼峰命名 | 格式化接口方法名称 | | `FormatModelName` | Function | ❌ | 去除特殊字符 | 格式化数据模型/枚举名称 | | `FormatMock` | Function | ❌ | 默认格式化规则 | 自定义 Mock 数据格式化函数 | ### 代码格式化配置 支持 Prettier 的所有配置选项,参考 [Prettier 官方文档](https://prettier.io/docs/en/options): ```javascript prettier: { parser: 'babel-ts', // 解析器 singleQuote: true, // 使用单引号 printWidth: 180, // 行宽 tabWidth: 2, // 缩进 semi: false, // 不使用分号 trailingComma: 'none' // 尾随逗号 } ``` ## 🎨 模板定制 ### 模板文件说明 - **`base.ejs.t`** - 接口调用基类模板,默认使用 axios - **`method.ejs.t`** - 接口函数生成模板 - **`model.ejs.t`** - 数据模型生成模板 - **`mock.ejs.t`** - Mock 数据调用模板 - **`mock-method.ejs.t`** - Mock 数据接口模板 ### 模板辅助函数 在模板中可以使用以下辅助函数: ```javascript // 1. 格式化参数对象,获取指定类型的参数 this.getParameter(参数对象, ['query', 'body'], callback) // 2. 获取指定控制器依赖的模块 this.getTagModels(tag) // 3. 格式化返回对象 this.getResponses(m.responses) // 4. 获取全部类型和枚举对象 this.getModelsAndEnums() // 5. 根据返回对象,生成Mock数据 this.mock(responses, data.Models) // 6. 获取全部控制器,swagger里面对应tag标签 this.getTags() ``` ### 自定义格式化函数 支持自定义命名和格式化规则,所有格式化函数都是可选的,不设置则使用默认规则。 #### FormatControllerName - 格式化模块/控制器名称 用于格式化生成的 API 控制器类名,对应 Swagger 中的 `tag` 标签。 **函数签名:** ```typescript FormatControllerName: (name: string) => string ``` **参数说明:** - `name`: Swagger 中的 tag 名称(如:`User`、`Order`) **返回值:** - 格式化后的控制器名称(如:`UserApi`、`OrderApi`) **默认行为:** - 如果名称已包含 `Api`,则直接返回;否则在名称后添加 `Api` **使用示例:** ```javascript { // 示例1:默认行为(接口名称+Api) FormatControllerName: (name) => { return name.indexOf('Api') !== -1 ? name : name + 'Api' }, // 示例2:统一添加 Service 后缀 FormatControllerName: (name) => { return name + 'Service' }, // 示例3:转换为大驼峰命名并添加 Controller FormatControllerName: (name) => { const formatted = name.charAt(0).toUpperCase() + name.slice(1) return formatted + 'Controller' } } ``` #### FormatMethodName - 格式化接口方法名称 用于格式化生成的 API 方法名,对应 Swagger 中的接口路径。 **函数签名:** ```typescript FormatMethodName: (url: string) => string ``` **参数说明:** - `url`: Swagger 中的接口路径(如:`/api/user/list`、`/api/order/{id}`) **返回值:** - 格式化后的方法名称(如:`getUserList`、`getOrderById`) **默认行为:** - 提取路径最后一段,转换为小驼峰命名(如:`/api/user/list` → `list`) **使用示例:** ```javascript { // 示例1:默认行为(小驼峰命名) FormatMethodName: (name) => { if (name === '/' || name === '') return '' const fnName = name.substring(name.lastIndexOf('/')) return _.camelCase(fnName) }, // 示例2:根据 HTTP 方法添加前缀 FormatMethodName: (name, method) => { const prefix = method === 'get' ? 'get' : method === 'post' ? 'create' : 'update' const fnName = name.substring(name.lastIndexOf('/')) return prefix + _.upperFirst(_.camelCase(fnName)) }, // 示例3:完整路径转换为方法名 FormatMethodName: (name) => { return _.camelCase(name.replace(/^\/api\//, '').replace(/\//g, '_')) } } ``` #### FormatModelName - 格式化数据模型/枚举名称 用于格式化生成的 TypeScript 类型/接口名称,对应 Swagger 中的 `definitions` 或 `components.schemas`。 **函数签名:** ```typescript FormatModelName: (ref: string) => string ``` **参数说明:** - `ref`: Swagger 中的类型引用路径(如:`#/definitions/UserDto`、`#/components/schemas/OrderInfo`) **返回值:** - 格式化后的类型名称(如:`UserDto`、`OrderInfo`) **默认行为:** - 提取路径最后一段,去除所有非字母数字字符 **使用示例:** ```javascript { // 示例1:默认行为(去除特殊字符) FormatModelName: (name) => { return name.substring(name.lastIndexOf('/') + 1).replace(/[^\w]/g, '') }, // 示例2:去除特殊字符并转换为大驼峰 FormatModelName: (name) => { const baseName = name.substring(name.lastIndexOf('/') + 1) const cleaned = baseName.replace(/[^\w]/g, '') return cleaned.charAt(0).toUpperCase() + cleaned.slice(1) }, // 示例3:统一添加 Model 后缀 FormatModelName: (name) => { const baseName = name.substring(name.lastIndexOf('/') + 1).replace(/[^\w]/g, '') return baseName + 'Model' } } ``` #### FormatMock - 自定义 Mock 数据格式化 用于自定义生成的 Mock 数据格式,支持 Mock.js 语法。 **函数签名:** ```typescript FormatMock: (val: any, property: Propertie, mock: any) => any ``` **参数说明:** - `val`: 默认格式化后的值(Mock.js 表达式) - `property`: 属性对象,包含 `name`、`type`、`description`、`format`、`required` 等 - `mock`: 当前正在构建的 Mock 数据对象 **返回值:** - 更新后的 Mock 数据对象 **默认行为:** - 根据属性类型和名称生成相应的 Mock.js 表达式 **使用示例:** ```javascript { // 示例1:根据属性名称自定义 Mock 数据 FormatMock: (val, property, mock) => { switch (property.type) { case 'string': switch (property.name) { case 'name': val = '@cname' // 中文姓名 break case 'email': val = '@email' // 邮箱 break case 'mobile': val = '@natural(10000000000, 19999999999)' // 手机号 break case 'address': val = '@county(true)' // 地址 break case 'idCard': val = '@id' // 身份证号 break default: val = '@ctitle(10, 20)' // 默认中文标题 break } break case 'number': switch (property.name) { case 'result_code': val = 0 // 成功状态码 break case 'page_index': val = 1 // 页码 break case 'page_size': val = 15 // 每页数量 break case 'total_count': val = 30 // 总数 break default: val = '@integer(0, 100)' // 默认整数 break } break case 'boolean': val = '@boolean' // 布尔值 break case 'array': // 数组类型,生成指定数量的元素 mock[property.name + '|20'] = val break } mock[property.name] = val return mock }, // 示例2:根据属性描述自定义 FormatMock: (val, property, mock) => { if (property.description) { if (property.description.includes('时间') || property.description.includes('日期')) { val = '@datetime("yyyy-MM-dd HH:mm:ss")' } else if (property.description.includes('图片') || property.description.includes('头像')) { val = '@image("200x200", "#50a3ff", "#fff", "avatar")' } else if (property.description.includes('URL') || property.description.includes('链接')) { val = '@url("http")' } } mock[property.name] = val return mock } } ``` **完整配置示例:** ```javascript module.exports = { Name: 'nswag-ts', Description: '根据swagger文档生成typescript客户端调用代码', Apis: [ { SwaggerUrl: 'https://your-api.com/swagger.json', ApiBase: 'https://your-api.com/api', ApiName: 'UserService', OutPath: 'src/api', TplPath: 'nswag/template', Mock: true, Int64ToString: true, // 自定义格式化函数 FormatControllerName: name => name + 'Api', FormatMethodName: name => { if (name === '/' || name === '') return '' const fnName = name.substring(name.lastIndexOf('/')) return _.camelCase(fnName) }, FormatModelName: name => { return name.substring(name.lastIndexOf('/') + 1).replace(/[^\w]/g, '') }, FormatMock: (val, property, mock) => { // 自定义 Mock 数据格式化逻辑 if (property.type === 'string' && property.name === 'name') { val = '@cname' } mock[property.name] = val return mock } } ], prettier: { parser: 'babel-ts', singleQuote: true, printWidth: 180, tabWidth: 2, semi: false, trailingComma: 'none' } } ``` ## 📁 项目结构 ``` your-project/ ├── nswag/ # 配置和模板目录 │ ├── nswag.js # 配置文件 │ └── template/ # 代码模板 │ ├── base.ejs.t # 基类模板 │ ├── method.ejs.t # 方法模板 │ ├── model.ejs.t # 模型模板 │ ├── mock.ejs.t # Mock模板 │ └── mock-method.ejs.t # Mock方法模板 ├── src/ │ └── api/ # 生成的API代码 │ └── UserService/ # 按API名称分类 └── package.json ``` ## 🔧 高级用法 ### 多 API 配置 支持同时配置多个 API 服务: ```javascript Apis: [ { SwaggerUrl: 'https://user-api.com/swagger.json', ApiBase: 'https://user-api.com/api', ApiName: 'UserService', OutPath: 'src/api/user' }, { SwaggerUrl: 'https://order-api.com/swagger.json', ApiBase: 'https://order-api.com/api', ApiName: 'OrderService', OutPath: 'src/api/order' } ] ``` ### 条件生成 在模板中使用条件判断: ```ejs <% if (this.hasProperty(model, 'required')) { %> required: true, <% } %> ``` ### 自定义类型映射 ```javascript // 在模板中处理特殊类型 <% if (property.type === 'integer' && property.format === 'int64') { %> type: 'string' // 将 long 类型转换为 string <% } else { %> type: '<%= property.type %>' <% } %> ``` ## 🐛 故障排除 ### 常见问题 1. **模板初始化失败** - 确保在项目根目录执行初始化 - 检查 VS Code 权限设置 2. **代码生成失败** - 验证 Swagger 文档地址是否可访问 - 检查配置文件格式是否正确 - 查看输出面板的详细错误信息 3. **生成的代码格式不正确** - 检查 Prettier 配置 - 确保项目已安装 Prettier 依赖 ### 日志查看 生成的代码会显示在 VS Code 的输出面板中,选择 "nswag-ts" 输出源查看详细日志。 ## 🤝 贡献 欢迎提交 Issue 和 Pull Request! - 项目地址:[https://gitee.com/money-code/nswag-ts-vscode](https://gitee.com/money-code/nswag-ts-vscode) - 问题反馈:[Issues](https://gitee.com/money-code/nswag-ts-vscode/issues) ## 📄 许可证 本项目采用 [MIT](LICENSE.md) 许可证。 ## 💭 作者感言 大家好,我是何泽长,开发这个插件的初衷,源于我在日常前端开发中遇到的痛点。每次对接后端 API 时,都需要手动编写大量的 TypeScript 接口代码,这个过程既繁琐又容易出错。特别是在处理 Swagger 文档时,重复性的工作让我意识到,应该有一个工具来自动化这个过程。 **nswag-ts** 从想法到实现,经历了多次迭代和优化。我希望通过这个工具,能够帮助更多的开发者提高开发效率,减少重复劳动,让大家有更多时间专注于业务逻辑的实现。 这个项目是开源的,我欢迎所有开发者提出建议、反馈问题,或者贡献代码。每一个 Issue、每一个 Star、每一次使用,都是对我最大的支持和鼓励。 如果这个插件能够帮助到您,让您的前端开发变得更加高效和愉悦,那就是我最大的收获! 感谢所有使用和支持 **nswag-ts** 的开发者们!🙏