nut-generator-cli 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/REDAME.MD ADDED
@@ -0,0 +1,3 @@
1
+ # NUT-CLI
2
+
3
+ 快速创建 wepack/vite 工程化模板实例
package/bin/nut.js ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ import figlet from "figlet";
3
+ import chalk from "chalk";
4
+ import { templates } from "../constants.js";
5
+ import initAction from "../initAction.js";
6
+ import { program } from "commander";
7
+ import { readFile } from 'fs/promises';
8
+
9
+ // es-module 默认不支持读取json文件
10
+ // 方法一
11
+ // const pkg = JSON.parse(
12
+ // await readFile(new URL("../package.json", import.meta.url))
13
+ // )
14
+
15
+ // 方法二
16
+ import { createRequire } from "module";
17
+ const require = createRequire(import.meta.url);
18
+ const pkg = require('../package.json');
19
+
20
+ // 方法三:使用插件fs-extra的api来读取json
21
+
22
+ program.version(pkg.version, "-v, --version");
23
+
24
+ program.name("nut")
25
+ .description(chalk.cyan("坚果 一个简单的脚手架工具"))
26
+ .usage("<command> [options]")
27
+ .on("--help", () => {
28
+ console.log("\r\n" + chalk.cyan(figlet.textSync("Nut Present", {
29
+ font: "Standard",
30
+ horizontalLayout: "default",
31
+ verticalLayout: "default",
32
+ width: 80,
33
+ whitespaceBreak: true
34
+ })));
35
+ })
36
+
37
+ program.command("create <app-name>")
38
+ .description("create a project")
39
+ .option("-t --template [template]", "输入模板名称创建项目")
40
+ .option("-f --force", "强制覆盖本地同名项目")
41
+ .option("-i --ignore", "忽略项目相关描述,快速创建项目")
42
+ .action(initAction);
43
+
44
+ program.command("list")
45
+ .description("查看所有可用的模板")
46
+ .action(() => {
47
+ console.log(chalk.bgCyanBright("所有可用模板:"));
48
+ templates.forEach((item, index) => {
49
+ console.log(`${index + 1}. ${chalk.cyan(item.name)} ${item.desc}`);
50
+ })
51
+ })
52
+
53
+ program.parse(process.argv);
@@ -0,0 +1,42 @@
1
+ #! /usr/bin/env sh
2
+ # 告诉脚本在任何命令出错的时候立即退出。这样可以确保在脚本执行过程中遇到错误时立即停止
3
+ set -e
4
+ # 输出提示信息
5
+ echo "输入新发布的版本号:"
6
+ # 等待用户在终端输入,输入的内容将赋值给变量 VERSION
7
+ read VERSION
8
+ # 输出信息并且让用户输入信息
9
+ # -p 选项用于在输出前显示提示信息, -n1 选项表示只接受一个字符的输入
10
+ read -p "确认发布 $VERSION ? (y/n)" -n1
11
+
12
+ # echo "\r\n----$VERSION----$REPLY\r\n"
13
+ # 直接输出一个空行
14
+ echo
15
+
16
+ # if []是直接判断 if [[]]是模糊判断
17
+ if [[ $REPLY =~ ^[Yy]$ ]];
18
+ then
19
+ if [[ `git status --porcelain` ]]; # 如果有未提交的文件
20
+ then
21
+ echo "\r\n---工作目录不干净,需要提交---\r\n"
22
+ git add -A
23
+ git commit -m "[commit]: $VERSION" # 提交版本信息log
24
+ else
25
+ echo "\r\n---工作目录没有任何需要提交的内容,不建议生产新的版本---\r\n"
26
+ exit 1
27
+ fi
28
+
29
+ # 修改package.json中的版本号
30
+ npm version $VERSION --message "[release]: $VERSION"
31
+
32
+ # 提交修改到远程仓库main分支
33
+ git push origin main
34
+
35
+ # 提交tag到仓库
36
+ git push origin refs/tags/v$VERSION
37
+
38
+ # 发布到npm
39
+ npm publish
40
+ else
41
+ echo "发布取消"
42
+ fi
package/constants.js ADDED
@@ -0,0 +1,32 @@
1
+ export const templates = [
2
+ {
3
+ name: "webpack-template",
4
+ value: "yingside/webpack-template",
5
+ desc: "基于webpack5自定义初始化vue3项目模板"
6
+ },
7
+ {
8
+ name: "vite-template",
9
+ value: "yingside/vite-template",
10
+ desc: "基于vite的vue3 + 前端工具链项目模板"
11
+ },
12
+ {
13
+ name: "vue-cli-template",
14
+ value: "yingside/vue-cli-template",
15
+ desc: "基于vue-cli自定义初始化vue3项目模板"
16
+ }
17
+ ];
18
+
19
+ export const message = [
20
+ {
21
+ message: "请输入作者",
22
+ name: "author"
23
+ },
24
+ {
25
+ message: "请输入项目关键词(,分割)",
26
+ name: "keywords"
27
+ },
28
+ {
29
+ message: "请输入项目描述",
30
+ name: "description"
31
+ }
32
+ ]
package/gitClone.js ADDED
@@ -0,0 +1,18 @@
1
+ import download from "download-git-repo";
2
+ import ora from "ora";
3
+ import chalk from "chalk";
4
+
5
+ export default function clone(remote, name, options) {
6
+ const spinner = ora("正在拉取项目......").start();
7
+ return new Promise((reslove, reject) => {
8
+ download(remote, name, options, err => {
9
+ if (err) {
10
+ spinner.fail(chalk.red(err));
11
+ reject(err);
12
+ return
13
+ }
14
+ spinner.succeed(chalk.green("拉取成功!"));
15
+ reslove();
16
+ })
17
+ })
18
+ }
package/initAction.js ADDED
@@ -0,0 +1,87 @@
1
+ import clone from "./gitClone.js";
2
+ import logSymbols from "log-symbols";
3
+ import shell from "shelljs";
4
+ import chalk from "chalk";
5
+ import figlet from "figlet";
6
+ import fs from "fs-extra";
7
+ import { templates, message } from "./constants.js";
8
+ import { inquirerConfirm, inquirerChoose, inquirerInputs } from './interactive.js';
9
+ import { removeDir, changePackageJson, npmInstall } from "./utils.js";
10
+
11
+ const initAction = async (name, option) => {
12
+ // 检测用户是否安装了git
13
+ if (!shell.which("git")) {
14
+ console.log(logSymbols.error, chalk.red("必须安装git后才能运行脚本!"));
15
+ shell.exit(1);
16
+ }
17
+
18
+ let repository = '';
19
+ if (option.template) {
20
+ const template = templates.find(item => item.name === option.template);
21
+ if (!template) {
22
+ console.log(logSymbols.error, chalk.red(`不存在模板${chalk.yellow(option.template)}`));
23
+ console.log(`\r\n 可输入命令 ${chalk.cyan("nut list")} 查看模板列表`);
24
+ return;
25
+ }
26
+ repository = template.value;
27
+ } else {
28
+ // 选择模板
29
+ const answer = await inquirerChoose("请选择一个项目模板", templates);
30
+ repository = answer.choose;
31
+ }
32
+
33
+ // 验证项目名称是否符合规范
34
+ if (name.match(/[\u4E00-\u9FFF`~!@#$%&^*[\]()\\;:<.>/?]/g)) {
35
+ console.log(logSymbols.error, chalk.red("项目名称存在非法字符!"));
36
+ return;
37
+ }
38
+
39
+ // 验证是否存在同名文件夹
40
+ if(fs.existsSync(name) && !option.force) {
41
+ console.log(logSymbols.warning, `检测已存在项目文件夹:${chalk.yellow(name)}`);
42
+ const answer = await inquirerConfirm("是否进行删除?");
43
+ if (answer.confirm) {
44
+ await removeDir(name);
45
+ } else {
46
+ console.log(logSymbols.error, chalk.red("项目创建失败,存在同名文件夹!"));
47
+ return;
48
+ }
49
+ } else if (fs.existsSync(name) && option.force) {
50
+ await removeDir(name);
51
+ }
52
+
53
+ // 拉取模板
54
+ try {
55
+ await clone(repository, name);
56
+ } catch (err) {
57
+ console.log(logSymbols.error, chalk.red("项目创建失败!"));
58
+ console.log("🚀 ~ initAction ~ err:", err);
59
+ shell.exit(1);
60
+ }
61
+
62
+ // 写入项目信息
63
+ let resMes;
64
+ if (!option.ignore) {
65
+ resMes = await inquirerInputs(message);
66
+ }
67
+ await changePackageJson(name, resMes, !option.ignore);
68
+
69
+ // 是否自动安装依赖
70
+ const answer = await inquirerConfirm("是否自动安装依赖?");
71
+ if (answer.confirm) {
72
+ npmInstall(name);
73
+ }
74
+
75
+ // 底部展示信息
76
+ console.log("\r\n" + chalk.cyan(figlet.textSync("welcome to NUT", {
77
+ font: "Standard",
78
+ horizontalLayout: "default",
79
+ verticalLayout: "default",
80
+ width: 80,
81
+ whitespaceBreak: true
82
+ })));
83
+
84
+ console.log(`\r\n Run ${chalk.cyan("nut <command> --help")} for detailed usage of given command.`);
85
+ }
86
+
87
+ export default initAction;
package/interactive.js ADDED
@@ -0,0 +1,29 @@
1
+ import inquirer from "inquirer";
2
+
3
+ export const inquirerConfirm = async (message) => {
4
+ const answer = await inquirer.prompt({
5
+ type: "confirm",
6
+ name: "confirm",
7
+ message
8
+ });
9
+ return answer;
10
+ }
11
+
12
+ export const inquirerChoose = async (message, choices, type = 'rawlist') => {
13
+ const answer = await inquirer.prompt({
14
+ type,
15
+ name: "choose",
16
+ message,
17
+ choices
18
+ });
19
+ return answer;
20
+ }
21
+
22
+ export const inquirerInputs = async (message) => {
23
+ const answer = await inquirer.prompt(message.map((item) => ({
24
+ type: "input",
25
+ name: item.name,
26
+ message: item.message
27
+ })));
28
+ return answer;
29
+ }
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "nut-generator-cli",
3
+ "version": "1.0.1",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1",
9
+ "release": "sh build/release.sh"
10
+ },
11
+ "bin": {
12
+ "nut": "./bin/nut.js"
13
+ },
14
+ "keywords": [],
15
+ "author": "",
16
+ "license": "ISC",
17
+ "dependencies": {
18
+ "chalk": "^5.6.2",
19
+ "commander": "^14.0.3",
20
+ "download-git-repo": "^3.0.2",
21
+ "figlet": "^1.10.0",
22
+ "fs-extra": "^11.3.4",
23
+ "inquirer": "^13.3.0",
24
+ "log-symbols": "^7.0.1",
25
+ "ora": "^9.3.0",
26
+ "shelljs": "^0.10.0"
27
+ }
28
+ }
package/utils.js ADDED
@@ -0,0 +1,61 @@
1
+ import fs from "fs-extra";
2
+ import ora from "ora";
3
+ import chalk from "chalk";
4
+ import path from "path";
5
+ import shell from "shelljs";
6
+ import logSymbols from "log-symbols";
7
+
8
+ const appDirectory = fs.realpathSync(process.cwd());
9
+ const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
10
+
11
+ // 删除文件夹
12
+ export async function removeDir(dir) {
13
+ const spinner = ora({
14
+ text: `正在删除文件夹${chalk.cyan(dir)}`,
15
+ color: "yellow"
16
+ }).start();
17
+
18
+ try {
19
+ await fs.remove(resolveApp(dir));
20
+ spinner.succeed(chalk.green(`删除文件夹 ${chalk.yellow(dir)} 成功`));
21
+ } catch(err) {
22
+ spinner.fail(chalk.red(`删除文件夹 ${chalk.yellow(dir)} 失败`));
23
+ console.log(err);
24
+ return;
25
+ }
26
+ }
27
+
28
+ export async function changePackageJson(name, info, isIgnore) {
29
+ try {
30
+ const pkg = await fs.readJson(resolveApp(`${name}/package.json`));
31
+ pkg.name = name;
32
+ if (isIgnore) {
33
+ Object.keys(info).forEach((item) => {
34
+ if (item === "keywords") {
35
+ if (info[item] && info[item].trim()) {
36
+ pkg[item] = info[item].split(",");
37
+ } else {
38
+ pkg[item] = [];
39
+ }
40
+ } else {
41
+ pkg[item] = info[item];
42
+ }
43
+ });
44
+ }
45
+ await fs.writeJson(resolveApp(`${name}/package.json`), pkg, { spaces: 2 });
46
+ } catch (err) {
47
+ console.log(logSymbols.warning, chalk.yellow(`自定义修改信息失败!可以去 ${name}/package.json 手动修改`));
48
+ console.log(err);
49
+ }
50
+ }
51
+
52
+ export function npmInstall(dir) {
53
+ const spinner = ora("正在安装依赖......").start();
54
+ if (shell.exec(`cd ${shell.pwd()}/${dir} && npm install --force -d`).code !== 0) {
55
+ console.log(
56
+ logSymbols.warning,
57
+ chalk.yellow(`自定义修改信息失败!可以去 ${name}/package.json 手动修改`)
58
+ );
59
+ }
60
+ spinner.succeed(chalk.green("~~~依赖安装成功~~~"));
61
+ }