#!/usr/bin/env bun /** * Walks tests/ directories at package roots (siblings of src/) and rewrites * relative imports that now point to migrated feature folders. * * For each `../src/.js` import that no longer resolves but * `../src//.ts` does, rewrites to `../src//.js`. * Falls back to `../src//index.js` if only the barrel exists. */ import { existsSync, readdirSync, readFileSync, statSync, writeFileSync, } from "node:fs"; import { dirname, join, relative } from "node:path"; const PACKAGES_DIR = "packages"; function walkTs(dir: string): string[] { const out: string[] = []; try { for (const name of readdirSync(dir)) { const full = join(dir, name); const s = statSync(full); if (s.isDirectory()) out.push(...walkTs(full)); else if ( (name.endsWith(".ts") || name.endsWith(".tsx")) && !name.endsWith(".d.ts") ) { out.push(full); } } } catch {} return out; } function listPackages(): string[] { const out: string[] = []; for (const cat of readdirSync(PACKAGES_DIR)) { const catDir = join(PACKAGES_DIR, cat); if (!statSync(catDir).isDirectory()) continue; for (const plugin of readdirSync(catDir)) { const pluginDir = join(catDir, plugin); if (!statSync(pluginDir).isDirectory()) continue; for (const pkg of readdirSync(pluginDir)) { const pkgDir = join(pluginDir, pkg); if (!statSync(pkgDir).isDirectory()) continue; if (existsSync(join(pkgDir, "src"))) out.push(pkgDir); } } } return out; } function fileExists(p: string): boolean { try { statSync(p); return true; } catch { return false; } } function isDirectory(p: string): boolean { try { return statSync(p).isDirectory(); } catch { return false; } } function fixFile(file: string): number { const src = readFileSync(file, "utf8"); let updated = src; let fixes = 0; const re = /"((?:\.\.?\/)+[^"]+\.js)"/g; const seen = new Set(); for (const m of src.matchAll(re)) seen.add(m[1] as string); for (const importPath of seen) { const fileDir = dirname(file); const stripped = importPath.replace(/\.js$/, ""); const resolved = join(fileDir, stripped); if (fileExists(`${resolved}.ts`) || fileExists(`${resolved}.tsx`)) continue; if (!isDirectory(resolved)) continue; const baseName = relative(fileDir, resolved).split("/").pop() as string; const innerImpl = join(resolved, `${baseName}.ts`); const innerIndex = join(resolved, "index.ts"); let newImportPath: string | null = null; if (fileExists(innerImpl)) { newImportPath = importPath.replace(/\.js$/, `/${baseName}.js`); } else if (fileExists(innerIndex)) { newImportPath = importPath.replace(/\.js$/, "/index.js"); } if (newImportPath === null) continue; updated = updated.split(`"${importPath}"`).join(`"${newImportPath}"`); fixes++; } if (updated !== src) writeFileSync(file, updated); return fixes; } function main(): void { let totalFiles = 0; let totalFixes = 0; for (const pkg of listPackages()) { const testsDir = join(pkg, "tests"); if (!isDirectory(testsDir)) continue; const files = walkTs(testsDir); for (const f of files) { const fixes = fixFile(f); if (fixes > 0) { totalFiles++; totalFixes += fixes; console.log(`FIX ${f} (${fixes})`); } } } console.log(`\nFixed ${totalFixes} imports across ${totalFiles} files.`); } main();