-
Notifications
You must be signed in to change notification settings - Fork 432
Expand file tree
/
Copy pathpackage-managers.ts
More file actions
84 lines (74 loc) · 2.5 KB
/
Copy pathpackage-managers.ts
File metadata and controls
84 lines (74 loc) · 2.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import {fileExists} from '@shopify/cli-kit/node/fs';
import {dirname, joinPath, resolvePath} from '@shopify/cli-kit/node/path';
import {
type Lockfile,
type PackageManager as Name,
} from '@shopify/cli-kit/node/node-package-manager';
export interface PackageManager {
name: Name;
lockfile: Lockfile;
alternativeLockfiles?: string[];
installCommand: string;
}
export const packageManagers: PackageManager[] = [
{
name: 'npm',
lockfile: 'package-lock.json',
alternativeLockfiles: ['npm-shrinkwrap.json'],
installCommand: 'npm ci',
},
{
name: 'yarn',
lockfile: 'yarn.lock',
installCommand: 'yarn install --frozen-lockfile',
},
{
name: 'pnpm',
lockfile: 'pnpm-lock.yaml',
installCommand: 'pnpm install --frozen-lockfile',
},
{
name: 'bun',
lockfile: 'bun.lockb',
alternativeLockfiles: ['bun.lock'],
installCommand: 'bun install --frozen-lockfile',
},
];
// Matches cli-kit's lockfile precedence (yarn, pnpm, bun, npm) so the
// tie-break is unchanged when multiple lockfiles coexist in one directory.
const lockfileDetectionOrder: Name[] = ['yarn', 'pnpm', 'bun', 'npm'];
/**
* Detects the package manager by searching for a known lockfile in
* `directory` and, if none is found there, each ancestor directory in turn.
* Monorepo workspaces keep the lockfile at the workspace root rather than in
* each app directory, so checking only the app directory misses it. The
* nearest lockfile wins, preserving single-repo behavior. Returns 'unknown'
* when no lockfile exists up to `options.stopAt` (or the filesystem root).
*/
export async function findPackageManagerByLockfile(
directory: string,
options?: {stopAt?: string},
): Promise<Name> {
let currentDirectory = resolvePath(directory);
const stopAt = options?.stopAt ? resolvePath(options.stopAt) : undefined;
for (;;) {
for (const name of lockfileDetectionOrder) {
const packageManager = packageManagers.find((pm) => pm.name === name);
if (!packageManager) continue;
const lockfiles = [
packageManager.lockfile,
...(packageManager.alternativeLockfiles ?? []),
];
for (const lockfile of lockfiles) {
if (await fileExists(joinPath(currentDirectory, lockfile))) {
return packageManager.name;
}
}
}
if (currentDirectory === stopAt) break;
const parentDirectory = dirname(currentDirectory);
if (parentDirectory === currentDirectory) break;
currentDirectory = parentDirectory;
}
return 'unknown';
}