create-pubinfo 2.0.0-beta.31 → 2.0.0-beta.32

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/index.js CHANGED
@@ -1,400 +1,387 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/index.ts
4
2
  import { Command } from "commander";
5
- import consola6 from "consola";
3
+ import consola from "consola";
4
+ import fs, { existsSync, readFileSync, readdirSync, renameSync, writeFileSync } from "node:fs";
5
+ import { dirname, resolve } from "node:path";
6
+ import process, { cwd } from "node:process";
7
+ import { fileURLToPath } from "node:url";
8
+ import { readFile, writeFile } from "node:fs/promises";
9
+ import { parseJSON, parseJSONC, stringifyJSON } from "confbox";
10
+ import { checkbox, confirm, input, select } from "@inquirer/prompts";
11
+ import colors from "ansi-colors";
12
+ import { ofetch } from "ofetch";
13
+ import ora from "ora";
14
+ import { coerce, compare } from "semver";
15
+ import fonts from "cfonts";
16
+ import { downloadTemplate } from "giget";
17
+ import { rimrafSync } from "rimraf";
6
18
 
7
- // package.json
19
+ //#region package.json
20
+ var name = "create-pubinfo";
21
+ var type = "module";
22
+ var version = "2.0.0-beta.32";
23
+ var description = "初始化项目框架";
24
+ var author = "Werheng <werheng.zhang@gmail.com>";
25
+ var license = "MIT";
26
+ var bin = { "pubinfo": "./dist/index.js" };
27
+ var files = ["dist", "templates"];
28
+ var scripts = {
29
+ "dev": "tsdown --watch src",
30
+ "build": "tsdown",
31
+ "cli": "node dist/index.js",
32
+ "cli:clean": "rimraf ./my-app",
33
+ "lint": "eslint . --cache --fix"
34
+ };
35
+ var dependencies = {
36
+ "@inquirer/prompts": "catalog:node",
37
+ "ansi-colors": "catalog:node",
38
+ "cfonts": "catalog:node",
39
+ "commander": "catalog:node",
40
+ "confbox": "catalog:node",
41
+ "consola": "catalog:browser",
42
+ "giget": "catalog:node",
43
+ "ofetch": "catalog:http",
44
+ "ora": "catalog:node",
45
+ "rimraf": "catalog:node",
46
+ "semver": "catalog:node"
47
+ };
48
+ var devDependencies = { "@types/node": "catalog:ts" };
8
49
  var package_default = {
9
- name: "create-pubinfo",
10
- type: "module",
11
- version: "2.0.0-beta.31",
12
- description: "\u521D\u59CB\u5316\u9879\u76EE\u6846\u67B6",
13
- author: "Werheng <werheng.zhang@gmail.com>",
14
- license: "MIT",
15
- bin: {
16
- pubinfo: "./dist/index.js"
17
- },
18
- files: [
19
- "dist",
20
- "templates"
21
- ],
22
- scripts: {
23
- dev: "tsup --watch src",
24
- build: "tsup",
25
- cli: "node dist/index.js",
26
- "cli:clean": "rimraf ./my-app",
27
- lint: "eslint . --cache --fix"
28
- },
29
- dependencies: {
30
- "@inquirer/prompts": "^5.5.0",
31
- "ansi-colors": "^4.1.3",
32
- cfonts: "^3.3.0",
33
- commander: "^12.1.0",
34
- confbox: "^0.1.8",
35
- consola: "^3.4.2",
36
- giget: "^1.2.5",
37
- ofetch: "^1.4.1",
38
- ora: "^8.2.0",
39
- rimraf: "^6.0.1",
40
- semver: "^7.7.2"
41
- },
42
- devDependencies: {
43
- "@types/node": "^22.15.27",
44
- tsup: "catalog:"
45
- }
50
+ name,
51
+ type,
52
+ version,
53
+ description,
54
+ author,
55
+ license,
56
+ bin,
57
+ files,
58
+ scripts,
59
+ dependencies,
60
+ devDependencies
46
61
  };
47
62
 
48
- // src/core/generate.ts
49
- import { renameSync } from "fs";
50
- import { dirname, resolve as resolve2 } from "path";
51
- import { cwd } from "process";
52
- import { fileURLToPath } from "url";
53
-
54
- // src/utils.ts
55
- import { existsSync, readFileSync, writeFileSync } from "fs";
56
- import * as fs from "fs";
57
- import { readFile, writeFile } from "fs/promises";
58
- import { resolve } from "path";
59
- import { parseJSON, parseJSONC, stringifyJSON } from "confbox";
60
- import consola from "consola";
63
+ //#endregion
64
+ //#region src/utils.ts
65
+ /**
66
+ * 重写文件内容
67
+ */
61
68
  function rewriteFile(path, fn) {
62
- if (!existsSync(path)) {
63
- consola.error(`RewriteFile fail: ${path} does not exist`);
64
- return;
65
- }
66
- try {
67
- const content = readFileSync(path, { encoding: "utf-8" });
68
- writeFileSync(path, fn(content));
69
- } catch (error) {
70
- consola.error(`RewriteFile fail: ${error}`);
71
- }
69
+ if (!existsSync(path)) {
70
+ consola.error(`RewriteFile fail: ${path} does not exist`);
71
+ return;
72
+ }
73
+ try {
74
+ const content = readFileSync(path, { encoding: "utf-8" });
75
+ writeFileSync(path, fn(content));
76
+ } catch (error) {
77
+ consola.error(`RewriteFile fail: ${error}`);
78
+ }
72
79
  }
73
80
  function copyDir(srcDir, destDir) {
74
- fs.mkdirSync(destDir, { recursive: true });
75
- for (const file of fs.readdirSync(srcDir)) {
76
- const srcFile = resolve(srcDir, file);
77
- const destFile = resolve(destDir, file);
78
- copy(srcFile, destFile);
79
- }
81
+ fs.mkdirSync(destDir, { recursive: true });
82
+ for (const file of fs.readdirSync(srcDir)) {
83
+ const srcFile = resolve(srcDir, file);
84
+ const destFile = resolve(destDir, file);
85
+ copy(srcFile, destFile);
86
+ }
80
87
  }
81
88
  function copy(src, dest) {
82
- const stat = fs.statSync(src);
83
- if (stat.isDirectory()) {
84
- copyDir(src, dest);
85
- } else {
86
- fs.copyFileSync(src, dest);
87
- }
89
+ const stat = fs.statSync(src);
90
+ if (stat.isDirectory()) copyDir(src, dest);
91
+ else fs.copyFileSync(src, dest);
88
92
  }
89
93
  async function readJSON(path) {
90
- const blob = await readFile(path, "utf-8");
91
- let parsed;
92
- try {
93
- parsed = parseJSON(blob);
94
- } catch {
95
- parsed = parseJSONC(blob);
96
- }
97
- return parsed;
94
+ const blob = await readFile(path, "utf-8");
95
+ let parsed;
96
+ try {
97
+ parsed = parseJSON(blob);
98
+ } catch {
99
+ parsed = parseJSONC(blob);
100
+ }
101
+ return parsed;
98
102
  }
99
103
  async function writeJSON(path, json) {
100
- await writeFile(path, stringifyJSON(json));
104
+ await writeFile(path, stringifyJSON(json));
101
105
  }
102
106
  function assignValues(target, source) {
103
- for (const [key, value] of Object.entries(source)) {
104
- target[key] = value;
105
- }
107
+ for (const [key, value] of Object.entries(source)) target[key] = value;
106
108
  }
107
- function validateInput(input2) {
108
- const forbiddenChars = /[<>:"/\\|?*\s]/;
109
- if (forbiddenChars.test(input2)) {
110
- return '\u9519\u8BEF\u63D0\u793A: \u8BE5\u503C\u4E0D\u80FD\u5305\u542B\u7A7A\u683C\u6216\u8005\u975E\u6CD5\u5B57\u7B26 (\u4F8B\u5982, <>:"/\\|?*).';
111
- }
112
- return true;
109
+ function validateInput(input$1) {
110
+ const forbiddenChars = /[<>:"/\\|?*\s]/;
111
+ if (forbiddenChars.test(input$1)) return "错误提示: 该值不能包含空格或者非法字符 (例如, <>:\"/\\|?*).";
112
+ return true;
113
113
  }
114
114
 
115
- // src/core/generate.ts
116
- var __dirname = dirname(fileURLToPath(import.meta.url));
117
- function generate(options, version) {
118
- const root = cwd();
119
- const templateDir = resolve2(
120
- __dirname,
121
- "../templates",
122
- `pubinfo-template`
123
- );
124
- const targetPath = resolve2(root, options.dir);
125
- copy(templateDir, targetPath);
126
- rewriteFile(resolve2(targetPath, "src/settings.ts"), (content) => {
127
- return content.replace(/storagePrefix:\s*'([^']*)'/g, `storagePrefix: '${options.key}'`);
128
- });
129
- rewriteFile(resolve2(targetPath, "openapi.config.ts"), (content) => {
130
- return content.replace(/enabled:[^,]+,/g, `enabled: ${options.openapi},`);
131
- });
132
- rewriteFile(resolve2(targetPath, "package.json"), (content) => {
133
- const pattern = /"(@?pubinfo(?:\/module-(?:auth|rbac))?)":\s*"[^"]+"/g;
134
- return content.replace(pattern, (_match, pkgName) => {
135
- return `"${pkgName}": "${version}"`;
136
- });
137
- });
138
- const renameFiles = {
139
- _gitignore: ".gitignore",
140
- _npmrc: ".npmrc"
141
- };
142
- for (const [oldName, newName] of Object.entries(renameFiles)) {
143
- const oldPath = resolve2(targetPath, oldName);
144
- const newPath = resolve2(targetPath, newName || oldName);
145
- renameSync(oldPath, newPath);
146
- }
115
+ //#endregion
116
+ //#region src/core/generate.ts
117
+ const __dirname = dirname(fileURLToPath(import.meta.url));
118
+ function generate(options, version$1) {
119
+ const root = cwd();
120
+ const templateDir = resolve(__dirname, "../templates", `pubinfo-template`);
121
+ const targetPath = resolve(root, options.dir);
122
+ copy(templateDir, targetPath);
123
+ rewriteFile(resolve(targetPath, "src/settings.ts"), (content) => {
124
+ return content.replace(/storagePrefix:\s*'([^']*)'/g, `storagePrefix: '${options.key}'`);
125
+ });
126
+ rewriteFile(resolve(targetPath, "openapi.config.ts"), (content) => {
127
+ return content.replace(/enabled:[^,]+,/g, `enabled: ${options.openapi},`);
128
+ });
129
+ rewriteFile(resolve(targetPath, "package.json"), (content) => {
130
+ const pattern = /"(@?pubinfo(?:\/module-(?:auth|rbac))?)":\s*"[^"]+"/g;
131
+ return content.replace(pattern, (_match, pkgName) => {
132
+ return `"${pkgName}": "${version$1}"`;
133
+ });
134
+ });
135
+ const renameFiles = {
136
+ _gitignore: ".gitignore",
137
+ _npmrc: ".npmrc"
138
+ };
139
+ for (const [oldName, newName] of Object.entries(renameFiles)) {
140
+ const oldPath = resolve(targetPath, oldName);
141
+ const newPath = resolve(targetPath, newName || oldName);
142
+ renameSync(oldPath, newPath);
143
+ }
147
144
  }
148
145
 
149
- // src/core/init.ts
150
- import { existsSync as existsSync2 } from "fs";
151
- import process2 from "process";
152
- import { checkbox, confirm, input, select } from "@inquirer/prompts";
153
- import colors from "ansi-colors";
154
- import consola3 from "consola";
155
-
156
- // src/v1/constant.ts
157
- var REMOTE_URL = "http://106.53.74.49:20000/templates";
158
- var PKG_NAME = "monorepo-project-template";
159
- var VERSION_FILE = "version.json";
160
- var SETTING_FILE_PATH = "src/settings.default.ts";
161
- var OPENAPI_FILE_PATH = "openapi.config.ts";
162
- var APPS_DIR = "apps";
163
- var APPS = [
164
- { name: "\u7528\u6237\u6743\u9650\u7CFB\u7EDF\uFF08rbac\uFF09", value: "rbac" }
165
- ];
166
- var METADATA_DIR = "configs/metadata";
167
- var META_FILENAME = "pubinfo.json";
146
+ //#endregion
147
+ //#region src/v1/constant.ts
148
+ const REMOTE_URL = "http://106.53.74.49:20000/templates";
149
+ const PKG_NAME = "monorepo-project-template";
150
+ const VERSION_FILE = "version.json";
151
+ const SETTING_FILE_PATH = "src/settings.default.ts";
152
+ const OPENAPI_FILE_PATH = "openapi.config.ts";
153
+ const APPS_DIR = "apps";
154
+ const APPS = [{
155
+ name: "用户权限系统(rbac)",
156
+ value: "rbac"
157
+ }];
158
+ const METADATA_DIR = "configs/metadata";
159
+ const META_FILENAME = "pubinfo.json";
168
160
 
169
- // src/v1/fetch.ts
170
- import process from "process";
171
- import consola2 from "consola";
172
- import { ofetch } from "ofetch";
173
- import ora from "ora";
174
- import { compare } from "semver";
161
+ //#endregion
162
+ //#region src/v1/fetch.ts
175
163
  async function fetchVersion() {
176
- const versions = await ofetch(`${REMOTE_URL}/${VERSION_FILE}`);
177
- versions.sort((v1, v2) => -compare(v1, v2));
178
- return {
179
- latest: versions[0],
180
- list: versions
181
- };
164
+ const versions = await ofetch(`${REMOTE_URL}/${VERSION_FILE}`);
165
+ versions.sort((v1, v2) => -compare(v1, v2));
166
+ return {
167
+ latest: versions[0],
168
+ list: versions
169
+ };
182
170
  }
183
171
  async function fetchData() {
184
- const spinner = ora({
185
- text: "\u68C0\u6D4B\u7F51\u7EDC\u8FDE\u63A5...",
186
- color: "blue"
187
- });
188
- spinner.start();
189
- try {
190
- const version = await fetchVersion();
191
- return {
192
- version
193
- };
194
- } catch (error) {
195
- if (error.message.includes(REMOTE_URL)) {
196
- error.message = error.message.replace(REMOTE_URL, "[REMOTE_URL]");
197
- }
198
- consola2.error(`\u7F51\u7EDC\u8FDE\u63A5\u5F02\u5E38: ${error.message}`);
199
- process.exit(1);
200
- } finally {
201
- spinner.stop();
202
- }
172
+ const spinner = ora({
173
+ text: "检测网络连接...",
174
+ color: "blue"
175
+ });
176
+ spinner.start();
177
+ try {
178
+ const version$1 = await fetchVersion();
179
+ return { version: version$1 };
180
+ } catch (error) {
181
+ if (error.message.includes(REMOTE_URL)) error.message = error.message.replace(REMOTE_URL, "[REMOTE_URL]");
182
+ consola.error(`网络连接异常: ${error.message}`);
183
+ process.exit(1);
184
+ } finally {
185
+ spinner.stop();
186
+ }
203
187
  }
204
188
 
205
- // src/core/init.ts
189
+ //#endregion
190
+ //#region src/core/init.ts
206
191
  async function init() {
207
- try {
208
- const answer = {};
209
- answer.dir = await input({ message: "\u76EE\u5F55\u540D\u79F0\uFF08dir\uFF09", default: "my-app", validate: validateInput });
210
- answer.key = await input({ message: "\u9879\u76EE\u6807\u8BC6\uFF08key\uFF09", default: answer.dir, validate: validateInput });
211
- if (existsSync2(answer.dir)) {
212
- const overwrite = await confirm({ message: `\u76EE\u5F55 ${colors.cyan(answer.dir)} \u5DF2\u5B58\u5728\uFF0C\u662F\u5426\u8986\u76D6\uFF1F` });
213
- if (!overwrite) {
214
- throw Error;
215
- }
216
- }
217
- answer.openapi = await confirm({
218
- message: "\u8FD0\u884C\u65F6\u81EA\u52A8\u751F\u6210\u63A5\u53E3\u5BF9\u63A5\u6587\u4EF6\uFF0C\u82E5\u5173\u95ED\u53EF\u901A\u8FC7\u6307\u4EE4\u751F\u6210\uFF08openapi\uFF09",
219
- default: false
220
- });
221
- const V1orV2 = await select({
222
- message: "\u4F7F\u7528 v1 or v2 \u7248\u672C\uFF1F",
223
- default: "v2",
224
- choices: ["v1", "v2"]
225
- });
226
- const isV1 = V1orV2 === "v1";
227
- if (isV1) {
228
- const { version } = await fetchData();
229
- answer.optionsV1 = JSON.parse(JSON.stringify(answer));
230
- answer.optionsV1.version = await select({
231
- message: "\u6846\u67B6\u7248\u672C\u53F7\uFF08version\uFF09",
232
- default: version.latest,
233
- choices: version.list
234
- });
235
- answer.optionsV1.apps = await checkbox({
236
- message: "\u9009\u62E9\u5E94\u7528\u6A21\u5757\uFF08apps\uFF09",
237
- choices: APPS,
238
- validate: (input2) => {
239
- if (input2.length === 0) {
240
- return "\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u4E2A\u5E94\u7528";
241
- }
242
- return true;
243
- }
244
- });
245
- }
246
- return answer;
247
- } catch {
248
- consola3.fail("\u64CD\u4F5C\u7EC8\u6B62");
249
- process2.exit(1);
250
- }
192
+ try {
193
+ const answer = {};
194
+ answer.dir = await input({
195
+ message: "目录名称(dir)",
196
+ default: "my-app",
197
+ validate: validateInput
198
+ });
199
+ answer.key = await input({
200
+ message: "项目标识(key)",
201
+ default: answer.dir,
202
+ validate: validateInput
203
+ });
204
+ if (existsSync(answer.dir)) {
205
+ const overwrite = await confirm({ message: `目录 ${colors.cyan(answer.dir)} 已存在,是否覆盖?` });
206
+ if (!overwrite) throw Error;
207
+ }
208
+ answer.openapi = await confirm({
209
+ message: "运行时自动生成接口对接文件,若关闭可通过指令生成(openapi)",
210
+ default: false
211
+ });
212
+ const V1orV2 = await select({
213
+ message: "使用 v1 or v2 版本?",
214
+ default: "v2",
215
+ choices: ["v1", "v2"]
216
+ });
217
+ const isV1 = V1orV2 === "v1";
218
+ if (isV1) {
219
+ const { version: version$1 } = await fetchData();
220
+ answer.optionsV1 = JSON.parse(JSON.stringify(answer));
221
+ answer.optionsV1.version = await select({
222
+ message: "框架版本号(version)",
223
+ default: version$1.latest,
224
+ choices: version$1.list
225
+ });
226
+ answer.optionsV1.apps = await checkbox({
227
+ message: "选择应用模块(apps)",
228
+ choices: APPS,
229
+ validate: (input$1) => {
230
+ if (input$1.length === 0) return "请至少选择一个应用";
231
+ return true;
232
+ }
233
+ });
234
+ }
235
+ return answer;
236
+ } catch {
237
+ consola.fail("操作终止");
238
+ process.exit(1);
239
+ }
251
240
  }
252
241
 
253
- // src/log.ts
254
- import fonts from "cfonts";
242
+ //#endregion
243
+ //#region src/log.ts
255
244
  function bootstrop() {
256
- printLoGo("PUBINFO");
257
- function printLoGo(logo) {
258
- fonts.say(logo, {
259
- font: "simple3d",
260
- align: "left",
261
- background: "transparent",
262
- letterSpacing: 1,
263
- lineHeight: 1,
264
- space: true,
265
- maxLength: 0,
266
- spaceless: false,
267
- gradient: ["blue", "magenta"],
268
- independentGradient: false,
269
- transitionGradient: false,
270
- env: "node"
271
- });
272
- }
245
+ printLoGo("PUBINFO");
246
+ function printLoGo(logo) {
247
+ fonts.say(logo, {
248
+ font: "simple3d",
249
+ align: "left",
250
+ background: "transparent",
251
+ letterSpacing: 1,
252
+ lineHeight: 1,
253
+ space: true,
254
+ maxLength: 0,
255
+ spaceless: false,
256
+ gradient: ["blue", "magenta"],
257
+ independentGradient: false,
258
+ transitionGradient: false,
259
+ env: "node"
260
+ });
261
+ }
273
262
  }
274
263
 
275
- // src/v1/download.ts
276
- import process3 from "process";
277
- import colors2 from "ansi-colors";
278
- import consola4 from "consola";
279
- import { downloadTemplate } from "giget";
280
- import ora2 from "ora";
281
- import { coerce } from "semver";
282
- var pubinfo = async (input2, { auth }) => {
283
- const semver = coerce(input2);
284
- return {
285
- name: "pubinfo",
286
- version: input2,
287
- headers: { Authorization: `token ${auth}` },
288
- tar: `${REMOTE_URL}/${PKG_NAME}-${semver?.version}.tar.gz`
289
- };
264
+ //#endregion
265
+ //#region src/v1/download.ts
266
+ const pubinfo = async (input$1, { auth }) => {
267
+ const semver = coerce(input$1);
268
+ return {
269
+ name: "pubinfo",
270
+ version: input$1,
271
+ headers: { Authorization: `token ${auth}` },
272
+ tar: `${REMOTE_URL}/${PKG_NAME}-${semver?.version}.tar.gz`
273
+ };
290
274
  };
291
275
  async function download(options) {
292
- const finish = loading();
293
- try {
294
- await downloadTemplate(`pubinfo:${PKG_NAME}-${options.version}`, {
295
- providers: { pubinfo },
296
- force: true,
297
- forceClean: true,
298
- dir: options.dir
299
- });
300
- } catch (error) {
301
- if (error.message.includes(REMOTE_URL)) {
302
- error.message = error.message.replace(REMOTE_URL, "[REMOTE_URL]");
303
- }
304
- consola4.error(`\u4E0B\u8F7D\u5931\u8D25: ${error.message}`);
305
- process3.exit(1);
306
- } finally {
307
- finish();
308
- }
276
+ const finish = loading();
277
+ try {
278
+ await downloadTemplate(`pubinfo:${PKG_NAME}-${options.version}`, {
279
+ providers: { pubinfo },
280
+ force: true,
281
+ forceClean: true,
282
+ dir: options.dir
283
+ });
284
+ } catch (error) {
285
+ if (error.message.includes(REMOTE_URL)) error.message = error.message.replace(REMOTE_URL, "[REMOTE_URL]");
286
+ consola.error(`下载失败: ${error.message}`);
287
+ process.exit(1);
288
+ } finally {
289
+ finish();
290
+ }
309
291
  }
310
292
  function loading() {
311
- const startTime = Date.now();
312
- const spinner = ora2({
313
- text: "\u4E0B\u8F7D\u4E2D...",
314
- color: "green"
315
- });
316
- spinner.start();
317
- return () => {
318
- const { green, yellow } = colors2;
319
- spinner.stop();
320
- consola4.success(`${green("\u4E0B\u8F7D\u5B8C\u6210, \u7528\u65F6")} ${yellow(`${Date.now() - startTime}`)} ${green("ms.")}`);
321
- };
293
+ const startTime = Date.now();
294
+ const spinner = ora({
295
+ text: "下载中...",
296
+ color: "green"
297
+ });
298
+ spinner.start();
299
+ return () => {
300
+ const { green, yellow } = colors;
301
+ spinner.stop();
302
+ consola.success(`${green("下载完成, 用时")} ${yellow(`${Date.now() - startTime}`)} ${green("ms.")}`);
303
+ };
322
304
  }
323
305
 
324
- // src/v1/rewrite.ts
325
- import { existsSync as existsSync3, readdirSync as readdirSync2 } from "fs";
326
- import { resolve as resolve3 } from "path";
327
- import process4 from "process";
328
- import consola5 from "consola";
329
- import { rimrafSync } from "rimraf";
306
+ //#endregion
307
+ //#region src/v1/rewrite.ts
330
308
  async function rewrite(options) {
331
- const { dir } = options;
332
- const root = process4.cwd();
333
- const projectDir = resolve3(root, dir);
334
- writeMetaJSON(resolve3(projectDir, METADATA_DIR), options);
335
- writeApps(resolve3(projectDir, APPS_DIR), options);
309
+ const { dir } = options;
310
+ const root = process.cwd();
311
+ const projectDir = resolve(root, dir);
312
+ writeMetaJSON(resolve(projectDir, METADATA_DIR), options);
313
+ writeApps(resolve(projectDir, APPS_DIR), options);
336
314
  }
315
+ /**
316
+ * 写入项目整体配置
317
+ */
337
318
  async function writeMetaJSON(metaDir, options) {
338
- const { key, version, apps, openapi } = options;
339
- const path = resolve3(metaDir, META_FILENAME);
340
- try {
341
- const json = await readJSON(path);
342
- assignValues(json, {
343
- key,
344
- version,
345
- apps,
346
- openapi
347
- });
348
- await writeJSON(path, json);
349
- } catch (error) {
350
- consola5.error(`\u521D\u59CB\u5316 metadata \u5931\u8D25: ${error}`);
351
- }
319
+ const { key, version: version$1, apps, openapi } = options;
320
+ const path = resolve(metaDir, META_FILENAME);
321
+ try {
322
+ const json = await readJSON(path);
323
+ assignValues(json, {
324
+ key,
325
+ version: version$1,
326
+ apps,
327
+ openapi
328
+ });
329
+ await writeJSON(path, json);
330
+ } catch (error) {
331
+ consola.error(`初始化 metadata 失败: ${error}`);
332
+ }
352
333
  }
334
+ /**
335
+ * 处理目录 `/apps` 下的各个应用
336
+ */
353
337
  function writeApps(appsDir, options) {
354
- const { key, apps = [], openapi } = options;
355
- if (!existsSync3(appsDir)) {
356
- consola5.error(`\u521D\u59CB\u5316 apps \u5931\u8D25: ${appsDir} \u4E0D\u5B58\u5728`);
357
- return;
358
- }
359
- try {
360
- readdirSync2(appsDir).forEach((app) => {
361
- const appPath = resolve3(appsDir, app);
362
- const settingPath = resolve3(appPath, SETTING_FILE_PATH);
363
- const openapiPath = resolve3(appPath, OPENAPI_FILE_PATH);
364
- if (!apps.includes(app)) {
365
- rimrafSync(appPath);
366
- return;
367
- }
368
- rewriteFile(settingPath, (content) => {
369
- return content.replace(/storagePrefix:\s*'([^']*)'/g, `storagePrefix: '${key}'`);
370
- });
371
- rewriteFile(openapiPath, (content) => {
372
- return content.replace(/enabled:[^,]+,/g, `enabled: ${openapi},`);
373
- });
374
- });
375
- } catch (error) {
376
- consola5.error(`\u521D\u59CB\u5316 apps \u5931\u8D25: ${error}`);
377
- }
338
+ const { key, apps = [], openapi } = options;
339
+ if (!existsSync(appsDir)) {
340
+ consola.error(`初始化 apps 失败: ${appsDir} 不存在`);
341
+ return;
342
+ }
343
+ try {
344
+ readdirSync(appsDir).forEach((app) => {
345
+ const appPath = resolve(appsDir, app);
346
+ const settingPath = resolve(appPath, SETTING_FILE_PATH);
347
+ const openapiPath = resolve(appPath, OPENAPI_FILE_PATH);
348
+ if (!apps.includes(app)) {
349
+ rimrafSync(appPath);
350
+ return;
351
+ }
352
+ rewriteFile(settingPath, (content) => {
353
+ return content.replace(/storagePrefix:\s*'([^']*)'/g, `storagePrefix: '${key}'`);
354
+ });
355
+ rewriteFile(openapiPath, (content) => {
356
+ return content.replace(/enabled:[^,]+,/g, `enabled: ${openapi},`);
357
+ });
358
+ });
359
+ } catch (error) {
360
+ consola.error(`初始化 apps 失败: ${error}`);
361
+ }
378
362
  }
379
363
 
380
- // src/index.ts
364
+ //#endregion
365
+ //#region src/index.ts
381
366
  async function main() {
382
- const program = new Command();
383
- program.name(package_default.name).description(package_default.description).version(package_default.version);
384
- program.description("\u521D\u59CB\u5316\u6846\u67B6").action(async () => {
385
- bootstrop();
386
- try {
387
- const answer = await init();
388
- if (answer.optionsV1) {
389
- await download(answer.optionsV1);
390
- await rewrite(answer.optionsV1);
391
- return;
392
- }
393
- generate(answer, package_default.version);
394
- } catch (error) {
395
- consola6.error(error);
396
- }
397
- });
398
- program.parse();
367
+ const program = new Command();
368
+ program.name(package_default.name).description(package_default.description).version(package_default.version);
369
+ program.description("初始化框架").action(async () => {
370
+ bootstrop();
371
+ try {
372
+ const answer = await init();
373
+ if (answer.optionsV1) {
374
+ await download(answer.optionsV1);
375
+ await rewrite(answer.optionsV1);
376
+ return;
377
+ }
378
+ generate(answer, package_default.version);
379
+ } catch (error) {
380
+ consola.error(error);
381
+ }
382
+ });
383
+ program.parse();
399
384
  }
400
385
  main();
386
+
387
+ //#endregion
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-pubinfo",
3
3
  "type": "module",
4
- "version": "2.0.0-beta.31",
4
+ "version": "2.0.0-beta.32",
5
5
  "description": "初始化项目框架",
6
6
  "author": "Werheng <werheng.zhang@gmail.com>",
7
7
  "license": "MIT",
@@ -13,25 +13,24 @@
13
13
  "templates"
14
14
  ],
15
15
  "dependencies": {
16
- "@inquirer/prompts": "^5.5.0",
16
+ "@inquirer/prompts": "^7.6.0",
17
17
  "ansi-colors": "^4.1.3",
18
18
  "cfonts": "^3.3.0",
19
- "commander": "^12.1.0",
20
- "confbox": "^0.1.8",
19
+ "commander": "^14.0.0",
20
+ "confbox": "^0.2.2",
21
21
  "consola": "^3.4.2",
22
- "giget": "^1.2.5",
22
+ "giget": "^2.0.0",
23
23
  "ofetch": "^1.4.1",
24
24
  "ora": "^8.2.0",
25
25
  "rimraf": "^6.0.1",
26
26
  "semver": "^7.7.2"
27
27
  },
28
28
  "devDependencies": {
29
- "@types/node": "^22.15.27",
30
- "tsup": "^8.5.0"
29
+ "@types/node": "^24.0.10"
31
30
  },
32
31
  "scripts": {
33
- "dev": "tsup --watch src",
34
- "build": "tsup",
32
+ "dev": "tsdown --watch src",
33
+ "build": "tsdown",
35
34
  "cli": "node dist/index.js",
36
35
  "cli:clean": "rimraf ./my-app",
37
36
  "lint": "eslint . --cache --fix"
@@ -2,7 +2,7 @@
2
2
  "name": "pubinfo-template",
3
3
  "type": "module",
4
4
  "private": true,
5
- "packageManager": "pnpm@10.11.0",
5
+ "packageManager": "pnpm@10.12.4",
6
6
  "scripts": {
7
7
  "dev": "pubinfo dev",
8
8
  "build": "pubinfo build",
@@ -15,14 +15,14 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@ant-design/icons-vue": "^7.0.1",
18
- "@pubinfo/module-auth": "^2.0.0-beta.27",
19
- "@pubinfo/module-rbac": "^2.0.0-beta.27",
18
+ "@pubinfo/module-auth": "^2.0.0-beta.31",
19
+ "@pubinfo/module-rbac": "^2.0.0-beta.31",
20
20
  "@pubinfo/pro-components": "^1.7.1",
21
21
  "@vueuse/core": "^12.8.2",
22
- "alova": "^3.2.13",
22
+ "alova": "^3.3.4",
23
23
  "ant-design-vue": "^4.2.6",
24
24
  "dayjs": "^1.11.13",
25
- "pubinfo": "^2.0.0-beta.27"
25
+ "pubinfo": "^2.0.0-beta.31"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@commitlint/config-conventional": "^19.8.1",
@@ -31,10 +31,10 @@
31
31
  "@pubinfo/preset-openapi": "^0.8.4",
32
32
  "commitizen": "^4.3.1",
33
33
  "commitlint": "^19.8.1",
34
- "eslint": "^9.27.0",
35
- "lint-staged": "^16.1.0",
34
+ "eslint": "^9.30.1",
35
+ "lint-staged": "^16.1.2",
36
36
  "simple-git-hooks": "^2.13.0",
37
- "stylelint": "^16.20.0",
37
+ "stylelint": "^16.21.0",
38
38
  "typescript": "^5.8.3"
39
39
  },
40
40
  "config": {
@@ -9,60 +9,21 @@ const { tabs, initialTab, changeActiveTab } = useLoginTabs();
9
9
  </script>
10
10
 
11
11
  <template>
12
- <div class="login-warp">
13
- <div class="login-tabs">
12
+ <div class="flex flex-col w-456px [background:transparent]">
13
+ <div class="flex flex-row overflow-hidden border border-solid border-[#e7e8e9] rounded-1">
14
14
  <div
15
15
  v-for="(tab, index) in tabs"
16
16
  :key="tab.title"
17
- class="login-tab"
18
- :class="{ active: initialTab === index }"
17
+ class="flex flex-row items-center justify-center h-10 text-base cursor-pointer rounded"
18
+ :class="[initialTab === index ? 'text-[#2f6bff] bg-[#ecf1fd]' : 'text-[#8a8e92] ']"
19
19
  :style="{ width: `${100 / tabs.length}%` }"
20
20
  @click="changeActiveTab(index)"
21
21
  >
22
22
  {{ tab.title }}
23
23
  </div>
24
24
  </div>
25
- <div class="login-form">
25
+ <div class="relative min-h-350px">
26
26
  <component :is="tabs[initialTab].component" :key="tabs[initialTab].title" :name="tabs[initialTab].title" />
27
27
  </div>
28
28
  </div>
29
29
  </template>
30
-
31
- <style scoped lang="scss">
32
- .login-warp {
33
- display: flex;
34
- flex-direction: column;
35
- width: 456px;
36
- background: transparent;
37
-
38
- .login-tabs {
39
- display: flex;
40
- flex-direction: row;
41
- overflow: hidden;
42
- border: 1px solid #e7e8e9;
43
- border-radius: 4px;
44
-
45
- .login-tab {
46
- display: flex;
47
- flex-direction: row;
48
- align-items: center;
49
- justify-content: center;
50
- height: 40px;
51
- font-size: 16px;
52
- color: #8a8e92;
53
- cursor: pointer;
54
- border-radius: 4px;
55
- }
56
-
57
- .active {
58
- color: #2f6bff;
59
- background: #ecf1fd;
60
- }
61
- }
62
-
63
- .login-form {
64
- position: relative;
65
- min-height: 350px;
66
- }
67
- }
68
- </style>
@@ -113,7 +113,7 @@ const AUTH_4A_ENABLED = import.meta.env.VITE_AUTH_4A_ENABLED === 'true';
113
113
  </script>
114
114
 
115
115
  <template>
116
- <div class="login-form">
116
+ <div class="mt-10">
117
117
  <AForm ref="loginForm" :model="formState" :rules="rules" @finish="onSubmit">
118
118
  <a-form-item name="account">
119
119
  <a-input
@@ -202,13 +202,9 @@ const AUTH_4A_ENABLED = import.meta.env.VITE_AUTH_4A_ENABLED === 'true';
202
202
  </div>
203
203
  </template>
204
204
 
205
- <style scoped lang="scss">
206
- .login-form {
207
- margin-top: 40px;
208
-
209
- :deep(.ant-input-group-addon) {
210
- padding: 0 !important;
211
- overflow: hidden;
212
- }
205
+ <style scoped>
206
+ :deep(.ant-input-group-addon) {
207
+ padding: 0 !important;
208
+ overflow: hidden;
213
209
  }
214
210
  </style>
@@ -105,41 +105,23 @@ const designDescription = [
105
105
  </div>
106
106
  </template>
107
107
 
108
- <style lang="scss" scoped>
108
+ <style scoped>
109
109
  .warp {
110
- position: relative;
111
- display: flex;
112
- flex-direction: row;
113
- width: 100%;
114
- height: 100%;
115
- overflow: hidden;
110
+ --at-apply: relative flex flex-row w-full h-full overflow-hidden;
116
111
  background: url("@/assets/images/login-bg.webp") no-repeat;
117
112
  background-size: cover;
113
+ }
118
114
 
119
- .warp-blank {
120
- flex: auto;
121
- flex-basis: 0;
122
- overflow: hidden;
123
- }
115
+ .warp .warp-blank {
116
+ --at-apply: flex-auto basis-0 overflow-hidden;
117
+ }
124
118
 
125
- .logo-group {
126
- display: flex;
127
- flex-direction: row;
128
- align-items: center;
129
- height: 33px;
130
- margin-bottom: 35px;
131
- font-size: 24px;
132
- font-weight: 400;
133
- color: #151e26;
134
- }
119
+ .warp .logo-group {
120
+ --at-apply: flex flex-row items-center h-33px mb-35px text-6 font-400 text-[#151e26];
121
+ }
135
122
 
136
- .title-group {
137
- height: 52px;
138
- font-size: 38px;
139
- font-weight: 800;
140
- color: #072347;
141
- letter-spacing: 1.5px;
142
- }
123
+ .warp .title-group {
124
+ --at-apply: h-52px text-38px font-800 text-[#072347] tracking-[1.5px];
143
125
  }
144
126
 
145
127
  @media (width < 1024px) {