oapiex 0.1.0 → 0.2.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 CHANGED
@@ -1,19 +1,20 @@
1
- # OPENAPIE
1
+ # OAPIEX
2
2
 
3
- [![NPM Downloads](https://img.shields.io/npm/dt/openapie.svg)](https://www.npmjs.com/package/openapie)
4
- [![npm version](https://img.shields.io/npm/v/openapie.svg)](https://www.npmjs.com/package/openapie)
5
- [![License](https://img.shields.io/npm/l/openapie.svg)](https://github.com/toneflix/openapie/blob/main/LICENSE)
6
- [![Deploy Docs](https://github.com/toneflix/openapie/actions/workflows/docs.yml/badge.svg)](https://github.com/toneflix/openapie/actions/workflows/docs.yml)
7
- [![Run Tests](https://github.com/toneflix/openapie/actions/workflows/test.yml/badge.svg)](https://github.com/toneflix/openapie/actions/workflows/test.yml)
8
- [![Publish Package](https://github.com/toneflix/openapie/actions/workflows/publish.yml/badge.svg)](https://github.com/toneflix/openapie/actions/workflows/publish.yml)
3
+ [![NPM Downloads](https://img.shields.io/npm/dt/oapiex.svg)](https://www.npmjs.com/package/oapiex)
4
+ [![npm version](https://img.shields.io/npm/v/oapiex.svg)](https://www.npmjs.com/package/oapiex)
5
+ [![License](https://img.shields.io/npm/l/oapiex.svg)](https://github.com/toneflix/oapiex/blob/main/LICENSE)
6
+ [![codecov](https://codecov.io/gh/toneflix/oapiex/graph/badge.svg?token=9C8arbqlX2)](https://codecov.io/gh/toneflix/oapiex)
7
+ [![Publish Package](https://github.com/toneflix/oapiex/actions/workflows/publish.yml/badge.svg)](https://github.com/toneflix/oapiex/actions/workflows/publish.yml)
8
+ [![Deploy Docs](https://github.com/toneflix/oapiex/actions/workflows/docs.yml/badge.svg)](https://github.com/toneflix/oapiex/actions/workflows/docs.yml)
9
+ [![Run Tests](https://github.com/toneflix/oapiex/actions/workflows/test.yml/badge.svg)](https://github.com/toneflix/oapiex/actions/workflows/test.yml)
9
10
 
10
11
  OAPIE is a CLI and TypeScript library for extracting API operation data from documentation sites and converting it into raw extracted payloads or OpenAPI-like documents.
11
12
 
12
13
  It currently focuses on ReadMe-powered API docs and saved HTML pages, with room to expand to additional documentation platforms.
13
14
 
14
- - npm: https://www.npmjs.com/package/openapie
15
- - docs: https://toneflix.github.io/openapie
16
- - repository: https://github.com/toneflix/oapi
15
+ - npm: https://www.npmjs.com/package/oapiex
16
+ - docs: https://toneflix.github.io/oapiex
17
+ - repository: https://github.com/toneflix/oapiex
17
18
 
18
19
  ## Features
19
20
 
@@ -28,34 +29,34 @@ It currently focuses on ReadMe-powered API docs and saved HTML pages, with room
28
29
 
29
30
  ### CLI
30
31
 
31
- Install globally if you want the `openapie` command available everywhere:
32
+ Install globally if you want the `oapiex` command available everywhere:
32
33
 
33
34
  ```bash
34
- pnpm add -g openapie
35
+ pnpm add -g oapiex
35
36
  ```
36
37
 
37
38
  ```bash
38
- npm i -g openapie
39
+ npm i -g oapiex
39
40
  ```
40
41
 
41
42
  ```bash
42
- yarn global add openapie
43
+ yarn global add oapiex
43
44
  ```
44
45
 
45
46
  ### Library
46
47
 
47
- Install locally if you want to use OPENAPIE from your own scripts or tooling:
48
+ Install locally if you want to use OAPIEX from your own scripts or tooling:
48
49
 
49
50
  ```bash
50
- pnpm add openapie
51
+ pnpm add oapiex
51
52
  ```
52
53
 
53
54
  ```bash
54
- npm i openapie
55
+ npm i oapiex
55
56
  ```
56
57
 
57
58
  ```bash
58
- yarn add openapie
59
+ yarn add oapiex
59
60
  ```
60
61
 
61
62
  ## CLI Quick Start
@@ -88,7 +89,7 @@ oapie init
88
89
  Extract a single operation:
89
90
 
90
91
  ```ts
91
- import { Application, extractReadmeOperationFromHtml } from 'openapie';
92
+ import { Application, extractReadmeOperationFromHtml } from 'oapiex';
92
93
 
93
94
  const app = new Application({
94
95
  browser: 'puppeteer',
@@ -110,9 +111,9 @@ Convert extracted data into an OpenAPI-like document:
110
111
  ```ts
111
112
  import {
112
113
  Application,
113
- createOpenApiDocumentFromReadmeOperations,
114
+ transformer,
114
115
  extractReadmeOperationFromHtml,
115
- } from 'openapie';
116
+ } from 'oapiex';
116
117
 
117
118
  const app = new Application({ browser: 'puppeteer' });
118
119
  const html = await app.loadHtmlSource(
@@ -121,7 +122,7 @@ const html = await app.loadHtmlSource(
121
122
  );
122
123
  const operation = extractReadmeOperationFromHtml(html);
123
124
 
124
- const document = createOpenApiDocumentFromReadmeOperations(
125
+ const document = transformer.createDocument(
125
126
  [operation],
126
127
  'Extracted API',
127
128
  '0.0.0',
@@ -132,16 +133,16 @@ console.log(document.paths);
132
133
 
133
134
  ## Configuration
134
135
 
135
- OPENAPIE looks for one of these files in the current working directory:
136
+ OAPIEX looks for one of these files in the current working directory:
136
137
 
137
- - `openapie.config.ts`
138
- - `openapie.config.js`
139
- - `openapie.config.cjs`
138
+ - `oapiex.config.ts`
139
+ - `oapiex.config.js`
140
+ - `oapiex.config.cjs`
140
141
 
141
142
  Example:
142
143
 
143
144
  ```ts
144
- import { defineConfig } from 'openapie';
145
+ import { defineConfig } from 'oapiex';
145
146
 
146
147
  export default defineConfig({
147
148
  outputFormat: 'json',
@@ -177,15 +178,15 @@ Available output formats:
177
178
 
178
179
  ## Documentation
179
180
 
180
- Full documentation is available at https://oapi-extractor.toneflix.net.
181
+ Full documentation is available at https://toneflix.github.io/oapiex.
181
182
 
182
183
  Useful sections:
183
184
 
184
- - Getting started: https://toneflix.github.io/openapie/guide/getting-started
185
- - CLI reference: https://toneflix.github.io/openapie/reference/cli
186
- - Programmatic usage: https://toneflix.github.io/openapie/reference/programmatic-usage
187
- - Configuration: https://toneflix.github.io/openapie/reference/configuration
188
- - Roadmap: https://toneflix.github.io/openapie/project/roadmap
185
+ - Getting started: https://toneflix.github.io/oapiex/guide/getting-started
186
+ - CLI reference: https://toneflix.github.io/oapiex/reference/cli
187
+ - Programmatic usage: https://toneflix.github.io/oapiex/reference/programmatic-usage
188
+ - Configuration: https://toneflix.github.io/oapiex/reference/configuration
189
+ - Roadmap: https://toneflix.github.io/oapiex/project/roadmap
189
190
 
190
191
  ## Roadmap Highlights
191
192
 
@@ -197,7 +198,7 @@ Current future-looking areas include:
197
198
  - support for Apidog documentation pages
198
199
  - support for Postman documentation pages
199
200
 
200
- See the full roadmap at https://toneflix.github.io/openapie/project/roadmap.
201
+ See the full roadmap at https://toneflix.github.io/oapiex/project/roadmap.
201
202
 
202
203
  ## Development
203
204
 
package/bin/cli.mjs CHANGED
@@ -1,2 +1,137 @@
1
- import{JSDOM as e}from"jsdom";import{Window as t}from"happy-dom";import n from"axios";import{Logger as r}from"@h3ravel/shared";import i from"node:path";import a,{readFile as o}from"node:fs/promises";import{Kernel as s}from"@h3ravel/musket";import{pathToFileURL as c}from"node:url";const l={outputFormat:`pretty`,outputShape:`raw`,requestTimeout:5e4,maxRedirects:5,userAgent:`Mozilla/5.0 (X11; Linux x64) AppleWebKit/537.36 (KHTML, like Gecko) OpenApiExtractor/1.0.0`,retryCount:3,retryDelay:1e3,browser:`puppeteer`,happyDom:{enableJavaScriptEvaluation:!0,suppressInsecureJavaScriptEnvironmentWarning:!0},puppeteer:{headless:!0,args:[`--no-sandbox`,`--disable-setuid-sandbox`]}};let u=l;const d=()=>globalThis.__oapieBrowserSession,ee=async(e=u)=>{let t=d();if(t?.browser===e.browser)return t;t&&await f();let n={browser:e.browser,closers:[]};return e.browser===`puppeteer`&&(n.puppeteerBrowser=await(await import(`puppeteer`)).launch({headless:e.puppeteer?.headless??!0,args:e.puppeteer?.args??[`--no-sandbox`,`--disable-setuid-sandbox`]})),globalThis.__oapieBrowserSession=n,n},f=async()=>{let e=d();if(e){globalThis.__oapieBrowserSession=void 0;for(let t of e.closers.reverse())await t();e.puppeteerBrowser&&await e.puppeteerBrowser.close()}},p=(e,t)=>{let n=d();return!n||n.browser!==e?!1:(n.closers.push(t),!0)},m=e=>{let t={...l,...e,happyDom:{...l.happyDom,...e.happyDom}};return u=t,t},te=async(r,i=u,a=!1)=>{let{data:o}=i.browser===`puppeteer`?{data:``}:await n.get(r,{timeout:i.requestTimeout,maxRedirects:i.maxRedirects,headers:{"User-Agent":i.userAgent,Accept:`text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8`}});if(i.browser===`axios`)return o;if(i.browser===`happy-dom`){let e=new t({url:r,innerWidth:1024,innerHeight:768,settings:i.happyDom});e.document.write(o),await e.happyDOM.waitUntilComplete();let n=e.document.documentElement.outerHTML;if(!n)throw await e.happyDOM.close(),Error(`Unable to extract HTML from remote source: ${r}`);return p(`happy-dom`,()=>e.happyDOM.close())||await e.happyDOM.close(),n}else if(i.browser===`jsdom`){let t;try{({window:t}=new e(o,{url:r,contentType:`text/html`,runScripts:`dangerously`,includeNodeLocations:!0}));let n=t.document.documentElement.outerHTML;if(!n)throw Error(`Unable to extract HTML from remote source: ${r}`);let i=t;return p(`jsdom`,()=>i.close())||t.close(),t=void 0,n}finally{t&&t.close()}}else if(i.browser===`puppeteer`){let e=d(),t=e?.browser===`puppeteer`?e.puppeteerBrowser:void 0,o=!1,s;try{t||(t=await(await import(`puppeteer`)).launch({headless:i.puppeteer?.headless??!0,args:i.puppeteer?.args??[`--no-sandbox`,`--disable-setuid-sandbox`]}),o=!0),s=await t.newPage(),await s.setUserAgent({userAgent:i.userAgent}),await s.setRequestInterception(!0),s.on(`request`,e=>{let t=e.resourceType();if([`image`,`font`,`media`,`stylesheet`].includes(t))return void e.abort();e.continue()});try{await s.goto(r,{waitUntil:`domcontentloaded`,timeout:i.requestTimeout})}catch(e){if(!s||!await g(s))throw e}await ne(s,i.requestTimeout,a),await h(s,i.requestTimeout);let e=await s.content();if(!e)throw Error(`Unable to extract HTML from remote source: ${r}`);if(!e.includes(`id="ssr-props"`)){let{data:t}=await n.get(r,{timeout:i.requestTimeout,maxRedirects:i.maxRedirects,headers:{"User-Agent":i.userAgent,Accept:`text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8`}});e=_(e,t)}return e}finally{s&&!s.isClosed()&&await s.close(),o&&t&&await t.close()}}else throw Error(`Unsupported browser specified in configuration: ${u.browser}`)},ne=async(e,t,n=!1)=>{try{n&&await e.waitForSelector(`.hub-sidebar-content .rm-Sidebar-link`),await e.waitForSelector(`[data-testid="http-method"], article#content, script#ssr-props`,{timeout:t})}catch{}},h=async(e,t)=>{try{await e.waitForFunction(()=>{let e=!!document.querySelector(`[data-testid="http-method"]`),t=!!document.querySelector(`form[name="Parameters"]`),n=!!document.querySelector(`.rm-PlaygroundRequest`),r=!!document.querySelector(`.rm-PlaygroundResponse`),i=!!document.querySelector(`script#ssr-props`);return e?t||n||r||i:!1},{timeout:t})}catch{}try{await e.waitForSelector(`.rm-PlaygroundRequest, .rm-PlaygroundResponse, form[name="Parameters"], script#ssr-props`,{timeout:Math.min(t,5e3)})}catch{}try{await e.waitForNetworkIdle?.({idleTime:500,timeout:Math.min(t,5e3)})}catch{}},g=async e=>!!await e.$(`[data-testid="http-method"], article#content, script#ssr-props`),_=(e,t)=>{if(e.includes(`id="ssr-props"`))return e;let n=v(t);return n?e.includes(`</body>`)?e.replace(`</body>`,`${n}</body>`):e.includes(`</html>`)?e.replace(`</html>`,`${n}</html>`):`${e}${n}`:e},v=e=>e.match(/<script id="ssr-props"[^>]*>[\s\S]*?<\/script>/i)?.[0]??null,y=e=>typeof e==`object`&&!!e&&!Array.isArray(e),re=e=>{let t=e.trim();if(!/^(?:\{|\[)/.test(t))return null;try{return JSON.parse(t)}catch{let e=ie(t);try{return JSON.parse(e)}catch{return null}}},ie=e=>{let t=ae(e);return`${t}${se(t)}`},ae=e=>{let t=``,n=!1,r=!1,i=``;for(let a=0;a<e.length;a+=1){let o=e[a];if(n){if(t+=o,r){r=!1;continue}if(o===`\\`){r=!0;continue}o===`"`&&(n=!1,i=`"`);continue}if(o===`"`){let r=e.slice(a);/^"(?:\\.|[^"\\])*"\s*:/.test(r)&&oe(i,t)&&(t+=`,`),t+=o,n=!0;continue}t+=o,/\s/.test(o)||(i=o)}return t},oe=(e,t)=>{if(!e||![`"`,`}`,`]`,`e`,`l`,`0`,`1`,`2`,`3`,`4`,`5`,`6`,`7`,`8`,`9`].includes(e))return!1;let n=t.trimEnd();return!n.endsWith(`,`)&&!n.endsWith(`{`)},se=e=>{let t=[],n=!1,r=!1;for(let i of e){if(r){r=!1;continue}if(i===`\\`){r=!0;continue}if(i===`"`){n=!n;continue}if(!n){if(i===`{`){t.push(`}`);continue}if(i===`[`){t.push(`]`);continue}(i===`}`||i===`]`)&&t[t.length-1]===i&&t.pop()}}return t.reverse().join(``)},ce=e=>{let n=new t;n.document.write(e);let{document:r}=n,i=r.querySelector(`article#content`)??r.body,a=i.querySelector(`form[name="Parameters"]`),o=r.querySelector(`.rm-PlaygroundRequest`),s=r.querySelector(`.rm-PlaygroundResponse`),c=j(o),l=me(c[0]??null),u=M(s);return b({method:Z(i.querySelector(`[data-testid="http-method"]`))?.toUpperCase()??null,url:Z(i.querySelector(`[data-testid="serverurl"]`)),description:A(i),sidebarLinks:N(r.querySelector(`.rm-Sidebar.hub-sidebar-content`)),requestParams:P(a),requestCodeSnippets:c,requestExample:c[0]?.body??null,requestExampleNormalized:l,responseSchemas:F(i),responseBodies:u,responseExample:u[0]?.body??null,responseExampleRaw:u[0]?.rawBody??null},x(r))},b=(e,t)=>t?{method:e.method??t.method,url:e.url??t.url,description:e.description??t.description,sidebarLinks:e.sidebarLinks.length>0?e.sidebarLinks:t.sidebarLinks,requestParams:e.requestParams.length>0?e.requestParams:t.requestParams,requestCodeSnippets:e.requestCodeSnippets.length>0?e.requestCodeSnippets:t.requestCodeSnippets,requestExample:e.requestExample??t.requestExample,requestExampleNormalized:e.requestExampleNormalized??t.requestExampleNormalized,responseSchemas:e.responseSchemas.length>0?e.responseSchemas:t.responseSchemas,responseBodies:e.responseBodies.length>0?e.responseBodies:t.responseBodies,responseExample:e.responseExample??t.responseExample,responseExampleRaw:e.responseExampleRaw??t.responseExampleRaw}:e,x=e=>{let t=e.querySelector(`script#ssr-props`)?.textContent?.trim();if(!t)return null;let n;try{n=JSON.parse(t)}catch{return null}let r=y(n)&&y(n.document)?n.document.api:null;if(!y(r))return null;let i=typeof r.method==`string`?r.method.toUpperCase():null,a=typeof r.path==`string`?r.path:null,o=y(r.schema)?r.schema:null,s=C(o,a,i?.toLowerCase()??null),c=Array.isArray(o?.servers)&&y(o.servers[0])&&typeof o.servers[0].url==`string`?o.servers[0].url:null;if(!s&&!i&&!a)return null;let l=O(s?.responses??{});return{method:i,url:w(c,a),description:s?.description??null,sidebarLinks:[],requestParams:[...S(s?.parameters),...T(s?.requestBody)],requestCodeSnippets:[],requestExample:null,requestExampleNormalized:null,responseSchemas:D(s?.responses??{}),responseBodies:l,responseExample:l[0]?.body??null,responseExampleRaw:l[0]?.rawBody??null}},S=e=>e?e.map(e=>({name:e.name,in:e.in,path:[e.name],type:e.schema?.type??null,required:e.required??!1,defaultValue:e.schema?.default==null?e.example==null?null:String(e.example):String(e.schema.default),description:e.description??e.schema?.description??null})):[],C=(e,t,n)=>{if(!e||!t||!n||!y(e.paths))return null;let r=e.paths[t];return!y(r)||!y(r[n])?null:r[n]},w=(e,t)=>!e||!t?null:`${e.replace(/\/$/,``)}${t.startsWith(`/`)?t:`/${t}`}`,T=e=>{let t=e?.content?.[`application/json`]?.schema;return t?E(t):[]},E=(e,t=[])=>{if(!e.properties)return[];let n=[];for(let[r,i]of Object.entries(e.properties)){let a=[...t,r],o=e.required?.includes(r)??!1;if(i.type===`object`&&i.properties){n.push(...E(i,a).map(e=>({...e,required:e.path.length===a.length+1?o&&e.required:e.required})));continue}n.push({name:r,in:`body`,path:a,type:i.type??null,required:o,defaultValue:i.default==null?null:String(i.default),description:i.description??null})}return n},D=e=>Object.entries(e).map(([e,t])=>({statusCode:e,description:t.description??e})),O=e=>{let t=[];for(let[n,r]of Object.entries(e))for(let[e,i]of Object.entries(r.content??{})){let a=k(i);if(a==null)continue;let o=typeof a==`string`?a:JSON.stringify(a,null,2),s=K(o,e);t.push({format:s.format,contentType:e,statusCode:n,label:r.description??n,body:s.body,rawBody:o})}return t},k=e=>{if(e.example!==void 0)return e.example;let t=e.examples;if(t&&y(t)){for(let e of Object.values(t))if(y(e)&&`value`in e)return e.value??null}return e.schema?.example===void 0?null:e.schema.example},A=e=>{let t=e.querySelector(`header`);if(!t)return null;let n=Array.from(t.querySelectorAll(`[data-testid="RDMD"]`));return Z(n[n.length-1]??null)},j=e=>{if(!e)return[];let t=R(e);return I(e).map(e=>({label:t,body:e}))},M=e=>{if(!e)return[];let t=I(e),n=V(e),r=H(e);return t.map((e,t)=>{let i=r[t]??r[0]??null,a=n[t]??n[0]??null,o=K(e,a);return{format:o.format,contentType:a,statusCode:i?.match(/\b\d{3}\b/)?.[0]??null,label:i,body:o.body,rawBody:e}})},N=e=>e?Array.from(e.querySelectorAll(`.rm-Sidebar-link`)).map(e=>{let t=e.closest(`.rm-Sidebar-section`),n=Z(e.querySelector(`[data-testid="http-method"]`))?.toUpperCase()??null;return{section:Z(t?.querySelector(`.rm-Sidebar-heading`)??null),label:B(e,n),href:e.getAttribute(`href`),method:n,active:e.classList.contains(`active`)||e.getAttribute(`aria-current`)===`page`,subpage:e.classList.contains(`subpage`)}}).filter(e=>e.label.length>0):[],P=e=>e?Array.from(e.querySelectorAll(`label`)).map(t=>{let n=Z(t),r=le(t,e),i=U(r,t);return{name:n??``,in:W(r,t,e),path:ue(t,n),type:de(r,i),required:fe(r,i),defaultValue:z(i),description:pe(r)}}).filter(e=>e.name.length>0):[],F=e=>{let t=e.querySelector(`#response-schemas`)?.nextElementSibling;return!t||!t.classList.contains(`rm-APIResponseSchemaPicker`)?[]:Array.from(t.querySelectorAll(`button`)).map(e=>{let t=Z(e),n=t?.match(/\b\d{3}\b/),r=Array.from(e.querySelectorAll(`[data-testid="RDMD"]`));return{statusCode:n?.[0]??null,description:Z(r[0]??null)??t}}).filter(e=>e.statusCode!==null)},I=e=>Array.from(e.querySelectorAll(`.CodeSnippet`)).map(e=>L(e)).filter(e=>!!e),L=e=>{if(!e)return null;let t=Array.from(e.querySelectorAll(`.CodeMirror-code pre.CodeMirror-line`));return t.length===0?null:t.map(e=>e.textContent?.replace(/\u00a0/g,` `)??``).join(`
2
- `).trimEnd()||null},R=e=>{let t=e.querySelector(`header`);if(!t)return null;let n=Array.from(t.querySelectorAll(`button`)).map(e=>$(e)).filter(e=>!!e);return n.find(e=>e.toLowerCase()!==`examples`)??n[0]??null},z=e=>e&&e.getAttribute(`value`)?.trim()||null,B=(e,t)=>Q(e.querySelectorAll(`span`)).filter(e=>!t||e.toUpperCase()!==t).sort((e,t)=>t.length-e.length)[0]??Z(e)??``,V=e=>Q(e.querySelectorAll(`div`)).filter(e=>/^[\w.+-]+\/[\w.+-]+$/i.test(e)),H=e=>Array.from(e.querySelectorAll(`button, [role="button"]`)).map(e=>$(e)).filter(e=>!!e).filter(e=>/\b\d{3}\b/.test(e)),le=(e,t)=>{let n=e.getAttribute(`for`),r=e;for(;r;){let e=n?r.querySelector(`#${X(n)}`):null,i=r.querySelector(`input, textarea, select`);if((e||i)&&r!==t)return r;r=r.parentElement}return e},U=(e,t)=>{let n=t.getAttribute(`for`),r=n?e.querySelector(`#${X(n)}`):null,i=e.querySelector(`input, textarea, select`);return r??i},W=(e,t,n)=>{let r=G(`${t.getAttribute(`for`)?.toLowerCase()??``} ${e.closest(`[id]`)?.getAttribute(`id`)?.toLowerCase()??``}`);if(r)return r;let i=e;for(;i&&i!==n;){let e=i.previousElementSibling;for(;e;){if(e.tagName===`HEADER`){let t=G(Z(e)??``);if(t)return t}e=e.previousElementSibling}i=i.parentElement}return null},G=e=>{let t=e.trim().toLowerCase();return t.includes(`query params`)||t.includes(`query-`)?`query`:t.includes(`headers`)||t.includes(`header-`)?`header`:t.includes(`body params`)||t.includes(`request body`)||t.includes(`body-`)?`body`:t.includes(`path params`)||t.includes(`path-`)?`path`:t.includes(`cookie`)||t.includes(`cookie-`)?`cookie`:null},ue=(e,t)=>{let n=e.getAttribute(`for`)??``,r=n.includes(`_`)?n.slice(n.indexOf(`_`)+1):``;return r.includes(`.`)?r.split(`.`).map(e=>e.trim()).filter(e=>e.length>0):t?[t]:[]},de=(e,t)=>{let n=t?.getAttribute(`type`)?.toLowerCase();if(n===`text`)return`string`;if(n)return n;let r=Array.from(e.querySelectorAll(`[class]`)).find(e=>(e.getAttribute(`class`)??``).split(/\s+/).some(e=>e.startsWith(`field-`)))?.getAttribute(`class`)?.split(/\s+/).find(e=>e.startsWith(`field-`));return r?r.replace(/^field-/,``):null},fe=(e,t)=>t?.hasAttribute(`required`)?!0:Q(e.querySelectorAll(`*`)).some(e=>e.toLowerCase()===`required`),pe=e=>Z(e.querySelector(`[id$="__description"]`)||(Array.from(e.querySelectorAll(`[data-testid="RDMD"]`))[0]??null)),K=(e,t)=>{let n=e.trim();if(t?.toLowerCase().includes(`json`)||/^(?:\{|\[)/.test(n)){let t=re(n);return t===null?{format:`text`,body:e}:{format:`json`,body:t}}return{format:`text`,body:e}},me=e=>e?he(e)??ge(e)??{sourceLabel:e.label,method:null,url:null,headers:{},bodyFormat:null,body:null,rawBody:null}:null,he=e=>{if(!e.body.startsWith(`curl `))return null;let t=e.body.match(/--request\s+([A-Z]+)/)?.[1]??null,n=e.body.match(/--url\s+(\S+)/)?.[1]??null,r=Object.fromEntries(Array.from(e.body.matchAll(/--header\s+'([^:]+):\s*([^']+)'/g)).map(e=>[e[1].trim(),e[2].trim()])),i=e.body.match(/--data\s+'([\s\S]*)'$/)?.[1]?.trim()??null,a=i?K(i,r[`content-type`]??r[`Content-Type`]??null):null;return{sourceLabel:e.label,method:t,url:n,headers:r,bodyFormat:a?.format??null,body:a?.body??null,rawBody:i}},ge=e=>{let t=e.body.match(/fetch\(\s*(["'])(.*?)\1\s*,\s*\{([\s\S]*)\}\s*\)/);if(!t)return null;let[,,n,r]=t,i=q(r,`method`)?.toUpperCase()??null,a=_e(r),o=ve(r),s=a[`content-type`]??a[`Content-Type`]??null,c=o?ye(o,s):null;return{sourceLabel:e.label,method:i,url:n,headers:a,bodyFormat:c?.format??null,body:c?.body??null,rawBody:o}},_e=e=>{let t=q(e,`headers`);if(!t)return{};let n=Y(t);return y(n)?Object.fromEntries(Object.entries(n).map(([e,t])=>[e,String(t)])):{}},ve=e=>q(e,`body`),ye=(e,t)=>{let n=Y(e);return n!==null&&(t?.toLowerCase().includes(`json`)||/^[[{]/.test(e.trim()))?{format:`json`,body:n}:K(e,t)},q=(e,t)=>{let n=e.match(RegExp(`\\b${t}\\s*:`,`m`));if(!n||n.index===void 0)return null;let r=n.index+n[0].length;for(;/\s/.test(e[r]??``);)r+=1;if(e.startsWith(`JSON.stringify`,r)){let t=e.indexOf(`(`,r);return t===-1?null:J(e,t,`(`,`)`)?.slice(1,-1).trim()??null}if(e[r]===`{`||e[r]===`[`){let t=e[r]===`{`?`}`:`]`;return J(e,r,e[r],t)?.trim()??null}return e[r]===`"`||e[r]===`'`?be(e,r):(e.slice(r).match(/^([^,\n]+)/)?.[1])?.trim()??null},J=(e,t,n,r)=>{let i=0,a=null,o=!1;for(let s=t;s<e.length;s+=1){let c=e[s];if(a){if(o){o=!1;continue}if(c===`\\`){o=!0;continue}c===a&&(a=null);continue}if(c===`"`||c===`'`){a=c;continue}if(c===n){i+=1;continue}if(c===r&&(--i,i===0))return e.slice(t,s+1)}return null},be=(e,t)=>{let n=e[t],r=``,i=!1;for(let a=t+1;a<e.length;a+=1){let t=e[a];if(i){r+=t,i=!1;continue}if(t===`\\`){i=!0;continue}if(t===n)return r;r+=t}return null},Y=e=>{let t=e.trim();if(!/^[[{]/.test(t))return null;let n=t.replace(/([{,]\s*)([A-Za-z_$][\w$-]*)(\s*:)/g,`$1"$2"$3`).replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g,(e,t)=>JSON.stringify(t.replace(/\\'/g,`'`))).replace(/,\s*([}\]])/g,`$1`);try{return JSON.parse(n)}catch{return null}},X=e=>e.replace(/([#.:[\],=])/g,`\\$1`),Z=e=>e?.textContent?.replace(/\s+/g,` `).trim()||null,Q=e=>Array.from(e).map(e=>Z(e)).filter(e=>!!e),$=e=>Q(e.querySelectorAll(`span, div, code`)).filter(e=>e.trim().length>0).sort((e,t)=>t.length-e.length)[0]??Z(e),xe=(e,t)=>{let n=new URL(t),r=e.sidebarLinks.map(e=>e.href).filter(e=>!!e).map(e=>new URL(e,n).toString()).filter(e=>/^https?:\/\//i.test(e));return Array.from(new Set(r))};var Se=class{config;constructor(e={}){this.config=m(e)}getConfig(e={}){return{...this.config,...e}}configure(e){return this.config=m({...this.config,...e}),this.config}async crawlReadmeOperations(e,t,n){let i=this.resolveCrawlBaseUrl(e,n);if(!i)throw Error(`Crawl mode requires a remote source URL or --base-url when using a local file`);let a=!!d();a||await ee(this.config);try{let e=xe(t,i),n=new URL(i).toString(),a=this.attachSourceUrl(n,t),o=e.filter(e=>e!==n);return{rootSource:n,discoveredUrls:e,operations:[a,...(await Promise.all(o.map(async e=>{let t=Date.now(),n=ce(await this.loadHtmlSource(e)),a=Date.now()-t;return n.method?(r.twoColumnDetail(r.log([[`Crawled`,`green`],[`${a/1e3}s`,`gray`]],` `,!1),e.replace(i,``)),this.attachSourceUrl(e,n)):null}))).filter(e=>e!==null)]}}finally{a||await f()}}attachSourceUrl(e,t){return{sourceUrl:e,...t}}resolveCrawlBaseUrl(e,t){return t?new URL(t).toString():/^https?:\/\//i.test(e)?e:null}async loadHtmlSource(e,t){if(!e)throw Error(`A source path or URL is required`);return/^https?:\/\//i.test(e)?te(e,this.config,t):o(i.resolve(process.cwd(),e),`utf8`)}};const Ce=[`openapie.config.ts`,`openapie.config.js`,`openapie.config.cjs`];async function we(e=process.cwd()){for(let t of Ce){let n=i.join(e,t);try{await a.access(n);let e=await import(c(n).href),t=e.default||e.config||e;if(typeof t==`object`&&t)return t}catch{continue}}return null}async function Te(e={}){let t=await we();return{...l,...t,...e,happyDom:{...l.happyDom,...t?.happyDom||{},...e.happyDom||{}}}}const Ee=new Se(await Te());await s.init(Ee,{name:`mycli`,discoveryPaths:[i.join(process.cwd(),`src/Commands/*.ts`)]});export{};
1
+ import{JSDOM as e}from"jsdom";import{Window as t}from"happy-dom";import n from"axios";import{Logger as r}from"@h3ravel/shared";import i from"node:path";import a,{readFile as o}from"node:fs/promises";import{Command as s,Kernel as c}from"@h3ravel/musket";import l from"prettier";import{pathToFileURL as u}from"node:url";import{existsSync as d,readdirSync as f}from"node:fs";import{fileURLToPath as p}from"url";const m=[`axios`,`happy-dom`,`jsdom`,`puppeteer`],h={outputFormat:`pretty`,outputShape:`raw`,requestTimeout:5e4,maxRedirects:5,userAgent:`Mozilla/5.0 (X11; Linux x64) AppleWebKit/537.36 (KHTML, like Gecko) OpenApiExtractor/1.0.0`,retryCount:3,retryDelay:1e3,browser:`puppeteer`,happyDom:{enableJavaScriptEvaluation:!0,suppressInsecureJavaScriptEnvironmentWarning:!0},puppeteer:{headless:!0,args:[`--no-sandbox`,`--disable-setuid-sandbox`]}};let g=h;const _=()=>globalThis.__oapieBrowserSession,v=async(e=g)=>{let t=_();if(t?.browser===e.browser)return t;t&&await y();let n={browser:e.browser,closers:[]};return e.browser===`puppeteer`&&(n.puppeteerBrowser=await(await import(`puppeteer`)).launch({headless:e.puppeteer?.headless??!0,args:e.puppeteer?.args??[`--no-sandbox`,`--disable-setuid-sandbox`]})),globalThis.__oapieBrowserSession=n,n},y=async()=>{let e=_();if(e){globalThis.__oapieBrowserSession=void 0;for(let t of e.closers.reverse())await t();e.puppeteerBrowser&&await e.puppeteerBrowser.close()}},b=(e,t)=>{let n=_();return!n||n.browser!==e?!1:(n.closers.push(t),!0)},x=e=>{let t={...h,...e,happyDom:{...h.happyDom,...e.happyDom}};return g=t,t},S=e=>m.includes(e),C=async(r,i=g,a=!1)=>{let{data:o}=i.browser===`puppeteer`?{data:``}:await n.get(r,{timeout:i.requestTimeout,maxRedirects:i.maxRedirects,headers:{"User-Agent":i.userAgent,Accept:`text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8`}});if(i.browser===`axios`)return o;if(i.browser===`happy-dom`){let e=new t({url:r,innerWidth:1024,innerHeight:768,settings:i.happyDom});e.document.write(o),await e.happyDOM.waitUntilComplete();let n=e.document.documentElement.outerHTML;if(!n)throw await e.happyDOM.close(),Error(`Unable to extract HTML from remote source: ${r}`);return b(`happy-dom`,()=>e.happyDOM.close())||await e.happyDOM.close(),n}else if(i.browser===`jsdom`){let t;try{({window:t}=new e(o,{url:r,contentType:`text/html`,runScripts:`dangerously`,includeNodeLocations:!0}));let n=t.document.documentElement.outerHTML;if(!n)throw Error(`Unable to extract HTML from remote source: ${r}`);let i=t;return b(`jsdom`,()=>i.close())||t.close(),t=void 0,n}finally{t&&t.close()}}else if(i.browser===`puppeteer`){let e=_(),t=Math.max(i.requestTimeout,3e4),o=e?.browser===`puppeteer`?e.puppeteerBrowser:void 0,s=!1,c;try{o||(o=await(await import(`puppeteer`)).launch({headless:i.puppeteer?.headless??!0,args:i.puppeteer?.args??[`--no-sandbox`,`--disable-setuid-sandbox`]}),s=!0),c=await o.newPage(),await c.setUserAgent({userAgent:i.userAgent}),await c.setRequestInterception(!0),c.on(`request`,e=>{let t=e.resourceType();if([`image`,`font`,`media`,`stylesheet`].includes(t))return void e.abort();e.continue()});try{await c.goto(r,{waitUntil:`domcontentloaded`,timeout:t})}catch(e){if(!c||!await ae(c))throw e}let e=await ne(c,t,a);if(!e)throw Error(`Unable to extract HTML from remote source: ${r}`);if(!e.includes(`id="ssr-props"`)){let{data:t}=await n.get(r,{timeout:i.requestTimeout,maxRedirects:i.maxRedirects,headers:{"User-Agent":i.userAgent,Accept:`text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8`}});e=oe(e,t)}return e}finally{c&&!c.isClosed()&&await c.close(),s&&o&&await o.close()}}else throw Error(`Unsupported browser specified in configuration: ${g.browser}`)},ee=async(e,t,n=!1)=>{try{n&&await e.waitForSelector(`.hub-sidebar-content .rm-Sidebar-link`),await e.waitForSelector(`[data-testid="http-method"], article#content, script#ssr-props`,{timeout:t})}catch{}},te=async(e,t)=>{try{await e.waitForFunction(()=>{let e=!!document.querySelector(`[data-testid="http-method"]`),t=!!document.querySelector(`form[name="Parameters"]`),n=!!document.querySelector(`.rm-PlaygroundRequest`),r=!!document.querySelector(`.rm-PlaygroundResponse`),i=!!document.querySelector(`script#ssr-props`);return e?t||n||r||i:!1},{timeout:t})}catch{}try{await e.waitForSelector(`.rm-PlaygroundRequest, .rm-PlaygroundResponse, form[name="Parameters"], script#ssr-props`,{timeout:Math.min(t,5e3)})}catch{}try{await e.waitForNetworkIdle?.({idleTime:500,timeout:Math.min(t,5e3)})}catch{}},ne=async(e,t,n=!1,r=3)=>{let i;for(let a=1;a<=r;a+=1)try{return await ee(e,t,n),await te(e,t),await e.content()}catch(n){if(i=n,!ie(n)||a===r)throw n;await re(e,t)}throw i instanceof Error?i:Error(`Unable to extract stable HTML from remote source`)},re=async(e,t)=>{try{await e.waitForFunction(()=>document.readyState===`interactive`||document.readyState===`complete`,{timeout:Math.min(t,5e3)})}catch{}try{await e.waitForNetworkIdle?.({idleTime:500,timeout:Math.min(t,5e3)})}catch{}},ie=e=>{if(!(e instanceof Error))return!1;let t=e.message.toLowerCase();return t.includes(`execution context was destroyed`)||t.includes(`cannot find context with specified id`)||t.includes(`most likely because of a navigation`)},ae=async e=>!!await e.$(`[data-testid="http-method"], article#content, script#ssr-props`),oe=(e,t)=>{if(e.includes(`id="ssr-props"`))return e;let n=se(t);return n?e.includes(`</body>`)?e.replace(`</body>`,`${n}</body>`):e.includes(`</html>`)?e.replace(`</html>`,`${n}</html>`):`${e}${n}`:e},se=e=>e.match(/<script id="ssr-props"[^>]*>[\s\S]*?<\/script>/i)?.[0]??null;var w=class e{static parsePossiblyTruncated=t=>{let n=new e,r=t.trim();if(!/^(?:\{|\[)/.test(r))return null;try{return JSON.parse(r)}catch{let e=n.repairCommonJsonIssues(r);try{return JSON.parse(e)}catch{return null}}};repairCommonJsonIssues=e=>{let t=this.removeUnexpectedObjectTokens(e),n=this.insertMissingCommas(t);return`${n}${this.buildMissingJsonClosers(n)}`};removeUnexpectedObjectTokens=e=>e.replace(/([[{,]\s*)([A-Za-z_$][\w$-]*)(?=\s*"(?:\\.|[^"\\])*"\s*:)/g,`$1`);insertMissingCommas=e=>{let t=``,n=!1,r=!1,i=``;for(let a=0;a<e.length;a+=1){let o=e[a];if(n){if(t+=o,r){r=!1;continue}if(o===`\\`){r=!0;continue}o===`"`&&(n=!1,i=`"`);continue}if(o===`"`){let r=e.slice(a);/^"(?:\\.|[^"\\])*"\s*:/.test(r)&&this.shouldInsertCommaBeforeKey(i,t)&&(t+=`,`),t+=o,n=!0;continue}t+=o,/\s/.test(o)||(i=o)}return t};shouldInsertCommaBeforeKey=(e,t)=>{if(!e||![`"`,`}`,`]`,`e`,`l`,`0`,`1`,`2`,`3`,`4`,`5`,`6`,`7`,`8`,`9`].includes(e))return!1;let n=t.trimEnd();return!n.endsWith(`,`)&&!n.endsWith(`{`)};buildMissingJsonClosers=e=>{let t=[],n=!1,r=!1;for(let i of e){if(r){r=!1;continue}if(i===`\\`){r=!0;continue}if(i===`"`){n=!n;continue}if(!n){if(i===`{`){t.push(`}`);continue}if(i===`[`){t.push(`]`);continue}(i===`}`||i===`]`)&&t[t.length-1]===i&&t.pop()}}return t.reverse().join(``)}};const T=e=>typeof e==`object`&&!!e&&!Array.isArray(e),E=e=>{let n=new t;n.document.write(e);let{document:r}=n,i=r.querySelector(`article#content`)??r.body,a=i.querySelector(`form[name="Parameters"]`),o=r.querySelector(`.rm-PlaygroundRequest`),s=r.querySelector(`.rm-PlaygroundResponse`),c=j(o),l=Te(c[0]??null),u=M(s);return ce({method:q(i.querySelector(`[data-testid="http-method"]`))?.toUpperCase()??null,url:q(i.querySelector(`[data-testid="serverurl"]`)),description:A(i),sidebarLinks:N(r.querySelector(`.rm-Sidebar.hub-sidebar-content`)),requestParams:P(a),requestCodeSnippets:c,requestExample:c[0]?.body??null,requestExampleNormalized:l,responseSchemas:F(i),responseBodies:u,responseExample:u[0]?.body??null,responseExampleRaw:u[0]?.rawBody??null},le(r))},ce=(e,t)=>t?{method:e.method??t.method,url:e.url??t.url,description:e.description??t.description,sidebarLinks:e.sidebarLinks.length>0?e.sidebarLinks:t.sidebarLinks,requestParams:e.requestParams.length>0?e.requestParams:t.requestParams,requestCodeSnippets:e.requestCodeSnippets.length>0?e.requestCodeSnippets:t.requestCodeSnippets,requestExample:e.requestExample??t.requestExample,requestExampleNormalized:e.requestExampleNormalized??t.requestExampleNormalized,responseSchemas:e.responseSchemas.length>0?e.responseSchemas:t.responseSchemas,responseBodies:e.responseBodies.length>0?e.responseBodies:t.responseBodies,responseExample:e.responseExample??t.responseExample,responseExampleRaw:e.responseExampleRaw??t.responseExampleRaw}:e,le=e=>{let t=e.querySelector(`script#ssr-props`)?.textContent?.trim();if(!t)return null;let n;try{n=JSON.parse(t)}catch{return null}let r=T(n)&&T(n.document)?n.document.api:null;if(!T(r))return null;let i=typeof r.method==`string`?r.method.toUpperCase():null,a=typeof r.path==`string`?r.path:null,o=T(r.schema)?r.schema:null,s=D(o,a,i?.toLowerCase()??null),c=Array.isArray(o?.servers)&&T(o.servers[0])&&typeof o.servers[0].url==`string`?o.servers[0].url:null;if(!s&&!i&&!a)return null;let l=me(s?.responses??{});return{method:i,url:de(c,a),description:s?.description??null,sidebarLinks:[],requestParams:[...ue(s?.parameters),...fe(s?.requestBody)],requestCodeSnippets:[],requestExample:null,requestExampleNormalized:null,responseSchemas:pe(s?.responses??{}),responseBodies:l,responseExample:l[0]?.body??null,responseExampleRaw:l[0]?.rawBody??null}},ue=e=>e?e.map(e=>({name:e.name,in:e.in,path:[e.name],type:e.schema?.type??null,required:e.required??!1,defaultValue:e.schema?.default==null?e.example==null?null:String(e.example):String(e.schema.default),description:e.description??e.schema?.description??null})):[],D=(e,t,n)=>{if(!e||!t||!n||!T(e.paths))return null;let r=e.paths[t];return!T(r)||!T(r[n])?null:r[n]},de=(e,t)=>!e||!t?null:`${e.replace(/\/$/,``)}${t.startsWith(`/`)?t:`/${t}`}`,fe=e=>{let t=e?.content?.[`application/json`]?.schema;return t?O(t):[]},O=(e,t=[])=>{if(!e.properties)return[];let n=[];for(let[r,i]of Object.entries(e.properties)){let a=[...t,r],o=e.required?.includes(r)??!1;if(i.type===`object`&&i.properties){n.push(...O(i,a).map(e=>({...e,required:e.path.length===a.length+1?o&&e.required:e.required})));continue}n.push({name:r,in:`body`,path:a,type:i.type??null,required:o,defaultValue:i.default==null?null:String(i.default),description:i.description??null})}return n},pe=e=>Object.entries(e).map(([e,t])=>({statusCode:e,description:t.description??e})),me=e=>{let t=[];for(let[n,r]of Object.entries(e))for(let[e,i]of Object.entries(r.content??{})){let a=k(i);if(a==null)continue;let o=typeof a==`string`?a:JSON.stringify(a,null,2),s=V(o,e);t.push({format:s.format,contentType:e,statusCode:n,label:r.description??n,body:s.body,rawBody:o})}return t},k=e=>{if(e.example!==void 0)return e.example;let t=e.examples;if(t&&T(t)){for(let e of Object.values(t))if(T(e)&&`value`in e)return e.value??null}return e.schema?.example===void 0?null:e.schema.example},A=e=>{let t=e.querySelector(`header`);if(!t)return null;let n=Array.from(t.querySelectorAll(`[data-testid="RDMD"]`));return q(n[n.length-1]??null)},j=e=>{if(!e)return[];let t=R(e);return I(e).map(e=>({label:t,body:e}))},M=e=>{if(!e)return[];let t=I(e),n=ge(e),r=_e(e);return t.map((e,t)=>{let i=r[t]??r[0]??null,a=n[t]??n[0]??null,o=V(e,a);return{format:o.format,contentType:a,statusCode:i?.match(/\b\d{3}\b/)?.[0]??null,label:i,body:o.body,rawBody:e}})},N=e=>e?Array.from(e.querySelectorAll(`.rm-Sidebar-link`)).map(e=>{let t=e.closest(`.rm-Sidebar-section`),n=q(e.querySelector(`[data-testid="http-method"]`))?.toUpperCase()??null;return{section:q(t?.querySelector(`.rm-Sidebar-heading`)??null),label:he(e,n),href:e.getAttribute(`href`),method:n,active:e.classList.contains(`active`)||e.getAttribute(`aria-current`)===`page`,subpage:e.classList.contains(`subpage`)}}).filter(e=>e.label.length>0):[],P=e=>e?Array.from(e.querySelectorAll(`label`)).map(t=>{let n=q(t),r=ve(t,e),i=ye(r,t);return{name:n??``,in:be(r,t,e),path:xe(t,n),type:Se(r,i),required:Ce(r,i),defaultValue:z(i),description:we(r)}}).filter(e=>e.name.length>0):[],F=e=>{let t=e.querySelector(`#response-schemas`)?.nextElementSibling;return!t||!t.classList.contains(`rm-APIResponseSchemaPicker`)?[]:Array.from(t.querySelectorAll(`button`)).map(e=>{let t=q(e),n=t?.match(/\b\d{3}\b/),r=Array.from(e.querySelectorAll(`[data-testid="RDMD"]`));return{statusCode:n?.[0]??null,description:q(r[0]??null)??t}}).filter(e=>e.statusCode!==null)},I=e=>Array.from(e.querySelectorAll(`.CodeSnippet`)).map(e=>L(e)).filter(e=>!!e),L=e=>{if(!e)return null;let t=Array.from(e.querySelectorAll(`.CodeMirror-code pre.CodeMirror-line`));return t.length===0?null:t.map(e=>e.textContent?.replace(/\u00a0/g,` `)??``).join(`
2
+ `).trimEnd()||null},R=e=>{let t=e.querySelector(`header`);if(!t)return null;let n=Array.from(t.querySelectorAll(`button`)).map(e=>Y(e)).filter(e=>!!e);return n.find(e=>e.toLowerCase()!==`examples`)??n[0]??null},z=e=>e&&e.getAttribute(`value`)?.trim()||null,he=(e,t)=>J(e.querySelectorAll(`span`)).filter(e=>!t||e.toUpperCase()!==t).sort((e,t)=>t.length-e.length)[0]??q(e)??``,ge=e=>J(e.querySelectorAll(`div`)).filter(e=>/^[\w.+-]+\/[\w.+-]+$/i.test(e)),_e=e=>Array.from(e.querySelectorAll(`button, [role="button"]`)).map(e=>Y(e)).filter(e=>!!e).filter(e=>/\b\d{3}\b/.test(e)),ve=(e,t)=>{let n=e.getAttribute(`for`),r=e;for(;r;){let e=n?r.querySelector(`#${K(n)}`):null,i=r.querySelector(`input, textarea, select`);if((e||i)&&r!==t)return r;r=r.parentElement}return e},ye=(e,t)=>{let n=t.getAttribute(`for`),r=n?e.querySelector(`#${K(n)}`):null,i=e.querySelector(`input, textarea, select`);return r??i},be=(e,t,n)=>{let r=B(`${t.getAttribute(`for`)?.toLowerCase()??``} ${e.closest(`[id]`)?.getAttribute(`id`)?.toLowerCase()??``}`);if(r)return r;let i=e;for(;i&&i!==n;){let e=i.previousElementSibling;for(;e;){if(e.tagName===`HEADER`){let t=B(q(e)??``);if(t)return t}e=e.previousElementSibling}i=i.parentElement}return null},B=e=>{let t=e.trim().toLowerCase();return t.includes(`query params`)||t.includes(`query-`)?`query`:t.includes(`headers`)||t.includes(`header-`)?`header`:t.includes(`body params`)||t.includes(`request body`)||t.includes(`body-`)?`body`:t.includes(`path params`)||t.includes(`path-`)?`path`:t.includes(`cookie`)||t.includes(`cookie-`)?`cookie`:null},xe=(e,t)=>{let n=e.getAttribute(`for`)??``,r=n.includes(`_`)?n.slice(n.indexOf(`_`)+1):``;return r.includes(`.`)?r.split(`.`).map(e=>e.trim()).filter(e=>e.length>0):t?[t]:[]},Se=(e,t)=>{let n=t?.getAttribute(`type`)?.toLowerCase();if(n===`text`)return`string`;if(n)return n;let r=Array.from(e.querySelectorAll(`[class]`)).find(e=>(e.getAttribute(`class`)??``).split(/\s+/).some(e=>e.startsWith(`field-`)))?.getAttribute(`class`)?.split(/\s+/).find(e=>e.startsWith(`field-`));return r?r.replace(/^field-/,``):null},Ce=(e,t)=>t?.hasAttribute(`required`)?!0:J(e.querySelectorAll(`*`)).some(e=>e.toLowerCase()===`required`),we=e=>q(e.querySelector(`[id$="__description"]`)||(Array.from(e.querySelectorAll(`[data-testid="RDMD"]`))[0]??null)),V=(e,t)=>{let n=e.trim();if(t?.toLowerCase().includes(`json`)||/^(?:\{|\[)/.test(n)){let t=w.parsePossiblyTruncated(n);if(t!==null)return{format:`json`,body:t};let r=G(n);return r===null?{format:`text`,body:e}:{format:`json`,body:r}}return{format:`text`,body:e}},Te=e=>e?Ee(e)??De(e)??{sourceLabel:e.label,method:null,url:null,headers:{},bodyFormat:null,body:null,rawBody:null}:null,Ee=e=>{if(!e.body.startsWith(`curl `))return null;let t=e.body.match(/--request\s+([A-Z]+)/)?.[1]??null,n=e.body.match(/--url\s+(\S+)/)?.[1]??null,r=Object.fromEntries(Array.from(e.body.matchAll(/--header\s+'([^:]+):\s*([^']+)'/g)).map(e=>[e[1].trim(),e[2].trim()])),i=e.body.match(/--data\s+'([\s\S]*)'$/)?.[1]?.trim()??null,a=i?V(i,r[`content-type`]??r[`Content-Type`]??null):null;return{sourceLabel:e.label,method:t,url:n,headers:r,bodyFormat:a?.format??null,body:a?.body??null,rawBody:i}},De=e=>{let t=e.body.match(/fetch\(\s*(["'])(.*?)\1\s*,\s*\{([\s\S]*)\}\s*\)/);if(!t)return null;let[,,n,r]=t,i=U(r,`method`)?.toUpperCase()??null,a=Oe(r),o=H(r),s=a[`content-type`]??a[`Content-Type`]??null,c=o?ke(o,s):null;return{sourceLabel:e.label,method:i,url:n,headers:a,bodyFormat:c?.format??null,body:c?.body??null,rawBody:o}},Oe=e=>{let t=U(e,`headers`);if(!t)return{};let n=G(t);return T(n)?Object.fromEntries(Object.entries(n).map(([e,t])=>[e,String(t)])):{}},H=e=>U(e,`body`),ke=(e,t)=>{let n=G(e);return n!==null&&(t?.toLowerCase().includes(`json`)||/^[[{]/.test(e.trim()))?{format:`json`,body:n}:V(e,t)},U=(e,t)=>{let n=e.match(RegExp(`\\b${t}\\s*:`,`m`));if(!n||n.index===void 0)return null;let r=n.index+n[0].length;for(;/\s/.test(e[r]??``);)r+=1;if(e.startsWith(`JSON.stringify`,r)){let t=e.indexOf(`(`,r);return t===-1?null:W(e,t,`(`,`)`)?.slice(1,-1).trim()??null}if(e[r]===`{`||e[r]===`[`){let t=e[r]===`{`?`}`:`]`;return W(e,r,e[r],t)?.trim()??null}return e[r]===`"`||e[r]===`'`?Ae(e,r):(e.slice(r).match(/^([^,\n]+)/)?.[1])?.trim()??null},W=(e,t,n,r)=>{let i=0,a=null,o=!1;for(let s=t;s<e.length;s+=1){let c=e[s];if(a){if(o){o=!1;continue}if(c===`\\`){o=!0;continue}c===a&&(a=null);continue}if(c===`"`||c===`'`){a=c;continue}if(c===n){i+=1;continue}if(c===r&&(--i,i===0))return e.slice(t,s+1)}return null},Ae=(e,t)=>{let n=e[t],r=``,i=!1;for(let a=t+1;a<e.length;a+=1){let t=e[a];if(i){r+=t,i=!1;continue}if(t===`\\`){i=!0;continue}if(t===n)return r;r+=t}return null},G=e=>{let t=Me(e).trim();if(!/^[[{]/.test(t))return null;let n=je(t.replace(/([{,]\s*)([A-Za-z_$][\w$-]*)(\s*:)/g,`$1"$2"$3`).replace(/,\s*([}\]])/g,`$1`));try{return JSON.parse(n)}catch{return null}},je=e=>{let t=``,n=!1,r=!1,i=!1,a=``;for(let o of e){if(r){if(i){a+=o,i=!1;continue}if(o===`\\`){i=!0;continue}if(o===`'`){t+=JSON.stringify(a),a=``,r=!1;continue}a+=o;continue}if(n){if(t+=o,i){i=!1;continue}if(o===`\\`){i=!0;continue}o===`"`&&(n=!1);continue}if(o===`'`){r=!0,a=``;continue}o===`"`&&(n=!0),t+=o}return t},Me=e=>{let t=Ne(e);return t=Pe(t),t=Fe(t),t},Ne=e=>{let t=``,n=!1,r=!1;for(let i=0;i<e.length;i+=1){let a=e[i],o=e[i+1];if(n){if(t+=a,r){r=!1;continue}if(a===`\\`){r=!0;continue}a===`"`&&(n=!1);continue}if(a===`"`){n=!0,t+=a;continue}if(a===`/`&&o===`/`){for(;i<e.length&&e[i]!==`
3
+ `;)i+=1;i<e.length&&(t+=e[i]);continue}t+=a}return t},Pe=e=>e.replace(/([[{]\s*)([A-Za-z_$][\w$-]*)(\s+)(?=")/g,`$1`),Fe=e=>{let t=e.trimStart();return!t.startsWith(`{`)||/"data"\s*:\s*\[/.test(t)||!/^\{\s*"[^"]+"\s*:/.test(t)||!/\]\s*,\s*"meta"\s*:/.test(t)?e:`${e.slice(0,e.indexOf(`{`))}{"data": [{${t.slice(1)}`},K=e=>e.replace(/([#.:[\],=])/g,`\\$1`),q=e=>e?.textContent?.replace(/\s+/g,` `).trim()||null,J=e=>Array.from(e).map(e=>q(e)).filter(e=>!!e),Y=e=>J(e.querySelectorAll(`span, div, code`)).filter(e=>e.trim().length>0).sort((e,t)=>t.length-e.length)[0]??q(e),Ie=(e,t)=>{let n=new URL(t),r=e.sidebarLinks.map(e=>e.href).filter(e=>!!e).map(e=>new URL(e,n).toString()).filter(e=>/^https?:\/\//i.test(e));return Array.from(new Set(r))};var Le=class{config;constructor(e={}){this.config=x(e)}getConfig(e={}){return{...this.config,...e}}configure(e){return this.config=x({...this.config,...e}),this.config}async crawlReadmeOperations(e,t,n){let i=this.resolveCrawlBaseUrl(e,n);if(!i)throw Error(`Crawl mode requires a remote source URL or --base-url when using a local file`);let a=!!_();a||await v(this.config);try{let e=Ie(t,i),n=new URL(i).toString(),a=this.attachSourceUrl(n,t),o=e.filter(e=>e!==n);return{rootSource:n,discoveredUrls:e,operations:[a,...(await Promise.all(o.map(async e=>{let t=Date.now(),n=E(await this.loadHtmlSource(e)),a=Date.now()-t;return n.method?(r.twoColumnDetail(r.log([[`Crawled`,`green`],[`${a/1e3}s`,`gray`]],` `,!1),e.replace(i,``)),this.attachSourceUrl(e,n)):null}))).filter(e=>e!==null)]}}finally{a||await y()}}attachSourceUrl(e,t){return{sourceUrl:e,...t}}resolveCrawlBaseUrl(e,t){return t?new URL(t).toString():/^https?:\/\//i.test(e)?e:null}async loadHtmlSource(e,t){if(!e)throw Error(`A source path or URL is required`);return/^https?:\/\//i.test(e)?C(e,this.config,t):o(i.resolve(process.cwd(),e),`utf8`)}},Re=class{renderDeclaration(e){switch(e.kind){case`interface`:return this.renderInterface(e);case`interface-alias`:return`export interface ${e.name} extends ${e.target} {}`;case`type-alias`:return`export type ${e.name} = ${e.target}`;case`shape-alias`:return`export type ${e.name} = ${this.renderShape(e.shape)}`}}renderOpenApiDocumentDefinitions(e,t,n){return[`export interface OpenApiInfo {
4
+ title: string
5
+ version: string
6
+ }`,`export interface OpenApiSchemaDefinition {
7
+ type?: string
8
+ description?: string
9
+ default?: unknown
10
+ properties?: Record<string, OpenApiSchemaDefinition>
11
+ items?: OpenApiSchemaDefinition
12
+ required?: string[]
13
+ example?: unknown
14
+ }`,`export interface OpenApiParameterDefinition {
15
+ name: string
16
+ in: 'query' | 'header' | 'path' | 'cookie'
17
+ required?: boolean
18
+ description?: string
19
+ schema?: OpenApiSchemaDefinition
20
+ example?: unknown
21
+ }`,`export interface OpenApiMediaTypeDefinition<TExample = unknown> {
22
+ schema?: OpenApiSchemaDefinition
23
+ example?: TExample
24
+ }`,`export interface OpenApiResponseDefinition<_TResponse = unknown, TExample = unknown> {
25
+ description: string
26
+ content?: Record<string, OpenApiMediaTypeDefinition<TExample>>
27
+ }`,`export interface OpenApiRequestBodyDefinition<TInput = unknown> {
28
+ description?: string
29
+ required: boolean
30
+ content: Record<string, OpenApiMediaTypeDefinition<TInput>>
31
+ }`,`export interface OpenApiOperationDefinition<_TResponse = unknown, TResponseExample = unknown, TInput = Record<string, never>, _TQuery = Record<string, never>, _THeader = Record<string, never>, _TParams = Record<string, never>> {
32
+ summary?: string
33
+ description?: string
34
+ operationId?: string
35
+ parameters?: OpenApiParameterDefinition[]
36
+ requestBody?: OpenApiRequestBodyDefinition<TInput>
37
+ responses: Record<string, OpenApiResponseDefinition<_TResponse, TResponseExample>>
38
+ }`,`export interface OpenApiSdkParameterManifest {
39
+ name: string
40
+ accessor: string
41
+ in: 'query' | 'header' | 'path'
42
+ required: boolean
43
+ description?: string
44
+ }`,`export interface OpenApiSdkOperationManifest {
45
+ path: string
46
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
47
+ methodName: string
48
+ summary?: string
49
+ description?: string
50
+ operationId?: string
51
+ requestBodyDescription?: string
52
+ responseDescription?: string
53
+ responseType: string
54
+ inputType: string
55
+ queryType: string
56
+ headerType: string
57
+ paramsType: string
58
+ hasBody: boolean
59
+ bodyRequired: boolean
60
+ pathParams: OpenApiSdkParameterManifest[]
61
+ queryParams: OpenApiSdkParameterManifest[]
62
+ headerParams: OpenApiSdkParameterManifest[]
63
+ }`,`export interface OpenApiSdkGroupManifest {
64
+ className: string
65
+ propertyName: string
66
+ operations: OpenApiSdkOperationManifest[]
67
+ }`,`export interface OpenApiSdkManifest {
68
+ groups: OpenApiSdkGroupManifest[]
69
+ }`,`export interface OpenApiRuntimeBundle<TApi = unknown> {
70
+ document: unknown
71
+ manifest: OpenApiSdkManifest
72
+ __api?: TApi
73
+ }`,Object.entries(t.paths).map(([e,t])=>{let r=this.derivePathTypeName(e);return[Object.keys(t).map(t=>{let r=this.deriveOperationInterfaceName(e,t),i=n.get(`${e}::${t}`)??{response:`Record<string, never>`,responseExample:`unknown`,input:`Record<string, never>`,query:`Record<string, never>`,header:`Record<string, never>`,params:`Record<string, never>`};return`export interface ${r} extends OpenApiOperationDefinition<${i.response}, ${i.responseExample}, ${i.input}, ${i.query}, ${i.header}, ${i.params}> {}`}).join(`
74
+
75
+ `),`export interface ${r} {\n${Object.keys(t).map(t=>` ${t}: ${this.deriveOperationInterfaceName(e,t)}`).join(`
76
+ `)}\n}`].join(`
77
+
78
+ `)}).join(`
79
+
80
+ `),`export interface Paths {\n${Object.keys(t.paths).map(e=>` ${this.formatPropertyKey(e)}: ${this.derivePathTypeName(e)}`).join(`
81
+ `)}\n}`,`export interface ${e} {\n openapi: '3.1.0'\n info: OpenApiInfo\n paths: Paths\n}`].join(`
82
+
83
+ `)}renderSdkApiInterface(e,t){return`export interface ${e}Api {\n${t.groups.map(e=>{let t=e.operations.map(e=>` ${e.methodName}${this.renderSdkMethodSignature(e)}`).join(`
84
+ `);return` ${e.propertyName}: {\n${t}\n }`}).join(`
85
+ `)}\n}`}renderSdkManifest(e,t){return`export const ${e}Manifest = ${this.renderValue(t)} as const satisfies OpenApiSdkManifest`}renderSdkBundle(e,t){return[`export const ${e}Sdk: OpenApiRuntimeBundle<${t}Api> = {`,` document: ${e},`,` manifest: ${e}Manifest,`,`}`].join(`
86
+ `)}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(`
87
+ `);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(`,
88
+ `)}\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(`,
89
+ `)}\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(/^:/,``)}},ze=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}`}},Be=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 ze;shapes=new Be(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;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)})}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))}}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}}},Z=class e{typeBuilder=new X;moduleRenderer=new Re;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(`
90
+
91
+ `),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(`
92
+
93
+ `)}generateGenericModule(e,t){let n=this.typeBuilder.createContext(),r=this.typeBuilder.inferShapeFromExample(e,t),i=this.typeBuilder.sanitizeTypeName(t),a=i;if(r.kind===`object`)a=this.typeBuilder.registerObjectShape(r,i,n,i);else{let e={kind:`shape-alias`,name:i,shape:r};n.declarations.push(e),n.declarationByName.set(i,e)}let o=a===t?``:`export type ${t} = ${a}`,s=this.moduleRenderer.toCamelCase(t);return[n.declarations.map(e=>this.moduleRenderer.renderDeclaration(e)).join(`
94
+
95
+ `),o,`export const ${s}: ${t} = ${this.moduleRenderer.renderValue(e)}`,``,`export default ${s}`].filter(Boolean).join(`
96
+
97
+ `)}isOpenApiDocumentLike(e){if(typeof e!=`object`||!e||Array.isArray(e))return!1;let t=e;if(typeof t.info!=`object`||t.info===null||Array.isArray(t.info))return!1;let n=t.info;return t.openapi===`3.1.0`&&typeof n.title==`string`&&typeof n.version==`string`&&typeof t.paths==`object`&&t.paths!==null&&!Array.isArray(t.paths)}},Q=class{static serializeOutput=async(e,t,n=`ExtractedApiDocument`,r={})=>t===`js`?l.format(`export default ${JSON.stringify(e,null,2)}`,{parser:`babel`,semi:!1,singleQuote:!0}):t===`ts`?l.format(Z.generateModule(e,n,r),{parser:`typescript`,semi:!1,singleQuote:!0}):JSON.stringify(e,null,t===`json`?0:2);static buildFilePath=(e,t,n,r)=>{let a={pretty:`txt`,json:`json`,js:`js`,ts:`ts`}[r],o=this.toSafeSourceName(t),s=n===`openapi`?`.openapi`:``;return i.join(e,`output`,`${o||`output`}${s}.${a}`)};static buildArtifactDirectory=(e,t,n)=>{let r=this.toSafeSourceName(t);return i.join(e,`output`,`${r||n}.${n}`)};static toSafeSourceName(e){return e.replace(/[^a-zA-Z0-9_-]+/g,`_`).replace(/^_+|_+$/g,``)}static getRootTypeName=e=>e===`openapi`?`ExtractedApiDocument`:`ExtractedPayload`},Ve=class{typeBuilder=new X;typeScriptGenerator=new Z;generate(e,t={}){let n=t.outputMode??`both`,r=t.signatureStyle??`grouped`,i=t.rootTypeName??`ExtractedApiDocument`,a=t.schemaModule??this.typeScriptGenerator.generateModule(e,i,t),o=this.createOperationTypeRefs(e),s=this.typeBuilder.buildSdkManifest(e,o,t),c=s.groups.map(e=>e.className),l={"package.json":this.renderPackageJson(t),"README.md":this.renderReadme(s,t,n,r),"src/Schema.ts":a,"src/index.ts":this.renderIndexFile(c,n,i),"tsconfig.json":this.renderTsconfig(),"tsdown.config.ts":this.renderTsdownConfig(),"vitest.config.ts":this.renderVitestConfig(),"tests/exports.test.ts":this.renderExportsTest(i,n)};if(n!==`runtime`){l[`src/BaseApi.ts`]=this.renderBaseApi(),l[`src/ApiBinder.ts`]=this.renderApiBinder(s);for(let e of s.groups)l[`src/Apis/${e.className}.ts`]=this.renderApiClass(e,r);l[`src/Core.ts`]=this.renderCoreFile()}return l}createOperationTypeRefs(e){let t=this.typeBuilder.createContext(),n=new Map;for(let r of this.typeBuilder.collectSemanticModels(e)){let e=`${r.path}::${r.method}`,i=this.typeBuilder.registerNamedShape(this.typeBuilder.namespaceTopLevelShape(r.shape,r.role),r.name,t,r.collisionSuffix),a=n.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[r.role]=i,n.set(e,a)}return n}renderBaseApi(){return[`import { BaseApi as KitBaseApi } from '@oapiex/sdk-kit'`,``,`export class BaseApi extends KitBaseApi {}`].join(`
98
+ `)}renderApiBinder(e){return[`import { BaseApi } from './BaseApi'`,``,...e.groups.map(e=>`import { ${e.className} } from './Apis/${e.className}'`),``,`export class ApiBinder extends BaseApi {`,...e.groups.map(e=>` ${e.propertyName}!: ${e.className}`),``,` protected override boot () {`,...e.groups.map(e=>` this.${e.propertyName} = new ${e.className}(this.core)`),` }`,`}`].join(`
99
+ `)}renderApiClass(e,t){let n=this.createTypeImportContext(e,t),r=[`import { BaseApi } from '../BaseApi'`,`import { Http } from '@oapiex/sdk-kit'`];return n.specifiers.length>0&&r.splice(1,0,`import type { ${n.specifiers.join(`, `)} } from '../Schema'`),[...r,``,`export class ${e.className} extends BaseApi {`,``,...e.operations.flatMap(e=>[this.renderApiMethod(e,t,n.aliasMap),``]).slice(0,-1),`}`].join(`
100
+ `)}renderApiMethod(e,t,n){let r=t===`flat`?this.renderFlatSignature(e,n):this.renderGroupedSignature(e,n),i=t===`flat`?this.renderFlatObjectLiteral(e.paramsType,e.pathParams):e.pathParams.length>0?`params`:`{}`,a=t===`flat`?this.renderFlatObjectLiteral(e.queryType,e.queryParams):e.queryParams.length>0?`query`:`{}`,o=t===`flat`?this.renderFlatHeaders(e):e.headerParams.length>0?`((headers ? { ...headers } : {}) as Record<string, string | undefined>)`:`{}`,s=t===`flat`?e.hasBody?`body`:`{}`:e.hasBody?`body ?? {}`:`{}`,c=this.renderMethodDocComment(e,t,n);return[...c?[c]:[],` async ${e.methodName} ${r}: Promise<${this.rewriteTypeReference(e.responseType,n)}> {`,` await this.core.validateAccess()`,``,` const { data } = await Http.send<${this.rewriteTypeReference(e.responseType,n)}>(`,` this.core.builder.buildTargetUrl('${e.path}', ${i}, ${a}),`,` '${e.method}',`,` ${s},`,` ${o}`,` )`,``,` return data`,` }`].join(`
101
+ `)}renderMethodDocComment(e,t,n){let r=[],i=e.summary?.trim(),a=e.description?.trim(),o=e.operationId?.trim(),s=this.rewriteTypeReference(e.responseType,n),c=e.responseDescription?.trim();i&&r.push(i),a&&a!==i&&(r.length>0&&r.push(``),r.push(...this.wrapDocText(a)));let l=[`HTTP ${e.method} ${e.path}`,...o?[`Operation ID: ${o}`]:[]];l.length>0&&(r.length>0&&r.push(``),r.push(...l));let u=t===`flat`?this.renderFlatParameterDocs(e,n):this.renderGroupedParameterDocs(e,n);return u.length>0&&(r.length>0&&r.push(``),r.push(...u)),r.push(`@returns ${c?`${c} `:``}${s}`.trim()),[` /**`,...r.map(e=>e?` * ${e}`:` *`),` */`].join(`
102
+ `)}renderGroupedParameterDocs(e,t){let n=[];return e.pathParams.length>0&&n.push(this.renderParamDoc(`params`,e.paramsType,t,this.describeParameterGroup(e.pathParams,`path parameters`))),e.queryParams.length>0&&n.push(this.renderParamDoc(`query`,e.queryType,t,this.describeParameterGroup(e.queryParams,`query parameters`))),e.hasBody&&n.push(this.renderParamDoc(`body`,e.inputType,t,e.requestBodyDescription?.trim()||`Request body`)),e.headerParams.length>0&&n.push(this.renderParamDoc(`headers`,e.headerType,t,this.describeParameterGroup(e.headerParams,`request headers`))),n}renderFlatParameterDocs(e,t){return[...e.pathParams.map(n=>this.renderParamDoc(n.accessor,`${e.paramsType}[${JSON.stringify(n.name)}]`,t,n.description?.trim()||`Path parameter ${n.name}`)),...e.queryParams.map(n=>this.renderParamDoc(n.accessor,`${e.queryType}[${JSON.stringify(n.name)}]`,t,n.description?.trim()||`Query parameter ${n.name}`)),...e.hasBody?[this.renderParamDoc(`body`,e.inputType,t,e.requestBodyDescription?.trim()||`Request body`)]:[],...e.headerParams.map(n=>this.renderParamDoc(n.accessor,`${e.headerType}[${JSON.stringify(n.name)}]`,t,n.description?.trim()||`Header ${n.name}`))]}renderParamDoc(e,t,n,r){return`@param ${e} ${r} Type: ${this.rewriteTypeReference(t,n)}`}describeParameterGroup(e,t){let n=e.map(e=>e.description?.trim()?`${e.name}: ${e.description.trim()}`:e.name).filter(Boolean);return n.length===0?t:n.join(`; `)}wrapDocText(e){return e.split(/\r?\n/).map(e=>e.trim()).filter(Boolean)}renderGroupedSignature(e,t){let n=[];return e.pathParams.length>0&&n.push(`params: ${this.rewriteTypeReference(e.paramsType,t)}`),e.queryParams.length>0&&n.push(`query: ${this.rewriteTypeReference(e.queryType,t)}`),e.hasBody&&n.push(`body${e.bodyRequired?``:`?`}: ${this.rewriteTypeReference(e.inputType,t)}`),e.headerParams.length>0&&n.push(`headers?: ${this.rewriteTypeReference(e.headerType,t)}`),`(${n.join(`, `)})`}renderFlatSignature(e,t){return`(${[...e.pathParams.map(n=>`${n.accessor}${n.required?``:`?`}: ${this.rewriteTypeReference(e.paramsType,t)}[${JSON.stringify(n.name)}]`),...e.queryParams.map(n=>`${n.accessor}${n.required?``:`?`}: ${this.rewriteTypeReference(e.queryType,t)}[${JSON.stringify(n.name)}]`),...e.hasBody?[`body${e.bodyRequired?``:`?`}: ${this.rewriteTypeReference(e.inputType,t)}`]:[],...e.headerParams.map(n=>`${n.accessor}${n.required?``:`?`}: ${this.rewriteTypeReference(e.headerType,t)}[${JSON.stringify(n.name)}]`)].join(`, `)})`}createTypeImportContext(e,t){let n=new Set;for(let t of e.operations)n.add(t.responseType),t.hasBody&&n.add(t.inputType),t.queryParams.length>0&&n.add(t.queryType),t.headerParams.length>0&&n.add(t.headerType),t.pathParams.length>0&&n.add(t.paramsType);let r=Array.from(new Set(Array.from(n).flatMap(e=>this.collectTypeIdentifiers(e)))).sort(),i=new Map;return{specifiers:r.map(t=>{if(t===e.className){let e=`${t}Model`;return i.set(t,e),`${t} as ${e}`}return t}),aliasMap:i}}rewriteTypeReference(e,t){let n=e;for(let[e,r]of t.entries())n=n.replace(RegExp(`\\b${e}\\b`,`g`),r);return n}renderFlatObjectLiteral(e,t){return t.length===0?`{}`:`{ ${t.map(e=>`${JSON.stringify(e.name)}: ${e.accessor}`).join(`, `)} }`}renderFlatHeaders(e){return e.headerParams.length===0?`{}`:`({ ${e.headerParams.map(e=>`${JSON.stringify(e.name)}: ${e.accessor}`).join(`, `)} } as Record<string, string | undefined>)`}renderCoreFile(){return[`import { Core as KitCore } from '@oapiex/sdk-kit'`,``,`import { ApiBinder } from './ApiBinder'`,``,`export class Core extends KitCore {`,` static override apiClass = ApiBinder`,``,` declare api: ApiBinder`,`}`].join(`
103
+ `)}renderPackageJson(e){return JSON.stringify({name:e.packageName??`generated-sdk`,type:`module`,version:e.packageVersion??`0.1.0`,private:!0,description:e.packageDescription??`Generated SDK scaffold emitted by oapiex.`,main:`./dist/index.cjs`,module:`./dist/index.js`,types:`./dist/index.d.ts`,exports:{".":{import:`./dist/index.js`,require:`./dist/index.cjs`},"./package.json":`./package.json`},files:[`dist`],scripts:{test:`pnpm vitest --run`,"test:watch":`pnpm vitest`,build:`tsdown`},dependencies:{[e.sdkKitPackageName??`@oapiex/sdk-kit`]:`^0.1.1`},devDependencies:{"@types/node":`^20.14.5`,tsdown:`^0.20.1`,typescript:`^5.4.5`,vitest:`^3.2.4`}},null,2)}renderReadme(e,t,n,r){let i=t.packageName??`generated-sdk`,a=`# ${i}`,o=this.renderReadmeDescription(n),s=this.renderReadmeUsage(e,i,n,r),c=this.renderReadmeExports(n);return[a,``,o,``,`## Install`,``,"```bash",`pnpm add ${i}`,"```",``,`## Quick Start`,``,"```ts",s,"```",``,`## Main Exports`,``,...c.map(e=>`- ${e}`),``,`## Commands`,``,"```bash",`pnpm test`,`pnpm build`,"```"].join(`
104
+ `)}renderReadmeDescription(e){return e===`runtime`?`Generated runtime-first TypeScript SDK emitted by oapiex.`:e===`classes`?`Generated class-based TypeScript SDK emitted by oapiex.`:`Generated TypeScript SDK emitted by oapiex with both class-based and runtime-first entrypoints.`}renderReadmeUsage(e,t,n,r){let i=this.pickExampleOperation(e),a=this.renderReadmeClientSnippet(t,`runtime`,r,i);if(n===`runtime`)return a;let o=this.renderReadmeClientSnippet(t,`classes`,r,i);if(n===`classes`)return o;let s=i?this.collectReadmeTypeImports(i.operation):[];return[s.length>0?`import { Core, createClient, type ${s.join(`, type `)} } from '${t}'`:`import { Core, createClient } from '${t}'`,``,...this.renderReadmeClientBody(`sdk`,`classes`,r,i),``,`// --- OR ---`,``,...this.renderReadmeClientBody(`runtimeSdk`,`runtime`,r,i)].join(`
105
+ `)}renderReadmeClientSnippet(e,t,n,r){let i=t===`runtime`?[`createClient`]:[`Core`],a=r?this.collectReadmeTypeImports(r.operation):[],o=a.length>0?`import { ${i.join(`, `)}, type ${a.join(`, type `)} } from '${e}'`:`import { ${i.join(`, `)} } from '${e}'`,s=t===`runtime`?`runtimeSdk`:`sdk`;return[o,``,...this.renderReadmeClientBody(s,t,n,r)].join(`
106
+ `)}renderReadmeClientBody(e,t,n,r){let i=t===`runtime`?`const ${e} = createClient({`:`const ${e} = new Core({`,a=r?this.renderReadmeOperationCall(e,r,t===`runtime`?`grouped`:n):[];return[i,` clientId: process.env.CLIENT_ID!,`,` clientSecret: process.env.CLIENT_SECRET!,`,` environment: 'sandbox',`,`})`,...a.length>0?[``,...a]:[]]}renderReadmeExports(e){return e===`runtime`?["`createClient()` for a typed runtime SDK instance","`Schema` exports for request, response, params, query, and header types"]:e===`classes`?["`Core` as the class-based SDK entrypoint","generated API classes plus `Schema` type exports"]:["`Core` for class-based usage","`createClient()` for runtime-first usage","`Schema` exports for generated request, response, params, query, and header types"]}pickExampleOperation(e){let t=e.groups[0],n=t?.operations[0];return!t||!n?null:{group:t,operation:n}}collectReadmeTypeImports(e){let t=new Set;return e.pathParams.length>0&&t.add(e.paramsType),e.queryParams.length>0&&t.add(e.queryType),e.hasBody&&t.add(e.inputType),e.headerParams.length>0&&t.add(e.headerType),Array.from(t).sort()}renderReadmeOperationCall(e,t,n){let{group:r,operation:i}=t,a=n===`flat`?this.renderReadmeFlatArgs(i):this.renderReadmeGroupedArgs(i);return[`await ${e}.api.${r.propertyName}.${i.methodName}(`,...a.map(e=>` ${e},`),`)`]}renderReadmeGroupedArgs(e){let t=[];return e.pathParams.length>0&&t.push(`{} as ${e.paramsType}`),e.queryParams.length>0&&t.push(`{} as ${e.queryType}`),e.hasBody&&t.push(`{} as ${e.inputType}`),e.headerParams.length>0&&t.push(`{} as ${e.headerType}`),t}renderReadmeFlatArgs(e){return[...e.pathParams.map(t=>`{} as ${e.paramsType}[${JSON.stringify(t.name)}]`),...e.queryParams.map(t=>`{} as ${e.queryType}[${JSON.stringify(t.name)}]`),...e.hasBody?[`{} as ${e.inputType}`]:[],...e.headerParams.map(t=>`{} as ${e.headerType}[${JSON.stringify(t.name)}]`)]}renderTsconfig(){return JSON.stringify({compilerOptions:{rootDir:`.`,outDir:`./dist`,target:`esnext`,module:`es2022`,moduleResolution:`bundler`,esModuleInterop:!0,strict:!0,allowJs:!0,skipLibCheck:!0,resolveJsonModule:!0},include:[`./src/**/*`,`./tests/**/*`],exclude:[`./dist`,`./node_modules`]},null,2)}renderTsdownConfig(){return[`import { defineConfig } from 'tsdown'`,``,`export default defineConfig({`,` entry: {`,` index: 'src/index.ts',`,` },`,` exports: true,`,` format: ['esm', 'cjs'],`,` outDir: 'dist',`,` dts: true,`,` sourcemap: false,`,` external: ['@oapiex/sdk-kit'],`,` clean: true,`,`})`].join(`
107
+ `)}renderVitestConfig(){return[`import { defineConfig } from 'vitest/config'`,``,`export default defineConfig({`,` test: {`,` name: 'generated-sdk',`,` environment: 'node',`,` include: ['tests/*.{test,spec}.?(c|m)[jt]s?(x)'],`,` },`,`})`].join(`
108
+ `)}renderExportsTest(e,t){let n=`${e.charAt(0).toLowerCase()}${e.slice(1)}`,r=[` expect(sdk.createClient).toBeTypeOf('function')`,` expect(sdk.createSdk).toBeTypeOf('function')`,` expect(sdk.${n}Sdk).toBeDefined()`,` expect(sdk.${n}Manifest).toBeDefined()`];return t!==`runtime`&&(r.unshift(` expect(sdk.Core).toBeTypeOf('function')`),r.unshift(` expect(sdk.BaseApi).toBeTypeOf('function')`)),[`import { describe, expect, it } from 'vitest'`,``,`import * as sdk from '../src/index'`,``,`describe('generated sdk exports', () => {`,` it('exposes the generated schema and runtime helpers', () => {`,...r,` })`,`})`].join(`
109
+ `)}renderIndexFile(e,t,n){let r=`${n.charAt(0).toLowerCase()}${n.slice(1)}`,i=[`import type { ${n}Api } from './Schema'`,`import { ${r}Sdk } from './Schema'`,`import { createSdk as createBoundSdk } from '@oapiex/sdk-kit'`,`import type { BaseApi as KitBaseApi, Core as KitCore, InitOptions } from '@oapiex/sdk-kit'`,``,`export * from './Schema'`];return t!==`runtime`&&(i.push(`export { ApiBinder } from './ApiBinder'`),i.push(`export { BaseApi } from './BaseApi'`),i.push(...e.map(e=>`export { ${e} as ${e}Api } from './Apis/${e}'`)),i.push(`export { Core } from './Core'`)),i.push(``),i.push(`export const createClient = (`),i.push(` options: InitOptions`),i.push(`): KitCore & { api: KitBaseApi & ${n}Api } =>`),i.push(` createBoundSdk(${r}Sdk, options) as KitCore & { api: KitBaseApi & ${n}Api }`),i.push(``),i.push(`export {`),i.push(` BadRequestException,`),i.push(` Builder,`),i.push(` ForbiddenRequestException,`),i.push(` Http,`),i.push(` HttpException,`),i.push(` UnauthorizedRequestException,`),i.push(` WebhookValidator,`),i.push(` createSdk,`),i.push(`} from '@oapiex/sdk-kit'`),i.push(``),i.push(`export type {`),i.push(` InitOptions,`),i.push(` UnifiedResponse,`),i.push(` XGenericObject,`),i.push(`} from '@oapiex/sdk-kit'`),i.join(`
110
+ `)}collectTypeIdentifiers(e){return Array.from(new Set((e.match(/\b[A-Z][A-Za-z0-9_]*/g)??[]).filter(e=>![`Record`,`Promise`].includes(e))))}};const $=new class{createDocument(e,t=`Extracted API`,n=`0.0.0`){let r={};for(let t of e){let e=this.transformOperation(t);!e||this.shouldSkipNormalizedOperation(e)||(r[e.path]??={},r[e.path][e.method]=e.operation)}return{openapi:`3.1.0`,info:{title:t,version:n},paths:r}}transformOperation(e){if(!e.method||!e.url)return null;let t=new URL(e.url);if(this.shouldSkipPlaceholderOperation(t,e))return null;let n=e.method.toLowerCase(),r=this.decodeOpenApiPathname(t.pathname);return{path:r,method:n,operation:{summary:e.sidebarLinks.find(e=>e.active)?.label,description:e.description??void 0,operationId:this.buildOperationId(n,r),parameters:this.createParameters(e.requestParams),requestBody:this.createRequestBody(e.requestParams,e.requestExampleNormalized?.body,this.hasExtractedBodyParams(e.requestParams)?null:this.resolveFallbackRequestBodyExample(e)),responses:this.createResponses(e.responseSchemas,e.responseBodies)}}}shouldSkipNormalizedOperation(e){return e.path===`/`&&e.method===`get`&&e.operation.operationId===`get`&&Object.keys(e.operation.responses).length===0}shouldSkipPlaceholderOperation(e,t){return e.hostname!==`example.com`||e.pathname!==`/`?!1:t.requestParams.length===0&&t.responseSchemas.length===0&&t.responseBodies.length===0&&t.requestExampleNormalized?.url===`https://example.com/`}decodeOpenApiPathname(e){return e.split(`/`).map(e=>{if(!e)return e;try{return decodeURIComponent(e)}catch{return e}}).join(`/`)}hasExtractedBodyParams(e){return e.some(e=>e.in===`body`||e.in===null)}createParameters(e){let t=e.filter(e=>this.isOpenApiParameterLocation(e.in)).map(e=>this.createParameter(e));return t.length>0?t:void 0}createRequestBody(e,t,n){let r=e.filter(e=>e.in===`body`||e.in===null);if(r.length===0&&t==null)return;let i=this.buildRequestBodySchema(r,t,n);return{required:r.length>0?r.some(e=>e.required):!1,content:{"application/json":{schema:i,...t==null?{}:{example:t}}}}}buildRequestBodySchema(e,t,n){let r=this.mergeOpenApiSchemas(this.createExampleSchema(t),this.createExampleSchema(n))??{type:`object`};t==null?n!=null&&(r.example=n):r.example=t;for(let t of e)this.insertRequestBodyParam(r,t);return r}inferSchemaFromExample(e){if(Array.isArray(e))return{type:`array`,items:this.inferSchemaFromExample(e[0])??{},example:e};if(T(e))return{type:`object`,properties:Object.fromEntries(Object.entries(e).map(([e,t])=>[e,this.inferSchemaFromExample(t)??{}])),example:e};if(typeof e==`string`)return{type:`string`,example:e};if(typeof e==`number`)return{type:Number.isInteger(e)?`integer`:`number`,example:e};if(typeof e==`boolean`)return{type:`boolean`,example:e};if(e===null)return{}}insertRequestBodyParam(e,t){let n=t.path.length>0?t.path:[t.name],r=e;for(let[e,i]of n.slice(0,-1).entries())r.properties??={},r.properties[i]??={type:`object`},t.required&&(r.required=Array.from(new Set([...r.required??[],i]))),r=r.properties[i],r.type??=`object`,e===n.length-2&&t.required&&(r.required??=[]);let i=n[n.length-1]??t.name;r.properties??={},r.properties[i]=this.createParameterSchema(t),t.required&&(r.required=Array.from(new Set([...r.required??[],i])))}createParameter(e){return{name:e.name,in:e.in,required:e.in===`path`?!0:e.required,description:e.description??void 0,schema:this.createParameterSchema(e),example:e.defaultValue??void 0}}createParameterSchema(e){return{type:e.type??void 0,description:e.description??void 0,default:e.defaultValue??void 0}}createResponses(e,t){let n={};for(let r of e){if(!r.statusCode)continue;let e=t.filter(e=>e.statusCode===r.statusCode),i=this.createResponseContent(e);n[r.statusCode]={description:r.description??r.statusCode,...i?{content:i}:{}}}for(let e of t){if(!e.statusCode||n[e.statusCode])continue;let t=this.createResponseContent([e]);n[e.statusCode]={description:e.label??e.statusCode,...t?{content:t}:{}}}return n}createResponseContent(e){if(e.length===0)return;let t={};for(let n of e){let e=n.contentType??(n.format===`json`?`application/json`:`text/plain`),r=this.normalizeResponseExampleValue(n.body,n.format);t[e]={schema:this.inferSchemaFromBody(r,n.format),example:r}}return t}inferSchemaFromBody(e,t){if(t===`json`)return this.inferSchemaFromExample(e);if(t===`text`)return{type:`string`,example:e}}normalizeResponseExampleValue(e,t){return t!==`json`||typeof e!=`string`?e:w.parsePossiblyTruncated(e)??G(e)??e}resolveFallbackRequestBodyExample(e){return e.responseBodies.find(e=>e.format===`json`)?.body??(typeof e.responseExample==`object`&&e.responseExample!==null?e.responseExample:typeof e.responseExampleRaw==`string`?w.parsePossiblyTruncated(e.responseExampleRaw):typeof e.responseExample==`string`?w.parsePossiblyTruncated(e.responseExample):null)}createExampleSchema(e){return e==null?null:this.inferSchemaFromExample(e)??null}mergeOpenApiSchemas(e,t){if(!e)return t;if(!t)return e;let n={...t,...e,...e.type||t.type?{type:e.type??t.type}:{},...e.description||t.description?{description:e.description??t.description}:{},...e.default!==void 0||t.default!==void 0?{default:e.default??t.default}:{},...e.example!==void 0||t.example!==void 0?{example:e.example??t.example}:{}};if(e.properties||t.properties){let r=new Set([...Object.keys(e.properties??{}),...Object.keys(t.properties??{})]);n.properties=Object.fromEntries(Array.from(r).map(n=>[n,this.mergeOpenApiSchemas(e.properties?.[n]??null,t.properties?.[n]??null)??{}]))}return(e.items||t.items)&&(n.items=this.mergeOpenApiSchemas(e.items??null,t.items??null)??{}),(e.required||t.required)&&(n.required=Array.from(new Set([...t.required??[],...e.required??[]]))),n}buildOperationId(e,t){return`${e}${t.replace(/\{([^}]+)\}/g,`$1`).split(`/`).filter(Boolean).map(e=>e.replace(/[^a-zA-Z0-9]+/g,` `)).map(e=>e.trim()).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1).replace(/\s+(.)/g,(e,t)=>t.toUpperCase())).join(``)}`}isOpenApiParameterLocation(e){return e===`query`||e===`header`||e===`path`||e===`cookie`}};var He=class extends s{signature=`generate
111
+ {artifact : Artifact to generate [sdk]}
112
+ {source? : Documentation URL/local source or parsed TypeScript output file}
113
+ {--d|dir? : Output directory for the generated artifact}
114
+ {--n|name? : Package name for generated SDK packages}
115
+ {--O|output-mode=both : SDK output mode [runtime,classes,both]}
116
+ {--S|signature-style=grouped : SDK method signature style [flat,grouped]}
117
+ {--N|namespace-strategy=smart : Namespace naming strategy [smart,scoped]}
118
+ {--M|method-strategy=smart : Method naming strategy [smart,operation-id]}
119
+ {--r|root-type-name=ExtractedApiDocument : Root type name for the generated Schema.ts module}
120
+ {--B|browser? : Remote loader [axios,happy-dom,jsdom,puppeteer]}
121
+ {--t|timeout? : Request/browser timeout in milliseconds}
122
+ {--c|crawl : Crawl sidebar links and parse every discovered operation}
123
+ {--b|base-url? : Base URL used to resolve sidebar links when crawling from a local file}
124
+ `;description=`Generate artifacts such as SDK packages from documentation sources or parsed TypeScript outputs`;async handle(){let e=this.app.getConfig(),t=String(this.argument(`artifact`,``)).trim().toLowerCase(),n=String(this.argument(`source`,``)).trim(),i=String(this.option(`browser`,e.browser)).trim().toLowerCase(),a=String(this.option(`timeout`,``)).trim(),o=this.option(`crawl`),s=String(this.option(`baseUrl`,``)).trim()||null,c=await this.resolveOutputDirectory(n),l=this.spinner(`Generating ${t} artifact...`).start(),u=!1;try{let d=Date.now();if(!S(i))throw Error(`Unsupported browser: ${i}`);if(t!==`sdk`)throw Error(`Unsupported artifact: ${t}`);if(!n)throw Error(`The sdk artifact requires a source argument`);if(!this.isTypeScriptArtifactSource(n)&&!S(i))throw Error(`Unsupported browser: ${i}`);let f=this.resolveTimeoutOverride(a,e.requestTimeout),p=this.parseNamespaceStrategy(this.option(`namespaceStrategy`,`smart`)),m=this.parseMethodStrategy(this.option(`methodStrategy`,`smart`)),h=this.parseOutputMode(this.option(`outputMode`,`both`)),g=this.parseSignatureStyle(this.option(`signatureStyle`,`grouped`)),_=String(this.option(`rootTypeName`,`ExtractedApiDocument`)).trim()||`ExtractedApiDocument`;this.app.configure({browser:i,requestTimeout:f}),!this.isTypeScriptArtifactSource(n)&&o&&(await v(this.app.getConfig()),u=!0);let y=await this.resolveSdkSource({source:n,crawl:o,baseUrl:s,rootTypeName:_,namespaceStrategy:p,methodStrategy:m}),b=this.resolvePackageName(c),x=new Ve().generate(y.document,{outputMode:h,signatureStyle:g,rootTypeName:_,namespaceStrategy:p,methodStrategy:m,schemaModule:y.schemaModule,packageName:String(this.option(`name`,``)).trim()||b});await this.writePackageFiles(c,x);let C=Date.now()-d;r.twoColumnDetail(r.log([[`Generated`,`green`],[`${C/1e3}s`,`gray`]],` `,!1),c.replace(process.cwd(),`.`)),l.succeed(`Artifact generation completed`)}catch(e){let t=e instanceof Error?e.message:`Unknown error`;l.fail(`Failed to generate artifact: ${t}`),process.exitCode=1}finally{u&&await y()}}async resolveSdkSource(e){if(this.isTypeScriptArtifactSource(e.source))return this.loadSdkSourceFromTypeScriptArtifact(e.source);let t=E(await this.app.loadHtmlSource(e.source,!0)),n=e.crawl?await this.app.crawlReadmeOperations(e.source,t,e.baseUrl):t,r=this.buildOpenApiPayload(n);return{document:r,schemaModule:await l.format(Z.generateModule(r,e.rootTypeName,{namespaceStrategy:e.namespaceStrategy,methodStrategy:e.methodStrategy}),{parser:`typescript`,semi:!1,singleQuote:!0})}}async loadSdkSourceFromTypeScriptArtifact(e){let t=i.resolve(process.cwd(),e),n=await a.readFile(t,`utf8`),r=await import(`${u(t).href}?t=${Date.now()}`),o=r.default??Object.values(r).find(e=>this.isOpenApiDocumentLike(e));if(!this.isOpenApiDocumentLike(o))throw Error(`The provided TypeScript source does not export an OpenAPI document`);return{document:o,schemaModule:n}}buildOpenApiPayload(e){return`operations`in e?$.createDocument(e.operations,`Extracted API`,`0.0.0`):$.createDocument([e],`Extracted API`,`0.0.0`)}resolveTimeoutOverride(e,t){if(!e)return t;let n=Number(e);if(!Number.isFinite(n)||n<=0)throw Error(`Invalid timeout override: ${e}`);return n}async resolveOutputDirectory(e,t){t??=String(this.option(`dir`,``)).trim();let n=t?i.resolve(process.cwd(),t):Q.buildArtifactDirectory(process.cwd(),e,`sdk`);if(d(n)&&f(n).length>0)switch(await this.choice(`Output directory (${t}) already exists and is not empty, what would you like to do?`,[{name:`Overwrite`,value:`overwrite`},{name:`Try to merge`,value:`merge`},{name:`Choose a different directory`,value:`choose`},{name:`Cancel`,value:`cancel`}])){case`overwrite`:await a.rm(n,{recursive:!0,force:!0});break;case`choose`:{let n=await this.ask(`Please enter a new output directory (relative to current directory):`,t);return this.resolveOutputDirectory(e,n)}case`cancel`:return this.info(`Operation cancelled by user`),process.exit(0);default:break}return n}resolvePackageName(e){return String(this.option(`name`,``)).trim()||i.basename(e).replace(/[^a-zA-Z0-9._-]+/g,`-`).replace(/^-+|-+$/g,``)||`generated-sdk`}parseOutputMode(e){let t=String(e??`both`).trim().toLowerCase();if(t===`runtime`||t===`classes`||t===`both`)return t;throw Error(`Unsupported sdk output mode: ${t}`)}parseSignatureStyle(e){let t=String(e??`grouped`).trim().toLowerCase();if(t===`flat`||t===`grouped`)return t;throw Error(`Unsupported signature style: ${t}`)}parseNamespaceStrategy(e){let t=String(e??`smart`).trim().toLowerCase();if(t===`smart`||t===`scoped`)return t;throw Error(`Unsupported namespace strategy: ${t}`)}parseMethodStrategy(e){let t=String(e??`smart`).trim().toLowerCase();if(t===`smart`||t===`operation-id`)return t;throw Error(`Unsupported method strategy: ${t}`)}isTypeScriptArtifactSource(e){return/\.(?:[cm]?ts|[cm]?js)$/i.test(e)}isOpenApiDocumentLike(e){if(typeof e!=`object`||!e||Array.isArray(e))return!1;let t=e,n=t.info;return t.openapi===`3.1.0`&&typeof n==`object`&&!!n&&!Array.isArray(n)&&typeof n.title==`string`&&typeof n.version==`string`&&typeof t.paths==`object`&&t.paths!==null&&!Array.isArray(t.paths)}async writePackageFiles(e,t){await Promise.all(Object.entries(t).map(async([t,n])=>{let r=i.join(e,t);await a.mkdir(i.dirname(r),{recursive:!0}),await a.writeFile(r,n,`utf8`)}))}};const Ue=p(import.meta.url);var We=class extends s{signature=`init
125
+ {--f|force : Overwrite existing config}
126
+ {--p|pkg? : Generate config for another package (e.g. sdk-kit) instead of oapiex [sdk]}
127
+ `;description=`Generate a default oapiex.config.ts in the current directory`;async handle(){let e=process.cwd(),t=i.join(e,`oapiex.config.js`),n=this.option(`force`,!1),r=this.option(`pkg`,`base`).trim().toLowerCase(),o={base:this.buildConfigTemplate(),sdk:this.buildSdkConfigTemplate()};if(![`base`,`sdk`].includes(r))return void this.error(`Invalid package option: ${r}`);try{await a.access(t),n||(this.error(`Config file already exists at ${t}. Use --force to overwrite.`),process.exit(1))}catch{}await a.writeFile(t,o[r],`utf8`),this.line(`Created ${t} `)}buildConfigTemplate(){let e=h;return[`import { defineConfig } from '${Ue.includes(`node_modules`)?`oapiex`:`./src/Manager`}'`,``,`/**`,` * See https://toneflix.github.io/oapiex/configuration for docs`,` */`,`export default defineConfig({`,` outputFormat: '${e.outputFormat}',`,` outputShape: '${e.outputShape}',`,` browser: '${e.browser}',`,` requestTimeout: ${e.requestTimeout},`,` maxRedirects: ${e.maxRedirects},`,` userAgent: '${e.userAgent}',`,` retryCount: ${e.retryCount},`,` retryDelay: ${e.retryDelay},`,`})`].join(`
128
+ `)}buildSdkConfigTemplate(){return[`import { defineConfig } from '@oapiex/sdk-kit'`,``,`/**`,` * See https://toneflix.github.io/oapiex/configuration for docs`,` */`,`export default defineConfig({`,` environment: 'sandbox',`,` urls: {`,` live: 'https://live.oapiex.com',`,` sandbox: 'https://sandbox.oapiex.com',`,` },`,`})`].join(`
129
+ `)}},Ge=class extends s{signature=`parse
130
+ {source : Local HTML file path or remote URL}
131
+ {--O|output=pretty : Output format [pretty,json,js,ts]}
132
+ {--S|shape=raw : Result shape [raw,openapi]}
133
+ {--B|browser? : Remote loader [axios,happy-dom,jsdom,puppeteer]}
134
+ {--t|timeout? : Request/browser timeout in milliseconds}
135
+ {--c|crawl : Crawl sidebar links and parse every discovered operation}
136
+ {--b|base-url? : Base URL used to resolve sidebar links when crawling from a local file}
137
+ `;description=`Parse a saved ReadMe page or remote documentation URL and print normalized output`;async handle(){let e=this.app.getConfig(),t=String(this.argument(`source`,``)).trim(),n=String(this.option(`output`,e.outputFormat)).trim().toLowerCase(),i=String(this.option(`shape`,e.outputShape)).trim().toLowerCase(),a=String(this.option(`browser`,e.browser)).trim().toLowerCase(),o=String(this.option(`timeout`,``)).trim(),s=this.option(`crawl`),c=String(this.option(`baseUrl`,``)).trim()||null,l=this.spinner(`${s?`Crawling and p`:`P`}arsing source...`).start(),u=!1;try{let d=Date.now();if(!S(a))throw Error(`Unsupported browser: ${a}`);let f=this.resolveTimeoutOverride(o,e.requestTimeout);this.app.configure({browser:a,requestTimeout:f}),s&&(await v(this.app.getConfig()),u=!0);let p=E(await this.app.loadHtmlSource(t,!0)),m=s?await this.app.crawlReadmeOperations(t,p,c):p,h=i===`openapi`?this.buildOpenApiPayload(m):m,g=await Q.serializeOutput(h,n,Q.getRootTypeName(i)),_=await this.saveOutputToFile(g,t,i,n),y=Date.now()-d;r.twoColumnDetail(r.log([[`Output`,`green`],[`${y/1e3}s`,`gray`]],` `,!1),_.replace(process.cwd(),`.`)),l.succeed(`Parsing completed`)}catch(e){let t=e instanceof Error?e.message:`Unknown error`;l.fail(`Failed to parse source: ${t}`),process.exitCode=1}finally{u&&await y()}}resolveTimeoutOverride=(e,t)=>{if(!e)return t;let n=Number(e);if(!Number.isFinite(n)||n<=0)throw Error(`Invalid timeout override: ${e}`);return n};buildOpenApiPayload=e=>`operations`in e?$.createDocument(e.operations,`Extracted API`,`0.0.0`):$.createDocument([e],`Extracted API`,`0.0.0`);saveOutputToFile=async(e,t,n,r)=>{let o=Q.buildFilePath(process.cwd(),t,n,r),s=i.dirname(o);return await a.mkdir(s,{recursive:!0}),await a.writeFile(o,e,`utf8`),o}};const Ke=[`oapiex.config.ts`,`oapiex.config.js`,`oapiex.config.cjs`];async function qe(e=process.cwd()){for(let t of Ke){let n=i.join(e,t);try{await a.access(n);let e=await import(u(n).href),t=e.default||e.config||e;if(typeof t==`object`&&t)return t}catch{continue}}return null}async function Je(e={}){let t=await qe();return{...h,...t,...e,happyDom:{...h.happyDom,...t?.happyDom||{},...e.happyDom||{}}}}const Ye=new Le(await Je());await c.init(Ye,{name:`OAPIEX`,logo:``,allowRebuilds:!1,packages:[`@h3ravel/musket`],baseCommands:[We,He,Ge],exceptionHandler(e){console.error(`An unexpected error occurred:`,e),process.exit(1)}});export{};