diff --git a/packages/vinext/src/check.ts b/packages/vinext/src/check.ts index c7a3f48ae..90cc34977 100644 --- a/packages/vinext/src/check.ts +++ b/packages/vinext/src/check.ts @@ -367,13 +367,7 @@ function findSourceFiles( for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory()) { - if ( - entry.name === "node_modules" || - entry.name === ".next" || - entry.name === "dist" || - entry.name === ".git" - ) - continue; + if (IGNORED_DIRECTORIES.has(entry.name)) continue; results.push(...findSourceFiles(fullPath, extensions)); } else if (extensions.some((ext) => entry.name.endsWith(ext))) { results.push(fullPath); @@ -382,6 +376,27 @@ function findSourceFiles( return results; } +/** + * Directories that never contain application source: dependency trees, + * VCS data, and — importantly for migrations — build output from other + * toolchains (Next.js/OpenNext/Nitro/wrangler). Scanning them reports + * bundled artifacts as source and produces false compatibility findings. + */ +const IGNORED_DIRECTORIES = new Set([ + "node_modules", + ".git", + ".next", + "dist", + ".open-next", + ".wrangler", + ".vinext", + ".output", + ".turbo", + ".vercel", + "build", + "out", +]); + /** * Find files that can contribute to the application compatibility surface. * Test modules and test-runner configuration are executed by their own runners diff --git a/tests/check.test.ts b/tests/check.test.ts index 8c9e94b87..2daec5fa8 100644 --- a/tests/check.test.ts +++ b/tests/check.test.ts @@ -216,6 +216,20 @@ describe("scanImports", () => { expect(items[0].name).toBe("next/image"); }); + it("ignores build output from other toolchains during migrations", () => { + // An OpenNext deployment's worker bundle and wrangler's local state + // contain bundled next/* imports and CJS globals that are not + // application source; reporting them blocks real migration findings. + writeFile(".open-next/server-functions/default/handler.mjs", `import Link from "next/link";`); + writeFile(".wrangler/state/v3/d1/cache.js", `import { useAmp } from "next/amp";`); + writeFile(".output/server/index.mjs", `import Link from "next/link";`); + writeFile("app/page.tsx", `import Image from "next/image";`); + + const items = scanImports(tmpDir); + expect(items).toHaveLength(1); + expect(items[0].name).toBe("next/image"); + }); + it("ignores imports used only by test modules and tool config files", () => { writeFile("app/page.test.tsx", `import { useAmp } from "next/amp";`); writeFile("vitest.config.ts", `import { useAmp } from "next/amp";`);