vite-plugin-swagger-typescript-api-transform 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,687 @@
1
+ import { ensureDir, findYamlDirectories, findYamlFiles, formatModuleName } from "./utils-DGqLkcWK.js";
2
+ import { createUnplugin } from "unplugin";
3
+ import path from "node:path";
4
+ import process from "node:process";
5
+ import fs from "node:fs";
6
+ import { generateApi } from "swagger-typescript-api";
7
+
8
+ //#region src/core/constants.ts
9
+ const PLUGIN_NAME = "swagger-typescript-api";
10
+ const DEFAULT_OPTIONS = {
11
+ outputDir: "src/api",
12
+ generateClient: true,
13
+ httpClient: "fetch",
14
+ watch: true,
15
+ moduleNameFormat: "kebab"
16
+ };
17
+
18
+ //#endregion
19
+ //#region src/core/generator.ts
20
+ /**
21
+ * 根据单个 YAML 文件生成 TypeScript API 代码
22
+ */
23
+ async function generateTypeScriptFromYaml(yamlPath, outputDir, options) {
24
+ const fileName = path.basename(yamlPath, path.extname(yamlPath));
25
+ const moduleName = formatModuleName(fileName, options.moduleNameFormat);
26
+ const apiClassName = options.apiClassName || `${formatModuleName(fileName, "pascal")}Api`;
27
+ const moduleOutputDir = path.join(outputDir, moduleName);
28
+ ensureDir(moduleOutputDir);
29
+ console.log(`[${PLUGIN_NAME}] 正在生成 API: ${fileName} -> ${moduleName}`);
30
+ try {
31
+ const result = await generateApi({
32
+ input: yamlPath,
33
+ httpClientType: options.httpClient,
34
+ generateClient: options.generateClient,
35
+ generateRouteTypes: true,
36
+ generateResponses: true,
37
+ defaultResponseAsSuccess: false,
38
+ toJS: false,
39
+ extractRequestParams: true,
40
+ extractRequestBody: true,
41
+ extractEnums: true,
42
+ singleHttpClient: true,
43
+ modular: false,
44
+ unwrapResponseData: true,
45
+ apiClassName,
46
+ silent: true
47
+ });
48
+ const files = result.files;
49
+ for (const file of files) {
50
+ const fullFileName = `${file.fileName}${file.fileExtension}`;
51
+ const filePath = path.join(moduleOutputDir, fullFileName);
52
+ fs.writeFileSync(filePath, file.fileContent, "utf-8");
53
+ console.log(`[${PLUGIN_NAME}] 生成文件: ${fullFileName}`);
54
+ }
55
+ return {
56
+ moduleName,
57
+ apiClassName
58
+ };
59
+ } catch (error) {
60
+ console.error(`[${PLUGIN_NAME}] 生成 API 失败: ${yamlPath}`);
61
+ console.error(error);
62
+ throw error;
63
+ }
64
+ }
65
+
66
+ //#endregion
67
+ //#region src/generators/example.ts
68
+ /**
69
+ * 为每个模块生成示例文件
70
+ */
71
+ function generateModuleExampleFile(moduleOutputDir, moduleName, apiClassName) {
72
+ const instanceName = moduleName.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
73
+ const exampleContent = `/**
74
+ * ${moduleName} API 使用示例
75
+ * 由 vite-plugin-swagger-typescript-api 自动生成
76
+ *
77
+ * 注意:此文件仅为示例,可以根据实际需求修改或删除
78
+ *
79
+ * @常见问题 - CORS 跨域请求失败
80
+ * 如果在 Network 面板看到 OPTIONS 请求(preflight)失败,这是因为跨域请求被浏览器拦截。
81
+ *
82
+ * 解决方案:使用 Vite 代理(推荐开发环境)
83
+ *
84
+ * 1. 在 vite.config.ts 中配置代理:
85
+ * \`\`\`typescript
86
+ * export default defineConfig({
87
+ * server: {
88
+ * proxy: {
89
+ * '/api': {
90
+ * target: 'https://your-api.example.com', // 替换为实际 API 地址
91
+ * changeOrigin: true,
92
+ * }
93
+ * }
94
+ * }
95
+ * })
96
+ * \`\`\`
97
+ *
98
+ * 2. 将 baseUrl 改为相对路径:
99
+ * \`\`\`typescript
100
+ * const httpClient = new HttpClient({
101
+ * baseUrl: '/api', // 走 Vite 代理,避免跨域
102
+ * baseApiParams: {
103
+ * headers: { Authorization: 'Bearer your-token' },
104
+ * }
105
+ * })
106
+ * \`\`\`
107
+ */
108
+
109
+ import { ${apiClassName}, HttpClient } from '.'
110
+
111
+ // ============================================
112
+ // 示例 1: 使用预配置的 API 实例(推荐)
113
+ // ============================================
114
+ // 从统一入口导入预配置的实例
115
+ import { ${instanceName}Api } from '..'
116
+
117
+ async function example1() {
118
+ try {
119
+ // 直接使用预配置的 API 实例
120
+ // const result = await ${instanceName}Api.xxx.xxxMethod({ ... })
121
+ console.log('使用预配置实例发起请求')
122
+ // return result
123
+ }
124
+ catch (error) {
125
+ console.error('请求失败:', error)
126
+ throw error
127
+ }
128
+ }
129
+
130
+ // ============================================
131
+ // 示例 2: 使用自定义配置的 HTTP 客户端
132
+ // ============================================
133
+
134
+ async function example2() {
135
+ // 创建自定义配置的 HTTP 客户端
136
+ const httpClient = new HttpClient({
137
+ baseUrl: 'https://api.example.com/v1',
138
+ baseApiParams: {
139
+ headers: {
140
+ Authorization: 'Bearer your-token-here',
141
+ },
142
+ },
143
+ })
144
+
145
+ // 使用自定义客户端创建 API 实例
146
+ const api = new ${apiClassName}(httpClient)
147
+
148
+ try {
149
+ // const result = await api.xxx.xxxMethod({ ... })
150
+ console.log('使用自定义配置发起请求')
151
+ // return result
152
+ }
153
+ catch (error) {
154
+ console.error('请求失败:', error)
155
+ throw error
156
+ }
157
+ }
158
+
159
+ // ============================================
160
+ // 示例 3: 带错误处理的请求封装
161
+ // ============================================
162
+
163
+ async function safeRequest<T>(
164
+ request: () => Promise<T>,
165
+ ): Promise<{ data?: T; error?: Error }> {
166
+ try {
167
+ const data = await request()
168
+ return { data }
169
+ }
170
+ catch (error) {
171
+ return { error: error as Error }
172
+ }
173
+ }
174
+
175
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
176
+ async function example3() {
177
+ // 替换 xxx 为实际的 API 分组名称(如 users、products 等)
178
+ // 替换 xxxMethod 为实际的方法名称(如 usersCreate、productsList 等)
179
+ // const { data, error } = await safeRequest(() =>
180
+ // ${instanceName}Api.xxx.xxxMethod({ /* params */ }),
181
+ // )
182
+ const { data, error } = { data: undefined, error: undefined }
183
+
184
+ if (error) {
185
+ console.error('请求失败:', error.message)
186
+ return
187
+ }
188
+
189
+ console.log('请求成功:', data)
190
+ }
191
+
192
+ // ============================================
193
+ // 导出示例函数
194
+ // ============================================
195
+
196
+ export { example1, example2, example3 }
197
+ `;
198
+ const examplePath = path.join(moduleOutputDir, "example.ts");
199
+ fs.writeFileSync(examplePath, exampleContent, "utf-8");
200
+ console.log(`[${PLUGIN_NAME}] 生成示例文件: example.ts`);
201
+ }
202
+
203
+ //#endregion
204
+ //#region src/generators/module-index.ts
205
+ /**
206
+ * 为每个模块生成 index.ts 导出文件
207
+ * 解决命名冲突:将 API 类重命名为 XxxApi,避免与接口类型同名
208
+ * 避免重复导出公共类型(HttpClient 等)
209
+ */
210
+ function generateModuleIndexFile(moduleOutputDir, moduleName, apiClassName, isFirstModule) {
211
+ const apiInstanceName = apiClassName;
212
+ const moduleIndexContent = `/**
213
+ * ${apiClassName} 模块导出
214
+ * 由 vite-plugin-swagger-typescript-api 自动生成
215
+ */
216
+
217
+ // 导出所有类型定义
218
+ export * from './Api'
219
+
220
+ // 重命名导出 API 类,避免与接口类型同名
221
+ export { ${apiClassName} as ${apiInstanceName} } from './Api'
222
+ ${isFirstModule ? `
223
+ // 导出公共类型(只在第一个模块导出)
224
+ // HttpClient 是类,ContentType 是枚举,可以正常导出
225
+ export { HttpClient, ContentType } from './Api'
226
+ // ApiConfig, RequestParams, HttpResponse 是纯类型,使用 export type
227
+ export type { ApiConfig, RequestParams, HttpResponse } from './Api'` : ""}
228
+ `;
229
+ const moduleIndexPath = path.join(moduleOutputDir, "index.ts");
230
+ fs.writeFileSync(moduleIndexPath, moduleIndexContent, "utf-8");
231
+ }
232
+
233
+ //#endregion
234
+ //#region src/generators/entry-index.ts
235
+ /**
236
+ * 生成统一导出的入口文件 index.ts
237
+ */
238
+ function generateIndexFile(outputDir, modules, options) {
239
+ if (modules.length === 0) return;
240
+ const firstModule = modules[0];
241
+ const firstModuleExport = `// ${firstModule.moduleName} API(包含公共类型:HttpClient, ApiConfig 等)
242
+ export * from './${firstModule.moduleName}'`;
243
+ const otherModuleExports = modules.slice(1).map(({ moduleName, apiClassName }) => {
244
+ return `// ${moduleName} API
245
+ export {
246
+ // API 类
247
+ ${apiClassName},
248
+ // 模块特有的类型(接口、枚举、命名空间)
249
+ ${apiClassName} as ${apiClassName}Client,
250
+ } from './${moduleName}'
251
+
252
+ // 导出 ${moduleName} 模块的所有类型(通过命名空间访问)
253
+ export * as ${apiClassName}Types from './${moduleName}'`;
254
+ }).join("\n\n");
255
+ const apiImports = modules.map(({ moduleName, apiClassName }) => {
256
+ return `import { ${apiClassName}, HttpClient as ${apiClassName}HttpClient } from './${moduleName}'`;
257
+ }).join("\n");
258
+ const apiInstances = modules.map(({ moduleName, apiClassName }) => {
259
+ const instanceName = moduleName.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
260
+ return `/** ${moduleName} API 实例(使用默认配置) */
261
+ export const ${instanceName}Api = new ${apiClassName}(new ${apiClassName}HttpClient())`;
262
+ }).join("\n\n");
263
+ const otherExportsSection = otherModuleExports ? `
264
+
265
+ // ============================================
266
+ // 其他模块导出(排除公共类型)
267
+ // ============================================
268
+
269
+ ${otherModuleExports}` : "";
270
+ const indexContent = `/**
271
+ * 自动生成的 API 统一入口文件
272
+ * 由 vite-plugin-swagger-typescript-api 生成
273
+ *
274
+ * 注意:此文件由插件自动生成,请勿手动修改
275
+ *
276
+ * @example 简单使用方式
277
+ * \`\`\`typescript
278
+ * import { productApi, HttpClient } from './api'
279
+ *
280
+ * // 直接使用预配置的 API 实例
281
+ * const products = await productApi.products.productsList({ page: 1, limit: 10 })
282
+ * \`\`\`
283
+ *
284
+ * @example 自定义配置方式
285
+ * \`\`\`typescript
286
+ * import { ProductApi, HttpClient } from './api/product'
287
+ *
288
+ * // 创建自定义配置的 HTTP 客户端
289
+ * const http = new HttpClient({
290
+ * baseUrl: 'https://custom-api.example.com',
291
+ * headers: { Authorization: 'Bearer your-token' }
292
+ * })
293
+ *
294
+ * // 使用自定义客户端创建 API 实例
295
+ * const productApi = new ProductApi(http)
296
+ *
297
+ * // 发起请求
298
+ * const products = await productApi.products.productsList({ page: 1 })
299
+ * \`\`\`
300
+ */
301
+
302
+ ${firstModuleExport}
303
+ ${otherExportsSection}
304
+
305
+ // ============================================
306
+ // 预配置的 API 实例(开箱即用)
307
+ // ============================================
308
+
309
+ ${apiImports}
310
+
311
+ ${apiInstances}
312
+ `;
313
+ const indexPath = path.join(outputDir, "index.ts");
314
+ fs.writeFileSync(indexPath, indexContent, "utf-8");
315
+ console.log(`[${PLUGIN_NAME}] 生成入口文件: index.ts`);
316
+ }
317
+
318
+ //#endregion
319
+ //#region src/generators/request.ts
320
+ /**
321
+ * 生成基于 Fetch 的 HTTP 请求工具函数
322
+ */
323
+ function generateFetchRequestUtil(baseURL) {
324
+ return `/**
325
+ * HTTP 请求工具函数(基于 Fetch)
326
+ * 由 vite-plugin-swagger-typescript-api 生成
327
+ */
328
+
329
+ /** 请求配置选项 */
330
+ interface RequestConfig extends Omit<RequestInit, 'body'> {
331
+ /** 请求参数(查询字符串) */
332
+ params?: Record<string, any>
333
+ /** 请求体数据 */
334
+ body?: any
335
+ /** 请求超时时间(毫秒) */
336
+ timeout?: number
337
+ }
338
+
339
+ /** 响应结果包装 */
340
+ interface ResponseResult<T> {
341
+ data: T
342
+ status: number
343
+ statusText: string
344
+ headers: Headers
345
+ }
346
+
347
+ /** 基础 URL 配置 */
348
+ const BASE_URL = '${baseURL}'
349
+
350
+ /** 默认请求头 */
351
+ const defaultHeaders: HeadersInit = {
352
+ 'Content-Type': 'application/json',
353
+ }
354
+
355
+ /**
356
+ * 获取认证 Token(可自定义实现)
357
+ */
358
+ function getAuthToken(): string | null {
359
+ // 从 localStorage 或其他存储中获取 token
360
+ // return localStorage.getItem('token')
361
+ return null
362
+ }
363
+
364
+ /**
365
+ * 构建查询字符串
366
+ */
367
+ function buildQueryString(params: Record<string, any>): string {
368
+ const searchParams = new URLSearchParams()
369
+ Object.entries(params).forEach(([key, value]) => {
370
+ if (value !== undefined && value !== null) {
371
+ searchParams.append(key, String(value))
372
+ }
373
+ })
374
+ return searchParams.toString()
375
+ }
376
+
377
+ /**
378
+ * 创建带超时的 fetch 请求
379
+ */
380
+ async function fetchWithTimeout(
381
+ url: string,
382
+ config: RequestInit,
383
+ timeout: number = 10000,
384
+ ): Promise<Response> {
385
+ const controller = new AbortController()
386
+ const timeoutId = setTimeout(() => controller.abort(), timeout)
387
+
388
+ try {
389
+ const response = await fetch(url, {
390
+ ...config,
391
+ signal: controller.signal,
392
+ })
393
+ return response
394
+ }
395
+ finally {
396
+ clearTimeout(timeoutId)
397
+ }
398
+ }
399
+
400
+ /**
401
+ * 核心请求方法
402
+ */
403
+ async function request<T>(
404
+ method: string,
405
+ url: string,
406
+ config: RequestConfig = {},
407
+ ): Promise<ResponseResult<T>> {
408
+ const { params, body, timeout = 10000, ...init } = config
409
+
410
+ // 构建完整 URL
411
+ let fullUrl = \`\${BASE_URL}\${url}\`
412
+ if (params && Object.keys(params).length > 0) {
413
+ fullUrl += \`?\${buildQueryString(params)}\`
414
+ }
415
+
416
+ // 设置请求头
417
+ const headers: HeadersInit = {
418
+ ...defaultHeaders,
419
+ ...init.headers,
420
+ }
421
+
422
+ // 添加认证 Token
423
+ const token = getAuthToken()
424
+ if (token) {
425
+ (headers as Record<string, string>)['Authorization'] = \`Bearer \${token}\`
426
+ }
427
+
428
+ // 发送请求
429
+ const response = await fetchWithTimeout(
430
+ fullUrl,
431
+ {
432
+ ...init,
433
+ method,
434
+ headers,
435
+ body: body ? JSON.stringify(body) : undefined,
436
+ },
437
+ timeout,
438
+ )
439
+
440
+ // 处理响应
441
+ if (!response.ok) {
442
+ const errorText = await response.text()
443
+ throw new Error(\`HTTP \${response.status}: \${errorText || response.statusText}\`)
444
+ }
445
+
446
+ // 解析 JSON 响应
447
+ const data = await response.json()
448
+
449
+ return {
450
+ data,
451
+ status: response.status,
452
+ statusText: response.statusText,
453
+ headers: response.headers,
454
+ }
455
+ }
456
+
457
+ /**
458
+ * HTTP 请求工具对象
459
+ */
460
+ export const http = {
461
+ /**
462
+ * GET 请求
463
+ */
464
+ get: <T>(url: string, params?: Record<string, any>, config?: RequestConfig) =>
465
+ request<T>('GET', url, { ...config, params }),
466
+
467
+ /**
468
+ * POST 请求
469
+ */
470
+ post: <T>(url: string, body?: any, config?: RequestConfig) =>
471
+ request<T>('POST', url, { ...config, body }),
472
+
473
+ /**
474
+ * PUT 请求
475
+ */
476
+ put: <T>(url: string, body?: any, config?: RequestConfig) =>
477
+ request<T>('PUT', url, { ...config, body }),
478
+
479
+ /**
480
+ * DELETE 请求
481
+ */
482
+ delete: <T>(url: string, config?: RequestConfig) =>
483
+ request<T>('DELETE', url, config),
484
+
485
+ /**
486
+ * PATCH 请求
487
+ */
488
+ patch: <T>(url: string, body?: any, config?: RequestConfig) =>
489
+ request<T>('PATCH', url, { ...config, body }),
490
+ }
491
+
492
+ /** 默认导出 http 对象 */
493
+ export default http
494
+ `;
495
+ }
496
+ /**
497
+ * 生成基于 Axios 的 HTTP 请求工具函数
498
+ */
499
+ function generateAxiosRequestUtil(baseURL) {
500
+ return `/**
501
+ * HTTP 请求工具函数(基于 Axios)
502
+ * 由 vite-plugin-swagger-typescript-api 生成
503
+ *
504
+ * 注意:需要安装 axios 依赖
505
+ */
506
+
507
+ import axios, { type AxiosInstance, type AxiosRequestConfig } from 'axios'
508
+
509
+ /** 创建 axios 实例 */
510
+ const instance: AxiosInstance = axios.create({
511
+ baseURL: '${baseURL}',
512
+ timeout: 10000,
513
+ headers: {
514
+ 'Content-Type': 'application/json',
515
+ },
516
+ })
517
+
518
+ /** 请求拦截器 */
519
+ instance.interceptors.request.use(
520
+ (config) => {
521
+ // 在这里可以添加 token 等认证信息
522
+ // const token = localStorage.getItem('token')
523
+ // if (token) {
524
+ // config.headers.Authorization = \`Bearer \${token}\`
525
+ // }
526
+ return config
527
+ },
528
+ (error) => {
529
+ return Promise.reject(error)
530
+ },
531
+ )
532
+
533
+ /** 响应拦截器 */
534
+ instance.interceptors.response.use(
535
+ (response) => {
536
+ return response.data
537
+ },
538
+ (error) => {
539
+ // 统一错误处理
540
+ console.error('API Error:', error.message)
541
+ return Promise.reject(error)
542
+ },
543
+ )
544
+
545
+ /**
546
+ * HTTP 请求工具对象
547
+ */
548
+ export const request = {
549
+ get: <T>(url: string, params?: Record<string, any>, config?: AxiosRequestConfig) =>
550
+ instance.get<T>(url, { params, ...config }),
551
+
552
+ post: <T>(url: string, data?: any, config?: AxiosRequestConfig) =>
553
+ instance.post<T>(url, data, config),
554
+
555
+ put: <T>(url: string, data?: any, config?: AxiosRequestConfig) =>
556
+ instance.put<T>(url, data, config),
557
+
558
+ delete: <T>(url: string, config?: AxiosRequestConfig) =>
559
+ instance.delete<T>(url, config),
560
+
561
+ patch: <T>(url: string, data?: any, config?: AxiosRequestConfig) =>
562
+ instance.patch<T>(url, data, config),
563
+ }
564
+
565
+ /** 默认导出 axios 实例 */
566
+ export default instance
567
+
568
+ /** 导出 axios 实例供高级使用 */
569
+ export { instance as axios }
570
+ `;
571
+ }
572
+ /**
573
+ * 生成 HTTP 请求工具函数
574
+ */
575
+ function generateRequestUtil(outputDir, options) {
576
+ if (!options.baseURL) return;
577
+ const requestContent = options.httpClient === "axios" ? generateAxiosRequestUtil(options.baseURL) : generateFetchRequestUtil(options.baseURL);
578
+ const requestPath = path.join(outputDir, "request.ts");
579
+ fs.writeFileSync(requestPath, requestContent, "utf-8");
580
+ console.log(`[${PLUGIN_NAME}] 生成请求工具: request.ts (${options.httpClient})`);
581
+ }
582
+
583
+ //#endregion
584
+ //#region src/core/scanner.ts
585
+ /**
586
+ * 扫描并生成所有 API 代码
587
+ */
588
+ async function scanAndGenerateApis(options, isRebuild = false) {
589
+ const rootDir = options.rootDir || process.cwd();
590
+ const outputDir = path.resolve(rootDir, options.outputDir);
591
+ if (isRebuild) console.log(`\n[${PLUGIN_NAME}] 检测到文件变化,重新生成 API...`);
592
+ else {
593
+ console.log(`\n[${PLUGIN_NAME}] 开始扫描 YAML 文件...`);
594
+ console.log(`[${PLUGIN_NAME}] 项目根目录: ${rootDir}`);
595
+ console.log(`[${PLUGIN_NAME}] 输出目录: ${outputDir}`);
596
+ }
597
+ const yamlDirs = findYamlDirectories(rootDir);
598
+ if (yamlDirs.length === 0) {
599
+ console.log(`[${PLUGIN_NAME}] 未找到名为 "yaml" 的文件夹`);
600
+ return [];
601
+ }
602
+ console.log(`[${PLUGIN_NAME}] 找到 ${yamlDirs.length} 个 yaml 目录:`);
603
+ yamlDirs.forEach((dir) => {
604
+ console.log(`[${PLUGIN_NAME}] - ${path.relative(rootDir, dir)}`);
605
+ });
606
+ const yamlFiles = [];
607
+ for (const dir of yamlDirs) yamlFiles.push(...findYamlFiles(dir));
608
+ if (yamlFiles.length === 0) {
609
+ console.log(`[${PLUGIN_NAME}] 未找到 .yaml 或 .yml 文件`);
610
+ return [];
611
+ }
612
+ console.log(`[${PLUGIN_NAME}] 找到 ${yamlFiles.length} 个 YAML 文件:`);
613
+ yamlFiles.forEach((file) => {
614
+ console.log(`[${PLUGIN_NAME}] - ${path.relative(rootDir, file)}`);
615
+ });
616
+ const { ensureDir: ensureDir$1 } = await import("./utils.js");
617
+ ensureDir$1(outputDir);
618
+ console.log(`\n[${PLUGIN_NAME}] 开始生成 TypeScript API 代码...`);
619
+ const modules = [];
620
+ for (const yamlFile of yamlFiles) try {
621
+ const moduleResult = await generateTypeScriptFromYaml(yamlFile, outputDir, options);
622
+ modules.push(moduleResult);
623
+ } catch (error) {
624
+ console.error(`[${PLUGIN_NAME}] 跳过文件: ${yamlFile}`);
625
+ }
626
+ modules.forEach(({ moduleName, apiClassName }, index) => {
627
+ const moduleOutputDir = path.join(outputDir, moduleName);
628
+ generateModuleIndexFile(moduleOutputDir, moduleName, apiClassName, index === 0);
629
+ generateModuleExampleFile(moduleOutputDir, moduleName, apiClassName);
630
+ });
631
+ if (modules.length > 0) {
632
+ generateIndexFile(outputDir, modules, options);
633
+ generateRequestUtil(outputDir, options);
634
+ }
635
+ console.log(`\n[${PLUGIN_NAME}] ✅ 成功生成 ${modules.length} 个 API 模块\n`);
636
+ return modules.map((m) => m.moduleName);
637
+ }
638
+
639
+ //#endregion
640
+ //#region src/core/plugin.ts
641
+ /**
642
+ * 插件工厂函数
643
+ */
644
+ const unpluginFactory = (options = {}) => {
645
+ const mergedOptions = {
646
+ ...DEFAULT_OPTIONS,
647
+ ...options
648
+ };
649
+ let hasGenerated = false;
650
+ return {
651
+ name: PLUGIN_NAME,
652
+ vite: {
653
+ configResolved() {
654
+ if (!hasGenerated) {
655
+ hasGenerated = true;
656
+ scanAndGenerateApis(mergedOptions);
657
+ }
658
+ },
659
+ configureServer(server) {
660
+ if (mergedOptions.watch) server.watcher.on("change", (file) => {
661
+ if (file.endsWith(".yaml") || file.endsWith(".yml")) {
662
+ hasGenerated = false;
663
+ scanAndGenerateApis(mergedOptions, true);
664
+ }
665
+ });
666
+ }
667
+ },
668
+ async buildStart() {
669
+ if (!hasGenerated) {
670
+ hasGenerated = true;
671
+ await scanAndGenerateApis(mergedOptions);
672
+ }
673
+ },
674
+ webpack(compiler) {
675
+ compiler.hooks.beforeRun.tapPromise(PLUGIN_NAME, async () => {
676
+ if (!hasGenerated) {
677
+ hasGenerated = true;
678
+ await scanAndGenerateApis(mergedOptions);
679
+ }
680
+ });
681
+ }
682
+ };
683
+ };
684
+ const unplugin = /* @__PURE__ */ createUnplugin(unpluginFactory);
685
+
686
+ //#endregion
687
+ export { DEFAULT_OPTIONS, PLUGIN_NAME, unplugin, unpluginFactory };
package/dist/types.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { HttpClientType, MergedOptions, Options } from "./types-CpgPraRT.js";
1
+ import { HttpClientType, MergedOptions, Options } from "./types-BJUz_-Xc.js";
2
2
  export { HttpClientType, MergedOptions, Options };
package/dist/utils.js CHANGED
@@ -1,3 +1,3 @@
1
- import { ensureDir, fileExists, findYamlDirectories, findYamlFiles, formatModuleName, getRelativePath, safeReaddir } from "./utils-BypLbD1p.js";
1
+ import { ensureDir, fileExists, findYamlDirectories, findYamlFiles, formatModuleName, getRelativePath, safeReaddir } from "./utils-DGqLkcWK.js";
2
2
 
3
3
  export { ensureDir, fileExists, findYamlDirectories, findYamlFiles, formatModuleName, getRelativePath, safeReaddir };
@@ -1,4 +1,4 @@
1
- import { unpluginFactory } from "./src-DPpaOQvV.js";
1
+ import { unpluginFactory } from "./src-Cs3STwE3.js";
2
2
  import { createVitePlugin } from "unplugin";
3
3
 
4
4
  //#region src/vite.ts
package/dist/vite.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { Options } from "./types-CpgPraRT.js";
2
- import * as vite8 from "vite";
1
+ import { Options } from "./types-BJUz_-Xc.js";
2
+ import * as vite3 from "vite";
3
3
 
4
4
  //#region src/vite.d.ts
5
- declare const _default: (options?: Options | undefined) => vite8.Plugin<any> | vite8.Plugin<any>[];
5
+ declare const _default: (options?: Options | undefined) => vite3.Plugin<any> | vite3.Plugin<any>[];
6
6
 
7
7
  //#endregion
8
8
  export { _default as default };