@gqty/cli
Version:
Interactive codegen for GQty
3 lines (2 loc) • 6.02 kB
JavaScript
import{cosmiconfig as I}from"cosmiconfig";import L from"assert";import{readFile as D,watch as M}from"fs/promises";import d from"path";import v from"process";import"@commander-js/extra-typings";import"@graphql-codegen/core";import"@graphql-codegen/typescript";import"@graphql-tools/utils";import"@graphql-tools/wrap";import*as g from"@inquirer/prompts";import"cross-fetch";import W from"fast-glob";import"graphql";import"prettier";import{convertHeadersInput as P}from"./default/convertHeadersInput.mjs";import{fetchSchema as O,isURL as j}from"./default/fetchSchema.mjs";import{generateClient as q}from"./default/generateClient.mjs";import{getCommandName as A}from"./default/getCommandName.mjs";import{logger as m}from"./default/logger.mjs";import{promptInstall as B,runInstall as Q}from"./default/promptInstall.mjs";const F=e=>e.name(A()).usage("[options] [endpoints...]").argument("[endpoints...]","GraphQL endpoints or schema files.").option("-H, --header <header>","Custom header for the introspection query.",(o,i)=>[...i,o],[]).option("--react","Include React hooks in the generated client.").option("--no-react").option("--solid","Include SolidJS signals in the generated client.").option("--no-solid").option("--pylon","Generate an unsorted schema compatible with Pylon GraphQL.").option("--no-pylon").option("--subscriptions [client]","Includes specified package as subscription client, must be graphql-ws compatible.").option("--no-subscriptions").option("--target <path>","Destination path for the generated client.").option("--typescript","Generates a TypeScript client over a JavaScript one.").option("--no-typescript").option("--install","Automatically install dependencies with current package manager.").option("--no-install").option("-w, --watch","Activate watch mode, regenerate on change changes.",!1).action(async(o,i)=>{const t=await I("gqty").search().then(c=>c?.config??{});let n=o;if(n.length===0&&(v.stdin.isTTY||(m.error("Please provide your GraphQL endpoint(s)."),v.exit(1)),n=await J(t.introspections?Object.keys(t.introspections).join(", "):t.introspection?.endpoint)),n=n.map(c=>c.trim()).filter(Boolean),n.length===0)return m.error("Please provide your GraphQL endpoint(s).");t.introspections||(t.introspections={});const b=await O(n,{headers:P(i.header)??t.introspection?.headers,headersByEndpoint:t.introspections}).catch(Y);Object.keys(t.introspections??{}).length>0,t.frameworks?.length===0&&(t.frameworks=[i.pylon&&"pylon",i.react&&"react",i.solid&&"solid-js"].filter(c=>!!c)),i.subscriptions!==void 0&&(t.subscriptions=i.subscriptions||!1),i.typescript&&(t.javascriptOutput=!1),i.target&&(t.destination=i.target,t.javascriptOutput=d.extname(i.target)===".js");const p=await(async()=>{try{return JSON.parse(await D("package.json",{encoding:"utf-8"}))}catch{return}})();if(p&&(t.frameworks??(t.frameworks=[p.dependencies?.["@getcronit/pylon"]&&"pylon",p.dependencies?.react&&"react",p.dependencies?.["solid-js"]&&"solid-js"].filter(c=>!!c)),t.javascriptOutput??(t.javascriptOutput=!p.dependencies?.typescript&&!p.devDependencies?.typescript&&(t.destination?.endsWith(".js")??!0))),b.getSubscriptionType()&&(t.subscriptions??(t.subscriptions="graphql-ws")),o.length===0&&(t.frameworks=await R(),t.subscriptions=await H(t.subscriptions?t.subscriptions===!0?"graphql-ws":t.subscriptions:void 0),t.javascriptOutput=!await U(!t.javascriptOutput),t.destination??(t.destination=await N(t.javascriptOutput?"gqty/index.js":"gqty/index.ts"))),t.destination??(t.destination=t.javascriptOutput?"gqty/index.js":"gqty/index.ts"),j(n[0])&&(t.endpoint=n[0]),await q(b,{destination:"",...t}),o.length===0&&i.install===void 0?await B(t):p&&i.install!==!1&&await Q(p,t),i.watch){const{default:{isMatch:c}}=await import("micromatch"),{default:T}=await import("just-throttle"),{FasterSMA:E}=await import("trading-signals"),{printSchema:k}=await import("graphql"),f=new E(3),G=()=>{try{return f.getResult()??0}catch{return f.prices.length===0?0:f.prices.reduce((s,a)=>s+a,0)/f.prices.length}},x=T(async()=>{if(y)return;y=!0;const s=Date.now();try{const a=await O(n,{headers:P(i.header),headersByEndpoint:t.introspections,silent:!0}).catch(r=>r instanceof Error?(m.errorProgress(r.message),Promise.resolve(void 0)):Promise.reject(r));if(!a)return;const u=k(a);u!==S&&(S=u,await q(a,{destination:"",...t}),f.update(Date.now()-s,!1)),m.infoProgress("Watching for schema changes... (Ctrl+C to exit)")}finally{y=!1}},1e3,{leading:!0,trailing:!0});let y=!1,S=k(b);m.infoProgress("Watching for schema changes... (Ctrl+C to exit)"),n.some(s=>j(s))&&(async()=>{for(;;){const s=Math.max(5e3,Math.min(3e4,G()*10));await new Promise(a=>setTimeout(a,s)),x()}})(),(async()=>{const s=n.filter(r=>!j(r)).map(r=>d.resolve(r));if(s.length===0)return;const a=await W(s,{absolute:!0}).then(r=>r.map(l=>d.dirname(l).split(d.sep)).reduce((l,C)=>{let h=0;for(;h<l.length&&l[h]===C[h];)h++;return l.slice(0,h)},[]).join(d.sep)||void 0);L(a,"No common path for specified endpoints.");let u=!1;for await(const{filename:r}of M(a,{recursive:!0})){if(!r)continue;const l=d.resolve(a,r);c(l,s)&&(y||u||(u=!0,setTimeout(()=>{x().finally(()=>{u=!1})})))}})()}}),J=async e=>(await g.input({message:"Where is your GraphQL endpoint or schema files?",default:e}).catch(w)).split(/[,\s+]/).map(i=>i.trim()).filter(Boolean),N=async e=>await g.input({message:"Where should the client be generated?",default:e}).catch(w),R=async()=>await g.checkbox({message:"Pick the frontend frameworks in use:",choices:[{value:"react"},{value:"solid-js"},{value:"pylon"}]}).catch(w),H=async e=>(await g.input({message:'Do you need a subscription client? (Enter "-" to skip)',default:e?.trim()||void 0}).catch(w))?.trim().replace(/^-$/,"")||!1,U=async e=>await g.confirm({message:"Do you want a TypeScript client over vanilla.js?",default:e}).catch(w),w=e=>{throw e instanceof Error&&e.name==="ExitPromptError"&&(m.info("Goodbye \u{1F44B}"),v.exit()),e},Y=e=>{throw e instanceof Error&&(m.error(e.message),v.exit(1)),e};export{F as addCommand};