88
99import { isJsonObject, json } from '@angular-devkit/core';
1010import { execSync, spawn } from 'node:child_process';
11- import { existsSync, promises as fs, realpathSync, rmSync } from 'node:fs';
11+ import { promises as fs, readdirSync , realpathSync, rmSync } from 'node:fs';
1212import { tmpdir } from 'node:os';
1313import { join } from 'node:path';
1414import { PackageManager } from '../../lib/config/workspace-schema';
1515import { AngularWorkspace, getProjectByCwd } from './config';
1616import { memoize } from './memoize';
1717
18+ /**
19+ * A map of package managers to their corresponding lockfile names.
20+ */
21+ const LOCKFILE_NAMES: Readonly<Record<PackageManager, string | readonly string[]>> = {
22+ [PackageManager.Yarn]: 'yarn.lock',
23+ [PackageManager.Pnpm]: 'pnpm-lock.yaml',
24+ [PackageManager.Bun]: ['bun.lockb', 'bun.lock'],
25+ [PackageManager.Npm]: 'package-lock.json',
26+ };
27+
1828interface PackageManagerOptions {
1929 saveDev: string;
2030 install: string;
@@ -29,7 +39,13 @@ export interface PackageManagerUtilsContext {
2939 root: string;
3040}
3141
42+ /**
43+ * Utilities for interacting with various package managers.
44+ */
3245export class PackageManagerUtils {
46+ /**
47+ * @param context The context for the package manager utilities, including workspace and global configuration.
48+ */
3349 constructor(private readonly context: PackageManagerUtilsContext) {}
3450
3551 /** Get the package manager name. */
@@ -216,10 +232,12 @@ export class PackageManagerUtils {
216232 return packageManager;
217233 }
218234
219- const hasNpmLock = this.hasLockfile(PackageManager.Npm);
220- const hasYarnLock = this.hasLockfile(PackageManager.Yarn);
221- const hasPnpmLock = this.hasLockfile(PackageManager.Pnpm);
222- const hasBunLock = this.hasLockfile(PackageManager.Bun);
235+ const filesInRoot = readdirSync(this.context.root);
236+
237+ const hasNpmLock = this.hasLockfile(PackageManager.Npm, filesInRoot);
238+ const hasYarnLock = this.hasLockfile(PackageManager.Yarn, filesInRoot);
239+ const hasPnpmLock = this.hasLockfile(PackageManager.Pnpm, filesInRoot);
240+ const hasBunLock = this.hasLockfile(PackageManager.Bun, filesInRoot);
223241
224242 // PERF NOTE: `this.getVersion` spawns the package a the child_process which can take around ~300ms at times.
225243 // Therefore, we should only call this method when needed. IE: don't call `this.getVersion(PackageManager.Pnpm)` unless truly needed.
@@ -265,25 +283,18 @@ export class PackageManagerUtils {
265283 return PackageManager.Npm;
266284 }
267285
268- private hasLockfile(packageManager: PackageManager): boolean {
269- let lockfileName: string;
270- switch (packageManager) {
271- case PackageManager.Yarn:
272- lockfileName = 'yarn.lock';
273- break;
274- case PackageManager.Pnpm:
275- lockfileName = 'pnpm-lock.yaml';
276- break;
277- case PackageManager.Bun:
278- lockfileName = 'bun.lockb';
279- break;
280- case PackageManager.Npm:
281- default:
282- lockfileName = 'package-lock.json';
283- break;
284- }
285-
286- return existsSync(join(this.context.root, lockfileName));
286+ /**
287+ * Checks if a lockfile for a specific package manager exists in the root directory.
288+ * @param packageManager The package manager to check for.
289+ * @param filesInRoot An array of file names in the root directory.
290+ * @returns True if the lockfile exists, false otherwise.
291+ */
292+ private hasLockfile(packageManager: PackageManager, filesInRoot: string[]): boolean {
293+ const lockfiles = LOCKFILE_NAMES[packageManager];
294+
295+ return typeof lockfiles === 'string'
296+ ? filesInRoot.includes(lockfiles)
297+ : lockfiles.some((lockfile) => filesInRoot.includes(lockfile));
287298 }
288299
289300 private getConfiguredPackageManager(): PackageManager | undefined {
0 commit comments