@reliverse/rse
Version:
@reliverse/rse is your all-in-one companion for bootstrapping and improving any kind of projects (especially web apps built with frameworks like Next.js) — whether you're kicking off something new or upgrading an existing app. It is also a little AI-power
192 lines (191 loc) • 6.56 kB
JavaScript
import path from "@reliverse/pathkit";
import { ensuredir } from "@reliverse/relifso";
import fs from "@reliverse/relifso";
import { relinka } from "@reliverse/relinka";
import { execa } from "execa";
import { readPackageJSON, writePackageJSON } from "pkg-types";
var PackageManager = /* @__PURE__ */ ((PackageManager2) => {
PackageManager2["Bun"] = "bun";
PackageManager2["Pnpm"] = "pnpm";
PackageManager2["Yarn"] = "yarn";
PackageManager2["Npm"] = "npm";
return PackageManager2;
})(PackageManager || {});
async function detectPackageManager(cwd) {
if (await fs.pathExists(path.join(cwd, "bun.lock"))) {
return "bun" /* Bun */;
}
if (await fs.pathExists(path.join(cwd, "pnpm-lock.yaml"))) {
return "pnpm" /* Pnpm */;
}
if (await fs.pathExists(path.join(cwd, "yarn.lock"))) {
return "yarn" /* Yarn */;
}
return "npm" /* Npm */;
}
async function installDependencies(cwd, dependencies, isDev) {
const pm = await detectPackageManager(cwd);
const installCmd = pm === "npm" /* Npm */ ? "install" : "add";
const args = [installCmd, ...dependencies];
if (isDev) {
args.push(pm === "npm" /* Npm */ ? "--save-dev" : "-D");
}
try {
await execa(pm, args, { cwd });
relinka(
"success",
`Installed ${isDev ? "dev " : ""}dependencies with ${pm}`
);
} catch (error) {
relinka(
"error",
`Failed to install dependencies: ${error instanceof Error ? error.message : String(error)}`
);
throw error;
}
}
export async function updatePackageJson(projectPath, options = {}) {
try {
const packageJson = await readPackageJSON(projectPath);
if (!packageJson) {
throw new Error("package.json not found or could not be read");
}
if (options.fields) {
Object.assign(packageJson, options.fields);
}
if (options.scripts) {
packageJson.scripts = { ...packageJson.scripts, ...options.scripts };
}
const packageJsonPath = path.join(projectPath, "package.json");
await writePackageJSON(packageJsonPath, packageJson);
return true;
} catch (error) {
relinka("error", "Error updating package.json:", String(error));
if (options.throwOnError) {
throw error;
}
return false;
}
}
async function updateEnvFile(cwd, envVars) {
const envPath = path.join(cwd, ".env");
const envExamplePath = path.join(cwd, ".env.example");
try {
let envContent = await fs.pathExists(envPath) ? await fs.readFile(envPath, "utf-8") : "";
let envExampleContent = await fs.pathExists(envExamplePath) ? await fs.readFile(envExamplePath, "utf-8") : "";
for (const [key, value] of Object.entries(envVars)) {
if (!envContent.includes(key)) {
envContent += `\\n${key}=${value}`;
}
if (!envExampleContent.includes(key)) {
envExampleContent += `\\n${key}=your_${key.toLowerCase()}_here`;
}
}
await fs.writeFile(envPath, envContent.trim());
await fs.writeFile(envExamplePath, envExampleContent.trim());
} catch (error) {
relinka(
"error",
`Failed to update env files: ${error instanceof Error ? error.message : String(error)}`
);
throw error;
}
}
export async function installIntegration(cwd, config, isDev) {
try {
relinka("info", `Installing ${config.name}...`);
for (const file of config.files) {
const filePath = path.join(cwd, file.path);
await ensuredir(path.dirname(filePath));
await fs.writeFile(filePath, file.content);
relinka("success", `Created ${file.path}`);
}
if (config.dependencies.length > 0) {
await installDependencies(cwd, config.dependencies, isDev);
}
if (config.devDependencies?.length) {
await installDependencies(cwd, config.devDependencies, isDev);
}
if (config.scripts) {
try {
await updatePackageJson(cwd, {
scripts: config.scripts,
throwOnError: true
});
} catch (error) {
relinka(
"error",
`Failed to update package.json: ${error instanceof Error ? error.message : String(error)}`
);
throw error;
}
}
if (config.envVars) {
await updateEnvFile(cwd, config.envVars);
}
if (config.postInstall) {
await config.postInstall(cwd);
}
relinka("success", `Successfully installed ${config.name}`);
} catch (error) {
relinka(
"error",
`Failed to install ${config.name}: ${error instanceof Error ? error.message : String(error)}`
);
throw error;
}
}
export async function removeIntegration(cwd, config) {
try {
relinka("info", `Removing ${config.name}...`);
const packageJsonPath = path.join(cwd, "package.json");
const pkg = await readPackageJSON(packageJsonPath);
if (!pkg) {
throw new Error("package.json not found or could not be read");
}
config.dependencies.forEach((dep) => delete pkg.dependencies?.[dep]);
config.devDependencies.forEach((dep) => delete pkg.devDependencies?.[dep]);
config.scripts.forEach((script) => delete pkg.scripts?.[script]);
await writePackageJSON(packageJsonPath, pkg);
for (const file of config.files) {
const filePath = path.join(cwd, file);
if (await fs.pathExists(filePath)) {
await fs.remove(filePath);
relinka("success", `Removed ${file}`);
}
}
for (const dir of config.directories) {
const dirPath = path.join(cwd, dir);
if (await fs.pathExists(dirPath)) {
await fs.remove(dirPath);
relinka("success", `Removed ${dir}`);
}
}
const envPath = path.join(cwd, ".env");
const envExamplePath = path.join(cwd, ".env.example");
if (await fs.pathExists(envPath)) {
let envContent = await fs.readFile(envPath, "utf-8");
config.envVars.forEach((key) => {
envContent = envContent.replace(new RegExp(`^${key}=.*$\\n?`, "m"), "");
});
await fs.writeFile(envPath, envContent.trim());
}
if (await fs.pathExists(envExamplePath)) {
let envExampleContent = await fs.readFile(envExamplePath, "utf-8");
config.envVars.forEach((key) => {
envExampleContent = envExampleContent.replace(
new RegExp(`^${key}=.*$\\n?`, "m"),
""
);
});
await fs.writeFile(envExamplePath, envExampleContent.trim());
}
relinka("success", `Successfully removed ${config.name}`);
} catch (error) {
relinka(
"error",
`Failed to remove ${config.name}: ${error instanceof Error ? error.message : String(error)}`
);
throw error;
}
}