@ahoo-wang/fetcher-generator 2.10.8 → 2.11.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.
package/README.md CHANGED
@@ -62,10 +62,8 @@ fetcher-generator generate [options]
62
62
  - Supports HTTP/HTTPS URLs (e.g., `https://api.example.com/openapi.json`)
63
63
  - `-o, --output <path>`: Output directory path (default: `src/generated`)
64
64
  - `-c, --config <file>`: Configuration file path (optional)
65
- - `-v, --verbose`: Enable verbose logging during generation
66
- - `--dry-run`: Show what would be generated without writing files (reserved for future use)
67
65
  - `-h, --help`: Display help information
68
- - `-V, --version`: Display version number
66
+ - `-v, --version`: Display version number
69
67
 
70
68
  #### Examples
71
69
 
package/README.zh-CN.md CHANGED
@@ -63,10 +63,8 @@ fetcher-generator generate [options]
63
63
  - 支持 HTTP/HTTPS URL(例如:`https://api.example.com/openapi.json`)
64
64
  - `-o, --output <path>`:输出目录路径(默认为 `src/generated`)
65
65
  - `-c, --config <file>`:配置文件路径(可选)
66
- - `-v, --verbose`:启用详细日志记录
67
- - `--dry-run`:显示将要生成的内容而不写入文件(保留供将来使用)
68
66
  - `-h, --help`:显示帮助信息
69
- - `-V, --version`:显示版本号
67
+ - `-v, --version`:显示版本号
70
68
 
71
69
  #### 示例
72
70
 
package/dist/cli.cjs CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("commander"),a=require("./index.cjs");require("@ahoo-wang/fetcher");require("yaml");require("fs");require("path");class f{getTimestamp(){return new Date().toTimeString().slice(0,8)}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 i=this.getTimestamp(),r=" ".repeat(t);o.length>0?console.log(`[${i}] 🔄 ${r}${e}`,...o):console.log(`[${i}] 🔄 ${r}${e}`)}progressWithCount(e,t,o,i=0,...r){const s=this.getTimestamp(),p=" ".repeat(i),l=`[${e}/${t}]`;r.length>0?console.log(`[${s}] 🔄 ${p}${l} ${o}`,...r):console.log(`[${s}] 🔄 ${p}${l} ${o}`)}}function h(n){if(!n)return!1;try{const e=new URL(n);return e.protocol==="http:"||e.protocol==="https:"}catch{return n.length>0}}async function d(n){const e=new f;process.on("SIGINT",()=>{e.error("Generation interrupted by user"),process.exit(130)}),h(n.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={inputPath:n.input,outputDir:n.output,configPath:n.config,tsConfigFilePath:n.tsConfigFilePath,logger:e};await new a.CodeGenerator(t).generate(),e.success(`Code generation completed successfully! Files generated in: ${n.output}`)}catch(t){e.error(`Error during code generation: ${t}`),process.exit(1)}}const $="2.10.8",m={version:$};function u(){return c.program.name("fetcher-generator").description("OpenAPI Specification TypeScript code generator for Wow").version(m.version),c.program.command("generate").description("Generate TypeScript code from OpenAPI specification").requiredOption("-i, --input <file>","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",a.DEFAULT_CONFIG_PATH).option("-t, --ts-config-file-path <file>","TypeScript configuration file path").option("-v, --verbose","Enable verbose logging").option("--dry-run","Show what would be generated without writing files").action(d),c.program}function g(){u().parse()}g();exports.runCLI=g;exports.setupCLI=u;
2
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("commander"),a=require("./index.cjs");require("@ahoo-wang/fetcher");require("yaml");require("fs");require("path");class f{getTimestamp(){return new Date().toTimeString().slice(0,8)}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 i=this.getTimestamp(),r=" ".repeat(t);o.length>0?console.log(`[${i}] 🔄 ${r}${e}`,...o):console.log(`[${i}] 🔄 ${r}${e}`)}progressWithCount(e,t,o,i=0,...r){const s=this.getTimestamp(),p=" ".repeat(i),l=`[${e}/${t}]`;r.length>0?console.log(`[${s}] 🔄 ${p}${l} ${o}`,...r):console.log(`[${s}] 🔄 ${p}${l} ${o}`)}}function h(n){if(!n)return!1;try{const e=new URL(n);return e.protocol==="http:"||e.protocol==="https:"}catch{return n.length>0}}async function $(n){const e=new f;process.on("SIGINT",()=>{e.error("Generation interrupted by user"),process.exit(130)}),h(n.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={inputPath:n.input,outputDir:n.output,configPath:n.config,tsConfigFilePath:n.tsConfigFilePath,logger:e};await new a.CodeGenerator(t).generate(),e.success(`Code generation completed successfully! Files generated in: ${n.output}`)}catch(t){e.error(`Error during code generation: ${t}`),process.exit(1)}}const d="2.11.0",m={version:d};function u(){return c.program.name("fetcher-generator").description("OpenAPI Specification TypeScript code generator for Wow").version(m.version,"-v, --version"),c.program.command("generate").description("Generate TypeScript code from OpenAPI specification").requiredOption("-i, --input <file>","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",a.DEFAULT_CONFIG_PATH).option("-t, --ts-config-file-path <file>","TypeScript configuration file path").action($),c.program}function g(){u().parse()}g();exports.runCLI=g;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 private getTimestamp(): string {\n return new Date().toTimeString().slice(0, 8); // 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 { CodeGenerator } from '../index';\nimport { GeneratorOptions } from '../types';\nimport { ConsoleLogger } from './logger';\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 tsConfigFilePath?: 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 generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n configPath: options.config,\n tsConfigFilePath: options.tsConfigFilePath,\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}\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 packageJson from '../package.json';\nimport { DEFAULT_CONFIG_PATH } from './index';\nimport { generateAction } from './utils';\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 <file>',\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', DEFAULT_CONFIG_PATH)\n .option('-t, --ts-config-file-path <file>', 'TypeScript 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","generatorOptions","CodeGenerator","error","setupCLI","program","packageJson","DEFAULT_CONFIG_PATH","runCLI"],"mappings":"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"}
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().toTimeString().slice(0, 8); // 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 { CodeGenerator } from '../index';\nimport { GeneratorOptions } from '../types';\nimport { ConsoleLogger } from './logger';\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 tsConfigFilePath?: string;\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 generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n configPath: options.config,\n tsConfigFilePath: options.tsConfigFilePath,\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}\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 packageJson from '../package.json';\nimport { DEFAULT_CONFIG_PATH } from './index';\nimport { generateAction } from './utils';\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,'-v, --version');\n\n program\n .command('generate')\n .description('Generate TypeScript code from OpenAPI specification')\n .requiredOption(\n '-i, --input <file>',\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', DEFAULT_CONFIG_PATH)\n .option('-t, --ts-config-file-path <file>', 'TypeScript configuration file path')\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","generatorOptions","CodeGenerator","error","setupCLI","program","packageJson","DEFAULT_CONFIG_PATH","runCLI"],"mappings":"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"}
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;AAOH;;;GAGG;AACH,wBAAgB,QAAQ,gCAqBvB;AAED;;;GAGG;AACH,wBAAgB,MAAM,SAErB"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAOH;;;GAGG;AACH,wBAAgB,QAAQ,gCAmBvB;AAED;;;GAGG;AACH,wBAAgB,MAAM,SAErB"}
package/dist/cli.js CHANGED
@@ -63,14 +63,14 @@ async function h(n) {
63
63
  e.error(`Error during code generation: ${t}`), process.exit(1);
64
64
  }
65
65
  }
66
- const $ = "2.10.8", m = {
66
+ const $ = "2.11.0", m = {
67
67
  version: $
68
68
  };
69
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(
70
+ return c.name("fetcher-generator").description("OpenAPI Specification TypeScript code generator for Wow").version(m.version, "-v, --version"), c.command("generate").description("Generate TypeScript code from OpenAPI specification").requiredOption(
71
71
  "-i, --input <file>",
72
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", g).option("-t, --ts-config-file-path <file>", "TypeScript configuration file path").option("-v, --verbose", "Enable verbose logging").option("--dry-run", "Show what would be generated without writing files").action(h), c;
73
+ ).option("-o, --output <path>", "Output directory path", "src/generated").option("-c, --config <file>", "Configuration file path", g).option("-t, --ts-config-file-path <file>", "TypeScript configuration file path").action(h), c;
74
74
  }
75
75
  function T() {
76
76
  d().parse();
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 private getTimestamp(): string {\n return new Date().toTimeString().slice(0, 8); // 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 { CodeGenerator } from '../index';\nimport { GeneratorOptions } from '../types';\nimport { ConsoleLogger } from './logger';\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 tsConfigFilePath?: 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 generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n configPath: options.config,\n tsConfigFilePath: options.tsConfigFilePath,\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}\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 packageJson from '../package.json';\nimport { DEFAULT_CONFIG_PATH } from './index';\nimport { generateAction } from './utils';\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 <file>',\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', DEFAULT_CONFIG_PATH)\n .option('-t, --ts-config-file-path <file>', 'TypeScript 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","generatorOptions","CodeGenerator","error","setupCLI","program","packageJson","DEFAULT_CONFIG_PATH","runCLI"],"mappings":"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"}
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().toTimeString().slice(0, 8); // 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 { CodeGenerator } from '../index';\nimport { GeneratorOptions } from '../types';\nimport { ConsoleLogger } from './logger';\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 tsConfigFilePath?: string;\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 generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n configPath: options.config,\n tsConfigFilePath: options.tsConfigFilePath,\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}\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 packageJson from '../package.json';\nimport { DEFAULT_CONFIG_PATH } from './index';\nimport { generateAction } from './utils';\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,'-v, --version');\n\n program\n .command('generate')\n .description('Generate TypeScript code from OpenAPI specification')\n .requiredOption(\n '-i, --input <file>',\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', DEFAULT_CONFIG_PATH)\n .option('-t, --ts-config-file-path <file>', 'TypeScript configuration file path')\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","generatorOptions","CodeGenerator","error","setupCLI","program","packageJson","DEFAULT_CONFIG_PATH","runCLI"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -1,12 +1,12 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("ts-morph"),h=require("@ahoo-wang/fetcher"),G=require("@ahoo-wang/fetcher-wow"),V=require("yaml"),pe=require("fs"),W=require("path");function I(o){return o.$ref.split("/").pop()}function v(o,e){const t=I(o);return e.schemas?.[t]}function K(o,e){const t=I(o);return e.requestBodies?.[t]}function H(o,e){const t=I(o);return e.parameters?.[t]}function E(o,e){return{key:I(o),schema:v(o,e)}}const L=/[-_\s.]+/;function q(o){return Array.isArray(o)?o.flatMap(e=>z(e.split(L))):z(o.split(L))}function z(o){return o.flatMap(e=>{if(e.length===0)return[];const t=[];let n="";for(let r=0;r<e.length;r++){const i=e[r],s=/[A-Z]/.test(i),a=r>0&&/[a-z]/.test(e[r-1]);s&&a&&n?(t.push(n),n=i):n+=i}return n&&t.push(n),t})}function C(o){return o===""||o.length===0?"":q(o).filter(t=>t.length>0).map(t=>{const n=t.charAt(0),r=t.slice(1);return(/[a-zA-Z]/.test(n)?n.toUpperCase():n)+r.toLowerCase()}).join("")}function y(o){const e=C(o);return e.charAt(0).toLowerCase()+e.slice(1)}function me(o){return o===""||Array.isArray(o)&&o.length===0?"":q(o).filter(t=>t.length>0).map(t=>t.toUpperCase()).join("_")}function g(o){return!!(o&&typeof o=="object"&&"$ref"in o)}function M(o,e){if(e&&!g(e)&&e.content)return e.content[o]?.schema}function Y(o){return M(h.ContentTypeValues.APPLICATION_JSON,o)}function de(o){return M(h.ContentTypeValues.TEXT_EVENT_STREAM,o)}function fe(o){return M("*/*",o)}const he=["string","number","integer","boolean","null"];function j(o){return Array.isArray(o)?!0:he.includes(o)}function O(o){return o.type==="array"}function ye(o){return Array.isArray(o.enum)&&o.enum.length>0}function X(o){return Array.isArray(o.anyOf)&&o.anyOf.length>0}function Z(o){return Array.isArray(o.oneOf)&&o.oneOf.length>0}function xe(o){return X(o)||Z(o)}function Ae(o){return Array.isArray(o.allOf)&&o.allOf.length>0}function U(o){return X(o)||Z(o)||Ae(o)}function B(o){return o.includes("|")||o.includes("&")?`(${o})[]`:`${o}[]`}function Ce(o){return o.type!=="object"?!1:o.properties?Object.keys(o.properties).length===0:!0}function P(o){if(Array.isArray(o))return o.map(e=>P(e)).join(" | ");switch(o){case"string":return"string";case"number":case"integer":return"number";case"boolean":return"boolean";case"null":return"null";default:return"any"}}function N(o){return[{method:"get",operation:o.get},{method:"put",operation:o.put},{method:"post",operation:o.post},{method:"delete",operation:o.delete},{method:"options",operation:o.options},{method:"head",operation:o.head},{method:"patch",operation:o.patch},{method:"trace",operation:o.trace}].filter(({operation:e})=>e!==void 0)}function _(o){return o.responses[200]}function k(o){const e=_(o);return Y(e)}function Pe(o,e){return o.parameters?o.parameters.map(t=>g(t)?H(t,e):t).filter(t=>t.in==="path"):[]}const $e="string";function ee(o){return!o.schema||g(o.schema)||!o.schema.type||!j(o.schema.type)?$e:P(o.schema.type)}function te(o){return o.startsWith("http://")||o.startsWith("https://")?Te(o):Ie(o)}async function Te(o){return await(await fetch(o)).text()}function Ie(o){return new Promise((e,t)=>{pe.readFile(o,"utf-8",(n,r)=>{n?t(n):e(r)})})}async function Ee(o){const e=await te(o);switch(ne(e)){case"json":return JSON.parse(e);case"yaml":return V.parse(e);default:throw new Error(`Unsupported file format: ${o}`)}}async function Se(o){const e=await te(o);switch(ne(e)){case"json":return JSON.parse(e);case"yaml":return V.parse(e);default:throw new Error(`Unsupported file format: ${o}`)}}function ne(o){const e=o.trimStart();if(e.startsWith("{")||e.startsWith("["))return"json";if(e.startsWith("-")||e.startsWith("%YAML"))return"yaml";try{return JSON.parse(e),"json"}catch{if(e.length>0)return"yaml"}throw new Error("Unable to infer file format")}const oe="types.ts",ve="@";function Re(o){return h.combineURLs(o.path,oe)}function re(o,e,t){const n=h.combineURLs(e,t),r=o.getSourceFile(n);return r||o.createSourceFile(n,"",{overwrite:!0})}function $(o,e,t){let n=o.getImportDeclaration(r=>r.getModuleSpecifierValue()===e);n||(n=o.addImportDeclaration({moduleSpecifier:e})),t.forEach(r=>{n.getNamedImports().some(s=>s.getName()===r)||n.addNamedImport(r)})}function f(o,e,t){if(t.path.startsWith(ve)){$(o,t.path,[t.name]);return}const n=o.getDirectoryPath(),r=W.join(e,t.path,oe);let i=W.relative(n,r);i=i.replace(/\.ts$/,""),i.startsWith(".")||(i="./"+i),$(o,i,[t.name])}function S(o,e,t,n){o.path!==n.path&&f(e,t,n)}function we(o){if(!Array.isArray(o))return;const e=o.filter(t=>typeof t=="string"&&t.length>0);return e.length>0?e.join(`
2
- `):void 0}function R(o,e){const t=we(e);t&&o.addJsDoc(t)}function w(o,e){const t=[e.title,e.description];e.format&&t.push(`- format: ${e.format}`),Q(t,e,"default"),Q(t,e,"example"),Oe(t,e),Ne(t,e),De(t,e),R(o,t)}function Q(o,e,t){const n=e[t];if(n){if(typeof n!="object"){o.push(`- ${t}: \`${n}\``);return}o.push(`- ${t}: `),o.push("```json"),o.push(JSON.stringify(n)),o.push("```")}}function Oe(o,e){const t=["- Numeric Constraints"];e.minimum!==void 0&&t.push(` - minimum: ${e.minimum}`),e.maximum!==void 0&&t.push(` - maximum: ${e.maximum}`),e.exclusiveMinimum!==void 0&&t.push(` - exclusiveMinimum: ${e.exclusiveMinimum}`),e.exclusiveMaximum!==void 0&&t.push(` - exclusiveMaximum: ${e.exclusiveMaximum}`),e.multipleOf!==void 0&&t.push(` - multipleOf: ${e.multipleOf}`),t.length!==1&&o.push(...t)}function Ne(o,e){const t=["- String Constraints"];e.minLength!==void 0&&t.push(` - minLength: ${e.minLength}`),e.maxLength!==void 0&&t.push(` - maxLength: ${e.maxLength}`),e.pattern!==void 0&&t.push(` - pattern: ${e.pattern}`),t.length!==1&&o.push(...t)}function De(o,e){const t=["- Array Constraints"];e.minItems!==void 0&&t.push(` - minItems: ${e.minItems}`),e.maxItems!==void 0&&t.push(` - maxItems: ${e.maxItems}`),e.uniqueItems!==void 0&&t.push(` - uniqueItems: ${e.uniqueItems}`),t.length!==1&&o.push(...t)}function be(o){const e=o.split(".");return e.length!=2||e[0].length===0||e[1].length===0?null:e}function qe(o){const e=be(o.name);return e?{tag:o,contextAlias:e[0],aggregateName:e[1]}:null}function Me(o){const e=o?.map(n=>qe(n)).filter(n=>n!==null);if(!e)return new Map;const t=new Map;return e.forEach(n=>{t.set(n.tag.name,{aggregate:n,commands:new Map,events:new Map})}),t}function je(o){if(!o)return null;const e=o.split(".");return e.length!=3?null:e[2]}const _e="#/components/responses/wow.CommandOk",Fe="#/components/parameters/wow.id";class Ge{constructor(e){this.openAPI=e,this.aggregates=Me(e.tags),this.build()}aggregates;build(){for(const[e,t]of Object.entries(this.openAPI.paths)){const n=N(t);for(const r of n)this.commands(e,r),this.state(r.operation),this.events(r.operation),this.fields(r.operation)}}resolve(){const e=new Map;for(const t of this.aggregates.values()){if(!t.state||!t.fields)continue;const n=t.aggregate.contextAlias;let r=e.get(n);r||(r=new Set,e.set(n,r)),r.add(t)}return e}commands(e,t){const n=t.operation;if(n.operationId==="wow.command.send")return;const r=je(n.operationId);if(!r)return;const i=_(n);if(!i||!g(i)||i.$ref!==_e||!n.requestBody)return;const s=n.parameters??[],a=s.filter(m=>g(m)&&m.$ref===Fe).at(0),c=s.filter(m=>!g(m)&&m.in==="path");if(a){const m=H(a,this.openAPI.components);c.push(m)}const l=n.requestBody.content[h.ContentTypeValues.APPLICATION_JSON].schema,p=E(l,this.openAPI.components);p.schema.title=p.schema.title||n.summary,p.schema.description=p.schema.description||n.description;const le={name:r,method:t.method,path:e,pathParameters:c,summary:n.summary,description:n.description,schema:p,operation:n};n.tags?.forEach(m=>{const F=this.aggregates.get(m);F&&F.commands.set(r,le)})}state(e){if(!e.operationId?.endsWith(".snapshot_state.single"))return;const t=k(e);if(!g(t))return;const n=E(t,this.openAPI.components);e.tags?.forEach(r=>{const i=this.aggregates.get(r);i&&(i.state=n)})}events(e){if(!this.openAPI.components||!e.operationId?.endsWith(".event.list_query"))return;const t=k(e);if(g(t))return;const n=t?.items;if(!g(n))return;const i=v(n,this.openAPI.components).properties.body.items.anyOf.map(s=>{const a=s.title,c=s.properties.name.const,u=s.properties.body,l=E(u,this.openAPI.components);return l.schema.title=l.schema.title||s.title,{title:a,name:c,schema:l}});e.tags?.forEach(s=>{const a=this.aggregates.get(s);a&&i.forEach(c=>{a.events.set(c.name,c)})})}fields(e){if(!this.openAPI.components||!e.operationId?.endsWith(".snapshot.count"))return;const n=K(e.requestBody,this.openAPI.components).content[h.ContentTypeValues.APPLICATION_JSON].schema,i=v(n,this.openAPI.components).properties?.field,s=E(i,this.openAPI.components);e.tags?.forEach(a=>{const c=this.aggregates.get(a);c&&(c.fields=s)})}}const T="@ahoo-wang/fetcher-wow",We={"wow.command.CommandResult":"CommandResult","wow.MessageHeaderSqlType":"MessageHeaderSqlType","wow.api.BindingError":"BindingError","wow.api.DefaultErrorInfo":"ErrorInfo","wow.api.RecoverableType":"RecoverableType","wow.api.command.DefaultDeleteAggregate":"DeleteAggregate","wow.api.command.DefaultRecoverAggregate":"RecoverAggregate","wow.api.messaging.FunctionInfoData":"FunctionInfo","wow.api.messaging.FunctionKind":"FunctionKind","wow.api.modeling.AggregateId":"AggregateId","wow.api.query.Condition":"Condition","wow.api.query.ConditionOptions":"ConditionOptions","wow.api.query.ListQuery":"ListQuery","wow.api.query.Operator":"Operator","wow.api.query.PagedQuery":"PagedQuery","wow.api.query.Pagination":"Pagination","wow.api.query.Projection":"Projection","wow.api.query.Sort":"FieldSort","wow.api.query.Sort.Direction":"SortDirection","wow.command.CommandStage":"CommandStage","wow.command.SimpleWaitSignal":"WaitSignal","wow.configuration.Aggregate":"Aggregate","wow.configuration.BoundedContext":"BoundedContext","wow.configuration.WowMetadata":"WowMetadata","wow.modeling.DomainEvent":"DomainEvent","wow.openapi.BatchResult":"BatchResult","wow.messaging.CompensationTarget":"CompensationTarget"};function d(o){if(!o)return{name:"",path:"/"};const e=We[o];if(e)return{name:e,path:T};const t=o.split(".");let n=-1;for(let c=0;c<t.length;c++)if(t[c]&&/^[A-Z]/.test(t[c])){n=c;break}const r=t.slice(0,n),i=r.length>0?`/${r.join("/")}`:"/",s=t.slice(n);return{name:C(s),path:i}}function x(o){const e=I(o);return d(e)}class Le{constructor(e){this.context=e}getOrCreateSourceFile(e){const t=Re(e);return this.context.getOrCreateSourceFile(t)}generate(){const e=this.context.openAPI.components?.schemas;if(!e){this.context.logger.info("No schemas found in OpenAPI specification");return}const t=this.stateAggregatedTypeNames(),n=this.filterSchemas(e,t);this.context.logger.progress(`Generating models for ${n.length} schemas`),n.forEach((r,i)=>{this.context.logger.progressWithCount(i+1,n.length,`Processing schema: ${r.key}`,2),this.generateKeyedSchema(r)}),this.context.logger.success("Model generation completed")}filterSchemas(e,t){return Object.entries(e).map(([n,r])=>({key:n,schema:r})).filter(n=>!this.isWowSchema(n.key,t))}isWowSchema(e,t){if(e.startsWith("wow.")||e.endsWith("AggregatedCondition")||e.endsWith("AggregatedDomainEventStream")||e.endsWith("AggregatedDomainEventStreamPagedList")||e.endsWith("AggregatedDomainEventStreamServerSentEventNonNullData")||e.endsWith("AggregatedListQuery")||e.endsWith("AggregatedPagedQuery")||e.endsWith("AggregatedSingleQuery"))return!0;const n=d(e);return t.has(n.name)}aggregatedSchemaSuffix=["MaterializedSnapshot","MaterializedSnapshotPagedList","MaterializedSnapshotServerSentEventNonNullData","PagedList","ServerSentEventNonNullData","Snapshot","StateEvent"];stateAggregatedTypeNames(){const e=new Set;for(const t of this.context.contextAggregates.values())for(const n of t)this.aggregatedSchemaSuffix.forEach(r=>{const i=d(n.state.key),s=C(i.name)+r;e.add(s)});return e}generateKeyedSchema({key:e,schema:t}){const n=d(e),r=this.getOrCreateSourceFile(n),i=this.process(n,r,t);i&&w(i,t)}process(e,t,n){if(ye(n))return t.addEnum({name:e.name,isExported:!0,members:n.enum.filter(i=>typeof i=="string"&&i.length>0).map(i=>({name:me(i),initializer:`'${i}'`}))});if(O(n)&&g(n.items)){const i=x(n.items);return S(e,t,this.context.outputDir,i),t.addTypeAlias({name:e.name,type:B(i.name),isExported:!0})}const r=t.addInterface({name:e.name,isExported:!0});return n.type==="object"&&n.properties?this.processInterface(t,e,n,r):(U(n)&&(n.anyOf||n.oneOf||n.allOf).forEach(s=>{if(g(s)){const a=x(s);S(e,t,this.context.outputDir,a),r.addExtends(a.name);return}this.processInterface(t,e,s,r)}),r)}processObject(e,t,n){const r=e.addInterface({name:t.name,isExported:!0});return this.processInterface(e,t,n,r)}processInterface(e,t,n,r){for(const[i,s]of Object.entries(n.properties)){const a=this.resolvePropertyType(t,e,i,s);let c=r.getProperty(i);c?c.setType(a):c=r.addProperty({name:i,type:a}),g(s)||w(c,s)}return r}resolvePropertyType(e,t,n,r){if(g(r)){const i=x(r);return S(e,t,this.context.outputDir,i),i.name}if(r.const)return`'${r.const}'`;if(O(r)){const i=this.resolvePropertyType(e,t,n,r.items);return B(i)}if(r.type&&j(r.type))return P(r.type);if(U(r))return this.resolvePropertyCompositionType(e,t,r);if(r.type==="object"&&r.properties){const i={path:e.path,name:`${e.name}${C(n)}`},s=this.processObject(t,i,r);return w(s,r),i.name}return"any"}resolvePropertyCompositionType(e,t,n){const r=n.anyOf||n.oneOf||n.allOf,i=new Set;r.forEach(a=>{if(g(a)){const c=x(a);S(e,t,this.context.outputDir,c),i.add(c.name);return}i.add(P(a.type??"string"))});const s=xe(n)?"|":"&";return Array.from(i).join(s)}}const ze="@ahoo-wang/fetcher-decorator",Ue=["type ApiMetadata","type ApiMetadataCapable","type ParameterRequest","api","get","post","put","patch","del","request","attribute","path","autoGeneratedError"],Be={type:"Promise<Response>",metadata:"{resultExtractor: ResultExtractors.Response }"},J={type:"Promise<string>",metadata:"{resultExtractor: ResultExtractors.Text }"},D=`{
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("ts-morph"),h=require("@ahoo-wang/fetcher"),G=require("@ahoo-wang/fetcher-wow"),J=require("yaml"),pe=require("fs"),W=require("path");function I(o){return o.$ref.split("/").pop()}function v(o,e){const t=I(o);return e.schemas?.[t]}function V(o,e){const t=I(o);return e.requestBodies?.[t]}function K(o,e){const t=I(o);return e.parameters?.[t]}function E(o,e){return{key:I(o),schema:v(o,e)}}const me=/[-_\s.]+/;function O(o){return o.split(me)}function H(o){return Array.isArray(o)?o.flatMap(e=>L(O(e))):L(O(o))}function L(o){return o.flatMap(e=>{if(e.length===0)return[];const t=[];let n="";for(let r=0;r<e.length;r++){const i=e[r],s=/[A-Z]/.test(i),a=r>0&&/[a-z]/.test(e[r-1]);s&&a&&n?(t.push(n),n=i):n+=i}return n&&t.push(n),t})}function C(o){return o===""||o.length===0?"":H(o).filter(t=>t.length>0).map(t=>{const n=t.charAt(0),r=t.slice(1);return(/[a-zA-Z]/.test(n)?n.toUpperCase():n)+r.toLowerCase()}).join("")}function y(o){const e=C(o);return e.charAt(0).toLowerCase()+e.slice(1)}function de(o){return o===""||Array.isArray(o)&&o.length===0?"":H(o).filter(t=>t.length>0).map(t=>t.toUpperCase()).join("_")}function g(o){return!!(o&&typeof o=="object"&&"$ref"in o)}function M(o,e){if(e&&!g(e)&&e.content)return e.content[o]?.schema}function Y(o){return M(h.ContentTypeValues.APPLICATION_JSON,o)}function fe(o){return M(h.ContentTypeValues.TEXT_EVENT_STREAM,o)}function he(o){return M("*/*",o)}const ye=["string","number","integer","boolean","null"];function j(o){return Array.isArray(o)?!0:ye.includes(o)}function N(o){return o.type==="array"}function xe(o){return Array.isArray(o.enum)&&o.enum.length>0}function X(o){return Array.isArray(o.anyOf)&&o.anyOf.length>0}function Z(o){return Array.isArray(o.oneOf)&&o.oneOf.length>0}function Ae(o){return X(o)||Z(o)}function Ce(o){return Array.isArray(o.allOf)&&o.allOf.length>0}function z(o){return X(o)||Z(o)||Ce(o)}function U(o){return o.includes("|")||o.includes("&")?`(${o})[]`:`${o}[]`}function Pe(o){return o.type!=="object"?!1:o.properties?Object.keys(o.properties).length===0:!0}function P(o){if(Array.isArray(o))return o.map(e=>P(e)).join(" | ");switch(o){case"string":return"string";case"number":case"integer":return"number";case"boolean":return"boolean";case"null":return"null";default:return"any"}}function D(o){return[{method:"get",operation:o.get},{method:"put",operation:o.put},{method:"post",operation:o.post},{method:"delete",operation:o.delete},{method:"options",operation:o.options},{method:"head",operation:o.head},{method:"patch",operation:o.patch},{method:"trace",operation:o.trace}].filter(({operation:e})=>e!==void 0)}function _(o){return o.responses[200]}function k(o){const e=_(o);return Y(e)}function $e(o,e){return o.parameters?o.parameters.map(t=>g(t)?K(t,e):t).filter(t=>t.in==="path"):[]}const Te="string";function ee(o){return!o.schema||g(o.schema)||!o.schema.type||!j(o.schema.type)?Te:P(o.schema.type)}function te(o){return o.startsWith("http://")||o.startsWith("https://")?Ie(o):Ee(o)}async function Ie(o){return await(await fetch(o)).text()}function Ee(o){return new Promise((e,t)=>{pe.readFile(o,"utf-8",(n,r)=>{n?t(n):e(r)})})}async function Se(o){const e=await te(o);switch(ne(e)){case"json":return JSON.parse(e);case"yaml":return J.parse(e);default:throw new Error(`Unsupported file format: ${o}`)}}async function ve(o){const e=await te(o);switch(ne(e)){case"json":return JSON.parse(e);case"yaml":return J.parse(e);default:throw new Error(`Unsupported file format: ${o}`)}}function ne(o){const e=o.trimStart();if(e.startsWith("{")||e.startsWith("["))return"json";if(e.startsWith("-")||e.startsWith("%YAML"))return"yaml";try{return JSON.parse(e),"json"}catch{if(e.length>0)return"yaml"}throw new Error("Unable to infer file format")}const oe="types.ts",Re="@";function we(o){return h.combineURLs(o.path,oe)}function re(o,e,t){const n=h.combineURLs(e,t),r=o.getSourceFile(n);return r||o.createSourceFile(n,"",{overwrite:!0})}function $(o,e,t){let n=o.getImportDeclaration(r=>r.getModuleSpecifierValue()===e);n||(n=o.addImportDeclaration({moduleSpecifier:e})),t.forEach(r=>{n.getNamedImports().some(s=>s.getName()===r)||n.addNamedImport(r)})}function f(o,e,t){if(t.path.startsWith(Re)){$(o,t.path,[t.name]);return}const n=o.getDirectoryPath(),r=W.join(e,t.path,oe);let i=W.relative(n,r);i=i.replace(/\.ts$/,""),i.startsWith(".")||(i="./"+i),$(o,i,[t.name])}function S(o,e,t,n){o.path!==n.path&&f(e,t,n)}function Oe(o){if(!Array.isArray(o))return;const e=o.filter(t=>typeof t=="string"&&t.length>0);return e.length>0?e.join(`
2
+ `):void 0}function R(o,e){const t=Oe(e);t&&o.addJsDoc(t)}function w(o,e){const t=[e.title,e.description];e.format&&t.push(`- format: ${e.format}`),B(t,e,"default"),B(t,e,"example"),Ne(t,e),De(t,e),be(t,e),R(o,t)}function B(o,e,t){const n=e[t];if(n){if(typeof n!="object"){o.push(`- ${t}: \`${n}\``);return}o.push(`- ${t}: `),o.push("```json"),o.push(JSON.stringify(n)),o.push("```")}}function Ne(o,e){const t=["- Numeric Constraints"];e.minimum!==void 0&&t.push(` - minimum: ${e.minimum}`),e.maximum!==void 0&&t.push(` - maximum: ${e.maximum}`),e.exclusiveMinimum!==void 0&&t.push(` - exclusiveMinimum: ${e.exclusiveMinimum}`),e.exclusiveMaximum!==void 0&&t.push(` - exclusiveMaximum: ${e.exclusiveMaximum}`),e.multipleOf!==void 0&&t.push(` - multipleOf: ${e.multipleOf}`),t.length!==1&&o.push(...t)}function De(o,e){const t=["- String Constraints"];e.minLength!==void 0&&t.push(` - minLength: ${e.minLength}`),e.maxLength!==void 0&&t.push(` - maxLength: ${e.maxLength}`),e.pattern!==void 0&&t.push(` - pattern: ${e.pattern}`),t.length!==1&&o.push(...t)}function be(o,e){const t=["- Array Constraints"];e.minItems!==void 0&&t.push(` - minItems: ${e.minItems}`),e.maxItems!==void 0&&t.push(` - maxItems: ${e.maxItems}`),e.uniqueItems!==void 0&&t.push(` - uniqueItems: ${e.uniqueItems}`),t.length!==1&&o.push(...t)}function qe(o){const e=o.split(".");return e.length!=2||e[0].length===0||e[1].length===0?null:e}function Me(o){const e=qe(o.name);return e?{tag:o,contextAlias:e[0],aggregateName:e[1]}:null}function je(o){const e=o?.map(n=>Me(n)).filter(n=>n!==null);if(!e)return new Map;const t=new Map;return e.forEach(n=>{t.set(n.tag.name,{aggregate:n,commands:new Map,events:new Map})}),t}function _e(o){if(!o)return null;const e=o.split(".");return e.length!=3?null:e[2]}const Fe="#/components/responses/wow.CommandOk",Ge="#/components/parameters/wow.id";class We{constructor(e){this.openAPI=e,this.aggregates=je(e.tags),this.build()}aggregates;build(){for(const[e,t]of Object.entries(this.openAPI.paths)){const n=D(t);for(const r of n)this.commands(e,r),this.state(r.operation),this.events(r.operation),this.fields(r.operation)}}resolve(){const e=new Map;for(const t of this.aggregates.values()){if(!t.state||!t.fields)continue;const n=t.aggregate.contextAlias;let r=e.get(n);r||(r=new Set,e.set(n,r)),r.add(t)}return e}commands(e,t){const n=t.operation;if(n.operationId==="wow.command.send")return;const r=_e(n.operationId);if(!r)return;const i=_(n);if(!i||!g(i)||i.$ref!==Fe||!n.requestBody)return;const s=n.parameters??[],a=s.filter(m=>g(m)&&m.$ref===Ge).at(0),c=s.filter(m=>!g(m)&&m.in==="path");if(a){const m=K(a,this.openAPI.components);c.push(m)}const l=n.requestBody.content[h.ContentTypeValues.APPLICATION_JSON].schema,p=E(l,this.openAPI.components);p.schema.title=p.schema.title||n.summary,p.schema.description=p.schema.description||n.description;const le={name:r,method:t.method,path:e,pathParameters:c,summary:n.summary,description:n.description,schema:p,operation:n};n.tags?.forEach(m=>{const F=this.aggregates.get(m);F&&F.commands.set(r,le)})}state(e){if(!e.operationId?.endsWith(".snapshot_state.single"))return;const t=k(e);if(!g(t))return;const n=E(t,this.openAPI.components);e.tags?.forEach(r=>{const i=this.aggregates.get(r);i&&(i.state=n)})}events(e){if(!this.openAPI.components||!e.operationId?.endsWith(".event.list_query"))return;const t=k(e);if(g(t))return;const n=t?.items;if(!g(n))return;const i=v(n,this.openAPI.components).properties.body.items.anyOf.map(s=>{const a=s.title,c=s.properties.name.const,u=s.properties.body,l=E(u,this.openAPI.components);return l.schema.title=l.schema.title||s.title,{title:a,name:c,schema:l}});e.tags?.forEach(s=>{const a=this.aggregates.get(s);a&&i.forEach(c=>{a.events.set(c.name,c)})})}fields(e){if(!this.openAPI.components||!e.operationId?.endsWith(".snapshot.count"))return;const n=V(e.requestBody,this.openAPI.components).content[h.ContentTypeValues.APPLICATION_JSON].schema,i=v(n,this.openAPI.components).properties?.field,s=E(i,this.openAPI.components);e.tags?.forEach(a=>{const c=this.aggregates.get(a);c&&(c.fields=s)})}}const T="@ahoo-wang/fetcher-wow",Le={"wow.command.CommandResult":"CommandResult","wow.MessageHeaderSqlType":"MessageHeaderSqlType","wow.api.BindingError":"BindingError","wow.api.DefaultErrorInfo":"ErrorInfo","wow.api.RecoverableType":"RecoverableType","wow.api.command.DefaultDeleteAggregate":"DeleteAggregate","wow.api.command.DefaultRecoverAggregate":"RecoverAggregate","wow.api.messaging.FunctionInfoData":"FunctionInfo","wow.api.messaging.FunctionKind":"FunctionKind","wow.api.modeling.AggregateId":"AggregateId","wow.api.query.Condition":"Condition","wow.api.query.ConditionOptions":"ConditionOptions","wow.api.query.ListQuery":"ListQuery","wow.api.query.Operator":"Operator","wow.api.query.PagedQuery":"PagedQuery","wow.api.query.Pagination":"Pagination","wow.api.query.Projection":"Projection","wow.api.query.Sort":"FieldSort","wow.api.query.Sort.Direction":"SortDirection","wow.command.CommandStage":"CommandStage","wow.command.SimpleWaitSignal":"WaitSignal","wow.configuration.Aggregate":"Aggregate","wow.configuration.BoundedContext":"BoundedContext","wow.configuration.WowMetadata":"WowMetadata","wow.modeling.DomainEvent":"DomainEvent","wow.openapi.BatchResult":"BatchResult","wow.messaging.CompensationTarget":"CompensationTarget"};function d(o){if(!o)return{name:"",path:"/"};const e=Le[o];if(e)return{name:e,path:T};const t=o.split(".");let n=-1;for(let c=0;c<t.length;c++)if(t[c]&&/^[A-Z]/.test(t[c])){n=c;break}const r=t.slice(0,n),i=r.length>0?`/${r.join("/")}`:"/",s=t.slice(n);return{name:C(s),path:i}}function x(o){const e=I(o);return d(e)}class ze{constructor(e){this.context=e}getOrCreateSourceFile(e){const t=we(e);return this.context.getOrCreateSourceFile(t)}generate(){const e=this.context.openAPI.components?.schemas;if(!e){this.context.logger.info("No schemas found in OpenAPI specification");return}const t=this.stateAggregatedTypeNames(),n=this.filterSchemas(e,t);this.context.logger.progress(`Generating models for ${n.length} schemas`),n.forEach((r,i)=>{this.context.logger.progressWithCount(i+1,n.length,`Processing schema: ${r.key}`,2),this.generateKeyedSchema(r)}),this.context.logger.success("Model generation completed")}filterSchemas(e,t){return Object.entries(e).map(([n,r])=>({key:n,schema:r})).filter(n=>!this.isWowSchema(n.key,t))}isWowSchema(e,t){if(e.startsWith("wow.")||e.endsWith("AggregatedCondition")||e.endsWith("AggregatedDomainEventStream")||e.endsWith("AggregatedDomainEventStreamPagedList")||e.endsWith("AggregatedDomainEventStreamServerSentEventNonNullData")||e.endsWith("AggregatedListQuery")||e.endsWith("AggregatedPagedQuery")||e.endsWith("AggregatedSingleQuery"))return!0;const n=d(e);return t.has(n.name)}aggregatedSchemaSuffix=["MaterializedSnapshot","MaterializedSnapshotPagedList","MaterializedSnapshotServerSentEventNonNullData","PagedList","ServerSentEventNonNullData","Snapshot","StateEvent"];stateAggregatedTypeNames(){const e=new Set;for(const t of this.context.contextAggregates.values())for(const n of t)this.aggregatedSchemaSuffix.forEach(r=>{const i=d(n.state.key),s=C(i.name)+r;e.add(s)});return e}generateKeyedSchema({key:e,schema:t}){const n=d(e),r=this.getOrCreateSourceFile(n),i=this.process(n,r,t);i&&w(i,t)}process(e,t,n){if(xe(n))return t.addEnum({name:e.name,isExported:!0,members:n.enum.filter(i=>typeof i=="string"&&i.length>0).map(i=>({name:de(i),initializer:`'${i}'`}))});if(N(n)&&g(n.items)){const i=x(n.items);return S(e,t,this.context.outputDir,i),t.addTypeAlias({name:e.name,type:U(i.name),isExported:!0})}const r=t.addInterface({name:e.name,isExported:!0});return n.type==="object"&&n.properties?this.processInterface(t,e,n,r):(z(n)&&(n.anyOf||n.oneOf||n.allOf).forEach(s=>{if(g(s)){const a=x(s);S(e,t,this.context.outputDir,a),r.addExtends(a.name);return}this.processInterface(t,e,s,r)}),r)}processObject(e,t,n){const r=e.addInterface({name:t.name,isExported:!0});return this.processInterface(e,t,n,r)}processInterface(e,t,n,r){for(const[i,s]of Object.entries(n.properties)){const a=this.resolvePropertyType(t,e,i,s);let c=r.getProperty(i);c?c.setType(a):c=r.addProperty({name:i,type:a}),g(s)||w(c,s)}return r}resolvePropertyType(e,t,n,r){if(g(r)){const i=x(r);return S(e,t,this.context.outputDir,i),i.name}if(r.const)return`'${r.const}'`;if(N(r)){const i=this.resolvePropertyType(e,t,n,r.items);return U(i)}if(r.type&&j(r.type))return P(r.type);if(z(r))return this.resolvePropertyCompositionType(e,t,r);if(r.type==="object"&&r.properties){const i={path:e.path,name:`${e.name}${C(n)}`},s=this.processObject(t,i,r);return w(s,r),i.name}return"any"}resolvePropertyCompositionType(e,t,n){const r=n.anyOf||n.oneOf||n.allOf,i=new Set;r.forEach(a=>{if(g(a)){const c=x(a);S(e,t,this.context.outputDir,c),i.add(c.name);return}i.add(P(a.type??"string"))});const s=Ae(n)?"|":"&";return Array.from(i).join(s)}}const Ue="@ahoo-wang/fetcher-decorator",ke=["type ApiMetadata","type ApiMetadataCapable","type ParameterRequest","api","get","post","put","patch","del","request","attribute","path","autoGeneratedError"],Be={type:"Promise<Response>",metadata:"{resultExtractor: ResultExtractors.Response }"},Q={type:"Promise<string>",metadata:"{resultExtractor: ResultExtractors.Text }"},b=`{
3
3
  headers: { Accept: ContentTypeValues.TEXT_EVENT_STREAM },
4
4
  resultExtractor: JsonEventStreamResultExtractor,
5
- }`;function ie(o){$(o,ze,Ue)}function se(o,e,t=[]){return e.addClass({name:o,isExported:!0,decorators:[{name:"api",arguments:t}]})}function ae(o,e){o.addImplements("ApiMetadataCapable"),o.addConstructor({parameters:[{name:"apiMetadata",type:"ApiMetadata",hasQuestionToken:e===void 0,scope:A.Scope.Public,isReadonly:!0,initializer:e}]})}const ke="@ahoo-wang/fetcher-eventstream";function ce(o){$(o,ke,["JsonEventStreamResultExtractor","type JsonServerSentEventStream"])}function Qe(o){let e=0,t=0;return o.commands.forEach(n=>{n.path.startsWith(G.ResourceAttributionPathSpec.TENANT)&&(e+=1),n.path.startsWith(G.ResourceAttributionPathSpec.OWNER)&&(t+=1)}),e===0&&t===0?"ResourceAttributionPathSpec.NONE":e>t?"ResourceAttributionPathSpec.TENANT":"ResourceAttributionPathSpec.OWNER"}function ge(o,e,t,n){const r=`${t.contextAlias}/${t.aggregateName}/${n}.ts`;return re(o,e,r)}function Je(o,e){return`${C(o.aggregateName)}${e}`}function b(o){return o==="delete"?"del":o}const Ve="x-fetcher-method";function Ke(o,e){const t=o[Ve];if(t)return t;if(!o.operationId)return;const n=q(o.operationId);for(let r=n.length-1;r>=0;r--){const i=y(n.slice(r));if(!e(i))return i}return y(n)}class He{constructor(e){this.context=e,this.apiMetadataCtorInitializer=this.context.currentContextAlias?`{basePath:'${this.context.currentContextAlias}'}`:void 0}defaultParameterRequestType="ParameterRequest";defaultReturnType=Be;apiMetadataCtorInitializer;generate(){this.context.logger.info("Starting API client generation");const e=this.resolveApiTags();this.context.logger.info(`Resolved ${e.size} API client tags: ${Array.from(e.keys()).join(", ")}`);const t=this.groupOperations(e);this.context.logger.info(`Grouped operations into ${t.size} tag groups`),this.generateApiClients(e,t),this.context.logger.success("API client generation completed")}generateApiClients(e,t){this.context.logger.info(`Generating ${t.size} API client classes`);let n=0;for(const[r,i]of t){n++,this.context.logger.progressWithCount(n,t.size,`Generating API client for tag: ${r}`);const s=e.get(r);this.generateApiClient(s,i)}}createApiClientFile(e){let t=e.path;return this.context.currentContextAlias&&(t=h.combineURLs(this.context.currentContextAlias,t)),t=h.combineURLs(t,`${e.name}ApiClient.ts`),this.context.logger.info(`Creating API client file: ${t}`),this.context.getOrCreateSourceFile(t)}generateApiClient(e,t){const n=d(e.name);this.context.logger.info(`Generating API client class: ${n.name}ApiClient with ${t.size} operations`);const r=this.createApiClientFile(n);ie(r),ce(r);const i=se(n.name+"ApiClient",r);R(i,[e.description]),ae(i,this.apiMetadataCtorInitializer),this.context.logger.info(`Processing ${t.size} operations for ${n.name}ApiClient`),t.forEach(s=>{this.processOperation(e,r,i,s)}),this.context.logger.success(`Completed API client: ${n.name}ApiClient`)}getMethodName(e,t){const n=Ke(t,r=>e.getMethod(r)!==void 0);if(!n)throw new Error(`Unable to resolve method name for apiClientClass:${e.getName()}.`);return n}resolveRequestType(e,t){if(!t.requestBody)return this.context.logger.info(`No request body found for operation ${t.operationId}, using default: ${this.defaultParameterRequestType}`),this.defaultParameterRequestType;let n;if(g(t.requestBody)?(this.context.logger.info(`Extracting request body from reference for operation: ${t.operationId}`),n=K(t.requestBody,this.context.openAPI.components)):n=t.requestBody,!n)return this.context.logger.info(`Request body extraction failed for operation ${t.operationId}, using default: ${this.defaultParameterRequestType}`),this.defaultParameterRequestType;if(n.content["multipart/form-data"])return this.context.logger.info(`Detected multipart/form-data content for operation ${t.operationId}, using ParameterRequest<FormData>`),"ParameterRequest<FormData>";if(n.content["application/json"]){const r=n.content["application/json"].schema;if(g(r)){const i=x(r);this.context.logger.info(`Adding import for request body model: ${i.name} from ${i.path}`),f(e,this.context.outputDir,i);const s=`ParameterRequest<${i.name}>`;return this.context.logger.info(`Resolved request type for operation ${t.operationId}: ${s}`),s}}return this.context.logger.info(`Using default request type for operation ${t.operationId}: ${this.defaultParameterRequestType}`),this.defaultParameterRequestType}resolveParameters(e,t,n){const r=Pe(n,this.context.openAPI.components).filter(a=>!this.context.isIgnoreApiClientPathParameters(e.name,a.name));this.context.logger.info(`Found ${r.length} path parameters for operation ${n.operationId}`);const i=r.map(a=>{const c=ee(a);return this.context.logger.info(`Adding path parameter: ${a.name} (type: ${c})`),{name:a.name,type:c,hasQuestionToken:!1,decorators:[{name:"path",arguments:[`'${a.name}'`]}]}}),s=this.resolveRequestType(t,n);return this.context.logger.info(`Adding httpRequest parameter: ${s}`),i.push({name:"httpRequest",hasQuestionToken:s===this.defaultParameterRequestType,type:`${s}`,decorators:[{name:"request",arguments:[]}]}),this.context.logger.info("Adding attributes parameter: Record<string, any>"),i.push({name:"attributes",hasQuestionToken:!0,type:"Record<string, any>",decorators:[{name:"attribute",arguments:[]}]}),i}resolveSchemaReturnType(e,t){const n="Promise<any>";if(g(t)){const r=x(t);this.context.logger.info(`Adding import for response model: ${r.name} from ${r.path}`),f(e,this.context.outputDir,r);const i=`Promise<${r.name}>`;return this.context.logger.info(`Resolved reference return type: ${i}`),i}if(!t.type)return this.context.logger.info(`Schema has no type, using default return type: ${n}`),n;if(j(t.type)){const i=`Promise<${P(t.type)}>`;return this.context.logger.info(`Resolved primitive return type: ${i}`),i}return this.context.logger.info(`Using default return type: ${n}`),n}resolveReturnType(e,t){const n=_(t);if(!n)return this.context.logger.info(`No OK response found for operation ${t.operationId}, using default return type: ${this.defaultReturnType.type}`),this.defaultReturnType;const r=Y(n)||fe(n);if(r){const s=this.resolveSchemaReturnType(e,r);return this.context.logger.info(`Resolved JSON/wildcard response return type for operation ${t.operationId}: ${s}`),{type:s,metadata:s===J.type?J.metadata:void 0}}const i=de(n);if(i){if(g(i)){const a=v(i,this.context.openAPI.components);if(O(a)&&g(a.items)){const c=x(a.items);this.context.logger.info(`Adding import for event stream model: ${c.name} from ${c.path}`),f(e,this.context.outputDir,c);const l=`Promise<JsonServerSentEventStream<${c.name.includes("ServerSentEvent")?`${c.name}['data']`:c.name}>>`;return this.context.logger.info(`Resolved event stream return type for operation ${t.operationId}: ${l}`),{type:l,metadata:D}}}const s="Promise<JsonServerSentEventStream<any>>";return this.context.logger.info(`Resolved generic event stream return type for operation ${t.operationId}: ${s}`),{type:s,metadata:D}}return this.context.logger.info(`Using default return type for operation ${t.operationId}: ${this.defaultReturnType.type}`),this.defaultReturnType}processOperation(e,t,n,r){this.context.logger.info(`Processing operation: ${r.operation.operationId} (${r.method} ${r.path})`);const i=this.getMethodName(n,r.operation);this.context.logger.info(`Generated method name: ${i}`);const s=this.resolveParameters(e,t,r.operation),a=this.resolveReturnType(t,r.operation),c=a.metadata?{name:b(r.method),arguments:[`'${r.path}'`,a.metadata]}:{name:b(r.method),arguments:[`'${r.path}'`]};this.context.logger.info(`Creating method with ${s.length} parameters, return type: ${a.type}`);const u=n.addMethod({name:i,decorators:[c],parameters:s,returnType:a.type,statements:[`throw autoGeneratedError(${s.map(l=>l.name).join(",")});`]});R(u,[r.operation.summary,r.operation.description,`- path: \`${r.path}\``]),this.context.logger.success(`Operation method generated: ${i}`)}groupOperations(e){this.context.logger.info("Grouping operations by API client tags");const t=new Map;let n=0;for(const[r,i]of Object.entries(this.context.openAPI.paths)){const s=N(i).filter(a=>{if(!a.operation.operationId)return!1;const c=a.operation.tags;return!c||c.length==0?!1:c.every(u=>e.has(u))});this.context.logger.info(`Path ${r}: found ${s.length} valid operations`);for(const a of s)a.operation.tags.forEach(c=>{const u={...a,path:r};t.has(c)||t.set(c,new Set),t.get(c).add(u),n++})}return this.context.logger.info(`Grouped ${n} operations into ${t.size} tag groups`),t}shouldIgnoreTag(e){return e==="wow"||e==="Actuator"||this.isAggregateTag(e)}resolveApiTags(){this.context.logger.info("Resolving API client tags from OpenAPI specification");const e=new Map,t=this.context.openAPI.tags?.length||0;for(const r of Object.values(this.context.openAPI.paths))N(r).forEach(i=>{i.operation.tags?.forEach(s=>{!this.shouldIgnoreTag(s)&&!e.has(s)&&e.set(s,{name:s,description:""})})});let n=0;return this.context.openAPI.tags?.forEach(r=>{this.shouldIgnoreTag(r.name)?this.context.logger.info(`Excluded tag: ${r.name} (wow/Actuator/aggregate)`):(e.set(r.name,r),n++,this.context.logger.info(`Included API client tag: ${r.name}`))}),this.context.logger.info(`Resolved ${n} API client tags from ${t} total tags`),e}isAggregateTag(e){for(const t of this.context.contextAggregates.values())for(const n of t)if(n.aggregate.tag.name===e)return!0;return!1}}class Ye{constructor(e){this.context=e}commandEndpointPathsName="COMMAND_ENDPOINT_PATHS";defaultCommandClientOptionsName="DEFAULT_COMMAND_CLIENT_OPTIONS";generate(){const e=Array.from(this.context.contextAggregates.values()).reduce((n,r)=>n+r.size,0);this.context.logger.info("--- Generating Command Clients ---"),this.context.logger.progress(`Generating command clients for ${e} aggregates`);let t=0;for(const[,n]of this.context.contextAggregates)n.forEach(r=>{t++,this.context.logger.progressWithCount(t,e,`Processing command client for aggregate: ${r.aggregate.aggregateName}`),this.processAggregate(r)});this.context.logger.success("Command client generation completed")}processAggregate(e){this.context.logger.info(`Processing command client for aggregate: ${e.aggregate.aggregateName} in context: ${e.aggregate.contextAlias}`);const t=ge(this.context.project,this.context.outputDir,e.aggregate,"commandClient");this.context.logger.info(`Processing command endpoint paths for ${e.commands.size} commands`),this.processCommandEndpointPaths(t,e),this.context.logger.info(`Creating default command client options: ${this.defaultCommandClientOptionsName}`),t.addVariableStatement({declarationKind:A.VariableDeclarationKind.Const,declarations:[{name:this.defaultCommandClientOptionsName,type:"ApiMetadata",initializer:`{
5
+ }`;function ie(o){$(o,Ue,ke)}function se(o,e,t=[]){return e.addClass({name:o,isExported:!0,decorators:[{name:"api",arguments:t}]})}function ae(o,e){o.addImplements("ApiMetadataCapable"),o.addConstructor({parameters:[{name:"apiMetadata",type:"ApiMetadata",hasQuestionToken:e===void 0,scope:A.Scope.Public,isReadonly:!0,initializer:e}]})}const Qe="@ahoo-wang/fetcher-eventstream";function ce(o){$(o,Qe,["JsonEventStreamResultExtractor","type JsonServerSentEventStream"])}function Je(o){let e=0,t=0;return o.commands.forEach(n=>{n.path.startsWith(G.ResourceAttributionPathSpec.TENANT)&&(e+=1),n.path.startsWith(G.ResourceAttributionPathSpec.OWNER)&&(t+=1)}),e===0&&t===0?"ResourceAttributionPathSpec.NONE":e>t?"ResourceAttributionPathSpec.TENANT":"ResourceAttributionPathSpec.OWNER"}function ge(o,e,t,n){const r=`${t.contextAlias}/${t.aggregateName}/${n}.ts`;return re(o,e,r)}function Ve(o,e){return`${C(o.aggregateName)}${e}`}function q(o){return o==="delete"?"del":o}const Ke="x-fetcher-method";function He(o,e){const t=o[Ke];if(t)return t;if(!o.operationId)return;const n=O(o.operationId);for(let r=n.length-1;r>=0;r--){const i=y(n.slice(r));if(!e(i))return i}return y(n)}class Ye{constructor(e){this.context=e,this.apiMetadataCtorInitializer=this.context.currentContextAlias?`{basePath:'${this.context.currentContextAlias}'}`:void 0}defaultParameterRequestType="ParameterRequest";defaultReturnType=Be;apiMetadataCtorInitializer;generate(){this.context.logger.info("Starting API client generation");const e=this.resolveApiTags();this.context.logger.info(`Resolved ${e.size} API client tags: ${Array.from(e.keys()).join(", ")}`);const t=this.groupOperations(e);this.context.logger.info(`Grouped operations into ${t.size} tag groups`),this.generateApiClients(e,t),this.context.logger.success("API client generation completed")}generateApiClients(e,t){this.context.logger.info(`Generating ${t.size} API client classes`);let n=0;for(const[r,i]of t){n++,this.context.logger.progressWithCount(n,t.size,`Generating API client for tag: ${r}`);const s=e.get(r);this.generateApiClient(s,i)}}createApiClientFile(e){let t=e.path;return this.context.currentContextAlias&&(t=h.combineURLs(this.context.currentContextAlias,t)),t=h.combineURLs(t,`${e.name}ApiClient.ts`),this.context.logger.info(`Creating API client file: ${t}`),this.context.getOrCreateSourceFile(t)}generateApiClient(e,t){const n=d(e.name);this.context.logger.info(`Generating API client class: ${n.name}ApiClient with ${t.size} operations`);const r=this.createApiClientFile(n);ie(r),ce(r);const i=se(n.name+"ApiClient",r);R(i,[e.description]),ae(i,this.apiMetadataCtorInitializer),this.context.logger.info(`Processing ${t.size} operations for ${n.name}ApiClient`),t.forEach(s=>{this.processOperation(e,r,i,s)}),this.context.logger.success(`Completed API client: ${n.name}ApiClient`)}getMethodName(e,t){const n=He(t,r=>e.getMethod(r)!==void 0);if(!n)throw new Error(`Unable to resolve method name for apiClientClass:${e.getName()}.`);return n}resolveRequestType(e,t){if(!t.requestBody)return this.context.logger.info(`No request body found for operation ${t.operationId}, using default: ${this.defaultParameterRequestType}`),this.defaultParameterRequestType;let n;if(g(t.requestBody)?(this.context.logger.info(`Extracting request body from reference for operation: ${t.operationId}`),n=V(t.requestBody,this.context.openAPI.components)):n=t.requestBody,!n)return this.context.logger.info(`Request body extraction failed for operation ${t.operationId}, using default: ${this.defaultParameterRequestType}`),this.defaultParameterRequestType;if(n.content["multipart/form-data"])return this.context.logger.info(`Detected multipart/form-data content for operation ${t.operationId}, using ParameterRequest<FormData>`),"ParameterRequest<FormData>";if(n.content["application/json"]){const r=n.content["application/json"].schema;if(g(r)){const i=x(r);this.context.logger.info(`Adding import for request body model: ${i.name} from ${i.path}`),f(e,this.context.outputDir,i);const s=`ParameterRequest<${i.name}>`;return this.context.logger.info(`Resolved request type for operation ${t.operationId}: ${s}`),s}}return this.context.logger.info(`Using default request type for operation ${t.operationId}: ${this.defaultParameterRequestType}`),this.defaultParameterRequestType}resolveParameters(e,t,n){const r=$e(n,this.context.openAPI.components).filter(a=>!this.context.isIgnoreApiClientPathParameters(e.name,a.name));this.context.logger.info(`Found ${r.length} path parameters for operation ${n.operationId}`);const i=r.map(a=>{const c=ee(a);return this.context.logger.info(`Adding path parameter: ${a.name} (type: ${c})`),{name:a.name,type:c,hasQuestionToken:!1,decorators:[{name:"path",arguments:[`'${a.name}'`]}]}}),s=this.resolveRequestType(t,n);return this.context.logger.info(`Adding httpRequest parameter: ${s}`),i.push({name:"httpRequest",hasQuestionToken:s===this.defaultParameterRequestType,type:`${s}`,decorators:[{name:"request",arguments:[]}]}),this.context.logger.info("Adding attributes parameter: Record<string, any>"),i.push({name:"attributes",hasQuestionToken:!0,type:"Record<string, any>",decorators:[{name:"attribute",arguments:[]}]}),i}resolveSchemaReturnType(e,t){const n="Promise<any>";if(g(t)){const r=x(t);this.context.logger.info(`Adding import for response model: ${r.name} from ${r.path}`),f(e,this.context.outputDir,r);const i=`Promise<${r.name}>`;return this.context.logger.info(`Resolved reference return type: ${i}`),i}if(!t.type)return this.context.logger.info(`Schema has no type, using default return type: ${n}`),n;if(j(t.type)){const i=`Promise<${P(t.type)}>`;return this.context.logger.info(`Resolved primitive return type: ${i}`),i}return this.context.logger.info(`Using default return type: ${n}`),n}resolveReturnType(e,t){const n=_(t);if(!n)return this.context.logger.info(`No OK response found for operation ${t.operationId}, using default return type: ${this.defaultReturnType.type}`),this.defaultReturnType;const r=Y(n)||he(n);if(r){const s=this.resolveSchemaReturnType(e,r);return this.context.logger.info(`Resolved JSON/wildcard response return type for operation ${t.operationId}: ${s}`),{type:s,metadata:s===Q.type?Q.metadata:void 0}}const i=fe(n);if(i){if(g(i)){const a=v(i,this.context.openAPI.components);if(N(a)&&g(a.items)){const c=x(a.items);this.context.logger.info(`Adding import for event stream model: ${c.name} from ${c.path}`),f(e,this.context.outputDir,c);const l=`Promise<JsonServerSentEventStream<${c.name.includes("ServerSentEvent")?`${c.name}['data']`:c.name}>>`;return this.context.logger.info(`Resolved event stream return type for operation ${t.operationId}: ${l}`),{type:l,metadata:b}}}const s="Promise<JsonServerSentEventStream<any>>";return this.context.logger.info(`Resolved generic event stream return type for operation ${t.operationId}: ${s}`),{type:s,metadata:b}}return this.context.logger.info(`Using default return type for operation ${t.operationId}: ${this.defaultReturnType.type}`),this.defaultReturnType}processOperation(e,t,n,r){this.context.logger.info(`Processing operation: ${r.operation.operationId} (${r.method} ${r.path})`);const i=this.getMethodName(n,r.operation);this.context.logger.info(`Generated method name: ${i}`);const s=this.resolveParameters(e,t,r.operation),a=this.resolveReturnType(t,r.operation),c=a.metadata?{name:q(r.method),arguments:[`'${r.path}'`,a.metadata]}:{name:q(r.method),arguments:[`'${r.path}'`]};this.context.logger.info(`Creating method with ${s.length} parameters, return type: ${a.type}`);const u=n.addMethod({name:i,decorators:[c],parameters:s,returnType:a.type,statements:[`throw autoGeneratedError(${s.map(l=>l.name).join(",")});`]});R(u,[r.operation.summary,r.operation.description,`- path: \`${r.path}\``]),this.context.logger.success(`Operation method generated: ${i}`)}groupOperations(e){this.context.logger.info("Grouping operations by API client tags");const t=new Map;let n=0;for(const[r,i]of Object.entries(this.context.openAPI.paths)){const s=D(i).filter(a=>{if(!a.operation.operationId)return!1;const c=a.operation.tags;return!c||c.length==0?!1:c.every(u=>e.has(u))});this.context.logger.info(`Path ${r}: found ${s.length} valid operations`);for(const a of s)a.operation.tags.forEach(c=>{const u={...a,path:r};t.has(c)||t.set(c,new Set),t.get(c).add(u),n++})}return this.context.logger.info(`Grouped ${n} operations into ${t.size} tag groups`),t}shouldIgnoreTag(e){return e==="wow"||e==="Actuator"||this.isAggregateTag(e)}resolveApiTags(){this.context.logger.info("Resolving API client tags from OpenAPI specification");const e=new Map,t=this.context.openAPI.tags?.length||0;for(const r of Object.values(this.context.openAPI.paths))D(r).forEach(i=>{i.operation.tags?.forEach(s=>{!this.shouldIgnoreTag(s)&&!e.has(s)&&e.set(s,{name:s,description:""})})});let n=0;return this.context.openAPI.tags?.forEach(r=>{this.shouldIgnoreTag(r.name)?this.context.logger.info(`Excluded tag: ${r.name} (wow/Actuator/aggregate)`):(e.set(r.name,r),n++,this.context.logger.info(`Included API client tag: ${r.name}`))}),this.context.logger.info(`Resolved ${n} API client tags from ${t} total tags`),e}isAggregateTag(e){for(const t of this.context.contextAggregates.values())for(const n of t)if(n.aggregate.tag.name===e)return!0;return!1}}class Xe{constructor(e){this.context=e}commandEndpointPathsName="COMMAND_ENDPOINT_PATHS";defaultCommandClientOptionsName="DEFAULT_COMMAND_CLIENT_OPTIONS";generate(){const e=Array.from(this.context.contextAggregates.values()).reduce((n,r)=>n+r.size,0);this.context.logger.info("--- Generating Command Clients ---"),this.context.logger.progress(`Generating command clients for ${e} aggregates`);let t=0;for(const[,n]of this.context.contextAggregates)n.forEach(r=>{t++,this.context.logger.progressWithCount(t,e,`Processing command client for aggregate: ${r.aggregate.aggregateName}`),this.processAggregate(r)});this.context.logger.success("Command client generation completed")}processAggregate(e){this.context.logger.info(`Processing command client for aggregate: ${e.aggregate.aggregateName} in context: ${e.aggregate.contextAlias}`);const t=ge(this.context.project,this.context.outputDir,e.aggregate,"commandClient");this.context.logger.info(`Processing command endpoint paths for ${e.commands.size} commands`),this.processCommandEndpointPaths(t,e),this.context.logger.info(`Creating default command client options: ${this.defaultCommandClientOptionsName}`),t.addVariableStatement({declarationKind:A.VariableDeclarationKind.Const,declarations:[{name:this.defaultCommandClientOptionsName,type:"ApiMetadata",initializer:`{
6
6
  basePath: '${e.aggregate.contextAlias}'
7
- }`}],isExported:!1}),this.context.logger.info(`Adding imports from ${T}: CommandRequest, CommandResult, CommandResultEventStream, DeleteAggregate, RecoverAggregate`),t.addImportDeclaration({moduleSpecifier:T,namedImports:["CommandRequest","CommandResult","CommandResultEventStream","DeleteAggregate","RecoverAggregate"],isTypeOnly:!0}),this.context.logger.info("Adding import from @ahoo-wang/fetcher-eventstream: JsonEventStreamResultExtractor"),ce(t),this.context.logger.info("Adding import from @ahoo-wang/fetcher: ContentTypeValues"),$(t,"@ahoo-wang/fetcher",["ContentTypeValues"]),this.context.logger.info("Adding imports from @ahoo-wang/fetcher-decorator: ApiMetadata types and decorators"),ie(t),this.context.logger.info("Generating standard command client class"),this.processCommandClient(t,e),this.context.logger.info("Generating stream command client class"),this.processCommandClient(t,e,!0),this.context.logger.success(`Command client generation completed for aggregate: ${e.aggregate.aggregateName}`)}processCommandEndpointPaths(e,t){this.context.logger.info(`Creating command endpoint paths enum: ${this.commandEndpointPathsName}`);const n=e.addEnum({name:this.commandEndpointPathsName});t.commands.forEach(r=>{this.context.logger.info(`Adding command endpoint: ${r.name.toUpperCase()} = '${r.path}'`),n.addMember({name:r.name.toUpperCase(),initializer:`'${r.path}'`})}),this.context.logger.success(`Command endpoint paths enum created with ${t.commands.size} entries`)}getEndpointPath(e){return`${this.commandEndpointPathsName}.${e.name.toUpperCase()}`}processCommandClient(e,t,n=!1){let r="CommandClient",i=[],s="Promise<CommandResult>";n&&(r="Stream"+r,i=["''",D],s="Promise<CommandResultEventStream>");const a=Je(t.aggregate,r),c=se(a,e,i);ae(c,this.defaultCommandClientOptionsName),t.commands.forEach(u=>{this.processCommandMethod(t,e,c,u,s)})}resolveParameters(e,t,n){const r=d(n.schema.key);this.context.logger.info(`Adding import for command model: ${r.name} from path: ${r.path}`),f(t,this.context.outputDir,r);const i=n.pathParameters.filter(s=>!this.context.isIgnoreCommandClientPathParameters(e.name,s.name)).map(s=>{const a=ee(s);return this.context.logger.info(`Adding path parameter: ${s.name} (type: ${a})`),{name:s.name,type:a,hasQuestionToken:!1,decorators:[{name:"path",arguments:[`'${s.name}'`]}]}});return this.context.logger.info(`Adding command request parameter: commandRequest (type: CommandRequest<${r.name}>)`),i.push({name:"commandRequest",hasQuestionToken:Ce(n.schema.schema),type:`CommandRequest<${r.name}>`,decorators:[{name:"request",arguments:[]}]}),this.context.logger.info("Adding attributes parameter: attributes (type: Record<string, any>)"),i.push({name:"attributes",hasQuestionToken:!0,type:"Record<string, any>",decorators:[{name:"attribute",arguments:[]}]}),i}processCommandMethod(e,t,n,r,i){this.context.logger.info(`Generating command method: ${y(r.name)} for command: ${r.name}`),this.context.logger.info(`Command method details: HTTP ${r.method}, path: ${r.path}, return type: ${i}`);const s=this.resolveParameters(e.aggregate.tag,t,r),a=n.addMethod({name:y(r.name),decorators:[{name:b(r.method),arguments:[`${this.getEndpointPath(r)}`]}],parameters:s,returnType:i,statements:[`throw autoGeneratedError(${s.map(c=>c.name).join(",")});`]});this.context.logger.info(`Adding JSDoc documentation for method: ${y(r.name)}`),R(a,[r.summary,r.description,`- path: \`${r.path}\``]),this.context.logger.success(`Command method generated: ${y(r.name)}`)}}class Xe{constructor(e){this.context=e}generate(){const e=Array.from(this.context.contextAggregates.values()).reduce((n,r)=>n+r.size,0);this.context.logger.info("--- Generating Query Clients ---"),this.context.logger.progress(`Generating query clients for ${e} aggregates`);let t=0;for(const[,n]of this.context.contextAggregates)n.forEach(r=>{t++,this.context.logger.progressWithCount(t,e,`Processing query client for aggregate: ${r.aggregate.aggregateName}`),this.processQueryClient(r)});this.context.logger.success("Query client generation completed")}createClientFilePath(e,t){return ge(this.context.project,this.context.outputDir,e,t)}processQueryClient(e){const t=this.createClientFilePath(e.aggregate,"queryClient");this.context.logger.info(`Processing query client for aggregate: ${e.aggregate.aggregateName} in context: ${e.aggregate.contextAlias}`),this.context.logger.info(`Adding imports from ${T}: QueryClientFactory, QueryClientOptions, ResourceAttributionPathSpec`),t.addImportDeclaration({moduleSpecifier:T,namedImports:["QueryClientFactory","QueryClientOptions","ResourceAttributionPathSpec"]});const n="DEFAULT_QUERY_CLIENT_OPTIONS";this.context.logger.info(`Creating default query client options: ${n}`),t.addVariableStatement({declarationKind:A.VariableDeclarationKind.Const,declarations:[{name:n,type:"QueryClientOptions",initializer:`{
7
+ }`}],isExported:!1}),this.context.logger.info(`Adding imports from ${T}: CommandRequest, CommandResult, CommandResultEventStream, DeleteAggregate, RecoverAggregate`),t.addImportDeclaration({moduleSpecifier:T,namedImports:["CommandRequest","CommandResult","CommandResultEventStream","DeleteAggregate","RecoverAggregate"],isTypeOnly:!0}),this.context.logger.info("Adding import from @ahoo-wang/fetcher-eventstream: JsonEventStreamResultExtractor"),ce(t),this.context.logger.info("Adding import from @ahoo-wang/fetcher: ContentTypeValues"),$(t,"@ahoo-wang/fetcher",["ContentTypeValues"]),this.context.logger.info("Adding imports from @ahoo-wang/fetcher-decorator: ApiMetadata types and decorators"),ie(t),this.context.logger.info("Generating standard command client class"),this.processCommandClient(t,e),this.context.logger.info("Generating stream command client class"),this.processCommandClient(t,e,!0),this.context.logger.success(`Command client generation completed for aggregate: ${e.aggregate.aggregateName}`)}processCommandEndpointPaths(e,t){this.context.logger.info(`Creating command endpoint paths enum: ${this.commandEndpointPathsName}`);const n=e.addEnum({name:this.commandEndpointPathsName});t.commands.forEach(r=>{this.context.logger.info(`Adding command endpoint: ${r.name.toUpperCase()} = '${r.path}'`),n.addMember({name:r.name.toUpperCase(),initializer:`'${r.path}'`})}),this.context.logger.success(`Command endpoint paths enum created with ${t.commands.size} entries`)}getEndpointPath(e){return`${this.commandEndpointPathsName}.${e.name.toUpperCase()}`}processCommandClient(e,t,n=!1){let r="CommandClient",i=[],s="Promise<CommandResult>";n&&(r="Stream"+r,i=["''",b],s="Promise<CommandResultEventStream>");const a=Ve(t.aggregate,r),c=se(a,e,i);ae(c,this.defaultCommandClientOptionsName),t.commands.forEach(u=>{this.processCommandMethod(t,e,c,u,s)})}resolveParameters(e,t,n){const r=d(n.schema.key);this.context.logger.info(`Adding import for command model: ${r.name} from path: ${r.path}`),f(t,this.context.outputDir,r);const i=n.pathParameters.filter(s=>!this.context.isIgnoreCommandClientPathParameters(e.name,s.name)).map(s=>{const a=ee(s);return this.context.logger.info(`Adding path parameter: ${s.name} (type: ${a})`),{name:s.name,type:a,hasQuestionToken:!1,decorators:[{name:"path",arguments:[`'${s.name}'`]}]}});return this.context.logger.info(`Adding command request parameter: commandRequest (type: CommandRequest<${r.name}>)`),i.push({name:"commandRequest",hasQuestionToken:Pe(n.schema.schema),type:`CommandRequest<${r.name}>`,decorators:[{name:"request",arguments:[]}]}),this.context.logger.info("Adding attributes parameter: attributes (type: Record<string, any>)"),i.push({name:"attributes",hasQuestionToken:!0,type:"Record<string, any>",decorators:[{name:"attribute",arguments:[]}]}),i}processCommandMethod(e,t,n,r,i){this.context.logger.info(`Generating command method: ${y(r.name)} for command: ${r.name}`),this.context.logger.info(`Command method details: HTTP ${r.method}, path: ${r.path}, return type: ${i}`);const s=this.resolveParameters(e.aggregate.tag,t,r),a=n.addMethod({name:y(r.name),decorators:[{name:q(r.method),arguments:[`${this.getEndpointPath(r)}`]}],parameters:s,returnType:i,statements:[`throw autoGeneratedError(${s.map(c=>c.name).join(",")});`]});this.context.logger.info(`Adding JSDoc documentation for method: ${y(r.name)}`),R(a,[r.summary,r.description,`- path: \`${r.path}\``]),this.context.logger.success(`Command method generated: ${y(r.name)}`)}}class Ze{constructor(e){this.context=e}generate(){const e=Array.from(this.context.contextAggregates.values()).reduce((n,r)=>n+r.size,0);this.context.logger.info("--- Generating Query Clients ---"),this.context.logger.progress(`Generating query clients for ${e} aggregates`);let t=0;for(const[,n]of this.context.contextAggregates)n.forEach(r=>{t++,this.context.logger.progressWithCount(t,e,`Processing query client for aggregate: ${r.aggregate.aggregateName}`),this.processQueryClient(r)});this.context.logger.success("Query client generation completed")}createClientFilePath(e,t){return ge(this.context.project,this.context.outputDir,e,t)}processQueryClient(e){const t=this.createClientFilePath(e.aggregate,"queryClient");this.context.logger.info(`Processing query client for aggregate: ${e.aggregate.aggregateName} in context: ${e.aggregate.contextAlias}`),this.context.logger.info(`Adding imports from ${T}: QueryClientFactory, QueryClientOptions, ResourceAttributionPathSpec`),t.addImportDeclaration({moduleSpecifier:T,namedImports:["QueryClientFactory","QueryClientOptions","ResourceAttributionPathSpec"]});const n="DEFAULT_QUERY_CLIENT_OPTIONS";this.context.logger.info(`Creating default query client options: ${n}`),t.addVariableStatement({declarationKind:A.VariableDeclarationKind.Const,declarations:[{name:n,type:"QueryClientOptions",initializer:`{
8
8
  contextAlias: '${e.aggregate.contextAlias}',
9
9
  aggregateName: '${e.aggregate.aggregateName}',
10
- resourceAttribution: ${Qe(e)},
11
- }`}],isExported:!1});const r=[];this.context.logger.info(`Processing ${e.events.size} domain events for aggregate: ${e.aggregate.aggregateName}`);for(const l of e.events.values()){const p=d(l.schema.key);this.context.logger.info(`Adding import for event model: ${p.name} from path: ${p.path}`),f(t,this.context.outputDir,p),r.push(p)}const i="DOMAIN_EVENT_TYPES",s=r.map(l=>l.name).join(" | ");this.context.logger.info(`Creating domain event types union: ${i} = ${s}`),t.addTypeAlias({name:i,type:s});const a=`${y(e.aggregate.aggregateName)}QueryClientFactory`,c=d(e.state.key),u=d(e.fields.key);this.context.logger.info(`Adding import for state model: ${c.name} from path: ${c.path}`),f(t,this.context.outputDir,c),this.context.logger.info(`Adding import for fields model: ${u.name} from path: ${u.path}`),f(t,this.context.outputDir,u),this.context.logger.info(`Creating query client factory: ${a}`),t.addVariableStatement({declarationKind:A.VariableDeclarationKind.Const,declarations:[{name:a,initializer:`new QueryClientFactory<${c.name}, ${u.name} | string, ${i}>(${n})`}],isExported:!0}),this.context.logger.success(`Query client generation completed for aggregate: ${e.aggregate.aggregateName}`)}}class Ze{constructor(e){this.context=e,this.queryClientGenerator=new Xe(e),this.commandClientGenerator=new Ye(e),this.apiClientGenerator=new He(e)}queryClientGenerator;commandClientGenerator;apiClientGenerator;generate(){this.context.logger.info("--- Generating Clients ---"),this.context.logger.progress(`Generating clients for ${this.context.contextAggregates.size} bounded contexts`);let e=0;for(const[t]of this.context.contextAggregates)e++,this.context.logger.progressWithCount(e,this.context.contextAggregates.size,`Processing bounded context: ${t}`,1),this.processBoundedContext(t);this.queryClientGenerator.generate(),this.commandClientGenerator.generate(),this.apiClientGenerator.generate(),this.context.logger.success("Client generation completed")}processBoundedContext(e){const t=`${e}/boundedContext.ts`;this.context.logger.info(`Creating bounded context file: ${t}`);const n=this.context.getOrCreateSourceFile(t);this.context.logger.info(`Adding bounded context alias constant: BOUNDED_CONTEXT_ALIAS = '${e}'`),n.addStatements(`export const BOUNDED_CONTEXT_ALIAS = '${e}';`),this.context.logger.success(`Bounded context file created successfully: ${t}`)}}class et{project;openAPI;outputDir;contextAggregates;logger;config;defaultIgnorePathParameters=["tenantId","ownerId"];currentContextAlias;constructor(e){this.project=e.project,this.openAPI=e.openAPI,this.outputDir=e.outputDir,this.contextAggregates=e.contextAggregates,this.logger=e.logger,this.config=e.config??{},this.currentContextAlias=this.openAPI.info["x-wow-context-alias"]}getOrCreateSourceFile(e){return re(this.project,this.outputDir,e)}isIgnoreApiClientPathParameters(e,t){return(this.config.apiClients?.[e]?.ignorePathParameters??this.defaultIgnorePathParameters).includes(t)}isIgnoreCommandClientPathParameters(e,t){return this.defaultIgnorePathParameters.includes(t)}}const ue="./fetcher-generator.config.json";class tt{constructor(e){this.options=e,this.project=new A.Project(e),this.options.logger.info("Project instance created with tsConfigFilePath: ",this.options.tsConfigFilePath)}project;async generate(){this.options.logger.info("Starting code generation from OpenAPI specification"),this.options.logger.info(`Input path: ${this.options.inputPath}`),this.options.logger.info(`Output directory: ${this.options.outputDir}`),this.options.logger.info("Parsing OpenAPI specification");const e=await Ee(this.options.inputPath);this.options.logger.info("OpenAPI specification parsed successfully"),this.options.logger.info("Resolving bounded context aggregates");const n=new Ge(e).resolve();this.options.logger.info(`Resolved ${n.size} bounded context aggregates`);const r=this.options.configPath??ue;let i={};try{this.options.logger.info("Parsing configuration file:",r),i=await Se(r)}catch(u){this.options.logger.info("Configuration file parsing failed ",u)}const s=new et({openAPI:e,project:this.project,outputDir:this.options.outputDir,contextAggregates:n,logger:this.options.logger,config:i});this.options.logger.info("Generating models"),new Le(s).generate(),this.options.logger.info("Models generated successfully"),this.options.logger.info("Generating clients"),new Ze(s).generate(),this.options.logger.info("Clients generated successfully"),this.options.logger.info("Generating index files"),this.generateIndex(),this.options.logger.info("Index files generated successfully"),this.options.logger.info("Optimizing source files"),this.optimizeSourceFiles(),this.options.logger.info("Source files optimized successfully"),this.options.logger.info("Saving project to disk"),await this.project.save(),this.options.logger.info("Code generation completed successfully")}generateIndex(){this.options.logger.info(`Generating index files for output directory: ${this.options.outputDir}`);const e=this.project.getDirectory(this.options.outputDir);if(!e){this.options.logger.info("Output directory not found, skipping index generation");return}this.processDirectory(e),this.generateIndexForDirectory(e),this.options.logger.info("Index file generation completed")}processDirectory(e){const t=e.getDirectories();this.options.logger.info(`Processing ${t.length} subdirectories`);for(const n of t)this.options.logger.info(`Processing subdirectory: ${n.getPath()}`),this.generateIndexForDirectory(n),this.processDirectory(n)}generateIndexForDirectory(e){const t=e.getPath();this.options.logger.info(`Generating index for directory: ${t}`);const n=e.getSourceFiles().filter(a=>a.getBaseName().endsWith(".ts")&&a.getBaseName()!=="index.ts"),r=e.getDirectories();if(this.options.logger.info(`Found ${n.length} TypeScript files and ${r.length} subdirectories in ${t}`),n.length===0&&r.length===0){this.options.logger.info(`No files or subdirectories to export in ${t}, skipping index generation`);return}const i=`${t}/index.ts`;this.options.logger.info(`Creating/updating index file: ${i}`);const s=this.project.getSourceFile(i)||this.project.createSourceFile(i,"",{overwrite:!0});s.removeText();for(const a of n){const c=`./${a.getBaseNameWithoutExtension()}`;this.options.logger.info(`Adding export for file: ${c}`),s.addExportDeclaration({moduleSpecifier:c,isTypeOnly:!1,namedExports:[]})}for(const a of r){const c=`./${a.getBaseName()}`;this.options.logger.info(`Adding export for subdirectory: ${c}`),s.addExportDeclaration({moduleSpecifier:c,isTypeOnly:!1,namedExports:[]})}this.options.logger.info(`Index file generated for ${t} with ${n.length+r.length} exports`)}optimizeSourceFiles(){const e=this.project.getSourceFiles();this.options.logger.info(`Optimizing ${e.length} source files`),e.forEach((t,n)=>{this.options.logger.info(`Optimizing file ${n+1}/${e.length}`),t.formatText(),t.organizeImports(),t.fixMissingImports()}),this.options.logger.info("All source files optimized")}}exports.CodeGenerator=tt;exports.DEFAULT_CONFIG_PATH=ue;
10
+ resourceAttribution: ${Je(e)},
11
+ }`}],isExported:!1});const r=[];this.context.logger.info(`Processing ${e.events.size} domain events for aggregate: ${e.aggregate.aggregateName}`);for(const l of e.events.values()){const p=d(l.schema.key);this.context.logger.info(`Adding import for event model: ${p.name} from path: ${p.path}`),f(t,this.context.outputDir,p),r.push(p)}const i="DOMAIN_EVENT_TYPES",s=r.map(l=>l.name).join(" | ");this.context.logger.info(`Creating domain event types union: ${i} = ${s}`),t.addTypeAlias({name:i,type:s});const a=`${y(e.aggregate.aggregateName)}QueryClientFactory`,c=d(e.state.key),u=d(e.fields.key);this.context.logger.info(`Adding import for state model: ${c.name} from path: ${c.path}`),f(t,this.context.outputDir,c),this.context.logger.info(`Adding import for fields model: ${u.name} from path: ${u.path}`),f(t,this.context.outputDir,u),this.context.logger.info(`Creating query client factory: ${a}`),t.addVariableStatement({declarationKind:A.VariableDeclarationKind.Const,declarations:[{name:a,initializer:`new QueryClientFactory<${c.name}, ${u.name} | string, ${i}>(${n})`}],isExported:!0}),this.context.logger.success(`Query client generation completed for aggregate: ${e.aggregate.aggregateName}`)}}class et{constructor(e){this.context=e,this.queryClientGenerator=new Ze(e),this.commandClientGenerator=new Xe(e),this.apiClientGenerator=new Ye(e)}queryClientGenerator;commandClientGenerator;apiClientGenerator;generate(){this.context.logger.info("--- Generating Clients ---"),this.context.logger.progress(`Generating clients for ${this.context.contextAggregates.size} bounded contexts`);let e=0;for(const[t]of this.context.contextAggregates)e++,this.context.logger.progressWithCount(e,this.context.contextAggregates.size,`Processing bounded context: ${t}`,1),this.processBoundedContext(t);this.queryClientGenerator.generate(),this.commandClientGenerator.generate(),this.apiClientGenerator.generate(),this.context.logger.success("Client generation completed")}processBoundedContext(e){const t=`${e}/boundedContext.ts`;this.context.logger.info(`Creating bounded context file: ${t}`);const n=this.context.getOrCreateSourceFile(t);this.context.logger.info(`Adding bounded context alias constant: BOUNDED_CONTEXT_ALIAS = '${e}'`),n.addStatements(`export const BOUNDED_CONTEXT_ALIAS = '${e}';`),this.context.logger.success(`Bounded context file created successfully: ${t}`)}}class tt{project;openAPI;outputDir;contextAggregates;logger;config;defaultIgnorePathParameters=["tenantId","ownerId"];currentContextAlias;constructor(e){this.project=e.project,this.openAPI=e.openAPI,this.outputDir=e.outputDir,this.contextAggregates=e.contextAggregates,this.logger=e.logger,this.config=e.config??{},this.currentContextAlias=this.openAPI.info["x-wow-context-alias"]}getOrCreateSourceFile(e){return re(this.project,this.outputDir,e)}isIgnoreApiClientPathParameters(e,t){return(this.config.apiClients?.[e]?.ignorePathParameters??this.defaultIgnorePathParameters).includes(t)}isIgnoreCommandClientPathParameters(e,t){return this.defaultIgnorePathParameters.includes(t)}}const ue="./fetcher-generator.config.json";class nt{constructor(e){this.options=e,this.project=new A.Project(e),this.options.logger.info("Project instance created with tsConfigFilePath: ",this.options.tsConfigFilePath)}project;async generate(){this.options.logger.info("Starting code generation from OpenAPI specification"),this.options.logger.info(`Input path: ${this.options.inputPath}`),this.options.logger.info(`Output directory: ${this.options.outputDir}`),this.options.logger.info("Parsing OpenAPI specification");const e=await Se(this.options.inputPath);this.options.logger.info("OpenAPI specification parsed successfully"),this.options.logger.info("Resolving bounded context aggregates");const n=new We(e).resolve();this.options.logger.info(`Resolved ${n.size} bounded context aggregates`);const r=this.options.configPath??ue;let i={};try{this.options.logger.info("Parsing configuration file:",r),i=await ve(r)}catch(u){this.options.logger.info("Configuration file parsing failed ",u)}const s=new tt({openAPI:e,project:this.project,outputDir:this.options.outputDir,contextAggregates:n,logger:this.options.logger,config:i});this.options.logger.info("Generating models"),new ze(s).generate(),this.options.logger.info("Models generated successfully"),this.options.logger.info("Generating clients"),new et(s).generate(),this.options.logger.info("Clients generated successfully"),this.options.logger.info("Generating index files"),this.generateIndex(),this.options.logger.info("Index files generated successfully"),this.options.logger.info("Optimizing source files"),this.optimizeSourceFiles(),this.options.logger.info("Source files optimized successfully"),this.options.logger.info("Saving project to disk"),await this.project.save(),this.options.logger.info("Code generation completed successfully")}generateIndex(){this.options.logger.info(`Generating index files for output directory: ${this.options.outputDir}`);const e=this.project.getDirectory(this.options.outputDir);if(!e){this.options.logger.info("Output directory not found, skipping index generation");return}this.processDirectory(e),this.generateIndexForDirectory(e),this.options.logger.info("Index file generation completed")}processDirectory(e){const t=e.getDirectories();this.options.logger.info(`Processing ${t.length} subdirectories`);for(const n of t)this.options.logger.info(`Processing subdirectory: ${n.getPath()}`),this.generateIndexForDirectory(n),this.processDirectory(n)}generateIndexForDirectory(e){const t=e.getPath();this.options.logger.info(`Generating index for directory: ${t}`);const n=e.getSourceFiles().filter(a=>a.getBaseName().endsWith(".ts")&&a.getBaseName()!=="index.ts"),r=e.getDirectories();if(this.options.logger.info(`Found ${n.length} TypeScript files and ${r.length} subdirectories in ${t}`),n.length===0&&r.length===0){this.options.logger.info(`No files or subdirectories to export in ${t}, skipping index generation`);return}const i=`${t}/index.ts`;this.options.logger.info(`Creating/updating index file: ${i}`);const s=this.project.getSourceFile(i)||this.project.createSourceFile(i,"",{overwrite:!0});s.removeText();for(const a of n){const c=`./${a.getBaseNameWithoutExtension()}`;this.options.logger.info(`Adding export for file: ${c}`),s.addExportDeclaration({moduleSpecifier:c,isTypeOnly:!1,namedExports:[]})}for(const a of r){const c=`./${a.getBaseName()}`;this.options.logger.info(`Adding export for subdirectory: ${c}`),s.addExportDeclaration({moduleSpecifier:c,isTypeOnly:!1,namedExports:[]})}this.options.logger.info(`Index file generated for ${t} with ${n.length+r.length} exports`)}optimizeSourceFiles(){const e=this.project.getSourceFiles();this.options.logger.info(`Optimizing ${e.length} source files`),e.forEach((t,n)=>{this.options.logger.info(`Optimizing file ${n+1}/${e.length}`),t.formatText(),t.organizeImports(),t.fixMissingImports()}),this.options.logger.info("All source files optimized")}}exports.CodeGenerator=nt;exports.DEFAULT_CONFIG_PATH=ue;
12
12
  //# sourceMappingURL=index.cjs.map