——————————☆☆☆——————————
Corresponding address of Node series:
- Code repository: https://github.com/LiangJunrong/all-for-one
- Article warehouse: https://github.com/LiangJunrong/document-library/tree/master/series-front-end data/Node
——————————☆☆☆——————————
commander.js
-a complete Node.js
command line solution.
This article explains how to walk around the Node.js command line commander.js
I. Introduction
When a Node.js
program is running, there will be many global variables stored in memory.
Among them, process
used as a process object, it has a argv
attribute, and the instructions can be viewed.
Let's just build a index.js
example, the terminal executes the command: node index.js --name jsliang
index.js
console.log(process.argv);
/*
[
'C:\\Program Files\\nodejs\\node.exe',
'F:\\jsliang\\index.js',
'--name',
'jsliang'
]
*/
Look at the printed data:
Node
Location:C:\\Program Files\\nodejs\\node.exe
- Current code path:
F:\\jsliang\\index.js
- Parameter 1:
--name
- Parameter 2:
jsliang
Therefore, when we write the command line program, we only need to process.argv
the third element of the array 060cdb9238e991 and the following parameters.
If it is not too troublesome, you can write a lot of judgment branches to do it.
However, if there is a ready-made one, why do I have to write it myself? If I can be lazy, I’ll be lazy~
Two commander.js
commander.js
is a tj
written by 060cdb9238e9e3, which is used to make Node
command line programs easier:
Understand you, Chinese README is here: https://github.com/tj/commander.js/blob/master/Readme_zh-CN.md
Let's start the operation:
Initialize
package.json
:npm init --yes
- ! ! [Note] This step can be omitted if it is learned in the order of the Node series
- ! ! [Note] The following code can create an
test
to play around
- Installation package:
npm i commander
- Write instruction file:
index.js
const program = require('commander');
program
.version('0.0.1')
.description('小工具指令清单')
.option('-s, --sort <path>', '排序功能', '')
program.parse(process.argv);
package.json (automatically generated)
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"commander": "^7.2.0"
}
}
The logic of this code is:
- Reference
commander
- Description
commander
theversion
parameters - With
commander
controlprocess.argv
Focus on the parameters in paragraph 2 of this code:
The parameters seem very irritating, but I don’t understand and don’t know how to use it.
version
: version- Usage:
.version('x.y.z')
- Usage:
description
: description- Usage:
.description('Widget instruction list')
- Usage:
option
: Option- Usage:
.option('-n, --name <name>', 'your name', 'jsliang')
- The first parameter is the option definition, which can be connected
|
,,
and' '
- The second parameter is the option description
- The third parameter is the default value of the option parameter (optional)
- Usage:
So below we can view some information.
- Execute the command:
node index.js -h
Get the following results:
Usage: index [options]
小工具指令清单
Options:
-V, --version output the version number
-s, --sort <path> 排序功能 (default: "")
-h, --help display help for command
So we have completed some small instructions, so how do we do it?
- Sort:
node index.js -s "jsliang"
Of course, this feels too weird, can it be npm run xxx
in the same way npm run dev
, 060cdb9238edb2?
Of course it is possible!
Three practice: file rearrangement function
Having said so much, let's do a little practice!
For a document library written in Markdown, if you don't set the document order, it will read the directory according to the system's rules:
- 1. Article 1
- 10. Article 10
- 2. Article 2
- ……
When there is too much content in a folder, we want to let users read it in our own order, so we can't find the system, so we need to write a small tool with Node, and read it in the desired order when reading it. This is Our original intention to develop gadgets.
Of course, there is another very important function, that is, when we want to insert an article between the first and second articles, for example:
- 1. Article 1
- 1-1. Article 1-1
- 2. Article 2
- ……
We also need to reorder this directory structure so that new articles can be inserted into the specified location.
3.1 Practice list
At this time our directory is:
+ docs
+ 3.目录c
- 1.目录c1.md
- 1-1.目录c2.md
- 2.目录c3.md
- 1.文章a.md
- 2.文章b.md
- 10.文章d.md
+ src
- config.ts
- index.ts【已有】
- sortCatalog.ts
- .eslintrc.js【已有】
- package.json【已有】
- tsconfig.json【已有】
.eslintrc.js
, package-lock.json
, 060cdb9238ef10 and tsconfig.json
in this directory package.json
previous article for the configuration of TypeScript, so I won’t repeat it here.
docs
directory, just copy the file names.
In order to avoid misoperation by your friends, let’s take a screenshot.
3.2 Writing commander
Adding commonder
only needs to configure on package.json
and index.ts
- Initialize
package.json
:npm init --yes
(previously configured) - Install
commander
:npm i commander
package.json
{
"name": "jsliang",
"version": "1.0.0",
"description": "FE-util",
"main": "index.js",
"scripts": {
"sort": "ts-node ./src/index.ts sort"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/node": "^15.0.2",
"@typescript-eslint/eslint-plugin": "^4.23.0",
"@typescript-eslint/parser": "^4.23.0",
"eslint": "^7.26.0",
"ts-node": "^9.1.1",
"typescript": "^4.2.4"
},
"dependencies": {
"commander": "^7.2.0"
}
}
Note that scripts
changed, remember to copy it
Then simply write the contents of index.ts
src/index.ts
import program from 'commander';
import { sortCatalog } from './sortCatalog';
program
.version('0.0.1')
.description('工具库')
program
.command('sort <path>')
.description('文件排序功能。示例:npm run sort "docs" 或者 npm run sort " C:/code/jsliang/src/docs"')
.action((path: string) => {
sortCatalog(`../${path}`); // 为了更便捷,先退一层到外边
});
program.parse(process.argv);
3.3 Write the sort function
After preparing the basic configuration, just add content sortCatalog.ts
src/sortCatalog.ts
/**
* @name 文件排序功能
* @time 2021-05-22 16:08:06
* @description 规则
1. 系统顺序 1/10/2/21/3,希望排序 1/2/3/10/21
2. 插入文件 1/2/1-1,希望排序 1/2/3(将 1-1 变成 2,2 变成 3)
*/
import fs from 'fs';
import path from 'path';
import { IGNORE_PATH } from './config';
const recursion = (filePath: string, level = 0) => {
const files = fs.readdirSync(filePath);
files
.filter((item => !IGNORE_PATH.includes(item))) // 过滤忽略文件/文件夹
.sort((a, b) =>
Number((a.split('.')[0]).replace('-', '.'))
- Number((b.split('.')[0]).replace('-', '.'))
) // 排序文件夹
.forEach((item, index) => { // 遍历文件夹
// 设置旧文件名称和新文件名称
const oldFileName = item;
const newFileName = `${index + 1}.${oldFileName.slice(oldFileName.indexOf('.') + 1)}`;
// 设置旧文件路径和新文件路径
const oldPath = `${filePath}/${oldFileName}`;
const newPath = `${filePath}/${newFileName}`;
// 判断文件格式
const stat = fs.statSync(oldPath);
// 判断是文件夹还是文件
if (stat.isFile()) {
fs.renameSync(oldPath, newPath); // 重命名文件
} else if (stat.isDirectory()) {
fs.renameSync(oldPath, newPath); // 重命名文件夹
recursion(newPath, level + 1); // 递归文件夹
}
});
};
export const sortCatalog = (filePath: string): boolean => {
// 绝对路径
if (path.isAbsolute(filePath)) {
recursion(filePath);
} else { // 相对路径
recursion(path.join(__dirname, filePath));
}
return true;
};
Some friends will definitely be curious about config.ts
is after reading it. In fact, it is just a global configuration:
/**
* @name 默认的全局配置
* @time 2021-05-22 16:12:21
*/
import path from 'path';
// 基础目录
export const BASE_PATH = path.join(__dirname, './docs');
// 忽略目录
export const IGNORE_PATH = [
'.vscode',
'node_modules',
];
When we have no configuration, we give the default configuration.
3.4 Operation content
OK, when you are ready, you can start playing.
The current directory structure under docs
- 1.文章a.md
- 10.文章d.md
- 2.文章b.md
- 3.目录c
- 1-1.目录c2.md
- 1.目录c1.md
- 2.目录c3.md
And after we run npm run sort "docs"
, the new directory list becomes:
- 1.文章a.md
- 2.文章b.md
- 3.目录c
- 1.目录c1.md
- 2.目录c2.md
- 3.目录c3.md
- 4.文章d.md
In this way, our simple case is ready! Is it very simple!
Four commonly used commander configuration
commander
configuration that we do not want to see very much, but is common in normal use:
version
: version. Used to set the version number of the command program- Usage:
.version('x.y.z')
- Usage:
description
: description. Used to set the description of the command- Usage:
.description('Widget instruction list')
- Usage:
option
: Options.- Usage:
.option('-n, --name <name>', 'your name', 'jsliang')
- The first parameter is the option definition, which can be
|
,,
and' '
. The parameter can be modified with<>
(required) or[]
(optional) - The second parameter is the option description
- The third parameter is the default value of the option parameter (optional)
- Usage:
command
: Command- Usage:
.command('init <path>', 'description')
command
slightly more complicated. In principle, it accepts 3 parameters, the first is the command definition, the second is the description of the command, and the third is the command auxiliary modification object- The first parameter can use
<>
or[]
modify the command parameters The second parameter is optional
- When there is no second parameter,
commander.js
will returnCommand
object - With the second parameter, the prototype object will be returned, and the subcommand mode will be used when
action(fn)
- Subcommand mode:
./pm
,./pm-install
,./pm-search
etc. These subcommands are in a different file from the main command
- When there is no second parameter,
- The third parameter is generally different, he can set whether to display the sub-command mode used
- Usage:
action
: Action. Used to set related callbacks for command execution- Usage:
.action(fn)
fn
can accept command parameters as function parameters, and the order is consistent with the order defined incommand()
- Usage:
parse
: Analysis ofprocess.argv
- Usage:
program.parse(process.argv)
- This API is generally called at the end to parse
process.argv
- Usage:
OK, this is the end of the brief introduction of commander
Five references
jsliang's document library is by 160cdb9238f5b0 Liang Junrong using Creative Commons Attribution-Non-commercial Use-Same Way Sharing 4.0 International License Agreement <br/>Based on https://github.com/LiangJunrong/document-library . <br/>Use rights not authorized by this license agreement can be obtained from https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ .
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。