@ahoo-wang/fetcher-generator 2.2.0 → 2.2.3
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/dist/cli.cjs +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +6 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +100 -96
- package/dist/index.js.map +1 -1
- package/dist/model/modelGenerator.d.ts +2 -0
- package/dist/model/modelGenerator.d.ts.map +1 -1
- package/package.json +6 -6
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"),g=require("./index.cjs"),d=require("ts-morph");require("yaml");require("fs");require("@ahoo-wang/fetcher");require("path");class h{getTimestamp(){return new Date().toISOString().slice(11,19)}info(e,...t){const o=this.getTimestamp();t.length>0?console.log(`[${o}] ℹ️ ${e}`,...t):console.log(`[${o}] ℹ️ ${e}`)}success(e,...t){const o=this.getTimestamp();t.length>0?console.log(`[${o}] ✅ ${e}`,...t):console.log(`[${o}] ✅ ${e}`)}error(e,...t){const o=this.getTimestamp();t.length>0?console.error(`[${o}] ❌ ${e}`,...t):console.error(`[${o}] ❌ ${e}`)}progress(e,t=0,...o){const n=this.getTimestamp(),i=" ".repeat(t);o.length>0?console.log(`[${n}] 🔄 ${i}${e}`,...o):console.log(`[${n}] 🔄 ${i}${e}`)}progressWithCount(e,t,o,n=0,...i){const s=this.getTimestamp(),p=" ".repeat(n),l=`[${e}/${t}]`;i.length>0?console.log(`[${s}] 🔄 ${p}${l} ${o}`,...i):console.log(`[${s}] 🔄 ${p}${l} ${o}`)}}function $(r){if(!r)return!1;try{const e=new URL(r);return e.protocol==="http:"||e.protocol==="https:"}catch{return r.length>0}}async function f(r){const e=new h;process.on("SIGINT",()=>{e.error("Generation interrupted by user"),process.exit(130)}),$(r.input)||(e.error("Invalid input: must be a valid file path or HTTP/HTTPS URL"),process.exit(2));try{e.info("Starting code generation...");const t=new d.Project,o={inputPath:r.input,outputDir:r.output,project:t,logger:e};await new g.CodeGenerator(o).generate(),e.success(`Code generation completed successfully! Files generated in: ${r.output}`)}catch(t){e.error(`Error during code generation: ${t}`),process.exit(1)}}const m="2.2.
|
|
2
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("commander"),g=require("./index.cjs"),d=require("ts-morph");require("yaml");require("fs");require("@ahoo-wang/fetcher");require("path");class h{getTimestamp(){return new Date().toISOString().slice(11,19)}info(e,...t){const o=this.getTimestamp();t.length>0?console.log(`[${o}] ℹ️ ${e}`,...t):console.log(`[${o}] ℹ️ ${e}`)}success(e,...t){const o=this.getTimestamp();t.length>0?console.log(`[${o}] ✅ ${e}`,...t):console.log(`[${o}] ✅ ${e}`)}error(e,...t){const o=this.getTimestamp();t.length>0?console.error(`[${o}] ❌ ${e}`,...t):console.error(`[${o}] ❌ ${e}`)}progress(e,t=0,...o){const n=this.getTimestamp(),i=" ".repeat(t);o.length>0?console.log(`[${n}] 🔄 ${i}${e}`,...o):console.log(`[${n}] 🔄 ${i}${e}`)}progressWithCount(e,t,o,n=0,...i){const s=this.getTimestamp(),p=" ".repeat(n),l=`[${e}/${t}]`;i.length>0?console.log(`[${s}] 🔄 ${p}${l} ${o}`,...i):console.log(`[${s}] 🔄 ${p}${l} ${o}`)}}function $(r){if(!r)return!1;try{const e=new URL(r);return e.protocol==="http:"||e.protocol==="https:"}catch{return r.length>0}}async function f(r){const e=new h;process.on("SIGINT",()=>{e.error("Generation interrupted by user"),process.exit(130)}),$(r.input)||(e.error("Invalid input: must be a valid file path or HTTP/HTTPS URL"),process.exit(2));try{e.info("Starting code generation...");const t=new d.Project,o={inputPath:r.input,outputDir:r.output,project:t,logger:e};await new g.CodeGenerator(o).generate(),e.success(`Code generation completed successfully! Files generated in: ${r.output}`)}catch(t){e.error(`Error during code generation: ${t}`),process.exit(1)}}const m="2.2.3",T={version:m};function u(){return c.program.name("fetcher-generator").description("OpenAPI Specification TypeScript code generator for Wow").version(T.version),c.program.command("generate").description("Generate TypeScript code from OpenAPI specification").requiredOption("-i, --input <path>","Input OpenAPI specification file path or URL (http/https)").option("-o, --output <path>","Output directory path","src/generated").option("-c, --config <file>","Configuration file path").option("-v, --verbose","Enable verbose logging").option("--dry-run","Show what would be generated without writing files").action(f),c.program}function a(){u().parse()}a();exports.runCLI=a;exports.setupCLI=u;
|
|
3
3
|
//# sourceMappingURL=cli.cjs.map
|
package/dist/cli.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.cjs","sources":["../src/utils/logger.ts","../src/utils/clis.ts","../src/cli.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from '../types';\n\n/**\n * Default console-based logger implementation.\n * Provides friendly colored output for different log levels.\n */\nexport class ConsoleLogger implements Logger {\n private getTimestamp(): string {\n return new Date().toISOString().slice(11, 19); // HH:MM:SS format\n }\n\n info(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.log(`[${timestamp}] ℹ️ ${message}`, ...params);\n } else {\n console.log(`[${timestamp}] ℹ️ ${message}`);\n }\n }\n\n success(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.log(`[${timestamp}] ✅ ${message}`, ...params);\n } else {\n console.log(`[${timestamp}] ✅ ${message}`);\n }\n }\n\n error(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.error(`[${timestamp}] ❌ ${message}`, ...params);\n } else {\n console.error(`[${timestamp}] ❌ ${message}`);\n }\n }\n\n progress(message: string, level = 0, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n const indent = ' '.repeat(level);\n if (params.length > 0) {\n console.log(`[${timestamp}] 🔄 ${indent}${message}`, ...params);\n } else {\n console.log(`[${timestamp}] 🔄 ${indent}${message}`);\n }\n }\n\n progressWithCount(\n current: number,\n total: number,\n message: string,\n level = 0,\n ...params: any[]\n ): void {\n const timestamp = this.getTimestamp();\n const indent = ' '.repeat(level);\n const countStr = `[${current}/${total}]`;\n if (params.length > 0) {\n console.log(\n `[${timestamp}] 🔄 ${indent}${countStr} ${message}`,\n ...params,\n );\n } else {\n console.log(`[${timestamp}] 🔄 ${indent}${countStr} ${message}`);\n }\n }\n}\n\n/**\n * Silent logger that suppresses all output.\n */\nexport class SilentLogger implements Logger {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n info(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n success(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n error(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n progress(_message: string, ...params: any[]): void {\n }\n\n /* eslint-disable @typescript-eslint/no-unused-vars */\n progressWithCount(\n _current: number,\n _total: number,\n _message: string,\n _level = 0,\n ..._params: any[]\n ): void {\n }\n\n /* eslint-enable @typescript-eslint/no-unused-vars */\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConsoleLogger } from './logger';\nimport { GeneratorOptions } from '../types';\nimport { CodeGenerator } from '../index';\nimport { Project } from 'ts-morph';\n\n/**\n * Validates the input path or URL.\n * @param input - Input path or URL\n * @returns true if valid\n */\nexport function validateInput(input: string): boolean {\n if (!input) return false;\n\n // Check if it's a URL\n try {\n const url = new URL(input);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n // Not a URL, check if it's a file path\n // For file paths, we'll let parseOpenAPI handle it\n return input.length > 0;\n }\n}\n\n/**\n * Action handler for the generate command.\n * @param options - Command options\n */\nexport async function generateAction(options: {\n input: string;\n output: string;\n config?: string;\n verbose?: boolean;\n dryRun?: boolean;\n}) {\n const logger = new ConsoleLogger();\n\n // Handle signals\n process.on('SIGINT', () => {\n logger.error('Generation interrupted by user');\n process.exit(130);\n });\n\n // Validate input\n if (!validateInput(options.input)) {\n logger.error('Invalid input: must be a valid file path or HTTP/HTTPS URL');\n process.exit(2);\n }\n\n try {\n logger.info('Starting code generation...');\n const project = new Project();\n const generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n project,\n logger,\n };\n const codeGenerator = new CodeGenerator(generatorOptions);\n await codeGenerator.generate();\n logger.success(\n `Code generation completed successfully! Files generated in: ${options.output}`,\n );\n } catch (error) {\n logger.error(`Error during code generation: ${error}`);\n process.exit(1);\n }\n}","#!/usr/bin/env node\n\n/**\n * CLI entry point for the Fetcher OpenAPI code generator.\n * Sets up the commander program with generate command and handles execution.\n */\n\nimport { program } from 'commander';\nimport { generateAction } from './utils';\nimport packageJson from '../package.json';\n\n/**\n * Sets up the CLI program with all commands and options.\n * @returns The configured commander program instance\n */\nexport function setupCLI() {\n program\n .name('fetcher-generator')\n .description('OpenAPI Specification TypeScript code generator for Wow')\n .version(packageJson.version);\n\n program\n .command('generate')\n .description('Generate TypeScript code from OpenAPI specification')\n .requiredOption(\n '-i, --input <path>',\n 'Input OpenAPI specification file path or URL (http/https)',\n )\n .option('-o, --output <path>', 'Output directory path', 'src/generated')\n .option('-c, --config <file>', 'Configuration file path')\n .option('-v, --verbose', 'Enable verbose logging')\n .option('--dry-run', 'Show what would be generated without writing files')\n .action(generateAction);\n\n return program;\n}\n\n/**\n * Runs the CLI program by parsing command line arguments.\n * Only executes when this file is run directly (not imported).\n */\nexport function runCLI() {\n setupCLI().parse();\n}\n\nrunCLI();\n"],"names":["ConsoleLogger","message","params","timestamp","level","indent","current","total","countStr","validateInput","input","url","generateAction","options","logger","project","Project","generatorOptions","CodeGenerator","error","setupCLI","program","packageJson","runCLI"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.cjs","sources":["../src/utils/logger.ts","../src/utils/clis.ts","../src/cli.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from '../types';\n\n/**\n * Default console-based logger implementation.\n * Provides friendly colored output for different log levels.\n */\nexport class ConsoleLogger implements Logger {\n private getTimestamp(): string {\n return new Date().toISOString().slice(11, 19); // HH:MM:SS format\n }\n\n info(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.log(`[${timestamp}] ℹ️ ${message}`, ...params);\n } else {\n console.log(`[${timestamp}] ℹ️ ${message}`);\n }\n }\n\n success(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.log(`[${timestamp}] ✅ ${message}`, ...params);\n } else {\n console.log(`[${timestamp}] ✅ ${message}`);\n }\n }\n\n error(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.error(`[${timestamp}] ❌ ${message}`, ...params);\n } else {\n console.error(`[${timestamp}] ❌ ${message}`);\n }\n }\n\n progress(message: string, level = 0, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n const indent = ' '.repeat(level);\n if (params.length > 0) {\n console.log(`[${timestamp}] 🔄 ${indent}${message}`, ...params);\n } else {\n console.log(`[${timestamp}] 🔄 ${indent}${message}`);\n }\n }\n\n progressWithCount(\n current: number,\n total: number,\n message: string,\n level = 0,\n ...params: any[]\n ): void {\n const timestamp = this.getTimestamp();\n const indent = ' '.repeat(level);\n const countStr = `[${current}/${total}]`;\n if (params.length > 0) {\n console.log(\n `[${timestamp}] 🔄 ${indent}${countStr} ${message}`,\n ...params,\n );\n } else {\n console.log(`[${timestamp}] 🔄 ${indent}${countStr} ${message}`);\n }\n }\n}\n\n/**\n * Silent logger that suppresses all output.\n */\nexport class SilentLogger implements Logger {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n info(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n success(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n error(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n progress(_message: string, ...params: any[]): void {\n }\n\n /* eslint-disable @typescript-eslint/no-unused-vars */\n progressWithCount(\n _current: number,\n _total: number,\n _message: string,\n _level = 0,\n ..._params: any[]\n ): void {\n }\n\n /* eslint-enable @typescript-eslint/no-unused-vars */\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConsoleLogger } from './logger';\nimport { GeneratorOptions } from '../types';\nimport { CodeGenerator } from '../index';\nimport { Project } from 'ts-morph';\n\n/**\n * Validates the input path or URL.\n * @param input - Input path or URL\n * @returns true if valid\n */\nexport function validateInput(input: string): boolean {\n if (!input) return false;\n\n // Check if it's a URL\n try {\n const url = new URL(input);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n // Not a URL, check if it's a file path\n // For file paths, we'll let parseOpenAPI handle it\n return input.length > 0;\n }\n}\n\n/**\n * Action handler for the generate command.\n * @param options - Command options\n */\nexport async function generateAction(options: {\n input: string;\n output: string;\n config?: string;\n verbose?: boolean;\n dryRun?: boolean;\n}) {\n const logger = new ConsoleLogger();\n\n // Handle signals\n process.on('SIGINT', () => {\n logger.error('Generation interrupted by user');\n process.exit(130);\n });\n\n // Validate input\n if (!validateInput(options.input)) {\n logger.error('Invalid input: must be a valid file path or HTTP/HTTPS URL');\n process.exit(2);\n }\n\n try {\n logger.info('Starting code generation...');\n const project = new Project();\n const generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n project,\n logger,\n };\n const codeGenerator = new CodeGenerator(generatorOptions);\n await codeGenerator.generate();\n logger.success(\n `Code generation completed successfully! Files generated in: ${options.output}`,\n );\n } catch (error) {\n logger.error(`Error during code generation: ${error}`);\n process.exit(1);\n }\n}\n","#!/usr/bin/env node\n\n/**\n * CLI entry point for the Fetcher OpenAPI code generator.\n * Sets up the commander program with generate command and handles execution.\n */\n\nimport { program } from 'commander';\nimport { generateAction } from './utils';\nimport packageJson from '../package.json';\n\n/**\n * Sets up the CLI program with all commands and options.\n * @returns The configured commander program instance\n */\nexport function setupCLI() {\n program\n .name('fetcher-generator')\n .description('OpenAPI Specification TypeScript code generator for Wow')\n .version(packageJson.version);\n\n program\n .command('generate')\n .description('Generate TypeScript code from OpenAPI specification')\n .requiredOption(\n '-i, --input <path>',\n 'Input OpenAPI specification file path or URL (http/https)',\n )\n .option('-o, --output <path>', 'Output directory path', 'src/generated')\n .option('-c, --config <file>', 'Configuration file path')\n .option('-v, --verbose', 'Enable verbose logging')\n .option('--dry-run', 'Show what would be generated without writing files')\n .action(generateAction);\n\n return program;\n}\n\n/**\n * Runs the CLI program by parsing command line arguments.\n * Only executes when this file is run directly (not imported).\n */\nexport function runCLI() {\n setupCLI().parse();\n}\n\nrunCLI();\n"],"names":["ConsoleLogger","message","params","timestamp","level","indent","current","total","countStr","validateInput","input","url","generateAction","options","logger","project","Project","generatorOptions","CodeGenerator","error","setupCLI","program","packageJson","runCLI"],"mappings":"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"}
|
package/dist/cli.js
CHANGED
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().toISOString().slice(11, 19); // HH:MM:SS format\n }\n\n info(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.log(`[${timestamp}] ℹ️ ${message}`, ...params);\n } else {\n console.log(`[${timestamp}] ℹ️ ${message}`);\n }\n }\n\n success(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.log(`[${timestamp}] ✅ ${message}`, ...params);\n } else {\n console.log(`[${timestamp}] ✅ ${message}`);\n }\n }\n\n error(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.error(`[${timestamp}] ❌ ${message}`, ...params);\n } else {\n console.error(`[${timestamp}] ❌ ${message}`);\n }\n }\n\n progress(message: string, level = 0, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n const indent = ' '.repeat(level);\n if (params.length > 0) {\n console.log(`[${timestamp}] 🔄 ${indent}${message}`, ...params);\n } else {\n console.log(`[${timestamp}] 🔄 ${indent}${message}`);\n }\n }\n\n progressWithCount(\n current: number,\n total: number,\n message: string,\n level = 0,\n ...params: any[]\n ): void {\n const timestamp = this.getTimestamp();\n const indent = ' '.repeat(level);\n const countStr = `[${current}/${total}]`;\n if (params.length > 0) {\n console.log(\n `[${timestamp}] 🔄 ${indent}${countStr} ${message}`,\n ...params,\n );\n } else {\n console.log(`[${timestamp}] 🔄 ${indent}${countStr} ${message}`);\n }\n }\n}\n\n/**\n * Silent logger that suppresses all output.\n */\nexport class SilentLogger implements Logger {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n info(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n success(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n error(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n progress(_message: string, ...params: any[]): void {\n }\n\n /* eslint-disable @typescript-eslint/no-unused-vars */\n progressWithCount(\n _current: number,\n _total: number,\n _message: string,\n _level = 0,\n ..._params: any[]\n ): void {\n }\n\n /* eslint-enable @typescript-eslint/no-unused-vars */\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConsoleLogger } from './logger';\nimport { GeneratorOptions } from '../types';\nimport { CodeGenerator } from '../index';\nimport { Project } from 'ts-morph';\n\n/**\n * Validates the input path or URL.\n * @param input - Input path or URL\n * @returns true if valid\n */\nexport function validateInput(input: string): boolean {\n if (!input) return false;\n\n // Check if it's a URL\n try {\n const url = new URL(input);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n // Not a URL, check if it's a file path\n // For file paths, we'll let parseOpenAPI handle it\n return input.length > 0;\n }\n}\n\n/**\n * Action handler for the generate command.\n * @param options - Command options\n */\nexport async function generateAction(options: {\n input: string;\n output: string;\n config?: string;\n verbose?: boolean;\n dryRun?: boolean;\n}) {\n const logger = new ConsoleLogger();\n\n // Handle signals\n process.on('SIGINT', () => {\n logger.error('Generation interrupted by user');\n process.exit(130);\n });\n\n // Validate input\n if (!validateInput(options.input)) {\n logger.error('Invalid input: must be a valid file path or HTTP/HTTPS URL');\n process.exit(2);\n }\n\n try {\n logger.info('Starting code generation...');\n const project = new Project();\n const generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n project,\n logger,\n };\n const codeGenerator = new CodeGenerator(generatorOptions);\n await codeGenerator.generate();\n logger.success(\n `Code generation completed successfully! Files generated in: ${options.output}`,\n );\n } catch (error) {\n logger.error(`Error during code generation: ${error}`);\n process.exit(1);\n }\n}","#!/usr/bin/env node\n\n/**\n * CLI entry point for the Fetcher OpenAPI code generator.\n * Sets up the commander program with generate command and handles execution.\n */\n\nimport { program } from 'commander';\nimport { generateAction } from './utils';\nimport packageJson from '../package.json';\n\n/**\n * Sets up the CLI program with all commands and options.\n * @returns The configured commander program instance\n */\nexport function setupCLI() {\n program\n .name('fetcher-generator')\n .description('OpenAPI Specification TypeScript code generator for Wow')\n .version(packageJson.version);\n\n program\n .command('generate')\n .description('Generate TypeScript code from OpenAPI specification')\n .requiredOption(\n '-i, --input <path>',\n 'Input OpenAPI specification file path or URL (http/https)',\n )\n .option('-o, --output <path>', 'Output directory path', 'src/generated')\n .option('-c, --config <file>', 'Configuration file path')\n .option('-v, --verbose', 'Enable verbose logging')\n .option('--dry-run', 'Show what would be generated without writing files')\n .action(generateAction);\n\n return program;\n}\n\n/**\n * Runs the CLI program by parsing command line arguments.\n * Only executes when this file is run directly (not imported).\n */\nexport function runCLI() {\n setupCLI().parse();\n}\n\nrunCLI();\n"],"names":["ConsoleLogger","message","params","timestamp","level","indent","current","total","countStr","validateInput","input","url","generateAction","options","logger","project","Project","generatorOptions","CodeGenerator","error","setupCLI","program","packageJson","runCLI"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.js","sources":["../src/utils/logger.ts","../src/utils/clis.ts","../src/cli.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from '../types';\n\n/**\n * Default console-based logger implementation.\n * Provides friendly colored output for different log levels.\n */\nexport class ConsoleLogger implements Logger {\n private getTimestamp(): string {\n return new Date().toISOString().slice(11, 19); // HH:MM:SS format\n }\n\n info(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.log(`[${timestamp}] ℹ️ ${message}`, ...params);\n } else {\n console.log(`[${timestamp}] ℹ️ ${message}`);\n }\n }\n\n success(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.log(`[${timestamp}] ✅ ${message}`, ...params);\n } else {\n console.log(`[${timestamp}] ✅ ${message}`);\n }\n }\n\n error(message: string, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n if (params.length > 0) {\n console.error(`[${timestamp}] ❌ ${message}`, ...params);\n } else {\n console.error(`[${timestamp}] ❌ ${message}`);\n }\n }\n\n progress(message: string, level = 0, ...params: any[]): void {\n const timestamp = this.getTimestamp();\n const indent = ' '.repeat(level);\n if (params.length > 0) {\n console.log(`[${timestamp}] 🔄 ${indent}${message}`, ...params);\n } else {\n console.log(`[${timestamp}] 🔄 ${indent}${message}`);\n }\n }\n\n progressWithCount(\n current: number,\n total: number,\n message: string,\n level = 0,\n ...params: any[]\n ): void {\n const timestamp = this.getTimestamp();\n const indent = ' '.repeat(level);\n const countStr = `[${current}/${total}]`;\n if (params.length > 0) {\n console.log(\n `[${timestamp}] 🔄 ${indent}${countStr} ${message}`,\n ...params,\n );\n } else {\n console.log(`[${timestamp}] 🔄 ${indent}${countStr} ${message}`);\n }\n }\n}\n\n/**\n * Silent logger that suppresses all output.\n */\nexport class SilentLogger implements Logger {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n info(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n success(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n error(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n progress(_message: string, ...params: any[]): void {\n }\n\n /* eslint-disable @typescript-eslint/no-unused-vars */\n progressWithCount(\n _current: number,\n _total: number,\n _message: string,\n _level = 0,\n ..._params: any[]\n ): void {\n }\n\n /* eslint-enable @typescript-eslint/no-unused-vars */\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConsoleLogger } from './logger';\nimport { GeneratorOptions } from '../types';\nimport { CodeGenerator } from '../index';\nimport { Project } from 'ts-morph';\n\n/**\n * Validates the input path or URL.\n * @param input - Input path or URL\n * @returns true if valid\n */\nexport function validateInput(input: string): boolean {\n if (!input) return false;\n\n // Check if it's a URL\n try {\n const url = new URL(input);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n // Not a URL, check if it's a file path\n // For file paths, we'll let parseOpenAPI handle it\n return input.length > 0;\n }\n}\n\n/**\n * Action handler for the generate command.\n * @param options - Command options\n */\nexport async function generateAction(options: {\n input: string;\n output: string;\n config?: string;\n verbose?: boolean;\n dryRun?: boolean;\n}) {\n const logger = new ConsoleLogger();\n\n // Handle signals\n process.on('SIGINT', () => {\n logger.error('Generation interrupted by user');\n process.exit(130);\n });\n\n // Validate input\n if (!validateInput(options.input)) {\n logger.error('Invalid input: must be a valid file path or HTTP/HTTPS URL');\n process.exit(2);\n }\n\n try {\n logger.info('Starting code generation...');\n const project = new Project();\n const generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n project,\n logger,\n };\n const codeGenerator = new CodeGenerator(generatorOptions);\n await codeGenerator.generate();\n logger.success(\n `Code generation completed successfully! Files generated in: ${options.output}`,\n );\n } catch (error) {\n logger.error(`Error during code generation: ${error}`);\n process.exit(1);\n }\n}\n","#!/usr/bin/env node\n\n/**\n * CLI entry point for the Fetcher OpenAPI code generator.\n * Sets up the commander program with generate command and handles execution.\n */\n\nimport { program } from 'commander';\nimport { generateAction } from './utils';\nimport packageJson from '../package.json';\n\n/**\n * Sets up the CLI program with all commands and options.\n * @returns The configured commander program instance\n */\nexport function setupCLI() {\n program\n .name('fetcher-generator')\n .description('OpenAPI Specification TypeScript code generator for Wow')\n .version(packageJson.version);\n\n program\n .command('generate')\n .description('Generate TypeScript code from OpenAPI specification')\n .requiredOption(\n '-i, --input <path>',\n 'Input OpenAPI specification file path or URL (http/https)',\n )\n .option('-o, --output <path>', 'Output directory path', 'src/generated')\n .option('-c, --config <file>', 'Configuration file path')\n .option('-v, --verbose', 'Enable verbose logging')\n .option('--dry-run', 'Show what would be generated without writing files')\n .action(generateAction);\n\n return program;\n}\n\n/**\n * Runs the CLI program by parsing command line arguments.\n * Only executes when this file is run directly (not imported).\n */\nexport function runCLI() {\n setupCLI().parse();\n}\n\nrunCLI();\n"],"names":["ConsoleLogger","message","params","timestamp","level","indent","current","total","countStr","validateInput","input","url","generateAction","options","logger","project","Project","generatorOptions","CodeGenerator","error","setupCLI","program","packageJson","runCLI"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
2
|
-
`):void 0}function
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const $=require("ts-morph"),Q=require("yaml"),G=require("fs"),A=require("@ahoo-wang/fetcher"),I=require("path"),v=require("@ahoo-wang/fetcher-wow");function _(o){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(o){for(const t in o)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(o,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>o[t]})}}return e.default=o,Object.freeze(e)}const R=_(G),K=_(I);function f(o){return o.$ref.split("/").pop()}function N(o,e){const t=f(o);return e.schemas?.[t]}function V(o,e){const t=f(o);return e.requestBodies?.[t]}function U(o,e){const t=f(o);return e.parameters?.[t]}function P(o,e){return{key:f(o),schema:N(o,e)}}const j=/[-_\s.]+|(?=[A-Z])/;function x(o){if(o===""||o.length===0)return"";let e;return Array.isArray(o)?e=o.flatMap(t=>t.split(j)):e=o.split(j),e.filter(t=>t.length>0).map(t=>{if(t.length===0)return"";const n=t.charAt(0),r=t.slice(1);return(/[a-zA-Z]/.test(n)?n.toUpperCase():n)+r.toLowerCase()}).join("")}function h(o){const e=x(o);return e.charAt(0).toLowerCase()+e.slice(1)}function J(o){return o.startsWith("http://")||o.startsWith("https://")?H(o):Y(o)}async function H(o){return await(await fetch(o)).text()}function Y(o){return new Promise((e,t)=>{G.readFile(o,"utf-8",(n,r)=>{n?t(n):e(r)})})}async function X(o){const e=await J(o);switch(Z(e)){case"json":return JSON.parse(e);case"yaml":return Q.parse(e);default:throw new Error(`Unsupported file format: ${o}`)}}function Z(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")}function g(o){return!!(o&&typeof o=="object"&&"$ref"in o)}function ee(o){return!o||g(o)||!o.content?void 0:o.content[A.ContentTypeValues.APPLICATION_JSON]?.schema}function te(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 F(o){return o.responses[200]}function M(o){const e=F(o);return ee(e)}const ne=["string","number","integer","boolean","null"];function oe(o){return Array.isArray(o)?!0:ne.includes(o)}function re(o){return o.type==="array"}function se(o){return Array.isArray(o.enum)&&o.enum.length>0}function W(o){return Array.isArray(o.anyOf)&&o.anyOf.length>0}function B(o){return Array.isArray(o.oneOf)&&o.oneOf.length>0}function ie(o){return W(o)||B(o)}function ae(o){return Array.isArray(o.allOf)&&o.allOf.length>0}function q(o){return W(o)||B(o)||ae(o)}function ce(o){return o.includes("|")||o.includes("&")?`(${o})[]`:`${o}[]`}function D(o){if(Array.isArray(o))return o.map(e=>D(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"}}const z="types.ts",ge="@";function le(o){return A.combineURLs(o.path,z)}function b(o,e,t){const n=A.combineURLs(e,t),r=o.getSourceFile(n);return r||o.createSourceFile(n,"",{overwrite:!0})}function O(o,e,t){let n=o.getImportDeclaration(r=>r.getModuleSpecifierValue()===e);n||(n=o.addImportDeclaration({moduleSpecifier:e})),t.forEach(r=>{n.getNamedImports().some(a=>a.getName()===r)||n.addNamedImport(r)})}function y(o,e,t){if(t.path.startsWith(ge)){O(o,t.path,[t.name]);return}const n=o.getDirectoryPath(),r=I.join(e,t.path,z);let s=I.relative(n,r);s=s.replace(/\.ts$/,""),s.startsWith(".")||(s="./"+s),O(o,s,[t.name])}function E(o,e,t,n){o.path!==n.path&&y(e,t,n)}function pe(o,e){const t=[o,e].filter(n=>n!==void 0&&n.length>0);return t.length>0?t.join(`
|
|
2
|
+
`):void 0}function w(o,e,t){const n=pe(e,t);n&&o.addJsDoc({description:n})}function ue(o){const e=o.split(".");return e.length!=2||e[0].length===0||e[1].length===0?null:e}function de(o){const e=ue(o.name);return e?{tag:o,contextAlias:e[0],aggregateName:e[1]}:null}function me(o){const e=o?.map(n=>de(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 fe(o){if(!o)return null;const e=o.split(".");return e.length!=3?null:e[2]}const he="#/components/responses/wow.CommandOk",ye="#/components/parameters/wow.id";class Ae{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=te(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=fe(n.operationId);if(!r)return;const s=F(n);if(!s||!g(s)||s.$ref!==he||!n.requestBody)return;const a=n.parameters??[],c=a.filter(d=>g(d)&&d.$ref===ye).at(0),i=a.filter(d=>!g(d)&&d.in==="path");if(c){const d=U(c,this.openAPI.components);i.push(d)}const u=n.requestBody.content[A.ContentTypeValues.APPLICATION_JSON].schema,l=P(u,this.openAPI.components);l.schema.title=l.schema.title||n.summary,l.schema.description=l.schema.description||n.description;const k={name:r,method:t.method,path:e,pathParameters:i,summary:n.summary,description:n.description,schema:l,operation:n};n.tags?.forEach(d=>{const T=this.aggregates.get(d);T&&T.commands.set(r,k)})}state(e){if(!e.operationId?.endsWith(".snapshot_state.single"))return;const t=M(e);if(!g(t))return;const n=P(t,this.openAPI.components);e.tags?.forEach(r=>{const s=this.aggregates.get(r);s&&(s.state=n)})}events(e){if(!this.openAPI.components||!e.operationId?.endsWith(".event.list_query"))return;const t=M(e);if(g(t))return;const n=t?.items;if(!g(n))return;const s=N(n,this.openAPI.components).properties.body.items.anyOf.map(a=>{const c=a.title,i=a.properties.name.const,p=a.properties.body,u=P(p,this.openAPI.components);return u.schema.title=u.schema.title||a.title,{title:c,name:i,schema:u}});e.tags?.forEach(a=>{const c=this.aggregates.get(a);c&&s.forEach(i=>{c.events.set(i.name,i)})})}fields(e){if(!this.openAPI.components||!e.operationId?.endsWith(".snapshot.count"))return;const n=V(e.requestBody,this.openAPI.components).content[A.ContentTypeValues.APPLICATION_JSON].schema,s=N(n,this.openAPI.components).properties?.field,a=P(s,this.openAPI.components);e.tags?.forEach(c=>{const i=this.aggregates.get(c);i&&(i.fields=a)})}}const C="@ahoo-wang/fetcher-wow",Ce={"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 m(o){if(!o)return{name:"",path:"/"};const e=Ce[o];if(e)return{name:e,path:C};const t=o.split(".");let n=-1;for(let i=0;i<t.length;i++)if(t[i]&&/^[A-Z]/.test(t[i])){n=i;break}if(n===-1)return{name:o,path:"/"};const r=t.slice(0,n),s=r.length>0?`/${r.join("/")}`:"/",a=t.slice(n);return{name:x(a),path:s}}class S{project;openAPI;outputDir;contextAggregates;logger;constructor(e){this.project=e.project,this.openAPI=e.openAPI,this.outputDir=e.outputDir,this.contextAggregates=e.contextAggregates,this.logger=e.logger}}class Pe extends S{constructor(e){super(e)}getOrCreateSourceFile(e){const t=le(e);return b(this.project,this.outputDir,t)}generate(){const e=this.openAPI.components?.schemas;if(!e){this.logger.info("No schemas found in OpenAPI specification");return}const t=this.filterSchemas(e);this.logger.progress(`Generating models for ${t.length} schemas`),t.forEach((n,r)=>{this.logger.progressWithCount(r+1,t.length,`Processing schema: ${n.key}`,2),this.generateKeyedSchema(n)}),this.logger.success("Model generation completed")}filterSchemas(e){return Object.entries(e).map(([t,n])=>({key:t,schema:n})).filter(t=>!this.isWowSchema(t.key))}isWowSchema(e){return e.startsWith("wow.")}generateKeyedSchema({key:e,schema:t}){const n=m(e),r=this.getOrCreateSourceFile(n),s=this.process(n,r,t);s&&w(s,t.title,t.description)}process(e,t,n){if(se(n))return t.addEnum({name:e.name,isExported:!0,members:n.enum.filter(s=>typeof s=="string"&&s.length>0).map(s=>({name:s,initializer:`'${s}'`}))});const r=t.addInterface({name:e.name,isExported:!0});return n.type==="object"&&n.properties?this.processInterface(t,e,n,r):(q(n)&&(n.anyOf||n.oneOf||n.allOf).forEach(a=>{if(g(a)){const c=m(f(a));E(e,t,this.outputDir,c),r.addExtends(c.name);return}this.processInterface(t,e,a,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[s,a]of Object.entries(n.properties)){const c=this.resolvePropertyType(t,e,s,a);let i=r.getProperty(s);i?i.setType(c):i=r.addProperty({name:s,type:c}),g(a)||w(i,a.title,a.description)}return r}resolvePropertyType(e,t,n,r){if(g(r)){const s=m(f(r));return E(e,t,this.outputDir,s),s.name}if(r.const)return`'${r.const}'`;if(re(r)){const s=this.resolvePropertyType(e,t,n,r.items);return ce(s)}if(r.type&&oe(r.type))return D(r.type);if(q(r))return this.resolvePropertyCompositionType(e,t,r);if(r.type==="object"&&r.properties){const s={path:e.path,name:`${e.name}${x(n)}`},a=this.processObject(t,s,r);return w(a,r.title,r.description),s.name}return"any"}resolvePropertyCompositionType(e,t,n){const r=n.anyOf||n.oneOf||n.allOf,s=new Set;r.forEach(c=>{if(g(c)){const i=m(f(c));E(e,t,this.outputDir,i),s.add(i.name);return}s.add(D(c.type??"string"))});const a=ie(n)?"|":"&";return Array.from(s).join(a)}}function we(o){let e=0,t=0;return o.commands.forEach(n=>{n.path.startsWith(v.ResourceAttributionPathSpec.TENANT)&&(e+=1),n.path.startsWith(v.ResourceAttributionPathSpec.OWNER)&&(t+=1)}),e===0&&t===0?"ResourceAttributionPathSpec.NONE":e>t?"ResourceAttributionPathSpec.TENANT":"ResourceAttributionPathSpec.OWNER"}function L(o,e,t,n){const r=`${t.contextAlias}/${t.aggregateName}/${n}.ts`;return b(o,e,r)}function $e(o,e){return`${x(o.aggregateName)}${e}`}class Oe extends S{constructor(e){super(e)}generate(){const e=Array.from(this.contextAggregates.values()).reduce((n,r)=>n+r.size,0);this.logger.info("--- Generating Query Clients ---"),this.logger.progress(`Generating query clients for ${e} aggregates`);let t=0;for(const[,n]of this.contextAggregates)n.forEach(r=>{t++,this.logger.progressWithCount(t,e,`Processing query client for aggregate: ${r.aggregate.aggregateName}`),this.processQueryClient(r)});this.logger.success("Query client generation completed")}createClientFilePath(e,t){return L(this.project,this.outputDir,e,t)}processQueryClient(e){const t=this.createClientFilePath(e.aggregate,"queryClient");this.logger.info(`Processing query client for aggregate: ${e.aggregate.aggregateName} in context: ${e.aggregate.contextAlias}`),this.logger.info(`Adding imports from ${C}: QueryClientFactory, QueryClientOptions, ResourceAttributionPathSpec`),t.addImportDeclaration({moduleSpecifier:C,namedImports:["QueryClientFactory","QueryClientOptions","ResourceAttributionPathSpec"]});const n="DEFAULT_QUERY_CLIENT_OPTIONS";this.logger.info(`Creating default query client options: ${n}`),t.addVariableStatement({declarationKind:$.VariableDeclarationKind.Const,declarations:[{name:n,type:"QueryClientOptions",initializer:`{
|
|
3
3
|
contextAlias: '${e.aggregate.contextAlias}',
|
|
4
4
|
aggregateName: '${e.aggregate.aggregateName}',
|
|
5
|
-
resourceAttribution: ${
|
|
6
|
-
}`}],isExported:!1});const r=[];this.logger.info(`Processing ${e.events.size} domain events for aggregate: ${e.aggregate.aggregateName}`);for(const u of e.events.values()){const l=m(u.schema.key);this.logger.info(`Adding import for event model: ${l.name} from path: ${l.path}`),y(t,this.outputDir,l),r.push(l)}const s="DOMAIN_EVENT_TYPES",
|
|
5
|
+
resourceAttribution: ${we(e)},
|
|
6
|
+
}`}],isExported:!1});const r=[];this.logger.info(`Processing ${e.events.size} domain events for aggregate: ${e.aggregate.aggregateName}`);for(const u of e.events.values()){const l=m(u.schema.key);this.logger.info(`Adding import for event model: ${l.name} from path: ${l.path}`),y(t,this.outputDir,l),r.push(l)}const s="DOMAIN_EVENT_TYPES",a=r.map(u=>u.name).join(" | ");this.logger.info(`Creating domain event types union: ${s} = ${a}`),t.addTypeAlias({name:s,type:a});const c=`${h(e.aggregate.aggregateName)}QueryClientFactory`,i=m(e.state.key),p=m(e.fields.key);this.logger.info(`Adding import for state model: ${i.name} from path: ${i.path}`),y(t,this.outputDir,i),this.logger.info(`Adding import for fields model: ${p.name} from path: ${p.path}`),y(t,this.outputDir,p),this.logger.info(`Creating query client factory: ${c}`),t.addVariableStatement({declarationKind:$.VariableDeclarationKind.Const,declarations:[{name:c,initializer:`new QueryClientFactory<${i.name}, ${p.name} | string, ${s}>(${n})`}],isExported:!0}),this.logger.success(`Query client generation completed for aggregate: ${e.aggregate.aggregateName}`)}}class xe extends S{commandEndpointPathsName="COMMAND_ENDPOINT_PATHS";defaultCommandClientOptionsName="DEFAULT_COMMAND_CLIENT_OPTIONS";constructor(e){super(e)}generate(){const e=Array.from(this.contextAggregates.values()).reduce((n,r)=>n+r.size,0);this.logger.info("--- Generating Command Clients ---"),this.logger.progress(`Generating command clients for ${e} aggregates`);let t=0;for(const[,n]of this.contextAggregates)n.forEach(r=>{t++,this.logger.progressWithCount(t,e,`Processing command client for aggregate: ${r.aggregate.aggregateName}`),this.processAggregate(r)});this.logger.success("Command client generation completed")}processAggregate(e){this.logger.info(`Processing command client for aggregate: ${e.aggregate.aggregateName} in context: ${e.aggregate.contextAlias}`);const t=L(this.project,this.outputDir,e.aggregate,"commandClient");this.logger.info(`Processing command endpoint paths for ${e.commands.size} commands`),this.processCommandEndpointPaths(t,e),this.logger.info(`Creating default command client options: ${this.defaultCommandClientOptionsName}`),t.addVariableStatement({declarationKind:$.VariableDeclarationKind.Const,declarations:[{name:this.defaultCommandClientOptionsName,type:"ApiMetadata",initializer:`{
|
|
7
7
|
basePath: '${e.aggregate.contextAlias}'
|
|
8
|
-
}`}],isExported:!1}),this.logger.info(`Adding imports from ${C}: CommandRequest, CommandResult, CommandResultEventStream, DeleteAggregate, RecoverAggregate`),t.addImportDeclaration({moduleSpecifier:C,namedImports:["CommandRequest","CommandResult","CommandResultEventStream","DeleteAggregate","RecoverAggregate"],isTypeOnly:!0}),this.logger.info("Adding import from @ahoo-wang/fetcher-eventstream: JsonEventStreamResultExtractor"),t.addImportDeclaration({moduleSpecifier:"@ahoo-wang/fetcher-eventstream",namedImports:["JsonEventStreamResultExtractor"]}),this.logger.info("Adding import from @ahoo-wang/fetcher: ContentTypeValues"),O(t,"@ahoo-wang/fetcher",["ContentTypeValues"]),this.logger.info("Adding imports from @ahoo-wang/fetcher-decorator: ApiMetadata types and decorators"),O(t,"@ahoo-wang/fetcher-decorator",["type ApiMetadata","type ApiMetadataCapable","api","post","put","patch","del","request","attribute","path","autoGeneratedError"]),this.logger.info("Generating standard command client class"),this.processCommandClient(t,e),this.logger.info("Generating stream command client class"),this.processCommandClient(t,e,!0),this.logger.success(`Command client generation completed for aggregate: ${e.aggregate.aggregateName}`)}processCommandEndpointPaths(e,t){this.logger.info(`Creating command endpoint paths enum: ${this.commandEndpointPathsName}`);const n=e.addEnum({name:this.commandEndpointPathsName});t.commands.forEach(r=>{this.logger.info(`Adding command endpoint: ${r.name.toUpperCase()} = '${r.path}'`),n.addMember({name:r.name.toUpperCase(),initializer:`'${r.path}'`})}),this.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",s={name:"api",arguments:[]},
|
|
8
|
+
}`}],isExported:!1}),this.logger.info(`Adding imports from ${C}: CommandRequest, CommandResult, CommandResultEventStream, DeleteAggregate, RecoverAggregate`),t.addImportDeclaration({moduleSpecifier:C,namedImports:["CommandRequest","CommandResult","CommandResultEventStream","DeleteAggregate","RecoverAggregate"],isTypeOnly:!0}),this.logger.info("Adding import from @ahoo-wang/fetcher-eventstream: JsonEventStreamResultExtractor"),t.addImportDeclaration({moduleSpecifier:"@ahoo-wang/fetcher-eventstream",namedImports:["JsonEventStreamResultExtractor"]}),this.logger.info("Adding import from @ahoo-wang/fetcher: ContentTypeValues"),O(t,"@ahoo-wang/fetcher",["ContentTypeValues"]),this.logger.info("Adding imports from @ahoo-wang/fetcher-decorator: ApiMetadata types and decorators"),O(t,"@ahoo-wang/fetcher-decorator",["type ApiMetadata","type ApiMetadataCapable","api","post","put","patch","del","request","attribute","path","autoGeneratedError"]),this.logger.info("Generating standard command client class"),this.processCommandClient(t,e),this.logger.info("Generating stream command client class"),this.processCommandClient(t,e,!0),this.logger.success(`Command client generation completed for aggregate: ${e.aggregate.aggregateName}`)}processCommandEndpointPaths(e,t){this.logger.info(`Creating command endpoint paths enum: ${this.commandEndpointPathsName}`);const n=e.addEnum({name:this.commandEndpointPathsName});t.commands.forEach(r=>{this.logger.info(`Adding command endpoint: ${r.name.toUpperCase()} = '${r.path}'`),n.addMember({name:r.name.toUpperCase(),initializer:`'${r.path}'`})}),this.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",s={name:"api",arguments:[]},a="Promise<CommandResult>";n&&(r="Stream"+r,s={name:"api",arguments:["''",`{
|
|
9
9
|
headers: { Accept: ContentTypeValues.TEXT_EVENT_STREAM },
|
|
10
10
|
resultExtractor: JsonEventStreamResultExtractor,
|
|
11
|
-
}`]},
|
|
11
|
+
}`]},a="Promise<CommandResultEventStream>");const c=$e(t.aggregate,r),i=e.addClass({name:c,isExported:!0,decorators:[s],implements:["ApiMetadataCapable"]});i.addConstructor({parameters:[{name:"apiMetadata",type:"ApiMetadata",scope:$.Scope.Public,isReadonly:!0,initializer:`${this.defaultCommandClientOptionsName}`}]}),t.commands.forEach(p=>{this.processCommandMethod(e,i,p,a)})}methodToDecorator(e){return e==="delete"?"del":e}processCommandMethod(e,t,n,r){const s=m(n.schema.key);this.logger.info(`Adding import for command model: ${s.name} from path: ${s.path}`),y(e,this.outputDir,s),this.logger.info(`Generating command method: ${h(n.name)} for command: ${n.name}`),this.logger.info(`Command method details: HTTP ${n.method}, path: ${n.path}, return type: ${r}`);const a=n.pathParameters.map(i=>(this.logger.info(`Adding path parameter: ${i.name} (type: string)`),{name:i.name,type:"string",decorators:[{name:"path",arguments:[`'${i.name}'`]}]}));this.logger.info(`Adding command request parameter: commandRequest (type: CommandRequest<${s.name}>)`),a.push({name:"commandRequest",type:`CommandRequest<${s.name}>`,decorators:[{name:"request",arguments:[]}]}),this.logger.info("Adding attributes parameter: attributes (type: Record<string, any>)"),a.push({name:"attributes",type:"Record<string, any>",decorators:[{name:"attribute",arguments:[]}]});const c=t.addMethod({name:h(n.name),decorators:[{name:this.methodToDecorator(n.method),arguments:[`${this.getEndpointPath(n)}`]}],parameters:a,returnType:r,statements:[`throw autoGeneratedError(${a.map(i=>i.name).join(",")});`]});(n.summary||n.description)&&this.logger.info(`Adding JSDoc documentation for method: ${h(n.name)}`),w(c,n.summary,n.description),this.logger.success(`Command method generated: ${h(n.name)}`)}}class Se extends S{queryClientGenerator;commandClientGenerator;constructor(e){super(e),this.queryClientGenerator=new Oe(e),this.commandClientGenerator=new xe(e)}generate(){this.logger.info("--- Generating Clients ---"),this.logger.progress(`Generating clients for ${this.contextAggregates.size} bounded contexts`);let e=0;for(const[t]of this.contextAggregates)e++,this.logger.progressWithCount(e,this.contextAggregates.size,`Processing bounded context: ${t}`,1),this.processBoundedContext(t);this.queryClientGenerator.generate(),this.commandClientGenerator.generate(),this.logger.success("Client generation completed")}processBoundedContext(e){const t=`${e}/boundedContext.ts`;this.logger.info(`Creating bounded context file: ${t}`);const n=b(this.project,this.outputDir,t);this.logger.info(`Adding bounded context alias constant: BOUNDED_CONTEXT_ALIAS = '${e}'`),n.addStatements(`export const BOUNDED_CONTEXT_ALIAS = '${e}';`),this.logger.success(`Bounded context file created successfully: ${t}`)}}class Ee{constructor(e){this.options=e,this.project=e.project,this.options.logger.info("CodeGenerator instance created")}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 X(this.options.inputPath);this.options.logger.info("OpenAPI specification parsed successfully"),this.options.logger.info("Resolving bounded context aggregates");const n=new Ae(e).resolve();this.options.logger.info(`Resolved ${n.size} bounded context aggregates`);const r={openAPI:e,project:this.project,outputDir:this.options.outputDir,contextAggregates:n,logger:this.options.logger};this.options.logger.info("Generating models"),new Pe(r).generate(),this.options.logger.info("Models generated successfully"),this.options.logger.info("Generating clients"),new Se(r).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.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(c=>c.getBaseName().endsWith(".ts")&&c.getBaseName()!=="index.ts");let r=[];try{r=R.readdirSync(t).filter(c=>{const i=K.join(t,c);return R.statSync(i).isDirectory()})}catch(c){this.options.logger.error(`Failed to read subdirectories for ${t}: ${c}`)}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 s=`${t}/index.ts`;this.options.logger.info(`Creating/updating index file: ${s}`);const a=this.project.getSourceFile(s)||this.project.createSourceFile(s,"",{overwrite:!0});a.removeText();for(const c of n){const i=`./${c.getBaseNameWithoutExtension()}`;this.options.logger.info(`Adding export for file: ${i}`),a.addExportDeclaration({moduleSpecifier:i,isTypeOnly:!1,namedExports:[]})}for(const c of r){const i=`./${c}`;this.options.logger.info(`Adding export for subdirectory: ${i}`),a.addExportDeclaration({moduleSpecifier:i,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=Ee;
|
|
12
12
|
//# sourceMappingURL=index.cjs.map
|