@visulima/jsdoc-open-api 4.0.0 → 4.0.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/CHANGELOG.md +7 -0
- package/dist/cli/commander/index.js +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/index.d.ts +0 -7
- package/dist/index.js +1 -1
- package/dist/packem_shared/SpecBuilder-CuS4pzgn.js +1 -0
- package/dist/packem_shared/SwaggerCompilerPlugin-CaTRl2dP.js +1 -0
- package/dist/packem_shared/customizer-BAodMCcL.js +1 -0
- package/dist/packem_shared/generateCommand-C8UiAcbb.js +1 -0
- package/dist/packem_shared/generateCommand-UX5Dt0_V.js +5 -0
- package/dist/packem_shared/{initCommand-Ca1hGdYS.js → initCommand-DyN1TM7N.js} +1 -1
- package/dist/packem_shared/initCommand-Qkr6cX4d.js +1 -0
- package/dist/packem_shared/jsDocumentCommentsToOpenApi-DAGZljgo.js +1 -0
- package/dist/packem_shared/loadDefinition-CTfgPhtU.js +1 -0
- package/dist/packem_shared/parseFile-D-YG728l.js +1 -0
- package/dist/packem_shared/swaggerJsDocumentCommentsToOpenApi-B3WXfu-w.js +10 -0
- package/dist/packem_shared/validate-BomABpjM.js +1 -0
- package/dist/packem_shared/yamlLoc-B-xW0eUp.js +1 -0
- package/package.json +5 -5
- package/dist/packem_shared/SpecBuilder-Vbq42UbW.js +0 -1
- package/dist/packem_shared/SwaggerCompilerPlugin-vT9UJGnF.js +0 -1
- package/dist/packem_shared/customizer-BXFVpImq.js +0 -1
- package/dist/packem_shared/generateCommand-C3riX6Is.js +0 -5
- package/dist/packem_shared/generateCommand-q_aBpnih.js +0 -1
- package/dist/packem_shared/initCommand-TixxsVQU.js +0 -1
- package/dist/packem_shared/jsDocumentCommentsToOpenApi-CuIbZppP.js +0 -1
- package/dist/packem_shared/loadDefinition-Cfj2-XHF.js +0 -1
- package/dist/packem_shared/parseFile-Dtv-2qq3.js +0 -1
- package/dist/packem_shared/swaggerJsDocumentCommentsToOpenApi-CWeEk_r1.js +0 -10
- package/dist/packem_shared/validate-9Rwe2A3r.js +0 -1
- package/dist/packem_shared/yamlLoc-DPq-xUM4.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## @visulima/jsdoc-open-api [4.0.1](https://github.com/visulima/visulima/compare/%40visulima%2Fjsdoc-open-api%404.0.0...%40visulima%2Fjsdoc-open-api%404.0.1) (2026-08-17)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Dependencies
|
|
5
|
+
|
|
6
|
+
* **@visulima/fs:** upgraded to 6.0.1
|
|
7
|
+
|
|
1
8
|
## @visulima/jsdoc-open-api [4.0.0](https://github.com/visulima/visulima/compare/%40visulima%2Fjsdoc-open-api%403.0.11...%40visulima%2Fjsdoc-open-api%404.0.0) (2026-08-08)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{default as m}from"../../packem_shared/generateCommand-
|
|
1
|
+
import{default as m}from"../../packem_shared/generateCommand-C8UiAcbb.js";import{default as t}from"../../packem_shared/initCommand-Qkr6cX4d.js";export{m as generateCommand,t as initCommand};
|
package/dist/cli/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{default as m}from"../packem_shared/generateCommand-
|
|
1
|
+
import{default as m}from"../packem_shared/generateCommand-UX5Dt0_V.js";import{default as t}from"../packem_shared/initCommand-DyN1TM7N.js";export{m as generateCommand,t as initCommand};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
import { Block } from 'comment-parser';
|
|
2
|
-
import 'buffer';
|
|
3
|
-
import 'http';
|
|
4
|
-
import 'https';
|
|
5
|
-
import 'inspector';
|
|
6
|
-
import 'net';
|
|
7
|
-
import 'url';
|
|
8
|
-
import 'vm';
|
|
9
2
|
interface BaseDefinition {
|
|
10
3
|
components?: ComponentsObject;
|
|
11
4
|
externalDocs?: ExternalDocumentationObject;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{default as a}from"./packem_shared/jsDocumentCommentsToOpenApi-
|
|
1
|
+
import{default as a}from"./packem_shared/jsDocumentCommentsToOpenApi-DAGZljgo.js";import{default as r}from"./packem_shared/DEFAULT_OPTIONS-QnOdktWv.js";import{default as l,parseFileMulti as m}from"./packem_shared/parseFile-D-YG728l.js";import{default as s}from"./packem_shared/SpecBuilder-CuS4pzgn.js";import{default as d}from"./packem_shared/swaggerJsDocumentCommentsToOpenApi-B3WXfu-w.js";import{default as n}from"./packem_shared/loadDefinition-CTfgPhtU.js";import{default as g}from"./packem_shared/yamlLoc-B-xW0eUp.js";import{default as D}from"./packem_shared/validate-BomABpjM.js";import{default as T}from"./packem_shared/SwaggerCompilerPlugin-CaTRl2dP.js";export{r as DEFAULT_OPTIONS,s as SpecBuilder,T as SwaggerCompilerPlugin,a as jsDocumentCommentsToOpenApi,n as loadDefinition,l as parseFile,m as parseFileMulti,d as swaggerJsDocumentCommentsToOpenApi,D as validate,g as yamlLoc};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const p=new Set(["__proto__","constructor","prototype"]),_=(o,t)=>{Object.keys(t).forEach(s=>{p.has(s)||(o[s]===void 0?o[s]={...t[s]}:Object.keys(t[s]).forEach(r=>{p.has(r)||(o[s][r]={...o[s][r],...t[s][r]})}))})},n=new Set(["__proto__","constructor","prototype"]);class E{components;externalDocs;info;openapi;paths;security;servers;tags;constructor(t){this.openapi=t.openapi,this.info=t.info,this.paths=t.paths??{},t.servers&&(this.servers=t.servers),t.components&&(this.components=t.components),t.security&&(this.security=t.security),t.tags&&(this.tags=t.tags),t.externalDocs&&(this.externalDocs=t.externalDocs)}addData(t){t.forEach(s=>{const{components:r,paths:h,...e}=s;_(this,{components:r??{},paths:h??{}}),Object.entries(e).forEach(([c,a])=>{n.has(c)||(this[c]=a)})})}}export{E as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{mkdir as c,writeFile as f}from"node:fs/promises";import{dirname as m}from"node:path";import{collect as p}from"@visulima/fs";import{D as u}from"./constants-CdEv9ZcD.js";import d from"./jsDocumentCommentsToOpenApi-DAGZljgo.js";import{parseFileMulti as w}from"./parseFile-D-YG728l.js";import v from"./SpecBuilder-CuS4pzgn.js";import y from"./swaggerJsDocumentCommentsToOpenApi-B3WXfu-w.js";import b from"./validate-BomABpjM.js";const S=[d,y],D=r=>r instanceof Error?r:new Error(String(r));class F{assetsPath;ignore;silent;sources;swaggerDefinition;verbose;constructor(i,a,e,s){this.assetsPath=i,this.swaggerDefinition=e,this.sources=a,this.verbose=s.verbose??!1,this.silent=s.silent??!1,this.ignore=s.ignore??[]}apply(i){const a=new Set([...u,...this.ignore]);i.hooks.make.tapAsync("SwaggerCompilerPlugin",async(e,s)=>{this.log("Build paused, switching to swagger build");const o=new v(this.swaggerDefinition);try{for(const t of this.sources){const l=await p(t,{extensions:[".js",".cjs",".mjs",".ts",".tsx",".jsx",".yaml",".yml"],includeDirs:!1,skip:[...a]});this.verbose&&(this.log(`Found ${String(l.length)} files in ${t}`),this.log(JSON.stringify(l))),l.forEach(g=>{this.verbose&&this.log(`Parsing file ${g}`),o.addData(w(g,S,this.verbose).map(h=>h.spec))})}this.verbose&&(this.log("Validating swagger spec"),this.log(JSON.stringify(o,void 0,2))),await b(structuredClone(o));const{assetsPath:n}=this;await c(m(n),{recursive:!0}),await f(n,JSON.stringify(o,void 0,2)),this.verbose&&this.log(`Written swagger spec to "${this.assetsPath}" file`)}catch(n){const t=D(n);Array.isArray(e.errors)&&e.errors.push(t),s(t);return}this.log("switching back to normal build"),s()})}log(i){this.silent||console.log(i)}}export{F as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const s=(r,i)=>{if(Array.isArray(r))return[...r,...i]};export{s as c};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{watch as v}from"node:fs";import{resolve as f}from"node:path";import l,{exit as m}from"node:process";import g from"./generateCommand-UX5Dt0_V.js";const y=200,s=n=>{console.error(n)},S=async(n,c,a)=>{let t=!1,e=!1;const i=async()=>{if(t){e=!0;return}t=!0;try{await g(n,c,a)}catch(r){s(r)}finally{t=!1,e&&(e=!1,i().catch(s))}},h=f(a.output??"swagger.json");let o;const d=()=>{o&&clearTimeout(o),o=setTimeout(()=>{o=void 0,i().catch(s)},y)},w=c.map(r=>v(r,{recursive:!0},(T,u)=>{u!==null&&f(r,u)===h||d()})),p=()=>{o&&clearTimeout(o),w.forEach(r=>{r.close()}),m(0)};l.once("SIGINT",p),l.once("SIGTERM",p),await i(),console.log("Watching for changes... (press Ctrl+C to exit)")},E=(n,c="generate",a=".openapirc.js")=>{n.command(c).description("Generates OpenAPI (Swagger) documentation from JSDoc's").usage("[options] <path ...>").argument("[path ...]","Paths to files or directories to parse").option("-c, --config [.openapirc.js]","@visulima/jsdoc-open-api config file path.").option("-d, --definition [definition.yaml]","Base OpenAPI definition file (YAML/JSON) to seed info/servers/components.").option("-o, --output [swaggerSpec.json]",'Output swagger specification. Use "-" to write to stdout, or a .yaml/.yml path for YAML output.').option("-w, --watch","Re-generate the specification whenever a watched path changes.").option("-v, --verbose","Verbose output.").option("--very-verbose","Very verbose output.").action(async(t,e)=>{try{if(e.watch){await S(a,t,e);return}await g(a,t,e)}catch(i){s(i),m(1)}})};export{E as default};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{mkdir as b,writeFile as h,stat as D,realpath as O}from"node:fs/promises";import{dirname as T,extname as E,normalize as U}from"node:path";import{stdout as _}from"node:process";import{pathToFileURL as $}from"node:url";import{collect as F}from"@visulima/fs";import{stringify as j}from"@visulima/yaml";import{MultiBar as C,Presets as L}from"cli-progress";import{D as N}from"./constants-CdEv9ZcD.js";import x from"./jsDocumentCommentsToOpenApi-DAGZljgo.js";import{parseFileMulti as d}from"./parseFile-D-YG728l.js";import k from"./SpecBuilder-CuS4pzgn.js";import R from"./swaggerJsDocumentCommentsToOpenApi-B3WXfu-w.js";import A from"./loadDefinition-CTfgPhtU.js";import M from"./validate-BomABpjM.js";const P=new Set([".yaml",".yml"]),p="-",g=[x,R],V=async r=>{try{let e=await import($(U(r)).href);return e?.default&&(e=e.default),e}catch(e){if(e?.code==="ERR_MODULE_NOT_FOUND"||e?.code==="MODULE_NOT_FOUND"||e?.code==="ERR_LOAD_URL")throw new Error(`No config file found, on: ${r}
|
|
2
|
+
`,{cause:e});const o=e instanceof Error?e.message:String(e);throw new Error(`Failed to load config file "${r}": ${o}`,{cause:e})}},z=async(r,e,o)=>{const t=await V(o.config??r),i=o.definition??t.definition;let{swaggerDefinition:n}=t;if(i&&(n={...A(i),...n}),n===null||typeof n!="object")throw new TypeError(`Invalid config "${o.config??r}": missing "swaggerDefinition" object. Provide it in the config or pass a base definition file via -d/--definition.`);const f=o.output===p?void 0:new C({clearOnComplete:!1,format:"{value}/{total} | {bar} | {filename}",hideCursor:!0},L.shades_grey),s=new k(n),w=new Set([...N,...t.exclude??[]]);try{for(const m of e){const y=(await D(m)).isDirectory(),a=await O(m);if(!y){s.addData(d(a,g,o.verbose).map(l=>l.spec));continue}const c=await F(a,{extensions:t.extensions??[".js",".cjs",".mjs",".ts",".tsx",".jsx",".yaml",".yml"],followSymlinks:t.followSymlinks??!1,match:t.include,skip:[...w]});(o.verbose??o.veryVerbose)&&console.log(`
|
|
3
|
+
Found ${String(c.length)} files in ${a}`),o.veryVerbose&&console.log(c);const v=f?.create(c.length,0);c.forEach(l=>{o.verbose&&console.log(`Parsing file ${l}`),v?.increment(1,{filename:a}),s.addData(d(l,g,o.verbose).map(S=>S.spec))})}o.verbose&&console.log("Validating swagger spec"),o.veryVerbose&&console.log(JSON.stringify(s,void 0,2)),await M(structuredClone(s))}finally{f?.stop()}return s},u=(r,e)=>P.has(E(e))?j(structuredClone(r)):JSON.stringify(r,void 0,2),te=async(r,e,o)=>{const t=await z(r,e,o),i=o.output??"swagger.json";if(i===p){_.write(`${u(t,"swagger.json")}
|
|
4
|
+
`);return}o.verbose&&console.log(`Written swagger spec to "${i}" file`),await b(T(i),{recursive:!0}),await h(i,u(t,i)),console.log(`
|
|
5
|
+
Swagger specification is ready, check the "${i}" file.`)};export{te as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
import{existsSync as n,realpathSync as c,writeFileSync as l}from"node:fs";import{findUpSync as i,readJsonSync as p}from"@visulima/fs";const j=(e,a=process.cwd())=>{if(n(e))throw new Error("Config file already exists");const s=i("package.json",{cwd:c(a)});let o="module.exports =";if(s){const t=p(s);console.info(`Found package.json at "${s}"`),t.type==="module"&&(console.info("Found package.json with type: module, using ES6 as export for the config file"),o="export default")}else console.info("No package.json found");l(e,`${o} {
|
|
2
2
|
exclude: [
|
|
3
3
|
'coverage/**',
|
|
4
4
|
'.github/**',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{exit as e}from"node:process";import a from"./initCommand-DyN1TM7N.js";const p=(i,o="init",r="Inits a pre-configured @visulima/jsdoc-open-api config file.",n=".openapirc.js")=>{i.command(o).description(r).action(()=>{try{a(n)}catch(t){console.error(t),e(1)}})};export{p as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{parse as l}from"comment-parser";import{mergeWith as y}from"es-toolkit";import{c as f}from"./customizer-BAodMCcL.js";const b=/\[\]$/,T=/^- /u,h=/Param$/u,$=/^(GET|PUT|POST|DELETE|OPTIONS|HEAD|PATCH|TRACE) \/.*$/,E=r=>{r.security&&(r.security=Object.keys(r.security).map(o=>({[o]:r.security[o]})))},w=new Set(["array","boolean","integer","number","object","string"]),m={binary:"string",byte:"string",date:"string","date-time":"string",double:"number",float:"number",int32:"integer",int64:"integer",password:"string"},x=r=>{const o=r.type,c=o.endsWith("[]"),e=o.replace(b,""),a=w.has(e),t=Object.keys(m).includes(e);let s;if(r.default)switch(e){case"double":case"float":case"number":{s=Number.parseFloat(r.default);break}case"int32":case"int64":case"integer":{s=Number.parseInt(r.default,10);break}default:{s=r.default;break}}let n;a?n={default:s,type:e}:t?n={default:s,format:e,type:m[e]}:n={$ref:`#/components/schemas/${e}`};let i=c?{items:{...n},type:"array"}:{...n};e===""&&(i=void 0);let p=r.description.trim().replace(T,"");return p===""&&(p=void 0),{description:p,name:r.name,rawType:o,required:!r.optional,schema:i}},P=(r,o)=>r.map(c=>{const e=x(c);let a="";switch(e.name&&(a+=e.name),e.description&&(a+=` ${e.description.trim()}`),c.tag){case"bodyComponent":return{requestBody:{$ref:`#/components/requestBodies/${e.rawType}`}};case"bodyContent":return{requestBody:{content:{[e.name.replaceAll(String.raw`*\/*`,"*/*")]:{schema:e.schema}}}};case"bodyDescription":return{requestBody:{description:a}};case"bodyExample":{const t=e.name.split("."),s=t.at(-1);return{requestBody:{content:{[t.slice(0,-1).join(".")]:{examples:{[s]:{$ref:`#/components/examples/${e.rawType}`}}}}}}}case"bodyRequired":return{requestBody:{required:!0}};case"callback":return{callbacks:{[e.name]:{$ref:`#/components/callbacks/${e.rawType}`}}};case"cookieParam":case"headerParam":case"pathParam":case"queryParam":return{parameters:[{description:e.description,in:c.tag.replace(h,""),name:e.name,required:e.required,schema:e.schema}]};case"deprecated":return{deprecated:!0};case"description":case"operationId":case"summary":return{[c.tag]:a};case"externalDocs":return{externalDocs:{description:e.description,url:e.name}};case"paramComponent":return{parameters:[{$ref:`#/components/parameters/${e.rawType}`}]};case"response":return{responses:{[e.name]:{description:e.description}}};case"responseComponent":return{responses:{[e.name]:{$ref:`#/components/responses/${e.rawType}`}}};case"responseContent":{const t=e.name.split("."),s=t[0],n=t.slice(1).join(".");return{responses:{[s]:{content:{[n]:{schema:e.schema}}}}}}case"responseExample":{const t=e.name.split("."),s=t[0],n=t.at(-1),i=t.slice(1,-1).join(".");return{responses:{[s]:{content:{[i]:{examples:{[n]:{$ref:`#/components/examples/${e.rawType}`}}}}}}}}case"responseHeader":{const[t,s]=e.name.split(".");return{responses:{[t]:{headers:{[s]:{description:e.description,schema:e.schema}}}}}}case"responseHeaderComponent":{const[t,s]=e.name.split(".");return{responses:{[t]:{headers:{[s]:{$ref:`#/components/headers/${e.rawType}`}}}}}}case"responseLink":{const[t,s]=e.name.split(".");return{responses:{[t]:{links:{[s]:{$ref:`#/components/links/${e.rawType}`}}}}}}case"security":{const[t,s]=e.name.split(".");let n=[];return s&&(n=[s]),{security:{[t]:n}}}case"server":return{servers:[{description:e.description,url:e.name}]};case"tag":return{tags:[a]};default:return{}}}),A=(r,o,c)=>(c??l(r,{spacing:"preserve"})).filter(a=>$.test(a.description.trim())).map(a=>{const t=a.tags.length+1,s={};for(const d of P(a.tags))y(s,d,f);E(s);const[n,i]=a.description.split(" "),p={[i.trim()]:{[n.toLowerCase().trim()]:{...s}}},u=JSON.parse(JSON.stringify({paths:p}));return{loc:t,spec:u}});export{A as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFileSync as n}from"node:fs";import o from"node:path";import{parse as i}from"@visulima/yaml";const s=r=>{const e=o.extname(r);if(e!==".yaml"&&e!==".yml"&&e!==".json")throw new Error("OpenAPI definition path must be YAML or JSON.");const t=n(r,{encoding:"utf8"});return e===".yaml"||e===".yml"?i(t):JSON.parse(t)};export{s as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFileSync as p}from"node:fs";import l from"node:path";import{parse as u}from"@visulima/yaml";import{parse as y}from"comment-parser";import x from"./yamlLoc-B-xW0eUp.js";const i=new Set(["components","externalDocs","info","openapi","paths","security","servers","tags"]);class d extends Error{filePath}const m=new Set([".yaml",".yml"]),f=(t,s)=>{const r=u(s);if(r===null||typeof r!="object")return[];const o=Object.keys(r).filter(e=>!i.has(e));if(o.length>0){const e=new d(`Unexpected keys: ${o.join(", ")}`);throw e.filePath=t,e}return Object.keys(r).some(e=>i.has(e))?[{loc:x(s),spec:r}]:[]},j=(t,s,r)=>{const o=p(t,{encoding:"utf8"}),e=l.extname(t);if(m.has(e))return f(t,o);try{return s(o,r)}catch(n){throw n.filePath=t,n}},F=(t,s,r)=>{const o=p(t,{encoding:"utf8"}),e=l.extname(t);if(m.has(e))return f(t,o);const n=y(o,{spacing:"preserve"}),c=[];for(const h of s)try{c.push(...h(o,r,n))}catch(a){throw a.filePath=t,a}return c};export{j as default,F as parseFileMulti};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import{parseDocument as g}from"@visulima/yaml";import{parse as p}from"comment-parser";import{mergeWith as f}from"es-toolkit";import{c as d}from"./customizer-BAodMCcL.js";const u=(n,t)=>{if(t===null)return n},h=(n,t)=>{const s=f({},n??{},u);return f(s,t??{},u)},v=n=>Object.keys(n).map(t=>n[t]).every(t=>typeof t=="object"&&Object.keys(t).every(s=>!(s in t))),l=(n,t)=>t.some(s=>n.name===s.name),S=n=>{switch(n.tag){case"asyncapi":return"v4";case"openapi":return"v3";case"swagger":return"v2";default:return"v2"}},E=(n,t,s)=>{if(s==="x-webhooks"&&(n[s]=t[s]),s.startsWith("x-"))return;if(["components","consumes","produces","paths","schemas","securityDefinitions","responses","parameters","definitions","channels"].includes(s)){const e=t[s];e!=null&&(n[s]??={},Object.keys(e).forEach(i=>{n[s][i]=h(n[s][i],e[i])}))}else if(s==="tags"){const{tags:e}=t;Array.isArray(e)?e.forEach(i=>{l(i,n.tags)||n.tags.push(i)}):l(e,n.tags)||n.tags.push(e)}else if(s==="security"){const{security:e}=t;n.security=e}else s.startsWith("/")&&(n.paths[s]=h(n.paths[s],t[s]))},D={v2:["paths","definitions","responses","parameters","securityDefinitions"],v3:["paths","definitions","responses","parameters","securityDefinitions","components"],v4:["components","channels"]},W=(n,t)=>n.map(s=>{const m=s.description!==""||s.name.startsWith("/")||s.name.endsWith(":");if((s.tag==="openapi"||s.tag==="swagger"||s.tag==="asyncapi")&&m){let e=s.description;(s.name.startsWith("/")||s.name.endsWith(":"))&&(e=e.trim()===""?s.name:`${s.name}
|
|
2
|
+
${e}`);const i=g(e);if(i.errors.length>0){i.errors.forEach(c=>{c.annotation=e});let o="Error parsing YAML in @openapi spec:";throw o+=t?i.errors.map(c=>`${c.toString()}
|
|
3
|
+
Imbedded within:
|
|
4
|
+
\`\`\`
|
|
5
|
+
${c.annotation?.replaceAll(`
|
|
6
|
+
`,`
|
|
7
|
+
`)}
|
|
8
|
+
\`\`\``).join(`
|
|
9
|
+
`):i.errors.map(c=>c.toString()).join(`
|
|
10
|
+
`),new Error(o)}const r=i.toJSON(),a={tags:[]};return D[S(s)].forEach(o=>{a[o]=a[o]??{}}),Object.keys(r).forEach(o=>{E(a,r,o)}),a}return{}}),A=new Set(["asyncapi","openapi","swagger"]),P=(n,t,s)=>(s??p(n,{spacing:"preserve"})).filter(e=>e.tags.some(i=>A.has(i.tag))).map(e=>{const i=e.tags.length+1,r={};for(const o of W(e.tags,t))f(r,o,d);["definitions","responses","parameters","securityDefinitions","components","tags"].forEach(o=>{r[o]!==void 0&&v(r[o])&&delete r[o]});const a=JSON.parse(JSON.stringify(r));return{loc:i,spec:a}});export{P as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import t from"@apidevtools/swagger-parser";const r=async a=>{await t.validate(a)};export{r as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const r=/\r\n|\r|\n/u,s=/^\s*(#\s*(?:\S.*)?)?$/u,i=e=>e.split(r).filter(t=>s.test(t)?!1:t.trim().length>0).length;export{i as default};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@visulima/jsdoc-open-api",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "Generates swagger doc based on JSDoc.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api",
|
|
@@ -90,15 +90,15 @@
|
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
92
|
"@apidevtools/swagger-parser": "^12.1.0",
|
|
93
|
-
"@visulima/fs": "6.0.
|
|
93
|
+
"@visulima/fs": "6.0.1",
|
|
94
94
|
"@visulima/yaml": "1.0.0",
|
|
95
|
-
"comment-parser": "1.4.
|
|
96
|
-
"es-toolkit": "^1.
|
|
95
|
+
"comment-parser": "1.4.8",
|
|
96
|
+
"es-toolkit": "^1.50.0"
|
|
97
97
|
},
|
|
98
98
|
"optionalDependencies": {
|
|
99
99
|
"cli-progress": "^3.12.0",
|
|
100
100
|
"commander": "^15.0.0",
|
|
101
|
-
"webpack": "^5.
|
|
101
|
+
"webpack": "^5.109.2"
|
|
102
102
|
},
|
|
103
103
|
"engines": {
|
|
104
104
|
"node": "^22.14.0 || >=24.10.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const c=new Set(["__proto__","constructor","prototype"]),h=(o,s)=>{Object.keys(s).forEach(t=>{c.has(t)||(o[t]===void 0?o[t]={...s[t]}:Object.keys(s[t]).forEach(e=>{c.has(e)||(o[t][e]={...o[t][e],...s[t][e]})}))})},i=new Set(["__proto__","constructor","prototype"]);class u{components;externalDocs;info;openapi;paths;security;servers;tags;constructor(s){this.openapi=s.openapi,this.info=s.info,this.paths=s.paths??{},s.servers&&(this.servers=s.servers),s.components&&(this.components=s.components),s.security&&(this.security=s.security),s.tags&&(this.tags=s.tags),s.externalDocs&&(this.externalDocs=s.externalDocs)}addData(s){s.forEach(t=>{const{components:e,paths:n,...a}=t;h(this,{components:e??{},paths:n??{}}),Object.entries(a).forEach(([r,p])=>{i.has(r)||(this[r]=p)})})}}export{u as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{mkdir as c,writeFile as m}from"node:fs/promises";import{dirname as f}from"node:path";import{collect as p}from"@visulima/fs";import{D as u}from"./constants-CdEv9ZcD.js";import w from"./jsDocumentCommentsToOpenApi-CuIbZppP.js";import{parseFileMulti as d}from"./parseFile-Dtv-2qq3.js";import b from"./SpecBuilder-Vbq42UbW.js";import v from"./swaggerJsDocumentCommentsToOpenApi-CWeEk_r1.js";import y from"./validate-9Rwe2A3r.js";const D=[w,v],S=r=>r instanceof Error?r:new Error(String(r));class J{assetsPath;ignore;silent;sources;swaggerDefinition;verbose;constructor(t,n,o,s){this.assetsPath=t,this.swaggerDefinition=o,this.sources=n,this.verbose=s.verbose??!1,this.silent=s.silent??!1,this.ignore=s.ignore??[]}apply(t){const n=new Set([...u,...this.ignore]);t.hooks.make.tapAsync("SwaggerCompilerPlugin",async(o,s)=>{this.log("Build paused, switching to swagger build");const e=new b(this.swaggerDefinition);try{for(const i of this.sources){const l=await p(i,{extensions:[".js",".cjs",".mjs",".ts",".tsx",".jsx",".yaml",".yml"],includeDirs:!1,skip:[...n]});this.verbose&&(this.log(`Found ${String(l.length)} files in ${i}`),this.log(JSON.stringify(l))),l.forEach(g=>{this.verbose&&this.log(`Parsing file ${g}`),e.addData(d(g,D,this.verbose).map(h=>h.spec))})}this.verbose&&(this.log("Validating swagger spec"),this.log(JSON.stringify(e,void 0,2))),await y(structuredClone(e));const{assetsPath:a}=this;await c(f(a),{recursive:!0}),await m(a,JSON.stringify(e,void 0,2)),this.verbose&&this.log(`Written swagger spec to "${this.assetsPath}" file`)}catch(a){const i=S(a);Array.isArray(o.errors)&&o.errors.push(i),s(i);return}this.log("switching back to normal build"),s()})}log(t){this.silent||console.log(t)}}export{J as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const a=(r,t)=>{if(Array.isArray(r))return[...r,...t]};export{a as u};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import{mkdir as b,writeFile as D,stat as E,realpath as O}from"node:fs/promises";import{dirname as S,extname as $,normalize as _}from"node:path";import{stdout as j}from"node:process";import{pathToFileURL as F}from"node:url";import{collect as U}from"@visulima/fs";import{stringify as x}from"@visulima/yaml";import{MultiBar as L,Presets as N}from"cli-progress";import{D as R}from"./constants-CdEv9ZcD.js";import k from"./jsDocumentCommentsToOpenApi-CuIbZppP.js";import{parseFileMulti as g}from"./parseFile-Dtv-2qq3.js";import C from"./SpecBuilder-Vbq42UbW.js";import M from"./swaggerJsDocumentCommentsToOpenApi-CWeEk_r1.js";import T from"./loadDefinition-Cfj2-XHF.js";import V from"./validate-9Rwe2A3r.js";const A=new Set([".yaml",".yml"]),u="-",d=[k,M],J=async t=>{try{let e=await import(F(_(t)).href);return e?.default&&(e=e.default),e}catch(e){if(e?.code==="ERR_MODULE_NOT_FOUND"||e?.code==="MODULE_NOT_FOUND"||e?.code==="ERR_LOAD_URL")throw new Error(`No config file found, on: ${t}
|
|
2
|
-
`,{cause:e});const o=e instanceof Error?e.message:String(e);throw new Error(`Failed to load config file "${t}": ${o}`,{cause:e})}},P=async(t,e,o)=>{const r=await J(o.config??t),i=o.definition??r.definition;let{swaggerDefinition:n}=r;if(i&&(n={...T(i),...n}),n===null||typeof n!="object")throw new TypeError(`Invalid config "${o.config??t}": missing "swaggerDefinition" object. Provide it in the config or pass a base definition file via -d/--definition.`);const f=o.output===u?void 0:new L({clearOnComplete:!1,format:"{value}/{total} | {bar} | {filename}",hideCursor:!0},N.shades_grey),s=new C(n),w=new Set([...R,...r.exclude??[]]);try{for(const m of e){const y=(await E(m)).isDirectory(),a=await O(m);if(!y){s.addData(g(a,d,o.verbose).map(c=>c.spec));continue}const l=await U(a,{extensions:r.extensions??[".js",".cjs",".mjs",".ts",".tsx",".jsx",".yaml",".yml"],followSymlinks:r.followSymlinks??!1,match:r.include,skip:[...w]});(o.verbose??o.veryVerbose)&&console.log(`
|
|
3
|
-
Found ${String(l.length)} files in ${a}`),o.veryVerbose&&console.log(l);const h=f?.create(l.length,0);l.forEach(c=>{o.verbose&&console.log(`Parsing file ${c}`),h?.increment(1,{filename:a}),s.addData(g(c,d,o.verbose).map(v=>v.spec))})}o.verbose&&console.log("Validating swagger spec"),o.veryVerbose&&console.log(JSON.stringify(s,void 0,2)),await V(structuredClone(s))}finally{f?.stop()}return s},p=(t,e)=>A.has($(e))?x(structuredClone(t)):JSON.stringify(t,void 0,2),te=async(t,e,o)=>{const r=await P(t,e,o),i=o.output??"swagger.json";if(i===u){j.write(`${p(r,"swagger.json")}
|
|
4
|
-
`);return}o.verbose&&console.log(`Written swagger spec to "${i}" file`),await b(S(i),{recursive:!0}),await D(i,p(r,i)),console.log(`
|
|
5
|
-
Swagger specification is ready, check the "${i}" file.`)};export{te as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{watch as y}from"node:fs";import{resolve as f}from"node:path";import l,{exit as h}from"node:process";import m from"./generateCommand-C3riX6Is.js";const v=200,c=i=>{console.error(i)},S=async(i,s,r)=>{let t=!1,e=!1;const n=async()=>{if(t){e=!0;return}t=!0;try{await m(i,s,r)}catch(a){c(a)}finally{t=!1,e&&(e=!1,n().catch(c))}},g=f(r.output??"swagger.json");let o;const w=()=>{o&&clearTimeout(o),o=setTimeout(()=>{o=void 0,n().catch(c)},v)},d=s.map(a=>y(a,{recursive:!0},(b,u)=>{u!==null&&f(a,u)===g||w()})),p=()=>{o&&clearTimeout(o),d.forEach(a=>{a.close()}),h(0)};l.once("SIGINT",p),l.once("SIGTERM",p),await n(),console.log("Watching for changes... (press Ctrl+C to exit)")},G=(i,s="generate",r=".openapirc.js")=>{i.command(s).description("Generates OpenAPI (Swagger) documentation from JSDoc's").usage("[options] <path ...>").argument("[path ...]","Paths to files or directories to parse").option("-c, --config [.openapirc.js]","@visulima/jsdoc-open-api config file path.").option("-d, --definition [definition.yaml]","Base OpenAPI definition file (YAML/JSON) to seed info/servers/components.").option("-o, --output [swaggerSpec.json]",'Output swagger specification. Use "-" to write to stdout, or a .yaml/.yml path for YAML output.').option("-w, --watch","Re-generate the specification whenever a watched path changes.").option("-v, --verbose","Verbose output.").option("--very-verbose","Very verbose output.").action(async(t,e)=>{try{if(e.watch){await S(r,t,e);return}await m(r,t,e)}catch(n){c(n),h(1)}})};export{G as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{exit as c}from"node:process";import e from"./initCommand-Ca1hGdYS.js";const s=(o,i="init",r="Inits a pre-configured @visulima/jsdoc-open-api config file.",n=".openapirc.js")=>{o.command(i).description(r).action(()=>{try{e(n)}catch(t){console.error(t),c(1)}})};export{s as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{parse as d}from"comment-parser";import{mergeWith as l}from"es-toolkit";import{u as y}from"./customizer-BXFVpImq.js";const f=/\[\]$/,b=/^- /u,$=/Param$/u,g=/^(GET|PUT|POST|DELETE|OPTIONS|HEAD|PATCH|TRACE) \/.*$/,h=t=>{t.security&&(t.security=Object.keys(t.security).map(o=>({[o]:t.security[o]})))},T=new Set(["array","boolean","integer","number","object","string"]),m={binary:"string",byte:"string",date:"string","date-time":"string",double:"number",float:"number",int32:"integer",int64:"integer",password:"string"},w=t=>{const o=t.type,c=o.endsWith("[]"),e=o.replace(f,""),a=T.has(e),s=Object.keys(m).includes(e);let r;if(t.default)switch(e){case"double":case"float":case"number":{r=Number.parseFloat(t.default);break}case"int32":case"int64":case"integer":{r=Number.parseInt(t.default,10);break}default:{r=t.default;break}}let n;a?n={default:r,type:e}:s?n={default:r,format:e,type:m[e]}:n={$ref:`#/components/schemas/${e}`};let i=c?{items:{...n},type:"array"}:{...n};e===""&&(i=void 0);let p=t.description.trim().replace(b,"");return p===""&&(p=void 0),{description:p,name:t.name,rawType:o,required:!t.optional,schema:i}},k=(t,o)=>t.map(c=>{const e=w(c);let a="";switch(e.name&&(a+=e.name),e.description&&(a+=` ${e.description.trim()}`),c.tag){case"bodyComponent":return{requestBody:{$ref:`#/components/requestBodies/${e.rawType}`}};case"bodyContent":return{requestBody:{content:{[e.name.replaceAll(String.raw`*\/*`,"*/*")]:{schema:e.schema}}}};case"bodyDescription":return{requestBody:{description:a}};case"bodyExample":{const s=e.name.split("."),r=s.at(-1);return{requestBody:{content:{[s.slice(0,-1).join(".")]:{examples:{[r]:{$ref:`#/components/examples/${e.rawType}`}}}}}}}case"bodyRequired":return{requestBody:{required:!0}};case"callback":return{callbacks:{[e.name]:{$ref:`#/components/callbacks/${e.rawType}`}}};case"cookieParam":case"headerParam":case"pathParam":case"queryParam":return{parameters:[{description:e.description,in:c.tag.replace($,""),name:e.name,required:e.required,schema:e.schema}]};case"deprecated":return{deprecated:!0};case"description":case"operationId":case"summary":return{[c.tag]:a};case"externalDocs":return{externalDocs:{description:e.description,url:e.name}};case"paramComponent":return{parameters:[{$ref:`#/components/parameters/${e.rawType}`}]};case"response":return{responses:{[e.name]:{description:e.description}}};case"responseComponent":return{responses:{[e.name]:{$ref:`#/components/responses/${e.rawType}`}}};case"responseContent":{const s=e.name.split("."),r=s[0],n=s.slice(1).join(".");return{responses:{[r]:{content:{[n]:{schema:e.schema}}}}}}case"responseExample":{const s=e.name.split("."),r=s[0],n=s.at(-1),i=s.slice(1,-1).join(".");return{responses:{[r]:{content:{[i]:{examples:{[n]:{$ref:`#/components/examples/${e.rawType}`}}}}}}}}case"responseHeader":{const[s,r]=e.name.split(".");return{responses:{[s]:{headers:{[r]:{description:e.description,schema:e.schema}}}}}}case"responseHeaderComponent":{const[s,r]=e.name.split(".");return{responses:{[s]:{headers:{[r]:{$ref:`#/components/headers/${e.rawType}`}}}}}}case"responseLink":{const[s,r]=e.name.split(".");return{responses:{[s]:{links:{[r]:{$ref:`#/components/links/${e.rawType}`}}}}}}case"security":{const[s,r]=e.name.split(".");let n=[];return r&&(n=[r]),{security:{[s]:n}}}case"server":return{servers:[{description:e.description,url:e.name}]};case"tag":return{tags:[a]};default:return{}}}),E=(t,o,c)=>(c??d(t,{spacing:"preserve"})).filter(e=>g.test(e.description.trim())).map(e=>{const a=e.tags.length+1,s={};for(const u of k(e.tags))l(s,u,y);h(s);const[r,n]=e.description.split(" "),i={[n.trim()]:{[r.toLowerCase().trim()]:{...s}}},p=JSON.parse(JSON.stringify({paths:i}));return{loc:a,spec:p}});export{E as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{readFileSync as n}from"node:fs";import t from"node:path";import{parse as m}from"@visulima/yaml";const s=o=>{const r=t.extname(o);if(r!==".yaml"&&r!==".yml"&&r!==".json")throw new Error("OpenAPI definition path must be YAML or JSON.");const e=n(o,{encoding:"utf8"});return r===".yaml"||r===".yml"?m(e):JSON.parse(e)};export{s as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{readFileSync as f}from"node:fs";import p from"node:path";import{parse as u}from"@visulima/yaml";import{parse as y}from"comment-parser";import d from"./yamlLoc-DPq-xUM4.js";const i=new Set(["components","externalDocs","info","openapi","paths","security","servers","tags"]);class w extends Error{filePath}const l=new Set([".yaml",".yml"]),m=(t,s)=>{const r=u(s);if(r===null||typeof r!="object")return[];const o=Object.keys(r).filter(e=>!i.has(e));if(o.length>0){const e=new w(`Unexpected keys: ${o.join(", ")}`);throw e.filePath=t,e}return Object.keys(r).some(e=>i.has(e))?[{loc:d(s),spec:r}]:[]},k=(t,s,r)=>{const o=f(t,{encoding:"utf8"}),e=p.extname(t);if(l.has(e))return m(t,o);try{return s(o,r)}catch(n){throw n.filePath=t,n}},O=(t,s,r)=>{const o=f(t,{encoding:"utf8"}),e=p.extname(t);if(l.has(e))return m(t,o);const n=y(o,{spacing:"preserve"}),c=[];for(const h of s)try{c.push(...h(o,r,n))}catch(a){throw a.filePath=t,a}return c};export{k as default,O as parseFileMulti};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import{parseDocument as f}from"@visulima/yaml";import{parse as y}from"comment-parser";import{mergeWith as m}from"es-toolkit";import{u as l}from"./customizer-BXFVpImq.js";const g=(s,t)=>{if(t===null)return s},h=(s,t)=>{const e=m({},s??{},g);return m(e,t??{},g)},d=s=>Object.keys(s).map(t=>s[t]).every(t=>typeof t=="object"&&Object.keys(t).every(e=>!(e in t))),u=(s,t)=>t.some(e=>s.name===e.name),v=s=>{switch(s.tag){case"asyncapi":return"v4";case"openapi":return"v3";case"swagger":return"v2";default:return"v2"}},w=(s,t,e)=>{if(e==="x-webhooks"&&(s[e]=t[e]),!e.startsWith("x-"))if(["components","consumes","produces","paths","schemas","securityDefinitions","responses","parameters","definitions","channels"].includes(e)){const r=t[e];r!=null&&(s[e]??={},Object.keys(r).forEach(n=>{s[e][n]=h(s[e][n],r[n])}))}else if(e==="tags"){const{tags:r}=t;Array.isArray(r)?r.forEach(n=>{u(n,s.tags)||s.tags.push(n)}):u(r,s.tags)||s.tags.push(r)}else if(e==="security"){const{security:r}=t;s.security=r}else e.startsWith("/")&&(s.paths[e]=h(s.paths[e],t[e]))},E={v2:["paths","definitions","responses","parameters","securityDefinitions"],v3:["paths","definitions","responses","parameters","securityDefinitions","components"],v4:["components","channels"]},S=(s,t)=>s.map(e=>{const r=e.description!==""||e.name.startsWith("/")||e.name.endsWith(":");if((e.tag==="openapi"||e.tag==="swagger"||e.tag==="asyncapi")&&r){let n=e.description;(e.name.startsWith("/")||e.name.endsWith(":"))&&(n=n.trim()===""?e.name:`${e.name}
|
|
2
|
-
${n}`);const a=f(n);if(a.errors.length>0){a.errors.forEach(c=>{c.annotation=n});let i="Error parsing YAML in @openapi spec:";throw i+=t?a.errors.map(c=>`${c.toString()}
|
|
3
|
-
Imbedded within:
|
|
4
|
-
\`\`\`
|
|
5
|
-
${c.annotation?.replaceAll(`
|
|
6
|
-
`,`
|
|
7
|
-
`)}
|
|
8
|
-
\`\`\``).join(`
|
|
9
|
-
`):a.errors.map(c=>c.toString()).join(`
|
|
10
|
-
`),new Error(i)}const p=a.toJSON(),o={tags:[]};return E[v(e)].forEach(i=>{o[i]=o[i]??{}}),Object.keys(p).forEach(i=>{w(o,p,i)}),o}return{}}),b=new Set(["asyncapi","openapi","swagger"]),k=(s,t,e)=>(e??y(s,{spacing:"preserve"})).filter(r=>r.tags.some(n=>b.has(n.tag))).map(r=>{const n=r.tags.length+1,a={};for(const o of S(r.tags,t))m(a,o,l);["definitions","responses","parameters","securityDefinitions","components","tags"].forEach(o=>{a[o]!==void 0&&d(a[o])&&delete a[o]});const p=JSON.parse(JSON.stringify(a));return{loc:n,spec:p}});export{k as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import t from"@apidevtools/swagger-parser";const e=async a=>{await t.validate(a)};export{e as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const s=/\r\n|\r|\n/u,l=/^\s*(#\s*(?:\S.*)?)?$/u,n=e=>e.split(s).filter(t=>l.test(t)?!1:t.trim().length>0).length;export{n as default};
|