gqty-dev / gqty

The No-GraphQL Client for TypeScript
https://gqty.dev
MIT License
932 stars 26 forks source link

@gqty/cli doesn't work correctly (watch mode) #2022

Open SpeedySH opened 1 month ago

SpeedySH commented 1 month ago

The idea, as well as the client, is great. But there are some points that make me uncomfortable

  1. When trying to run the CLI, with --install enabled, it does not install dependencies, or even add them to package.json
  2. If not explicitly specified in package.json or with --react option, it generates a client not for react (the hooks are just not there)
  3. I need to be able to disable dependency installation and customization in general. For example: I want to regenerate a client, and I have all the settings already specified in package.json (gqty block), gqty reads them, and still asks me to use CLI input! Why?
  4. watch just doesn't work. Let's start from the beginning: 4.1 See point 1, dependencies are simply not added. 4.2 On startup, I get an error, and that's the end of it, error text:
    
    ℹ Watching for schema changes... (Ctrl+C to exit)file:///E:/Projects/ONREZA/TEST_FRONTEND/node_modules/@gqty/cli/commands/default.mjs:2
    import{cosmiconfig as I}from"cosmiconfig";import D from"assert";import{readFile as G,watch as L}from"fs/promises";import u 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 M from"fast-glob";import"graphql";import"lodash-es/sortBy.js";import"prettier";import{convertHeadersInput as x}from"./default/convertHeadersInput.mjs";import{fetchSchema as S,isURL as q}from"./default/fetchSchema.mjs";import{generateClient as O}from"./default/generateClient.mjs";import{getCommandName as A}from"./default/getCommandName.mjs";import{logger as d}from"./default/logger.mjs";import{promptInstall as W,runInstall as B}from"./default/promptInstall.mjs";const Q=i=>i.name(A()).usage("[options] [endpoints...]").argument("[endpoints...]","GraphQL endpoints or schema files.").option("-H, --header <header>","Custom header for the introspection query.",(o,e)=>[...e,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("--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,e)=>{const t=await I("gqty").search().then(c=>c?.config??{});let r=o;if(r.length===0&&(v.stdin.isTTY||(d.error("Please provide your GraphQL endpoint(s)."),v.exit(1)),r=await F(t.introspections?Object.keys(t.introspections).join(", "):t.introspection?.endpoint)),r=r.map(c=>c.trim()).filter(Boolean),r.length===0)return d.error("Please provide your GraphQL endpoint(s).");t.introspections||(t.introspections={});const y=await S(r,{headers:x(e.header)??t.introspection?.headers,headersByEndpoint:t.introspections}).catch(U);Object.keys(t.introspections??{}).length>0,t.frameworks??(t.frameworks=[e.react&&"react",e.solid&&"solid-js"].filter(c=>!!c)),e.subscriptions!==void 0&&(t.subscriptions=e.subscriptions||!1),e.typescript&&(t.javascriptOutput=!1),e.target&&(t.destination=e.target,t.javascriptOutput=u.extname(e.target)===".js");const p=await(async()=>{try{return JSON.parse(await G("package.json",{encoding:"utf-8"}))}catch{return}})();if(p&&(t.frameworks??(t.frameworks=[p.dependencies?.react&&"react",p.dependencies?.["solid-js"]&&"solid-js"].filter(c=>!!c)),t.javascriptOutput??(t.javascriptOutput=p.dependencies?.typescript===void 0&&p.devDependencies?.typescript===void 0)),y.getSubscriptionType()&&(t.subscriptions??(t.subscriptions="graphql-ws")),o.length===0&&(t.frameworks=await N(),t.subscriptions=await R(t.subscriptions?t.subscriptions===!0?"graphql-ws":t.subscriptions:void 0),t.javascriptOutput=!await H(!t.javascriptOutput),t.destination??(t.destination=await J(t.javascriptOutput?"gqty/index.js":"gqty/index.ts"))),t.destination??(t.destination=t.javascriptOutput?"gqty/index.js":"gqty/index.ts"),q(r[0])&&(t.endpoint=r[0]),await O(y,{destination:"",...t}),o.length===0&&e.install===void 0?await W(t):p&&e.install!==!1&&await B(p,t),e.watch){const{default:{isMatch:c}}=await import("micromatch"),{default:P}=await import("lodash-es/throttle.js"),{FasterSMA:T}=await import("trading-signals/dist/SMA/SMA.js"),{printSchema:b}=await import("graphql"),f=new T(3),C=()=>{try{return f.getResult()}catch{return f.prices.length===0?0:f.prices.reduce((n,s)=>n+s,0)/f.prices.length}},j=P(async()=>{if(w)return;w=!0;const n=Date.now();try{const s=await S(r,{headers:x(e.header),headersByEndpoint:t.introspections,silent:!0}).catch(a=>a instanceof Error?(d.errorProgress(a.message),Promise.resolve(void 0)):Promise.reject(a));if(!s)return;const m=b(s);m!==k&&(k=m,await O(s,{destination:"",...t}),f.update(Date.now()-n)),d.infoProgress("Watching for schema changes... (Ctrl+C to exit)")}finally{w=!1}},1e3,{leading:!0,trailing:!0});let w=!1,k=b(y);d.infoProgress("Watching for schema changes... (Ctrl+C to exit)"),r.some(n=>q(n))&&(async()=>{for(;;){const n=Math.max(5e3,Math.min(3e4,C()*10));await new Promise(s=>setTimeout(s,n)),j()}})(),(async()=>{const n=r.map(a=>u.resolve(a)),s=await M(n,{absolute:!0}).then(a=>a.map(l=>u.dirname(l).split(u.sep)).reduce((l,E)=>{let h=0;for(;h<l.length&&l[h]===E[h];)h++;return l.slice(0,h)}).join(u.sep)||void 0);D(s,"No common path for specified endpoints.");let m=!1;for await(const{filename:a}of L(s,{recursive:!0})){if(!a)continue;const l=u.resolve(s,a);c(l,n)&&(w||m||(m=!0,setTimeout(()=>{j().finally(()=>{m=!1})})))}})()}}),F=async i=>(await g.input({message:"Where is your GraphQL endpoint or schema files?",default:i})).split(/[,\s+]/).map(e=>e.trim()).filter(Boolean),J=async i=>await g.input({message:"Where should the client be generated?",default:i}),N=async()=>await g.checkbox({message:"Pick the frontend frameworks in use:",choices:[{value:"react"},{value:"solid-js"}]}),R=async i=>(await g.input({message:'Do you need a subscription client? (Enter "-" to skip)',default:i?.trim()||void 0}))?.trim().replace(/^-$/,"")||!1,H=async i=>await g.confirm({message:"Do you want a TypeScript client over vanilla.js?",default:i}),U=i=>{throw i instanceof Error&&(d.error(i.message),v.exit(1)),i};export{Q as addCommand};

TypeError: Reduce of empty array with no initial value at Array.reduce () at file:///E:/Projects/ONREZA/TEST_FRONTEND/node_modules/@gqty/cli/commands/default.mjs:2:4624 at async file:///E:/Projects/ONREZA/TEST_FRONTEND/node_modules/@gqty/cli/commands/default.mjs:2:4555

vicary commented 1 month ago

Thanks, let's make it more comfortable to use.

I can roughly tell what's going on, but I'd like to know the exact commands used for each point.

Relevant info that I can share:

  1. When trying to run the CLI, with --install enabled, it does not install dependencies, or even add them to package.json
    • CLI detects what package manager you used to invoke it, so it depends. For example NPM creates a package.json when none is there, Yarn cannot.
    • CLI skips the installation when no missing dependencies are found.
  2. If not explicitly specified in package.json or with --react option, it generates a client not for react (the hooks are just not there)
    • When no options are defined, the default is to look for react in all dependencies, and if that's not found it skips the react part.
    • Same logic goes for solid.
  3. I need to be able to disable dependency installation and customization in general. For example: I want to regenerate a client, and I have all the settings already specified in package.json (gqty block), gqty reads them, and still asks me to use CLI input! Why?
    • The minimum required option to skip interactive mode is the GraphQL endpoint, I may need to read your config block and the command you used to know exactly why.
  4. watch just doesn't work. Let's start from the beginning:
    • The error is most likely caused by a wildcard endpoint that resolves to NO files, I'll make a quick patch update when we confirm this one.
SpeedySH commented 1 month ago

Thanks, let's make it more comfortable to use.

I can roughly tell what's going on, but I'd like to know the exact commands used for each point.

Relevant info that I can share:

  1. When trying to run the CLI, with --install enabled, it does not install dependencies, or even add them to package.json
  • CLI detects what package manager you used to invoke it, so it depends. For example NPM creates a package.json when none is there, Yarn cannot.
  • CLI skips the installation when no missing dependencies are found.
  1. If not explicitly specified in package.json or with --react option, it generates a client not for react (the hooks are just not there)
  • When no options are defined, the default is to look for react in all dependencies, and if that's not found it skips the react part.
  • Same logic goes for solid.
  1. I need to be able to disable dependency installation and customization in general. For example: I want to regenerate a client, and I have all the settings already specified in package.json (gqty block), gqty reads them, and still asks me to use CLI input! Why?
  • The minimum required option to skip interactive mode is the GraphQL endpoint, I may need to read your config block and the command you used to know exactly why.
  1. watch just doesn't work. Let's start from the beginning:
  • The error is most likely caused by a wildcard endpoint that resolves to NO files, I'll make a quick patch update when we confirm this one.

Am I right that now, packages are only installed if you use npm? it won't work with bun or pnpm?

My package.json has information in react packages, but all ravon until I used the --react option it only generated basic (i.e. no hooks)

Command to start watch mode: bun gqty --watch. I also tried npx @gqty/cli --watch and bunx @gqty/cli --watch

  "gqty": {
    "introspection": {
      "endpoint": "https://localhost:51835/graphql"
    },
    "react": true,
    "javascriptOutput": false,
    "subscriptions": false,
    "destination": "./generated/index.ts",
    "scalarTypes": {
      "DateTime": "Date"
    },
    "enumStyle": "const"
  }
vicary commented 1 month ago

@SpeedySH The CLI auto-detects NPM, Yarn and PNPM. Bun is possible, let me put that in the roadmaps.