@ahoo-wang/fetcher-generator 2.1.1 → 2.2.0

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,406 @@
1
+ # @ahoo-wang/fetcher-generator
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@ahoo-wang/fetcher-generator.svg)](https://www.npmjs.com/package/@ahoo-wang/fetcher-generator)
4
+ [![Build Status](https://github.com/Ahoo-Wang/fetcher/actions/workflows/ci.yml/badge.svg)](https://github.com/Ahoo-Wang/fetcher/actions)
5
+ [![codecov](https://codecov.io/gh/Ahoo-Wang/fetcher/graph/badge.svg?token=JGiWZ52CvJ)](https://codecov.io/gh/Ahoo-Wang/fetcher)
6
+ [![License](https://img.shields.io/npm/l/@ahoo-wang/fetcher-generator.svg)](https://github.com/Ahoo-Wang/fetcher/blob/main/LICENSE)
7
+ [![npm downloads](https://img.shields.io/npm/dm/@ahoo-wang/fetcher-generator.svg)](https://www.npmjs.com/package/@ahoo-wang/fetcher-generator)
8
+ [![npm bundle size](https://img.shields.io/bundlephobia/minzip/%40ahoo-wang%2Ffetcher-generator)](https://www.npmjs.com/package/@ahoo-wang/fetcher-generator)
9
+
10
+ 从 OpenAPI 规范生成 TypeScript 代码,专为 [Wow](https://github.com/Ahoo-Wang/Wow) 领域驱动设计框架打造。生成类型安全的模型、查询客户端和命令客户端。
11
+
12
+ **[Wow](https://github.com/Ahoo-Wang/Wow) 框架**:一个领域驱动设计框架,提供事件溯源、CQRS(命令查询责任分离)和聚合模式,用于构建可扩展的分布式系统。
13
+
14
+ ## 🌟 特性
15
+
16
+ - **🎯 OpenAPI 3.0+ 支持**:完整支持 OpenAPI 3.0+ 规范(JSON/YAML)
17
+ - **📦 TypeScript 代码生成**:生成类型安全的 TypeScript 接口、枚举和类
18
+ - **🏗️ 领域驱动设计**:专为 WOW 框架打造,支持聚合、命令、查询和领域事件
19
+ - **🔧 CLI 工具**:易用的命令行界面,用于代码生成
20
+ - **🎨 装饰器式 API**:生成装饰器式的客户端类,实现清晰的 API 交互
21
+ - **📋 全面的模型**:处理复杂的模式,包括联合、交集、枚举和引用
22
+ - **🚀 Fetcher 生态集成**:无缝集成 Fetcher 生态系统包
23
+ - **📊 进度日志**:生成过程中的友好日志记录和进度指示器
24
+ - **📁 自动索引生成**:自动生成 index.ts 文件,实现清晰的模块组织
25
+ - **🌐 远程规范支持**:直接从 HTTP/HTTPS URL 加载 OpenAPI 规范
26
+ - **🎭 事件流**:生成常规和事件流命令客户端
27
+
28
+ ## 🚀 快速开始
29
+
30
+ ### 安装
31
+
32
+ ```bash
33
+ # 使用 npm
34
+ npm install -g @ahoo-wang/fetcher-generator
35
+
36
+ # 使用 pnpm
37
+ pnpm add -g @ahoo-wang/fetcher-generator
38
+
39
+ # 使用 yarn
40
+ yarn global add @ahoo-wang/fetcher-generator
41
+ ```
42
+
43
+ ### 基本用法
44
+
45
+ ```bash
46
+ # 从 OpenAPI 规范生成 TypeScript 代码
47
+ fetcher-generator generate -i ./openapi-spec.json -o ./generated
48
+ ```
49
+
50
+ ## 📖 使用方法
51
+
52
+ ### 命令行界面
53
+
54
+ ```bash
55
+ fetcher-generator generate [options]
56
+ ```
57
+
58
+ #### 选项
59
+
60
+ - `-i, --input <path>`:输入 OpenAPI 规范文件路径或 URL(必需)
61
+ - 支持本地文件路径(例如:`./api-spec.json`、`./api-spec.yaml`)
62
+ - 支持 HTTP/HTTPS URL(例如:`https://api.example.com/openapi.json`)
63
+ - `-o, --output <path>`:输出目录路径(默认为 `src/generated`)
64
+ - `-c, --config <file>`:配置文件路径(可选)
65
+ - `-v, --verbose`:启用详细日志记录
66
+ - `--dry-run`:显示将要生成的内容而不写入文件(保留供将来使用)
67
+ - `-h, --help`:显示帮助信息
68
+ - `-V, --version`:显示版本号
69
+
70
+ #### 示例
71
+
72
+ ```bash
73
+ # 从本地 OpenAPI JSON 文件生成代码
74
+ fetcher-generator generate -i ./api-spec.json -o ./src/generated
75
+
76
+ # 从 YAML 规范生成代码
77
+ fetcher-generator generate -i ./api-spec.yaml -o ./src/generated
78
+
79
+ # 从远程 OpenAPI 规范通过 HTTPS 生成代码
80
+ fetcher-generator generate -i https://api.example.com/openapi.json -o ./src/generated
81
+
82
+ # 从远程 YAML 规范通过 HTTP 生成代码
83
+ fetcher-generator generate -i http://localhost:8080/api-spec.yaml -o ./src/generated
84
+ ```
85
+
86
+ ### 生成的代码结构
87
+
88
+ 生成器在输出目录中创建以下结构:
89
+
90
+ ```
91
+ output/
92
+ ├── {bounded-context}/
93
+ │ ├── index.ts # 自动生成的索引文件,导出所有聚合
94
+ │ ├── boundedContext.ts # 有界上下文别名常量
95
+ │ ├── types.ts # 有界上下文的共享类型
96
+ │ └── {aggregate}/ # 聚合特定文件
97
+ │ ├── index.ts # 聚合的自动生成索引文件
98
+ │ ├── types.ts # 聚合特定类型、模型和枚举
99
+ │ ├── queryClient.ts # 查询客户端工厂,用于状态和事件查询
100
+ │ └── commandClient.ts # 命令客户端类(常规和流式)
101
+ ├── index.ts # 根索引文件,导出所有有界上下文
102
+ └── tsconfig.json # 生成代码的 TypeScript 配置
103
+ ```
104
+
105
+ #### 索引文件生成
106
+
107
+ 生成器自动创建 `index.ts` 文件,为便捷的模块导出提供支持:
108
+
109
+ - **根 index.ts**:导出所有有界上下文
110
+ - **有界上下文 index.ts**:导出上下文中的所有聚合
111
+ - **聚合 index.ts**:导出聚合中的所有文件
112
+
113
+ 这允许干净的导入,例如:
114
+
115
+ ```typescript
116
+ // 导入有界上下文的所有内容
117
+ import * as compensation from './generated/compensation';
118
+
119
+ // 导入特定聚合
120
+ import { executionFailed } from './generated/compensation';
121
+
122
+ // 导入特定文件
123
+ import { ExecutionFailedState } from './generated/compensation/execution_failed';
124
+ ```
125
+
126
+ ## 🎯 生成的代码示例
127
+
128
+ ### 模型
129
+
130
+ ```typescript
131
+ /** apply_execution_failed */
132
+ export interface ApplyExecutionFailed {
133
+ error: ErrorDetails;
134
+ executeAt: number;
135
+ recoverable: RecoverableType | undefined;
136
+ }
137
+
138
+ /** apply_execution_success */
139
+ export interface ApplyExecutionSuccess {
140
+ executeAt: number;
141
+ }
142
+
143
+ /** execution_failed_status */
144
+ export enum ExecutionFailedStatus {
145
+ PREPARED = 'PREPARED',
146
+ SUCCEEDED = 'SUCCEEDED',
147
+ FAILED = 'FAILED',
148
+ COMPENSATED = 'COMPENSATED',
149
+ }
150
+ ```
151
+
152
+ ### 查询客户端
153
+
154
+ ```typescript
155
+ // 生成的查询客户端工厂,用于领域驱动设计
156
+ import {
157
+ QueryClientFactory,
158
+ QueryClientOptions,
159
+ ResourceAttributionPathSpec,
160
+ } from '@ahoo-wang/fetcher-wow';
161
+ import {
162
+ CartAggregatedFields,
163
+ CartItemAdded,
164
+ CartItemRemoved,
165
+ CartQuantityChanged,
166
+ CartState,
167
+ } from './types';
168
+
169
+ const DEFAULT_QUERY_CLIENT_OPTIONS: QueryClientOptions = {
170
+ contextAlias: 'example',
171
+ aggregateName: 'cart',
172
+ resourceAttribution: ResourceAttributionPathSpec.OWNER,
173
+ };
174
+
175
+ type DOMAIN_EVENT_TYPES = CartItemAdded | CartItemRemoved | CartQuantityChanged;
176
+
177
+ export const cartQueryClientFactory = new QueryClientFactory<
178
+ CartState,
179
+ CartAggregatedFields | string,
180
+ DOMAIN_EVENT_TYPES
181
+ >(DEFAULT_QUERY_CLIENT_OPTIONS);
182
+ ```
183
+
184
+ ### 命令客户端
185
+
186
+ ```typescript
187
+ // 生成的命令客户端,具有装饰器式 API
188
+ import { ContentTypeValues } from '@ahoo-wang/fetcher';
189
+ import {
190
+ type ApiMetadata,
191
+ type ApiMetadataCapable,
192
+ api,
193
+ attribute,
194
+ autoGeneratedError,
195
+ del,
196
+ path,
197
+ post,
198
+ put,
199
+ request,
200
+ } from '@ahoo-wang/fetcher-decorator';
201
+ import { JsonEventStreamResultExtractor } from '@ahoo-wang/fetcher-eventstream';
202
+ import type {
203
+ CommandRequest,
204
+ CommandResult,
205
+ CommandResultEventStream,
206
+ DeleteAggregate,
207
+ RecoverAggregate,
208
+ } from '@ahoo-wang/fetcher-wow';
209
+ import {
210
+ AddCartItem,
211
+ ChangeQuantity,
212
+ MockVariableCommand,
213
+ MountedCommand,
214
+ RemoveCartItem,
215
+ ViewCart,
216
+ } from './types';
217
+
218
+ enum COMMAND_ENDPOINT_PATHS {
219
+ VIEW_CART = '/owner/{ownerId}/cart/view_cart',
220
+ ADD_CART_ITEM = '/owner/{ownerId}/cart/add_cart_item',
221
+ CHANGE_QUANTITY = '/owner/{ownerId}/cart/change_quantity',
222
+ REMOVE_CART_ITEM = '/owner/{ownerId}/cart/remove_cart_item',
223
+ MOUNTED_COMMAND = '/owner/{ownerId}/cart/mounted_command',
224
+ MOCK_VARIABLE_COMMAND = '/tenant/{tenantId}/owner/{ownerId}/cart/{id}/{customerId}/{mockEnum}',
225
+ DEFAULT_DELETE_AGGREGATE = '/owner/{ownerId}/cart',
226
+ DEFAULT_RECOVER_AGGREGATE = '/owner/{ownerId}/cart/recover',
227
+ }
228
+
229
+ const DEFAULT_COMMAND_CLIENT_OPTIONS: ApiMetadata = {
230
+ basePath: 'example',
231
+ };
232
+
233
+ @api()
234
+ export class CartCommandClient implements ApiMetadataCapable {
235
+ constructor(
236
+ public readonly apiMetadata: ApiMetadata = DEFAULT_COMMAND_CLIENT_OPTIONS,
237
+ ) {}
238
+
239
+ /** view_cart */
240
+ @put(COMMAND_ENDPOINT_PATHS.VIEW_CART)
241
+ viewCart(
242
+ @request() commandRequest: CommandRequest<ViewCart>,
243
+ @attribute() attributes: Record<string, any>,
244
+ ): Promise<CommandResult> {
245
+ throw autoGeneratedError(commandRequest, attributes);
246
+ }
247
+
248
+ /**
249
+ * 加入购物车
250
+ * 加入购物车
251
+ */
252
+ @post(COMMAND_ENDPOINT_PATHS.ADD_CART_ITEM)
253
+ addCartItem(
254
+ @request() commandRequest: CommandRequest<AddCartItem>,
255
+ @attribute() attributes: Record<string, any>,
256
+ ): Promise<CommandResult> {
257
+ throw autoGeneratedError(commandRequest, attributes);
258
+ }
259
+
260
+ /** 变更购买数量 */
261
+ @put(COMMAND_ENDPOINT_PATHS.CHANGE_QUANTITY)
262
+ changeQuantity(
263
+ @request() commandRequest: CommandRequest<ChangeQuantity>,
264
+ @attribute() attributes: Record<string, any>,
265
+ ): Promise<CommandResult> {
266
+ throw autoGeneratedError(commandRequest, attributes);
267
+ }
268
+
269
+ /** 删除商品 */
270
+ @put(COMMAND_ENDPOINT_PATHS.REMOVE_CART_ITEM)
271
+ removeCartItem(
272
+ @request() commandRequest: CommandRequest<RemoveCartItem>,
273
+ @attribute() attributes: Record<string, any>,
274
+ ): Promise<CommandResult> {
275
+ throw autoGeneratedError(commandRequest, attributes);
276
+ }
277
+ }
278
+ ```
279
+
280
+ 生成器还创建流式命令客户端,用于事件驱动的交互:
281
+
282
+ ```typescript
283
+ @api('', {
284
+ headers: { Accept: ContentTypeValues.TEXT_EVENT_STREAM },
285
+ resultExtractor: JsonEventStreamResultExtractor,
286
+ })
287
+ export class CartStreamCommandClient implements ApiMetadataCapable {
288
+ constructor(
289
+ public readonly apiMetadata: ApiMetadata = DEFAULT_COMMAND_CLIENT_OPTIONS,
290
+ ) {}
291
+
292
+ /** view_cart */
293
+ @put(COMMAND_ENDPOINT_PATHS.VIEW_CART)
294
+ viewCart(
295
+ @request() commandRequest: CommandRequest<ViewCart>,
296
+ @attribute() attributes: Record<string, any>,
297
+ ): Promise<CommandResultEventStream> {
298
+ throw autoGeneratedError(commandRequest, attributes);
299
+ }
300
+ // ... 其他流式方法
301
+ }
302
+ ```
303
+
304
+ ## 🔧 与 Fetcher 集成
305
+
306
+ 生成的代码设计为与 Fetcher 生态系统无缝集成:
307
+
308
+ ```typescript
309
+ import { Fetcher } from '@ahoo-wang/fetcher';
310
+ import { cartQueryClientFactory } from './generated/example/cart/queryClient';
311
+ import { CartCommandClient } from './generated/example/cart/commandClient';
312
+
313
+ // 创建 fetcher 实例
314
+ const fetcher = new Fetcher({
315
+ baseURL: 'https://api.example.com',
316
+ });
317
+
318
+ // 注册 fetcher(如果使用命名 fetcher)
319
+ Fetcher.register('api', fetcher);
320
+
321
+ // 使用生成的查询客户端工厂
322
+ const queryClient = cartQueryClientFactory.createQueryClient();
323
+ const cartState = await queryClient.loadAggregate('cart-id');
324
+
325
+ // 使用生成的命令客户端
326
+ const commandClient = new CartCommandClient();
327
+ const result = await commandClient.addCartItem(
328
+ {
329
+ command: {
330
+ productId: 'product-123',
331
+ quantity: 2,
332
+ },
333
+ },
334
+ {
335
+ ownerId: 'user-456',
336
+ },
337
+ );
338
+ ```
339
+
340
+ ## 📋 OpenAPI 规范要求
341
+
342
+ 生成器期望 OpenAPI 3.0+ 规范具有 WOW 领域驱动设计框架的特定模式:
343
+
344
+ ### 聚合定义
345
+
346
+ 聚合通过遵循 `{context}.{aggregate}` 模式的标签进行识别。
347
+
348
+ ### 操作模式
349
+
350
+ 生成器通过 `operationId` 后缀识别操作:
351
+
352
+ - **状态快照**:以 `.snapshot_state.single` 结尾的操作
353
+ - **事件查询**:以 `.event.list_query` 结尾的操作
354
+ - **字段查询**:以 `.snapshot.count` 结尾的操作
355
+ - **命令**:任何具有有效命令请求/响应结构的 HTTP 操作
356
+
357
+ ### 命令和查询
358
+
359
+ - **命令**:具有 `POST`、`PUT`、`DELETE` 方法的操作,返回 `wow.CommandOk` 响应
360
+ - **查询**:具有 `GET` 方法的操作,用于检索聚合状态或事件
361
+ - **事件**:返回事件流数组的操作,具有领域事件结构
362
+
363
+ ### 模式约定
364
+
365
+ - 为模式使用描述性名称
366
+ - 避免以 `wow.` 为前缀的模式(保留供内部框架使用)
367
+ - 命令请求正文应引用 `components/schemas` 中的模式
368
+ - 状态和事件模式应遵循域建模的预期结构
369
+
370
+ ## 🛠️ 开发
371
+
372
+ ### 构建
373
+
374
+ ```bash
375
+ # 构建包
376
+ pnpm build
377
+
378
+ # 运行测试
379
+ pnpm test
380
+
381
+ # 运行 linting
382
+ pnpm lint
383
+ ```
384
+
385
+ ### 测试生成器
386
+
387
+ ```bash
388
+ # 生成测试输出
389
+ pnpm generate
390
+ ```
391
+
392
+ ## 🤝 贡献
393
+
394
+ 欢迎贡献!请随时提交拉取请求。对于重大更改,请先打开 issue 进行讨论。
395
+
396
+ ## 📄 许可证
397
+
398
+ 本项目采用 Apache License 2.0 许可证 - 查看 [LICENSE](../../LICENSE) 文件获取详情。
399
+
400
+ ## 🔗 链接
401
+
402
+ - [Fetcher 核心](https://github.com/Ahoo-Wang/fetcher/tree/main/packages/fetcher)
403
+ - [Fetcher 装饰器](https://github.com/Ahoo-Wang/fetcher/tree/main/packages/decorator)
404
+ - [Fetcher 事件流](https://github.com/Ahoo-Wang/fetcher/tree/main/packages/eventstream)
405
+ - [GitHub 仓库](https://github.com/Ahoo-Wang/fetcher)
406
+ - [NPM 包](https://www.npmjs.com/package/@ahoo-wang/fetcher-generator)
package/dist/cli.cjs CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- "use strict";const t=require("commander"),i=require("./index.cjs"),c=require("ts-morph");require("yaml");require("fs");require("@ahoo-wang/fetcher");class s{info(e,...r){console.log(`ℹ️ ${e}`,r)}success(e,...r){console.log(`✅ ${e}`,r)}error(e,...r){console.error(`❌ ${e}`,r)}progress(e,...r){console.log(`🔄 ${e}`,r)}}function a(o){if(!o)return!1;try{const e=new URL(o);return e.protocol==="http:"||e.protocol==="https:"}catch{return o.length>0}}async function p(o){const e=new s;process.on("SIGINT",()=>{e.error("Generation interrupted by user"),process.exit(130)}),a(o.input)||(e.error("Invalid input: must be a valid file path or HTTP/HTTPS URL"),process.exit(2));try{e.info("Starting code generation...");const r=new c.Project,n={inputPath:o.input,outputDir:o.output,project:r,logger:e};await new i.CodeGenerator(n).generate(),e.success(`Code generation completed successfully! Files generated in: ${o.output}`)}catch(r){e.error(`Error during code generation: ${r}`),process.exit(1)}}t.program.name("fetcher-generator").description("OpenAPI Specification TypeScript code generator for Wow").version("2.1.1");t.program.command("generate").description("Generate TypeScript code from OpenAPI specification").requiredOption("-i, --input <path>","Input OpenAPI specification file path or URL (http/https)").option("-o, --output <path>","Output directory path","src/generated").option("-c, --config <file>","Configuration file path").option("-v, --verbose","Enable verbose logging").option("--dry-run","Show what would be generated without writing files").action(p);t.program.parse();
2
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("commander"),g=require("./index.cjs"),d=require("ts-morph");require("yaml");require("fs");require("@ahoo-wang/fetcher");require("path");class h{getTimestamp(){return new Date().toISOString().slice(11,19)}info(e,...t){const o=this.getTimestamp();t.length>0?console.log(`[${o}] ℹ️ ${e}`,...t):console.log(`[${o}] ℹ️ ${e}`)}success(e,...t){const o=this.getTimestamp();t.length>0?console.log(`[${o}] ${e}`,...t):console.log(`[${o}] ✅ ${e}`)}error(e,...t){const o=this.getTimestamp();t.length>0?console.error(`[${o}] ${e}`,...t):console.error(`[${o}] ❌ ${e}`)}progress(e,t=0,...o){const n=this.getTimestamp(),i=" ".repeat(t);o.length>0?console.log(`[${n}] 🔄 ${i}${e}`,...o):console.log(`[${n}] 🔄 ${i}${e}`)}progressWithCount(e,t,o,n=0,...i){const s=this.getTimestamp(),p=" ".repeat(n),l=`[${e}/${t}]`;i.length>0?console.log(`[${s}] 🔄 ${p}${l} ${o}`,...i):console.log(`[${s}] 🔄 ${p}${l} ${o}`)}}function $(r){if(!r)return!1;try{const e=new URL(r);return e.protocol==="http:"||e.protocol==="https:"}catch{return r.length>0}}async function f(r){const e=new h;process.on("SIGINT",()=>{e.error("Generation interrupted by user"),process.exit(130)}),$(r.input)||(e.error("Invalid input: must be a valid file path or HTTP/HTTPS URL"),process.exit(2));try{e.info("Starting code generation...");const t=new d.Project,o={inputPath:r.input,outputDir:r.output,project:t,logger:e};await new g.CodeGenerator(o).generate(),e.success(`Code generation completed successfully! Files generated in: ${r.output}`)}catch(t){e.error(`Error during code generation: ${t}`),process.exit(1)}}const m="2.2.0",T={version:m};function u(){return c.program.name("fetcher-generator").description("OpenAPI Specification TypeScript code generator for Wow").version(T.version),c.program.command("generate").description("Generate TypeScript code from OpenAPI specification").requiredOption("-i, --input <path>","Input OpenAPI specification file path or URL (http/https)").option("-o, --output <path>","Output directory path","src/generated").option("-c, --config <file>","Configuration file path").option("-v, --verbose","Enable verbose logging").option("--dry-run","Show what would be generated without writing files").action(f),c.program}function a(){u().parse()}a();exports.runCLI=a;exports.setupCLI=u;
3
3
  //# sourceMappingURL=cli.cjs.map
package/dist/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.cjs","sources":["../src/utils/logger.ts","../src/utils/clis.ts","../src/cli.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from '../types';\n\n/**\n * Default console-based logger implementation.\n * Provides friendly colored output for different log levels.\n */\nexport class ConsoleLogger implements Logger {\n info(message: string, ...params: any[]): void {\n console.log(`ℹ️ ${message}`, params);\n }\n\n success(message: string, ...params: any[]): void {\n console.log(`✅ ${message}`, params);\n }\n\n error(message: string, ...params: any[]): void {\n console.error(`❌ ${message}`, params);\n }\n\n progress(message: string, ...params: any[]): void {\n console.log(`🔄 ${message}`, params);\n }\n}\n\n/**\n * Silent logger that suppresses all output.\n */\nexport class SilentLogger implements Logger {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n info(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n success(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n error(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n progress(_message: string, ...params: any[]): void {\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConsoleLogger } from './logger';\nimport { GeneratorOptions } from '../types';\nimport { CodeGenerator } from '../index';\nimport { Project } from 'ts-morph';\n\n/**\n * Validates the input path or URL.\n * @param input - Input path or URL\n * @returns true if valid\n */\nexport function validateInput(input: string): boolean {\n if (!input) return false;\n\n // Check if it's a URL\n try {\n const url = new URL(input);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n // Not a URL, check if it's a file path\n // For file paths, we'll let parseOpenAPI handle it\n return input.length > 0;\n }\n}\n\n/**\n * Action handler for the generate command.\n * @param options - Command options\n */\nexport async function generateAction(options: {\n input: string;\n output: string;\n config?: string;\n verbose?: boolean;\n dryRun?: boolean;\n}) {\n const logger = new ConsoleLogger();\n\n // Handle signals\n process.on('SIGINT', () => {\n logger.error('Generation interrupted by user');\n process.exit(130);\n });\n\n // Validate input\n if (!validateInput(options.input)) {\n logger.error('Invalid input: must be a valid file path or HTTP/HTTPS URL');\n process.exit(2);\n }\n\n try {\n logger.info('Starting code generation...');\n const project = new Project();\n const generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n project,\n logger,\n };\n const codeGenerator = new CodeGenerator(generatorOptions);\n await codeGenerator.generate();\n logger.success(\n `Code generation completed successfully! Files generated in: ${options.output}`,\n );\n } catch (error) {\n logger.error(`Error during code generation: ${error}`);\n process.exit(1);\n }\n}","#!/usr/bin/env node\n\n/**\n * CLI entry point for the Fetcher OpenAPI code generator.\n * Sets up the commander program with generate command and handles execution.\n */\n\nimport { program } from 'commander';\nimport { generateAction } from './utils';\n\nprogram\n .name('fetcher-generator')\n .description('OpenAPI Specification TypeScript code generator for Wow')\n .version('2.1.1');\n\nprogram\n .command('generate')\n .description('Generate TypeScript code from OpenAPI specification')\n .requiredOption(\n '-i, --input <path>',\n 'Input OpenAPI specification file path or URL (http/https)',\n )\n .option('-o, --output <path>', 'Output directory path', 'src/generated')\n .option('-c, --config <file>', 'Configuration file path')\n .option('-v, --verbose', 'Enable verbose logging')\n .option('--dry-run', 'Show what would be generated without writing files')\n .action(generateAction);\n\nprogram.parse();\n"],"names":["ConsoleLogger","message","params","validateInput","input","url","generateAction","options","logger","project","Project","generatorOptions","CodeGenerator","error","program"],"mappings":";qJAmBO,MAAMA,CAAgC,CAC3C,KAAKC,KAAoBC,EAAqB,CAC5C,QAAQ,IAAI,OAAOD,CAAO,GAAIC,CAAM,CACtC,CAEA,QAAQD,KAAoBC,EAAqB,CAC/C,QAAQ,IAAI,KAAKD,CAAO,GAAIC,CAAM,CACpC,CAEA,MAAMD,KAAoBC,EAAqB,CAC7C,QAAQ,MAAM,KAAKD,CAAO,GAAIC,CAAM,CACtC,CAEA,SAASD,KAAoBC,EAAqB,CAChD,QAAQ,IAAI,MAAMD,CAAO,GAAIC,CAAM,CACrC,CACF,CCZO,SAASC,EAAcC,EAAwB,CACpD,GAAI,CAACA,EAAO,MAAO,GAGnB,GAAI,CACF,MAAMC,EAAM,IAAI,IAAID,CAAK,EACzB,OAAOC,EAAI,WAAa,SAAWA,EAAI,WAAa,QACtD,MAAQ,CAGN,OAAOD,EAAM,OAAS,CACxB,CACF,CAMA,eAAsBE,EAAeC,EAMlC,CACD,MAAMC,EAAS,IAAIR,EAGnB,QAAQ,GAAG,SAAU,IAAM,CACzBQ,EAAO,MAAM,gCAAgC,EAC7C,QAAQ,KAAK,GAAG,CAClB,CAAC,EAGIL,EAAcI,EAAQ,KAAK,IAC9BC,EAAO,MAAM,4DAA4D,EACzE,QAAQ,KAAK,CAAC,GAGhB,GAAI,CACFA,EAAO,KAAK,6BAA6B,EACzC,MAAMC,EAAU,IAAIC,UACdC,EAAqC,CACzC,UAAWJ,EAAQ,MACnB,UAAWA,EAAQ,OACnB,QAAAE,EACA,OAAAD,CAAA,EAGF,MADsB,IAAII,EAAAA,cAAcD,CAAgB,EACpC,SAAA,EACpBH,EAAO,QACL,+DAA+DD,EAAQ,MAAM,EAAA,CAEjF,OAASM,EAAO,CACdL,EAAO,MAAM,iCAAiCK,CAAK,EAAE,EACrD,QAAQ,KAAK,CAAC,CAChB,CACF,CCtEAC,EAAAA,QACG,KAAK,mBAAmB,EACxB,YAAY,yDAAyD,EACrE,QAAQ,OAAO,EAElBA,EAAAA,QACG,QAAQ,UAAU,EAClB,YAAY,qDAAqD,EACjE,eACC,qBACA,2DACF,EACC,OAAO,sBAAuB,wBAAyB,eAAe,EACtE,OAAO,sBAAuB,yBAAyB,EACvD,OAAO,gBAAiB,wBAAwB,EAChD,OAAO,YAAa,oDAAoD,EACxE,OAAOR,CAAc,EAExBQ,EAAAA,QAAQ,MAAA"}
1
+ {"version":3,"file":"cli.cjs","sources":["../src/utils/logger.ts","../src/utils/clis.ts","../src/cli.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from '../types';\n\n/**\n * Default console-based logger implementation.\n * Provides friendly colored output for different log levels.\n */\nexport class ConsoleLogger implements Logger {\n private getTimestamp(): string {\n return new Date().toISOString().slice(11, 19); // HH:MM:SS format\n }\n\n info(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.log(`[${timestamp}] ℹ️ ${message}`, ...params);\n } else {\n console.log(`[${timestamp}] ℹ️ ${message}`);\n }\n }\n\n success(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.log(`[${timestamp}] ${message}`, ...params);\n } else {\n console.log(`[${timestamp}] ✅ ${message}`);\n }\n }\n\n error(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.error(`[${timestamp}] ${message}`, ...params);\n } else {\n console.error(`[${timestamp}] ❌ ${message}`);\n }\n }\n\n progress(message: string, level = 0, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n const indent = ' '.repeat(level);\n if (params.length > 0) {\n console.log(`[${timestamp}] 🔄 ${indent}${message}`, ...params);\n } else {\n console.log(`[${timestamp}] 🔄 ${indent}${message}`);\n }\n }\n\n progressWithCount(\n current: number,\n total: number,\n message: string,\n level = 0,\n ...params: any[]\n ): void {\n const timestamp = this.getTimestamp();\n const indent = ' '.repeat(level);\n const countStr = `[${current}/${total}]`;\n if (params.length > 0) {\n console.log(\n `[${timestamp}] 🔄 ${indent}${countStr} ${message}`,\n ...params,\n );\n } else {\n console.log(`[${timestamp}] 🔄 ${indent}${countStr} ${message}`);\n }\n }\n}\n\n/**\n * Silent logger that suppresses all output.\n */\nexport class SilentLogger implements Logger {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n info(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n success(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n error(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n progress(_message: string, ...params: any[]): void {\n }\n\n /* eslint-disable @typescript-eslint/no-unused-vars */\n progressWithCount(\n _current: number,\n _total: number,\n _message: string,\n _level = 0,\n ..._params: any[]\n ): void {\n }\n\n /* eslint-enable @typescript-eslint/no-unused-vars */\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConsoleLogger } from './logger';\nimport { GeneratorOptions } from '../types';\nimport { CodeGenerator } from '../index';\nimport { Project } from 'ts-morph';\n\n/**\n * Validates the input path or URL.\n * @param input - Input path or URL\n * @returns true if valid\n */\nexport function validateInput(input: string): boolean {\n if (!input) return false;\n\n // Check if it's a URL\n try {\n const url = new URL(input);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n // Not a URL, check if it's a file path\n // For file paths, we'll let parseOpenAPI handle it\n return input.length > 0;\n }\n}\n\n/**\n * Action handler for the generate command.\n * @param options - Command options\n */\nexport async function generateAction(options: {\n input: string;\n output: string;\n config?: string;\n verbose?: boolean;\n dryRun?: boolean;\n}) {\n const logger = new ConsoleLogger();\n\n // Handle signals\n process.on('SIGINT', () => {\n logger.error('Generation interrupted by user');\n process.exit(130);\n });\n\n // Validate input\n if (!validateInput(options.input)) {\n logger.error('Invalid input: must be a valid file path or HTTP/HTTPS URL');\n process.exit(2);\n }\n\n try {\n logger.info('Starting code generation...');\n const project = new Project();\n const generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n project,\n logger,\n };\n const codeGenerator = new CodeGenerator(generatorOptions);\n await codeGenerator.generate();\n logger.success(\n `Code generation completed successfully! Files generated in: ${options.output}`,\n );\n } catch (error) {\n logger.error(`Error during code generation: ${error}`);\n process.exit(1);\n }\n}","#!/usr/bin/env node\n\n/**\n * CLI entry point for the Fetcher OpenAPI code generator.\n * Sets up the commander program with generate command and handles execution.\n */\n\nimport { program } from 'commander';\nimport { generateAction } from './utils';\nimport packageJson from '../package.json';\n\n/**\n * Sets up the CLI program with all commands and options.\n * @returns The configured commander program instance\n */\nexport function setupCLI() {\n program\n .name('fetcher-generator')\n .description('OpenAPI Specification TypeScript code generator for Wow')\n .version(packageJson.version);\n\n program\n .command('generate')\n .description('Generate TypeScript code from OpenAPI specification')\n .requiredOption(\n '-i, --input <path>',\n 'Input OpenAPI specification file path or URL (http/https)',\n )\n .option('-o, --output <path>', 'Output directory path', 'src/generated')\n .option('-c, --config <file>', 'Configuration file path')\n .option('-v, --verbose', 'Enable verbose logging')\n .option('--dry-run', 'Show what would be generated without writing files')\n .action(generateAction);\n\n return program;\n}\n\n/**\n * Runs the CLI program by parsing command line arguments.\n * Only executes when this file is run directly (not imported).\n */\nexport function runCLI() {\n setupCLI().parse();\n}\n\nrunCLI();\n"],"names":["ConsoleLogger","message","params","timestamp","level","indent","current","total","countStr","validateInput","input","url","generateAction","options","logger","project","Project","generatorOptions","CodeGenerator","error","setupCLI","program","packageJson","runCLI"],"mappings":"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"}
package/dist/cli.d.ts CHANGED
@@ -3,5 +3,14 @@
3
3
  * CLI entry point for the Fetcher OpenAPI code generator.
4
4
  * Sets up the commander program with generate command and handles execution.
5
5
  */
6
- export {};
6
+ /**
7
+ * Sets up the CLI program with all commands and options.
8
+ * @returns The configured commander program instance
9
+ */
10
+ export declare function setupCLI(): import('commander').Command;
11
+ /**
12
+ * Runs the CLI program by parsing command line arguments.
13
+ * Only executes when this file is run directly (not imported).
14
+ */
15
+ export declare function runCLI(): void;
7
16
  //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;GAGG"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAMH;;;GAGG;AACH,wBAAgB,QAAQ,gCAoBvB;AAED;;;GAGG;AACH,wBAAgB,MAAM,SAErB"}
package/dist/cli.js CHANGED
@@ -1,57 +1,83 @@
1
1
  #!/usr/bin/env node
2
- import { program as t } from "commander";
3
- import { CodeGenerator as i } from "./index.js";
4
- import { Project as c } from "ts-morph";
2
+ import { program as c } from "commander";
3
+ import { CodeGenerator as a } from "./index.js";
4
+ import { Project as g } from "ts-morph";
5
5
  import "yaml";
6
6
  import "fs";
7
7
  import "@ahoo-wang/fetcher";
8
- class p {
9
- info(e, ...o) {
10
- console.log(`ℹ️ ${e}`, o);
8
+ import "path";
9
+ class u {
10
+ getTimestamp() {
11
+ return (/* @__PURE__ */ new Date()).toISOString().slice(11, 19);
11
12
  }
12
- success(e, ...o) {
13
- console.log(`✅ ${e}`, o);
13
+ info(e, ...t) {
14
+ const o = this.getTimestamp();
15
+ t.length > 0 ? console.log(`[${o}] ℹ️ ${e}`, ...t) : console.log(`[${o}] ℹ️ ${e}`);
14
16
  }
15
- error(e, ...o) {
16
- console.error(`❌ ${e}`, o);
17
+ success(e, ...t) {
18
+ const o = this.getTimestamp();
19
+ t.length > 0 ? console.log(`[${o}] ✅ ${e}`, ...t) : console.log(`[${o}] ✅ ${e}`);
17
20
  }
18
- progress(e, ...o) {
19
- console.log(`🔄 ${e}`, o);
21
+ error(e, ...t) {
22
+ const o = this.getTimestamp();
23
+ t.length > 0 ? console.error(`[${o}] ❌ ${e}`, ...t) : console.error(`[${o}] ❌ ${e}`);
24
+ }
25
+ progress(e, t = 0, ...o) {
26
+ const r = this.getTimestamp(), i = " ".repeat(t);
27
+ o.length > 0 ? console.log(`[${r}] 🔄 ${i}${e}`, ...o) : console.log(`[${r}] 🔄 ${i}${e}`);
28
+ }
29
+ progressWithCount(e, t, o, r = 0, ...i) {
30
+ const s = this.getTimestamp(), p = " ".repeat(r), l = `[${e}/${t}]`;
31
+ i.length > 0 ? console.log(
32
+ `[${s}] 🔄 ${p}${l} ${o}`,
33
+ ...i
34
+ ) : console.log(`[${s}] 🔄 ${p}${l} ${o}`);
20
35
  }
21
36
  }
22
- function a(r) {
23
- if (!r) return !1;
37
+ function f(n) {
38
+ if (!n) return !1;
24
39
  try {
25
- const e = new URL(r);
40
+ const e = new URL(n);
26
41
  return e.protocol === "http:" || e.protocol === "https:";
27
42
  } catch {
28
- return r.length > 0;
43
+ return n.length > 0;
29
44
  }
30
45
  }
31
- async function s(r) {
32
- const e = new p();
46
+ async function $(n) {
47
+ const e = new u();
33
48
  process.on("SIGINT", () => {
34
49
  e.error("Generation interrupted by user"), process.exit(130);
35
- }), a(r.input) || (e.error("Invalid input: must be a valid file path or HTTP/HTTPS URL"), process.exit(2));
50
+ }), f(n.input) || (e.error("Invalid input: must be a valid file path or HTTP/HTTPS URL"), process.exit(2));
36
51
  try {
37
52
  e.info("Starting code generation...");
38
- const o = new c(), n = {
39
- inputPath: r.input,
40
- outputDir: r.output,
41
- project: o,
53
+ const t = new g(), o = {
54
+ inputPath: n.input,
55
+ outputDir: n.output,
56
+ project: t,
42
57
  logger: e
43
58
  };
44
- await new i(n).generate(), e.success(
45
- `Code generation completed successfully! Files generated in: ${r.output}`
59
+ await new a(o).generate(), e.success(
60
+ `Code generation completed successfully! Files generated in: ${n.output}`
46
61
  );
47
- } catch (o) {
48
- e.error(`Error during code generation: ${o}`), process.exit(1);
62
+ } catch (t) {
63
+ e.error(`Error during code generation: ${t}`), process.exit(1);
49
64
  }
50
65
  }
51
- t.name("fetcher-generator").description("OpenAPI Specification TypeScript code generator for Wow").version("2.1.1");
52
- t.command("generate").description("Generate TypeScript code from OpenAPI specification").requiredOption(
53
- "-i, --input <path>",
54
- "Input OpenAPI specification file path or URL (http/https)"
55
- ).option("-o, --output <path>", "Output directory path", "src/generated").option("-c, --config <file>", "Configuration file path").option("-v, --verbose", "Enable verbose logging").option("--dry-run", "Show what would be generated without writing files").action(s);
56
- t.parse();
66
+ const h = "2.2.0", m = {
67
+ version: h
68
+ };
69
+ function d() {
70
+ return c.name("fetcher-generator").description("OpenAPI Specification TypeScript code generator for Wow").version(m.version), c.command("generate").description("Generate TypeScript code from OpenAPI specification").requiredOption(
71
+ "-i, --input <path>",
72
+ "Input OpenAPI specification file path or URL (http/https)"
73
+ ).option("-o, --output <path>", "Output directory path", "src/generated").option("-c, --config <file>", "Configuration file path").option("-v, --verbose", "Enable verbose logging").option("--dry-run", "Show what would be generated without writing files").action($), c;
74
+ }
75
+ function T() {
76
+ d().parse();
77
+ }
78
+ T();
79
+ export {
80
+ T as runCLI,
81
+ d as setupCLI
82
+ };
57
83
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sources":["../src/utils/logger.ts","../src/utils/clis.ts","../src/cli.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from '../types';\n\n/**\n * Default console-based logger implementation.\n * Provides friendly colored output for different log levels.\n */\nexport class ConsoleLogger implements Logger {\n info(message: string, ...params: any[]): void {\n console.log(`ℹ️ ${message}`, params);\n }\n\n success(message: string, ...params: any[]): void {\n console.log(`✅ ${message}`, params);\n }\n\n error(message: string, ...params: any[]): void {\n console.error(`❌ ${message}`, params);\n }\n\n progress(message: string, ...params: any[]): void {\n console.log(`🔄 ${message}`, params);\n }\n}\n\n/**\n * Silent logger that suppresses all output.\n */\nexport class SilentLogger implements Logger {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n info(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n success(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n error(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n progress(_message: string, ...params: any[]): void {\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConsoleLogger } from './logger';\nimport { GeneratorOptions } from '../types';\nimport { CodeGenerator } from '../index';\nimport { Project } from 'ts-morph';\n\n/**\n * Validates the input path or URL.\n * @param input - Input path or URL\n * @returns true if valid\n */\nexport function validateInput(input: string): boolean {\n if (!input) return false;\n\n // Check if it's a URL\n try {\n const url = new URL(input);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n // Not a URL, check if it's a file path\n // For file paths, we'll let parseOpenAPI handle it\n return input.length > 0;\n }\n}\n\n/**\n * Action handler for the generate command.\n * @param options - Command options\n */\nexport async function generateAction(options: {\n input: string;\n output: string;\n config?: string;\n verbose?: boolean;\n dryRun?: boolean;\n}) {\n const logger = new ConsoleLogger();\n\n // Handle signals\n process.on('SIGINT', () => {\n logger.error('Generation interrupted by user');\n process.exit(130);\n });\n\n // Validate input\n if (!validateInput(options.input)) {\n logger.error('Invalid input: must be a valid file path or HTTP/HTTPS URL');\n process.exit(2);\n }\n\n try {\n logger.info('Starting code generation...');\n const project = new Project();\n const generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n project,\n logger,\n };\n const codeGenerator = new CodeGenerator(generatorOptions);\n await codeGenerator.generate();\n logger.success(\n `Code generation completed successfully! Files generated in: ${options.output}`,\n );\n } catch (error) {\n logger.error(`Error during code generation: ${error}`);\n process.exit(1);\n }\n}","#!/usr/bin/env node\n\n/**\n * CLI entry point for the Fetcher OpenAPI code generator.\n * Sets up the commander program with generate command and handles execution.\n */\n\nimport { program } from 'commander';\nimport { generateAction } from './utils';\n\nprogram\n .name('fetcher-generator')\n .description('OpenAPI Specification TypeScript code generator for Wow')\n .version('2.1.1');\n\nprogram\n .command('generate')\n .description('Generate TypeScript code from OpenAPI specification')\n .requiredOption(\n '-i, --input <path>',\n 'Input OpenAPI specification file path or URL (http/https)',\n )\n .option('-o, --output <path>', 'Output directory path', 'src/generated')\n .option('-c, --config <file>', 'Configuration file path')\n .option('-v, --verbose', 'Enable verbose logging')\n .option('--dry-run', 'Show what would be generated without writing files')\n .action(generateAction);\n\nprogram.parse();\n"],"names":["ConsoleLogger","message","params","validateInput","input","url","generateAction","options","logger","project","Project","generatorOptions","CodeGenerator","error","program"],"mappings":";;;;;;;AAmBO,MAAMA,EAAgC;AAAA,EAC3C,KAAKC,MAAoBC,GAAqB;AAC5C,YAAQ,IAAI,OAAOD,CAAO,IAAIC,CAAM;AAAA,EACtC;AAAA,EAEA,QAAQD,MAAoBC,GAAqB;AAC/C,YAAQ,IAAI,KAAKD,CAAO,IAAIC,CAAM;AAAA,EACpC;AAAA,EAEA,MAAMD,MAAoBC,GAAqB;AAC7C,YAAQ,MAAM,KAAKD,CAAO,IAAIC,CAAM;AAAA,EACtC;AAAA,EAEA,SAASD,MAAoBC,GAAqB;AAChD,YAAQ,IAAI,MAAMD,CAAO,IAAIC,CAAM;AAAA,EACrC;AACF;ACZO,SAASC,EAAcC,GAAwB;AACpD,MAAI,CAACA,EAAO,QAAO;AAGnB,MAAI;AACF,UAAMC,IAAM,IAAI,IAAID,CAAK;AACzB,WAAOC,EAAI,aAAa,WAAWA,EAAI,aAAa;AAAA,EACtD,QAAQ;AAGN,WAAOD,EAAM,SAAS;AAAA,EACxB;AACF;AAMA,eAAsBE,EAAeC,GAMlC;AACD,QAAMC,IAAS,IAAIR,EAAA;AAGnB,UAAQ,GAAG,UAAU,MAAM;AACzB,IAAAQ,EAAO,MAAM,gCAAgC,GAC7C,QAAQ,KAAK,GAAG;AAAA,EAClB,CAAC,GAGIL,EAAcI,EAAQ,KAAK,MAC9BC,EAAO,MAAM,4DAA4D,GACzE,QAAQ,KAAK,CAAC;AAGhB,MAAI;AACF,IAAAA,EAAO,KAAK,6BAA6B;AACzC,UAAMC,IAAU,IAAIC,EAAA,GACdC,IAAqC;AAAA,MACzC,WAAWJ,EAAQ;AAAA,MACnB,WAAWA,EAAQ;AAAA,MACnB,SAAAE;AAAA,MACA,QAAAD;AAAA,IAAA;AAGF,UADsB,IAAII,EAAcD,CAAgB,EACpC,SAAA,GACpBH,EAAO;AAAA,MACL,+DAA+DD,EAAQ,MAAM;AAAA,IAAA;AAAA,EAEjF,SAASM,GAAO;AACd,IAAAL,EAAO,MAAM,iCAAiCK,CAAK,EAAE,GACrD,QAAQ,KAAK,CAAC;AAAA,EAChB;AACF;ACtEAC,EACG,KAAK,mBAAmB,EACxB,YAAY,yDAAyD,EACrE,QAAQ,OAAO;AAElBA,EACG,QAAQ,UAAU,EAClB,YAAY,qDAAqD,EACjE;AAAA,EACC;AAAA,EACA;AACF,EACC,OAAO,uBAAuB,yBAAyB,eAAe,EACtE,OAAO,uBAAuB,yBAAyB,EACvD,OAAO,iBAAiB,wBAAwB,EAChD,OAAO,aAAa,oDAAoD,EACxE,OAAOR,CAAc;AAExBQ,EAAQ,MAAA;"}
1
+ {"version":3,"file":"cli.js","sources":["../src/utils/logger.ts","../src/utils/clis.ts","../src/cli.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from '../types';\n\n/**\n * Default console-based logger implementation.\n * Provides friendly colored output for different log levels.\n */\nexport class ConsoleLogger implements Logger {\n private getTimestamp(): string {\n return new Date().toISOString().slice(11, 19); // HH:MM:SS format\n }\n\n info(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.log(`[${timestamp}] ℹ️ ${message}`, ...params);\n } else {\n console.log(`[${timestamp}] ℹ️ ${message}`);\n }\n }\n\n success(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.log(`[${timestamp}] ✅ ${message}`, ...params);\n } else {\n console.log(`[${timestamp}] ✅ ${message}`);\n }\n }\n\n error(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.error(`[${timestamp}] ❌ ${message}`, ...params);\n } else {\n console.error(`[${timestamp}] ❌ ${message}`);\n }\n }\n\n progress(message: string, level = 0, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n const indent = ' '.repeat(level);\n if (params.length > 0) {\n console.log(`[${timestamp}] 🔄 ${indent}${message}`, ...params);\n } else {\n console.log(`[${timestamp}] 🔄 ${indent}${message}`);\n }\n }\n\n progressWithCount(\n current: number,\n total: number,\n message: string,\n level = 0,\n ...params: any[]\n ): void {\n const timestamp = this.getTimestamp();\n const indent = ' '.repeat(level);\n const countStr = `[${current}/${total}]`;\n if (params.length > 0) {\n console.log(\n `[${timestamp}] 🔄 ${indent}${countStr} ${message}`,\n ...params,\n );\n } else {\n console.log(`[${timestamp}] 🔄 ${indent}${countStr} ${message}`);\n }\n }\n}\n\n/**\n * Silent logger that suppresses all output.\n */\nexport class SilentLogger implements Logger {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n info(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n success(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n error(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n progress(_message: string, ...params: any[]): void {\n }\n\n /* eslint-disable @typescript-eslint/no-unused-vars */\n progressWithCount(\n _current: number,\n _total: number,\n _message: string,\n _level = 0,\n ..._params: any[]\n ): void {\n }\n\n /* eslint-enable @typescript-eslint/no-unused-vars */\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConsoleLogger } from './logger';\nimport { GeneratorOptions } from '../types';\nimport { CodeGenerator } from '../index';\nimport { Project } from 'ts-morph';\n\n/**\n * Validates the input path or URL.\n * @param input - Input path or URL\n * @returns true if valid\n */\nexport function validateInput(input: string): boolean {\n if (!input) return false;\n\n // Check if it's a URL\n try {\n const url = new URL(input);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n // Not a URL, check if it's a file path\n // For file paths, we'll let parseOpenAPI handle it\n return input.length > 0;\n }\n}\n\n/**\n * Action handler for the generate command.\n * @param options - Command options\n */\nexport async function generateAction(options: {\n input: string;\n output: string;\n config?: string;\n verbose?: boolean;\n dryRun?: boolean;\n}) {\n const logger = new ConsoleLogger();\n\n // Handle signals\n process.on('SIGINT', () => {\n logger.error('Generation interrupted by user');\n process.exit(130);\n });\n\n // Validate input\n if (!validateInput(options.input)) {\n logger.error('Invalid input: must be a valid file path or HTTP/HTTPS URL');\n process.exit(2);\n }\n\n try {\n logger.info('Starting code generation...');\n const project = new Project();\n const generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n project,\n logger,\n };\n const codeGenerator = new CodeGenerator(generatorOptions);\n await codeGenerator.generate();\n logger.success(\n `Code generation completed successfully! Files generated in: ${options.output}`,\n );\n } catch (error) {\n logger.error(`Error during code generation: ${error}`);\n process.exit(1);\n }\n}","#!/usr/bin/env node\n\n/**\n * CLI entry point for the Fetcher OpenAPI code generator.\n * Sets up the commander program with generate command and handles execution.\n */\n\nimport { program } from 'commander';\nimport { generateAction } from './utils';\nimport packageJson from '../package.json';\n\n/**\n * Sets up the CLI program with all commands and options.\n * @returns The configured commander program instance\n */\nexport function setupCLI() {\n program\n .name('fetcher-generator')\n .description('OpenAPI Specification TypeScript code generator for Wow')\n .version(packageJson.version);\n\n program\n .command('generate')\n .description('Generate TypeScript code from OpenAPI specification')\n .requiredOption(\n '-i, --input <path>',\n 'Input OpenAPI specification file path or URL (http/https)',\n )\n .option('-o, --output <path>', 'Output directory path', 'src/generated')\n .option('-c, --config <file>', 'Configuration file path')\n .option('-v, --verbose', 'Enable verbose logging')\n .option('--dry-run', 'Show what would be generated without writing files')\n .action(generateAction);\n\n return program;\n}\n\n/**\n * Runs the CLI program by parsing command line arguments.\n * Only executes when this file is run directly (not imported).\n */\nexport function runCLI() {\n setupCLI().parse();\n}\n\nrunCLI();\n"],"names":["ConsoleLogger","message","params","timestamp","level","indent","current","total","countStr","validateInput","input","url","generateAction","options","logger","project","Project","generatorOptions","CodeGenerator","error","setupCLI","program","packageJson","runCLI"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"clientGenerator.d.ts","sourceRoot":"","sources":["../../src/client/clientGenerator.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAGzD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAG3C;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,iBAAiB;IACpD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAuB;IAC5D,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAyB;IAEhE;;;OAGG;gBACS,OAAO,EAAE,eAAe;IAMpC;;OAEG;IACH,QAAQ,IAAI,IAAI;IAahB;;;OAGG;IACH,qBAAqB,CAAC,YAAY,EAAE,MAAM;CAO3C"}
1
+ {"version":3,"file":"clientGenerator.d.ts","sourceRoot":"","sources":["../../src/client/clientGenerator.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAGzD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAG3C;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,iBAAiB;IACpD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAuB;IAC5D,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAyB;IAEhE;;;OAGG;gBACS,OAAO,EAAE,eAAe;IAMpC;;OAEG;IACH,QAAQ,IAAI,IAAI;IAqBhB;;;OAGG;IACH,qBAAqB,CAAC,YAAY,EAAE,MAAM;CAc3C"}