my-code-style 1.8.0 → 1.8.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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  ## 变更日志
2
2
 
3
+ ## [1.8.2](https://github.com/myvn/codeStyle/compare/v1.8.1...v1.8.2) (2026-09-21)
4
+
5
+
6
+ ### 🐛 Bug Fixes | Bug 修复
7
+
8
+ * versionrc 静默压优先级警告 + CHANGELOG 结构修复 + 发布工具迁移 catv@12 ([d1b8abf](https://github.com/myvn/codeStyle/commit/d1b8abfcccb595c33d4b9490e87b0599fe37b6bc))
9
+
10
+ ### [1.8.1](https://github.com/myvn/codeStyle/compare/v1.8.0...v1.8.1) (2026-09-20)
11
+
12
+
13
+ ### 🐛 Bug Fixes | Bug 修复
14
+
15
+ * **init:** 安装命令里的版本范围加引号,粘贴不再被 shell 截断 ([9abaf1d](https://github.com/myvn/codeStyle/commit/9abaf1d76ea3aff05f0d26d11a43e8661ed6221a))
16
+
17
+
18
+ ### ✨ Features | 新功能
19
+
20
+ * **init:** 输出步骤化为固定六步,dry-run 全流程预览 ([f14ca47](https://github.com/myvn/codeStyle/commit/f14ca47449b7d3e8f9a381b6e145e99232586886))
21
+
3
22
  ## [1.8.0](https://github.com/myvn/codeStyle/compare/v1.7.2...v1.8.0) (2026-09-20)
4
23
 
5
24
  ### ✨ Features | 新功能
@@ -12,8 +31,6 @@
12
31
  - **publish:** 增强 provenance 校验与日志自证,同步文档与发布流程 ([ba6db63](https://github.com/myvn/codeStyle/commit/ba6db63dce8144f53ad2be9c49278ff67b924518))
13
32
  - **修复:** Merge branch 'arena/01a0b214-codestyle' ([7c024dc](https://github.com/myvn/codeStyle/commit/7c024dce1bc1ef9d7fc9ef03b74f936b87a4704a))
14
33
 
15
- ## [1.5.0](https://github.com/myvn/codeStyle/compare/v1.4.0...v1.5.0) (2026-09-18)
16
-
17
34
  ### [1.7.2](https://github.com/myvn/codeStyle/compare/v1.7.1...v1.7.2) (2026-09-20)
18
35
 
19
36
  ### 🐛 Bug Fixes | Bug 修复
package/README.md CHANGED
@@ -189,7 +189,7 @@ module.exports = {
189
189
  | `my-code-style/stylelint/less-override` | Less 专用覆写配置 |
190
190
  | `my-code-style/commitlint` | Commitlint 基础配置 |
191
191
  | `my-code-style/commitlint/scopes` | 动态 scope 工具函数 |
192
- | `my-code-style/versionrc` | standard-version 配置 |
192
+ | `my-code-style/versionrc` | commit-and-tag-version 配置 |
193
193
 
194
194
  ## CLI 初始化参数
195
195
 
@@ -213,7 +213,7 @@ npx my-code-style-init [--dry-run] [--backup] [--version|-v] [--help|-h]
213
213
  - **现代化 Git Hooks**:采用 Husky 9 原生极简 hook + lint-staged 互斥文件分组,串行运行、消除并发写入缓存冲突
214
214
  - **Stylelint SCSS、Less 及混合工程双支持**:支持纯 SCSS、纯 Less 以及两者共存的混合工程,放行 `@` 变量、小程序 `rpx`/`page`、深度选择器 `::v-deep` 及现代 CSS 伪类,组件内嵌多预处理器样式全面检查
215
215
  - **严格暂存区 Scope 猜测**:`guessCurrentScope()` 严格只依据 Git 暂存区推断 scope,支持多目录频次投票、重命名、物理删除、中文路径与空格路径
216
- - **ESM 兼容的自动版本发布**:支持 CommonJS(`.versionrc.js`)与 ESM(`.versionrc.cjs`)工程无缝对接 standard-version,一键版本递增与 CHANGELOG 生成
216
+ - **ESM 兼容的自动版本发布**:支持 CommonJS(`.versionrc.js`)与 ESM(`.versionrc.cjs`)工程无缝对接 commit-and-tag-version(standard-version 的社区维护分支),一键版本递增与 CHANGELOG 生成
217
217
 
218
218
  ## 常见问题(使用中遇到的问题)
219
219
 
@@ -239,10 +239,10 @@ npx my-code-style-init [--dry-run] [--backup] [--version|-v] [--help|-h]
239
239
  ## 测试套件
240
240
 
241
241
  ```bash
242
- npm run test:all # 全量运行 175 项:用例明细 + 分类统计 + 最慢文件定位
242
+ npm run test:all # 全量运行 179 项:用例明细 + 分类统计 + 最慢文件定位
243
243
  npm run diagnose # 换机器后先跑它:进程 / git / 文件系统 / hooks 各占多少
244
244
  npm run sweep # 给本机找最佳文件级并发(扫 integration 套件)
245
- npm test # 只跑基础 CLI 与配置矩阵(81 项)
245
+ npm test # 只跑基础 CLI 与配置矩阵(85 项)
246
246
  npm run test:integration:setup # 安装现代化隔离依赖运行环境
247
247
  npm run test:integration # Flat Config、真实 Husky 及提交链路测试(59 项)
248
248
  npm run test:legacy:setup # 安装 ESLint 8 隔离运行环境
@@ -257,46 +257,46 @@ npm run test:stylelint17 # Stylelint 17 生态兼容性回归(8 项)
257
257
  ```text
258
258
  my-code-style 测试套件
259
259
 
260
- ▶ [1/4] 基础 CLI 与配置矩阵 (共 81 项,5 文件 · 3 文件并发(自动:2 核 / 内存 4G))
261
- ✓ 运行器 TAP 解析:统计通过与失败、SKIP 与每用例耗时 · 2ms
262
- ✓ 运行器表格:CJK 宽度按两列计算,耗时格式化区分秒与毫秒 · 1ms
260
+ ▶ [1/4] 基础 CLI 与配置矩阵 (共 85 项,5 文件 · 3 文件并发(自动:2 核 / 内存 4G))
261
+ ✓ 运行器 TAP 解析:统计通过与失败、SKIP 与每用例耗时 · 7ms
263
262
  ✓ cz 交互提示为中文,且可选类型与 type-enum 一一对应 · 1ms
264
- ✓ 初始化结尾指引把 cz 用法说清楚(先 git add + 指到 README 手册) · 83ms
263
+ ✓ 一键安装命令对含 || 的版本范围加引号,可整段粘贴执行 · 44ms
264
+ ✓ 初始化结尾指引把 cz 用法说清楚(先 git add + 指到 README 手册) · 80ms
265
265
  …
266
- ✓ 通过 81 · 3.8s · 最慢文件 init-matrix.test.cjs 3.5s
266
+ ✓ 通过 85 · 3.7s · 最慢文件 init-matrix.test.cjs 3.2s
267
267
 
268
268
  ▶ [2/4] 现代工具链与提交链 (共 59 项,23 文件 · 3 文件并发(自动:2 核 / 内存 4G))
269
- ✓ 完整提交链:JS/TS/Vue/nvue/CSS/less 自动修复及二次复检 · 10.9s
270
- ✓ 发布防呆:HEAD 已有 v* tag 时拦截(此时 standard-version 会静默抬版并写出空 CHANGELOG) · 461ms
269
+ ✓ 完整提交链:JS/TS/Vue/nvue/CSS/less 自动修复及二次复检 · 10.4s
270
+ ✓ 发布防呆:HEAD 已有 v* tag 时拦截(此时 release 工具会静默抬版并写出空 CHANGELOG) · 609ms
271
271
  …
272
- ✓ 通过 59 · 41.6s · 最慢文件 commit-chain-scss.test.cjs 11.5s
272
+ ✓ 通过 59 · 41.0s · 最慢文件 commit-chain-both.test.cjs 10.6s
273
273
 
274
274
  ▶ [3/4] ESLint 8 兼容性 (共 27 项,1 文件 · 3 文件并发(自动:2 核 / 内存 4G))
275
275
  ✓ 独立运行 ESLint 8 支持下限而非 ESLint 9 · 1ms
276
- ✓ ESLint 8 base:实际 CLI 加载生成配置并接受正常文件 · 1.7s
276
+ ✓ ESLint 8 base:实际 CLI 加载生成配置并接受正常文件 · 1.3s
277
277
  …
278
- ✓ 通过 27 · 20.5s
278
+ ✓ 通过 27 · 18.3s
279
279
 
280
280
  ▶ [4/4] Stylelint 17 兼容性 (共 8 项,1 文件 · 3 文件并发(自动:2 核 / 内存 4G))
281
281
  ✓ 隔离环境装的是 stylelint 17(不是 16) · 2ms
282
- ✓ 生成的 .stylelintrc.cjs 在 stylelint 17 下可加载并放过正常 SCSS · 747ms
282
+ ✓ 生成的 .stylelintrc.cjs 在 stylelint 17 下可加载并放过正常 SCSS · 700ms
283
283
  …
284
- ✓ 通过 8 · 7.5s
284
+ ✓ 通过 8 · 7.2s
285
285
 
286
286
  ──────────────────────────────────────────────────────
287
287
  套件 通过 失败 跳过 用时
288
288
  ──────────────────────────────────────────────────────
289
- 基础 CLI 与配置矩阵 81 0 - 3.8s
290
- 现代工具链与提交链 59 0 - 41.6s
291
- ESLint 8 兼容性 27 0 - 20.5s
292
- Stylelint 17 兼容性 8 0 - 7.5s
289
+ 基础 CLI 与配置矩阵 85 0 - 3.7s
290
+ 现代工具链与提交链 59 0 - 41.0s
291
+ ESLint 8 兼容性 27 0 - 18.3s
292
+ Stylelint 17 兼容性 8 0 - 7.2s
293
293
  ──────────────────────────────────────────────────────
294
- 合计 175 0 - 73.5s
294
+ 合计 179 0 - 71.1s
295
295
  ──────────────────────────────────────────────────────
296
296
 
297
- ⏱ 最慢文件:eslint8.test.cjs 20.5s · commit-chain-scss.test.cjs 11.5s · commit-chain-both.test.cjs 11.2s
297
+ ⏱ 最慢文件:eslint8.test.cjs 18.3s · commit-chain-both.test.cjs 10.6s · commit-chain-scss.test.cjs 10.6s
298
298
 
299
- ✅ 全部通过:175/175 项,用时 73.5s
299
+ ✅ 全部通过:179/179 项,用时 71.1s
300
300
  ```
301
301
 
302
302
  终端里每个套件下方还有一条实时进度条(`██████░░░░ 38/66 失败 0 4.0s`)。附加参数:
@@ -353,7 +353,7 @@ npm run test:all -- --profile # 看每个测试文件耗时,定位瓶颈
353
353
  | `partial-staging{,-unstaged,-invalid-message,-conflict}` | 0.5–1.7s | 部分暂存与冲突恢复 |
354
354
  | `error-recovery-{css,scss,less,js,ts,vue,nvue}` | 0.5–1.4s | 不可修复错误的回滚 |
355
355
  | `lint` | 3.9s | 32 条规则与格式化行为(无提交链) |
356
- | `release` | 0.8s | standard-version |
356
+ | `release` | 0.8s | commit-and-tag-version |
357
357
 
358
358
  两层并发都要控制规模,所以默认并发不交给 Node 猜,而是运行器自己算——**核数 × 1.5
359
359
  (至少 核数 - 1),再乘内存上限,最后封顶 8**(16 核机器实测:4/6/8/12/16/24 并发对应
@@ -374,7 +374,7 @@ npm run test:all -- --profile # 看每个测试文件耗时,定位瓶颈
374
374
  | `npm run test:integration`(运行器调度,自动并发 3) | 30.6s(只看集成套件那一段) |
375
375
  | 串行套件 + 文件级并发 23(全部一波) | ✗ 3.8G 内存沙箱被 OOM 压垮(19 项 SIGKILL) |
376
376
 
377
- 同机复测(175 项,同一台 2 核沙箱连续跑;绝对秒数随机器负载波动,相对关系稳定):串行套件 + 文件级并发 1 = 85.1s、默认自动并发 3 = 73.5s、`--parallel` 四套件 = 63.8s、`npm run test:integration` = 40.7s、`node --test demo-test/integration/*.test.cjs` = 54.5s。
377
+ 同机复测(179 项,同一台 2 核沙箱连续跑;绝对秒数随机器负载波动,相对关系稳定):串行套件 + 文件级并发 1 = 70.4s、默认自动并发 3 = 71.1s、`--parallel` 四套件 = 66.8s、`npm run test:integration` = 41.2s、`node --test demo-test/integration/*.test.cjs` = 53.3s。
378
378
 
379
379
  (2 核沙箱里并行收益被 CPU 争抢吃掉大半,`--concurrency=1` 时单个文件只要 0.7–4.2s;
380
380
  16 核机器上集成套件那段 ≈ 最慢子文件,即"一次真实提交"的量级。)
@@ -399,7 +399,7 @@ npm run release:push
399
399
 
400
400
  也可以拆成两步:`npm run release` 只做到打 tag,之后用 `git push --follow-tags origin <分支>` 手动推送。
401
401
 
402
- > ⚠️ **别把两条命令连起来跑**:`release` 已经把 tag 打在 HEAD 上了,紧接着跑 `release:push`,standard-version **不会报错**,而是把版本号再抬一级、写出一个没有条目的空 CHANGELOG 并打出第二个 tag —— 等于多发一个空版本(npm 上不可撤销)。
402
+ > ⚠️ **别把两条命令连起来跑**:`release` 已经把 tag 打在 HEAD 上了,紧接着跑 `release:push`,发布工具 **不会报错**,而是把版本号再抬一级、写出一个没有条目的空 CHANGELOG 并打出第二个 tag —— 等于多发一个空版本(npm 上不可撤销)。
403
403
  >
404
404
  > 两条命令的第一步都是 `scripts/release-guard.cjs` 发布前防呆,命中下面两种情况会直接中止并打印该执行的命令:HEAD 上已经有 `v*` tag(说明这一版已生成,只差推送)、已跟踪文件还有未提交改动(会被卷进版本提交)。未跟踪文件不拦截。
405
405
 
package/bin/init CHANGED
@@ -65,7 +65,6 @@ function ensureGitignoreEntry(entry) {
65
65
  `${content}${separator}\n# my-code-style 初始化备份目录\n${entry}\n`,
66
66
  "utf8",
67
67
  )
68
- log(`已将 ${entry} 追加到 .gitignore`)
69
68
  }
70
69
 
71
70
  function getProjectPkg() {
@@ -431,6 +430,28 @@ function addDevCommand(packageManager) {
431
430
  }
432
431
  }
433
432
 
433
+ // 步骤标题行:CJK 字符按 2 列计宽,右侧补齐横线,让每个步骤标题线等长
434
+ function displayWidth(text) {
435
+ let width = 0
436
+ for (const ch of text) {
437
+ width += ch.codePointAt(0) > 0xff ? 2 : 1
438
+ }
439
+ return width
440
+ }
441
+
442
+ function stepHeader(current, total, title) {
443
+ const head = `步骤 ${current}/${total} · ${title}`
444
+ const pad = Math.max(4, 46 - displayWidth(head))
445
+ console.log(`\n ── ${head} ${"─".repeat(pad)}`)
446
+ }
447
+
448
+ // 打印安装规格时按需加引号:`name@range` 里含 || 或 >= 等字符会被 shell 当成
449
+ // 管道/重定向,把整条命令截断(stylelint@^16.24.0 || ^17.0.0 原样粘贴必炸)。
450
+ // 规格含安全字符集(字母数字 @ / . _ ^ ~ -)之外的任何字符就整体包一层双引号。
451
+ function shellSafeSpec(spec) {
452
+ return /[^A-Za-z0-9@/._^~-]/.test(spec) ? `"${spec}"` : spec
453
+ }
454
+
434
455
  /**
435
456
  * `pnpm prepare` / `yarn prepare` run the script directly, but npm needs an
436
457
  * explicit `npm run prepare` (plain `npm prepare` is not a command).
@@ -600,7 +621,7 @@ module.exports = {
600
621
  }
601
622
 
602
623
  function versionrcContent() {
603
- return `// standard-version config — powered by my-code-style
624
+ return `// commit-and-tag-version config — powered by my-code-style
604
625
  module.exports = require("my-code-style/versionrc")
605
626
  `
606
627
  }
@@ -712,15 +733,17 @@ function main() {
712
733
  }
713
734
 
714
735
  const dryRun = process.argv.includes("--dry-run")
715
- const label = dryRun ? "[DRY RUN] " : ""
716
736
 
717
- console.log("")
718
- console.log(" my-code-style-init — 初始化项目配置")
719
- console.log("")
737
+ let toolVersion = ""
738
+ try {
739
+ toolVersion = ` v${require("../package.json").version}`
740
+ } catch {}
720
741
 
742
+ console.log("")
743
+ console.log(` my-code-style-init${toolVersion} — 把 my-code-style 接入当前项目`)
721
744
  if (dryRun) {
722
- warn("Dry run mode — no files will be written")
723
745
  console.log("")
746
+ warn("Dry run 预览模式:以下所有步骤都不会写入文件")
724
747
  }
725
748
 
726
749
  // --- Detection phase ---
@@ -752,11 +775,7 @@ function main() {
752
775
  return
753
776
  }
754
777
 
755
- if (eslintVersion !== null && eslintVersion > 10) {
756
- warn(
757
- `ESLint ${eslintVersion} 尚未在 peerDependencies 声明支持(^8.57.0 || ^9.0.0 || ^10.0.0),将按 Flat Config 生成`,
758
- )
759
- }
778
+ const eslintUnannounced = eslintVersion !== null && eslintVersion > 10
760
779
 
761
780
  // Do not silently mix an installed major version with an incompatible format.
762
781
  if (
@@ -777,21 +796,32 @@ function main() {
777
796
  const useFlatConfig = eslintVersion !== 8
778
797
  const eslintFormat = useFlatConfig ? "flat" : "eslintrc"
779
798
 
780
- log(`检测到 ESLint 版本: ${eslintVersion || "默认最新 (9+)"} → 使用 ${eslintFormat} 格式`)
781
- log(
782
- `检测到项目类型: ${projectType === "uniapp" ? "uni-app" : projectType === "vue" ? "Vue" : "Node/TS 基础"}`,
799
+ stepHeader(1, 6, "检测项目环境")
800
+ console.log(` · 包管理器:${pm}`)
801
+ console.log(
802
+ ` · ESLint:${eslintVersion || "未声明,按已安装版本处理"} → ${eslintFormat === "flat" ? "Flat Config" : "传统 .eslintrc 格式"}`,
783
803
  )
784
- log(
785
- `检测到 CSS 预处理器: ${cssPreprocessor === "both" ? "SCSS + Less (混合)" : cssPreprocessor}`,
804
+ console.log(
805
+ ` · 项目类型:${projectType === "uniapp" ? "uni-app" : projectType === "vue" ? "Vue" : "Node/TS 基础库"}`,
786
806
  )
787
- console.log("")
807
+ console.log(
808
+ ` · CSS 预处理器:${cssPreprocessor === "both" ? "SCSS + Less(混合)" : cssPreprocessor === "none" ? "未检测到" : cssPreprocessor}`,
809
+ )
810
+ if (eslintUnannounced) {
811
+ warn(
812
+ `ESLint ${eslintVersion} 尚未在 peerDependencies 声明支持(^8.57.0 || ^9.0.0 || ^10.0.0),将按 Flat Config 生成`,
813
+ )
814
+ }
788
815
 
789
816
  // --- Build file list based on detection ---
790
817
  const files = []
818
+ let skipStylelint = false
791
819
 
820
+ stepHeader(2, 6, "ESLint 入口")
792
821
  if (hasFlatConfigFile || hasLegacyConfigFile) {
793
- log("保留已有 ESLint 配置,不生成额外入口")
822
+ console.log(" 保留已有 ESLint 配置,不生成额外入口")
794
823
  } else if (useFlatConfig) {
824
+ console.log(" 生成 Flat Config 入口 eslint.config.mjs")
795
825
  files.push({
796
826
  path: "eslint.config.mjs",
797
827
  exists:
@@ -802,6 +832,7 @@ function main() {
802
832
  content: eslintFlatConfigContent(projectType),
803
833
  })
804
834
  } else {
835
+ console.log(" 生成传统格式入口 .eslintrc.cjs")
805
836
  files.push({
806
837
  path: ".eslintrc.cjs",
807
838
  exists: fileExists(".eslintrc.cjs"),
@@ -829,7 +860,7 @@ function main() {
829
860
  content: stylelintrcContent(cssPreprocessor),
830
861
  })
831
862
  } else {
832
- log("跳过 Stylelint 配置 (未检测到 CSS 预处理器)")
863
+ skipStylelint = true
833
864
  }
834
865
 
835
866
  files.push({
@@ -844,11 +875,10 @@ function main() {
844
875
  versionrcPath = ".versionrc.cjs"
845
876
  }
846
877
 
847
- if (isEsm && fileExists(".versionrc.js") && !fileExists(".versionrc.cjs")) {
848
- warn(
849
- "检测到 ESM 项目 (type: module) 存在旧的 .versionrc.js,standard-version 需使用 .versionrc.cjs",
850
- )
851
- }
878
+ const staleVersionrc = isEsm && fileExists(".versionrc.js") && !fileExists(".versionrc.cjs")
879
+ // 发布工具读配置的顺序是 ['.versionrc', '.versionrc.cjs', '.versionrc.json', '.versionrc.js']:
880
+ // 无扩展名或 .json 的旧文件会压过本次生成的 .versionrc.cjs(实测 standard-version 9.5 / catv 均如此)
881
+ const staleVersionrcTop = [".versionrc", ".versionrc.json"].filter((f) => fileExists(f))
852
882
 
853
883
  files.push({
854
884
  path: versionrcPath,
@@ -876,12 +906,17 @@ function main() {
876
906
  })
877
907
  }
878
908
 
879
- // Show what will be created/overwritten
909
+ const backup = args.includes("--backup")
910
+ stepHeader(3, 6, "配置文件与 Git hooks")
911
+ let overwriteTotal = 0
912
+ let createTotal = 0
880
913
  for (const f of files) {
881
914
  if (f.exists) {
882
- warn(`${label}覆盖 ${f.path}`)
915
+ overwriteTotal++
916
+ console.log(` 覆盖 ${f.path}`)
883
917
  } else {
884
- success(`${label}创建 ${f.path}`)
918
+ createTotal++
919
+ console.log(` 新建 ${f.path}`)
885
920
  }
886
921
  }
887
922
 
@@ -889,7 +924,7 @@ function main() {
889
924
  const huskyDir = path.resolve(PROJECT_ROOT, ".husky")
890
925
  const hasHusky = fs.existsSync(huskyDir)
891
926
  if (!hasHusky) {
892
- success(`${label}创建 .husky/ 目录`)
927
+ console.log(" 新建 .husky/ 目录")
893
928
  }
894
929
 
895
930
  const hooks = [
@@ -899,23 +934,91 @@ function main() {
899
934
 
900
935
  for (const h of hooks) {
901
936
  if (fileExists(h.path)) {
902
- warn(`${label}覆盖 ${h.path}`)
937
+ overwriteTotal++
938
+ console.log(` 覆盖 ${h.path}`)
903
939
  } else {
904
- success(`${label}创建 ${h.path}`)
940
+ createTotal++
941
+ console.log(` 新建 ${h.path}`)
905
942
  }
906
943
  }
907
944
 
908
- if (dryRun) {
945
+ console.log(
946
+ ` 小计:覆盖 ${overwriteTotal} 个 · 新建 ${createTotal} 个` +
947
+ (backup ? " · 旧文件将备份到 .my-code-style-backup/" : "") +
948
+ (dryRun ? "(Dry run 预览,不写入)" : ""),
949
+ )
950
+ if (skipStylelint) {
951
+ console.log(" · 跳过 .stylelintrc.cjs(未检测到 CSS 预处理器)")
952
+ }
953
+ if (staleVersionrc) {
954
+ warn(
955
+ "检测到 ESM 项目 (type: module) 存在旧的 .versionrc.js,发布工具需要使用 .versionrc.cjs",
956
+ )
957
+ }
958
+ if (staleVersionrcTop.length > 0) {
959
+ warn(
960
+ `检测到 ${staleVersionrcTop.join("、")}:发布工具会优先读取它,本次生成的 .versionrc.cjs 不会生效;请把配置合并进来或删除旧文件`,
961
+ )
962
+ }
963
+
964
+ const printPackageJsonStep = () => {
965
+ stepHeader(4, 6, "package.json")
966
+ if (dryRun) {
967
+ console.log(
968
+ " · 将更新 scripts(lint / lint:fix / format / prepare / release / cz)与 lint-staged",
969
+ )
970
+ return
971
+ }
972
+ console.log(" ✓ scripts 已更新(lint / lint:fix / format / prepare / release / cz)")
973
+ console.log(" ✓ lint-staged 已按检测到的 CSS 预处理器生成")
974
+ }
975
+
976
+ const printDepsStep = () => {
977
+ stepHeader(5, 6, "依赖体检")
978
+ const findings = checkPeerDeps({ useFlatConfig, cssPreprocessor, projectType })
979
+ if (findings === 0) {
980
+ console.log(" ✓ 已装依赖版本都在要求范围内,声明的依赖也都已安装")
981
+ }
982
+ }
983
+
984
+ const printFooter = () => {
985
+ stepHeader(6, 6, "接下来")
986
+ console.log(` 1. 启用 husky hooks:${runScriptCommand(pm, "prepare")}`)
987
+ console.log(` 2. 首次检查:${runScriptCommand(pm, "lint")}`)
988
+ console.log(" 3. 使用 czg 提交 commit:")
989
+ console.log(` ${runScriptCommand(pm, "cz")}`)
990
+ console.log(
991
+ " (先 git add 暂存改动;交互步骤、类型与 scope 规则见本包 README《用 pnpm cz 提交》)",
992
+ )
993
+ if (pm === "pnpm") {
994
+ console.log("")
995
+ console.log(
996
+ " 提示:pnpm 10+ 默认拦截依赖的构建脚本,若安装时提示 ERR_PNPM_IGNORED_BUILDS(如 unrs-resolver),执行 pnpm approve-builds 后重试。",
997
+ )
998
+ }
909
999
  console.log("")
910
- warn("Dry run 结束,未修改任何文件")
1000
+ if (dryRun) {
1001
+ success("Dry run 结束:未写入任何文件;去掉 --dry-run 执行真实初始化")
1002
+ } else {
1003
+ success(
1004
+ `初始化完成:覆盖 ${overwriteTotal} 个 · 新建 ${createTotal} 个 · package.json 已更新`,
1005
+ )
1006
+ }
911
1007
  console.log("")
1008
+ }
1009
+
1010
+ // Dry run:把 package.json / 依赖体检 / 下一步三步也预览出来,然后结束
1011
+ if (dryRun) {
1012
+ printPackageJsonStep()
1013
+ printDepsStep()
1014
+ printFooter()
912
1015
  return
913
1016
  }
914
1017
 
915
1018
  // Optional backup of existing files before modifying
916
- const backup = args.includes("--backup")
1019
+ const backupDir = path.resolve(PROJECT_ROOT, ".my-code-style-backup")
1020
+ let backedUpCount = 0
917
1021
  if (backup) {
918
- const backupDir = path.resolve(PROJECT_ROOT, ".my-code-style-backup")
919
1022
  ensureDir(backupDir)
920
1023
  // package.json is rewritten (scripts + lint-staged), so it must be backed
921
1024
  // up as well — users lose custom lint-staged groups otherwise.
@@ -925,7 +1028,7 @@ function main() {
925
1028
  const targetPath = path.resolve(backupDir, item.path)
926
1029
  ensureDir(path.dirname(targetPath))
927
1030
  fs.copyFileSync(srcPath, targetPath)
928
- log(`已备份 ${item.path} -> .my-code-style-backup/${item.path}`)
1031
+ backedUpCount++
929
1032
  }
930
1033
  }
931
1034
  }
@@ -1003,16 +1106,19 @@ function main() {
1003
1106
  "lint:fix": `${lintCommand} --fix`,
1004
1107
  format: "prettier --write .",
1005
1108
  prepare: "husky",
1006
- release: "standard-version",
1109
+ release: "commit-and-tag-version",
1007
1110
  cz: "czg",
1008
1111
  },
1009
1112
  "lint-staged": getLintStagedConfig(cssPreprocessor),
1010
1113
  })
1011
- success("更新 package.json (scripts + lint-staged)")
1114
+ printPackageJsonStep()
1012
1115
 
1013
1116
  // The backup directory is ours, not the user's source — keep it out of git
1014
1117
  if (backup) {
1015
1118
  ensureGitignoreEntry(".my-code-style-backup/")
1119
+ console.log(
1120
+ ` ✓ ${backedUpCount} 个旧文件已备份到 .my-code-style-backup/(目录已写入 .gitignore)`,
1121
+ )
1016
1122
  }
1017
1123
  } catch (err) {
1018
1124
  console.error(`\n ✖ 初始化写入失败: ${err.message};正在回滚...`)
@@ -1048,40 +1154,8 @@ function main() {
1048
1154
  return
1049
1155
  }
1050
1156
 
1051
- // Check for missing peerDependencies
1052
- checkPeerDeps({ useFlatConfig, cssPreprocessor, projectType })
1053
-
1054
- console.log("")
1055
- success("配置初始化完成!")
1056
- console.log("")
1057
- console.log(" 下一步:")
1058
- console.log(" 1. 确保已安装 peerDependencies:")
1059
- console.log(` ${addDevCommand(pm)} my-code-style`)
1060
- if (useFlatConfig) {
1061
- console.log(" 2. Flat Config 需要的额外依赖:")
1062
- console.log(
1063
- ` ${addDevCommand(pm)} typescript-eslint globals eslint-plugin-import-x @eslint/js`,
1064
- )
1065
- console.log(" 3. 初始化 husky:")
1066
- console.log(` ${runScriptCommand(pm, "prepare")}`)
1067
- console.log(" 4. 使用 czg 提交 commit:")
1068
- } else {
1069
- console.log(" 2. 初始化 husky:")
1070
- console.log(` ${runScriptCommand(pm, "prepare")}`)
1071
- console.log(" 3. 使用 czg 提交 commit:")
1072
- }
1073
- console.log(` ${runScriptCommand(pm, "cz")}`)
1074
- console.log(
1075
- " (先 git add 暂存改动;交互步骤、类型与 scope 规则见本包 README《用 pnpm cz 提交》)",
1076
- )
1077
- if (pm === "pnpm") {
1078
- console.log("")
1079
- console.log(" 提示:pnpm 10+ 默认拦截依赖的构建脚本,若安装时提示")
1080
- console.log(
1081
- " ERR_PNPM_IGNORED_BUILDS(如 unrs-resolver),执行 pnpm approve-builds 后重试。",
1082
- )
1083
- }
1084
- console.log("")
1157
+ printDepsStep()
1158
+ printFooter()
1085
1159
  }
1086
1160
 
1087
1161
  function modifyPackageJson(updates) {
@@ -1131,11 +1205,11 @@ function checkPeerDeps({
1131
1205
  projectType = "base",
1132
1206
  } = {}) {
1133
1207
  const pkg = getProjectPkg()
1134
- if (!pkg) return
1208
+ if (!pkg) return 0
1135
1209
 
1136
1210
  // If running within the package itself, skip external missing deps check
1137
1211
  if (pkg.name === "my-code-style") {
1138
- return
1212
+ return 0
1139
1213
  }
1140
1214
 
1141
1215
  const baseDeps = [
@@ -1149,7 +1223,7 @@ function checkPeerDeps({
1149
1223
  "husky",
1150
1224
  "lint-staged",
1151
1225
  "czg",
1152
- "standard-version",
1226
+ "commit-and-tag-version",
1153
1227
  ]
1154
1228
 
1155
1229
  const flatDeps = useFlatConfig
@@ -1225,23 +1299,24 @@ function checkPeerDeps({
1225
1299
  ...(pkg.devDependencies || {}),
1226
1300
  }
1227
1301
 
1228
- checkInstalledVersions({ peerDeps, allPeerDeps })
1302
+ const versionProblems = checkInstalledVersions({ peerDeps, allPeerDeps })
1229
1303
 
1230
1304
  const missing = allPeerDeps.filter((dep) => !allDeps[dep])
1231
1305
  if (missing.length > 0) {
1232
1306
  console.log("")
1233
- warn(`以下依赖未安装:${missing.join(", ")}`)
1307
+ warn(`以下依赖未安装(${missing.length} 个):${missing.join(", ")}`)
1234
1308
  console.log("")
1235
- warn("一键安装命令:")
1236
- console.log(` ${addDevCommand(detectPackageManager())} my-code-style \\`)
1309
+ warn("一键安装命令(可整段粘贴执行):")
1310
+ console.log(` ${addDevCommand(detectPackageManager())} my-code-style \\`)
1237
1311
  missing.forEach((dep, i) => {
1238
1312
  const version =
1239
1313
  dep === "eslint" ? (useFlatConfig ? "^9.0.0" : "^8.57.0") : peerDeps[dep] || ""
1240
- const depWithVersion = version ? `${dep}@${version}` : dep
1314
+ const depWithVersion = shellSafeSpec(version ? `${dep}@${version}` : dep)
1241
1315
  const suffix = i < missing.length - 1 ? " \\" : ""
1242
- console.log(` ${depWithVersion}${suffix}`)
1316
+ console.log(` ${depWithVersion}${suffix}`)
1243
1317
  })
1244
1318
  }
1319
+ return missing.length + versionProblems
1245
1320
  }
1246
1321
 
1247
1322
  // 体检时会顺着这些包的 peerDependencies 反查底层依赖的实际版本
@@ -1337,14 +1412,17 @@ function checkInstalledVersions({ peerDeps, allPeerDeps, rootDir = PROJECT_ROOT
1337
1412
  }
1338
1413
  }
1339
1414
 
1340
- if (!problems.length) return;
1415
+ if (!problems.length) return 0
1341
1416
  console.log("");
1342
- warn("以下依赖已安装,但版本与当前配置不匹配:");
1343
- for (const problem of problems) console.log(` · ${problem.message}`);
1417
+ warn(`以下依赖已安装,但版本与当前配置不匹配(${problems.length} 个):`);
1418
+ for (const problem of problems) console.log(` · ${problem.message}`);
1344
1419
  console.log("");
1345
- warn("对齐命令(也可以把上游配置包降到与你现有版本匹配的大版本):");
1420
+ warn("对齐命令(可整段粘贴执行;也可以把上游配置包降到匹配的大版本):");
1346
1421
  const targets = [...new Set(problems.map((problem) => problem.target))];
1347
- console.log(` ${addDevCommand(detectPackageManager())} ${targets.join(" ")}`);
1422
+ console.log(
1423
+ ` ${addDevCommand(detectPackageManager())} ${targets.map(shellSafeSpec).join(" ")}`,
1424
+ );
1425
+ return problems.length
1348
1426
  }
1349
1427
 
1350
1428
  // Only run when executed directly; requiring this file must be side-effect free.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-code-style",
3
- "version": "1.8.0",
3
+ "version": "1.8.2",
4
4
  "description": "Lint/Format/Git 配置工程化 npm 包(ESLint + Prettier + Stylelint + Commitlint + Husky + standard-version)",
5
5
  "type": "commonjs",
6
6
  "main": "src/eslint/uniapp.cjs",
@@ -57,8 +57,8 @@
57
57
  "lint:fix": "eslint . --fix",
58
58
  "format": "prettier --write .",
59
59
  "prepare": "node -e \"if (!process.env.CI) { try { require('child_process').execSync('husky', { stdio: 'ignore' }) } catch {} }\"",
60
- "release": "node scripts/release-guard.cjs && standard-version",
61
- "release:push": "node scripts/release-guard.cjs && standard-version && git push --follow-tags origin HEAD",
60
+ "release": "node scripts/release-guard.cjs && commit-and-tag-version",
61
+ "release:push": "node scripts/release-guard.cjs && commit-and-tag-version && git push --follow-tags origin HEAD",
62
62
  "pub": "npm run release:push",
63
63
  "cz": "czg",
64
64
  "link": "pnpm link --global",
@@ -74,6 +74,7 @@
74
74
  "@eslint/js": "^9.0.0",
75
75
  "@typescript-eslint/eslint-plugin": "^8.0.0",
76
76
  "@typescript-eslint/parser": "^8.0.0",
77
+ "commit-and-tag-version": "^12.0.0",
77
78
  "czg": "^1.0.0",
78
79
  "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
79
80
  "eslint-config-prettier": "^10.1.8",
@@ -89,7 +90,6 @@
89
90
  "postcss-less": "^6.0.0",
90
91
  "postcss-scss": "^4.0.0",
91
92
  "prettier": "^3.0.0",
92
- "standard-version": "^9.0.0",
93
93
  "stylelint": "^16.24.0 || ^17.0.0",
94
94
  "stylelint-config-html": "^2.0.0",
95
95
  "stylelint-config-recess-order": "^5.0.0 || ^6.0.0 || ^7.0.0",
@@ -163,9 +163,6 @@
163
163
  "prettier": {
164
164
  "optional": true
165
165
  },
166
- "standard-version": {
167
- "optional": true
168
- },
169
166
  "stylelint": {
170
167
  "optional": true
171
168
  },
@@ -198,10 +195,28 @@
198
195
  },
199
196
  "vue-eslint-parser": {
200
197
  "optional": true
198
+ },
199
+ "commit-and-tag-version": {
200
+ "optional": true
201
201
  }
202
202
  },
203
203
  "devDependencies": {
204
- "standard-version": "^9.5.0"
204
+ "@commitlint/cli": "^19.8.1",
205
+ "@commitlint/config-conventional": "^19.8.1",
206
+ "@eslint/js": "^9.39.5",
207
+ "commit-and-tag-version": "^12.7.3",
208
+ "czg": "^1.14.0",
209
+ "eslint": "^9.39.5",
210
+ "eslint-config-prettier": "^10.1.8",
211
+ "eslint-import-resolver-typescript": "^3.10.1",
212
+ "eslint-plugin-import-x": "^4.17.1",
213
+ "eslint-plugin-prettier": "^5.5.6",
214
+ "globals": "^16.5.0",
215
+ "husky": "^9.1.7",
216
+ "lint-staged": "^16.4.0",
217
+ "prettier": "^3.9.8",
218
+ "typescript": "^5.9.3",
219
+ "typescript-eslint": "^8.70.0"
205
220
  },
206
221
  "keywords": [
207
222
  "eslint-config",
@@ -1,4 +1,4 @@
1
- // standard-version config
1
+ // commit-and-tag-version config(standard-version 的社区维护分支,配置兼容)
2
2
  module.exports = {
3
3
  header: "## 变更日志\n",
4
4
  types: [