@blimu/codegen 0.4.1 → 0.5.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/README.md +17 -17
- package/dist/generator/typescript/templates/auth-strategies.ts.hbs +1 -1
- package/dist/generator/typescript/templates/client.ts.hbs +2 -2
- package/dist/generator/typescript/templates/package.json.hbs +14 -13
- package/dist/generator/typescript/templates/service.ts.hbs +12 -6
- package/dist/generator/typescript/templates/tsconfig.json.hbs +2 -1
- package/dist/generator/typescript/templates/tsup.config.ts.hbs +10 -1
- package/dist/generator/typescript/templates/utils.ts.hbs +11 -6
- package/dist/index.d.mts +25 -25
- package/dist/index.d.ts +25 -25
- package/dist/index.js +3688 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3638 -7
- package/dist/index.mjs.map +1 -1
- package/dist/main.js +6 -6
- package/dist/main.js.map +1 -1
- package/package.json +10 -9
package/dist/index.js
CHANGED
|
@@ -1,10 +1,3489 @@
|
|
|
1
|
-
"use strict";var et=Object.create;var G=Object.defineProperty;var tt=Object.getOwnPropertyDescriptor;var rt=Object.getOwnPropertyNames;var nt=Object.getPrototypeOf,ot=Object.prototype.hasOwnProperty;var p=(o,e)=>G(o,"name",{value:e,configurable:!0});var st=(o,e)=>{for(var t in e)G(o,t,{get:e[t],enumerable:!0})},de=(o,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of rt(e))!ot.call(o,n)&&n!==t&&G(o,n,{get:()=>e[n],enumerable:!(r=tt(e,n))||r.enumerable});return o};var O=(o,e,t)=>(t=o!=null?et(nt(o)):{},de(e||!o||!o.__esModule?G(t,"default",{value:o,enumerable:!0}):t,o)),at=o=>de(G({},"__esModule",{value:!0}),o);var xt={};st(xt,{ClientSchema:()=>ye,ConfigModule:()=>B,ConfigSchema:()=>L,ConfigService:()=>k,GeneratorModule:()=>K,GeneratorService:()=>C,IRSchemaKind:()=>l,OpenApiModule:()=>M,OpenApiService:()=>x,PredefinedTypeSchema:()=>he,TYPESCRIPT_TEMPLATE_NAMES:()=>se,TypeScriptClientSchema:()=>ge,defineConfig:()=>pt,generate:()=>Tt,loadConfig:()=>vt,loadMjsConfig:()=>_});module.exports=at(xt);var d=require("zod"),he=d.z.object({type:d.z.string().min(1,"Type name is required"),package:d.z.string().min(1,"Package name is required"),importPath:d.z.string().optional()}),se=["client.ts.hbs","index.ts.hbs","package.json.hbs","README.md.hbs","schema.ts.hbs","schema.zod.ts.hbs","service.ts.hbs","tsconfig.json.hbs","utils.ts.hbs"],it=d.z.object({type:d.z.string().min(1,"Type is required"),outDir:d.z.string().min(1,"OutDir is required"),name:d.z.string().min(1,"Name is required"),includeTags:d.z.array(d.z.string()).optional(),excludeTags:d.z.array(d.z.string()).optional(),operationIdParser:d.z.custom().optional(),preCommand:d.z.array(d.z.string()).optional(),postCommand:d.z.array(d.z.string()).optional(),defaultBaseURL:d.z.string().optional(),exclude:d.z.array(d.z.string()).optional()}),ge=it.extend({type:d.z.literal("typescript"),packageName:d.z.string().min(1,"PackageName is required"),moduleName:d.z.string().optional(),srcDir:d.z.string().optional(),includeQueryKeys:d.z.boolean().optional(),predefinedTypes:d.z.array(he).optional(),dependencies:d.z.record(d.z.string(),d.z.string()).optional(),devDependencies:d.z.record(d.z.string(),d.z.string()).optional(),formatCode:d.z.boolean().optional(),templates:d.z.record(d.z.string(),d.z.string()).refine(o=>Object.keys(o).every(e=>se.includes(e)),{message:`Template names must be one of: ${se.join(", ")}`}).optional()}),ye=d.z.discriminatedUnion("type",[ge]),L=d.z.object({spec:d.z.string().min(1,"Spec is required"),name:d.z.string().optional(),clients:d.z.array(ye).min(1,"At least one client is required")});var ee=require("@nestjs/common"),we=O(require("fs")),T=O(require("path"));var be=require("url"),X=O(require("path"));async function _(o){try{let e=X.isAbsolute(o)?o:X.resolve(o),r=await import((0,be.pathToFileURL)(e).href),n=r.default||r;if(!n)throw new Error(`Config file must export a default export or named export: ${o}`);return L.parse(n)}catch(e){throw e instanceof Error?new Error(`Failed to load MJS config from ${o}: ${e.message}`):e}}p(_,"loadMjsConfig");function ct(o,e,t,r){var n=arguments.length,s=n<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(o,e,t,r);else for(var i=o.length-1;i>=0;i--)(a=o[i])&&(s=(n<3?a(s):n>3?a(e,t,s):a(e,t))||s);return n>3&&s&&Object.defineProperty(e,t,s),s}p(ct,"_ts_decorate");var k=class o{static{p(this,"ConfigService")}logger=new ee.Logger(o.name);DEFAULT_CONFIG_FILE="chunkflow-codegen.config.mjs";async findDefaultConfig(){let e=process.cwd(),t=T.parse(e).root;for(;e!==t;){let r=T.join(e,this.DEFAULT_CONFIG_FILE);try{return await we.promises.access(r),r}catch{}e=T.dirname(e)}return null}async load(e){try{let t=await _(e);return this.normalizePaths(t,e)}catch(t){throw t instanceof Error?new Error(`Failed to load config from ${e}: ${t.message}`):t}}normalizePaths(e,t){let r=T.dirname(T.resolve(t)),n=e.spec;this.isUrl(n)||T.isAbsolute(n)||(n=T.resolve(r,n));let s=e.clients.map(a=>{let i=a.outDir;return T.isAbsolute(i)||(i=T.resolve(r,i)),{...a,outDir:i}});return{...e,spec:n,clients:s}}isUrl(e){try{let t=new URL(e);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}}getPreCommand(e){return e.preCommand||[]}getPostCommand(e){return e.postCommand||[]}shouldExcludeFile(e,t){if(!e.exclude||e.exclude.length===0)return!1;let r;try{r=T.relative(e.outDir,t)}catch{return!1}r=T.posix.normalize(r),r==="."&&(r="");for(let n of e.exclude){let s=T.posix.normalize(n);if(r===s||s!==""&&r.startsWith(s+"/"))return!0}return!1}};k=ct([(0,ee.Injectable)()],k);var Se=require("@nestjs/common");function ft(o,e,t,r){var n=arguments.length,s=n<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(o,e,t,r);else for(var i=o.length-1;i>=0;i--)(a=o[i])&&(s=(n<3?a(s):n>3?a(e,t,s):a(e,t))||s);return n>3&&s&&Object.defineProperty(e,t,s),s}p(ft,"_ts_decorate");var B=class{static{p(this,"ConfigModule")}};B=ft([(0,Se.Module)({providers:[k],exports:[k]})],B);function pt(o){return L.parse(o)}p(pt,"defineConfig");var l=(function(o){return o.Unknown="unknown",o.String="string",o.Number="number",o.Integer="integer",o.Boolean="boolean",o.Null="null",o.Array="array",o.Object="object",o.Enum="enum",o.Ref="ref",o.OneOf="oneOf",o.AnyOf="anyOf",o.AllOf="allOf",o.Not="not",o})({});var re=require("@nestjs/common");var je=require("@nestjs/common");var ve=require("@nestjs/common");function Te(o){let e=o.openapi;return typeof e!="string"?"unknown":e.startsWith("3.1")?"3.1":e.startsWith("3.0")?"3.0":"unknown"}p(Te,"detectOpenAPIVersion");function Oe(o){return o==="3.0"||o==="3.1"}p(Oe,"isSupportedVersion");function ae(o,e){if(!(!e||typeof e!="object")){if("$ref"in e&&e.$ref){let t=e.$ref;if(t.startsWith("#/components/schemas/")){let r=t.replace("#/components/schemas/","");if(o.components?.schemas?.[r]){let n=o.components.schemas[r];return"$ref"in n?ae(o,n):n}}return}return e}}p(ae,"getSchemaFromRef");function ke(o){return o?"nullable"in o&&o.nullable===!0?!0:"type"in o&&Array.isArray(o.type)?o.type.includes("null"):!1:!1}p(ke,"isSchemaNullable");function ie(o){if(!(!o||!("type"in o)))return o.type}p(ie,"getSchemaType");function lt(o,e,t,r){var n=arguments.length,s=n<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(o,e,t,r);else for(var i=o.length-1;i>=0;i--)(a=o[i])&&(s=(n<3?a(s):n>3?a(e,t,s):a(e,t))||s);return n>3&&s&&Object.defineProperty(e,t,s),s}p(lt,"_ts_decorate");var P=class{static{p(this,"SchemaConverterService")}schemaRefToIR(e,t){if(!t)return{kind:l.Unknown,nullable:!1};if("$ref"in t&&t.$ref){let c=t.$ref;if(c.startsWith("#/components/schemas/")){let u=c.replace("#/components/schemas/","");return{kind:l.Ref,ref:u,nullable:!1}}let f=c.split("/");if(f.length>0){let u=f[f.length-1];if(u)return{kind:l.Ref,ref:u,nullable:!1}}return{kind:l.Unknown,nullable:!1}}let r=ae(e,t);if(!r)return{kind:l.Unknown,nullable:!1};let n=ke(r),s;if(r.discriminator&&(s={propertyName:r.discriminator.propertyName,mapping:r.discriminator.mapping}),r.oneOf&&r.oneOf.length>0){let c=r.oneOf.map(f=>this.schemaRefToIR(e,f));return{kind:l.OneOf,oneOf:c,nullable:n,discriminator:s}}if(r.anyOf&&r.anyOf.length>0){let c=r.anyOf.map(f=>this.schemaRefToIR(e,f));return{kind:l.AnyOf,anyOf:c,nullable:n,discriminator:s}}if(r.allOf&&r.allOf.length>0){let c=r.allOf.map(f=>this.schemaRefToIR(e,f));return{kind:l.AllOf,allOf:c,nullable:n,discriminator:s}}if(r.not){let c=this.schemaRefToIR(e,r.not);return{kind:l.Not,not:c,nullable:n,discriminator:s}}if(r.enum&&r.enum.length>0){let c=r.enum.map(u=>String(u)),f=this.inferEnumBaseKind(r);return{kind:l.Enum,enumValues:c,enumRaw:r.enum,enumBase:f,nullable:n,discriminator:s}}let a=ie(r),i=Array.isArray(a)?a.filter(c=>c!=="null")[0]:a;if(i)switch(i){case"string":return{kind:l.String,nullable:n,format:r.format,discriminator:s};case"integer":return{kind:l.Integer,nullable:n,discriminator:s};case"number":return{kind:l.Number,nullable:n,discriminator:s};case"boolean":return{kind:l.Boolean,nullable:n,discriminator:s};case"array":let c=r,f=this.schemaRefToIR(e,c.items);return{kind:l.Array,items:f,nullable:n,discriminator:s};case"object":let u=[];if(r.properties){let h=Object.keys(r.properties).sort();for(let S of h){let I=r.properties[S],N=this.schemaRefToIR(e,I),z=r.required?.includes(S)||!1;u.push({name:S,type:N,required:z,annotations:this.extractAnnotations(I)})}}let b;return r.additionalProperties&&typeof r.additionalProperties=="object"&&(b=this.schemaRefToIR(e,r.additionalProperties)),{kind:l.Object,properties:u,additionalProperties:b,nullable:n,discriminator:s}}return{kind:l.Unknown,nullable:n,discriminator:s}}extractAnnotations(e){if(!e||"$ref"in e)return{};let t=e;return{title:t.title,description:t.description,deprecated:t.deprecated,readOnly:t.readOnly,writeOnly:t.writeOnly,default:t.default,examples:t.example?Array.isArray(t.example)?t.example:[t.example]:void 0}}inferEnumBaseKind(e){let t=ie(e);if(t){let r=Array.isArray(t)?t.filter(n=>n!=="null")[0]:t;if(r)switch(r){case"string":return l.String;case"integer":return l.Integer;case"number":return l.Number;case"boolean":return l.Boolean}}if(e.enum&&e.enum.length>0){let r=e.enum[0];if(typeof r=="string")return l.String;if(typeof r=="number")return Number.isInteger(r)?l.Integer:l.Number;if(typeof r=="boolean")return l.Boolean}return l.Unknown}};P=lt([(0,ve.Injectable)()],P);function v(o){if(o=o.trim(),o==="")return"";let e=o.split(/[^A-Za-z0-9]+/).filter(r=>r!==""),t=[];for(let r of e){let n=fe(r);t.push(...n)}return t.filter(r=>r!=="").map(r=>r.charAt(0).toUpperCase()+r.slice(1).toLowerCase()).join("")}p(v,"toPascalCase");function $(o){let e=v(o);return e===""?"":e.charAt(0).toLowerCase()+e.slice(1)}p($,"toCamelCase");function Z(o){if(o=o.trim(),o==="")return"";let e=o.split(/[^A-Za-z0-9]+/).filter(r=>r!==""),t=[];for(let r of e){let n=fe(r);t.push(...n)}return t.filter(r=>r!=="").map(r=>r.toLowerCase()).join("_")}p(Z,"toSnakeCase");function xe(o){if(o=o.trim(),o==="")return"";let e=o.split(/[^A-Za-z0-9]+/).filter(r=>r!==""),t=[];for(let r of e){let n=fe(r);t.push(...n)}return t.filter(r=>r!=="").map(r=>r.toLowerCase()).join("-")}p(xe,"toKebabCase");function fe(o){if(o==="")return[];let e=[],t="",r=Array.from(o);for(let n=0;n<r.length;n++){let s=r[n],a=!1;n>0&&ce(s)&&(ce(r[n-1])?n<r.length-1&&!ce(r[n+1])&&(a=!0):a=!0),a&&t.length>0&&(e.push(t),t=""),t+=s}return t.length>0&&e.push(t),e}p(fe,"splitCamelCase");function ce(o){return o>="A"&&o<="Z"}p(ce,"isUppercase");function ut(o,e,t,r){var n=arguments.length,s=n<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(o,e,t,r);else for(var i=o.length-1;i>=0;i--)(a=o[i])&&(s=(n<3?a(s):n>3?a(e,t,s):a(e,t))||s);return n>3&&s&&Object.defineProperty(e,t,s),s}p(ut,"_ts_decorate");function Pe(o,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(o,e)}p(Pe,"_ts_metadata");var j=class{static{p(this,"IrBuilderService")}schemaConverter;constructor(e){this.schemaConverter=e}buildIR(e){let t=this.collectTags(e),r=this.collectSecuritySchemes(e),n=this.buildStructuredModels(e),s={};for(let i of t)s[i]=!0;let a=this.buildIRFromDoc(e,s);return a.securitySchemes=r,a.modelDefs=[...n,...a.modelDefs],a.openApiDocument=e,a}filterIR(e,t){let r=this.compileTagFilters(t.includeTags||[]),n=this.compileTagFilters(t.excludeTags||[]),s=[];for(let i of e.services){let c=[];for(let f of i.operations)this.shouldIncludeOperation(f.originalTags,r,n)&&c.push(f);c.length>0&&s.push({...i,operations:c})}let a={services:s,models:e.models,securitySchemes:e.securitySchemes,modelDefs:e.modelDefs,openApiDocument:e.openApiDocument};return a.modelDefs=this.filterUnusedModelDefs(a,e.modelDefs),a}detectStreamingContentType(e){let t=e.toLowerCase().split(";")[0].trim();return t==="text/event-stream"?{isStreaming:!0,format:"sse"}:t==="application/x-ndjson"||t==="application/x-jsonlines"||t==="application/jsonl"?{isStreaming:!0,format:"ndjson"}:t.includes("stream")||t.includes("chunked")?{isStreaming:!0,format:"chunked"}:{isStreaming:!1}}collectTags(e){let t=new Set;if(t.add("misc"),e.paths)for(let[r,n]of Object.entries(e.paths)){if(!n)continue;let s=[n.get,n.post,n.put,n.patch,n.delete,n.options,n.head,n.trace];for(let a of s)if(!(!a||!a.tags))for(let i of a.tags)t.add(i)}return Array.from(t).sort()}compileTagFilters(e){return e.map(t=>{try{return new RegExp(t)}catch(r){throw new Error(`Invalid tag filter pattern "${t}": ${r instanceof Error?r.message:String(r)}`)}})}shouldIncludeOperation(e,t,r){let n=t.length===0;if(t.length>0)for(let s of e){for(let a of t)if(a.test(s)){n=!0;break}if(n)break}if(!n)return!1;if(r.length>0){for(let s of e)for(let a of r)if(a.test(s))return!1}return!0}buildIRFromDoc(e,t){let r={};r.misc={tag:"misc",operations:[]};let n=[],s=new Set;if(e.components?.schemas)for(let c of Object.keys(e.components.schemas))s.add(c);let a=p((c,f,u,b)=>{r[c]||(r[c]={tag:c,operations:[]});let h=f.operationId||"",{pathParams:S,queryParams:I}=this.collectParams(e,f),{requestBody:N,extractedTypes:z}=this.extractRequestBodyWithTypes(e,f,c,h,u,s);n.push(...z);let{response:q,extractedTypes:W}=this.extractResponseWithTypes(e,f,c,h,u,s);n.push(...W);let Q=f.tags&&f.tags.length>0?[...f.tags]:["misc"];r[c].operations.push({operationID:h,method:u,path:b,tag:c,originalTags:Q,summary:f.summary||"",description:f.description||"",deprecated:f.deprecated||!1,pathParams:S,queryParams:I,requestBody:N,response:q})},"addOp");if(e.paths)for(let[c,f]of Object.entries(e.paths)){if(!f)continue;let u=[{op:f.get,method:"GET"},{op:f.post,method:"POST"},{op:f.put,method:"PUT"},{op:f.patch,method:"PATCH"},{op:f.delete,method:"DELETE"},{op:f.options,method:"OPTIONS"},{op:f.head,method:"HEAD"},{op:f.trace,method:"TRACE"}];for(let{op:b,method:h}of u){if(!b)continue;let S=this.firstAllowedTag(b.tags||[],t);S&&a(S,b,h,c)}}let i=Object.values(r);for(let c of i)c.operations.sort((f,u)=>f.path===u.path?f.method.localeCompare(u.method):f.path.localeCompare(u.path));return i.sort((c,f)=>c.tag.localeCompare(f.tag)),{services:i,models:[],securitySchemes:[],modelDefs:n}}deriveMethodName(e,t,r){if(e){let s=e.indexOf("Controller_"),a=s>=0?e.substring(s+11):e;return $(a)}let n=r.includes("{")&&r.includes("}");switch(t){case"GET":return n?"get":"list";case"POST":return"create";case"PUT":case"PATCH":return"update";case"DELETE":return"delete";default:return t.toLowerCase()}}firstAllowedTag(e,t){for(let r of e)if(t[r])return r;return e.length===0&&t.misc?"misc":""}collectSecuritySchemes(e){if(!e.components?.securitySchemes)return[];let t=Object.keys(e.components.securitySchemes).sort(),r=[];for(let n of t){let s=e.components.securitySchemes[n];if(!s||"$ref"in s)continue;let a={key:n,type:s.type};switch(s.type){case"http":a.scheme=s.scheme,a.bearerFormat=s.bearerFormat;break;case"apiKey":a.in=s.in,a.name=s.name;break;case"oauth2":case"openIdConnect":break}r.push(a)}return r}collectParams(e,t){let r=[],n=[];if(t.parameters)for(let s of t.parameters){if(!s||"$ref"in s)continue;let a=s,i=this.schemaConverter.schemaRefToIR(e,a.schema),c={name:a.name,required:a.required||!1,schema:i,description:a.description||""};a.in==="path"?r.push(c):a.in==="query"&&n.push(c)}return r.sort((s,a)=>s.name.localeCompare(a.name)),n.sort((s,a)=>s.name.localeCompare(a.name)),{pathParams:r,queryParams:n}}findMatchingComponentSchema(e,t){if(!t||!e.components?.schemas)return null;if("$ref"in t&&t.$ref){let n=t.$ref;if(n.startsWith("#/components/schemas/")){let s=n.replace("#/components/schemas/","");if(e.components.schemas[s])return s}}let r=this.schemaConverter.schemaRefToIR(e,t);for(let[n,s]of Object.entries(e.components.schemas)){let a=this.schemaConverter.schemaRefToIR(e,s);if(this.compareSchemas(r,a))return n}return null}compareSchemas(e,t){if(e.kind!==t.kind)return!1;if(e.kind===l.Ref&&t.kind===l.Ref)return e.ref===t.ref;if(e.kind===l.Object&&t.kind===l.Object){let r=e.properties||[],n=t.properties||[];if(r.length!==n.length)return!1;let s=new Map(r.map(i=>[i.name,{type:i.type,required:i.required}])),a=new Map(n.map(i=>[i.name,{type:i.type,required:i.required}]));if(s.size!==a.size)return!1;for(let[i,c]of s){let f=a.get(i);if(!f||c.required!==f.required||!this.compareSchemas(c.type,f.type))return!1}return!0}return e.kind===l.Array&&t.kind===l.Array?!e.items||!t.items?e.items===t.items:this.compareSchemas(e.items,t.items):!0}extractModelNameFromSchema(e){return e.kind===l.Ref&&e.ref?e.ref:e.kind===l.Array&&e.items&&e.items.kind===l.Ref&&e.items.ref?e.items.ref:null}generateTypeName(e,t,r,n,s,a){let i=this.extractModelNameFromSchema(e);if(i)return i;let c=this.deriveMethodName(r,n,s);return`${v(t)}${v(c)}${a}`}extractRequestBodyWithTypes(e,t,r,n,s,a){let i=[];if(!t.requestBody||"$ref"in t.requestBody)return{requestBody:null,extractedTypes:[]};let c=t.requestBody;if(c.content?.["application/json"]){let u=c.content["application/json"],b=this.schemaConverter.schemaRefToIR(e,u.schema),h=this.findMatchingComponentSchema(e,u.schema);if(h)return{requestBody:{contentType:"application/json",typeTS:"",schema:{kind:l.Ref,ref:h,nullable:!1},required:c.required||!1},extractedTypes:[]};let S=this.generateTypeName(b,r,n,s,t.path,"RequestBody");return b.kind===l.Object&&!a.has(S)?(a.add(S),i.push({name:S,schema:b,annotations:this.schemaConverter.extractAnnotations(u.schema)}),{requestBody:{contentType:"application/json",typeTS:"",schema:{kind:l.Ref,ref:S,nullable:!1},required:c.required||!1},extractedTypes:i}):{requestBody:{contentType:"application/json",typeTS:"",schema:b,required:c.required||!1},extractedTypes:[]}}return{requestBody:this.extractRequestBody(e,t),extractedTypes:[]}}extractRequestBody(e,t){if(!t.requestBody||"$ref"in t.requestBody)return null;let r=t.requestBody;if(r.content?.["application/json"]){let n=r.content["application/json"];return{contentType:"application/json",typeTS:"",schema:this.schemaConverter.schemaRefToIR(e,n.schema),required:r.required||!1}}if(r.content?.["application/x-www-form-urlencoded"]){let n=r.content["application/x-www-form-urlencoded"];return{contentType:"application/x-www-form-urlencoded",typeTS:"",schema:this.schemaConverter.schemaRefToIR(e,n.schema),required:r.required||!1}}if(r.content?.["multipart/form-data"])return{contentType:"multipart/form-data",typeTS:"",schema:{kind:"unknown",nullable:!1},required:r.required||!1};if(r.content){let n=Object.keys(r.content)[0],s=r.content[n];return{contentType:n,typeTS:"",schema:this.schemaConverter.schemaRefToIR(e,s.schema),required:r.required||!1}}return null}extractResponseWithTypes(e,t,r,n,s,a){let i=[];if(!t.responses)return{response:{typeTS:"unknown",schema:{kind:l.Unknown,nullable:!1},description:"",isStreaming:!1,contentType:""},extractedTypes:[]};let c=["200","201"];for(let u of c){let b=t.responses[u];if(b&&!("$ref"in b)){let h=b;if(h.content){for(let[q,W]of Object.entries(h.content)){let Q=this.detectStreamingContentType(q),V=this.schemaConverter.schemaRefToIR(e,W.schema);if(Q.isStreaming)return{response:{typeTS:"",schema:V,description:h.description||"",isStreaming:!0,contentType:q,streamingFormat:Q.format},extractedTypes:[]};if(q==="application/json"){let me=this.findMatchingComponentSchema(e,W.schema);if(me)return{response:{typeTS:"",schema:{kind:l.Ref,ref:me,nullable:!1},description:h.description||"",isStreaming:!1,contentType:q},extractedTypes:[]};let Y=this.generateTypeName(V,r,n,s,t.path,"Response");return V.kind===l.Object&&!a.has(Y)?(a.add(Y),i.push({name:Y,schema:V,annotations:this.schemaConverter.extractAnnotations(W.schema)}),{response:{typeTS:"",schema:{kind:l.Ref,ref:Y,nullable:!1},description:h.description||"",isStreaming:!1,contentType:q},extractedTypes:i}):{response:{typeTS:"",schema:V,description:h.description||"",isStreaming:!1,contentType:q},extractedTypes:[]}}}let S=Object.keys(h.content)[0],I=h.content[S],N=this.schemaConverter.schemaRefToIR(e,I.schema),z=this.detectStreamingContentType(S);return{response:{typeTS:"",schema:N,description:h.description||"",isStreaming:z.isStreaming,contentType:S,streamingFormat:z.format},extractedTypes:[]}}return{response:{typeTS:"void",schema:{kind:l.Unknown,nullable:!1},description:h.description||"",isStreaming:!1,contentType:""},extractedTypes:[]}}}return{response:this.extractResponse(e,t),extractedTypes:[]}}extractResponse(e,t){if(!t.responses)return{typeTS:"unknown",schema:{kind:l.Unknown,nullable:!1},description:"",isStreaming:!1,contentType:""};let r=["200","201"];for(let n of r){let s=t.responses[n];if(s&&!("$ref"in s)){let a=s;if(a.content){for(let[u,b]of Object.entries(a.content)){let h=this.detectStreamingContentType(u);if(h.isStreaming)return{typeTS:"",schema:this.schemaConverter.schemaRefToIR(e,b.schema),description:a.description||"",isStreaming:!0,contentType:u,streamingFormat:h.format}}if(a.content["application/json"]){let u=a.content["application/json"];return{typeTS:"",schema:this.schemaConverter.schemaRefToIR(e,u.schema),description:a.description||"",isStreaming:!1,contentType:"application/json"}}let i=Object.keys(a.content)[0],c=a.content[i],f=this.detectStreamingContentType(i);return{typeTS:"",schema:this.schemaConverter.schemaRefToIR(e,c.schema),description:a.description||"",isStreaming:f.isStreaming,contentType:i,streamingFormat:f.format}}return{typeTS:"void",schema:{kind:l.Unknown,nullable:!1},description:a.description||"",isStreaming:!1,contentType:""}}}for(let[n,s]of Object.entries(t.responses))if(n.length===3&&n[0]==="2"&&s&&!("$ref"in s)){let a=s;if(n==="204")return{typeTS:"void",schema:{kind:l.Unknown,nullable:!1},description:a.description||"",isStreaming:!1,contentType:""};if(a.content){for(let[u,b]of Object.entries(a.content)){let h=this.detectStreamingContentType(u);if(h.isStreaming)return{typeTS:"",schema:this.schemaConverter.schemaRefToIR(e,b.schema),description:a.description||"",isStreaming:!0,contentType:u,streamingFormat:h.format}}if(a.content["application/json"]){let u=a.content["application/json"];return{typeTS:"",schema:this.schemaConverter.schemaRefToIR(e,u.schema),description:a.description||"",isStreaming:!1,contentType:"application/json"}}let i=Object.keys(a.content)[0],c=a.content[i],f=this.detectStreamingContentType(i);return{typeTS:"",schema:this.schemaConverter.schemaRefToIR(e,c.schema),description:a.description||"",isStreaming:f.isStreaming,contentType:i,streamingFormat:f.format}}}return{typeTS:"unknown",schema:{kind:l.Unknown,nullable:!1},description:"",isStreaming:!1,contentType:""}}buildStructuredModels(e){let t=[];if(!e.components?.schemas)return t;let r=Object.keys(e.components.schemas).sort(),n=new Set;for(let s of r)n.add(s);for(let s of r){let a=e.components.schemas[s],i=this.schemaConverter.schemaRefToIR(e,a);t.push({name:s,schema:i,annotations:this.schemaConverter.extractAnnotations(a)})}return t}filterUnusedModelDefs(e,t){let r=new Map;for(let i of t)r.set(i.name,i);let n=new Set,s=new Set,a=p(i=>{if(i.kind==="ref"&&i.ref){let c=i.ref;if(n.add(c),!s.has(c)){s.add(c);let f=r.get(c);f&&a(f.schema)}}if(i.items&&a(i.items),i.additionalProperties&&a(i.additionalProperties),i.oneOf)for(let c of i.oneOf)a(c);if(i.anyOf)for(let c of i.anyOf)a(c);if(i.allOf)for(let c of i.allOf)a(c);if(i.not&&a(i.not),i.properties)for(let c of i.properties)a(c.type)},"collectRefs");for(let i of e.services)for(let c of i.operations){for(let f of c.pathParams)a(f.schema);for(let f of c.queryParams)a(f.schema);c.requestBody&&a(c.requestBody.schema),a(c.response.schema)}return t.filter(i=>n.has(i.name))}};j=ut([(0,je.Injectable)(),Pe("design:type",Function),Pe("design:paramtypes",[typeof P>"u"?Object:P])],j);var te=require("@nestjs/common"),D=O(require("@apidevtools/swagger-parser")),pe=O(require("fs")),le=O(require("path"));function mt(o,e,t,r){var n=arguments.length,s=n<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(o,e,t,r);else for(var i=o.length-1;i>=0;i--)(a=o[i])&&(s=(n<3?a(s):n>3?a(e,t,s):a(e,t))||s);return n>3&&s&&Object.defineProperty(e,t,s),s}p(mt,"_ts_decorate");var x=class o{static{p(this,"OpenApiService")}logger=new te.Logger(o.name);async loadDocument(e){try{let t=null;try{t=new URL(e)}catch{}let r;if(t&&(t.protocol==="http:"||t.protocol==="https:")){this.logger.debug(`Loading OpenAPI spec from URL: ${e}`);let s=await fetch(e,{signal:AbortSignal.timeout(1e4)});if(!s.ok)throw new Error(`Failed to fetch OpenAPI spec: HTTP ${s.status} ${s.statusText}`);let a=await s.text(),i;try{i=JSON.parse(a)}catch{throw new Error("OpenAPI spec is not valid JSON")}try{let c=await D.default.parse(i);r=await D.default.bundle(c)}catch(c){this.logger.debug(`Bundle failed: ${c instanceof Error?c.message:String(c)}`),this.logger.debug("Attempting dereference directly");try{let f=await D.default.parse(i);r=await D.default.dereference(f)}catch(f){throw f}}}else{let s=le.resolve(e);if(!pe.existsSync(s))throw new Error(`OpenAPI spec file not found: ${s}`);this.logger.debug(`Loading OpenAPI spec from file: ${s}`);try{r=await D.default.bundle(s)}catch(a){this.logger.debug(`Bundle failed: ${a instanceof Error?a.message:String(a)}`),this.logger.debug("Attempting dereference directly"),r=await D.default.dereference(s)}}let n=Te(r);if(!Oe(n))throw new Error(`Unsupported OpenAPI version: ${r.openapi}. Only versions 3.0.x and 3.1.0 are supported.`);return this.logger.log(`Detected OpenAPI version: ${n} (${r.openapi})`),r}catch(t){throw t instanceof Error?new Error(`Failed to load OpenAPI document from ${e}: ${t.message}`):t}}async validateDocument(e){try{let t=null;try{t=new URL(e)}catch{}if(t&&(t.protocol==="http:"||t.protocol==="https:"))await D.default.validate(e);else{let r=le.resolve(e);if(!pe.existsSync(r))throw new Error(`OpenAPI spec file not found: ${r}`);await D.default.validate(r)}}catch(t){throw t instanceof Error?new Error(`Invalid OpenAPI document: ${t.message}`):t}}};x=mt([(0,te.Injectable)()],x);function dt(o,e,t,r){var n=arguments.length,s=n<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(o,e,t,r);else for(var i=o.length-1;i>=0;i--)(a=o[i])&&(s=(n<3?a(s):n>3?a(e,t,s):a(e,t))||s);return n>3&&s&&Object.defineProperty(e,t,s),s}p(dt,"_ts_decorate");function Ce(o,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(o,e)}p(Ce,"_ts_metadata");var C=class o{static{p(this,"GeneratorService")}irBuilder;openApiService;logger=new re.Logger(o.name);generators=new Map;constructor(e,t){this.irBuilder=e,this.openApiService=t}register(e){this.generators.set(e.getType(),e),this.logger.debug(`Registered generator: ${e.getType()}`)}getGenerator(e){return this.generators.get(e)}getAvailableTypes(){return Array.from(this.generators.keys())}async generate(e,t){let r=this.getGenerator(t.type);if(!r)throw new Error(`Unsupported client type: ${t.type}`);let n=await this.openApiService.loadDocument(e),s=this.irBuilder.buildIR(n),a=this.irBuilder.filterIR(s,t);await r.generate(t,a)}};C=dt([(0,re.Injectable)(),Ce("design:type",Function),Ce("design:paramtypes",[typeof j>"u"?Object:j,typeof x>"u"?Object:x])],C);var Je=require("@nestjs/common");var Re=require("@nestjs/common");function ht(o,e,t,r){var n=arguments.length,s=n<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(o,e,t,r);else for(var i=o.length-1;i>=0;i--)(a=o[i])&&(s=(n<3?a(s):n>3?a(e,t,s):a(e,t))||s);return n>3&&s&&Object.defineProperty(e,t,s),s}p(ht,"_ts_decorate");var M=class{static{p(this,"OpenApiModule")}};M=ht([(0,Re.Module)({providers:[x],exports:[x]})],M);var oe=require("@nestjs/common"),w=O(require("fs")),g=O(require("path")),m=O(require("handlebars"));var y=O(require("handlebars"));function He(){y.registerHelper("pascal",o=>v(o)),y.registerHelper("camel",o=>$(o)),y.registerHelper("kebab",o=>xe(o)),y.registerHelper("snake",o=>Z(o)),y.registerHelper("serviceName",o=>v(o)+"Service"),y.registerHelper("serviceProp",o=>$(o)),y.registerHelper("fileBase",o=>Z(o).toLowerCase()),y.registerHelper("eq",(o,e)=>o===e),y.registerHelper("ne",(o,e)=>o!==e),y.registerHelper("gt",(o,e)=>o>e),y.registerHelper("lt",(o,e)=>o<e),y.registerHelper("sub",(o,e)=>o-e),y.registerHelper("len",o=>Array.isArray(o)?o.length:0),y.registerHelper("or",function(...o){let e=o[o.length-1];return e&&e.fn?o.slice(0,-1).some(t=>t)?e.fn(this):e.inverse(this):o.slice(0,-1).some(t=>t)}),y.registerHelper("and",function(...o){let e=o[o.length-1];return e&&e.fn?o.slice(0,-1).every(t=>t)?e.fn(this):e.inverse(this):o.slice(0,-1).every(t=>t)}),y.registerHelper("replace",(o,e,t)=>typeof o!="string"?o:o.replace(new RegExp(e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g"),t)),y.registerHelper("index",(o,e)=>o?.[e]),y.registerHelper("getServiceName",o=>{let e=o.split(".");return e.length>1?e[1]:o}),y.registerHelper("groupByNamespace",o=>{let e={};for(let t of o){let r=t.tag.split(".");if(r.length===1)e[""]||(e[""]=[]),e[""].push(t);else{let n=r[0];e[n]||(e[n]=[]),e[n].push(t)}}return e}),y.registerHelper("getRootServices",o=>o.filter(e=>!e.tag.includes("."))),y.registerHelper("dict",()=>({})),y.registerHelper("setVar",(o,e,t)=>(t&&t.data&&t.data.root&&(t.data.root[`_${o}`]=e),"")),y.registerHelper("getVar",(o,e)=>e&&e.data&&e.data.root&&e.data.root[`_${o}`]||!1),y.registerHelper("set",(o,e,t)=>(o&&typeof o=="object"&&(o[e]=t),"")),y.registerHelper("hasKey",(o,e)=>o&&typeof o=="object"&&e in o),y.registerHelper("lookup",(o,e)=>o&&typeof o=="object"?o[e]:void 0),y.registerHelper("reMatch",(o,e)=>{try{return new RegExp(o).test(e)}catch{return!1}})}p(He,"registerCommonHandlebarsHelpers");function gt(o){return o.replace(/"/g,'"').replace(/</g,"<").replace(/>/g,">").replace(/`/g,"`").replace(/`/g,"`").replace(/&/g,"&")}p(gt,"decodeHtmlEntities");function R(o,e,t,r=!1){let n;switch(o.kind){case l.String:o.format==="binary"?n="Blob":n="string";break;case l.Number:case l.Integer:n="number";break;case l.Boolean:n="boolean";break;case l.Null:n="null";break;case l.Ref:o.ref?e?.some(s=>s.type===o.ref)||r&&t&&t.find(a=>a.name===o.ref)?n=o.ref:n="Schema."+o.ref:n="unknown";break;case l.Array:if(o.items){let s=R(o.items,e,t);s.includes(" | ")||s.includes(" & ")?n=`Array<(${s})>`:n=`Array<${s}>`}else n="Array<unknown>";break;case l.OneOf:o.oneOf?n=o.oneOf.map(a=>R(a,e,t)).join(" | "):n="unknown";break;case l.AnyOf:o.anyOf?n=o.anyOf.map(a=>R(a,e,t)).join(" | "):n="unknown";break;case l.AllOf:o.allOf?n=o.allOf.map(a=>R(a,e,t)).join(" & "):n="unknown";break;case l.Enum:if(o.enumValues&&o.enumValues.length>0){let s=[];switch(o.enumBase){case l.Number:case l.Integer:for(let a of o.enumValues)s.push(a);break;case l.Boolean:for(let a of o.enumValues)a==="true"||a==="false"?s.push(a):s.push(`"${a}"`);break;default:for(let a of o.enumValues)s.push(`"${a}"`)}n=s.join(" | ")}else n="unknown";break;case l.Object:if(!o.properties||o.properties.length===0)n="Record<string, unknown>";else{let s=[];for(let a of o.properties){let i=R(a.type,e,t,r);a.required?s.push(`${a.name}: ${i}`):s.push(`${a.name}?: ${i}`)}n="{ "+s.join("; ")+" }"}break;default:n="unknown"}return o.nullable&&n!=="null"&&(n+=" | null"),gt(n)}p(R,"schemaToTSType");function U(o){let e=o.path,t=e.includes("{")&&e.includes("}");if(o.operationID)return $(o.operationID);switch(o.method){case"GET":return t?"get":"list";case"POST":return"create";case"PUT":case"PATCH":return"update";case"DELETE":return"delete";default:return o.method.toLowerCase()}}p(U,"deriveMethodName");async function De(o,e){if(o.operationIdParser)try{let r=await o.operationIdParser(e.operationID,e.method,e.path);if(r)return $(r)}catch{}let t=yt(e.operationID);return t?$(t):U(e)}p(De,"resolveMethodName");function yt(o){if(!o)return"";let e=o.indexOf("Controller_");return e>=0?o.substring(e+11):o}p(yt,"defaultParseOperationID");function Ae(o){let e=o.path,t="`";for(let r=0;r<e.length;r++){if(e[r]==="{"){let n=r+1;for(;n<e.length&&e[n]!=="}";)n++;if(n<e.length){let s=e.substring(r+1,n);t+=`\${encodeURIComponent(${s})}`,r=n;continue}}t+=e[r]}return t+="`",t}p(Ae,"buildPathTemplate");function Ie(o){let t=o.path.split("/"),r=[];for(let s of t)s!==""&&(s.startsWith("{")&&s.endsWith("}")||r.push(s));return`'${r.join("/")}'`}p(Ie,"buildQueryKeyBase");function ne(o){let e=[],t=new Map;for(let n=0;n<o.pathParams.length;n++)t.set(o.pathParams[n].name,n);let r=o.path;for(let n=0;n<r.length;n++)if(r[n]==="{"){let s=n+1;for(;s<r.length&&r[s]!=="}";)s++;if(s<r.length){let a=r.substring(n+1,s),i=t.get(a);i!==void 0&&e.push(o.pathParams[i]),n=s;continue}}return e}p(ne,"orderPathParams");function $e(o,e,t,r=!1){return R(o,t,e,r)}p($e,"schemaToTSTypeWithSimpleTypes");function ue(o,e,t,r,n=!1){let s=[];for(let a of ne(o))s.push(`${a.name}: ${$e(a.schema,t,r,n)}`);if(o.queryParams.length>0){let a=v(o.tag)+v(e)+"Query";s.push(`query?: Schema.${a}`)}if(o.requestBody){let a=o.requestBody.required===!0?"":"?";s.push(`body${a}: ${$e(o.requestBody.schema,t,r,n)}`)}return s.push('init?: Omit<RequestInit, "method" | "body">'),s}p(ue,"buildMethodSignature");function qe(o,e){if(!e||e.length===0)return[];let t=new Set,r=p(s=>{let a=o.find(i=>i.name===s);return a?a.schema:null},"resolveRef"),n=p(s=>{if(s.kind==="ref"&&s.ref)if(e.some(i=>i.type===s.ref))t.add(s.ref);else{let i=r(s.ref);i&&n(i)}else if(s.kind==="array"&&s.items)n(s.items);else if(s.kind==="object"&&s.properties)for(let a of s.properties)n(a.type);else if(s.kind==="oneOf"&&s.oneOf)for(let a of s.oneOf)n(a);else if(s.kind==="anyOf"&&s.anyOf)for(let a of s.anyOf)n(a);else if(s.kind==="allOf"&&s.allOf)for(let a of s.allOf)n(a)},"checkSchema");for(let s of o)n(s.schema);return e.filter(s=>t.has(s.type))}p(qe,"collectPredefinedTypesUsedInSchema");function Ee(o,e,t){if(!e||e.length===0)return[];let r=new Set,n=p(a=>{if(!t)return null;let i=t.find(c=>c.name===a);return i?i.schema:null},"resolveRef"),s=p(a=>{if(a.kind==="ref"&&a.ref)if(e.some(c=>c.type===a.ref))r.add(a.ref);else{let c=n(a.ref);c&&s(c)}else if(a.kind==="array"&&a.items)s(a.items);else if(a.kind==="object"&&a.properties)for(let i of a.properties)s(i.type);else if(a.kind==="oneOf"&&a.oneOf)for(let i of a.oneOf)s(i);else if(a.kind==="anyOf"&&a.anyOf)for(let i of a.anyOf)s(i);else if(a.kind==="allOf"&&a.allOf)for(let i of a.allOf)s(i)},"checkSchema");for(let a of o.operations)for(let i of a.pathParams)s(i.schema);return e.filter(a=>r.has(a.type))}p(Ee,"collectPredefinedTypesUsedInService");function Fe(o){let e=[];for(let t of ne(o))e.push(t.name);return o.queryParams.length>0&&e.push("query"),o.requestBody&&e.push("body"),e}p(Fe,"queryKeyArgs");function J(o){let e=!1;for(let t of o)if(!(t>="a"&&t<="z"||t>="A"&&t<="Z"||t>="0"&&t<="9"||t==="_"||t==="$")){e=!0;break}return o.length>0&&o[0]>="0"&&o[0]<="9"&&(e=!0),e?`"${o}"`:o}p(J,"quoteTSPropertyName");function E(o,e=new Set){let t=new Set;if(o.kind==="ref"&&o.ref){let r=o.ref;e.has(r)||(e.add(r),t.add(r))}else if(o.kind==="array"&&o.items)E(o.items,e).forEach(n=>t.add(n));else if(o.kind==="object"&&o.properties){for(let r of o.properties)E(r.type,e).forEach(s=>t.add(s));o.additionalProperties&&E(o.additionalProperties,e).forEach(n=>t.add(n))}else if(o.kind==="oneOf"&&o.oneOf)for(let r of o.oneOf)E(r,e).forEach(s=>t.add(s));else if(o.kind==="anyOf"&&o.anyOf)for(let r of o.anyOf)E(r,e).forEach(s=>t.add(s));else if(o.kind==="allOf"&&o.allOf)for(let r of o.allOf)E(r,e).forEach(s=>t.add(s));else o.kind==="not"&&o.not&&E(o.not,e).forEach(n=>t.add(n));return t}p(E,"extractRefDependencies");function Ne(o){let e=new Map;for(let a of o)e.set(a.name,a);let t=new Map;for(let a of o){let i=E(a.schema),c=new Set;for(let f of i)e.has(f)&&c.add(f);t.set(a.name,c)}let r=[],n=new Map,s=[];for(let a of o)n.set(a.name,t.get(a.name)?.size||0),n.get(a.name)===0&&s.push(a.name);for(;s.length>0;){let a=s.shift(),i=e.get(a);i&&r.push(i);for(let c of o)if(t.get(c.name)?.has(a)){let u=(n.get(c.name)||0)-1;n.set(c.name,u),u===0&&s.push(c.name)}}if(r.length<o.length){let a=new Set(r.map(i=>i.name));for(let i of o)a.has(i.name)||r.push(i)}return r}p(Ne,"sortModelDefsByDependencies");function Be(o){return o.response.isStreaming===!0}p(Be,"isStreamingOperation");function Me(o){let e=o.response.schema;return e.kind===l.Array&&e.items?R(e.items):o.response.streamingFormat==="sse"?"string":R(e)}p(Me,"getStreamingItemType");function A(o,e="",t,r=!1){let n=e+" ",s;switch(o.kind){case l.String:s="z.string()",o.format==="date"||o.format==="date-time"?s="z.iso.datetime()":o.format==="email"?s="z.email()":o.format==="uri"||o.format==="url"?s="z.url()":o.format==="uuid"&&(s="z.uuid()");break;case l.Number:s="z.number()";break;case l.Integer:s="z.number().int()";break;case l.Boolean:s="z.boolean()";break;case l.Null:s="z.null()";break;case l.Ref:o.ref?s=r?`${o.ref}Schema`:`Schema.${o.ref}Schema`:s="z.unknown()";break;case l.Array:o.items?s=`${A(o.items,n,t,r)}.array()`:s="z.unknown().array()";break;case l.Object:if(!o.properties||o.properties.length===0)o.additionalProperties?s=`z.record(z.string(), ${A(o.additionalProperties,n,t,r)})`:s="z.record(z.string(), z.unknown())";else{let a=[];for(let c of o.properties){let f=A(c.type,n,t,r),u=J(c.name);c.required?a.push(`${n}${u}: ${f}`):a.push(`${n}${u}: ${f}.optional()`)}let i=`z.object({
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
${e}})`;if(o.additionalProperties){let c=A(o.additionalProperties,n,t,r);s=`${i}.catchall(${c})`}else s=i}break;case l.Enum:o.enumValues&&o.enumValues.length>0?s=`z.enum([${o.enumValues.map(i=>i==="true"||i==="false"||/^-?[0-9]+(\.[0-9]+)?$/.test(i)?i:JSON.stringify(i)).join(", ")}])`:s="z.string()";break;case l.OneOf:o.oneOf&&o.oneOf.length>0?s=`z.union([${o.oneOf.map(i=>A(i,n,t,r)).join(", ")}])`:s="z.unknown()";break;case l.AnyOf:o.anyOf&&o.anyOf.length>0?s=`z.union([${o.anyOf.map(i=>A(i,n,t,r)).join(", ")}])`:s="z.unknown()";break;case l.AllOf:if(o.allOf&&o.allOf.length>0){let a=o.allOf.map(i=>A(i,n,t,r));s=a.join(".and(")+")".repeat(a.length-1)}else s="z.unknown()";break;default:s="z.unknown()"}return o.nullable&&s!=="z.null()"&&(s=`${s}.nullable()`),s}p(A,"schemaToZodSchema");var _e=require("child_process"),Ue=require("util"),We=O(require("path")),Ve=O(require("fs"));var ze=(0,Ue.promisify)(_e.exec);async function Ge(o,e,t){let r=t||console;try{try{await ze("npx --yes prettier --version",{cwd:o,maxBuffer:10*1024*1024})}catch{r.warn?.("Prettier is not available. Skipping code formatting. Install prettier to enable formatting.");return}let n=[];for(let c of e)if(c.endsWith(".ts")||c.endsWith(".tsx")){let f=We.join(o,c);Ve.existsSync(f)&&n.push(c)}if(n.length===0){r.debug?.("No TypeScript files to format.");return}let s=n.map(c=>`"${c.replace(/\\/g,"/")}"`).join(" "),{stdout:a,stderr:i}=await ze(`npx --yes prettier --write --log-level=error ${s}`,{cwd:o,maxBuffer:10*1024*1024});i&&!i.includes("warning")&&r.warn?.(i)}catch(n){let s=n instanceof Error?n.message:String(n);r.warn?.(`Failed to format code with Prettier: ${s}. Generated code will not be formatted.`)}}p(Ge,"formatWithPrettier");function bt(o,e,t,r){var n=arguments.length,s=n<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(o,e,t,r);else for(var i=o.length-1;i>=0;i--)(a=o[i])&&(s=(n<3?a(s):n>3?a(e,t,s):a(e,t))||s);return n>3&&s&&Object.defineProperty(e,t,s),s}p(bt,"_ts_decorate");function Le(o,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(o,e)}p(Le,"_ts_metadata");var H=class o{static{p(this,"TypeScriptGeneratorService")}configService;logger=new oe.Logger(o.name);constructor(e){this.configService=e}getType(){return"typescript"}async generate(e,t){if(!e.defaultBaseURL&&t.openApiDocument?.servers){let f=t.openApiDocument.servers;Array.isArray(f)&&f.length>0&&(e.defaultBaseURL=f[0].url||"")}e.srcDir||(e.srcDir="src");let r=e.srcDir,n=g.join(e.outDir,r),s=g.join(n,"services");await w.promises.mkdir(s,{recursive:!0});let a=await this.preprocessIR(e,t);this.registerHandlebarsHelpers(e);let i=[];i.push(...await this.generateClient(e,a,n)),i.push(...await this.generateAuthStrategies(e,a,n)),i.push(...await this.generateIndex(e,a,n)),i.push(...await this.generateUtils(e,a,n)),i.push(...await this.generateServices(e,a,s)),i.push(...await this.generateSchema(e,a,n)),i.push(...await this.generateZodSchema(e,a,n)),await this.generatePackageJson(e),await this.generateTsConfig(e),i.push(...await this.generateTsupConfig(e)),await this.generateReadme(e,a),e.formatCode!==!1?(await this.generatePrettierConfig(e),this.logger.debug("Formatting generated TypeScript files with Prettier..."),await Ge(e.outDir,i,this.logger)):this.logger.debug("Code formatting is disabled for this client.")}async preprocessIR(e,t){let r=await Promise.all(t.services.map(async n=>({...n,operations:await Promise.all(n.operations.map(async s=>{let a=await De(e,s);return{...s,_resolvedMethodName:a}}))})));return{...t,services:r}}registerHandlebarsHelpers(e){He(),m.registerHelper("methodName",t=>t._resolvedMethodName||U(t)),m.registerHelper("queryTypeName",t=>{let r=t._resolvedMethodName||U(t);return v(t.tag)+v(r)+"Query"}),m.registerHelper("pathTemplate",t=>{let r=Ae(t);return new m.SafeString(r)}),m.registerHelper("queryKeyBase",t=>{let r=Ie(t);return new m.SafeString(r)}),m.registerHelper("pathParamsInOrder",t=>ne(t)),m.registerHelper("methodSignature",(t,r)=>{let n=t._resolvedMethodName||U(t),s=r?.data?.root?.IR?.modelDefs||[],a=r?.data?.root?.PredefinedTypes||[],i=r?.data?.root?.isSameFile||!1;return ue(t,n,s,a,i).map(f=>new m.SafeString(f))}),m.registerHelper("methodSignatureNoInit",(t,r)=>{let n=t._resolvedMethodName||U(t),s=r?.data?.root?.IR?.modelDefs||[],a=r?.data?.root?.PredefinedTypes||[],i=r?.data?.root?.isSameFile||!1;return ue(t,n,s,a,i).slice(0,-1)}),m.registerHelper("queryKeyArgs",t=>Fe(t).map(n=>new m.SafeString(n))),m.registerHelper("tsType",(t,r)=>{if(t&&typeof t=="object"&&"kind"in t){let n=r?.data?.root?.PredefinedTypes||[],s=r?.data?.root?.IR?.modelDefs||[],a=r?.data?.root?.isSameFile||!1;return R(t,n,s,a)}return"unknown"}),m.registerHelper("stripSchemaNs",t=>t.replace(/^Schema\./,"")),m.registerHelper("tsTypeStripNs",(t,r)=>{let n=r?.data?.root?.PredefinedTypes||[],s=r?.data?.root?.IR?.modelDefs||[],a=r?.data?.root?.isSameFile||!1;if(t&&typeof t=="object"&&"kind"in t){let c=R(t,n,s,a).replace(/Schema\./g,"");return new m.SafeString(c)}if(typeof t=="string"){if(t.startsWith("Schema.")){let i=t.replace(/^Schema\./,"");return n.find(f=>f.type===i)?new m.SafeString(i):new m.SafeString(i)}return new m.SafeString(t)}return"unknown"}),m.registerHelper("isPredefinedType",(t,r)=>(r?.data?.root?.PredefinedTypes||[]).some(s=>s.type===t)),m.registerHelper("getPredefinedType",(t,r)=>(r?.data?.root?.PredefinedTypes||[]).find(s=>s.type===t)),m.registerHelper("groupByPackage",t=>{let r={};for(let n of t||[])r[n.package]||(r[n.package]={package:n.package,types:[]}),r[n.package].types.push(n.type);return Object.values(r)}),m.registerHelper("getServicePredefinedTypes",(t,r)=>{let n=r?.data?.root?.PredefinedTypes||[],s=r?.data?.root?.IR?.modelDefs||[];return Ee(t,n,s)}),m.registerHelper("getSchemaPredefinedTypes",t=>{let r=t?.data?.root?.PredefinedTypes||[],n=t?.data?.root?.IR?.modelDefs||[];return qe(n,r)}),m.registerHelper("joinTypes",t=>t.join(", ")),m.registerHelper("uniquePackages",t=>{let r=new Set;for(let n of t||[])n.package&&r.add(n.package);return Array.from(r)}),m.registerHelper("isPredefinedPackage",(t,r)=>r?r.some(n=>n.package===t):!1),m.registerHelper("getAllDependencies",t=>{let r={"@blimu/fetch":"^0.2.0",zod:"^4.3.5"};if(t.predefinedTypes)for(let n of t.predefinedTypes)n.package&&!r[n.package]&&(r[n.package]=t.dependencies?.[n.package]||"*");if(t.dependencies)for(let[n,s]of Object.entries(t.dependencies))n!=="zod"&&!r[n]&&(r[n]=s);return r}),m.registerHelper("decodeHtml",t=>{if(typeof t!="string")return t;let r=t.replace(/&#x60;/g,"`").replace(/&#96;/g,"`").replace(/&quot;/g,""").replace(/&lt;/g,"<").replace(/&gt;/g,">");return r=r.replace(/"/g,'"').replace(/</g,"<").replace(/>/g,">").replace(/`/g,"`").replace(/`/g,"`").replace(/&/g,"&"),new m.SafeString(r)}),m.registerHelper("quotePropName",t=>J(t)),m.registerHelper("zodSchema",(t,r)=>{if(t&&typeof t=="object"&&"kind"in t){let n=r?.data?.root?.IR?.modelDefs||[],s=r?.data?.root?._templateName==="schema.zod.ts.hbs";return new m.SafeString(A(t,"",n,s))}return"z.unknown()"}),m.registerHelper("isStreaming",t=>Be(t)),m.registerHelper("hasBearerScheme",t=>Array.isArray(t)?t.some(r=>r.type==="http"&&r.scheme==="bearer"):!1),m.registerHelper("hasApiKeyScheme",t=>Array.isArray(t)?t.some(r=>r.type==="apiKey"):!1),m.registerHelper("serviceUsesSchema",t=>!t||!t.operations||!Array.isArray(t.operations)?!1:t.operations.some(r=>{if(r.response?.schema){let n=r.response.schema;if(n.kind==="ref"||n.kind==="object"||n.kind==="array"||n.kind==="oneOf"||n.kind==="anyOf"||n.kind==="allOf")return!0}if(r.requestBody?.schema){let n=r.requestBody.schema;if(n.kind==="ref"||n.kind==="object"||n.kind==="array"||n.kind==="oneOf"||n.kind==="anyOf"||n.kind==="allOf")return!0}return!!(r.queryParams&&r.queryParams.length>0)})),m.registerHelper("streamingItemType",t=>new m.SafeString(Me(t)))}async renderTemplate(e,t,r,n){let s=n.templates?.[e];if(s){this.logger.debug(`Using template override for ${e}: ${s}`);try{await w.promises.access(s,w.constants.R_OK);let h=await w.promises.readFile(s,"utf-8"),S=m.compile(h),I={...t,_templateName:e},N=S(I);await w.promises.writeFile(r,N,"utf-8");return}catch(h){let S=h instanceof Error?h.message:String(h);throw this.logger.error(`Template override file not found or not readable: ${s}. Error: ${S}`),new Error(`Template override file not found or not readable: ${s}`)}}let a=[g.join(__dirname,"generator/typescript/templates",e),g.join(__dirname,"templates",e),g.join(__dirname,"../typescript/templates",e),g.join(process.cwd(),"src/generator/typescript/templates",e)],i=null;for(let h of a)try{await w.promises.access(h),i=h;break}catch{this.logger.debug(`Template not found at: ${h}`)}if(!i)throw this.logger.error(`Template not found: ${e}`),this.logger.error(`Checked paths: ${a.join(", ")}`),this.logger.error(`__dirname: ${__dirname}`),new Error(`Template not found: ${e}`);let c=await w.promises.readFile(i,"utf-8"),f=m.compile(c),u={...t,_templateName:e},b=f(u);await w.promises.writeFile(r,b,"utf-8")}async generateClient(e,t,r){let n=g.join(r,"client.ts");if(this.configService.shouldExcludeFile(e,n))return[];try{return await this.renderTemplate("client.ts.hbs",{Client:e,IR:t},n,e),[g.relative(e.outDir,n)]}catch(s){let a=s instanceof Error?s.message:String(s);return this.logger.warn(`Template client.ts.hbs not found: ${a}, using placeholder`),await w.promises.writeFile(n,"// Generated client - template rendering to be implemented","utf-8"),[g.relative(e.outDir,n)]}}async generateAuthStrategies(e,t,r){let n=g.join(r,"auth-strategies.ts");if(this.configService.shouldExcludeFile(e,n))return[];try{return await this.renderTemplate("auth-strategies.ts.hbs",{Client:e,IR:t},n,e),[g.relative(e.outDir,n)]}catch{return this.logger.warn("Template auth-strategies.ts.hbs not found, using placeholder"),await w.promises.writeFile(n,"// Generated auth-strategies - template rendering to be implemented","utf-8"),[g.relative(e.outDir,n)]}}async generateIndex(e,t,r){let n=g.join(r,"index.ts");if(this.configService.shouldExcludeFile(e,n))return[];try{return await w.promises.access(n),this.logger.debug(`index.ts already exists at ${n}, skipping generation to preserve customizations`),[]}catch{}try{return await this.renderTemplate("index.ts.hbs",{Client:e,IR:t},n,e),[g.relative(e.outDir,n)]}catch{return this.logger.warn("Template index.ts.hbs not found, using placeholder"),await w.promises.writeFile(n,"// Generated index - template rendering to be implemented","utf-8"),[g.relative(e.outDir,n)]}}async generateUtils(e,t,r){let n=g.join(r,"utils.ts");if(this.configService.shouldExcludeFile(e,n))return[];try{return await this.renderTemplate("utils.ts.hbs",{Client:e,IR:t},n,e),[g.relative(e.outDir,n)]}catch{return this.logger.warn("Template utils.ts.hbs not found, using placeholder"),await w.promises.writeFile(n,"// Generated utils - template rendering to be implemented","utf-8"),[g.relative(e.outDir,n)]}}async generateServices(e,t,r){let n=[];for(let s of t.services){let a=g.join(r,`${Z(s.tag).toLowerCase()}.ts`);if(!this.configService.shouldExcludeFile(e,a))try{await this.renderTemplate("service.ts.hbs",{Client:e,Service:s,IR:t,PredefinedTypes:e.predefinedTypes||[],isSameFile:!1},a,e),n.push(g.relative(e.outDir,a))}catch{this.logger.warn("Template service.ts.hbs not found, using placeholder");let c=`// Generated service ${s.tag} - template rendering to be implemented`;await w.promises.writeFile(a,c,"utf-8"),n.push(g.relative(e.outDir,a))}}return n}async generateSchema(e,t,r){let n=g.join(r,"schema.ts");if(this.configService.shouldExcludeFile(e,n))return[];try{return await this.renderTemplate("schema.ts.hbs",{Client:e,IR:t,PredefinedTypes:e.predefinedTypes||[],isSameFile:!0},n,e),[g.relative(e.outDir,n)]}catch(s){let a=s instanceof Error?s.message:String(s);return this.logger.warn(`Template schema.ts.hbs error: ${a}, using placeholder`),await w.promises.writeFile(n,"// Generated schema - template rendering to be implemented","utf-8"),[g.relative(e.outDir,n)]}}async generateZodSchema(e,t,r){let n=g.join(r,"schema.zod.ts");if(this.configService.shouldExcludeFile(e,n))return[];try{let s=Ne(t.modelDefs),a={...t,modelDefs:s};return await this.renderTemplate("schema.zod.ts.hbs",{Client:e,IR:a},n,e),[g.relative(e.outDir,n)]}catch(s){let a=s instanceof Error?s.message:String(s);return this.logger.warn(`Template schema.zod.ts.hbs error: ${a}, using placeholder`),await w.promises.writeFile(n,"// Generated Zod schemas - template rendering to be implemented","utf-8"),[g.relative(e.outDir,n)]}}async generatePackageJson(e){let t=g.join(e.outDir,"package.json");if(!this.configService.shouldExcludeFile(e,t))try{await this.renderTemplate("package.json.hbs",{Client:e},t,e)}catch{this.logger.warn("Template package.json.hbs not found, using fallback");let n=JSON.stringify({name:e.packageName,version:"0.0.1",main:"dist/index.js",types:"dist/index.d.ts"},null,2);await w.promises.writeFile(t,n,"utf-8")}}async generateTsConfig(e){let t=g.join(e.outDir,"tsconfig.json");if(!this.configService.shouldExcludeFile(e,t))try{await this.renderTemplate("tsconfig.json.hbs",{Client:e},t,e)}catch{this.logger.warn("Template tsconfig.json.hbs not found, using fallback");let n=e.srcDir||"src",s=JSON.stringify({compilerOptions:{target:"ES2020",module:"commonjs",lib:["ES2020"],declaration:!0,outDir:"./dist",rootDir:`./${n}`,strict:!0,esModuleInterop:!0,skipLibCheck:!0,forceConsistentCasingInFileNames:!0},include:[`${n}/**/*`]},null,2);await w.promises.writeFile(t,s,"utf-8")}}async generateTsupConfig(e){let t=g.join(e.outDir,"tsup.config.ts");if(this.configService.shouldExcludeFile(e,t))return[];try{await this.renderTemplate("tsup.config.ts.hbs",{Client:e},t,e)}catch{this.logger.warn("Template tsup.config.ts.hbs not found, using fallback");let s=`import { defineConfig } from "tsup";
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var index_exports = {};
|
|
33
|
+
__export(index_exports, {
|
|
34
|
+
ClientSchema: () => ClientSchema,
|
|
35
|
+
ConfigModule: () => ConfigModule,
|
|
36
|
+
ConfigSchema: () => ConfigSchema,
|
|
37
|
+
ConfigService: () => ConfigService,
|
|
38
|
+
GeneratorModule: () => GeneratorModule,
|
|
39
|
+
GeneratorService: () => GeneratorService,
|
|
40
|
+
IRSchemaKind: () => IRSchemaKind,
|
|
41
|
+
OpenApiModule: () => OpenApiModule,
|
|
42
|
+
OpenApiService: () => OpenApiService,
|
|
43
|
+
PredefinedTypeSchema: () => PredefinedTypeSchema,
|
|
44
|
+
TYPESCRIPT_TEMPLATE_NAMES: () => TYPESCRIPT_TEMPLATE_NAMES,
|
|
45
|
+
TypeScriptClientSchema: () => TypeScriptClientSchema,
|
|
46
|
+
defineConfig: () => defineConfig,
|
|
47
|
+
generate: () => generate,
|
|
48
|
+
loadConfig: () => loadConfig,
|
|
49
|
+
loadMjsConfig: () => loadMjsConfig
|
|
50
|
+
});
|
|
51
|
+
module.exports = __toCommonJS(index_exports);
|
|
52
|
+
|
|
53
|
+
// src/config/config.schema.ts
|
|
54
|
+
var import_zod = require("zod");
|
|
55
|
+
var PredefinedTypeSchema = import_zod.z.object({
|
|
56
|
+
// Component schema name (e.g., "ResourceType")
|
|
57
|
+
type: import_zod.z.string().min(1, "Type name is required"),
|
|
58
|
+
// Package name (e.g., "@blimu/types")
|
|
59
|
+
package: import_zod.z.string().min(1, "Package name is required"),
|
|
60
|
+
// Optional import path (defaults to package root)
|
|
61
|
+
importPath: import_zod.z.string().optional()
|
|
62
|
+
});
|
|
63
|
+
var TYPESCRIPT_TEMPLATE_NAMES = [
|
|
64
|
+
"client.ts.hbs",
|
|
65
|
+
"index.ts.hbs",
|
|
66
|
+
"package.json.hbs",
|
|
67
|
+
"README.md.hbs",
|
|
68
|
+
"schema.ts.hbs",
|
|
69
|
+
"schema.zod.ts.hbs",
|
|
70
|
+
"service.ts.hbs",
|
|
71
|
+
"tsconfig.json.hbs",
|
|
72
|
+
"utils.ts.hbs"
|
|
73
|
+
];
|
|
74
|
+
var BaseClientSchema = import_zod.z.object({
|
|
75
|
+
type: import_zod.z.string().min(1, "Type is required"),
|
|
76
|
+
outDir: import_zod.z.string().min(1, "OutDir is required"),
|
|
77
|
+
name: import_zod.z.string().min(1, "Name is required"),
|
|
78
|
+
includeTags: import_zod.z.array(import_zod.z.string()).optional(),
|
|
79
|
+
excludeTags: import_zod.z.array(import_zod.z.string()).optional(),
|
|
80
|
+
// OperationIDParser is an optional function to transform operationId to a method name.
|
|
81
|
+
// Function signature: (operationId: string, method: string, path: string) => string | Promise<string>
|
|
82
|
+
// Note: Zod doesn't validate function signatures at runtime, but TypeScript will enforce the type
|
|
83
|
+
operationIdParser: import_zod.z.custom().optional(),
|
|
84
|
+
// PreCommand is an optional command to run before SDK generation starts.
|
|
85
|
+
// Uses Docker Compose array format: ["goimports", "-w", "."]
|
|
86
|
+
// The command will be executed in the output directory.
|
|
87
|
+
preCommand: import_zod.z.array(import_zod.z.string()).optional(),
|
|
88
|
+
// PostCommand is an optional command to run after SDK generation completes.
|
|
89
|
+
// Uses Docker Compose array format: ["goimports", "-w", "."]
|
|
90
|
+
// The command will be executed in the output directory.
|
|
91
|
+
postCommand: import_zod.z.array(import_zod.z.string()).optional(),
|
|
92
|
+
// DefaultBaseURL is the default base URL that will be used if no base URL is provided when creating a client
|
|
93
|
+
defaultBaseURL: import_zod.z.string().optional(),
|
|
94
|
+
// ExcludeFiles is a list of file paths (relative to outDir) that should not be generated
|
|
95
|
+
// Example: ["package.json", "src/client.ts"]
|
|
96
|
+
exclude: import_zod.z.array(import_zod.z.string()).optional()
|
|
97
|
+
});
|
|
98
|
+
var TypeScriptClientSchema = BaseClientSchema.extend({
|
|
99
|
+
type: import_zod.z.literal("typescript"),
|
|
100
|
+
packageName: import_zod.z.string().min(1, "PackageName is required"),
|
|
101
|
+
moduleName: import_zod.z.string().optional(),
|
|
102
|
+
// Source directory path (e.g., "src" or "src/sdk"). Defaults to "src" if not specified.
|
|
103
|
+
srcDir: import_zod.z.string().optional(),
|
|
104
|
+
// IncludeQueryKeys toggles generation of __queryKeys helper methods in services
|
|
105
|
+
includeQueryKeys: import_zod.z.boolean().optional(),
|
|
106
|
+
// Pre-defined types to import from external packages instead of generating locally
|
|
107
|
+
predefinedTypes: import_zod.z.array(PredefinedTypeSchema).optional(),
|
|
108
|
+
// Dependencies with explicit versions (e.g., { "@blimu/types": "^0.1.0" })
|
|
109
|
+
// If not specified, predefined type packages will use "*" version
|
|
110
|
+
dependencies: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
111
|
+
// DevDependencies with explicit versions (e.g., { "@types/jsonwebtoken": "^9" })
|
|
112
|
+
devDependencies: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
113
|
+
// FormatCode enables automatic formatting of generated TypeScript files using Prettier
|
|
114
|
+
// Defaults to true if not specified
|
|
115
|
+
formatCode: import_zod.z.boolean().optional(),
|
|
116
|
+
// Template overrides - maps valid template names to file paths
|
|
117
|
+
templates: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).refine((templates) => {
|
|
118
|
+
return Object.keys(templates).every((key) => TYPESCRIPT_TEMPLATE_NAMES.includes(key));
|
|
119
|
+
}, {
|
|
120
|
+
message: `Template names must be one of: ${TYPESCRIPT_TEMPLATE_NAMES.join(", ")}`
|
|
121
|
+
}).optional()
|
|
122
|
+
});
|
|
123
|
+
var ClientSchema = import_zod.z.discriminatedUnion("type", [
|
|
124
|
+
TypeScriptClientSchema
|
|
125
|
+
]);
|
|
126
|
+
var ConfigSchema = import_zod.z.object({
|
|
127
|
+
spec: import_zod.z.string().min(1, "Spec is required"),
|
|
128
|
+
name: import_zod.z.string().optional(),
|
|
129
|
+
clients: import_zod.z.array(ClientSchema).min(1, "At least one client is required")
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// src/config/config.service.ts
|
|
133
|
+
var import_common = require("@nestjs/common");
|
|
134
|
+
var fs = __toESM(require("fs"));
|
|
135
|
+
var path2 = __toESM(require("path"));
|
|
136
|
+
|
|
137
|
+
// src/config/mjs-config-loader.ts
|
|
138
|
+
var import_url = require("url");
|
|
139
|
+
var path = __toESM(require("path"));
|
|
140
|
+
async function loadMjsConfig(configPath) {
|
|
141
|
+
try {
|
|
142
|
+
const absolutePath = path.isAbsolute(configPath) ? configPath : path.resolve(configPath);
|
|
143
|
+
const fileUrl = (0, import_url.pathToFileURL)(absolutePath).href;
|
|
144
|
+
const configModule = await import(fileUrl);
|
|
145
|
+
const config = configModule.default || configModule;
|
|
146
|
+
if (!config) {
|
|
147
|
+
throw new Error(`Config file must export a default export or named export: ${configPath}`);
|
|
148
|
+
}
|
|
149
|
+
const validated = ConfigSchema.parse(config);
|
|
150
|
+
return validated;
|
|
151
|
+
} catch (error) {
|
|
152
|
+
if (error instanceof Error) {
|
|
153
|
+
throw new Error(`Failed to load MJS config from ${configPath}: ${error.message}`);
|
|
154
|
+
}
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
__name(loadMjsConfig, "loadMjsConfig");
|
|
159
|
+
|
|
160
|
+
// src/config/config.service.ts
|
|
161
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
162
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
163
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
164
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
165
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
166
|
+
}
|
|
167
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
168
|
+
var ConfigService = class _ConfigService {
|
|
169
|
+
static {
|
|
170
|
+
__name(this, "ConfigService");
|
|
171
|
+
}
|
|
172
|
+
logger = new import_common.Logger(_ConfigService.name);
|
|
173
|
+
DEFAULT_CONFIG_FILE = "chunkflow-codegen.config.mjs";
|
|
174
|
+
/**
|
|
175
|
+
* Find default config file in current directory and parent directories
|
|
176
|
+
*/
|
|
177
|
+
async findDefaultConfig() {
|
|
178
|
+
let currentDir = process.cwd();
|
|
179
|
+
const root = path2.parse(currentDir).root;
|
|
180
|
+
while (currentDir !== root) {
|
|
181
|
+
const configPath = path2.join(currentDir, this.DEFAULT_CONFIG_FILE);
|
|
182
|
+
try {
|
|
183
|
+
await fs.promises.access(configPath);
|
|
184
|
+
return configPath;
|
|
185
|
+
} catch {
|
|
186
|
+
}
|
|
187
|
+
currentDir = path2.dirname(currentDir);
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Load configuration from an MJS file
|
|
193
|
+
*/
|
|
194
|
+
async load(configPath) {
|
|
195
|
+
try {
|
|
196
|
+
const config = await loadMjsConfig(configPath);
|
|
197
|
+
return this.normalizePaths(config, configPath);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
if (error instanceof Error) {
|
|
200
|
+
throw new Error(`Failed to load config from ${configPath}: ${error.message}`);
|
|
201
|
+
}
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Normalize paths in the config to be absolute
|
|
207
|
+
*/
|
|
208
|
+
normalizePaths(config, configPath) {
|
|
209
|
+
const configDir = path2.dirname(path2.resolve(configPath));
|
|
210
|
+
let spec = config.spec;
|
|
211
|
+
if (!this.isUrl(spec)) {
|
|
212
|
+
if (!path2.isAbsolute(spec)) {
|
|
213
|
+
spec = path2.resolve(configDir, spec);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const clients = config.clients.map((client) => {
|
|
217
|
+
let outDir = client.outDir;
|
|
218
|
+
if (!path2.isAbsolute(outDir)) {
|
|
219
|
+
outDir = path2.resolve(configDir, outDir);
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
...client,
|
|
223
|
+
outDir
|
|
224
|
+
};
|
|
225
|
+
});
|
|
226
|
+
return {
|
|
227
|
+
...config,
|
|
228
|
+
spec,
|
|
229
|
+
clients
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Check if a string is a URL
|
|
234
|
+
*/
|
|
235
|
+
isUrl(str) {
|
|
236
|
+
try {
|
|
237
|
+
const url = new URL(str);
|
|
238
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
239
|
+
} catch {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Get pre-command for a client
|
|
245
|
+
*/
|
|
246
|
+
getPreCommand(client) {
|
|
247
|
+
return client.preCommand || [];
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Get post-command for a client
|
|
251
|
+
*/
|
|
252
|
+
getPostCommand(client) {
|
|
253
|
+
return client.postCommand || [];
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Check if a file should be excluded based on the ExcludeFiles list.
|
|
257
|
+
* targetPath should be an absolute path, and the comparison is done relative to OutDir.
|
|
258
|
+
*/
|
|
259
|
+
shouldExcludeFile(client, targetPath) {
|
|
260
|
+
if (!client.exclude || client.exclude.length === 0) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
let relPath;
|
|
264
|
+
try {
|
|
265
|
+
relPath = path2.relative(client.outDir, targetPath);
|
|
266
|
+
} catch {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
relPath = path2.posix.normalize(relPath);
|
|
270
|
+
if (relPath === ".") {
|
|
271
|
+
relPath = "";
|
|
272
|
+
}
|
|
273
|
+
for (const excludePattern of client.exclude) {
|
|
274
|
+
const normalizedExclude = path2.posix.normalize(excludePattern);
|
|
275
|
+
if (relPath === normalizedExclude) {
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
if (normalizedExclude !== "" && relPath.startsWith(normalizedExclude + "/")) {
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
ConfigService = _ts_decorate([
|
|
286
|
+
(0, import_common.Injectable)()
|
|
287
|
+
], ConfigService);
|
|
288
|
+
|
|
289
|
+
// src/config/config.module.ts
|
|
290
|
+
var import_common2 = require("@nestjs/common");
|
|
291
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
292
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
293
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
294
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
295
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
296
|
+
}
|
|
297
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
298
|
+
var ConfigModule = class {
|
|
299
|
+
static {
|
|
300
|
+
__name(this, "ConfigModule");
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
ConfigModule = _ts_decorate2([
|
|
304
|
+
(0, import_common2.Module)({
|
|
305
|
+
providers: [
|
|
306
|
+
ConfigService
|
|
307
|
+
],
|
|
308
|
+
exports: [
|
|
309
|
+
ConfigService
|
|
310
|
+
]
|
|
311
|
+
})
|
|
312
|
+
], ConfigModule);
|
|
313
|
+
|
|
314
|
+
// src/config/config-helper.ts
|
|
315
|
+
function defineConfig(config) {
|
|
316
|
+
return ConfigSchema.parse(config);
|
|
317
|
+
}
|
|
318
|
+
__name(defineConfig, "defineConfig");
|
|
319
|
+
|
|
320
|
+
// src/ir/ir.types.ts
|
|
321
|
+
var IRSchemaKind = /* @__PURE__ */ (function(IRSchemaKind2) {
|
|
322
|
+
IRSchemaKind2["Unknown"] = "unknown";
|
|
323
|
+
IRSchemaKind2["String"] = "string";
|
|
324
|
+
IRSchemaKind2["Number"] = "number";
|
|
325
|
+
IRSchemaKind2["Integer"] = "integer";
|
|
326
|
+
IRSchemaKind2["Boolean"] = "boolean";
|
|
327
|
+
IRSchemaKind2["Null"] = "null";
|
|
328
|
+
IRSchemaKind2["Array"] = "array";
|
|
329
|
+
IRSchemaKind2["Object"] = "object";
|
|
330
|
+
IRSchemaKind2["Enum"] = "enum";
|
|
331
|
+
IRSchemaKind2["Ref"] = "ref";
|
|
332
|
+
IRSchemaKind2["OneOf"] = "oneOf";
|
|
333
|
+
IRSchemaKind2["AnyOf"] = "anyOf";
|
|
334
|
+
IRSchemaKind2["AllOf"] = "allOf";
|
|
335
|
+
IRSchemaKind2["Not"] = "not";
|
|
336
|
+
return IRSchemaKind2;
|
|
337
|
+
})({});
|
|
338
|
+
|
|
339
|
+
// src/generator/generator.service.ts
|
|
340
|
+
var import_common6 = require("@nestjs/common");
|
|
341
|
+
|
|
342
|
+
// src/generator/ir-builder.service.ts
|
|
343
|
+
var import_common4 = require("@nestjs/common");
|
|
344
|
+
|
|
345
|
+
// src/generator/schema-converter.service.ts
|
|
346
|
+
var import_common3 = require("@nestjs/common");
|
|
347
|
+
|
|
348
|
+
// src/openapi/openapi-version.utils.ts
|
|
349
|
+
function detectOpenAPIVersion(doc) {
|
|
350
|
+
const version = doc.openapi;
|
|
351
|
+
if (typeof version !== "string") {
|
|
352
|
+
return "unknown";
|
|
353
|
+
}
|
|
354
|
+
if (version.startsWith("3.1")) {
|
|
355
|
+
return "3.1";
|
|
356
|
+
}
|
|
357
|
+
if (version.startsWith("3.0")) {
|
|
358
|
+
return "3.0";
|
|
359
|
+
}
|
|
360
|
+
return "unknown";
|
|
361
|
+
}
|
|
362
|
+
__name(detectOpenAPIVersion, "detectOpenAPIVersion");
|
|
363
|
+
function isSupportedVersion(version) {
|
|
364
|
+
return version === "3.0" || version === "3.1";
|
|
365
|
+
}
|
|
366
|
+
__name(isSupportedVersion, "isSupportedVersion");
|
|
367
|
+
|
|
368
|
+
// src/openapi/openapi.types.ts
|
|
369
|
+
function getSchemaFromRef(doc, schemaRef) {
|
|
370
|
+
if (!schemaRef || typeof schemaRef !== "object") {
|
|
371
|
+
return void 0;
|
|
372
|
+
}
|
|
373
|
+
if ("$ref" in schemaRef && schemaRef.$ref) {
|
|
374
|
+
const ref = schemaRef.$ref;
|
|
375
|
+
if (ref.startsWith("#/components/schemas/")) {
|
|
376
|
+
const name = ref.replace("#/components/schemas/", "");
|
|
377
|
+
if (doc.components?.schemas?.[name]) {
|
|
378
|
+
const schema = doc.components.schemas[name];
|
|
379
|
+
if ("$ref" in schema) {
|
|
380
|
+
return getSchemaFromRef(doc, schema);
|
|
381
|
+
}
|
|
382
|
+
return schema;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return void 0;
|
|
386
|
+
}
|
|
387
|
+
return schemaRef;
|
|
388
|
+
}
|
|
389
|
+
__name(getSchemaFromRef, "getSchemaFromRef");
|
|
390
|
+
function isSchemaNullable(schema) {
|
|
391
|
+
if (!schema) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
if ("nullable" in schema && schema.nullable === true) {
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
if ("type" in schema && Array.isArray(schema.type)) {
|
|
398
|
+
return schema.type.includes("null");
|
|
399
|
+
}
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
__name(isSchemaNullable, "isSchemaNullable");
|
|
403
|
+
function getSchemaType(schema) {
|
|
404
|
+
if (!schema || !("type" in schema)) {
|
|
405
|
+
return void 0;
|
|
406
|
+
}
|
|
407
|
+
return schema.type;
|
|
408
|
+
}
|
|
409
|
+
__name(getSchemaType, "getSchemaType");
|
|
410
|
+
|
|
411
|
+
// src/generator/schema-converter.service.ts
|
|
412
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
413
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
414
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
415
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
416
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
417
|
+
}
|
|
418
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
419
|
+
var SchemaConverterService = class {
|
|
420
|
+
static {
|
|
421
|
+
__name(this, "SchemaConverterService");
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Convert an OpenAPI schema reference to IR schema
|
|
425
|
+
* Supports both OpenAPI 3.0 and 3.1
|
|
426
|
+
*/
|
|
427
|
+
schemaRefToIR(doc, schemaRef) {
|
|
428
|
+
if (!schemaRef) {
|
|
429
|
+
return {
|
|
430
|
+
kind: IRSchemaKind.Unknown,
|
|
431
|
+
nullable: false
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
if ("$ref" in schemaRef && schemaRef.$ref) {
|
|
435
|
+
const ref = schemaRef.$ref;
|
|
436
|
+
if (ref.startsWith("#/components/schemas/")) {
|
|
437
|
+
const name = ref.replace("#/components/schemas/", "");
|
|
438
|
+
return {
|
|
439
|
+
kind: IRSchemaKind.Ref,
|
|
440
|
+
ref: name,
|
|
441
|
+
nullable: false
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
const parts = ref.split("/");
|
|
445
|
+
if (parts.length > 0) {
|
|
446
|
+
const name = parts[parts.length - 1];
|
|
447
|
+
if (name) {
|
|
448
|
+
return {
|
|
449
|
+
kind: IRSchemaKind.Ref,
|
|
450
|
+
ref: name,
|
|
451
|
+
nullable: false
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return {
|
|
456
|
+
kind: IRSchemaKind.Unknown,
|
|
457
|
+
nullable: false
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
const schema = getSchemaFromRef(doc, schemaRef);
|
|
461
|
+
if (!schema) {
|
|
462
|
+
return {
|
|
463
|
+
kind: IRSchemaKind.Unknown,
|
|
464
|
+
nullable: false
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
const nullable = isSchemaNullable(schema);
|
|
468
|
+
let discriminator;
|
|
469
|
+
if (schema.discriminator) {
|
|
470
|
+
discriminator = {
|
|
471
|
+
propertyName: schema.discriminator.propertyName,
|
|
472
|
+
mapping: schema.discriminator.mapping
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
if (schema.oneOf && schema.oneOf.length > 0) {
|
|
476
|
+
const subs = schema.oneOf.map((sub) => this.schemaRefToIR(doc, sub));
|
|
477
|
+
return {
|
|
478
|
+
kind: IRSchemaKind.OneOf,
|
|
479
|
+
oneOf: subs,
|
|
480
|
+
nullable,
|
|
481
|
+
discriminator
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
if (schema.anyOf && schema.anyOf.length > 0) {
|
|
485
|
+
const subs = schema.anyOf.map((sub) => this.schemaRefToIR(doc, sub));
|
|
486
|
+
return {
|
|
487
|
+
kind: IRSchemaKind.AnyOf,
|
|
488
|
+
anyOf: subs,
|
|
489
|
+
nullable,
|
|
490
|
+
discriminator
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
if (schema.allOf && schema.allOf.length > 0) {
|
|
494
|
+
const subs = schema.allOf.map((sub) => this.schemaRefToIR(doc, sub));
|
|
495
|
+
return {
|
|
496
|
+
kind: IRSchemaKind.AllOf,
|
|
497
|
+
allOf: subs,
|
|
498
|
+
nullable,
|
|
499
|
+
discriminator
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
if (schema.not) {
|
|
503
|
+
const not = this.schemaRefToIR(doc, schema.not);
|
|
504
|
+
return {
|
|
505
|
+
kind: IRSchemaKind.Not,
|
|
506
|
+
not,
|
|
507
|
+
nullable,
|
|
508
|
+
discriminator
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
if (schema.enum && schema.enum.length > 0) {
|
|
512
|
+
const enumValues = schema.enum.map((v) => String(v));
|
|
513
|
+
const enumBase = this.inferEnumBaseKind(schema);
|
|
514
|
+
return {
|
|
515
|
+
kind: IRSchemaKind.Enum,
|
|
516
|
+
enumValues,
|
|
517
|
+
enumRaw: schema.enum,
|
|
518
|
+
enumBase,
|
|
519
|
+
nullable,
|
|
520
|
+
discriminator
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
const type = getSchemaType(schema);
|
|
524
|
+
const normalizedType = Array.isArray(type) ? type.filter((t) => t !== "null")[0] : type;
|
|
525
|
+
if (normalizedType) {
|
|
526
|
+
switch (normalizedType) {
|
|
527
|
+
case "string":
|
|
528
|
+
return {
|
|
529
|
+
kind: IRSchemaKind.String,
|
|
530
|
+
nullable,
|
|
531
|
+
format: schema.format,
|
|
532
|
+
discriminator
|
|
533
|
+
};
|
|
534
|
+
case "integer":
|
|
535
|
+
return {
|
|
536
|
+
kind: IRSchemaKind.Integer,
|
|
537
|
+
nullable,
|
|
538
|
+
discriminator
|
|
539
|
+
};
|
|
540
|
+
case "number":
|
|
541
|
+
return {
|
|
542
|
+
kind: IRSchemaKind.Number,
|
|
543
|
+
nullable,
|
|
544
|
+
discriminator
|
|
545
|
+
};
|
|
546
|
+
case "boolean":
|
|
547
|
+
return {
|
|
548
|
+
kind: IRSchemaKind.Boolean,
|
|
549
|
+
nullable,
|
|
550
|
+
discriminator
|
|
551
|
+
};
|
|
552
|
+
case "array": {
|
|
553
|
+
const arraySchema = schema;
|
|
554
|
+
const items = this.schemaRefToIR(doc, arraySchema.items);
|
|
555
|
+
return {
|
|
556
|
+
kind: IRSchemaKind.Array,
|
|
557
|
+
items,
|
|
558
|
+
nullable,
|
|
559
|
+
discriminator
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
case "object": {
|
|
563
|
+
const properties = [];
|
|
564
|
+
if (schema.properties) {
|
|
565
|
+
const propNames = Object.keys(schema.properties).sort();
|
|
566
|
+
for (const name of propNames) {
|
|
567
|
+
const prop = schema.properties[name];
|
|
568
|
+
const fieldType = this.schemaRefToIR(doc, prop);
|
|
569
|
+
const required = schema.required?.includes(name) || false;
|
|
570
|
+
properties.push({
|
|
571
|
+
name,
|
|
572
|
+
type: fieldType,
|
|
573
|
+
required,
|
|
574
|
+
annotations: this.extractAnnotations(prop)
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
let additionalProperties;
|
|
579
|
+
if (schema.additionalProperties) {
|
|
580
|
+
if (typeof schema.additionalProperties === "object") {
|
|
581
|
+
additionalProperties = this.schemaRefToIR(doc, schema.additionalProperties);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
return {
|
|
585
|
+
kind: IRSchemaKind.Object,
|
|
586
|
+
properties,
|
|
587
|
+
additionalProperties,
|
|
588
|
+
nullable,
|
|
589
|
+
discriminator
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return {
|
|
595
|
+
kind: IRSchemaKind.Unknown,
|
|
596
|
+
nullable,
|
|
597
|
+
discriminator
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Extract annotations from a schema reference
|
|
602
|
+
* Supports both OpenAPI 3.0 and 3.1
|
|
603
|
+
*/
|
|
604
|
+
extractAnnotations(schemaRef) {
|
|
605
|
+
if (!schemaRef || "$ref" in schemaRef) {
|
|
606
|
+
return {};
|
|
607
|
+
}
|
|
608
|
+
const schema = schemaRef;
|
|
609
|
+
return {
|
|
610
|
+
title: schema.title,
|
|
611
|
+
description: schema.description,
|
|
612
|
+
deprecated: schema.deprecated,
|
|
613
|
+
readOnly: schema.readOnly,
|
|
614
|
+
writeOnly: schema.writeOnly,
|
|
615
|
+
default: schema.default,
|
|
616
|
+
examples: schema.example ? Array.isArray(schema.example) ? schema.example : [
|
|
617
|
+
schema.example
|
|
618
|
+
] : void 0
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Infer the base kind for an enum
|
|
623
|
+
* Supports both OpenAPI 3.0 and 3.1
|
|
624
|
+
*/
|
|
625
|
+
inferEnumBaseKind(schema) {
|
|
626
|
+
const type = getSchemaType(schema);
|
|
627
|
+
if (type) {
|
|
628
|
+
const normalizedType = Array.isArray(type) ? type.filter((t) => t !== "null")[0] : type;
|
|
629
|
+
if (normalizedType) {
|
|
630
|
+
switch (normalizedType) {
|
|
631
|
+
case "string":
|
|
632
|
+
return IRSchemaKind.String;
|
|
633
|
+
case "integer":
|
|
634
|
+
return IRSchemaKind.Integer;
|
|
635
|
+
case "number":
|
|
636
|
+
return IRSchemaKind.Number;
|
|
637
|
+
case "boolean":
|
|
638
|
+
return IRSchemaKind.Boolean;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
if (schema.enum && schema.enum.length > 0) {
|
|
643
|
+
const first = schema.enum[0];
|
|
644
|
+
if (typeof first === "string") {
|
|
645
|
+
return IRSchemaKind.String;
|
|
646
|
+
}
|
|
647
|
+
if (typeof first === "number") {
|
|
648
|
+
return Number.isInteger(first) ? IRSchemaKind.Integer : IRSchemaKind.Number;
|
|
649
|
+
}
|
|
650
|
+
if (typeof first === "boolean") {
|
|
651
|
+
return IRSchemaKind.Boolean;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return IRSchemaKind.Unknown;
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
SchemaConverterService = _ts_decorate3([
|
|
658
|
+
(0, import_common3.Injectable)()
|
|
659
|
+
], SchemaConverterService);
|
|
660
|
+
|
|
661
|
+
// src/utils/string.utils.ts
|
|
662
|
+
function toPascalCase(s) {
|
|
663
|
+
s = s.trim();
|
|
664
|
+
if (s === "") {
|
|
665
|
+
return "";
|
|
666
|
+
}
|
|
667
|
+
const parts = s.split(/[^A-Za-z0-9]+/).filter((p) => p !== "");
|
|
668
|
+
const allParts = [];
|
|
669
|
+
for (const part of parts) {
|
|
670
|
+
const subParts = splitCamelCase(part);
|
|
671
|
+
allParts.push(...subParts);
|
|
672
|
+
}
|
|
673
|
+
return allParts.filter((p) => p !== "").map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase()).join("");
|
|
674
|
+
}
|
|
675
|
+
__name(toPascalCase, "toPascalCase");
|
|
676
|
+
function toCamelCase(s) {
|
|
677
|
+
const pascal = toPascalCase(s);
|
|
678
|
+
if (pascal === "") {
|
|
679
|
+
return "";
|
|
680
|
+
}
|
|
681
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
682
|
+
}
|
|
683
|
+
__name(toCamelCase, "toCamelCase");
|
|
684
|
+
function toSnakeCase(s) {
|
|
685
|
+
s = s.trim();
|
|
686
|
+
if (s === "") {
|
|
687
|
+
return "";
|
|
688
|
+
}
|
|
689
|
+
const parts = s.split(/[^A-Za-z0-9]+/).filter((p) => p !== "");
|
|
690
|
+
const allParts = [];
|
|
691
|
+
for (const part of parts) {
|
|
692
|
+
const subParts = splitCamelCase(part);
|
|
693
|
+
allParts.push(...subParts);
|
|
694
|
+
}
|
|
695
|
+
return allParts.filter((p) => p !== "").map((p) => p.toLowerCase()).join("_");
|
|
696
|
+
}
|
|
697
|
+
__name(toSnakeCase, "toSnakeCase");
|
|
698
|
+
function toKebabCase(s) {
|
|
699
|
+
s = s.trim();
|
|
700
|
+
if (s === "") {
|
|
701
|
+
return "";
|
|
702
|
+
}
|
|
703
|
+
const parts = s.split(/[^A-Za-z0-9]+/).filter((p) => p !== "");
|
|
704
|
+
const allParts = [];
|
|
705
|
+
for (const part of parts) {
|
|
706
|
+
const subParts = splitCamelCase(part);
|
|
707
|
+
allParts.push(...subParts);
|
|
708
|
+
}
|
|
709
|
+
return allParts.filter((p) => p !== "").map((p) => p.toLowerCase()).join("-");
|
|
710
|
+
}
|
|
711
|
+
__name(toKebabCase, "toKebabCase");
|
|
712
|
+
function splitCamelCase(s) {
|
|
713
|
+
if (s === "") {
|
|
714
|
+
return [];
|
|
715
|
+
}
|
|
716
|
+
const parts = [];
|
|
717
|
+
let current = "";
|
|
718
|
+
const chars = Array.from(s);
|
|
719
|
+
for (let i = 0; i < chars.length; i++) {
|
|
720
|
+
const char = chars[i];
|
|
721
|
+
if (!char) {
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
let isNewWord = false;
|
|
725
|
+
if (i > 0 && isUppercase(char)) {
|
|
726
|
+
const prevChar = chars[i - 1];
|
|
727
|
+
if (prevChar && !isUppercase(prevChar)) {
|
|
728
|
+
isNewWord = true;
|
|
729
|
+
} else if (i < chars.length - 1) {
|
|
730
|
+
const nextChar = chars[i + 1];
|
|
731
|
+
if (nextChar && !isUppercase(nextChar)) {
|
|
732
|
+
isNewWord = true;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
if (isNewWord && current.length > 0) {
|
|
737
|
+
parts.push(current);
|
|
738
|
+
current = "";
|
|
739
|
+
}
|
|
740
|
+
current += char;
|
|
741
|
+
}
|
|
742
|
+
if (current.length > 0) {
|
|
743
|
+
parts.push(current);
|
|
744
|
+
}
|
|
745
|
+
return parts;
|
|
746
|
+
}
|
|
747
|
+
__name(splitCamelCase, "splitCamelCase");
|
|
748
|
+
function isUppercase(char) {
|
|
749
|
+
return char >= "A" && char <= "Z";
|
|
750
|
+
}
|
|
751
|
+
__name(isUppercase, "isUppercase");
|
|
752
|
+
|
|
753
|
+
// src/generator/ir-builder.service.ts
|
|
754
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
755
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
756
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
757
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
758
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
759
|
+
}
|
|
760
|
+
__name(_ts_decorate4, "_ts_decorate");
|
|
761
|
+
function _ts_metadata(k, v) {
|
|
762
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
763
|
+
}
|
|
764
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
765
|
+
var IrBuilderService = class {
|
|
766
|
+
static {
|
|
767
|
+
__name(this, "IrBuilderService");
|
|
768
|
+
}
|
|
769
|
+
schemaConverter;
|
|
770
|
+
constructor(schemaConverter) {
|
|
771
|
+
this.schemaConverter = schemaConverter;
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Build IR from an OpenAPI document
|
|
775
|
+
* Supports both OpenAPI 3.0 and 3.1
|
|
776
|
+
*/
|
|
777
|
+
buildIR(doc) {
|
|
778
|
+
const tags = this.collectTags(doc);
|
|
779
|
+
const securitySchemes = this.collectSecuritySchemes(doc);
|
|
780
|
+
const modelDefs = this.buildStructuredModels(doc);
|
|
781
|
+
const allowed = {};
|
|
782
|
+
for (const tag of tags) {
|
|
783
|
+
allowed[tag] = true;
|
|
784
|
+
}
|
|
785
|
+
const result = this.buildIRFromDoc(doc, allowed);
|
|
786
|
+
result.securitySchemes = securitySchemes;
|
|
787
|
+
result.modelDefs = [
|
|
788
|
+
...modelDefs,
|
|
789
|
+
...result.modelDefs
|
|
790
|
+
];
|
|
791
|
+
result.openApiDocument = doc;
|
|
792
|
+
return result;
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Filter IR based on client configuration
|
|
796
|
+
*/
|
|
797
|
+
filterIR(fullIR, client) {
|
|
798
|
+
const include = this.compileTagFilters(client.includeTags || []);
|
|
799
|
+
const exclude = this.compileTagFilters(client.excludeTags || []);
|
|
800
|
+
const filteredServices = [];
|
|
801
|
+
for (const service of fullIR.services) {
|
|
802
|
+
const filteredOps = [];
|
|
803
|
+
for (const op of service.operations) {
|
|
804
|
+
if (this.shouldIncludeOperation(op.originalTags, include, exclude)) {
|
|
805
|
+
filteredOps.push(op);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
if (filteredOps.length > 0) {
|
|
809
|
+
filteredServices.push({
|
|
810
|
+
...service,
|
|
811
|
+
operations: filteredOps
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
const filteredIR = {
|
|
816
|
+
services: filteredServices,
|
|
817
|
+
models: fullIR.models,
|
|
818
|
+
securitySchemes: fullIR.securitySchemes,
|
|
819
|
+
modelDefs: fullIR.modelDefs,
|
|
820
|
+
openApiDocument: fullIR.openApiDocument
|
|
821
|
+
};
|
|
822
|
+
filteredIR.modelDefs = this.filterUnusedModelDefs(filteredIR, fullIR.modelDefs);
|
|
823
|
+
return filteredIR;
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Detect if a content type indicates streaming
|
|
827
|
+
*/
|
|
828
|
+
detectStreamingContentType(contentType) {
|
|
829
|
+
const normalized = contentType.toLowerCase().split(";")[0]?.trim();
|
|
830
|
+
if (!normalized) {
|
|
831
|
+
return {
|
|
832
|
+
isStreaming: false
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
if (normalized === "text/event-stream") {
|
|
836
|
+
return {
|
|
837
|
+
isStreaming: true,
|
|
838
|
+
format: "sse"
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
if (normalized === "application/x-ndjson" || normalized === "application/x-jsonlines" || normalized === "application/jsonl") {
|
|
842
|
+
return {
|
|
843
|
+
isStreaming: true,
|
|
844
|
+
format: "ndjson"
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
if (normalized.includes("stream") || normalized.includes("chunked")) {
|
|
848
|
+
return {
|
|
849
|
+
isStreaming: true,
|
|
850
|
+
format: "chunked"
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
return {
|
|
854
|
+
isStreaming: false
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Collect all tags from the OpenAPI document
|
|
859
|
+
*/
|
|
860
|
+
collectTags(doc) {
|
|
861
|
+
const uniq = /* @__PURE__ */ new Set();
|
|
862
|
+
uniq.add("misc");
|
|
863
|
+
if (doc.paths) {
|
|
864
|
+
for (const [_path, pathItem] of Object.entries(doc.paths)) {
|
|
865
|
+
if (!pathItem) continue;
|
|
866
|
+
const operations = [
|
|
867
|
+
pathItem.get,
|
|
868
|
+
pathItem.post,
|
|
869
|
+
pathItem.put,
|
|
870
|
+
pathItem.patch,
|
|
871
|
+
pathItem.delete,
|
|
872
|
+
pathItem.options,
|
|
873
|
+
pathItem.head,
|
|
874
|
+
pathItem.trace
|
|
875
|
+
];
|
|
876
|
+
for (const op of operations) {
|
|
877
|
+
if (!op || !op.tags) continue;
|
|
878
|
+
for (const tag of op.tags) {
|
|
879
|
+
uniq.add(tag);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
return Array.from(uniq).sort();
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Compile regex patterns for tag filtering
|
|
888
|
+
*/
|
|
889
|
+
compileTagFilters(patterns) {
|
|
890
|
+
return patterns.map((p) => {
|
|
891
|
+
try {
|
|
892
|
+
return new RegExp(p);
|
|
893
|
+
} catch (error) {
|
|
894
|
+
throw new Error(`Invalid tag filter pattern "${p}": ${error instanceof Error ? error.message : String(error)}`);
|
|
895
|
+
}
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* Determine if an operation should be included based on its original tags
|
|
900
|
+
*/
|
|
901
|
+
shouldIncludeOperation(originalTags, include, exclude) {
|
|
902
|
+
let included = include.length === 0;
|
|
903
|
+
if (include.length > 0) {
|
|
904
|
+
for (const tag of originalTags) {
|
|
905
|
+
for (const r of include) {
|
|
906
|
+
if (r.test(tag)) {
|
|
907
|
+
included = true;
|
|
908
|
+
break;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
if (included) {
|
|
912
|
+
break;
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
if (!included) {
|
|
917
|
+
return false;
|
|
918
|
+
}
|
|
919
|
+
if (exclude.length > 0) {
|
|
920
|
+
for (const tag of originalTags) {
|
|
921
|
+
for (const r of exclude) {
|
|
922
|
+
if (r.test(tag)) {
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
return true;
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* Build IR structures from OpenAPI document
|
|
932
|
+
*/
|
|
933
|
+
buildIRFromDoc(doc, allowed) {
|
|
934
|
+
const servicesMap = {};
|
|
935
|
+
servicesMap["misc"] = {
|
|
936
|
+
tag: "misc",
|
|
937
|
+
operations: []
|
|
938
|
+
};
|
|
939
|
+
const extractedTypes = [];
|
|
940
|
+
const seenTypeNames = /* @__PURE__ */ new Set();
|
|
941
|
+
if (doc.components?.schemas) {
|
|
942
|
+
for (const name of Object.keys(doc.components.schemas)) {
|
|
943
|
+
seenTypeNames.add(name);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
const addOp = /* @__PURE__ */ __name((tag, op, method, path7) => {
|
|
947
|
+
if (!servicesMap[tag]) {
|
|
948
|
+
servicesMap[tag] = {
|
|
949
|
+
tag,
|
|
950
|
+
operations: []
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
const id = op.operationId || "";
|
|
954
|
+
const { pathParams, queryParams } = this.collectParams(doc, op);
|
|
955
|
+
const { requestBody: reqBody, extractedTypes: reqBodyTypes } = this.extractRequestBodyWithTypes(doc, op, tag, id, method, seenTypeNames);
|
|
956
|
+
extractedTypes.push(...reqBodyTypes);
|
|
957
|
+
const { response: resp, extractedTypes: respTypes } = this.extractResponseWithTypes(doc, op, tag, id, method, seenTypeNames);
|
|
958
|
+
extractedTypes.push(...respTypes);
|
|
959
|
+
const originalTags = op.tags && op.tags.length > 0 ? [
|
|
960
|
+
...op.tags
|
|
961
|
+
] : [
|
|
962
|
+
"misc"
|
|
963
|
+
];
|
|
964
|
+
servicesMap[tag].operations.push({
|
|
965
|
+
operationID: id,
|
|
966
|
+
method,
|
|
967
|
+
path: path7,
|
|
968
|
+
tag,
|
|
969
|
+
originalTags,
|
|
970
|
+
summary: op.summary || "",
|
|
971
|
+
description: op.description || "",
|
|
972
|
+
deprecated: op.deprecated || false,
|
|
973
|
+
pathParams,
|
|
974
|
+
queryParams,
|
|
975
|
+
requestBody: reqBody,
|
|
976
|
+
response: resp
|
|
977
|
+
});
|
|
978
|
+
}, "addOp");
|
|
979
|
+
if (doc.paths) {
|
|
980
|
+
for (const [path7, pathItem] of Object.entries(doc.paths)) {
|
|
981
|
+
if (!pathItem) continue;
|
|
982
|
+
const operations = [
|
|
983
|
+
{
|
|
984
|
+
op: pathItem.get,
|
|
985
|
+
method: "GET"
|
|
986
|
+
},
|
|
987
|
+
{
|
|
988
|
+
op: pathItem.post,
|
|
989
|
+
method: "POST"
|
|
990
|
+
},
|
|
991
|
+
{
|
|
992
|
+
op: pathItem.put,
|
|
993
|
+
method: "PUT"
|
|
994
|
+
},
|
|
995
|
+
{
|
|
996
|
+
op: pathItem.patch,
|
|
997
|
+
method: "PATCH"
|
|
998
|
+
},
|
|
999
|
+
{
|
|
1000
|
+
op: pathItem.delete,
|
|
1001
|
+
method: "DELETE"
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
op: pathItem.options,
|
|
1005
|
+
method: "OPTIONS"
|
|
1006
|
+
},
|
|
1007
|
+
{
|
|
1008
|
+
op: pathItem.head,
|
|
1009
|
+
method: "HEAD"
|
|
1010
|
+
},
|
|
1011
|
+
{
|
|
1012
|
+
op: pathItem.trace,
|
|
1013
|
+
method: "TRACE"
|
|
1014
|
+
}
|
|
1015
|
+
];
|
|
1016
|
+
for (const { op, method } of operations) {
|
|
1017
|
+
if (!op) continue;
|
|
1018
|
+
const t = this.firstAllowedTag(op.tags || [], allowed);
|
|
1019
|
+
if (t) {
|
|
1020
|
+
addOp(t, op, method, path7);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
const services = Object.values(servicesMap);
|
|
1026
|
+
for (const service of services) {
|
|
1027
|
+
service.operations.sort((a, b) => {
|
|
1028
|
+
if (a.path === b.path) {
|
|
1029
|
+
return a.method.localeCompare(b.method);
|
|
1030
|
+
}
|
|
1031
|
+
return a.path.localeCompare(b.path);
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
services.sort((a, b) => a.tag.localeCompare(b.tag));
|
|
1035
|
+
return {
|
|
1036
|
+
services,
|
|
1037
|
+
models: [],
|
|
1038
|
+
securitySchemes: [],
|
|
1039
|
+
modelDefs: extractedTypes
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Get the first allowed tag from a list
|
|
1044
|
+
*/
|
|
1045
|
+
/**
|
|
1046
|
+
* Derive method name from operation ID, method, and path
|
|
1047
|
+
*/
|
|
1048
|
+
deriveMethodName(operationId, method, path7) {
|
|
1049
|
+
if (operationId) {
|
|
1050
|
+
const idx = operationId.indexOf("Controller_");
|
|
1051
|
+
const cleanedId = idx >= 0 ? operationId.substring(idx + "Controller_".length) : operationId;
|
|
1052
|
+
return toCamelCase(cleanedId);
|
|
1053
|
+
}
|
|
1054
|
+
const hasID = path7.includes("{") && path7.includes("}");
|
|
1055
|
+
switch (method) {
|
|
1056
|
+
case "GET":
|
|
1057
|
+
return hasID ? "get" : "list";
|
|
1058
|
+
case "POST":
|
|
1059
|
+
return "create";
|
|
1060
|
+
case "PUT":
|
|
1061
|
+
case "PATCH":
|
|
1062
|
+
return "update";
|
|
1063
|
+
case "DELETE":
|
|
1064
|
+
return "delete";
|
|
1065
|
+
default:
|
|
1066
|
+
return method.toLowerCase();
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
firstAllowedTag(tags, allowed) {
|
|
1070
|
+
for (const t of tags) {
|
|
1071
|
+
if (allowed[t]) {
|
|
1072
|
+
return t;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
if (tags.length === 0 && allowed["misc"]) {
|
|
1076
|
+
return "misc";
|
|
1077
|
+
}
|
|
1078
|
+
return "";
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Collect security schemes
|
|
1082
|
+
*/
|
|
1083
|
+
collectSecuritySchemes(doc) {
|
|
1084
|
+
if (!doc.components?.securitySchemes) {
|
|
1085
|
+
return [];
|
|
1086
|
+
}
|
|
1087
|
+
const names = Object.keys(doc.components.securitySchemes).sort();
|
|
1088
|
+
const out = [];
|
|
1089
|
+
for (const name of names) {
|
|
1090
|
+
const scheme = doc.components.securitySchemes[name];
|
|
1091
|
+
if (!scheme || "$ref" in scheme) continue;
|
|
1092
|
+
const sc = {
|
|
1093
|
+
key: name,
|
|
1094
|
+
type: scheme.type
|
|
1095
|
+
};
|
|
1096
|
+
switch (scheme.type) {
|
|
1097
|
+
case "http":
|
|
1098
|
+
sc.scheme = scheme.scheme;
|
|
1099
|
+
if (scheme.bearerFormat) {
|
|
1100
|
+
sc.bearerFormat = scheme.bearerFormat;
|
|
1101
|
+
}
|
|
1102
|
+
break;
|
|
1103
|
+
case "apiKey":
|
|
1104
|
+
sc.in = scheme.in;
|
|
1105
|
+
sc.name = scheme.name;
|
|
1106
|
+
break;
|
|
1107
|
+
case "oauth2":
|
|
1108
|
+
case "openIdConnect":
|
|
1109
|
+
break;
|
|
1110
|
+
}
|
|
1111
|
+
out.push(sc);
|
|
1112
|
+
}
|
|
1113
|
+
return out;
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Collect parameters from an operation
|
|
1117
|
+
*/
|
|
1118
|
+
collectParams(doc, op) {
|
|
1119
|
+
const pathParams = [];
|
|
1120
|
+
const queryParams = [];
|
|
1121
|
+
if (op.parameters) {
|
|
1122
|
+
for (const pr of op.parameters) {
|
|
1123
|
+
if (!pr || "$ref" in pr) continue;
|
|
1124
|
+
const p = pr;
|
|
1125
|
+
const schema = this.schemaConverter.schemaRefToIR(doc, p.schema);
|
|
1126
|
+
const param = {
|
|
1127
|
+
name: p.name,
|
|
1128
|
+
required: p.required || false,
|
|
1129
|
+
schema,
|
|
1130
|
+
description: p.description || ""
|
|
1131
|
+
};
|
|
1132
|
+
if (p.in === "path") {
|
|
1133
|
+
pathParams.push(param);
|
|
1134
|
+
} else if (p.in === "query") {
|
|
1135
|
+
queryParams.push(param);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
pathParams.sort((a, b) => a.name.localeCompare(b.name));
|
|
1140
|
+
queryParams.sort((a, b) => a.name.localeCompare(b.name));
|
|
1141
|
+
return {
|
|
1142
|
+
pathParams,
|
|
1143
|
+
queryParams
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Extract request body information with inline type extraction
|
|
1148
|
+
*/
|
|
1149
|
+
/**
|
|
1150
|
+
* Find if a schema matches a component schema (useful after dereferencing)
|
|
1151
|
+
* Returns the component schema name if found, null otherwise
|
|
1152
|
+
*/
|
|
1153
|
+
findMatchingComponentSchema(doc, schema) {
|
|
1154
|
+
if (!schema || !doc.components?.schemas) {
|
|
1155
|
+
return null;
|
|
1156
|
+
}
|
|
1157
|
+
if ("$ref" in schema && schema.$ref) {
|
|
1158
|
+
const ref = schema.$ref;
|
|
1159
|
+
if (ref.startsWith("#/components/schemas/")) {
|
|
1160
|
+
const name = ref.replace("#/components/schemas/", "");
|
|
1161
|
+
if (doc.components.schemas[name]) {
|
|
1162
|
+
return name;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
const schemaIR = this.schemaConverter.schemaRefToIR(doc, schema);
|
|
1167
|
+
for (const [name, componentSchema] of Object.entries(doc.components.schemas)) {
|
|
1168
|
+
const componentIR = this.schemaConverter.schemaRefToIR(doc, componentSchema);
|
|
1169
|
+
if (this.compareSchemas(schemaIR, componentIR)) {
|
|
1170
|
+
return name;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
return null;
|
|
1174
|
+
}
|
|
1175
|
+
/**
|
|
1176
|
+
* Compare two IR schemas for structural equality
|
|
1177
|
+
*/
|
|
1178
|
+
compareSchemas(schema1, schema2) {
|
|
1179
|
+
if (schema1.kind !== schema2.kind) {
|
|
1180
|
+
return false;
|
|
1181
|
+
}
|
|
1182
|
+
if (schema1.kind === IRSchemaKind.Ref && schema2.kind === IRSchemaKind.Ref) {
|
|
1183
|
+
return schema1.ref === schema2.ref;
|
|
1184
|
+
}
|
|
1185
|
+
if (schema1.kind === IRSchemaKind.Object && schema2.kind === IRSchemaKind.Object) {
|
|
1186
|
+
const props1 = schema1.properties || [];
|
|
1187
|
+
const props2 = schema2.properties || [];
|
|
1188
|
+
if (props1.length !== props2.length) {
|
|
1189
|
+
return false;
|
|
1190
|
+
}
|
|
1191
|
+
const props1Map = new Map(props1.map((p) => [
|
|
1192
|
+
p.name,
|
|
1193
|
+
{
|
|
1194
|
+
type: p.type,
|
|
1195
|
+
required: p.required
|
|
1196
|
+
}
|
|
1197
|
+
]));
|
|
1198
|
+
const props2Map = new Map(props2.map((p) => [
|
|
1199
|
+
p.name,
|
|
1200
|
+
{
|
|
1201
|
+
type: p.type,
|
|
1202
|
+
required: p.required
|
|
1203
|
+
}
|
|
1204
|
+
]));
|
|
1205
|
+
if (props1Map.size !== props2Map.size) {
|
|
1206
|
+
return false;
|
|
1207
|
+
}
|
|
1208
|
+
for (const [name, prop1] of props1Map) {
|
|
1209
|
+
const prop2 = props2Map.get(name);
|
|
1210
|
+
if (!prop2 || prop1.required !== prop2.required || !this.compareSchemas(prop1.type, prop2.type)) {
|
|
1211
|
+
return false;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
return true;
|
|
1215
|
+
}
|
|
1216
|
+
if (schema1.kind === IRSchemaKind.Array && schema2.kind === IRSchemaKind.Array) {
|
|
1217
|
+
if (!schema1.items || !schema2.items) {
|
|
1218
|
+
return schema1.items === schema2.items;
|
|
1219
|
+
}
|
|
1220
|
+
return this.compareSchemas(schema1.items, schema2.items);
|
|
1221
|
+
}
|
|
1222
|
+
return true;
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* Extract model name from schema if it's a reference, otherwise return null
|
|
1226
|
+
* Handles direct refs and arrays of refs
|
|
1227
|
+
*/
|
|
1228
|
+
extractModelNameFromSchema(schema) {
|
|
1229
|
+
if (schema.kind === IRSchemaKind.Ref && schema.ref) {
|
|
1230
|
+
return schema.ref;
|
|
1231
|
+
}
|
|
1232
|
+
if (schema.kind === IRSchemaKind.Array && schema.items) {
|
|
1233
|
+
if (schema.items.kind === IRSchemaKind.Ref && schema.items.ref) {
|
|
1234
|
+
return schema.items.ref;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
return null;
|
|
1238
|
+
}
|
|
1239
|
+
/**
|
|
1240
|
+
* Generate type name for request/response body
|
|
1241
|
+
* Prefers model name from schema reference, falls back to operation-based naming
|
|
1242
|
+
*/
|
|
1243
|
+
generateTypeName(schema, tag, operationId, method, path7, suffix) {
|
|
1244
|
+
const modelName = this.extractModelNameFromSchema(schema);
|
|
1245
|
+
if (modelName) {
|
|
1246
|
+
return modelName;
|
|
1247
|
+
}
|
|
1248
|
+
const methodName = this.deriveMethodName(operationId, method, path7);
|
|
1249
|
+
return `${toPascalCase(tag)}${toPascalCase(methodName)}${suffix}`;
|
|
1250
|
+
}
|
|
1251
|
+
extractRequestBodyWithTypes(doc, op, tag, operationId, method, seenTypeNames) {
|
|
1252
|
+
const extractedTypes = [];
|
|
1253
|
+
if (!op.requestBody || "$ref" in op.requestBody) {
|
|
1254
|
+
return {
|
|
1255
|
+
requestBody: null,
|
|
1256
|
+
extractedTypes: []
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
const rb = op.requestBody;
|
|
1260
|
+
if (rb.content?.["application/json"]) {
|
|
1261
|
+
const media = rb.content["application/json"];
|
|
1262
|
+
const schema = this.schemaConverter.schemaRefToIR(doc, media.schema);
|
|
1263
|
+
const componentSchemaName = this.findMatchingComponentSchema(doc, media.schema);
|
|
1264
|
+
if (componentSchemaName) {
|
|
1265
|
+
return {
|
|
1266
|
+
requestBody: {
|
|
1267
|
+
contentType: "application/json",
|
|
1268
|
+
typeTS: "",
|
|
1269
|
+
schema: {
|
|
1270
|
+
kind: IRSchemaKind.Ref,
|
|
1271
|
+
ref: componentSchemaName,
|
|
1272
|
+
nullable: false
|
|
1273
|
+
},
|
|
1274
|
+
required: rb.required || false
|
|
1275
|
+
},
|
|
1276
|
+
extractedTypes: []
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
const typeName = this.generateTypeName(schema, tag, operationId, method, op.path, "RequestBody");
|
|
1280
|
+
if (schema.kind === IRSchemaKind.Object && !seenTypeNames.has(typeName)) {
|
|
1281
|
+
seenTypeNames.add(typeName);
|
|
1282
|
+
extractedTypes.push({
|
|
1283
|
+
name: typeName,
|
|
1284
|
+
schema,
|
|
1285
|
+
annotations: this.schemaConverter.extractAnnotations(media.schema)
|
|
1286
|
+
});
|
|
1287
|
+
return {
|
|
1288
|
+
requestBody: {
|
|
1289
|
+
contentType: "application/json",
|
|
1290
|
+
typeTS: "",
|
|
1291
|
+
schema: {
|
|
1292
|
+
kind: IRSchemaKind.Ref,
|
|
1293
|
+
ref: typeName,
|
|
1294
|
+
nullable: false
|
|
1295
|
+
},
|
|
1296
|
+
required: rb.required || false
|
|
1297
|
+
},
|
|
1298
|
+
extractedTypes
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
return {
|
|
1302
|
+
requestBody: {
|
|
1303
|
+
contentType: "application/json",
|
|
1304
|
+
typeTS: "",
|
|
1305
|
+
schema,
|
|
1306
|
+
required: rb.required || false
|
|
1307
|
+
},
|
|
1308
|
+
extractedTypes: []
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
const reqBody = this.extractRequestBody(doc, op);
|
|
1312
|
+
return {
|
|
1313
|
+
requestBody: reqBody,
|
|
1314
|
+
extractedTypes: []
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
/**
|
|
1318
|
+
* Extract request body information (legacy method, kept for fallback)
|
|
1319
|
+
*/
|
|
1320
|
+
extractRequestBody(doc, op) {
|
|
1321
|
+
if (!op.requestBody || "$ref" in op.requestBody) {
|
|
1322
|
+
return null;
|
|
1323
|
+
}
|
|
1324
|
+
const rb = op.requestBody;
|
|
1325
|
+
if (rb.content?.["application/json"]) {
|
|
1326
|
+
const media = rb.content["application/json"];
|
|
1327
|
+
return {
|
|
1328
|
+
contentType: "application/json",
|
|
1329
|
+
typeTS: "",
|
|
1330
|
+
schema: this.schemaConverter.schemaRefToIR(doc, media.schema),
|
|
1331
|
+
required: rb.required || false
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
if (rb.content?.["application/x-www-form-urlencoded"]) {
|
|
1335
|
+
const media = rb.content["application/x-www-form-urlencoded"];
|
|
1336
|
+
return {
|
|
1337
|
+
contentType: "application/x-www-form-urlencoded",
|
|
1338
|
+
typeTS: "",
|
|
1339
|
+
schema: this.schemaConverter.schemaRefToIR(doc, media.schema),
|
|
1340
|
+
required: rb.required || false
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
if (rb.content?.["multipart/form-data"]) {
|
|
1344
|
+
return {
|
|
1345
|
+
contentType: "multipart/form-data",
|
|
1346
|
+
typeTS: "",
|
|
1347
|
+
schema: {
|
|
1348
|
+
kind: IRSchemaKind.Unknown,
|
|
1349
|
+
nullable: false
|
|
1350
|
+
},
|
|
1351
|
+
required: rb.required || false
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1354
|
+
if (rb.content) {
|
|
1355
|
+
const firstContentType = Object.keys(rb.content)[0];
|
|
1356
|
+
if (!firstContentType) {
|
|
1357
|
+
return null;
|
|
1358
|
+
}
|
|
1359
|
+
const media = rb.content[firstContentType];
|
|
1360
|
+
if (!media) {
|
|
1361
|
+
return null;
|
|
1362
|
+
}
|
|
1363
|
+
return {
|
|
1364
|
+
contentType: firstContentType,
|
|
1365
|
+
typeTS: "",
|
|
1366
|
+
schema: this.schemaConverter.schemaRefToIR(doc, media.schema),
|
|
1367
|
+
required: rb.required || false
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
return null;
|
|
1371
|
+
}
|
|
1372
|
+
/**
|
|
1373
|
+
* Extract response information with inline type extraction
|
|
1374
|
+
*/
|
|
1375
|
+
extractResponseWithTypes(doc, op, tag, operationId, method, seenTypeNames) {
|
|
1376
|
+
const extractedTypes = [];
|
|
1377
|
+
if (!op.responses) {
|
|
1378
|
+
return {
|
|
1379
|
+
response: {
|
|
1380
|
+
typeTS: "unknown",
|
|
1381
|
+
schema: {
|
|
1382
|
+
kind: IRSchemaKind.Unknown,
|
|
1383
|
+
nullable: false
|
|
1384
|
+
},
|
|
1385
|
+
description: "",
|
|
1386
|
+
isStreaming: false,
|
|
1387
|
+
contentType: ""
|
|
1388
|
+
},
|
|
1389
|
+
extractedTypes: []
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
const tryCodes = [
|
|
1393
|
+
"200",
|
|
1394
|
+
"201"
|
|
1395
|
+
];
|
|
1396
|
+
for (const code of tryCodes) {
|
|
1397
|
+
const response = op.responses[code];
|
|
1398
|
+
if (response && !("$ref" in response)) {
|
|
1399
|
+
const resp2 = response;
|
|
1400
|
+
if (resp2.content) {
|
|
1401
|
+
for (const [contentType, media] of Object.entries(resp2.content)) {
|
|
1402
|
+
const streaming = this.detectStreamingContentType(contentType);
|
|
1403
|
+
const schema = this.schemaConverter.schemaRefToIR(doc, media.schema);
|
|
1404
|
+
if (streaming.isStreaming) {
|
|
1405
|
+
return {
|
|
1406
|
+
response: {
|
|
1407
|
+
typeTS: "",
|
|
1408
|
+
schema,
|
|
1409
|
+
description: resp2.description || "",
|
|
1410
|
+
isStreaming: true,
|
|
1411
|
+
contentType,
|
|
1412
|
+
...streaming.format && {
|
|
1413
|
+
streamingFormat: streaming.format
|
|
1414
|
+
}
|
|
1415
|
+
},
|
|
1416
|
+
extractedTypes: []
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
if (contentType === "application/json") {
|
|
1420
|
+
const componentSchemaName = this.findMatchingComponentSchema(doc, media.schema);
|
|
1421
|
+
if (componentSchemaName) {
|
|
1422
|
+
return {
|
|
1423
|
+
response: {
|
|
1424
|
+
typeTS: "",
|
|
1425
|
+
schema: {
|
|
1426
|
+
kind: IRSchemaKind.Ref,
|
|
1427
|
+
ref: componentSchemaName,
|
|
1428
|
+
nullable: false
|
|
1429
|
+
},
|
|
1430
|
+
description: resp2.description || "",
|
|
1431
|
+
isStreaming: false,
|
|
1432
|
+
contentType
|
|
1433
|
+
},
|
|
1434
|
+
extractedTypes: []
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
const typeName = this.generateTypeName(schema, tag, operationId, method, op.path, "Response");
|
|
1438
|
+
if (schema.kind === IRSchemaKind.Object && !seenTypeNames.has(typeName)) {
|
|
1439
|
+
seenTypeNames.add(typeName);
|
|
1440
|
+
extractedTypes.push({
|
|
1441
|
+
name: typeName,
|
|
1442
|
+
schema,
|
|
1443
|
+
annotations: this.schemaConverter.extractAnnotations(media.schema)
|
|
1444
|
+
});
|
|
1445
|
+
return {
|
|
1446
|
+
response: {
|
|
1447
|
+
typeTS: "",
|
|
1448
|
+
schema: {
|
|
1449
|
+
kind: IRSchemaKind.Ref,
|
|
1450
|
+
ref: typeName,
|
|
1451
|
+
nullable: false
|
|
1452
|
+
},
|
|
1453
|
+
description: resp2.description || "",
|
|
1454
|
+
isStreaming: false,
|
|
1455
|
+
contentType
|
|
1456
|
+
},
|
|
1457
|
+
extractedTypes
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
return {
|
|
1461
|
+
response: {
|
|
1462
|
+
typeTS: "",
|
|
1463
|
+
schema,
|
|
1464
|
+
description: resp2.description || "",
|
|
1465
|
+
isStreaming: false,
|
|
1466
|
+
contentType
|
|
1467
|
+
},
|
|
1468
|
+
extractedTypes: []
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
const firstContentType = Object.keys(resp2.content)[0];
|
|
1473
|
+
if (!firstContentType) {
|
|
1474
|
+
return {
|
|
1475
|
+
response: {
|
|
1476
|
+
typeTS: "unknown",
|
|
1477
|
+
schema: {
|
|
1478
|
+
kind: IRSchemaKind.Unknown,
|
|
1479
|
+
nullable: false
|
|
1480
|
+
},
|
|
1481
|
+
description: resp2.description || "",
|
|
1482
|
+
isStreaming: false,
|
|
1483
|
+
contentType: ""
|
|
1484
|
+
},
|
|
1485
|
+
extractedTypes: []
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
const firstMedia = resp2.content[firstContentType];
|
|
1489
|
+
if (!firstMedia) {
|
|
1490
|
+
return {
|
|
1491
|
+
response: {
|
|
1492
|
+
typeTS: "unknown",
|
|
1493
|
+
schema: {
|
|
1494
|
+
kind: IRSchemaKind.Unknown,
|
|
1495
|
+
nullable: false
|
|
1496
|
+
},
|
|
1497
|
+
description: resp2.description || "",
|
|
1498
|
+
isStreaming: false,
|
|
1499
|
+
contentType: ""
|
|
1500
|
+
},
|
|
1501
|
+
extractedTypes: []
|
|
1502
|
+
};
|
|
1503
|
+
}
|
|
1504
|
+
const firstSchema = this.schemaConverter.schemaRefToIR(doc, firstMedia.schema);
|
|
1505
|
+
const firstStreaming = this.detectStreamingContentType(firstContentType);
|
|
1506
|
+
return {
|
|
1507
|
+
response: {
|
|
1508
|
+
typeTS: "",
|
|
1509
|
+
schema: firstSchema,
|
|
1510
|
+
description: resp2.description || "",
|
|
1511
|
+
isStreaming: firstStreaming.isStreaming,
|
|
1512
|
+
contentType: firstContentType,
|
|
1513
|
+
streamingFormat: firstStreaming.format
|
|
1514
|
+
},
|
|
1515
|
+
extractedTypes: []
|
|
1516
|
+
};
|
|
1517
|
+
}
|
|
1518
|
+
return {
|
|
1519
|
+
response: {
|
|
1520
|
+
typeTS: "void",
|
|
1521
|
+
schema: {
|
|
1522
|
+
kind: IRSchemaKind.Unknown,
|
|
1523
|
+
nullable: false
|
|
1524
|
+
},
|
|
1525
|
+
description: resp2.description || "",
|
|
1526
|
+
isStreaming: false,
|
|
1527
|
+
contentType: ""
|
|
1528
|
+
},
|
|
1529
|
+
extractedTypes: []
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
const resp = this.extractResponse(doc, op);
|
|
1534
|
+
return {
|
|
1535
|
+
response: resp,
|
|
1536
|
+
extractedTypes: []
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* Extract response information (legacy method, kept for fallback)
|
|
1541
|
+
*/
|
|
1542
|
+
extractResponse(doc, op) {
|
|
1543
|
+
if (!op.responses) {
|
|
1544
|
+
return {
|
|
1545
|
+
typeTS: "unknown",
|
|
1546
|
+
schema: {
|
|
1547
|
+
kind: IRSchemaKind.Unknown,
|
|
1548
|
+
nullable: false
|
|
1549
|
+
},
|
|
1550
|
+
description: "",
|
|
1551
|
+
isStreaming: false,
|
|
1552
|
+
contentType: ""
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1555
|
+
const tryCodes = [
|
|
1556
|
+
"200",
|
|
1557
|
+
"201"
|
|
1558
|
+
];
|
|
1559
|
+
for (const code of tryCodes) {
|
|
1560
|
+
const response = op.responses[code];
|
|
1561
|
+
if (response && !("$ref" in response)) {
|
|
1562
|
+
const resp = response;
|
|
1563
|
+
if (resp.content) {
|
|
1564
|
+
for (const [contentType, media2] of Object.entries(resp.content)) {
|
|
1565
|
+
const streaming2 = this.detectStreamingContentType(contentType);
|
|
1566
|
+
if (streaming2.isStreaming) {
|
|
1567
|
+
return {
|
|
1568
|
+
typeTS: "",
|
|
1569
|
+
schema: this.schemaConverter.schemaRefToIR(doc, media2.schema),
|
|
1570
|
+
description: resp.description || "",
|
|
1571
|
+
isStreaming: true,
|
|
1572
|
+
contentType,
|
|
1573
|
+
streamingFormat: streaming2.format
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
if (resp.content["application/json"]) {
|
|
1578
|
+
const media2 = resp.content["application/json"];
|
|
1579
|
+
return {
|
|
1580
|
+
typeTS: "",
|
|
1581
|
+
schema: this.schemaConverter.schemaRefToIR(doc, media2.schema),
|
|
1582
|
+
description: resp.description || "",
|
|
1583
|
+
isStreaming: false,
|
|
1584
|
+
contentType: "application/json"
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
const [firstContentType, media] = Object.entries(resp.content)[0] ?? [];
|
|
1588
|
+
if (!firstContentType || !media) {
|
|
1589
|
+
return {
|
|
1590
|
+
typeTS: "void",
|
|
1591
|
+
schema: {
|
|
1592
|
+
kind: IRSchemaKind.Unknown,
|
|
1593
|
+
nullable: false
|
|
1594
|
+
},
|
|
1595
|
+
description: resp.description || "",
|
|
1596
|
+
isStreaming: false,
|
|
1597
|
+
contentType: ""
|
|
1598
|
+
};
|
|
1599
|
+
}
|
|
1600
|
+
const streaming = this.detectStreamingContentType(firstContentType);
|
|
1601
|
+
return {
|
|
1602
|
+
typeTS: "",
|
|
1603
|
+
schema: this.schemaConverter.schemaRefToIR(doc, media.schema),
|
|
1604
|
+
description: resp.description || "",
|
|
1605
|
+
isStreaming: streaming.isStreaming,
|
|
1606
|
+
contentType: firstContentType,
|
|
1607
|
+
streamingFormat: streaming.format
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
return {
|
|
1611
|
+
typeTS: "void",
|
|
1612
|
+
schema: {
|
|
1613
|
+
kind: IRSchemaKind.Unknown,
|
|
1614
|
+
nullable: false
|
|
1615
|
+
},
|
|
1616
|
+
description: resp.description || "",
|
|
1617
|
+
isStreaming: false,
|
|
1618
|
+
contentType: ""
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
for (const [code, response] of Object.entries(op.responses)) {
|
|
1623
|
+
if (code.length === 3 && code[0] === "2" && response && !("$ref" in response)) {
|
|
1624
|
+
const resp = response;
|
|
1625
|
+
if (code === "204") {
|
|
1626
|
+
return {
|
|
1627
|
+
typeTS: "void",
|
|
1628
|
+
schema: {
|
|
1629
|
+
kind: IRSchemaKind.Unknown,
|
|
1630
|
+
nullable: false
|
|
1631
|
+
},
|
|
1632
|
+
description: resp.description || "",
|
|
1633
|
+
isStreaming: false,
|
|
1634
|
+
contentType: ""
|
|
1635
|
+
};
|
|
1636
|
+
}
|
|
1637
|
+
if (resp.content) {
|
|
1638
|
+
for (const [contentType, media2] of Object.entries(resp.content)) {
|
|
1639
|
+
const streaming2 = this.detectStreamingContentType(contentType);
|
|
1640
|
+
if (streaming2.isStreaming) {
|
|
1641
|
+
return {
|
|
1642
|
+
typeTS: "",
|
|
1643
|
+
schema: this.schemaConverter.schemaRefToIR(doc, media2.schema),
|
|
1644
|
+
description: resp.description || "",
|
|
1645
|
+
isStreaming: true,
|
|
1646
|
+
contentType,
|
|
1647
|
+
streamingFormat: streaming2.format
|
|
1648
|
+
};
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
if (resp.content["application/json"]) {
|
|
1652
|
+
const media2 = resp.content["application/json"];
|
|
1653
|
+
return {
|
|
1654
|
+
typeTS: "",
|
|
1655
|
+
schema: this.schemaConverter.schemaRefToIR(doc, media2.schema),
|
|
1656
|
+
description: resp.description || "",
|
|
1657
|
+
isStreaming: false,
|
|
1658
|
+
contentType: "application/json"
|
|
1659
|
+
};
|
|
1660
|
+
}
|
|
1661
|
+
const [firstContentType, media] = Object.entries(resp.content)[0] ?? [];
|
|
1662
|
+
if (!firstContentType || !media) {
|
|
1663
|
+
return {
|
|
1664
|
+
typeTS: "void",
|
|
1665
|
+
schema: {
|
|
1666
|
+
kind: IRSchemaKind.Unknown,
|
|
1667
|
+
nullable: false
|
|
1668
|
+
},
|
|
1669
|
+
description: resp.description || "",
|
|
1670
|
+
isStreaming: false,
|
|
1671
|
+
contentType: ""
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1674
|
+
const streaming = this.detectStreamingContentType(firstContentType);
|
|
1675
|
+
return {
|
|
1676
|
+
typeTS: "",
|
|
1677
|
+
schema: this.schemaConverter.schemaRefToIR(doc, media.schema),
|
|
1678
|
+
description: resp.description || "",
|
|
1679
|
+
isStreaming: streaming.isStreaming,
|
|
1680
|
+
contentType: firstContentType,
|
|
1681
|
+
streamingFormat: streaming.format
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
return {
|
|
1687
|
+
typeTS: "unknown",
|
|
1688
|
+
schema: {
|
|
1689
|
+
kind: IRSchemaKind.Unknown,
|
|
1690
|
+
nullable: false
|
|
1691
|
+
},
|
|
1692
|
+
description: "",
|
|
1693
|
+
isStreaming: false,
|
|
1694
|
+
contentType: ""
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
/**
|
|
1698
|
+
* Build structured models from components.schemas
|
|
1699
|
+
*/
|
|
1700
|
+
buildStructuredModels(doc) {
|
|
1701
|
+
const out = [];
|
|
1702
|
+
if (!doc.components?.schemas) {
|
|
1703
|
+
return out;
|
|
1704
|
+
}
|
|
1705
|
+
const names = Object.keys(doc.components.schemas).sort();
|
|
1706
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1707
|
+
for (const name of names) {
|
|
1708
|
+
seen.add(name);
|
|
1709
|
+
}
|
|
1710
|
+
for (const name of names) {
|
|
1711
|
+
const sr = doc.components.schemas[name];
|
|
1712
|
+
const schema = this.schemaConverter.schemaRefToIR(doc, sr);
|
|
1713
|
+
out.push({
|
|
1714
|
+
name,
|
|
1715
|
+
schema,
|
|
1716
|
+
annotations: this.schemaConverter.extractAnnotations(sr)
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
return out;
|
|
1720
|
+
}
|
|
1721
|
+
/**
|
|
1722
|
+
* Filter unused ModelDefs
|
|
1723
|
+
*/
|
|
1724
|
+
filterUnusedModelDefs(filteredIR, allModelDefs) {
|
|
1725
|
+
const modelDefMap = /* @__PURE__ */ new Map();
|
|
1726
|
+
for (const md of allModelDefs) {
|
|
1727
|
+
modelDefMap.set(md.name, md);
|
|
1728
|
+
}
|
|
1729
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
1730
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1731
|
+
const collectRefs = /* @__PURE__ */ __name((schema) => {
|
|
1732
|
+
if (schema.kind === "ref" && schema.ref) {
|
|
1733
|
+
const refName = schema.ref;
|
|
1734
|
+
referenced.add(refName);
|
|
1735
|
+
if (!visited.has(refName)) {
|
|
1736
|
+
visited.add(refName);
|
|
1737
|
+
const md = modelDefMap.get(refName);
|
|
1738
|
+
if (md) {
|
|
1739
|
+
collectRefs(md.schema);
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
if (schema.items) {
|
|
1744
|
+
collectRefs(schema.items);
|
|
1745
|
+
}
|
|
1746
|
+
if (schema.additionalProperties) {
|
|
1747
|
+
collectRefs(schema.additionalProperties);
|
|
1748
|
+
}
|
|
1749
|
+
if (schema.oneOf) {
|
|
1750
|
+
for (const sub of schema.oneOf) {
|
|
1751
|
+
collectRefs(sub);
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
if (schema.anyOf) {
|
|
1755
|
+
for (const sub of schema.anyOf) {
|
|
1756
|
+
collectRefs(sub);
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
if (schema.allOf) {
|
|
1760
|
+
for (const sub of schema.allOf) {
|
|
1761
|
+
collectRefs(sub);
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
if (schema.not) {
|
|
1765
|
+
collectRefs(schema.not);
|
|
1766
|
+
}
|
|
1767
|
+
if (schema.properties) {
|
|
1768
|
+
for (const field of schema.properties) {
|
|
1769
|
+
collectRefs(field.type);
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
}, "collectRefs");
|
|
1773
|
+
for (const service of filteredIR.services) {
|
|
1774
|
+
for (const op of service.operations) {
|
|
1775
|
+
for (const param of op.pathParams) {
|
|
1776
|
+
collectRefs(param.schema);
|
|
1777
|
+
}
|
|
1778
|
+
for (const param of op.queryParams) {
|
|
1779
|
+
collectRefs(param.schema);
|
|
1780
|
+
}
|
|
1781
|
+
if (op.requestBody) {
|
|
1782
|
+
collectRefs(op.requestBody.schema);
|
|
1783
|
+
}
|
|
1784
|
+
collectRefs(op.response.schema);
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
return allModelDefs.filter((md) => referenced.has(md.name));
|
|
1788
|
+
}
|
|
1789
|
+
};
|
|
1790
|
+
IrBuilderService = _ts_decorate4([
|
|
1791
|
+
(0, import_common4.Injectable)(),
|
|
1792
|
+
_ts_metadata("design:type", Function),
|
|
1793
|
+
_ts_metadata("design:paramtypes", [
|
|
1794
|
+
typeof SchemaConverterService === "undefined" ? Object : SchemaConverterService
|
|
1795
|
+
])
|
|
1796
|
+
], IrBuilderService);
|
|
1797
|
+
|
|
1798
|
+
// src/openapi/openapi.service.ts
|
|
1799
|
+
var import_common5 = require("@nestjs/common");
|
|
1800
|
+
var import_swagger_parser = __toESM(require("@apidevtools/swagger-parser"));
|
|
1801
|
+
var fs2 = __toESM(require("fs"));
|
|
1802
|
+
var path3 = __toESM(require("path"));
|
|
1803
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
1804
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1805
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1806
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1807
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1808
|
+
}
|
|
1809
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
1810
|
+
var OpenApiService = class _OpenApiService {
|
|
1811
|
+
static {
|
|
1812
|
+
__name(this, "OpenApiService");
|
|
1813
|
+
}
|
|
1814
|
+
logger = new import_common5.Logger(_OpenApiService.name);
|
|
1815
|
+
/**
|
|
1816
|
+
* Load an OpenAPI document from a local file path or an HTTP(S) URL
|
|
1817
|
+
* Supports both OpenAPI 3.0 and 3.1
|
|
1818
|
+
*/
|
|
1819
|
+
async loadDocument(input) {
|
|
1820
|
+
try {
|
|
1821
|
+
let url = null;
|
|
1822
|
+
try {
|
|
1823
|
+
url = new URL(input);
|
|
1824
|
+
} catch {
|
|
1825
|
+
}
|
|
1826
|
+
let api;
|
|
1827
|
+
if (url && (url.protocol === "http:" || url.protocol === "https:")) {
|
|
1828
|
+
this.logger.debug(`Loading OpenAPI spec from URL: ${input}`);
|
|
1829
|
+
const response = await fetch(input, {
|
|
1830
|
+
signal: AbortSignal.timeout(1e4)
|
|
1831
|
+
});
|
|
1832
|
+
if (!response.ok) {
|
|
1833
|
+
throw new Error(`Failed to fetch OpenAPI spec: HTTP ${response.status} ${response.statusText}`);
|
|
1834
|
+
}
|
|
1835
|
+
const documentText = await response.text();
|
|
1836
|
+
let documentJson;
|
|
1837
|
+
try {
|
|
1838
|
+
documentJson = JSON.parse(documentText);
|
|
1839
|
+
} catch {
|
|
1840
|
+
throw new Error("OpenAPI spec is not valid JSON");
|
|
1841
|
+
}
|
|
1842
|
+
try {
|
|
1843
|
+
const parsed = await import_swagger_parser.default.parse(documentJson);
|
|
1844
|
+
const bundled = await import_swagger_parser.default.bundle(parsed);
|
|
1845
|
+
api = bundled;
|
|
1846
|
+
} catch (error) {
|
|
1847
|
+
this.logger.debug(`Bundle failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1848
|
+
this.logger.debug("Attempting dereference directly");
|
|
1849
|
+
const parsed = await import_swagger_parser.default.parse(documentJson);
|
|
1850
|
+
const dereferenced = await import_swagger_parser.default.dereference(parsed);
|
|
1851
|
+
api = dereferenced;
|
|
1852
|
+
}
|
|
1853
|
+
} else {
|
|
1854
|
+
const filePath = path3.resolve(input);
|
|
1855
|
+
if (!fs2.existsSync(filePath)) {
|
|
1856
|
+
throw new Error(`OpenAPI spec file not found: ${filePath}`);
|
|
1857
|
+
}
|
|
1858
|
+
this.logger.debug(`Loading OpenAPI spec from file: ${filePath}`);
|
|
1859
|
+
try {
|
|
1860
|
+
api = await import_swagger_parser.default.bundle(filePath);
|
|
1861
|
+
} catch (error) {
|
|
1862
|
+
this.logger.debug(`Bundle failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1863
|
+
this.logger.debug("Attempting dereference directly");
|
|
1864
|
+
api = await import_swagger_parser.default.dereference(filePath);
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
const version = detectOpenAPIVersion(api);
|
|
1868
|
+
if (!isSupportedVersion(version)) {
|
|
1869
|
+
throw new Error(`Unsupported OpenAPI version: ${api.openapi}. Only versions 3.0.x and 3.1.0 are supported.`);
|
|
1870
|
+
}
|
|
1871
|
+
this.logger.log(`Detected OpenAPI version: ${version} (${api.openapi})`);
|
|
1872
|
+
return api;
|
|
1873
|
+
} catch (error) {
|
|
1874
|
+
if (error instanceof Error) {
|
|
1875
|
+
throw new Error(`Failed to load OpenAPI document from ${input}: ${error.message}`);
|
|
1876
|
+
}
|
|
1877
|
+
throw error;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
/**
|
|
1881
|
+
* Validate an OpenAPI document
|
|
1882
|
+
*/
|
|
1883
|
+
async validateDocument(input) {
|
|
1884
|
+
try {
|
|
1885
|
+
let url = null;
|
|
1886
|
+
try {
|
|
1887
|
+
url = new URL(input);
|
|
1888
|
+
} catch {
|
|
1889
|
+
}
|
|
1890
|
+
if (url && (url.protocol === "http:" || url.protocol === "https:")) {
|
|
1891
|
+
await import_swagger_parser.default.validate(input);
|
|
1892
|
+
} else {
|
|
1893
|
+
const filePath = path3.resolve(input);
|
|
1894
|
+
if (!fs2.existsSync(filePath)) {
|
|
1895
|
+
throw new Error(`OpenAPI spec file not found: ${filePath}`);
|
|
1896
|
+
}
|
|
1897
|
+
await import_swagger_parser.default.validate(filePath);
|
|
1898
|
+
}
|
|
1899
|
+
} catch (error) {
|
|
1900
|
+
if (error instanceof Error) {
|
|
1901
|
+
throw new Error(`Invalid OpenAPI document: ${error.message}`);
|
|
1902
|
+
}
|
|
1903
|
+
throw error;
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
};
|
|
1907
|
+
OpenApiService = _ts_decorate5([
|
|
1908
|
+
(0, import_common5.Injectable)()
|
|
1909
|
+
], OpenApiService);
|
|
1910
|
+
|
|
1911
|
+
// src/generator/generator.service.ts
|
|
1912
|
+
function _ts_decorate6(decorators, target, key, desc) {
|
|
1913
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1914
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1915
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1916
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1917
|
+
}
|
|
1918
|
+
__name(_ts_decorate6, "_ts_decorate");
|
|
1919
|
+
function _ts_metadata2(k, v) {
|
|
1920
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1921
|
+
}
|
|
1922
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
1923
|
+
var GeneratorService = class _GeneratorService {
|
|
1924
|
+
static {
|
|
1925
|
+
__name(this, "GeneratorService");
|
|
1926
|
+
}
|
|
1927
|
+
irBuilder;
|
|
1928
|
+
openApiService;
|
|
1929
|
+
logger = new import_common6.Logger(_GeneratorService.name);
|
|
1930
|
+
generators = /* @__PURE__ */ new Map();
|
|
1931
|
+
constructor(irBuilder, openApiService) {
|
|
1932
|
+
this.irBuilder = irBuilder;
|
|
1933
|
+
this.openApiService = openApiService;
|
|
1934
|
+
}
|
|
1935
|
+
/**
|
|
1936
|
+
* Register a generator
|
|
1937
|
+
*/
|
|
1938
|
+
register(generator) {
|
|
1939
|
+
this.generators.set(generator.getType(), generator);
|
|
1940
|
+
this.logger.debug(`Registered generator: ${generator.getType()}`);
|
|
1941
|
+
}
|
|
1942
|
+
/**
|
|
1943
|
+
* Get a generator by type
|
|
1944
|
+
*/
|
|
1945
|
+
getGenerator(type) {
|
|
1946
|
+
return this.generators.get(type);
|
|
1947
|
+
}
|
|
1948
|
+
/**
|
|
1949
|
+
* Get all available generator types
|
|
1950
|
+
*/
|
|
1951
|
+
getAvailableTypes() {
|
|
1952
|
+
return Array.from(this.generators.keys());
|
|
1953
|
+
}
|
|
1954
|
+
/**
|
|
1955
|
+
* Generate SDK for a client
|
|
1956
|
+
* TypeScript will narrow the client type based on the discriminated union
|
|
1957
|
+
*/
|
|
1958
|
+
async generate(spec, client) {
|
|
1959
|
+
const generator = this.getGenerator(client.type);
|
|
1960
|
+
if (!generator) {
|
|
1961
|
+
throw new Error(`Unsupported client type: ${client.type}`);
|
|
1962
|
+
}
|
|
1963
|
+
const doc = await this.openApiService.loadDocument(spec);
|
|
1964
|
+
const fullIR = this.irBuilder.buildIR(doc);
|
|
1965
|
+
const filteredIR = this.irBuilder.filterIR(fullIR, client);
|
|
1966
|
+
await generator.generate(client, filteredIR);
|
|
1967
|
+
}
|
|
1968
|
+
};
|
|
1969
|
+
GeneratorService = _ts_decorate6([
|
|
1970
|
+
(0, import_common6.Injectable)(),
|
|
1971
|
+
_ts_metadata2("design:type", Function),
|
|
1972
|
+
_ts_metadata2("design:paramtypes", [
|
|
1973
|
+
typeof IrBuilderService === "undefined" ? Object : IrBuilderService,
|
|
1974
|
+
typeof OpenApiService === "undefined" ? Object : OpenApiService
|
|
1975
|
+
])
|
|
1976
|
+
], GeneratorService);
|
|
1977
|
+
|
|
1978
|
+
// src/generator/generator.module.ts
|
|
1979
|
+
var import_common9 = require("@nestjs/common");
|
|
1980
|
+
|
|
1981
|
+
// src/openapi/openapi.module.ts
|
|
1982
|
+
var import_common7 = require("@nestjs/common");
|
|
1983
|
+
function _ts_decorate7(decorators, target, key, desc) {
|
|
1984
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1985
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1986
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1987
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1988
|
+
}
|
|
1989
|
+
__name(_ts_decorate7, "_ts_decorate");
|
|
1990
|
+
var OpenApiModule = class {
|
|
1991
|
+
static {
|
|
1992
|
+
__name(this, "OpenApiModule");
|
|
1993
|
+
}
|
|
1994
|
+
};
|
|
1995
|
+
OpenApiModule = _ts_decorate7([
|
|
1996
|
+
(0, import_common7.Module)({
|
|
1997
|
+
providers: [
|
|
1998
|
+
OpenApiService
|
|
1999
|
+
],
|
|
2000
|
+
exports: [
|
|
2001
|
+
OpenApiService
|
|
2002
|
+
]
|
|
2003
|
+
})
|
|
2004
|
+
], OpenApiModule);
|
|
2005
|
+
|
|
2006
|
+
// src/generator/typescript/typescript-generator.service.ts
|
|
2007
|
+
var import_common8 = require("@nestjs/common");
|
|
2008
|
+
var fs4 = __toESM(require("fs"));
|
|
2009
|
+
var path5 = __toESM(require("path"));
|
|
2010
|
+
var Handlebars2 = __toESM(require("handlebars"));
|
|
2011
|
+
|
|
2012
|
+
// src/generator/handlebars-helpers.ts
|
|
2013
|
+
var Handlebars = __toESM(require("handlebars"));
|
|
2014
|
+
function registerCommonHandlebarsHelpers() {
|
|
2015
|
+
Handlebars.registerHelper("pascal", (str) => toPascalCase(str));
|
|
2016
|
+
Handlebars.registerHelper("camel", (str) => toCamelCase(str));
|
|
2017
|
+
Handlebars.registerHelper("kebab", (str) => toKebabCase(str));
|
|
2018
|
+
Handlebars.registerHelper("snake", (str) => toSnakeCase(str));
|
|
2019
|
+
Handlebars.registerHelper("serviceName", (tag) => toPascalCase(tag) + "Service");
|
|
2020
|
+
Handlebars.registerHelper("serviceProp", (tag) => toCamelCase(tag));
|
|
2021
|
+
Handlebars.registerHelper("fileBase", (tag) => toSnakeCase(tag).toLowerCase());
|
|
2022
|
+
Handlebars.registerHelper("eq", (a, b) => a === b);
|
|
2023
|
+
Handlebars.registerHelper("ne", (a, b) => a !== b);
|
|
2024
|
+
Handlebars.registerHelper("gt", (a, b) => a > b);
|
|
2025
|
+
Handlebars.registerHelper("lt", (a, b) => a < b);
|
|
2026
|
+
Handlebars.registerHelper("sub", (a, b) => a - b);
|
|
2027
|
+
Handlebars.registerHelper("subtract", (a, b) => a - b);
|
|
2028
|
+
Handlebars.registerHelper("len", (arr) => Array.isArray(arr) ? arr.length : 0);
|
|
2029
|
+
Handlebars.registerHelper("lte", (a, b) => a <= b);
|
|
2030
|
+
Handlebars.registerHelper("or", function(...args) {
|
|
2031
|
+
const options = args[args.length - 1];
|
|
2032
|
+
if (options && "fn" in options && options.fn) {
|
|
2033
|
+
return args.slice(0, -1).some((a) => a) ? options.fn(this) : options.inverse?.(this);
|
|
2034
|
+
}
|
|
2035
|
+
return args.slice(0, -1).some((a) => a);
|
|
2036
|
+
});
|
|
2037
|
+
Handlebars.registerHelper("and", function(...args) {
|
|
2038
|
+
const options = args[args.length - 1];
|
|
2039
|
+
if (options && "fn" in options && options.fn) {
|
|
2040
|
+
return args.slice(0, -1).every((a) => a) ? options.fn(this) : options.inverse?.(this);
|
|
2041
|
+
}
|
|
2042
|
+
return args.slice(0, -1).every((a) => a);
|
|
2043
|
+
});
|
|
2044
|
+
Handlebars.registerHelper("replace", (str, search, replace) => {
|
|
2045
|
+
if (typeof str !== "string") return str;
|
|
2046
|
+
return str.replace(new RegExp(search.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), replace);
|
|
2047
|
+
});
|
|
2048
|
+
Handlebars.registerHelper("index", (arr, idx) => arr?.[idx]);
|
|
2049
|
+
Handlebars.registerHelper("getServiceName", (tag) => {
|
|
2050
|
+
const parts = tag.split(".");
|
|
2051
|
+
return parts.length > 1 ? parts[1] : tag;
|
|
2052
|
+
});
|
|
2053
|
+
Handlebars.registerHelper("groupByNamespace", (services) => {
|
|
2054
|
+
const namespaces = {};
|
|
2055
|
+
for (const service of services) {
|
|
2056
|
+
const parts = service.tag.split(".");
|
|
2057
|
+
if (parts.length === 1) {
|
|
2058
|
+
if (!namespaces[""]) namespaces[""] = [];
|
|
2059
|
+
namespaces[""]?.push(service);
|
|
2060
|
+
} else {
|
|
2061
|
+
const namespace = parts[0];
|
|
2062
|
+
if (namespace && !namespaces[namespace]) {
|
|
2063
|
+
namespaces[namespace] = [];
|
|
2064
|
+
}
|
|
2065
|
+
if (namespace) {
|
|
2066
|
+
namespaces[namespace]?.push(service);
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
return namespaces;
|
|
2071
|
+
});
|
|
2072
|
+
Handlebars.registerHelper("getRootServices", (services) => {
|
|
2073
|
+
return services.filter((s) => !s.tag.includes("."));
|
|
2074
|
+
});
|
|
2075
|
+
Handlebars.registerHelper("dict", () => ({}));
|
|
2076
|
+
Handlebars.registerHelper("setVar", (name, value, options) => {
|
|
2077
|
+
if (options?.data?.root && typeof options.data.root === "object") {
|
|
2078
|
+
options.data.root[`_${name}`] = value;
|
|
2079
|
+
}
|
|
2080
|
+
return "";
|
|
2081
|
+
});
|
|
2082
|
+
Handlebars.registerHelper("getVar", (name, options) => {
|
|
2083
|
+
if (options?.data?.root && typeof options.data.root === "object") {
|
|
2084
|
+
return options.data.root[`_${name}`] || false;
|
|
2085
|
+
}
|
|
2086
|
+
return false;
|
|
2087
|
+
});
|
|
2088
|
+
Handlebars.registerHelper("set", (obj, key, value) => {
|
|
2089
|
+
if (obj && typeof obj === "object") {
|
|
2090
|
+
obj[key] = value;
|
|
2091
|
+
}
|
|
2092
|
+
return "";
|
|
2093
|
+
});
|
|
2094
|
+
Handlebars.registerHelper("hasKey", (obj, key) => {
|
|
2095
|
+
return obj && typeof obj === "object" && key in obj;
|
|
2096
|
+
});
|
|
2097
|
+
Handlebars.registerHelper("lookup", (obj, key) => {
|
|
2098
|
+
return obj && typeof obj === "object" ? obj[key] : void 0;
|
|
2099
|
+
});
|
|
2100
|
+
Handlebars.registerHelper("reMatch", (pattern, str) => {
|
|
2101
|
+
try {
|
|
2102
|
+
const regex = new RegExp(pattern);
|
|
2103
|
+
return regex.test(str);
|
|
2104
|
+
} catch {
|
|
2105
|
+
return false;
|
|
2106
|
+
}
|
|
2107
|
+
});
|
|
2108
|
+
}
|
|
2109
|
+
__name(registerCommonHandlebarsHelpers, "registerCommonHandlebarsHelpers");
|
|
2110
|
+
|
|
2111
|
+
// src/generator/typescript/helpers.ts
|
|
2112
|
+
function decodeHtmlEntities(str) {
|
|
2113
|
+
return str.replace(/"/g, '"').replace(/</g, "<").replace(/>/g, ">").replace(/`/g, "`").replace(/`/g, "`").replace(/&/g, "&");
|
|
2114
|
+
}
|
|
2115
|
+
__name(decodeHtmlEntities, "decodeHtmlEntities");
|
|
2116
|
+
function schemaToTSType(s, predefinedTypes, modelDefs, isSameFile = false) {
|
|
2117
|
+
let t;
|
|
2118
|
+
switch (s.kind) {
|
|
2119
|
+
case IRSchemaKind.String:
|
|
2120
|
+
if (s.format === "binary") {
|
|
2121
|
+
t = "Blob";
|
|
2122
|
+
} else {
|
|
2123
|
+
t = "string";
|
|
2124
|
+
}
|
|
2125
|
+
break;
|
|
2126
|
+
case IRSchemaKind.Number:
|
|
2127
|
+
case IRSchemaKind.Integer:
|
|
2128
|
+
t = "number";
|
|
2129
|
+
break;
|
|
2130
|
+
case IRSchemaKind.Boolean:
|
|
2131
|
+
t = "boolean";
|
|
2132
|
+
break;
|
|
2133
|
+
case IRSchemaKind.Null:
|
|
2134
|
+
t = "null";
|
|
2135
|
+
break;
|
|
2136
|
+
case IRSchemaKind.Ref:
|
|
2137
|
+
if (s.ref) {
|
|
2138
|
+
if (predefinedTypes?.some((pt) => pt.type === s.ref)) {
|
|
2139
|
+
t = s.ref;
|
|
2140
|
+
} else if (isSameFile && modelDefs) {
|
|
2141
|
+
const localType = modelDefs.find((md) => md.name === s.ref);
|
|
2142
|
+
if (localType) {
|
|
2143
|
+
t = s.ref;
|
|
2144
|
+
} else {
|
|
2145
|
+
t = "Schema." + s.ref;
|
|
2146
|
+
}
|
|
2147
|
+
} else {
|
|
2148
|
+
t = "Schema." + s.ref;
|
|
2149
|
+
}
|
|
2150
|
+
} else {
|
|
2151
|
+
t = "unknown";
|
|
2152
|
+
}
|
|
2153
|
+
break;
|
|
2154
|
+
case IRSchemaKind.Array:
|
|
2155
|
+
if (s.items) {
|
|
2156
|
+
const inner = schemaToTSType(s.items, predefinedTypes, modelDefs);
|
|
2157
|
+
if (inner.includes(" | ") || inner.includes(" & ")) {
|
|
2158
|
+
t = `(${inner})[]`;
|
|
2159
|
+
} else {
|
|
2160
|
+
t = `${inner}[]`;
|
|
2161
|
+
}
|
|
2162
|
+
} else {
|
|
2163
|
+
t = "unknown[]";
|
|
2164
|
+
}
|
|
2165
|
+
break;
|
|
2166
|
+
case IRSchemaKind.OneOf:
|
|
2167
|
+
if (s.oneOf) {
|
|
2168
|
+
const parts = s.oneOf.map((sub) => schemaToTSType(sub, predefinedTypes, modelDefs));
|
|
2169
|
+
t = parts.join(" | ");
|
|
2170
|
+
} else {
|
|
2171
|
+
t = "unknown";
|
|
2172
|
+
}
|
|
2173
|
+
break;
|
|
2174
|
+
case IRSchemaKind.AnyOf:
|
|
2175
|
+
if (s.anyOf) {
|
|
2176
|
+
const parts = s.anyOf.map((sub) => schemaToTSType(sub, predefinedTypes, modelDefs));
|
|
2177
|
+
t = parts.join(" | ");
|
|
2178
|
+
} else {
|
|
2179
|
+
t = "unknown";
|
|
2180
|
+
}
|
|
2181
|
+
break;
|
|
2182
|
+
case IRSchemaKind.AllOf:
|
|
2183
|
+
if (s.allOf) {
|
|
2184
|
+
const parts = s.allOf.map((sub) => schemaToTSType(sub, predefinedTypes, modelDefs));
|
|
2185
|
+
t = parts.join(" & ");
|
|
2186
|
+
} else {
|
|
2187
|
+
t = "unknown";
|
|
2188
|
+
}
|
|
2189
|
+
break;
|
|
2190
|
+
case IRSchemaKind.Enum:
|
|
2191
|
+
if (s.enumValues && s.enumValues.length > 0) {
|
|
2192
|
+
const vals = [];
|
|
2193
|
+
switch (s.enumBase) {
|
|
2194
|
+
case IRSchemaKind.Number:
|
|
2195
|
+
case IRSchemaKind.Integer:
|
|
2196
|
+
for (const v of s.enumValues) {
|
|
2197
|
+
vals.push(v);
|
|
2198
|
+
}
|
|
2199
|
+
break;
|
|
2200
|
+
case IRSchemaKind.Boolean:
|
|
2201
|
+
for (const v of s.enumValues) {
|
|
2202
|
+
if (v === "true" || v === "false") {
|
|
2203
|
+
vals.push(v);
|
|
2204
|
+
} else {
|
|
2205
|
+
vals.push(`"${v}"`);
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
break;
|
|
2209
|
+
default:
|
|
2210
|
+
for (const v of s.enumValues) {
|
|
2211
|
+
vals.push(`"${v}"`);
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
t = vals.join(" | ");
|
|
2215
|
+
} else {
|
|
2216
|
+
t = "unknown";
|
|
2217
|
+
}
|
|
2218
|
+
break;
|
|
2219
|
+
case IRSchemaKind.Object:
|
|
2220
|
+
if (!s.properties || s.properties.length === 0) {
|
|
2221
|
+
t = "Record<string, unknown>";
|
|
2222
|
+
} else {
|
|
2223
|
+
const parts = [];
|
|
2224
|
+
for (const f of s.properties) {
|
|
2225
|
+
const ft = schemaToTSType(f.type, predefinedTypes, modelDefs, isSameFile);
|
|
2226
|
+
if (f.required) {
|
|
2227
|
+
parts.push(`${f.name}: ${ft}`);
|
|
2228
|
+
} else {
|
|
2229
|
+
parts.push(`${f.name}?: ${ft}`);
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
t = "{ " + parts.join("; ") + " }";
|
|
2233
|
+
}
|
|
2234
|
+
break;
|
|
2235
|
+
default:
|
|
2236
|
+
t = "unknown";
|
|
2237
|
+
}
|
|
2238
|
+
if (s.nullable && t !== "null") {
|
|
2239
|
+
t += " | null";
|
|
2240
|
+
}
|
|
2241
|
+
return decodeHtmlEntities(t);
|
|
2242
|
+
}
|
|
2243
|
+
__name(schemaToTSType, "schemaToTSType");
|
|
2244
|
+
function deriveMethodName(op) {
|
|
2245
|
+
const path7 = op.path;
|
|
2246
|
+
const hasID = path7.includes("{") && path7.includes("}");
|
|
2247
|
+
if (op.operationID) {
|
|
2248
|
+
return toCamelCase(op.operationID);
|
|
2249
|
+
}
|
|
2250
|
+
switch (op.method) {
|
|
2251
|
+
case "GET":
|
|
2252
|
+
return hasID ? "get" : "list";
|
|
2253
|
+
case "POST":
|
|
2254
|
+
return "create";
|
|
2255
|
+
case "PUT":
|
|
2256
|
+
case "PATCH":
|
|
2257
|
+
return "update";
|
|
2258
|
+
case "DELETE":
|
|
2259
|
+
return "delete";
|
|
2260
|
+
default:
|
|
2261
|
+
return op.method.toLowerCase();
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
__name(deriveMethodName, "deriveMethodName");
|
|
2265
|
+
async function resolveMethodName(client, op) {
|
|
2266
|
+
if (client.operationIdParser) {
|
|
2267
|
+
try {
|
|
2268
|
+
const name = await client.operationIdParser(op.operationID, op.method, op.path);
|
|
2269
|
+
if (name) {
|
|
2270
|
+
return toCamelCase(name);
|
|
2271
|
+
}
|
|
2272
|
+
} catch {
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
const defaultParsed = defaultParseOperationID(op.operationID);
|
|
2276
|
+
if (defaultParsed) {
|
|
2277
|
+
return toCamelCase(defaultParsed);
|
|
2278
|
+
}
|
|
2279
|
+
return deriveMethodName(op);
|
|
2280
|
+
}
|
|
2281
|
+
__name(resolveMethodName, "resolveMethodName");
|
|
2282
|
+
function defaultParseOperationID(opID) {
|
|
2283
|
+
if (!opID) {
|
|
2284
|
+
return "";
|
|
2285
|
+
}
|
|
2286
|
+
const idx = opID.indexOf("Controller_");
|
|
2287
|
+
if (idx >= 0) {
|
|
2288
|
+
return opID.substring(idx + "Controller_".length);
|
|
2289
|
+
}
|
|
2290
|
+
return opID;
|
|
2291
|
+
}
|
|
2292
|
+
__name(defaultParseOperationID, "defaultParseOperationID");
|
|
2293
|
+
function buildPathTemplate(op) {
|
|
2294
|
+
const path7 = op.path;
|
|
2295
|
+
let result = "`";
|
|
2296
|
+
for (let i = 0; i < path7.length; i++) {
|
|
2297
|
+
if (path7[i] === "{") {
|
|
2298
|
+
let j = i + 1;
|
|
2299
|
+
while (j < path7.length && path7[j] !== "}") {
|
|
2300
|
+
j++;
|
|
2301
|
+
}
|
|
2302
|
+
if (j < path7.length) {
|
|
2303
|
+
const name = path7.substring(i + 1, j);
|
|
2304
|
+
result += `\${encodeURIComponent(${name})}`;
|
|
2305
|
+
i = j;
|
|
2306
|
+
continue;
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
result += path7[i];
|
|
2310
|
+
}
|
|
2311
|
+
result += "`";
|
|
2312
|
+
return result;
|
|
2313
|
+
}
|
|
2314
|
+
__name(buildPathTemplate, "buildPathTemplate");
|
|
2315
|
+
function buildQueryKeyBase(op) {
|
|
2316
|
+
const path7 = op.path;
|
|
2317
|
+
const parts = path7.split("/");
|
|
2318
|
+
const baseParts = [];
|
|
2319
|
+
for (const p of parts) {
|
|
2320
|
+
if (p === "") {
|
|
2321
|
+
continue;
|
|
2322
|
+
}
|
|
2323
|
+
if (p.startsWith("{") && p.endsWith("}")) {
|
|
2324
|
+
continue;
|
|
2325
|
+
}
|
|
2326
|
+
baseParts.push(p);
|
|
2327
|
+
}
|
|
2328
|
+
const base = baseParts.join("/");
|
|
2329
|
+
return `'${base}'`;
|
|
2330
|
+
}
|
|
2331
|
+
__name(buildQueryKeyBase, "buildQueryKeyBase");
|
|
2332
|
+
function orderPathParams(op) {
|
|
2333
|
+
const ordered = [];
|
|
2334
|
+
const index = /* @__PURE__ */ new Map();
|
|
2335
|
+
for (let i = 0; i < op.pathParams.length; i++) {
|
|
2336
|
+
const param = op.pathParams[i];
|
|
2337
|
+
if (param) {
|
|
2338
|
+
index.set(param.name, i);
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
const path7 = op.path;
|
|
2342
|
+
for (let i = 0; i < path7.length; i++) {
|
|
2343
|
+
if (path7[i] === "{") {
|
|
2344
|
+
let j = i + 1;
|
|
2345
|
+
while (j < path7.length && path7[j] !== "}") {
|
|
2346
|
+
j++;
|
|
2347
|
+
}
|
|
2348
|
+
if (j < path7.length) {
|
|
2349
|
+
const name = path7.substring(i + 1, j);
|
|
2350
|
+
const idx = index.get(name);
|
|
2351
|
+
if (idx !== void 0) {
|
|
2352
|
+
const param = op.pathParams[idx];
|
|
2353
|
+
if (param) {
|
|
2354
|
+
ordered.push(param);
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
i = j;
|
|
2358
|
+
continue;
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
return ordered;
|
|
2363
|
+
}
|
|
2364
|
+
__name(orderPathParams, "orderPathParams");
|
|
2365
|
+
function schemaToTSTypeWithSimpleTypes(s, modelDefs, predefinedTypes, isSameFile = false) {
|
|
2366
|
+
return schemaToTSType(s, predefinedTypes, modelDefs, isSameFile);
|
|
2367
|
+
}
|
|
2368
|
+
__name(schemaToTSTypeWithSimpleTypes, "schemaToTSTypeWithSimpleTypes");
|
|
2369
|
+
function buildMethodSignature(op, methodName, modelDefs, predefinedTypes, isSameFile = false) {
|
|
2370
|
+
const parts = [];
|
|
2371
|
+
for (const p of orderPathParams(op)) {
|
|
2372
|
+
parts.push(`${p.name}: ${schemaToTSTypeWithSimpleTypes(p.schema, modelDefs, predefinedTypes, isSameFile)}`);
|
|
2373
|
+
}
|
|
2374
|
+
if (op.queryParams.length > 0) {
|
|
2375
|
+
const queryType = toPascalCase(op.tag) + toPascalCase(methodName) + "Query";
|
|
2376
|
+
parts.push(`query?: Schema.${queryType}`);
|
|
2377
|
+
}
|
|
2378
|
+
if (op.requestBody) {
|
|
2379
|
+
const opt = op.requestBody.required === true ? "" : "?";
|
|
2380
|
+
parts.push(`body${opt}: ${schemaToTSTypeWithSimpleTypes(op.requestBody.schema, modelDefs, predefinedTypes, isSameFile)}`);
|
|
2381
|
+
}
|
|
2382
|
+
parts.push('init?: Omit<RequestInit, "method" | "body">');
|
|
2383
|
+
return parts;
|
|
2384
|
+
}
|
|
2385
|
+
__name(buildMethodSignature, "buildMethodSignature");
|
|
2386
|
+
function collectPredefinedTypesUsedInSchema(modelDefs, predefinedTypes) {
|
|
2387
|
+
if (!predefinedTypes || predefinedTypes.length === 0) {
|
|
2388
|
+
return [];
|
|
2389
|
+
}
|
|
2390
|
+
const usedTypes = /* @__PURE__ */ new Set();
|
|
2391
|
+
const resolveRef = /* @__PURE__ */ __name((ref) => {
|
|
2392
|
+
const modelDef = modelDefs.find((md) => md.name === ref);
|
|
2393
|
+
return modelDef ? modelDef.schema : null;
|
|
2394
|
+
}, "resolveRef");
|
|
2395
|
+
const checkSchema = /* @__PURE__ */ __name((schema) => {
|
|
2396
|
+
if (schema.kind === "ref" && schema.ref) {
|
|
2397
|
+
const isPredefined = predefinedTypes.some((pt) => pt.type === schema.ref);
|
|
2398
|
+
if (isPredefined) {
|
|
2399
|
+
usedTypes.add(schema.ref);
|
|
2400
|
+
} else {
|
|
2401
|
+
const resolved = resolveRef(schema.ref);
|
|
2402
|
+
if (resolved) {
|
|
2403
|
+
checkSchema(resolved);
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
} else if (schema.kind === "array" && schema.items) {
|
|
2407
|
+
checkSchema(schema.items);
|
|
2408
|
+
} else if (schema.kind === "object" && schema.properties) {
|
|
2409
|
+
for (const prop of schema.properties) {
|
|
2410
|
+
checkSchema(prop.type);
|
|
2411
|
+
}
|
|
2412
|
+
} else if (schema.kind === "oneOf" && schema.oneOf) {
|
|
2413
|
+
for (const sub of schema.oneOf) {
|
|
2414
|
+
checkSchema(sub);
|
|
2415
|
+
}
|
|
2416
|
+
} else if (schema.kind === "anyOf" && schema.anyOf) {
|
|
2417
|
+
for (const sub of schema.anyOf) {
|
|
2418
|
+
checkSchema(sub);
|
|
2419
|
+
}
|
|
2420
|
+
} else if (schema.kind === "allOf" && schema.allOf) {
|
|
2421
|
+
for (const sub of schema.allOf) {
|
|
2422
|
+
checkSchema(sub);
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
}, "checkSchema");
|
|
2426
|
+
for (const modelDef of modelDefs) {
|
|
2427
|
+
checkSchema(modelDef.schema);
|
|
2428
|
+
}
|
|
2429
|
+
return predefinedTypes.filter((pt) => usedTypes.has(pt.type));
|
|
2430
|
+
}
|
|
2431
|
+
__name(collectPredefinedTypesUsedInSchema, "collectPredefinedTypesUsedInSchema");
|
|
2432
|
+
function collectPredefinedTypesUsedInService(service, predefinedTypes, modelDefs) {
|
|
2433
|
+
if (!predefinedTypes || predefinedTypes.length === 0) {
|
|
2434
|
+
return [];
|
|
2435
|
+
}
|
|
2436
|
+
const usedTypes = /* @__PURE__ */ new Set();
|
|
2437
|
+
const resolveRef = /* @__PURE__ */ __name((ref) => {
|
|
2438
|
+
if (!modelDefs) return null;
|
|
2439
|
+
const modelDef = modelDefs.find((md) => md.name === ref);
|
|
2440
|
+
return modelDef ? modelDef.schema : null;
|
|
2441
|
+
}, "resolveRef");
|
|
2442
|
+
const checkSchema = /* @__PURE__ */ __name((schema) => {
|
|
2443
|
+
if (schema.kind === "ref" && schema.ref) {
|
|
2444
|
+
const isPredefined = predefinedTypes.some((pt) => pt.type === schema.ref);
|
|
2445
|
+
if (isPredefined) {
|
|
2446
|
+
usedTypes.add(schema.ref);
|
|
2447
|
+
} else {
|
|
2448
|
+
const resolved = resolveRef(schema.ref);
|
|
2449
|
+
if (resolved) {
|
|
2450
|
+
checkSchema(resolved);
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
} else if (schema.kind === "array" && schema.items) {
|
|
2454
|
+
checkSchema(schema.items);
|
|
2455
|
+
} else if (schema.kind === "object" && schema.properties) {
|
|
2456
|
+
for (const prop of schema.properties) {
|
|
2457
|
+
checkSchema(prop.type);
|
|
2458
|
+
}
|
|
2459
|
+
} else if (schema.kind === "oneOf" && schema.oneOf) {
|
|
2460
|
+
for (const sub of schema.oneOf) {
|
|
2461
|
+
checkSchema(sub);
|
|
2462
|
+
}
|
|
2463
|
+
} else if (schema.kind === "anyOf" && schema.anyOf) {
|
|
2464
|
+
for (const sub of schema.anyOf) {
|
|
2465
|
+
checkSchema(sub);
|
|
2466
|
+
}
|
|
2467
|
+
} else if (schema.kind === "allOf" && schema.allOf) {
|
|
2468
|
+
for (const sub of schema.allOf) {
|
|
2469
|
+
checkSchema(sub);
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
}, "checkSchema");
|
|
2473
|
+
for (const op of service.operations) {
|
|
2474
|
+
for (const param of op.pathParams) {
|
|
2475
|
+
checkSchema(param.schema);
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
return predefinedTypes.filter((pt) => usedTypes.has(pt.type));
|
|
2479
|
+
}
|
|
2480
|
+
__name(collectPredefinedTypesUsedInService, "collectPredefinedTypesUsedInService");
|
|
2481
|
+
function queryKeyArgs(op) {
|
|
2482
|
+
const out = [];
|
|
2483
|
+
for (const p of orderPathParams(op)) {
|
|
2484
|
+
out.push(p.name);
|
|
2485
|
+
}
|
|
2486
|
+
if (op.queryParams.length > 0) {
|
|
2487
|
+
out.push("query");
|
|
2488
|
+
}
|
|
2489
|
+
if (op.requestBody) {
|
|
2490
|
+
out.push("body");
|
|
2491
|
+
}
|
|
2492
|
+
return out;
|
|
2493
|
+
}
|
|
2494
|
+
__name(queryKeyArgs, "queryKeyArgs");
|
|
2495
|
+
function buildQueryKeyReturnType(op, methodName, modelDefs, predefinedTypes, isSameFile = false) {
|
|
2496
|
+
const baseType = buildQueryKeyBase(op);
|
|
2497
|
+
const pathParamTypes = [];
|
|
2498
|
+
for (const p of orderPathParams(op)) {
|
|
2499
|
+
const type = schemaToTSTypeWithSimpleTypes(p.schema, modelDefs, predefinedTypes, isSameFile);
|
|
2500
|
+
pathParamTypes.push(type);
|
|
2501
|
+
}
|
|
2502
|
+
const hasOptionalQuery = op.queryParams.length > 0;
|
|
2503
|
+
const hasOptionalBody = op.requestBody && !op.requestBody.required;
|
|
2504
|
+
const hasRequiredBody = op.requestBody && op.requestBody.required;
|
|
2505
|
+
const buildTuple = /* @__PURE__ */ __name((types) => {
|
|
2506
|
+
const allTypes = [
|
|
2507
|
+
baseType,
|
|
2508
|
+
...types
|
|
2509
|
+
];
|
|
2510
|
+
return `readonly [${allTypes.join(", ")}]`;
|
|
2511
|
+
}, "buildTuple");
|
|
2512
|
+
if (!hasOptionalQuery && !hasOptionalBody) {
|
|
2513
|
+
if (hasRequiredBody) {
|
|
2514
|
+
if (!op.requestBody?.schema) {
|
|
2515
|
+
throw new Error("Request body schema is required");
|
|
2516
|
+
}
|
|
2517
|
+
const bodyType = schemaToTSTypeWithSimpleTypes(op.requestBody.schema, modelDefs, predefinedTypes, isSameFile);
|
|
2518
|
+
return buildTuple([
|
|
2519
|
+
...pathParamTypes,
|
|
2520
|
+
bodyType
|
|
2521
|
+
]);
|
|
2522
|
+
}
|
|
2523
|
+
return buildTuple(pathParamTypes);
|
|
2524
|
+
}
|
|
2525
|
+
const unionTypes = [];
|
|
2526
|
+
if (hasOptionalQuery && hasOptionalBody) {
|
|
2527
|
+
const queryType = `Schema.${toPascalCase(op.tag)}${toPascalCase(methodName)}Query`;
|
|
2528
|
+
const bodyType = schemaToTSTypeWithSimpleTypes(
|
|
2529
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
2530
|
+
op.requestBody.schema,
|
|
2531
|
+
modelDefs,
|
|
2532
|
+
predefinedTypes,
|
|
2533
|
+
isSameFile
|
|
2534
|
+
);
|
|
2535
|
+
unionTypes.push(buildTuple(pathParamTypes));
|
|
2536
|
+
unionTypes.push(buildTuple([
|
|
2537
|
+
...pathParamTypes,
|
|
2538
|
+
queryType
|
|
2539
|
+
]));
|
|
2540
|
+
unionTypes.push(buildTuple([
|
|
2541
|
+
...pathParamTypes,
|
|
2542
|
+
bodyType
|
|
2543
|
+
]));
|
|
2544
|
+
unionTypes.push(buildTuple([
|
|
2545
|
+
...pathParamTypes,
|
|
2546
|
+
queryType,
|
|
2547
|
+
bodyType
|
|
2548
|
+
]));
|
|
2549
|
+
} else if (hasOptionalQuery) {
|
|
2550
|
+
const queryType = `Schema.${toPascalCase(op.tag)}${toPascalCase(methodName)}Query`;
|
|
2551
|
+
if (hasRequiredBody) {
|
|
2552
|
+
if (!op.requestBody?.schema) {
|
|
2553
|
+
throw new Error("Request body schema is required");
|
|
2554
|
+
}
|
|
2555
|
+
const bodyType = schemaToTSTypeWithSimpleTypes(op.requestBody.schema, modelDefs, predefinedTypes, isSameFile);
|
|
2556
|
+
unionTypes.push(buildTuple([
|
|
2557
|
+
...pathParamTypes,
|
|
2558
|
+
bodyType
|
|
2559
|
+
]));
|
|
2560
|
+
unionTypes.push(buildTuple([
|
|
2561
|
+
...pathParamTypes,
|
|
2562
|
+
bodyType,
|
|
2563
|
+
queryType
|
|
2564
|
+
]));
|
|
2565
|
+
} else {
|
|
2566
|
+
unionTypes.push(buildTuple(pathParamTypes));
|
|
2567
|
+
unionTypes.push(buildTuple([
|
|
2568
|
+
...pathParamTypes,
|
|
2569
|
+
queryType
|
|
2570
|
+
]));
|
|
2571
|
+
}
|
|
2572
|
+
} else if (hasOptionalBody) {
|
|
2573
|
+
if (!op.requestBody?.schema) {
|
|
2574
|
+
throw new Error("Request body schema is required");
|
|
2575
|
+
}
|
|
2576
|
+
const bodyType = schemaToTSTypeWithSimpleTypes(op.requestBody.schema, modelDefs, predefinedTypes, isSameFile);
|
|
2577
|
+
unionTypes.push(buildTuple(pathParamTypes));
|
|
2578
|
+
unionTypes.push(buildTuple([
|
|
2579
|
+
...pathParamTypes,
|
|
2580
|
+
bodyType
|
|
2581
|
+
]));
|
|
2582
|
+
}
|
|
2583
|
+
return unionTypes.join(" | ");
|
|
2584
|
+
}
|
|
2585
|
+
__name(buildQueryKeyReturnType, "buildQueryKeyReturnType");
|
|
2586
|
+
function hasOptionalQueryKeyParams(op) {
|
|
2587
|
+
return op.queryParams.length > 0 || op.requestBody !== null && !op.requestBody.required;
|
|
2588
|
+
}
|
|
2589
|
+
__name(hasOptionalQueryKeyParams, "hasOptionalQueryKeyParams");
|
|
2590
|
+
function quoteTSPropertyName(name) {
|
|
2591
|
+
let needsQuoting = false;
|
|
2592
|
+
for (const char of name) {
|
|
2593
|
+
if (!(char >= "a" && char <= "z" || char >= "A" && char <= "Z" || char >= "0" && char <= "9" || char === "_" || char === "$")) {
|
|
2594
|
+
needsQuoting = true;
|
|
2595
|
+
break;
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
const firstChar = name[0];
|
|
2599
|
+
if (firstChar && firstChar >= "0" && firstChar <= "9") {
|
|
2600
|
+
needsQuoting = true;
|
|
2601
|
+
}
|
|
2602
|
+
if (needsQuoting) {
|
|
2603
|
+
return `"${name}"`;
|
|
2604
|
+
}
|
|
2605
|
+
return name;
|
|
2606
|
+
}
|
|
2607
|
+
__name(quoteTSPropertyName, "quoteTSPropertyName");
|
|
2608
|
+
function extractRefDependencies(schema, visited = /* @__PURE__ */ new Set()) {
|
|
2609
|
+
const deps = /* @__PURE__ */ new Set();
|
|
2610
|
+
if (schema.kind === "ref" && schema.ref) {
|
|
2611
|
+
const refName = schema.ref;
|
|
2612
|
+
if (!visited.has(refName)) {
|
|
2613
|
+
visited.add(refName);
|
|
2614
|
+
deps.add(refName);
|
|
2615
|
+
}
|
|
2616
|
+
} else if (schema.kind === "array" && schema.items) {
|
|
2617
|
+
const itemDeps = extractRefDependencies(schema.items, visited);
|
|
2618
|
+
itemDeps.forEach((dep) => deps.add(dep));
|
|
2619
|
+
} else if (schema.kind === "object" && schema.properties) {
|
|
2620
|
+
for (const prop of schema.properties) {
|
|
2621
|
+
const propDeps = extractRefDependencies(prop.type, visited);
|
|
2622
|
+
propDeps.forEach((dep) => deps.add(dep));
|
|
2623
|
+
}
|
|
2624
|
+
if (schema.additionalProperties) {
|
|
2625
|
+
const addlDeps = extractRefDependencies(schema.additionalProperties, visited);
|
|
2626
|
+
addlDeps.forEach((dep) => deps.add(dep));
|
|
2627
|
+
}
|
|
2628
|
+
} else if (schema.kind === "oneOf" && schema.oneOf) {
|
|
2629
|
+
for (const opt of schema.oneOf) {
|
|
2630
|
+
const optDeps = extractRefDependencies(opt, visited);
|
|
2631
|
+
optDeps.forEach((dep) => deps.add(dep));
|
|
2632
|
+
}
|
|
2633
|
+
} else if (schema.kind === "anyOf" && schema.anyOf) {
|
|
2634
|
+
for (const opt of schema.anyOf) {
|
|
2635
|
+
const optDeps = extractRefDependencies(opt, visited);
|
|
2636
|
+
optDeps.forEach((dep) => deps.add(dep));
|
|
2637
|
+
}
|
|
2638
|
+
} else if (schema.kind === "allOf" && schema.allOf) {
|
|
2639
|
+
for (const sch of schema.allOf) {
|
|
2640
|
+
const schDeps = extractRefDependencies(sch, visited);
|
|
2641
|
+
schDeps.forEach((dep) => deps.add(dep));
|
|
2642
|
+
}
|
|
2643
|
+
} else if (schema.kind === "not" && schema.not) {
|
|
2644
|
+
const notDeps = extractRefDependencies(schema.not, visited);
|
|
2645
|
+
notDeps.forEach((dep) => deps.add(dep));
|
|
2646
|
+
}
|
|
2647
|
+
return deps;
|
|
2648
|
+
}
|
|
2649
|
+
__name(extractRefDependencies, "extractRefDependencies");
|
|
2650
|
+
function sortModelDefsByDependencies(modelDefs) {
|
|
2651
|
+
const modelDefMap = /* @__PURE__ */ new Map();
|
|
2652
|
+
for (const md of modelDefs) {
|
|
2653
|
+
modelDefMap.set(md.name, md);
|
|
2654
|
+
}
|
|
2655
|
+
const dependencies = /* @__PURE__ */ new Map();
|
|
2656
|
+
for (const md of modelDefs) {
|
|
2657
|
+
const deps = extractRefDependencies(md.schema);
|
|
2658
|
+
const validDeps = /* @__PURE__ */ new Set();
|
|
2659
|
+
for (const dep of deps) {
|
|
2660
|
+
if (modelDefMap.has(dep)) {
|
|
2661
|
+
validDeps.add(dep);
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
dependencies.set(md.name, validDeps);
|
|
2665
|
+
}
|
|
2666
|
+
const sorted = [];
|
|
2667
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
2668
|
+
const queue = [];
|
|
2669
|
+
for (const md of modelDefs) {
|
|
2670
|
+
inDegree.set(md.name, dependencies.get(md.name)?.size || 0);
|
|
2671
|
+
if (inDegree.get(md.name) === 0) {
|
|
2672
|
+
queue.push(md.name);
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
while (queue.length > 0) {
|
|
2676
|
+
const current = queue.shift();
|
|
2677
|
+
if (!current) {
|
|
2678
|
+
continue;
|
|
2679
|
+
}
|
|
2680
|
+
const modelDef = modelDefMap.get(current);
|
|
2681
|
+
if (modelDef) {
|
|
2682
|
+
sorted.push(modelDef);
|
|
2683
|
+
}
|
|
2684
|
+
for (const md of modelDefs) {
|
|
2685
|
+
const deps = dependencies.get(md.name);
|
|
2686
|
+
if (deps?.has(current)) {
|
|
2687
|
+
const newInDegree = (inDegree.get(md.name) || 0) - 1;
|
|
2688
|
+
inDegree.set(md.name, newInDegree);
|
|
2689
|
+
if (newInDegree === 0) {
|
|
2690
|
+
queue.push(md.name);
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
if (sorted.length < modelDefs.length) {
|
|
2696
|
+
const sortedNames = new Set(sorted.map((md) => md.name));
|
|
2697
|
+
for (const md of modelDefs) {
|
|
2698
|
+
if (!sortedNames.has(md.name)) {
|
|
2699
|
+
sorted.push(md);
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
return sorted;
|
|
2704
|
+
}
|
|
2705
|
+
__name(sortModelDefsByDependencies, "sortModelDefsByDependencies");
|
|
2706
|
+
function isStreamingOperation(op) {
|
|
2707
|
+
return op.response.isStreaming === true;
|
|
2708
|
+
}
|
|
2709
|
+
__name(isStreamingOperation, "isStreamingOperation");
|
|
2710
|
+
function getStreamingItemType(op) {
|
|
2711
|
+
const schema = op.response.schema;
|
|
2712
|
+
if (schema.kind === IRSchemaKind.Array && schema.items) {
|
|
2713
|
+
return schemaToTSType(schema.items);
|
|
2714
|
+
}
|
|
2715
|
+
if (op.response.streamingFormat === "sse") {
|
|
2716
|
+
return "string";
|
|
2717
|
+
}
|
|
2718
|
+
return schemaToTSType(schema);
|
|
2719
|
+
}
|
|
2720
|
+
__name(getStreamingItemType, "getStreamingItemType");
|
|
2721
|
+
|
|
2722
|
+
// src/generator/typescript/zod-schema-converter.ts
|
|
2723
|
+
function schemaToZodSchema(s, indent = "", modelDefs, useLocalSchemaTypes = false) {
|
|
2724
|
+
const nextIndent = indent + " ";
|
|
2725
|
+
let zod;
|
|
2726
|
+
switch (s.kind) {
|
|
2727
|
+
case IRSchemaKind.String:
|
|
2728
|
+
zod = "z.string()";
|
|
2729
|
+
if (s.format === "date" || s.format === "date-time") {
|
|
2730
|
+
zod = "z.iso.datetime()";
|
|
2731
|
+
} else if (s.format === "email") {
|
|
2732
|
+
zod = "z.email()";
|
|
2733
|
+
} else if (s.format === "uri" || s.format === "url") {
|
|
2734
|
+
zod = "z.url()";
|
|
2735
|
+
} else if (s.format === "uuid") {
|
|
2736
|
+
zod = "z.uuid()";
|
|
2737
|
+
}
|
|
2738
|
+
break;
|
|
2739
|
+
case IRSchemaKind.Number:
|
|
2740
|
+
zod = "z.number()";
|
|
2741
|
+
break;
|
|
2742
|
+
case IRSchemaKind.Integer:
|
|
2743
|
+
zod = "z.number().int()";
|
|
2744
|
+
break;
|
|
2745
|
+
case IRSchemaKind.Boolean:
|
|
2746
|
+
zod = "z.boolean()";
|
|
2747
|
+
break;
|
|
2748
|
+
case IRSchemaKind.Null:
|
|
2749
|
+
zod = "z.null()";
|
|
2750
|
+
break;
|
|
2751
|
+
case IRSchemaKind.Ref:
|
|
2752
|
+
if (s.ref) {
|
|
2753
|
+
zod = useLocalSchemaTypes ? `${s.ref}Schema` : `Schema.${s.ref}Schema`;
|
|
2754
|
+
} else {
|
|
2755
|
+
zod = "z.unknown()";
|
|
2756
|
+
}
|
|
2757
|
+
break;
|
|
2758
|
+
case IRSchemaKind.Array:
|
|
2759
|
+
if (s.items) {
|
|
2760
|
+
const itemsZod = schemaToZodSchema(s.items, nextIndent, modelDefs, useLocalSchemaTypes);
|
|
2761
|
+
zod = `${itemsZod}.array()`;
|
|
2762
|
+
} else {
|
|
2763
|
+
zod = "z.unknown().array()";
|
|
2764
|
+
}
|
|
2765
|
+
break;
|
|
2766
|
+
case IRSchemaKind.Object:
|
|
2767
|
+
if (!s.properties || s.properties.length === 0) {
|
|
2768
|
+
if (s.additionalProperties) {
|
|
2769
|
+
const valueZod = schemaToZodSchema(s.additionalProperties, nextIndent, modelDefs, useLocalSchemaTypes);
|
|
2770
|
+
zod = `z.record(z.string(), ${valueZod})`;
|
|
2771
|
+
} else {
|
|
2772
|
+
zod = "z.record(z.string(), z.unknown())";
|
|
2773
|
+
}
|
|
2774
|
+
} else {
|
|
2775
|
+
const props = [];
|
|
2776
|
+
for (const field of s.properties) {
|
|
2777
|
+
const fieldZod = schemaToZodSchema(field.type, nextIndent, modelDefs, useLocalSchemaTypes);
|
|
2778
|
+
const fieldName = quoteTSPropertyName(field.name);
|
|
2779
|
+
if (field.required) {
|
|
2780
|
+
props.push(`${nextIndent}${fieldName}: ${fieldZod}`);
|
|
2781
|
+
} else {
|
|
2782
|
+
props.push(`${nextIndent}${fieldName}: ${fieldZod}.optional()`);
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
const objectZod = `z.object({
|
|
2786
|
+
${props.join(",\n")}
|
|
2787
|
+
${indent}})`;
|
|
2788
|
+
if (s.additionalProperties) {
|
|
2789
|
+
const valueZod = schemaToZodSchema(s.additionalProperties, nextIndent, modelDefs, useLocalSchemaTypes);
|
|
2790
|
+
zod = `${objectZod}.catchall(${valueZod})`;
|
|
2791
|
+
} else {
|
|
2792
|
+
zod = objectZod;
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2795
|
+
break;
|
|
2796
|
+
case IRSchemaKind.Enum:
|
|
2797
|
+
if (s.enumValues && s.enumValues.length > 0) {
|
|
2798
|
+
const enumValues = s.enumValues.map((v) => {
|
|
2799
|
+
if (v === "true" || v === "false") {
|
|
2800
|
+
return v;
|
|
2801
|
+
}
|
|
2802
|
+
if (/^-?[0-9]+(\.[0-9]+)?$/.test(v)) {
|
|
2803
|
+
return v;
|
|
2804
|
+
}
|
|
2805
|
+
return JSON.stringify(v);
|
|
2806
|
+
});
|
|
2807
|
+
zod = `z.enum([${enumValues.join(", ")}])`;
|
|
2808
|
+
} else {
|
|
2809
|
+
zod = "z.string()";
|
|
2810
|
+
}
|
|
2811
|
+
break;
|
|
2812
|
+
case IRSchemaKind.OneOf:
|
|
2813
|
+
if (s.oneOf && s.oneOf.length > 0) {
|
|
2814
|
+
const options = s.oneOf.map((opt) => schemaToZodSchema(opt, nextIndent, modelDefs, useLocalSchemaTypes));
|
|
2815
|
+
zod = `z.union([${options.join(", ")}])`;
|
|
2816
|
+
} else {
|
|
2817
|
+
zod = "z.unknown()";
|
|
2818
|
+
}
|
|
2819
|
+
break;
|
|
2820
|
+
case IRSchemaKind.AnyOf:
|
|
2821
|
+
if (s.anyOf && s.anyOf.length > 0) {
|
|
2822
|
+
const options = s.anyOf.map((opt) => schemaToZodSchema(opt, nextIndent, modelDefs, useLocalSchemaTypes));
|
|
2823
|
+
zod = `z.union([${options.join(", ")}])`;
|
|
2824
|
+
} else {
|
|
2825
|
+
zod = "z.unknown()";
|
|
2826
|
+
}
|
|
2827
|
+
break;
|
|
2828
|
+
case IRSchemaKind.AllOf:
|
|
2829
|
+
if (s.allOf && s.allOf.length > 0) {
|
|
2830
|
+
const schemas = s.allOf.map((sch) => schemaToZodSchema(sch, nextIndent, modelDefs, useLocalSchemaTypes));
|
|
2831
|
+
zod = schemas.join(".and(") + ")".repeat(schemas.length - 1);
|
|
2832
|
+
} else {
|
|
2833
|
+
zod = "z.unknown()";
|
|
2834
|
+
}
|
|
2835
|
+
break;
|
|
2836
|
+
default:
|
|
2837
|
+
zod = "z.unknown()";
|
|
2838
|
+
}
|
|
2839
|
+
if (s.nullable && zod !== "z.null()") {
|
|
2840
|
+
zod = `${zod}.nullable()`;
|
|
2841
|
+
}
|
|
2842
|
+
return zod;
|
|
2843
|
+
}
|
|
2844
|
+
__name(schemaToZodSchema, "schemaToZodSchema");
|
|
2845
|
+
|
|
2846
|
+
// src/generator/typescript/prettier-formatter.ts
|
|
2847
|
+
var import_child_process = require("child_process");
|
|
2848
|
+
var import_util = require("util");
|
|
2849
|
+
var path4 = __toESM(require("path"));
|
|
2850
|
+
var fs3 = __toESM(require("fs"));
|
|
2851
|
+
var execAsync = (0, import_util.promisify)(import_child_process.exec);
|
|
2852
|
+
async function formatWithPrettier(outDir, filesToFormat, logger) {
|
|
2853
|
+
const log = logger || console;
|
|
2854
|
+
try {
|
|
2855
|
+
try {
|
|
2856
|
+
await execAsync("npx --yes prettier --version", {
|
|
2857
|
+
cwd: outDir,
|
|
2858
|
+
maxBuffer: 10 * 1024 * 1024
|
|
2859
|
+
});
|
|
2860
|
+
} catch {
|
|
2861
|
+
log.warn?.("Prettier is not available. Skipping code formatting. Install prettier to enable formatting.");
|
|
2862
|
+
return;
|
|
2863
|
+
}
|
|
2864
|
+
const tsFilesToFormat = [];
|
|
2865
|
+
for (const file of filesToFormat) {
|
|
2866
|
+
if (file.endsWith(".ts") || file.endsWith(".tsx")) {
|
|
2867
|
+
const fullPath = path4.join(outDir, file);
|
|
2868
|
+
if (fs3.existsSync(fullPath)) {
|
|
2869
|
+
tsFilesToFormat.push(file);
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
if (tsFilesToFormat.length === 0) {
|
|
2874
|
+
log.debug?.("No TypeScript files to format.");
|
|
2875
|
+
return;
|
|
2876
|
+
}
|
|
2877
|
+
const escapedFiles = tsFilesToFormat.map((file) => {
|
|
2878
|
+
const escaped = file.replace(/\\/g, "/");
|
|
2879
|
+
return `"${escaped}"`;
|
|
2880
|
+
}).join(" ");
|
|
2881
|
+
const { stderr } = await execAsync(`npx --yes prettier --write --log-level=error ${escapedFiles}`, {
|
|
2882
|
+
cwd: outDir,
|
|
2883
|
+
maxBuffer: 10 * 1024 * 1024
|
|
2884
|
+
});
|
|
2885
|
+
if (stderr && !stderr.includes("warning")) {
|
|
2886
|
+
log.warn?.(stderr);
|
|
2887
|
+
}
|
|
2888
|
+
} catch (error) {
|
|
2889
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2890
|
+
log.warn?.(`Failed to format code with Prettier: ${errorMessage}. Generated code will not be formatted.`);
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
__name(formatWithPrettier, "formatWithPrettier");
|
|
2894
|
+
|
|
2895
|
+
// src/generator/typescript/typescript-generator.service.ts
|
|
2896
|
+
function _ts_decorate8(decorators, target, key, desc) {
|
|
2897
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2898
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2899
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2900
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2901
|
+
}
|
|
2902
|
+
__name(_ts_decorate8, "_ts_decorate");
|
|
2903
|
+
function _ts_metadata3(k, v) {
|
|
2904
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2905
|
+
}
|
|
2906
|
+
__name(_ts_metadata3, "_ts_metadata");
|
|
2907
|
+
var TypeScriptGeneratorService = class _TypeScriptGeneratorService {
|
|
2908
|
+
static {
|
|
2909
|
+
__name(this, "TypeScriptGeneratorService");
|
|
2910
|
+
}
|
|
2911
|
+
configService;
|
|
2912
|
+
logger = new import_common8.Logger(_TypeScriptGeneratorService.name);
|
|
2913
|
+
constructor(configService) {
|
|
2914
|
+
this.configService = configService;
|
|
2915
|
+
}
|
|
2916
|
+
getType() {
|
|
2917
|
+
return "typescript";
|
|
2918
|
+
}
|
|
2919
|
+
async generate(client, ir) {
|
|
2920
|
+
if (!client.defaultBaseURL && ir.openApiDocument) {
|
|
2921
|
+
const doc = ir.openApiDocument;
|
|
2922
|
+
const servers = doc.servers;
|
|
2923
|
+
if (Array.isArray(servers) && servers.length > 0) {
|
|
2924
|
+
client.defaultBaseURL = servers[0]?.url || "";
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
if (!client.srcDir) {
|
|
2928
|
+
client.srcDir = "src";
|
|
2929
|
+
}
|
|
2930
|
+
const srcDirPath = client.srcDir;
|
|
2931
|
+
const srcDir = path5.join(client.outDir, srcDirPath);
|
|
2932
|
+
const servicesDir = path5.join(srcDir, "services");
|
|
2933
|
+
await fs4.promises.mkdir(servicesDir, {
|
|
2934
|
+
recursive: true
|
|
2935
|
+
});
|
|
2936
|
+
const processedIR = await this.preprocessIR(client, ir);
|
|
2937
|
+
this.registerHandlebarsHelpers(client);
|
|
2938
|
+
const generatedTypeScriptFiles = [];
|
|
2939
|
+
generatedTypeScriptFiles.push(...await this.generateClient(client, processedIR, srcDir));
|
|
2940
|
+
generatedTypeScriptFiles.push(...await this.generateAuthStrategies(client, processedIR, srcDir));
|
|
2941
|
+
generatedTypeScriptFiles.push(...await this.generateIndex(client, processedIR, srcDir));
|
|
2942
|
+
generatedTypeScriptFiles.push(...await this.generateUtils(client, processedIR, srcDir));
|
|
2943
|
+
generatedTypeScriptFiles.push(...await this.generateServices(client, processedIR, servicesDir));
|
|
2944
|
+
generatedTypeScriptFiles.push(...await this.generateSchema(client, processedIR, srcDir));
|
|
2945
|
+
generatedTypeScriptFiles.push(...await this.generateZodSchema(client, processedIR, srcDir));
|
|
2946
|
+
await this.generatePackageJson(client);
|
|
2947
|
+
await this.generateTsConfig(client);
|
|
2948
|
+
generatedTypeScriptFiles.push(...await this.generateTsupConfig(client));
|
|
2949
|
+
await this.generateReadme(client, processedIR);
|
|
2950
|
+
const shouldFormat = client.formatCode !== false;
|
|
2951
|
+
if (shouldFormat) {
|
|
2952
|
+
await this.generatePrettierConfig(client);
|
|
2953
|
+
this.logger.debug("Formatting generated TypeScript files with Prettier...", client.packageName);
|
|
2954
|
+
await formatWithPrettier(client.outDir, generatedTypeScriptFiles, this.logger);
|
|
2955
|
+
} else {
|
|
2956
|
+
this.logger.debug("Code formatting is disabled for this client.", client.packageName);
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
/**
|
|
2960
|
+
* Pre-process IR to resolve method names and add cached values
|
|
2961
|
+
*/
|
|
2962
|
+
async preprocessIR(client, ir) {
|
|
2963
|
+
const processedServices = await Promise.all(ir.services.map(async (service) => ({
|
|
2964
|
+
...service,
|
|
2965
|
+
operations: await Promise.all(service.operations.map(async (op) => {
|
|
2966
|
+
const methodName = await resolveMethodName(client, op);
|
|
2967
|
+
return {
|
|
2968
|
+
...op,
|
|
2969
|
+
_resolvedMethodName: methodName
|
|
2970
|
+
};
|
|
2971
|
+
}))
|
|
2972
|
+
})));
|
|
2973
|
+
return {
|
|
2974
|
+
...ir,
|
|
2975
|
+
services: processedServices
|
|
2976
|
+
};
|
|
2977
|
+
}
|
|
2978
|
+
registerHandlebarsHelpers(_client) {
|
|
2979
|
+
registerCommonHandlebarsHelpers();
|
|
2980
|
+
Handlebars2.registerHelper("methodName", (op) => {
|
|
2981
|
+
return op._resolvedMethodName || deriveMethodName(op);
|
|
2982
|
+
});
|
|
2983
|
+
Handlebars2.registerHelper("queryTypeName", (op) => {
|
|
2984
|
+
const methodName = op._resolvedMethodName || deriveMethodName(op);
|
|
2985
|
+
return toPascalCase(op.tag) + toPascalCase(methodName) + "Query";
|
|
2986
|
+
});
|
|
2987
|
+
Handlebars2.registerHelper("pathTemplate", (op) => {
|
|
2988
|
+
const result = buildPathTemplate(op);
|
|
2989
|
+
return new Handlebars2.SafeString(result);
|
|
2990
|
+
});
|
|
2991
|
+
Handlebars2.registerHelper("queryKeyBase", (op) => {
|
|
2992
|
+
const result = buildQueryKeyBase(op);
|
|
2993
|
+
return new Handlebars2.SafeString(result);
|
|
2994
|
+
});
|
|
2995
|
+
Handlebars2.registerHelper("pathParamsInOrder", (op) => orderPathParams(op));
|
|
2996
|
+
Handlebars2.registerHelper("methodSignature", (op, options) => {
|
|
2997
|
+
const methodName = op._resolvedMethodName || deriveMethodName(op);
|
|
2998
|
+
const modelDefs = options?.data?.root?.IR?.modelDefs || [];
|
|
2999
|
+
const predefinedTypes = options?.data?.root?.PredefinedTypes || [];
|
|
3000
|
+
const isSameFile = options?.data?.root?.isSameFile || false;
|
|
3001
|
+
const signature = buildMethodSignature(op, methodName, modelDefs, predefinedTypes, isSameFile);
|
|
3002
|
+
return signature.map((s) => new Handlebars2.SafeString(s));
|
|
3003
|
+
});
|
|
3004
|
+
Handlebars2.registerHelper("methodSignatureNoInit", (op, options) => {
|
|
3005
|
+
const methodName = op._resolvedMethodName || deriveMethodName(op);
|
|
3006
|
+
const modelDefs = options?.data?.root?.IR?.modelDefs || [];
|
|
3007
|
+
const predefinedTypes = options?.data?.root?.PredefinedTypes || [];
|
|
3008
|
+
const isSameFile = options?.data?.root?.isSameFile || false;
|
|
3009
|
+
const parts = buildMethodSignature(op, methodName, modelDefs, predefinedTypes, isSameFile);
|
|
3010
|
+
return parts.slice(0, -1);
|
|
3011
|
+
});
|
|
3012
|
+
Handlebars2.registerHelper("queryKeyArgs", (op) => {
|
|
3013
|
+
const args = queryKeyArgs(op);
|
|
3014
|
+
return args.map((arg) => new Handlebars2.SafeString(arg));
|
|
3015
|
+
});
|
|
3016
|
+
Handlebars2.registerHelper("queryKeyReturnType", (op, options) => {
|
|
3017
|
+
const methodName = op._resolvedMethodName || deriveMethodName(op);
|
|
3018
|
+
const modelDefs = options?.data?.root?.IR?.modelDefs || [];
|
|
3019
|
+
const predefinedTypes = options?.data?.root?.PredefinedTypes || [];
|
|
3020
|
+
const isSameFile = options?.data?.root?.isSameFile || false;
|
|
3021
|
+
const returnType = buildQueryKeyReturnType(op, methodName, modelDefs, predefinedTypes, isSameFile);
|
|
3022
|
+
return new Handlebars2.SafeString(returnType);
|
|
3023
|
+
});
|
|
3024
|
+
Handlebars2.registerHelper("hasOptionalQueryKeyParams", (op) => {
|
|
3025
|
+
return hasOptionalQueryKeyParams(op);
|
|
3026
|
+
});
|
|
3027
|
+
Handlebars2.registerHelper("hasAnyOptionalQueryKeyParams", (service) => {
|
|
3028
|
+
return service.operations.some((op) => hasOptionalQueryKeyParams(op));
|
|
3029
|
+
});
|
|
3030
|
+
Handlebars2.registerHelper("tsType", (x, options) => {
|
|
3031
|
+
if (x && typeof x === "object" && "kind" in x) {
|
|
3032
|
+
const predefinedTypes = options?.data?.root?.PredefinedTypes || [];
|
|
3033
|
+
const modelDefs = options?.data?.root?.IR?.modelDefs || [];
|
|
3034
|
+
const isSameFile = options?.data?.root?.isSameFile || false;
|
|
3035
|
+
return schemaToTSType(x, predefinedTypes, modelDefs, isSameFile);
|
|
3036
|
+
}
|
|
3037
|
+
return "unknown";
|
|
3038
|
+
});
|
|
3039
|
+
Handlebars2.registerHelper("stripSchemaNs", (s) => s.replace(/^Schema\./, ""));
|
|
3040
|
+
Handlebars2.registerHelper("tsTypeStripNs", (x, options) => {
|
|
3041
|
+
const predefinedTypes = options?.data?.root?.PredefinedTypes || [];
|
|
3042
|
+
const modelDefs = options?.data?.root?.IR?.modelDefs || [];
|
|
3043
|
+
const isSameFile = options?.data?.root?.isSameFile || false;
|
|
3044
|
+
if (x && typeof x === "object" && "kind" in x) {
|
|
3045
|
+
const typeStr = schemaToTSType(x, predefinedTypes, modelDefs, isSameFile);
|
|
3046
|
+
const stripped = typeStr.replace(/Schema\./g, "");
|
|
3047
|
+
return new Handlebars2.SafeString(stripped);
|
|
3048
|
+
}
|
|
3049
|
+
if (typeof x === "string") {
|
|
3050
|
+
if (x.startsWith("Schema.")) {
|
|
3051
|
+
const typeName = x.replace(/^Schema\./, "");
|
|
3052
|
+
const predefinedType = predefinedTypes.find((pt) => pt.type === typeName);
|
|
3053
|
+
if (predefinedType) {
|
|
3054
|
+
return new Handlebars2.SafeString(typeName);
|
|
3055
|
+
}
|
|
3056
|
+
return new Handlebars2.SafeString(typeName);
|
|
3057
|
+
}
|
|
3058
|
+
return new Handlebars2.SafeString(x);
|
|
3059
|
+
}
|
|
3060
|
+
return "unknown";
|
|
3061
|
+
});
|
|
3062
|
+
Handlebars2.registerHelper("isPredefinedType", (typeName, options) => {
|
|
3063
|
+
const predefinedTypes = options?.data?.root?.PredefinedTypes || [];
|
|
3064
|
+
return predefinedTypes.some((pt) => pt.type === typeName);
|
|
3065
|
+
});
|
|
3066
|
+
Handlebars2.registerHelper("getPredefinedType", (typeName, options) => {
|
|
3067
|
+
const predefinedTypes = options?.data?.root?.PredefinedTypes || [];
|
|
3068
|
+
return predefinedTypes.find((pt) => pt.type === typeName);
|
|
3069
|
+
});
|
|
3070
|
+
Handlebars2.registerHelper("groupByPackage", (predefinedTypes) => {
|
|
3071
|
+
const grouped = {};
|
|
3072
|
+
for (const pt of predefinedTypes || []) {
|
|
3073
|
+
if (!grouped[pt.package]) {
|
|
3074
|
+
grouped[pt.package] = {
|
|
3075
|
+
package: pt.package,
|
|
3076
|
+
types: []
|
|
3077
|
+
};
|
|
3078
|
+
}
|
|
3079
|
+
grouped[pt.package]?.types.push(pt.type);
|
|
3080
|
+
}
|
|
3081
|
+
return Object.values(grouped);
|
|
3082
|
+
});
|
|
3083
|
+
Handlebars2.registerHelper("getServicePredefinedTypes", (service, options) => {
|
|
3084
|
+
const predefinedTypes = options?.data?.root?.PredefinedTypes || [];
|
|
3085
|
+
const modelDefs = options?.data?.root?.IR?.modelDefs || [];
|
|
3086
|
+
return collectPredefinedTypesUsedInService(service, predefinedTypes, modelDefs);
|
|
3087
|
+
});
|
|
3088
|
+
Handlebars2.registerHelper("getSchemaPredefinedTypes", (options) => {
|
|
3089
|
+
const predefinedTypes = options?.data?.root?.PredefinedTypes || [];
|
|
3090
|
+
const modelDefs = options?.data?.root?.IR?.modelDefs || [];
|
|
3091
|
+
return collectPredefinedTypesUsedInSchema(modelDefs, predefinedTypes);
|
|
3092
|
+
});
|
|
3093
|
+
Handlebars2.registerHelper("joinTypes", (types) => {
|
|
3094
|
+
return types.join(", ");
|
|
3095
|
+
});
|
|
3096
|
+
Handlebars2.registerHelper("uniquePackages", (predefinedTypes) => {
|
|
3097
|
+
const packages = /* @__PURE__ */ new Set();
|
|
3098
|
+
for (const pt of predefinedTypes || []) {
|
|
3099
|
+
if (pt.package) {
|
|
3100
|
+
packages.add(pt.package);
|
|
3101
|
+
}
|
|
3102
|
+
}
|
|
3103
|
+
return Array.from(packages);
|
|
3104
|
+
});
|
|
3105
|
+
Handlebars2.registerHelper("isPredefinedPackage", (packageName, predefinedTypes) => {
|
|
3106
|
+
if (!predefinedTypes) return false;
|
|
3107
|
+
return predefinedTypes.some((pt) => pt.package === packageName);
|
|
3108
|
+
});
|
|
3109
|
+
Handlebars2.registerHelper("getAllDependencies", (client) => {
|
|
3110
|
+
const deps = {
|
|
3111
|
+
"@blimu/fetch": "^0.4.0",
|
|
3112
|
+
zod: "^4.3.5"
|
|
3113
|
+
};
|
|
3114
|
+
if (client.predefinedTypes) {
|
|
3115
|
+
for (const pt of client.predefinedTypes) {
|
|
3116
|
+
if (pt.package && !deps[pt.package]) {
|
|
3117
|
+
deps[pt.package] = client.dependencies?.[pt.package] || "*";
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
}
|
|
3121
|
+
if (client.dependencies) {
|
|
3122
|
+
for (const [pkg, version] of Object.entries(client.dependencies)) {
|
|
3123
|
+
if (pkg !== "zod" && !deps[pkg]) {
|
|
3124
|
+
deps[pkg] = version;
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
return deps;
|
|
3129
|
+
});
|
|
3130
|
+
Handlebars2.registerHelper("decodeHtml", (str) => {
|
|
3131
|
+
if (typeof str !== "string") return str;
|
|
3132
|
+
let decoded = str.replace(/&#x60;/g, "`").replace(/&#96;/g, "`").replace(/&quot;/g, """).replace(/&lt;/g, "<").replace(/&gt;/g, ">");
|
|
3133
|
+
decoded = decoded.replace(/"/g, '"').replace(/</g, "<").replace(/>/g, ">").replace(/`/g, "`").replace(/`/g, "`").replace(/&/g, "&");
|
|
3134
|
+
return new Handlebars2.SafeString(decoded);
|
|
3135
|
+
});
|
|
3136
|
+
Handlebars2.registerHelper("quotePropName", (name) => quoteTSPropertyName(name));
|
|
3137
|
+
Handlebars2.registerHelper("zodSchema", (x, options) => {
|
|
3138
|
+
if (x && typeof x === "object" && "kind" in x) {
|
|
3139
|
+
const modelDefs = options?.data?.root?.IR?.modelDefs || [];
|
|
3140
|
+
const useLocalSchemaTypes = options?.data?.root?._templateName === "schema.zod.ts.hbs";
|
|
3141
|
+
return new Handlebars2.SafeString(schemaToZodSchema(x, "", modelDefs, useLocalSchemaTypes));
|
|
3142
|
+
}
|
|
3143
|
+
return "z.unknown()";
|
|
3144
|
+
});
|
|
3145
|
+
Handlebars2.registerHelper("isStreaming", (op) => {
|
|
3146
|
+
return isStreamingOperation(op);
|
|
3147
|
+
});
|
|
3148
|
+
Handlebars2.registerHelper("hasBearerScheme", (schemes) => {
|
|
3149
|
+
if (!Array.isArray(schemes)) return false;
|
|
3150
|
+
return schemes.some((s) => s.type === "http" && s.scheme === "bearer");
|
|
3151
|
+
});
|
|
3152
|
+
Handlebars2.registerHelper("hasApiKeyScheme", (schemes) => {
|
|
3153
|
+
if (!Array.isArray(schemes)) return false;
|
|
3154
|
+
return schemes.some((s) => s.type === "apiKey");
|
|
3155
|
+
});
|
|
3156
|
+
Handlebars2.registerHelper("serviceUsesSchema", (service) => {
|
|
3157
|
+
if (!service || !service.operations || !Array.isArray(service.operations)) {
|
|
3158
|
+
return false;
|
|
3159
|
+
}
|
|
3160
|
+
return service.operations.some((op) => {
|
|
3161
|
+
if (op.response?.schema) {
|
|
3162
|
+
const schema = op.response.schema;
|
|
3163
|
+
if (schema.kind === "ref" || schema.kind === "object" || schema.kind === "array" || schema.kind === "oneOf" || schema.kind === "anyOf" || schema.kind === "allOf") {
|
|
3164
|
+
return true;
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
if (op.requestBody?.schema) {
|
|
3168
|
+
const schema = op.requestBody.schema;
|
|
3169
|
+
if (schema.kind === "ref" || schema.kind === "object" || schema.kind === "array" || schema.kind === "oneOf" || schema.kind === "anyOf" || schema.kind === "allOf") {
|
|
3170
|
+
return true;
|
|
3171
|
+
}
|
|
3172
|
+
}
|
|
3173
|
+
if (op.queryParams && op.queryParams.length > 0) {
|
|
3174
|
+
return true;
|
|
3175
|
+
}
|
|
3176
|
+
return false;
|
|
3177
|
+
});
|
|
3178
|
+
});
|
|
3179
|
+
Handlebars2.registerHelper("streamingItemType", (op) => {
|
|
3180
|
+
return new Handlebars2.SafeString(getStreamingItemType(op));
|
|
3181
|
+
});
|
|
3182
|
+
}
|
|
3183
|
+
async renderTemplate(templateName, data, outputPath, client) {
|
|
3184
|
+
const overridePath = client.templates?.[templateName];
|
|
3185
|
+
if (overridePath) {
|
|
3186
|
+
this.logger.debug(`Using template override for ${templateName}: ${overridePath}`);
|
|
3187
|
+
try {
|
|
3188
|
+
await fs4.promises.access(overridePath, fs4.constants.R_OK);
|
|
3189
|
+
const templateContent2 = await fs4.promises.readFile(overridePath, "utf-8");
|
|
3190
|
+
const template2 = Handlebars2.compile(templateContent2);
|
|
3191
|
+
const contextWithTemplate2 = {
|
|
3192
|
+
...data,
|
|
3193
|
+
_templateName: templateName
|
|
3194
|
+
};
|
|
3195
|
+
const rendered2 = template2(contextWithTemplate2);
|
|
3196
|
+
await fs4.promises.writeFile(outputPath, rendered2, "utf-8");
|
|
3197
|
+
return;
|
|
3198
|
+
} catch (error) {
|
|
3199
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3200
|
+
this.logger.error(`Template override file not found or not readable: ${overridePath}. Error: ${errorMsg}`);
|
|
3201
|
+
throw new Error(`Template override file not found or not readable: ${overridePath}`);
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
const possiblePaths = [
|
|
3205
|
+
path5.join(__dirname, "generator/typescript/templates", templateName),
|
|
3206
|
+
path5.join(__dirname, "templates", templateName),
|
|
3207
|
+
path5.join(__dirname, "../typescript/templates", templateName),
|
|
3208
|
+
path5.join(process.cwd(), "src/generator/typescript/templates", templateName),
|
|
3209
|
+
path5.join(process.cwd(), "packages/codegen/src/generator/typescript/templates", templateName)
|
|
3210
|
+
];
|
|
3211
|
+
let templatePath = null;
|
|
3212
|
+
for (const possiblePath of possiblePaths) {
|
|
3213
|
+
try {
|
|
3214
|
+
await fs4.promises.access(possiblePath);
|
|
3215
|
+
templatePath = possiblePath;
|
|
3216
|
+
break;
|
|
3217
|
+
} catch {
|
|
3218
|
+
this.logger.debug(`Template not found at: ${possiblePath}`);
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
if (!templatePath) {
|
|
3222
|
+
this.logger.error(`Template not found: ${templateName}`);
|
|
3223
|
+
this.logger.error(`Checked paths: ${possiblePaths.join(", ")}`);
|
|
3224
|
+
this.logger.error(`__dirname: ${__dirname}`);
|
|
3225
|
+
throw new Error(`Template not found: ${templateName}`);
|
|
3226
|
+
}
|
|
3227
|
+
const templateContent = await fs4.promises.readFile(templatePath, "utf-8");
|
|
3228
|
+
const template = Handlebars2.compile(templateContent);
|
|
3229
|
+
const contextWithTemplate = {
|
|
3230
|
+
...data,
|
|
3231
|
+
_templateName: templateName
|
|
3232
|
+
};
|
|
3233
|
+
const rendered = template(contextWithTemplate);
|
|
3234
|
+
const outputDir = path5.dirname(outputPath);
|
|
3235
|
+
await fs4.promises.mkdir(outputDir, {
|
|
3236
|
+
recursive: true
|
|
3237
|
+
});
|
|
3238
|
+
await fs4.promises.writeFile(outputPath, rendered, "utf-8");
|
|
3239
|
+
}
|
|
3240
|
+
async generateClient(client, ir, srcDir) {
|
|
3241
|
+
const clientPath = path5.join(srcDir, "client.ts");
|
|
3242
|
+
if (this.configService.shouldExcludeFile(client, clientPath)) {
|
|
3243
|
+
return [];
|
|
3244
|
+
}
|
|
3245
|
+
try {
|
|
3246
|
+
await this.renderTemplate("client.ts.hbs", {
|
|
3247
|
+
Client: client,
|
|
3248
|
+
IR: ir
|
|
3249
|
+
}, clientPath, client);
|
|
3250
|
+
return [
|
|
3251
|
+
path5.relative(client.outDir, clientPath)
|
|
3252
|
+
];
|
|
3253
|
+
} catch (error) {
|
|
3254
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3255
|
+
this.logger.warn(`Template client.ts.hbs not found: ${errorMsg}, using placeholder`);
|
|
3256
|
+
const content = `// Generated client - template rendering to be implemented`;
|
|
3257
|
+
await fs4.promises.writeFile(clientPath, content, "utf-8");
|
|
3258
|
+
return [
|
|
3259
|
+
path5.relative(client.outDir, clientPath)
|
|
3260
|
+
];
|
|
3261
|
+
}
|
|
3262
|
+
}
|
|
3263
|
+
async generateAuthStrategies(client, ir, srcDir) {
|
|
3264
|
+
const authStrategiesPath = path5.join(srcDir, "auth-strategies.ts");
|
|
3265
|
+
if (this.configService.shouldExcludeFile(client, authStrategiesPath)) {
|
|
3266
|
+
return [];
|
|
3267
|
+
}
|
|
3268
|
+
try {
|
|
3269
|
+
await this.renderTemplate("auth-strategies.ts.hbs", {
|
|
3270
|
+
Client: client,
|
|
3271
|
+
IR: ir
|
|
3272
|
+
}, authStrategiesPath, client);
|
|
3273
|
+
return [
|
|
3274
|
+
path5.relative(client.outDir, authStrategiesPath)
|
|
3275
|
+
];
|
|
3276
|
+
} catch {
|
|
3277
|
+
this.logger.warn(`Template auth-strategies.ts.hbs not found, using placeholder`);
|
|
3278
|
+
const content = `// Generated auth-strategies - template rendering to be implemented`;
|
|
3279
|
+
await fs4.promises.writeFile(authStrategiesPath, content, "utf-8");
|
|
3280
|
+
return [
|
|
3281
|
+
path5.relative(client.outDir, authStrategiesPath)
|
|
3282
|
+
];
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
async generateIndex(client, ir, srcDir) {
|
|
3286
|
+
const indexPath = path5.join(srcDir, "index.ts");
|
|
3287
|
+
if (this.configService.shouldExcludeFile(client, indexPath)) {
|
|
3288
|
+
return [];
|
|
3289
|
+
}
|
|
3290
|
+
try {
|
|
3291
|
+
await fs4.promises.access(indexPath);
|
|
3292
|
+
this.logger.debug(`index.ts already exists at ${indexPath}, skipping generation to preserve customizations`);
|
|
3293
|
+
return [];
|
|
3294
|
+
} catch {
|
|
3295
|
+
}
|
|
3296
|
+
try {
|
|
3297
|
+
await this.renderTemplate("index.ts.hbs", {
|
|
3298
|
+
Client: client,
|
|
3299
|
+
IR: ir
|
|
3300
|
+
}, indexPath, client);
|
|
3301
|
+
return [
|
|
3302
|
+
path5.relative(client.outDir, indexPath)
|
|
3303
|
+
];
|
|
3304
|
+
} catch {
|
|
3305
|
+
this.logger.warn(`Template index.ts.hbs not found, using placeholder`);
|
|
3306
|
+
const content = `// Generated index - template rendering to be implemented`;
|
|
3307
|
+
await fs4.promises.writeFile(indexPath, content, "utf-8");
|
|
3308
|
+
return [
|
|
3309
|
+
path5.relative(client.outDir, indexPath)
|
|
3310
|
+
];
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
async generateUtils(client, ir, srcDir) {
|
|
3314
|
+
const utilsPath = path5.join(srcDir, "utils.ts");
|
|
3315
|
+
if (this.configService.shouldExcludeFile(client, utilsPath)) {
|
|
3316
|
+
return [];
|
|
3317
|
+
}
|
|
3318
|
+
try {
|
|
3319
|
+
await this.renderTemplate("utils.ts.hbs", {
|
|
3320
|
+
Client: client,
|
|
3321
|
+
IR: ir
|
|
3322
|
+
}, utilsPath, client);
|
|
3323
|
+
return [
|
|
3324
|
+
path5.relative(client.outDir, utilsPath)
|
|
3325
|
+
];
|
|
3326
|
+
} catch {
|
|
3327
|
+
this.logger.warn(`Template utils.ts.hbs not found, using placeholder`);
|
|
3328
|
+
const content = `// Generated utils - template rendering to be implemented`;
|
|
3329
|
+
await fs4.promises.writeFile(utilsPath, content, "utf-8");
|
|
3330
|
+
return [
|
|
3331
|
+
path5.relative(client.outDir, utilsPath)
|
|
3332
|
+
];
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
async generateServices(client, ir, servicesDir) {
|
|
3336
|
+
const generatedFiles = [];
|
|
3337
|
+
for (const service of ir.services) {
|
|
3338
|
+
const servicePath = path5.join(servicesDir, `${toSnakeCase(service.tag).toLowerCase()}.ts`);
|
|
3339
|
+
if (this.configService.shouldExcludeFile(client, servicePath)) {
|
|
3340
|
+
continue;
|
|
3341
|
+
}
|
|
3342
|
+
try {
|
|
3343
|
+
await this.renderTemplate("service.ts.hbs", {
|
|
3344
|
+
Client: client,
|
|
3345
|
+
Service: service,
|
|
3346
|
+
IR: ir,
|
|
3347
|
+
PredefinedTypes: client.predefinedTypes || [],
|
|
3348
|
+
isSameFile: false
|
|
3349
|
+
}, servicePath, client);
|
|
3350
|
+
generatedFiles.push(path5.relative(client.outDir, servicePath));
|
|
3351
|
+
} catch {
|
|
3352
|
+
this.logger.warn(`Template service.ts.hbs not found, using placeholder`);
|
|
3353
|
+
const content = `// Generated service ${service.tag} - template rendering to be implemented`;
|
|
3354
|
+
await fs4.promises.writeFile(servicePath, content, "utf-8");
|
|
3355
|
+
generatedFiles.push(path5.relative(client.outDir, servicePath));
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
return generatedFiles;
|
|
3359
|
+
}
|
|
3360
|
+
async generateSchema(client, ir, srcDir) {
|
|
3361
|
+
const schemaPath = path5.join(srcDir, "schema.ts");
|
|
3362
|
+
if (this.configService.shouldExcludeFile(client, schemaPath)) {
|
|
3363
|
+
return [];
|
|
3364
|
+
}
|
|
3365
|
+
try {
|
|
3366
|
+
await this.renderTemplate("schema.ts.hbs", {
|
|
3367
|
+
Client: client,
|
|
3368
|
+
IR: ir,
|
|
3369
|
+
PredefinedTypes: client.predefinedTypes || [],
|
|
3370
|
+
isSameFile: true
|
|
3371
|
+
}, schemaPath, client);
|
|
3372
|
+
return [
|
|
3373
|
+
path5.relative(client.outDir, schemaPath)
|
|
3374
|
+
];
|
|
3375
|
+
} catch (error) {
|
|
3376
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3377
|
+
this.logger.warn(`Template schema.ts.hbs error: ${errorMsg}, using placeholder`);
|
|
3378
|
+
const content = `// Generated schema - template rendering to be implemented`;
|
|
3379
|
+
await fs4.promises.writeFile(schemaPath, content, "utf-8");
|
|
3380
|
+
return [
|
|
3381
|
+
path5.relative(client.outDir, schemaPath)
|
|
3382
|
+
];
|
|
3383
|
+
}
|
|
3384
|
+
}
|
|
3385
|
+
async generateZodSchema(client, ir, srcDir) {
|
|
3386
|
+
const zodSchemaPath = path5.join(srcDir, "schema.zod.ts");
|
|
3387
|
+
if (this.configService.shouldExcludeFile(client, zodSchemaPath)) {
|
|
3388
|
+
return [];
|
|
3389
|
+
}
|
|
3390
|
+
try {
|
|
3391
|
+
const sortedModelDefs = sortModelDefsByDependencies(ir.modelDefs);
|
|
3392
|
+
const sortedIR = {
|
|
3393
|
+
...ir,
|
|
3394
|
+
modelDefs: sortedModelDefs
|
|
3395
|
+
};
|
|
3396
|
+
await this.renderTemplate("schema.zod.ts.hbs", {
|
|
3397
|
+
Client: client,
|
|
3398
|
+
IR: sortedIR
|
|
3399
|
+
}, zodSchemaPath, client);
|
|
3400
|
+
return [
|
|
3401
|
+
path5.relative(client.outDir, zodSchemaPath)
|
|
3402
|
+
];
|
|
3403
|
+
} catch (error) {
|
|
3404
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
3405
|
+
this.logger.warn(`Template schema.zod.ts.hbs error: ${errorMsg}, using placeholder`);
|
|
3406
|
+
const content = `// Generated Zod schemas - template rendering to be implemented`;
|
|
3407
|
+
await fs4.promises.writeFile(zodSchemaPath, content, "utf-8");
|
|
3408
|
+
return [
|
|
3409
|
+
path5.relative(client.outDir, zodSchemaPath)
|
|
3410
|
+
];
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
async generatePackageJson(client) {
|
|
3414
|
+
const packageJsonPath = path5.join(client.outDir, "package.json");
|
|
3415
|
+
if (this.configService.shouldExcludeFile(client, packageJsonPath)) {
|
|
3416
|
+
return;
|
|
3417
|
+
}
|
|
3418
|
+
try {
|
|
3419
|
+
await this.renderTemplate("package.json.hbs", {
|
|
3420
|
+
Client: client
|
|
3421
|
+
}, packageJsonPath, client);
|
|
3422
|
+
} catch {
|
|
3423
|
+
this.logger.warn(`Template package.json.hbs not found, using fallback`);
|
|
3424
|
+
const content = JSON.stringify({
|
|
3425
|
+
name: client.packageName,
|
|
3426
|
+
version: "0.0.1",
|
|
3427
|
+
main: "dist/index.js",
|
|
3428
|
+
types: "dist/index.d.ts"
|
|
3429
|
+
}, null, 2);
|
|
3430
|
+
await fs4.promises.writeFile(packageJsonPath, content, "utf-8");
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
async generateTsConfig(client) {
|
|
3434
|
+
const tsConfigPath = path5.join(client.outDir, "tsconfig.json");
|
|
3435
|
+
if (this.configService.shouldExcludeFile(client, tsConfigPath)) {
|
|
3436
|
+
return;
|
|
3437
|
+
}
|
|
3438
|
+
try {
|
|
3439
|
+
await this.renderTemplate("tsconfig.json.hbs", {
|
|
3440
|
+
Client: client
|
|
3441
|
+
}, tsConfigPath, client);
|
|
3442
|
+
} catch {
|
|
3443
|
+
this.logger.warn(`Template tsconfig.json.hbs not found, using fallback`);
|
|
3444
|
+
const srcDir = client.srcDir || "src";
|
|
3445
|
+
const content = JSON.stringify({
|
|
3446
|
+
compilerOptions: {
|
|
3447
|
+
target: "ES2020",
|
|
3448
|
+
module: "commonjs",
|
|
3449
|
+
lib: [
|
|
3450
|
+
"ES2020"
|
|
3451
|
+
],
|
|
3452
|
+
declaration: true,
|
|
3453
|
+
outDir: "./dist",
|
|
3454
|
+
rootDir: `./${srcDir}`,
|
|
3455
|
+
strict: true,
|
|
3456
|
+
esModuleInterop: true,
|
|
3457
|
+
skipLibCheck: true,
|
|
3458
|
+
forceConsistentCasingInFileNames: true
|
|
3459
|
+
},
|
|
3460
|
+
include: [
|
|
3461
|
+
`${srcDir}/**/*`
|
|
3462
|
+
]
|
|
3463
|
+
}, null, 2);
|
|
3464
|
+
const outputDir = path5.dirname(tsConfigPath);
|
|
3465
|
+
await fs4.promises.mkdir(outputDir, {
|
|
3466
|
+
recursive: true
|
|
3467
|
+
});
|
|
3468
|
+
await fs4.promises.writeFile(tsConfigPath, content, "utf-8");
|
|
3469
|
+
}
|
|
3470
|
+
}
|
|
3471
|
+
async generateTsupConfig(client) {
|
|
3472
|
+
const tsupConfigPath = path5.join(client.outDir, "tsup.config.ts");
|
|
3473
|
+
if (this.configService.shouldExcludeFile(client, tsupConfigPath)) {
|
|
3474
|
+
return [];
|
|
3475
|
+
}
|
|
3476
|
+
try {
|
|
3477
|
+
await this.renderTemplate("tsup.config.ts.hbs", {
|
|
3478
|
+
Client: client
|
|
3479
|
+
}, tsupConfigPath, client);
|
|
3480
|
+
} catch {
|
|
3481
|
+
this.logger.warn(`Template tsup.config.ts.hbs not found, using fallback`);
|
|
3482
|
+
const srcDir = client.srcDir || "src";
|
|
3483
|
+
const content = `import { defineConfig } from "tsup";
|
|
5
3484
|
|
|
6
3485
|
export default defineConfig({
|
|
7
|
-
entry: ["${
|
|
3486
|
+
entry: ["${srcDir}/index.ts"],
|
|
8
3487
|
format: ["cjs", "esm"],
|
|
9
3488
|
dts: {
|
|
10
3489
|
resolve: true,
|
|
@@ -16,7 +3495,209 @@ export default defineConfig({
|
|
|
16
3495
|
tsconfig: "./tsconfig.json",
|
|
17
3496
|
external: [],
|
|
18
3497
|
});
|
|
19
|
-
`;
|
|
3498
|
+
`;
|
|
3499
|
+
await fs4.promises.writeFile(tsupConfigPath, content, "utf-8");
|
|
3500
|
+
}
|
|
3501
|
+
return [
|
|
3502
|
+
"tsup.config.ts"
|
|
3503
|
+
];
|
|
3504
|
+
}
|
|
3505
|
+
async generateReadme(client, ir) {
|
|
3506
|
+
const readmePath = path5.join(client.outDir, "README.md");
|
|
3507
|
+
if (this.configService.shouldExcludeFile(client, readmePath)) {
|
|
3508
|
+
return;
|
|
3509
|
+
}
|
|
3510
|
+
try {
|
|
3511
|
+
await this.renderTemplate("README.md.hbs", {
|
|
3512
|
+
Client: client,
|
|
3513
|
+
IR: ir
|
|
3514
|
+
}, readmePath, client);
|
|
3515
|
+
} catch {
|
|
3516
|
+
this.logger.warn(`Template README.md.hbs not found, using fallback`);
|
|
3517
|
+
const content = `# ${client.name}
|
|
3518
|
+
|
|
3519
|
+
Generated SDK from OpenAPI specification.`;
|
|
3520
|
+
await fs4.promises.writeFile(readmePath, content, "utf-8");
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3523
|
+
async generatePrettierConfig(client) {
|
|
3524
|
+
const prettierConfigPath = path5.join(client.outDir, ".prettierrc");
|
|
3525
|
+
if (this.configService.shouldExcludeFile(client, prettierConfigPath)) {
|
|
3526
|
+
return;
|
|
3527
|
+
}
|
|
3528
|
+
try {
|
|
3529
|
+
await this.renderTemplate(".prettierrc.hbs", {
|
|
3530
|
+
Client: client
|
|
3531
|
+
}, prettierConfigPath, client);
|
|
3532
|
+
} catch {
|
|
3533
|
+
this.logger.warn(`Template .prettierrc.hbs not found, using fallback`);
|
|
3534
|
+
const content = JSON.stringify({
|
|
3535
|
+
semi: true,
|
|
3536
|
+
trailingComma: "es5",
|
|
3537
|
+
singleQuote: true,
|
|
3538
|
+
printWidth: 80,
|
|
3539
|
+
tabWidth: 2,
|
|
3540
|
+
useTabs: false
|
|
3541
|
+
}, null, 2);
|
|
3542
|
+
await fs4.promises.writeFile(prettierConfigPath, content, "utf-8");
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
};
|
|
3546
|
+
TypeScriptGeneratorService = _ts_decorate8([
|
|
3547
|
+
(0, import_common8.Injectable)(),
|
|
3548
|
+
_ts_metadata3("design:type", Function),
|
|
3549
|
+
_ts_metadata3("design:paramtypes", [
|
|
3550
|
+
typeof ConfigService === "undefined" ? Object : ConfigService
|
|
3551
|
+
])
|
|
3552
|
+
], TypeScriptGeneratorService);
|
|
20
3553
|
|
|
21
|
-
|
|
3554
|
+
// src/generator/generator.module.ts
|
|
3555
|
+
function _ts_decorate9(decorators, target, key, desc) {
|
|
3556
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3557
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
3558
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
3559
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3560
|
+
}
|
|
3561
|
+
__name(_ts_decorate9, "_ts_decorate");
|
|
3562
|
+
function _ts_metadata4(k, v) {
|
|
3563
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
3564
|
+
}
|
|
3565
|
+
__name(_ts_metadata4, "_ts_metadata");
|
|
3566
|
+
var GeneratorModule = class {
|
|
3567
|
+
static {
|
|
3568
|
+
__name(this, "GeneratorModule");
|
|
3569
|
+
}
|
|
3570
|
+
generatorService;
|
|
3571
|
+
typeScriptGenerator;
|
|
3572
|
+
constructor(generatorService, typeScriptGenerator) {
|
|
3573
|
+
this.generatorService = generatorService;
|
|
3574
|
+
this.typeScriptGenerator = typeScriptGenerator;
|
|
3575
|
+
this.generatorService.register(this.typeScriptGenerator);
|
|
3576
|
+
}
|
|
3577
|
+
};
|
|
3578
|
+
GeneratorModule = _ts_decorate9([
|
|
3579
|
+
(0, import_common9.Module)({
|
|
3580
|
+
imports: [
|
|
3581
|
+
OpenApiModule,
|
|
3582
|
+
ConfigModule
|
|
3583
|
+
],
|
|
3584
|
+
providers: [
|
|
3585
|
+
GeneratorService,
|
|
3586
|
+
IrBuilderService,
|
|
3587
|
+
SchemaConverterService,
|
|
3588
|
+
TypeScriptGeneratorService
|
|
3589
|
+
],
|
|
3590
|
+
exports: [
|
|
3591
|
+
GeneratorService,
|
|
3592
|
+
IrBuilderService,
|
|
3593
|
+
SchemaConverterService
|
|
3594
|
+
]
|
|
3595
|
+
}),
|
|
3596
|
+
_ts_metadata4("design:type", Function),
|
|
3597
|
+
_ts_metadata4("design:paramtypes", [
|
|
3598
|
+
typeof GeneratorService === "undefined" ? Object : GeneratorService,
|
|
3599
|
+
typeof TypeScriptGeneratorService === "undefined" ? Object : TypeScriptGeneratorService
|
|
3600
|
+
])
|
|
3601
|
+
], GeneratorModule);
|
|
3602
|
+
|
|
3603
|
+
// src/api/generate.ts
|
|
3604
|
+
var path6 = __toESM(require("path"));
|
|
3605
|
+
var fs5 = __toESM(require("fs"));
|
|
3606
|
+
var import_child_process2 = require("child_process");
|
|
3607
|
+
var import_util2 = require("util");
|
|
3608
|
+
var execAsync2 = (0, import_util2.promisify)(import_child_process2.exec);
|
|
3609
|
+
async function generate(configOrPath, options) {
|
|
3610
|
+
let config;
|
|
3611
|
+
let baseDir;
|
|
3612
|
+
if (typeof configOrPath === "string") {
|
|
3613
|
+
const configPath = path6.isAbsolute(configOrPath) ? configOrPath : path6.resolve(configOrPath);
|
|
3614
|
+
config = await loadMjsConfig(configPath);
|
|
3615
|
+
baseDir = options?.baseDir ?? path6.dirname(configPath);
|
|
3616
|
+
} else {
|
|
3617
|
+
config = configOrPath;
|
|
3618
|
+
baseDir = options?.baseDir;
|
|
3619
|
+
}
|
|
3620
|
+
const configService = new ConfigService();
|
|
3621
|
+
const openApiService = new OpenApiService();
|
|
3622
|
+
const schemaConverter = new SchemaConverterService();
|
|
3623
|
+
const irBuilder = new IrBuilderService(schemaConverter);
|
|
3624
|
+
const generatorService = new GeneratorService(irBuilder, openApiService);
|
|
3625
|
+
const typeScriptGenerator = new TypeScriptGeneratorService(configService);
|
|
3626
|
+
generatorService.register(typeScriptGenerator);
|
|
3627
|
+
for (const client of config.clients) {
|
|
3628
|
+
if (options?.client && client.name !== options.client) {
|
|
3629
|
+
continue;
|
|
3630
|
+
}
|
|
3631
|
+
const resolvedOutDir = baseDir ? path6.resolve(baseDir, client.outDir) : path6.resolve(client.outDir);
|
|
3632
|
+
await fs5.promises.mkdir(resolvedOutDir, {
|
|
3633
|
+
recursive: true
|
|
3634
|
+
});
|
|
3635
|
+
const clientWithResolvedPath = {
|
|
3636
|
+
...client,
|
|
3637
|
+
outDir: resolvedOutDir
|
|
3638
|
+
};
|
|
3639
|
+
await executePreCommands(configService, clientWithResolvedPath);
|
|
3640
|
+
await generatorService.generate(config.spec, clientWithResolvedPath);
|
|
3641
|
+
await executePostCommands(configService, clientWithResolvedPath);
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3644
|
+
__name(generate, "generate");
|
|
3645
|
+
async function executePreCommands(configService, client) {
|
|
3646
|
+
const command = configService.getPreCommand(client);
|
|
3647
|
+
if (command.length === 0) {
|
|
3648
|
+
return;
|
|
3649
|
+
}
|
|
3650
|
+
await executeCommand(command, client.outDir, "pre-command");
|
|
3651
|
+
}
|
|
3652
|
+
__name(executePreCommands, "executePreCommands");
|
|
3653
|
+
async function executePostCommands(configService, client) {
|
|
3654
|
+
const command = configService.getPostCommand(client);
|
|
3655
|
+
if (command.length === 0) {
|
|
3656
|
+
return;
|
|
3657
|
+
}
|
|
3658
|
+
await executeCommand(command, client.outDir, "post-command");
|
|
3659
|
+
}
|
|
3660
|
+
__name(executePostCommands, "executePostCommands");
|
|
3661
|
+
async function executeCommand(command, cwd, label) {
|
|
3662
|
+
try {
|
|
3663
|
+
const [cmd, ...args] = command;
|
|
3664
|
+
const { stdout, stderr } = await execAsync2(`${cmd} ${args.map((a) => `"${a}"`).join(" ")}`, {
|
|
3665
|
+
cwd,
|
|
3666
|
+
maxBuffer: 10 * 1024 * 1024
|
|
3667
|
+
});
|
|
3668
|
+
if (stdout) {
|
|
3669
|
+
console.debug(`[${label}] ${stdout}`);
|
|
3670
|
+
}
|
|
3671
|
+
if (stderr && !stderr.includes("warning")) {
|
|
3672
|
+
console.warn(`[${label}] ${stderr}`);
|
|
3673
|
+
}
|
|
3674
|
+
} catch (error) {
|
|
3675
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3676
|
+
throw new Error(`${label} failed: ${errorMessage}`);
|
|
3677
|
+
}
|
|
3678
|
+
}
|
|
3679
|
+
__name(executeCommand, "executeCommand");
|
|
3680
|
+
async function loadConfig(configPath) {
|
|
3681
|
+
return loadMjsConfig(configPath);
|
|
3682
|
+
}
|
|
3683
|
+
__name(loadConfig, "loadConfig");
|
|
3684
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
3685
|
+
0 && (module.exports = {
|
|
3686
|
+
ClientSchema,
|
|
3687
|
+
ConfigModule,
|
|
3688
|
+
ConfigSchema,
|
|
3689
|
+
ConfigService,
|
|
3690
|
+
GeneratorModule,
|
|
3691
|
+
GeneratorService,
|
|
3692
|
+
IRSchemaKind,
|
|
3693
|
+
OpenApiModule,
|
|
3694
|
+
OpenApiService,
|
|
3695
|
+
PredefinedTypeSchema,
|
|
3696
|
+
TYPESCRIPT_TEMPLATE_NAMES,
|
|
3697
|
+
TypeScriptClientSchema,
|
|
3698
|
+
defineConfig,
|
|
3699
|
+
generate,
|
|
3700
|
+
loadConfig,
|
|
3701
|
+
loadMjsConfig
|
|
3702
|
+
});
|
|
22
3703
|
//# sourceMappingURL=index.js.map
|