204 lines
7.9 KiB
JavaScript
204 lines
7.9 KiB
JavaScript
|
|
import { o as logLevelArgs, t as cwdArgs } from "./_shared-B6XhZQ-m.mjs";
|
||
|
|
import { n as logger } from "./logger-C1qVsppt.mjs";
|
||
|
|
import { r as relativeToProcess } from "./kit-gdbmFADU.mjs";
|
||
|
|
import { t as runCommand$1 } from "./run-Bk6AOWq7.mjs";
|
||
|
|
import { a as getProjectDependencies, i as forwardCommandArgs, n as ensureNuxtDependency, r as fetchModules, s as isPnpmWorkspace } from "./_utils-CCLBPsec.mjs";
|
||
|
|
import { t as prepare_default } from "./prepare-kyMoAaxl.mjs";
|
||
|
|
import process from "node:process";
|
||
|
|
import { defineCommand } from "citty";
|
||
|
|
import { colors } from "consola/utils";
|
||
|
|
import { cancel, confirm, isCancel, multiselect } from "@clack/prompts";
|
||
|
|
import { resolve } from "pathe";
|
||
|
|
import { readPackageJSON } from "pkg-types";
|
||
|
|
import { detectPackageManager, removeDependency } from "nypm";
|
||
|
|
import { updateConfig } from "c12/update";
|
||
|
|
//#region ../nuxi/src/commands/module/remove.ts
|
||
|
|
var remove_default = defineCommand({
|
||
|
|
meta: {
|
||
|
|
name: "remove",
|
||
|
|
description: "Remove Nuxt modules"
|
||
|
|
},
|
||
|
|
args: {
|
||
|
|
...cwdArgs,
|
||
|
|
...logLevelArgs,
|
||
|
|
moduleName: {
|
||
|
|
type: "positional",
|
||
|
|
description: "Specify one or more modules to remove by name, separated by spaces",
|
||
|
|
required: false
|
||
|
|
},
|
||
|
|
skipInstall: {
|
||
|
|
type: "boolean",
|
||
|
|
description: "Skip dependency uninstall"
|
||
|
|
},
|
||
|
|
skipConfig: {
|
||
|
|
type: "boolean",
|
||
|
|
description: "Skip nuxt.config.ts update"
|
||
|
|
}
|
||
|
|
},
|
||
|
|
async setup(ctx) {
|
||
|
|
const cwd = resolve(ctx.args.cwd);
|
||
|
|
const modules = ctx.args._.map((e) => e.trim()).filter(Boolean);
|
||
|
|
const projectPkg = await readPackageJSON(cwd).catch(() => ({}));
|
||
|
|
if (!await ensureNuxtDependency(cwd, projectPkg)) process.exit(1);
|
||
|
|
if (ctx.args.skipConfig && modules.length === 0) {
|
||
|
|
cancel(`Specify one or more modules to remove when ${colors.cyan("--skipConfig")} is set.`);
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
const installedNames = getProjectDependencies(projectPkg);
|
||
|
|
const modulesDB = modules.some((m) => !installedNames.has(m)) ? await fetchModules().catch((err) => {
|
||
|
|
logger.warn(`Cannot search in the Nuxt Modules database: ${err}`);
|
||
|
|
return [];
|
||
|
|
}) : [];
|
||
|
|
const resolvedModules = modules.map((m) => resolveModuleName(m, modulesDB, installedNames));
|
||
|
|
if (resolvedModules.length > 0) logger.info(`Resolved ${resolvedModules.map((x) => colors.cyan(x)).join(", ")}, removing module${resolvedModules.length > 1 ? "s" : ""}...`);
|
||
|
|
if (!await removeModules(resolvedModules, {
|
||
|
|
...ctx.args,
|
||
|
|
cwd
|
||
|
|
}, projectPkg)) process.exit(0);
|
||
|
|
if (!ctx.args.skipInstall) await runCommand$1(prepare_default, forwardCommandArgs(ctx.args));
|
||
|
|
}
|
||
|
|
});
|
||
|
|
async function removeModules(modules, { skipInstall = false, skipConfig = false, cwd }, projectPkg) {
|
||
|
|
const removedFromConfig = [];
|
||
|
|
if (!skipConfig) {
|
||
|
|
let configMissing = false;
|
||
|
|
let cancelled = false;
|
||
|
|
await updateConfig({
|
||
|
|
cwd,
|
||
|
|
configFile: "nuxt.config",
|
||
|
|
onCreate() {
|
||
|
|
configMissing = true;
|
||
|
|
return false;
|
||
|
|
},
|
||
|
|
async onUpdate(config) {
|
||
|
|
if (!Array.isArray(config.modules)) return;
|
||
|
|
const present = [];
|
||
|
|
for (const item of config.modules) {
|
||
|
|
const name = readModuleName(item);
|
||
|
|
if (name) present.push(name);
|
||
|
|
}
|
||
|
|
let toRemove;
|
||
|
|
if (modules.length === 0) {
|
||
|
|
if (present.length === 0) return;
|
||
|
|
const picked = await multiselect({
|
||
|
|
message: "Select modules to remove:",
|
||
|
|
options: present.map((m) => ({
|
||
|
|
value: m,
|
||
|
|
label: m
|
||
|
|
})),
|
||
|
|
required: true
|
||
|
|
});
|
||
|
|
if (isCancel(picked)) {
|
||
|
|
cancelled = true;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
toRemove = new Set(picked);
|
||
|
|
} else toRemove = new Set(modules);
|
||
|
|
for (let i = config.modules.length - 1; i >= 0; i--) {
|
||
|
|
const name = readModuleName(config.modules[i]);
|
||
|
|
if (name && toRemove.has(name)) {
|
||
|
|
logger.info(`Removing ${colors.cyan(name)} from the ${colors.cyan("modules")}`);
|
||
|
|
config.modules.splice(i, 1);
|
||
|
|
removedFromConfig.push(name);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}).catch((error) => {
|
||
|
|
if (configMissing) return;
|
||
|
|
logger.error(`Failed to update ${colors.cyan("nuxt.config")}: ${error.message}`);
|
||
|
|
logger.error(`Please manually remove ${colors.cyan(modules.join(", ") || "the relevant modules")} from the ${colors.cyan("modules")} array in ${colors.cyan("nuxt.config.ts")}`);
|
||
|
|
});
|
||
|
|
if (cancelled) {
|
||
|
|
cancel("No modules selected.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (modules.length === 0 && removedFromConfig.length === 0) {
|
||
|
|
cancel(configMissing ? `No ${colors.cyan("nuxt.config")} found in ${colors.cyan(relativeToProcess(cwd))}.` : `No modules configured in ${colors.cyan("nuxt.config")}.`);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!skipInstall) {
|
||
|
|
const installedModules = [];
|
||
|
|
const notInstalledModules = [];
|
||
|
|
const dependencies = getProjectDependencies(projectPkg);
|
||
|
|
const targets = Array.from(new Set([...modules, ...removedFromConfig]));
|
||
|
|
for (const module of targets) if (dependencies.has(module)) installedModules.push(module);
|
||
|
|
else notInstalledModules.push(module);
|
||
|
|
if (notInstalledModules.length > 0) {
|
||
|
|
const notInstalledList = notInstalledModules.map((m) => colors.cyan(m)).join(", ");
|
||
|
|
const are = notInstalledModules.length > 1 ? "are" : "is";
|
||
|
|
logger.info(`${notInstalledList} ${are} not installed as a dependency`);
|
||
|
|
}
|
||
|
|
if (installedModules.length === 0) return true;
|
||
|
|
const toRemove = [...installedModules];
|
||
|
|
const orphanedPeers = await findOrphanedPeers(installedModules, projectPkg, cwd);
|
||
|
|
if (orphanedPeers.length > 0) {
|
||
|
|
const peersList = orphanedPeers.map(({ peer, source }) => `${colors.cyan(peer)} (peer of ${colors.cyan(source)})`).join(", ");
|
||
|
|
const peerDep = orphanedPeers.length > 1 ? "dependencies" : "dependency";
|
||
|
|
const them = orphanedPeers.length > 1 ? "them" : "it";
|
||
|
|
logger.info(`The following peer ${peerDep} ${orphanedPeers.length > 1 ? "are" : "is"} no longer used by any other dependency: ${peersList}`);
|
||
|
|
const alsoRemove = await confirm({
|
||
|
|
message: `Do you also want to remove ${them}?`,
|
||
|
|
initialValue: false
|
||
|
|
});
|
||
|
|
if (isCancel(alsoRemove)) {
|
||
|
|
cancel("Aborted.");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (alsoRemove) toRemove.push(...orphanedPeers.map((o) => o.peer));
|
||
|
|
}
|
||
|
|
const removeList = toRemove.map((m) => colors.cyan(m)).join(", ");
|
||
|
|
const dependency = toRemove.length > 1 ? "dependencies" : "dependency";
|
||
|
|
logger.info(`Uninstalling ${removeList} ${dependency}`);
|
||
|
|
const packageManager = await detectPackageManager(cwd);
|
||
|
|
if (!await removeDependency(toRemove, {
|
||
|
|
cwd,
|
||
|
|
packageManager,
|
||
|
|
workspace: isPnpmWorkspace(packageManager, cwd)
|
||
|
|
}).then(() => true).catch((error) => {
|
||
|
|
logger.error(String(error));
|
||
|
|
return false;
|
||
|
|
})) return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
function readModuleName(item) {
|
||
|
|
if (typeof item === "string") return item;
|
||
|
|
if (Array.isArray(item) && typeof item[0] === "string") return item[0];
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
function resolveModuleName(input, modulesDB, installed) {
|
||
|
|
if (installed.has(input)) return input;
|
||
|
|
return modulesDB.find((m) => m.name === input || m.npm === input || m.aliases?.includes(input))?.npm || input;
|
||
|
|
}
|
||
|
|
async function findOrphanedPeers(removing, projectPkg, cwd) {
|
||
|
|
const projectDeps = getProjectDependencies(projectPkg);
|
||
|
|
const removingSet = new Set(removing);
|
||
|
|
const candidates = /* @__PURE__ */ new Map();
|
||
|
|
for (const m of removing) {
|
||
|
|
const pkg = await readPackageJSON(m, { from: cwd }).catch(() => null);
|
||
|
|
if (!pkg?.peerDependencies) continue;
|
||
|
|
for (const peer of Object.keys(pkg.peerDependencies)) {
|
||
|
|
if (!projectDeps.has(peer) || removingSet.has(peer) || candidates.has(peer)) continue;
|
||
|
|
candidates.set(peer, m);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (candidates.size === 0) return [];
|
||
|
|
const stillNeeded = /* @__PURE__ */ new Set();
|
||
|
|
for (const dep of projectDeps) {
|
||
|
|
if (removingSet.has(dep) || candidates.has(dep)) continue;
|
||
|
|
const depPkg = await readPackageJSON(dep, { from: cwd }).catch(() => null);
|
||
|
|
if (!depPkg) continue;
|
||
|
|
const depDeps = new Set([...Object.keys(depPkg.dependencies || {}), ...Object.keys(depPkg.peerDependencies || {})]);
|
||
|
|
for (const peer of candidates.keys()) if (depDeps.has(peer)) stillNeeded.add(peer);
|
||
|
|
}
|
||
|
|
const orphans = [];
|
||
|
|
for (const [peer, source] of candidates) if (!stillNeeded.has(peer)) orphans.push({
|
||
|
|
peer,
|
||
|
|
source
|
||
|
|
});
|
||
|
|
return orphans;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
export { remove_default as default };
|