Skip to content

Repository files navigation

Table of Contentsgenerated with DocToc

@s54a/init || TempLate CLI || Project Initializer

When I was starting a new project, I used the 'create vite app' command. Then, I began to remove and add files for the project. It struck me that I could create it once and paste it everywhere when I start a new project. Thats how I started building this.

There are two branch of this project in this one I have removed images & a few files to reduce the size

Visit the NPM Readme to see examples

How it Works

The package stores Templates inside a folder called "Templates" then when you run the init command it displays the templates and then it will paste the folder at the location where the terminal is open.

Simply it just copies & pastes the Folders from one place to another

Video Tutorial

Video Tutorial

Folder Structure

📁 init
├── 🌅 images
│ ├── 🖼️ article.png
│ ├── 🖼️ init -a.png
│ ├── 🖼️ init -c.png
│ ├── 🖼️ init -h.png
│ ├── 🖼️ init -r.png
│ └── 🖼️ init.png
├── 📁 templates
│ └── 📁 templateTest
│ ├── 📄 index.html
│ ├── 📄 main.js
│ └── 📄 style.css
├── 📄 .gitignore
├── 📄 .npmignore
├── 📄 index.js
├── 📜 LICENSE
├── 📝 Readme.md
├── 📋 package.json
└── 📋 package-lock.json

For testing purposes, only one template has been included, consisting of three files (HTML, CSS & JS). Additional templates have not been added to avoid making the package unnecessarily large.

(Note ChatGPT built this folder structure)

Installation

This package provides an Executable Command

You will have to install this package globally to be able to use the init command.

npm install -g @s54a/init

Usage

To begin, open a terminal at the desired project location and run this command

init
Example

init

This displays all available templates from the template folder, listed by folder name. Choose a template and enter the desired folder name when prompted to create a new project with the selected template's contents.

Users can also create templates themselves by running:

init -a "C:\Users\{User}\Desktop\Projects\Ongoing Projects"
Example

init

Upon execution, the tool generates a new folder path containing the contents of the user-created template. Subsequently, when the init command is invoked, it showcases the recently created template under the specified name.

Tip: For Windows users, you can quickly access the folder by selecting it and then pressing ctrl + shift + c.

By Default when you create a Template it skips the node_modules folder and its contents.

But for reason you want to create a template with node_modules folder you will have to pass the -y flag.

init -a "O:\test\cliTest" -y
Example

init

Templates can be removed using the following command:

init -r "template name"
Example

init

(Note: The name must match exactly.)

Templates can also be added from GitHub with:

init -c "https://github.com/user/repoitoryName.git"
Example

init

This process involves cloning the repository into the current terminal directory, removing the .git folder from the cloned repository, executing the init -a "repoName" command to create a copy in the templates folder, and then deleting the cloned repository folder from the current terminal location.

I have used this Regex to verify if the given string is a link or not.

consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;

The reason it performs all these steps is because I attempted to accomplish it in a simpler manner but couldn't find one.

To see all the Commands (Help)

init -h
Example

init

Resources

These are the YouTube Videos & Article which helped me build this

The Article Link

The Video Link

The Video Link

& ChatGPT

This a similar project built with Typescript https://github.com/pongsatt/mycli/blob/master/src/index.ts

Extra Resources https://github.com/lirantal/nodejs-cli-apps-best-practices

Take a look at https://yeoman.io/generators/

Read this if you are a beginner

I asked one of my friend who is a beginner in Web Dev. She asked me a question how will I make templates or why use this instead of Copy Pasting

So when ever you do

npm create-react-app ProjectName

or

npm create-vite-app ProjectName

These files are generated (with create react app)

my-app/
├── README.md
├── node_modules/
├── package.json
├── .gitignore
├── public/
│ ├── favicon.ico
│ ├── index.html
│ ├── manifest.json
│ └── robots.txt
└── src/
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
└── logo.svg

As you can see there are so many files which aren't necessary so you will have to remove these files remove code from index.css or maybe more files.

So you can do this once and use this template by using this package or just copy paste.

So why use this package instead of copy pasting So assume you have created many templates now you will create a folder to store them and every time you will start a new project you will have to go to that location copy that file and paste it at the location where you are starting the project and then change the name.

So this package does all that when you create a template and add it as a template from Command Line Interface and what I have learned & heard is that you will much faster at things with CLI then GUI.

Why I Created this

When you start Learning to code you will create multiple new projects so every time you will have to create new files

e.g. index.html, style.css, app.js

When you will advance to React you will do

So every time you will do that you will have to remove files edit content of the files.

So I thought it is a hassle so lets just do it once and I wil copy & paste it every time whenever I start a new project.

Then I thought I can create a cli which does that for me & I started building this package.

Then on a suggestion of a friend I also added the Clone & Create Template from Github Feature.

How I use this Package

I use this Package whenever I start a new project.

I have created my own template and added them as templates using init -a "folder path" command.

I have also added templates on Github.

So if I am on a new device or format my current one so I can just run the init -c "github_url" command after installing the package to clone new project and create a new template.

So if you are a Freelancer or Someone who is learning to code, or starting a new Project you can use this.

Extra Info

While Deploying Packages on NPM I realized that whatever you have in your project will get included even if you use npm ignore. I don't know if npm ignore works or failed. So I created another branch of this project in which I removed images and extra files. To reduce the size of the package & the node_modules size.

Here is the difference

size differencesize difference

So the Package Size is reduced by 300 Kilo Bytes

Source Code

Every time when I look at the open source I feel it is a hassle to navigate around files to see the code.

And this project source code is in a single file.

So I am adding the source code in the markdown file so you can read it all in one place.

index.js

#!/usr/bin/env node
importinquirerfrom"inquirer";importfsfrom"fs";importpathfrom"path";import{fileURLToPath}from"url";import{execSync}from"child_process";importchalkfrom"chalk";const__dirname=path.dirname(fileURLToPath(import.meta.url));constCHOICES=fs.readdirSync(path.join(__dirname,"templates"));constQUESTIONS=[{name: "project-choice",type: "list",message: "What project template would you like to generate?",choices: CHOICES,},{name: "project-name",type: "input",message: "Project name:",validate: function(input){if(/^([A-Za-z\-\_\d])+$/.test(input))returntrue;elsereturn"Project name may only include letters, numbers, underscores and hashes.";},},];constCURR_DIR=process.cwd();letnodeFlag=false;// Set nodeFlag as a global variable with a default value of false// Command line argumentsconst[,,condition,folderPath,nodeFlagParam]=process.argv;const[,, ...args]=process.argv;constoptions={condition: null,folderPathOrNameOrLink: null,nodeFlagParam: "",};// Parse command line argumentsfor(leti=0;i<args.length;i++){constarg=args[i];switch(arg){case"-a":
case"-r":
case"-c":
options.condition=arg;break;case"-h":
options.condition=arg;options.folderPathOrNameOrLink="";break;case"-y":
// Check if the previous option was '-a'if(options.condition==="-a"){options.nodeFlagParam=arg;}else{console.error(`Invalid usage of '-y' flag.`);process.exit(1);}break;default:
if(arg.startsWith("-")){console.error(`Invalid option: ${arg}`);process.exit(1);}else{options.folderPathOrNameOrLink=arg;}break;}}if(!args.length){options.condition="";options.folderPathOrNameOrLink="";}// Check for unsupported or invalid optionsif(Object.values(options).some((value)=>value===null)){console.error(`Missing required option or invalid usage.`);process.exit(1);}// Update the value of nodeFlag based on the command line argumentif(nodeFlagParam==="-y"){nodeFlag=true;}functioncreateDirectoryContents(templatePath,newProjectPath){constfilesToCreate=fs.readdirSync(templatePath);filesToCreate.forEach((file)=>{constorigFilePath=path.join(templatePath,file);// get stats about the current fileconststats=fs.statSync(origFilePath);if(stats.isFile()){constcontents=fs.readFileSync(origFilePath,"utf8");// Renameif(file===".npmignore")file=".gitignore";if(condition==="-a"){fs.writeFileSync(path.join(__dirname,"templates",newProjectPath,file),contents,"utf8");}else{fs.writeFileSync(path.join(CURR_DIR,newProjectPath,file),contents,"utf8");}}elseif(stats.isDirectory()){if(condition==="-a"){if(file==="node_modules"&&!nodeFlag){return;}else{fs.mkdirSync(path.join(__dirname,"templates",newProjectPath,file));}}else{fs.mkdirSync(path.join(CURR_DIR,newProjectPath,file));}// Then recursively copy contentscreateDirectoryContents(path.join(templatePath,file),path.join(newProjectPath,file));}});}if(!condition){inquirer.prompt(QUESTIONS).then((answers)=>{constprojectChoice=answers["project-choice"];constprojectName=answers["project-name"];consttemplatePath=path.join(__dirname,"templates",projectChoice);constprojectPath=path.join(CURR_DIR,projectName);// Create project directory if it doesn't existif(!fs.existsSync(projectPath)){fs.mkdirSync(projectPath);}else{console.log(`\nProject directory '${projectName}' already exists.`);{process.exit(1);}}createDirectoryContents(templatePath,projectName);console.log("\nTemplate successfully created.");});}elseif(condition==="-a"){// Validate folder pathif(!folderPath){console.error("\nError: provide a folder path.");{process.exit(1);}}// Validate folder existenceif(!fs.existsSync(folderPath)){console.error("\nError: Folder does not exist.");{process.exit(1);}}// Create project name from folder pathconstprojectName=path.basename(folderPath);// Create directory for new project if it doesn't existconsttemplateFolderPath=path.join(__dirname,"templates",projectName);if(!fs.existsSync(templateFolderPath)){fs.mkdirSync(templateFolderPath);}else{console.log(`\nFolder '${templateFolderPath}' already exists.`);{process.exit(1);}}// Copy contents from folderPath to projectName/templatecreateDirectoryContents(folderPath,projectName);// InformSync user about successful operationif(nodeFlag){console.log("\nTemplate successfully created with node_modules.");}else{console.log("\nTemplate successfully created.");}}elseif(condition==="-r"){consttemplateToRemove=process.argv[3];// Validate if the template existsconsttemplatePathToRemove=path.join(__dirname,"templates",templateToRemove);if(!fs.existsSync(templatePathToRemove)){console.error(`\nError: Template '${templateToRemove}' does not exist.`);{process.exit(1);}}// Remove the template directoryfs.rmSync(templatePathToRemove,{recursive: true});// InformSync user about successful operationconsole.log(`\nTemplate '${templateToRemove}' was successfully removed.`);}elseif(condition==="-c"){construnCommand=(command)=>{returnnewPromise((resolve,reject)=>{try{execSync(command,{stdio: "inherit"});resolve();// Resolve the promise when the command completes successfully}catch(error){console.error(`Failed to Execute ${command}`,error);reject(error);// Reject the promise with the error if the command fails}});};consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;constrepoLink=process.argv[3];if(!urlRegex.test(repoLink)){console.log("Invalid repository link provided.");process.exit(1);}else{console.log("Repository link is valid.");}constgitCommand=`git clone --depth 1 ${repoLink}`;letprojectName;// Check if a changed name is provided in the clone commandif(repoLink.includes(" ")){// Extract the project name from the clone commandconstcloneCommandParts=repoLink.split(" ");// Split the clone command by whitespaceprojectName=cloneCommandParts[cloneCommandParts.length-1];// Get the last part as the project name}else{// Extract the project name from the repository linkprojectName=path.basename(repoLink,".git");}runCommand(gitCommand).then(async()=>{console.log("\nRepository Cloned");// Remove the .git folderconstclonedFolderPath=path.join(CURR_DIR,projectName);constgitFolderPath=path.join(clonedFolderPath,".git");if(fs.existsSync(gitFolderPath)){awaitfs.promises.rm(gitFolderPath,{recursive: true});}// Run the 'init -a' command with the cloned folder pathconstinitCommand=`init -a "${clonedFolderPath}"`;awaitrunCommand(initCommand);// Remove the cloned project folder asynchronouslytry{awaitfs.promises.rm(clonedFolderPath,{recursive: true});}catch(error){console.error(`Failed to remove cloned folder: ${error}`);}}).catch((error)=>{console.error("Error cloning repository:",error);process.exit(1);// Exit the script with an error status code});}elseif(condition==="-h"){// Clear the terminal by printing ANSI escape codesprocess.stdout.write("\u001b[2J\u001b[0;0H");constmessage=`${chalk.bold.underline.white("Package Commands:")}${chalk.green("Create a New Template:")} - Type ${chalk.cyan("'init'")} and press Enter at your desired location.${chalk.green("Add a Template:")} - Use the ${chalk.cyan("-a")} flag followed by the path in quotes. By default it skips the node_modules folder.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')} - But if you want to add node_modules folder with the template you are creating then ${chalk.cyan("-y")} flag after the command.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')}${chalk.cyan("-y")}${chalk.green("Clone a Repository and Add as a Template:")} - Use the ${chalk.cyan("-c")} flag followed by the repository link in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -c")}${chalk.yellow('"https://github.com/user/repoitoryName"')}${chalk.green("Remove a Template:")} - Use the ${chalk.cyan("-r")} flag followed by the exact name of the template in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -r")}${chalk.yellow('"Template Name"')}${chalk.green("Help:")} - Use ${chalk.cyan("init -h")} to see help. Made By Sooraj Gupta Email : soorajgupta00@gmail.com Github Repository : https://github.com/s54a/s54a-init`;console.log(message);}elseif(condition){console.log(chalk.red(` Invalid command: "${condition}". Please use one of the supported commands. Run ${chalk.yellow("init -h")} to see help. `));}else{console.log(chalk.red(`An error occurred or an invalid command was provided. Run ${chalk.yellow("init -h")} to see help.`));}

package.json

{
"name": "@s54a/init",
"version": "5.0.0",
"description": "Project Initializer",
"main": "./index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"init": "index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/s54a/s54a-init.git"
},
"keywords": ["Project Initializer", "Initializer", "Init"],
"author": "Sooraj Gupta",
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
"inquirer": "^9.2.15"
},
"bugs": {
"url": "https://github.com/s54a/s54a-init/issues"
},
"homepage": "https://github.com/s54a/s54a-init#readme"
}

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - s54a/s54a-init: Project Initializer || Template CLI · GitHub
Skip to content

Repository files navigation

Table of Contentsgenerated with DocToc

@s54a/init || TempLate CLI || Project Initializer

When I was starting a new project, I used the 'create vite app' command. Then, I began to remove and add files for the project. It struck me that I could create it once and paste it everywhere when I start a new project. Thats how I started building this.

There are two branch of this project in this one I have removed images & a few files to reduce the size

Visit the NPM Readme to see examples

How it Works

The package stores Templates inside a folder called "Templates" then when you run the init command it displays the templates and then it will paste the folder at the location where the terminal is open.

Simply it just copies & pastes the Folders from one place to another

Video Tutorial

Video Tutorial

Folder Structure

📁 init
├── 🌅 images
│ ├── 🖼️ article.png
│ ├── 🖼️ init -a.png
│ ├── 🖼️ init -c.png
│ ├── 🖼️ init -h.png
│ ├── 🖼️ init -r.png
│ └── 🖼️ init.png
├── 📁 templates
│ └── 📁 templateTest
│ ├── 📄 index.html
│ ├── 📄 main.js
│ └── 📄 style.css
├── 📄 .gitignore
├── 📄 .npmignore
├── 📄 index.js
├── 📜 LICENSE
├── 📝 Readme.md
├── 📋 package.json
└── 📋 package-lock.json

For testing purposes, only one template has been included, consisting of three files (HTML, CSS & JS). Additional templates have not been added to avoid making the package unnecessarily large.

(Note ChatGPT built this folder structure)

Installation

This package provides an Executable Command

You will have to install this package globally to be able to use the init command.

npm install -g @s54a/init

Usage

To begin, open a terminal at the desired project location and run this command

init
Example

init

This displays all available templates from the template folder, listed by folder name. Choose a template and enter the desired folder name when prompted to create a new project with the selected template's contents.

Users can also create templates themselves by running:

init -a "C:\Users\{User}\Desktop\Projects\Ongoing Projects"
Example

init

Upon execution, the tool generates a new folder path containing the contents of the user-created template. Subsequently, when the init command is invoked, it showcases the recently created template under the specified name.

Tip: For Windows users, you can quickly access the folder by selecting it and then pressing ctrl + shift + c.

By Default when you create a Template it skips the node_modules folder and its contents.

But for reason you want to create a template with node_modules folder you will have to pass the -y flag.

init -a "O:\test\cliTest" -y
Example

init

Templates can be removed using the following command:

init -r "template name"
Example

init

(Note: The name must match exactly.)

Templates can also be added from GitHub with:

init -c "https://github.com/user/repoitoryName.git"
Example

init

This process involves cloning the repository into the current terminal directory, removing the .git folder from the cloned repository, executing the init -a "repoName" command to create a copy in the templates folder, and then deleting the cloned repository folder from the current terminal location.

I have used this Regex to verify if the given string is a link or not.

consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;

The reason it performs all these steps is because I attempted to accomplish it in a simpler manner but couldn't find one.

To see all the Commands (Help)

init -h
Example

init

Resources

These are the YouTube Videos & Article which helped me build this

The Article Link

The Video Link

The Video Link

& ChatGPT

This a similar project built with Typescript https://github.com/pongsatt/mycli/blob/master/src/index.ts

Extra Resources https://github.com/lirantal/nodejs-cli-apps-best-practices

Take a look at https://yeoman.io/generators/

Read this if you are a beginner

I asked one of my friend who is a beginner in Web Dev. She asked me a question how will I make templates or why use this instead of Copy Pasting

So when ever you do

npm create-react-app ProjectName

or

npm create-vite-app ProjectName

These files are generated (with create react app)

my-app/
├── README.md
├── node_modules/
├── package.json
├── .gitignore
├── public/
│ ├── favicon.ico
│ ├── index.html
│ ├── manifest.json
│ └── robots.txt
└── src/
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
└── logo.svg

As you can see there are so many files which aren't necessary so you will have to remove these files remove code from index.css or maybe more files.

So you can do this once and use this template by using this package or just copy paste.

So why use this package instead of copy pasting So assume you have created many templates now you will create a folder to store them and every time you will start a new project you will have to go to that location copy that file and paste it at the location where you are starting the project and then change the name.

So this package does all that when you create a template and add it as a template from Command Line Interface and what I have learned & heard is that you will much faster at things with CLI then GUI.

Why I Created this

When you start Learning to code you will create multiple new projects so every time you will have to create new files

e.g. index.html, style.css, app.js

When you will advance to React you will do

So every time you will do that you will have to remove files edit content of the files.

So I thought it is a hassle so lets just do it once and I wil copy & paste it every time whenever I start a new project.

Then I thought I can create a cli which does that for me & I started building this package.

Then on a suggestion of a friend I also added the Clone & Create Template from Github Feature.

How I use this Package

I use this Package whenever I start a new project.

I have created my own template and added them as templates using init -a "folder path" command.

I have also added templates on Github.

So if I am on a new device or format my current one so I can just run the init -c "github_url" command after installing the package to clone new project and create a new template.

So if you are a Freelancer or Someone who is learning to code, or starting a new Project you can use this.

Extra Info

While Deploying Packages on NPM I realized that whatever you have in your project will get included even if you use npm ignore. I don't know if npm ignore works or failed. So I created another branch of this project in which I removed images and extra files. To reduce the size of the package & the node_modules size.

Here is the difference

size differencesize difference

So the Package Size is reduced by 300 Kilo Bytes

Source Code

Every time when I look at the open source I feel it is a hassle to navigate around files to see the code.

And this project source code is in a single file.

So I am adding the source code in the markdown file so you can read it all in one place.

index.js

#!/usr/bin/env node
importinquirerfrom"inquirer";importfsfrom"fs";importpathfrom"path";import{fileURLToPath}from"url";import{execSync}from"child_process";importchalkfrom"chalk";const__dirname=path.dirname(fileURLToPath(import.meta.url));constCHOICES=fs.readdirSync(path.join(__dirname,"templates"));constQUESTIONS=[{name: "project-choice",type: "list",message: "What project template would you like to generate?",choices: CHOICES,},{name: "project-name",type: "input",message: "Project name:",validate: function(input){if(/^([A-Za-z\-\_\d])+$/.test(input))returntrue;elsereturn"Project name may only include letters, numbers, underscores and hashes.";},},];constCURR_DIR=process.cwd();letnodeFlag=false;// Set nodeFlag as a global variable with a default value of false// Command line argumentsconst[,,condition,folderPath,nodeFlagParam]=process.argv;const[,, ...args]=process.argv;constoptions={condition: null,folderPathOrNameOrLink: null,nodeFlagParam: "",};// Parse command line argumentsfor(leti=0;i<args.length;i++){constarg=args[i];switch(arg){case"-a":
case"-r":
case"-c":
options.condition=arg;break;case"-h":
options.condition=arg;options.folderPathOrNameOrLink="";break;case"-y":
// Check if the previous option was '-a'if(options.condition==="-a"){options.nodeFlagParam=arg;}else{console.error(`Invalid usage of '-y' flag.`);process.exit(1);}break;default:
if(arg.startsWith("-")){console.error(`Invalid option: ${arg}`);process.exit(1);}else{options.folderPathOrNameOrLink=arg;}break;}}if(!args.length){options.condition="";options.folderPathOrNameOrLink="";}// Check for unsupported or invalid optionsif(Object.values(options).some((value)=>value===null)){console.error(`Missing required option or invalid usage.`);process.exit(1);}// Update the value of nodeFlag based on the command line argumentif(nodeFlagParam==="-y"){nodeFlag=true;}functioncreateDirectoryContents(templatePath,newProjectPath){constfilesToCreate=fs.readdirSync(templatePath);filesToCreate.forEach((file)=>{constorigFilePath=path.join(templatePath,file);// get stats about the current fileconststats=fs.statSync(origFilePath);if(stats.isFile()){constcontents=fs.readFileSync(origFilePath,"utf8");// Renameif(file===".npmignore")file=".gitignore";if(condition==="-a"){fs.writeFileSync(path.join(__dirname,"templates",newProjectPath,file),contents,"utf8");}else{fs.writeFileSync(path.join(CURR_DIR,newProjectPath,file),contents,"utf8");}}elseif(stats.isDirectory()){if(condition==="-a"){if(file==="node_modules"&&!nodeFlag){return;}else{fs.mkdirSync(path.join(__dirname,"templates",newProjectPath,file));}}else{fs.mkdirSync(path.join(CURR_DIR,newProjectPath,file));}// Then recursively copy contentscreateDirectoryContents(path.join(templatePath,file),path.join(newProjectPath,file));}});}if(!condition){inquirer.prompt(QUESTIONS).then((answers)=>{constprojectChoice=answers["project-choice"];constprojectName=answers["project-name"];consttemplatePath=path.join(__dirname,"templates",projectChoice);constprojectPath=path.join(CURR_DIR,projectName);// Create project directory if it doesn't existif(!fs.existsSync(projectPath)){fs.mkdirSync(projectPath);}else{console.log(`\nProject directory '${projectName}' already exists.`);{process.exit(1);}}createDirectoryContents(templatePath,projectName);console.log("\nTemplate successfully created.");});}elseif(condition==="-a"){// Validate folder pathif(!folderPath){console.error("\nError: provide a folder path.");{process.exit(1);}}// Validate folder existenceif(!fs.existsSync(folderPath)){console.error("\nError: Folder does not exist.");{process.exit(1);}}// Create project name from folder pathconstprojectName=path.basename(folderPath);// Create directory for new project if it doesn't existconsttemplateFolderPath=path.join(__dirname,"templates",projectName);if(!fs.existsSync(templateFolderPath)){fs.mkdirSync(templateFolderPath);}else{console.log(`\nFolder '${templateFolderPath}' already exists.`);{process.exit(1);}}// Copy contents from folderPath to projectName/templatecreateDirectoryContents(folderPath,projectName);// InformSync user about successful operationif(nodeFlag){console.log("\nTemplate successfully created with node_modules.");}else{console.log("\nTemplate successfully created.");}}elseif(condition==="-r"){consttemplateToRemove=process.argv[3];// Validate if the template existsconsttemplatePathToRemove=path.join(__dirname,"templates",templateToRemove);if(!fs.existsSync(templatePathToRemove)){console.error(`\nError: Template '${templateToRemove}' does not exist.`);{process.exit(1);}}// Remove the template directoryfs.rmSync(templatePathToRemove,{recursive: true});// InformSync user about successful operationconsole.log(`\nTemplate '${templateToRemove}' was successfully removed.`);}elseif(condition==="-c"){construnCommand=(command)=>{returnnewPromise((resolve,reject)=>{try{execSync(command,{stdio: "inherit"});resolve();// Resolve the promise when the command completes successfully}catch(error){console.error(`Failed to Execute ${command}`,error);reject(error);// Reject the promise with the error if the command fails}});};consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;constrepoLink=process.argv[3];if(!urlRegex.test(repoLink)){console.log("Invalid repository link provided.");process.exit(1);}else{console.log("Repository link is valid.");}constgitCommand=`git clone --depth 1 ${repoLink}`;letprojectName;// Check if a changed name is provided in the clone commandif(repoLink.includes(" ")){// Extract the project name from the clone commandconstcloneCommandParts=repoLink.split(" ");// Split the clone command by whitespaceprojectName=cloneCommandParts[cloneCommandParts.length-1];// Get the last part as the project name}else{// Extract the project name from the repository linkprojectName=path.basename(repoLink,".git");}runCommand(gitCommand).then(async()=>{console.log("\nRepository Cloned");// Remove the .git folderconstclonedFolderPath=path.join(CURR_DIR,projectName);constgitFolderPath=path.join(clonedFolderPath,".git");if(fs.existsSync(gitFolderPath)){awaitfs.promises.rm(gitFolderPath,{recursive: true});}// Run the 'init -a' command with the cloned folder pathconstinitCommand=`init -a "${clonedFolderPath}"`;awaitrunCommand(initCommand);// Remove the cloned project folder asynchronouslytry{awaitfs.promises.rm(clonedFolderPath,{recursive: true});}catch(error){console.error(`Failed to remove cloned folder: ${error}`);}}).catch((error)=>{console.error("Error cloning repository:",error);process.exit(1);// Exit the script with an error status code});}elseif(condition==="-h"){// Clear the terminal by printing ANSI escape codesprocess.stdout.write("\u001b[2J\u001b[0;0H");constmessage=`${chalk.bold.underline.white("Package Commands:")}${chalk.green("Create a New Template:")} - Type ${chalk.cyan("'init'")} and press Enter at your desired location.${chalk.green("Add a Template:")} - Use the ${chalk.cyan("-a")} flag followed by the path in quotes. By default it skips the node_modules folder.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')} - But if you want to add node_modules folder with the template you are creating then ${chalk.cyan("-y")} flag after the command.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')}${chalk.cyan("-y")}${chalk.green("Clone a Repository and Add as a Template:")} - Use the ${chalk.cyan("-c")} flag followed by the repository link in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -c")}${chalk.yellow('"https://github.com/user/repoitoryName"')}${chalk.green("Remove a Template:")} - Use the ${chalk.cyan("-r")} flag followed by the exact name of the template in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -r")}${chalk.yellow('"Template Name"')}${chalk.green("Help:")} - Use ${chalk.cyan("init -h")} to see help. Made By Sooraj Gupta Email : soorajgupta00@gmail.com Github Repository : https://github.com/s54a/s54a-init`;console.log(message);}elseif(condition){console.log(chalk.red(` Invalid command: "${condition}". Please use one of the supported commands. Run ${chalk.yellow("init -h")} to see help. `));}else{console.log(chalk.red(`An error occurred or an invalid command was provided. Run ${chalk.yellow("init -h")} to see help.`));}

package.json

{
"name": "@s54a/init",
"version": "5.0.0",
"description": "Project Initializer",
"main": "./index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"init": "index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/s54a/s54a-init.git"
},
"keywords": ["Project Initializer", "Initializer", "Init"],
"author": "Sooraj Gupta",
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
"inquirer": "^9.2.15"
},
"bugs": {
"url": "https://github.com/s54a/s54a-init/issues"
},
"homepage": "https://github.com/s54a/s54a-init#readme"
}

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - s54a/s54a-init: Project Initializer || Template CLI · GitHub
Skip to content

Repository files navigation

Table of Contentsgenerated with DocToc

@s54a/init || TempLate CLI || Project Initializer

When I was starting a new project, I used the 'create vite app' command. Then, I began to remove and add files for the project. It struck me that I could create it once and paste it everywhere when I start a new project. Thats how I started building this.

There are two branch of this project in this one I have removed images & a few files to reduce the size

Visit the NPM Readme to see examples

How it Works

The package stores Templates inside a folder called "Templates" then when you run the init command it displays the templates and then it will paste the folder at the location where the terminal is open.

Simply it just copies & pastes the Folders from one place to another

Video Tutorial

Video Tutorial

Folder Structure

📁 init
├── 🌅 images
│ ├── 🖼️ article.png
│ ├── 🖼️ init -a.png
│ ├── 🖼️ init -c.png
│ ├── 🖼️ init -h.png
│ ├── 🖼️ init -r.png
│ └── 🖼️ init.png
├── 📁 templates
│ └── 📁 templateTest
│ ├── 📄 index.html
│ ├── 📄 main.js
│ └── 📄 style.css
├── 📄 .gitignore
├── 📄 .npmignore
├── 📄 index.js
├── 📜 LICENSE
├── 📝 Readme.md
├── 📋 package.json
└── 📋 package-lock.json

For testing purposes, only one template has been included, consisting of three files (HTML, CSS & JS). Additional templates have not been added to avoid making the package unnecessarily large.

(Note ChatGPT built this folder structure)

Installation

This package provides an Executable Command

You will have to install this package globally to be able to use the init command.

npm install -g @s54a/init

Usage

To begin, open a terminal at the desired project location and run this command

init
Example

init

This displays all available templates from the template folder, listed by folder name. Choose a template and enter the desired folder name when prompted to create a new project with the selected template's contents.

Users can also create templates themselves by running:

init -a "C:\Users\{User}\Desktop\Projects\Ongoing Projects"
Example

init

Upon execution, the tool generates a new folder path containing the contents of the user-created template. Subsequently, when the init command is invoked, it showcases the recently created template under the specified name.

Tip: For Windows users, you can quickly access the folder by selecting it and then pressing ctrl + shift + c.

By Default when you create a Template it skips the node_modules folder and its contents.

But for reason you want to create a template with node_modules folder you will have to pass the -y flag.

init -a "O:\test\cliTest" -y
Example

init

Templates can be removed using the following command:

init -r "template name"
Example

init

(Note: The name must match exactly.)

Templates can also be added from GitHub with:

init -c "https://github.com/user/repoitoryName.git"
Example

init

This process involves cloning the repository into the current terminal directory, removing the .git folder from the cloned repository, executing the init -a "repoName" command to create a copy in the templates folder, and then deleting the cloned repository folder from the current terminal location.

I have used this Regex to verify if the given string is a link or not.

consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;

The reason it performs all these steps is because I attempted to accomplish it in a simpler manner but couldn't find one.

To see all the Commands (Help)

init -h
Example

init

Resources

These are the YouTube Videos & Article which helped me build this

The Article Link

The Video Link

The Video Link

& ChatGPT

This a similar project built with Typescript https://github.com/pongsatt/mycli/blob/master/src/index.ts

Extra Resources https://github.com/lirantal/nodejs-cli-apps-best-practices

Take a look at https://yeoman.io/generators/

Read this if you are a beginner

I asked one of my friend who is a beginner in Web Dev. She asked me a question how will I make templates or why use this instead of Copy Pasting

So when ever you do

npm create-react-app ProjectName

or

npm create-vite-app ProjectName

These files are generated (with create react app)

my-app/
├── README.md
├── node_modules/
├── package.json
├── .gitignore
├── public/
│ ├── favicon.ico
│ ├── index.html
│ ├── manifest.json
│ └── robots.txt
└── src/
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
└── logo.svg

As you can see there are so many files which aren't necessary so you will have to remove these files remove code from index.css or maybe more files.

So you can do this once and use this template by using this package or just copy paste.

So why use this package instead of copy pasting So assume you have created many templates now you will create a folder to store them and every time you will start a new project you will have to go to that location copy that file and paste it at the location where you are starting the project and then change the name.

So this package does all that when you create a template and add it as a template from Command Line Interface and what I have learned & heard is that you will much faster at things with CLI then GUI.

Why I Created this

When you start Learning to code you will create multiple new projects so every time you will have to create new files

e.g. index.html, style.css, app.js

When you will advance to React you will do

So every time you will do that you will have to remove files edit content of the files.

So I thought it is a hassle so lets just do it once and I wil copy & paste it every time whenever I start a new project.

Then I thought I can create a cli which does that for me & I started building this package.

Then on a suggestion of a friend I also added the Clone & Create Template from Github Feature.

How I use this Package

I use this Package whenever I start a new project.

I have created my own template and added them as templates using init -a "folder path" command.

I have also added templates on Github.

So if I am on a new device or format my current one so I can just run the init -c "github_url" command after installing the package to clone new project and create a new template.

So if you are a Freelancer or Someone who is learning to code, or starting a new Project you can use this.

Extra Info

While Deploying Packages on NPM I realized that whatever you have in your project will get included even if you use npm ignore. I don't know if npm ignore works or failed. So I created another branch of this project in which I removed images and extra files. To reduce the size of the package & the node_modules size.

Here is the difference

size differencesize difference

So the Package Size is reduced by 300 Kilo Bytes

Source Code

Every time when I look at the open source I feel it is a hassle to navigate around files to see the code.

And this project source code is in a single file.

So I am adding the source code in the markdown file so you can read it all in one place.

index.js

#!/usr/bin/env node
importinquirerfrom"inquirer";importfsfrom"fs";importpathfrom"path";import{fileURLToPath}from"url";import{execSync}from"child_process";importchalkfrom"chalk";const__dirname=path.dirname(fileURLToPath(import.meta.url));constCHOICES=fs.readdirSync(path.join(__dirname,"templates"));constQUESTIONS=[{name: "project-choice",type: "list",message: "What project template would you like to generate?",choices: CHOICES,},{name: "project-name",type: "input",message: "Project name:",validate: function(input){if(/^([A-Za-z\-\_\d])+$/.test(input))returntrue;elsereturn"Project name may only include letters, numbers, underscores and hashes.";},},];constCURR_DIR=process.cwd();letnodeFlag=false;// Set nodeFlag as a global variable with a default value of false// Command line argumentsconst[,,condition,folderPath,nodeFlagParam]=process.argv;const[,, ...args]=process.argv;constoptions={condition: null,folderPathOrNameOrLink: null,nodeFlagParam: "",};// Parse command line argumentsfor(leti=0;i<args.length;i++){constarg=args[i];switch(arg){case"-a":
case"-r":
case"-c":
options.condition=arg;break;case"-h":
options.condition=arg;options.folderPathOrNameOrLink="";break;case"-y":
// Check if the previous option was '-a'if(options.condition==="-a"){options.nodeFlagParam=arg;}else{console.error(`Invalid usage of '-y' flag.`);process.exit(1);}break;default:
if(arg.startsWith("-")){console.error(`Invalid option: ${arg}`);process.exit(1);}else{options.folderPathOrNameOrLink=arg;}break;}}if(!args.length){options.condition="";options.folderPathOrNameOrLink="";}// Check for unsupported or invalid optionsif(Object.values(options).some((value)=>value===null)){console.error(`Missing required option or invalid usage.`);process.exit(1);}// Update the value of nodeFlag based on the command line argumentif(nodeFlagParam==="-y"){nodeFlag=true;}functioncreateDirectoryContents(templatePath,newProjectPath){constfilesToCreate=fs.readdirSync(templatePath);filesToCreate.forEach((file)=>{constorigFilePath=path.join(templatePath,file);// get stats about the current fileconststats=fs.statSync(origFilePath);if(stats.isFile()){constcontents=fs.readFileSync(origFilePath,"utf8");// Renameif(file===".npmignore")file=".gitignore";if(condition==="-a"){fs.writeFileSync(path.join(__dirname,"templates",newProjectPath,file),contents,"utf8");}else{fs.writeFileSync(path.join(CURR_DIR,newProjectPath,file),contents,"utf8");}}elseif(stats.isDirectory()){if(condition==="-a"){if(file==="node_modules"&&!nodeFlag){return;}else{fs.mkdirSync(path.join(__dirname,"templates",newProjectPath,file));}}else{fs.mkdirSync(path.join(CURR_DIR,newProjectPath,file));}// Then recursively copy contentscreateDirectoryContents(path.join(templatePath,file),path.join(newProjectPath,file));}});}if(!condition){inquirer.prompt(QUESTIONS).then((answers)=>{constprojectChoice=answers["project-choice"];constprojectName=answers["project-name"];consttemplatePath=path.join(__dirname,"templates",projectChoice);constprojectPath=path.join(CURR_DIR,projectName);// Create project directory if it doesn't existif(!fs.existsSync(projectPath)){fs.mkdirSync(projectPath);}else{console.log(`\nProject directory '${projectName}' already exists.`);{process.exit(1);}}createDirectoryContents(templatePath,projectName);console.log("\nTemplate successfully created.");});}elseif(condition==="-a"){// Validate folder pathif(!folderPath){console.error("\nError: provide a folder path.");{process.exit(1);}}// Validate folder existenceif(!fs.existsSync(folderPath)){console.error("\nError: Folder does not exist.");{process.exit(1);}}// Create project name from folder pathconstprojectName=path.basename(folderPath);// Create directory for new project if it doesn't existconsttemplateFolderPath=path.join(__dirname,"templates",projectName);if(!fs.existsSync(templateFolderPath)){fs.mkdirSync(templateFolderPath);}else{console.log(`\nFolder '${templateFolderPath}' already exists.`);{process.exit(1);}}// Copy contents from folderPath to projectName/templatecreateDirectoryContents(folderPath,projectName);// InformSync user about successful operationif(nodeFlag){console.log("\nTemplate successfully created with node_modules.");}else{console.log("\nTemplate successfully created.");}}elseif(condition==="-r"){consttemplateToRemove=process.argv[3];// Validate if the template existsconsttemplatePathToRemove=path.join(__dirname,"templates",templateToRemove);if(!fs.existsSync(templatePathToRemove)){console.error(`\nError: Template '${templateToRemove}' does not exist.`);{process.exit(1);}}// Remove the template directoryfs.rmSync(templatePathToRemove,{recursive: true});// InformSync user about successful operationconsole.log(`\nTemplate '${templateToRemove}' was successfully removed.`);}elseif(condition==="-c"){construnCommand=(command)=>{returnnewPromise((resolve,reject)=>{try{execSync(command,{stdio: "inherit"});resolve();// Resolve the promise when the command completes successfully}catch(error){console.error(`Failed to Execute ${command}`,error);reject(error);// Reject the promise with the error if the command fails}});};consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;constrepoLink=process.argv[3];if(!urlRegex.test(repoLink)){console.log("Invalid repository link provided.");process.exit(1);}else{console.log("Repository link is valid.");}constgitCommand=`git clone --depth 1 ${repoLink}`;letprojectName;// Check if a changed name is provided in the clone commandif(repoLink.includes(" ")){// Extract the project name from the clone commandconstcloneCommandParts=repoLink.split(" ");// Split the clone command by whitespaceprojectName=cloneCommandParts[cloneCommandParts.length-1];// Get the last part as the project name}else{// Extract the project name from the repository linkprojectName=path.basename(repoLink,".git");}runCommand(gitCommand).then(async()=>{console.log("\nRepository Cloned");// Remove the .git folderconstclonedFolderPath=path.join(CURR_DIR,projectName);constgitFolderPath=path.join(clonedFolderPath,".git");if(fs.existsSync(gitFolderPath)){awaitfs.promises.rm(gitFolderPath,{recursive: true});}// Run the 'init -a' command with the cloned folder pathconstinitCommand=`init -a "${clonedFolderPath}"`;awaitrunCommand(initCommand);// Remove the cloned project folder asynchronouslytry{awaitfs.promises.rm(clonedFolderPath,{recursive: true});}catch(error){console.error(`Failed to remove cloned folder: ${error}`);}}).catch((error)=>{console.error("Error cloning repository:",error);process.exit(1);// Exit the script with an error status code});}elseif(condition==="-h"){// Clear the terminal by printing ANSI escape codesprocess.stdout.write("\u001b[2J\u001b[0;0H");constmessage=`${chalk.bold.underline.white("Package Commands:")}${chalk.green("Create a New Template:")} - Type ${chalk.cyan("'init'")} and press Enter at your desired location.${chalk.green("Add a Template:")} - Use the ${chalk.cyan("-a")} flag followed by the path in quotes. By default it skips the node_modules folder.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')} - But if you want to add node_modules folder with the template you are creating then ${chalk.cyan("-y")} flag after the command.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')}${chalk.cyan("-y")}${chalk.green("Clone a Repository and Add as a Template:")} - Use the ${chalk.cyan("-c")} flag followed by the repository link in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -c")}${chalk.yellow('"https://github.com/user/repoitoryName"')}${chalk.green("Remove a Template:")} - Use the ${chalk.cyan("-r")} flag followed by the exact name of the template in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -r")}${chalk.yellow('"Template Name"')}${chalk.green("Help:")} - Use ${chalk.cyan("init -h")} to see help. Made By Sooraj Gupta Email : soorajgupta00@gmail.com Github Repository : https://github.com/s54a/s54a-init`;console.log(message);}elseif(condition){console.log(chalk.red(` Invalid command: "${condition}". Please use one of the supported commands. Run ${chalk.yellow("init -h")} to see help. `));}else{console.log(chalk.red(`An error occurred or an invalid command was provided. Run ${chalk.yellow("init -h")} to see help.`));}

package.json

{
"name": "@s54a/init",
"version": "5.0.0",
"description": "Project Initializer",
"main": "./index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"init": "index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/s54a/s54a-init.git"
},
"keywords": ["Project Initializer", "Initializer", "Init"],
"author": "Sooraj Gupta",
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
"inquirer": "^9.2.15"
},
"bugs": {
"url": "https://github.com/s54a/s54a-init/issues"
},
"homepage": "https://github.com/s54a/s54a-init#readme"
}

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - s54a/s54a-init: Project Initializer || Template CLI · GitHub
Skip to content

Repository files navigation

Table of Contentsgenerated with DocToc

@s54a/init || TempLate CLI || Project Initializer

When I was starting a new project, I used the 'create vite app' command. Then, I began to remove and add files for the project. It struck me that I could create it once and paste it everywhere when I start a new project. Thats how I started building this.

There are two branch of this project in this one I have removed images & a few files to reduce the size

Visit the NPM Readme to see examples

How it Works

The package stores Templates inside a folder called "Templates" then when you run the init command it displays the templates and then it will paste the folder at the location where the terminal is open.

Simply it just copies & pastes the Folders from one place to another

Video Tutorial

Video Tutorial

Folder Structure

📁 init
├── 🌅 images
│ ├── 🖼️ article.png
│ ├── 🖼️ init -a.png
│ ├── 🖼️ init -c.png
│ ├── 🖼️ init -h.png
│ ├── 🖼️ init -r.png
│ └── 🖼️ init.png
├── 📁 templates
│ └── 📁 templateTest
│ ├── 📄 index.html
│ ├── 📄 main.js
│ └── 📄 style.css
├── 📄 .gitignore
├── 📄 .npmignore
├── 📄 index.js
├── 📜 LICENSE
├── 📝 Readme.md
├── 📋 package.json
└── 📋 package-lock.json

For testing purposes, only one template has been included, consisting of three files (HTML, CSS & JS). Additional templates have not been added to avoid making the package unnecessarily large.

(Note ChatGPT built this folder structure)

Installation

This package provides an Executable Command

You will have to install this package globally to be able to use the init command.

npm install -g @s54a/init

Usage

To begin, open a terminal at the desired project location and run this command

init
Example

init

This displays all available templates from the template folder, listed by folder name. Choose a template and enter the desired folder name when prompted to create a new project with the selected template's contents.

Users can also create templates themselves by running:

init -a "C:\Users\{User}\Desktop\Projects\Ongoing Projects"
Example

init

Upon execution, the tool generates a new folder path containing the contents of the user-created template. Subsequently, when the init command is invoked, it showcases the recently created template under the specified name.

Tip: For Windows users, you can quickly access the folder by selecting it and then pressing ctrl + shift + c.

By Default when you create a Template it skips the node_modules folder and its contents.

But for reason you want to create a template with node_modules folder you will have to pass the -y flag.

init -a "O:\test\cliTest" -y
Example

init

Templates can be removed using the following command:

init -r "template name"
Example

init

(Note: The name must match exactly.)

Templates can also be added from GitHub with:

init -c "https://github.com/user/repoitoryName.git"
Example

init

This process involves cloning the repository into the current terminal directory, removing the .git folder from the cloned repository, executing the init -a "repoName" command to create a copy in the templates folder, and then deleting the cloned repository folder from the current terminal location.

I have used this Regex to verify if the given string is a link or not.

consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;

The reason it performs all these steps is because I attempted to accomplish it in a simpler manner but couldn't find one.

To see all the Commands (Help)

init -h
Example

init

Resources

These are the YouTube Videos & Article which helped me build this

The Article Link

The Video Link

The Video Link

& ChatGPT

This a similar project built with Typescript https://github.com/pongsatt/mycli/blob/master/src/index.ts

Extra Resources https://github.com/lirantal/nodejs-cli-apps-best-practices

Take a look at https://yeoman.io/generators/

Read this if you are a beginner

I asked one of my friend who is a beginner in Web Dev. She asked me a question how will I make templates or why use this instead of Copy Pasting

So when ever you do

npm create-react-app ProjectName

or

npm create-vite-app ProjectName

These files are generated (with create react app)

my-app/
├── README.md
├── node_modules/
├── package.json
├── .gitignore
├── public/
│ ├── favicon.ico
│ ├── index.html
│ ├── manifest.json
│ └── robots.txt
└── src/
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
└── logo.svg

As you can see there are so many files which aren't necessary so you will have to remove these files remove code from index.css or maybe more files.

So you can do this once and use this template by using this package or just copy paste.

So why use this package instead of copy pasting So assume you have created many templates now you will create a folder to store them and every time you will start a new project you will have to go to that location copy that file and paste it at the location where you are starting the project and then change the name.

So this package does all that when you create a template and add it as a template from Command Line Interface and what I have learned & heard is that you will much faster at things with CLI then GUI.

Why I Created this

When you start Learning to code you will create multiple new projects so every time you will have to create new files

e.g. index.html, style.css, app.js

When you will advance to React you will do

So every time you will do that you will have to remove files edit content of the files.

So I thought it is a hassle so lets just do it once and I wil copy & paste it every time whenever I start a new project.

Then I thought I can create a cli which does that for me & I started building this package.

Then on a suggestion of a friend I also added the Clone & Create Template from Github Feature.

How I use this Package

I use this Package whenever I start a new project.

I have created my own template and added them as templates using init -a "folder path" command.

I have also added templates on Github.

So if I am on a new device or format my current one so I can just run the init -c "github_url" command after installing the package to clone new project and create a new template.

So if you are a Freelancer or Someone who is learning to code, or starting a new Project you can use this.

Extra Info

While Deploying Packages on NPM I realized that whatever you have in your project will get included even if you use npm ignore. I don't know if npm ignore works or failed. So I created another branch of this project in which I removed images and extra files. To reduce the size of the package & the node_modules size.

Here is the difference

size differencesize difference

So the Package Size is reduced by 300 Kilo Bytes

Source Code

Every time when I look at the open source I feel it is a hassle to navigate around files to see the code.

And this project source code is in a single file.

So I am adding the source code in the markdown file so you can read it all in one place.

index.js

#!/usr/bin/env node
importinquirerfrom"inquirer";importfsfrom"fs";importpathfrom"path";import{fileURLToPath}from"url";import{execSync}from"child_process";importchalkfrom"chalk";const__dirname=path.dirname(fileURLToPath(import.meta.url));constCHOICES=fs.readdirSync(path.join(__dirname,"templates"));constQUESTIONS=[{name: "project-choice",type: "list",message: "What project template would you like to generate?",choices: CHOICES,},{name: "project-name",type: "input",message: "Project name:",validate: function(input){if(/^([A-Za-z\-\_\d])+$/.test(input))returntrue;elsereturn"Project name may only include letters, numbers, underscores and hashes.";},},];constCURR_DIR=process.cwd();letnodeFlag=false;// Set nodeFlag as a global variable with a default value of false// Command line argumentsconst[,,condition,folderPath,nodeFlagParam]=process.argv;const[,, ...args]=process.argv;constoptions={condition: null,folderPathOrNameOrLink: null,nodeFlagParam: "",};// Parse command line argumentsfor(leti=0;i<args.length;i++){constarg=args[i];switch(arg){case"-a":
case"-r":
case"-c":
options.condition=arg;break;case"-h":
options.condition=arg;options.folderPathOrNameOrLink="";break;case"-y":
// Check if the previous option was '-a'if(options.condition==="-a"){options.nodeFlagParam=arg;}else{console.error(`Invalid usage of '-y' flag.`);process.exit(1);}break;default:
if(arg.startsWith("-")){console.error(`Invalid option: ${arg}`);process.exit(1);}else{options.folderPathOrNameOrLink=arg;}break;}}if(!args.length){options.condition="";options.folderPathOrNameOrLink="";}// Check for unsupported or invalid optionsif(Object.values(options).some((value)=>value===null)){console.error(`Missing required option or invalid usage.`);process.exit(1);}// Update the value of nodeFlag based on the command line argumentif(nodeFlagParam==="-y"){nodeFlag=true;}functioncreateDirectoryContents(templatePath,newProjectPath){constfilesToCreate=fs.readdirSync(templatePath);filesToCreate.forEach((file)=>{constorigFilePath=path.join(templatePath,file);// get stats about the current fileconststats=fs.statSync(origFilePath);if(stats.isFile()){constcontents=fs.readFileSync(origFilePath,"utf8");// Renameif(file===".npmignore")file=".gitignore";if(condition==="-a"){fs.writeFileSync(path.join(__dirname,"templates",newProjectPath,file),contents,"utf8");}else{fs.writeFileSync(path.join(CURR_DIR,newProjectPath,file),contents,"utf8");}}elseif(stats.isDirectory()){if(condition==="-a"){if(file==="node_modules"&&!nodeFlag){return;}else{fs.mkdirSync(path.join(__dirname,"templates",newProjectPath,file));}}else{fs.mkdirSync(path.join(CURR_DIR,newProjectPath,file));}// Then recursively copy contentscreateDirectoryContents(path.join(templatePath,file),path.join(newProjectPath,file));}});}if(!condition){inquirer.prompt(QUESTIONS).then((answers)=>{constprojectChoice=answers["project-choice"];constprojectName=answers["project-name"];consttemplatePath=path.join(__dirname,"templates",projectChoice);constprojectPath=path.join(CURR_DIR,projectName);// Create project directory if it doesn't existif(!fs.existsSync(projectPath)){fs.mkdirSync(projectPath);}else{console.log(`\nProject directory '${projectName}' already exists.`);{process.exit(1);}}createDirectoryContents(templatePath,projectName);console.log("\nTemplate successfully created.");});}elseif(condition==="-a"){// Validate folder pathif(!folderPath){console.error("\nError: provide a folder path.");{process.exit(1);}}// Validate folder existenceif(!fs.existsSync(folderPath)){console.error("\nError: Folder does not exist.");{process.exit(1);}}// Create project name from folder pathconstprojectName=path.basename(folderPath);// Create directory for new project if it doesn't existconsttemplateFolderPath=path.join(__dirname,"templates",projectName);if(!fs.existsSync(templateFolderPath)){fs.mkdirSync(templateFolderPath);}else{console.log(`\nFolder '${templateFolderPath}' already exists.`);{process.exit(1);}}// Copy contents from folderPath to projectName/templatecreateDirectoryContents(folderPath,projectName);// InformSync user about successful operationif(nodeFlag){console.log("\nTemplate successfully created with node_modules.");}else{console.log("\nTemplate successfully created.");}}elseif(condition==="-r"){consttemplateToRemove=process.argv[3];// Validate if the template existsconsttemplatePathToRemove=path.join(__dirname,"templates",templateToRemove);if(!fs.existsSync(templatePathToRemove)){console.error(`\nError: Template '${templateToRemove}' does not exist.`);{process.exit(1);}}// Remove the template directoryfs.rmSync(templatePathToRemove,{recursive: true});// InformSync user about successful operationconsole.log(`\nTemplate '${templateToRemove}' was successfully removed.`);}elseif(condition==="-c"){construnCommand=(command)=>{returnnewPromise((resolve,reject)=>{try{execSync(command,{stdio: "inherit"});resolve();// Resolve the promise when the command completes successfully}catch(error){console.error(`Failed to Execute ${command}`,error);reject(error);// Reject the promise with the error if the command fails}});};consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;constrepoLink=process.argv[3];if(!urlRegex.test(repoLink)){console.log("Invalid repository link provided.");process.exit(1);}else{console.log("Repository link is valid.");}constgitCommand=`git clone --depth 1 ${repoLink}`;letprojectName;// Check if a changed name is provided in the clone commandif(repoLink.includes(" ")){// Extract the project name from the clone commandconstcloneCommandParts=repoLink.split(" ");// Split the clone command by whitespaceprojectName=cloneCommandParts[cloneCommandParts.length-1];// Get the last part as the project name}else{// Extract the project name from the repository linkprojectName=path.basename(repoLink,".git");}runCommand(gitCommand).then(async()=>{console.log("\nRepository Cloned");// Remove the .git folderconstclonedFolderPath=path.join(CURR_DIR,projectName);constgitFolderPath=path.join(clonedFolderPath,".git");if(fs.existsSync(gitFolderPath)){awaitfs.promises.rm(gitFolderPath,{recursive: true});}// Run the 'init -a' command with the cloned folder pathconstinitCommand=`init -a "${clonedFolderPath}"`;awaitrunCommand(initCommand);// Remove the cloned project folder asynchronouslytry{awaitfs.promises.rm(clonedFolderPath,{recursive: true});}catch(error){console.error(`Failed to remove cloned folder: ${error}`);}}).catch((error)=>{console.error("Error cloning repository:",error);process.exit(1);// Exit the script with an error status code});}elseif(condition==="-h"){// Clear the terminal by printing ANSI escape codesprocess.stdout.write("\u001b[2J\u001b[0;0H");constmessage=`${chalk.bold.underline.white("Package Commands:")}${chalk.green("Create a New Template:")} - Type ${chalk.cyan("'init'")} and press Enter at your desired location.${chalk.green("Add a Template:")} - Use the ${chalk.cyan("-a")} flag followed by the path in quotes. By default it skips the node_modules folder.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')} - But if you want to add node_modules folder with the template you are creating then ${chalk.cyan("-y")} flag after the command.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')}${chalk.cyan("-y")}${chalk.green("Clone a Repository and Add as a Template:")} - Use the ${chalk.cyan("-c")} flag followed by the repository link in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -c")}${chalk.yellow('"https://github.com/user/repoitoryName"')}${chalk.green("Remove a Template:")} - Use the ${chalk.cyan("-r")} flag followed by the exact name of the template in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -r")}${chalk.yellow('"Template Name"')}${chalk.green("Help:")} - Use ${chalk.cyan("init -h")} to see help. Made By Sooraj Gupta Email : soorajgupta00@gmail.com Github Repository : https://github.com/s54a/s54a-init`;console.log(message);}elseif(condition){console.log(chalk.red(` Invalid command: "${condition}". Please use one of the supported commands. Run ${chalk.yellow("init -h")} to see help. `));}else{console.log(chalk.red(`An error occurred or an invalid command was provided. Run ${chalk.yellow("init -h")} to see help.`));}

package.json

{
"name": "@s54a/init",
"version": "5.0.0",
"description": "Project Initializer",
"main": "./index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"init": "index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/s54a/s54a-init.git"
},
"keywords": ["Project Initializer", "Initializer", "Init"],
"author": "Sooraj Gupta",
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
"inquirer": "^9.2.15"
},
"bugs": {
"url": "https://github.com/s54a/s54a-init/issues"
},
"homepage": "https://github.com/s54a/s54a-init#readme"
}

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - s54a/s54a-init: Project Initializer || Template CLI · GitHub
Skip to content

Repository files navigation

Table of Contentsgenerated with DocToc

@s54a/init || TempLate CLI || Project Initializer

When I was starting a new project, I used the 'create vite app' command. Then, I began to remove and add files for the project. It struck me that I could create it once and paste it everywhere when I start a new project. Thats how I started building this.

There are two branch of this project in this one I have removed images & a few files to reduce the size

Visit the NPM Readme to see examples

How it Works

The package stores Templates inside a folder called "Templates" then when you run the init command it displays the templates and then it will paste the folder at the location where the terminal is open.

Simply it just copies & pastes the Folders from one place to another

Video Tutorial

Video Tutorial

Folder Structure

📁 init
├── 🌅 images
│ ├── 🖼️ article.png
│ ├── 🖼️ init -a.png
│ ├── 🖼️ init -c.png
│ ├── 🖼️ init -h.png
│ ├── 🖼️ init -r.png
│ └── 🖼️ init.png
├── 📁 templates
│ └── 📁 templateTest
│ ├── 📄 index.html
│ ├── 📄 main.js
│ └── 📄 style.css
├── 📄 .gitignore
├── 📄 .npmignore
├── 📄 index.js
├── 📜 LICENSE
├── 📝 Readme.md
├── 📋 package.json
└── 📋 package-lock.json

For testing purposes, only one template has been included, consisting of three files (HTML, CSS & JS). Additional templates have not been added to avoid making the package unnecessarily large.

(Note ChatGPT built this folder structure)

Installation

This package provides an Executable Command

You will have to install this package globally to be able to use the init command.

npm install -g @s54a/init

Usage

To begin, open a terminal at the desired project location and run this command

init
Example

init

This displays all available templates from the template folder, listed by folder name. Choose a template and enter the desired folder name when prompted to create a new project with the selected template's contents.

Users can also create templates themselves by running:

init -a "C:\Users\{User}\Desktop\Projects\Ongoing Projects"
Example

init

Upon execution, the tool generates a new folder path containing the contents of the user-created template. Subsequently, when the init command is invoked, it showcases the recently created template under the specified name.

Tip: For Windows users, you can quickly access the folder by selecting it and then pressing ctrl + shift + c.

By Default when you create a Template it skips the node_modules folder and its contents.

But for reason you want to create a template with node_modules folder you will have to pass the -y flag.

init -a "O:\test\cliTest" -y
Example

init

Templates can be removed using the following command:

init -r "template name"
Example

init

(Note: The name must match exactly.)

Templates can also be added from GitHub with:

init -c "https://github.com/user/repoitoryName.git"
Example

init

This process involves cloning the repository into the current terminal directory, removing the .git folder from the cloned repository, executing the init -a "repoName" command to create a copy in the templates folder, and then deleting the cloned repository folder from the current terminal location.

I have used this Regex to verify if the given string is a link or not.

consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;

The reason it performs all these steps is because I attempted to accomplish it in a simpler manner but couldn't find one.

To see all the Commands (Help)

init -h
Example

init

Resources

These are the YouTube Videos & Article which helped me build this

The Article Link

The Video Link

The Video Link

& ChatGPT

This a similar project built with Typescript https://github.com/pongsatt/mycli/blob/master/src/index.ts

Extra Resources https://github.com/lirantal/nodejs-cli-apps-best-practices

Take a look at https://yeoman.io/generators/

Read this if you are a beginner

I asked one of my friend who is a beginner in Web Dev. She asked me a question how will I make templates or why use this instead of Copy Pasting

So when ever you do

npm create-react-app ProjectName

or

npm create-vite-app ProjectName

These files are generated (with create react app)

my-app/
├── README.md
├── node_modules/
├── package.json
├── .gitignore
├── public/
│ ├── favicon.ico
│ ├── index.html
│ ├── manifest.json
│ └── robots.txt
└── src/
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
└── logo.svg

As you can see there are so many files which aren't necessary so you will have to remove these files remove code from index.css or maybe more files.

So you can do this once and use this template by using this package or just copy paste.

So why use this package instead of copy pasting So assume you have created many templates now you will create a folder to store them and every time you will start a new project you will have to go to that location copy that file and paste it at the location where you are starting the project and then change the name.

So this package does all that when you create a template and add it as a template from Command Line Interface and what I have learned & heard is that you will much faster at things with CLI then GUI.

Why I Created this

When you start Learning to code you will create multiple new projects so every time you will have to create new files

e.g. index.html, style.css, app.js

When you will advance to React you will do

So every time you will do that you will have to remove files edit content of the files.

So I thought it is a hassle so lets just do it once and I wil copy & paste it every time whenever I start a new project.

Then I thought I can create a cli which does that for me & I started building this package.

Then on a suggestion of a friend I also added the Clone & Create Template from Github Feature.

How I use this Package

I use this Package whenever I start a new project.

I have created my own template and added them as templates using init -a "folder path" command.

I have also added templates on Github.

So if I am on a new device or format my current one so I can just run the init -c "github_url" command after installing the package to clone new project and create a new template.

So if you are a Freelancer or Someone who is learning to code, or starting a new Project you can use this.

Extra Info

While Deploying Packages on NPM I realized that whatever you have in your project will get included even if you use npm ignore. I don't know if npm ignore works or failed. So I created another branch of this project in which I removed images and extra files. To reduce the size of the package & the node_modules size.

Here is the difference

size differencesize difference

So the Package Size is reduced by 300 Kilo Bytes

Source Code

Every time when I look at the open source I feel it is a hassle to navigate around files to see the code.

And this project source code is in a single file.

So I am adding the source code in the markdown file so you can read it all in one place.

index.js

#!/usr/bin/env node
importinquirerfrom"inquirer";importfsfrom"fs";importpathfrom"path";import{fileURLToPath}from"url";import{execSync}from"child_process";importchalkfrom"chalk";const__dirname=path.dirname(fileURLToPath(import.meta.url));constCHOICES=fs.readdirSync(path.join(__dirname,"templates"));constQUESTIONS=[{name: "project-choice",type: "list",message: "What project template would you like to generate?",choices: CHOICES,},{name: "project-name",type: "input",message: "Project name:",validate: function(input){if(/^([A-Za-z\-\_\d])+$/.test(input))returntrue;elsereturn"Project name may only include letters, numbers, underscores and hashes.";},},];constCURR_DIR=process.cwd();letnodeFlag=false;// Set nodeFlag as a global variable with a default value of false// Command line argumentsconst[,,condition,folderPath,nodeFlagParam]=process.argv;const[,, ...args]=process.argv;constoptions={condition: null,folderPathOrNameOrLink: null,nodeFlagParam: "",};// Parse command line argumentsfor(leti=0;i<args.length;i++){constarg=args[i];switch(arg){case"-a":
case"-r":
case"-c":
options.condition=arg;break;case"-h":
options.condition=arg;options.folderPathOrNameOrLink="";break;case"-y":
// Check if the previous option was '-a'if(options.condition==="-a"){options.nodeFlagParam=arg;}else{console.error(`Invalid usage of '-y' flag.`);process.exit(1);}break;default:
if(arg.startsWith("-")){console.error(`Invalid option: ${arg}`);process.exit(1);}else{options.folderPathOrNameOrLink=arg;}break;}}if(!args.length){options.condition="";options.folderPathOrNameOrLink="";}// Check for unsupported or invalid optionsif(Object.values(options).some((value)=>value===null)){console.error(`Missing required option or invalid usage.`);process.exit(1);}// Update the value of nodeFlag based on the command line argumentif(nodeFlagParam==="-y"){nodeFlag=true;}functioncreateDirectoryContents(templatePath,newProjectPath){constfilesToCreate=fs.readdirSync(templatePath);filesToCreate.forEach((file)=>{constorigFilePath=path.join(templatePath,file);// get stats about the current fileconststats=fs.statSync(origFilePath);if(stats.isFile()){constcontents=fs.readFileSync(origFilePath,"utf8");// Renameif(file===".npmignore")file=".gitignore";if(condition==="-a"){fs.writeFileSync(path.join(__dirname,"templates",newProjectPath,file),contents,"utf8");}else{fs.writeFileSync(path.join(CURR_DIR,newProjectPath,file),contents,"utf8");}}elseif(stats.isDirectory()){if(condition==="-a"){if(file==="node_modules"&&!nodeFlag){return;}else{fs.mkdirSync(path.join(__dirname,"templates",newProjectPath,file));}}else{fs.mkdirSync(path.join(CURR_DIR,newProjectPath,file));}// Then recursively copy contentscreateDirectoryContents(path.join(templatePath,file),path.join(newProjectPath,file));}});}if(!condition){inquirer.prompt(QUESTIONS).then((answers)=>{constprojectChoice=answers["project-choice"];constprojectName=answers["project-name"];consttemplatePath=path.join(__dirname,"templates",projectChoice);constprojectPath=path.join(CURR_DIR,projectName);// Create project directory if it doesn't existif(!fs.existsSync(projectPath)){fs.mkdirSync(projectPath);}else{console.log(`\nProject directory '${projectName}' already exists.`);{process.exit(1);}}createDirectoryContents(templatePath,projectName);console.log("\nTemplate successfully created.");});}elseif(condition==="-a"){// Validate folder pathif(!folderPath){console.error("\nError: provide a folder path.");{process.exit(1);}}// Validate folder existenceif(!fs.existsSync(folderPath)){console.error("\nError: Folder does not exist.");{process.exit(1);}}// Create project name from folder pathconstprojectName=path.basename(folderPath);// Create directory for new project if it doesn't existconsttemplateFolderPath=path.join(__dirname,"templates",projectName);if(!fs.existsSync(templateFolderPath)){fs.mkdirSync(templateFolderPath);}else{console.log(`\nFolder '${templateFolderPath}' already exists.`);{process.exit(1);}}// Copy contents from folderPath to projectName/templatecreateDirectoryContents(folderPath,projectName);// InformSync user about successful operationif(nodeFlag){console.log("\nTemplate successfully created with node_modules.");}else{console.log("\nTemplate successfully created.");}}elseif(condition==="-r"){consttemplateToRemove=process.argv[3];// Validate if the template existsconsttemplatePathToRemove=path.join(__dirname,"templates",templateToRemove);if(!fs.existsSync(templatePathToRemove)){console.error(`\nError: Template '${templateToRemove}' does not exist.`);{process.exit(1);}}// Remove the template directoryfs.rmSync(templatePathToRemove,{recursive: true});// InformSync user about successful operationconsole.log(`\nTemplate '${templateToRemove}' was successfully removed.`);}elseif(condition==="-c"){construnCommand=(command)=>{returnnewPromise((resolve,reject)=>{try{execSync(command,{stdio: "inherit"});resolve();// Resolve the promise when the command completes successfully}catch(error){console.error(`Failed to Execute ${command}`,error);reject(error);// Reject the promise with the error if the command fails}});};consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;constrepoLink=process.argv[3];if(!urlRegex.test(repoLink)){console.log("Invalid repository link provided.");process.exit(1);}else{console.log("Repository link is valid.");}constgitCommand=`git clone --depth 1 ${repoLink}`;letprojectName;// Check if a changed name is provided in the clone commandif(repoLink.includes(" ")){// Extract the project name from the clone commandconstcloneCommandParts=repoLink.split(" ");// Split the clone command by whitespaceprojectName=cloneCommandParts[cloneCommandParts.length-1];// Get the last part as the project name}else{// Extract the project name from the repository linkprojectName=path.basename(repoLink,".git");}runCommand(gitCommand).then(async()=>{console.log("\nRepository Cloned");// Remove the .git folderconstclonedFolderPath=path.join(CURR_DIR,projectName);constgitFolderPath=path.join(clonedFolderPath,".git");if(fs.existsSync(gitFolderPath)){awaitfs.promises.rm(gitFolderPath,{recursive: true});}// Run the 'init -a' command with the cloned folder pathconstinitCommand=`init -a "${clonedFolderPath}"`;awaitrunCommand(initCommand);// Remove the cloned project folder asynchronouslytry{awaitfs.promises.rm(clonedFolderPath,{recursive: true});}catch(error){console.error(`Failed to remove cloned folder: ${error}`);}}).catch((error)=>{console.error("Error cloning repository:",error);process.exit(1);// Exit the script with an error status code});}elseif(condition==="-h"){// Clear the terminal by printing ANSI escape codesprocess.stdout.write("\u001b[2J\u001b[0;0H");constmessage=`${chalk.bold.underline.white("Package Commands:")}${chalk.green("Create a New Template:")} - Type ${chalk.cyan("'init'")} and press Enter at your desired location.${chalk.green("Add a Template:")} - Use the ${chalk.cyan("-a")} flag followed by the path in quotes. By default it skips the node_modules folder.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')} - But if you want to add node_modules folder with the template you are creating then ${chalk.cyan("-y")} flag after the command.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')}${chalk.cyan("-y")}${chalk.green("Clone a Repository and Add as a Template:")} - Use the ${chalk.cyan("-c")} flag followed by the repository link in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -c")}${chalk.yellow('"https://github.com/user/repoitoryName"')}${chalk.green("Remove a Template:")} - Use the ${chalk.cyan("-r")} flag followed by the exact name of the template in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -r")}${chalk.yellow('"Template Name"')}${chalk.green("Help:")} - Use ${chalk.cyan("init -h")} to see help. Made By Sooraj Gupta Email : soorajgupta00@gmail.com Github Repository : https://github.com/s54a/s54a-init`;console.log(message);}elseif(condition){console.log(chalk.red(` Invalid command: "${condition}". Please use one of the supported commands. Run ${chalk.yellow("init -h")} to see help. `));}else{console.log(chalk.red(`An error occurred or an invalid command was provided. Run ${chalk.yellow("init -h")} to see help.`));}

package.json

{
"name": "@s54a/init",
"version": "5.0.0",
"description": "Project Initializer",
"main": "./index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"init": "index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/s54a/s54a-init.git"
},
"keywords": ["Project Initializer", "Initializer", "Init"],
"author": "Sooraj Gupta",
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
"inquirer": "^9.2.15"
},
"bugs": {
"url": "https://github.com/s54a/s54a-init/issues"
},
"homepage": "https://github.com/s54a/s54a-init#readme"
}

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - s54a/s54a-init: Project Initializer || Template CLI · GitHub
Skip to content

Repository files navigation

Table of Contentsgenerated with DocToc

@s54a/init || TempLate CLI || Project Initializer

When I was starting a new project, I used the 'create vite app' command. Then, I began to remove and add files for the project. It struck me that I could create it once and paste it everywhere when I start a new project. Thats how I started building this.

There are two branch of this project in this one I have removed images & a few files to reduce the size

Visit the NPM Readme to see examples

How it Works

The package stores Templates inside a folder called "Templates" then when you run the init command it displays the templates and then it will paste the folder at the location where the terminal is open.

Simply it just copies & pastes the Folders from one place to another

Video Tutorial

Video Tutorial

Folder Structure

📁 init
├── 🌅 images
│ ├── 🖼️ article.png
│ ├── 🖼️ init -a.png
│ ├── 🖼️ init -c.png
│ ├── 🖼️ init -h.png
│ ├── 🖼️ init -r.png
│ └── 🖼️ init.png
├── 📁 templates
│ └── 📁 templateTest
│ ├── 📄 index.html
│ ├── 📄 main.js
│ └── 📄 style.css
├── 📄 .gitignore
├── 📄 .npmignore
├── 📄 index.js
├── 📜 LICENSE
├── 📝 Readme.md
├── 📋 package.json
└── 📋 package-lock.json

For testing purposes, only one template has been included, consisting of three files (HTML, CSS & JS). Additional templates have not been added to avoid making the package unnecessarily large.

(Note ChatGPT built this folder structure)

Installation

This package provides an Executable Command

You will have to install this package globally to be able to use the init command.

npm install -g @s54a/init

Usage

To begin, open a terminal at the desired project location and run this command

init
Example

init

This displays all available templates from the template folder, listed by folder name. Choose a template and enter the desired folder name when prompted to create a new project with the selected template's contents.

Users can also create templates themselves by running:

init -a "C:\Users\{User}\Desktop\Projects\Ongoing Projects"
Example

init

Upon execution, the tool generates a new folder path containing the contents of the user-created template. Subsequently, when the init command is invoked, it showcases the recently created template under the specified name.

Tip: For Windows users, you can quickly access the folder by selecting it and then pressing ctrl + shift + c.

By Default when you create a Template it skips the node_modules folder and its contents.

But for reason you want to create a template with node_modules folder you will have to pass the -y flag.

init -a "O:\test\cliTest" -y
Example

init

Templates can be removed using the following command:

init -r "template name"
Example

init

(Note: The name must match exactly.)

Templates can also be added from GitHub with:

init -c "https://github.com/user/repoitoryName.git"
Example

init

This process involves cloning the repository into the current terminal directory, removing the .git folder from the cloned repository, executing the init -a "repoName" command to create a copy in the templates folder, and then deleting the cloned repository folder from the current terminal location.

I have used this Regex to verify if the given string is a link or not.

consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;

The reason it performs all these steps is because I attempted to accomplish it in a simpler manner but couldn't find one.

To see all the Commands (Help)

init -h
Example

init

Resources

These are the YouTube Videos & Article which helped me build this

The Article Link

The Video Link

The Video Link

& ChatGPT

This a similar project built with Typescript https://github.com/pongsatt/mycli/blob/master/src/index.ts

Extra Resources https://github.com/lirantal/nodejs-cli-apps-best-practices

Take a look at https://yeoman.io/generators/

Read this if you are a beginner

I asked one of my friend who is a beginner in Web Dev. She asked me a question how will I make templates or why use this instead of Copy Pasting

So when ever you do

npm create-react-app ProjectName

or

npm create-vite-app ProjectName

These files are generated (with create react app)

my-app/
├── README.md
├── node_modules/
├── package.json
├── .gitignore
├── public/
│ ├── favicon.ico
│ ├── index.html
│ ├── manifest.json
│ └── robots.txt
└── src/
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
└── logo.svg

As you can see there are so many files which aren't necessary so you will have to remove these files remove code from index.css or maybe more files.

So you can do this once and use this template by using this package or just copy paste.

So why use this package instead of copy pasting So assume you have created many templates now you will create a folder to store them and every time you will start a new project you will have to go to that location copy that file and paste it at the location where you are starting the project and then change the name.

So this package does all that when you create a template and add it as a template from Command Line Interface and what I have learned & heard is that you will much faster at things with CLI then GUI.

Why I Created this

When you start Learning to code you will create multiple new projects so every time you will have to create new files

e.g. index.html, style.css, app.js

When you will advance to React you will do

So every time you will do that you will have to remove files edit content of the files.

So I thought it is a hassle so lets just do it once and I wil copy & paste it every time whenever I start a new project.

Then I thought I can create a cli which does that for me & I started building this package.

Then on a suggestion of a friend I also added the Clone & Create Template from Github Feature.

How I use this Package

I use this Package whenever I start a new project.

I have created my own template and added them as templates using init -a "folder path" command.

I have also added templates on Github.

So if I am on a new device or format my current one so I can just run the init -c "github_url" command after installing the package to clone new project and create a new template.

So if you are a Freelancer or Someone who is learning to code, or starting a new Project you can use this.

Extra Info

While Deploying Packages on NPM I realized that whatever you have in your project will get included even if you use npm ignore. I don't know if npm ignore works or failed. So I created another branch of this project in which I removed images and extra files. To reduce the size of the package & the node_modules size.

Here is the difference

size differencesize difference

So the Package Size is reduced by 300 Kilo Bytes

Source Code

Every time when I look at the open source I feel it is a hassle to navigate around files to see the code.

And this project source code is in a single file.

So I am adding the source code in the markdown file so you can read it all in one place.

index.js

#!/usr/bin/env node
importinquirerfrom"inquirer";importfsfrom"fs";importpathfrom"path";import{fileURLToPath}from"url";import{execSync}from"child_process";importchalkfrom"chalk";const__dirname=path.dirname(fileURLToPath(import.meta.url));constCHOICES=fs.readdirSync(path.join(__dirname,"templates"));constQUESTIONS=[{name: "project-choice",type: "list",message: "What project template would you like to generate?",choices: CHOICES,},{name: "project-name",type: "input",message: "Project name:",validate: function(input){if(/^([A-Za-z\-\_\d])+$/.test(input))returntrue;elsereturn"Project name may only include letters, numbers, underscores and hashes.";},},];constCURR_DIR=process.cwd();letnodeFlag=false;// Set nodeFlag as a global variable with a default value of false// Command line argumentsconst[,,condition,folderPath,nodeFlagParam]=process.argv;const[,, ...args]=process.argv;constoptions={condition: null,folderPathOrNameOrLink: null,nodeFlagParam: "",};// Parse command line argumentsfor(leti=0;i<args.length;i++){constarg=args[i];switch(arg){case"-a":
case"-r":
case"-c":
options.condition=arg;break;case"-h":
options.condition=arg;options.folderPathOrNameOrLink="";break;case"-y":
// Check if the previous option was '-a'if(options.condition==="-a"){options.nodeFlagParam=arg;}else{console.error(`Invalid usage of '-y' flag.`);process.exit(1);}break;default:
if(arg.startsWith("-")){console.error(`Invalid option: ${arg}`);process.exit(1);}else{options.folderPathOrNameOrLink=arg;}break;}}if(!args.length){options.condition="";options.folderPathOrNameOrLink="";}// Check for unsupported or invalid optionsif(Object.values(options).some((value)=>value===null)){console.error(`Missing required option or invalid usage.`);process.exit(1);}// Update the value of nodeFlag based on the command line argumentif(nodeFlagParam==="-y"){nodeFlag=true;}functioncreateDirectoryContents(templatePath,newProjectPath){constfilesToCreate=fs.readdirSync(templatePath);filesToCreate.forEach((file)=>{constorigFilePath=path.join(templatePath,file);// get stats about the current fileconststats=fs.statSync(origFilePath);if(stats.isFile()){constcontents=fs.readFileSync(origFilePath,"utf8");// Renameif(file===".npmignore")file=".gitignore";if(condition==="-a"){fs.writeFileSync(path.join(__dirname,"templates",newProjectPath,file),contents,"utf8");}else{fs.writeFileSync(path.join(CURR_DIR,newProjectPath,file),contents,"utf8");}}elseif(stats.isDirectory()){if(condition==="-a"){if(file==="node_modules"&&!nodeFlag){return;}else{fs.mkdirSync(path.join(__dirname,"templates",newProjectPath,file));}}else{fs.mkdirSync(path.join(CURR_DIR,newProjectPath,file));}// Then recursively copy contentscreateDirectoryContents(path.join(templatePath,file),path.join(newProjectPath,file));}});}if(!condition){inquirer.prompt(QUESTIONS).then((answers)=>{constprojectChoice=answers["project-choice"];constprojectName=answers["project-name"];consttemplatePath=path.join(__dirname,"templates",projectChoice);constprojectPath=path.join(CURR_DIR,projectName);// Create project directory if it doesn't existif(!fs.existsSync(projectPath)){fs.mkdirSync(projectPath);}else{console.log(`\nProject directory '${projectName}' already exists.`);{process.exit(1);}}createDirectoryContents(templatePath,projectName);console.log("\nTemplate successfully created.");});}elseif(condition==="-a"){// Validate folder pathif(!folderPath){console.error("\nError: provide a folder path.");{process.exit(1);}}// Validate folder existenceif(!fs.existsSync(folderPath)){console.error("\nError: Folder does not exist.");{process.exit(1);}}// Create project name from folder pathconstprojectName=path.basename(folderPath);// Create directory for new project if it doesn't existconsttemplateFolderPath=path.join(__dirname,"templates",projectName);if(!fs.existsSync(templateFolderPath)){fs.mkdirSync(templateFolderPath);}else{console.log(`\nFolder '${templateFolderPath}' already exists.`);{process.exit(1);}}// Copy contents from folderPath to projectName/templatecreateDirectoryContents(folderPath,projectName);// InformSync user about successful operationif(nodeFlag){console.log("\nTemplate successfully created with node_modules.");}else{console.log("\nTemplate successfully created.");}}elseif(condition==="-r"){consttemplateToRemove=process.argv[3];// Validate if the template existsconsttemplatePathToRemove=path.join(__dirname,"templates",templateToRemove);if(!fs.existsSync(templatePathToRemove)){console.error(`\nError: Template '${templateToRemove}' does not exist.`);{process.exit(1);}}// Remove the template directoryfs.rmSync(templatePathToRemove,{recursive: true});// InformSync user about successful operationconsole.log(`\nTemplate '${templateToRemove}' was successfully removed.`);}elseif(condition==="-c"){construnCommand=(command)=>{returnnewPromise((resolve,reject)=>{try{execSync(command,{stdio: "inherit"});resolve();// Resolve the promise when the command completes successfully}catch(error){console.error(`Failed to Execute ${command}`,error);reject(error);// Reject the promise with the error if the command fails}});};consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;constrepoLink=process.argv[3];if(!urlRegex.test(repoLink)){console.log("Invalid repository link provided.");process.exit(1);}else{console.log("Repository link is valid.");}constgitCommand=`git clone --depth 1 ${repoLink}`;letprojectName;// Check if a changed name is provided in the clone commandif(repoLink.includes(" ")){// Extract the project name from the clone commandconstcloneCommandParts=repoLink.split(" ");// Split the clone command by whitespaceprojectName=cloneCommandParts[cloneCommandParts.length-1];// Get the last part as the project name}else{// Extract the project name from the repository linkprojectName=path.basename(repoLink,".git");}runCommand(gitCommand).then(async()=>{console.log("\nRepository Cloned");// Remove the .git folderconstclonedFolderPath=path.join(CURR_DIR,projectName);constgitFolderPath=path.join(clonedFolderPath,".git");if(fs.existsSync(gitFolderPath)){awaitfs.promises.rm(gitFolderPath,{recursive: true});}// Run the 'init -a' command with the cloned folder pathconstinitCommand=`init -a "${clonedFolderPath}"`;awaitrunCommand(initCommand);// Remove the cloned project folder asynchronouslytry{awaitfs.promises.rm(clonedFolderPath,{recursive: true});}catch(error){console.error(`Failed to remove cloned folder: ${error}`);}}).catch((error)=>{console.error("Error cloning repository:",error);process.exit(1);// Exit the script with an error status code});}elseif(condition==="-h"){// Clear the terminal by printing ANSI escape codesprocess.stdout.write("\u001b[2J\u001b[0;0H");constmessage=`${chalk.bold.underline.white("Package Commands:")}${chalk.green("Create a New Template:")} - Type ${chalk.cyan("'init'")} and press Enter at your desired location.${chalk.green("Add a Template:")} - Use the ${chalk.cyan("-a")} flag followed by the path in quotes. By default it skips the node_modules folder.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')} - But if you want to add node_modules folder with the template you are creating then ${chalk.cyan("-y")} flag after the command.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')}${chalk.cyan("-y")}${chalk.green("Clone a Repository and Add as a Template:")} - Use the ${chalk.cyan("-c")} flag followed by the repository link in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -c")}${chalk.yellow('"https://github.com/user/repoitoryName"')}${chalk.green("Remove a Template:")} - Use the ${chalk.cyan("-r")} flag followed by the exact name of the template in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -r")}${chalk.yellow('"Template Name"')}${chalk.green("Help:")} - Use ${chalk.cyan("init -h")} to see help. Made By Sooraj Gupta Email : soorajgupta00@gmail.com Github Repository : https://github.com/s54a/s54a-init`;console.log(message);}elseif(condition){console.log(chalk.red(` Invalid command: "${condition}". Please use one of the supported commands. Run ${chalk.yellow("init -h")} to see help. `));}else{console.log(chalk.red(`An error occurred or an invalid command was provided. Run ${chalk.yellow("init -h")} to see help.`));}

package.json

{
"name": "@s54a/init",
"version": "5.0.0",
"description": "Project Initializer",
"main": "./index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"init": "index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/s54a/s54a-init.git"
},
"keywords": ["Project Initializer", "Initializer", "Init"],
"author": "Sooraj Gupta",
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
"inquirer": "^9.2.15"
},
"bugs": {
"url": "https://github.com/s54a/s54a-init/issues"
},
"homepage": "https://github.com/s54a/s54a-init#readme"
}

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - s54a/s54a-init: Project Initializer || Template CLI · GitHub
Skip to content

Repository files navigation

Table of Contentsgenerated with DocToc

@s54a/init || TempLate CLI || Project Initializer

When I was starting a new project, I used the 'create vite app' command. Then, I began to remove and add files for the project. It struck me that I could create it once and paste it everywhere when I start a new project. Thats how I started building this.

There are two branch of this project in this one I have removed images & a few files to reduce the size

Visit the NPM Readme to see examples

How it Works

The package stores Templates inside a folder called "Templates" then when you run the init command it displays the templates and then it will paste the folder at the location where the terminal is open.

Simply it just copies & pastes the Folders from one place to another

Video Tutorial

Video Tutorial

Folder Structure

📁 init
├── 🌅 images
│ ├── 🖼️ article.png
│ ├── 🖼️ init -a.png
│ ├── 🖼️ init -c.png
│ ├── 🖼️ init -h.png
│ ├── 🖼️ init -r.png
│ └── 🖼️ init.png
├── 📁 templates
│ └── 📁 templateTest
│ ├── 📄 index.html
│ ├── 📄 main.js
│ └── 📄 style.css
├── 📄 .gitignore
├── 📄 .npmignore
├── 📄 index.js
├── 📜 LICENSE
├── 📝 Readme.md
├── 📋 package.json
└── 📋 package-lock.json

For testing purposes, only one template has been included, consisting of three files (HTML, CSS & JS). Additional templates have not been added to avoid making the package unnecessarily large.

(Note ChatGPT built this folder structure)

Installation

This package provides an Executable Command

You will have to install this package globally to be able to use the init command.

npm install -g @s54a/init

Usage

To begin, open a terminal at the desired project location and run this command

init
Example

init

This displays all available templates from the template folder, listed by folder name. Choose a template and enter the desired folder name when prompted to create a new project with the selected template's contents.

Users can also create templates themselves by running:

init -a "C:\Users\{User}\Desktop\Projects\Ongoing Projects"
Example

init

Upon execution, the tool generates a new folder path containing the contents of the user-created template. Subsequently, when the init command is invoked, it showcases the recently created template under the specified name.

Tip: For Windows users, you can quickly access the folder by selecting it and then pressing ctrl + shift + c.

By Default when you create a Template it skips the node_modules folder and its contents.

But for reason you want to create a template with node_modules folder you will have to pass the -y flag.

init -a "O:\test\cliTest" -y
Example

init

Templates can be removed using the following command:

init -r "template name"
Example

init

(Note: The name must match exactly.)

Templates can also be added from GitHub with:

init -c "https://github.com/user/repoitoryName.git"
Example

init

This process involves cloning the repository into the current terminal directory, removing the .git folder from the cloned repository, executing the init -a "repoName" command to create a copy in the templates folder, and then deleting the cloned repository folder from the current terminal location.

I have used this Regex to verify if the given string is a link or not.

consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;

The reason it performs all these steps is because I attempted to accomplish it in a simpler manner but couldn't find one.

To see all the Commands (Help)

init -h
Example

init

Resources

These are the YouTube Videos & Article which helped me build this

The Article Link

The Video Link

The Video Link

& ChatGPT

This a similar project built with Typescript https://github.com/pongsatt/mycli/blob/master/src/index.ts

Extra Resources https://github.com/lirantal/nodejs-cli-apps-best-practices

Take a look at https://yeoman.io/generators/

Read this if you are a beginner

I asked one of my friend who is a beginner in Web Dev. She asked me a question how will I make templates or why use this instead of Copy Pasting

So when ever you do

npm create-react-app ProjectName

or

npm create-vite-app ProjectName

These files are generated (with create react app)

my-app/
├── README.md
├── node_modules/
├── package.json
├── .gitignore
├── public/
│ ├── favicon.ico
│ ├── index.html
│ ├── manifest.json
│ └── robots.txt
└── src/
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
└── logo.svg

As you can see there are so many files which aren't necessary so you will have to remove these files remove code from index.css or maybe more files.

So you can do this once and use this template by using this package or just copy paste.

So why use this package instead of copy pasting So assume you have created many templates now you will create a folder to store them and every time you will start a new project you will have to go to that location copy that file and paste it at the location where you are starting the project and then change the name.

So this package does all that when you create a template and add it as a template from Command Line Interface and what I have learned & heard is that you will much faster at things with CLI then GUI.

Why I Created this

When you start Learning to code you will create multiple new projects so every time you will have to create new files

e.g. index.html, style.css, app.js

When you will advance to React you will do

So every time you will do that you will have to remove files edit content of the files.

So I thought it is a hassle so lets just do it once and I wil copy & paste it every time whenever I start a new project.

Then I thought I can create a cli which does that for me & I started building this package.

Then on a suggestion of a friend I also added the Clone & Create Template from Github Feature.

How I use this Package

I use this Package whenever I start a new project.

I have created my own template and added them as templates using init -a "folder path" command.

I have also added templates on Github.

So if I am on a new device or format my current one so I can just run the init -c "github_url" command after installing the package to clone new project and create a new template.

So if you are a Freelancer or Someone who is learning to code, or starting a new Project you can use this.

Extra Info

While Deploying Packages on NPM I realized that whatever you have in your project will get included even if you use npm ignore. I don't know if npm ignore works or failed. So I created another branch of this project in which I removed images and extra files. To reduce the size of the package & the node_modules size.

Here is the difference

size differencesize difference

So the Package Size is reduced by 300 Kilo Bytes

Source Code

Every time when I look at the open source I feel it is a hassle to navigate around files to see the code.

And this project source code is in a single file.

So I am adding the source code in the markdown file so you can read it all in one place.

index.js

#!/usr/bin/env node
importinquirerfrom"inquirer";importfsfrom"fs";importpathfrom"path";import{fileURLToPath}from"url";import{execSync}from"child_process";importchalkfrom"chalk";const__dirname=path.dirname(fileURLToPath(import.meta.url));constCHOICES=fs.readdirSync(path.join(__dirname,"templates"));constQUESTIONS=[{name: "project-choice",type: "list",message: "What project template would you like to generate?",choices: CHOICES,},{name: "project-name",type: "input",message: "Project name:",validate: function(input){if(/^([A-Za-z\-\_\d])+$/.test(input))returntrue;elsereturn"Project name may only include letters, numbers, underscores and hashes.";},},];constCURR_DIR=process.cwd();letnodeFlag=false;// Set nodeFlag as a global variable with a default value of false// Command line argumentsconst[,,condition,folderPath,nodeFlagParam]=process.argv;const[,, ...args]=process.argv;constoptions={condition: null,folderPathOrNameOrLink: null,nodeFlagParam: "",};// Parse command line argumentsfor(leti=0;i<args.length;i++){constarg=args[i];switch(arg){case"-a":
case"-r":
case"-c":
options.condition=arg;break;case"-h":
options.condition=arg;options.folderPathOrNameOrLink="";break;case"-y":
// Check if the previous option was '-a'if(options.condition==="-a"){options.nodeFlagParam=arg;}else{console.error(`Invalid usage of '-y' flag.`);process.exit(1);}break;default:
if(arg.startsWith("-")){console.error(`Invalid option: ${arg}`);process.exit(1);}else{options.folderPathOrNameOrLink=arg;}break;}}if(!args.length){options.condition="";options.folderPathOrNameOrLink="";}// Check for unsupported or invalid optionsif(Object.values(options).some((value)=>value===null)){console.error(`Missing required option or invalid usage.`);process.exit(1);}// Update the value of nodeFlag based on the command line argumentif(nodeFlagParam==="-y"){nodeFlag=true;}functioncreateDirectoryContents(templatePath,newProjectPath){constfilesToCreate=fs.readdirSync(templatePath);filesToCreate.forEach((file)=>{constorigFilePath=path.join(templatePath,file);// get stats about the current fileconststats=fs.statSync(origFilePath);if(stats.isFile()){constcontents=fs.readFileSync(origFilePath,"utf8");// Renameif(file===".npmignore")file=".gitignore";if(condition==="-a"){fs.writeFileSync(path.join(__dirname,"templates",newProjectPath,file),contents,"utf8");}else{fs.writeFileSync(path.join(CURR_DIR,newProjectPath,file),contents,"utf8");}}elseif(stats.isDirectory()){if(condition==="-a"){if(file==="node_modules"&&!nodeFlag){return;}else{fs.mkdirSync(path.join(__dirname,"templates",newProjectPath,file));}}else{fs.mkdirSync(path.join(CURR_DIR,newProjectPath,file));}// Then recursively copy contentscreateDirectoryContents(path.join(templatePath,file),path.join(newProjectPath,file));}});}if(!condition){inquirer.prompt(QUESTIONS).then((answers)=>{constprojectChoice=answers["project-choice"];constprojectName=answers["project-name"];consttemplatePath=path.join(__dirname,"templates",projectChoice);constprojectPath=path.join(CURR_DIR,projectName);// Create project directory if it doesn't existif(!fs.existsSync(projectPath)){fs.mkdirSync(projectPath);}else{console.log(`\nProject directory '${projectName}' already exists.`);{process.exit(1);}}createDirectoryContents(templatePath,projectName);console.log("\nTemplate successfully created.");});}elseif(condition==="-a"){// Validate folder pathif(!folderPath){console.error("\nError: provide a folder path.");{process.exit(1);}}// Validate folder existenceif(!fs.existsSync(folderPath)){console.error("\nError: Folder does not exist.");{process.exit(1);}}// Create project name from folder pathconstprojectName=path.basename(folderPath);// Create directory for new project if it doesn't existconsttemplateFolderPath=path.join(__dirname,"templates",projectName);if(!fs.existsSync(templateFolderPath)){fs.mkdirSync(templateFolderPath);}else{console.log(`\nFolder '${templateFolderPath}' already exists.`);{process.exit(1);}}// Copy contents from folderPath to projectName/templatecreateDirectoryContents(folderPath,projectName);// InformSync user about successful operationif(nodeFlag){console.log("\nTemplate successfully created with node_modules.");}else{console.log("\nTemplate successfully created.");}}elseif(condition==="-r"){consttemplateToRemove=process.argv[3];// Validate if the template existsconsttemplatePathToRemove=path.join(__dirname,"templates",templateToRemove);if(!fs.existsSync(templatePathToRemove)){console.error(`\nError: Template '${templateToRemove}' does not exist.`);{process.exit(1);}}// Remove the template directoryfs.rmSync(templatePathToRemove,{recursive: true});// InformSync user about successful operationconsole.log(`\nTemplate '${templateToRemove}' was successfully removed.`);}elseif(condition==="-c"){construnCommand=(command)=>{returnnewPromise((resolve,reject)=>{try{execSync(command,{stdio: "inherit"});resolve();// Resolve the promise when the command completes successfully}catch(error){console.error(`Failed to Execute ${command}`,error);reject(error);// Reject the promise with the error if the command fails}});};consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;constrepoLink=process.argv[3];if(!urlRegex.test(repoLink)){console.log("Invalid repository link provided.");process.exit(1);}else{console.log("Repository link is valid.");}constgitCommand=`git clone --depth 1 ${repoLink}`;letprojectName;// Check if a changed name is provided in the clone commandif(repoLink.includes(" ")){// Extract the project name from the clone commandconstcloneCommandParts=repoLink.split(" ");// Split the clone command by whitespaceprojectName=cloneCommandParts[cloneCommandParts.length-1];// Get the last part as the project name}else{// Extract the project name from the repository linkprojectName=path.basename(repoLink,".git");}runCommand(gitCommand).then(async()=>{console.log("\nRepository Cloned");// Remove the .git folderconstclonedFolderPath=path.join(CURR_DIR,projectName);constgitFolderPath=path.join(clonedFolderPath,".git");if(fs.existsSync(gitFolderPath)){awaitfs.promises.rm(gitFolderPath,{recursive: true});}// Run the 'init -a' command with the cloned folder pathconstinitCommand=`init -a "${clonedFolderPath}"`;awaitrunCommand(initCommand);// Remove the cloned project folder asynchronouslytry{awaitfs.promises.rm(clonedFolderPath,{recursive: true});}catch(error){console.error(`Failed to remove cloned folder: ${error}`);}}).catch((error)=>{console.error("Error cloning repository:",error);process.exit(1);// Exit the script with an error status code});}elseif(condition==="-h"){// Clear the terminal by printing ANSI escape codesprocess.stdout.write("\u001b[2J\u001b[0;0H");constmessage=`${chalk.bold.underline.white("Package Commands:")}${chalk.green("Create a New Template:")} - Type ${chalk.cyan("'init'")} and press Enter at your desired location.${chalk.green("Add a Template:")} - Use the ${chalk.cyan("-a")} flag followed by the path in quotes. By default it skips the node_modules folder.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')} - But if you want to add node_modules folder with the template you are creating then ${chalk.cyan("-y")} flag after the command.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')}${chalk.cyan("-y")}${chalk.green("Clone a Repository and Add as a Template:")} - Use the ${chalk.cyan("-c")} flag followed by the repository link in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -c")}${chalk.yellow('"https://github.com/user/repoitoryName"')}${chalk.green("Remove a Template:")} - Use the ${chalk.cyan("-r")} flag followed by the exact name of the template in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -r")}${chalk.yellow('"Template Name"')}${chalk.green("Help:")} - Use ${chalk.cyan("init -h")} to see help. Made By Sooraj Gupta Email : soorajgupta00@gmail.com Github Repository : https://github.com/s54a/s54a-init`;console.log(message);}elseif(condition){console.log(chalk.red(` Invalid command: "${condition}". Please use one of the supported commands. Run ${chalk.yellow("init -h")} to see help. `));}else{console.log(chalk.red(`An error occurred or an invalid command was provided. Run ${chalk.yellow("init -h")} to see help.`));}

package.json

{
"name": "@s54a/init",
"version": "5.0.0",
"description": "Project Initializer",
"main": "./index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"init": "index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/s54a/s54a-init.git"
},
"keywords": ["Project Initializer", "Initializer", "Init"],
"author": "Sooraj Gupta",
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
"inquirer": "^9.2.15"
},
"bugs": {
"url": "https://github.com/s54a/s54a-init/issues"
},
"homepage": "https://github.com/s54a/s54a-init#readme"
}

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - s54a/s54a-init: Project Initializer || Template CLI · GitHub
Skip to content

Repository files navigation

Table of Contentsgenerated with DocToc

@s54a/init || TempLate CLI || Project Initializer

When I was starting a new project, I used the 'create vite app' command. Then, I began to remove and add files for the project. It struck me that I could create it once and paste it everywhere when I start a new project. Thats how I started building this.

There are two branch of this project in this one I have removed images & a few files to reduce the size

Visit the NPM Readme to see examples

How it Works

The package stores Templates inside a folder called "Templates" then when you run the init command it displays the templates and then it will paste the folder at the location where the terminal is open.

Simply it just copies & pastes the Folders from one place to another

Video Tutorial

Video Tutorial

Folder Structure

📁 init
├── 🌅 images
│ ├── 🖼️ article.png
│ ├── 🖼️ init -a.png
│ ├── 🖼️ init -c.png
│ ├── 🖼️ init -h.png
│ ├── 🖼️ init -r.png
│ └── 🖼️ init.png
├── 📁 templates
│ └── 📁 templateTest
│ ├── 📄 index.html
│ ├── 📄 main.js
│ └── 📄 style.css
├── 📄 .gitignore
├── 📄 .npmignore
├── 📄 index.js
├── 📜 LICENSE
├── 📝 Readme.md
├── 📋 package.json
└── 📋 package-lock.json

For testing purposes, only one template has been included, consisting of three files (HTML, CSS & JS). Additional templates have not been added to avoid making the package unnecessarily large.

(Note ChatGPT built this folder structure)

Installation

This package provides an Executable Command

You will have to install this package globally to be able to use the init command.

npm install -g @s54a/init

Usage

To begin, open a terminal at the desired project location and run this command

init
Example

init

This displays all available templates from the template folder, listed by folder name. Choose a template and enter the desired folder name when prompted to create a new project with the selected template's contents.

Users can also create templates themselves by running:

init -a "C:\Users\{User}\Desktop\Projects\Ongoing Projects"
Example

init

Upon execution, the tool generates a new folder path containing the contents of the user-created template. Subsequently, when the init command is invoked, it showcases the recently created template under the specified name.

Tip: For Windows users, you can quickly access the folder by selecting it and then pressing ctrl + shift + c.

By Default when you create a Template it skips the node_modules folder and its contents.

But for reason you want to create a template with node_modules folder you will have to pass the -y flag.

init -a "O:\test\cliTest" -y
Example

init

Templates can be removed using the following command:

init -r "template name"
Example

init

(Note: The name must match exactly.)

Templates can also be added from GitHub with:

init -c "https://github.com/user/repoitoryName.git"
Example

init

This process involves cloning the repository into the current terminal directory, removing the .git folder from the cloned repository, executing the init -a "repoName" command to create a copy in the templates folder, and then deleting the cloned repository folder from the current terminal location.

I have used this Regex to verify if the given string is a link or not.

consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;

The reason it performs all these steps is because I attempted to accomplish it in a simpler manner but couldn't find one.

To see all the Commands (Help)

init -h
Example

init

Resources

These are the YouTube Videos & Article which helped me build this

The Article Link

The Video Link

The Video Link

& ChatGPT

This a similar project built with Typescript https://github.com/pongsatt/mycli/blob/master/src/index.ts

Extra Resources https://github.com/lirantal/nodejs-cli-apps-best-practices

Take a look at https://yeoman.io/generators/

Read this if you are a beginner

I asked one of my friend who is a beginner in Web Dev. She asked me a question how will I make templates or why use this instead of Copy Pasting

So when ever you do

npm create-react-app ProjectName

or

npm create-vite-app ProjectName

These files are generated (with create react app)

my-app/
├── README.md
├── node_modules/
├── package.json
├── .gitignore
├── public/
│ ├── favicon.ico
│ ├── index.html
│ ├── manifest.json
│ └── robots.txt
└── src/
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
└── logo.svg

As you can see there are so many files which aren't necessary so you will have to remove these files remove code from index.css or maybe more files.

So you can do this once and use this template by using this package or just copy paste.

So why use this package instead of copy pasting So assume you have created many templates now you will create a folder to store them and every time you will start a new project you will have to go to that location copy that file and paste it at the location where you are starting the project and then change the name.

So this package does all that when you create a template and add it as a template from Command Line Interface and what I have learned & heard is that you will much faster at things with CLI then GUI.

Why I Created this

When you start Learning to code you will create multiple new projects so every time you will have to create new files

e.g. index.html, style.css, app.js

When you will advance to React you will do

So every time you will do that you will have to remove files edit content of the files.

So I thought it is a hassle so lets just do it once and I wil copy & paste it every time whenever I start a new project.

Then I thought I can create a cli which does that for me & I started building this package.

Then on a suggestion of a friend I also added the Clone & Create Template from Github Feature.

How I use this Package

I use this Package whenever I start a new project.

I have created my own template and added them as templates using init -a "folder path" command.

I have also added templates on Github.

So if I am on a new device or format my current one so I can just run the init -c "github_url" command after installing the package to clone new project and create a new template.

So if you are a Freelancer or Someone who is learning to code, or starting a new Project you can use this.

Extra Info

While Deploying Packages on NPM I realized that whatever you have in your project will get included even if you use npm ignore. I don't know if npm ignore works or failed. So I created another branch of this project in which I removed images and extra files. To reduce the size of the package & the node_modules size.

Here is the difference

size differencesize difference

So the Package Size is reduced by 300 Kilo Bytes

Source Code

Every time when I look at the open source I feel it is a hassle to navigate around files to see the code.

And this project source code is in a single file.

So I am adding the source code in the markdown file so you can read it all in one place.

index.js

#!/usr/bin/env node
importinquirerfrom"inquirer";importfsfrom"fs";importpathfrom"path";import{fileURLToPath}from"url";import{execSync}from"child_process";importchalkfrom"chalk";const__dirname=path.dirname(fileURLToPath(import.meta.url));constCHOICES=fs.readdirSync(path.join(__dirname,"templates"));constQUESTIONS=[{name: "project-choice",type: "list",message: "What project template would you like to generate?",choices: CHOICES,},{name: "project-name",type: "input",message: "Project name:",validate: function(input){if(/^([A-Za-z\-\_\d])+$/.test(input))returntrue;elsereturn"Project name may only include letters, numbers, underscores and hashes.";},},];constCURR_DIR=process.cwd();letnodeFlag=false;// Set nodeFlag as a global variable with a default value of false// Command line argumentsconst[,,condition,folderPath,nodeFlagParam]=process.argv;const[,, ...args]=process.argv;constoptions={condition: null,folderPathOrNameOrLink: null,nodeFlagParam: "",};// Parse command line argumentsfor(leti=0;i<args.length;i++){constarg=args[i];switch(arg){case"-a":
case"-r":
case"-c":
options.condition=arg;break;case"-h":
options.condition=arg;options.folderPathOrNameOrLink="";break;case"-y":
// Check if the previous option was '-a'if(options.condition==="-a"){options.nodeFlagParam=arg;}else{console.error(`Invalid usage of '-y' flag.`);process.exit(1);}break;default:
if(arg.startsWith("-")){console.error(`Invalid option: ${arg}`);process.exit(1);}else{options.folderPathOrNameOrLink=arg;}break;}}if(!args.length){options.condition="";options.folderPathOrNameOrLink="";}// Check for unsupported or invalid optionsif(Object.values(options).some((value)=>value===null)){console.error(`Missing required option or invalid usage.`);process.exit(1);}// Update the value of nodeFlag based on the command line argumentif(nodeFlagParam==="-y"){nodeFlag=true;}functioncreateDirectoryContents(templatePath,newProjectPath){constfilesToCreate=fs.readdirSync(templatePath);filesToCreate.forEach((file)=>{constorigFilePath=path.join(templatePath,file);// get stats about the current fileconststats=fs.statSync(origFilePath);if(stats.isFile()){constcontents=fs.readFileSync(origFilePath,"utf8");// Renameif(file===".npmignore")file=".gitignore";if(condition==="-a"){fs.writeFileSync(path.join(__dirname,"templates",newProjectPath,file),contents,"utf8");}else{fs.writeFileSync(path.join(CURR_DIR,newProjectPath,file),contents,"utf8");}}elseif(stats.isDirectory()){if(condition==="-a"){if(file==="node_modules"&&!nodeFlag){return;}else{fs.mkdirSync(path.join(__dirname,"templates",newProjectPath,file));}}else{fs.mkdirSync(path.join(CURR_DIR,newProjectPath,file));}// Then recursively copy contentscreateDirectoryContents(path.join(templatePath,file),path.join(newProjectPath,file));}});}if(!condition){inquirer.prompt(QUESTIONS).then((answers)=>{constprojectChoice=answers["project-choice"];constprojectName=answers["project-name"];consttemplatePath=path.join(__dirname,"templates",projectChoice);constprojectPath=path.join(CURR_DIR,projectName);// Create project directory if it doesn't existif(!fs.existsSync(projectPath)){fs.mkdirSync(projectPath);}else{console.log(`\nProject directory '${projectName}' already exists.`);{process.exit(1);}}createDirectoryContents(templatePath,projectName);console.log("\nTemplate successfully created.");});}elseif(condition==="-a"){// Validate folder pathif(!folderPath){console.error("\nError: provide a folder path.");{process.exit(1);}}// Validate folder existenceif(!fs.existsSync(folderPath)){console.error("\nError: Folder does not exist.");{process.exit(1);}}// Create project name from folder pathconstprojectName=path.basename(folderPath);// Create directory for new project if it doesn't existconsttemplateFolderPath=path.join(__dirname,"templates",projectName);if(!fs.existsSync(templateFolderPath)){fs.mkdirSync(templateFolderPath);}else{console.log(`\nFolder '${templateFolderPath}' already exists.`);{process.exit(1);}}// Copy contents from folderPath to projectName/templatecreateDirectoryContents(folderPath,projectName);// InformSync user about successful operationif(nodeFlag){console.log("\nTemplate successfully created with node_modules.");}else{console.log("\nTemplate successfully created.");}}elseif(condition==="-r"){consttemplateToRemove=process.argv[3];// Validate if the template existsconsttemplatePathToRemove=path.join(__dirname,"templates",templateToRemove);if(!fs.existsSync(templatePathToRemove)){console.error(`\nError: Template '${templateToRemove}' does not exist.`);{process.exit(1);}}// Remove the template directoryfs.rmSync(templatePathToRemove,{recursive: true});// InformSync user about successful operationconsole.log(`\nTemplate '${templateToRemove}' was successfully removed.`);}elseif(condition==="-c"){construnCommand=(command)=>{returnnewPromise((resolve,reject)=>{try{execSync(command,{stdio: "inherit"});resolve();// Resolve the promise when the command completes successfully}catch(error){console.error(`Failed to Execute ${command}`,error);reject(error);// Reject the promise with the error if the command fails}});};consturlRegex=/^(https?|ftp):\/\/(([a-z\d]([a-z\d-]*[a-z\d])?\.)+[a-z]{2,}|localhost)(\/[-a-z\d%_.~+]*)*(\?[;&a-z\d%_.~+=-]*)?(\#[-a-z\d_]*)?$/i;constrepoLink=process.argv[3];if(!urlRegex.test(repoLink)){console.log("Invalid repository link provided.");process.exit(1);}else{console.log("Repository link is valid.");}constgitCommand=`git clone --depth 1 ${repoLink}`;letprojectName;// Check if a changed name is provided in the clone commandif(repoLink.includes(" ")){// Extract the project name from the clone commandconstcloneCommandParts=repoLink.split(" ");// Split the clone command by whitespaceprojectName=cloneCommandParts[cloneCommandParts.length-1];// Get the last part as the project name}else{// Extract the project name from the repository linkprojectName=path.basename(repoLink,".git");}runCommand(gitCommand).then(async()=>{console.log("\nRepository Cloned");// Remove the .git folderconstclonedFolderPath=path.join(CURR_DIR,projectName);constgitFolderPath=path.join(clonedFolderPath,".git");if(fs.existsSync(gitFolderPath)){awaitfs.promises.rm(gitFolderPath,{recursive: true});}// Run the 'init -a' command with the cloned folder pathconstinitCommand=`init -a "${clonedFolderPath}"`;awaitrunCommand(initCommand);// Remove the cloned project folder asynchronouslytry{awaitfs.promises.rm(clonedFolderPath,{recursive: true});}catch(error){console.error(`Failed to remove cloned folder: ${error}`);}}).catch((error)=>{console.error("Error cloning repository:",error);process.exit(1);// Exit the script with an error status code});}elseif(condition==="-h"){// Clear the terminal by printing ANSI escape codesprocess.stdout.write("\u001b[2J\u001b[0;0H");constmessage=`${chalk.bold.underline.white("Package Commands:")}${chalk.green("Create a New Template:")} - Type ${chalk.cyan("'init'")} and press Enter at your desired location.${chalk.green("Add a Template:")} - Use the ${chalk.cyan("-a")} flag followed by the path in quotes. By default it skips the node_modules folder.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')} - But if you want to add node_modules folder with the template you are creating then ${chalk.cyan("-y")} flag after the command.${chalk.yellow("Example:")}${chalk.cyan("init -a")}${chalk.yellow('"C:\\Users\\{User}\\Desktop\\Projects\\Ongoing Projects"')}${chalk.cyan("-y")}${chalk.green("Clone a Repository and Add as a Template:")} - Use the ${chalk.cyan("-c")} flag followed by the repository link in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -c")}${chalk.yellow('"https://github.com/user/repoitoryName"')}${chalk.green("Remove a Template:")} - Use the ${chalk.cyan("-r")} flag followed by the exact name of the template in quotes.${chalk.yellow("Example:")}${chalk.cyan("init -r")}${chalk.yellow('"Template Name"')}${chalk.green("Help:")} - Use ${chalk.cyan("init -h")} to see help. Made By Sooraj Gupta Email : soorajgupta00@gmail.com Github Repository : https://github.com/s54a/s54a-init`;console.log(message);}elseif(condition){console.log(chalk.red(` Invalid command: "${condition}". Please use one of the supported commands. Run ${chalk.yellow("init -h")} to see help. `));}else{console.log(chalk.red(`An error occurred or an invalid command was provided. Run ${chalk.yellow("init -h")} to see help.`));}

package.json

{
"name": "@s54a/init",
"version": "5.0.0",
"description": "Project Initializer",
"main": "./index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"init": "index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/s54a/s54a-init.git"
},
"keywords": ["Project Initializer", "Initializer", "Init"],
"author": "Sooraj Gupta",
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
"inquirer": "^9.2.15"
},
"bugs": {
"url": "https://github.com/s54a/s54a-init/issues"
},
"homepage": "https://github.com/s54a/s54a-init#readme"
}

Releases

Packages

Used by

Contributors

Languages