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