create-pubinfo 2.2.0 → 2.2.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/README.md
CHANGED
|
@@ -1,20 +1,80 @@
|
|
|
1
1
|
# create-pubinfo
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[![Monorepo][monorepo-src]][monorepo-href]
|
|
5
|
-
![License][License-src]
|
|
3
|
+
Pubinfo 的项目脚手架,用来生成应用模板、模块模板和 monorepo 模板。
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
## 它在做什么
|
|
6
|
+
|
|
7
|
+
- 提供交互式初始化流程
|
|
8
|
+
- 支持三套本地模板:`pubinfo-app`、`pubinfo-module`、`pubinfo-monorepo`
|
|
9
|
+
- 根据勾选结果裁剪可选模块,目前内置 `rbac`
|
|
10
|
+
- 支持按模板变量渲染 `.hbs` 文件,并复制原始资源文件
|
|
11
|
+
- 初始化完成后自动尝试执行 `git init`
|
|
12
|
+
- 保留一套 `v1` 兼容流程,用远端模板包下载旧版脚手架
|
|
8
13
|
|
|
9
14
|
## 基本用法
|
|
10
15
|
|
|
11
16
|
```bash
|
|
12
|
-
|
|
17
|
+
pnpm create pubinfo
|
|
18
|
+
pnpx create-pubinfo
|
|
19
|
+
npx create-pubinfo
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
运行后会询问:
|
|
23
|
+
|
|
24
|
+
- 目录名称 `dir`
|
|
25
|
+
- 项目标识 `key`
|
|
26
|
+
- 模板类型
|
|
27
|
+
- 是否启用 `rbac`
|
|
28
|
+
- 是否启用 `openapi`
|
|
29
|
+
- 使用 `v1` 还是 `v2`
|
|
30
|
+
|
|
31
|
+
## 非交互式用法
|
|
32
|
+
|
|
33
|
+
如果需要给 agent、脚本或 CI 调用,可以直接通过命令行参数生成项目:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
create-pubinfo --dir my-app --key my-app --template pubinfo-app --modules rbac --openapi false --yes
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
参数说明:
|
|
40
|
+
|
|
41
|
+
- `--dir`: 目标目录名称
|
|
42
|
+
- `--key`: 项目标识
|
|
43
|
+
- `--template`: 模板类型,支持 `pubinfo-app`、`pubinfo-module`、`pubinfo-monorepo`
|
|
44
|
+
- `--modules`: 模块列表,多个模块用逗号分隔;目前支持 `rbac`,不启用模块可传 `none`
|
|
45
|
+
- `--openapi`: 是否启用运行时接口生成,支持 `true` 或 `false`
|
|
46
|
+
- `--yes`: 跳过确认;当目标目录已存在时会覆盖该目录
|
|
47
|
+
|
|
48
|
+
只要传入上述生成参数,CLI 就会进入非交互模式,不再询问 `v1/v2` 或其他问题。
|
|
49
|
+
|
|
50
|
+
## 模板类型
|
|
51
|
+
|
|
52
|
+
- `pubinfo-app`: 单应用模板
|
|
53
|
+
- `pubinfo-module`: 模块开发模板,带 playground
|
|
54
|
+
- `pubinfo-monorepo`: monorepo 模板
|
|
55
|
+
|
|
56
|
+
## 代码用法
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { generate } from 'create-pubinfo';
|
|
60
|
+
|
|
61
|
+
await generate({
|
|
62
|
+
templateName: 'pubinfo-app',
|
|
63
|
+
key: 'demo',
|
|
64
|
+
version: '2.2.0',
|
|
65
|
+
modules: ['rbac'],
|
|
66
|
+
openapi: false,
|
|
67
|
+
});
|
|
13
68
|
```
|
|
14
69
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
70
|
+
## 主要导出
|
|
71
|
+
|
|
72
|
+
- `generate`: 基于模板生成项目
|
|
73
|
+
- `copyTemplate`: 直接复制模板目录
|
|
74
|
+
- `interaction`: 获取交互式选项
|
|
75
|
+
- `readPackageJSON`: 读取脚手架自身包信息
|
|
76
|
+
|
|
77
|
+
## 仓库关系
|
|
78
|
+
|
|
79
|
+
- 被 `@pubinfo/cli` 的 `generate` 和 `monorepo` 子命令直接复用。
|
|
80
|
+
- `templates/` 目录就是这个包真正的核心资产。
|
package/dist/cli.mjs
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as validateInput, n as readPackageJSON, r as run, t as bootstrop } from "./helper.mjs";
|
|
2
|
+
import { a as validateInput, n as readPackageJSON, o as generate, r as run, t as bootstrop } from "./helper.mjs";
|
|
3
|
+
import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { readFile, rm, writeFile } from "node:fs/promises";
|
|
5
|
+
import { dirname, resolve } from "node:path";
|
|
6
|
+
import process from "node:process";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
3
8
|
import { checkbox, confirm, input, select } from "@inquirer/prompts";
|
|
4
9
|
import { logger } from "@pubinfo/shared";
|
|
5
10
|
import { Command } from "commander";
|
|
6
|
-
import { resolve } from "node:path";
|
|
7
|
-
import process from "node:process";
|
|
8
|
-
import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
9
11
|
import colors from "ansi-colors";
|
|
10
12
|
import { downloadTemplate } from "giget";
|
|
11
13
|
import ora from "ora";
|
|
12
14
|
import { coerce, compare } from "semver";
|
|
13
15
|
import { ofetch } from "ofetch";
|
|
14
16
|
import { rimrafSync } from "rimraf";
|
|
15
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
16
17
|
import { parseJSON, parseJSONC, stringifyJSON } from "confbox";
|
|
17
18
|
|
|
18
19
|
//#region src/v1/constant.ts
|
|
@@ -230,13 +231,76 @@ async function runV1() {
|
|
|
230
231
|
|
|
231
232
|
//#endregion
|
|
232
233
|
//#region src/cli.ts
|
|
234
|
+
const TEMPLATE_NAMES = [
|
|
235
|
+
"pubinfo-app",
|
|
236
|
+
"pubinfo-module",
|
|
237
|
+
"pubinfo-monorepo"
|
|
238
|
+
];
|
|
239
|
+
const MODULE_NAMES = ["rbac"];
|
|
240
|
+
const templateDir = resolve(dirname(fileURLToPath(import.meta.url)), "../templates");
|
|
241
|
+
function parseBoolean(value, name) {
|
|
242
|
+
if (value === void 0) return false;
|
|
243
|
+
if ([
|
|
244
|
+
"true",
|
|
245
|
+
"1",
|
|
246
|
+
"yes"
|
|
247
|
+
].includes(value)) return true;
|
|
248
|
+
if ([
|
|
249
|
+
"false",
|
|
250
|
+
"0",
|
|
251
|
+
"no"
|
|
252
|
+
].includes(value)) return false;
|
|
253
|
+
throw new Error(`参数 ${name} 只能是 true 或 false`);
|
|
254
|
+
}
|
|
255
|
+
function isTemplateName(value) {
|
|
256
|
+
return TEMPLATE_NAMES.includes(value);
|
|
257
|
+
}
|
|
258
|
+
function isModuleName(value) {
|
|
259
|
+
return MODULE_NAMES.includes(value);
|
|
260
|
+
}
|
|
261
|
+
function parseModules(value) {
|
|
262
|
+
if (!value || value === "none") return [];
|
|
263
|
+
const modules = value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
264
|
+
const invalidModules = modules.filter((moduleName) => !isModuleName(moduleName));
|
|
265
|
+
if (invalidModules.length > 0) throw new Error(`未知模块: ${invalidModules.join(", ")}`);
|
|
266
|
+
return modules;
|
|
267
|
+
}
|
|
268
|
+
function hasGenerateOptions(options) {
|
|
269
|
+
return Boolean(options.dir || options.key || options.template || options.modules || options.openapi !== void 0 || options.yes);
|
|
270
|
+
}
|
|
271
|
+
async function runWithCliOptions(options, version) {
|
|
272
|
+
if (!options.dir || !options.key || !options.template) throw new Error("非交互模式必须提供 --dir、--key 和 --template");
|
|
273
|
+
if (!isTemplateName(options.template)) throw new Error(`未知模板: ${options.template}`);
|
|
274
|
+
const targetDir = resolve(process.cwd(), options.dir);
|
|
275
|
+
if (existsSync(targetDir)) {
|
|
276
|
+
if (!options.yes) throw new Error(`目录 ${options.dir} 已存在,请添加 --yes 覆盖`);
|
|
277
|
+
await rm(targetDir, {
|
|
278
|
+
recursive: true,
|
|
279
|
+
force: true
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
await generate({
|
|
283
|
+
dir: options.dir,
|
|
284
|
+
key: options.key,
|
|
285
|
+
templateName: options.template,
|
|
286
|
+
modules: parseModules(options.modules),
|
|
287
|
+
openapi: parseBoolean(options.openapi, "--openapi"),
|
|
288
|
+
templateDir,
|
|
289
|
+
version
|
|
290
|
+
});
|
|
291
|
+
}
|
|
233
292
|
async function main() {
|
|
234
293
|
const program = new Command();
|
|
235
294
|
const pkg = readPackageJSON();
|
|
236
295
|
program.name(pkg.name).description(pkg.description).version(pkg.version);
|
|
237
|
-
program.description("初始化框架").action(async () => {
|
|
238
|
-
bootstrop();
|
|
296
|
+
program.description("初始化框架").option("--dir <dir>", "目录名称").option("--key <key>", "项目唯一标识").option("--template <template>", "模板类型: pubinfo-app | pubinfo-module | pubinfo-monorepo").option("--modules <modules>", "模块列表,多个模块使用逗号分隔,例如 rbac").option("--openapi <boolean>", "是否运行时自动生成接口文件").option("-y, --yes", "跳过确认;目标目录已存在时覆盖").action(async () => {
|
|
239
297
|
try {
|
|
298
|
+
const options = program.opts();
|
|
299
|
+
if (hasGenerateOptions(options)) {
|
|
300
|
+
await runWithCliOptions(options, pkg.version);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
bootstrop();
|
|
240
304
|
if (await select({
|
|
241
305
|
message: "使用 v1/v2 版本?",
|
|
242
306
|
default: "v2",
|
|
@@ -250,7 +314,7 @@ async function main() {
|
|
|
250
314
|
logger.error(error);
|
|
251
315
|
}
|
|
252
316
|
});
|
|
253
|
-
program.
|
|
317
|
+
await program.parseAsync();
|
|
254
318
|
}
|
|
255
319
|
main();
|
|
256
320
|
|
package/dist/helper.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { logger } from "@pubinfo/shared";
|
|
1
|
+
import fs, { existsSync, renameSync } from "node:fs";
|
|
3
2
|
import { dirname, posix, relative, resolve, sep } from "node:path";
|
|
4
3
|
import process, { cwd } from "node:process";
|
|
5
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { checkbox, confirm, input, select } from "@inquirer/prompts";
|
|
6
|
+
import { logger } from "@pubinfo/shared";
|
|
6
7
|
import { copy } from "fs-extra";
|
|
7
|
-
import fs, { existsSync, renameSync } from "node:fs";
|
|
8
8
|
import colors from "ansi-colors";
|
|
9
9
|
import nodePlop from "node-plop";
|
|
10
10
|
import { spawn } from "node:child_process";
|
|
@@ -196,7 +196,7 @@ async function run(version) {
|
|
|
196
196
|
var package_default = {
|
|
197
197
|
name: "create-pubinfo",
|
|
198
198
|
type: "module",
|
|
199
|
-
version: "2.2.
|
|
199
|
+
version: "2.2.2",
|
|
200
200
|
description: "初始化项目框架",
|
|
201
201
|
author: "Werheng <werheng.zhang@gmail.com>",
|
|
202
202
|
license: "MIT",
|
|
@@ -216,7 +216,7 @@ var package_default = {
|
|
|
216
216
|
scripts: {
|
|
217
217
|
"dev": "tsdown --watch src",
|
|
218
218
|
"build": "tsdown",
|
|
219
|
-
"cli": "node dist/cli.
|
|
219
|
+
"cli": "node dist/cli.mjs",
|
|
220
220
|
"cli:clean": "rimraf ./my-app",
|
|
221
221
|
"lint": "eslint . --cache --fix"
|
|
222
222
|
},
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-pubinfo",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.2.
|
|
4
|
+
"version": "2.2.2",
|
|
5
5
|
"description": "初始化项目框架",
|
|
6
6
|
"author": "Werheng <werheng.zhang@gmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"ora": "^9.3.0",
|
|
39
39
|
"rimraf": "^6.1.2",
|
|
40
40
|
"semver": "^7.7.4",
|
|
41
|
-
"@pubinfo/shared": "2.2.
|
|
41
|
+
"@pubinfo/shared": "2.2.2"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "^25.2.2"
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"scripts": {
|
|
47
47
|
"dev": "tsdown --watch src",
|
|
48
48
|
"build": "tsdown",
|
|
49
|
-
"cli": "node dist/cli.
|
|
49
|
+
"cli": "node dist/cli.mjs",
|
|
50
50
|
"cli:clean": "rimraf ./my-app",
|
|
51
51
|
"lint": "eslint . --cache --fix"
|
|
52
52
|
}
|