my-code-style 1.5.0 → 1.6.0
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 +22 -0
- package/README.md +135 -4
- package/bin/init +63 -23
- package/package.json +7 -9
- package/src/commitlint/scopes.cjs +3 -0
- package/src/eslint/base.cjs +6 -10
- package/src/eslint/flat/_shared.mjs +12 -10
- package/src/eslint/flat/base.mjs +7 -1
- package/src/eslint/flat/vue3.mjs +2 -1
- package/src/eslint/vue3.cjs +5 -1
- package/src/husky/commit-msg +5 -1
- package/src/husky/pre-commit +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,36 @@
|
|
|
1
1
|
## 变更日志
|
|
2
2
|
|
|
3
|
+
## [1.6.0](https://github.com/myvn/codeStyle/compare/v1.4.0...v1.6.0) (2026-09-18)
|
|
4
|
+
|
|
5
|
+
### 🐛 Bug Fixes | Bug 修复
|
|
6
|
+
|
|
7
|
+
- 修复 ESLint 版本/样式检测误判、规则冲突与 scope 生成缺陷 ([033967b](https://github.com/myvn/codeStyle/commit/033967b0efadbb705bdafe5d4dfc34dbc90578c2))
|
|
8
|
+
- 修复 Flat Config 缺 eslint:recommended、Prettier 选项漂移等 7 类问题 ([e4533bb](https://github.com/myvn/codeStyle/commit/e4533bbdaf5752146289a2b4e044ce59658c9453))
|
|
9
|
+
|
|
10
|
+
### ✨ Features | 新功能
|
|
11
|
+
|
|
12
|
+
- **diagnose:** ⑤ 拆分排队来源:纯 git 链膨胀 vs 完整链膨胀 vs 错峰启动 ([5caa437](https://github.com/myvn/codeStyle/commit/5caa4372d6ebbc52e19ec771b65d9a0edf041d63))
|
|
13
|
+
- **diagnose:** 增加 ⑤ 并发压力段,量"单个耗时被并发放大多少倍" ([df060d5](https://github.com/myvn/codeStyle/commit/df060d56cecfa7f3b830864cc01082ee14583662))
|
|
14
|
+
- **diagnose:** 对照 fixture 落在仓库内 vs 系统临时目录 ([7ea7fdc](https://github.com/myvn/codeStyle/commit/7ea7fdc6f913dcad1e76fb110241f875a204c341))
|
|
15
|
+
- **diagnose:** 新增 npm run diagnose,定位"一次提交到底花在哪" ([61dbfdb](https://github.com/myvn/codeStyle/commit/61dbfdb99813384097cf2f243b31d20c84695cbd))
|
|
16
|
+
- **init:** 补全 peer 体检并按包管理器输出命令,新增初始化链路文档 ([0396198](https://github.com/myvn/codeStyle/commit/03961983be3a6f8cda96d4047450e7595ffefb97))
|
|
17
|
+
- **sweep:** 新增 --suite 过滤与 npm run sweep,给本机找最佳并发 ([d65254d](https://github.com/myvn/codeStyle/commit/d65254d1c9ef3277fbc23dc87bb6285d5ef3829c))
|
|
18
|
+
|
|
3
19
|
## [1.5.0](https://github.com/myvn/codeStyle/compare/v1.4.0...v1.5.0) (2026-09-18)
|
|
4
20
|
|
|
5
21
|
### 🐛 Bug Fixes | Bug 修复
|
|
6
22
|
|
|
7
23
|
- 修复 ESLint 版本/样式检测误判、规则冲突与 scope 生成缺陷 ([033967b](https://github.com/myvn/codeStyle/commit/033967b0efadbb705bdafe5d4dfc34dbc90578c2))
|
|
24
|
+
- 修复 Flat Config 缺 eslint:recommended、Prettier 选项漂移等 7 类问题 ([e4533bb](https://github.com/myvn/codeStyle/commit/e4533bbdaf5752146289a2b4e044ce59658c9453))
|
|
8
25
|
|
|
9
26
|
### ✨ Features | 新功能
|
|
10
27
|
|
|
28
|
+
- **diagnose:** ⑤ 拆分排队来源:纯 git 链膨胀 vs 完整链膨胀 vs 错峰启动 ([5caa437](https://github.com/myvn/codeStyle/commit/5caa4372d6ebbc52e19ec771b65d9a0edf041d63))
|
|
29
|
+
- **diagnose:** 增加 ⑤ 并发压力段,量"单个耗时被并发放大多少倍" ([df060d5](https://github.com/myvn/codeStyle/commit/df060d56cecfa7f3b830864cc01082ee14583662))
|
|
30
|
+
- **diagnose:** 对照 fixture 落在仓库内 vs 系统临时目录 ([7ea7fdc](https://github.com/myvn/codeStyle/commit/7ea7fdc6f913dcad1e76fb110241f875a204c341))
|
|
31
|
+
- **diagnose:** 新增 npm run diagnose,定位"一次提交到底花在哪" ([61dbfdb](https://github.com/myvn/codeStyle/commit/61dbfdb99813384097cf2f243b31d20c84695cbd))
|
|
11
32
|
- **init:** 补全 peer 体检并按包管理器输出命令,新增初始化链路文档 ([0396198](https://github.com/myvn/codeStyle/commit/03961983be3a6f8cda96d4047450e7595ffefb97))
|
|
33
|
+
- **sweep:** 新增 --suite 过滤与 npm run sweep,给本机找最佳并发 ([d65254d](https://github.com/myvn/codeStyle/commit/d65254d1c9ef3277fbc23dc87bb6285d5ef3829c))
|
|
12
34
|
|
|
13
35
|
## [1.4.0](https://github.com/myvn/codeStyle/compare/v1.2.0...v1.4.0) (2026-09-17)
|
|
14
36
|
|
package/README.md
CHANGED
|
@@ -191,14 +191,145 @@ npx my-code-style-init [--dry-run] [--backup] [--version|-v] [--help|-h]
|
|
|
191
191
|
## 测试套件
|
|
192
192
|
|
|
193
193
|
```bash
|
|
194
|
-
npm test
|
|
194
|
+
npm run test:all # 全量运行 152 项:用例明细 + 分类统计 + 最慢文件定位
|
|
195
|
+
npm run diagnose # 换机器后先跑它:进程 / git / 文件系统 / hooks 各占多少
|
|
196
|
+
npm run sweep # 给本机找最佳文件级并发(扫 integration 套件)
|
|
197
|
+
npm test # 只跑基础 CLI 与配置矩阵(70 项)
|
|
195
198
|
npm run test:integration:setup # 安装现代化隔离依赖运行环境
|
|
196
|
-
npm run test:integration #
|
|
199
|
+
npm run test:integration # Flat Config、真实 Husky 及提交链路测试(55 项)
|
|
197
200
|
npm run test:legacy:setup # 安装 ESLint 8 隔离运行环境
|
|
198
|
-
npm run test:legacy #
|
|
199
|
-
npm run test:all # 全量运行全部 133 项测试
|
|
201
|
+
npm run test:legacy # ESLint 8.57.0 兼容性回归测试(27 项)
|
|
200
202
|
```
|
|
201
203
|
|
|
204
|
+
`npm run test:all` 由 `scripts/test-all.cjs` 驱动,输出**套件 → 用例 → 汇总**三层:
|
|
205
|
+
每个大类下面列出它的每条用例(✓/✗/○ + 耗时),最后给出分类统计与总条数。
|
|
206
|
+
|
|
207
|
+
```text
|
|
208
|
+
my-code-style 测试套件
|
|
209
|
+
|
|
210
|
+
▶ [1/3] 基础 CLI 与配置矩阵 (共 70 项,5 文件 · 3 文件并发(自动:2 核 / 内存 4G))
|
|
211
|
+
✓ 运行器 TAP 解析:统计通过与失败、SKIP 与每用例耗时 · 2ms
|
|
212
|
+
✓ 所有公共导出目标存在且可通过包名解析 · 11ms
|
|
213
|
+
✓ Prettier 默认值和 JSON/YAML/nvue 文件例外 · 1ms
|
|
214
|
+
…
|
|
215
|
+
✓ 通过 70 · 2.1s · 最慢文件 init-matrix.test.cjs 1.9s
|
|
216
|
+
|
|
217
|
+
▶ [2/3] 现代工具链与提交链 (共 55 项,23 文件 · 3 文件并发(自动:2 核 / 内存 4G))
|
|
218
|
+
✓ 完整提交链:JS/TS/Vue/nvue/CSS/scss 自动修复及二次复检 · 8.0s
|
|
219
|
+
✓ 完整提交链拦截 nvue 内嵌样式错误(不是仅检查脚本) · 3.6s
|
|
220
|
+
✓ Flat Config 启用 eslint:recommended 核心规则:no-debugger · 45ms
|
|
221
|
+
…
|
|
222
|
+
✓ 通过 55 · 30.8s · 最慢文件 commit-chain-both.test.cjs 8.4s
|
|
223
|
+
|
|
224
|
+
▶ [3/3] ESLint 8 兼容性 (共 27 项,1 文件 · 3 文件并发(自动:2 核 / 内存 4G))
|
|
225
|
+
✓ ESLint 8 base:生成的 lint 脚本遍历并拦截 broken.ts · 1.1s
|
|
226
|
+
…
|
|
227
|
+
✓ 通过 27 · 14.3s
|
|
228
|
+
|
|
229
|
+
──────────────────────────────────────────────────────
|
|
230
|
+
套件 通过 失败 跳过 用时
|
|
231
|
+
──────────────────────────────────────────────────────
|
|
232
|
+
基础 CLI 与配置矩阵 70 0 - 2.1s
|
|
233
|
+
现代工具链与提交链 55 0 - 30.8s
|
|
234
|
+
ESLint 8 兼容性 27 0 - 14.3s
|
|
235
|
+
──────────────────────────────────────────────────────
|
|
236
|
+
合计 152 0 - 47.2s
|
|
237
|
+
──────────────────────────────────────────────────────
|
|
238
|
+
|
|
239
|
+
⏱ 最慢文件:eslint8.test.cjs 14.3s · commit-chain-both.test.cjs 8.4s · commit-chain-scss.test.cjs 8.3s
|
|
240
|
+
|
|
241
|
+
✅ 全部通过:152/152 项,用时 47.2s
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
终端里每个套件下方还有一条实时进度条(`██████░░░░ 38/66 失败 0 4.0s`)。附加参数:
|
|
247
|
+
|
|
248
|
+
| 参数 | 作用 |
|
|
249
|
+
| -------------------- | ------------------------------------------------------------- |
|
|
250
|
+
| `-- --quiet` | 只看套件结论与汇总表,不列用例明细(长输出时用) |
|
|
251
|
+
| `-- --parallel` | 强制三个套件同时跑(核数 ≥ 8 时默认已自动开启) |
|
|
252
|
+
| `-- --serial` | 强制串行(CI 形态,输出顺序最稳定) |
|
|
253
|
+
| `-- --jobs=2` | 配合并行限制同时运行的套件数,其余排队(面板显示"等待中") |
|
|
254
|
+
| `-- --suite=base,legacy` | 只跑指定套件(base / integration / legacy,逗号分隔) |
|
|
255
|
+
| `-- --concurrency=4` | 覆盖套件内文件级并发(默认按核数与内存自动算,封顶 8) |
|
|
256
|
+
| `-- --verbose` | 展开每个套件的原始 TAP 输出(排查单条用例) |
|
|
257
|
+
| `-- --profile` | 额外列出每个测试文件的耗时(定位集成套件瓶颈时用) |
|
|
258
|
+
| `-- --no-count` | 跳过预统计,进度条退化为"已完成 N 项" |
|
|
259
|
+
| `-- --progress` | 在非 TTY(CI 日志)中也强制刷新进度行 |
|
|
260
|
+
|
|
261
|
+
### 并行跑更快
|
|
262
|
+
|
|
263
|
+
测试用例之间不用同一份目录:基础套件只用临时目录,集成套件用 `demo-test/.runtime`,
|
|
264
|
+
ESLint 8 套件用 `demo-test/.runtime-legacy`,所以两层并行都是安全的。**核数 ≥ 8 的机器
|
|
265
|
+
会自动开启套件级并行**(想固定成 CI 那种串行输出用 `--serial`):
|
|
266
|
+
|
|
267
|
+
想给本机定一个更合适的并发数,跑 `npm run sweep`:它会把 integration 套件在 auto/1/2/4/6/8/12/16/24 各跑一次,直接给出最快的那一档(并发越高越慢就说明瓶颈在进程启动而非 CPU)。
|
|
268
|
+
|
|
269
|
+
换了机器发现某个套件特别慢?先跑 `npm run diagnose`:它会把「进程启动 / npx 开销 / git / 文件系统 / 一次真实提交的 hooks」逐项列出来,直接指出时间花在哪一层。
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
npm run test:all # 16 核机器:自动并行,墙钟 ≈ 最慢的那套
|
|
273
|
+
npm run test:all -- --serial # 强制串行
|
|
274
|
+
npm run test:all -- --parallel # 低核机器上强制并行
|
|
275
|
+
npm run test:all -- --profile # 看每个测试文件耗时,定位瓶颈
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
两层并行的实现:
|
|
279
|
+
|
|
280
|
+
- **文件级**:集成套件按"一条提交链一个文件"拆成 23 个测试文件,**由运行器自己按文件
|
|
281
|
+
调度**(每个文件一个 `node --test` 进程),不依赖 Node 的 `--test` 默认并发值——
|
|
282
|
+
同一个文件内的用例仍然串行(真实 git 仓库不能并行改),文件之间才是并发的。
|
|
283
|
+
- **套件级**:三个套件再并行,互不共享目录。
|
|
284
|
+
|
|
285
|
+
因为每个文件里跑的都是真实 `git commit`(单次 0.5–3.9s),墙钟由**最慢的那个文件**
|
|
286
|
+
决定,所以文件尽量拆到"一个文件一次提交"。每个套件跑完会直接告诉你最慢文件是谁,
|
|
287
|
+
汇总区再给一次全局 `⏱ 最慢文件`:
|
|
288
|
+
|
|
289
|
+
| integration 子文件(23 个) | 单文件耗时(2 核、串行) | 内容 |
|
|
290
|
+
| -------------------------- | ---------------------- | ---- |
|
|
291
|
+
| `commit-chain-{scss,less,both}` | 2.7–3.3s | 三种预处理器的完整提交链(各 1 次提交) |
|
|
292
|
+
| `empty-commit-guard` | 2.7s | 空提交守卫(重复暂存不得产生漂移提交) |
|
|
293
|
+
| `git-mv-rm` | 3.2s | `git mv` / `git rm` 走 lint-staged |
|
|
294
|
+
| `embedded-style-{vue,nvue,mixed-less}` | 1.9–2.0s | Vue/nvue 内嵌样式错误拦截 |
|
|
295
|
+
| `git-edge-{first-commit,stash}` | 2.1s / 1.7s | 首次提交、用户 stash 保留 |
|
|
296
|
+
| `partial-staging{,-unstaged,-invalid-message,-conflict}` | 0.5–1.7s | 部分暂存与冲突恢复 |
|
|
297
|
+
| `error-recovery-{css,scss,less,js,ts,vue,nvue}` | 0.5–1.4s | 不可修复错误的回滚 |
|
|
298
|
+
| `lint` | 3.9s | 32 条规则与格式化行为(无提交链) |
|
|
299
|
+
| `release` | 0.8s | standard-version |
|
|
300
|
+
|
|
301
|
+
两层并发都要控制规模,所以默认并发不交给 Node 猜,而是运行器自己算——**核数 × 1.5
|
|
302
|
+
(至少 核数 - 1),再乘内存上限,最后封顶 8**(16 核机器实测:4/6/8/12/16/24 并发对应
|
|
303
|
+
20.3/18.7/19.0/19.2/18.9/19.1s,6–8 之后加并发只会让每个文件变慢;要更多用
|
|
304
|
+
`--concurrency` 覆盖):实测一条真实提交链(`git` + `npx` + `eslint` +
|
|
305
|
+
`prettier`)峰值 RSS 约 0.8GB,运行器留 30% 内存给系统,避免并发过多的小内存机器被
|
|
306
|
+
并发 git/npx 撑到 OOM(进程被 SIGKILL);文件数多于并发数时,**用例少的文件(多半是同
|
|
307
|
+
一条重链)优先开跑**,避免长任务被排进最后一波、墙钟再多乘一倍。
|
|
308
|
+
|
|
309
|
+
实测(2 核沙箱,152 项;沙箱内存 4G,所以自动并发是 3):
|
|
310
|
+
|
|
311
|
+
| 运行方式 | 墙钟时间 |
|
|
312
|
+
| ----------------------------------- | ----------------------------------------------- |
|
|
313
|
+
| 串行套件 + 文件级并发 1(CI 旧形态) | 62.4s(hook 改造前同配置 70.3s) |
|
|
314
|
+
| 串行套件 + 自动并发 3(默认) | 47.2s(hook 改造前同配置 51.8s) |
|
|
315
|
+
| `--parallel` 三套件 + 自动并发 3 | 43.0s(hook 改造前同配置 46.6s) |
|
|
316
|
+
| `node --test demo-test/integration/*.test.cjs`(Node 自己调度,等同旧命令) | 43.7s(只看集成套件那一段) |
|
|
317
|
+
| `npm run test:integration`(运行器调度,自动并发 3) | 30.6s(只看集成套件那一段) |
|
|
318
|
+
| 串行套件 + 文件级并发 23(全部一波) | ✗ 3.8G 内存沙箱被 OOM 压垮(19 项 SIGKILL) |
|
|
319
|
+
|
|
320
|
+
(2 核沙箱里并行收益被 CPU 争抢吃掉大半,`--concurrency=1` 时单个文件只要 0.7–4.2s;
|
|
321
|
+
16 核机器上集成套件那段 ≈ 最慢子文件,即"一次真实提交"的量级。)
|
|
322
|
+
生成的 hook 优先直连本地 bin(husky 已把 `node_modules/.bin` 放进 PATH),
|
|
323
|
+
找不到时才退回 `npx --no-install`——每次提交因此少起两个 npm CLI(实测每个 hook
|
|
324
|
+
省 130–185ms),提交链从 3.3s 降到 2.8s。集成 fixture 同样用环境变量传 git 身份
|
|
325
|
+
(`GIT_AUTHOR_*` / `GIT_CONFIG_COUNT`)代替 4 次 `git config`。
|
|
326
|
+
|
|
327
|
+
`demo-test/integration/_runtime.cjs` 用「指纹 + 目录锁」保证并发启动时只同步一次
|
|
328
|
+
隔离环境源码,不会读到写了一半的文件;`prettier` / `eslint` 以 getter 惰性加载,
|
|
329
|
+
只做提交链的 8 个文件不再为它们付启动开销。
|
|
330
|
+
|
|
331
|
+
未安装隔离运行环境时,对应套件会明确标记"未运行"并给出 setup 命令,退出码为 1(不会假装全绿)。
|
|
332
|
+
|
|
202
333
|
## License
|
|
203
334
|
|
|
204
335
|
MIT
|
package/bin/init
CHANGED
|
@@ -233,24 +233,58 @@ function majorsForRange(range) {
|
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
/**
|
|
236
|
-
*
|
|
237
|
-
*
|
|
236
|
+
* Read the actually installed ESLint major version. In a monorepo the binary is
|
|
237
|
+
* usually hoisted to the workspace root, so walk up to 8 levels; a version is
|
|
238
|
+
* only accepted from the project root itself or from an ancestor that looks
|
|
239
|
+
* like a workspace root (package.json / pnpm-workspace.yaml / lerna.json).
|
|
240
|
+
*/
|
|
241
|
+
function findInstalledEslintMajor(rootDir) {
|
|
242
|
+
let dir = rootDir
|
|
243
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
244
|
+
// 只采纳项目根或“像工作区根”的祖先里的安装(package.json / pnpm-workspace.yaml /
|
|
245
|
+
// lerna.json)。中间层(如 monorepo 的 packages/)通常没有任何 manifest,
|
|
246
|
+
// 必须继续向上找;而完全无关的上级目录(例如 /tmp 或 $HOME 的 node_modules)
|
|
247
|
+
// 即使存在 eslint 也不能当作项目依赖。
|
|
248
|
+
const isProjectRoot = dir === rootDir
|
|
249
|
+
const isWorkspaceRoot =
|
|
250
|
+
fs.existsSync(path.resolve(dir, "package.json")) ||
|
|
251
|
+
fs.existsSync(path.resolve(dir, "pnpm-workspace.yaml")) ||
|
|
252
|
+
fs.existsSync(path.resolve(dir, "lerna.json"))
|
|
253
|
+
|
|
254
|
+
if (isProjectRoot || isWorkspaceRoot) {
|
|
255
|
+
try {
|
|
256
|
+
const installedPkgPath = path.resolve(dir, "node_modules", "eslint", "package.json")
|
|
257
|
+
if (fs.existsSync(installedPkgPath)) {
|
|
258
|
+
const installedPkg = JSON.parse(fs.readFileSync(installedPkgPath, "utf8"))
|
|
259
|
+
const installedMajor = parseInt(String(installedPkg.version).split(".")[0], 10)
|
|
260
|
+
if (!Number.isNaN(installedMajor)) {
|
|
261
|
+
return installedMajor
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
} catch {
|
|
265
|
+
// ignore unreadable/partial installs and keep walking up
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const parent = path.dirname(dir)
|
|
270
|
+
if (parent === dir) break
|
|
271
|
+
dir = parent
|
|
272
|
+
}
|
|
273
|
+
return null
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Detect ESLint major version from the installed package or the declared range.
|
|
278
|
+
* Returns 8, 9, 10, … or null (not installed and no usable range).
|
|
238
279
|
*/
|
|
239
280
|
function detectEslintVersion(pkg = getProjectPkg(), rootDir = PROJECT_ROOT) {
|
|
240
281
|
if (!pkg) return null
|
|
241
282
|
|
|
242
|
-
// 1. If eslint is installed in node_modules
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const installedMajor = parseInt(installedPkg.version?.split(".")[0], 10)
|
|
248
|
-
if (!Number.isNaN(installedMajor)) {
|
|
249
|
-
return installedMajor
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
} catch {
|
|
253
|
-
// Fall through to package.json dependency declaration
|
|
283
|
+
// 1. If eslint is installed in node_modules (or hoisted to the workspace root),
|
|
284
|
+
// read its actual major version directly
|
|
285
|
+
const installedMajor = findInstalledEslintMajor(rootDir)
|
|
286
|
+
if (installedMajor !== null) {
|
|
287
|
+
return installedMajor
|
|
254
288
|
}
|
|
255
289
|
|
|
256
290
|
// 2. Parse package.json dependency declaration
|
|
@@ -398,12 +432,13 @@ function detectProjectType() {
|
|
|
398
432
|
*/
|
|
399
433
|
function detectCssPreprocessor() {
|
|
400
434
|
const pkg = getProjectPkg()
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
435
|
+
const allDeps = pkg
|
|
436
|
+
? {
|
|
437
|
+
...(pkg.dependencies || {}),
|
|
438
|
+
...(pkg.devDependencies || {}),
|
|
439
|
+
...(pkg.peerDependencies || {}),
|
|
440
|
+
}
|
|
441
|
+
: {}
|
|
407
442
|
|
|
408
443
|
const hasSass = allDeps["sass"] || allDeps["node-sass"] || allDeps["sass-loader"]
|
|
409
444
|
const hasLess = allDeps["less"] || allDeps["less-loader"]
|
|
@@ -437,6 +472,11 @@ function detectCssPreprocessor() {
|
|
|
437
472
|
return "scss"
|
|
438
473
|
}
|
|
439
474
|
|
|
475
|
+
// 无 package.json 时无法判断项目类型,不猜测样式方案(避免凭空安装一堆 stylelint 依赖)
|
|
476
|
+
if (!pkg) {
|
|
477
|
+
return "none"
|
|
478
|
+
}
|
|
479
|
+
|
|
440
480
|
// If not a Vue/uni-app project and no css preprocessor found, skip stylelint
|
|
441
481
|
if (!isVueProject()) {
|
|
442
482
|
return "none"
|
|
@@ -678,15 +718,15 @@ function main() {
|
|
|
678
718
|
|
|
679
719
|
if (eslintVersion !== null && eslintVersion < 8) {
|
|
680
720
|
console.error(
|
|
681
|
-
`不支持 ESLint ${eslintVersion} 版本;本配置包仅支持 ESLint 8
|
|
721
|
+
`不支持 ESLint ${eslintVersion} 版本;本配置包仅支持 ESLint 8 / 9 / 10,未修改任何文件`,
|
|
682
722
|
)
|
|
683
723
|
process.exitCode = 1
|
|
684
724
|
return
|
|
685
725
|
}
|
|
686
726
|
|
|
687
|
-
if (eslintVersion !== null && eslintVersion
|
|
727
|
+
if (eslintVersion !== null && eslintVersion > 10) {
|
|
688
728
|
warn(
|
|
689
|
-
`ESLint ${eslintVersion} 尚未在 peerDependencies 声明支持(^8.57.0 || ^9.0.0),将按 Flat Config 生成`,
|
|
729
|
+
`ESLint ${eslintVersion} 尚未在 peerDependencies 声明支持(^8.57.0 || ^9.0.0 || ^10.0.0),将按 Flat Config 生成`,
|
|
690
730
|
)
|
|
691
731
|
}
|
|
692
732
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-code-style",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
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",
|
|
@@ -45,10 +45,12 @@
|
|
|
45
45
|
"test": "node --test tests/*.test.cjs demo-test/*.test.cjs",
|
|
46
46
|
"test:demo": "node --test demo-test/*.test.cjs",
|
|
47
47
|
"test:integration:setup": "node demo-test/setup-integration.cjs",
|
|
48
|
-
"test:integration": "node
|
|
48
|
+
"test:integration": "node scripts/test-all.cjs --suite=integration",
|
|
49
49
|
"test:legacy:setup": "node demo-test/setup-legacy.cjs",
|
|
50
|
-
"test:legacy": "node
|
|
51
|
-
"test:all": "
|
|
50
|
+
"test:legacy": "node scripts/test-all.cjs --suite=legacy",
|
|
51
|
+
"test:all": "node scripts/test-all.cjs",
|
|
52
|
+
"diagnose": "node scripts/diagnose-speed.cjs",
|
|
53
|
+
"sweep": "node scripts/sweep-concurrency.cjs",
|
|
52
54
|
"lint": "eslint .",
|
|
53
55
|
"lint:fix": "eslint . --fix",
|
|
54
56
|
"format": "prettier --write .",
|
|
@@ -67,12 +69,11 @@
|
|
|
67
69
|
"peerDependencies": {
|
|
68
70
|
"@commitlint/cli": "^19.0.0",
|
|
69
71
|
"@commitlint/config-conventional": "^19.0.0",
|
|
70
|
-
"@eslint/eslintrc": "^3.0.0",
|
|
71
72
|
"@eslint/js": "^9.0.0",
|
|
72
73
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
73
74
|
"@typescript-eslint/parser": "^8.0.0",
|
|
74
75
|
"czg": "^1.0.0",
|
|
75
|
-
"eslint": "^8.57.0 || ^9.0.0",
|
|
76
|
+
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
|
76
77
|
"eslint-config-prettier": "^10.1.8",
|
|
77
78
|
"eslint-import-resolver-typescript": "^3.0.0",
|
|
78
79
|
"eslint-plugin-import": "^2.0.0",
|
|
@@ -105,9 +106,6 @@
|
|
|
105
106
|
"@commitlint/config-conventional": {
|
|
106
107
|
"optional": true
|
|
107
108
|
},
|
|
108
|
-
"@eslint/eslintrc": {
|
|
109
|
-
"optional": true
|
|
110
|
-
},
|
|
111
109
|
"@eslint/js": {
|
|
112
110
|
"optional": true
|
|
113
111
|
},
|
|
@@ -147,6 +147,8 @@ function getStagedFiles(cwd) {
|
|
|
147
147
|
const output = execSync("git diff --cached --name-only -z", {
|
|
148
148
|
cwd,
|
|
149
149
|
stdio: ["pipe", "pipe", "ignore"],
|
|
150
|
+
// 大仓库/大量暂存文件可能超过默认 1MB,避免 ENOBUFS 导致 scope 猜测整体失败
|
|
151
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
150
152
|
}).toString()
|
|
151
153
|
return output.split("\0").filter(Boolean)
|
|
152
154
|
} catch {
|
|
@@ -154,6 +156,7 @@ function getStagedFiles(cwd) {
|
|
|
154
156
|
const output = execSync("git status --porcelain -z", {
|
|
155
157
|
cwd,
|
|
156
158
|
stdio: ["pipe", "pipe", "ignore"],
|
|
159
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
157
160
|
}).toString()
|
|
158
161
|
const parts = output.split("\0")
|
|
159
162
|
const staged = []
|
package/src/eslint/base.cjs
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
// Base ESLint config for TypeScript projects
|
|
2
|
+
//
|
|
3
|
+
// Prettier 选项以 src/prettier/index.cjs 为唯一来源,避免 rules 与 prettier 配置文件漂移
|
|
4
|
+
const prettierConfig = require("../prettier/index.cjs")
|
|
5
|
+
const { overrides: _prettierOverrides, ...prettierOptions } = prettierConfig
|
|
6
|
+
|
|
2
7
|
module.exports = {
|
|
3
8
|
env: {
|
|
4
9
|
browser: true,
|
|
@@ -40,16 +45,7 @@ module.exports = {
|
|
|
40
45
|
],
|
|
41
46
|
rules: {
|
|
42
47
|
// Prettier 集成
|
|
43
|
-
"prettier/prettier": [
|
|
44
|
-
"error",
|
|
45
|
-
{
|
|
46
|
-
singleQuote: false,
|
|
47
|
-
tabWidth: 4,
|
|
48
|
-
semi: false,
|
|
49
|
-
trailingComma: "all",
|
|
50
|
-
endOfLine: "lf",
|
|
51
|
-
},
|
|
52
|
-
],
|
|
48
|
+
"prettier/prettier": ["error", prettierOptions],
|
|
53
49
|
// 格式化与风格
|
|
54
50
|
indent: "off",
|
|
55
51
|
semi: ["error", "never"],
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
// Shared constants and rule objects for Flat Config files
|
|
2
|
+
import prettierConfig from "../../prettier/index.cjs"
|
|
3
|
+
|
|
4
|
+
// Prettier 选项以 src/prettier/index.cjs 为唯一来源,避免 rules 与配置文件漂移
|
|
5
|
+
const { overrides: _prettierOverrides, ...prettierOptions } = prettierConfig
|
|
2
6
|
|
|
3
7
|
/**
|
|
4
8
|
* Prettier plugin rules — mirrors base.cjs prettier/prettier config
|
|
5
9
|
*/
|
|
6
10
|
export const prettierRules = {
|
|
7
|
-
"prettier/prettier": [
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
},
|
|
16
|
-
],
|
|
11
|
+
"prettier/prettier": ["error", prettierOptions],
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* .nvue 覆写:规则内联 options 会整体替换而非合并,必须携带完整选项
|
|
16
|
+
*/
|
|
17
|
+
export const nvuePrettierRules = {
|
|
18
|
+
"prettier/prettier": ["error", { ...prettierOptions, parser: "vue", semi: true }],
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
/**
|
package/src/eslint/flat/base.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Base ESLint Flat Config for TypeScript projects (ESLint v9+)
|
|
2
2
|
// Equivalent to src/eslint/base.cjs but in flat config format
|
|
3
3
|
|
|
4
|
+
import js from "@eslint/js"
|
|
4
5
|
import tseslint from "typescript-eslint"
|
|
5
6
|
import importX from "eslint-plugin-import-x"
|
|
6
7
|
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"
|
|
@@ -22,8 +23,13 @@ export default [
|
|
|
22
23
|
],
|
|
23
24
|
},
|
|
24
25
|
|
|
26
|
+
// ESLint 官方推荐规则
|
|
27
|
+
// Replaces: extends: ["eslint:recommended"] — 缺失它会让 flat 配置弱于传统配置
|
|
28
|
+
// (no-debugger / no-cond-assign / no-constant-condition / no-empty 等不会被检查)
|
|
29
|
+
js.configs.recommended,
|
|
30
|
+
|
|
25
31
|
// TypeScript recommended rules
|
|
26
|
-
// Replaces: extends: ["
|
|
32
|
+
// Replaces: extends: ["plugin:@typescript-eslint/recommended"]
|
|
27
33
|
...tseslint.configs.recommended,
|
|
28
34
|
|
|
29
35
|
// eslint-plugin-import-x configuration
|
package/src/eslint/flat/vue3.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import pluginVue from "eslint-plugin-vue"
|
|
|
4
4
|
import tseslint from "typescript-eslint"
|
|
5
5
|
import parserVue from "vue-eslint-parser"
|
|
6
6
|
import baseConfig from "./base.mjs"
|
|
7
|
+
import { nvuePrettierRules } from "./_shared.mjs"
|
|
7
8
|
|
|
8
9
|
export default [
|
|
9
10
|
// Spread all base configs first
|
|
@@ -54,7 +55,7 @@ export default [
|
|
|
54
55
|
// the legacy config in src/eslint/vue3.cjs.
|
|
55
56
|
semi: "off",
|
|
56
57
|
// Prettier cannot infer a parser from the custom .nvue extension.
|
|
57
|
-
|
|
58
|
+
...nvuePrettierRules,
|
|
58
59
|
},
|
|
59
60
|
},
|
|
60
61
|
]
|
package/src/eslint/vue3.cjs
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// Vue 3 ESLint config — extends base, adds Vue-specific rules
|
|
2
2
|
const base = require("./base.cjs")
|
|
3
3
|
|
|
4
|
+
// .nvue 覆写必须携带完整 Prettier 选项:规则内联 options 会整体替换而非合并
|
|
5
|
+
const prettierConfig = require("../prettier/index.cjs")
|
|
6
|
+
const { overrides: _prettierOverrides, ...prettierOptions } = prettierConfig
|
|
7
|
+
|
|
4
8
|
module.exports = {
|
|
5
9
|
...base,
|
|
6
10
|
parser: "vue-eslint-parser",
|
|
@@ -25,7 +29,7 @@ module.exports = {
|
|
|
25
29
|
rules: {
|
|
26
30
|
"vue/comment-directive": "off",
|
|
27
31
|
semi: "off",
|
|
28
|
-
"prettier/prettier": ["error", { parser: "vue", semi: true }],
|
|
32
|
+
"prettier/prettier": ["error", { ...prettierOptions, parser: "vue", semi: true }],
|
|
29
33
|
},
|
|
30
34
|
},
|
|
31
35
|
],
|
package/src/husky/commit-msg
CHANGED
package/src/husky/pre-commit
CHANGED