1b939fa09SCedric van Puttenimport { sync as findUpSync } from 'find-up'; 28d3f3824SCedric van Puttenimport findYarnOrNpmWorkspaceRootUnsafe from 'find-yarn-workspace-root'; 38d3f3824SCedric van Puttenimport fs from 'fs'; 48d3f3824SCedric van Puttenimport yaml from 'js-yaml'; 58d3f3824SCedric van Puttenimport micromatch from 'micromatch'; 6b939fa09SCedric van Puttenimport path from 'path'; 7b939fa09SCedric van Putten 8b939fa09SCedric van Puttenexport const NPM_LOCK_FILE = 'package-lock.json'; 9b939fa09SCedric van Puttenexport const YARN_LOCK_FILE = 'yarn.lock'; 10b939fa09SCedric van Puttenexport const PNPM_LOCK_FILE = 'pnpm-lock.yaml'; 11b939fa09SCedric van Puttenexport const PNPM_WORKSPACE_FILE = 'pnpm-workspace.yaml'; 12*6a725f6fSColin McDonnellexport const BUN_LOCK_FILE = 'bun.lockb'; 13b939fa09SCedric van Putten 148d3f3824SCedric van Putten/** Wraps `find-yarn-workspace-root` and guards against having an empty `package.json` file in an upper directory. */ 158d3f3824SCedric van Puttenexport function findYarnOrNpmWorkspaceRoot(projectRoot: string): string | null { 16b939fa09SCedric van Putten try { 178d3f3824SCedric van Putten return findYarnOrNpmWorkspaceRootUnsafe(projectRoot); 18b939fa09SCedric van Putten } catch (error: any) { 19b939fa09SCedric van Putten if (error.message.includes('Unexpected end of JSON input')) { 20b939fa09SCedric van Putten return null; 21b939fa09SCedric van Putten } 22b939fa09SCedric van Putten throw error; 23b939fa09SCedric van Putten } 24b939fa09SCedric van Putten} 25b939fa09SCedric van Putten 26b939fa09SCedric van Putten/** 278d3f3824SCedric van Putten * Find the `pnpm-workspace.yaml` file that represents the root of the monorepo. 288d3f3824SCedric van Putten * This is a synchronous function based on the original async library. 298d3f3824SCedric van Putten * @see https://github.com/pnpm/pnpm/blob/main/packages/find-workspace-dir/src/index.ts 30b939fa09SCedric van Putten */ 318d3f3824SCedric van Puttenexport function findPnpmWorkspaceRoot(projectRoot: string): string | null { 328d3f3824SCedric van Putten const workspaceEnvName = 'NPM_CONFIG_WORKSPACE_DIR'; 338d3f3824SCedric van Putten const workspaceEnvValue = 348d3f3824SCedric van Putten process.env[workspaceEnvName] ?? process.env[workspaceEnvName.toLowerCase()]; 35b939fa09SCedric van Putten 368d3f3824SCedric van Putten const workspaceFile = workspaceEnvValue 378d3f3824SCedric van Putten ? path.join(workspaceEnvValue, PNPM_WORKSPACE_FILE) 388d3f3824SCedric van Putten : findUpSync(PNPM_WORKSPACE_FILE, { cwd: projectRoot }); 39b939fa09SCedric van Putten 408d3f3824SCedric van Putten if (!workspaceFile || !fs.existsSync(workspaceFile)) { 41b939fa09SCedric van Putten return null; 42b939fa09SCedric van Putten } 43b939fa09SCedric van Putten 448d3f3824SCedric van Putten try { 458d3f3824SCedric van Putten // See: https://pnpm.io/pnpm-workspace_yaml 468d3f3824SCedric van Putten const { packages: workspaces } = yaml.load(fs.readFileSync(workspaceFile, 'utf8')); 478d3f3824SCedric van Putten // See: https://github.com/square/find-yarn-workspace-root/blob/11f6e31d3fa15a5bb7b7419f0091390e4c16204c/index.js#L26-L33 488d3f3824SCedric van Putten const workspaceRoot = path.dirname(workspaceFile); 498d3f3824SCedric van Putten const relativePath = path.relative(workspaceRoot, projectRoot); 50b939fa09SCedric van Putten 518d3f3824SCedric van Putten if (relativePath === '' || micromatch([relativePath], workspaces).length > 0) { 528d3f3824SCedric van Putten return workspaceRoot; 53b939fa09SCedric van Putten } 548d3f3824SCedric van Putten } catch { 558d3f3824SCedric van Putten // TODO: implement debug logger? 56b939fa09SCedric van Putten return null; 57b939fa09SCedric van Putten } 58b939fa09SCedric van Putten 59b939fa09SCedric van Putten return null; 60b939fa09SCedric van Putten} 61