oapiex 0.3.2 → 0.3.3

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/bin/cli.mjs CHANGED
@@ -136,7 +136,7 @@ import{JSDOM as e}from"jsdom";import{Window as t}from"happy-dom";import n from"a
136
136
  `)}renderValue(e){return this.renderLiteral(e,0)}renderOpenApiDocumentValue(e){return this.renderLiteral(this.normalizeOpenApiDocument(e),0)}toCamelCase(e){let t=this.sanitizeTypeName(e);return t.charAt(0).toLowerCase()+t.slice(1)}renderInterface(e){let t=e.properties.map(e=>` ${this.formatPropertyKey(e.key)}${e.optional?`?`:``}: ${this.renderShape(e.shape)}`).join(`
137
137
  `);return`export interface ${e.name} {\n${t}\n}`}renderShape(e){switch(e.kind){case`primitive`:return e.type;case`array`:return`${this.wrapUnion(this.renderShape(e.item))}[]`;case`union`:return e.types.map(e=>this.renderShape(e)).join(` | `);case`object`:return this.inlineObjectShape(e)}}inlineObjectShape(e){return e.properties.length===0?`Record<string, never>`:`{ ${e.properties.map(e=>`${this.formatPropertyKey(e.key)}${e.optional?`?`:``}: ${this.renderShape(e.shape)}`).join(`; `)} }`}wrapUnion(e){return e.includes(` | `)?`(${e})`:e}derivePathTypeName(e){let t=e.split(`/`).map(e=>e.trim()).filter(Boolean).filter(e=>!/^v\d+$/i.test(e)).map(e=>this.isPathParam(e)?`by ${this.stripPathParam(e)}`:e);return`${this.sanitizeTypeName(t.join(` `))}Path`}deriveOperationInterfaceName(e,t){return`${this.derivePathTypeName(e)}${this.sanitizeTypeName(t)}Operation`}sanitizeTypeName(e){let t=e.replace(/[^A-Za-z0-9]+/g,` `).trim();if(!t)return`GeneratedEntity`;let n=t.split(/\s+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(``);return/^[A-Za-z_$]/.test(n)?n:`Type${n}`}formatPropertyKey(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)?e:`'${this.escapeStringLiteral(e)}'`}renderSdkMethodSignature(e){let t=[];return e.pathParams.length>0&&t.push(`(params: ${e.paramsType}`),e.queryParams.length>0&&t.push(`${t.length===0?`(`:`, `}query: ${e.queryType}`),e.hasBody&&t.push(`${t.length===0?`(`:`, `}body${e.bodyRequired?``:`?`}: ${e.inputType}`),e.headerParams.length>0&&t.push(`${t.length===0?`(`:`, `}headers?: ${e.headerType}`),t.length===0?`(): Promise<${e.responseType}>`:`${t.join(``)}): Promise<${e.responseType}>`}renderLiteral(e,t){if(e===null)return`null`;if(typeof e==`string`)return`'${this.escapeStringLiteral(e)}'`;if(typeof e==`number`||typeof e==`boolean`)return String(e);if(Array.isArray(e)){if(e.length===0)return`[]`;let n=this.indent(t+1),r=this.indent(t);return`[\n${e.map(e=>`${n}${this.renderLiteral(e,t+1)}`).join(`,
138
138
  `)}\n${r}]`}if(typeof e==`object`){let n=Object.entries(e);if(n.length===0)return`{}`;let r=this.indent(t+1),i=this.indent(t);return`{\n${n.map(([e,n])=>`${r}${this.formatPropertyKey(e)}: ${this.renderLiteral(n,t+1)}`).join(`,
139
- `)}\n${i}}`}return`undefined`}normalizeOpenApiDocument(e){return this.normalizeObject(e,(e,t,n)=>{if(e===`example`&&n&&typeof n==`object`&&!Array.isArray(n)){let e=n;if(e.schema&&this.isPlainObject(e.schema))return this.normalizeExample(t,e.schema);if(this.isSchemaLike(e))return this.normalizeExample(t,e)}return t})}normalizeObject(e,t){if(Array.isArray(e))return e.map(e=>this.normalizeObject(e,t)).filter(e=>e!==void 0);if(!this.isPlainObject(e))return e;let n={};for(let[r,i]of Object.entries(e)){let a=t(r,i,e),o=this.normalizeObject(a,t);o!==void 0&&(n[r]=o)}return n}normalizeExample(e,t){if(e===void 0)return;let n=typeof t.type==`string`?t.type:void 0;if(n===`string`)return typeof e==`string`?e:typeof e==`number`||typeof e==`boolean`?String(e):void 0;if(n===`number`||n===`integer`)return typeof e==`number`?e:typeof e==`string`&&e.trim()!==``&&Number.isFinite(Number(e))?Number(e):void 0;if(n===`boolean`)return typeof e==`boolean`?e:e===`true`?!0:e===`false`?!1:void 0;if(n===`array`){if(!Array.isArray(e))return;let n=this.isPlainObject(t.items)?t.items:void 0;return n?e.map(e=>this.normalizeExample(e,n)).filter(e=>e!==void 0):e}if(n===`object`){if(!this.isPlainObject(e))return;let n=this.isPlainObject(t.properties)?t.properties:{},r=Array.isArray(t.required)?t.required.filter(e=>typeof e==`string`):[],i={};for(let[t,r]of Object.entries(e)){let e=n[t],a=e?this.normalizeExample(r,e):r;a!==void 0&&(i[t]=a)}for(let e of r){if(e in i)continue;let t=n[e];if(!t)return;let r=t.default===void 0?t.example===void 0?void 0:this.normalizeExample(t.example,t):this.normalizeExample(t.default,t);if(r===void 0)return;i[e]=r}return i}return e}isPlainObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}isSchemaLike(e){return`type`in e||`properties`in e||`items`in e||`required`in e||`default`in e}indent(e){return` `.repeat(e)}escapeStringLiteral(e){return e.replace(/\\/g,String.raw`\\`).replace(/'/g,String.raw`\'`).replace(/\r/g,String.raw`\r`).replace(/\n/g,String.raw`\n`).replace(/\t/g,String.raw`\t`).replace(/\f/g,String.raw`\f`).replace(/\x08/g,String.raw`\b`).replace(/\u2028/g,String.raw`\u2028`).replace(/\u2029/g,String.raw`\u2029`)}isPathParam(e){return e.startsWith(`{`)&&e.endsWith(`}`)||/^:[A-Za-z0-9_]+$/.test(e)}stripPathParam(e){return e.replace(/^\{/,``).replace(/\}$/,``).replace(/^:/,``)}},Ye=class e{static contextualTailSegments=new Set([`history`,`status`,`detail`,`details`]);static nestedContextSegments=new Set([`account`,`accounts`,`transaction`,`transactions`,`wallet`,`wallets`,`virtual-account`,`virtual-accounts`,`history`]);static roleSuffixes=[`Input`,`Query`,`Header`,`Params`];sanitizeTypeName(e){let t=e.replace(/[^A-Za-z0-9]+/g,` `).trim();if(!t)return`GeneratedEntity`;let n=t.split(/\s+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(``);return/^[A-Za-z_$]/.test(n)?n:`Type${n}`}isPathParam(e){return e.startsWith(`{`)&&e.endsWith(`}`)||/^:[A-Za-z0-9_]+$/.test(e)}stripPathParam(e){return e.replace(/^\{/,``).replace(/\}$/,``).replace(/^:/,``)}singularize(e){return/ies$/i.test(e)?`${e.slice(0,-3)}y`:/(sses|shes|ches|xes|zes)$/i.test(e)?e.slice(0,-2):e.endsWith(`s`)&&!e.endsWith(`ss`)&&e.length>1?e.slice(0,-1):e}pluralize(e){return/y$/i.test(e)?`${e.slice(0,-1)}ies`:/s$/i.test(e)?e:`${e}s`}toCamelCase(e){let t=this.sanitizeTypeName(e);return t.charAt(0).toLowerCase()+t.slice(1)}deriveOperationNaming(t){let n=this.getNormalizedPathSegments(t),r=n.filter(e=>!this.isPathParam(e)).map(e=>this.singularize(e)),i=n.filter(e=>this.isPathParam(e)).map(e=>this.singularize(this.stripPathParam(e))),a=r[r.length-1]??`resource`,o=r[r.length-2]??null,s=n.slice(0,-1).some(e=>this.isPathParam(e)),c=!!(o&&(e.contextualTailSegments.has(a.toLowerCase())||s&&e.nestedContextSegments.has(a.toLowerCase())));return{baseName:this.sanitizeTypeName(c?`${o} ${a}`:a),collisionSuffix:i.length>0?`By ${i.map(e=>this.sanitizeTypeName(e)).join(` And `)}`:o&&!c?this.sanitizeTypeName(o):``}}fallbackCollisionSuffix(e,t,n){let r=this.getNormalizedPathSegments(t),i=r.filter(e=>!this.isPathParam(e)),a=i[i.length-1]??``,o=r.some(e=>this.isPathParam(e));return e===`get`&&!o&&/s$/i.test(a)?`List`:e===`post`&&!o?`Create`:(e===`put`||e===`patch`)&&o?`Update`:e===`delete`?`Delete`:`${this.sanitizeTypeName(e)}${n}`}insertCollisionSuffix(t,n){if(!n)return t;for(let r of e.roleSuffixes)if(t.endsWith(r)&&t.length>r.length)return`${t.slice(0,-r.length)}${n}${r}`;return`${t}${n}`}deriveSdkGroupNamesBySignature(e,t){let n=new Map;for(let t of Object.keys(e.paths)){let e=this.getStaticPathSignature(t);n.has(e)||n.set(e,t)}let r=Array.from(n.entries()).map(([e,n])=>({signature:e,staticSegments:e.split(`/`).filter(Boolean),candidates:this.buildSdkGroupNameCandidates(n,t)})).sort((e,t)=>e.staticSegments.length-t.staticSegments.length||e.signature.localeCompare(t.signature)),i=new Map,a=new Set;for(let e of r){let t=e.candidates.find(e=>!a.has(e))??this.createUniqueSdkGroupName(e.candidates[e.candidates.length-1]??`Resource`,a);a.add(t),i.set(e.signature,t)}return i}getStaticPathSegments(e){return this.getNormalizedPathSegments(e).filter(e=>!this.isPathParam(e)).map(e=>this.singularize(e))}getStaticPathSignature(e){return this.getStaticPathSegments(e).join(`/`)}getNormalizedPathSegments(e){return e.split(`/`).map(e=>e.trim()).filter(Boolean).filter(e=>!/^v\d+$/i.test(e))}deriveSdkMethodName(e,t,n,r){if(r===`operation-id`&&n.operationId)return this.toCamelCase(this.sanitizeTypeName(n.operationId));let i=this.getNormalizedPathSegments(t).some(e=>this.isPathParam(e));return e===`get`?this.endsWithPluralStaticSegment(t)?`list`:i?`get`:`list`:e===`post`?`create`:e===`patch`||e===`put`?`update`:e===`delete`?`delete`:this.toCamelCase(this.sanitizeTypeName(e))}ensureUniqueSdkMethodNames(e){let t=new Map;return e.map(e=>{let n=t.get(e.methodName)??0;if(t.set(e.methodName,n+1),n===0)return e;let r=this.sanitizeTypeName(this.fallbackCollisionSuffix(e.method.toLowerCase(),e.path,`Operation`));return{...e,methodName:`${e.methodName}${r}`}})}createSdkParameterManifest(e,t,n){return[...(e??[]).filter(e=>e.in===t).sort((e,t)=>e.name.localeCompare(t.name)),...this.getInferredPathParameters(n,t,(e??[]).filter(e=>e.in===t))].sort((e,t)=>e.name.localeCompare(t.name)).map(e=>({name:e.name,accessor:this.toParameterAccessor(e.name),in:t,required:e.required??!1,description:e.description}))}getInferredPathParameters(e,t,n){if(t!==`path`||!e)return[];let r=new Set(n.map(e=>e.name));return this.getNormalizedPathSegments(e).filter(e=>this.isPathParam(e)).map(e=>this.stripPathParam(e)).filter(e=>!r.has(e)).map(e=>({name:e,in:`path`,required:!0,schema:{type:`string`}}))}buildSdkGroupNameCandidates(e,t){let n=this.getNormalizedPathSegments(e),r=n.filter(e=>!this.isPathParam(e)),i=r.map(e=>this.singularize(e)),a=this.deriveOperationNaming(e).baseName,o=this.getPreferredSdkGroupName(n,r,i),s=i.map((e,t,n)=>this.sanitizeTypeName(n.slice(t).join(` `))).reverse();return t===`scoped`?Array.from(new Set([o??``,this.sanitizeTypeName(i.join(` `)),...s,a].filter(Boolean))):Array.from(new Set([o??``,a,...s].filter(Boolean)))}getPreferredSdkGroupName(e,t,n){let r=t[t.length-1],i=n[n.length-1],a=n[n.length-2],o=e.some(e=>this.isPathParam(e)),s=e.slice(0,-1).some(e=>this.isPathParam(e));return!r||!i||!a?null:t.length===2&&!o?this.sanitizeTypeName(`${i} ${a}`):s?this.singularize(r)===r?this.sanitizeTypeName(`${i} ${a}`):this.sanitizeTypeName(`${a} ${i}`):null}createUniqueSdkGroupName(e,t){let n=2,r=e;for(;t.has(r);)r=`${e}${n}`,n+=1;return r}endsWithPluralStaticSegment(e){let t=this.getNormalizedPathSegments(e).at(-1);return!t||this.isPathParam(t)?!1:this.singularize(t)!==t}toParameterAccessor(e){let t=e.replace(/[^A-Za-z0-9]+/g,` `).trim();if(!t)return`value`;let[n,...r]=t.split(/\s+/).filter(Boolean),i=[n.toLowerCase(),...r.map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase())].join(``);return/^[A-Za-z_$]/.test(i)?i:`value${i}`}},Xe=class{constructor(e){this.naming=e}createContext(){return{declarations:[],declarationByName:new Map,nameBySignature:new Map,usedNames:new Set}}namespaceTopLevelShape(e,t){return e.kind===`object`?{...e,signature:`${t}:${e.signature}`}:e}inferShapeFromExample(e,t){if(e===null)return{kind:`primitive`,type:`null`};if(Array.isArray(e)){if(e.length===0)return{kind:`array`,item:{kind:`primitive`,type:`unknown`}};let n=this.dedupeShapes(e.map(e=>this.inferShapeFromExample(e,this.naming.singularize(t))));return{kind:`array`,item:n.length===1?n[0]:{kind:`union`,types:n}}}if(this.isRecord(e))return this.createObjectShape(Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>({key:e,optional:!1,shape:this.inferShapeFromExample(t,e)})));switch(typeof e){case`string`:return{kind:`primitive`,type:`string`};case`number`:return{kind:`primitive`,type:`number`};case`boolean`:return{kind:`primitive`,type:`boolean`};default:return{kind:`primitive`,type:`unknown`}}}registerNamedShape(e,t,n,r){if(e.kind===`object`)return this.registerObjectShape(e,t,n,r,!0);let i=this.createUniqueTypeName(t,n,r),a={kind:`shape-alias`,name:i,shape:this.prepareNestedShape(e,t,n)};return n.declarations.push(a),n.declarationByName.set(i,a),i}registerObjectShape(e,t,n,r,i=!1){let a=n.nameBySignature.get(e.signature),o=this.findCompatibleObjectDeclaration(e,t,n);if(a){if(i&&a!==t&&!n.declarationByName.has(t)){let e=this.createUniqueTypeName(t,n,r);if(e!==a){let t={kind:`interface-alias`,name:e,target:a};n.declarations.push(t),n.declarationByName.set(e,t)}}return a}if(o){if(this.isObjectShapeAssignableTo(e,o.rawShape))return n.nameBySignature.set(e.signature,o.name),o.name;let t=this.mergeObjectShapes(o.rawShape,e);return o.rawShape=t,o.properties=t.properties.map(e=>({...e,shape:this.prepareNestedShape(e.shape,e.key,n)})),n.nameBySignature.set(e.signature,o.name),n.nameBySignature.set(t.signature,o.name),o.name}let s=this.createUniqueTypeName(t,n,r),c={kind:`interface`,name:s,baseName:this.naming.sanitizeTypeName(t),rawShape:e,properties:[]};return n.nameBySignature.set(e.signature,s),n.declarations.push(c),n.declarationByName.set(s,c),c.properties=e.properties.map(e=>({...e,shape:this.prepareNestedShape(e.shape,e.key,n)})),s}resolveSdkResponseType(e,t){let n=Object.entries(e).filter(([e])=>/^2\d\d$/.test(e)).sort(([e],[t])=>e.localeCompare(t))[0]?.[1];if(!n)return t;let r=this.getPreferredMediaType(n.content);if(!r)return t;let i=this.resolveResponsePayloadSchema(r.schema,r.example).schema??r.schema;return i&&this.resolveSchemaType(i)===`array`?`${t}[]`:t}getSuccessResponseShape(e){let t=Object.entries(e).filter(([e])=>/^2\d\d$/.test(e)).sort(([e],[t])=>e.localeCompare(t))[0]?.[1];if(!t)return this.emptyObjectShape;let n=this.getPreferredMediaType(t.content);if(!n)return this.emptyObjectShape;let r=this.resolveResponsePayloadSchema(n.schema,n.example);return r.schema?this.resolveSchemaType(r.schema)===`array`?this.schemaToShape(r.schema.items,`Item`,this.extractExampleArrayItem(r.example)):this.schemaToShape(r.schema,`Response`,r.example):this.schemaToShape(n.schema,`Response`,n.example)}getRequestInputShape(e){if(!e)return this.emptyObjectShape;let t=this.getPreferredMediaType(e.content);return t?this.schemaToShape(t.schema,`Input`,t.example):this.emptyObjectShape}getResponseExampleShape(e){let t=Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).flatMap(([,e])=>{let t=this.getPreferredMediaType(e.content);if(!t)return[];let n=t.example??t.schema?.example;return t.schema?[this.schemaToShape(t.schema,`ResponseExample`,n)]:n===void 0?[]:[this.inferShapeFromExample(n,`ResponseExample`)]}),n=this.dedupeShapes(t);return n.length===0?{kind:`primitive`,type:`unknown`}:n.length===1?n[0]:{kind:`union`,types:n}}createParameterGroupShape(e,t,n){let r=(e??[]).filter(e=>e.in===t).sort((e,t)=>e.name.localeCompare(t.name)),i=[...r,...this.naming.getInferredPathParameters(n,t,r)].sort((e,t)=>e.name.localeCompare(t.name));return i.length===0?this.emptyObjectShape:this.createObjectShape(i.map(e=>({key:e.name,optional:!(e.required??!1),shape:this.schemaToShape(e.schema,e.name,e.example)})))}get emptyObjectShape(){return this.createObjectShape([])}findCompatibleObjectDeclaration(e,t,n){let r=this.naming.sanitizeTypeName(t);return n.declarations.find(t=>t.kind!==`interface`||t.baseName!==r?!1:this.isObjectShapeAssignableTo(e,t.rawShape)||this.isObjectShapeAssignableTo(t.rawShape,e)||this.canMergeObjectShapes(t.rawShape,e))}canMergeObjectShapes(e,t){let n=new Set([...e.properties.map(e=>e.key),...t.properties.map(e=>e.key)]);for(let r of n){let n=e.properties.find(e=>e.key===r),i=t.properties.find(e=>e.key===r);if(!n||!i){if(!(n??i)?.optional)return!1;continue}if(!this.canMergeShapes(n.shape,i.shape))return!1}return!0}isObjectShapeAssignableTo(e,t){let n=new Map(t.properties.map(e=>[e.key,e]));for(let t of e.properties){let e=n.get(t.key);if(!e||t.optional&&!e.optional||!this.isShapeAssignableTo(t.shape,e.shape))return!1}return t.properties.every(t=>e.properties.some(e=>e.key===t.key)||t.optional)}isShapeAssignableTo(e,t){if(t.kind===`union`)return t.types.some(t=>this.isShapeAssignableTo(e,t));switch(e.kind){case`primitive`:return t.kind===`primitive`?e.type===t.type:!1;case`array`:return t.kind===`array`?this.isShapeAssignableTo(e.item,t.item):!1;case`union`:return e.types.every(e=>this.isShapeAssignableTo(e,t));case`object`:return t.kind===`object`?this.isObjectShapeAssignableTo(e,t):!1}}canMergeShapes(e,t){return e.kind===`union`?e.types.every(e=>this.canMergeShapes(e,t)):t.kind===`union`?t.types.every(t=>this.canMergeShapes(e,t)):e.kind===`primitive`&&t.kind===`primitive`?!0:e.kind===`array`&&t.kind===`array`?this.canMergeShapes(e.item,t.item):e.kind===`object`&&t.kind===`object`?this.canMergeObjectShapes(e,t):!1}mergeObjectShapes(e,t){let n=new Set([...e.properties.map(e=>e.key),...t.properties.map(e=>e.key)]);return this.createObjectShape(Array.from(n).map(n=>{let r=e.properties.find(e=>e.key===n),i=t.properties.find(e=>e.key===n);return r&&i?{key:n,optional:r.optional||i.optional,shape:this.mergeShapes(r.shape,i.shape)}:{key:n,optional:!0,shape:(r??i).shape}}))}mergeShapes(e,t){if(e.kind===`union`||t.kind===`union`||e.kind!==t.kind)return this.createUnionShape(e,t);switch(e.kind){case`primitive`:return t.kind===`primitive`&&e.type===t.type?e:this.createUnionShape(e,t);case`array`:return t.kind===`array`?{kind:`array`,item:this.mergeShapes(e.item,t.item)}:e;case`object`:return t.kind===`object`?this.mergeObjectShapes(e,t):e}}createUnionShape(...e){let t=e.flatMap(e=>e.kind===`union`?e.types:[e]),n=this.dedupeShapes(t);return n.length===1?n[0]:{kind:`union`,types:n}}prepareNestedShape(e,t,n){if(e.kind===`object`)return{kind:`primitive`,type:this.registerObjectShape(e,this.naming.sanitizeTypeName(this.naming.singularize(t)),n,this.naming.sanitizeTypeName(t))};if(e.kind===`array`)return{kind:`array`,item:this.prepareNestedShape(e.item,this.naming.singularize(t),n)};if(e.kind===`union`){let r=this.dedupeShapes(e.types.map((e,r)=>this.prepareNestedShape(e,this.getUnionMemberKeyHint(t,r,e),n)));return r.length===1?r[0]:{kind:`union`,types:r}}return e}getUnionMemberKeyHint(e,t,n){if(n.kind!==`object`&&n.kind!==`array`)return e;let r=this.naming.sanitizeTypeName(e);return r.endsWith(`ResponseExample`)?`${r}Variant${t+1}`:e}schemaToShape(e,t,n){if(!e)return this.inferShapeFromExample(n,t);let r=this.resolveSchemaType(e);if(r===`array`)return{kind:`array`,item:this.schemaToShape(e.items,this.naming.singularize(t),this.extractExampleArrayItem(e.example)??this.extractExampleArrayItem(n))};if(r===`object`){let r=this.isRecord(e.example)?e.example:this.isRecord(n)?n:void 0,i=Object.entries(e.properties??{}).sort(([e],[t])=>e.localeCompare(t)).map(([t,n])=>({key:t,optional:!(e.required??[]).includes(t),shape:this.schemaToShape(n,t,r?.[t])}));return i.length>0?this.createObjectShape(i):this.inferShapeFromExample(e.example??n,t)}return r===`integer`||r===`number`?{kind:`primitive`,type:`number`}:r===`string`?{kind:`primitive`,type:`string`}:r===`boolean`?{kind:`primitive`,type:`boolean`}:e.example===null||n===null?{kind:`primitive`,type:`null`}:e.example!==void 0||n!==void 0?this.inferShapeFromExample(e.example??n,t):{kind:`primitive`,type:`unknown`}}dedupeShapes(e){let t=new Set;return e.filter(e=>{let n=this.getShapeSignature(e);return t.has(n)?!1:(t.add(n),!0)})}createObjectShape(e){let t=e.map(e=>({...e})).sort((e,t)=>e.key.localeCompare(t.key));return{kind:`object`,signature:JSON.stringify(t.map(e=>({key:e.key,optional:e.optional,shape:this.getShapeSignature(e.shape)}))),properties:t}}getShapeSignature(e){switch(e.kind){case`primitive`:return`primitive:${e.type}`;case`array`:return`array:${this.getShapeSignature(e.item)}`;case`union`:return`union:${e.types.map(e=>this.getShapeSignature(e)).join(`|`)}`;case`object`:return`object:${e.signature}`}}getPreferredMediaType(e){if(e)return e[`application/json`]??e[`application/*+json`]??Object.values(e)[0]}resolveResponsePayloadSchema(e,t){for(let n of[[`data`],[`meta`,`data`]]){let r=this.getSchemaCandidateAtPath(e,t,n);if(r)return r}return{}}getSchemaCandidateAtPath(e,t,n){let r=this.getSchemaAtPath(e,n),i=this.getExampleAtPath(t,n);if(!(!r&&i===void 0))return r?{schema:r.example===void 0&&i!==void 0?{...r,example:i}:r,example:i??r.example}:{schema:{...this.inferSchemaTypeFromExample(i),example:i},example:i}}getSchemaAtPath(e,t){let n=e;for(let e of t){if(!n?.properties?.[e])return;n=n.properties[e]}return n}getExampleAtPath(e,t){let n=e;for(let e of t){if(!this.isRecord(n)||!(e in n))return;n=n[e]}return n}inferSchemaTypeFromExample(e){return Array.isArray(e)?{type:`array`,items:e.map(e=>this.inferSchemaTypeFromExample(e)).find(e=>this.hasSchemaDetails(e))??{}}:this.isRecord(e)?{type:`object`,properties:Object.fromEntries(Object.entries(e).map(([e,t])=>[e,this.inferSchemaTypeFromExample(t)]))}:typeof e==`string`?{type:`string`}:typeof e==`number`?{type:`number`}:typeof e==`boolean`?{type:`boolean`}:{}}hasSchemaDetails(e){return!!(e?.type||e?.properties||e?.items||e?.example!==void 0)}resolveSchemaType(e){return e.type??(e.properties?`object`:void 0)}extractExampleArrayItem(e){return Array.isArray(e)?e[0]:void 0}createUniqueTypeName(e,t,n){let r=this.naming.sanitizeTypeName(e)||`GeneratedEntity`,i=this.naming.sanitizeTypeName(n),a=r,o=2;if(!t.usedNames.has(a)||(a=this.naming.insertCollisionSuffix(r,i),!t.usedNames.has(a)))return t.usedNames.add(a),a;for(;t.usedNames.has(a);)a=`${r}${o}`,o+=1;return t.usedNames.add(a),a}isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}},X=class{naming=new Ye;shapes=new Xe(this.naming);createContext(){return this.shapes.createContext()}collectSemanticModels(e){let t=[];for(let[n,r]of Object.entries(e.paths)){let e=this.naming.deriveOperationNaming(n),i=e.baseName,a=Object.entries(r).sort(([,e],[,t])=>this.getOperationPriority(t)-this.getOperationPriority(e));for(let[r,o]of a){let a=e.collisionSuffix||this.naming.fallbackCollisionSuffix(r,n,i);t.push({path:n,method:r,name:i,role:`response`,shape:this.shapes.getSuccessResponseShape(o.responses),collisionSuffix:a}),t.push({path:n,method:r,name:`${i}ResponseExample`,role:`responseExample`,shape:this.shapes.getResponseExampleShape(o.responses),collisionSuffix:a}),t.push({path:n,method:r,name:`${i}Input`,role:`input`,shape:this.shapes.getRequestInputShape(o.requestBody),collisionSuffix:a}),t.push({path:n,method:r,name:`${i}Query`,role:`query`,shape:this.shapes.createParameterGroupShape(o.parameters,`query`,n),collisionSuffix:a}),t.push({path:n,method:r,name:`${i}Header`,role:`header`,shape:this.shapes.createParameterGroupShape(o.parameters,`header`,n),collisionSuffix:a}),t.push({path:n,method:r,name:`${i}Params`,role:`params`,shape:this.shapes.createParameterGroupShape(o.parameters,`path`,n),collisionSuffix:a})}}return t}buildSdkManifest(e,t,n={}){let r=this.naming.deriveSdkGroupNamesBySignature(e,n.namespaceStrategy??`smart`),i=new Map,a=this.buildSecuritySchemes(e),o=this.buildSecurityRequirements(e.security);for(let[a,o]of Object.entries(e.paths)){let e=this.naming.getStaticPathSegments(a).join(`/`),s=r.get(e)??`Resource`,c=this.naming.toCamelCase(this.naming.pluralize(s)),l=i.get(c)??{className:s,propertyName:c,operations:[]};for(let[e,r]of Object.entries(o)){let i=t.get(`${a}::${e}`)??{response:`Record<string, never>`,responseExample:`unknown`,input:`Record<string, never>`,query:`Record<string, never>`,header:`Record<string, never>`,params:`Record<string, never>`};l.operations.push({path:a,method:e.toUpperCase(),methodName:this.naming.deriveSdkMethodName(e,a,r,n.methodStrategy??`smart`),summary:r.summary,description:r.description,operationId:r.operationId,requestBodyDescription:r.requestBody?.description,responseDescription:this.resolveSuccessResponseDescription(r.responses),responseType:this.shapes.resolveSdkResponseType(r.responses,i.response),inputType:i.input,queryType:i.query,headerType:i.header,paramsType:i.params,hasBody:!!r.requestBody,bodyRequired:r.requestBody?.required??!1,pathParams:this.naming.createSdkParameterManifest(r.parameters,`path`,a),queryParams:this.naming.createSdkParameterManifest(r.parameters,`query`,a),headerParams:this.naming.createSdkParameterManifest(r.parameters,`header`,a),security:this.buildSecurityRequirements(r.security)})}i.set(c,l)}return{groups:Array.from(i.values()).map(e=>({...e,operations:this.naming.ensureUniqueSdkMethodNames(e.operations)})).sort((e,t)=>e.propertyName.localeCompare(t.propertyName)),securitySchemes:a,security:o}}inferShapeFromExample(e,t){return this.shapes.inferShapeFromExample(e,t)}sanitizeTypeName(e){return this.naming.sanitizeTypeName(e)}registerNamedShape(e,t,n,r){return this.shapes.registerNamedShape(e,t,n,r)}namespaceTopLevelShape(e,t){return this.shapes.namespaceTopLevelShape(e,t)}registerObjectShape(e,t,n,r,i=!1){return this.shapes.registerObjectShape(e,t,n,r,i)}getOperationPriority(e){return Number(!!e.requestBody)*10}resolveSuccessResponseDescription(e){for(let t of[`200`,`201`,`202`,`204`]){let n=e[t]?.description?.trim();if(n)return n}for(let t of Object.values(e)){let e=t.description?.trim();if(e)return e}}buildSecuritySchemes(e){return Object.entries(e.components?.securitySchemes??{}).map(([e,t])=>this.createSecuritySchemeManifest(e,t)).filter(e=>e!==null).sort((e,t)=>e.name.localeCompare(t.name))}createSecuritySchemeManifest(e,t){let n=this.createSecurityHelperName(e);if(t.type===`apiKey`)return{name:e,helperName:n,description:t.description,type:`apiKey`,authType:`apiKey`,in:t.in,parameterName:t.name};if(t.type===`oauth2`)return{name:e,helperName:n,description:t.description,type:`oauth2`,authType:`oauth2`,scopes:this.collectSecurityScopes(t)};if(t.type===`openIdConnect`)return{name:e,helperName:n,description:t.description,type:`openIdConnect`,authType:`oauth2`,openIdConnectUrl:t.openIdConnectUrl};let r=t.scheme.toLowerCase();return{name:e,helperName:n,description:t.description,type:`http`,authType:r===`basic`?`basic`:`bearer`,scheme:t.scheme,bearerFormat:t.bearerFormat}}buildSecurityRequirements(e){if(!e||e.length===0)return;let t=e.map(e=>({schemes:Object.entries(e).map(([e,t])=>({name:e,scopes:[...t].sort()})).sort((e,t)=>e.name.localeCompare(t.name))})).filter(e=>e.schemes.length>0);return t.length>0?t:void 0}collectSecurityScopes(e){let t=new Set;for(let n of Object.values(e.flows??{}))for(let e of Object.keys(n.scopes??{}))t.add(e);return t.size>0?Array.from(t).sort():void 0}createSecurityHelperName(e){let t=this.naming.sanitizeTypeName(e);return t.endsWith(`Auth`)?`create${t}`:`create${t}Auth`}},Z=class e{typeBuilder=new X;moduleRenderer=new Je;static generateModule=(t,n=`GeneratedOutput`,r={})=>new e().generate(t,n,r);generate(e,t=`GeneratedOutput`,n={}){return this.isOpenApiDocumentLike(e)?this.generateModule(e,t,n):this.generateGenericModule(e,t)}generateModule(e,t,n={}){let r=this.typeBuilder.createContext(),i=new Map;for(let t of this.typeBuilder.collectSemanticModels(e)){let e=`${t.path}::${t.method}`,n=this.typeBuilder.registerNamedShape(this.typeBuilder.namespaceTopLevelShape(t.shape,t.role),t.name,r,t.collisionSuffix),a=i.get(e)??{response:`Record<string, never>`,responseExample:`unknown`,input:`Record<string, never>`,query:`Record<string, never>`,header:`Record<string, never>`,params:`Record<string, never>`};a[t.role]=n,i.set(e,a)}let a=r.declarations.map(e=>this.moduleRenderer.renderDeclaration(e)).join(`
139
+ `)}\n${i}}`}return`undefined`}normalizeOpenApiDocument(e){return this.normalizeObject(e,(e,t,n)=>{if(e===`example`&&n&&typeof n==`object`&&!Array.isArray(n)){let e=n;if(e.schema&&this.isPlainObject(e.schema))return this.normalizeExample(t,e.schema);if(this.isSchemaLike(e))return this.normalizeExample(t,e)}return t})}normalizeObject(e,t){if(Array.isArray(e))return e.map(e=>this.normalizeObject(e,t)).filter(e=>e!==void 0);if(!this.isPlainObject(e))return e;let n={};for(let[r,i]of Object.entries(e)){let a=t(r,i,e),o=this.normalizeObject(a,t);o!==void 0&&(n[r]=o)}return n}normalizeExample(e,t){if(e===void 0)return;let n=typeof t.type==`string`?t.type:void 0;if(n===`string`)return typeof e==`string`?e:typeof e==`number`||typeof e==`boolean`?String(e):void 0;if(n===`number`||n===`integer`)return typeof e==`number`?e:typeof e==`string`&&e.trim()!==``&&Number.isFinite(Number(e))?Number(e):void 0;if(n===`boolean`)return typeof e==`boolean`?e:e===`true`?!0:e===`false`?!1:void 0;if(n===`array`){if(!Array.isArray(e))return;let n=this.isPlainObject(t.items)?t.items:void 0;return n?e.map(e=>this.normalizeExample(e,n)).filter(e=>e!==void 0):e}if(n===`object`){if(!this.isPlainObject(e))return;let n=this.isPlainObject(t.properties)?t.properties:{},r=Array.isArray(t.required)?t.required.filter(e=>typeof e==`string`):[],i={};for(let[t,r]of Object.entries(e)){let e=n[t],a=e?this.normalizeExample(r,e):r;a!==void 0&&(i[t]=a)}for(let e of r){if(e in i)continue;let t=n[e];if(!t)return;let r=t.default===void 0?t.example===void 0?void 0:this.normalizeExample(t.example,t):this.normalizeExample(t.default,t);if(r===void 0)return;i[e]=r}return i}return e}isPlainObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}isSchemaLike(e){return`type`in e||`properties`in e||`items`in e||`required`in e||`default`in e}indent(e){return` `.repeat(e)}escapeStringLiteral(e){return e.replace(/\\/g,String.raw`\\`).replace(/'/g,String.raw`\'`).replace(/\r/g,String.raw`\r`).replace(/\n/g,String.raw`\n`).replace(/\t/g,String.raw`\t`).replace(/\f/g,String.raw`\f`).replace(/\x08/g,String.raw`\b`).replace(/\u2028/g,String.raw`\u2028`).replace(/\u2029/g,String.raw`\u2029`)}isPathParam(e){return e.startsWith(`{`)&&e.endsWith(`}`)||/^:[A-Za-z0-9_]+$/.test(e)}stripPathParam(e){return e.replace(/^\{/,``).replace(/\}$/,``).replace(/^:/,``)}},Ye=class e{static contextualTailSegments=new Set([`history`,`status`,`detail`,`details`]);static irregularSingulars=new Map([[`analyses`,`analysis`],[`diagnoses`,`diagnosis`],[`parentheses`,`parenthesis`],[`statuses`,`status`],[`synopses`,`synopsis`],[`theses`,`thesis`]]);static invariantSingulars=new Set([`analysis`,`diagnosis`,`news`,`series`,`species`,`status`,`synopsis`,`thesis`]);static nestedContextSegments=new Set([`account`,`accounts`,`transaction`,`transactions`,`wallet`,`wallets`,`virtual-account`,`virtual-accounts`,`history`]);static roleSuffixes=[`Input`,`Query`,`Header`,`Params`];sanitizeTypeName(e){let t=e.replace(/[^A-Za-z0-9]+/g,` `).trim();if(!t)return`GeneratedEntity`;let n=t.split(/\s+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(``);return/^[A-Za-z_$]/.test(n)?n:`Type${n}`}isPathParam(e){return e.startsWith(`{`)&&e.endsWith(`}`)||/^:[A-Za-z0-9_]+$/.test(e)}stripPathParam(e){return e.replace(/^\{/,``).replace(/\}$/,``).replace(/^:/,``)}singularize(t){let n=t.toLowerCase();return e.irregularSingulars.has(n)?e.irregularSingulars.get(n)??t:e.invariantSingulars.has(n)?t:/ies$/i.test(t)?`${t.slice(0,-3)}y`:/(sses|shes|ches|xes|zes)$/i.test(t)||/uses$/i.test(t)?t.slice(0,-2):t.endsWith(`s`)&&!t.endsWith(`ss`)&&t.length>1?t.slice(0,-1):t}pluralize(e){return/y$/i.test(e)?`${e.slice(0,-1)}ies`:/s$/i.test(e)?e:`${e}s`}toCamelCase(e){let t=this.sanitizeTypeName(e);return t.charAt(0).toLowerCase()+t.slice(1)}deriveOperationNaming(t){let n=this.getNormalizedPathSegments(t),r=n.filter(e=>!this.isPathParam(e)).map(e=>this.singularize(e)),i=n.filter(e=>this.isPathParam(e)).map(e=>this.singularize(this.stripPathParam(e))),a=r[r.length-1]??`resource`,o=r[r.length-2]??null,s=n.slice(0,-1).some(e=>this.isPathParam(e)),c=!!(o&&(e.contextualTailSegments.has(a.toLowerCase())||s&&e.nestedContextSegments.has(a.toLowerCase())));return{baseName:this.sanitizeTypeName(c?`${o} ${a}`:a),collisionSuffix:i.length>0?`By ${i.map(e=>this.sanitizeTypeName(e)).join(` And `)}`:o&&!c?this.sanitizeTypeName(o):``}}fallbackCollisionSuffix(e,t,n){let r=this.getNormalizedPathSegments(t),i=r.filter(e=>!this.isPathParam(e)),a=i[i.length-1]??``,o=r.some(e=>this.isPathParam(e));return e===`get`&&!o&&/s$/i.test(a)?`List`:e===`post`&&!o?`Create`:(e===`put`||e===`patch`)&&o?`Update`:e===`delete`?`Delete`:`${this.sanitizeTypeName(e)}${n}`}insertCollisionSuffix(t,n){if(!n)return t;for(let r of e.roleSuffixes)if(t.endsWith(r)&&t.length>r.length)return`${t.slice(0,-r.length)}${n}${r}`;return`${t}${n}`}deriveSdkGroupNamesBySignature(e,t){let n=new Map;for(let t of Object.keys(e.paths)){let e=this.getStaticPathSignature(t);n.has(e)||n.set(e,t)}let r=Array.from(n.entries()).map(([e,n])=>({signature:e,staticSegments:e.split(`/`).filter(Boolean),candidates:this.buildSdkGroupNameCandidates(n,t)})).sort((e,t)=>e.staticSegments.length-t.staticSegments.length||e.signature.localeCompare(t.signature)),i=new Map,a=new Set;for(let e of r){let t=e.candidates.find(e=>!a.has(e))??this.createUniqueSdkGroupName(e.candidates[e.candidates.length-1]??`Resource`,a);a.add(t),i.set(e.signature,t)}return i}getStaticPathSegments(e){return this.getNormalizedPathSegments(e).filter(e=>!this.isPathParam(e)).map(e=>this.singularize(e))}getStaticPathSignature(e){return this.getStaticPathSegments(e).join(`/`)}getNormalizedPathSegments(e){return e.split(`/`).map(e=>e.trim()).filter(Boolean).filter(e=>!/^v\d+$/i.test(e))}deriveSdkMethodName(e,t,n,r){if(r===`operation-id`&&n.operationId)return this.toCamelCase(this.sanitizeTypeName(n.operationId));let i=this.getNormalizedPathSegments(t).some(e=>this.isPathParam(e));return e===`get`?this.endsWithPluralStaticSegment(t)?`list`:i?`get`:`list`:e===`post`?`create`:e===`patch`||e===`put`?`update`:e===`delete`?`delete`:this.toCamelCase(this.sanitizeTypeName(e))}ensureUniqueSdkMethodNames(e){let t=new Map;return e.map(e=>{let n=t.get(e.methodName)??0;if(t.set(e.methodName,n+1),n===0)return e;let r=this.sanitizeTypeName(this.fallbackCollisionSuffix(e.method.toLowerCase(),e.path,`Operation`));return{...e,methodName:`${e.methodName}${r}`}})}createSdkParameterManifest(e,t,n){return[...(e??[]).filter(e=>e.in===t).sort((e,t)=>e.name.localeCompare(t.name)),...this.getInferredPathParameters(n,t,(e??[]).filter(e=>e.in===t))].sort((e,t)=>e.name.localeCompare(t.name)).map(e=>({name:e.name,accessor:this.toParameterAccessor(e.name),in:t,required:e.required??!1,description:e.description}))}getInferredPathParameters(e,t,n){if(t!==`path`||!e)return[];let r=new Set(n.map(e=>e.name));return this.getNormalizedPathSegments(e).filter(e=>this.isPathParam(e)).map(e=>this.stripPathParam(e)).filter(e=>!r.has(e)).map(e=>({name:e,in:`path`,required:!0,schema:{type:`string`}}))}buildSdkGroupNameCandidates(e,t){let n=this.getNormalizedPathSegments(e),r=n.filter(e=>!this.isPathParam(e)),i=r.map(e=>this.singularize(e)),a=this.deriveOperationNaming(e).baseName,o=this.getPreferredSdkGroupName(n,r,i),s=i.map((e,t,n)=>this.sanitizeTypeName(n.slice(t).join(` `))).reverse();return t===`scoped`?Array.from(new Set([o??``,this.sanitizeTypeName(i.join(` `)),...s,a].filter(Boolean))):Array.from(new Set([o??``,a,...s].filter(Boolean)))}getPreferredSdkGroupName(e,t,n){let r=t[t.length-1],i=n[n.length-1],a=n[n.length-2],o=e.some(e=>this.isPathParam(e)),s=e.slice(0,-1).some(e=>this.isPathParam(e));return!r||!i||!a?null:t.length===2&&!o?this.sanitizeTypeName(`${i} ${a}`):s?this.singularize(r)===r?this.sanitizeTypeName(`${i} ${a}`):this.sanitizeTypeName(`${a} ${i}`):null}createUniqueSdkGroupName(e,t){let n=2,r=e;for(;t.has(r);)r=`${e}${n}`,n+=1;return r}endsWithPluralStaticSegment(e){let t=this.getNormalizedPathSegments(e).at(-1);return!t||this.isPathParam(t)?!1:this.singularize(t)!==t}toParameterAccessor(e){let t=e.replace(/[^A-Za-z0-9]+/g,` `).trim();if(!t)return`value`;let[n,...r]=t.split(/\s+/).filter(Boolean),i=[n.toLowerCase(),...r.map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase())].join(``);return/^[A-Za-z_$]/.test(i)?i:`value${i}`}},Xe=class{constructor(e){this.naming=e}createContext(){return{declarations:[],declarationByName:new Map,nameBySignature:new Map,usedNames:new Set}}namespaceTopLevelShape(e,t){return e.kind===`object`?{...e,signature:`${t}:${e.signature}`}:e}inferShapeFromExample(e,t){if(e===null)return{kind:`primitive`,type:`null`};if(Array.isArray(e)){if(e.length===0)return{kind:`array`,item:{kind:`primitive`,type:`unknown`}};let n=this.dedupeShapes(e.map(e=>this.inferShapeFromExample(e,this.naming.singularize(t))));return{kind:`array`,item:n.length===1?n[0]:{kind:`union`,types:n}}}if(this.isRecord(e))return this.createObjectShape(Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>({key:e,optional:!1,shape:this.inferShapeFromExample(t,e)})));switch(typeof e){case`string`:return{kind:`primitive`,type:`string`};case`number`:return{kind:`primitive`,type:`number`};case`boolean`:return{kind:`primitive`,type:`boolean`};default:return{kind:`primitive`,type:`unknown`}}}registerNamedShape(e,t,n,r){if(e.kind===`object`)return this.registerObjectShape(e,t,n,r,!0);let i=this.createUniqueTypeName(t,n,r),a={kind:`shape-alias`,name:i,shape:this.prepareNestedShape(e,t,n)};return n.declarations.push(a),n.declarationByName.set(i,a),i}registerObjectShape(e,t,n,r,i=!1){let a=n.nameBySignature.get(e.signature),o=this.findCompatibleObjectDeclaration(e,t,n);if(a){if(i&&a!==t&&!n.declarationByName.has(t)){let e=this.createUniqueTypeName(t,n,r);if(e!==a){let t={kind:`interface-alias`,name:e,target:a};n.declarations.push(t),n.declarationByName.set(e,t)}}return a}if(o){if(this.isObjectShapeAssignableTo(e,o.rawShape))return n.nameBySignature.set(e.signature,o.name),o.name;let t=this.mergeObjectShapes(o.rawShape,e);return o.rawShape=t,o.properties=t.properties.map(e=>({...e,shape:this.prepareNestedShape(e.shape,e.key,n)})),n.nameBySignature.set(e.signature,o.name),n.nameBySignature.set(t.signature,o.name),o.name}let s=this.createUniqueTypeName(t,n,r),c={kind:`interface`,name:s,baseName:this.naming.sanitizeTypeName(t),rawShape:e,properties:[]};return n.nameBySignature.set(e.signature,s),n.declarations.push(c),n.declarationByName.set(s,c),c.properties=e.properties.map(e=>({...e,shape:this.prepareNestedShape(e.shape,e.key,n)})),s}resolveSdkResponseType(e,t){let n=Object.entries(e).filter(([e])=>/^2\d\d$/.test(e)).sort(([e],[t])=>e.localeCompare(t))[0]?.[1];if(!n)return t;let r=this.getPreferredMediaType(n.content);if(!r)return t;let i=this.resolveResponsePayloadSchema(r.schema,r.example).schema??r.schema;return i&&this.resolveSchemaType(i)===`array`?`${t}[]`:t}getSuccessResponseShape(e){let t=Object.entries(e).filter(([e])=>/^2\d\d$/.test(e)).sort(([e],[t])=>e.localeCompare(t))[0]?.[1];if(!t)return this.emptyObjectShape;let n=this.getPreferredMediaType(t.content);if(!n)return this.emptyObjectShape;let r=this.resolveResponsePayloadSchema(n.schema,n.example);return r.schema?this.resolveSchemaType(r.schema)===`array`?this.schemaToShape(r.schema.items,`Item`,this.extractExampleArrayItem(r.example)):this.schemaToShape(r.schema,`Response`,r.example):this.schemaToShape(n.schema,`Response`,n.example)}getRequestInputShape(e){if(!e)return this.emptyObjectShape;let t=this.getPreferredMediaType(e.content);return t?this.schemaToShape(t.schema,`Input`,t.example):this.emptyObjectShape}getResponseExampleShape(e){let t=Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).flatMap(([,e])=>{let t=this.getPreferredMediaType(e.content);if(!t)return[];let n=t.example??t.schema?.example;return t.schema?[this.schemaToShape(t.schema,`ResponseExample`,n)]:n===void 0?[]:[this.inferShapeFromExample(n,`ResponseExample`)]}),n=this.dedupeShapes(t);return n.length===0?{kind:`primitive`,type:`unknown`}:n.length===1?n[0]:{kind:`union`,types:n}}createParameterGroupShape(e,t,n){let r=(e??[]).filter(e=>e.in===t).sort((e,t)=>e.name.localeCompare(t.name)),i=[...r,...this.naming.getInferredPathParameters(n,t,r)].sort((e,t)=>e.name.localeCompare(t.name));return i.length===0?this.emptyObjectShape:this.createObjectShape(i.map(e=>({key:e.name,optional:!(e.required??!1),shape:this.schemaToShape(e.schema,e.name,e.example)})))}get emptyObjectShape(){return this.createObjectShape([])}findCompatibleObjectDeclaration(e,t,n){let r=this.naming.sanitizeTypeName(t);return n.declarations.find(t=>t.kind!==`interface`||t.baseName!==r?!1:this.isObjectShapeAssignableTo(e,t.rawShape)||this.isObjectShapeAssignableTo(t.rawShape,e)||this.canMergeObjectShapes(t.rawShape,e))}canMergeObjectShapes(e,t){let n=new Set([...e.properties.map(e=>e.key),...t.properties.map(e=>e.key)]);for(let r of n){let n=e.properties.find(e=>e.key===r),i=t.properties.find(e=>e.key===r);if(!n||!i){if(!(n??i)?.optional)return!1;continue}if(!this.canMergeShapes(n.shape,i.shape))return!1}return!0}isObjectShapeAssignableTo(e,t){let n=new Map(t.properties.map(e=>[e.key,e]));for(let t of e.properties){let e=n.get(t.key);if(!e||t.optional&&!e.optional||!this.isShapeAssignableTo(t.shape,e.shape))return!1}return t.properties.every(t=>e.properties.some(e=>e.key===t.key)||t.optional)}isShapeAssignableTo(e,t){if(t.kind===`union`)return t.types.some(t=>this.isShapeAssignableTo(e,t));switch(e.kind){case`primitive`:return t.kind===`primitive`?e.type===t.type:!1;case`array`:return t.kind===`array`?this.isShapeAssignableTo(e.item,t.item):!1;case`union`:return e.types.every(e=>this.isShapeAssignableTo(e,t));case`object`:return t.kind===`object`?this.isObjectShapeAssignableTo(e,t):!1}}canMergeShapes(e,t){return e.kind===`union`?e.types.every(e=>this.canMergeShapes(e,t)):t.kind===`union`?t.types.every(t=>this.canMergeShapes(e,t)):e.kind===`primitive`&&t.kind===`primitive`?!0:e.kind===`array`&&t.kind===`array`?this.canMergeShapes(e.item,t.item):e.kind===`object`&&t.kind===`object`?this.canMergeObjectShapes(e,t):!1}mergeObjectShapes(e,t){let n=new Set([...e.properties.map(e=>e.key),...t.properties.map(e=>e.key)]);return this.createObjectShape(Array.from(n).map(n=>{let r=e.properties.find(e=>e.key===n),i=t.properties.find(e=>e.key===n);return r&&i?{key:n,optional:r.optional||i.optional,shape:this.mergeShapes(r.shape,i.shape)}:{key:n,optional:!0,shape:(r??i).shape}}))}mergeShapes(e,t){if(e.kind===`union`||t.kind===`union`||e.kind!==t.kind)return this.createUnionShape(e,t);switch(e.kind){case`primitive`:return t.kind===`primitive`&&e.type===t.type?e:this.createUnionShape(e,t);case`array`:return t.kind===`array`?{kind:`array`,item:this.mergeShapes(e.item,t.item)}:e;case`object`:return t.kind===`object`?this.mergeObjectShapes(e,t):e}}createUnionShape(...e){let t=e.flatMap(e=>e.kind===`union`?e.types:[e]),n=this.dedupeShapes(t);return n.length===1?n[0]:{kind:`union`,types:n}}prepareNestedShape(e,t,n){if(e.kind===`object`)return{kind:`primitive`,type:this.registerObjectShape(e,this.naming.sanitizeTypeName(this.naming.singularize(t)),n,this.naming.sanitizeTypeName(t))};if(e.kind===`array`)return{kind:`array`,item:this.prepareNestedShape(e.item,this.naming.singularize(t),n)};if(e.kind===`union`){let r=this.dedupeShapes(e.types.map((e,r)=>this.prepareNestedShape(e,this.getUnionMemberKeyHint(t,r,e),n)));return r.length===1?r[0]:{kind:`union`,types:r}}return e}getUnionMemberKeyHint(e,t,n){if(n.kind!==`object`&&n.kind!==`array`)return e;let r=this.naming.sanitizeTypeName(e);return r.endsWith(`ResponseExample`)?`${r}Variant${t+1}`:e}schemaToShape(e,t,n){if(!e)return this.inferShapeFromExample(n,t);let r=this.resolveSchemaType(e);if(r===`array`)return{kind:`array`,item:this.schemaToShape(e.items,this.naming.singularize(t),this.extractExampleArrayItem(e.example)??this.extractExampleArrayItem(n))};if(r===`object`){let r=this.isRecord(e.example)?e.example:this.isRecord(n)?n:void 0,i=Object.entries(e.properties??{}).sort(([e],[t])=>e.localeCompare(t)).map(([t,n])=>({key:t,optional:!(e.required??[]).includes(t),shape:this.schemaToShape(n,t,r?.[t])}));return i.length>0?this.createObjectShape(i):this.inferShapeFromExample(e.example??n,t)}return r===`integer`||r===`number`?{kind:`primitive`,type:`number`}:r===`string`?{kind:`primitive`,type:`string`}:r===`boolean`?{kind:`primitive`,type:`boolean`}:e.example===null||n===null?{kind:`primitive`,type:`null`}:e.example!==void 0||n!==void 0?this.inferShapeFromExample(e.example??n,t):{kind:`primitive`,type:`unknown`}}dedupeShapes(e){let t=new Set;return e.filter(e=>{let n=this.getShapeSignature(e);return t.has(n)?!1:(t.add(n),!0)})}createObjectShape(e){let t=e.map(e=>({...e})).sort((e,t)=>e.key.localeCompare(t.key));return{kind:`object`,signature:JSON.stringify(t.map(e=>({key:e.key,optional:e.optional,shape:this.getShapeSignature(e.shape)}))),properties:t}}getShapeSignature(e){switch(e.kind){case`primitive`:return`primitive:${e.type}`;case`array`:return`array:${this.getShapeSignature(e.item)}`;case`union`:return`union:${e.types.map(e=>this.getShapeSignature(e)).join(`|`)}`;case`object`:return`object:${e.signature}`}}getPreferredMediaType(e){if(e)return e[`application/json`]??e[`application/*+json`]??Object.values(e)[0]}resolveResponsePayloadSchema(e,t){for(let n of[[`data`],[`meta`,`data`]]){let r=this.getSchemaCandidateAtPath(e,t,n);if(r)return r}return{}}getSchemaCandidateAtPath(e,t,n){let r=this.getSchemaAtPath(e,n),i=this.getExampleAtPath(t,n);if(!(!r&&i===void 0))return r?{schema:r.example===void 0&&i!==void 0?{...r,example:i}:r,example:i??r.example}:{schema:{...this.inferSchemaTypeFromExample(i),example:i},example:i}}getSchemaAtPath(e,t){let n=e;for(let e of t){if(!n?.properties?.[e])return;n=n.properties[e]}return n}getExampleAtPath(e,t){let n=e;for(let e of t){if(!this.isRecord(n)||!(e in n))return;n=n[e]}return n}inferSchemaTypeFromExample(e){return Array.isArray(e)?{type:`array`,items:e.map(e=>this.inferSchemaTypeFromExample(e)).find(e=>this.hasSchemaDetails(e))??{}}:this.isRecord(e)?{type:`object`,properties:Object.fromEntries(Object.entries(e).map(([e,t])=>[e,this.inferSchemaTypeFromExample(t)]))}:typeof e==`string`?{type:`string`}:typeof e==`number`?{type:`number`}:typeof e==`boolean`?{type:`boolean`}:{}}hasSchemaDetails(e){return!!(e?.type||e?.properties||e?.items||e?.example!==void 0)}resolveSchemaType(e){return e.type??(e.properties?`object`:void 0)}extractExampleArrayItem(e){return Array.isArray(e)?e[0]:void 0}createUniqueTypeName(e,t,n){let r=this.naming.sanitizeTypeName(e)||`GeneratedEntity`,i=this.naming.sanitizeTypeName(n),a=r,o=2;if(!t.usedNames.has(a)||(a=this.naming.insertCollisionSuffix(r,i),!t.usedNames.has(a)))return t.usedNames.add(a),a;for(;t.usedNames.has(a);)a=`${r}${o}`,o+=1;return t.usedNames.add(a),a}isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}},X=class{naming=new Ye;shapes=new Xe(this.naming);createContext(){return this.shapes.createContext()}collectSemanticModels(e){let t=[];for(let[n,r]of Object.entries(e.paths)){let e=this.naming.deriveOperationNaming(n),i=e.baseName,a=Object.entries(r).sort(([,e],[,t])=>this.getOperationPriority(t)-this.getOperationPriority(e));for(let[r,o]of a){let a=e.collisionSuffix||this.naming.fallbackCollisionSuffix(r,n,i);t.push({path:n,method:r,name:i,role:`response`,shape:this.shapes.getSuccessResponseShape(o.responses),collisionSuffix:a}),t.push({path:n,method:r,name:`${i}ResponseExample`,role:`responseExample`,shape:this.shapes.getResponseExampleShape(o.responses),collisionSuffix:a}),t.push({path:n,method:r,name:`${i}Input`,role:`input`,shape:this.shapes.getRequestInputShape(o.requestBody),collisionSuffix:a}),t.push({path:n,method:r,name:`${i}Query`,role:`query`,shape:this.shapes.createParameterGroupShape(o.parameters,`query`,n),collisionSuffix:a}),t.push({path:n,method:r,name:`${i}Header`,role:`header`,shape:this.shapes.createParameterGroupShape(o.parameters,`header`,n),collisionSuffix:a}),t.push({path:n,method:r,name:`${i}Params`,role:`params`,shape:this.shapes.createParameterGroupShape(o.parameters,`path`,n),collisionSuffix:a})}}return t}buildSdkManifest(e,t,n={}){let r=this.naming.deriveSdkGroupNamesBySignature(e,n.namespaceStrategy??`smart`),i=new Map,a=this.buildSecuritySchemes(e),o=this.buildSecurityRequirements(e.security);for(let[a,o]of Object.entries(e.paths)){let e=this.naming.getStaticPathSegments(a).join(`/`),s=r.get(e)??`Resource`,c=this.naming.toCamelCase(this.naming.pluralize(s)),l=i.get(c)??{className:s,propertyName:c,operations:[]};for(let[e,r]of Object.entries(o)){let i=t.get(`${a}::${e}`)??{response:`Record<string, never>`,responseExample:`unknown`,input:`Record<string, never>`,query:`Record<string, never>`,header:`Record<string, never>`,params:`Record<string, never>`};l.operations.push({path:a,method:e.toUpperCase(),methodName:this.naming.deriveSdkMethodName(e,a,r,n.methodStrategy??`smart`),summary:r.summary,description:r.description,operationId:r.operationId,requestBodyDescription:r.requestBody?.description,responseDescription:this.resolveSuccessResponseDescription(r.responses),responseType:this.shapes.resolveSdkResponseType(r.responses,i.response),inputType:i.input,queryType:i.query,headerType:i.header,paramsType:i.params,hasBody:!!r.requestBody,bodyRequired:r.requestBody?.required??!1,pathParams:this.naming.createSdkParameterManifest(r.parameters,`path`,a),queryParams:this.naming.createSdkParameterManifest(r.parameters,`query`,a),headerParams:this.naming.createSdkParameterManifest(r.parameters,`header`,a),security:this.buildSecurityRequirements(r.security)})}i.set(c,l)}return{groups:Array.from(i.values()).map(e=>({...e,operations:this.naming.ensureUniqueSdkMethodNames(e.operations)})).sort((e,t)=>e.propertyName.localeCompare(t.propertyName)),securitySchemes:a,security:o}}inferShapeFromExample(e,t){return this.shapes.inferShapeFromExample(e,t)}sanitizeTypeName(e){return this.naming.sanitizeTypeName(e)}registerNamedShape(e,t,n,r){return this.shapes.registerNamedShape(e,t,n,r)}namespaceTopLevelShape(e,t){return this.shapes.namespaceTopLevelShape(e,t)}registerObjectShape(e,t,n,r,i=!1){return this.shapes.registerObjectShape(e,t,n,r,i)}getOperationPriority(e){return Number(!!e.requestBody)*10}resolveSuccessResponseDescription(e){for(let t of[`200`,`201`,`202`,`204`]){let n=e[t]?.description?.trim();if(n)return n}for(let t of Object.values(e)){let e=t.description?.trim();if(e)return e}}buildSecuritySchemes(e){return Object.entries(e.components?.securitySchemes??{}).map(([e,t])=>this.createSecuritySchemeManifest(e,t)).filter(e=>e!==null).sort((e,t)=>e.name.localeCompare(t.name))}createSecuritySchemeManifest(e,t){let n=this.createSecurityHelperName(e);if(t.type===`apiKey`)return{name:e,helperName:n,description:t.description,type:`apiKey`,authType:`apiKey`,in:t.in,parameterName:t.name};if(t.type===`oauth2`)return{name:e,helperName:n,description:t.description,type:`oauth2`,authType:`oauth2`,scopes:this.collectSecurityScopes(t)};if(t.type===`openIdConnect`)return{name:e,helperName:n,description:t.description,type:`openIdConnect`,authType:`oauth2`,openIdConnectUrl:t.openIdConnectUrl};let r=t.scheme.toLowerCase();return{name:e,helperName:n,description:t.description,type:`http`,authType:r===`basic`?`basic`:`bearer`,scheme:t.scheme,bearerFormat:t.bearerFormat}}buildSecurityRequirements(e){if(!e||e.length===0)return;let t=e.map(e=>({schemes:Object.entries(e).map(([e,t])=>({name:e,scopes:[...t].sort()})).sort((e,t)=>e.name.localeCompare(t.name))})).filter(e=>e.schemes.length>0);return t.length>0?t:void 0}collectSecurityScopes(e){let t=new Set;for(let n of Object.values(e.flows??{}))for(let e of Object.keys(n.scopes??{}))t.add(e);return t.size>0?Array.from(t).sort():void 0}createSecurityHelperName(e){let t=this.naming.sanitizeTypeName(e);return t.endsWith(`Auth`)?`create${t}`:`create${t}Auth`}},Z=class e{typeBuilder=new X;moduleRenderer=new Je;static generateModule=(t,n=`GeneratedOutput`,r={})=>new e().generate(t,n,r);generate(e,t=`GeneratedOutput`,n={}){return this.isOpenApiDocumentLike(e)?this.generateModule(e,t,n):this.generateGenericModule(e,t)}generateModule(e,t,n={}){let r=this.typeBuilder.createContext(),i=new Map;for(let t of this.typeBuilder.collectSemanticModels(e)){let e=`${t.path}::${t.method}`,n=this.typeBuilder.registerNamedShape(this.typeBuilder.namespaceTopLevelShape(t.shape,t.role),t.name,r,t.collisionSuffix),a=i.get(e)??{response:`Record<string, never>`,responseExample:`unknown`,input:`Record<string, never>`,query:`Record<string, never>`,header:`Record<string, never>`,params:`Record<string, never>`};a[t.role]=n,i.set(e,a)}let a=r.declarations.map(e=>this.moduleRenderer.renderDeclaration(e)).join(`
140
140
 
141
141
  `),o=this.moduleRenderer.toCamelCase(t),s=this.typeBuilder.buildSdkManifest(e,i,n);return[a,this.moduleRenderer.renderOpenApiDocumentDefinitions(t,e,i),this.moduleRenderer.renderSdkApiInterface(t,s),this.moduleRenderer.renderSdkManifest(o,s),`export const ${o}: ${t} = ${this.moduleRenderer.renderOpenApiDocumentValue(e)}`,this.moduleRenderer.renderSdkBundle(o,t),``,`export default ${o}`].filter(Boolean).join(`
142
142
 
package/dist/index.cjs CHANGED
@@ -1438,14 +1438,32 @@ var TypeScriptModuleRenderer = class {
1438
1438
  };
1439
1439
 
1440
1440
  //#endregion
1441
- //#region src/generator/TypeScriptNamingSupport.ts
1442
- var TypeScriptNamingSupport = class TypeScriptNamingSupport {
1441
+ //#region src/generator/NamingSupport.ts
1442
+ var NamingSupport = class NamingSupport {
1443
1443
  static contextualTailSegments = new Set([
1444
1444
  "history",
1445
1445
  "status",
1446
1446
  "detail",
1447
1447
  "details"
1448
1448
  ]);
1449
+ static irregularSingulars = new Map([
1450
+ ["analyses", "analysis"],
1451
+ ["diagnoses", "diagnosis"],
1452
+ ["parentheses", "parenthesis"],
1453
+ ["statuses", "status"],
1454
+ ["synopses", "synopsis"],
1455
+ ["theses", "thesis"]
1456
+ ]);
1457
+ static invariantSingulars = new Set([
1458
+ "analysis",
1459
+ "diagnosis",
1460
+ "news",
1461
+ "series",
1462
+ "species",
1463
+ "status",
1464
+ "synopsis",
1465
+ "thesis"
1466
+ ]);
1449
1467
  static nestedContextSegments = new Set([
1450
1468
  "account",
1451
1469
  "accounts",
@@ -1476,8 +1494,12 @@ var TypeScriptNamingSupport = class TypeScriptNamingSupport {
1476
1494
  return segment.replace(/^\{/, "").replace(/\}$/, "").replace(/^:/, "");
1477
1495
  }
1478
1496
  singularize(value) {
1497
+ const normalized = value.toLowerCase();
1498
+ if (NamingSupport.irregularSingulars.has(normalized)) return NamingSupport.irregularSingulars.get(normalized) ?? value;
1499
+ if (NamingSupport.invariantSingulars.has(normalized)) return value;
1479
1500
  if (/ies$/i.test(value)) return `${value.slice(0, -3)}y`;
1480
1501
  if (/(sses|shes|ches|xes|zes)$/i.test(value)) return value.slice(0, -2);
1502
+ if (/uses$/i.test(value)) return value.slice(0, -2);
1481
1503
  if (value.endsWith("s") && !value.endsWith("ss") && value.length > 1) return value.slice(0, -1);
1482
1504
  return value;
1483
1505
  }
@@ -1497,7 +1519,7 @@ var TypeScriptNamingSupport = class TypeScriptNamingSupport {
1497
1519
  const tailSegment = staticSegments[staticSegments.length - 1] ?? "resource";
1498
1520
  const parentSegment = staticSegments[staticSegments.length - 2] ?? null;
1499
1521
  const hasPathParamBeforeTail = pathSegments.slice(0, -1).some((segment) => this.isPathParam(segment));
1500
- const shouldPrefixParent = Boolean(parentSegment && (TypeScriptNamingSupport.contextualTailSegments.has(tailSegment.toLowerCase()) || hasPathParamBeforeTail && TypeScriptNamingSupport.nestedContextSegments.has(tailSegment.toLowerCase())));
1522
+ const shouldPrefixParent = Boolean(parentSegment && (NamingSupport.contextualTailSegments.has(tailSegment.toLowerCase()) || hasPathParamBeforeTail && NamingSupport.nestedContextSegments.has(tailSegment.toLowerCase())));
1501
1523
  return {
1502
1524
  baseName: this.sanitizeTypeName(shouldPrefixParent ? `${parentSegment} ${tailSegment}` : tailSegment),
1503
1525
  collisionSuffix: paramSegments.length > 0 ? `By ${paramSegments.map((segment) => this.sanitizeTypeName(segment)).join(" And ")}` : parentSegment && !shouldPrefixParent ? this.sanitizeTypeName(parentSegment) : ""
@@ -1516,7 +1538,7 @@ var TypeScriptNamingSupport = class TypeScriptNamingSupport {
1516
1538
  }
1517
1539
  insertCollisionSuffix(baseName, collisionName) {
1518
1540
  if (!collisionName) return baseName;
1519
- for (const roleSuffix of TypeScriptNamingSupport.roleSuffixes) if (baseName.endsWith(roleSuffix) && baseName.length > roleSuffix.length) return `${baseName.slice(0, -roleSuffix.length)}${collisionName}${roleSuffix}`;
1541
+ for (const roleSuffix of NamingSupport.roleSuffixes) if (baseName.endsWith(roleSuffix) && baseName.length > roleSuffix.length) return `${baseName.slice(0, -roleSuffix.length)}${collisionName}${roleSuffix}`;
1520
1542
  return `${baseName}${collisionName}`;
1521
1543
  }
1522
1544
  deriveSdkGroupNamesBySignature(document, namespaceStrategy) {
@@ -2117,9 +2139,9 @@ var TypeScriptShapeBuilder = class {
2117
2139
  };
2118
2140
 
2119
2141
  //#endregion
2120
- //#region src/generator/TypeScriptTypeBuilder.ts
2121
- var TypeScriptTypeBuilder = class {
2122
- naming = new TypeScriptNamingSupport();
2142
+ //#region src/generator/TypeBuilder.ts
2143
+ var TypeBuilder = class {
2144
+ naming = new NamingSupport();
2123
2145
  shapes = new TypeScriptShapeBuilder(this.naming);
2124
2146
  /**
2125
2147
  * Creates a new generator context, which holds the state of the type generation process.
@@ -2438,7 +2460,7 @@ var TypeScriptTypeBuilder = class {
2438
2460
  //#endregion
2439
2461
  //#region src/generator/TypeScriptGenerator.ts
2440
2462
  var TypeScriptGenerator = class TypeScriptGenerator {
2441
- typeBuilder = new TypeScriptTypeBuilder();
2463
+ typeBuilder = new TypeBuilder();
2442
2464
  moduleRenderer = new TypeScriptModuleRenderer();
2443
2465
  /**
2444
2466
  * Static helper method to generate a TypeScript module string from a generic JSON-like
@@ -2605,7 +2627,7 @@ var OutputGenerator = class {
2605
2627
  //#endregion
2606
2628
  //#region src/generator/SdkPackageGenerator.ts
2607
2629
  var SdkPackageGenerator = class {
2608
- typeBuilder = new TypeScriptTypeBuilder();
2630
+ typeBuilder = new TypeBuilder();
2609
2631
  typeScriptGenerator = new TypeScriptGenerator();
2610
2632
  generate(document, options = {}) {
2611
2633
  const outputMode = options.outputMode ?? "both";
package/dist/index.mjs CHANGED
@@ -1406,14 +1406,32 @@ var TypeScriptModuleRenderer = class {
1406
1406
  };
1407
1407
 
1408
1408
  //#endregion
1409
- //#region src/generator/TypeScriptNamingSupport.ts
1410
- var TypeScriptNamingSupport = class TypeScriptNamingSupport {
1409
+ //#region src/generator/NamingSupport.ts
1410
+ var NamingSupport = class NamingSupport {
1411
1411
  static contextualTailSegments = new Set([
1412
1412
  "history",
1413
1413
  "status",
1414
1414
  "detail",
1415
1415
  "details"
1416
1416
  ]);
1417
+ static irregularSingulars = new Map([
1418
+ ["analyses", "analysis"],
1419
+ ["diagnoses", "diagnosis"],
1420
+ ["parentheses", "parenthesis"],
1421
+ ["statuses", "status"],
1422
+ ["synopses", "synopsis"],
1423
+ ["theses", "thesis"]
1424
+ ]);
1425
+ static invariantSingulars = new Set([
1426
+ "analysis",
1427
+ "diagnosis",
1428
+ "news",
1429
+ "series",
1430
+ "species",
1431
+ "status",
1432
+ "synopsis",
1433
+ "thesis"
1434
+ ]);
1417
1435
  static nestedContextSegments = new Set([
1418
1436
  "account",
1419
1437
  "accounts",
@@ -1444,8 +1462,12 @@ var TypeScriptNamingSupport = class TypeScriptNamingSupport {
1444
1462
  return segment.replace(/^\{/, "").replace(/\}$/, "").replace(/^:/, "");
1445
1463
  }
1446
1464
  singularize(value) {
1465
+ const normalized = value.toLowerCase();
1466
+ if (NamingSupport.irregularSingulars.has(normalized)) return NamingSupport.irregularSingulars.get(normalized) ?? value;
1467
+ if (NamingSupport.invariantSingulars.has(normalized)) return value;
1447
1468
  if (/ies$/i.test(value)) return `${value.slice(0, -3)}y`;
1448
1469
  if (/(sses|shes|ches|xes|zes)$/i.test(value)) return value.slice(0, -2);
1470
+ if (/uses$/i.test(value)) return value.slice(0, -2);
1449
1471
  if (value.endsWith("s") && !value.endsWith("ss") && value.length > 1) return value.slice(0, -1);
1450
1472
  return value;
1451
1473
  }
@@ -1465,7 +1487,7 @@ var TypeScriptNamingSupport = class TypeScriptNamingSupport {
1465
1487
  const tailSegment = staticSegments[staticSegments.length - 1] ?? "resource";
1466
1488
  const parentSegment = staticSegments[staticSegments.length - 2] ?? null;
1467
1489
  const hasPathParamBeforeTail = pathSegments.slice(0, -1).some((segment) => this.isPathParam(segment));
1468
- const shouldPrefixParent = Boolean(parentSegment && (TypeScriptNamingSupport.contextualTailSegments.has(tailSegment.toLowerCase()) || hasPathParamBeforeTail && TypeScriptNamingSupport.nestedContextSegments.has(tailSegment.toLowerCase())));
1490
+ const shouldPrefixParent = Boolean(parentSegment && (NamingSupport.contextualTailSegments.has(tailSegment.toLowerCase()) || hasPathParamBeforeTail && NamingSupport.nestedContextSegments.has(tailSegment.toLowerCase())));
1469
1491
  return {
1470
1492
  baseName: this.sanitizeTypeName(shouldPrefixParent ? `${parentSegment} ${tailSegment}` : tailSegment),
1471
1493
  collisionSuffix: paramSegments.length > 0 ? `By ${paramSegments.map((segment) => this.sanitizeTypeName(segment)).join(" And ")}` : parentSegment && !shouldPrefixParent ? this.sanitizeTypeName(parentSegment) : ""
@@ -1484,7 +1506,7 @@ var TypeScriptNamingSupport = class TypeScriptNamingSupport {
1484
1506
  }
1485
1507
  insertCollisionSuffix(baseName, collisionName) {
1486
1508
  if (!collisionName) return baseName;
1487
- for (const roleSuffix of TypeScriptNamingSupport.roleSuffixes) if (baseName.endsWith(roleSuffix) && baseName.length > roleSuffix.length) return `${baseName.slice(0, -roleSuffix.length)}${collisionName}${roleSuffix}`;
1509
+ for (const roleSuffix of NamingSupport.roleSuffixes) if (baseName.endsWith(roleSuffix) && baseName.length > roleSuffix.length) return `${baseName.slice(0, -roleSuffix.length)}${collisionName}${roleSuffix}`;
1488
1510
  return `${baseName}${collisionName}`;
1489
1511
  }
1490
1512
  deriveSdkGroupNamesBySignature(document, namespaceStrategy) {
@@ -2085,9 +2107,9 @@ var TypeScriptShapeBuilder = class {
2085
2107
  };
2086
2108
 
2087
2109
  //#endregion
2088
- //#region src/generator/TypeScriptTypeBuilder.ts
2089
- var TypeScriptTypeBuilder = class {
2090
- naming = new TypeScriptNamingSupport();
2110
+ //#region src/generator/TypeBuilder.ts
2111
+ var TypeBuilder = class {
2112
+ naming = new NamingSupport();
2091
2113
  shapes = new TypeScriptShapeBuilder(this.naming);
2092
2114
  /**
2093
2115
  * Creates a new generator context, which holds the state of the type generation process.
@@ -2406,7 +2428,7 @@ var TypeScriptTypeBuilder = class {
2406
2428
  //#endregion
2407
2429
  //#region src/generator/TypeScriptGenerator.ts
2408
2430
  var TypeScriptGenerator = class TypeScriptGenerator {
2409
- typeBuilder = new TypeScriptTypeBuilder();
2431
+ typeBuilder = new TypeBuilder();
2410
2432
  moduleRenderer = new TypeScriptModuleRenderer();
2411
2433
  /**
2412
2434
  * Static helper method to generate a TypeScript module string from a generic JSON-like
@@ -2573,7 +2595,7 @@ var OutputGenerator = class {
2573
2595
  //#endregion
2574
2596
  //#region src/generator/SdkPackageGenerator.ts
2575
2597
  var SdkPackageGenerator = class {
2576
- typeBuilder = new TypeScriptTypeBuilder();
2598
+ typeBuilder = new TypeBuilder();
2577
2599
  typeScriptGenerator = new TypeScriptGenerator();
2578
2600
  generate(document, options = {}) {
2579
2601
  const outputMode = options.outputMode ?? "both";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "oapiex",
3
3
  "type": "module",
4
- "version": "0.3.2",
4
+ "version": "0.3.3",
5
5
  "description": "CLI and TypeScript toolkit for turning documentation pages into usable developer artifacts.",
6
6
  "main": "./dist/index.cjs",
7
7
  "private": false,