@jointly/gen-ts-from-wsdl
Version:
A command-line tool to generate TypeScript interfaces from WSDL files for SOAP services
6 lines • 10.1 kB
JavaScript
import*as E from"xml2js";import W from"axios";import*as C from"fs";var L=class{constructor(){this.namespaces=new Map}async parseWSDL(e){let s;e.startsWith("http://")||e.startsWith("https://")?s=await this.downloadWSDL(e):s=await this.readWSDLFile(e);let n=await new E.Parser({explicitArray:!1,ignoreAttrs:!1,mergeAttrs:!0,explicitCharkey:!1}).parseStringPromise(s);return this.extractTypes(n)}async downloadWSDL(e){try{return console.log(`Downloading WSDL from: ${e}`),(await W.get(e,{headers:{"User-Agent":"wsdl-to-ts/1.0.0"},timeout:3e4})).data}catch(s){throw new Error(`Failed to download WSDL from ${e}: ${s}`)}}async readWSDLFile(e){try{return console.log(`Reading WSDL file: ${e}`),C.readFileSync(e,"utf-8")}catch(s){throw new Error(`Failed to read WSDL file ${e}: ${s}`)}}extractTypes(e){let s=e.definitions||e["wsdl:definitions"];if(!s)throw new Error("Invalid WSDL: No definitions found");this.extractNamespaces(s);let t=s.targetNamespace||"",n=s.types||s["wsdl:types"]||{},r=n.schema||n["xs:schema"]||n["xsd:schema"]||[],i=Array.isArray(r)?r:[r].filter(Boolean),p=[],l=[],y=[];i.forEach(m=>{let g=m.complexType||m["xs:complexType"]||m["xsd:complexType"];if(g){let d=Array.isArray(g)?g:[g];p.push(...d.map(T=>this.parseComplexType(T)))}let A=m.simpleType||m["xs:simpleType"]||m["xsd:simpleType"];if(A){let d=Array.isArray(A)?A:[A];l.push(...d.map(T=>this.parseSimpleType(T)))}let S=m.element||m["xs:element"]||m["xsd:element"];if(S){let d=Array.isArray(S)?S:[S];y.push(...d.map(T=>this.parseElement(T)))}});let a=[],o=s.message||s["wsdl:message"]||[];(Array.isArray(o)?o:[o].filter(Boolean)).forEach(m=>{a.push(this.parseMessage(m))});let f=[],h=s.portType||s["wsdl:portType"]||[];return(Array.isArray(h)?h:[h].filter(Boolean)).forEach(m=>{f.push(this.parsePortType(m))}),{targetNamespace:t,complexTypes:p,simpleTypes:l,messages:a,portTypes:f,elements:y}}extractNamespaces(e){Object.keys(e).forEach(s=>{if(s.startsWith("xmlns:")||s==="xmlns"){let t=s==="xmlns"?"":s.substring(6);this.namespaces.set(t,e[s])}})}parseComplexType(e){let s=e.name,t=[],n=[],r=e.sequence||e["xs:sequence"]||e["xsd:sequence"];if(r){let a=r.element||r["xs:element"]||r["xsd:element"];if(a){let o=Array.isArray(a)?a:[a];t.push(...o.map(c=>this.parseElement(c)))}}let i=e.all||e["xs:all"]||e["xsd:all"];if(i){let a=i.element||i["xs:element"]||i["xsd:element"];if(a){let o=Array.isArray(a)?a:[a];t.push(...o.map(c=>this.parseElement(c)))}}let p=e.choice||e["xs:choice"]||e["xsd:choice"];if(p){let a=p.element||p["xs:element"]||p["xsd:element"];if(a){let o=Array.isArray(a)?a:[a];t.push(...o.map(c=>this.parseElement(c)))}}let l=e.attribute||e["xs:attribute"]||e["xsd:attribute"];if(l){let a=Array.isArray(l)?l:[l];n.push(...a.map(o=>this.parseAttribute(o)))}let y=e.complexContent||e["xs:complexContent"]||e["xsd:complexContent"];if(y){let a=y.extension||y["xs:extension"]||y["xsd:extension"];if(a){let c=a.sequence||a["xs:sequence"]||a["xsd:sequence"];if(c){let u=c.element||c["xs:element"]||c["xsd:element"];if(u){let m=Array.isArray(u)?u:[u];t.push(...m.map(g=>this.parseElement(g)))}}let f=a.all||a["xs:all"]||a["xsd:all"];if(f){let u=f.element||f["xs:element"]||f["xsd:element"];if(u){let m=Array.isArray(u)?u:[u];t.push(...m.map(g=>this.parseElement(g)))}}let h=a.choice||a["xs:choice"]||a["xsd:choice"];if(h){let u=h.element||h["xs:element"]||h["xsd:element"];if(u){let m=Array.isArray(u)?u:[u];t.push(...m.map(g=>this.parseElement(g)))}}}let o=y.restriction||y["xs:restriction"]||y["xsd:restriction"];if(o&&(o.base==="soapenc:Array"||o.base==="SOAP-ENC:Array")){let c=o.attribute;if(c){let h=(Array.isArray(c)?c[0]:c)["wsdl:arrayType"];if(h){let u=h.replace(/\[\]$/,"");return{name:s,elements:t,attributes:n.length>0?n:void 0,soapArrayType:this.cleanTypeName(u)}}}}}return{name:s,elements:t,attributes:n.length>0?n:void 0}}parseSimpleType(e){let s=e.name,t=e.restriction||e["xs:restriction"]||e["xsd:restriction"];if(t){let n={name:s,restriction:{base:this.cleanTypeName(t.base)}},r=t.enumeration||t["xs:enumeration"]||t["xsd:enumeration"];if(r){let y=Array.isArray(r)?r:[r];n.restriction.enumeration=y.map(a=>a.value)}let i=t.pattern||t["xs:pattern"]||t["xsd:pattern"];i&&(n.restriction.pattern=i.value);let p=t.minLength||t["xs:minLength"]||t["xsd:minLength"];p&&(n.restriction.minLength=parseInt(p.value));let l=t.maxLength||t["xs:maxLength"]||t["xsd:maxLength"];return l&&(n.restriction.maxLength=parseInt(l.value)),n}return{name:s}}parseElement(e){return{name:e.name,type:this.cleanTypeName(e.type),minOccurs:e.minOccurs,maxOccurs:e.maxOccurs,nillable:e.nillable==="true"}}parseAttribute(e){return{name:e.name,type:this.cleanTypeName(e.type),use:e.use}}parseMessage(e){let s=e.part?Array.isArray(e.part)?e.part:[e.part]:[];return{name:e.name,parts:s.map(t=>({name:t.name,element:t.element,type:t.type?this.cleanTypeName(t.type):void 0}))}}parsePortType(e){let s=e.operation?Array.isArray(e.operation)?e.operation:[e.operation]:[];return{name:e.name,operations:s.map(t=>({name:t.name,input:t.input?{message:this.cleanTypeName(t.input.message)}:void 0,output:t.output?{message:this.cleanTypeName(t.output.message)}:void 0,fault:t.fault?(Array.isArray(t.fault)?t.fault:[t.fault]).map(n=>({name:n.name,message:this.cleanTypeName(n.message)})):void 0}))}}cleanTypeName(e){if(!e)return"any";let s=e.lastIndexOf(":");return s!==-1?e.substring(s+1):e}};import*as x from"fs";import*as $ from"path";var b=class{constructor(){this.typeMapping=new Map([["string","string"],["int","number"],["integer","number"],["long","number"],["short","number"],["byte","number"],["unsignedlong","number"],["unsignedint","number"],["unsignedshort","number"],["unsignedbyte","number"],["float","number"],["double","number"],["decimal","number"],["boolean","boolean"],["date","Date"],["datetime","Date"],["time","Date"],["base64binary","string"],["hexbinary","string"],["anyuri","string"],["qname","string"],["anytype","any"]])}generateTypes(e,s={}){let t=[];return t.push("// Generated TypeScript types from WSDL"),t.push("// Generated on: "+new Date().toISOString()),t.push(""),e.simpleTypes.length>0&&(t.push("// Simple Types"),e.simpleTypes.forEach(n=>{t.push(...this.generateSimpleType(n)),t.push("")})),e.complexTypes.length>0&&(t.push("// Complex Types"),e.complexTypes.forEach(n=>{t.push(...this.generateComplexType(n,s)),t.push("")})),e.elements.length>0&&(t.push("// Element Types"),e.elements.forEach(n=>{t.push(...this.generateElementType(n)),t.push("")})),e.messages.length>0&&(t.push("// Message Types"),e.messages.forEach(n=>{t.push(...this.generateMessageType(n,e,s)),t.push("")})),s.includeOperations&&e.portTypes.length>0&&(t.push("// Service Operations"),e.portTypes.forEach(n=>{t.push(...this.generatePortTypeInterface(n)),t.push("")})),t.join(`
`)}async writeTypesToFile(e,s="./types.ts",t={}){let n=this.generateTypes(e,t),r=$.dirname(s);x.existsSync(r)||x.mkdirSync(r,{recursive:!0}),x.writeFileSync(s,n),console.log(`TypeScript types written to: ${s}`)}generateSimpleType(e){let s=[];if(e.restriction?.enumeration)s.push(`export enum ${this.toPascalCase(e.name)} {`),e.restriction.enumeration.forEach((t,n)=>{let r=this.toEnumKey(t),i=n<e.restriction.enumeration.length-1?",":"";s.push(` ${r} = '${t}'${i}`)}),s.push("}");else if(e.restriction){let t=this.mapXmlTypeToTypeScript(e.restriction.base),n="";e.restriction.pattern&&(n+=`// Pattern: ${e.restriction.pattern}
`),e.restriction.minLength!==void 0&&(n+=`// Min length: ${e.restriction.minLength}
`),e.restriction.maxLength!==void 0&&(n+=`// Max length: ${e.restriction.maxLength}
`),n&&s.push(n.trim()),s.push(`export type ${this.toPascalCase(e.name)} = ${t};`)}else s.push(`export type ${this.toPascalCase(e.name)} = any;`);return s}generateComplexType(e,s={}){let t=[],n=this.toPascalCase(e.name);if(e.soapArrayType){let r=this.mapXmlTypeToTypeScript(e.soapArrayType);return t.push(`export type ${n} = ${r}[];`),t}return t.push(`export interface ${n} {`),e.elements.forEach(r=>{let i=r.name,p=this.mapXmlTypeToTypeScript(r.type),l=s.strict?r.minOccurs==="0"||r.nillable:r.minOccurs==="0"||r.nillable||r.minOccurs===void 0,y=r.maxOccurs==="unbounded"||r.maxOccurs&&parseInt(r.maxOccurs)>1,a=p;y&&(a=`${p}[]`),r.nillable&&(a=`${a} | null`);let o=l?"?":"";t.push(` ${i}${o}: ${a};`)}),e.attributes&&e.attributes.forEach(r=>{let i=this.toCamelCase(r.name),p=this.mapXmlTypeToTypeScript(r.type),y=r.use!=="required"?"?":"";t.push(` ${i}${y}: ${p};`)}),t.push("}"),t}generateElementType(e){let s=[],t=this.toPascalCase(e.name),n=this.mapXmlTypeToTypeScript(e.type),r=e.maxOccurs==="unbounded"||e.maxOccurs&&parseInt(e.maxOccurs)>1,i=n;return r&&(i=`${n}[]`),e.nillable&&(i=`${i} | null`),s.push(`export type ${t} = ${i};`),s}generateMessageType(e,s,t={}){let n=[],r=this.toPascalCase(e.name);return n.push(`export interface ${r} {`),e.parts.forEach(i=>{let p=i.name,l="any";if(i.element){let o=this.cleanTypeName(i.element),c=s.elements.find(f=>f.name===o);c?l=this.mapXmlTypeToTypeScript(c.type):l=this.toPascalCase(o)}else i.type&&(l=this.mapXmlTypeToTypeScript(i.type));let a=!t.strict?"?":"";n.push(` ${p}${a}: ${l};`)}),n.push("}"),n}generatePortTypeInterface(e){let s=[],t=`I${this.toPascalCase(e.name)}`;return s.push(`export interface ${t} {`),e.operations.forEach(n=>{let r=this.toCamelCase(n.name),i=n.input?this.toPascalCase(n.input.message):"void",p=n.output?this.toPascalCase(n.output.message):"void";s.push(` ${r}(request: ${i}): Promise<${p}>;`)}),s.push("}"),s}mapXmlTypeToTypeScript(e){if(!e)return"any";let s=this.cleanTypeName(e),t=this.typeMapping.get(s.toLowerCase());return t||this.toPascalCase(s)}toPascalCase(e){return e?e.replace(/[-_\s]+(.)?/g,(s,t)=>t?t.toUpperCase():"").replace(/^(.)/,(s,t)=>t.toUpperCase()):""}toCamelCase(e){if(!e)return"";let s=this.toPascalCase(e);return s.charAt(0).toLowerCase()+s.slice(1)}toEnumKey(e){return e.replace(/[^a-zA-Z0-9]/g,"_").replace(/^(\d)/,"_$1").toUpperCase()}cleanTypeName(e){if(!e)return"any";let s=e.lastIndexOf(":");return s!==-1?e.substring(s+1):e}};export{b as TypeScriptGenerator,L as WSDLParser};
//# sourceMappingURL=index.js.map