From fcb15f1f0f769b7a0d4630c594a946be2587f6b0 Mon Sep 17 00:00:00 2001 From: Tomeshwari-02 Date: Fri, 3 Jul 2026 20:07:48 +0530 Subject: [PATCH] Detect package manager for create app add --- .../src/commands/add.test.ts | 38 +++++++++++++++++-- .../create-termui-app/src/commands/add.ts | 17 ++++++++- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/packages/create-termui-app/src/commands/add.test.ts b/packages/create-termui-app/src/commands/add.test.ts index f440b72eb..d0f5163ae 100644 --- a/packages/create-termui-app/src/commands/add.test.ts +++ b/packages/create-termui-app/src/commands/add.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it, beforeEach, afterEach, vi } from "vitest"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { mkdirSync, rmSync, existsSync, readFileSync } from "node:fs"; +import { mkdirSync, rmSync, existsSync, readFileSync, writeFileSync } from "node:fs"; vi.mock("node:child_process", () => ({ execFileSync: vi.fn(), @@ -133,8 +133,8 @@ describe("runAddCommand", () => { 'export const Badge = () => "badge";', ); expect(execSpy).toHaveBeenCalledWith( - "bun", - ["add", "@termuijs/core", "@termuijs/widgets"], + "npm", + ["install", "@termuijs/core", "@termuijs/widgets"], { stdio: "inherit", }, @@ -144,6 +144,38 @@ describe("runAddCommand", () => { ); }); + it("uses bun when bun.lock is present", async () => { + setupFetchMock(); + writeFileSync(join(tempDir, "bun.lock"), ""); + const execSpy = vi.spyOn(childProcess, "execFileSync"); + + await runAddCommand({ component: "Badge" }); + + expect(execSpy).toHaveBeenCalledWith( + "bun", + ["add", "@termuijs/core", "@termuijs/widgets"], + { + stdio: "inherit", + }, + ); + }); + + it("uses pnpm when pnpm-lock.yaml is present", async () => { + setupFetchMock(); + writeFileSync(join(tempDir, "pnpm-lock.yaml"), ""); + const execSpy = vi.spyOn(childProcess, "execFileSync"); + + await runAddCommand({ component: "Badge" }); + + expect(execSpy).toHaveBeenCalledWith( + "pnpm", + ["add", "@termuijs/core", "@termuijs/widgets"], + { + stdio: "inherit", + }, + ); + }); + it("resolves component names case-insensitively", async () => { setupFetchMock(); vi.spyOn(childProcess, "execFileSync"); diff --git a/packages/create-termui-app/src/commands/add.ts b/packages/create-termui-app/src/commands/add.ts index 2559b0ecd..fdd394dad 100644 --- a/packages/create-termui-app/src/commands/add.ts +++ b/packages/create-termui-app/src/commands/add.ts @@ -27,6 +27,8 @@ interface RegistrySchema { components: RegistryComponent[]; } +type PackageManager = "npm" | "yarn" | "pnpm" | "bun"; + export async function runAddCommand(options: AddCommandOptions): Promise { const componentName = options.component.trim(); if (!componentName) { @@ -213,11 +215,24 @@ async function installPackages(entry: RegistryComponent): Promise { return; } - execFileSync("bun", ["add", ...deps], { + const pm = detectPackageManager(process.cwd()); + execFileSync(pm, installArgs(pm, deps), { stdio: "inherit", }); } +function detectPackageManager(cwd: string): PackageManager { + if (existsSync(join(cwd, "bun.lock"))) return "bun"; + if (existsSync(join(cwd, "pnpm-lock.yaml"))) return "pnpm"; + if (existsSync(join(cwd, "yarn.lock"))) return "yarn"; + return "npm"; +} + +function installArgs(pm: PackageManager, deps: string[]): string[] { + if (pm === "npm") return ["install", ...deps]; + return ["add", ...deps]; +} + function pascalCase(value: string): string { return value .split(/[^a-zA-Z0-9]+/)