From 380c3e1f7be29fe34aa6bb4c9b2cc307b56e3cf1 Mon Sep 17 00:00:00 2001 From: Sheraff Date: Thu, 6 Aug 2026 00:12:03 +0200 Subject: [PATCH 1/5] test createFileRoute factory behavior --- packages/react-router/tests/fileRoute.test.ts | 27 ++++++++++++++++++- packages/solid-router/tests/fileRoute.test.ts | 27 ++++++++++++++++++- packages/vue-router/tests/fileRoute.test.ts | 27 ++++++++++++++++++- 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/packages/react-router/tests/fileRoute.test.ts b/packages/react-router/tests/fileRoute.test.ts index 2a8e225371e..9f3fa290d3a 100644 --- a/packages/react-router/tests/fileRoute.test.ts +++ b/packages/react-router/tests/fileRoute.test.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -import { describe, it, expect } from 'vitest' +import { afterEach, describe, it, expect, vi } from 'vitest' import { getRouteApi, createFileRoute, @@ -7,8 +7,33 @@ import { createLazyFileRoute, LazyRoute, AnyRoute, + FileRoute, } from '../src' +afterEach(() => { + vi.restoreAllMocks() +}) + +describe('createFileRoute', () => { + it('creates a non-root route without a deprecation warning', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}) + // @ts-expect-error + const route = createFileRoute('')({}) + + expect(route.isRoot).toBe(false) + expect(warn).not.toHaveBeenCalled() + }) + + it('keeps the deprecation warning for direct FileRoute usage', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}) + // @ts-expect-error + const route = new FileRoute('').createRoute({}) + + expect(route.isRoot).toBe(false) + expect(warn).toHaveBeenCalledOnce() + }) +}) + describe('createFileRoute has the same hooks as getRouteApi', () => { const routeApi = getRouteApi('foo') const hookNames = Object.keys(routeApi).filter((key) => key.startsWith('use')) diff --git a/packages/solid-router/tests/fileRoute.test.ts b/packages/solid-router/tests/fileRoute.test.ts index f6b92298c8e..5d459d1b7ed 100644 --- a/packages/solid-router/tests/fileRoute.test.ts +++ b/packages/solid-router/tests/fileRoute.test.ts @@ -1,13 +1,38 @@ /* eslint-disable */ -import { describe, it, expect } from 'vitest' +import { afterEach, describe, it, expect, vi } from 'vitest' import { getRouteApi, createFileRoute, createLazyRoute, createLazyFileRoute, LazyRoute, + FileRoute, } from '../src' +afterEach(() => { + vi.restoreAllMocks() +}) + +describe('createFileRoute', () => { + it('creates a non-root route without a deprecation warning', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}) + // @ts-expect-error + const route = createFileRoute('')({}) + + expect(route.isRoot).toBe(false) + expect(warn).not.toHaveBeenCalled() + }) + + it('keeps the deprecation warning for direct FileRoute usage', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}) + // @ts-expect-error + const route = new FileRoute('').createRoute({}) + + expect(route.isRoot).toBe(false) + expect(warn).toHaveBeenCalledOnce() + }) +}) + describe('createFileRoute has the same hooks as getRouteApi', () => { const routeApi = getRouteApi('foo') const hookNames = Object.keys(routeApi).filter((key) => key.startsWith('use')) diff --git a/packages/vue-router/tests/fileRoute.test.ts b/packages/vue-router/tests/fileRoute.test.ts index f6b92298c8e..5d459d1b7ed 100644 --- a/packages/vue-router/tests/fileRoute.test.ts +++ b/packages/vue-router/tests/fileRoute.test.ts @@ -1,13 +1,38 @@ /* eslint-disable */ -import { describe, it, expect } from 'vitest' +import { afterEach, describe, it, expect, vi } from 'vitest' import { getRouteApi, createFileRoute, createLazyRoute, createLazyFileRoute, LazyRoute, + FileRoute, } from '../src' +afterEach(() => { + vi.restoreAllMocks() +}) + +describe('createFileRoute', () => { + it('creates a non-root route without a deprecation warning', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}) + // @ts-expect-error + const route = createFileRoute('')({}) + + expect(route.isRoot).toBe(false) + expect(warn).not.toHaveBeenCalled() + }) + + it('keeps the deprecation warning for direct FileRoute usage', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}) + // @ts-expect-error + const route = new FileRoute('').createRoute({}) + + expect(route.isRoot).toBe(false) + expect(warn).toHaveBeenCalledOnce() + }) +}) + describe('createFileRoute has the same hooks as getRouteApi', () => { const routeApi = getRouteApi('foo') const hookNames = Object.keys(routeApi).filter((key) => key.startsWith('use')) From 572da9dc985c9fead80878db0b403c7bdce97bff Mon Sep 17 00:00:00 2001 From: Sheraff Date: Thu, 6 Aug 2026 00:17:51 +0200 Subject: [PATCH 2/5] create file routes directly --- packages/react-router/src/fileRoute.ts | 17 ++++++++++------- packages/solid-router/src/fileRoute.ts | 15 +++++++++------ packages/vue-router/src/fileRoute.ts | 15 +++++++++------ 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/packages/react-router/src/fileRoute.ts b/packages/react-router/src/fileRoute.ts index 46b96240a47..633fa988123 100644 --- a/packages/react-router/src/fileRoute.ts +++ b/packages/react-router/src/fileRoute.ts @@ -1,4 +1,4 @@ -import { createRoute } from './route' +import { createRoute as createRouteImpl } from './route' import { useMatch } from './useMatch' import { useLoaderDeps } from './useLoaderDeps' @@ -42,7 +42,7 @@ import type { UseRouteContextRoute } from './useRouteContext' * route. The returned function accepts standard route options. In normal usage * the `path` string is inserted and maintained by the `tsr` generator. * - * @param path File path literal for the route (usually auto-generated). + * @param _path File path literal for the route (usually auto-generated). * @returns A function that accepts Route options and returns a Route instance. * @link https://tanstack.com/router/latest/docs/framework/react/api/router/createFileRouteFunction */ @@ -54,11 +54,14 @@ export function createFileRoute< TFullPath extends RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'], >( - path?: TFilePath, + _path?: TFilePath, ): FileRoute['createRoute'] { - return new FileRoute(path, { - silent: true, - }).createRoute + const createRoute = (options?: any) => { + const route = createRouteImpl(options) + ;(route as any).isRoot = false + return route + } + return createRoute as any } /** @@ -151,7 +154,7 @@ export class FileRoute< ) } } - const route = createRoute(options as any) + const route = createRouteImpl(options as any) ;(route as any).isRoot = false return route as any } diff --git a/packages/solid-router/src/fileRoute.ts b/packages/solid-router/src/fileRoute.ts index 35aa4de1717..18638b615ab 100644 --- a/packages/solid-router/src/fileRoute.ts +++ b/packages/solid-router/src/fileRoute.ts @@ -1,4 +1,4 @@ -import { createRoute } from './route' +import { createRoute as createRouteImpl } from './route' import { useMatch } from './useMatch' import { useLoaderDeps } from './useLoaderDeps' @@ -43,11 +43,14 @@ export function createFileRoute< TFullPath extends RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'], >( - path?: TFilePath, + _path?: TFilePath, ): FileRoute['createRoute'] { - return new FileRoute(path, { - silent: true, - }).createRoute + const createRoute = (options?: any) => { + const route = createRouteImpl(options) + ;(route as any).isRoot = false + return route + } + return createRoute as any } /** @@ -140,7 +143,7 @@ export class FileRoute< ) } } - const route = createRoute(options as any) + const route = createRouteImpl(options as any) ;(route as any).isRoot = false return route as any } diff --git a/packages/vue-router/src/fileRoute.ts b/packages/vue-router/src/fileRoute.ts index 672328b5607..0fa9f89f0e7 100644 --- a/packages/vue-router/src/fileRoute.ts +++ b/packages/vue-router/src/fileRoute.ts @@ -1,4 +1,4 @@ -import { createRoute } from './route' +import { createRoute as createRouteImpl } from './route' import { useMatch } from './useMatch' import { useLoaderDeps } from './useLoaderDeps' @@ -43,11 +43,14 @@ export function createFileRoute< TFullPath extends RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'], >( - path?: TFilePath, + _path?: TFilePath, ): FileRoute['createRoute'] { - return new FileRoute(path, { - silent: true, - }).createRoute + const createRoute = (options?: any) => { + const route = createRouteImpl(options) + ;(route as any).isRoot = false + return route + } + return createRoute as any } /** @@ -140,7 +143,7 @@ export class FileRoute< ) } } - const route = createRoute(options as any) + const route = createRouteImpl(options as any) ;(route as any).isRoot = false return route as any } From d34c25f17fe08d91413a3b66cc3675cb66debe7c Mon Sep 17 00:00:00 2001 From: Sheraff Date: Thu, 6 Aug 2026 00:34:20 +0200 Subject: [PATCH 3/5] preserve createFileRoute parameter name --- packages/react-router/src/fileRoute.ts | 5 +++-- packages/solid-router/src/fileRoute.ts | 3 ++- packages/vue-router/src/fileRoute.ts | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/react-router/src/fileRoute.ts b/packages/react-router/src/fileRoute.ts index 633fa988123..388745c728b 100644 --- a/packages/react-router/src/fileRoute.ts +++ b/packages/react-router/src/fileRoute.ts @@ -42,7 +42,7 @@ import type { UseRouteContextRoute } from './useRouteContext' * route. The returned function accepts standard route options. In normal usage * the `path` string is inserted and maintained by the `tsr` generator. * - * @param _path File path literal for the route (usually auto-generated). + * @param path File path literal for the route (usually auto-generated). * @returns A function that accepts Route options and returns a Route instance. * @link https://tanstack.com/router/latest/docs/framework/react/api/router/createFileRouteFunction */ @@ -54,7 +54,8 @@ export function createFileRoute< TFullPath extends RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'], >( - _path?: TFilePath, + // eslint-disable-next-line unused-imports/no-unused-vars + path?: TFilePath, ): FileRoute['createRoute'] { const createRoute = (options?: any) => { const route = createRouteImpl(options) diff --git a/packages/solid-router/src/fileRoute.ts b/packages/solid-router/src/fileRoute.ts index 18638b615ab..9f985909afb 100644 --- a/packages/solid-router/src/fileRoute.ts +++ b/packages/solid-router/src/fileRoute.ts @@ -43,7 +43,8 @@ export function createFileRoute< TFullPath extends RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'], >( - _path?: TFilePath, + // eslint-disable-next-line unused-imports/no-unused-vars + path?: TFilePath, ): FileRoute['createRoute'] { const createRoute = (options?: any) => { const route = createRouteImpl(options) diff --git a/packages/vue-router/src/fileRoute.ts b/packages/vue-router/src/fileRoute.ts index 0fa9f89f0e7..ba2d72a2d36 100644 --- a/packages/vue-router/src/fileRoute.ts +++ b/packages/vue-router/src/fileRoute.ts @@ -43,7 +43,8 @@ export function createFileRoute< TFullPath extends RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'], >( - _path?: TFilePath, + // eslint-disable-next-line unused-imports/no-unused-vars + path?: TFilePath, ): FileRoute['createRoute'] { const createRoute = (options?: any) => { const route = createRouteImpl(options) From d11e28c168f0d9e23d170633ffcd3d1bd100aa83 Mon Sep 17 00:00:00 2001 From: Sheraff Date: Thu, 6 Aug 2026 12:55:07 +0200 Subject: [PATCH 4/5] cleanup --- packages/react-router/src/fileRoute.ts | 11 +++++------ packages/solid-router/src/fileRoute.ts | 11 +++++------ packages/vue-router/src/fileRoute.ts | 11 +++++------ 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/packages/react-router/src/fileRoute.ts b/packages/react-router/src/fileRoute.ts index 388745c728b..e5fdb4993b9 100644 --- a/packages/react-router/src/fileRoute.ts +++ b/packages/react-router/src/fileRoute.ts @@ -1,4 +1,4 @@ -import { createRoute as createRouteImpl } from './route' +import { createRoute } from './route' import { useMatch } from './useMatch' import { useLoaderDeps } from './useLoaderDeps' @@ -57,12 +57,11 @@ export function createFileRoute< // eslint-disable-next-line unused-imports/no-unused-vars path?: TFilePath, ): FileRoute['createRoute'] { - const createRoute = (options?: any) => { - const route = createRouteImpl(options) + return (options) => { + const route = createRoute(options as any) ;(route as any).isRoot = false - return route + return route as any } - return createRoute as any } /** @@ -155,7 +154,7 @@ export class FileRoute< ) } } - const route = createRouteImpl(options as any) + const route = createRoute(options as any) ;(route as any).isRoot = false return route as any } diff --git a/packages/solid-router/src/fileRoute.ts b/packages/solid-router/src/fileRoute.ts index 9f985909afb..1115ee54144 100644 --- a/packages/solid-router/src/fileRoute.ts +++ b/packages/solid-router/src/fileRoute.ts @@ -1,4 +1,4 @@ -import { createRoute as createRouteImpl } from './route' +import { createRoute } from './route' import { useMatch } from './useMatch' import { useLoaderDeps } from './useLoaderDeps' @@ -46,12 +46,11 @@ export function createFileRoute< // eslint-disable-next-line unused-imports/no-unused-vars path?: TFilePath, ): FileRoute['createRoute'] { - const createRoute = (options?: any) => { - const route = createRouteImpl(options) + return (options) => { + const route = createRoute(options as any) ;(route as any).isRoot = false - return route + return route as any } - return createRoute as any } /** @@ -144,7 +143,7 @@ export class FileRoute< ) } } - const route = createRouteImpl(options as any) + const route = createRoute(options as any) ;(route as any).isRoot = false return route as any } diff --git a/packages/vue-router/src/fileRoute.ts b/packages/vue-router/src/fileRoute.ts index ba2d72a2d36..0e0b6c8368f 100644 --- a/packages/vue-router/src/fileRoute.ts +++ b/packages/vue-router/src/fileRoute.ts @@ -1,4 +1,4 @@ -import { createRoute as createRouteImpl } from './route' +import { createRoute } from './route' import { useMatch } from './useMatch' import { useLoaderDeps } from './useLoaderDeps' @@ -46,12 +46,11 @@ export function createFileRoute< // eslint-disable-next-line unused-imports/no-unused-vars path?: TFilePath, ): FileRoute['createRoute'] { - const createRoute = (options?: any) => { - const route = createRouteImpl(options) + return (options) => { + const route = createRoute(options as any) ;(route as any).isRoot = false - return route + return route as any } - return createRoute as any } /** @@ -144,7 +143,7 @@ export class FileRoute< ) } } - const route = createRouteImpl(options as any) + const route = createRoute(options as any) ;(route as any).isRoot = false return route as any } From abf976721ce17febb722896c9df132f96239b28f Mon Sep 17 00:00:00 2001 From: Sheraff Date: Thu, 6 Aug 2026 12:56:18 +0200 Subject: [PATCH 5/5] changeset --- .changeset/easy-zoos-greet.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/easy-zoos-greet.md diff --git a/.changeset/easy-zoos-greet.md b/.changeset/easy-zoos-greet.md new file mode 100644 index 00000000000..6e222967819 --- /dev/null +++ b/.changeset/easy-zoos-greet.md @@ -0,0 +1,7 @@ +--- +'@tanstack/react-router': patch +'@tanstack/solid-router': patch +'@tanstack/vue-router': patch +--- + +createFileRoute does not rely on FileRoute class