@pubinfo/cli 2.0.0-rc.2 → 2.0.0-rc.4

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.
@@ -1,4 +1,4 @@
1
- import { generate_default } from "./generate-B8E8h4SV.js";
1
+ import { setup_default } from "./setup-CeXxy5Fk.js";
2
2
  import { defineCommand, runMain } from "citty";
3
3
  import { build, mergeConfig } from "@pubinfo/vite";
4
4
  import { loadConfig } from "unconfig";
@@ -24,7 +24,7 @@ const command = defineCommand({
24
24
  }
25
25
  },
26
26
  async run({ args }) {
27
- await runMain(generate_default);
27
+ await runMain(setup_default);
28
28
  const { config } = await loadConfig({
29
29
  sources: [{ files: args.config || "pubinfo.config" }],
30
30
  merge: false
@@ -0,0 +1,72 @@
1
+ import fs from "node:fs";
2
+ import process from "node:process";
3
+
4
+ //#region src/commands/commit.ts
5
+ /**
6
+ * `pubinfo commit` 子命令:
7
+ * 统一封装项目级提交体验,复用 @pubinfo/commitlint 的核心能力。
8
+ * 功能概述:
9
+ * 1. 交互式生成符合规范的提交信息(中文 + 可选 emoji)。
10
+ * 2. 支持 `--edit` 供 commit-msg 钩子调用,读取临时文件并执行 lint。
11
+ * 4. 支持 `--init` 一键初始化(cz 配置 / 模板 / git hooks)。
12
+ * 5. 不直接执行 `git commit`,保持透明,调用者自行决定是否提交。
13
+ */
14
+ var commit_default = {
15
+ meta: {
16
+ name: "commit",
17
+ description: "交互式规范 Commit Lint 提交"
18
+ },
19
+ args: {
20
+ edit: {
21
+ type: "string",
22
+ description: "从 commit-msg 钩子传入的临时文件路径 (--edit $1)"
23
+ },
24
+ init: {
25
+ type: "boolean",
26
+ description: "初始化提交环境 (cz 配置 / 模板 / git hooks)"
27
+ }
28
+ },
29
+ run: async ({ args }) => {
30
+ const { createCzConfig, createGitMessage, runCzConfig, runNpx, runSimpleGitHooks, runGitMessage, lintMessage, runPrompt } = await import("@pubinfo/commitlint");
31
+ if (args.init) {
32
+ const pubinfoDir = `${process.cwd()}/.pubinfo`;
33
+ if (!fs.existsSync(pubinfoDir)) fs.mkdirSync(pubinfoDir);
34
+ const gitMessageStatus = createGitMessage();
35
+ const czConfigStatus = createCzConfig(pubinfoDir);
36
+ const gitHookStatus = runGitMessage();
37
+ const simpleGitHooks = runSimpleGitHooks("pubinfo commit");
38
+ const czConfig = runCzConfig(".pubinfo/cz.config.cjs");
39
+ const npxStatus = runNpx();
40
+ console.log("[pubinfo-commit] 初始化结果:");
41
+ console.log(`- cz.config.cjs: ${czConfigStatus ? "已创建" : "已存在"}`);
42
+ console.log(`- .gitmessage: ${gitMessageStatus ? "已创建" : "已存在"}`);
43
+ console.log(`- Git hooks: ${gitHookStatus ? "已写入" : "已存在"}`);
44
+ console.log(`- package.json 配置 cz-git: ${czConfig ? "已写入" : "已存在"}`);
45
+ console.log(`- package.json 配置 simple-git-hooks: ${simpleGitHooks ? "已写入" : "已存在"}`);
46
+ console.log(`- npx simple-git-hooks 安装: ${npxStatus ? "成功" : "失败,请手动安装"}`);
47
+ return;
48
+ }
49
+ if (args.edit) {
50
+ try {
51
+ const raw = fs.readFileSync(String(args.edit), "utf8").trim();
52
+ if (!raw) {
53
+ console.error("[pubinfo commit] 空的 commit message");
54
+ return;
55
+ }
56
+ await lintMessage(raw);
57
+ } catch (e) {
58
+ console.error("[pubinfo commit] 读取 --edit 文件失败", e);
59
+ }
60
+ return;
61
+ }
62
+ const result = await runPrompt();
63
+ if (!result) {
64
+ console.error("[pubinfo-commit] 未找到 cz-git 或交互被中断");
65
+ return;
66
+ }
67
+ await lintMessage(result.raw);
68
+ }
69
+ };
70
+
71
+ //#endregion
72
+ export { commit_default as default };
@@ -1,4 +1,4 @@
1
- import { generate_default } from "./generate-B8E8h4SV.js";
1
+ import { setup_default } from "./setup-CeXxy5Fk.js";
2
2
  import { defineCommand, runMain } from "citty";
3
3
  import { createServer, mergeConfig } from "@pubinfo/vite";
4
4
  import { loadConfig } from "unconfig";
@@ -22,7 +22,7 @@ const command = defineCommand({
22
22
  }
23
23
  },
24
24
  async run({ args }) {
25
- await runMain(generate_default);
25
+ await runMain(setup_default);
26
26
  const { config } = await loadConfig({
27
27
  sources: [{ files: args.config || "pubinfo.config" }],
28
28
  merge: false
@@ -0,0 +1,153 @@
1
+ import { defineCommand } from "citty";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import process from "node:process";
5
+ import { load } from "cheerio";
6
+ import { globby } from "globby";
7
+
8
+ //#region src/commands/icon.ts
9
+ function parseNumberLike(v) {
10
+ if (!v) return;
11
+ const num = Number.parseFloat(String(v).trim());
12
+ return Number.isFinite(num) ? num : void 0;
13
+ }
14
+ function toPreserveAspectRatio(aspect) {
15
+ if (aspect === "none") return "none";
16
+ return `xMidYMid ${aspect}`;
17
+ }
18
+ async function processFile(file, opts) {
19
+ const raw = await fs.readFile(file, "utf8");
20
+ const $ = load(raw, { xmlMode: true });
21
+ const $svg = $("svg").first();
22
+ if ($svg.length === 0) {
23
+ console.warn(`[skip] Not an <svg> root: ${file}`);
24
+ return;
25
+ }
26
+ const origW = parseNumberLike($svg.attr("width"));
27
+ const origH = parseNumberLike($svg.attr("height"));
28
+ const vbAttr = $svg.attr("viewBox");
29
+ let vbW;
30
+ let vbH;
31
+ if (vbAttr) {
32
+ const nums = vbAttr.split(/[\s,]+/).map((x) => Number.parseFloat(x)).filter((x) => Number.isFinite(x));
33
+ if (nums.length === 4) {
34
+ vbW = nums[2];
35
+ vbH = nums[3];
36
+ }
37
+ }
38
+ if (!vbW || !vbH) if (origW && origH) {
39
+ vbW = origW;
40
+ vbH = origH;
41
+ } else {
42
+ vbW = 24;
43
+ vbH = 24;
44
+ console.warn(`[warn] ${file} 无有效 viewBox/width/height,兜底为 24x24`);
45
+ }
46
+ $svg.attr("width", String(opts.size));
47
+ $svg.attr("height", String(opts.size));
48
+ $svg.attr("viewBox", `0 0 ${vbW} ${vbH}`);
49
+ $svg.attr("preserveAspectRatio", toPreserveAspectRatio(opts.aspect));
50
+ const output = $.xml($svg);
51
+ const targetPath = opts.inplace ? file : path.join(opts.outDir, path.relative(path.resolve(opts.baseDir), file));
52
+ await fs.mkdir(path.dirname(targetPath), { recursive: true });
53
+ await fs.writeFile(targetPath, output, "utf8");
54
+ console.log(`[ok] ${path.relative(process.cwd(), targetPath)}`);
55
+ }
56
+ var icon_default = defineCommand({
57
+ meta: {
58
+ name: "normalize-svg",
59
+ description: "批量把 SVG 规范为固定 24x24(或自定义)且用原始尺寸写入 viewBox"
60
+ },
61
+ args: {
62
+ dir: {
63
+ type: "positional",
64
+ required: false,
65
+ default: ".",
66
+ description: "要扫描的目录(默认当前工作目录)"
67
+ },
68
+ size: {
69
+ type: "string",
70
+ default: "24",
71
+ description: "输出的外部宽高(px)"
72
+ },
73
+ aspect: {
74
+ type: "string",
75
+ default: "meet",
76
+ description: "preserveAspectRatio: meet | slice | none"
77
+ },
78
+ pattern: {
79
+ type: "string",
80
+ default: "**/*.svg",
81
+ description: "匹配的 glob 模式"
82
+ },
83
+ inplace: {
84
+ type: "boolean",
85
+ default: true,
86
+ description: "是否就地覆盖原文件"
87
+ },
88
+ outDir: {
89
+ type: "string",
90
+ description: "输出目录(未指定 --inplace 时生效)"
91
+ },
92
+ gitignore: {
93
+ type: "boolean",
94
+ default: true,
95
+ description: "是否遵守 .gitignore"
96
+ },
97
+ ignore: {
98
+ type: "string",
99
+ required: false,
100
+ description: "额外忽略(可多次传入),如 \"**/snapshots/**\""
101
+ }
102
+ },
103
+ run: async (ctx) => {
104
+ const dir = ctx.args.dir ? String(ctx.args.dir) : ".";
105
+ const size = Number(ctx.args.size ?? 24);
106
+ const aspect = String(ctx.args.aspect ?? "meet");
107
+ if (![
108
+ "meet",
109
+ "slice",
110
+ "none"
111
+ ].includes(aspect)) throw new Error(`--aspect 仅支持 meet|slice|none,当前:${aspect}`);
112
+ const base = path.resolve(dir);
113
+ const pattern = String(ctx.args.pattern ?? "**/*.svg");
114
+ const inplace = Boolean(ctx.args.inplace);
115
+ const gitignore = Boolean(ctx.args.gitignore);
116
+ const raw = ctx.rawArgs || [];
117
+ const extraIgnores = [];
118
+ for (let i = 0; i < raw.length; i++) if (raw[i] === "--ignore" && raw[i + 1]) {
119
+ extraIgnores.push(String(raw[i + 1]));
120
+ i++;
121
+ }
122
+ let outDir = ctx.args.outDir ? path.resolve(String(ctx.args.outDir)) : void 0;
123
+ if (!inplace && !outDir) outDir = path.resolve(base, `svg-${size}`);
124
+ const patterns = [path.join(base, pattern).replace(/\\/g, "/")];
125
+ const files = await globby(patterns, {
126
+ cwd: base,
127
+ gitignore,
128
+ absolute: true,
129
+ onlyFiles: true,
130
+ expandDirectories: false,
131
+ ignore: extraIgnores
132
+ });
133
+ if (!files.length) {
134
+ console.warn(`No SVG matched: ${pattern} (dir: ${base})`);
135
+ return;
136
+ }
137
+ if (!inplace && outDir) await fs.mkdir(outDir, { recursive: true });
138
+ for (const file of files) try {
139
+ await processFile(file, {
140
+ size,
141
+ aspect,
142
+ baseDir: base,
143
+ inplace,
144
+ outDir
145
+ });
146
+ } catch (e) {
147
+ console.error(`[error] ${file}: ${e.message}`);
148
+ }
149
+ }
150
+ });
151
+
152
+ //#endregion
153
+ export { icon_default as default };
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { fileURLToPath } from "node:url";
4
4
  //#region package.json
5
5
  var name = "@pubinfo/cli";
6
6
  var type = "module";
7
- var version = "2.0.0-rc.2";
7
+ var version = "2.0.0-rc.4";
8
8
  var description = "CLI for Pubinfo";
9
9
  var exports = { ".": "./bin/pubinfo.mjs" };
10
10
  var types = "./dist/index.d.ts";
@@ -20,6 +20,7 @@ var dependencies = {
20
20
  "@pubinfo/commitlint": "workspace:*",
21
21
  "cheerio": "catalog:node",
22
22
  "citty": "catalog:node",
23
+ "globby": "catalog:node",
23
24
  "pathe": "catalog:node",
24
25
  "unconfig": "catalog:node"
25
26
  };
@@ -46,12 +47,12 @@ var package_default = {
46
47
  //#region src/commands/index.ts
47
48
  const _rDefault = (r) => r.default || r;
48
49
  const commands = {
49
- dev: () => import("./dev-CxmFmMRs.js").then(_rDefault),
50
- build: () => import("./build-IhQTnwHT.js").then(_rDefault),
50
+ dev: () => import("./dev-CYJ3T2Hr.js").then(_rDefault),
51
+ build: () => import("./build-BL7ZjVB5.js").then(_rDefault),
51
52
  preview: () => import("./preview-IG8wXay6.js").then(_rDefault),
52
- generate: () => import("./generate-De0efY0o.js").then(_rDefault),
53
- commit: () => import("./commit-BT18KgTK.js").then(_rDefault),
54
- icon: () => import("./icon-DEFBRPY4.js").then(_rDefault)
53
+ setup: () => import("./setup-bq4v7xFD.js").then(_rDefault),
54
+ commit: () => import("./commit-CkxIeWgN.js").then(_rDefault),
55
+ icon: () => import("./icon-DWczAqmo.js").then(_rDefault)
55
56
  };
56
57
 
57
58
  //#endregion
@@ -1,8 +1,8 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { defineCommand } from "citty";
3
- import { mkdir, rm } from "node:fs/promises";
3
+ import { existsSync, unlinkSync, writeFileSync } from "node:fs";
4
+ import { mkdir } from "node:fs/promises";
4
5
  import { resolve } from "pathe";
5
- import { writeFileSync } from "node:fs";
6
6
  import { join } from "node:path";
7
7
 
8
8
  //#region src/utils/tsconfig.ts
@@ -11,6 +11,7 @@ function writeTsconfig(filePath) {
11
11
  const resolveDeps = (name, path$1) => {
12
12
  return join(require.resolve(name), path$1).replace(/\\/g, "/");
13
13
  };
14
+ if (existsSync(filePath)) unlinkSync(filePath);
14
15
  writeFileSync(filePath, `/* eslint-disable */
15
16
  /* prettier-ignore */
16
17
  // Generated by pubinfo
@@ -75,23 +76,20 @@ function writeTsconfig(filePath) {
75
76
  }
76
77
 
77
78
  //#endregion
78
- //#region src/commands/generate.ts
79
+ //#region src/commands/setup.ts
79
80
  const command = defineCommand({
80
81
  meta: {
81
- name: "generate",
82
+ name: "setup",
82
83
  description: "Generate Pubinfo static site"
83
84
  },
84
85
  async run() {
85
86
  const cwd = resolve(".");
86
- await rm(resolve(cwd, ".pubinfo"), {
87
- recursive: true,
88
- force: true
89
- });
90
- await mkdir(resolve(cwd, ".pubinfo"), { recursive: true });
87
+ const pubinfoDir = resolve(cwd, ".pubinfo");
88
+ if (!existsSync(pubinfoDir)) await mkdir(pubinfoDir, { recursive: true });
91
89
  writeTsconfig(resolve(cwd, ".pubinfo/tsconfig.app.json"));
92
90
  }
93
91
  });
94
- var generate_default = command;
92
+ var setup_default = command;
95
93
 
96
94
  //#endregion
97
- export { generate_default };
95
+ export { setup_default };
@@ -0,0 +1,3 @@
1
+ import { setup_default } from "./setup-CeXxy5Fk.js";
2
+
3
+ export { setup_default as default };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pubinfo/cli",
3
3
  "type": "module",
4
- "version": "2.0.0-rc.2",
4
+ "version": "2.0.0-rc.4",
5
5
  "description": "CLI for Pubinfo",
6
6
  "exports": {
7
7
  ".": "./bin/pubinfo.mjs"
@@ -15,18 +15,19 @@
15
15
  "dist"
16
16
  ],
17
17
  "peerDependencies": {
18
- "@pubinfo/vite": "2.0.0-rc.2"
18
+ "@pubinfo/vite": "2.0.0-rc.4"
19
19
  },
20
20
  "dependencies": {
21
21
  "cheerio": "^1.1.2",
22
22
  "citty": "^0.1.6",
23
+ "globby": "^14.1.0",
23
24
  "pathe": "^2.0.3",
24
25
  "unconfig": "^7.3.2",
25
- "@pubinfo/commitlint": "2.0.0-rc.2"
26
+ "@pubinfo/commitlint": "2.0.0-rc.4"
26
27
  },
27
28
  "devDependencies": {
28
29
  "@types/node": "^24.0.10",
29
- "@pubinfo/vite": "2.0.0-rc.2"
30
+ "@pubinfo/vite": "2.0.0-rc.4"
30
31
  },
31
32
  "scripts": {
32
33
  "dev": "tsdown --watch",
@@ -1,77 +0,0 @@
1
- import fs from "node:fs";
2
-
3
- //#region src/commands/commit.ts
4
- /**
5
- * `pubinfo commit` 子命令:
6
- * 统一封装项目级提交体验,复用 @pubinfo/commitlint 的核心能力。
7
- * 功能概述:
8
- * 1. 交互式生成符合规范的提交信息(中文 + 可选 emoji)。
9
- * 2. 支持 `--edit` 供 commit-msg 钩子调用,读取临时文件并执行 lint。
10
- * 3. 支持 `--message/-m` 直接传入字符串校验。
11
- * 4. 支持 `--init` 一键初始化(cz 配置 / 模板 / git hooks)。
12
- * 5. 不直接执行 `git commit`,保持透明,调用者自行决定是否提交。
13
- */
14
- var commit_default = {
15
- meta: {
16
- name: "commit",
17
- description: "交互式规范 Commit Lint 提交"
18
- },
19
- args: {
20
- message: {
21
- type: "string",
22
- alias: "m",
23
- description: "直接提交 message (跳过交互)"
24
- },
25
- edit: {
26
- type: "string",
27
- description: "从 commit-msg 钩子传入的临时文件路径 (--edit $1)"
28
- },
29
- init: {
30
- type: "boolean",
31
- description: "初始化提交环境 (cz 配置 / 模板 / git hooks)"
32
- },
33
- emoji: {
34
- type: "boolean",
35
- description: "交互模式使用 emoji 类型"
36
- }
37
- },
38
- run: async ({ args }) => {
39
- const { runPrompt, loadCommitConfig, lintMessage, createCzConfigFile, initCommitEnvironment } = await import("@pubinfo/commitlint");
40
- if (args.init) {
41
- const r = initCommitEnvironment();
42
- console.log("[pubinfo commit:init]", r);
43
- return;
44
- }
45
- if (args.edit) {
46
- try {
47
- const raw = fs.readFileSync(String(args.edit), "utf8").trim();
48
- if (!raw) {
49
- console.error("[pubinfo commit] 空的 commit message");
50
- return;
51
- }
52
- await lintMessage(raw);
53
- } catch (e) {
54
- console.error("[pubinfo commit] 读取 --edit 文件失败", e);
55
- }
56
- return;
57
- }
58
- createCzConfigFile();
59
- const cfg = loadCommitConfig();
60
- if (args.message) {
61
- await lintMessage(String(args.message));
62
- console.log("\n✔ 已通过 lint,可执行: git commit -m %s");
63
- return;
64
- }
65
- const result = await runPrompt(cfg, { emoji: !!args.emoji });
66
- if (!result) {
67
- console.error("[pubinfo commit] 未能获取提交信息 (可能已取消)");
68
- return;
69
- }
70
- await lintMessage(result.raw);
71
- console.log("\nCommit message:");
72
- console.log(result.raw);
73
- }
74
- };
75
-
76
- //#endregion
77
- export { commit_default as default };
@@ -1,3 +0,0 @@
1
- import { generate_default } from "./generate-B8E8h4SV.js";
2
-
3
- export { generate_default as default };