my-code-style 1.8.0 → 1.8.1

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.
Files changed (4) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +22 -22
  3. package/bin/init +153 -83
  4. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  ## 变更日志
2
2
 
3
+ ### [1.8.1](https://github.com/myvn/codeStyle/compare/v1.8.0...v1.8.1) (2026-09-20)
4
+
5
+
6
+ ### 🐛 Bug Fixes | Bug 修复
7
+
8
+ * **init:** 安装命令里的版本范围加引号,粘贴不再被 shell 截断 ([9abaf1d](https://github.com/myvn/codeStyle/commit/9abaf1d76ea3aff05f0d26d11a43e8661ed6221a))
9
+
10
+
11
+ ### ✨ Features | 新功能
12
+
13
+ * **init:** 输出步骤化为固定六步,dry-run 全流程预览 ([f14ca47](https://github.com/myvn/codeStyle/commit/f14ca47449b7d3e8f9a381b6e145e99232586886))
14
+
3
15
  ## [1.8.0](https://github.com/myvn/codeStyle/compare/v1.7.2...v1.8.0) (2026-09-20)
4
16
 
5
17
  ### ✨ Features | 新功能
package/README.md CHANGED
@@ -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 # 全量运行 178 项:用例明细 + 分类统计 + 最慢文件定位
243
243
  npm run diagnose # 换机器后先跑它:进程 / git / 文件系统 / hooks 各占多少
244
244
  npm run sweep # 给本机找最佳文件级并发(扫 integration 套件)
245
- npm test # 只跑基础 CLI 与配置矩阵(81 项)
245
+ npm test # 只跑基础 CLI 与配置矩阵(84 项)
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 与配置矩阵 (共 84 项,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
+ ✓ 通过 84 · 3.5s · 最慢文件 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 时拦截(此时 standard-version 会静默抬版并写出空 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 与配置矩阵 84 0 - 3.5s
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
+ 合计 178 0 - 81.3s
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
+ ✅ 全部通过:178/178 项,用时 81.3s
300
300
  ```
301
301
 
302
302
  终端里每个套件下方还有一条实时进度条(`██████░░░░ 38/66 失败 0 4.0s`)。附加参数:
@@ -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
+ 同机复测(178 项,同一台 2 核沙箱连续跑;绝对秒数随机器负载波动,相对关系稳定):串行套件 + 文件级并发 1 = 70.3s、默认自动并发 3 = 81.3s、`--parallel` 四套件 = 59.1s、`npm run test:integration` = 41.5s、`node --test demo-test/integration/*.test.cjs` = 58.4s(后四项为 177 项时实测,仅基础套件 +2 用例,差值在秒级)。
378
378
 
379
379
  (2 核沙箱里并行收益被 CPU 争抢吃掉大半,`--concurrency=1` 时单个文件只要 0.7–4.2s;
380
380
  16 核机器上集成套件那段 ≈ 最慢子文件,即"一次真实提交"的量级。)
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).
@@ -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,7 @@ 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")
852
879
 
853
880
  files.push({
854
881
  path: versionrcPath,
@@ -876,12 +903,17 @@ function main() {
876
903
  })
877
904
  }
878
905
 
879
- // Show what will be created/overwritten
906
+ const backup = args.includes("--backup")
907
+ stepHeader(3, 6, "配置文件与 Git hooks")
908
+ let overwriteTotal = 0
909
+ let createTotal = 0
880
910
  for (const f of files) {
881
911
  if (f.exists) {
882
- warn(`${label}覆盖 ${f.path}`)
912
+ overwriteTotal++
913
+ console.log(` 覆盖 ${f.path}`)
883
914
  } else {
884
- success(`${label}创建 ${f.path}`)
915
+ createTotal++
916
+ console.log(` 新建 ${f.path}`)
885
917
  }
886
918
  }
887
919
 
@@ -889,7 +921,7 @@ function main() {
889
921
  const huskyDir = path.resolve(PROJECT_ROOT, ".husky")
890
922
  const hasHusky = fs.existsSync(huskyDir)
891
923
  if (!hasHusky) {
892
- success(`${label}创建 .husky/ 目录`)
924
+ console.log(" 新建 .husky/ 目录")
893
925
  }
894
926
 
895
927
  const hooks = [
@@ -899,23 +931,86 @@ function main() {
899
931
 
900
932
  for (const h of hooks) {
901
933
  if (fileExists(h.path)) {
902
- warn(`${label}覆盖 ${h.path}`)
934
+ overwriteTotal++
935
+ console.log(` 覆盖 ${h.path}`)
903
936
  } else {
904
- success(`${label}创建 ${h.path}`)
937
+ createTotal++
938
+ console.log(` 新建 ${h.path}`)
905
939
  }
906
940
  }
907
941
 
908
- if (dryRun) {
942
+ console.log(
943
+ ` 小计:覆盖 ${overwriteTotal} 个 · 新建 ${createTotal} 个` +
944
+ (backup ? " · 旧文件将备份到 .my-code-style-backup/" : "") +
945
+ (dryRun ? "(Dry run 预览,不写入)" : ""),
946
+ )
947
+ if (skipStylelint) {
948
+ console.log(" · 跳过 .stylelintrc.cjs(未检测到 CSS 预处理器)")
949
+ }
950
+ if (staleVersionrc) {
951
+ warn(
952
+ "检测到 ESM 项目 (type: module) 存在旧的 .versionrc.js,standard-version 需使用 .versionrc.cjs",
953
+ )
954
+ }
955
+
956
+ const printPackageJsonStep = () => {
957
+ stepHeader(4, 6, "package.json")
958
+ if (dryRun) {
959
+ console.log(
960
+ " · 将更新 scripts(lint / lint:fix / format / prepare / release / cz)与 lint-staged",
961
+ )
962
+ return
963
+ }
964
+ console.log(" ✓ scripts 已更新(lint / lint:fix / format / prepare / release / cz)")
965
+ console.log(" ✓ lint-staged 已按检测到的 CSS 预处理器生成")
966
+ }
967
+
968
+ const printDepsStep = () => {
969
+ stepHeader(5, 6, "依赖体检")
970
+ const findings = checkPeerDeps({ useFlatConfig, cssPreprocessor, projectType })
971
+ if (findings === 0) {
972
+ console.log(" ✓ 已装依赖版本都在要求范围内,声明的依赖也都已安装")
973
+ }
974
+ }
975
+
976
+ const printFooter = () => {
977
+ stepHeader(6, 6, "接下来")
978
+ console.log(` 1. 启用 husky hooks:${runScriptCommand(pm, "prepare")}`)
979
+ console.log(` 2. 首次检查:${runScriptCommand(pm, "lint")}`)
980
+ console.log(" 3. 使用 czg 提交 commit:")
981
+ console.log(` ${runScriptCommand(pm, "cz")}`)
982
+ console.log(
983
+ " (先 git add 暂存改动;交互步骤、类型与 scope 规则见本包 README《用 pnpm cz 提交》)",
984
+ )
985
+ if (pm === "pnpm") {
986
+ console.log("")
987
+ console.log(
988
+ " 提示:pnpm 10+ 默认拦截依赖的构建脚本,若安装时提示 ERR_PNPM_IGNORED_BUILDS(如 unrs-resolver),执行 pnpm approve-builds 后重试。",
989
+ )
990
+ }
909
991
  console.log("")
910
- warn("Dry run 结束,未修改任何文件")
992
+ if (dryRun) {
993
+ success("Dry run 结束:未写入任何文件;去掉 --dry-run 执行真实初始化")
994
+ } else {
995
+ success(
996
+ `初始化完成:覆盖 ${overwriteTotal} 个 · 新建 ${createTotal} 个 · package.json 已更新`,
997
+ )
998
+ }
911
999
  console.log("")
1000
+ }
1001
+
1002
+ // Dry run:把 package.json / 依赖体检 / 下一步三步也预览出来,然后结束
1003
+ if (dryRun) {
1004
+ printPackageJsonStep()
1005
+ printDepsStep()
1006
+ printFooter()
912
1007
  return
913
1008
  }
914
1009
 
915
1010
  // Optional backup of existing files before modifying
916
- const backup = args.includes("--backup")
1011
+ const backupDir = path.resolve(PROJECT_ROOT, ".my-code-style-backup")
1012
+ let backedUpCount = 0
917
1013
  if (backup) {
918
- const backupDir = path.resolve(PROJECT_ROOT, ".my-code-style-backup")
919
1014
  ensureDir(backupDir)
920
1015
  // package.json is rewritten (scripts + lint-staged), so it must be backed
921
1016
  // up as well — users lose custom lint-staged groups otherwise.
@@ -925,7 +1020,7 @@ function main() {
925
1020
  const targetPath = path.resolve(backupDir, item.path)
926
1021
  ensureDir(path.dirname(targetPath))
927
1022
  fs.copyFileSync(srcPath, targetPath)
928
- log(`已备份 ${item.path} -> .my-code-style-backup/${item.path}`)
1023
+ backedUpCount++
929
1024
  }
930
1025
  }
931
1026
  }
@@ -1008,11 +1103,14 @@ function main() {
1008
1103
  },
1009
1104
  "lint-staged": getLintStagedConfig(cssPreprocessor),
1010
1105
  })
1011
- success("更新 package.json (scripts + lint-staged)")
1106
+ printPackageJsonStep()
1012
1107
 
1013
1108
  // The backup directory is ours, not the user's source — keep it out of git
1014
1109
  if (backup) {
1015
1110
  ensureGitignoreEntry(".my-code-style-backup/")
1111
+ console.log(
1112
+ ` ✓ ${backedUpCount} 个旧文件已备份到 .my-code-style-backup/(目录已写入 .gitignore)`,
1113
+ )
1016
1114
  }
1017
1115
  } catch (err) {
1018
1116
  console.error(`\n ✖ 初始化写入失败: ${err.message};正在回滚...`)
@@ -1048,40 +1146,8 @@ function main() {
1048
1146
  return
1049
1147
  }
1050
1148
 
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("")
1149
+ printDepsStep()
1150
+ printFooter()
1085
1151
  }
1086
1152
 
1087
1153
  function modifyPackageJson(updates) {
@@ -1131,11 +1197,11 @@ function checkPeerDeps({
1131
1197
  projectType = "base",
1132
1198
  } = {}) {
1133
1199
  const pkg = getProjectPkg()
1134
- if (!pkg) return
1200
+ if (!pkg) return 0
1135
1201
 
1136
1202
  // If running within the package itself, skip external missing deps check
1137
1203
  if (pkg.name === "my-code-style") {
1138
- return
1204
+ return 0
1139
1205
  }
1140
1206
 
1141
1207
  const baseDeps = [
@@ -1225,23 +1291,24 @@ function checkPeerDeps({
1225
1291
  ...(pkg.devDependencies || {}),
1226
1292
  }
1227
1293
 
1228
- checkInstalledVersions({ peerDeps, allPeerDeps })
1294
+ const versionProblems = checkInstalledVersions({ peerDeps, allPeerDeps })
1229
1295
 
1230
1296
  const missing = allPeerDeps.filter((dep) => !allDeps[dep])
1231
1297
  if (missing.length > 0) {
1232
1298
  console.log("")
1233
- warn(`以下依赖未安装:${missing.join(", ")}`)
1299
+ warn(`以下依赖未安装(${missing.length} 个):${missing.join(", ")}`)
1234
1300
  console.log("")
1235
- warn("一键安装命令:")
1236
- console.log(` ${addDevCommand(detectPackageManager())} my-code-style \\`)
1301
+ warn("一键安装命令(可整段粘贴执行):")
1302
+ console.log(` ${addDevCommand(detectPackageManager())} my-code-style \\`)
1237
1303
  missing.forEach((dep, i) => {
1238
1304
  const version =
1239
1305
  dep === "eslint" ? (useFlatConfig ? "^9.0.0" : "^8.57.0") : peerDeps[dep] || ""
1240
- const depWithVersion = version ? `${dep}@${version}` : dep
1306
+ const depWithVersion = shellSafeSpec(version ? `${dep}@${version}` : dep)
1241
1307
  const suffix = i < missing.length - 1 ? " \\" : ""
1242
- console.log(` ${depWithVersion}${suffix}`)
1308
+ console.log(` ${depWithVersion}${suffix}`)
1243
1309
  })
1244
1310
  }
1311
+ return missing.length + versionProblems
1245
1312
  }
1246
1313
 
1247
1314
  // 体检时会顺着这些包的 peerDependencies 反查底层依赖的实际版本
@@ -1337,14 +1404,17 @@ function checkInstalledVersions({ peerDeps, allPeerDeps, rootDir = PROJECT_ROOT
1337
1404
  }
1338
1405
  }
1339
1406
 
1340
- if (!problems.length) return;
1407
+ if (!problems.length) return 0
1341
1408
  console.log("");
1342
- warn("以下依赖已安装,但版本与当前配置不匹配:");
1343
- for (const problem of problems) console.log(` · ${problem.message}`);
1409
+ warn(`以下依赖已安装,但版本与当前配置不匹配(${problems.length} 个):`);
1410
+ for (const problem of problems) console.log(` · ${problem.message}`);
1344
1411
  console.log("");
1345
- warn("对齐命令(也可以把上游配置包降到与你现有版本匹配的大版本):");
1412
+ warn("对齐命令(可整段粘贴执行;也可以把上游配置包降到匹配的大版本):");
1346
1413
  const targets = [...new Set(problems.map((problem) => problem.target))];
1347
- console.log(` ${addDevCommand(detectPackageManager())} ${targets.join(" ")}`);
1414
+ console.log(
1415
+ ` ${addDevCommand(detectPackageManager())} ${targets.map(shellSafeSpec).join(" ")}`,
1416
+ );
1417
+ return problems.length
1348
1418
  }
1349
1419
 
1350
1420
  // 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.1",
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",