diff --git a/src/core/utils.ts b/src/core/utils.ts index 2cff5bfe4..7f8cba601 100644 --- a/src/core/utils.ts +++ b/src/core/utils.ts @@ -3,12 +3,6 @@ import type { RouteRecordOverride, TreeRouteParam } from './treeNodeValue' import { pascalCase } from 'scule' import { ResolvedOptions, RoutesFolderOption } from '../options' -/** - * Maybe a promise maybe not - * @internal - */ -export type _Awaitable = T | PromiseLike - export type LiteralStringUnion = | LiteralType | (BaseType & Record) diff --git a/src/data-fetching/createDataLoader.ts b/src/data-fetching/createDataLoader.ts index b6c5b66eb..8eca6cef0 100644 --- a/src/data-fetching/createDataLoader.ts +++ b/src/data-fetching/createDataLoader.ts @@ -1,11 +1,10 @@ -import { TypeEqual, expectType } from 'ts-expect' import { type ShallowRef, effectScope, shallowRef } from 'vue' import { IS_USE_DATA_LOADER_KEY, STAGED_NO_VALUE } from './meta-extensions' -import { _Awaitable } from '../core/utils' -import { _PromiseMerged } from './utils' -import { NavigationResult } from './navigation-guard' -import { _RouteLocationNormalizedLoaded } from '../type-extensions/routeLocation' -import { _Router } from '../type-extensions/router' +import { type _PromiseMerged } from './utils' +import { type NavigationResult } from './navigation-guard' +import { type _RouteLocationNormalizedLoaded } from '../type-extensions/routeLocation' +import { type _Router } from '../type-extensions/router' +import { type _Awaitable } from '../utils' /** * Base type for a data loader entry. Each Data Loader has its own entry in the `loaderEntries` (accessible via `[LOADER_ENTRIES_KEY]`) map. @@ -314,33 +313,6 @@ export interface UseDataLoaderResult< reload(route: _RouteLocationNormalizedLoaded): Promise } -function _testing() { - const defineBasicLoader = createDataLoader({ - before: (context) => { - // do nothing, always reexecute - return context - }, - // no caching or anything - after: (data) => {}, - }) - - const useUserData = defineBasicLoader( - async (context) => { - return { - user: { - name: 'Eduardo', - }, - } - }, - { - // lazy: true - } - ) - - const { data } = useUserData() - expectType>(true) -} - /** * Loader function that can be passed to `defineLoader()`. */ diff --git a/src/data-fetching/defineColadaLoader.ts b/src/data-fetching/defineColadaLoader.ts index f044e7077..12682c736 100644 --- a/src/data-fetching/defineColadaLoader.ts +++ b/src/data-fetching/defineColadaLoader.ts @@ -58,30 +58,34 @@ export function defineColadaLoader< isLazy extends boolean, >( name: Name, - options: DefineDataLoaderOptions + options: DefineDataColadaLoaderOptions ): UseDataLoaderColada export function defineColadaLoader( - options: DefineDataLoaderOptions + options: DefineDataColadaLoaderOptions ): UseDataLoaderColada export function defineColadaLoader( nameOrOptions: | _RouteRecordName - | DefineDataLoaderOptions, - _options?: DefineDataLoaderOptions + | DefineDataColadaLoaderOptions, + _options?: DefineDataColadaLoaderOptions ): UseDataLoaderColada { // TODO: make it DEV only and remove the first argument in production mode // resolve option overrides _options = _options || - (nameOrOptions as DefineDataLoaderOptions) + (nameOrOptions as DefineDataColadaLoaderOptions< + isLazy, + _RouteRecordName, + Data + >) const loader = _options.query const options = { ...DEFAULT_DEFINE_LOADER_OPTIONS, ..._options, commit: _options?.commit || 'after-load', - } as DefineDataLoaderOptions + } as DefineDataColadaLoaderOptions let isInitial = true @@ -449,7 +453,7 @@ export function defineColadaLoader( return useDataLoader } -export interface DefineDataLoaderOptions< +export interface DefineDataColadaLoaderOptions< isLazy extends boolean, Name extends _RouteRecordName, Data, @@ -466,14 +470,17 @@ export interface DefineDataLoaderOptions< */ query: DefineLoaderFn< Data, - DataLoaderContext, + DataColadaLoaderContext, _RouteLocationNormalizedLoaded > // TODO: option to skip refresh if the used properties of the route haven't changed } -export interface DataLoaderContext extends DataLoaderContextBase {} +/** + * @internal + */ +export interface DataColadaLoaderContext extends DataLoaderContextBase {} export interface UseDataLoaderColadaResult extends UseDataLoaderResult, @@ -559,7 +566,7 @@ const DEFAULT_DEFINE_LOADER_OPTIONS = { server: true, commit: 'after-load', } satisfies Omit< - DefineDataLoaderOptions, + DefineDataColadaLoaderOptions, 'key' | 'query' > diff --git a/src/data-fetching/defineQueryLoader.spec.ts b/src/data-fetching/defineQueryLoader.spec.ts index 5a0851b1f..b67378367 100644 --- a/src/data-fetching/defineQueryLoader.spec.ts +++ b/src/data-fetching/defineQueryLoader.spec.ts @@ -32,6 +32,7 @@ describe.skip('defineQueryLoader', () => { // dts testing function dts(_fn: () => unknown) {} +// FIXME: move to a test-d.ts file dts(async () => { interface UserData { id: string diff --git a/src/data-fetching/navigation-guard.ts b/src/data-fetching/navigation-guard.ts index ef2ed9dcb..ce4847352 100644 --- a/src/data-fetching/navigation-guard.ts +++ b/src/data-fetching/navigation-guard.ts @@ -10,9 +10,9 @@ import { PENDING_LOCATION_KEY, } from './meta-extensions' import { IS_CLIENT, assign, isDataLoader, setCurrentContext } from './utils' -import type { _Awaitable } from '../core/utils' import type { _RouteLocationNormalizedLoaded } from '../type-extensions/routeLocation' import type { _Router } from '../type-extensions/router' +import { type _Awaitable } from '../utils' /** * TODO: export functions that allow preloading outside of a navigation guard diff --git a/src/data-fetching/utils.ts b/src/data-fetching/utils.ts index 269712cfa..96f089b87 100644 --- a/src/data-fetching/utils.ts +++ b/src/data-fetching/utils.ts @@ -54,11 +54,6 @@ export const IS_CLIENT = typeof window !== 'undefined' export const assign = Object.assign -/** - * @internal - */ -export type _MaybePromise = T | Promise - /** * Track the reads of a route and its properties * @internal diff --git a/src/options.ts b/src/options.ts index 8feaaab2d..eff298b17 100644 --- a/src/options.ts +++ b/src/options.ts @@ -1,9 +1,10 @@ import { isPackageExists as isPackageInstalled } from 'local-pkg' -import { _Awaitable, getFileBasedRouteName, isArray, warn } from './core/utils' +import { getFileBasedRouteName, isArray, warn } from './core/utils' import type { TreeNode } from './core/tree' import { resolve } from 'pathe' import { EditableTreeNode } from './core/extendRoutes' import { type ParseSegmentOptions } from './core/treeNodeValue' +import { type _Awaitable } from './utils' /** * Options for a routes folder. diff --git a/src/runtime.ts b/src/runtime.ts index 130bf5953..f2f3d63ba 100644 --- a/src/runtime.ts +++ b/src/runtime.ts @@ -1,17 +1,44 @@ import { type RouteRecordRaw } from 'vue-router' import { type _Router } from './type-extensions/router' +export type { + UseDataLoader, + UseDataLoaderInternals, + UseDataLoaderResult, + DataLoaderContextBase, + DataLoaderEntryBase, + DefineDataLoaderOptionsBase, + DefineLoaderFn, + _DataMaybeLazy, +} from './data-fetching/createDataLoader' + // new data fetching export { defineBasicLoader } from './data-fetching/defineLoader' +export type { + DataLoaderContext, + DefineDataLoaderOptions, +} from './data-fetching/defineLoader' export { DataLoaderPlugin, NavigationResult, } from './data-fetching/navigation-guard' -export type { DataLoaderPluginOptions } from './data-fetching/navigation-guard' +export type { + DataLoaderPluginOptions, + SetupLoaderGuardOptions, + _DataLoaderRedirectResult, +} from './data-fetching/navigation-guard' + +export type { + DataLoaderColadaEntry, + DataColadaLoaderContext, + DefineDataColadaLoaderOptions, + UseDataLoaderColada, + UseDataLoaderColadaResult, +} from './data-fetching/defineColadaLoader' +export { defineColadaLoader } from './data-fetching/defineColadaLoader' // NOTE: for tests only // export * from './data-fetching/defineQueryLoader' -export { defineColadaLoader } from './data-fetching/defineColadaLoader' /** * Defines properties of the route for the current page component. diff --git a/src/type-extensions/RouterTyped.test-d.ts b/src/type-extensions/RouterTyped.test-d.ts index 8bf77313a..23d1b6f84 100644 --- a/src/type-extensions/RouterTyped.test-d.ts +++ b/src/type-extensions/RouterTyped.test-d.ts @@ -1,5 +1,4 @@ import { describe, it, expectTypeOf } from 'vitest' -import { expectType } from 'ts-expect' import type { RouteRecordInfo, _RouteMapGeneric, @@ -15,10 +14,6 @@ function defineRouter(): RouterTyped { return {} as RouterTyped } -function typeTest(fn: () => any) { - return fn -} - describe('RouterTyped', () => { // type is needed instead of an interface // https://github.com/microsoft/TypeScript/issues/15300 @@ -51,105 +46,95 @@ describe('RouterTyped', () => { const router = defineRouter() it('resolve', () => { - typeTest(() => { - expectTypeOf>(router.resolve({ name: '/a' }).params) - expectTypeOf<{ a: ParamValue }>( - router.resolve({ name: '/[a]' }).params - ) + expectTypeOf>(router.resolve({ name: '/a' }).params) + expectTypeOf<{ a: ParamValue }>( + router.resolve({ name: '/[a]' }).params + ) - expectTypeOf>( - router.resolve({ name: '/a' }) - ) - expectTypeOf<'/a'>( - // @ts-expect-error: cannot infer based on path - router.resolve({ path: '/a' }).name - ) - expectTypeOf(router.resolve({ path: '/a' }).name) - }) + expectTypeOf>( + router.resolve({ name: '/a' }) + ) + expectTypeOf<'/a'>( + // @ts-expect-error: cannot infer based on path + router.resolve({ path: '/a' }).name + ) + expectTypeOf(router.resolve({ path: '/a' }).name) }) it('resolve', () => { - typeTest(() => { - router.push({ name: '/a', params: { a: 2 } }) - // @ts-expect-error - router.push({ name: '/[a]', params: {} }) - // still allow relative params - router.push({ name: '/[a]' }) - // @ts-expect-error - router.push({ name: '/[a]', params: { a: [2] } }) - router.push({ name: '/[id]+', params: { id: [2] } }) - router.push({ name: '/[id]+', params: { id: [2, '3'] } }) - // @ts-expect-error - router.push({ name: '/[id]+', params: { id: 2 } }) - }) + router.push({ name: '/a', params: { a: 2 } }) + // @ts-expect-error + router.push({ name: '/[a]', params: {} }) + // still allow relative params + router.push({ name: '/[a]' }) + // @ts-expect-error + router.push({ name: '/[a]', params: { a: [2] } }) + router.push({ name: '/[id]+', params: { id: [2] } }) + router.push({ name: '/[id]+', params: { id: [2, '3'] } }) + // @ts-expect-error + router.push({ name: '/[id]+', params: { id: 2 } }) }) it('beforeEach', () => { - typeTest(() => { - router.beforeEach((to, from) => { - // @ts-expect-error: no route named this way - if (to.name === '/[id]') { - } else if (to.name === '/[a]') { - expectTypeOf<{ a: ParamValue }>(to.params) - } - // @ts-expect-error: no route named this way - if (from.name === '/[id]') { - } else if (to.name === '/[a]') { - expectTypeOf<{ a: ParamValue }>(to.params) - } - if (Math.random()) { - return { name: '/[a]', params: { a: 2 } } - } else if (Math.random()) { - return '/any route does' - } - return true - }) + router.beforeEach((to, from) => { + // @ts-expect-error: no route named this way + if (to.name === '/[id]') { + } else if (to.name === '/[a]') { + expectTypeOf<{ a: ParamValue }>(to.params) + } + // @ts-expect-error: no route named this way + if (from.name === '/[id]') { + } else if (to.name === '/[a]') { + expectTypeOf<{ a: ParamValue }>(to.params) + } + if (Math.random()) { + return { name: '/[a]', params: { a: 2 } } + } else if (Math.random()) { + return '/any route does' + } + return true }) }) it('beforeResolve', () => { - typeTest(() => { - router.beforeResolve((to, from) => { - // @ts-expect-error: no route named this way - if (to.name === '/[id]') { - } else if (to.name === '/[a]') { - expectTypeOf<{ a: ParamValue }>(to.params) - } - // @ts-expect-error: no route named this way - if (from.name === '/[id]') { - } else if (to.name === '/[a]') { - expectTypeOf<{ a: ParamValue }>(to.params) - } - if (Math.random()) { - return { name: '/[a]', params: { a: 2 } } - } else if (Math.random()) { - return '/any route does' - } - return true - }) + router.beforeResolve((to, from) => { + // @ts-expect-error: no route named this way + if (to.name === '/[id]') { + } else if (to.name === '/[a]') { + expectTypeOf<{ a: ParamValue }>(to.params) + } + // @ts-expect-error: no route named this way + if (from.name === '/[id]') { + } else if (to.name === '/[a]') { + expectTypeOf<{ a: ParamValue }>(to.params) + } + if (Math.random()) { + return { name: '/[a]', params: { a: 2 } } + } else if (Math.random()) { + return '/any route does' + } + return true }) }) it('afterEach', () => { - typeTest(() => { - router.afterEach((to, from) => { - // @ts-expect-error: no route named this way - if (to.name === '/[id]') { - } else if (to.name === '/[a]') { - expectTypeOf<{ a: ParamValue }>(to.params) - } - // @ts-expect-error: no route named this way - if (from.name === '/[id]') { - } else if (to.name === '/[a]') { - expectTypeOf<{ a: ParamValue }>(to.params) - } - if (Math.random()) { - return { name: '/[a]', params: { a: 2 } } - } else if (Math.random()) { - return '/any route does' - } - return true - }) + router.afterEach((to, from) => { + // @ts-expect-error: no route named this way + if (to.name === '/[id]') { + } else if (to.name === '/[a]') { + expectTypeOf<{ a: ParamValue }>(to.params) + } + // @ts-expect-error: no route named this way + if (from.name === '/[id]') { + } else if (to.name === '/[a]') { + expectTypeOf<{ a: ParamValue }>(to.params) + } + if (Math.random()) { + return { name: '/[a]', params: { a: 2 } } + } else if (Math.random()) { + return '/any route does' + } + return true }) }) }) diff --git a/src/type-extensions/navigationGuards.ts b/src/type-extensions/navigationGuards.ts index c24e63bf0..01d48c7ff 100644 --- a/src/type-extensions/navigationGuards.ts +++ b/src/type-extensions/navigationGuards.ts @@ -15,7 +15,7 @@ import type { } from './routeLocation' import type { _Router } from './router' import type { RouteNamedMap, TypesConfig } from './types-config' -import type { _MaybePromise } from '../data-fetching/utils' +import { type _Awaitable } from '../utils' /** * Return types for a Navigation Guard. Accepts a type param for the RouteMap. @@ -49,7 +49,7 @@ export interface NavigationGuardWithThisTyped< from: RouteLocationNormalizedLoadedTypedList[keyof RouteMap], // intentionally not typed to make people use the return next: NavigationGuardNext - ): _MaybePromise> + ): _Awaitable> } /** @@ -73,7 +73,7 @@ export interface _NavigationGuardResolved { from: _RouteLocationNormalizedLoaded, // intentionally not typed to make people use the return next: NavigationGuardNext - ): _MaybePromise + ): _Awaitable } /** @@ -85,7 +85,7 @@ export interface NavigationGuardTyped { from: RouteLocationNormalizedLoadedTypedList[keyof RouteMap], // intentionally not typed to make people use the return next: NavigationGuardNext - ): _MaybePromise> + ): _Awaitable> } /** diff --git a/src/types.ts b/src/types.ts index 5c94fc56d..22e191a10 100644 --- a/src/types.ts +++ b/src/types.ts @@ -72,17 +72,3 @@ export type { TreeNodeValueParam, TreeNodeValueStatic, } from './core/treeNodeValue' - -// expose for generated type extensions -export type { - DefineLoaderFn as _DefineLoaderFn, - UseDataLoader as _UseDataLoader, -} from './data-fetching/createDataLoader' -export type { - // ... - NavigationResult, -} from './data-fetching/navigation-guard' -export type { - DefineDataLoaderOptions as _DefineDataLoaderOptions, - DataLoaderContext as _DataLoaderContext, -} from './data-fetching/defineLoader' diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 000000000..a6bf3beca --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,5 @@ +/** + * Maybe a promise maybe not + * @internal + */ +export type _Awaitable = T | PromiseLike