diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6fa7d6e..7456104 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -45,6 +45,10 @@ jobs: - name: Run tsc run: pnpm --filter @7nohe/react-app test:generated + - name: Run biome + run: pnpm biome check . + if: ${{ matrix.os == 'ubuntu-latest' }} + - name: Run test run: pnpm test diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..b18a81f --- /dev/null +++ b/biome.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.7.2/schema.json", + "organizeImports": { + "enabled": true + }, + "files": { + "ignore": [ + "dist", + "examples/react-app/openapi", + "coverage", + "examples/nextjs-app/openapi", + "examples/nextjs-app/.next" + ] + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2 + } +} diff --git a/examples/nextjs-app/app/layout.tsx b/examples/nextjs-app/app/layout.tsx index 96ea52e..c85a6e1 100644 --- a/examples/nextjs-app/app/layout.tsx +++ b/examples/nextjs-app/app/layout.tsx @@ -1,7 +1,7 @@ import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; -import Providers from './providers' +import Providers from "./providers"; const inter = Inter({ subsets: ["latin"] }); diff --git a/examples/nextjs-app/app/page.tsx b/examples/nextjs-app/app/page.tsx index 207d45e..fa9e68f 100644 --- a/examples/nextjs-app/app/page.tsx +++ b/examples/nextjs-app/app/page.tsx @@ -1,24 +1,24 @@ +import { prefetchUseDefaultServiceFindPets } from "@/openapi/queries/prefetch"; import { - dehydrate, HydrationBoundary, QueryClient, -} from '@tanstack/react-query' -import { prefetchUseDefaultServiceFindPets } from "@/openapi/queries/prefetch"; + dehydrate, +} from "@tanstack/react-query"; import Pets from "./pets"; export default async function Home() { - const queryClient = new QueryClient() + const queryClient = new QueryClient(); await prefetchUseDefaultServiceFindPets(queryClient, { limit: 10, tags: [], - }) + }); return (
- - + +
); } diff --git a/examples/nextjs-app/app/pets.tsx b/examples/nextjs-app/app/pets.tsx index 6953abd..e40fa9a 100644 --- a/examples/nextjs-app/app/pets.tsx +++ b/examples/nextjs-app/app/pets.tsx @@ -1,7 +1,7 @@ -'use client' +"use client"; import { useDefaultServiceFindPets } from "@/openapi/queries"; -import { ReactQueryDevtools } from '@tanstack/react-query-devtools' +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; export default function Pets() { const { data } = useDefaultServiceFindPets({ @@ -11,7 +11,7 @@ export default function Pets() { return ( <> -

Pet List

+

Pet List

- ) + ); } diff --git a/examples/nextjs-app/app/providers.tsx b/examples/nextjs-app/app/providers.tsx index 164fb19..804498c 100644 --- a/examples/nextjs-app/app/providers.tsx +++ b/examples/nextjs-app/app/providers.tsx @@ -1,9 +1,9 @@ -'use client' +"use client"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; // We can not useState or useRef in a server component, which is why we are // extracting this part out into it's own file with 'use client' on top -import { useState } from 'react' -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { useState } from "react"; function makeQueryClient() { return new QueryClient({ @@ -14,23 +14,22 @@ function makeQueryClient() { staleTime: 60 * 1000, }, }, - }) + }); } -let browserQueryClient: QueryClient | undefined = undefined +let browserQueryClient: QueryClient | undefined = undefined; function getQueryClient() { - if (typeof window === 'undefined') { + if (typeof window === "undefined") { // Server: always make a new query client - return makeQueryClient() - } else { - // Browser: make a new query client if we don't already have one - // This is very important so we don't re-make a new client if React - // suspends during the initial render. This may not be needed if we - // have a suspense boundary BELOW the creation of the query client - if (!browserQueryClient) browserQueryClient = makeQueryClient() - return browserQueryClient + return makeQueryClient(); } + // Browser: make a new query client if we don't already have one + // This is very important so we don't re-make a new client if React + // suspends during the initial render. This may not be needed if we + // have a suspense boundary BELOW the creation of the query client + if (!browserQueryClient) browserQueryClient = makeQueryClient(); + return browserQueryClient; } export default function Providers({ children }: { children: React.ReactNode }) { @@ -38,9 +37,9 @@ export default function Providers({ children }: { children: React.ReactNode }) { // have a suspense boundary between this and the code that may // suspend because React will throw away the client on the initial // render if it suspends and there is no boundary - const queryClient = getQueryClient() + const queryClient = getQueryClient(); return ( {children} - ) + ); } diff --git a/examples/nextjs-app/request.ts b/examples/nextjs-app/request.ts index 6e46d69..dd12c47 100644 --- a/examples/nextjs-app/request.ts +++ b/examples/nextjs-app/request.ts @@ -18,45 +18,48 @@ const axiosInstance = axios.create({ // Add a request interceptor axiosInstance.interceptors.request.use( - function (config) { - // Do something before request is sent - if (!config.url || !config.params) { - return config; - } - - Object.entries(config.params).forEach(([key, value]) => { - const stringToSearch = `{${key}}`; - if(config.url !== undefined && config.url.search(stringToSearch) !== -1) { - config.url = config.url.replace(`{${key}}`, encodeURIComponent(value)); - delete config.params[key]; - } - }); + (config) => { + // Do something before request is sent + if (!config.url || !config.params) { + return config; + } - return config; - }, - function (error) { - // Do something with request error - return Promise.reject(error); + for (const [key, value] of Object.entries(config.params)) { + const stringToSearch = `{${key}}`; + if ( + config.url !== undefined && + config.url.search(stringToSearch) !== -1 + ) { + config.url = config.url.replace(`{${key}}`, encodeURIComponent(value)); + delete config.params[key]; + } } + + return config; + }, + (error) => { + // Do something with request error + return Promise.reject(error); + }, ); // Add a response interceptor axiosInstance.interceptors.response.use( - function (response) { + (response) => { // Any status code that lie within the range of 2xx cause this function to trigger // Do something with response data return response; }, - function (error) { + (error) => { // Any status codes that falls outside the range of 2xx cause this function to trigger // Do something with response error return Promise.reject(error); - } + }, ); export const request = ( config: OpenAPIConfig, - options: ApiRequestOptions + options: ApiRequestOptions, ): CancelablePromise => { return new CancelablePromise((resolve, reject, onCancel) => { onCancel(() => source.cancel("The user aborted a request.")); diff --git a/examples/react-app/package.json b/examples/react-app/package.json index ce60b5f..e9f9755 100644 --- a/examples/react-app/package.json +++ b/examples/react-app/package.json @@ -9,18 +9,18 @@ "dev:mock": "prism mock ./petstore.yaml --dynamic", "build": "tsc && vite build", "preview": "vite preview", - "generate:api": "rimraf ./openapi && node ../../dist/cli.mjs -i ./petstore.yaml -c axios --request ./request.ts", + "generate:api": "rimraf ./openapi && node ../../dist/cli.mjs -i ./petstore.yaml -c axios --request ./request.ts --format=biome --lint=biome", "test:generated": "tsc -p ./tsconfig.openapi.json --noEmit" }, "dependencies": { "@tanstack/react-query": "^5.18.1", "axios": "^1.6.7", "form-data": "~4.0.0", - "prettier": "^3.2.5", "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { + "@biomejs/biome": "1.7.2", "@stoplight/prism-cli": "^5.5.2", "@types/react": "^18.2.52", "@types/react-dom": "^18.2.18", diff --git a/examples/react-app/request.ts b/examples/react-app/request.ts index 6e46d69..dd12c47 100644 --- a/examples/react-app/request.ts +++ b/examples/react-app/request.ts @@ -18,45 +18,48 @@ const axiosInstance = axios.create({ // Add a request interceptor axiosInstance.interceptors.request.use( - function (config) { - // Do something before request is sent - if (!config.url || !config.params) { - return config; - } - - Object.entries(config.params).forEach(([key, value]) => { - const stringToSearch = `{${key}}`; - if(config.url !== undefined && config.url.search(stringToSearch) !== -1) { - config.url = config.url.replace(`{${key}}`, encodeURIComponent(value)); - delete config.params[key]; - } - }); + (config) => { + // Do something before request is sent + if (!config.url || !config.params) { + return config; + } - return config; - }, - function (error) { - // Do something with request error - return Promise.reject(error); + for (const [key, value] of Object.entries(config.params)) { + const stringToSearch = `{${key}}`; + if ( + config.url !== undefined && + config.url.search(stringToSearch) !== -1 + ) { + config.url = config.url.replace(`{${key}}`, encodeURIComponent(value)); + delete config.params[key]; + } } + + return config; + }, + (error) => { + // Do something with request error + return Promise.reject(error); + }, ); // Add a response interceptor axiosInstance.interceptors.response.use( - function (response) { + (response) => { // Any status code that lie within the range of 2xx cause this function to trigger // Do something with response data return response; }, - function (error) { + (error) => { // Any status codes that falls outside the range of 2xx cause this function to trigger // Do something with response error return Promise.reject(error); - } + }, ); export const request = ( config: OpenAPIConfig, - options: ApiRequestOptions + options: ApiRequestOptions, ): CancelablePromise => { return new CancelablePromise((resolve, reject, onCancel) => { onCancel(() => source.cancel("The user aborted a request.")); diff --git a/examples/react-app/src/App.tsx b/examples/react-app/src/App.tsx index c0712fc..df58103 100644 --- a/examples/react-app/src/App.tsx +++ b/examples/react-app/src/App.tsx @@ -1,14 +1,14 @@ import "./App.css"; +import { useState } from "react"; import { + UseDefaultServiceFindPetsKeyFn, useDefaultServiceAddPet, useDefaultServiceFindPets, - UseDefaultServiceFindPetsKeyFn, useDefaultServiceGetNotDefined, useDefaultServicePostNotDefined, } from "../openapi/queries"; -import { useState } from "react"; -import { queryClient } from "./queryClient"; import { SuspenseParent } from "./components/SuspenseParent"; +import { queryClient } from "./queryClient"; function App() { const [tags, _setTags] = useState([]); @@ -17,7 +17,7 @@ function App() { const { data, error, refetch } = useDefaultServiceFindPets({ tags, limit }); // This is an example of using a hook that has all parameters optional; // Here we do not have to pass in an object - const {} = useDefaultServiceFindPets(); + const { data: _ } = useDefaultServiceFindPets(); // This is an example of a query that is not defined in the OpenAPI spec // this defaults to any - here we are showing how to override the type @@ -32,7 +32,9 @@ function App() { return (

Failed to fetch pets

- +
); @@ -40,12 +42,13 @@ function App() {

Pet List

    - {data instanceof Array && + {Array.isArray(data) && data?.map((pet, index) => ( -
  • {pet.name}
  • +
  • {pet.name}
  • ))}