@roboplay/sage
Version:
Codemod for Robo.js
146 lines (143 loc) • 6.79 kB
JavaScript
import { Command } from 'commander';
import tar from 'tar';
import { color, composeColors } from '../core/color.js';
import { logger } from '../core/logger.js';
import { getPackageManager, checkSageUpdates, isRoboProject, downloadFile, exec } from '../core/utils.js';
import path from 'node:path';
import { mkdirSync } from 'node:fs';
import { readFile, access, cp, writeFile } from 'node:fs/promises';
import { cleanTempDir } from 'robo.js/utils.js';
const command = new Command("import").arguments("[plugins...]").description("Import plugin(s) as modules into your Robo").option("-ns --no-self-check", "do not check for updates to Sage CLI").option("-s --silent", "do not print anything").option("-v --verbose", "print more information for debugging").action(importAction);
var import_default = command;
async function importAction(plugins, options) {
logger({
enabled: !options.silent,
level: options.verbose ? "debug" : "info"
}).info(`Importing ${plugins.length} plugin${plugins.length === 1 ? "" : "s"}...`);
logger.debug(`CLI Options:`, options);
logger.debug(`Package manager:`, getPackageManager());
logger.debug(`Current working directory:`, process.cwd());
logger.debug(`Plugins:`, plugins);
if (options.selfCheck) {
await checkSageUpdates();
}
if (plugins.length < 1) {
logger.error("Please provide at least one plugin to import!");
process.exit(1);
}
if (!await isRoboProject()) {
logger.error(`This does not appear to be a Robo project!`);
process.exit(1);
}
const packageJsonPath = path.join(process.cwd(), "package.json");
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf-8"));
const success = [];
try {
await cleanTempDir();
} catch (error) {
logger.debug(`Failed to clean temp directory:`, error);
}
let needsTypescript = false;
for (const plugin of plugins) {
try {
const result = await importPlugin(plugin, packageJson);
if (result.typescript) {
needsTypescript = true;
}
success.push(plugin);
} catch (error) {
logger.error(`Failed to import plugin "${color.bold(plugin)}":`, error);
}
}
if (success.length > 0) {
logger.ready(`Successfully imported ${success.length} plugin${success.length === 1 ? "" : "s"}!`);
} else {
logger.error(`Failed to import any plugins.`);
}
const tsPath = path.join(process.cwd(), "tsconfig.json");
const tsExists = await access(tsPath).then(() => true).catch(() => false);
if (needsTypescript && !tsExists) {
const docs = composeColors(color.underline, color.cyan)("https://docs.roboplay.dev/docs/advanced/typescript");
logger.warn(`One or more of your plugins requires TypeScript.`);
logger.warn(`See the following docs for more information:`, docs);
}
}
async function importPlugin(plugin, packageJson) {
const npmResponse = await fetch(`https://registry.npmjs.org/${plugin}/latest`);
const info = await npmResponse.json();
const prefix = color.bold(plugin + " >");
logger.debug(prefix, `Registry info:`, info);
if (!npmResponse.ok) {
throw new Error(`Plugin "${color.bold(plugin)}" does not exist!`);
}
const packageName = info.name.replace("/", "_").replace("@", "");
const distDir = path.join(".robo", "temp", `${packageName}_${info.version}`);
const sourceTar = distDir + ".tgz";
logger.info(prefix, `Downloading tarball...`);
await downloadFile(info.dist.tarball, sourceTar);
mkdirSync(distDir, { recursive: true });
logger.debug(prefix, `Extracting tarball...`);
await tar.x({
file: sourceTar,
cwd: distDir
});
logger.debug(prefix, `Verifying "src" directory...`);
const pluginDir = path.join(distDir, "package");
const pluginSrcDir = path.join(pluginDir, "src");
const pluginSrcDirExists = await access(pluginSrcDir).then(() => true).catch(() => false);
if (!pluginSrcDirExists) {
throw new Error(`Plugin "${color.bold(plugin)}" does not have a "src" directory!`);
}
logger.info(prefix, "Copying plugin source files to Robo project...");
const roboSrcDir = path.join(process.cwd(), "src", "modules", packageName);
mkdirSync(roboSrcDir, { recursive: true });
await cp(pluginSrcDir, roboSrcDir, {
recursive: true
});
const pluginReadmePath = path.join(pluginDir, "README.md");
const pluginReadmeExists = await access(pluginReadmePath).then(() => true).catch(() => false);
if (pluginReadmeExists) {
const readmeContents = await readFile(pluginReadmePath, "utf-8");
const readmeSource = `**[View original source](https://www.npmjs.com/package/${plugin})**`;
const readmeHeader = `> ***Import*ant:** This module was imported from the plugin package "${plugin}". ${readmeSource}
`;
await writeFile(pluginReadmePath, readmeHeader + readmeContents);
await cp(pluginReadmePath, path.join(roboSrcDir, "README.md"));
}
logger.debug(prefix, `Reading plugin's package.json...`);
const pluginPackageJson = JSON.parse(await readFile(path.join(pluginDir, "package.json"), "utf-8"));
const pluginDeps = pluginPackageJson.dependencies ?? {};
const pluginDevDeps = pluginPackageJson.devDependencies ?? {};
const projectDeps = packageJson.dependencies ?? {};
const projectDevDeps = packageJson.devDependencies ?? {};
logger.info(prefix, `Checking for TypeScript...`);
const pluginHasTs = Object.keys(pluginDevDeps).includes("typescript");
logger.debug(prefix, `Plugin ${pluginHasTs ? "contains" : "does not contain"} TypeScript.`);
delete pluginDevDeps["robo.js"];
delete projectDevDeps["discord.js"];
logger.debug(prefix, `Comparing dependencies...`);
const depsToInstall = Object.keys(pluginDeps).filter((dep) => !projectDeps[dep]);
const devDepsToInstall = Object.keys(pluginDevDeps).filter((dep) => !projectDevDeps[dep]);
logger.debug(prefix, `Dependencies to install:`, depsToInstall);
logger.debug(prefix, `Dev dependencies to install:`, devDepsToInstall);
if (depsToInstall.length > 0) {
logger.info(prefix, `Installing dependencies...`);
const packageManager = getPackageManager();
const command2 = packageManager === "npm" ? "install" : "add";
await exec(`${packageManager} ${command2} ${depsToInstall.join(" ")}`);
}
if (devDepsToInstall.length > 0) {
logger.info(prefix, `Installing dev dependencies...`);
const packageManager = getPackageManager();
const command2 = packageManager === "npm" ? "install" : "add";
const commandOption = packageManager === "npm" ? "--save-dev" : "--dev";
await exec(`${packageManager} ${command2} ${commandOption} ${devDepsToInstall.join(" ")}`);
}
logger.info(prefix, `Successfully imported!`);
return {
typescript: pluginHasTs
};
}
export { import_default as default };
//# sourceMappingURL=out.js.map
//# sourceMappingURL=import.js.map