UNPKG

@visulima/cerebro

Version:

A delightful toolkit for building cross-runtime CLIs for Node.js, Deno, and Bun.

46 lines (41 loc) 6.63 kB
var S=Object.defineProperty;var f=(e,n)=>S(e,"name",{value:n,configurable:!0});import{createRequire as L}from"node:module";import G from"github-slugger";import{p as U}from"../packem_shared/index-DQ3pvLQH.js";import{g as F,a as M,b as W,c as z}from"../packem_shared/runtime-process-G-n-wOub.js";const N=L(import.meta.url),g=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,w=f(e=>{if(typeof g<"u"&&g.versions&&g.versions.node){const[n,t]=g.versions.node.split(".").map(Number);if(n>22||n===22&&t>=3||n===20&&t>=16)return g.getBuiltinModule(e)}return N(e)},"__cjs_getBuiltinModule"),{existsSync:E}=w("node:fs"),{readFile:T,mkdir:k,writeFile:B}=w("node:fs/promises"),{resolve:v,join:V,dirname:q}=w("node:path");var H=Object.defineProperty,d=f((e,n)=>H(e,"name",{value:n,configurable:!0}),"d");const I=new G,b=I.slug,J=d(e=>e.filter(Boolean),"compact"),K=d((e,n)=>{const t=new Set,a=[];for(const r of e){const i=n(r);t.has(i)||(t.add(i),a.push(r))}return a},"uniqBy"),D=d((e,n)=>{const t=(e.commandPath?[...e.commandPath,e.name]:[e.name]).join(" ");if(e.argument){const a=e.argument.name?.toUpperCase()??"ARG",r=e.argument.required?a:`[${a}]`;return`${n} ${t} ${r}`}return`${n} ${t}`},"formatCommandUsage"),Q=d((e,n)=>{if(!Array.isArray(e.env)||e.env.length===0)return;const t=e.env.filter(a=>!a.hidden);t.length>0&&n.push({content:t.map(a=>[a.name,a.description??""]),header:" Environment Variables "})},"addEnvironmentVariables"),X=d((e,n)=>{const t=[],a=(e.commandPath?[...e.commandPath,e.name]:[e.name]).join(" "),r=!!e.argument,i=!!e.options;if(t.push({content:`${n} ${a}${r?" [positional arguments]":""}${i?" [options]":""}`,header:" Usage "}),e.description&&t.push({content:e.description,header:" Description "}),e.argument&&t.push({header:"Command Positional Arguments",isArgument:!0,optionList:[e.argument]}),Array.isArray(e.options)&&e.options.length>0&&t.push({header:" Command Options ",optionList:e.options.filter(o=>typeof o=="object"&&o!==null&&(!("hidden"in o)||!o.hidden))}),Q(e,t),e.alias!==void 0&&e.alias.length>0){const o=Array.isArray(e.alias)?e.alias:[e.alias];t.splice(1,0,{content:o,header:"Alias(es)"})}return Array.isArray(e.examples)&&e.examples.length>0&&t.push({content:e.examples,header:"Examples"}),U(t)},"formatCommandHelp"),Y=d((e,n)=>{const t=e.description?.trim().split(` `)[0]??"",a=D(e,n),r=X(e,n);return J([`## \`${a}\``,t,`\`\`\` ${r.trim()} \`\`\``]).join(` `)},"renderCommand"),Z=d((e,n,t,a)=>{const r=`(${["--version","-V"].join("|")})`,i=W(),o=z();return`\`\`\`sh-session $ npm install -g ${n} $ ${e} COMMAND running command... $ ${e} ${r} ${n}/${t??"unknown"} ${i}-${o} node-v${a} $ ${e} --help [COMMAND] USAGE $ ${e} COMMAND ... \`\`\` `},"generateUsage"),R=d(async(e,n,t)=>{const a=await Promise.all(e.map(async i=>{const o=D(i,n);return`* [\`${o}\`](#${await b(o)})`})),r=e.map(i=>Y(i,n)).map(i=>`${i.trim()} `);return[...a,"",...r].join(` `).trim()},"generateCommands"),j=d(async(e,n)=>{const t=q(e);E(t)||await k(t,{recursive:!0}),await B(e,n,"utf8")},"writeFileWithDirectory"),ee=d(async(e,n,t,a)=>{const r=new Map;for(const o of e){const s=o.group??"__Other",l=r.get(s)??[];l.push(o),r.set(s,l)}const i=[...r.entries()].map(([o,s])=>o==="__Other"?["Other",s]:[o,s]);return await Promise.all(i.map(async([o,s])=>{const l=o.replaceAll(":","/"),$=V(".",n,`${l}.md`),p=`\`${t} ${o}\``,c=`${[p,"=".repeat(p.length),"",`Commands in the ${o} group.`,"",await R(s,t,a)].join(` `).trim()} `;a.dryRun||await j(v(M(),$),c)})),`${[`# Command Topics `,...i.map(([o])=>{const s=o.replaceAll(":","/");return`* [\`${t} ${o}\`](${n}/${s}.md)`})].join(` `).trim()} `},"generateMultiCommands"),A=d(e=>e.replaceAll(`\r `,` `).replaceAll("\r",` `),"normalizeLineEndings"),te=d(async e=>{const n=A(e);return(await Promise.all(n.split(` `).filter(t=>t.startsWith("# ")).map(t=>t.trim().slice(2)).map(async t=>`* [${t}](#${await b(t)})`))).join(` `)},"generateTableOfContents"),P=d(e=>e.replaceAll(/[.*+?^${}()|[\]\\]/g,String.raw`\$&`),"escapeRegex"),y=d((e,n,t)=>{const a=A(e),r=`<!-- ${n} -->`,i=`<!-- ${n}stop -->`;if(a.includes(r)&&a.includes(i)){const o=P(r),s=P(i),l=new RegExp(`${o}(.|\\n)*${s}`,"m");return a.replace(l,`${r} ${t} ${i}`)}return a.replace(r,`${r} ${t} ${i}`)},"replaceTag"),se={description:"Generate README documentation for CLI commands",execute:d(async({logger:e,options:n,runtime:t})=>{const a=t.getCliName(),r=t.getPackageName()??a,i=t.getPackageVersion(),o=F().node??"unknown",s={aliases:n?.aliases,dryRun:n?.dryRun,multi:n?.multi,nestedTopicsDepth:n?.nestedTopicsDepth,outputDir:n?.outputDir??"docs",readmePath:n?.readmePath??"README.md",repositoryPrefix:n?.repositoryPrefix,version:n?.version??i??void 0},l=t.getCommands(),$=[...l.values()].filter(m=>!m.hidden).filter(m=>s.aliases?!0:m.name===l.get(m.name)?.name).toSorted((m,h)=>{const _=m.commandPath?[...m.commandPath,m.name].join(" "):m.name,O=h.commandPath?[...h.commandPath,h.name].join(" "):h.name;return _.localeCompare(O)}),p=K($,m=>m.commandPath?[...m.commandPath,m.name].join(" "):m.name);e.debug(`Processing ${p.length} commands for README generation`);let c;const u=v(M(),s.readmePath??"README.md");if(E(u)){const m=await T(u,"utf8");c=A(m)}else e.warn(`README file not found at ${u}, creating template`),c=`# ${r} <!-- usage --> <!-- usagestop --> <!-- commands --> <!-- commandsstop --> <!-- toc --> <!-- tocstop --> `;const C=s.outputDir??"docs",x=s.version??i??"unknown";c=y(c,"usage",Z(a,r,x,o)),c=y(c,"commands",s.multi?await ee(p,C,a,s):await R(p,a,s)),c=y(c,"toc",await te(c)),c=`${c.trimEnd()} `,s.dryRun?(e.info("Dry run mode - README not written"),e.info(`Generated README content: ${c}`)):(await j(u,c),e.info(`README generated successfully at ${u}`))},"execute"),name:"readme",options:[{description:"Include aliases in command list",name:"aliases",type:Boolean},{description:"Show what would be generated without writing files",name:"dry-run",type:Boolean},{description:"Generate multi-file documentation by command groups",name:"multi",type:Boolean},{description:"Maximum depth for nested topics when using multi-file mode",name:"nested-topics-depth",type:Number},{description:"Output directory for multi-file documentation",name:"output-dir",type:String,typeLabel:"{underline directory}"},{description:"Path to README file to generate",name:"readme-path",type:String,typeLabel:"{underline path}"},{description:"Repository prefix for code links",name:"repository-prefix",type:String,typeLabel:"{underline prefix}"},{description:"Version to use in generated documentation",name:"version",type:String,typeLabel:"{underline version}"}]};export{se as default};