@ahoo-wang/fetcher-generator 2.2.8 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.zh-CN.md +2 -2
- package/dist/cli.cjs +1 -1
- package/dist/cli.js +1 -1
- package/dist/client/commandClientGenerator.d.ts.map +1 -1
- package/dist/index.cjs +6 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +197 -186
- package/dist/index.js.map +1 -1
- package/dist/model/modelGenerator.d.ts.map +1 -1
- package/dist/utils/naming.d.ts +12 -0
- package/dist/utils/naming.d.ts.map +1 -1
- package/package.json +6 -6
package/README.zh-CN.md
CHANGED
|
@@ -58,8 +58,8 @@ fetcher-generator generate [options]
|
|
|
58
58
|
#### 选项
|
|
59
59
|
|
|
60
60
|
- `-i, --input <path>`:输入 OpenAPI 规范文件路径或 URL(必需)
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
- 支持本地文件路径(例如:`./api-spec.json`、`./api-spec.yaml`)
|
|
62
|
+
- 支持 HTTP/HTTPS URL(例如:`https://api.example.com/openapi.json`)
|
|
63
63
|
- `-o, --output <path>`:输出目录路径(默认为 `src/generated`)
|
|
64
64
|
- `-c, --config <file>`:配置文件路径(可选)
|
|
65
65
|
- `-v, --verbose`:启用详细日志记录
|
package/dist/cli.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("commander"),g=require("./index.cjs"),d=require("ts-morph");require("yaml");require("fs");require("@ahoo-wang/fetcher");require("path");class h{getTimestamp(){return new Date().toISOString().slice(11,19)}info(e,...t){const o=this.getTimestamp();t.length>0?console.log(`[${o}] ℹ️ ${e}`,...t):console.log(`[${o}] ℹ️ ${e}`)}success(e,...t){const o=this.getTimestamp();t.length>0?console.log(`[${o}] ✅ ${e}`,...t):console.log(`[${o}] ✅ ${e}`)}error(e,...t){const o=this.getTimestamp();t.length>0?console.error(`[${o}] ❌ ${e}`,...t):console.error(`[${o}] ❌ ${e}`)}progress(e,t=0,...o){const n=this.getTimestamp(),i=" ".repeat(t);o.length>0?console.log(`[${n}] 🔄 ${i}${e}`,...o):console.log(`[${n}] 🔄 ${i}${e}`)}progressWithCount(e,t,o,n=0,...i){const s=this.getTimestamp(),p=" ".repeat(n),l=`[${e}/${t}]`;i.length>0?console.log(`[${s}] 🔄 ${p}${l} ${o}`,...i):console.log(`[${s}] 🔄 ${p}${l} ${o}`)}}function $(r){if(!r)return!1;try{const e=new URL(r);return e.protocol==="http:"||e.protocol==="https:"}catch{return r.length>0}}async function f(r){const e=new h;process.on("SIGINT",()=>{e.error("Generation interrupted by user"),process.exit(130)}),$(r.input)||(e.error("Invalid input: must be a valid file path or HTTP/HTTPS URL"),process.exit(2));try{e.info("Starting code generation...");const t=new d.Project,o={inputPath:r.input,outputDir:r.output,project:t,logger:e};await new g.CodeGenerator(o).generate(),e.success(`Code generation completed successfully! Files generated in: ${r.output}`)}catch(t){e.error(`Error during code generation: ${t}`),process.exit(1)}}const m="2.
|
|
2
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("commander"),g=require("./index.cjs"),d=require("ts-morph");require("yaml");require("fs");require("@ahoo-wang/fetcher");require("path");class h{getTimestamp(){return new Date().toISOString().slice(11,19)}info(e,...t){const o=this.getTimestamp();t.length>0?console.log(`[${o}] ℹ️ ${e}`,...t):console.log(`[${o}] ℹ️ ${e}`)}success(e,...t){const o=this.getTimestamp();t.length>0?console.log(`[${o}] ✅ ${e}`,...t):console.log(`[${o}] ✅ ${e}`)}error(e,...t){const o=this.getTimestamp();t.length>0?console.error(`[${o}] ❌ ${e}`,...t):console.error(`[${o}] ❌ ${e}`)}progress(e,t=0,...o){const n=this.getTimestamp(),i=" ".repeat(t);o.length>0?console.log(`[${n}] 🔄 ${i}${e}`,...o):console.log(`[${n}] 🔄 ${i}${e}`)}progressWithCount(e,t,o,n=0,...i){const s=this.getTimestamp(),p=" ".repeat(n),l=`[${e}/${t}]`;i.length>0?console.log(`[${s}] 🔄 ${p}${l} ${o}`,...i):console.log(`[${s}] 🔄 ${p}${l} ${o}`)}}function $(r){if(!r)return!1;try{const e=new URL(r);return e.protocol==="http:"||e.protocol==="https:"}catch{return r.length>0}}async function f(r){const e=new h;process.on("SIGINT",()=>{e.error("Generation interrupted by user"),process.exit(130)}),$(r.input)||(e.error("Invalid input: must be a valid file path or HTTP/HTTPS URL"),process.exit(2));try{e.info("Starting code generation...");const t=new d.Project,o={inputPath:r.input,outputDir:r.output,project:t,logger:e};await new g.CodeGenerator(o).generate(),e.success(`Code generation completed successfully! Files generated in: ${r.output}`)}catch(t){e.error(`Error during code generation: ${t}`),process.exit(1)}}const m="2.3.0",T={version:m};function u(){return c.program.name("fetcher-generator").description("OpenAPI Specification TypeScript code generator for Wow").version(T.version),c.program.command("generate").description("Generate TypeScript code from OpenAPI specification").requiredOption("-i, --input <path>","Input OpenAPI specification file path or URL (http/https)").option("-o, --output <path>","Output directory path","src/generated").option("-c, --config <file>","Configuration file path").option("-v, --verbose","Enable verbose logging").option("--dry-run","Show what would be generated without writing files").action(f),c.program}function a(){u().parse()}a();exports.runCLI=a;exports.setupCLI=u;
|
|
3
3
|
//# sourceMappingURL=cli.cjs.map
|
package/dist/cli.js
CHANGED
|
@@ -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,
|
|
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;AAWtE;;;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;IAwBhB;;;OAGG;IACH,gBAAgB,CAAC,SAAS,EAAE,mBAAmB;IA0F/C,2BAA2B,CACzB,UAAU,EAAE,UAAU,EACtB,mBAAmB,EAAE,mBAAmB;IAsB1C,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;CAwFrB"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const $=require("ts-morph"),
|
|
2
|
-
`):void 0}function w(o,e,t){const n=
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const $=require("ts-morph"),U=require("yaml"),_=require("fs"),C=require("@ahoo-wang/fetcher"),I=require("path"),v=require("@ahoo-wang/fetcher-wow");function F(o){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(o){for(const t in o)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(o,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>o[t]})}}return e.default=o,Object.freeze(e)}const R=F(_),V=F(I);function f(o){return o.$ref.split("/").pop()}function N(o,e){const t=f(o);return e.schemas?.[t]}function J(o,e){const t=f(o);return e.requestBodies?.[t]}function H(o,e){const t=f(o);return e.parameters?.[t]}function P(o,e){return{key:f(o),schema:N(o,e)}}const j=/[-_\s.]+/;function W(o){return Array.isArray(o)?o.flatMap(e=>M(e.split(j))):M(o.split(j))}function M(o){return o.flatMap(e=>{if(e.length===0)return[];const t=[];let n="";for(let r=0;r<e.length;r++){const s=e[r],i=/[A-Z]/.test(s),c=r>0&&/[a-z]/.test(e[r-1]);i&&c&&n?(t.push(n),n=s):n+=s}return n&&t.push(n),t})}function x(o){return o===""||o.length===0?"":W(o).filter(t=>t.length>0).map(t=>{if(t.length===0)return"";const n=t.charAt(0),r=t.slice(1);return(/[a-zA-Z]/.test(n)?n.toUpperCase():n)+r.toLowerCase()}).join("")}function h(o){const e=x(o);return e.charAt(0).toLowerCase()+e.slice(1)}function Y(o){return o===""||Array.isArray(o)&&o.length===0?"":W(o).filter(t=>t.length>0).map(t=>t.toUpperCase()).join("_")}function X(o){return o.startsWith("http://")||o.startsWith("https://")?Z(o):ee(o)}async function Z(o){return await(await fetch(o)).text()}function ee(o){return new Promise((e,t)=>{_.readFile(o,"utf-8",(n,r)=>{n?t(n):e(r)})})}async function te(o){const e=await X(o);switch(ne(e)){case"json":return JSON.parse(e);case"yaml":return U.parse(e);default:throw new Error(`Unsupported file format: ${o}`)}}function ne(o){const e=o.trimStart();if(e.startsWith("{")||e.startsWith("["))return"json";if(e.startsWith("-")||e.startsWith("%YAML"))return"yaml";try{return JSON.parse(e),"json"}catch{if(e.length>0)return"yaml"}throw new Error("Unable to infer file format")}function g(o){return!!(o&&typeof o=="object"&&"$ref"in o)}function oe(o){return!o||g(o)||!o.content?void 0:o.content[C.ContentTypeValues.APPLICATION_JSON]?.schema}function re(o){return[{method:"get",operation:o.get},{method:"put",operation:o.put},{method:"post",operation:o.post},{method:"delete",operation:o.delete},{method:"options",operation:o.options},{method:"head",operation:o.head},{method:"patch",operation:o.patch},{method:"trace",operation:o.trace}].filter(({operation:e})=>e!==void 0)}function B(o){return o.responses[200]}function q(o){const e=B(o);return oe(e)}const se=["string","number","integer","boolean","null"];function ie(o){return Array.isArray(o)?!0:se.includes(o)}function ae(o){return o.type==="array"}function ce(o){return Array.isArray(o.enum)&&o.enum.length>0}function z(o){return Array.isArray(o.anyOf)&&o.anyOf.length>0}function k(o){return Array.isArray(o.oneOf)&&o.oneOf.length>0}function ge(o){return z(o)||k(o)}function le(o){return Array.isArray(o.allOf)&&o.allOf.length>0}function G(o){return z(o)||k(o)||le(o)}function ue(o){return o.includes("|")||o.includes("&")?`(${o})[]`:`${o}[]`}function pe(o){return o.type!=="object"?!1:o.properties?Object.keys(o.properties).length===0:!0}function b(o){if(Array.isArray(o))return o.map(e=>b(e)).join(" | ");switch(o){case"string":return"string";case"number":case"integer":return"number";case"boolean":return"boolean";case"null":return"null";default:return"any"}}const Q="types.ts",me="@";function de(o){return C.combineURLs(o.path,Q)}function T(o,e,t){const n=C.combineURLs(e,t),r=o.getSourceFile(n);return r||o.createSourceFile(n,"",{overwrite:!0})}function O(o,e,t){let n=o.getImportDeclaration(r=>r.getModuleSpecifierValue()===e);n||(n=o.addImportDeclaration({moduleSpecifier:e})),t.forEach(r=>{n.getNamedImports().some(i=>i.getName()===r)||n.addNamedImport(r)})}function y(o,e,t){if(t.path.startsWith(me)){O(o,t.path,[t.name]);return}const n=o.getDirectoryPath(),r=I.join(e,t.path,Q);let s=I.relative(n,r);s=s.replace(/\.ts$/,""),s.startsWith(".")||(s="./"+s),O(o,s,[t.name])}function E(o,e,t,n){o.path!==n.path&&y(e,t,n)}function fe(o,e){const t=[o,e].filter(n=>n!==void 0&&n.length>0);return t.length>0?t.join(`
|
|
2
|
+
`):void 0}function w(o,e,t){const n=fe(e,t);n&&o.addJsDoc({description:n})}function he(o){const e=o.split(".");return e.length!=2||e[0].length===0||e[1].length===0?null:e}function ye(o){const e=he(o.name);return e?{tag:o,contextAlias:e[0],aggregateName:e[1]}:null}function Ce(o){const e=o?.map(n=>ye(n)).filter(n=>n!==null);if(!e)return new Map;const t=new Map;return e.forEach(n=>{t.set(n.tag.name,{aggregate:n,commands:new Map,events:new Map})}),t}function Ae(o){if(!o)return null;const e=o.split(".");return e.length!=3?null:e[2]}const Pe="#/components/responses/wow.CommandOk",we="#/components/parameters/wow.id";class $e{constructor(e){this.openAPI=e,this.aggregates=Ce(e.tags),this.build()}aggregates;build(){for(const[e,t]of Object.entries(this.openAPI.paths)){const n=re(t);for(const r of n)this.commands(e,r),this.state(r.operation),this.events(r.operation),this.fields(r.operation)}}resolve(){const e=new Map;for(const t of this.aggregates.values()){if(!t.state||!t.fields)continue;const n=t.aggregate.contextAlias;let r=e.get(n);r||(r=new Set,e.set(n,r)),r.add(t)}return e}commands(e,t){const n=t.operation;if(n.operationId==="wow.command.send")return;const r=Ae(n.operationId);if(!r)return;const s=B(n);if(!s||!g(s)||s.$ref!==Pe||!n.requestBody)return;const i=n.parameters??[],c=i.filter(m=>g(m)&&m.$ref===we).at(0),a=i.filter(m=>!g(m)&&m.in==="path");if(c){const m=H(c,this.openAPI.components);a.push(m)}const p=n.requestBody.content[C.ContentTypeValues.APPLICATION_JSON].schema,l=P(p,this.openAPI.components);l.schema.title=l.schema.title||n.summary,l.schema.description=l.schema.description||n.description;const K={name:r,method:t.method,path:e,pathParameters:a,summary:n.summary,description:n.description,schema:l,operation:n};n.tags?.forEach(m=>{const D=this.aggregates.get(m);D&&D.commands.set(r,K)})}state(e){if(!e.operationId?.endsWith(".snapshot_state.single"))return;const t=q(e);if(!g(t))return;const n=P(t,this.openAPI.components);e.tags?.forEach(r=>{const s=this.aggregates.get(r);s&&(s.state=n)})}events(e){if(!this.openAPI.components||!e.operationId?.endsWith(".event.list_query"))return;const t=q(e);if(g(t))return;const n=t?.items;if(!g(n))return;const s=N(n,this.openAPI.components).properties.body.items.anyOf.map(i=>{const c=i.title,a=i.properties.name.const,u=i.properties.body,p=P(u,this.openAPI.components);return p.schema.title=p.schema.title||i.title,{title:c,name:a,schema:p}});e.tags?.forEach(i=>{const c=this.aggregates.get(i);c&&s.forEach(a=>{c.events.set(a.name,a)})})}fields(e){if(!this.openAPI.components||!e.operationId?.endsWith(".snapshot.count"))return;const n=J(e.requestBody,this.openAPI.components).content[C.ContentTypeValues.APPLICATION_JSON].schema,s=N(n,this.openAPI.components).properties?.field,i=P(s,this.openAPI.components);e.tags?.forEach(c=>{const a=this.aggregates.get(c);a&&(a.fields=i)})}}const A="@ahoo-wang/fetcher-wow",Oe={"wow.command.CommandResult":"CommandResult","wow.MessageHeaderSqlType":"MessageHeaderSqlType","wow.api.BindingError":"BindingError","wow.api.DefaultErrorInfo":"ErrorInfo","wow.api.RecoverableType":"RecoverableType","wow.api.command.DefaultDeleteAggregate":"DeleteAggregate","wow.api.command.DefaultRecoverAggregate":"RecoverAggregate","wow.api.messaging.FunctionInfoData":"FunctionInfo","wow.api.messaging.FunctionKind":"FunctionKind","wow.api.modeling.AggregateId":"AggregateId","wow.api.query.Condition":"Condition","wow.api.query.ConditionOptions":"ConditionOptions","wow.api.query.ListQuery":"ListQuery","wow.api.query.Operator":"Operator","wow.api.query.PagedQuery":"PagedQuery","wow.api.query.Pagination":"Pagination","wow.api.query.Projection":"Projection","wow.api.query.Sort":"FieldSort","wow.api.query.Sort.Direction":"SortDirection","wow.command.CommandStage":"CommandStage","wow.command.SimpleWaitSignal":"WaitSignal","wow.configuration.Aggregate":"Aggregate","wow.configuration.BoundedContext":"BoundedContext","wow.configuration.WowMetadata":"WowMetadata","wow.modeling.DomainEvent":"DomainEvent","wow.openapi.BatchResult":"BatchResult","wow.messaging.CompensationTarget":"CompensationTarget"};function d(o){if(!o)return{name:"",path:"/"};const e=Oe[o];if(e)return{name:e,path:A};const t=o.split(".");let n=-1;for(let a=0;a<t.length;a++)if(t[a]&&/^[A-Z]/.test(t[a])){n=a;break}if(n===-1)return{name:o,path:"/"};const r=t.slice(0,n),s=r.length>0?`/${r.join("/")}`:"/",i=t.slice(n);return{name:x(i),path:s}}class S{project;openAPI;outputDir;contextAggregates;logger;constructor(e){this.project=e.project,this.openAPI=e.openAPI,this.outputDir=e.outputDir,this.contextAggregates=e.contextAggregates,this.logger=e.logger}}class xe extends S{constructor(e){super(e)}getOrCreateSourceFile(e){const t=de(e);return T(this.project,this.outputDir,t)}generate(){const e=this.openAPI.components?.schemas;if(!e){this.logger.info("No schemas found in OpenAPI specification");return}const t=this.filterSchemas(e);this.logger.progress(`Generating models for ${t.length} schemas`),t.forEach((n,r)=>{this.logger.progressWithCount(r+1,t.length,`Processing schema: ${n.key}`,2),this.generateKeyedSchema(n)}),this.logger.success("Model generation completed")}filterSchemas(e){return Object.entries(e).map(([t,n])=>({key:t,schema:n})).filter(t=>!this.isWowSchema(t.key))}isWowSchema(e){return e.startsWith("wow.")}generateKeyedSchema({key:e,schema:t}){const n=d(e),r=this.getOrCreateSourceFile(n),s=this.process(n,r,t);s&&w(s,t.title,t.description)}process(e,t,n){if(ce(n))return t.addEnum({name:e.name,isExported:!0,members:n.enum.filter(s=>typeof s=="string"&&s.length>0).map(s=>({name:Y(s),initializer:`'${s}'`}))});const r=t.addInterface({name:e.name,isExported:!0});return n.type==="object"&&n.properties?this.processInterface(t,e,n,r):(G(n)&&(n.anyOf||n.oneOf||n.allOf).forEach(i=>{if(g(i)){const c=d(f(i));E(e,t,this.outputDir,c),r.addExtends(c.name);return}this.processInterface(t,e,i,r)}),r)}processObject(e,t,n){const r=e.addInterface({name:t.name,isExported:!0});return this.processInterface(e,t,n,r)}processInterface(e,t,n,r){for(const[s,i]of Object.entries(n.properties)){const c=this.resolvePropertyType(t,e,s,i);let a=r.getProperty(s);a?a.setType(c):a=r.addProperty({name:s,type:c}),g(i)||w(a,i.title,i.description)}return r}resolvePropertyType(e,t,n,r){if(g(r)){const s=d(f(r));return E(e,t,this.outputDir,s),s.name}if(r.const)return`'${r.const}'`;if(ae(r)){const s=this.resolvePropertyType(e,t,n,r.items);return ue(s)}if(r.type&&ie(r.type))return b(r.type);if(G(r))return this.resolvePropertyCompositionType(e,t,r);if(r.type==="object"&&r.properties){const s={path:e.path,name:`${e.name}${x(n)}`},i=this.processObject(t,s,r);return w(i,r.title,r.description),s.name}return"any"}resolvePropertyCompositionType(e,t,n){const r=n.anyOf||n.oneOf||n.allOf,s=new Set;r.forEach(c=>{if(g(c)){const a=d(f(c));E(e,t,this.outputDir,a),s.add(a.name);return}s.add(b(c.type??"string"))});const i=ge(n)?"|":"&";return Array.from(s).join(i)}}function Se(o){let e=0,t=0;return o.commands.forEach(n=>{n.path.startsWith(v.ResourceAttributionPathSpec.TENANT)&&(e+=1),n.path.startsWith(v.ResourceAttributionPathSpec.OWNER)&&(t+=1)}),e===0&&t===0?"ResourceAttributionPathSpec.NONE":e>t?"ResourceAttributionPathSpec.TENANT":"ResourceAttributionPathSpec.OWNER"}function L(o,e,t,n){const r=`${t.contextAlias}/${t.aggregateName}/${n}.ts`;return T(o,e,r)}function Ee(o,e){return`${x(o.aggregateName)}${e}`}class Ie extends S{constructor(e){super(e)}generate(){const e=Array.from(this.contextAggregates.values()).reduce((n,r)=>n+r.size,0);this.logger.info("--- Generating Query Clients ---"),this.logger.progress(`Generating query clients for ${e} aggregates`);let t=0;for(const[,n]of this.contextAggregates)n.forEach(r=>{t++,this.logger.progressWithCount(t,e,`Processing query client for aggregate: ${r.aggregate.aggregateName}`),this.processQueryClient(r)});this.logger.success("Query client generation completed")}createClientFilePath(e,t){return L(this.project,this.outputDir,e,t)}processQueryClient(e){const t=this.createClientFilePath(e.aggregate,"queryClient");this.logger.info(`Processing query client for aggregate: ${e.aggregate.aggregateName} in context: ${e.aggregate.contextAlias}`),this.logger.info(`Adding imports from ${A}: QueryClientFactory, QueryClientOptions, ResourceAttributionPathSpec`),t.addImportDeclaration({moduleSpecifier:A,namedImports:["QueryClientFactory","QueryClientOptions","ResourceAttributionPathSpec"]});const n="DEFAULT_QUERY_CLIENT_OPTIONS";this.logger.info(`Creating default query client options: ${n}`),t.addVariableStatement({declarationKind:$.VariableDeclarationKind.Const,declarations:[{name:n,type:"QueryClientOptions",initializer:`{
|
|
3
3
|
contextAlias: '${e.aggregate.contextAlias}',
|
|
4
4
|
aggregateName: '${e.aggregate.aggregateName}',
|
|
5
|
-
resourceAttribution: ${
|
|
6
|
-
}`}],isExported:!1});const r=[];this.logger.info(`Processing ${e.events.size} domain events for aggregate: ${e.aggregate.aggregateName}`);for(const
|
|
5
|
+
resourceAttribution: ${Se(e)},
|
|
6
|
+
}`}],isExported:!1});const r=[];this.logger.info(`Processing ${e.events.size} domain events for aggregate: ${e.aggregate.aggregateName}`);for(const p of e.events.values()){const l=d(p.schema.key);this.logger.info(`Adding import for event model: ${l.name} from path: ${l.path}`),y(t,this.outputDir,l),r.push(l)}const s="DOMAIN_EVENT_TYPES",i=r.map(p=>p.name).join(" | ");this.logger.info(`Creating domain event types union: ${s} = ${i}`),t.addTypeAlias({name:s,type:i});const c=`${h(e.aggregate.aggregateName)}QueryClientFactory`,a=d(e.state.key),u=d(e.fields.key);this.logger.info(`Adding import for state model: ${a.name} from path: ${a.path}`),y(t,this.outputDir,a),this.logger.info(`Adding import for fields model: ${u.name} from path: ${u.path}`),y(t,this.outputDir,u),this.logger.info(`Creating query client factory: ${c}`),t.addVariableStatement({declarationKind:$.VariableDeclarationKind.Const,declarations:[{name:c,initializer:`new QueryClientFactory<${a.name}, ${u.name} | string, ${s}>(${n})`}],isExported:!0}),this.logger.success(`Query client generation completed for aggregate: ${e.aggregate.aggregateName}`)}}class Ne extends S{commandEndpointPathsName="COMMAND_ENDPOINT_PATHS";defaultCommandClientOptionsName="DEFAULT_COMMAND_CLIENT_OPTIONS";constructor(e){super(e)}generate(){const e=Array.from(this.contextAggregates.values()).reduce((n,r)=>n+r.size,0);this.logger.info("--- Generating Command Clients ---"),this.logger.progress(`Generating command clients for ${e} aggregates`);let t=0;for(const[,n]of this.contextAggregates)n.forEach(r=>{t++,this.logger.progressWithCount(t,e,`Processing command client for aggregate: ${r.aggregate.aggregateName}`),this.processAggregate(r)});this.logger.success("Command client generation completed")}processAggregate(e){this.logger.info(`Processing command client for aggregate: ${e.aggregate.aggregateName} in context: ${e.aggregate.contextAlias}`);const t=L(this.project,this.outputDir,e.aggregate,"commandClient");this.logger.info(`Processing command endpoint paths for ${e.commands.size} commands`),this.processCommandEndpointPaths(t,e),this.logger.info(`Creating default command client options: ${this.defaultCommandClientOptionsName}`),t.addVariableStatement({declarationKind:$.VariableDeclarationKind.Const,declarations:[{name:this.defaultCommandClientOptionsName,type:"ApiMetadata",initializer:`{
|
|
7
7
|
basePath: '${e.aggregate.contextAlias}'
|
|
8
|
-
}`}],isExported:!1}),this.logger.info(`Adding imports from ${
|
|
8
|
+
}`}],isExported:!1}),this.logger.info(`Adding imports from ${A}: CommandRequest, CommandResult, CommandResultEventStream, DeleteAggregate, RecoverAggregate`),t.addImportDeclaration({moduleSpecifier:A,namedImports:["CommandRequest","CommandResult","CommandResultEventStream","DeleteAggregate","RecoverAggregate"],isTypeOnly:!0}),this.logger.info("Adding import from @ahoo-wang/fetcher-eventstream: JsonEventStreamResultExtractor"),t.addImportDeclaration({moduleSpecifier:"@ahoo-wang/fetcher-eventstream",namedImports:["JsonEventStreamResultExtractor"]}),this.logger.info("Adding import from @ahoo-wang/fetcher: ContentTypeValues"),O(t,"@ahoo-wang/fetcher",["ContentTypeValues"]),this.logger.info("Adding imports from @ahoo-wang/fetcher-decorator: ApiMetadata types and decorators"),O(t,"@ahoo-wang/fetcher-decorator",["type ApiMetadata","type ApiMetadataCapable","api","post","put","patch","del","request","attribute","path","autoGeneratedError"]),this.logger.info("Generating standard command client class"),this.processCommandClient(t,e),this.logger.info("Generating stream command client class"),this.processCommandClient(t,e,!0),this.logger.success(`Command client generation completed for aggregate: ${e.aggregate.aggregateName}`)}processCommandEndpointPaths(e,t){this.logger.info(`Creating command endpoint paths enum: ${this.commandEndpointPathsName}`);const n=e.addEnum({name:this.commandEndpointPathsName});t.commands.forEach(r=>{this.logger.info(`Adding command endpoint: ${r.name.toUpperCase()} = '${r.path}'`),n.addMember({name:r.name.toUpperCase(),initializer:`'${r.path}'`})}),this.logger.success(`Command endpoint paths enum created with ${t.commands.size} entries`)}getEndpointPath(e){return`${this.commandEndpointPathsName}.${e.name.toUpperCase()}`}processCommandClient(e,t,n=!1){let r="CommandClient",s={name:"api",arguments:[]},i="Promise<CommandResult>";n&&(r="Stream"+r,s={name:"api",arguments:["''",`{
|
|
9
9
|
headers: { Accept: ContentTypeValues.TEXT_EVENT_STREAM },
|
|
10
10
|
resultExtractor: JsonEventStreamResultExtractor,
|
|
11
|
-
}`]},
|
|
11
|
+
}`]},i="Promise<CommandResultEventStream>");const c=Ee(t.aggregate,r),a=e.addClass({name:c,isExported:!0,decorators:[s],implements:["ApiMetadataCapable"]});a.addConstructor({parameters:[{name:"apiMetadata",type:"ApiMetadata",scope:$.Scope.Public,isReadonly:!0,initializer:`${this.defaultCommandClientOptionsName}`}]}),t.commands.forEach(u=>{this.processCommandMethod(e,a,u,i)})}methodToDecorator(e){return e==="delete"?"del":e}processCommandMethod(e,t,n,r){const s=d(n.schema.key);this.logger.info(`Adding import for command model: ${s.name} from path: ${s.path}`),y(e,this.outputDir,s),this.logger.info(`Generating command method: ${h(n.name)} for command: ${n.name}`),this.logger.info(`Command method details: HTTP ${n.method}, path: ${n.path}, return type: ${r}`);const i=n.pathParameters.map(a=>(this.logger.info(`Adding path parameter: ${a.name} (type: string)`),{name:a.name,type:"string",hasQuestionToken:!1,decorators:[{name:"path",arguments:[`'${a.name}'`]}]}));this.logger.info(`Adding command request parameter: commandRequest (type: CommandRequest<${s.name}>)`),i.push({name:"commandRequest",hasQuestionToken:pe(n.schema.schema),type:`CommandRequest<${s.name}>`,decorators:[{name:"request",arguments:[]}]}),this.logger.info("Adding attributes parameter: attributes (type: Record<string, any>)"),i.push({name:"attributes",hasQuestionToken:!0,type:"Record<string, any>",decorators:[{name:"attribute",arguments:[]}]});const c=t.addMethod({name:h(n.name),decorators:[{name:this.methodToDecorator(n.method),arguments:[`${this.getEndpointPath(n)}`]}],parameters:i,returnType:r,statements:[`throw autoGeneratedError(${i.map(a=>a.name).join(",")});`]});(n.summary||n.description)&&this.logger.info(`Adding JSDoc documentation for method: ${h(n.name)}`),w(c,n.summary,n.description),this.logger.success(`Command method generated: ${h(n.name)}`)}}class be extends S{queryClientGenerator;commandClientGenerator;constructor(e){super(e),this.queryClientGenerator=new Ie(e),this.commandClientGenerator=new Ne(e)}generate(){this.logger.info("--- Generating Clients ---"),this.logger.progress(`Generating clients for ${this.contextAggregates.size} bounded contexts`);let e=0;for(const[t]of this.contextAggregates)e++,this.logger.progressWithCount(e,this.contextAggregates.size,`Processing bounded context: ${t}`,1),this.processBoundedContext(t);this.queryClientGenerator.generate(),this.commandClientGenerator.generate(),this.logger.success("Client generation completed")}processBoundedContext(e){const t=`${e}/boundedContext.ts`;this.logger.info(`Creating bounded context file: ${t}`);const n=T(this.project,this.outputDir,t);this.logger.info(`Adding bounded context alias constant: BOUNDED_CONTEXT_ALIAS = '${e}'`),n.addStatements(`export const BOUNDED_CONTEXT_ALIAS = '${e}';`),this.logger.success(`Bounded context file created successfully: ${t}`)}}class Te{constructor(e){this.options=e,this.project=e.project,this.options.logger.info("CodeGenerator instance created")}project;async generate(){this.options.logger.info("Starting code generation from OpenAPI specification"),this.options.logger.info(`Input path: ${this.options.inputPath}`),this.options.logger.info(`Output directory: ${this.options.outputDir}`),this.options.logger.info("Parsing OpenAPI specification");const e=await te(this.options.inputPath);this.options.logger.info("OpenAPI specification parsed successfully"),this.options.logger.info("Resolving bounded context aggregates");const n=new $e(e).resolve();this.options.logger.info(`Resolved ${n.size} bounded context aggregates`);const r={openAPI:e,project:this.project,outputDir:this.options.outputDir,contextAggregates:n,logger:this.options.logger};this.options.logger.info("Generating models"),new xe(r).generate(),this.options.logger.info("Models generated successfully"),this.options.logger.info("Generating clients"),new be(r).generate(),this.options.logger.info("Clients generated successfully"),this.options.logger.info("Generating index files"),this.generateIndex(),this.options.logger.info("Index files generated successfully"),this.options.logger.info("Optimizing source files"),this.optimizeSourceFiles(),this.options.logger.info("Source files optimized successfully"),this.options.logger.info("Saving project to disk"),await this.project.save(),this.options.logger.info("Code generation completed successfully")}generateIndex(){this.options.logger.info(`Generating index files for output directory: ${this.options.outputDir}`);const e=this.project.getDirectory(this.options.outputDir);if(!e){this.options.logger.info("Output directory not found, skipping index generation");return}this.processDirectory(e),this.options.logger.info("Index file generation completed")}processDirectory(e){const t=e.getDirectories();this.options.logger.info(`Processing ${t.length} subdirectories`);for(const n of t)this.options.logger.info(`Processing subdirectory: ${n.getPath()}`),this.generateIndexForDirectory(n),this.processDirectory(n)}generateIndexForDirectory(e){const t=e.getPath();this.options.logger.info(`Generating index for directory: ${t}`);const n=e.getSourceFiles().filter(c=>c.getBaseName().endsWith(".ts")&&c.getBaseName()!=="index.ts");let r=[];try{r=R.readdirSync(t).filter(c=>{const a=V.join(t,c);return R.statSync(a).isDirectory()})}catch(c){this.options.logger.error(`Failed to read subdirectories for ${t}: ${c}`)}if(this.options.logger.info(`Found ${n.length} TypeScript files and ${r.length} subdirectories in ${t}`),n.length===0&&r.length===0){this.options.logger.info(`No files or subdirectories to export in ${t}, skipping index generation`);return}const s=`${t}/index.ts`;this.options.logger.info(`Creating/updating index file: ${s}`);const i=this.project.getSourceFile(s)||this.project.createSourceFile(s,"",{overwrite:!0});i.removeText();for(const c of n){const a=`./${c.getBaseNameWithoutExtension()}`;this.options.logger.info(`Adding export for file: ${a}`),i.addExportDeclaration({moduleSpecifier:a,isTypeOnly:!1,namedExports:[]})}for(const c of r){const a=`./${c}`;this.options.logger.info(`Adding export for subdirectory: ${a}`),i.addExportDeclaration({moduleSpecifier:a,isTypeOnly:!1,namedExports:[]})}this.options.logger.info(`Index file generated for ${t} with ${n.length+r.length} exports`)}optimizeSourceFiles(){const e=this.project.getSourceFiles();this.options.logger.info(`Optimizing ${e.length} source files`),e.forEach((t,n)=>{this.options.logger.info(`Optimizing file ${n+1}/${e.length}`),t.formatText(),t.organizeImports(),t.fixMissingImports()}),this.options.logger.info("All source files optimized")}}exports.CodeGenerator=Te;
|
|
12
12
|
//# sourceMappingURL=index.cjs.map
|