@gqty/cli
Version:
Interactive codegen for GQty
177 lines (156 loc) • 11.6 kB
JavaScript
import{SchemaUnionsKey as Te,parseSchemaType as J}from"gqty";import*as ee from"graphql";import{defaultConfig as d}from"./config.mjs";import"@commander-js/extra-typings";import{codegen as Re}from"@graphql-codegen/core";import*as we from"@graphql-codegen/typescript";import{printSchemaWithDirectives as Ae}from"@graphql-tools/utils";import"@graphql-tools/wrap";import"@inquirer/prompts";import"cosmiconfig";import"cross-fetch";import"fast-glob";import w from"lodash-es/sortBy.js";import"prettier";import{formatPrettier as Me}from"./prettier.mjs";const{isEnumType:De,isInputObjectType:xe,isInterfaceType:Fe,isNullableType:te,isObjectType:Ve,isScalarType:Qe,isUnionType:He,lexicographicSortSchema:Ue,parse:Ge,isSchema:Ie,assertSchema:qe}=ee;async function Le(h,{enumsAsConst:ne,enumsAsStrings:re,enumStyle:g=ne?"assertion":re?"string":d.enumStyle,introspection:se=d.introspections,endpoint:A=se?.endpoint??d.endpoint,javascriptOutput:l=d.javascriptOutput,preImport:oe=d.preImport,react:b=d.react,frameworks:I=d.frameworks,scalarTypes:ie=d.scalarTypes,subscriptions:y=d.subscriptions,transformSchema:q=d.transformSchema}={},{ignoreArgs:C}={}){l&&(g!=="string"&&g!==d.enumStyle&&console.warn('"enumStyle" must be string unions with "javascriptOutput" enabled.'),g="string");const{format:M}=Me({parser:"typescript"});if(h=Ue(qe(h)),q&&(h=await q(h,ee),!Ie(h)))throw Error('"transformSchema" returned an invalid GraphQL Schema!');b??(b=I.includes("react"));const L=I.includes("solid-js"),ae=Re({schema:Ge(Ae(h)),config:{},documents:[],filename:"gqty.generated.ts",pluginMap:{typescript:we},plugins:[{typescript:{constEnums:g==="const",onlyOperationTypes:!0,declarationKind:"interface",addUnderscoreToArgsType:!0,scalars:ie,namingConvention:"keep",enumsAsTypes:g==="string",enumsAsConst:g==="assertion"}}]}),E=h.toConfig(),$={},D=[],P=new Set,m={query:{},mutation:{},subscription:{}},x=E.query,F=E.mutation,V=E.subscription,k=new Map,_=new Map,S=new Map;function Q(e){if(Array.isArray(e)){const t=e[2]?S.get(e[0])?.[e[1]]?.[e[2]]:_.get(e[0])?.[e[1]];let r="";return t?.description&&(r+=`
`+t.description.trim().split(`
`).map(n=>"* "+n).join(`
`)),t?.deprecated&&(r+=`
* @deprecated `+t.deprecated.trim().replace(/\n/g,". ").trim()),t?.defaultValue&&(r+="\n* @defaultValue `"+t.defaultValue.trim()+"`"),r?`/** ${r}
*/
`:""}else{const t=k.get(e);return t?`/**
${t.trim().split(`
`).map(r=>"* "+r).join(`
`)}
*/
`:""}}const ce=e=>{$[e.name]=!0,D.push(e.name);const t=e.getValues(),r={};for(const n of t)(n.deprecationReason||n.description)&&(r[n.name]={description:n.description,deprecated:n.deprecationReason});_.set(e.name,r)},ue=e=>{$[e.name]=!0},pe=new Map,j=(e,t=e.name)=>{const r=e.getFields(),n=e.getInterfaces();if(n.length){pe.set(e.name,n.map(o=>o.name));for(const o of n){let a=f.get(o.name);a==null&&f.set(o.name,a=[]),a.push(e.name)}}const s={__typename:{__type:"String!"}},u={},i={};Object.entries(r).forEach(([o,a])=>{if((a.description||a.deprecationReason)&&(u[o]={description:a.description,deprecated:a.deprecationReason}),s[o]={__type:a.type.toString()},a.args.length){if(C&&a.args.every(({type:p})=>te(p))&&C(a))return;i[o]||(i[o]={}),s[o].__args=a.args.reduce((c,p)=>(c[p.name]=p.type.toString(),(p.description||p.deprecationReason||p.defaultValue!=null)&&(i[o][p.name]={defaultValue:p.defaultValue!=null?JSON.stringify(p.defaultValue):null,deprecated:p.deprecationReason,description:p.description}),c),{})}}),_.set(e.name,u),S.set(e.name,i),m[t]=s},f=new Map,le=e=>{const t=e.getTypes(),r=[];f.set(e.name,r);for(const n of t)r.push(n.name);m[e.name]={__typename:{__type:"String!"}}},de=e=>{P.add(e.name);const t=e.getFields(),r={};Object.entries(t).forEach(([n,s])=>{r[n]={__type:s.type.toString()},(s.description||s.deprecationReason||s.defaultValue)&&(s.description,s.deprecationReason,s.defaultValue!=null&&JSON.stringify(s.defaultValue))}),m[e.name]=r},fe=e=>{const t={__typename:{__type:"String!"}},r=e.getFields(),n={},s={};Object.entries(r).forEach(([u,i])=>{i.type.toString(),t[u]={__type:i.type.toString()};let o=!0;i.args.length?C&&i.args.every(({type:c})=>te(c))&&C(i)&&(o=!1):o=!1,o&&(s[u]||(s[u]={}),t[u].__args=i.args.reduce((a,c)=>(a[c.name]=c.type.toString(),(c.description||c.deprecationReason||c.defaultValue!=null)&&(s[u][c.name]={defaultValue:c.defaultValue!=null?JSON.stringify(c.defaultValue):null,deprecated:c.deprecationReason,description:c.description}),a),{})),(i.description||i.deprecationReason)&&(n[u]={description:i.description,deprecated:i.deprecationReason})}),_.set(e.name,n),S.set(e.name,s),m[e.name]=t};E.types.forEach(e=>{e.description&&k.set(e.name,e.description),!(e.name.startsWith("__")||e===x||e===F||e===V)&&(Qe(e)?ue(e):Ve(e)?j(e):Fe(e)?fe(e):He(e)?le(e):De(e)?ce(e):xe(e)&&de(e))}),x&&j(x,"query"),F&&j(F,"mutation"),V&&j(V,"subscription");const z=Array.from(f.entries()).reduce((e,[t,r])=>(m[t].$on={__type:`$${t}!`},e[t]=r,e),{});f.size&&(m[Te]=z);function me({pureType:e,isArray:t,nullableItems:r,isNullable:n,hasDefaultValue:s}){let u=[$[e]?D.includes(e)?e:`ScalarsEnums["${e}"]`:e];return t&&(u=["Array<",...r?["Maybe<",...u,">"]:u,">"]),(n||s)&&(u=["Maybe<",...u,">"]),u.join("")}function he({pureType:e,isArray:t,nullableItems:r,isNullable:n}){let s=[$[e]?`ScalarsEnums["${e}"]`:e];return t&&(s=["Array<",...r?["Maybe<",...s,">"]:s,">"]),n&&(s=["Maybe<",...s,">"]),s.join("")}const ye=new Map;let H=w(Object.entries(m),e=>e[0]).reduce((e,[t,r])=>{const n=(()=>{switch(t){case"query":return"Query";case"mutation":return"Mutation";case"subscription":return"Subscription";default:return t}})();if(P.has(n))return e;const s=new Map;f.has(n)||ye.set(n,s);const u=f.get(n);return e+=`
${Q(n)}export interface ${n} {
__typename?: ${u?u.map(i=>`"${i}"`).join(" | "):`"${n}"`}; ${Object.entries(r).reduce((i,[o,a])=>{if(o==="__typename")return s.set(o,`?: "${n}"`),i;const c=S.has(n)?S.get(n):void 0,p=c&&c[o]?c[o]:{},B=J(a.__type),W=he(B);let T;if(a.__args){const X=Object.entries(a.__args);let Z=!0;const Ee=X.reduce((K,[G,_e])=>{const R=J(_e,p[G]),je=R.isNullable||R.hasDefaultValue?"?:":":";R.isNullable||(Z=!1);const Oe=me(R);return K+=`${Q([n,o,G])}${G}${je} ${Oe};
`,K},"");T=`: (args${Z?"?:":":"} {${Ee}}) => ${W}`}else T=`${B.isNullable?"?:":":"} ${W}`;return s.set(o,T),i+=`
`+Q([n,o])+o+T,i},"")}
}
`,e},"");f.size&&(H+=`
${w(Array.from(f.entries()),e=>e[0]).reduce((e,[t,r])=>(e+=`
export interface $${t} {
${r.map(n=>`${n}?:${n}`).join(`
`)}
}
`,e),"")}
`),H+=`
export interface GeneratedSchema {
query: Query
mutation: Mutation
subscription: Subscription
}
export type ScalarsEnums = {
[Key in keyof Scalars]: Scalars[Key] extends { output: unknown }
? Scalars[Key]['output']
: never;
} & {
${w(D).reduce((e,t)=>(e+=`${t}: ${t};`,e),"")}
}
`;function O(e){return`/**
* @type {${e}}
*/
`}const ge=`
${l?O('import("gqty").QueryFetcher')+"const queryFetcher":"const queryFetcher: QueryFetcher"} = async function ({ query, variables, operationName }, fetchOptions) {
// Modify "${A}" if needed
const response = await fetch("${A}", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query,
variables,
operationName,
}),
mode: "cors",
...fetchOptions
});
return await defaultResponseHandler(response);
};
`,U=!!f.size,v=JSON.stringify(Object.keys($).sort().reduce((e,t)=>(e[t]=!0,e),{})),Y=w(Object.entries(m),e=>e[0]).reduceRight((e,[t,r])=>`${JSON.stringify(t)}:${JSON.stringify(r)}, ${e}`,U?`[SchemaUnionsKey]: ${JSON.stringify(z)}`:""),$e=await M(`
/**
* GQty AUTO-GENERATED CODE: PLEASE DO NOT MODIFY MANUALLY
*/
${U?'import { SchemaUnionsKey } from "gqty";':""}
${O('import("gqty").ScalarsEnumsHash')}export const scalarsEnumsHash = ${v};
export const generatedSchema = {${Y}};
`),N=[U&&"SchemaUnionsKey",!l&&"type ScalarsEnumsHash"].filter(e=>!!e),Se=await M(`
/**
* GQty AUTO-GENERATED CODE: PLEASE DO NOT MODIFY MANUALLY
*/
${oe}
${N.length?`import { ${N.join(", ")} } from "gqty";`:""}
${await ae}
export${l?" declare":""} const scalarsEnumsHash: ScalarsEnumsHash${l?";":` = ${v};`}
export${l?" declare":""} const generatedSchema ${l?":":"="} {${Y}}${l?"":" as const"};
${H}
`),be=b?`
export const {
graphql,
useQuery,
usePaginatedQuery,
useTransactionQuery,
useLazyQuery,
useRefetch,
useMutation,
useMetaState,
prepareReactRender,
useHydrateCache,
prepareQuery,
${y?"useSubscription,":""}
} = ${l?`${O('import("@gqty/react").ReactClient<import("./schema.generated").GeneratedSchema>')}createReactClient(client, {`:"createReactClient<GeneratedSchema>(client, {"}
defaults: {
// Enable Suspense, you can override this option for each hook.
suspense: true,
}
});
`.trim():"",Ce=L?`
export const { createQuery } = createSolidClient(client);
`:"";return{clientCode:await M(`
/**
* GQty: You can safely modify this file based on your needs.
*/
${[b?'import { createReactClient } from "@gqty/react";':"",L?'import { createSolidClient } from "@gqty/solid";':"",y?`import { createClient as createSubscriptionsClient } from "${y===!0?"graphql-ws":y}";`:"",l?'import { Cache, createClient, defaultResponseHandler } from "gqty";':'import { Cache, createClient, defaultResponseHandler, type QueryFetcher } from "gqty";',l?'import { generatedSchema, scalarsEnumsHash } from "./schema.generated";':'import { generatedSchema, scalarsEnumsHash, type GeneratedSchema } from "./schema.generated";'].filter(Boolean).join(`
`)}
${ge}
${y?`const subscriptionsClient =
typeof window !== "undefined" ?
createSubscriptionsClient({
lazy: true,
url: () => {
// Modify if needed
const url = new URL("${A}", window.location.href);
url.protocol = url.protocol.replace('http', 'ws');
return url.href;
}
}) : undefined;`:""}
const cache = new Cache(
undefined,
/**
* Default option is immediate cache expiry but keep it for 5 minutes,
* allowing soft refetches in background.
*/
{
maxAge: 0,
staleWhileRevalidate: 5 * 60 * 1000,
normalization: true,
}
);
${l?`${O('import("gqty").GQtyClient<import("./schema.generated").GeneratedSchema>')}export const client = createClient({
schema: generatedSchema,
scalars: scalarsEnumsHash,
cache,
fetchOptions: {
fetcher: queryFetcher,
${y?"subscriber: subscriptionsClient":""}
},
});
`:`
export const client = createClient<GeneratedSchema>({
schema: generatedSchema,
scalars: scalarsEnumsHash,
cache,
fetchOptions:{
fetcher: queryFetcher,
${y?"subscriber: subscriptionsClient":""}
},
});
`}
// Core functions
export const { resolve, subscribe, schema } = client;
// Legacy functions
export const { query, mutation, mutate, subscription, resolved, refetch, track } = client;
${be}
${Ce}
export * from "./schema.generated";
`),generatedSchema:m,isJavascriptOutput:l,javascriptSchemaCode:$e,scalarsEnumsHash:$,schemaCode:Se}}export{Le as generate};