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

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.
@@ -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 void 0;
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.3";
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
  };
@@ -51,7 +52,7 @@ const commands = {
51
52
  preview: () => import("./preview-IG8wXay6.js").then(_rDefault),
52
53
  generate: () => import("./generate-De0efY0o.js").then(_rDefault),
53
54
  commit: () => import("./commit-BT18KgTK.js").then(_rDefault),
54
- icon: () => import("./icon-DEFBRPY4.js").then(_rDefault)
55
+ icon: () => import("./icon-BPS--AyP.js").then(_rDefault)
55
56
  };
56
57
 
57
58
  //#endregion
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.3",
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.3"
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.3"
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.3"
30
31
  },
31
32
  "scripts": {
32
33
  "dev": "tsdown --watch",