oapiex 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 ToneFlix Technologies Limited
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,221 @@
1
+ # OPENAPIE
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)
9
+
10
+ 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
+ It currently focuses on ReadMe-powered API docs and saved HTML pages, with room to expand to additional documentation platforms.
13
+
14
+ - npm: https://www.npmjs.com/package/openapie
15
+ - docs: https://toneflix.github.io/openapie
16
+ - repository: https://github.com/toneflix/oapi
17
+
18
+ ## Features
19
+
20
+ - parse remote documentation URLs or saved local HTML files
21
+ - extract methods, URLs, parameters, request examples, and response examples
22
+ - crawl linked sidebar pages for multi-endpoint references
23
+ - transform extracted operations into an OpenAPI-like document
24
+ - use the tool as a CLI or as a programmatic package
25
+ - choose among `axios`, `happy-dom`, `jsdom`, and `puppeteer` loaders
26
+
27
+ ## Installation
28
+
29
+ ### CLI
30
+
31
+ Install globally if you want the `openapie` command available everywhere:
32
+
33
+ ```bash
34
+ pnpm add -g openapie
35
+ ```
36
+
37
+ ```bash
38
+ npm i -g openapie
39
+ ```
40
+
41
+ ```bash
42
+ yarn global add openapie
43
+ ```
44
+
45
+ ### Library
46
+
47
+ Install locally if you want to use OPENAPIE from your own scripts or tooling:
48
+
49
+ ```bash
50
+ pnpm add openapie
51
+ ```
52
+
53
+ ```bash
54
+ npm i openapie
55
+ ```
56
+
57
+ ```bash
58
+ yarn add openapie
59
+ ```
60
+
61
+ ## CLI Quick Start
62
+
63
+ Extract a single page into an OpenAPI-like JSON document:
64
+
65
+ ```bash
66
+ oapie parse https://maplerad.dev/reference/create-a-customer \
67
+ --shape=openapi \
68
+ --output=json
69
+ ```
70
+
71
+ Crawl a sidebar section and write a JavaScript module:
72
+
73
+ ```bash
74
+ oapie parse https://maplerad.dev/reference/create-a-customer \
75
+ --shape=openapi \
76
+ --output=js \
77
+ --crawl
78
+ ```
79
+
80
+ Generate a config file:
81
+
82
+ ```bash
83
+ oapie init
84
+ ```
85
+
86
+ ## Programmatic Usage
87
+
88
+ Extract a single operation:
89
+
90
+ ```ts
91
+ import { Application, extractReadmeOperationFromHtml } from 'openapie';
92
+
93
+ const app = new Application({
94
+ browser: 'puppeteer',
95
+ });
96
+
97
+ const html = await app.loadHtmlSource(
98
+ 'https://maplerad.dev/reference/create-a-customer',
99
+ true,
100
+ );
101
+
102
+ const operation = extractReadmeOperationFromHtml(html);
103
+
104
+ console.log(operation.method);
105
+ console.log(operation.url);
106
+ ```
107
+
108
+ Convert extracted data into an OpenAPI-like document:
109
+
110
+ ```ts
111
+ import {
112
+ Application,
113
+ createOpenApiDocumentFromReadmeOperations,
114
+ extractReadmeOperationFromHtml,
115
+ } from 'openapie';
116
+
117
+ const app = new Application({ browser: 'puppeteer' });
118
+ const html = await app.loadHtmlSource(
119
+ 'https://maplerad.dev/reference/create-a-customer',
120
+ true,
121
+ );
122
+ const operation = extractReadmeOperationFromHtml(html);
123
+
124
+ const document = createOpenApiDocumentFromReadmeOperations(
125
+ [operation],
126
+ 'Extracted API',
127
+ '0.0.0',
128
+ );
129
+
130
+ console.log(document.paths);
131
+ ```
132
+
133
+ ## Configuration
134
+
135
+ OPENAPIE looks for one of these files in the current working directory:
136
+
137
+ - `openapie.config.ts`
138
+ - `openapie.config.js`
139
+ - `openapie.config.cjs`
140
+
141
+ Example:
142
+
143
+ ```ts
144
+ import { defineConfig } from 'openapie';
145
+
146
+ export default defineConfig({
147
+ outputFormat: 'json',
148
+ outputShape: 'openapi',
149
+ browser: 'puppeteer',
150
+ requestTimeout: 50000,
151
+ });
152
+ ```
153
+
154
+ ## Supported Loaders
155
+
156
+ - `axios`
157
+ - `happy-dom`
158
+ - `jsdom`
159
+ - `puppeteer`
160
+
161
+ The default browser is `puppeteer`.
162
+
163
+ ## Output
164
+
165
+ CLI parse results are written to the local `output/` directory.
166
+
167
+ Available output shapes:
168
+
169
+ - `raw`
170
+ - `openapi`
171
+
172
+ Available output formats:
173
+
174
+ - `pretty`
175
+ - `json`
176
+ - `js`
177
+
178
+ ## Documentation
179
+
180
+ Full documentation is available at https://oapi-extractor.toneflix.net.
181
+
182
+ Useful sections:
183
+
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
189
+
190
+ ## Roadmap Highlights
191
+
192
+ Current future-looking areas include:
193
+
194
+ - improved ReadMe extraction coverage
195
+ - stronger schema and example inference
196
+ - broader programmatic API helpers
197
+ - support for Apidog documentation pages
198
+ - support for Postman documentation pages
199
+
200
+ See the full roadmap at https://toneflix.github.io/openapie/project/roadmap.
201
+
202
+ ## Development
203
+
204
+ Install dependencies:
205
+
206
+ ```bash
207
+ pnpm install
208
+ ```
209
+
210
+ Common commands:
211
+
212
+ ```bash
213
+ pnpm test
214
+ pnpm build
215
+ pnpm docs:dev
216
+ pnpm docs:build
217
+ ```
218
+
219
+ ## License
220
+
221
+ MIT
package/bin/cli.mjs ADDED
@@ -0,0 +1,2 @@
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{};