#!/usr/bin/env bun /** * Fixes vite.config.ts entry points and package.json subpath exports for * features that were migrated from flat `src/.ts` to nested * `src//.ts` by `migrate-feature-layout.ts`. * * For each package that has a `src//.ts` AND no longer has * a `src/.ts`, rewrites: * - vite.config.ts entry: "./src/.ts" → "./src//index.ts" * - package.json exports: "./dist/.js" → "./dist//index.js" * "./dist/.d.ts" → "./dist//index.d.ts" * * Uses the sub-barrel (index.ts) rather than the impl directly so that * downstream consumers get the explicit named re-exports defined there. * * Idempotent. */ import { existsSync, readdirSync, readFileSync, statSync, writeFileSync, } from "node:fs"; import { join } from "node:path"; const PACKAGES_DIR = "packages"; interface FeatureRename { readonly feature: string; } function listPackages(): readonly 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 findMigratedFeatures(pkgDir: string): FeatureRename[] { const srcDir = join(pkgDir, "src"); const out: FeatureRename[] = []; for (const entry of readdirSync(srcDir)) { const featureDir = join(srcDir, entry); try { if (!statSync(featureDir).isDirectory()) continue; } catch { continue; } const impl = join(featureDir, `${entry}.ts`); const flatImpl = join(srcDir, `${entry}.ts`); // Migrated if nested impl exists AND no flat sibling exists. if (existsSync(impl) && !existsSync(flatImpl)) { out.push({ feature: entry }); } } return out; } function rewriteFileRefs( file: string, features: readonly FeatureRename[] ): boolean { const src = readFileSync(file, "utf8"); let updated = src; for (const { feature } of features) { // vite.config: "./src/.ts" / "src/.ts" → folder/index.ts updated = updated .split(`"./src/${feature}.ts"`) .join(`"./src/${feature}/index.ts"`); updated = updated .split(`"src/${feature}.ts"`) .join(`"src/${feature}/index.ts"`); // package.json: "./dist/.js" / .d.ts → "./dist//index.{js,d.ts}" updated = updated .split(`"./dist/${feature}.js"`) .join(`"./dist/${feature}/index.js"`); updated = updated .split(`"./dist/${feature}.d.ts"`) .join(`"./dist/${feature}/index.d.ts"`); } if (updated !== src) { writeFileSync(file, updated); return true; } return false; } function main(): void { const pkgs = listPackages(); let touched = 0; for (const pkgDir of pkgs) { const features = findMigratedFeatures(pkgDir); if (features.length === 0) continue; const targets = [ join(pkgDir, "vite.config.ts"), join(pkgDir, "package.json"), join(pkgDir, "vite.lib.config.ts"), join(pkgDir, "tsup.config.ts"), ]; for (const t of targets) { if (!existsSync(t)) continue; if (rewriteFileRefs(t, features)) { touched++; console.log(`FIX ${t}`); } } } console.log(`\nUpdated ${touched} config file${touched === 1 ? "" : "s"}.`); } main();