@pubinfo/commitlint 2.0.13 → 2.0.14

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,3 +1,3 @@
1
- import { a as configureGitHooksPath, c as createGitMessage, d as runCzConfig, f as isCommitlintEnabled, i as runPrompt, l as runGitMessage, m as loadCommitConfig, n as lintMessage, o as runNpx, p as commitPreset, r as isInsideGitRepo, s as runSimpleGitHooks, t as lintAndReturn, u as createCzConfig } from "./lint.message-DVvlpU1w.js";
1
+ import { a as configureGitHooksPath, c as createGitMessage, d as runCzConfig, f as isCommitlintEnabled, i as runPrompt, l as runGitMessage, m as loadCommitConfig, n as lintMessage, o as runNpx, p as commitPreset, r as isInsideGitRepo, s as runSimpleGitHooks, t as lintAndReturn, u as createCzConfig } from "./lint.message-Cdip9x5S.js";
2
2
 
3
3
  export { commitPreset, configureGitHooksPath, createCzConfig, createGitMessage, isCommitlintEnabled, isInsideGitRepo, lintAndReturn, lintMessage, loadCommitConfig, runCzConfig, runGitMessage, runNpx, runPrompt, runSimpleGitHooks };
@@ -0,0 +1,467 @@
1
+ import { createRequire } from "node:module";
2
+ import { execSync, spawn } from "node:child_process";
3
+ import { loadConfig } from "unconfig";
4
+ import { join, resolve } from "node:path";
5
+ import process from "node:process";
6
+ import CZGPackage from "czg/package.json" with { type: "json" };
7
+ import fs from "fs-extra";
8
+ import fs$1 from "node:fs";
9
+
10
+ //#region src/config/index.ts
11
+ const notWip = [
12
+ "main",
13
+ "master",
14
+ "dev",
15
+ "test",
16
+ "release"
17
+ ];
18
+ function isMainBranch() {
19
+ try {
20
+ try {
21
+ const currentBranch = execSync("git branch --show-current", { encoding: "utf8" }).trim();
22
+ if (currentBranch) return notWip.includes(currentBranch);
23
+ } catch {
24
+ try {
25
+ const currentBranch = execSync("git symbolic-ref --short HEAD", { encoding: "utf8" }).trim();
26
+ return notWip.includes(currentBranch);
27
+ } catch {
28
+ return false;
29
+ }
30
+ }
31
+ } catch {
32
+ return false;
33
+ }
34
+ return false;
35
+ }
36
+ function generateCommitTypes() {
37
+ const allTypes = [
38
+ "feat",
39
+ "fix",
40
+ "docs",
41
+ "style",
42
+ "refactor",
43
+ "perf",
44
+ "test",
45
+ "build",
46
+ "ci",
47
+ "chore",
48
+ "revert",
49
+ "types",
50
+ "release",
51
+ "init",
52
+ "wip"
53
+ ];
54
+ if (isMainBranch()) return allTypes.filter((type) => type !== "wip");
55
+ return allTypes;
56
+ }
57
+ function generateCzGitTypes() {
58
+ const all = [
59
+ {
60
+ value: "feat",
61
+ name: "feat: ✨ 新功能",
62
+ emoji: ":sparkles:"
63
+ },
64
+ {
65
+ value: "fix",
66
+ name: "fix: 🐛 修复缺陷",
67
+ emoji: ":bug:"
68
+ },
69
+ {
70
+ value: "types",
71
+ name: "types: 🎨 类型相关",
72
+ emoji: ":art:"
73
+ },
74
+ {
75
+ value: "docs",
76
+ name: "docs: 📝 文档更新",
77
+ emoji: ":memo:"
78
+ },
79
+ {
80
+ value: "style",
81
+ name: "style: 💄 代码格式",
82
+ emoji: ":lipstick:"
83
+ },
84
+ {
85
+ value: "refactor",
86
+ name: "refactor: ♻️ 代码重构",
87
+ emoji: ":recycle:"
88
+ },
89
+ {
90
+ value: "perf",
91
+ name: "perf: ⚡️ 性能提升",
92
+ emoji: ":zap:"
93
+ },
94
+ {
95
+ value: "test",
96
+ name: "test: ✅ 测试相关",
97
+ emoji: ":white_check_mark:"
98
+ },
99
+ {
100
+ value: "build",
101
+ name: "build: 📦️ 构建相关",
102
+ emoji: ":package:"
103
+ },
104
+ {
105
+ value: "release",
106
+ name: "release: 🔖 版本提升",
107
+ emoji: ":bookmark:"
108
+ },
109
+ {
110
+ value: "ci",
111
+ name: "ci: 🎡 持续集成",
112
+ emoji: ":ferris_wheel:"
113
+ },
114
+ {
115
+ value: "revert",
116
+ name: "revert: ⏪️ 回退代码",
117
+ emoji: ":rewind:"
118
+ },
119
+ {
120
+ value: "chore",
121
+ name: "chore: 🔨 其他修改",
122
+ emoji: ":hammer:"
123
+ },
124
+ {
125
+ value: "init",
126
+ name: "init: 🎉 初始化",
127
+ emoji: ":tada:"
128
+ },
129
+ {
130
+ value: "wip",
131
+ name: "wip: 🚧 工作进行中",
132
+ emoji: ":construction:"
133
+ }
134
+ ];
135
+ if (isMainBranch()) return all.filter((t) => t.value !== "wip");
136
+ return all;
137
+ }
138
+ const commitPreset = {
139
+ extends: ["@commitlint/config-conventional"],
140
+ rules: {
141
+ "scope-enum": [0],
142
+ "type-enum": [
143
+ 2,
144
+ "always",
145
+ generateCommitTypes()
146
+ ],
147
+ "type-empty": [2, "never"],
148
+ "type-case": [
149
+ 2,
150
+ "always",
151
+ "lower-case"
152
+ ],
153
+ "subject-empty": [2, "never"],
154
+ "subject-full-stop": [
155
+ 2,
156
+ "never",
157
+ "."
158
+ ],
159
+ "subject-case": [
160
+ 2,
161
+ "never",
162
+ [
163
+ "sentence-case",
164
+ "start-case",
165
+ "pascal-case",
166
+ "upper-case"
167
+ ]
168
+ ],
169
+ "header-max-length": [
170
+ 2,
171
+ "always",
172
+ 100
173
+ ],
174
+ "body-leading-blank": [1, "always"],
175
+ "footer-leading-blank": [1, "always"]
176
+ },
177
+ prompt: {
178
+ alias: { fd: "docs: fix typos" },
179
+ messages: {
180
+ scope: "选择一个提交范围 (可回车跳过):",
181
+ customScope: "请输入自定义的提交范围 :",
182
+ type: "选择你要提交的类型 :",
183
+ subject: "填写简短精炼的变更描述 :\n",
184
+ body: "填写更加详细的变更描述(可选)。使用 \"|\" 换行 :\n",
185
+ breaking: "列举非兼容性重大的变更(可选)。使用 \"|\" 换行 :\n",
186
+ footerPrefixsSelect: "选择关联issue前缀(可选):",
187
+ customFooterPrefixs: "输入自定义issue前缀 :",
188
+ footer: "列举关联issue (可选) 例如: #31, #I3244 :\n",
189
+ confirmCommit: "是否提交或修改commit ?"
190
+ },
191
+ types: generateCzGitTypes(),
192
+ useEmoji: false,
193
+ emojiAlign: "center",
194
+ themeColorCode: "",
195
+ enableMultipleScopes: true,
196
+ skipQuestions: ["scope"],
197
+ defaultScope: "___CUSTOM___:",
198
+ customScopesAlign: "bottom",
199
+ customScopesAlias: "custom",
200
+ emptyScopesAlias: "empty",
201
+ upperCaseSubject: false,
202
+ markBreakingChangeMode: true,
203
+ allowBreakingChanges: ["feat", "fix"],
204
+ breaklineNumber: 100,
205
+ breaklineChar: "|",
206
+ issuePrefixs: [{
207
+ value: "link",
208
+ name: "link: 链接 ISSUES 进行中"
209
+ }, {
210
+ value: "closed",
211
+ name: "closed: 标记 ISSUES 已完成"
212
+ }],
213
+ customIssuePrefixsAlign: "top",
214
+ emptyIssuePrefixsAlias: "skip",
215
+ customIssuePrefixsAlias: "custom",
216
+ allowCustomIssuePrefixs: true,
217
+ allowEmptyIssuePrefixs: true,
218
+ confirmColorize: true,
219
+ maxHeaderLength: Number.POSITIVE_INFINITY,
220
+ maxSubjectLength: Number.POSITIVE_INFINITY,
221
+ minSubjectLength: 0,
222
+ scopeOverrides: void 0,
223
+ defaultBody: "",
224
+ defaultIssues: "",
225
+ defaultSubject: ""
226
+ }
227
+ };
228
+ function loadCommitConfig() {
229
+ return commitPreset;
230
+ }
231
+
232
+ //#endregion
233
+ //#region src/config/commitlint.ts
234
+ let cachedState;
235
+ function resolveCommitlintEnabled(value) {
236
+ if (typeof value === "boolean") return value;
237
+ if (value && typeof value === "object") {
238
+ if (typeof value.enabled === "boolean") return value.enabled;
239
+ if (typeof value.disable === "boolean") return !value.disable;
240
+ }
241
+ }
242
+ async function isCommitlintEnabled() {
243
+ if (typeof cachedState === "boolean") return cachedState;
244
+ try {
245
+ const resolved = resolveCommitlintEnabled((await loadConfig({
246
+ sources: [{ files: "pubinfo.config" }],
247
+ merge: false
248
+ }))?.config?.commitlint);
249
+ cachedState = typeof resolved === "boolean" ? resolved : true;
250
+ } catch {
251
+ cachedState = true;
252
+ }
253
+ return cachedState;
254
+ }
255
+
256
+ //#endregion
257
+ //#region src/init/cz.config.ts
258
+ function createCzConfig(cwd = process.cwd()) {
259
+ const target = resolve(cwd, "cz.config.cjs");
260
+ if (fs.existsSync(target)) fs.unlinkSync(target);
261
+ try {
262
+ const cfg = {
263
+ $schema: `https://raw.githubusercontent.com/Zhengqbbb/cz-git/refs/tags/v${CZGPackage.version}/docs/public/schema/cz-git.json`,
264
+ ...commitPreset.prompt,
265
+ types: commitPreset.prompt?.types?.map((t) => ({
266
+ value: t.value,
267
+ name: t.name,
268
+ emoji: t.emoji
269
+ })),
270
+ scopes: commitPreset.prompt?.scopes
271
+ };
272
+ const content = `module.exports = ${JSON.stringify(cfg, null, 2)}\n`;
273
+ fs.writeFileSync(target, content, "utf8");
274
+ return true;
275
+ } catch {
276
+ return false;
277
+ }
278
+ }
279
+ function runCzConfig(czConfigPath, cwd = process.cwd()) {
280
+ const packagePath = resolve(cwd, "package.json");
281
+ if (!fs.existsSync(packagePath)) return false;
282
+ try {
283
+ const raw = fs.readFileSync(packagePath, "utf8");
284
+ const json = JSON.parse(raw);
285
+ const desiredPath = "node_modules/cz-git";
286
+ const desiredCzConfig = czConfigPath;
287
+ json.config = json.config || {};
288
+ json.config.commitizen = json.config.commitizen || {};
289
+ let changed = false;
290
+ if (json.config.commitizen.path !== desiredPath) {
291
+ json.config.commitizen.path = desiredPath;
292
+ changed = true;
293
+ }
294
+ const currentCz = json.config.commitizen.czConfig;
295
+ const normalize = (p) => p ? p.replace(/^\.\/?/, "") : p;
296
+ const isOldRoot = normalize(currentCz) === "cz.config.cjs" || normalize(currentCz) === "cz.config.js";
297
+ if (!currentCz || isOldRoot || normalize(currentCz) === "cz.config.mjs") {
298
+ if (currentCz !== desiredCzConfig) {
299
+ json.config.commitizen.czConfig = desiredCzConfig;
300
+ changed = true;
301
+ }
302
+ }
303
+ if (!changed) return false;
304
+ fs.writeFileSync(packagePath, `${JSON.stringify(json, null, 2)}\n`, "utf8");
305
+ return true;
306
+ } catch {
307
+ return false;
308
+ }
309
+ }
310
+
311
+ //#endregion
312
+ //#region src/init/git.message.ts
313
+ function createGitMessage(rootPath = process.cwd()) {
314
+ const target = resolve(rootPath, ".gitmessage");
315
+ if (fs.existsSync(target)) fs.unlinkSync(target);
316
+ const tpl = `# Commit Message 模板 (首行: <type>(<scope>): <subject>)\n# 可用类型: ${(commitPreset.prompt?.types || []).map((t) => t.value).join(", ")}\n# 可用范围: ${(commitPreset.prompt?.scopes || []).join(", ")}\n# 示例: feat(core): add http client abstraction\n# 空行后可写入 body, 使用 | 换行 (交互模式会自动处理)\n`;
317
+ fs.writeFileSync(target, tpl, "utf8");
318
+ return true;
319
+ }
320
+ function runGitMessage(rootPath = process.cwd()) {
321
+ try {
322
+ if (execSync("git config --get commit.template", {
323
+ cwd: rootPath,
324
+ stdio: "pipe"
325
+ }).toString().trim()) return false;
326
+ } catch {}
327
+ try {
328
+ execSync("git config commit.template .gitmessage", {
329
+ cwd: rootPath,
330
+ stdio: "ignore"
331
+ });
332
+ return true;
333
+ } catch {
334
+ return false;
335
+ }
336
+ }
337
+
338
+ //#endregion
339
+ //#region src/init/simple.git.hook.ts
340
+ function runSimpleGitHooks(script = "pubinfo-commit", cwd = process.cwd(), enabled = true) {
341
+ if (!enabled) return false;
342
+ const pkgPath = resolve(cwd, "package.json");
343
+ if (!fs.existsSync(pkgPath)) return false;
344
+ try {
345
+ const raw = fs.readFileSync(pkgPath, "utf8");
346
+ const json = JSON.parse(raw);
347
+ const hooks = json["simple-git-hooks"] || {};
348
+ const desiredPre = "pnpm lint-staged";
349
+ const desiredCommitMsg = `pnpm exec ${script} --edit $1`;
350
+ json["simple-git-hooks"] = hooks;
351
+ if (hooks["pre-commit"] !== desiredPre) hooks["pre-commit"] = desiredPre;
352
+ if (hooks["commit-msg"] !== desiredCommitMsg) hooks["commit-msg"] = desiredCommitMsg;
353
+ json["simple-git-hooks"] = hooks;
354
+ fs.writeFileSync(pkgPath, `${JSON.stringify(json, null, 2)}\n`, "utf8");
355
+ return true;
356
+ } catch {
357
+ return false;
358
+ }
359
+ }
360
+ function runNpx(cwd = process.cwd()) {
361
+ try {
362
+ execSync("npx simple-git-hooks", {
363
+ cwd,
364
+ stdio: "ignore"
365
+ });
366
+ return true;
367
+ } catch {
368
+ return false;
369
+ }
370
+ }
371
+ function configureGitHooksPath(enabled = true, cwd = process.cwd()) {
372
+ try {
373
+ if (enabled) {
374
+ execSync("git config --unset core.hooksPath", {
375
+ cwd,
376
+ stdio: "ignore"
377
+ });
378
+ return true;
379
+ }
380
+ execSync("git config core.hooksPath /dev/null", {
381
+ cwd,
382
+ stdio: "ignore"
383
+ });
384
+ return true;
385
+ } catch {
386
+ return enabled;
387
+ }
388
+ }
389
+
390
+ //#endregion
391
+ //#region src/prompt/index.ts
392
+ async function runPrompt() {
393
+ try {
394
+ const require = createRequire(import.meta.url);
395
+ try {
396
+ const czg = require("czg");
397
+ if (czg && typeof czg.default === "function") {
398
+ const api = await czg.default({ emoji: false });
399
+ if (api && api.raw) return { raw: api.raw };
400
+ }
401
+ } catch {}
402
+ const binDir = resolve(process.cwd(), "node_modules/.bin");
403
+ const isWin = process.platform === "win32";
404
+ const czgBin = (isWin ? [
405
+ join(binDir, "czg.cmd"),
406
+ join(binDir, "czg.ps1"),
407
+ join(binDir, "czg")
408
+ ] : [join(binDir, "czg")]).find((p) => fs$1.existsSync(p));
409
+ if (czgBin) {
410
+ await new Promise((res) => {
411
+ const child = spawn(czgBin, [], {
412
+ stdio: "inherit",
413
+ shell: isWin
414
+ });
415
+ child.on("exit", () => res());
416
+ child.on("error", () => res());
417
+ });
418
+ const msgPath = resolve(process.cwd(), ".git/COMMIT_EDITMSG");
419
+ if (fs$1.existsSync(msgPath)) return { raw: fs$1.readFileSync(msgPath, "utf8").trim() };
420
+ }
421
+ return null;
422
+ } catch {
423
+ return null;
424
+ }
425
+ }
426
+
427
+ //#endregion
428
+ //#region src/utils/git.ts
429
+ /**
430
+ * 判断当前工作目录是否处在 Git 仓库内。
431
+ */
432
+ function isInsideGitRepo() {
433
+ try {
434
+ const out = execSync("git rev-parse --is-inside-work-tree", { stdio: [
435
+ "ignore",
436
+ "pipe",
437
+ "ignore"
438
+ ] });
439
+ return String(out).trim() === "true";
440
+ } catch {
441
+ return false;
442
+ }
443
+ }
444
+
445
+ //#endregion
446
+ //#region src/utils/lint.message.ts
447
+ async function lintMessage(message) {
448
+ if (!await isCommitlintEnabled()) return true;
449
+ try {
450
+ const result = await (await import("@commitlint/lint")).default(message, commitPreset.rules, commitPreset);
451
+ if (!result.valid) {
452
+ console.error("✖ Commit message failed lint:\n");
453
+ for (const err of result.errors) console.error(` • ${err.message}`);
454
+ process.exit(1);
455
+ }
456
+ } catch (e) {
457
+ console.error("[pubinfo-commit] lint failed to run:", e);
458
+ }
459
+ return true;
460
+ }
461
+ async function lintAndReturn(message) {
462
+ await lintMessage(message);
463
+ return message;
464
+ }
465
+
466
+ //#endregion
467
+ export { configureGitHooksPath as a, createGitMessage as c, runCzConfig as d, isCommitlintEnabled as f, runPrompt as i, runGitMessage as l, loadCommitConfig as m, lintMessage as n, runNpx as o, commitPreset as p, isInsideGitRepo as r, runSimpleGitHooks as s, lintAndReturn as t, createCzConfig as u };
package/dist/run.js CHANGED
@@ -1,11 +1,11 @@
1
- import { a as configureGitHooksPath, c as createGitMessage, d as runCzConfig, f as isCommitlintEnabled, i as runPrompt, l as runGitMessage, n as lintMessage, o as runNpx, r as isInsideGitRepo, s as runSimpleGitHooks, u as createCzConfig } from "./lint.message-DVvlpU1w.js";
1
+ import { a as configureGitHooksPath, c as createGitMessage, d as runCzConfig, f as isCommitlintEnabled, i as runPrompt, l as runGitMessage, n as lintMessage, o as runNpx, r as isInsideGitRepo, s as runSimpleGitHooks, u as createCzConfig } from "./lint.message-Cdip9x5S.js";
2
2
  import process from "node:process";
3
3
  import fs from "node:fs";
4
4
  import { defineCommand, runMain as runMain$1 } from "citty";
5
5
 
6
6
  //#region package.json
7
7
  var name = "@pubinfo/commitlint";
8
- var version = "2.0.13";
8
+ var version = "2.0.14";
9
9
  var description = "commitlint config for Pubinfo projects";
10
10
 
11
11
  //#endregion
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pubinfo/commitlint",
3
3
  "type": "module",
4
- "version": "2.0.13",
4
+ "version": "2.0.14",
5
5
  "description": "commitlint config for Pubinfo projects",
6
6
  "exports": {
7
7
  ".": "./dist/index.js"
@@ -33,7 +33,8 @@
33
33
  "@commitlint/load": "^19.8.1",
34
34
  "citty": "^0.1.6",
35
35
  "czg": "^1.12.0",
36
- "unconfig": "^7.3.2"
36
+ "fs-extra": "^11.3.0",
37
+ "unconfig": "^7.3.3"
37
38
  },
38
39
  "scripts": {
39
40
  "build": "tsdown",