react-cleanup-cli
Version:
Ever wanted a tool that creates a React project for you with all the clutter removed? Vite is a great bundling tool that sets up a React Project quickly. But for those of us who don't want any of the boilerplate css or jsx or to remove the svgs it has to
210 lines (209 loc) • 7.99 kB
JavaScript
import chalk from "chalk";
import path from "path";
import { exit } from "process";
import welcome from "cli-welcome";
import * as fs from "fs";
import * as fsP from "node:fs/promises";
import { select, confirm } from "@inquirer/prompts";
import { runCommand } from "./custom.js";
export function colorMessage(color, message) {
if (color === "green")
console.log(chalk.rgb(0, 204, 153)(message));
else if (color === "red")
console.log(chalk.rgb(188, 11, 70)(message));
else if (color === "magenta")
console.log(chalk.rgb(119, 51, 187)(message));
}
export function welcomeMessage() {
welcome({
title: `react-cleanup-cli`,
tagLine: `by Souvik Roy`,
description: "A cli to set up a clean React project",
version: "0.0.7",
bgColor: "#6cc24a",
color: "#000000",
bold: true,
});
}
export function handleExit() {
colorMessage("red", "❌ Process was interrupted by user");
colorMessage("red", "👋 Exiting....");
process.exit(0);
}
function checkNode_Modules(dirpath) {
let modulePath = path.resolve(dirpath, "node_modules");
if (!fs.existsSync(modulePath)) {
colorMessage("red", "Not a React project");
colorMessage("red", "Exiting...");
exit(1);
}
else {
colorMessage("green", "Verified React Project");
return;
}
}
//function to delete a specific line from App.jsx or App.tsx
export async function updateFile(pathOf, mainFile) {
let updatedData = [
"import './App.css'",
"function App() {",
" return (",
" <>",
" <h1>Vite + React</h1>",
" </>",
" )",
"}",
"export default App",
];
updatedData = updatedData.join("\n");
await fsP.writeFile(pathOf, updatedData, "utf8");
colorMessage("green", mainFile + " Cleaned");
}
//function to cleanup App.css and add basic reset
export async function cleanAppCss(filePath) {
let updatedCss = [
"*{",
" padding:0;",
" margin:0;",
" box-sizing:border-box;",
"}",
];
updatedCss = updatedCss.join("\n");
await fsP.writeFile(filePath, updatedCss, "utf8");
colorMessage("green", "App.css file cleaned");
}
export async function removeImport(pathOf, stringToSearch) {
try {
let data = await fsP.readFile(pathOf, "utf8");
let lines = data.split("\n");
lines = lines.filter((line) => !line.includes(stringToSearch));
let updatedData = lines.join("\n");
await fsP.writeFile(pathOf, updatedData, "utf8");
colorMessage("green", "index.css import removed from main");
}
catch (err) {
console.log(err);
console.log(chalk.red("Error reading file"));
return;
}
}
export async function changeSiteTitle(pathOf, stringToSearch, siteTitle) {
try {
let data = await fsP.readFile(pathOf, "utf8");
let updatedData = data.replace(stringToSearch, siteTitle);
await fsP.writeFile(pathOf, updatedData, "utf8");
colorMessage("green", `Site Title changed to ${siteTitle}`);
}
catch (err) {
console.log(err);
console.log(chalk.red("Error reading file"));
return;
}
}
export async function removeSvgs(pathToFiles) {
for (let file of pathToFiles) {
if (fs.existsSync(file)) {
await fsP.rm(file);
colorMessage("green", `Removed ${path.basename(file)} successfully`);
}
else {
colorMessage("red", `${file} does not exist`);
}
}
}
export async function performOperations({ fullPath, confirmAll = false, isTypeScript = false, htmlTitle = false, deleteSvgs = false, }) {
const packageJson = path.resolve(fullPath, "package.json");
try {
const file = await fsP.readFile(packageJson, "utf-8");
// check if react is part of dependenies or devDependencies
const jsonData = JSON.parse(file.toString());
const { dependencies, devDependencies } = jsonData;
const reactExist = (dependencies === null || dependencies === void 0 ? void 0 : dependencies.react) !== undefined || (devDependencies === null || devDependencies === void 0 ? void 0 : devDependencies.react) !== undefined;
if (!reactExist) {
colorMessage("red", "Unable to find react as a dependency in package.json");
colorMessage("red", "Exiting...");
exit(1);
}
else {
//Verified that this is a react project
// Check if this is a Javascript or TypeScript project
// By checking the presence of a tsconfig.json in the root folder
let projectMain;
if (fs.existsSync(path.resolve(fullPath, "tsconfig.json")) ||
isTypeScript) {
projectMain = "App.tsx";
}
else {
projectMain = "App.jsx";
}
let mainFileName = "main." + projectMain.split(".")[1];
console.log();
let mainFilePath = path.join(fullPath, "src", projectMain);
let appCssPath = path.join(fullPath, "src", "App.css");
let mainJsxPath = path.join(fullPath, "src", mainFileName);
await updateFile(mainFilePath, projectMain);
await cleanAppCss(appCssPath);
await removeImport(mainJsxPath, "index.css");
if (fs.existsSync(path.resolve(fullPath, "src", "index.css"))) {
let pathToremove = path.resolve(fullPath, "src", "index.css");
await fsP.rm(pathToremove);
colorMessage("green", "Deleting index.css");
}
else {
colorMessage("red", "index.css does not exist");
}
if (htmlTitle || confirmAll) {
let indexHtmlFile = path.join(fullPath, "index.html");
let siteTitle = path.basename(fullPath);
const titleToReplace = projectMain === "App.jsx" ? "Vite + React" : "Vite + React + TS";
await changeSiteTitle(indexHtmlFile, titleToReplace, siteTitle);
}
if (deleteSvgs || confirmAll) {
const reactSvgPath = path.join(fullPath, "src/assets", "react.svg");
const viteSvgPath = path.join(fullPath, "public/vite.svg");
await removeSvgs([reactSvgPath, viteSvgPath]);
}
}
colorMessage("magenta", `Files cleaned and project created at ${fullPath}`);
console.log();
let confirmEmptyFolders;
if (!confirmAll) {
let emptyFolderString = `There are 2 empty folders: 'assets' and 'public'
Do you want to delete them?`;
confirmEmptyFolders = await confirm({
message: emptyFolderString,
});
}
else {
confirmEmptyFolders = true;
}
if (confirmEmptyFolders || confirmAll) {
await fsP.rmdir(path.join(fullPath, "public"));
await fsP.rmdir(path.join(fullPath, "src", "assets"));
colorMessage("green", "Empty folders 'assets' and 'public' deleted");
}
let additionalOptions = await select({
message: "What do you want to do next?",
choices: [
{
name: "Open Project with VS Code ( You need to have the command code in $path )",
value: "openCode",
},
{ name: "Exit", value: "Exit" },
],
});
if (additionalOptions === "openCode") {
runCommand(`code ${fullPath}`);
colorMessage("green", "👋 Exiting..");
process.exit(0);
}
else {
colorMessage("green", "👋 Exiting..");
process.exit(0);
}
}
catch (err) {
console.log(err);
colorMessage("red", "Error while reading json file");
}
}