create-pubinfo 2.2.1 → 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
@@ -28,6 +28,25 @@ npx create-pubinfo
28
28
  - 是否启用 `openapi`
29
29
  - 使用 `v1` 还是 `v2`
30
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
+
31
50
  ## 模板类型
32
51
 
33
52
  - `pubinfo-app`: 单应用模板
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.parse();
317
+ await program.parseAsync();
254
318
  }
255
319
  main();
256
320
 
package/dist/helper.mjs CHANGED
@@ -1,10 +1,10 @@
1
- import { checkbox, confirm, input, select } from "@inquirer/prompts";
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.1",
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.js",
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.1",
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.1"
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.js",
49
+ "cli": "node dist/cli.mjs",
50
50
  "cli:clean": "rimraf ./my-app",
51
51
  "lint": "eslint . --cache --fix"
52
52
  }