import { readdir, readFile, stat } from "node:fs/promises"; import path from "node:path"; import process from "node:process"; import { resolveRealWorkspaceRoot } from "./load-env.mjs"; const rootDir = resolveRealWorkspaceRoot(); const workspaceDirs = ["packages", "tooling"]; const violations = []; async function pathExists(targetPath) { try { await stat(targetPath); return true; } catch { return false; } } async function listPackageJsonFiles(baseDir) { const absoluteBaseDir = path.join(rootDir, baseDir); if (!(await pathExists(absoluteBaseDir))) { return []; } const entries = await readdir(absoluteBaseDir, { withFileTypes: true }); return entries .filter((entry) => entry.isDirectory()) .map((entry) => path.join(baseDir, entry.name, "package.json")); } function collectExportTargets(value, keyPath, targets) { if (typeof value === "string") { targets.push({ keyPath, target: value }); return; } if (!value || typeof value !== "object") { return; } for (const [key, nestedValue] of Object.entries(value)) { collectExportTargets(nestedValue, `${keyPath}.${key}`, targets); } } function getWildcardBaseDir(target) { const wildcardIndex = target.indexOf("*"); if (wildcardIndex === -1) { return target; } const targetPrefix = target.slice(0, wildcardIndex); const lastSlashIndex = targetPrefix.lastIndexOf("/"); return lastSlashIndex === -1 ? "." : targetPrefix.slice(0, lastSlashIndex); } const packageJsonFiles = ( await Promise.all(workspaceDirs.map((workspaceDir) => listPackageJsonFiles(workspaceDir))) ).flat(); for (const packageJsonFile of packageJsonFiles) { const packageJsonPath = path.join(rootDir, packageJsonFile); if (!(await pathExists(packageJsonPath))) { continue; } const packageDir = path.dirname(packageJsonPath); const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8")); const exportsField = packageJson.exports; if (!exportsField || typeof exportsField !== "object") { continue; } const exportTargets = []; collectExportTargets(exportsField, "exports", exportTargets); for (const exportTarget of exportTargets) { const exportPath = exportTarget.target; const containsWildcard = exportPath.includes("*"); const relativeCheckPath = containsWildcard ? getWildcardBaseDir(exportPath) : exportPath; const absoluteCheckPath = path.resolve(packageDir, relativeCheckPath); const relativeFromRoot = path.relative(rootDir, absoluteCheckPath) || "."; if (!relativeFromRoot || relativeFromRoot.startsWith("..")) { violations.push( `${packageJsonFile}: ${exportTarget.keyPath} points outside the repository: ${exportPath}`, ); continue; } if (!(await pathExists(absoluteCheckPath))) { violations.push( `${packageJsonFile}: ${exportTarget.keyPath} references a missing path: ${exportPath}`, ); } } } if (violations.length > 0) { console.error("Workspace export check failed:"); for (const violation of violations) { console.error(`- ${violation}`); } process.exit(1); } console.log("Workspace exports passed.");