@ahoo-wang/fetcher-generator 2.1.0 → 2.1.1
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/baseCodeGenerator.d.ts +6 -1
- package/dist/baseCodeGenerator.d.ts.map +1 -1
- package/dist/cli.cjs +2 -1
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.js +23 -22
- package/dist/cli.js.map +1 -0
- package/dist/client/commandClientGenerator.d.ts.map +1 -1
- package/dist/index.cjs +7 -6
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +443 -469
- package/dist/index.js.map +1 -0
- package/dist/model/modelGenerator.d.ts +6 -90
- package/dist/model/modelGenerator.d.ts.map +1 -1
- package/dist/types.d.ts +6 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/logger.d.ts +8 -8
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/schemas.d.ts +63 -2
- package/dist/utils/schemas.d.ts.map +1 -1
- package/dist/utils/sourceFiles.d.ts +3 -3
- package/dist/utils/sourceFiles.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -3,11 +3,16 @@ import { OpenAPI } from '@ahoo-wang/fetcher-openapi';
|
|
|
3
3
|
import { GenerateContext, Logger } from './types';
|
|
4
4
|
import { BoundedContextAggregates } from './aggregate';
|
|
5
5
|
export declare abstract class BaseCodeGenerator implements GenerateContext {
|
|
6
|
+
/** The ts-morph project instance used for code generation */
|
|
6
7
|
readonly project: Project;
|
|
8
|
+
/** The OpenAPI specification object */
|
|
7
9
|
readonly openAPI: OpenAPI;
|
|
10
|
+
/** The output directory path for generated files */
|
|
8
11
|
readonly outputDir: string;
|
|
12
|
+
/** Map of bounded context aggregates for domain modeling */
|
|
9
13
|
readonly contextAggregates: BoundedContextAggregates;
|
|
10
|
-
|
|
14
|
+
/** Optional logger for generation progress and errors */
|
|
15
|
+
readonly logger: Logger;
|
|
11
16
|
/**
|
|
12
17
|
* Creates a new ClientGenerator instance.
|
|
13
18
|
* @param context - The generation context containing OpenAPI spec and project details
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baseCodeGenerator.d.ts","sourceRoot":"","sources":["../src/baseCodeGenerator.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,8BAAsB,iBAAkB,YAAW,eAAe;IAChE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,iBAAiB,EAAE,wBAAwB,CAAC;IACrD,QAAQ,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"baseCodeGenerator.d.ts","sourceRoot":"","sources":["../src/baseCodeGenerator.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEvD,8BAAsB,iBAAkB,YAAW,eAAe;IAChE,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,uCAAuC;IACvC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,4DAA4D;IAC5D,QAAQ,CAAC,iBAAiB,EAAE,wBAAwB,CAAC;IACrD,yDAAyD;IACzD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,SAAS,aAAa,OAAO,EAAE,eAAe;IAQ9C;;;OAGG;IACH,QAAQ,CAAC,QAAQ,IAAI,IAAI;CAC1B"}
|
package/dist/cli.cjs
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";const t=require("commander"),i=require("./index.cjs"),c=require("ts-morph");require("yaml");require("fs");require("@ahoo-wang/fetcher");class s{info(e){console.log(`ℹ️ ${e}
|
|
2
|
+
"use strict";const t=require("commander"),i=require("./index.cjs"),c=require("ts-morph");require("yaml");require("fs");require("@ahoo-wang/fetcher");class s{info(e,...r){console.log(`ℹ️ ${e}`,r)}success(e,...r){console.log(`✅ ${e}`,r)}error(e,...r){console.error(`❌ ${e}`,r)}progress(e,...r){console.log(`🔄 ${e}`,r)}}function a(o){if(!o)return!1;try{const e=new URL(o);return e.protocol==="http:"||e.protocol==="https:"}catch{return o.length>0}}async function p(o){const e=new s;process.on("SIGINT",()=>{e.error("Generation interrupted by user"),process.exit(130)}),a(o.input)||(e.error("Invalid input: must be a valid file path or HTTP/HTTPS URL"),process.exit(2));try{e.info("Starting code generation...");const r=new c.Project,n={inputPath:o.input,outputDir:o.output,project:r,logger:e};await new i.CodeGenerator(n).generate(),e.success(`Code generation completed successfully! Files generated in: ${o.output}`)}catch(r){e.error(`Error during code generation: ${r}`),process.exit(1)}}t.program.name("fetcher-generator").description("OpenAPI Specification TypeScript code generator for Wow").version("2.1.1");t.program.command("generate").description("Generate TypeScript code from OpenAPI specification").requiredOption("-i, --input <path>","Input OpenAPI specification file path or URL (http/https)").option("-o, --output <path>","Output directory path","src/generated").option("-c, --config <file>","Configuration file path").option("-v, --verbose","Enable verbose logging").option("--dry-run","Show what would be generated without writing files").action(p);t.program.parse();
|
|
3
|
+
//# sourceMappingURL=cli.cjs.map
|
package/dist/cli.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.cjs","sources":["../src/utils/logger.ts","../src/utils/clis.ts","../src/cli.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from '../types';\n\n/**\n * Default console-based logger implementation.\n * Provides friendly colored output for different log levels.\n */\nexport class ConsoleLogger implements Logger {\n info(message: string, ...params: any[]): void {\n console.log(`ℹ️ ${message}`, params);\n }\n\n success(message: string, ...params: any[]): void {\n console.log(`✅ ${message}`, params);\n }\n\n error(message: string, ...params: any[]): void {\n console.error(`❌ ${message}`, params);\n }\n\n progress(message: string, ...params: any[]): void {\n console.log(`🔄 ${message}`, params);\n }\n}\n\n/**\n * Silent logger that suppresses all output.\n */\nexport class SilentLogger implements Logger {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n info(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n success(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n error(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n progress(_message: string, ...params: any[]): void {\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConsoleLogger } from './logger';\nimport { GeneratorOptions } from '../types';\nimport { CodeGenerator } from '../index';\nimport { Project } from 'ts-morph';\n\n/**\n * Validates the input path or URL.\n * @param input - Input path or URL\n * @returns true if valid\n */\nexport function validateInput(input: string): boolean {\n if (!input) return false;\n\n // Check if it's a URL\n try {\n const url = new URL(input);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n // Not a URL, check if it's a file path\n // For file paths, we'll let parseOpenAPI handle it\n return input.length > 0;\n }\n}\n\n/**\n * Action handler for the generate command.\n * @param options - Command options\n */\nexport async function generateAction(options: {\n input: string;\n output: string;\n config?: string;\n verbose?: boolean;\n dryRun?: boolean;\n}) {\n const logger = new ConsoleLogger();\n\n // Handle signals\n process.on('SIGINT', () => {\n logger.error('Generation interrupted by user');\n process.exit(130);\n });\n\n // Validate input\n if (!validateInput(options.input)) {\n logger.error('Invalid input: must be a valid file path or HTTP/HTTPS URL');\n process.exit(2);\n }\n\n try {\n logger.info('Starting code generation...');\n const project = new Project();\n const generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n project,\n logger,\n };\n const codeGenerator = new CodeGenerator(generatorOptions);\n await codeGenerator.generate();\n logger.success(\n `Code generation completed successfully! Files generated in: ${options.output}`,\n );\n } catch (error) {\n logger.error(`Error during code generation: ${error}`);\n process.exit(1);\n }\n}","#!/usr/bin/env node\n\n/**\n * CLI entry point for the Fetcher OpenAPI code generator.\n * Sets up the commander program with generate command and handles execution.\n */\n\nimport { program } from 'commander';\nimport { generateAction } from './utils';\n\nprogram\n .name('fetcher-generator')\n .description('OpenAPI Specification TypeScript code generator for Wow')\n .version('2.1.1');\n\nprogram\n .command('generate')\n .description('Generate TypeScript code from OpenAPI specification')\n .requiredOption(\n '-i, --input <path>',\n 'Input OpenAPI specification file path or URL (http/https)',\n )\n .option('-o, --output <path>', 'Output directory path', 'src/generated')\n .option('-c, --config <file>', 'Configuration file path')\n .option('-v, --verbose', 'Enable verbose logging')\n .option('--dry-run', 'Show what would be generated without writing files')\n .action(generateAction);\n\nprogram.parse();\n"],"names":["ConsoleLogger","message","params","validateInput","input","url","generateAction","options","logger","project","Project","generatorOptions","CodeGenerator","error","program"],"mappings":";qJAmBO,MAAMA,CAAgC,CAC3C,KAAKC,KAAoBC,EAAqB,CAC5C,QAAQ,IAAI,OAAOD,CAAO,GAAIC,CAAM,CACtC,CAEA,QAAQD,KAAoBC,EAAqB,CAC/C,QAAQ,IAAI,KAAKD,CAAO,GAAIC,CAAM,CACpC,CAEA,MAAMD,KAAoBC,EAAqB,CAC7C,QAAQ,MAAM,KAAKD,CAAO,GAAIC,CAAM,CACtC,CAEA,SAASD,KAAoBC,EAAqB,CAChD,QAAQ,IAAI,MAAMD,CAAO,GAAIC,CAAM,CACrC,CACF,CCZO,SAASC,EAAcC,EAAwB,CACpD,GAAI,CAACA,EAAO,MAAO,GAGnB,GAAI,CACF,MAAMC,EAAM,IAAI,IAAID,CAAK,EACzB,OAAOC,EAAI,WAAa,SAAWA,EAAI,WAAa,QACtD,MAAQ,CAGN,OAAOD,EAAM,OAAS,CACxB,CACF,CAMA,eAAsBE,EAAeC,EAMlC,CACD,MAAMC,EAAS,IAAIR,EAGnB,QAAQ,GAAG,SAAU,IAAM,CACzBQ,EAAO,MAAM,gCAAgC,EAC7C,QAAQ,KAAK,GAAG,CAClB,CAAC,EAGIL,EAAcI,EAAQ,KAAK,IAC9BC,EAAO,MAAM,4DAA4D,EACzE,QAAQ,KAAK,CAAC,GAGhB,GAAI,CACFA,EAAO,KAAK,6BAA6B,EACzC,MAAMC,EAAU,IAAIC,UACdC,EAAqC,CACzC,UAAWJ,EAAQ,MACnB,UAAWA,EAAQ,OACnB,QAAAE,EACA,OAAAD,CAAA,EAGF,MADsB,IAAII,EAAAA,cAAcD,CAAgB,EACpC,SAAA,EACpBH,EAAO,QACL,+DAA+DD,EAAQ,MAAM,EAAA,CAEjF,OAASM,EAAO,CACdL,EAAO,MAAM,iCAAiCK,CAAK,EAAE,EACrD,QAAQ,KAAK,CAAC,CAChB,CACF,CCtEAC,EAAAA,QACG,KAAK,mBAAmB,EACxB,YAAY,yDAAyD,EACrE,QAAQ,OAAO,EAElBA,EAAAA,QACG,QAAQ,UAAU,EAClB,YAAY,qDAAqD,EACjE,eACC,qBACA,2DACF,EACC,OAAO,sBAAuB,wBAAyB,eAAe,EACtE,OAAO,sBAAuB,yBAAyB,EACvD,OAAO,gBAAiB,wBAAwB,EAChD,OAAO,YAAa,oDAAoD,EACxE,OAAOR,CAAc,EAExBQ,EAAAA,QAAQ,MAAA"}
|
package/dist/cli.js
CHANGED
|
@@ -6,51 +6,52 @@ import "yaml";
|
|
|
6
6
|
import "fs";
|
|
7
7
|
import "@ahoo-wang/fetcher";
|
|
8
8
|
class p {
|
|
9
|
-
info(e) {
|
|
10
|
-
console.log(`ℹ️ ${e}
|
|
9
|
+
info(e, ...o) {
|
|
10
|
+
console.log(`ℹ️ ${e}`, o);
|
|
11
11
|
}
|
|
12
|
-
success(e) {
|
|
13
|
-
console.log(`✅ ${e}
|
|
12
|
+
success(e, ...o) {
|
|
13
|
+
console.log(`✅ ${e}`, o);
|
|
14
14
|
}
|
|
15
|
-
error(e) {
|
|
16
|
-
console.error(`❌ ${e}
|
|
15
|
+
error(e, ...o) {
|
|
16
|
+
console.error(`❌ ${e}`, o);
|
|
17
17
|
}
|
|
18
|
-
progress(e) {
|
|
19
|
-
console.log(`🔄 ${e}
|
|
18
|
+
progress(e, ...o) {
|
|
19
|
+
console.log(`🔄 ${e}`, o);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
function a(
|
|
23
|
-
if (!
|
|
22
|
+
function a(r) {
|
|
23
|
+
if (!r) return !1;
|
|
24
24
|
try {
|
|
25
|
-
const e = new URL(
|
|
25
|
+
const e = new URL(r);
|
|
26
26
|
return e.protocol === "http:" || e.protocol === "https:";
|
|
27
27
|
} catch {
|
|
28
|
-
return
|
|
28
|
+
return r.length > 0;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
async function s(
|
|
31
|
+
async function s(r) {
|
|
32
32
|
const e = new p();
|
|
33
33
|
process.on("SIGINT", () => {
|
|
34
34
|
e.error("Generation interrupted by user"), process.exit(130);
|
|
35
|
-
}), a(
|
|
35
|
+
}), a(r.input) || (e.error("Invalid input: must be a valid file path or HTTP/HTTPS URL"), process.exit(2));
|
|
36
36
|
try {
|
|
37
37
|
e.info("Starting code generation...");
|
|
38
|
-
const
|
|
39
|
-
inputPath:
|
|
40
|
-
outputDir:
|
|
41
|
-
project:
|
|
38
|
+
const o = new c(), n = {
|
|
39
|
+
inputPath: r.input,
|
|
40
|
+
outputDir: r.output,
|
|
41
|
+
project: o,
|
|
42
42
|
logger: e
|
|
43
43
|
};
|
|
44
44
|
await new i(n).generate(), e.success(
|
|
45
|
-
`Code generation completed successfully! Files generated in: ${
|
|
45
|
+
`Code generation completed successfully! Files generated in: ${r.output}`
|
|
46
46
|
);
|
|
47
|
-
} catch (
|
|
48
|
-
e.error(`Error during code generation: ${
|
|
47
|
+
} catch (o) {
|
|
48
|
+
e.error(`Error during code generation: ${o}`), process.exit(1);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
t.name("fetcher-generator").description("OpenAPI Specification TypeScript code generator for Wow").version("1.
|
|
51
|
+
t.name("fetcher-generator").description("OpenAPI Specification TypeScript code generator for Wow").version("2.1.1");
|
|
52
52
|
t.command("generate").description("Generate TypeScript code from OpenAPI specification").requiredOption(
|
|
53
53
|
"-i, --input <path>",
|
|
54
54
|
"Input OpenAPI specification file path or URL (http/https)"
|
|
55
55
|
).option("-o, --output <path>", "Output directory path", "src/generated").option("-c, --config <file>", "Configuration file path").option("-v, --verbose", "Enable verbose logging").option("--dry-run", "Show what would be generated without writing files").action(s);
|
|
56
56
|
t.parse();
|
|
57
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sources":["../src/utils/logger.ts","../src/utils/clis.ts","../src/cli.ts"],"sourcesContent":["/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Logger } from '../types';\n\n/**\n * Default console-based logger implementation.\n * Provides friendly colored output for different log levels.\n */\nexport class ConsoleLogger implements Logger {\n info(message: string, ...params: any[]): void {\n console.log(`ℹ️ ${message}`, params);\n }\n\n success(message: string, ...params: any[]): void {\n console.log(`✅ ${message}`, params);\n }\n\n error(message: string, ...params: any[]): void {\n console.error(`❌ ${message}`, params);\n }\n\n progress(message: string, ...params: any[]): void {\n console.log(`🔄 ${message}`, params);\n }\n}\n\n/**\n * Silent logger that suppresses all output.\n */\nexport class SilentLogger implements Logger {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n info(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n success(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n error(_message: string, ...params: any[]): void {\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n progress(_message: string, ...params: any[]): void {\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConsoleLogger } from './logger';\nimport { GeneratorOptions } from '../types';\nimport { CodeGenerator } from '../index';\nimport { Project } from 'ts-morph';\n\n/**\n * Validates the input path or URL.\n * @param input - Input path or URL\n * @returns true if valid\n */\nexport function validateInput(input: string): boolean {\n if (!input) return false;\n\n // Check if it's a URL\n try {\n const url = new URL(input);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n // Not a URL, check if it's a file path\n // For file paths, we'll let parseOpenAPI handle it\n return input.length > 0;\n }\n}\n\n/**\n * Action handler for the generate command.\n * @param options - Command options\n */\nexport async function generateAction(options: {\n input: string;\n output: string;\n config?: string;\n verbose?: boolean;\n dryRun?: boolean;\n}) {\n const logger = new ConsoleLogger();\n\n // Handle signals\n process.on('SIGINT', () => {\n logger.error('Generation interrupted by user');\n process.exit(130);\n });\n\n // Validate input\n if (!validateInput(options.input)) {\n logger.error('Invalid input: must be a valid file path or HTTP/HTTPS URL');\n process.exit(2);\n }\n\n try {\n logger.info('Starting code generation...');\n const project = new Project();\n const generatorOptions: GeneratorOptions = {\n inputPath: options.input,\n outputDir: options.output,\n project,\n logger,\n };\n const codeGenerator = new CodeGenerator(generatorOptions);\n await codeGenerator.generate();\n logger.success(\n `Code generation completed successfully! Files generated in: ${options.output}`,\n );\n } catch (error) {\n logger.error(`Error during code generation: ${error}`);\n process.exit(1);\n }\n}","#!/usr/bin/env node\n\n/**\n * CLI entry point for the Fetcher OpenAPI code generator.\n * Sets up the commander program with generate command and handles execution.\n */\n\nimport { program } from 'commander';\nimport { generateAction } from './utils';\n\nprogram\n .name('fetcher-generator')\n .description('OpenAPI Specification TypeScript code generator for Wow')\n .version('2.1.1');\n\nprogram\n .command('generate')\n .description('Generate TypeScript code from OpenAPI specification')\n .requiredOption(\n '-i, --input <path>',\n 'Input OpenAPI specification file path or URL (http/https)',\n )\n .option('-o, --output <path>', 'Output directory path', 'src/generated')\n .option('-c, --config <file>', 'Configuration file path')\n .option('-v, --verbose', 'Enable verbose logging')\n .option('--dry-run', 'Show what would be generated without writing files')\n .action(generateAction);\n\nprogram.parse();\n"],"names":["ConsoleLogger","message","params","validateInput","input","url","generateAction","options","logger","project","Project","generatorOptions","CodeGenerator","error","program"],"mappings":";;;;;;;AAmBO,MAAMA,EAAgC;AAAA,EAC3C,KAAKC,MAAoBC,GAAqB;AAC5C,YAAQ,IAAI,OAAOD,CAAO,IAAIC,CAAM;AAAA,EACtC;AAAA,EAEA,QAAQD,MAAoBC,GAAqB;AAC/C,YAAQ,IAAI,KAAKD,CAAO,IAAIC,CAAM;AAAA,EACpC;AAAA,EAEA,MAAMD,MAAoBC,GAAqB;AAC7C,YAAQ,MAAM,KAAKD,CAAO,IAAIC,CAAM;AAAA,EACtC;AAAA,EAEA,SAASD,MAAoBC,GAAqB;AAChD,YAAQ,IAAI,MAAMD,CAAO,IAAIC,CAAM;AAAA,EACrC;AACF;ACZO,SAASC,EAAcC,GAAwB;AACpD,MAAI,CAACA,EAAO,QAAO;AAGnB,MAAI;AACF,UAAMC,IAAM,IAAI,IAAID,CAAK;AACzB,WAAOC,EAAI,aAAa,WAAWA,EAAI,aAAa;AAAA,EACtD,QAAQ;AAGN,WAAOD,EAAM,SAAS;AAAA,EACxB;AACF;AAMA,eAAsBE,EAAeC,GAMlC;AACD,QAAMC,IAAS,IAAIR,EAAA;AAGnB,UAAQ,GAAG,UAAU,MAAM;AACzB,IAAAQ,EAAO,MAAM,gCAAgC,GAC7C,QAAQ,KAAK,GAAG;AAAA,EAClB,CAAC,GAGIL,EAAcI,EAAQ,KAAK,MAC9BC,EAAO,MAAM,4DAA4D,GACzE,QAAQ,KAAK,CAAC;AAGhB,MAAI;AACF,IAAAA,EAAO,KAAK,6BAA6B;AACzC,UAAMC,IAAU,IAAIC,EAAA,GACdC,IAAqC;AAAA,MACzC,WAAWJ,EAAQ;AAAA,MACnB,WAAWA,EAAQ;AAAA,MACnB,SAAAE;AAAA,MACA,QAAAD;AAAA,IAAA;AAGF,UADsB,IAAII,EAAcD,CAAgB,EACpC,SAAA,GACpBH,EAAO;AAAA,MACL,+DAA+DD,EAAQ,MAAM;AAAA,IAAA;AAAA,EAEjF,SAASM,GAAO;AACd,IAAAL,EAAO,MAAM,iCAAiCK,CAAK,EAAE,GACrD,QAAQ,KAAK,CAAC;AAAA,EAChB;AACF;ACtEAC,EACG,KAAK,mBAAmB,EACxB,YAAY,yDAAyD,EACrE,QAAQ,OAAO;AAElBA,EACG,QAAQ,UAAU,EAClB,YAAY,qDAAqD,EACjE;AAAA,EACC;AAAA,EACA;AACF,EACC,OAAO,uBAAuB,yBAAyB,eAAe,EACtE,OAAO,uBAAuB,yBAAyB,EACvD,OAAO,iBAAiB,wBAAwB,EAChD,OAAO,aAAa,oDAAoD,EACxE,OAAOR,CAAc;AAExBQ,EAAQ,MAAA;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commandClientGenerator.d.ts","sourceRoot":"","sources":["../../src/client/commandClientGenerator.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EACL,gBAAgB,EAIhB,UAAU,EAEX,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAKtE;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,iBAAiB;IAC3D,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAA4B;IACrE,OAAO,CAAC,QAAQ,CAAC,+BAA+B,CACb;IAEnC;;;OAGG;gBACS,OAAO,EAAE,eAAe;IAIpC;;OAEG;IACH,QAAQ,IAAI,IAAI;IAiBhB;;;OAGG;IACH,gBAAgB,CAAC,SAAS,EAAE,mBAAmB;
|
|
1
|
+
{"version":3,"file":"commandClientGenerator.d.ts","sourceRoot":"","sources":["../../src/client/commandClientGenerator.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EACL,gBAAgB,EAIhB,UAAU,EAEX,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAKtE;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,iBAAiB;IAC3D,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAA4B;IACrE,OAAO,CAAC,QAAQ,CAAC,+BAA+B,CACb;IAEnC;;;OAGG;gBACS,OAAO,EAAE,eAAe;IAIpC;;OAEG;IACH,QAAQ,IAAI,IAAI;IAiBhB;;;OAGG;IACH,gBAAgB,CAAC,SAAS,EAAE,mBAAmB;IAuD/C,2BAA2B,CACzB,UAAU,EAAE,UAAU,EACtB,mBAAmB,EAAE,mBAAmB;IAa1C,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM;IAInD,oBAAoB,CAClB,UAAU,EAAE,UAAU,EACtB,mBAAmB,EAAE,mBAAmB,EACxC,QAAQ,GAAE,OAAe;IAiD3B,OAAO,CAAC,iBAAiB;IAOzB;;;;;OAKG;IACH,oBAAoB,CAClB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,iBAAiB,EAC7B,UAAU,EAAE,MAAM;CAoDrB"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,11 +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 w=require("ts-morph"),F=require("yaml"),K=require("fs"),f=require("@ahoo-wang/fetcher"),v=require("@ahoo-wang/fetcher-wow");function d(t){return t.$ref.split("/").pop()}function T(t,e){const n=d(t);return e.schemas?.[n]}function V(t,e){const n=d(t);return e.requestBodies?.[n]}function k(t,e){const n=d(t);return e.parameters?.[n]}function A(t,e){return{key:d(t),schema:T(t,e)}}const D=/[-_\s.]+|(?=[A-Z])/;function E(t){if(t===""||t.length===0)return"";let e;return Array.isArray(t)?e=t.flatMap(n=>n.split(D)):e=t.split(D),e.filter(n=>n.length>0).map(n=>{if(n.length===0)return"";const r=n.charAt(0),o=n.slice(1);return(/[a-zA-Z]/.test(r)?r.toUpperCase():r)+o.toLowerCase()}).join("")}function j(t){const e=E(t);return e.charAt(0).toLowerCase()+e.slice(1)}function Q(t){return t.startsWith("http://")||t.startsWith("https://")?U(t):J(t)}async function U(t){return await(await fetch(t)).text()}function J(t){return new Promise((e,n)=>{K.readFile(t,"utf-8",(r,o)=>{r?n(r):e(o)})})}async function z(t){const e=await Q(t);switch(H(e)){case"json":return JSON.parse(e);case"yaml":return F.parse(e);default:throw new Error(`Unsupported file format: ${t}`)}}function H(t){const e=t.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 u(t){return!!(t&&typeof t=="object"&&"$ref"in t)}function Y(t){return!t||u(t)||!t.content?void 0:t.content[f.ContentTypeValues.APPLICATION_JSON]?.schema}function Z(t){return[{method:"get",operation:t.get},{method:"put",operation:t.put},{method:"post",operation:t.post},{method:"delete",operation:t.delete},{method:"options",operation:t.options},{method:"head",operation:t.head},{method:"patch",operation:t.patch},{method:"trace",operation:t.trace}].filter(({operation:e})=>e!==void 0)}function q(t){return t.responses[200]}function $(t){const e=q(t);return Y(e)}const X=["string","number","integer","boolean","null"];function ee(t){return Array.isArray(t)?!0:X.includes(t)}function te(t){return t.type==="array"}function ne(t){return Array.isArray(t.enum)&&t.enum.length>0}function _(t){return Array.isArray(t.anyOf)&&t.anyOf.length>0}function G(t){return Array.isArray(t.oneOf)&&t.oneOf.length>0}function re(t){return _(t)||G(t)}function oe(t){return Array.isArray(t.allOf)&&t.allOf.length>0}function M(t){return _(t)||G(t)||oe(t)}function ae(t){return t.includes("|")||t.includes("&")?`(${t})[]`:`${t}[]`}function R(t){if(Array.isArray(t))return t.map(e=>R(e)).join(" | ");switch(t){case"string":return"string";case"number":case"integer":return"number";case"boolean":return"boolean";case"null":return"null";default:return"any"}}const O="@ahoo-wang/fetcher-wow",se={"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 l(t){if(!t)return{name:"",path:"/"};const e=se[t];if(e)return{name:e,path:O};const n=t.split(".");let r=-1;for(let i=0;i<n.length;i++)if(n[i]&&/^[A-Z]/.test(n[i])){r=i;break}if(r===-1)return{name:t,path:"/"};const o=n.slice(0,r),a=o.length>0?`/${o.join("/")}`:"/",s=n.slice(r);return{name:E(s),path:a}}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 ie extends S{constructor(e){super(e)}getOrCreateSourceFile(e){const n=W(e);return b(this.project,this.outputDir,n)}generate(){const e=this.openAPI.components?.schemas;if(!e){this.logger.info("No schemas found in OpenAPI specification");return}this.logger.progress(`Generating models for ${Object.keys(e).length} schemas`),Object.entries(e).forEach(([n,r])=>{if(n.startsWith("wow."))return;this.logger.progress(`Processing schema: ${n}`);const o={key:n,schema:r};this.generateKeyedSchema(o)}),this.logger.success("Model generation completed")}generateKeyedSchema({key:e,schema:n}){const r=l(e),o=this.getOrCreateSourceFile(r),a=this.process(r,o,n);a&&C(a,n.title,n.description)}process(e,n,r){if(ne(r))return n.addEnum({name:e.name,isExported:!0,members:r.enum.filter(a=>typeof a=="string"&&a.length>0).map(a=>({name:a,initializer:`'${a}'`}))});const o=n.addInterface({name:e.name,isExported:!0});return r.type==="object"&&r.properties?this.processInterface(n,e,r,o):(M(r)&&(r.anyOf||r.oneOf||r.allOf).forEach(s=>{if(u(s)){const c=l(d(s));N(e,n,this.outputDir,c),o.addExtends(c.name);return}this.processInterface(n,e,s,o)}),o)}processObject(e,n,r){const o=e.addInterface({name:n.name,isExported:!0});return this.processInterface(e,n,r,o)}processInterface(e,n,r,o){for(const[a,s]of Object.entries(r.properties)){const c=this.resolvePropertyType(n,e,a,s);let i=o.getProperty(a);i?i.setType(c):i=o.addProperty({name:a,type:c}),u(s)||C(i,s.title,s.description)}return o}resolvePropertyType(e,n,r,o){if(u(o)){const a=l(d(o));return N(e,n,this.outputDir,a),a.name}if(o.const)return`'${o.const}'`;if(te(o)){const a=this.resolvePropertyType(e,n,r,o.items);return ae(a)}if(o.type&&ee(o.type))return R(o.type);if(M(o))return this.resolvePropertyCompositionType(e,n,o);if(o.type==="object"&&o.properties){const a={path:e.path,name:`${e.name}${E(r)}`},s=this.processObject(n,a,o);return C(s,o.title,o.description),a.name}return"any"}resolvePropertyCompositionType(e,n,r){const o=r.anyOf||r.oneOf||r.allOf,a=new Set;o.forEach(c=>{if(u(c)){const i=l(d(c));N(e,n,this.outputDir,i),a.add(i.name);return}a.add(R(c.type??"string"))});const s=re(r)?"|":"&";return Array.from(a).join(s)}}const ce="types.ts",I="@";function W(t){return f.combineURLs(t.path,ce)}function b(t,e,n){const r=f.combineURLs(e,n),o=t.getSourceFile(r);return o||t.createSourceFile(r,"",{overwrite:!0})}function P(t,e,n){let r=t.getImportDeclaration(o=>o.getModuleSpecifierValue()===e);r||(r=t.addImportDeclaration({moduleSpecifier:e})),n.forEach(o=>{r.getNamedImports().some(s=>s.getName()===o)||r.addNamedImport(o)})}function y(t,e,n){if(n.path===O){P(t,n.path,[n.name]);return}let r=W(n);n.path.startsWith(I)||(r=f.combineURLs(e,r));let o=r;r.startsWith(I)||(o=f.combineURLs(I,r)),P(t,o,[n.name])}function N(t,e,n,r){t.path!==r.path&&y(e,n,r)}function ue(t,e){const n=[t,e].filter(r=>r!==void 0&&r.length>0);return n.length>0?n.join(`
|
|
2
|
+
`):void 0}function C(t,e,n){const r=ue(e,n);r&&t.addJsDoc({description:r})}function pe(t){const e=t.split(".");return e.length!=2||e[0].length===0||e[1].length===0?null:e}function me(t){const e=pe(t.name);return e?{tag:t,contextAlias:e[0],aggregateName:e[1]}:null}function ge(t){const e=t?.map(r=>me(r)).filter(r=>r!==null);if(!e)return new Map;const n=new Map;return e.forEach(r=>{n.set(r.tag.name,{aggregate:r,commands:new Map,events:new Map})}),n}function le(t){if(!t)return null;const e=t.split(".");return e.length!=3?null:e[2]}const de="#/components/responses/wow.CommandOk",fe="#/components/parameters/wow.id";class he{constructor(e){this.openAPI=e,this.aggregates=ge(e.tags),this.build()}aggregates;build(){for(const[e,n]of Object.entries(this.openAPI.paths)){const r=Z(n);for(const o of r)this.commands(e,o),this.state(o.operation),this.events(o.operation),this.fields(o.operation)}}resolve(){const e=new Map;for(const n of this.aggregates.values()){if(!n.state||!n.fields)continue;const r=n.aggregate.contextAlias;let o=e.get(r);o||(o=new Set,e.set(r,o)),o.add(n)}return e}commands(e,n){const r=n.operation;if(r.operationId==="wow.command.send")return;const o=le(r.operationId);if(!o)return;const a=q(r);if(!a||!u(a)||a.$ref!==de||!r.requestBody)return;const s=r.parameters??[],c=s.filter(p=>u(p)&&p.$ref===fe).at(0),i=s.filter(p=>!u(p)&&p.in==="path");if(c){const p=k(c,this.openAPI.components);i.push(p)}const g=r.requestBody.content[f.ContentTypeValues.APPLICATION_JSON].schema,h=A(g,this.openAPI.components);h.schema.title=h.schema.title||r.summary,h.schema.description=h.schema.description||r.description;const L={name:o,method:n.method,path:e,pathParameters:i,summary:r.summary,description:r.description,schema:h,operation:r};r.tags?.forEach(p=>{const x=this.aggregates.get(p);x&&x.commands.set(o,L)})}state(e){if(!e.operationId?.endsWith(".snapshot_state.single"))return;const n=$(e);if(!u(n))return;const r=A(n,this.openAPI.components);e.tags?.forEach(o=>{const a=this.aggregates.get(o);a&&(a.state=r)})}events(e){if(!this.openAPI.components||!e.operationId?.endsWith(".event.list_query"))return;const n=$(e);if(u(n))return;const r=n?.items;if(!u(r))return;const a=T(r,this.openAPI.components).properties.body.items.anyOf.map(s=>{const c=s.title,i=s.properties.name.const,m=s.properties.body,g=A(m,this.openAPI.components);return g.schema.title=g.schema.title||s.title,{title:c,name:i,schema:g}});e.tags?.forEach(s=>{const c=this.aggregates.get(s);c&&a.forEach(i=>{c.events.set(i.name,i)})})}fields(e){if(!this.openAPI.components||!e.operationId?.endsWith(".snapshot.count"))return;const r=V(e.requestBody,this.openAPI.components).content[f.ContentTypeValues.APPLICATION_JSON].schema,a=T(r,this.openAPI.components).properties?.field,s=A(a,this.openAPI.components);e.tags?.forEach(c=>{const i=this.aggregates.get(c);i&&(i.fields=s)})}}function ye(t){let e=0,n=0;return t.commands.forEach(r=>{r.path.startsWith(v.ResourceAttributionPathSpec.TENANT)&&(e+=1),r.path.startsWith(v.ResourceAttributionPathSpec.OWNER)&&(n+=1)}),e===0&&n===0?"ResourceAttributionPathSpec.NONE":e>n?"ResourceAttributionPathSpec.TENANT":"ResourceAttributionPathSpec.OWNER"}function B(t,e,n,r){const o=`${n.contextAlias}/${n.aggregateName}/${r}.ts`;return b(t,e,o)}function Ae(t,e){return`${E(t.aggregateName)}${e}`}class Ce extends S{constructor(e){super(e)}generate(){const e=Array.from(this.contextAggregates.values()).flat().length;this.logger.progress(`Generating query clients for ${e} aggregates`);for(const[,n]of this.contextAggregates)n.forEach(r=>{this.logger.progress(`Processing query client for aggregate: ${r.aggregate.aggregateName}`),this.processQueryClient(r)});this.logger.success("Query client generation completed")}createClientFilePath(e,n){return B(this.project,this.outputDir,e,n)}processQueryClient(e){const n=this.createClientFilePath(e.aggregate,"queryClient");n.addImportDeclaration({moduleSpecifier:O,namedImports:["QueryClientFactory","QueryClientOptions","ResourceAttributionPathSpec"]});const r="DEFAULT_QUERY_CLIENT_OPTIONS";n.addVariableStatement({declarationKind:w.VariableDeclarationKind.Const,declarations:[{name:r,type:"QueryClientOptions",initializer:`{
|
|
3
3
|
contextAlias: '${e.aggregate.contextAlias}',
|
|
4
4
|
aggregateName: '${e.aggregate.aggregateName}',
|
|
5
|
-
resourceAttribution: ${
|
|
6
|
-
}`}],isExported:!1});const o=[];for(const
|
|
5
|
+
resourceAttribution: ${ye(e)},
|
|
6
|
+
}`}],isExported:!1});const o=[];for(const m of e.events.values()){const g=l(m.schema.key);y(n,this.outputDir,g),o.push(g)}const a="DOMAIN_EVENT_TYPES";n.addTypeAlias({name:a,type:o.map(m=>m.name).join(" | ")});const s=`${j(e.aggregate.aggregateName)}QueryClientFactory`,c=l(e.state.key),i=l(e.fields.key);y(n,this.outputDir,c),y(n,this.outputDir,i),n.addVariableStatement({declarationKind:w.VariableDeclarationKind.Const,declarations:[{name:s,initializer:`new QueryClientFactory<${c.name}, ${i.name} | string, ${a}>(${r})`}],isExported:!0})}}class we extends S{commandEndpointPathsName="COMMAND_ENDPOINT_PATHS";defaultCommandClientOptionsName="DEFAULT_COMMAND_CLIENT_OPTIONS";constructor(e){super(e)}generate(){const e=Array.from(this.contextAggregates.values()).flat().length;this.logger.progress(`Generating command clients for ${e} aggregates`);for(const[,n]of this.contextAggregates)n.forEach(r=>{this.logger.progress(`Processing command client for aggregate: ${r.aggregate.aggregateName}`),this.processAggregate(r)});this.logger.success("Command client generation completed")}processAggregate(e){const n=B(this.project,this.outputDir,e.aggregate,"commandClient");this.processCommandEndpointPaths(n,e),n.addVariableStatement({declarationKind:w.VariableDeclarationKind.Const,declarations:[{name:this.defaultCommandClientOptionsName,type:"ApiMetadata",initializer:`{
|
|
7
7
|
basePath: '${e.aggregate.contextAlias}'
|
|
8
|
-
}`}],isExported:!1}),n.addImportDeclaration({moduleSpecifier:
|
|
8
|
+
}`}],isExported:!1}),n.addImportDeclaration({moduleSpecifier:O,namedImports:["CommandRequest","CommandResult","CommandResultEventStream","DeleteAggregate","RecoverAggregate"],isTypeOnly:!0}),n.addImportDeclaration({moduleSpecifier:"@ahoo-wang/fetcher-eventstream",namedImports:["JsonEventStreamResultExtractor"]}),P(n,"@ahoo-wang/fetcher",["ContentTypeValues"]),P(n,"@ahoo-wang/fetcher-decorator",["type ApiMetadata","type ApiMetadataCapable","api","post","put","patch","del","request","attribute","path","autoGeneratedError"]),this.processCommandClient(n,e),this.processCommandClient(n,e,!0)}processCommandEndpointPaths(e,n){const r=e.addEnum({name:this.commandEndpointPathsName});n.commands.forEach(o=>{r.addMember({name:o.name.toUpperCase(),initializer:`'${o.path}'`})})}getEndpointPath(e){return`${this.commandEndpointPathsName}.${e.name.toUpperCase()}`}processCommandClient(e,n,r=!1){let o="CommandClient",a={name:"api",arguments:[]},s="Promise<CommandResult>";r&&(o="Stream"+o,a={name:"api",arguments:["''",`{
|
|
9
9
|
headers: { Accept: ContentTypeValues.TEXT_EVENT_STREAM },
|
|
10
10
|
resultExtractor: JsonEventStreamResultExtractor,
|
|
11
|
-
}`]},s="Promise<CommandResultEventStream>");const c=
|
|
11
|
+
}`]},s="Promise<CommandResultEventStream>");const c=Ae(n.aggregate,o),i=e.addClass({name:c,isExported:!0,decorators:[a],implements:["ApiMetadataCapable"]});i.addConstructor({parameters:[{name:"apiMetadata",type:"ApiMetadata",scope:w.Scope.Public,isReadonly:!0,initializer:`${this.defaultCommandClientOptionsName}`}]}),n.commands.forEach(m=>{this.processCommandMethod(e,i,m,s)})}methodToDecorator(e){return e==="delete"?"del":e}processCommandMethod(e,n,r,o){const a=l(r.schema.key);y(e,this.outputDir,a);const s=r.pathParameters.map(i=>({name:i.name,type:"string",decorators:[{name:"path",arguments:[`'${i.name}'`]}]}));s.push({name:"commandRequest",type:`CommandRequest<${a.name}>`,decorators:[{name:"request",arguments:[]}]}),s.push({name:"attributes",type:"Record<string, any>",decorators:[{name:"attribute",arguments:[]}]});const c=n.addMethod({name:j(r.name),decorators:[{name:this.methodToDecorator(r.method),arguments:[`${this.getEndpointPath(r)}`]}],parameters:s,returnType:o,statements:[`throw autoGeneratedError(${s.map(i=>i.name).join(",")});`]});C(c,r.summary,r.description)}}class Pe extends S{queryClientGenerator;commandClientGenerator;constructor(e){super(e),this.queryClientGenerator=new Ce(e),this.commandClientGenerator=new we(e)}generate(){this.logger.progress(`Generating clients for ${this.contextAggregates.size} bounded contexts`);for(const[e]of this.contextAggregates)this.logger.progress(`Processing bounded context: ${e}`),this.processBoundedContext(e);this.queryClientGenerator.generate(),this.commandClientGenerator.generate(),this.logger.success("Client generation completed")}processBoundedContext(e){const n=`${e}/boundedContext.ts`;b(this.project,this.outputDir,n).addStatements(`export const BOUNDED_CONTEXT_ALIAS = '${e}';`)}}class Ee{constructor(e){this.options=e,this.project=e.project}project;async generate(){const e=await z(this.options.inputPath),r=new he(e).resolve(),o={openAPI:e,project:this.project,outputDir:this.options.outputDir,contextAggregates:r,logger:this.options.logger};new ie(o).generate(),new Pe(o).generate(),this.project.getSourceFiles().forEach(c=>{c.formatText(),c.organizeImports(),c.fixMissingImports()}),await this.project.save()}}exports.CodeGenerator=Ee;
|
|
12
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/utils/components.ts","../src/utils/naming.ts","../src/utils/resources.ts","../src/utils/openAPIParser.ts","../src/utils/references.ts","../src/utils/responses.ts","../src/utils/operations.ts","../src/utils/schemas.ts","../src/model/wowTypeMapping.ts","../src/model/modelInfo.ts","../src/baseCodeGenerator.ts","../src/model/modelGenerator.ts","../src/utils/sourceFiles.ts","../src/aggregate/utils.ts","../src/aggregate/aggregateResolver.ts","../src/client/utils.ts","../src/client/queryClientGenerator.ts","../src/client/commandClientGenerator.ts","../src/client/clientGenerator.ts","../src/index.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 {\n Components,\n Parameter,\n Reference,\n RequestBody,\n Response,\n Schema,\n} from '@ahoo-wang/fetcher-openapi';\n\n/** Prefix for OpenAPI components references */\nexport const COMPONENTS_PREFIX = '#/components/';\n/** Reference prefix for headers components */\nexport const COMPONENTS_HEADERS_REF = `${COMPONENTS_PREFIX}headers/`;\n/** Reference prefix for parameters components */\nexport const COMPONENTS_PARAMETERS_REF = `${COMPONENTS_PREFIX}parameters/`;\n/** Reference prefix for request bodies components */\nexport const COMPONENTS_REQUEST_BODIES_REF = `${COMPONENTS_PREFIX}requestBodies/`;\n/** Reference prefix for responses components */\nexport const COMPONENTS_RESPONSES_REF = `${COMPONENTS_PREFIX}responses/`;\n/** Reference prefix for schemas components */\nexport const COMPONENTS_SCHEMAS_REF = `${COMPONENTS_PREFIX}schemas/`;\n\n/**\n * Represents a schema with its key identifier.\n */\nexport interface KeySchema {\n /** The schema key */\n key: string;\n /** The schema definition */\n schema: Schema;\n}\n\n/**\n * Extracts the component key from an OpenAPI reference.\n * @param reference - The OpenAPI reference object\n * @returns The component key (last part of the reference path)\n */\nexport function extractComponentKey(reference: Reference): string {\n return reference.$ref.split('/').pop() as string;\n}\n\n/**\n * Extracts a schema from OpenAPI components using a reference.\n * @param reference - The reference to the schema\n * @param components - The OpenAPI components object\n * @returns The schema if found, undefined otherwise\n */\nexport function extractSchema(\n reference: Reference,\n components: Components,\n): Schema | undefined {\n const componentKey = extractComponentKey(reference);\n return components.schemas?.[componentKey];\n}\n\n/**\n * Extracts a response from OpenAPI components using a reference.\n * @param reference - The reference to the response\n * @param components - The OpenAPI components object\n * @returns The response if found, undefined otherwise\n */\nexport function extractResponse(\n reference: Reference,\n components: Components,\n): Response | undefined {\n const componentKey = extractComponentKey(reference);\n return components.responses?.[componentKey];\n}\n\n/**\n * Extracts a request body from OpenAPI components using a reference.\n * @param reference - The reference to the request body\n * @param components - The OpenAPI components object\n * @returns The request body if found, undefined otherwise\n */\nexport function extractRequestBody(\n reference: Reference,\n components: Components,\n): RequestBody | undefined {\n const componentKey = extractComponentKey(reference);\n return components.requestBodies?.[componentKey];\n}\n\n/**\n * Extracts a parameter from OpenAPI components using a reference.\n * @param reference - The reference to the parameter\n * @param components - The OpenAPI components object\n * @returns The parameter if found, undefined otherwise\n */\nexport function extractParameter(\n reference: Reference,\n components: Components,\n): Parameter | undefined {\n const componentKey = extractComponentKey(reference);\n return components.parameters?.[componentKey];\n}\n\n/**\n * Creates a KeySchema object from a reference and components.\n * @param reference - The reference to the schema\n * @param components - The OpenAPI components object\n * @returns A KeySchema containing the key and resolved schema\n */\nexport function keySchema(\n reference: Reference,\n components: Components,\n): KeySchema {\n const componentKey = extractComponentKey(reference);\n return {\n key: componentKey,\n schema: extractSchema(reference, components)!,\n };\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst NAMING_SEPARATORS = /[-_\\s.]+|(?=[A-Z])/;\n\n/**\n * Converts a string or array of strings to PascalCase format.\n *\n * This function takes a string or array of strings and converts them to PascalCase format\n * by splitting the input based on common naming separators and capitalizing the first\n * letter of each part.\n *\n * @param name - A string or array of strings to convert to PascalCase\n * @returns The PascalCase formatted string\n */\nexport function pascalCase(name: string | string[]): string {\n if (name === '' || name.length === 0) {\n return '';\n }\n let names: string[];\n if (Array.isArray(name)) {\n // If input is an array, split each element by naming separators and flatten the result\n names = name.flatMap(part => part.split(NAMING_SEPARATORS));\n } else {\n // If input is a string, split it by naming separators\n names = name.split(NAMING_SEPARATORS);\n }\n return names\n .filter(part => part.length > 0)\n .map(part => {\n if (part.length === 0) return '';\n const firstChar = part.charAt(0);\n const rest = part.slice(1);\n return (\n (/[a-zA-Z]/.test(firstChar) ? firstChar.toUpperCase() : firstChar) +\n rest.toLowerCase()\n );\n })\n .join('');\n}\n\n/**\n * Converts a string or array of strings to camelCase format.\n *\n * This function first converts the input to PascalCase and then converts the first character to lowercase.\n *\n * @param name - A string or array of strings to convert to camelCase\n * @returns The camelCase formatted string\n */\nexport function camelCase(name: string | string[]): string {\n const pascalCaseName = pascalCase(name);\n return pascalCaseName.charAt(0).toLowerCase() + pascalCaseName.slice(1);\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 { readFile } from 'fs';\n\nexport function loadResource(path: string): Promise<string> {\n if (path.startsWith('http://') || path.startsWith('https://')) {\n return loadHttpResource(path);\n }\n return loadFile(path);\n}\n\nexport async function loadHttpResource(url: string): Promise<string> {\n const response = await fetch(url);\n return await response.text();\n}\n\nexport function loadFile(path: string): Promise<string> {\n return new Promise((resolve, reject) => {\n readFile(path, 'utf-8', (err, data) => {\n if (err) {\n reject(err);\n } else {\n resolve(data);\n }\n });\n });\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { OpenAPI } from '@ahoo-wang/fetcher-openapi';\nimport { parse } from 'yaml';\nimport { loadResource } from './resources';\n\n/**\n * Parses an OpenAPI specification from a file path.\n *\n * @param inputPath - The path to the OpenAPI specification file\n * @returns A promise that resolves to the parsed OpenAPI object\n */\nexport async function parseOpenAPI(inputPath: string): Promise<OpenAPI> {\n const content = await loadResource(inputPath);\n const fileFormat = inferFileFormat(content);\n switch (fileFormat) {\n case FileFormat.JSON:\n return JSON.parse(content);\n case FileFormat.YAML:\n return parse(content);\n default:\n throw new Error(`Unsupported file format: ${inputPath}`);\n }\n}\n\nexport enum FileFormat {\n JSON = 'json',\n YAML = 'yaml',\n}\n\nexport function inferFileFormat(content: string): FileFormat {\n // Trim whitespace and BOM characters from the beginning\n const trimmedContent = content.trimStart();\n\n if (trimmedContent.startsWith('{') || trimmedContent.startsWith('[')) {\n return FileFormat.JSON;\n }\n\n // YAML can start with various characters, but commonly with '-' (for arrays) or '%YAML'\n // We'll check for common YAML indicators\n if (trimmedContent.startsWith('-') || trimmedContent.startsWith('%YAML')) {\n return FileFormat.YAML;\n }\n\n // Try to parse as JSON to see if it's valid JSON despite not starting with { or [\n try {\n JSON.parse(trimmedContent);\n return FileFormat.JSON;\n } catch {\n // If it's not valid JSON, we'll assume it's YAML if it's not empty\n if (trimmedContent.length > 0) {\n return FileFormat.YAML;\n }\n }\n\n throw new Error('Unable to infer file format');\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 { Reference } from '@ahoo-wang/fetcher-openapi';\n\nexport function isReference(schema: any): schema is Reference {\n return !!(schema && typeof schema === 'object' && '$ref' in schema);\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 { Reference, Schema, Response } from '@ahoo-wang/fetcher-openapi';\nimport { ContentTypeValues } from '@ahoo-wang/fetcher';\nimport { isReference } from './references';\n\n/**\n * Extracts the JSON schema from an OK response.\n * @param okResponse - The response object or reference\n * @returns The JSON schema from the response content or undefined if not found\n */\nexport function extractOkResponseJsonSchema(\n okResponse?: Response | Reference,\n): Schema | Reference | undefined {\n if (!okResponse) {\n return;\n }\n if (isReference(okResponse)) {\n return undefined;\n }\n\n if (!okResponse.content) {\n return undefined;\n }\n const jsonContent = okResponse.content[ContentTypeValues.APPLICATION_JSON];\n return jsonContent?.schema;\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 {\n HTTPMethod,\n Operation,\n PathItem,\n Reference,\n Response,\n Schema,\n} from '@ahoo-wang/fetcher-openapi';\nimport { extractOkResponseJsonSchema } from './responses';\n\n/**\n * Represents an HTTP method and its associated operation.\n */\nexport interface MethodOperation {\n /** The HTTP method */\n method: HTTPMethod;\n /** The OpenAPI operation */\n operation: Operation;\n}\n\n/**\n * Extracts all operations from a path item.\n * @param pathItem - The OpenAPI path item\n * @returns Array of method-operation pairs\n */\nexport function extractOperations(pathItem: PathItem): MethodOperation[] {\n return [\n { method: 'get', operation: pathItem.get },\n { method: 'put', operation: pathItem.put },\n { method: 'post', operation: pathItem.post },\n { method: 'delete', operation: pathItem.delete },\n { method: 'options', operation: pathItem.options },\n { method: 'head', operation: pathItem.head },\n { method: 'patch', operation: pathItem.patch },\n { method: 'trace', operation: pathItem.trace },\n ].filter(({ operation }) => operation !== undefined) as Array<{\n method: HTTPMethod;\n operation: Operation;\n }>;\n}\n\n/**\n * Extracts the OK (200) response from an operation.\n * @param operation - The OpenAPI operation\n * @returns The 200 response or undefined if not found\n */\nexport function extractOkResponse(\n operation: Operation,\n): Response | Reference | undefined {\n return operation.responses['200'];\n}\n\n/**\n * Extracts the JSON schema from the OK response of an operation.\n * @param operation - The OpenAPI operation\n * @returns The JSON schema from the OK response or undefined if not found\n */\nexport function extractOperationOkResponseJsonSchema(\n operation: Operation,\n): Schema | Reference | undefined {\n const okResponse = extractOkResponse(operation);\n return extractOkResponseJsonSchema(okResponse);\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 { Schema, SchemaType } from '@ahoo-wang/fetcher-openapi';\n\n/** List of primitive schema types */\nconst PRIMITIVE_TYPES: SchemaType[] = [\n 'string',\n 'number',\n 'integer',\n 'boolean',\n 'null',\n];\n\n/**\n * Checks if a schema type is primitive.\n * @param type - The schema type to check\n * @returns True if the type is primitive, false otherwise\n */\nexport function isPrimitive(type: SchemaType | SchemaType[]): boolean {\n if (Array.isArray(type)) {\n return true;\n }\n return PRIMITIVE_TYPES.includes(type);\n}\n\n/**\n * Checks if a schema is an array type.\n * @param schema - The schema to check\n * @returns True if the schema is an array type, false otherwise\n */\nexport function isArray(schema: Schema): schema is Schema & { type: 'array' } {\n return schema.type === 'array';\n}\n\nexport type EnumSchema = Schema & { enum: any[] };\n\n/**\n * Checks if a schema represents an enum.\n * @param schema - The schema to check\n * @returns True if the schema has an enum property, false otherwise\n */\nexport function isEnum(schema: Schema): schema is EnumSchema {\n return Array.isArray(schema.enum) && schema.enum.length > 0;\n}\n\nexport type AnyOfSchema = Schema & { anyOf: any[] };\n\n/**\n * Checks if a schema is an anyOf composition.\n * @param schema - The schema to check\n * @returns True if the schema has a non-empty anyOf property, false otherwise\n */\nexport function isAnyOf(schema: Schema): schema is AnyOfSchema {\n return Array.isArray(schema.anyOf) && schema.anyOf.length > 0;\n}\n\nexport type OneOfSchema = Schema & { oneOf: any[] };\n\n/**\n * Checks if a schema is a oneOf composition.\n * @param schema - The schema to check\n * @returns True if the schema has a non-empty oneOf property, false otherwise\n */\nexport function isOneOf(schema: Schema): schema is OneOfSchema {\n return Array.isArray(schema.oneOf) && schema.oneOf.length > 0;\n}\n\nexport type UnionSchema = Schema & ({ anyOf: any[] } | { oneOf: any[] });\n\n/**\n * Checks if a schema is a union (either anyOf or oneOf).\n * @param schema - The schema to check\n * @returns True if the schema is either an anyOf or oneOf composition, false otherwise\n */\nexport function isUnion(schema: Schema): schema is UnionSchema {\n return isAnyOf(schema) || isOneOf(schema);\n}\n\nexport type AllOfSchema = Schema & { allOf: any[] };\n\n/**\n * Checks if a schema is an allOf composition.\n * @param schema - The schema to check\n * @returns True if the schema has a non-empty allOf property, false otherwise\n */\nexport function isAllOf(schema: Schema): schema is AllOfSchema {\n return Array.isArray(schema.allOf) && schema.allOf.length > 0;\n}\n\nexport type CompositionSchema = AnyOfSchema | OneOfSchema | AllOfSchema;\n\n/**\n * Checks if a schema is a composition (anyOf, oneOf, or allOf).\n * @param schema - The schema to check\n * @returns True if the schema is anyOf, oneOf, or allOf composition, false otherwise\n */\nexport function isComposition(schema: Schema): schema is CompositionSchema {\n return isAnyOf(schema) || isOneOf(schema) || isAllOf(schema);\n}\n\n/**\n * Converts a type string to an array type.\n * Wraps complex types (containing | or &) in parentheses before adding array notation.\n * @param type - The type string to convert to an array type\n * @returns The array type string\n */\nexport function toArrayType(type: string): string {\n if (type.includes('|') || type.includes('&')) {\n return `(${type})[]`;\n }\n return `${type}[]`;\n}\n\n/**\n * Resolves a schema type to its TypeScript equivalent.\n * @param type - The schema type(s) to resolve\n * @returns The TypeScript type string\n */\nexport function resolvePrimitiveType(type: SchemaType | SchemaType[]): string {\n if (Array.isArray(type)) {\n return type.map(it => resolvePrimitiveType(it)).join(' | ');\n }\n switch (type) {\n case 'string':\n return 'string';\n case 'number':\n case 'integer':\n return 'number';\n case 'boolean':\n return 'boolean';\n case 'null':\n return 'null';\n default:\n return 'any';\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** Import path for the WOW framework types */\nexport const IMPORT_WOW_PATH = '@ahoo-wang/fetcher-wow';\n\n/** Mapping of OpenAPI schema keys to WOW framework types */\nexport const WOW_TYPE_MAPPING = {\n 'wow.command.CommandResult': 'CommandResult',\n 'wow.MessageHeaderSqlType': 'MessageHeaderSqlType',\n 'wow.api.BindingError': 'BindingError',\n 'wow.api.DefaultErrorInfo': 'ErrorInfo',\n 'wow.api.RecoverableType': 'RecoverableType',\n 'wow.api.command.DefaultDeleteAggregate': 'DeleteAggregate',\n 'wow.api.command.DefaultRecoverAggregate': 'RecoverAggregate',\n 'wow.api.messaging.FunctionInfoData': 'FunctionInfo',\n 'wow.api.messaging.FunctionKind': 'FunctionKind',\n 'wow.api.modeling.AggregateId': 'AggregateId',\n 'wow.api.query.Condition': 'Condition',\n 'wow.api.query.ConditionOptions': 'ConditionOptions',\n 'wow.api.query.ListQuery': 'ListQuery',\n 'wow.api.query.Operator': 'Operator',\n 'wow.api.query.PagedQuery': 'PagedQuery',\n 'wow.api.query.Pagination': 'Pagination',\n 'wow.api.query.Projection': 'Projection',\n 'wow.api.query.Sort': 'FieldSort',\n 'wow.api.query.Sort.Direction': 'SortDirection',\n 'wow.command.CommandStage': 'CommandStage',\n 'wow.command.SimpleWaitSignal': 'WaitSignal',\n 'wow.configuration.Aggregate': 'Aggregate',\n 'wow.configuration.BoundedContext': 'BoundedContext',\n 'wow.configuration.WowMetadata': 'WowMetadata',\n 'wow.modeling.DomainEvent': 'DomainEvent',\n 'wow.openapi.BatchResult': 'BatchResult',\n 'wow.messaging.CompensationTarget': 'CompensationTarget',\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 { Named } from '@ahoo-wang/fetcher-wow';\nimport { IMPORT_WOW_PATH, WOW_TYPE_MAPPING } from './wowTypeMapping';\nimport { pascalCase } from '../utils';\n\n/**\n * Data Model Info\n */\nexport interface ModelInfo extends Named {\n name: string;\n path: string;\n}\n\n/**\n * Resolves model information from a schema key.\n *\n * This function parses a dot-separated schema key and extracts the model name and path.\n * It assumes that the model name is the first part that starts with an uppercase letter.\n * All parts before the model name are treated as the path.\n *\n * @example\n *\n * - \"wow.api.BindingError\" -> {path:'/wow/api',name:'BindingError'}\n * - \"compensation.ApiVersion\" -> {path:'/compensation',name:'ApiVersion'}\n * - \"ai.AiMessage.Assistant\" -> {path:'/ai',name:'AiMessageAssistant'}\n * - \"Result\" -> {path:'/',name:'Result'}\n *\n * @param schemaKey - The dot-separated schema key (e.g., \"com.example.User\")\n * @returns ModelInfo object containing the parsed name and path\n */\nexport function resolveModelInfo(schemaKey: string): ModelInfo {\n if (!schemaKey) {\n return { name: '', path: '/' };\n }\n const mappedType =\n WOW_TYPE_MAPPING[schemaKey as keyof typeof WOW_TYPE_MAPPING];\n if (mappedType) {\n return { name: mappedType, path: IMPORT_WOW_PATH };\n }\n\n const parts = schemaKey.split('.');\n let modelNameIndex = -1;\n\n // Find the first part that starts with an uppercase letter\n for (let i = 0; i < parts.length; i++) {\n if (parts[i] && /^[A-Z]/.test(parts[i])) {\n modelNameIndex = i;\n break;\n }\n }\n\n // If no part starts with uppercase letter, treat the whole thing as the name\n if (modelNameIndex === -1) {\n return { name: schemaKey, path: '/' };\n }\n\n // Construct the path from parts before the model name\n const pathParts = parts.slice(0, modelNameIndex);\n const path = pathParts.length > 0 ? `/${pathParts.join('/')}` : '/';\n\n // Construct the model name from the remaining parts\n const nameParts = parts.slice(modelNameIndex);\n const name = pascalCase(nameParts);\n\n return { name, path };\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 { Project } from 'ts-morph';\nimport { OpenAPI } from '@ahoo-wang/fetcher-openapi';\nimport { GenerateContext, Logger } from './types';\nimport { BoundedContextAggregates } from './aggregate';\n\nexport abstract class BaseCodeGenerator implements GenerateContext {\n /** The ts-morph project instance used for code generation */\n readonly project: Project;\n /** The OpenAPI specification object */\n readonly openAPI: OpenAPI;\n /** The output directory path for generated files */\n readonly outputDir: string;\n /** Map of bounded context aggregates for domain modeling */\n readonly contextAggregates: BoundedContextAggregates;\n /** Optional logger for generation progress and errors */\n readonly logger: Logger;\n\n /**\n * Creates a new ClientGenerator instance.\n * @param context - The generation context containing OpenAPI spec and project details\n */\n protected constructor(context: GenerateContext) {\n this.project = context.project;\n this.openAPI = context.openAPI;\n this.outputDir = context.outputDir;\n this.contextAggregates = context.contextAggregates;\n this.logger = context.logger;\n }\n\n /**\n * Generates code based on the provided context.\n * Subclasses must implement this method to define their specific generation logic.\n */\n abstract generate(): void;\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 { Schema, Reference } from '@ahoo-wang/fetcher-openapi';\nimport {\n InterfaceDeclaration,\n JSDocableNode,\n SourceFile,\n\n} from 'ts-morph';\nimport { GenerateContext } from '../types';\nimport { ModelInfo, resolveModelInfo } from './modelInfo';\nimport {\n addImportModelInfo,\n addJSDoc, CompositionSchema,\n extractComponentKey,\n getModelFileName,\n getOrCreateSourceFile, isArray, isComposition,\n isEnum, isPrimitive,\n isReference, isUnion,\n KeySchema, pascalCase,\n resolvePrimitiveType, toArrayType,\n} from '../utils';\nimport { BaseCodeGenerator } from '../baseCodeGenerator';\n\n/**\n * Generates TypeScript models from OpenAPI schemas.\n * Handles enum, object, union, and type alias generation.\n *\n * @property project - The ts-morph project instance\n * @property openAPI - The OpenAPI specification\n * @property outputDir - The output directory for generated files\n * @property contextAggregates - Map of aggregate definitions\n */\nexport class ModelGenerator extends BaseCodeGenerator {\n constructor(context: GenerateContext) {\n super(context);\n }\n\n private getOrCreateSourceFile(modelInfo: ModelInfo): SourceFile {\n const fileName = getModelFileName(modelInfo);\n return getOrCreateSourceFile(this.project, this.outputDir, fileName);\n }\n\n /**\n * Generates models for all schemas in the OpenAPI specification.\n * Skips schemas with keys starting with 'wow.'.\n *\n * @remarks\n * This method iterates through all schemas in the OpenAPI specification\n * and generates corresponding TypeScript models for each one.\n */\n generate() {\n const schemas = this.openAPI.components?.schemas;\n if (!schemas) {\n this.logger.info('No schemas found in OpenAPI specification');\n return;\n }\n this.logger.progress(\n `Generating models for ${Object.keys(schemas).length} schemas`,\n );\n Object.entries(schemas).forEach(([schemaKey, schema]) => {\n if (schemaKey.startsWith('wow.')) {\n return;\n }\n this.logger.progress(`Processing schema: ${schemaKey}`);\n const keySchema: KeySchema = {\n key: schemaKey,\n schema,\n };\n this.generateKeyedSchema(keySchema);\n });\n this.logger.success('Model generation completed');\n }\n\n /**\n * Generates a model for a specific schema key.\n * Processes enums, objects, unions, and type aliases in order.\n *\n * @param schemaKey - The key of the schema to generate\n * @param schema - The schema definition\n *\n * @remarks\n * The generation process follows this order:\n * 1. Enum processing\n * 2. Object processing\n * 3. Union processing\n * 4. Type alias processing\n */\n generateKeyedSchema({ key, schema }: KeySchema) {\n const modelInfo = resolveModelInfo(key);\n const sourceFile = this.getOrCreateSourceFile(modelInfo);\n const node = this.process(modelInfo, sourceFile, schema);\n if (node) {\n addJSDoc(node, schema.title, schema.description);\n }\n }\n\n private process(\n modelInfo: ModelInfo,\n sourceFile: SourceFile,\n schema: Schema,\n ): JSDocableNode | undefined {\n if (isEnum(schema)) {\n return sourceFile.addEnum({\n name: modelInfo.name,\n isExported: true,\n members: schema.enum\n .filter(value => typeof value === 'string' && value.length > 0)\n .map(value => ({\n name: value,\n initializer: `'${value}'`,\n })),\n });\n }\n const interfaceDeclaration = sourceFile.addInterface({\n name: modelInfo.name,\n isExported: true,\n });\n if (schema.type === 'object' && schema.properties) {\n return this.processInterface(sourceFile, modelInfo, schema, interfaceDeclaration);\n }\n\n if (isComposition(schema)) {\n const compositionTypes = schema.anyOf || schema.oneOf || schema.allOf;\n compositionTypes!.forEach(compositionTypeSchema => {\n if (isReference(compositionTypeSchema)) {\n const refModelInfo = resolveModelInfo(extractComponentKey(compositionTypeSchema));\n addImportModelInfo(modelInfo, sourceFile, this.outputDir, refModelInfo);\n interfaceDeclaration.addExtends(refModelInfo.name);\n return;\n }\n this.processInterface(sourceFile, modelInfo, compositionTypeSchema, interfaceDeclaration);\n });\n }\n return interfaceDeclaration;\n }\n\n private processObject(sourceFile: SourceFile, modelInfo: ModelInfo, schema: Schema) {\n const interfaceDeclaration = sourceFile.addInterface({\n name: modelInfo.name,\n isExported: true,\n });\n return this.processInterface(sourceFile, modelInfo, schema, interfaceDeclaration);\n }\n\n private processInterface(sourceFile: SourceFile, modelInfo: ModelInfo, schema: Schema, interfaceDeclaration: InterfaceDeclaration) {\n for (const [propName, propSchema] of Object.entries(schema.properties!)) {\n const propType: string = this.resolvePropertyType(modelInfo, sourceFile, propName, propSchema);\n let propertySignature = interfaceDeclaration.getProperty(propName);\n if (propertySignature) {\n propertySignature.setType(propType);\n } else {\n propertySignature = interfaceDeclaration.addProperty({\n name: propName,\n type: propType,\n });\n }\n if (!isReference(propSchema)) {\n addJSDoc(propertySignature, propSchema.title, propSchema.description);\n }\n }\n return interfaceDeclaration;\n }\n\n\n private resolvePropertyType(currentModelInfo: ModelInfo, sourceFile: SourceFile, propName: string, propSchema: Schema | Reference): string {\n if (isReference(propSchema)) {\n const refModelInfo = resolveModelInfo(extractComponentKey(propSchema));\n addImportModelInfo(currentModelInfo, sourceFile, this.outputDir, refModelInfo);\n return refModelInfo.name;\n }\n if (propSchema.const) {\n return `'${propSchema.const}'`;\n }\n if (isArray(propSchema)) {\n const itemsType = this.resolvePropertyType(currentModelInfo, sourceFile, propName, propSchema.items!);\n return toArrayType(itemsType);\n }\n if (propSchema.type && isPrimitive(propSchema.type)) {\n return resolvePrimitiveType(propSchema.type!);\n }\n if (isComposition(propSchema)) {\n return this.resolvePropertyCompositionType(currentModelInfo, sourceFile, propSchema);\n }\n /**\n * handle object\n */\n if (propSchema.type === 'object' && propSchema.properties) {\n const propModelInfo: ModelInfo = {\n path: currentModelInfo.path,\n name: `${currentModelInfo.name}${pascalCase(propName)}`,\n };\n const interfaceDeclaration = this.processObject(sourceFile, propModelInfo, propSchema);\n addJSDoc(interfaceDeclaration, propSchema.title, propSchema.description);\n return propModelInfo.name;\n }\n return 'any';\n }\n\n private resolvePropertyCompositionType(currentModelInfo: ModelInfo, sourceFile: SourceFile, schema: CompositionSchema): string {\n const compositionTypes = schema.anyOf || schema.oneOf || schema.allOf;\n const types: Set<string> = new Set<string>();\n compositionTypes!.forEach(compositionTypeSchema => {\n if (isReference(compositionTypeSchema)) {\n const refModelInfo = resolveModelInfo(extractComponentKey(compositionTypeSchema));\n addImportModelInfo(currentModelInfo, sourceFile, this.outputDir, refModelInfo);\n types.add(refModelInfo.name);\n return;\n }\n types.add(resolvePrimitiveType(compositionTypeSchema.type ?? 'string'));\n });\n const separator = isUnion(schema) ? '|' : '&';\n return Array.from(types).join(separator);\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JSDocableNode, Project, SourceFile } from 'ts-morph';\nimport { combineURLs } from '@ahoo-wang/fetcher';\nimport { IMPORT_WOW_PATH, ModelInfo } from '../model';\n\n/** Default file name for model files */\nconst MODEL_FILE_NAME = 'types.ts';\n/** Alias for import paths */\nconst IMPORT_ALIAS = '@';\n\n/**\n * Generates the file path for a model file.\n * @param modelInfo - The model information\n * @returns The full file path for the model\n */\nexport function getModelFileName(modelInfo: ModelInfo): string {\n return combineURLs(modelInfo.path, MODEL_FILE_NAME);\n}\n\n/**\n * Gets or creates a source file in the project.\n * @param project - The ts-morph project\n * @param outputDir - The output directory\n * @param filePath - The relative file path\n * @returns The source file\n */\nexport function getOrCreateSourceFile(\n project: Project,\n outputDir: string,\n filePath: string,\n): SourceFile {\n const fileName = combineURLs(outputDir, filePath);\n const file = project.getSourceFile(fileName);\n if (file) {\n return file;\n }\n return project.createSourceFile(fileName, '', {\n overwrite: true,\n });\n}\n\n/**\n * Adds named imports to a source file.\n * @param sourceFile - The source file to modify\n * @param moduleSpecifier - The module to import from\n * @param namedImports - Array of named imports to add\n */\nexport function addImport(\n sourceFile: SourceFile,\n moduleSpecifier: string,\n namedImports: string[],\n) {\n let declaration = sourceFile.getImportDeclaration(\n importDeclaration =>\n importDeclaration.getModuleSpecifierValue() === moduleSpecifier,\n );\n if (!declaration) {\n declaration = sourceFile.addImportDeclaration({\n moduleSpecifier,\n });\n }\n namedImports.forEach(namedImport => {\n const exited = declaration\n .getNamedImports()\n .some(\n existingNamedImport => existingNamedImport.getName() === namedImport,\n );\n if (exited) {\n return;\n }\n declaration.addNamedImport(namedImport);\n });\n}\n\n/**\n * Adds an import for a referenced model.\n * @param sourceFile - The source file to modify\n * @param outputDir - The output directory\n * @param refModelInfo - The referenced model information\n */\nexport function addImportRefModel(\n sourceFile: SourceFile,\n outputDir: string,\n refModelInfo: ModelInfo,\n) {\n if (refModelInfo.path === IMPORT_WOW_PATH) {\n addImport(sourceFile, refModelInfo.path, [refModelInfo.name]);\n return;\n }\n let fileName = getModelFileName(refModelInfo);\n // If the path already starts with an alias, don't combine with outputDir\n if (!refModelInfo.path.startsWith(IMPORT_ALIAS)) {\n fileName = combineURLs(outputDir, fileName);\n }\n let moduleSpecifier = fileName;\n if (!fileName.startsWith(IMPORT_ALIAS)) {\n moduleSpecifier = combineURLs(IMPORT_ALIAS, fileName);\n }\n addImport(sourceFile, moduleSpecifier, [refModelInfo.name]);\n}\n\n/**\n * Adds an import for a model if it's in a different path.\n * @param currentModel - The current model information\n * @param sourceFile - The source file to modify\n * @param outputDir - The output directory\n * @param refModel - The referenced model information\n */\nexport function addImportModelInfo(\n currentModel: ModelInfo,\n sourceFile: SourceFile,\n outputDir: string,\n refModel: ModelInfo,\n) {\n if (currentModel.path === refModel.path) {\n return;\n }\n addImportRefModel(sourceFile, outputDir, refModel);\n}\n\n/**\n * Generates a JSDoc comment string from a title and description.\n * @param title - The title for the JSDoc comment\n * @param description - The description for the JSDoc comment\n * @returns The formatted JSDoc string or undefined if both title and description are empty\n */\nexport function jsDoc(\n title?: string,\n description?: string,\n): string | undefined {\n const filtered = [title, description].filter(\n v => v !== undefined && v.length > 0,\n );\n return filtered.length > 0 ? filtered.join('\\n') : undefined;\n}\n\nexport function jsDocs(title?: string, description?: string): string[] {\n const jsdoc = jsDoc(title, description);\n return jsdoc ? [jsdoc] : [];\n}\n\n/**\n * Adds a JSDoc comment to a node with the provided title and description.\n * @param node - The node to add the JSDoc comment to\n * @param title - The title for the JSDoc comment\n * @param description - The description for the JSDoc comment\n */\nexport function addJSDoc(\n node: JSDocableNode,\n title?: string,\n description?: string,\n) {\n const jsdoc = jsDoc(title, description);\n if (!jsdoc) {\n return;\n }\n node.addJsDoc({\n description: jsdoc,\n });\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Tag } from '@ahoo-wang/fetcher-openapi';\nimport { PartialBy } from '@ahoo-wang/fetcher';\nimport { AggregateDefinition, TagAliasAggregate } from './aggregate';\n\n/**\n * Checks if a tag name follows the alias aggregate pattern and extracts its components.\n *\n * This function determines if a tag name follows the format \"contextAlias.aggregateName\"\n * and returns the components if it matches.\n *\n * @param tagName - The tag name to check\n * @returns A tuple with [contextAlias, aggregateName] if the pattern matches, null otherwise\n */\nexport function isAliasAggregate(tagName: string): [string, string] | null {\n const parts = tagName.split('.');\n if (parts.length != 2 || parts[0].length === 0 || parts[1].length === 0) {\n return null;\n }\n return parts as [string, string];\n}\n\n/**\n * Converts a Tag to a TagAliasAggregate if it follows the alias pattern.\n *\n * This function checks if a tag name follows the alias aggregate pattern and\n * creates a TagAliasAggregate object with the tag and its parsed components.\n *\n * @param tag - The Tag to convert\n * @returns A TagAliasAggregate if the tag name matches the pattern, null otherwise\n */\nexport function tagToAggregate(tag: Tag): TagAliasAggregate | null {\n const parts = isAliasAggregate(tag.name);\n if (!parts) {\n return null;\n }\n\n return {\n tag,\n contextAlias: parts[0],\n aggregateName: parts[1],\n };\n}\n\n/**\n * Converts an array of Tags to a map of aggregates.\n *\n * This function processes an array of tags, converts those that follow the alias pattern\n * to aggregates, and returns a map where keys are tag names and values are partial\n * aggregate definitions.\n *\n * @param tags - Optional array of Tags to process\n * @returns A map of aggregate definitions keyed by tag name\n */\nexport function tagsToAggregates(\n tags?: Tag[],\n): Map<string, PartialBy<AggregateDefinition, 'state' | 'fields'>> {\n const tagAliasAggregates = tags\n ?.map(tag => tagToAggregate(tag))\n .filter(tag => tag !== null);\n if (!tagAliasAggregates) {\n return new Map();\n }\n const aggregates = new Map<\n string,\n PartialBy<AggregateDefinition, 'state' | 'fields'>\n >();\n tagAliasAggregates.forEach(tagAliasAggregate => {\n aggregates.set(tagAliasAggregate.tag.name, {\n aggregate: tagAliasAggregate,\n commands: new Map(),\n events: new Map(),\n });\n });\n return aggregates;\n}\n\n/**\n * Extracts the command name from an operation ID.\n *\n * This function parses an operation ID expected to follow the format\n * \"context.aggregate.command\" and returns the command part.\n *\n * @param operationId - Optional operation ID to parse\n * @returns The command name if the operation ID follows the expected format, null otherwise\n */\nexport function operationIdToCommandName(operationId?: string): string | null {\n if (!operationId) {\n return null;\n }\n const parts = operationId.split('.');\n if (parts.length != 3) {\n return null;\n }\n return parts[2];\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 {\n OpenAPI,\n Operation,\n Parameter,\n Reference,\n RequestBody,\n Schema,\n} from '@ahoo-wang/fetcher-openapi';\nimport {\n AggregateDefinition,\n BoundedContextAggregates,\n CommandDefinition,\n EventDefinition,\n} from './aggregate';\n\nimport { ContentTypeValues, PartialBy } from '@ahoo-wang/fetcher';\nimport { operationIdToCommandName, tagsToAggregates } from './utils';\nimport {\n extractOkResponse,\n extractOperationOkResponseJsonSchema,\n extractOperations,\n extractParameter,\n extractRequestBody,\n extractSchema,\n isReference,\n keySchema,\n MethodOperation,\n} from '../utils';\nimport { EventStreamSchema } from './types';\n\nconst CommandOkResponseRef = '#/components/responses/wow.CommandOk';\nconst IdParameterRef = '#/components/parameters/wow.id';\n\n/**\n * Resolves aggregate definitions from OpenAPI specifications.\n * Parses operations to extract commands, events, and state information for each aggregate.\n */\nexport class AggregateResolver {\n private readonly aggregates: Map<\n string,\n PartialBy<AggregateDefinition, 'state' | 'fields'>\n >;\n\n /**\n * Creates a new AggregateResolver instance.\n * @param openAPI - The OpenAPI specification to resolve aggregates from\n */\n constructor(private readonly openAPI: OpenAPI) {\n this.aggregates = tagsToAggregates(openAPI.tags);\n this.build();\n }\n\n /**\n * Builds the aggregate definitions by processing all operations in the OpenAPI spec.\n * @private\n */\n private build() {\n for (const [path, pathItem] of Object.entries(this.openAPI.paths)) {\n const methodOperations = extractOperations(pathItem);\n for (const methodOperation of methodOperations) {\n this.commands(path, methodOperation);\n this.state(methodOperation.operation);\n this.events(methodOperation.operation);\n this.fields(methodOperation.operation);\n }\n }\n }\n\n /**\n * Returns the resolved aggregate definitions.\n * @returns Map of aggregate definitions keyed by context alias\n */\n resolve(): BoundedContextAggregates {\n const resolvedContextAggregates = new Map<\n string,\n Set<AggregateDefinition>\n >();\n for (const aggregate of this.aggregates.values()) {\n if (!aggregate.state || !aggregate.fields) {\n continue;\n }\n const contextAlias = aggregate.aggregate.contextAlias;\n let aggregates = resolvedContextAggregates.get(contextAlias);\n if (!aggregates) {\n aggregates = new Set<AggregateDefinition>();\n resolvedContextAggregates.set(contextAlias, aggregates);\n }\n aggregates.add(aggregate as AggregateDefinition);\n }\n return resolvedContextAggregates;\n }\n\n /**\n * Processes command operations and adds them to the appropriate aggregates.\n * @param path - The API path\n * @param methodOperation - The HTTP method and operation details\n */\n commands(path: string, methodOperation: MethodOperation) {\n const operation = methodOperation.operation;\n if (operation.operationId === 'wow.command.send') {\n return;\n }\n const commandName = operationIdToCommandName(operation.operationId);\n if (!commandName) {\n return;\n }\n const okResponse = extractOkResponse(operation);\n if (!okResponse) {\n return;\n }\n if (!isReference(okResponse)) {\n return;\n }\n if (okResponse.$ref !== CommandOkResponseRef) {\n return;\n }\n if (!operation.requestBody) {\n return;\n }\n\n const parameters = operation.parameters ?? [];\n const idRefParameter = parameters\n .filter(p => isReference(p) && p.$ref === IdParameterRef)\n .at(0) as Reference | undefined;\n const pathParameters = parameters.filter(\n p => !isReference(p) && p.in === 'path',\n ) as Parameter[];\n if (idRefParameter) {\n const idParameter = extractParameter(\n idRefParameter,\n this.openAPI.components!,\n );\n pathParameters.push(idParameter!);\n }\n const requestBody = operation.requestBody as RequestBody;\n const commandRefSchema = requestBody.content[\n ContentTypeValues.APPLICATION_JSON\n ].schema as Reference;\n const commandKeyedSchema = keySchema(\n commandRefSchema,\n this.openAPI.components!,\n );\n commandKeyedSchema.schema.title =\n commandKeyedSchema.schema.title || operation.summary;\n commandKeyedSchema.schema.description =\n commandKeyedSchema.schema.description || operation.description;\n const commandDefinition: CommandDefinition = {\n name: commandName,\n method: methodOperation.method,\n path,\n pathParameters,\n summary: operation.summary,\n description: operation.description,\n schema: commandKeyedSchema,\n operation: operation,\n };\n operation.tags?.forEach(tag => {\n const aggregate = this.aggregates.get(tag);\n if (!aggregate) {\n return;\n }\n aggregate.commands.set(commandName, commandDefinition);\n });\n }\n\n /**\n * Processes state snapshot operations and associates them with aggregates.\n * @param operation - The OpenAPI operation\n */\n state(operation: Operation) {\n if (!operation.operationId?.endsWith('.snapshot_state.single')) {\n return;\n }\n const stateRefSchema = extractOperationOkResponseJsonSchema(operation);\n if (!isReference(stateRefSchema)) {\n return;\n }\n const stateKeyedSchema = keySchema(\n stateRefSchema,\n this.openAPI.components!,\n );\n operation.tags?.forEach(tag => {\n const aggregate = this.aggregates.get(tag);\n if (!aggregate) {\n return;\n }\n aggregate.state = stateKeyedSchema;\n });\n }\n\n /**\n * Processes event stream operations and extracts domain events for aggregates.\n * @param operation - The OpenAPI operation\n */\n events(operation: Operation) {\n if (!this.openAPI.components) {\n return;\n }\n if (!operation.operationId?.endsWith('.event.list_query')) {\n return;\n }\n const eventStreamArraySchema =\n extractOperationOkResponseJsonSchema(operation);\n if (isReference(eventStreamArraySchema)) {\n return;\n }\n const eventStreamRefSchema = eventStreamArraySchema?.items;\n if (!isReference(eventStreamRefSchema)) {\n return;\n }\n const eventStreamSchema = extractSchema(\n eventStreamRefSchema,\n this.openAPI.components,\n ) as EventStreamSchema;\n\n const events: EventDefinition[] =\n eventStreamSchema.properties.body.items.anyOf.map(domainEventSchema => {\n const eventTitle = domainEventSchema.title;\n const eventName = domainEventSchema.properties.name.const;\n const eventBodySchema = domainEventSchema.properties.body;\n const eventBodyKeyedSchema = keySchema(\n eventBodySchema,\n this.openAPI.components!,\n );\n eventBodyKeyedSchema.schema.title =\n eventBodyKeyedSchema.schema.title || domainEventSchema.title;\n return {\n title: eventTitle,\n name: eventName,\n schema: eventBodyKeyedSchema,\n };\n });\n\n operation.tags?.forEach(tag => {\n const aggregate = this.aggregates.get(tag);\n if (!aggregate) {\n return;\n }\n events.forEach(event => {\n aggregate.events.set(event.name, event);\n });\n });\n }\n\n /**\n * Processes field query operations and associates field schemas with aggregates.\n * @param operation - The OpenAPI operation\n */\n fields(operation: Operation): void {\n if (!this.openAPI.components) {\n return;\n }\n if (!operation.operationId?.endsWith('.snapshot.count')) {\n return;\n }\n const requestBody = extractRequestBody(\n operation.requestBody as Reference,\n this.openAPI.components,\n ) as RequestBody;\n const conditionRefSchema = requestBody.content[\n ContentTypeValues.APPLICATION_JSON\n ].schema as Reference;\n const conditionSchema = extractSchema(\n conditionRefSchema,\n this.openAPI.components,\n ) as Schema;\n const fieldRefSchema = conditionSchema.properties?.field as Reference;\n const fieldKeyedSchema = keySchema(fieldRefSchema, this.openAPI.components);\n operation.tags?.forEach(tag => {\n const aggregate = this.aggregates.get(tag);\n if (!aggregate) {\n return;\n }\n aggregate.fields = fieldKeyedSchema;\n });\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ResourceAttributionPathSpec } from '@ahoo-wang/fetcher-wow';\nimport { Project, SourceFile } from 'ts-morph';\nimport { AggregateDefinition, TagAliasAggregate } from '../aggregate';\nimport { getOrCreateSourceFile, pascalCase } from '../utils';\n\nexport function inferPathSpecType(\n aggregateDefinition: AggregateDefinition,\n): string {\n let tenantSpecCount = 0;\n let ownerSpecCount = 0;\n aggregateDefinition.commands.forEach(command => {\n if (command.path.startsWith(ResourceAttributionPathSpec.TENANT)) {\n tenantSpecCount += 1;\n }\n if (command.path.startsWith(ResourceAttributionPathSpec.OWNER)) {\n ownerSpecCount += 1;\n }\n });\n if (tenantSpecCount === 0 && ownerSpecCount === 0) {\n return 'ResourceAttributionPathSpec.NONE';\n }\n return tenantSpecCount > ownerSpecCount\n ? 'ResourceAttributionPathSpec.TENANT'\n : 'ResourceAttributionPathSpec.OWNER';\n}\n\nexport function createClientFilePath(\n project: Project,\n outputDir: string,\n aggregate: TagAliasAggregate,\n fileName: string,\n): SourceFile {\n const filePath = `${aggregate.contextAlias}/${aggregate.aggregateName}/${fileName}.ts`;\n return getOrCreateSourceFile(project, outputDir, filePath);\n}\n\n/**\n * Generates the client class name for an aggregate.\n * @param aggregate - The aggregate metadata\n * @param suffix - The suffix to append to the aggregate name\n * @returns The generated client class name\n */\nexport function getClientName(\n aggregate: TagAliasAggregate,\n suffix: string,\n): string {\n return `${pascalCase(aggregate.aggregateName)}${suffix}`;\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 { SourceFile, VariableDeclarationKind } from 'ts-morph';\nimport { GenerateContext } from '../types';\nimport { BaseCodeGenerator } from '../baseCodeGenerator';\nimport { AggregateDefinition, TagAliasAggregate } from '../aggregate';\nimport { IMPORT_WOW_PATH, ModelInfo, resolveModelInfo } from '../model';\nimport { createClientFilePath, inferPathSpecType } from './utils';\nimport { addImportRefModel, camelCase } from '../utils';\n\n/**\n * Generates TypeScript query client classes for aggregates.\n * Creates query clients that can perform state queries and event streaming.\n */\nexport class QueryClientGenerator extends BaseCodeGenerator {\n /**\n * Creates a new QueryClientGenerator instance.\n * @param context - The generation context containing OpenAPI spec and project details\n */\n constructor(context: GenerateContext) {\n super(context);\n }\n\n /**\n * Generates query client classes for all aggregates.\n */\n generate(): void {\n const totalAggregates = Array.from(this.contextAggregates.values()).flat()\n .length;\n this.logger.progress(\n `Generating query clients for ${totalAggregates} aggregates`,\n );\n for (const [, aggregates] of this.contextAggregates) {\n aggregates.forEach(aggregateDefinition => {\n this.logger.progress(\n `Processing query client for aggregate: ${aggregateDefinition.aggregate.aggregateName}`,\n );\n this.processQueryClient(aggregateDefinition);\n });\n }\n this.logger.success('Query client generation completed');\n }\n\n /**\n * Creates or retrieves a source file for client generation.\n * @param aggregate - The aggregate metadata\n * @param fileName - The name of the client file\n * @returns The source file for the client\n */\n createClientFilePath(\n aggregate: TagAliasAggregate,\n fileName: string,\n ): SourceFile {\n return createClientFilePath(\n this.project,\n this.outputDir,\n aggregate,\n fileName,\n );\n }\n\n /**\n * Processes and generates query client classes for an aggregate.\n * @param aggregate - The aggregate definition\n */\n processQueryClient(aggregate: AggregateDefinition) {\n const queryClientFile = this.createClientFilePath(\n aggregate.aggregate,\n 'queryClient',\n );\n queryClientFile.addImportDeclaration({\n moduleSpecifier: IMPORT_WOW_PATH,\n namedImports: [\n 'QueryClientFactory',\n 'QueryClientOptions',\n 'ResourceAttributionPathSpec',\n ],\n });\n const defaultClientOptionsName = 'DEFAULT_QUERY_CLIENT_OPTIONS';\n queryClientFile.addVariableStatement({\n declarationKind: VariableDeclarationKind.Const,\n declarations: [\n {\n name: defaultClientOptionsName,\n type: 'QueryClientOptions',\n initializer: `{\n contextAlias: '${aggregate.aggregate.contextAlias}',\n aggregateName: '${aggregate.aggregate.aggregateName}',\n resourceAttribution: ${inferPathSpecType(aggregate)},\n }`,\n },\n ],\n isExported: false,\n });\n const eventModelInfos: ModelInfo[] = [];\n for (const event of aggregate.events.values()) {\n const eventModelInfo = resolveModelInfo(event.schema.key);\n addImportRefModel(queryClientFile, this.outputDir, eventModelInfo);\n eventModelInfos.push(eventModelInfo);\n }\n const domainEventTypesName = 'DOMAIN_EVENT_TYPES';\n queryClientFile.addTypeAlias({\n name: domainEventTypesName,\n type: eventModelInfos.map(it => it.name).join(' | '),\n });\n const clientFactoryName = `${camelCase(aggregate.aggregate.aggregateName)}QueryClientFactory`;\n const stateModelInfo = resolveModelInfo(aggregate.state.key);\n const fieldsModelInfo = resolveModelInfo(aggregate.fields.key);\n addImportRefModel(queryClientFile, this.outputDir, stateModelInfo);\n addImportRefModel(queryClientFile, this.outputDir, fieldsModelInfo);\n queryClientFile.addVariableStatement({\n declarationKind: VariableDeclarationKind.Const,\n declarations: [\n {\n name: clientFactoryName,\n initializer: `new QueryClientFactory<${stateModelInfo.name}, ${fieldsModelInfo.name} | string, ${domainEventTypesName}>(${defaultClientOptionsName})`,\n },\n ],\n isExported: true,\n });\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { BaseCodeGenerator } from '../baseCodeGenerator';\nimport { GenerateContext } from '../types';\nimport {\n ClassDeclaration,\n DecoratorStructure,\n OptionalKind,\n Scope,\n SourceFile,\n VariableDeclarationKind,\n} from 'ts-morph';\nimport { HTTPMethod } from '@ahoo-wang/fetcher-openapi';\nimport { AggregateDefinition, CommandDefinition } from '../aggregate';\nimport { createClientFilePath, getClientName } from './utils';\nimport { IMPORT_WOW_PATH, resolveModelInfo } from '../model';\nimport { addImport, addImportRefModel, addJSDoc, camelCase } from '../utils';\n\n/**\n * Generates TypeScript command client classes for aggregates.\n * Creates command clients that can send commands to aggregates.\n */\nexport class CommandClientGenerator extends BaseCodeGenerator {\n private readonly commandEndpointPathsName = 'COMMAND_ENDPOINT_PATHS';\n private readonly defaultCommandClientOptionsName =\n 'DEFAULT_COMMAND_CLIENT_OPTIONS';\n\n /**\n * Creates a new CommandClientGenerator instance.\n * @param context - The generation context containing OpenAPI spec and project details\n */\n constructor(context: GenerateContext) {\n super(context);\n }\n\n /**\n * Generates command client classes for all aggregates.\n */\n generate(): void {\n const totalAggregates = Array.from(this.contextAggregates.values()).flat()\n .length;\n this.logger.progress(\n `Generating command clients for ${totalAggregates} aggregates`,\n );\n for (const [, aggregates] of this.contextAggregates) {\n aggregates.forEach(aggregateDefinition => {\n this.logger.progress(\n `Processing command client for aggregate: ${aggregateDefinition.aggregate.aggregateName}`,\n );\n this.processAggregate(aggregateDefinition);\n });\n }\n this.logger.success('Command client generation completed');\n }\n\n /**\n * Processes and generates command client for an aggregate.\n * @param aggregate - The aggregate definition\n */\n processAggregate(aggregate: AggregateDefinition) {\n const commandClientFile = createClientFilePath(\n this.project,\n this.outputDir,\n aggregate.aggregate,\n 'commandClient',\n );\n this.processCommandEndpointPaths(commandClientFile, aggregate);\n commandClientFile.addVariableStatement({\n declarationKind: VariableDeclarationKind.Const,\n declarations: [\n {\n name: this.defaultCommandClientOptionsName,\n type: 'ApiMetadata',\n initializer: `{\n basePath: '${aggregate.aggregate.contextAlias}'\n }`,\n },\n ],\n isExported: false,\n });\n commandClientFile.addImportDeclaration({\n moduleSpecifier: IMPORT_WOW_PATH,\n namedImports: [\n 'CommandRequest',\n 'CommandResult',\n 'CommandResultEventStream',\n 'DeleteAggregate',\n 'RecoverAggregate',\n ],\n isTypeOnly: true,\n });\n commandClientFile.addImportDeclaration({\n moduleSpecifier: '@ahoo-wang/fetcher-eventstream',\n namedImports: ['JsonEventStreamResultExtractor'],\n });\n addImport(commandClientFile, '@ahoo-wang/fetcher', ['ContentTypeValues']);\n addImport(commandClientFile, '@ahoo-wang/fetcher-decorator', [\n 'type ApiMetadata',\n 'type ApiMetadataCapable',\n 'api',\n 'post',\n 'put',\n 'patch',\n 'del',\n 'request',\n 'attribute',\n 'path',\n 'autoGeneratedError',\n ]);\n\n this.processCommandClient(commandClientFile, aggregate);\n this.processCommandClient(commandClientFile, aggregate, true);\n }\n\n processCommandEndpointPaths(\n clientFile: SourceFile,\n aggregateDefinition: AggregateDefinition,\n ) {\n const enumDeclaration = clientFile.addEnum({\n name: this.commandEndpointPathsName,\n });\n aggregateDefinition.commands.forEach(command => {\n enumDeclaration.addMember({\n name: command.name.toUpperCase(),\n initializer: `'${command.path}'`,\n });\n });\n }\n\n getEndpointPath(command: CommandDefinition): string {\n return `${this.commandEndpointPathsName}.${command.name.toUpperCase()}`;\n }\n\n processCommandClient(\n clientFile: SourceFile,\n aggregateDefinition: AggregateDefinition,\n isStream: boolean = false,\n ) {\n let suffix = 'CommandClient';\n let apiDecorator: OptionalKind<DecoratorStructure> = {\n name: 'api',\n arguments: [],\n };\n let returnType = `Promise<CommandResult>`;\n if (isStream) {\n suffix = 'Stream' + suffix;\n apiDecorator = {\n name: 'api',\n arguments: [\n `''`,\n `{\n headers: { Accept: ContentTypeValues.TEXT_EVENT_STREAM },\n resultExtractor: JsonEventStreamResultExtractor,\n}`,\n ],\n };\n returnType = `Promise<CommandResultEventStream>`;\n }\n const commandClientName = getClientName(\n aggregateDefinition.aggregate,\n suffix,\n );\n\n const commandClient = clientFile.addClass({\n name: commandClientName,\n isExported: true,\n decorators: [apiDecorator],\n implements: ['ApiMetadataCapable'],\n });\n commandClient.addConstructor({\n parameters: [\n {\n name: 'apiMetadata',\n type: 'ApiMetadata',\n scope: Scope.Public,\n isReadonly: true,\n initializer: `${this.defaultCommandClientOptionsName}`,\n },\n ],\n });\n aggregateDefinition.commands.forEach(command => {\n this.processCommandMethod(clientFile, commandClient, command, returnType);\n });\n }\n\n private methodToDecorator(method: HTTPMethod): string {\n if (method === 'delete') {\n return 'del';\n }\n return method;\n }\n\n /**\n * Processes and generates a command method for the command client.\n * @param sourceFile - The source file containing the client\n * @param client - The client class declaration\n * @param definition - The command definition\n */\n processCommandMethod(\n sourceFile: SourceFile,\n client: ClassDeclaration,\n definition: CommandDefinition,\n returnType: string,\n ) {\n const commandModelInfo = resolveModelInfo(definition.schema.key);\n addImportRefModel(sourceFile, this.outputDir, commandModelInfo);\n const parameters = definition.pathParameters.map(parameter => {\n return {\n name: parameter.name,\n type: 'string',\n decorators: [\n {\n name: 'path',\n arguments: [`'${parameter.name}'`],\n },\n ],\n };\n });\n parameters.push({\n name: 'commandRequest',\n type: `CommandRequest<${commandModelInfo.name}>`,\n decorators: [\n {\n name: 'request',\n arguments: [],\n },\n ],\n });\n parameters.push({\n name: 'attributes',\n type: 'Record<string, any>',\n decorators: [\n {\n name: 'attribute',\n arguments: [],\n },\n ],\n });\n const methodDeclaration = client.addMethod({\n name: camelCase(definition.name),\n decorators: [\n {\n name: this.methodToDecorator(definition.method),\n arguments: [`${this.getEndpointPath(definition)}`],\n },\n ],\n parameters: parameters,\n returnType: returnType,\n statements: [\n `throw autoGeneratedError(${parameters.map(parameter => parameter.name).join(',')});`,\n ],\n });\n addJSDoc(methodDeclaration, definition.summary, definition.description);\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { BaseCodeGenerator } from '../baseCodeGenerator';\nimport { QueryClientGenerator } from './queryClientGenerator';\nimport { CommandClientGenerator } from './commandClientGenerator';\nimport { GenerateContext } from '../types';\nimport { getOrCreateSourceFile } from '../utils';\n\n/**\n * Generates TypeScript client classes for aggregates.\n * Creates query clients and command clients based on aggregate definitions.\n */\nexport class ClientGenerator extends BaseCodeGenerator {\n private readonly queryClientGenerator: QueryClientGenerator;\n private readonly commandClientGenerator: CommandClientGenerator;\n\n /**\n * Creates a new ClientGenerator instance.\n * @param context - The generation context containing OpenAPI spec and project details\n */\n constructor(context: GenerateContext) {\n super(context);\n this.queryClientGenerator = new QueryClientGenerator(context);\n this.commandClientGenerator = new CommandClientGenerator(context);\n }\n\n /**\n * Generates client classes for all aggregates.\n */\n generate(): void {\n this.logger.progress(\n `Generating clients for ${this.contextAggregates.size} bounded contexts`,\n );\n for (const [contextAlias] of this.contextAggregates) {\n this.logger.progress(`Processing bounded context: ${contextAlias}`);\n this.processBoundedContext(contextAlias);\n }\n this.queryClientGenerator.generate();\n this.commandClientGenerator.generate();\n this.logger.success('Client generation completed');\n }\n\n /**\n * Processes a bounded context by creating a file with the context alias constant.\n * @param contextAlias - The alias of the bounded context to process\n */\n processBoundedContext(contextAlias: string) {\n const filePath = `${contextAlias}/boundedContext.ts`;\n const file = getOrCreateSourceFile(this.project, this.outputDir, filePath);\n file.addStatements(\n `export const BOUNDED_CONTEXT_ALIAS = '${contextAlias}';`,\n );\n }\n}\n","/*\n * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Project } from 'ts-morph';\nimport { GenerateContext, GeneratorOptions } from './types';\nimport { parseOpenAPI } from './utils';\nimport { AggregateResolver } from './aggregate';\nimport { ModelGenerator } from './model';\nimport { ClientGenerator } from './client';\n\n/**\n * Main code generator class that orchestrates the generation of TypeScript code from OpenAPI specifications.\n * Handles model generation, client generation, and project formatting.\n */\nexport class CodeGenerator {\n private readonly project: Project;\n\n /**\n * Creates a new CodeGenerator instance.\n * @param options - Configuration options for code generation\n */\n constructor(private readonly options: GeneratorOptions) {\n this.project = options.project;\n }\n\n /**\n * Generates TypeScript code from the OpenAPI specification.\n * Parses the OpenAPI spec, resolves aggregates, generates models and clients,\n * and formats the output files.\n */\n async generate(): Promise<void> {\n const openAPI = await parseOpenAPI(this.options.inputPath);\n const aggregateResolver = new AggregateResolver(openAPI);\n const boundedContextAggregates = aggregateResolver.resolve();\n const context: GenerateContext = {\n openAPI: openAPI,\n project: this.project,\n outputDir: this.options.outputDir,\n contextAggregates: boundedContextAggregates,\n logger: this.options.logger,\n };\n const modelGenerator = new ModelGenerator(context);\n modelGenerator.generate();\n const clientGenerator = new ClientGenerator(context);\n clientGenerator.generate();\n this.project.getSourceFiles().forEach(sourceFile => {\n sourceFile.formatText();\n sourceFile.organizeImports();\n sourceFile.fixMissingImports();\n });\n await this.project.save();\n }\n}\n"],"names":["extractComponentKey","reference","extractSchema","components","componentKey","extractRequestBody","extractParameter","keySchema","NAMING_SEPARATORS","pascalCase","name","names","part","firstChar","rest","camelCase","pascalCaseName","loadResource","path","loadHttpResource","loadFile","url","resolve","reject","readFile","err","data","parseOpenAPI","inputPath","content","inferFileFormat","parse","trimmedContent","isReference","schema","extractOkResponseJsonSchema","okResponse","ContentTypeValues","extractOperations","pathItem","operation","extractOkResponse","extractOperationOkResponseJsonSchema","PRIMITIVE_TYPES","isPrimitive","type","isArray","isEnum","isAnyOf","isOneOf","isUnion","isAllOf","isComposition","toArrayType","resolvePrimitiveType","it","IMPORT_WOW_PATH","WOW_TYPE_MAPPING","resolveModelInfo","schemaKey","mappedType","parts","modelNameIndex","pathParts","nameParts","BaseCodeGenerator","context","ModelGenerator","modelInfo","fileName","getModelFileName","getOrCreateSourceFile","schemas","key","sourceFile","node","addJSDoc","value","interfaceDeclaration","compositionTypeSchema","refModelInfo","addImportModelInfo","propName","propSchema","propType","propertySignature","currentModelInfo","itemsType","propModelInfo","compositionTypes","types","separator","MODEL_FILE_NAME","IMPORT_ALIAS","combineURLs","project","outputDir","filePath","file","addImport","moduleSpecifier","namedImports","declaration","importDeclaration","namedImport","existingNamedImport","addImportRefModel","currentModel","refModel","jsDoc","title","description","filtered","v","jsdoc","isAliasAggregate","tagName","tagToAggregate","tag","tagsToAggregates","tags","tagAliasAggregates","aggregates","tagAliasAggregate","operationIdToCommandName","operationId","CommandOkResponseRef","IdParameterRef","AggregateResolver","openAPI","methodOperations","methodOperation","resolvedContextAggregates","aggregate","contextAlias","commandName","parameters","idRefParameter","pathParameters","idParameter","commandRefSchema","commandKeyedSchema","commandDefinition","stateRefSchema","stateKeyedSchema","eventStreamArraySchema","eventStreamRefSchema","events","domainEventSchema","eventTitle","eventName","eventBodySchema","eventBodyKeyedSchema","event","conditionRefSchema","fieldRefSchema","fieldKeyedSchema","inferPathSpecType","aggregateDefinition","tenantSpecCount","ownerSpecCount","command","ResourceAttributionPathSpec","createClientFilePath","getClientName","suffix","QueryClientGenerator","totalAggregates","queryClientFile","defaultClientOptionsName","VariableDeclarationKind","eventModelInfos","eventModelInfo","domainEventTypesName","clientFactoryName","stateModelInfo","fieldsModelInfo","CommandClientGenerator","commandClientFile","clientFile","enumDeclaration","isStream","apiDecorator","returnType","commandClientName","commandClient","Scope","method","client","definition","commandModelInfo","parameter","methodDeclaration","ClientGenerator","CodeGenerator","options","boundedContextAggregates"],"mappings":"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"}
|