create-pubinfo 2.0.0 → 2.0.2
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/dist/cli.d.ts +2 -0
- package/dist/cli.js +260 -0
- package/dist/helper-D73z-FZU.js +217 -0
- package/dist/index.d.ts +113 -0
- package/dist/index.js +2 -431
- package/package.json +13 -3
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { bootstrop, readPackageJSON, run, validateInput } from "./helper-D73z-FZU.js";
|
|
3
|
+
import { checkbox, confirm, input, select } from "@inquirer/prompts";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import consola from "consola";
|
|
6
|
+
import { resolve } from "node:path";
|
|
7
|
+
import process from "node:process";
|
|
8
|
+
import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
9
|
+
import colors from "ansi-colors";
|
|
10
|
+
import { downloadTemplate } from "giget";
|
|
11
|
+
import ora from "ora";
|
|
12
|
+
import { coerce, compare } from "semver";
|
|
13
|
+
import { ofetch } from "ofetch";
|
|
14
|
+
import { rimrafSync } from "rimraf";
|
|
15
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
16
|
+
import { parseJSON, parseJSONC, stringifyJSON } from "confbox";
|
|
17
|
+
|
|
18
|
+
//#region src/v1/constant.ts
|
|
19
|
+
const REMOTE_URL = "http://106.53.74.49:20000/templates";
|
|
20
|
+
const PKG_NAME = "monorepo-project-template";
|
|
21
|
+
const VERSION_FILE = "version.json";
|
|
22
|
+
const SETTING_FILE_PATH = "src/settings.default.ts";
|
|
23
|
+
const OPENAPI_FILE_PATH = "openapi.config.ts";
|
|
24
|
+
const APPS_DIR = "apps";
|
|
25
|
+
const APPS = [{
|
|
26
|
+
name: "用户权限系统(rbac)",
|
|
27
|
+
value: "rbac"
|
|
28
|
+
}];
|
|
29
|
+
const METADATA_DIR = "configs/metadata";
|
|
30
|
+
const META_FILENAME = "pubinfo.json";
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/v1/download.ts
|
|
34
|
+
const pubinfo = async (input$1, { auth }) => {
|
|
35
|
+
const semver = coerce(input$1);
|
|
36
|
+
return {
|
|
37
|
+
name: "pubinfo",
|
|
38
|
+
version: input$1,
|
|
39
|
+
headers: { Authorization: `token ${auth}` },
|
|
40
|
+
tar: `${REMOTE_URL}/${PKG_NAME}-${semver?.version}.tar.gz`
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
async function download(options) {
|
|
44
|
+
const finish = loading();
|
|
45
|
+
try {
|
|
46
|
+
await downloadTemplate(`pubinfo:${PKG_NAME}-${options.version}`, {
|
|
47
|
+
providers: { pubinfo },
|
|
48
|
+
force: true,
|
|
49
|
+
forceClean: true,
|
|
50
|
+
dir: options.dir
|
|
51
|
+
});
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (error.message.includes(REMOTE_URL)) error.message = error.message.replace(REMOTE_URL, "[REMOTE_URL]");
|
|
54
|
+
consola.error(`下载失败: ${error.message}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
} finally {
|
|
57
|
+
finish();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function loading() {
|
|
61
|
+
const startTime = Date.now();
|
|
62
|
+
const spinner = ora({
|
|
63
|
+
text: "下载中...",
|
|
64
|
+
color: "green"
|
|
65
|
+
});
|
|
66
|
+
spinner.start();
|
|
67
|
+
return () => {
|
|
68
|
+
const { green, yellow } = colors;
|
|
69
|
+
spinner.stop();
|
|
70
|
+
consola.success(`${green("下载完成, 用时")} ${yellow(`${Date.now() - startTime}`)} ${green("ms.")}`);
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/v1/fetch.ts
|
|
76
|
+
async function fetchVersion() {
|
|
77
|
+
const versions = await ofetch(`${REMOTE_URL}/${VERSION_FILE}`);
|
|
78
|
+
versions.sort((v1, v2) => -compare(v1, v2));
|
|
79
|
+
return {
|
|
80
|
+
latest: versions[0],
|
|
81
|
+
list: versions
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
async function fetchData() {
|
|
85
|
+
const spinner = ora({
|
|
86
|
+
text: "检测网络连接...",
|
|
87
|
+
color: "blue"
|
|
88
|
+
});
|
|
89
|
+
spinner.start();
|
|
90
|
+
try {
|
|
91
|
+
return { version: await fetchVersion() };
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (error.message.includes(REMOTE_URL)) error.message = error.message.replace(REMOTE_URL, "[REMOTE_URL]");
|
|
94
|
+
consola.error(`网络连接异常: ${error.message}`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
} finally {
|
|
97
|
+
spinner.stop();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/v1/utils.ts
|
|
103
|
+
function assignValues(target, source) {
|
|
104
|
+
for (const [key, value] of Object.entries(source)) target[key] = value;
|
|
105
|
+
}
|
|
106
|
+
async function readJSON(path) {
|
|
107
|
+
const blob = await readFile(path, "utf-8");
|
|
108
|
+
let parsed;
|
|
109
|
+
try {
|
|
110
|
+
parsed = parseJSON(blob);
|
|
111
|
+
} catch {
|
|
112
|
+
parsed = parseJSONC(blob);
|
|
113
|
+
}
|
|
114
|
+
return parsed;
|
|
115
|
+
}
|
|
116
|
+
async function writeJSON(path, json) {
|
|
117
|
+
await writeFile(path, stringifyJSON(json));
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 重写文件内容
|
|
121
|
+
*/
|
|
122
|
+
function rewriteFile(path, fn) {
|
|
123
|
+
if (!existsSync(path)) {
|
|
124
|
+
consola.error(`RewriteFile fail: ${path} does not exist`);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const content = readFileSync(path, { encoding: "utf-8" });
|
|
129
|
+
writeFileSync(path, fn(content));
|
|
130
|
+
} catch (error) {
|
|
131
|
+
consola.error(`RewriteFile fail: ${error}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
//#endregion
|
|
136
|
+
//#region src/v1/rewrite.ts
|
|
137
|
+
async function rewrite(options) {
|
|
138
|
+
const { dir } = options;
|
|
139
|
+
const root = process.cwd();
|
|
140
|
+
const projectDir = resolve(root, dir);
|
|
141
|
+
writeMetaJSON(resolve(projectDir, METADATA_DIR), options);
|
|
142
|
+
writeApps(resolve(projectDir, APPS_DIR), options);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* 写入项目整体配置
|
|
146
|
+
*/
|
|
147
|
+
async function writeMetaJSON(metaDir, options) {
|
|
148
|
+
const { key, version, apps, openapi } = options;
|
|
149
|
+
const path = resolve(metaDir, META_FILENAME);
|
|
150
|
+
try {
|
|
151
|
+
const json = await readJSON(path);
|
|
152
|
+
assignValues(json, {
|
|
153
|
+
key,
|
|
154
|
+
version,
|
|
155
|
+
apps,
|
|
156
|
+
openapi
|
|
157
|
+
});
|
|
158
|
+
await writeJSON(path, json);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
consola.error(`初始化 metadata 失败: ${error}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 处理目录 `/apps` 下的各个应用
|
|
165
|
+
*/
|
|
166
|
+
function writeApps(appsDir, options) {
|
|
167
|
+
const { key, apps = [], openapi } = options;
|
|
168
|
+
if (!existsSync(appsDir)) {
|
|
169
|
+
consola.error(`初始化 apps 失败: ${appsDir} 不存在`);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
readdirSync(appsDir).forEach((app) => {
|
|
174
|
+
const appPath = resolve(appsDir, app);
|
|
175
|
+
const settingPath = resolve(appPath, SETTING_FILE_PATH);
|
|
176
|
+
const openapiPath = resolve(appPath, OPENAPI_FILE_PATH);
|
|
177
|
+
if (!apps.includes(app)) {
|
|
178
|
+
rimrafSync(appPath);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
rewriteFile(settingPath, (content) => {
|
|
182
|
+
return content.replace(/storagePrefix:\s*'([^']*)'/g, `storagePrefix: '${key}'`);
|
|
183
|
+
});
|
|
184
|
+
rewriteFile(openapiPath, (content) => {
|
|
185
|
+
return content.replace(/enabled:[^,]+,/g, `enabled: ${openapi},`);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
} catch (error) {
|
|
189
|
+
consola.error(`初始化 apps 失败: ${error}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/v1/index.ts
|
|
195
|
+
async function runV1() {
|
|
196
|
+
const { version } = await fetchData();
|
|
197
|
+
const answer = {};
|
|
198
|
+
answer.dir = await input({
|
|
199
|
+
message: "目录名称(dir)",
|
|
200
|
+
default: "my-app",
|
|
201
|
+
validate: validateInput
|
|
202
|
+
});
|
|
203
|
+
answer.key = await input({
|
|
204
|
+
message: "项目标识(key)",
|
|
205
|
+
default: answer.dir,
|
|
206
|
+
validate: validateInput
|
|
207
|
+
});
|
|
208
|
+
if (existsSync(answer.dir)) {
|
|
209
|
+
if (!await confirm({ message: `目录 ${colors.cyan(answer.dir)} 已存在,是否覆盖?` })) throw Error;
|
|
210
|
+
}
|
|
211
|
+
answer.openapi = await confirm({
|
|
212
|
+
message: "运行时自动生成接口对接文件,若关闭可通过指令生成(openapi)",
|
|
213
|
+
default: false
|
|
214
|
+
});
|
|
215
|
+
const optionsV1 = JSON.parse(JSON.stringify(answer));
|
|
216
|
+
optionsV1.version = await select({
|
|
217
|
+
message: "框架版本号(version)",
|
|
218
|
+
default: version.latest,
|
|
219
|
+
choices: version.list
|
|
220
|
+
});
|
|
221
|
+
optionsV1.apps = await checkbox({
|
|
222
|
+
message: "选择应用模块(apps)",
|
|
223
|
+
choices: APPS,
|
|
224
|
+
validate: (input$1) => {
|
|
225
|
+
if (input$1.length === 0) return "请至少选择一个应用";
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
await download(optionsV1);
|
|
230
|
+
await rewrite(optionsV1);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region src/cli.ts
|
|
235
|
+
async function main() {
|
|
236
|
+
const program = new Command();
|
|
237
|
+
const pkg = readPackageJSON();
|
|
238
|
+
program.name(pkg.name).description(pkg.description).version(pkg.version);
|
|
239
|
+
program.description("初始化框架").action(async () => {
|
|
240
|
+
bootstrop();
|
|
241
|
+
try {
|
|
242
|
+
if (await select({
|
|
243
|
+
message: "使用 v1/v2 版本?",
|
|
244
|
+
default: "v2",
|
|
245
|
+
choices: ["v1", "v2"]
|
|
246
|
+
}) === "v1") {
|
|
247
|
+
await runV1();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
await run(pkg.version);
|
|
251
|
+
} catch (error) {
|
|
252
|
+
consola.error(error);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
program.parse();
|
|
256
|
+
}
|
|
257
|
+
main();
|
|
258
|
+
|
|
259
|
+
//#endregion
|
|
260
|
+
export { };
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { confirm, input, select } from "@inquirer/prompts";
|
|
2
|
+
import consola from "consola";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import process, { cwd } from "node:process";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { copy } from "fs-extra";
|
|
7
|
+
import fs, { existsSync, renameSync } from "node:fs";
|
|
8
|
+
import colors from "ansi-colors";
|
|
9
|
+
import nodePlop from "node-plop";
|
|
10
|
+
import fonts from "cfonts";
|
|
11
|
+
|
|
12
|
+
//#region src/core/copy.ts
|
|
13
|
+
const __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
async function copyTemplate(options) {
|
|
15
|
+
const { templateDir, targetDir, templateName } = {
|
|
16
|
+
templateDir: resolve(__dirname$1, "../templates"),
|
|
17
|
+
targetDir: cwd(),
|
|
18
|
+
...options
|
|
19
|
+
};
|
|
20
|
+
await copy(resolve(templateDir, templateName), targetDir);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/core/generate.ts
|
|
25
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
async function generate(options) {
|
|
27
|
+
const root = cwd();
|
|
28
|
+
const plop = await nodePlop();
|
|
29
|
+
const { templateName, templateDir, targetDir } = {
|
|
30
|
+
templateDir: resolve(__dirname, "../templates"),
|
|
31
|
+
targetDir: options.dir ? resolve(root, options.dir) : void 0,
|
|
32
|
+
...options
|
|
33
|
+
};
|
|
34
|
+
plop.setGenerator("generate", { actions: () => {
|
|
35
|
+
return [{
|
|
36
|
+
type: "addMany",
|
|
37
|
+
destination: targetDir,
|
|
38
|
+
base: resolve(templateDir, templateName),
|
|
39
|
+
templateFiles: resolve(templateDir, templateName, "**/*.hbs"),
|
|
40
|
+
globOptions: { dot: true }
|
|
41
|
+
}, async function copyRawFiles() {
|
|
42
|
+
const baseDir = resolve(templateDir, templateName);
|
|
43
|
+
async function walk(dir) {
|
|
44
|
+
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
45
|
+
for (const e of entries) {
|
|
46
|
+
const srcPath = resolve(dir, e.name);
|
|
47
|
+
const rel = srcPath.replace(`${baseDir}/`, "");
|
|
48
|
+
if (e.isDirectory()) {
|
|
49
|
+
await walk(srcPath);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (e.name.endsWith(".hbs")) continue;
|
|
53
|
+
const targetPath = resolve(targetDir, rel);
|
|
54
|
+
await fs.promises.mkdir(resolve(targetPath, ".."), { recursive: true });
|
|
55
|
+
await fs.promises.copyFile(srcPath, targetPath);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
await walk(baseDir);
|
|
59
|
+
return `Copied raw files from ${templateName}`;
|
|
60
|
+
}];
|
|
61
|
+
} });
|
|
62
|
+
await plop.getGenerator("generate").runActions(options);
|
|
63
|
+
for (const [oldName, newName] of Object.entries({
|
|
64
|
+
_gitignore: ".gitignore",
|
|
65
|
+
_npmrc: ".npmrc"
|
|
66
|
+
})) {
|
|
67
|
+
const oldPath = resolve(targetDir, oldName);
|
|
68
|
+
const newPath = resolve(targetDir, newName || oldName);
|
|
69
|
+
if (existsSync(oldPath)) renameSync(oldPath, newPath);
|
|
70
|
+
}
|
|
71
|
+
consola.success(`${colors.green("项目模板初始化完成.")}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/utils.ts
|
|
76
|
+
function validateInput(input$1) {
|
|
77
|
+
if (/[<>:"/\\|?*\s]/.test(input$1)) return "错误提示: 该值不能包含空格或者非法字符 (例如, <>:\"/\\|?*).";
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/core/interaction.ts
|
|
83
|
+
async function interaction() {
|
|
84
|
+
try {
|
|
85
|
+
const answer = {};
|
|
86
|
+
answer.dir = await input({
|
|
87
|
+
message: "目录名称(dir)",
|
|
88
|
+
default: "my-app",
|
|
89
|
+
validate: validateInput
|
|
90
|
+
});
|
|
91
|
+
answer.key = await input({
|
|
92
|
+
message: "项目标识(key)",
|
|
93
|
+
default: answer.dir,
|
|
94
|
+
validate: validateInput
|
|
95
|
+
});
|
|
96
|
+
if (existsSync(answer.dir)) {
|
|
97
|
+
if (!await confirm({ message: `目录 ${colors.cyan(answer.dir)} 已存在,是否覆盖?` })) throw Error;
|
|
98
|
+
}
|
|
99
|
+
answer.templateName = await select({
|
|
100
|
+
message: "选择模板类型",
|
|
101
|
+
default: "pubinfo-app",
|
|
102
|
+
choices: [{
|
|
103
|
+
name: "Web应用(app)",
|
|
104
|
+
value: "pubinfo-app"
|
|
105
|
+
}, {
|
|
106
|
+
name: "模块插件(module)",
|
|
107
|
+
value: "pubinfo-module"
|
|
108
|
+
}]
|
|
109
|
+
});
|
|
110
|
+
answer.openapi = await confirm({
|
|
111
|
+
message: "运行时自动生成接口对接文件,若关闭可通过指令生成(openapi)",
|
|
112
|
+
default: false
|
|
113
|
+
});
|
|
114
|
+
return answer;
|
|
115
|
+
} catch {
|
|
116
|
+
consola.fail("操作终止");
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/core/index.ts
|
|
123
|
+
async function run(version$1) {
|
|
124
|
+
const options = await interaction();
|
|
125
|
+
generate({
|
|
126
|
+
...options,
|
|
127
|
+
version: version$1
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region package.json
|
|
133
|
+
var name = "create-pubinfo";
|
|
134
|
+
var type = "module";
|
|
135
|
+
var version = "2.0.2";
|
|
136
|
+
var description = "初始化项目框架";
|
|
137
|
+
var author = "Werheng <werheng.zhang@gmail.com>";
|
|
138
|
+
var license = "MIT";
|
|
139
|
+
var exports = { ".": {
|
|
140
|
+
"types": "./dist/index.d.ts",
|
|
141
|
+
"default": "./dist/index.js"
|
|
142
|
+
} };
|
|
143
|
+
var main = "./dist/index.js";
|
|
144
|
+
var module = "./dist/index.js";
|
|
145
|
+
var types = "./dist/index.d.ts";
|
|
146
|
+
var bin = { "pubinfo": "./dist/cli.js" };
|
|
147
|
+
var files = ["dist", "templates"];
|
|
148
|
+
var engines = { "node": "^20.19.0 || >=22.12.0" };
|
|
149
|
+
var scripts = {
|
|
150
|
+
"dev": "tsdown --watch src",
|
|
151
|
+
"build": "tsdown",
|
|
152
|
+
"cli": "node dist/cli.js",
|
|
153
|
+
"cli:clean": "rimraf ./my-app",
|
|
154
|
+
"lint": "eslint . --cache --fix"
|
|
155
|
+
};
|
|
156
|
+
var dependencies = {
|
|
157
|
+
"@inquirer/prompts": "catalog:node",
|
|
158
|
+
"ansi-colors": "catalog:node",
|
|
159
|
+
"cfonts": "catalog:node",
|
|
160
|
+
"commander": "catalog:node",
|
|
161
|
+
"confbox": "catalog:node",
|
|
162
|
+
"consola": "catalog:browser",
|
|
163
|
+
"fs-extra": "^11.3.2",
|
|
164
|
+
"giget": "catalog:node",
|
|
165
|
+
"node-plop": "catalog:node",
|
|
166
|
+
"ofetch": "catalog:http",
|
|
167
|
+
"ora": "catalog:node",
|
|
168
|
+
"rimraf": "catalog:node",
|
|
169
|
+
"semver": "catalog:node"
|
|
170
|
+
};
|
|
171
|
+
var devDependencies = { "@types/node": "catalog:ts" };
|
|
172
|
+
var package_default = {
|
|
173
|
+
name,
|
|
174
|
+
type,
|
|
175
|
+
version,
|
|
176
|
+
description,
|
|
177
|
+
author,
|
|
178
|
+
license,
|
|
179
|
+
exports,
|
|
180
|
+
main,
|
|
181
|
+
module,
|
|
182
|
+
types,
|
|
183
|
+
bin,
|
|
184
|
+
files,
|
|
185
|
+
engines,
|
|
186
|
+
scripts,
|
|
187
|
+
dependencies,
|
|
188
|
+
devDependencies
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
//#endregion
|
|
192
|
+
//#region src/helper.ts
|
|
193
|
+
function bootstrop() {
|
|
194
|
+
printLoGo("PUBINFO");
|
|
195
|
+
function printLoGo(logo) {
|
|
196
|
+
fonts.say(logo, {
|
|
197
|
+
font: "simple3d",
|
|
198
|
+
align: "left",
|
|
199
|
+
background: "transparent",
|
|
200
|
+
letterSpacing: 1,
|
|
201
|
+
lineHeight: 1,
|
|
202
|
+
space: true,
|
|
203
|
+
maxLength: 0,
|
|
204
|
+
spaceless: false,
|
|
205
|
+
gradient: ["blue", "magenta"],
|
|
206
|
+
independentGradient: false,
|
|
207
|
+
transitionGradient: false,
|
|
208
|
+
env: "node"
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function readPackageJSON() {
|
|
213
|
+
return package_default;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
//#endregion
|
|
217
|
+
export { bootstrop, copyTemplate, generate, interaction, readPackageJSON, run, validateInput };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
//#region src/interface.d.ts
|
|
2
|
+
type TemplateName = 'pubinfo-app' | 'pubinfo-module';
|
|
3
|
+
interface Options {
|
|
4
|
+
/**
|
|
5
|
+
* 目录名称
|
|
6
|
+
*/
|
|
7
|
+
dir?: string;
|
|
8
|
+
/**
|
|
9
|
+
* 项目唯一标识
|
|
10
|
+
*/
|
|
11
|
+
key: string;
|
|
12
|
+
/**
|
|
13
|
+
* 运行时自动生成接口文件
|
|
14
|
+
*/
|
|
15
|
+
openapi?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* 模板名称
|
|
18
|
+
*/
|
|
19
|
+
templateName: TemplateName;
|
|
20
|
+
}
|
|
21
|
+
interface GenerateOptions extends Options {
|
|
22
|
+
/**
|
|
23
|
+
* 版本号
|
|
24
|
+
*/
|
|
25
|
+
version: string;
|
|
26
|
+
/**
|
|
27
|
+
* 模板文件夹
|
|
28
|
+
*/
|
|
29
|
+
templateDir?: string;
|
|
30
|
+
/**
|
|
31
|
+
* 目标文件夹
|
|
32
|
+
*/
|
|
33
|
+
targetDir?: string;
|
|
34
|
+
}
|
|
35
|
+
interface CopyTemplatesOptions {
|
|
36
|
+
/**
|
|
37
|
+
* 模板名称
|
|
38
|
+
*/
|
|
39
|
+
templateName: TemplateName;
|
|
40
|
+
/**
|
|
41
|
+
* 模板文件夹
|
|
42
|
+
*/
|
|
43
|
+
templateDir?: string;
|
|
44
|
+
/**
|
|
45
|
+
* 目标文件夹
|
|
46
|
+
*/
|
|
47
|
+
targetDir?: string;
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/core/copy.d.ts
|
|
51
|
+
declare function copyTemplate(options: CopyTemplatesOptions): Promise<void>;
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/core/generate.d.ts
|
|
54
|
+
declare function generate(options: GenerateOptions): Promise<void>;
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/core/interaction.d.ts
|
|
57
|
+
declare function interaction(): Promise<GenerateOptions>;
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/core/index.d.ts
|
|
60
|
+
declare function run(version: string): Promise<void>;
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/helper.d.ts
|
|
63
|
+
declare function readPackageJSON(): {
|
|
64
|
+
name: string;
|
|
65
|
+
type: string;
|
|
66
|
+
version: string;
|
|
67
|
+
description: string;
|
|
68
|
+
author: string;
|
|
69
|
+
license: string;
|
|
70
|
+
exports: {
|
|
71
|
+
".": {
|
|
72
|
+
types: string;
|
|
73
|
+
default: string;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
main: string;
|
|
77
|
+
module: string;
|
|
78
|
+
types: string;
|
|
79
|
+
bin: {
|
|
80
|
+
pubinfo: string;
|
|
81
|
+
};
|
|
82
|
+
files: string[];
|
|
83
|
+
engines: {
|
|
84
|
+
node: string;
|
|
85
|
+
};
|
|
86
|
+
scripts: {
|
|
87
|
+
dev: string;
|
|
88
|
+
build: string;
|
|
89
|
+
cli: string;
|
|
90
|
+
"cli:clean": string;
|
|
91
|
+
lint: string;
|
|
92
|
+
};
|
|
93
|
+
dependencies: {
|
|
94
|
+
"@inquirer/prompts": string;
|
|
95
|
+
"ansi-colors": string;
|
|
96
|
+
cfonts: string;
|
|
97
|
+
commander: string;
|
|
98
|
+
confbox: string;
|
|
99
|
+
consola: string;
|
|
100
|
+
"fs-extra": string;
|
|
101
|
+
giget: string;
|
|
102
|
+
"node-plop": string;
|
|
103
|
+
ofetch: string;
|
|
104
|
+
ora: string;
|
|
105
|
+
rimraf: string;
|
|
106
|
+
semver: string;
|
|
107
|
+
};
|
|
108
|
+
devDependencies: {
|
|
109
|
+
"@types/node": string;
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
//#endregion
|
|
113
|
+
export { copyTemplate, generate, interaction, readPackageJSON, run };
|
package/dist/index.js
CHANGED
|
@@ -1,432 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
import { checkbox, confirm, input, select } from "@inquirer/prompts";
|
|
3
|
-
import { Command } from "commander";
|
|
4
|
-
import consola from "consola";
|
|
5
|
-
import fs, { existsSync, readFileSync, readdirSync, renameSync, writeFileSync } from "node:fs";
|
|
6
|
-
import { dirname, resolve } from "node:path";
|
|
7
|
-
import process, { cwd } from "node:process";
|
|
8
|
-
import { fileURLToPath } from "node:url";
|
|
9
|
-
import colors from "ansi-colors";
|
|
10
|
-
import nodePlop from "node-plop";
|
|
11
|
-
import fonts from "cfonts";
|
|
12
|
-
import { downloadTemplate } from "giget";
|
|
13
|
-
import ora from "ora";
|
|
14
|
-
import { coerce, compare } from "semver";
|
|
15
|
-
import { ofetch } from "ofetch";
|
|
16
|
-
import { rimrafSync } from "rimraf";
|
|
17
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
18
|
-
import { parseJSON, parseJSONC, stringifyJSON } from "confbox";
|
|
1
|
+
import { copyTemplate, generate, interaction, readPackageJSON, run } from "./helper-D73z-FZU.js";
|
|
19
2
|
|
|
20
|
-
|
|
21
|
-
var name = "create-pubinfo";
|
|
22
|
-
var type = "module";
|
|
23
|
-
var version = "2.0.0";
|
|
24
|
-
var description = "初始化项目框架";
|
|
25
|
-
var author = "Werheng <werheng.zhang@gmail.com>";
|
|
26
|
-
var license = "MIT";
|
|
27
|
-
var bin = { "pubinfo": "./dist/index.js" };
|
|
28
|
-
var files = ["dist", "templates"];
|
|
29
|
-
var engines = { "node": "^20.19.0 || >=22.12.0" };
|
|
30
|
-
var scripts = {
|
|
31
|
-
"dev": "tsdown --watch src",
|
|
32
|
-
"build": "tsdown",
|
|
33
|
-
"cli": "node dist/index.js",
|
|
34
|
-
"cli:clean": "rimraf ./my-app",
|
|
35
|
-
"lint": "eslint . --cache --fix"
|
|
36
|
-
};
|
|
37
|
-
var dependencies = {
|
|
38
|
-
"@inquirer/prompts": "catalog:node",
|
|
39
|
-
"ansi-colors": "catalog:node",
|
|
40
|
-
"cfonts": "catalog:node",
|
|
41
|
-
"commander": "catalog:node",
|
|
42
|
-
"confbox": "catalog:node",
|
|
43
|
-
"consola": "catalog:browser",
|
|
44
|
-
"giget": "catalog:node",
|
|
45
|
-
"node-plop": "catalog:node",
|
|
46
|
-
"ofetch": "catalog:http",
|
|
47
|
-
"ora": "catalog:node",
|
|
48
|
-
"rimraf": "catalog:node",
|
|
49
|
-
"semver": "catalog:node"
|
|
50
|
-
};
|
|
51
|
-
var devDependencies = { "@types/node": "catalog:ts" };
|
|
52
|
-
var package_default = {
|
|
53
|
-
name,
|
|
54
|
-
type,
|
|
55
|
-
version,
|
|
56
|
-
description,
|
|
57
|
-
author,
|
|
58
|
-
license,
|
|
59
|
-
bin,
|
|
60
|
-
files,
|
|
61
|
-
engines,
|
|
62
|
-
scripts,
|
|
63
|
-
dependencies,
|
|
64
|
-
devDependencies
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
//#endregion
|
|
68
|
-
//#region src/utils.ts
|
|
69
|
-
function validateInput(input$1) {
|
|
70
|
-
if (/[<>:"/\\|?*\s]/.test(input$1)) return "错误提示: 该值不能包含空格或者非法字符 (例如, <>:\"/\\|?*).";
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
//#endregion
|
|
75
|
-
//#region src/core/init.ts
|
|
76
|
-
async function init() {
|
|
77
|
-
try {
|
|
78
|
-
const answer = {};
|
|
79
|
-
answer.dir = await input({
|
|
80
|
-
message: "目录名称(dir)",
|
|
81
|
-
default: "my-app",
|
|
82
|
-
validate: validateInput
|
|
83
|
-
});
|
|
84
|
-
answer.key = await input({
|
|
85
|
-
message: "项目标识(key)",
|
|
86
|
-
default: answer.dir,
|
|
87
|
-
validate: validateInput
|
|
88
|
-
});
|
|
89
|
-
if (existsSync(answer.dir)) {
|
|
90
|
-
if (!await confirm({ message: `目录 ${colors.cyan(answer.dir)} 已存在,是否覆盖?` })) throw Error;
|
|
91
|
-
}
|
|
92
|
-
answer.templateName = await select({
|
|
93
|
-
message: "选择模板类型",
|
|
94
|
-
default: "pubinfo-app",
|
|
95
|
-
choices: [{
|
|
96
|
-
name: "Web应用(app)",
|
|
97
|
-
value: "pubinfo-app"
|
|
98
|
-
}, {
|
|
99
|
-
name: "模块插件(module)",
|
|
100
|
-
value: "pubinfo-module"
|
|
101
|
-
}]
|
|
102
|
-
});
|
|
103
|
-
answer.openapi = await confirm({
|
|
104
|
-
message: "运行时自动生成接口对接文件,若关闭可通过指令生成(openapi)",
|
|
105
|
-
default: false
|
|
106
|
-
});
|
|
107
|
-
return answer;
|
|
108
|
-
} catch {
|
|
109
|
-
consola.fail("操作终止");
|
|
110
|
-
process.exit(1);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
//#endregion
|
|
115
|
-
//#region src/core/index.ts
|
|
116
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
117
|
-
async function generate(version$1) {
|
|
118
|
-
const options = await init();
|
|
119
|
-
const root = cwd();
|
|
120
|
-
const plop = await nodePlop();
|
|
121
|
-
const templateDir = resolve(__dirname, "../templates");
|
|
122
|
-
const destDir = resolve(root, options.dir);
|
|
123
|
-
plop.setGenerator("generate", { actions: () => {
|
|
124
|
-
return [{
|
|
125
|
-
type: "addMany",
|
|
126
|
-
destination: destDir,
|
|
127
|
-
base: resolve(templateDir, options.templateName),
|
|
128
|
-
templateFiles: resolve(templateDir, options.templateName, "**/*.hbs"),
|
|
129
|
-
globOptions: { dot: true }
|
|
130
|
-
}, async function copyRawFiles() {
|
|
131
|
-
const baseDir = resolve(templateDir, options.templateName);
|
|
132
|
-
async function walk(dir) {
|
|
133
|
-
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
134
|
-
for (const e of entries) {
|
|
135
|
-
const srcPath = resolve(dir, e.name);
|
|
136
|
-
const rel = srcPath.replace(`${baseDir}/`, "");
|
|
137
|
-
if (e.isDirectory()) {
|
|
138
|
-
await walk(srcPath);
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
if (e.name.endsWith(".hbs")) continue;
|
|
142
|
-
const targetPath$1 = resolve(destDir, rel);
|
|
143
|
-
await fs.promises.mkdir(resolve(targetPath$1, ".."), { recursive: true });
|
|
144
|
-
await fs.promises.copyFile(srcPath, targetPath$1);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
await walk(baseDir);
|
|
148
|
-
return `Copied raw files from ${options.templateName}`;
|
|
149
|
-
}];
|
|
150
|
-
} });
|
|
151
|
-
await plop.getGenerator("generate").runActions({
|
|
152
|
-
...options,
|
|
153
|
-
version: version$1
|
|
154
|
-
});
|
|
155
|
-
const renameFiles = {
|
|
156
|
-
_gitignore: ".gitignore",
|
|
157
|
-
_npmrc: ".npmrc"
|
|
158
|
-
};
|
|
159
|
-
const targetPath = resolve(root, options.dir);
|
|
160
|
-
for (const [oldName, newName] of Object.entries(renameFiles)) {
|
|
161
|
-
const oldPath = resolve(targetPath, oldName);
|
|
162
|
-
const newPath = resolve(targetPath, newName || oldName);
|
|
163
|
-
if (existsSync(oldPath)) renameSync(oldPath, newPath);
|
|
164
|
-
}
|
|
165
|
-
consola.success(`${colors.green("项目模板初始化完成.")}`);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
//#endregion
|
|
169
|
-
//#region src/log.ts
|
|
170
|
-
function bootstrop() {
|
|
171
|
-
printLoGo("PUBINFO");
|
|
172
|
-
function printLoGo(logo) {
|
|
173
|
-
fonts.say(logo, {
|
|
174
|
-
font: "simple3d",
|
|
175
|
-
align: "left",
|
|
176
|
-
background: "transparent",
|
|
177
|
-
letterSpacing: 1,
|
|
178
|
-
lineHeight: 1,
|
|
179
|
-
space: true,
|
|
180
|
-
maxLength: 0,
|
|
181
|
-
spaceless: false,
|
|
182
|
-
gradient: ["blue", "magenta"],
|
|
183
|
-
independentGradient: false,
|
|
184
|
-
transitionGradient: false,
|
|
185
|
-
env: "node"
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
//#endregion
|
|
191
|
-
//#region src/v1/constant.ts
|
|
192
|
-
const REMOTE_URL = "http://106.53.74.49:20000/templates";
|
|
193
|
-
const PKG_NAME = "monorepo-project-template";
|
|
194
|
-
const VERSION_FILE = "version.json";
|
|
195
|
-
const SETTING_FILE_PATH = "src/settings.default.ts";
|
|
196
|
-
const OPENAPI_FILE_PATH = "openapi.config.ts";
|
|
197
|
-
const APPS_DIR = "apps";
|
|
198
|
-
const APPS = [{
|
|
199
|
-
name: "用户权限系统(rbac)",
|
|
200
|
-
value: "rbac"
|
|
201
|
-
}];
|
|
202
|
-
const METADATA_DIR = "configs/metadata";
|
|
203
|
-
const META_FILENAME = "pubinfo.json";
|
|
204
|
-
|
|
205
|
-
//#endregion
|
|
206
|
-
//#region src/v1/download.ts
|
|
207
|
-
const pubinfo = async (input$1, { auth }) => {
|
|
208
|
-
const semver = coerce(input$1);
|
|
209
|
-
return {
|
|
210
|
-
name: "pubinfo",
|
|
211
|
-
version: input$1,
|
|
212
|
-
headers: { Authorization: `token ${auth}` },
|
|
213
|
-
tar: `${REMOTE_URL}/${PKG_NAME}-${semver?.version}.tar.gz`
|
|
214
|
-
};
|
|
215
|
-
};
|
|
216
|
-
async function download(options) {
|
|
217
|
-
const finish = loading();
|
|
218
|
-
try {
|
|
219
|
-
await downloadTemplate(`pubinfo:${PKG_NAME}-${options.version}`, {
|
|
220
|
-
providers: { pubinfo },
|
|
221
|
-
force: true,
|
|
222
|
-
forceClean: true,
|
|
223
|
-
dir: options.dir
|
|
224
|
-
});
|
|
225
|
-
} catch (error) {
|
|
226
|
-
if (error.message.includes(REMOTE_URL)) error.message = error.message.replace(REMOTE_URL, "[REMOTE_URL]");
|
|
227
|
-
consola.error(`下载失败: ${error.message}`);
|
|
228
|
-
process.exit(1);
|
|
229
|
-
} finally {
|
|
230
|
-
finish();
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
function loading() {
|
|
234
|
-
const startTime = Date.now();
|
|
235
|
-
const spinner = ora({
|
|
236
|
-
text: "下载中...",
|
|
237
|
-
color: "green"
|
|
238
|
-
});
|
|
239
|
-
spinner.start();
|
|
240
|
-
return () => {
|
|
241
|
-
const { green, yellow } = colors;
|
|
242
|
-
spinner.stop();
|
|
243
|
-
consola.success(`${green("下载完成, 用时")} ${yellow(`${Date.now() - startTime}`)} ${green("ms.")}`);
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
//#endregion
|
|
248
|
-
//#region src/v1/fetch.ts
|
|
249
|
-
async function fetchVersion() {
|
|
250
|
-
const versions = await ofetch(`${REMOTE_URL}/${VERSION_FILE}`);
|
|
251
|
-
versions.sort((v1, v2) => -compare(v1, v2));
|
|
252
|
-
return {
|
|
253
|
-
latest: versions[0],
|
|
254
|
-
list: versions
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
async function fetchData() {
|
|
258
|
-
const spinner = ora({
|
|
259
|
-
text: "检测网络连接...",
|
|
260
|
-
color: "blue"
|
|
261
|
-
});
|
|
262
|
-
spinner.start();
|
|
263
|
-
try {
|
|
264
|
-
return { version: await fetchVersion() };
|
|
265
|
-
} catch (error) {
|
|
266
|
-
if (error.message.includes(REMOTE_URL)) error.message = error.message.replace(REMOTE_URL, "[REMOTE_URL]");
|
|
267
|
-
consola.error(`网络连接异常: ${error.message}`);
|
|
268
|
-
process.exit(1);
|
|
269
|
-
} finally {
|
|
270
|
-
spinner.stop();
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
//#endregion
|
|
275
|
-
//#region src/v1/utils.ts
|
|
276
|
-
function assignValues(target, source) {
|
|
277
|
-
for (const [key, value] of Object.entries(source)) target[key] = value;
|
|
278
|
-
}
|
|
279
|
-
async function readJSON(path) {
|
|
280
|
-
const blob = await readFile(path, "utf-8");
|
|
281
|
-
let parsed;
|
|
282
|
-
try {
|
|
283
|
-
parsed = parseJSON(blob);
|
|
284
|
-
} catch {
|
|
285
|
-
parsed = parseJSONC(blob);
|
|
286
|
-
}
|
|
287
|
-
return parsed;
|
|
288
|
-
}
|
|
289
|
-
async function writeJSON(path, json) {
|
|
290
|
-
await writeFile(path, stringifyJSON(json));
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* 重写文件内容
|
|
294
|
-
*/
|
|
295
|
-
function rewriteFile(path, fn) {
|
|
296
|
-
if (!existsSync(path)) {
|
|
297
|
-
consola.error(`RewriteFile fail: ${path} does not exist`);
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
try {
|
|
301
|
-
const content = readFileSync(path, { encoding: "utf-8" });
|
|
302
|
-
writeFileSync(path, fn(content));
|
|
303
|
-
} catch (error) {
|
|
304
|
-
consola.error(`RewriteFile fail: ${error}`);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
//#endregion
|
|
309
|
-
//#region src/v1/rewrite.ts
|
|
310
|
-
async function rewrite(options) {
|
|
311
|
-
const { dir } = options;
|
|
312
|
-
const root = process.cwd();
|
|
313
|
-
const projectDir = resolve(root, dir);
|
|
314
|
-
writeMetaJSON(resolve(projectDir, METADATA_DIR), options);
|
|
315
|
-
writeApps(resolve(projectDir, APPS_DIR), options);
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* 写入项目整体配置
|
|
319
|
-
*/
|
|
320
|
-
async function writeMetaJSON(metaDir, options) {
|
|
321
|
-
const { key, version: version$1, apps, openapi } = options;
|
|
322
|
-
const path = resolve(metaDir, META_FILENAME);
|
|
323
|
-
try {
|
|
324
|
-
const json = await readJSON(path);
|
|
325
|
-
assignValues(json, {
|
|
326
|
-
key,
|
|
327
|
-
version: version$1,
|
|
328
|
-
apps,
|
|
329
|
-
openapi
|
|
330
|
-
});
|
|
331
|
-
await writeJSON(path, json);
|
|
332
|
-
} catch (error) {
|
|
333
|
-
consola.error(`初始化 metadata 失败: ${error}`);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
* 处理目录 `/apps` 下的各个应用
|
|
338
|
-
*/
|
|
339
|
-
function writeApps(appsDir, options) {
|
|
340
|
-
const { key, apps = [], openapi } = options;
|
|
341
|
-
if (!existsSync(appsDir)) {
|
|
342
|
-
consola.error(`初始化 apps 失败: ${appsDir} 不存在`);
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
try {
|
|
346
|
-
readdirSync(appsDir).forEach((app) => {
|
|
347
|
-
const appPath = resolve(appsDir, app);
|
|
348
|
-
const settingPath = resolve(appPath, SETTING_FILE_PATH);
|
|
349
|
-
const openapiPath = resolve(appPath, OPENAPI_FILE_PATH);
|
|
350
|
-
if (!apps.includes(app)) {
|
|
351
|
-
rimrafSync(appPath);
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
rewriteFile(settingPath, (content) => {
|
|
355
|
-
return content.replace(/storagePrefix:\s*'([^']*)'/g, `storagePrefix: '${key}'`);
|
|
356
|
-
});
|
|
357
|
-
rewriteFile(openapiPath, (content) => {
|
|
358
|
-
return content.replace(/enabled:[^,]+,/g, `enabled: ${openapi},`);
|
|
359
|
-
});
|
|
360
|
-
});
|
|
361
|
-
} catch (error) {
|
|
362
|
-
consola.error(`初始化 apps 失败: ${error}`);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
//#endregion
|
|
367
|
-
//#region src/v1/index.ts
|
|
368
|
-
async function generateV1() {
|
|
369
|
-
const { version: version$1 } = await fetchData();
|
|
370
|
-
const answer = {};
|
|
371
|
-
answer.dir = await input({
|
|
372
|
-
message: "目录名称(dir)",
|
|
373
|
-
default: "my-app",
|
|
374
|
-
validate: validateInput
|
|
375
|
-
});
|
|
376
|
-
answer.key = await input({
|
|
377
|
-
message: "项目标识(key)",
|
|
378
|
-
default: answer.dir,
|
|
379
|
-
validate: validateInput
|
|
380
|
-
});
|
|
381
|
-
if (existsSync(answer.dir)) {
|
|
382
|
-
if (!await confirm({ message: `目录 ${colors.cyan(answer.dir)} 已存在,是否覆盖?` })) throw Error;
|
|
383
|
-
}
|
|
384
|
-
answer.openapi = await confirm({
|
|
385
|
-
message: "运行时自动生成接口对接文件,若关闭可通过指令生成(openapi)",
|
|
386
|
-
default: false
|
|
387
|
-
});
|
|
388
|
-
const optionsV1 = JSON.parse(JSON.stringify(answer));
|
|
389
|
-
optionsV1.version = await select({
|
|
390
|
-
message: "框架版本号(version)",
|
|
391
|
-
default: version$1.latest,
|
|
392
|
-
choices: version$1.list
|
|
393
|
-
});
|
|
394
|
-
optionsV1.apps = await checkbox({
|
|
395
|
-
message: "选择应用模块(apps)",
|
|
396
|
-
choices: APPS,
|
|
397
|
-
validate: (input$1) => {
|
|
398
|
-
if (input$1.length === 0) return "请至少选择一个应用";
|
|
399
|
-
return true;
|
|
400
|
-
}
|
|
401
|
-
});
|
|
402
|
-
await download(optionsV1);
|
|
403
|
-
await rewrite(optionsV1);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
//#endregion
|
|
407
|
-
//#region src/index.ts
|
|
408
|
-
async function main() {
|
|
409
|
-
const program = new Command();
|
|
410
|
-
program.name(package_default.name).description(package_default.description).version(package_default.version);
|
|
411
|
-
program.description("初始化框架").action(async () => {
|
|
412
|
-
bootstrop();
|
|
413
|
-
try {
|
|
414
|
-
if (await select({
|
|
415
|
-
message: "使用 v1/v2 版本?",
|
|
416
|
-
default: "v2",
|
|
417
|
-
choices: ["v1", "v2"]
|
|
418
|
-
}) === "v1") {
|
|
419
|
-
await generateV1();
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
422
|
-
await generate(package_default.version);
|
|
423
|
-
} catch (error) {
|
|
424
|
-
consola.error(error);
|
|
425
|
-
}
|
|
426
|
-
});
|
|
427
|
-
program.parse();
|
|
428
|
-
}
|
|
429
|
-
main();
|
|
430
|
-
|
|
431
|
-
//#endregion
|
|
432
|
-
export { };
|
|
3
|
+
export { copyTemplate, generate, interaction, readPackageJSON, run };
|
package/package.json
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-pubinfo",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.2",
|
|
5
5
|
"description": "初始化项目框架",
|
|
6
6
|
"author": "Werheng <werheng.zhang@gmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"module": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
8
17
|
"bin": {
|
|
9
|
-
"pubinfo": "./dist/
|
|
18
|
+
"pubinfo": "./dist/cli.js"
|
|
10
19
|
},
|
|
11
20
|
"files": [
|
|
12
21
|
"dist",
|
|
@@ -22,6 +31,7 @@
|
|
|
22
31
|
"commander": "^14.0.0",
|
|
23
32
|
"confbox": "^0.2.2",
|
|
24
33
|
"consola": "^3.4.2",
|
|
34
|
+
"fs-extra": "^11.3.2",
|
|
25
35
|
"giget": "^2.0.0",
|
|
26
36
|
"node-plop": "0.32.1",
|
|
27
37
|
"ofetch": "^1.4.1",
|
|
@@ -35,7 +45,7 @@
|
|
|
35
45
|
"scripts": {
|
|
36
46
|
"dev": "tsdown --watch src",
|
|
37
47
|
"build": "tsdown",
|
|
38
|
-
"cli": "node dist/
|
|
48
|
+
"cli": "node dist/cli.js",
|
|
39
49
|
"cli:clean": "rimraf ./my-app",
|
|
40
50
|
"lint": "eslint . --cache --fix"
|
|
41
51
|
}
|