Node command line script
I want to develop the usual scattered learned knowledge to record, like to write some articles to record. So you set up a Git repository. Then you run into a problem, because the file directory structure is the same when writing the article, and it feels painful to create it manually every time. In the spirit of technical literacy, just want to be able to write a command line script to complete automatic creation.
In fact, this exercise is for the future to create their own CLI tools to lay a certain foundation.
Libraries used:
"devDependencies": {
"chalk": "^ 4.1.0." "."commander": "^ 7.1.0"."inquirer": "^ 8.0.0." "."lodash": "^ 4.17.21"
}
Copy the code
Post the code first, which will have detailed comments, and then explain the libraries used.
const path = require("path");
const fs = require("fs");
const program = require("commander");
const _ = require("lodash");
const inquirer = require("inquirer");
const chalk = require("chalk");
const os = require("os");
const { dir } = require("console");
// Define constants
const Technology = "technology";
const Diary = "diary";
const TypeSelection = "typeSelection";
const MaxLoop = 10;
const typeMap = {
file: "file"};let count = 1;
function handleDirObj(dirObj = {}, abPath = "") {
// Determine the system type, and decide whether to use/or \, the default is Windows, because it is recursive, so this part can be written outside
let dilimiter = "\ \";
switch (os.type()) {
case "Linux":
case "Darwin":
dilimiter = "/";
}
for (const key in dirObj) {
const exact = dirObj[key];
const exactPath = abPath + dilimiter + exact.name;
const mustr = exactPath.slice(1);
console.log(exact, exact.name, exactPath, mustr);
if(! exact.type) {// when directory processing
if(!!!!! fs.existsSync(mustr)) {console.log(` directory:${mustr}Existing `);
} else {
if(! fs.mkdirSync(mustr)) {console.log(` directory:${mustr}Create success ');
} else {
console.log(` directory:${mustr}Failed to create '); }}}else {
switch (exact.type) {
case typeMap.file:
if(!!!!! fs.existsSync(mustr)) {return console.log("Document:" + mustr + "Pre-existing");
} else {
if (fs.writeFileSync(mustr, ""."utf8")) {
return console.log("Document:" + mustr + "Create failed");
} else {
return console.log("Document:" + mustr + "Created successfully");
}
}
}
}
count++;
// Set a maximum level to prevent circular references from being created forever
// We can write a stack to place each exact in it, and then run the exact sequence === = to see if there is a loop
if (count > MaxLoop) {
throw new Error("max loop");
}
// The structure used to determine the path must be an object with the name attribute
if (typeofexact ! = ='object' || typeofexact.name ! = ="string") {
return;
}
if(exact.children) { handleDirObj(exact.children, exactPath); }}}function getDiaryName() {
return new Date().toLocaleDateString().split("/").join("-");
}
program
.command("create")
.alias("c")
.description("Create a new folder")
.option("--name [name]")
.option("--technology"."Create technical articles")
.option("--diary"."Create a Journal")
.action((option) = > {
var config = _.assign(
{
name: null.description: "".technology: false.diary: false,
},
option
);
var promps = [];
if (config.technology === false && config.diary === false) {
promps.push({
type: "checkbox".name: TypeSelection,
message: "What kind of file do you want to create?".choices: [{name: "Technology/Technology article".value: Technology,
},
{
name: "Diary/journal".value: Diary,
},
],
});
}
if(! config.description) { promps.push({type: "input".name: "description".message: "Please enter a description"}); }if(! config.technology) {if (typeofconfig.name ! = ="string") {
promps.push({
type: "input".name: "name".message: "Please enter a name".validate: function (input) {
if(! input) {return "Can't be empty.";
}
if (typeofinput ! = ="string") {
return "Please enter a string";
}
return true; }}); } } inquirer.prompt(promps).then((answers) = > {
console.log(answers);
// Process logic
// Normalize the create type first
let type = [];
if (answers[TypeSelection]) {
type = answers[TypeSelection];
} else {
if (answers.technology) {
type.push(Technology);
}
if(answers.diary) { type.push(Diary); }}// File root path
const root = path.resolve(__dirname, "..");
// Handle each type accordingly
type.forEach((item) = > {
switch (item) {
case Technology:
// Create technical articles for processing
const Tech = "tech";
const techName = answers.name;
// Create file directory structure with obj representation
// type does not write the default is folder
const dirObj = {
root: {
name: root,
children: {
Tech: {
name: Tech,
children: {
[techName]: {
name: techName,
children: {
img: {
name: "img",},indexMd: {
name: "index.md".type: typeMap.file,
},
},
},
},
},
},
},
};
handleDirObj(dirObj);
break;
case Diary:
// Process the creation of a diary
console.log("handle diary");
const diaryDirObj = {
root: {
name: root,
children: {
src: {
name: "src".children: {
indexMd: {
name: `${getDiaryName()}.md`.type: typeMap.file,
},
},
},
},
},
};
handleDirObj(diaryDirObj);
break; }}); }); }) .on("--help".function () {
console.log(" Examples:");
console.log("");
console.log("$ app module moduleName");
console.log("$ app m moduleName");
});
program.parse(process.argv);
Copy the code
commander API
-
Command – Defines a command line directive, followed by a name separated by a space, e.g..command(‘app [name] ‘)
-
Alias – Defining a shorter command line directive, such as executing the command $app m, is equivalent
-
Description — description, which is going to be shown in help
Option – Defines parameters. It accepts four parameters, in the first parameter, and it can enter a short name – a long name, app, use | or separated, when used in the command line, the two are equivalent, the difference is that the latter can be in the program through the callback is available; The second is the description, which will be displayed in the + + help message. The third parameter is the callback function, which takes a string as an argument. Sometimes we need a command line to create multiple modules, so we need a callback. The fourth parameter is the default value
-
Action – Register a callback function. Note that the callback does not currently support let declarations
-
Parse — Parses the command line
Inquirer features introduction
- Input, the input
- Validate – validation
- List — List options
- Confirm – tip
- Checkbox — checkbox and so on
chalk
Finally, we introduce Chalk to beautify the command line, which is lightweight, high performance and low learning cost.
The code structure is not very good, can be broken down. Switch code can use object storage handle as in Pubsub, which will have better scalability.
Reference website:
Jelly.jd.com/article/600…