From 7570428fd93d8b02f23c611cd51c1308ba676bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Lo=CC=81pez=20Guevara?= Date: Mon, 19 Aug 2024 22:16:36 -0300 Subject: [PATCH] feat(cli): let choose the package manager --- packages/cli/src/commands/add.ts | 21 ++++++++++----- packages/cli/src/commands/init.ts | 38 +++++++++++++++------------ packages/cli/src/commands/update.ts | 23 ++++++++++------ packages/cli/src/utils/auto-detect.ts | 14 +++++++--- 4 files changed, 61 insertions(+), 35 deletions(-) diff --git a/packages/cli/src/commands/add.ts b/packages/cli/src/commands/add.ts index 1d2151229..c73214cd3 100644 --- a/packages/cli/src/commands/add.ts +++ b/packages/cli/src/commands/add.ts @@ -2,12 +2,15 @@ import { existsSync, promises as fs } from "node:fs"; import path from "node:path"; import process from "node:process"; import color from "chalk"; -import { Command } from "commander"; +import { Command, Option } from "commander"; import { execa } from "execa"; import * as v from "valibot"; +import { AGENTS, COMMANDS, detectPM } from "../utils/auto-detect.js"; +import { ConfigError, error, handleError } from "../utils/errors.js"; import { type Config, getConfig } from "../utils/get-config.js"; import { getEnvProxy } from "../utils/get-env-proxy.js"; -import { ConfigError, error, handleError } from "../utils/errors.js"; +import { intro, prettifyList } from "../utils/prompt-helpers.js"; +import * as p from "../utils/prompts.js"; import { fetchTree, getItemTargetPath, @@ -16,9 +19,6 @@ import { resolveTree, } from "../utils/registry"; import { transformImports } from "../utils/transformers.js"; -import * as p from "../utils/prompts.js"; -import { intro, prettifyList } from "../utils/prompt-helpers.js"; -import { detectPM } from "../utils/auto-detect.js"; const highlight = (...args: unknown[]) => color.bold.cyan(...args); @@ -30,6 +30,7 @@ const addOptionsSchema = v.object({ cwd: v.string(), path: v.optional(v.string()), deps: v.boolean(), + pm: v.optional(v.picklist(AGENTS)), proxy: v.optional(v.string()), }); @@ -46,6 +47,12 @@ export const add = new Command() .option("-o, --overwrite", "overwrite existing files", false) .option("--proxy ", "fetch components from registry using a proxy", getEnvProxy()) .option("-p, --path ", "the path to add the component to") + .addOption( + new Option( + "--pm ", + "specify the package manager. if not provided, the tool will auto-detect one based on the current project." + ).choices(AGENTS) + ) .action(async (components, opts) => { try { intro(); @@ -244,11 +251,11 @@ async function runAdd(cwd: string, config: Config, options: AddOptions) { } // Install dependencies. - const commands = await detectPM(cwd, options.deps); + const commands = !options.pm ? await detectPM(cwd, options.deps) : COMMANDS[options.pm]; if (commands) { const [pm, add] = commands.add.split(" ") as [string, string]; tasks.push({ - title: `${highlight(pm)}: Installing dependencies`, + title: `${highlight(pm)} Installing dependencies`, enabled: dependencies.size > 0, async task() { await execa(pm, [add, ...dependencies], { diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index e98874313..92c8da39b 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -2,24 +2,26 @@ import { existsSync, promises as fs } from "node:fs"; import path from "node:path"; import process from "node:process"; import color from "chalk"; -import * as v from "valibot"; import { Command, Option } from "commander"; import { execa } from "execa"; -import * as cliConfig from "../utils/get-config.js"; -import type { Config } from "../utils/get-config.js"; -import { error, handleError } from "../utils/errors.js"; -import { getBaseColors, getRegistryBaseColor, getStyles } from "../utils/registry"; -import * as templates from "../utils/templates.js"; -import * as p from "../utils/prompts.js"; -import { intro, prettifyList } from "../utils/prompt-helpers.js"; -import { resolveImport } from "../utils/resolve-imports.js"; -import { syncSvelteKit } from "../utils/sveltekit.js"; +import * as v from "valibot"; import { + AGENTS, + COMMANDS, type DetectLanguageResult, detectConfigs, detectLanguage, detectPM, } from "../utils/auto-detect.js"; +import { error, handleError } from "../utils/errors.js"; +import type { Config } from "../utils/get-config.js"; +import * as cliConfig from "../utils/get-config.js"; +import { intro, prettifyList } from "../utils/prompt-helpers.js"; +import * as p from "../utils/prompts.js"; +import { getBaseColors, getRegistryBaseColor, getStyles } from "../utils/registry"; +import { resolveImport } from "../utils/resolve-imports.js"; +import { syncSvelteKit } from "../utils/sveltekit.js"; +import * as templates from "../utils/templates.js"; const PROJECT_DEPENDENCIES = ["tailwind-variants", "clsx", "tailwind-merge"] as const; const highlight = (...args: unknown[]) => color.bold.cyan(...args); @@ -36,6 +38,7 @@ const initOptionsSchema = v.object({ componentsAlias: v.optional(v.string()), utilsAlias: v.optional(v.string()), deps: v.boolean(), + pm: v.optional(v.picklist(AGENTS)), }); type InitOptions = v.InferOutput; @@ -50,15 +53,16 @@ export const init = new Command() styles.map((style) => style.name) ) ) - .addOption( - new Option("--base-color ", "the base color for the components").choices( - baseColors.map((color) => color.name) - ) - ) .option("--css ", "path to the global CSS file") .option("--tailwind-config ", "path to the tailwind config file") .option("--components-alias ", "import alias for components") .option("--utils-alias ", "import alias for utils") + .addOption( + new Option( + "--pm ", + "specify the package manager. If not provided, the tool will auto-detect one based on the current project." + ).choices(AGENTS) + ) .action(async (opts) => { intro(); const options = v.parse(initOptionsSchema, opts); @@ -363,11 +367,11 @@ export async function runInit(cwd: string, config: Config, options: InitOptions) }); // Install dependencies. - const commands = await detectPM(cwd, options.deps); + const commands = !options.pm ? await detectPM(cwd, options.deps) : COMMANDS[options.pm]; if (commands) { const [pm, add] = commands.add.split(" ") as [string, string]; tasks.push({ - title: `${highlight(pm)}: Installing dependencies`, + title: `${highlight(pm)} Installing dependencies`, enabled: options.deps, async task() { await execa(pm, [add, ...PROJECT_DEPENDENCIES], { diff --git a/packages/cli/src/commands/update.ts b/packages/cli/src/commands/update.ts index 84f2a8eb2..2276b1601 100644 --- a/packages/cli/src/commands/update.ts +++ b/packages/cli/src/commands/update.ts @@ -2,18 +2,18 @@ import { existsSync, promises as fs } from "node:fs"; import path from "node:path"; import process from "node:process"; import color from "chalk"; -import { Command } from "commander"; +import { Command, Option } from "commander"; import { execa } from "execa"; import * as v from "valibot"; -import { type Config, getConfig } from "../utils/get-config.js"; +import { AGENTS, COMMANDS, detectPM } from "../utils/auto-detect.js"; import { error, handleError } from "../utils/errors.js"; +import { type Config, getConfig } from "../utils/get-config.js"; +import { getEnvProxy } from "../utils/get-env-proxy.js"; +import { intro, prettifyList } from "../utils/prompt-helpers.js"; +import * as p from "../utils/prompts.js"; import { fetchTree, getItemTargetPath, getRegistryIndex, resolveTree } from "../utils/registry"; import { UTILS, UTILS_JS } from "../utils/templates.js"; import { transformImports } from "../utils/transformers.js"; -import * as p from "../utils/prompts.js"; -import { intro, prettifyList } from "../utils/prompt-helpers.js"; -import { getEnvProxy } from "../utils/get-env-proxy.js"; -import { detectPM } from "../utils/auto-detect.js"; const highlight = (msg: string) => color.bold.cyan(msg); @@ -23,6 +23,7 @@ const updateOptionsSchema = v.object({ cwd: v.string(), proxy: v.optional(v.string()), yes: v.boolean(), + pm: v.optional(v.picklist(AGENTS)), }); type UpdateOptions = v.InferOutput; @@ -35,6 +36,12 @@ export const update = new Command() .option("-a, --all", "update all existing components", false) .option("-y, --yes", "skip confirmation prompt", false) .option("--proxy ", "fetch components from registry using a proxy", getEnvProxy()) + .addOption( + new Option( + "--pm ", + "specify the package manager. if not provided, the tool will auto-detect one based on the current project." + ).choices(AGENTS) + ) .action(async (components, opts) => { intro(); @@ -225,11 +232,11 @@ async function runUpdate(cwd: string, config: Config, options: UpdateOptions) { } // Install dependencies. - const commands = await detectPM(cwd, true); + const commands = !options.pm ? await detectPM(cwd, true) : COMMANDS[options.pm]; if (commands) { const [pm, add] = commands.add.split(" ") as [string, string]; tasks.push({ - title: `${highlight(pm)}: Installing dependencies`, + title: `${highlight(pm)} Installing dependencies`, enabled: dependencies.size > 0, async task() { await execa(pm, [add, ...dependencies], { diff --git a/packages/cli/src/utils/auto-detect.ts b/packages/cli/src/utils/auto-detect.ts index 997475c84..3abcdf315 100644 --- a/packages/cli/src/utils/auto-detect.ts +++ b/packages/cli/src/utils/auto-detect.ts @@ -3,10 +3,18 @@ import path from "node:path"; import ignore, { type Ignore } from "ignore"; import { type TsConfigResult, getTsconfig } from "get-tsconfig"; import { detect } from "package-manager-detector"; -import { AGENTS, type Agent, COMMANDS } from "package-manager-detector/agents"; +import { + type Agent, + AGENTS as _AGENTS, + COMMANDS as _COMMANDS, +} from "package-manager-detector/agents"; import * as p from "./prompts.js"; import { cancel } from "./prompt-helpers.js"; +export const AGENTS = _AGENTS.filter((agent) => !agent.includes("@")); + +export const COMMANDS = _COMMANDS; + const STYLESHEETS = [ "app.css", "app.pcss", @@ -96,12 +104,12 @@ export function detectLanguage(cwd: string): DetectLanguageResult | undefined { if (jsConfig !== null) return { type: "jsconfig.json", config: jsConfig }; } -type Options = Array<{ value: Agent | undefined; label: Agent | "None" }>; export async function detectPM(cwd: string, prompt: boolean) { + type Options = Array<{ value: Agent | undefined; label: Agent | "None" }>; let { agent } = await detect({ cwd }); if (agent === undefined && prompt) { - const options: Options = AGENTS.filter((agent) => !agent.includes("@")).map((pm) => ({ + const options: Options = AGENTS.map((pm) => ({ value: pm, label: pm, }));