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 +19 -2
- package/README.md +26 -26
- package/bin/init +164 -86
- package/package.json +23 -8
- package/src/versionrc/index.cjs +1 -1
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` |
|
|
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
|
|
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 # 全量运行
|
|
242
|
+
npm run test:all # 全量运行 179 项:用例明细 + 分类统计 + 最慢文件定位
|
|
243
243
|
npm run diagnose # 换机器后先跑它:进程 / git / 文件系统 / hooks 各占多少
|
|
244
244
|
npm run sweep # 给本机找最佳文件级并发(扫 integration 套件)
|
|
245
|
-
npm test # 只跑基础 CLI 与配置矩阵(
|
|
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 与配置矩阵 (共
|
|
261
|
-
✓ 运行器 TAP 解析:统计通过与失败、SKIP 与每用例耗时 ·
|
|
262
|
-
✓ 运行器表格:CJK 宽度按两列计算,耗时格式化区分秒与毫秒 · 1ms
|
|
260
|
+
▶ [1/4] 基础 CLI 与配置矩阵 (共 85 项,5 文件 · 3 文件并发(自动:2 核 / 内存 4G))
|
|
261
|
+
✓ 运行器 TAP 解析:统计通过与失败、SKIP 与每用例耗时 · 7ms
|
|
263
262
|
✓ cz 交互提示为中文,且可选类型与 type-enum 一一对应 · 1ms
|
|
264
|
-
✓
|
|
263
|
+
✓ 一键安装命令对含 || 的版本范围加引号,可整段粘贴执行 · 44ms
|
|
264
|
+
✓ 初始化结尾指引把 cz 用法说清楚(先 git add + 指到 README 手册) · 80ms
|
|
265
265
|
…
|
|
266
|
-
✓ 通过
|
|
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.
|
|
270
|
-
✓ 发布防呆:HEAD 已有 v* tag 时拦截(此时
|
|
269
|
+
✓ 完整提交链:JS/TS/Vue/nvue/CSS/less 自动修复及二次复检 · 10.4s
|
|
270
|
+
✓ 发布防呆:HEAD 已有 v* tag 时拦截(此时 release 工具会静默抬版并写出空 CHANGELOG) · 609ms
|
|
271
271
|
…
|
|
272
|
-
✓ 通过 59 · 41.
|
|
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.
|
|
276
|
+
✓ ESLint 8 base:实际 CLI 加载生成配置并接受正常文件 · 1.3s
|
|
277
277
|
…
|
|
278
|
-
✓ 通过 27 ·
|
|
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 ·
|
|
282
|
+
✓ 生成的 .stylelintrc.cjs 在 stylelint 17 下可加载并放过正常 SCSS · 700ms
|
|
283
283
|
…
|
|
284
|
-
✓ 通过 8 · 7.
|
|
284
|
+
✓ 通过 8 · 7.2s
|
|
285
285
|
|
|
286
286
|
──────────────────────────────────────────────────────
|
|
287
287
|
套件 通过 失败 跳过 用时
|
|
288
288
|
──────────────────────────────────────────────────────
|
|
289
|
-
基础 CLI 与配置矩阵
|
|
290
|
-
现代工具链与提交链 59 0 - 41.
|
|
291
|
-
ESLint 8 兼容性 27 0 -
|
|
292
|
-
Stylelint 17 兼容性 8 0 - 7.
|
|
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
|
-
合计
|
|
294
|
+
合计 179 0 - 71.1s
|
|
295
295
|
──────────────────────────────────────────────────────
|
|
296
296
|
|
|
297
|
-
⏱ 最慢文件:eslint8.test.cjs
|
|
297
|
+
⏱ 最慢文件:eslint8.test.cjs 18.3s · commit-chain-both.test.cjs 10.6s · commit-chain-scss.test.cjs 10.6s
|
|
298
298
|
|
|
299
|
-
✅ 全部通过:
|
|
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 |
|
|
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
|
-
同机复测(
|
|
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
|
|
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 `//
|
|
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
|
-
|
|
718
|
-
|
|
719
|
-
|
|
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
|
-
|
|
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
|
-
|
|
781
|
-
log(
|
|
782
|
-
|
|
799
|
+
stepHeader(1, 6, "检测项目环境")
|
|
800
|
+
console.log(` · 包管理器:${pm}`)
|
|
801
|
+
console.log(
|
|
802
|
+
` · ESLint:${eslintVersion || "未声明,按已安装版本处理"} → ${eslintFormat === "flat" ? "Flat Config" : "传统 .eslintrc 格式"}`,
|
|
783
803
|
)
|
|
784
|
-
log(
|
|
785
|
-
|
|
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
|
-
|
|
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
|
-
|
|
848
|
-
|
|
849
|
-
|
|
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
|
-
|
|
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
|
-
|
|
915
|
+
overwriteTotal++
|
|
916
|
+
console.log(` 覆盖 ${f.path}`)
|
|
883
917
|
} else {
|
|
884
|
-
|
|
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
|
-
|
|
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
|
-
|
|
937
|
+
overwriteTotal++
|
|
938
|
+
console.log(` 覆盖 ${h.path}`)
|
|
903
939
|
} else {
|
|
904
|
-
|
|
940
|
+
createTotal++
|
|
941
|
+
console.log(` 新建 ${h.path}`)
|
|
905
942
|
}
|
|
906
943
|
}
|
|
907
944
|
|
|
908
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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: "
|
|
1109
|
+
release: "commit-and-tag-version",
|
|
1007
1110
|
cz: "czg",
|
|
1008
1111
|
},
|
|
1009
1112
|
"lint-staged": getLintStagedConfig(cssPreprocessor),
|
|
1010
1113
|
})
|
|
1011
|
-
|
|
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
|
-
|
|
1052
|
-
|
|
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
|
-
"
|
|
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(
|
|
1307
|
+
warn(`以下依赖未安装(${missing.length} 个):${missing.join(", ")}`)
|
|
1234
1308
|
console.log("")
|
|
1235
|
-
warn("
|
|
1236
|
-
console.log(`
|
|
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(`
|
|
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(`
|
|
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(
|
|
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.
|
|
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 &&
|
|
61
|
-
"release:push": "node scripts/release-guard.cjs &&
|
|
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
|
-
"
|
|
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",
|
package/src/versionrc/index.cjs
CHANGED