gqty icon indicating copy to clipboard operation
gqty copied to clipboard

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

Open SpeedySH opened this issue 1 year ago • 4 comments

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 (<anonymous>)
    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

SpeedySH avatar Sep 27 '24 19:09 SpeedySH

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.

vicary avatar Sep 30 '24 02:09 vicary

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"
  }

SpeedySH avatar Sep 30 '24 13:09 SpeedySH

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

vicary avatar Oct 02 '24 05:10 vicary

+1 on this:

➤ YN0000: · Yarn 4.9.1
➤ YN0000: ┌ Resolution step
➤ YN0085: │ + @gqty/cli@npm:4.2.6, @ardatan/relay-compiler@npm:12.0.3, @babel/code-frame@npm:7.27.1, @babel/generator@npm:7.27.3, @babel/helper-string-parser@npm:7.27.1, @babel/helper-validator-identifier@npm:7.27.1, and 180 more.
➤ YN0000: └ Completed in 0s 665ms
➤ YN0000: ┌ Fetch step
➤ YN0013: │ 186 packages were added to the project (+ 32.86 MiB).
➤ YN0000: └ Completed
➤ YN0000: ┌ Link step
➤ YN0000: └ Completed in 0s 744ms
➤ YN0000: · Done in 1s 526ms

(node:11702) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
✔ Schema introspection completed.       
✔ Code generation completed.      
node:internal/modules/esm/resolve:857
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'trading-signals' imported from /private/var/folders/86/d9nbkhj51670jggprv8jd8bw0000gn/T/xfs-43db1f81/dlx-11692/node_modules/@gqty/cli/commands/default.mjs
    at packageResolve (node:internal/modules/esm/resolve:857:9)
    at moduleResolve (node:internal/modules/esm/resolve:926:18)
    at defaultResolve (node:internal/modules/esm/resolve:1056:11)
    at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:654:12)
    at #cachedDefaultResolve (node:internal/modules/esm/loader:603:25)
    at ModuleLoader.resolve (node:internal/modules/esm/loader:586:38)
    at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:242:38)
    at onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:546:36)
    at TracingChannel.tracePromise (node:diagnostics_channel:344:14)
    at ModuleLoader.import (node:internal/modules/esm/loader:545:21) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Node.js v22.12.0```

alexcatdad avatar May 28 '25 15:05 alexcatdad