diff --git a/packages/react-router-devtools/src/vite/utils/data-functions-augment.test.ts b/packages/react-router-devtools/src/vite/utils/data-functions-augment.test.ts index fa9ac43..ce14d58 100644 --- a/packages/react-router-devtools/src/vite/utils/data-functions-augment.test.ts +++ b/packages/react-router-devtools/src/vite/utils/data-functions-augment.test.ts @@ -722,6 +722,99 @@ describe("transform", () => { }) }) +describe("aliased import transforms", () => { + it("should transform aliased loader import where local name is loader", () => { + const result = augmentDataFetchingFunctions( + ` + import { myLoader as loader } from "./loaders"; + export { loader }; + `, + "test", + "/file/path" + ) + const expected = removeWhitespace(` + import { withLoaderWrapper as _withLoaderWrapper } from "react-router-devtools/server"; + import { myLoader as _loader } from "./loaders"; + export const loader = _withLoaderWrapper(_loader, "test"); + `) + expect(removeWhitespace(result.code)).toStrictEqual(expected) + }) + + it("should transform aliased action import where local name is action", () => { + const result = augmentDataFetchingFunctions( + ` + import { myLoaderAction as action } from "./actions"; + export { action }; + `, + "test", + "/file/path" + ) + const expected = removeWhitespace(` + import { withActionWrapper as _withActionWrapper } from "react-router-devtools/server"; + import { myLoaderAction as _action } from "./actions"; + export const action = _withActionWrapper(_action, "test"); + `) + expect(removeWhitespace(result.code)).toStrictEqual(expected) + }) + + it("should transform aliased clientLoader import where local name is clientLoader", () => { + const result = augmentDataFetchingFunctions( + ` + import { myLoaderClientLoader as clientLoader } from "./loaders"; + export { clientLoader }; + `, + "test", + "/file/path" + ) + const expected = removeWhitespace(` + import { withClientLoaderWrapper as _withClientLoaderWrapper } from "react-router-devtools/client"; + import { myLoaderClientLoader as _clientLoader } from "./loaders"; + export const clientLoader = _withClientLoaderWrapper(_clientLoader, "test"); + `) + expect(removeWhitespace(result.code)).toStrictEqual(expected) + }) + + it("should transform aliased clientAction import where local name is clientAction", () => { + const result = augmentDataFetchingFunctions( + ` + import { myLoaderClientAction as clientAction } from "./actions"; + export { clientAction }; + `, + "test", + "/file/path" + ) + const expected = removeWhitespace(` + import { withClientActionWrapper as _withClientActionWrapper } from "react-router-devtools/client"; + import { myLoaderClientAction as _clientAction } from "./actions"; + export const clientAction = _withClientActionWrapper(_clientAction, "test"); + `) + expect(removeWhitespace(result.code)).toStrictEqual(expected) + }) + + it("should transform aliased loader import and update usages in code", () => { + const result = augmentDataFetchingFunctions( + ` + import { myLoader as loader } from "./loaders"; + const test = () => { + return loader(); + } + export { loader }; + `, + "test", + "/file/path" + ) + const expected = removeWhitespace(` + import { withLoaderWrapper as _withLoaderWrapper } from "react-router-devtools/server"; + import { myLoader as _loader } from "./loaders"; + const test = () => { + return _loader(); + }; + export const loader = _withLoaderWrapper(_loader, "test"); + `) + expect(removeWhitespace(result.code)).toStrictEqual(expected) + }) +}) + it("should transform the re-exports when it's re-exported from another file with multiple re-exports", () => { const result = augmentDataFetchingFunctions( ` diff --git a/packages/react-router-devtools/src/vite/utils/data-functions-augment.ts b/packages/react-router-devtools/src/vite/utils/data-functions-augment.ts index 51f8b0d..44ac448 100644 --- a/packages/react-router-devtools/src/vite/utils/data-functions-augment.ts +++ b/packages/react-router-devtools/src/vite/utils/data-functions-augment.ts @@ -43,7 +43,17 @@ const transform = (ast: ParseResult, routeId: string) => { if (!t.isImportSpecifier(specifier) || !t.isIdentifier(specifier.imported)) { continue } - const name = specifier.imported.name + const importedName = specifier.imported.name + const localName = specifier.local.name + // Handle aliased imports where local name is a target export + // e.g., import { myLoader as loader } + if (ALL_EXPORTS.includes(localName) && !ALL_EXPORTS.includes(importedName)) { + const uniqueName = path.scope.generateUidIdentifier(localName) + imports.push([localName, uniqueName]) + path.scope.rename(localName, uniqueName.name) + continue + } + const name = importedName if (!ALL_EXPORTS.includes(name)) { continue } diff --git a/packages/react-router-devtools/src/vite/utils/inject-context.test.ts b/packages/react-router-devtools/src/vite/utils/inject-context.test.ts index c663ea3..1af443d 100644 --- a/packages/react-router-devtools/src/vite/utils/inject-context.test.ts +++ b/packages/react-router-devtools/src/vite/utils/inject-context.test.ts @@ -622,6 +622,99 @@ describe("transform", () => { }) }) +describe("aliased import transforms", () => { + it("should transform aliased loader import where local name is loader", () => { + const result = injectContext( + ` + import { myLoader as loader } from "./loaders"; + export { loader }; + `, + "test", + "/file/path" + ) + const expected = removeWhitespace(` + import { withLoaderContextWrapper as _withLoaderContextWrapper } from "react-router-devtools/context"; + import { myLoader as _loader } from "./loaders"; + export const loader = _withLoaderContextWrapper(_loader, "test"); + `) + expect(removeWhitespace(result.code)).toStrictEqual(expected) + }) + + it("should transform aliased action import where local name is action", () => { + const result = injectContext( + ` + import { myLoaderAction as action } from "./actions"; + export { action }; + `, + "test", + "/file/path" + ) + const expected = removeWhitespace(` + import { withActionContextWrapper as _withActionContextWrapper } from "react-router-devtools/context"; + import { myLoaderAction as _action } from "./actions"; + export const action = _withActionContextWrapper(_action, "test"); + `) + expect(removeWhitespace(result.code)).toStrictEqual(expected) + }) + + it("should transform aliased clientLoader import where local name is clientLoader", () => { + const result = injectContext( + ` + import { myLoaderClientLoader as clientLoader } from "./loaders"; + export { clientLoader }; + `, + "test", + "/file/path" + ) + const expected = removeWhitespace(` + import { withClientLoaderContextWrapper as _withClientLoaderContextWrapper } from "react-router-devtools/context"; + import { myLoaderClientLoader as _clientLoader } from "./loaders"; + export const clientLoader = _withClientLoaderContextWrapper(_clientLoader, "test"); + `) + expect(removeWhitespace(result.code)).toStrictEqual(expected) + }) + + it("should transform aliased clientAction import where local name is clientAction", () => { + const result = injectContext( + ` + import { myLoaderClientAction as clientAction } from "./actions"; + export { clientAction }; + `, + "test", + "/file/path" + ) + const expected = removeWhitespace(` + import { withClientActionContextWrapper as _withClientActionContextWrapper } from "react-router-devtools/context"; + import { myLoaderClientAction as _clientAction } from "./actions"; + export const clientAction = _withClientActionContextWrapper(_clientAction, "test"); + `) + expect(removeWhitespace(result.code)).toStrictEqual(expected) + }) + + it("should transform aliased loader import and update usages in code", () => { + const result = injectContext( + ` + import { myLoader as loader } from "./loaders"; + const test = () => { + return loader(); + } + export { loader }; + `, + "test", + "/file/path" + ) + const expected = removeWhitespace(` + import { withLoaderContextWrapper as _withLoaderContextWrapper } from "react-router-devtools/context"; + import { myLoader as _loader } from "./loaders"; + const test = () => { + return _loader(); + }; + export const loader = _withLoaderContextWrapper(_loader, "test"); + `) + expect(removeWhitespace(result.code)).toStrictEqual(expected) + }) +}) + it("should transform the re-exports when it's re-exported from another file with multiple re-exports", () => { const result = injectContext( ` diff --git a/packages/react-router-devtools/src/vite/utils/inject-context.ts b/packages/react-router-devtools/src/vite/utils/inject-context.ts index 161a778..6ca499e 100644 --- a/packages/react-router-devtools/src/vite/utils/inject-context.ts +++ b/packages/react-router-devtools/src/vite/utils/inject-context.ts @@ -33,7 +33,17 @@ const transform = (ast: ParseResult, routeId: string) => { if (!t.isImportSpecifier(specifier) || !t.isIdentifier(specifier.imported)) { continue } - const name = specifier.imported.name + const importedName = specifier.imported.name + const localName = specifier.local.name + // Handle aliased imports where local name is a target export + // e.g., import { myLoader as loader } + if (ALL_EXPORTS.includes(localName) && !ALL_EXPORTS.includes(importedName)) { + const uniqueName = path.scope.generateUidIdentifier(localName) + imports.push([localName, uniqueName]) + path.scope.rename(localName, uniqueName.name) + continue + } + const name = importedName if (!ALL_EXPORTS.includes(name)) { continue } diff --git a/packages/react-router-devtools/src/vite/utils/middleware-augment.test.ts b/packages/react-router-devtools/src/vite/utils/middleware-augment.test.ts index 722ed95..50ca17f 100644 --- a/packages/react-router-devtools/src/vite/utils/middleware-augment.test.ts +++ b/packages/react-router-devtools/src/vite/utils/middleware-augment.test.ts @@ -630,4 +630,71 @@ describe("middleware augmentation", () => { expect(result.code).toContain('"authMiddleware"') }) }) + + describe("aliased import transforms", () => { + it("should transform aliased middleware import where local name is middleware", () => { + const result = augmentMiddlewareFunctions( + ` + import { authMiddleware as middleware } from "./middlewares"; + export { middleware }; + `, + "test", + "/file/path" + ) + // Should skip transformation for re-exported imported middleware + // The aliased import handler renames it but since it's imported and re-exported, it skips + expect(result.code).toContain("authMiddleware") + }) + + it("should transform aliased clientMiddleware import where local name is clientMiddleware", () => { + const result = augmentMiddlewareFunctions( + ` + import { clientAuthMiddleware as clientMiddleware } from "./middlewares"; + export { clientMiddleware }; + `, + "test", + "/file/path" + ) + // Should skip transformation for re-exported imported middleware + expect(result.code).toContain("clientAuthMiddleware") + }) + + it("should handle aliased middleware import used in array", () => { + const result = augmentMiddlewareFunctions( + ` + import { someAuthFn as authMiddleware } from "./auth"; + export const middleware = [authMiddleware]; + `, + "test", + "/file/path" + ) + const expected = removeWhitespace(` + import { withMiddlewareWrapperSingle as _withMiddlewareWrapperSingle } from "react-router-devtools/server"; + import { someAuthFn as authMiddleware } from "./auth"; + export const middleware = [ + _withMiddlewareWrapperSingle(authMiddleware, "test", 0, "authMiddleware") + ]; + `) + expect(removeWhitespace(result.code)).toStrictEqual(expected) + }) + + it("should handle aliased clientMiddleware import used in array", () => { + const result = augmentMiddlewareFunctions( + ` + import { someClientAuthFn as clientAuthMiddleware } from "./auth"; + export const clientMiddleware = [clientAuthMiddleware]; + `, + "test", + "/file/path" + ) + const expected = removeWhitespace(` + import { withClientMiddlewareWrapperSingle as _withClientMiddlewareWrapperSingle } from "react-router-devtools/client"; + import { someClientAuthFn as clientAuthMiddleware } from "./auth"; + export const clientMiddleware = [ + _withClientMiddlewareWrapperSingle(clientAuthMiddleware, "test", 0, "clientAuthMiddleware") + ]; + `) + expect(removeWhitespace(result.code)).toStrictEqual(expected) + }) + }) }) diff --git a/packages/react-router-devtools/src/vite/utils/middleware-augment.ts b/packages/react-router-devtools/src/vite/utils/middleware-augment.ts index aef71b5..f7a1ce8 100644 --- a/packages/react-router-devtools/src/vite/utils/middleware-augment.ts +++ b/packages/react-router-devtools/src/vite/utils/middleware-augment.ts @@ -46,7 +46,17 @@ const transform = (ast: ParseResult, routeId: string) => { if (!t.isImportSpecifier(specifier) || !t.isIdentifier(specifier.imported)) { continue } - const name = specifier.imported.name + const importedName = specifier.imported.name + const localName = specifier.local.name + // Handle aliased imports where local name is a target export + // e.g., import { someMiddleware as middleware } + if (ALL_MIDDLEWARE_EXPORTS.includes(localName) && !ALL_MIDDLEWARE_EXPORTS.includes(importedName)) { + const uniqueName = path.scope.generateUidIdentifier(localName) + imports.push([localName, uniqueName]) + path.scope.rename(localName, uniqueName.name) + continue + } + const name = importedName if (!ALL_MIDDLEWARE_EXPORTS.includes(name)) { continue }