@cyber-tools/create-cyber-project 7.7.0 → 9.0.0
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/.bin/index.js +2 -1
- package/commons/ApplicationConfigManager.ts +77 -0
- package/commons/IOCContainer.ts +4 -0
- package/index.ts +22 -0
- package/package.json +14 -8
- package/tsconfig.json +21 -0
- package/utils/CommandLineToast.ts +26 -0
- package/utils/CommandLineUtils.ts +120 -0
- package/configs/runtime.config.js +0 -23
- package/index.js +0 -17
- package/utils/changeJsonFile.js +0 -23
- package/utils/downloadTemplate.js +0 -18
- package/utils/inputPackageName.js +0 -24
- package/utils/selectTemplate.js +0 -13
package/.bin/index.js
CHANGED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import os from "os";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { merge } from "lodash";
|
|
4
|
+
import pathExists from "path-exists";
|
|
5
|
+
import { readFile } from "jsonfile";
|
|
6
|
+
import { injectable } from "inversify";
|
|
7
|
+
|
|
8
|
+
import { IOCContainer } from "@/commons/IOCContainer";
|
|
9
|
+
|
|
10
|
+
@injectable()
|
|
11
|
+
export class ApplicationConfigManager {
|
|
12
|
+
|
|
13
|
+
/** 应用层内置的默认配置 **/
|
|
14
|
+
private defaultConfig: any = {
|
|
15
|
+
projects: [{
|
|
16
|
+
name: "基本的typescript项目",
|
|
17
|
+
value: {
|
|
18
|
+
remote: "https://github.com/cyber-scaffold/typescript-bootstrap-project"
|
|
19
|
+
}
|
|
20
|
+
}, {
|
|
21
|
+
name: "基于MVC和控制反转的全栈项目",
|
|
22
|
+
value: {
|
|
23
|
+
remote: "https://github.com/cyber-scaffold/mvc-fullstack-scaffold"
|
|
24
|
+
}
|
|
25
|
+
}, {
|
|
26
|
+
name: "基于typescript和express的纯后端项目",
|
|
27
|
+
value: {
|
|
28
|
+
remote: "https://github.com/cyber-scaffold/pure-typescript-server-project"
|
|
29
|
+
}
|
|
30
|
+
}, {
|
|
31
|
+
name: "基于typescript和express的没有ssr的spa全栈项目",
|
|
32
|
+
value: {
|
|
33
|
+
remote: "https://github.com/cyber-scaffold/server-spa-client-project"
|
|
34
|
+
}
|
|
35
|
+
}, {
|
|
36
|
+
name: "基于typescript的electron项目",
|
|
37
|
+
value: {
|
|
38
|
+
remote: "https://github.com/cyber-scaffold/omni-electron-project"
|
|
39
|
+
}
|
|
40
|
+
}]
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** 操作系统层的配置 **/
|
|
44
|
+
private systemConfig: any = {};
|
|
45
|
+
|
|
46
|
+
/** $HOME目录下的配置 **/
|
|
47
|
+
private custmerConfig: any = {};
|
|
48
|
+
|
|
49
|
+
/** 声明在操作系统层的配置文件路径 **/
|
|
50
|
+
get systemConfigPath() {
|
|
51
|
+
return path.join("/etc/", "/redis-broadcast-discover/", "./config.json");
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/** 声明在$HOME目录下的配置文件路径 **/
|
|
55
|
+
get custmerConfigPath() {
|
|
56
|
+
return path.join(os.homedir(), "/.redis-broadcast-discover/", "./config.json");
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/** 初始化并加载配置到运行时 **/
|
|
60
|
+
public async initialize() {
|
|
61
|
+
if (await pathExists(this.systemConfigPath)) {
|
|
62
|
+
this.systemConfig = await readFile(this.systemConfigPath);
|
|
63
|
+
};
|
|
64
|
+
if (await pathExists(this.custmerConfigPath)) {
|
|
65
|
+
this.custmerConfig = await readFile(this.custmerConfigPath);
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/** 获取最终组合之后的运行时配置 **/
|
|
70
|
+
public getRuntimeConfig() {
|
|
71
|
+
const composeConfig = merge(this.defaultConfig, this.systemConfig, this.custmerConfig);
|
|
72
|
+
return composeConfig;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
IOCContainer.bind(ApplicationConfigManager).toSelf().inSingletonScope();
|
package/index.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { IOCContainer } from "@/commons/IOCContainer";
|
|
2
|
+
import { CommandLineUtils } from "@/utils/CommandLineUtils";
|
|
3
|
+
import { ApplicationConfigManager } from "@/commons/ApplicationConfigManager";
|
|
4
|
+
|
|
5
|
+
//@ts-ignore
|
|
6
|
+
setImmediate(async () => {
|
|
7
|
+
try {
|
|
8
|
+
/** 初始化配置文件 **/
|
|
9
|
+
const $ApplicationConfigManager = IOCContainer.get(ApplicationConfigManager);
|
|
10
|
+
await $ApplicationConfigManager.initialize();
|
|
11
|
+
/** 选择远程摸板 **/
|
|
12
|
+
const $CommandLineUtils = IOCContainer.get(CommandLineUtils);
|
|
13
|
+
const { remote, devDependencies } = await $CommandLineUtils.selectTemplate();
|
|
14
|
+
/** 输入项目名称 **/
|
|
15
|
+
const packageName = await $CommandLineUtils.inputPackageName();
|
|
16
|
+
/** 拉取并创建项目 **/
|
|
17
|
+
await $CommandLineUtils.downloadTemplate({ folderName: packageName, remote });
|
|
18
|
+
await $CommandLineUtils.changeJsonFile({ folderName: packageName, projectName: packageName, devDependencies });
|
|
19
|
+
} catch (error) {
|
|
20
|
+
throw error;
|
|
21
|
+
};
|
|
22
|
+
});
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyber-tools/create-cyber-project",
|
|
3
|
-
"version": "
|
|
4
|
-
"main": "index.js",
|
|
3
|
+
"version": "9.0.0",
|
|
4
|
+
"main": "./.bin/index.js",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"test": "echo
|
|
6
|
+
"test": "echo test"
|
|
7
7
|
},
|
|
8
8
|
"publishConfig": {
|
|
9
9
|
"access": "public"
|
|
10
10
|
},
|
|
11
|
+
"bin": "./.bin/index.js",
|
|
11
12
|
"keywords": [
|
|
12
13
|
"cli",
|
|
13
14
|
"cyber",
|
|
@@ -19,16 +20,21 @@
|
|
|
19
20
|
"license": "ISC",
|
|
20
21
|
"description": "用于创建cyber系列项目的命令行工具",
|
|
21
22
|
"dependencies": {
|
|
22
|
-
"
|
|
23
|
+
"ora": "^5.1.0",
|
|
23
24
|
"colors": "1.4.0",
|
|
25
|
+
"path-exists": "^4.0.0",
|
|
26
|
+
"cli-spinners": "^2.4.0",
|
|
24
27
|
"download-git-repo": "^3.0.2",
|
|
25
|
-
"es6-promisify": "^6.1.1",
|
|
26
28
|
"inquirer": "^7.3.3",
|
|
29
|
+
"inversify": "^6.0.2",
|
|
27
30
|
"jsonfile": "^6.0.1",
|
|
28
|
-
"
|
|
31
|
+
"lodash": "^4.17.23",
|
|
29
32
|
"prompt": "1.2.2",
|
|
33
|
+
"reflect-metadata": "^0.2.2",
|
|
34
|
+
"esbuild-register": "^3.6.0",
|
|
30
35
|
"winston": "3.6.0"
|
|
31
36
|
},
|
|
32
|
-
"
|
|
33
|
-
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"esbuild": "^0.27.4"
|
|
39
|
+
}
|
|
34
40
|
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"emitDecoratorMetadata": true,
|
|
4
|
+
"experimentalDecorators": true,
|
|
5
|
+
"target": "es2016",
|
|
6
|
+
"module": "commonjs",
|
|
7
|
+
"baseUrl": "./",
|
|
8
|
+
"moduleResolution": "node",
|
|
9
|
+
"resolveJsonModule": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"strict": false,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"sourceMap": true,
|
|
15
|
+
"paths": {
|
|
16
|
+
"@/*": [
|
|
17
|
+
"./*"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import ora from "ora";
|
|
2
|
+
import { dots } from "cli-spinners";
|
|
3
|
+
import { injectable, inject } from "inversify";
|
|
4
|
+
import { IOCContainer } from "@/commons/IOCContainer";
|
|
5
|
+
|
|
6
|
+
@injectable()
|
|
7
|
+
export class CommandLineToast {
|
|
8
|
+
|
|
9
|
+
public toast = ora(dots);
|
|
10
|
+
|
|
11
|
+
public start(...params: any) {
|
|
12
|
+
this.toast.start(...arguments);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
public succeed(params: any) {
|
|
16
|
+
this.toast.succeed(...arguments);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
public fail(params: any) {
|
|
20
|
+
this.toast.fail(...arguments);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
IOCContainer.bind(CommandLineToast).toSelf().inRequestScope();
|
|
26
|
+
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import prompt from "prompt";
|
|
3
|
+
import colors from "colors";
|
|
4
|
+
import npmName from "npm-name";
|
|
5
|
+
import inquirer from "inquirer";
|
|
6
|
+
import { promisify } from "util";
|
|
7
|
+
import download from "download-git-repo";
|
|
8
|
+
import { readFile, writeFile } from "jsonfile";
|
|
9
|
+
import { injectable, inject } from "inversify";
|
|
10
|
+
import validate from "validate-npm-package-name";
|
|
11
|
+
|
|
12
|
+
import { IOCContainer } from "@/commons/IOCContainer";
|
|
13
|
+
import { CommandLineToast } from "@/utils/CommandLineToast";
|
|
14
|
+
import { ApplicationConfigManager } from "@/commons/ApplicationConfigManager";
|
|
15
|
+
|
|
16
|
+
@injectable()
|
|
17
|
+
export class CommandLineUtils {
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
@inject(CommandLineToast) private readonly $CommandLineToast: CommandLineToast,
|
|
21
|
+
@inject(ApplicationConfigManager) private readonly $ApplicationConfigManager: ApplicationConfigManager
|
|
22
|
+
) { };
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 选择远程摸板
|
|
26
|
+
* **/
|
|
27
|
+
public async selectTemplate() {
|
|
28
|
+
const { projects } = await this.$ApplicationConfigManager.getRuntimeConfig();
|
|
29
|
+
const { template } = await inquirer.prompt({
|
|
30
|
+
type: "list",
|
|
31
|
+
name: "template",
|
|
32
|
+
defaultValue: projects[0]["name"],
|
|
33
|
+
message: "选择拉取的项目脚手架:",
|
|
34
|
+
choices: projects
|
|
35
|
+
});
|
|
36
|
+
return template;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 输入包的名称@packageName
|
|
41
|
+
* **/
|
|
42
|
+
public async inputPackageName() {
|
|
43
|
+
try {
|
|
44
|
+
prompt.message = undefined;
|
|
45
|
+
prompt.delimiter = ":";
|
|
46
|
+
prompt.start();
|
|
47
|
+
const { packageName } = await promisify(prompt.get)([{
|
|
48
|
+
name: "packageName",
|
|
49
|
+
required: true,
|
|
50
|
+
message: colors.red("项目名称必须填写!"),
|
|
51
|
+
description: colors.white("请输入项目名称")
|
|
52
|
+
}]);
|
|
53
|
+
return packageName;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error.message === "canceled") {
|
|
56
|
+
process.exit(0);
|
|
57
|
+
};
|
|
58
|
+
throw error;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 检查包明是否已经在npm注册
|
|
64
|
+
* **/
|
|
65
|
+
public async caniUseName(name: string) {
|
|
66
|
+
try {
|
|
67
|
+
this.$CommandLineToast.start(["正在查询包名(", name, ")是否可用", "... ..."].join(""));
|
|
68
|
+
const { validForNewPackages, validForOldPackages } = await validate(name);
|
|
69
|
+
const isValidate = (validForNewPackages && validForOldPackages);
|
|
70
|
+
const isAvailable = await npmName(name);
|
|
71
|
+
if (isValidate && isAvailable) {
|
|
72
|
+
this.$CommandLineToast.toast.succeed(["包名(", name, ")可用!"].join(""));
|
|
73
|
+
return true;
|
|
74
|
+
};
|
|
75
|
+
this.$CommandLineToast.toast.fail(["包名(", name, ")不可用!"].join(""));
|
|
76
|
+
return false;
|
|
77
|
+
} catch (error) {
|
|
78
|
+
throw error;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 下载远程仓库中的代码摸板
|
|
84
|
+
* **/
|
|
85
|
+
public async downloadTemplate({ remote, folderName }) {
|
|
86
|
+
try {
|
|
87
|
+
const downloadTemplate = `direct:${remote.replace(/\.git$/ig, "")}.git`;
|
|
88
|
+
this.$CommandLineToast.start("正在拉取项目文件...");
|
|
89
|
+
const projectPath = path.join(process.cwd(), folderName);
|
|
90
|
+
await promisify(download)(downloadTemplate, projectPath, { clone: true });
|
|
91
|
+
this.$CommandLineToast.succeed("拉取成功!");
|
|
92
|
+
} catch (error) {
|
|
93
|
+
this.$CommandLineToast.fail("拉取失败!");
|
|
94
|
+
throw error;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 修改package.json中的相关内容
|
|
100
|
+
* **/
|
|
101
|
+
public async changeJsonFile({ folderName, projectName, devDependencies }) {
|
|
102
|
+
try {
|
|
103
|
+
this.$CommandLineToast.toast.start("修改package.json");
|
|
104
|
+
const jsonFilePath = path.resolve(process.cwd(), folderName, "./package.json");
|
|
105
|
+
const jsonObject = await promisify(readFile)(jsonFilePath);
|
|
106
|
+
const rewriteJsonObject = Object.assign({}, jsonObject, {
|
|
107
|
+
name: projectName,
|
|
108
|
+
devDependencies: Object.assign({}, jsonObject.devDependencies, devDependencies)
|
|
109
|
+
});
|
|
110
|
+
await promisify(writeFile)(jsonFilePath, rewriteJsonObject, { spaces: 2, EOL: '\r\n' });
|
|
111
|
+
this.$CommandLineToast.succeed("package.json修改成功!");
|
|
112
|
+
} catch (error) {
|
|
113
|
+
this.$CommandLineToast.fail("package.json修改失败!");
|
|
114
|
+
throw error;
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
IOCContainer.bind(CommandLineUtils).toSelf().inRequestScope();
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
module.exports = [{
|
|
4
|
-
name: "基本的typescript项目",
|
|
5
|
-
value: {
|
|
6
|
-
remote: "https://github.com/cyber-scaffold/typescript-bootstrap-project"
|
|
7
|
-
}
|
|
8
|
-
}, {
|
|
9
|
-
name: "基于typescript和express的纯后端项目",
|
|
10
|
-
value: {
|
|
11
|
-
remote: "https://github.com/cyber-scaffold/pure-typescript-server-project"
|
|
12
|
-
}
|
|
13
|
-
}, {
|
|
14
|
-
name: "基于typescript和express的没有ssr的spa全栈项目",
|
|
15
|
-
value: {
|
|
16
|
-
remote: "https://github.com/cyber-scaffold/server-spa-client-project"
|
|
17
|
-
}
|
|
18
|
-
}, {
|
|
19
|
-
name: "基于typescript的electron项目",
|
|
20
|
-
value: {
|
|
21
|
-
remote: "https://github.com/cyber-scaffold/omni-electron-project"
|
|
22
|
-
}
|
|
23
|
-
}];
|
package/index.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
require("@cyber-tools/cli-utils/initial");
|
|
2
|
-
require("module-alias").addAlias("@", __dirname);
|
|
3
|
-
const selectTemplate = require("@/utils/selectTemplate");
|
|
4
|
-
const inputPackageName = require("@/utils/inputPackageName");
|
|
5
|
-
const downloadTemplate = require("@/utils/downloadTemplate");
|
|
6
|
-
const changeJsonFile = require("@/utils/changeJsonFile");
|
|
7
|
-
|
|
8
|
-
(async () => {
|
|
9
|
-
try {
|
|
10
|
-
const { remote, devDependencies } = await selectTemplate();
|
|
11
|
-
const packageName = await inputPackageName();
|
|
12
|
-
await downloadTemplate({ folderName: packageName, remote });
|
|
13
|
-
await changeJsonFile({ folderName: packageName, projectName: packageName, devDependencies });
|
|
14
|
-
} catch (error) {
|
|
15
|
-
throw error;
|
|
16
|
-
}
|
|
17
|
-
})();
|
package/utils/changeJsonFile.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const ora = require("ora");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const { promisify } = require("es6-promisify");
|
|
4
|
-
const { readFile, writeFile } = require("jsonfile");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
module.exports = async ({ folderName, projectName, devDependencies }) => {
|
|
8
|
-
const toast = ora();
|
|
9
|
-
try {
|
|
10
|
-
toast.start("修改package.json");
|
|
11
|
-
const jsonFilePath = path.resolve(process.cwd(), folderName, "./package.json");
|
|
12
|
-
const jsonObject = await promisify(readFile)(jsonFilePath);
|
|
13
|
-
const rewriteJsonObject = Object.assign({}, jsonObject, {
|
|
14
|
-
name: projectName,
|
|
15
|
-
devDependencies: Object.assign({}, jsonObject.devDependencies, devDependencies)
|
|
16
|
-
});
|
|
17
|
-
await promisify(writeFile)(jsonFilePath, rewriteJsonObject, { spaces: 2, EOL: '\r\n' });
|
|
18
|
-
toast.succeed("package.json修改成功!");
|
|
19
|
-
} catch (error) {
|
|
20
|
-
toast.fail("package.json修改失败!");
|
|
21
|
-
throw error;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
const path = require("path");
|
|
2
|
-
const download = require("download-git-repo");
|
|
3
|
-
const { promisify } = require("es6-promisify");
|
|
4
|
-
|
|
5
|
-
const toast = require("@cyber-tools/cli-utils/toast");
|
|
6
|
-
|
|
7
|
-
module.exports = async ({ folderName, remote }) => {
|
|
8
|
-
try {
|
|
9
|
-
const downloadTemplate = `direct:${remote.replace(/\.git$/ig, "")}.git`;
|
|
10
|
-
toast.start("正在拉取项目文件...");
|
|
11
|
-
const projectPath = path.join(process.cwd(), folderName);
|
|
12
|
-
await promisify(download)(downloadTemplate, projectPath, { clone: true });
|
|
13
|
-
toast.succeed("拉取成功!");
|
|
14
|
-
} catch (error) {
|
|
15
|
-
toast.fail("拉取失败!");
|
|
16
|
-
throw error;
|
|
17
|
-
};
|
|
18
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const colors = require("colors");
|
|
2
|
-
const prompt = require("prompt");
|
|
3
|
-
const { promisify } = require("es6-promisify");
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
module.exports = async () => {
|
|
7
|
-
try {
|
|
8
|
-
prompt.message = undefined;
|
|
9
|
-
prompt.delimiter = ":";
|
|
10
|
-
prompt.start();
|
|
11
|
-
const { packageName } = await promisify(prompt.get)([{
|
|
12
|
-
name: "packageName",
|
|
13
|
-
required: true,
|
|
14
|
-
message: colors.red("项目名称必须填写!"),
|
|
15
|
-
description: colors.white("请输入项目名称")
|
|
16
|
-
}]);
|
|
17
|
-
return packageName;
|
|
18
|
-
} catch (error) {
|
|
19
|
-
if (error.message === "canceled") {
|
|
20
|
-
process.exit(0);
|
|
21
|
-
};
|
|
22
|
-
throw error;
|
|
23
|
-
};
|
|
24
|
-
};
|
package/utils/selectTemplate.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
const inquirer = require("inquirer");
|
|
2
|
-
const PROJECT_LIST = require("@/configs/runtime.config");
|
|
3
|
-
|
|
4
|
-
module.exports = async () => {
|
|
5
|
-
const { template } = await inquirer.prompt({
|
|
6
|
-
type: "list",
|
|
7
|
-
name: "template",
|
|
8
|
-
defaultValue: "dva-app",
|
|
9
|
-
message: "选择拉取的项目脚手架:",
|
|
10
|
-
choices: PROJECT_LIST
|
|
11
|
-
});
|
|
12
|
-
return template;
|
|
13
|
-
};
|