Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
hungify committed May 6, 2024
1 parent 6bb3d3e commit d2cf0d6
Show file tree
Hide file tree
Showing 11 changed files with 2,516 additions and 26 deletions.
Binary file added bun.lockb
Binary file not shown.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@
"test:e2e": "start-server-and-test preview http://localhost:4173 'cypress run --e2e'",
"test:e2e:dev": "start-server-and-test 'vite dev --port 4173' http://localhost:4173 'cypress open --e2e'",
"postinstall": "run-p build:icons",
"generate:api": "openapi-typescript http://localhost:8000/api/docs-yaml -o src/generated/api-schema.d.ts"
"generate:api": "openapi-typescript src/pets-store.yml -o src/generated/pets-schema.d.ts"
},
"dependencies": {
"@unocss/reset": "^0.58.4",
"@vueuse/core": "^10.7.2",
"@vueuse/integrations": "^10.8.0",
"openapi-fetch": "^0.9.2",
"ofetch": "^1.3.4",
"openapi-typescript-helpers": "^0.0.7",
"pinia": "^2.1.7",
"ufo": "^1.5.3",
Expand Down
35 changes: 13 additions & 22 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion src/App.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<script setup lang="ts"></script>

<template>
<RouterView />
<Suspense>
<RouterView />
</Suspense>
</template>
22 changes: 22 additions & 0 deletions src/auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ declare global {
const chai: typeof import('vitest')['chai']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const createFetch: typeof import('./composables/use-raw-fetch')['createFetch']
const createImageSchema: typeof import('./utils/schema')['createImageSchema']
const createOpenFetch: typeof import('./composables/fetch')['createOpenFetch']
const createPinia: typeof import('pinia')['createPinia']
const createRawFetch: typeof import('./composables/use-raw-fetch')['createRawFetch']
const createSignal: typeof import('./composables/create-signal')['createSignal']
const createStrictSchema: typeof import('./utils/schema')['createStrictSchema']
const createUseOpenFetch: typeof import('./composables/use-fetch')['createUseOpenFetch']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
Expand All @@ -29,6 +33,7 @@ declare global {
const effectScope: typeof import('vue')['effectScope']
const envVariables: typeof import('./utils/env')['envVariables']
const expect: typeof import('vitest')['expect']
const fillPath: typeof import('./composables/fetch')['fillPath']
const getActivePinia: typeof import('pinia')['getActivePinia']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
Expand Down Expand Up @@ -70,6 +75,7 @@ declare global {
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const openFetchRequestInterceptor: typeof import('./composables/fetch')['openFetchRequestInterceptor']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
Expand Down Expand Up @@ -98,9 +104,11 @@ declare global {
const useAxios: typeof import('./composables/use-axios')['useAxios']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useFetch: typeof import('./composables/use-raw-fetch')['useFetch']
const useImmer: typeof import('./composables/useImmer')['useImmer']
const useLink: typeof import('vue-router')['useLink']
const useQuery: typeof import('./composables/use-query')['useQuery']
const useRawFetch: typeof import('./composables/use-raw-fetch')['useRawFetch']
const useRoute: typeof import('vue-router/auto')['useRoute']
const useRouteQuery: typeof import('./composables/use-route-query')['useRouteQuery']
const useRouter: typeof import('vue-router/auto')['useRouter']
Expand All @@ -122,6 +130,7 @@ declare global {
// for vue template auto import
import { UnwrapRef } from 'vue'
declare module 'vue' {
interface GlobalComponents {}
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly acceptHMRUpdate: UnwrapRef<typeof import('pinia')['acceptHMRUpdate']>
Expand All @@ -133,8 +142,11 @@ declare module 'vue' {
readonly chai: UnwrapRef<typeof import('vitest')['chai']>
readonly computed: UnwrapRef<typeof import('vue')['computed']>
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
readonly createOpenFetch: UnwrapRef<typeof import('./composables/fetch')['createOpenFetch']>
readonly createPinia: UnwrapRef<typeof import('pinia')['createPinia']>
readonly createRawFetch: UnwrapRef<typeof import('./composables/use-raw-fetch')['createRawFetch']>
readonly createSignal: UnwrapRef<typeof import('./composables/create-signal')['createSignal']>
readonly createUseOpenFetch: UnwrapRef<typeof import('./composables/use-fetch')['createUseOpenFetch']>
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
Expand All @@ -145,6 +157,7 @@ declare module 'vue' {
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
readonly envVariables: UnwrapRef<typeof import('./utils/env')['envVariables']>
readonly expect: UnwrapRef<typeof import('vitest')['expect']>
readonly fillPath: UnwrapRef<typeof import('./composables/fetch')['fillPath']>
readonly getActivePinia: UnwrapRef<typeof import('pinia')['getActivePinia']>
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
Expand Down Expand Up @@ -180,6 +193,7 @@ declare module 'vue' {
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
readonly openFetchRequestInterceptor: UnwrapRef<typeof import('./composables/fetch')['openFetchRequestInterceptor']>
readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
Expand All @@ -205,6 +219,7 @@ declare module 'vue' {
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
readonly useQuery: UnwrapRef<typeof import('./composables/use-query')['useQuery']>
readonly useRawFetch: UnwrapRef<typeof import('./composables/use-raw-fetch')['useRawFetch']>
readonly useRoute: UnwrapRef<typeof import('vue-router/auto')['useRoute']>
readonly useRouteQuery: UnwrapRef<typeof import('./composables/use-route-query')['useRouteQuery']>
readonly useRouter: UnwrapRef<typeof import('vue-router/auto')['useRouter']>
Expand All @@ -219,6 +234,7 @@ declare module 'vue' {
}
}
declare module '@vue/runtime-core' {
interface GlobalComponents {}
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly acceptHMRUpdate: UnwrapRef<typeof import('pinia')['acceptHMRUpdate']>
Expand All @@ -230,8 +246,11 @@ declare module '@vue/runtime-core' {
readonly chai: UnwrapRef<typeof import('vitest')['chai']>
readonly computed: UnwrapRef<typeof import('vue')['computed']>
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
readonly createOpenFetch: UnwrapRef<typeof import('./composables/fetch')['createOpenFetch']>
readonly createPinia: UnwrapRef<typeof import('pinia')['createPinia']>
readonly createRawFetch: UnwrapRef<typeof import('./composables/use-raw-fetch')['createRawFetch']>
readonly createSignal: UnwrapRef<typeof import('./composables/create-signal')['createSignal']>
readonly createUseOpenFetch: UnwrapRef<typeof import('./composables/use-fetch')['createUseOpenFetch']>
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
Expand All @@ -242,6 +261,7 @@ declare module '@vue/runtime-core' {
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
readonly envVariables: UnwrapRef<typeof import('./utils/env')['envVariables']>
readonly expect: UnwrapRef<typeof import('vitest')['expect']>
readonly fillPath: UnwrapRef<typeof import('./composables/fetch')['fillPath']>
readonly getActivePinia: UnwrapRef<typeof import('pinia')['getActivePinia']>
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
Expand Down Expand Up @@ -277,6 +297,7 @@ declare module '@vue/runtime-core' {
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
readonly openFetchRequestInterceptor: UnwrapRef<typeof import('./composables/fetch')['openFetchRequestInterceptor']>
readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
Expand All @@ -302,6 +323,7 @@ declare module '@vue/runtime-core' {
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
readonly useQuery: UnwrapRef<typeof import('./composables/use-query')['useQuery']>
readonly useRawFetch: UnwrapRef<typeof import('./composables/use-raw-fetch')['useRawFetch']>
readonly useRoute: UnwrapRef<typeof import('vue-router/auto')['useRoute']>
readonly useRouteQuery: UnwrapRef<typeof import('./composables/use-route-query')['useRouteQuery']>
readonly useRouter: UnwrapRef<typeof import('vue-router/auto')['useRouter']>
Expand Down
112 changes: 112 additions & 0 deletions src/composables/fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import {
$fetch,
type FetchContext,
type FetchError,
type FetchOptions,
ofetch,

Check failure on line 6 in src/composables/fetch.ts

View workflow job for this annotation

GitHub Actions / typecheck

'ofetch' is declared but its value is never read.

Check failure on line 6 in src/composables/fetch.ts

View workflow job for this annotation

GitHub Actions / lint

'ofetch' is defined but never used
} from 'ofetch'
import type {
ErrorResponse,
FilterKeys,
MediaType,
OperationRequestBodyContent,
ResponseObjectMap,
SuccessResponse,
} from 'openapi-typescript-helpers'

export type FetchResponseData<T> = FilterKeys<
SuccessResponse<ResponseObjectMap<T>>,
MediaType
>
export type FetchResponseError<T> = FetchError<
FilterKeys<ErrorResponse<ResponseObjectMap<T>>, MediaType>
>

export type MethodOption<M, P> = 'get' extends keyof P
? { method?: M }
: { method: M }

export type ParamsOption<T> = T extends { parameters?: any; query?: any }
? T['parameters']
: Record<string, never>

export type RequestBodyOption<T> =
OperationRequestBodyContent<T> extends never
? { body?: never }
: undefined extends OperationRequestBodyContent<T>
? { body?: OperationRequestBodyContent<T> }
: { body: OperationRequestBodyContent<T> }

export type FilterMethods<T> = {
[K in keyof Omit<T, 'parameters'> as T[K] extends never | undefined
? never
: K]: T[K]
}

type OpenFetchOptions<
Method,
LowercasedMethod,
Params,
Operation = 'get' extends LowercasedMethod
? 'get' extends keyof Params
? Params['get']
: never
: LowercasedMethod extends keyof Params
? Params[LowercasedMethod]
: never,
> = MethodOption<Method, Params> &
ParamsOption<Operation> &
RequestBodyOption<Operation> &
Omit<FetchOptions, 'query' | 'body' | 'method'>

export type OpenFetchClient<Paths> = <
ReqT extends Extract<keyof Paths, string>,
Methods extends FilterMethods<Paths[ReqT]>,
Method extends
| Extract<keyof Methods, string>
| Uppercase<Extract<keyof Methods, string>>,
LowercasedMethod extends Lowercase<Method> extends keyof FilterMethods<
Paths[ReqT]
>
? Lowercase<Method>
: never,
DefaultMethod extends 'get' extends LowercasedMethod
? 'get'
: LowercasedMethod,
ResT = FetchResponseData<Paths[ReqT][DefaultMethod]>,
>(
url: ReqT,
options?: OpenFetchOptions<Method, LowercasedMethod, Methods>,
) => Promise<ResT>

// More flexible way to rewrite the request path,
// but has problems - https://github.com/unjs/ofetch/issues/319
export function openFetchRequestInterceptor(ctx: FetchContext) {
ctx.request = fillPath(
ctx.request as string,
(ctx.options as { path: Record<string, string> }).path,
)
}

export function createOpenFetch<Paths>(
options: FetchOptions | ((options: FetchOptions) => FetchOptions),
): OpenFetchClient<Paths> {
return (url: string, opts: any) => {
console.log('### :: file: fetch.ts:95 :: opts:', opts)

Check warning on line 95 in src/composables/fetch.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected console statement
return $fetch(
fillPath(url, opts?.path),
typeof options === 'function'
? options(opts)
: {
...options,
...opts,
},
)
}
}

export function fillPath(path: string, params: object = {}) {
for (const [k, v] of Object.entries(params))
path = path.replace(`{${k}}`, encodeURIComponent(String(v)))
return path
}
Loading

0 comments on commit d2cf0d6

Please sign in to comment.