Skip to content

Commit

Permalink
feat(cli): let choose the package manager
Browse files Browse the repository at this point in the history
  • Loading branch information
fernandolguevara committed Aug 20, 2024
1 parent 871d72d commit c24033f
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 33 deletions.
21 changes: 14 additions & 7 deletions packages/cli/src/commands/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);

Expand All @@ -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.filter((agent) => !agent.includes("@")))),
proxy: v.optional(v.string()),
});

Expand All @@ -46,6 +47,12 @@ export const add = new Command()
.option("-o, --overwrite", "overwrite existing files", false)
.option("--proxy <proxy>", "fetch components from registry using a proxy", getEnvProxy())
.option("-p, --path <path>", "the path to add the component to")
.addOption(
new Option(
"--pm <name>",
"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();
Expand Down Expand Up @@ -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], {
Expand Down
40 changes: 25 additions & 15 deletions packages/cli/src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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<typeof initOptionsSchema>;
Expand All @@ -51,14 +54,21 @@ export const init = new Command()
)
)
.addOption(
new Option("--base-color <name>", "the base color for the components").choices(
baseColors.map((color) => color.name)
)
new Option(
"--pm <name>",
"specify the package manager. if not provided, the tool will auto-detect one based on the current project."
).choices(AGENTS)
)
.option("--css <path>", "path to the global CSS file")
.option("--tailwind-config <path>", "path to the tailwind config file")
.option("--components-alias <path>", "import alias for components")
.option("--utils-alias <path>", "import alias for utils")
.addOption(
new Option(
"--pm <name>",
"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);
Expand Down Expand Up @@ -363,11 +373,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, 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: options.deps,
async task() {
await execa(pm, [add, ...PROJECT_DEPENDENCIES], {
Expand Down
23 changes: 15 additions & 8 deletions packages/cli/src/commands/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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<typeof updateOptionsSchema>;
Expand All @@ -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 <proxy>", "fetch components from registry using a proxy", getEnvProxy())
.addOption(
new Option(
"--pm <name>",
"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();

Expand Down Expand Up @@ -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], {
Expand Down
14 changes: 11 additions & 3 deletions packages/cli/src/utils/auto-detect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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,
}));
Expand Down

0 comments on commit c24033f

Please sign in to comment.