#!/usr/bin/env bun /** * check-fixture-resolves — verifies that every `@suaveplan/testing-integration-*` * package's `package.json` `exports."." → import.default` points at a file that * actually exists on disk and loads cleanly via dynamic `import()`. * * The bug this guards against: a vite.config.ts using `preserveModules: true` * without `output.entryFileNames: "[name].js"` causes Rollup to derive the * entry filename from the package name (e.g. `dist/testing-integration-redis.js`), * leaving `package.json`'s declared entry pointing at a file that does not * exist. Consumers then get * `Failed to resolve entry for package "@suaveplan/testing-integration-"` * from esbuild/Vite/Bun. * * Resolves package paths from the repo's `packages/testing/testing-integration*` * tree directly, since the repo-root `scripts/` directory is not a workspace * member and cannot import `@suaveplan/*` by name under Bun's hoisting. * * Exits 0 when all entries resolve and import, 1 when any fail. Prints a * per-package row so a CI failure is unambiguous. * * @module */ import { existsSync, readdirSync, readFileSync } from "node:fs"; import { join, resolve } from "node:path"; import { pathToFileURL } from "node:url"; const REPO_ROOT = resolve(import.meta.dir, ".."); const FIXTURES_DIR = join(REPO_ROOT, "packages", "dev"); interface ExportConditions { import?: string | { default?: string }; default?: string; } interface PackageManifest { name?: string; exports?: Record | string; } interface Result { pkg: string; ok: boolean; error: string | undefined; } function discoverFixtures(): Array<{ name: string; dir: string }> { const entries = readdirSync(FIXTURES_DIR, { withFileTypes: true }); const result: Array<{ name: string; dir: string }> = []; for (const entry of entries) { if (!entry.isDirectory()) continue; if (!entry.name.startsWith("testing-integration")) continue; const dir = join(FIXTURES_DIR, entry.name); const manifestPath = join(dir, "package.json"); if (!existsSync(manifestPath)) continue; const manifest = JSON.parse( readFileSync(manifestPath, "utf-8") ) as PackageManifest; if (typeof manifest.name !== "string") continue; result.push({ name: manifest.name, dir }); } return result.sort((a, b) => a.name.localeCompare(b.name)); } function resolveMainEntry(dir: string): string | null { const manifest = JSON.parse( readFileSync(join(dir, "package.json"), "utf-8") ) as PackageManifest; const exp = manifest.exports; if (exp === undefined) return null; if (typeof exp === "string") return join(dir, exp); const root = exp["."]; if (root === undefined) return null; if (typeof root === "string") return join(dir, root); const importEntry = root.import; if (typeof importEntry === "string") return join(dir, importEntry); if ( importEntry !== undefined && typeof importEntry === "object" && typeof importEntry.default === "string" ) { return join(dir, importEntry.default); } if (typeof root.default === "string") return join(dir, root.default); return null; } async function check(pkg: { name: string; dir: string }): Promise { const entry = resolveMainEntry(pkg.dir); if (entry === null) { return { pkg: pkg.name, ok: false, error: 'package.json "exports" missing or has no "." entry', }; } if (!existsSync(entry)) { return { pkg: pkg.name, ok: false, error: `declared entry does not exist on disk: ${entry}`, }; } try { const mod = await import(pathToFileURL(entry).href); if (mod === null || typeof mod !== "object") { return { pkg: pkg.name, ok: false, error: `import resolved but module is not an object (got ${typeof mod})`, }; } return { pkg: pkg.name, ok: true, error: undefined }; } catch (err) { const message = err instanceof Error ? err.message : String(err); return { pkg: pkg.name, ok: false, error: message }; } } async function main(): Promise { const fixtures = discoverFixtures(); if (fixtures.length === 0) { process.stderr.write( `No testing-integration packages found under ${FIXTURES_DIR}\n` ); return 1; } const results = await Promise.all(fixtures.map(check)); const width = Math.max(...fixtures.map((f) => f.name.length)); for (const r of results) { const tag = r.ok ? "PASS" : "FAIL"; const padded = r.pkg.padEnd(width, " "); const tail = r.ok ? "" : ` — ${r.error}`; process.stdout.write(`${tag} ${padded}${tail}\n`); } const failed = results.filter((r) => !r.ok); if (failed.length > 0) { process.stderr.write( `\n${failed.length}/${results.length} testing-integration packages failed to resolve.\n` ); return 1; } process.stdout.write( `\nAll ${results.length} testing-integration packages resolve.\n` ); return 0; } const code = await main(); process.exit(code);