@openapi-integration/swr-request-generator
Version:
A tool for generating TypeScript code and interface from swagger by using SWR and axios as client.
147 lines (133 loc) • 17.9 kB
JavaScript
"use strict";var Re=Object.create;var U=Object.defineProperty;var Oe=Object.getOwnPropertyDescriptor;var Se=Object.getOwnPropertyNames;var be=Object.getPrototypeOf,Te=Object.prototype.hasOwnProperty;var xe=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Se(e))!Te.call(r,o)&&o!==t&&U(r,o,{get:()=>e[o],enumerable:!(s=Oe(e,o))||s.enumerable});return r};var P=(r,e,t)=>(t=r!=null?Re(be(r)):{},xe(e||!r||!r.__esModule?U(t,"default",{value:r,enumerable:!0}):t,r));var d=P(require("fs"),1),le=P(require("js-yaml"),1);var me=require("moderndash");var a=(r,e,t)=>{if(!r||!e)return t;let o=(Array.isArray(e)?e:e?.match(/([^[.\]])+/g))?.reduce((n,i)=>n&&n[i],r);return o===void 0?t:o},B=(r,e)=>!r||!e?!1:!!e?.match(/([^[.\]])+/g)?.reduce((s,o)=>s&&s[o],r),H=r=>(e,t)=>e[r]>t[r]?1:t[r]>e[r]?-1:0,J=(r,e)=>e.reduce((t,s)=>(r.hasOwnProperty(s)&&(t[s]=r[s]),t),{}),w=(r,e)=>{for(let t in r)if(e(r[t]))return r[t]},V=(r,e="\\s")=>r.replace(new RegExp(`^(.*?)([${e}]*)$`),"$1");var K=r=>Array.isArray(r),l=r=>Object.prototype.toString.call(r)==="[object Object]",Q=r=>typeof r=="number",z=r=>!B(r,"$ref"),I=r=>!B(r,"$ref"),q=r=>/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(r);var y=require("moderndash"),ee=P(require("prettier"),1);var j={INVALID_JSON_FILE_ERROR:`Your json file is invalid, please check it!
`,INVALID_FILE_FORMAT:`Your input file is invalid, please check if it json or yaml!
`,FETCH_CLIENT_FAILED_ERROR:`Fetch client failed! Please check your network or ts-codegen.config.ts file.
`},b={GENERATING:"generating...",SUCCESSFUL:"successful!!!",READING:`reading swagger schema from local file...
`,GETTING_FROM_REMOTE:r=>`getting swagger schema from client ${r+1}...
`},X=["get","post","put","delete","patch","options","head"],k="/",Y=`
/*
* this file is generated by @openapi-integration/swr-request-generator.
* please do not modify it manually.
*/
`,f="#EnumTypeSuffix";var W=r=>console.log(`\x1B[32m${r}\x1B[39m`),Z=r=>console.log(`\x1B[33m${r}\x1B[39m`),$=r=>console.log(`\x1B[41m${r}\x1B[49m`);var u=r=>{if(!r)return"";let e=(0,y.camelCase)(r);return`${e.charAt(0).toUpperCase()}${e.slice(1)}`},te=(r=[])=>{let e={};return r.forEach(t=>{e[t]=t}),e},N=r=>ee.default.format(r,{printWidth:120,trailingComma:"all",arrowParens:"always",parser:"typescript"}),E=r=>{if((0,y.isEmpty)(r))return;let e=Object.entries(r).map(([t,s])=>l(s)&&Object.keys(s).length===1&&!(0,y.isEmpty)(w(s,o=>o==="FormData"))?`${M(t)}: FormData`:l(s)?`${M(t)}: ${JSON.stringify(s).replace(/"/g,"")};`:`${M(t)}: ${s.replace(f,"")};`);return r&&`{
${e.sort().join(`
`)}
}`},re=r=>{let e=Object.entries(r.body??{}).map(([,n])=>l(n)&&Object.keys(n).length===1&&!(0,y.isEmpty)(w(n,i=>i==="FormData"))?"FormData;":l(n)?`${JSON.stringify(n).replace(/"/g,"")};`:`${n.replace(f,"")};`),t=(0,y.isEmpty)(e)?"":`body: ${e.sort().join(`
`)}`;if(r.query&&Object.keys(r.query).length>0){let n=`query: ${E(r.query)}`;return`{
${t}
${n}
}`}let s=Object.entries(r.query||{}).map(([,n])=>l(n)?`${JSON.stringify(n).replace(/"/g,"")};`:`${n.replace(f,"")};`),o=(0,y.isEmpty)(s)?"":`query: ${s.sort().join(`
`)}`;return`{
${t}
${o}
}`},M=r=>{let e=r.includes("?"),t=V(r,"?");return`'${q(t)?t:(0,y.camelCase)(u(t))}'${e?"?":""}`},se=(r,e=j.INVALID_JSON_FILE_ERROR,t=$)=>{if(typeof r=="string")try{return JSON.parse(r)}catch{t(e);return}},D=r=>{if(l(r))return JSON.stringify(r).replace(/"/g,"");if(r!=="")return r};var c=class{constructor(e){this.inputs=e}schemaType={};static of(e){return new c(e)}getSchemaType=()=>this.schemaType;resolve=e=>{let{schema:t={},results:s,parentKey:o,key:n}=this.inputs;if(t.$ref)return this.schemaType=this.resolveRef(t.$ref,e||t.type),this.schemaType=this.resolveNullable().getSchemaType(),this;if(t.oneOf||t.anyOf)return this.schemaType=this.resolveOneOfAndAnyOf(t.oneOf||t.anyOf),this.schemaType=this.resolveNullable().getSchemaType(),this;if(t.allOf)return this.schemaType=this.resolveAllOf(t.allOf),this.schemaType=this.resolveNullable().getSchemaType(),this;if(t.items)return this.schemaType=this.resolveItems(t.items,t.type,n,o),this.schemaType=this.resolveNullable().getSchemaType(),this;if(t.enum){let i=this.getEnumName(n,o);return s[i]=t.enum,this.schemaType=i,this.schemaType=this.resolveNullable().getSchemaType(),this}return t.type==="object"?t.properties?(this.schemaType=this.resolveProperties(t.properties,t.required,o),this.schemaType=this.resolveNullable().getSchemaType(),this):t.title?(this.schemaType=t.type,this.schemaType=this.resolveNullable().getSchemaType(),this):(this.schemaType="{[key:string]:any}",this.schemaType=this.resolveNullable().getSchemaType(),this):t.type==="string"&&t.format==="binary"?(this.schemaType="FormData",this.schemaType=this.resolveNullable().getSchemaType(),this):(this.schemaType=this.getBasicType(t.type,this.resolveRef(t.$ref,e||t.type)),this.schemaType=this.resolveNullable().getSchemaType(),this)};resolveNullable=()=>(this.inputs.schema?.nullable&&(this.schemaType=l(this.schemaType)?`${JSON.stringify(this.schemaType)} | null`:`${this.schemaType} | null`),this);getEnumName=(e,t="")=>`${u(t)}${u(e)}${f}`;resolveRef=(e,t)=>{if(!e)return"";let s=u(this.pickTypeByRef(e));return t==="array"?`${s}[]`:s};resolveOneOfAndAnyOf=e=>e.map(t=>{let s=c.of({results:{},schema:t}).resolve(t.type).getSchemaType();return JSON.stringify(s)}).join(" | ").replace(f,"").replace(/"/g,"");resolveAllOf=e=>e.map(t=>{let s=c.of({results:{},schema:t}).resolve(t.type).getSchemaType();return JSON.stringify(s)}).join(" & ").replace(f,"").replace(/"/g,"");getBasicType=(e,t)=>{switch(e){case"integer":return"number";case"array":return this.getTypeForArray(t);case void 0:return t||"";default:return e}};getTypeForArray=e=>e?`${e}[]`:"Array<any>";pickTypeByRef=e=>{if(!e)return;let t=e.split("/");return t[t.length-1]};resolveItems=(e,t,s,o)=>{if(!e)return{};let n=a(e,"items");if(t==="array"){if(n)return`${this.resolveItems(n,e.type,s,o)}[]`;if(!a(e,"$ref"))return`${a(e,"type")}[]`}return K(e)?e.map(i=>c.of({results:this.inputs.results,schema:i,key:s,parentKey:o}).resolve().getSchemaType()):c.of({results:this.inputs.results,schema:e,key:s,parentKey:o}).resolve(t).getSchemaType()};resolveProperties=(e={},t=[],s)=>Object.entries(e).reduce((o,[n,i])=>({...o,[`${n}${t.indexOf(n)>-1?"":"?"}`]:c.of({results:this.inputs.results,schema:i,key:n,parentKey:s}).resolve().getSchemaType()}),{})};var h=require("moderndash");var F=(r,e)=>{if((0,h.isEmpty)(r))return"";let t=r[e],s=t.some(n=>Q(n)),o=e.replace(f,"");return s?`export type ${o} = ${t.map(n=>JSON.stringify(n)).join("|")}`:`export enum ${o} ${JSON.stringify(te(t)).replace(/:/gi,"=")}`},L=r=>`use${u((0,h.camelCase)(r||""))}Request`,oe=r=>`useGetRequest<${D(r)}, ResponseError>`,ne=(r,e)=>`useMutationRequest<${e}, AxiosResponse<${D(r)}>, ResponseError>`,ie=(r,e,t="")=>(0,h.isEmpty)(r)&&(0,h.isEmpty)(e)?[void 0,void 0]:[`${u(t)}Request`,{query:e,body:r}],ae=r=>{let e={...r.TReqQuery,...r.TReqPath,...r.THeader},t=(0,h.isEmpty)(e)?void 0:E(e),s=[...r.pathParams??[],...r.queryParams??[],...Object.keys(r.THeader??{})].filter(Boolean).map(n=>q(n)?n:(0,h.camelCase)(n)),o=s.length===0?"":`{${s.join(",")}}:${t}`;return`${o?o+", ":""}SWRConfig?: SWRConfig<${D(r.TResp)}, ResponseError>, axiosConfig?: AxiosRequestConfig`},ce=(r,e)=>{let t={...r.TReqPath,...r.THeader},s=(0,h.isEmpty)(t)?void 0:E(t),o=[...r.pathParams??[],...Object.keys(r.THeader??{})].filter(Boolean).map(i=>q(i)?i:(0,h.camelCase)(i)),n=o.length===0?"":`{${o.join(",")}}:${s}`;return`${n?n+", ":""}mutationConfig?: SWRMutationConfig<${e}, AxiosResponse<${D(r.TResp)}>, ResponseError>, axiosConfig?: AxiosRequestConfig`},pe=(r,e,t,s)=>{let o=Object.entries(s??{}).reduce((i,[m])=>{let g=q(m)?m:(0,h.camelCase)(m);return i+`"${m}": `+g+", "},""),n=r?`"Content-Type": "${a(e,t??"","application/json")}"`:"";return`headers: { ${o}${n}},`},_=r=>r.includes('"Accept":')?'responseType: "blob",':"";var C=class{constructor(e){this.components=e}resolvedDefinitions={};static of(e){return new C(e)}scanDefinitions=()=>{let e={},t=a(this.components,"requestBodies",{}),s=a(this.components,"schemas",{});return Object.entries(t).forEach(([o,n])=>I(n)?e[o]=c.of({results:e,schema:a(n,"content.application/json.schema"),key:o,parentKey:o}).resolve().getSchemaType():e[o]=c.of({results:e,schema:n,key:o,parentKey:o}).resolve().getSchemaType()),Object.entries(s).forEach(([o,n])=>{let i=c.of({results:e,schema:n,key:o,parentKey:n.enum?"":o}).resolve().getSchemaType();return n.enum||(e[o]=i),i}),this.resolvedDefinitions=e,this};toDeclarations=()=>Object.keys(this.resolvedDefinitions).sort().map(e=>{if(e.includes(f))return F(this.resolvedDefinitions,e);if(this.resolvedDefinitions[e]==="object"||(0,me.isEmpty)(this.resolvedDefinitions[e]))return`export interface ${u(e)} {[key:string]:any}`;let t=E(this.resolvedDefinitions[e]);if(t)return`export interface ${u(e)} ${t}`}).filter(e=>!!e)};var v=P(require("path"),1);var T=require("moderndash");var A=class{constructor(e){this.paths=e}resolvedPaths=[];extraDefinitions={};contentType={};static of(e){return new A(e)}resolve=()=>(this.resolvedPaths=Object.entries(this.paths).reduce((e,[t,s])=>[...e,...this.resolvePath(s,t)],[]),this);toRequest=()=>{let e=this.resolvedPaths.sort(H("operationId")),t=[],s=e.map(i=>{let m=a(i,"THeader"),g=a(i.cookieParams,"[0]"),p=a(i,"requestBody"),R=(0,T.camelCase)(u(p||g)),O=this.toHookParams(a(i,"queryParams")),x=pe(!(0,T.isEmpty)(R),this.contentType,i.operationId,m),[S,de]=ie(i.TReqBody,i.TReqQuery,i.operationId);return t.push([S,de]),i.method==="get"?`export const ${L(i.operationId)} = (${ae(i)}) =>
${oe(i.TResp)}({
url: \`${i.url}\`,
method: "${i.method}",${x}${_(x)}
${O?`params: ${O},`:""}...axiosConfig}, SWRConfig);`:`export const ${L(i.operationId)} = (${ce(i,S)}) =>
${ne(i.TResp,S)}({
url: \`${i.url}\`,
method: "${i.method}",${x}${_(x)}
mutationConfig,
axiosConfig});`}),o=Object.keys(this.extraDefinitions).map(i=>F(this.extraDefinitions,i)),n=t.map(([i,m])=>{if(i)return Object.keys(m).forEach(g=>{(0,T.isEmpty)(m[g])&&delete m[g]}),`export interface ${i} ${re(m)}`}).filter(Boolean);return[...s,...n,...o]};toHookParams=(e=[])=>(0,T.isEmpty)(e)?void 0:`{
${e.join(`,
`)}
}`;resolvePath(e,t){let s=J(e,X);return Object.keys(s).map(o=>({url:this.getRequestURL(t),method:o,...this.resolveOperation(s[o])}))}getRequestURL=e=>e.split(k).map(t=>this.isPathParam(t)?`$${t}`:t).join(k);isPathParam=e=>e.startsWith("{");resolveOperation=e=>{e.operationId||Z(`your request does not have an operation id, generated request method will not has uniq name!
`);let t=this.pickParams(e.parameters),s=t("header"),o={pathParams:t("path"),queryParams:t("query"),cookieParams:t("cookie")};return{operationId:e.operationId,TResp:this.getResponseTypes(e.responses),TReqQuery:this.getQueryParamsTypes(o.queryParams),TReqPath:this.getPathParamsTypes(o.pathParams),TReqCookie:this.getCookieParamsTypes(o.cookieParams),TReqBody:this.getRequestBodyTypes(e.operationId,a(e,"requestBody")),THeader:this.getPathParamsTypes(s),...this.getParamsNames(o),...this.getRequestBodyName(a(e,"requestBody"),e.operationId)}};getParamsNames=e=>{let t=s=>(0,T.isEmpty)(s)?[]:s?.map(o=>o.name);return{pathParams:t(e.pathParams),queryParams:t(e.queryParams),cookieParams:t(e.cookieParams)}};getPathParamsTypes=e=>e?.reduce((t,s)=>{let o=a(s,"schema");return z(o)?{...t,[`${s.name}${s.required?"":"?"}`]:o.type==="integer"?"number":o.type}:{...t}},{})??{};getQueryParamsTypes=e=>e?.reduce((t,s)=>({...t,[`${s.name}${s.required?"":"?"}`]:c.of({results:this.extraDefinitions,schema:s.schema,key:s.name,parentKey:s.name}).resolve().getSchemaType()}),{})??{};getCookieParamsTypes=e=>e?.reduce((t,s)=>({...t,[`${s.name}${s.required?"":"?"}`]:c.of({results:this.extraDefinitions,schema:s.schema,key:s.name,parentKey:s.name}).resolve().getSchemaType()}),{})??{};getResponseTypes=e=>c.of({results:this.extraDefinitions,schema:a(e,"200.content.application/json.schema")||a(e,"200.content.*/*.schema")||a(e,"201.content.application/json.schema")||a(e,"201.content.*/*.schema")||a(e,"default.content.application/json.schema")||a(e,"default.content.application/json; charset=UTF-8.schema")}).resolve().getSchemaType();pickParams=e=>t=>e?.filter(s=>s.in===t);getContentType(e,t){t&&Object.assign(this.contentType,{[t]:e})}getRequestBodyTypes(e,t){if(I(t)){let s=a(t,"content",{});return Object.entries(s).reduce((o,[n,i])=>(this.getContentType(n,e),{...o,[`${e}Request`]:c.of({results:this.extraDefinitions,schema:i.schema,key:`${e}Request`,parentKey:`${e}Request`}).resolve().getSchemaType()}),{})}return{[`${e}Request`]:c.of({results:this.extraDefinitions,schema:t,key:`${e}Request`,parentKey:`${e}Request`}).resolve().getSchemaType()}}getRequestBodyName(e,t){if(e)return{requestBody:`${t}Request`}}};var ye=P(require("axios"),1);var G=require("commander");var ue=`// you can use this file as your request handler directly,
// or you can use your own request handler file, just need to align hook name and interface
import useSWR, { SWRResponse } from "swr";
import { SWRConfiguration } from "swr/_internal";
import { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios";
import { client } from "./client";
export interface Return<Data, Error>
extends Pick<SWRResponse<AxiosResponse<Data>, AxiosError<Error>>, "isValidating" | "error" | "mutate" | "isLoading"> {
data: Data | undefined;
response: AxiosResponse<Data> | undefined;
}
export interface SWRConfig<Data = unknown, Error = unknown>
extends Omit<SWRConfiguration<AxiosResponse<Data>, AxiosError<Error>>, "onSuccess"> {
onSuccess?: (response: AxiosResponse<Data>, key: string) => void;
shouldFetch?: boolean;
}
export const generateSwrConfigWithShouldFetchProperty = <Data, Error>(
SWRConfig?: SWRConfig<Data, Error>,
): SWRConfig<Data, Error> =>
SWRConfig
? !SWRConfig.shouldFetch
? SWRConfig
: {
...SWRConfig,
shouldFetch: true,
}
: { shouldFetch: true };
export const useGetRequest = <Data = unknown, Error = unknown>(
axiosConfig: AxiosRequestConfig,
SWRConfig?: SWRConfig<Data, Error>,
): Return<Data, Error> => {
const swrConfig = generateSwrConfigWithShouldFetchProperty(SWRConfig);
const shouldFetch = swrConfig.shouldFetch;
delete swrConfig.shouldFetch;
const {
data: response,
error,
isValidating,
mutate,
isLoading,
} = useSWR<AxiosResponse<Data>, AxiosError<Error>>(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
() => (shouldFetch ? axiosConfig.url! : null),
() => client(axiosConfig),
swrConfig,
);
return { data: response && response.data, response, error, isValidating, isLoading, mutate };
};`;var fe=`import useSWRMutation, { SWRMutationConfiguration } from "swr/mutation";
import { AxiosError, AxiosRequestConfig, AxiosResponse, RawAxiosRequestHeaders } from "axios";
import { client } from "src/request/client";
export type SWRMutationConfig<Request = any, Response = any, Error = any> = SWRMutationConfiguration<
AxiosResponse<Response>,
AxiosError<Error>,
Request,
string
>;
export const useMutationRequest = <
Request extends { body?: any; query?: any } | undefined,
Response = any,
Error = any,
>({
url,
method,
headers,
mutationConfig,
axiosConfig,
}: {
url: string;
method: string;
headers: RawAxiosRequestHeaders;
mutationConfig?: SWRMutationConfiguration<AxiosResponse<Response>, AxiosError<Error>, Request, string>;
axiosConfig?: AxiosRequestConfig;
}) => {
const { trigger, data, isMutating, error, reset } = useSWRMutation<
AxiosResponse<Response>,
AxiosError<Error>,
// assume all key is url, so it will be string type
string,
Request
>(
url,
(url: string, options: { arg: Request }) =>
client.request({ url, method, headers, data: options.arg?.body, params: options.arg?.query, ...axiosConfig }),
mutationConfig,
);
return { trigger, data, isMutating, error, reset };
};`;var he=`import axios, { AxiosInstance } from "axios";
export const API_DEFAULT_TIMEOUT = 30 * 1000;
export const client: AxiosInstance = axios.create({
baseURL: "/api",
timeout: API_DEFAULT_TIMEOUT,
});`;G.program.option("-a, --authorization <value>","authorization header value").parse(process.argv);var ge=v.default.resolve("ts-codegen.config.json"),qe=async()=>d.default.existsSync(ge)?await import(ge,{assert:{type:"json"}}).then(r=>r.default):{output:".output",fileHeaders:[],clients:[]};qe().then(({output:r=".output",fileHeaders:e,timeout:t,data:s,clients:o,fileName:n,needRequestHook:i,needClient:m})=>{let g=p=>{if(typeof p=="string"){$(j.INVALID_JSON_FILE_ERROR);return}d.default.existsSync(r)||d.default.mkdirSync(r);let R=(e?e.join(`
`):"")+`
`+Y+[...A.of(p.paths).resolve().toRequest(),...C.of(p.components).scanDefinitions().toDeclarations()].join(`
`);d.default.writeFileSync(v.default.resolve(r,`./${n||"request"}.ts`),N(R),"utf-8")};if((s||[]).map(p=>{if(!p.endsWith("json")&&!p.endsWith("yml")&&!p.endsWith("yaml")){$(j.INVALID_FILE_FORMAT);return}console.log(b.READING);let R=d.default.readFileSync(p,"utf8"),O=p.endsWith("json")?se(R):le.load(R);O&&(console.log(b.GENERATING+`
`),g(O),W(b.SUCCESSFUL+`
`))}),o){let p=G.program.opts(),R=ye.default.create({timeout:t||10*1e3,headers:p.authorization?{Authorization:p.authorization}:void 0});o.map((O,x)=>{console.log(b.GETTING_FROM_REMOTE(x)),R.get(O).then(S=>{console.log(b.GENERATING+`
`),g(S.data),W(b.SUCCESSFUL+`
`)}).catch(S=>{$(`${S.code}: ${j.FETCH_CLIENT_FAILED_ERROR}`)})})}i&&(d.default.writeFileSync(v.default.resolve(r,"./useGetRequest.ts"),N(ue),"utf-8"),d.default.writeFileSync(v.default.resolve(r,"./useMutationRequest.ts"),N(fe),"utf-8")),m&&d.default.writeFileSync(v.default.resolve(r,"./client.ts"),N(he),"utf-8")});