pm.ts63 lines · main
1export type Pm = 'npm' | 'pnpm' | 'yarn' | 'bun';
2export const PMS: readonly Pm[] = ['npm', 'pnpm', 'yarn', 'bun'];
3
4export type PmBlock = Record<Pm, string>;
5
6/**
7 * Run an already-installed bin (from ./node_modules/.bin) using each PM's
8 * native shortcut. Lines are prefixed with `$ ` to match the existing docs
9 * code style.
10 */
11export function pmExec(...lines: string[]): PmBlock {
12 const prefix: PmBlock = {
13 npm: 'npx',
14 pnpm: 'pnpm',
15 yarn: 'yarn',
16 bun: 'bunx',
17 };
18 const out = {} as PmBlock;
19 for (const m of PMS) {
20 out[m] = lines.map((l) => `$ ${prefix[m]} ${l}`).join('\n');
21 }
22 return out;
23}
24
25/**
26 * One-shot remote execution without a prior install (npx / dlx / bunx style).
27 */
28export function pmDlx(cmd: string): PmBlock {
29 return {
30 npm: `$ npx ${cmd}`,
31 pnpm: `$ pnpm dlx ${cmd}`,
32 yarn: `$ yarn dlx ${cmd}`,
33 bun: `$ bunx ${cmd}`,
34 };
35}
36
37/**
38 * Install one or more packages. `dev: true` switches to a dev-dep install.
39 */
40export function pmInstall(pkgs: string, options: { dev?: boolean } = {}): PmBlock {
41 const dev = options.dev ?? false;
42 return {
43 npm: `$ npm install ${dev ? '-D ' : ''}${pkgs}`,
44 pnpm: `$ pnpm add ${dev ? '-D ' : ''}${pkgs}`,
45 yarn: `$ yarn add ${dev ? '-D ' : ''}${pkgs}`,
46 bun: `$ bun add ${dev ? '-d ' : ''}${pkgs}`,
47 };
48}
49
50/** Same literal line across every PM — for things like `mkdir` that don't vary. */
51export function pmPlain(...lines: string[]): PmBlock {
52 const body = lines.join('\n');
53 return { npm: body, pnpm: body, yarn: body, bun: body };
54}
55
56/** Concatenate several blocks vertically, preserving each PM's own body. */
57export function pmJoin(...blocks: PmBlock[]): PmBlock {
58 const out = {} as PmBlock;
59 for (const m of PMS) {
60 out[m] = blocks.map((b) => b[m]).join('\n');
61 }
62 return out;
63}