diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..28f2292 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Node Modules + +/node_modules/ \ No newline at end of file diff --git a/bin/configs.js b/bin/configs.js new file mode 100644 index 0000000..b0f06c3 --- /dev/null +++ b/bin/configs.js @@ -0,0 +1,33 @@ +export const metadata = { + name: "Quick Start Express", + version: "v1.0.0", + description: + "A simple CLI tool to generate Express servers from multiple available templates.", + oneLineDescription: "A simple Express.js server generator CLI tool.", +}; + +export const commands = { + version: { + versionFlags: "-v, --version", + }, + init: { + command: "init", + description: "Initialize a new Express server.", + }, + clear: { + command: "clear", + description: "Clear the directory.", + }, +}; + +export const templates = { + basic: { + name: "basic", + dependencies: [ + { + name: "express", + version: "^4.17.1", + }, + ], + }, +}; diff --git a/bin/index.js b/bin/index.js new file mode 100644 index 0000000..7f6a1b1 --- /dev/null +++ b/bin/index.js @@ -0,0 +1,141 @@ +#!/usr/bin/env node + +import { program } from "commander"; +import fs from "fs-extra"; +import path from "path"; +import { fileURLToPath } from "url"; +import { execSync } from "child_process"; +import figlet from "figlet"; +import chalk from "chalk"; +import { createSpinner } from "nanospinner"; +import { metadata, commands, templates } from "./configs.js"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const template = templates.basic; + +program + .version(metadata.version, commands.version.versionFlags) + .description(metadata.description); + +program + .command(commands.init.command) + .description(commands.init.description) + .action(() => { + toolIntro(); + + console.log("Starting server initialization..."); + + const targetDir = process.cwd(); + const parentDir = path.dirname(__dirname); + const templatePath = path.join(parentDir, "templates", template.name); + const destinationPath = path.join(targetDir); + const npmInit = chalk.yellow.bold("npm init"); + + const initSpinner = createSpinner(`Running ${npmInit}...`).start(); + try { + // execSync('npm init -y', { stdio: 'inherit', cwd: targetDir }); + execSync("npm init -y", { stdio: "ignore", cwd: targetDir }); + initSpinner.success({ text: `${npmInit} completed successfully.` }); + } catch (err) { + initSpinner.error({ text: `Error running ${npmInit}:\n` }); + console.error(err.message); + return; + } + + //console.log(`Copying server template from ${templatePath} to ${destinationPath}`); + + const copySpinner = createSpinner("Creating server files...").start(); + try { + fs.copySync(templatePath, destinationPath); + copySpinner.success({ text: "Created server files successfully." }); + } catch (err) { + copySpinner.error({ text: "Error creating server files.\n" }); + console.error(err.message); + } + + const addDependencies = createSpinner( + "Adding dependency packages..." + ).start(); + try { + // Update package.json to add express as a dependency. + const packageJsonPath = path.join(targetDir, "package.json"); + const packageJsonContent = fs.readFileSync(packageJsonPath, "utf8"); + const packageJson = JSON.parse(packageJsonContent); + packageJson.dependencies = packageJson.dependencies || {}; + // packageJson.dependencies.express = "^4.17.1"; + template.dependencies.forEach((dependency) => { + packageJson.dependencies[`${dependency.name}`] = dependency.version; + }); + fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); + + addDependencies.success({ + text: "Added dependency packages successfully.", + }); + } catch (err) { + addDependencies.error("Error adding dependency packages.\n"); + console.error(err.message); + } + + const installDependencies = createSpinner( + "Installing dependency packages..." + ).start(); + try { + //execSync('npm i', { stdio: 'inherit', cwd: targetDir }); + execSync("npm i", { stdio: "ignore", cwd: targetDir }); + + installDependencies.success({ + text: "Installed dependencies successfully.", + }); + + console.log(chalk.green.bold("\nSetup complete! To run your server:")); + console.log(chalk.yellow("Run:"), chalk.white.bold("npm start")); + } catch (err) { + installDependencies.error({ text: "Error installing dependencies.\n" }); + console.error(err); + } + }); + +program + .command(commands.clear.command) + .description(commands.clear.description) + .action(() => { + const targetDir = process.cwd(); + console.log("Clearing Directory...", chalk.bgRed.white(targetDir)); + const clearingDirectory = createSpinner("Deleting All Files...").start(); + try { + // Read the directory. + const files = fs.readdirSync(targetDir); + + for (const file of files) { + const filePath = path.join(targetDir, file); + // if (file !== '.' && file !== '..') { + fs.removeSync(filePath); + // } + } + + clearingDirectory.success({ + text: "Successfully cleared project directory.", + }); + } catch (error) { + clearingDirectory.error({ text: "Error clearing project directory" }); + console.error(error); + } + }); + +const toolIntro = () => { + console.log( + figlet.textSync(metadata.name, { + font: "Standard", + horizontalLayout: "default", + verticalLayout: "default", + width: 90, + whitespaceBreak: true, + }) + ); + + console.log(chalk.green.bold(metadata.oneLineDescription)); +}; + +program.parse(process.argv); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..069353b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,109 @@ +{ + "name": "qse", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "qse", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^12.1.0", + "figlet": "^1.7.0", + "fs-extra": "^11.2.0", + "nanospinner": "^1.1.0" + } + }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/figlet": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.7.0.tgz", + "integrity": "sha512-gO8l3wvqo0V7wEFLXPbkX83b7MVjRrk1oRLfYlZXol8nEpb/ON9pcKLI4qpBv5YtOTfrINtqb7b40iYY2FTWFg==", + "license": "MIT", + "bin": { + "figlet": "bin/index.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/nanospinner": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nanospinner/-/nanospinner-1.1.0.tgz", + "integrity": "sha512-yFvNYMig4AthKYfHFl1sLj7B2nkHL4lzdig4osvl9/LdGbXwrdFRoqBS98gsEsOakr0yH+r5NZ/1Y9gdVB8trA==", + "license": "ISC", + "dependencies": { + "picocolors": "^1.0.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "license": "ISC" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..ba30861 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "qse", + "version": "1.0.0", + "description": "A simple CLI tool to generate Express servers from multiple available templates.", + "type": "module", + "main": "index.js", + "scripts": { + "dev": "node bin/index.js init" + }, + "author": "Abhinav Ramakrishnan, Ashwin Narayanan S", + "license": "ISC", + "bin":"./bin/index.js", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^12.1.0", + "figlet": "^1.7.0", + "fs-extra": "^11.2.0", + "nanospinner": "^1.1.0" + } +} diff --git a/templates/basic/server.js b/templates/basic/server.js new file mode 100644 index 0000000..94cd768 --- /dev/null +++ b/templates/basic/server.js @@ -0,0 +1,11 @@ +const express = require("express"); +const app = express(); +const port = 3000; + +app.get("/", (req, res) => { + return res.send("Hello World!"); +}); + +app.listen(port, () => { + console.log(`Example app listening on port ${port}.`); +});