核心代码逻辑 - whiter001/vue-tsc-files GitHub Wiki
基于版本 1.3.4,提交
9372517d的源码静态阅读。
vue-tsc-files 本身不实现类型检查,而是围绕 vue-tsc 的轻量 CLI 包装器。它解决两个问题:
- 保留项目 tsconfig 配置,同时缩小类型检查的入口文件范围。
- 可选择只让目标文件自身的错误影响退出码,依赖文件的错误仍完整展示。
解析命令行参数,合并显式文件和 Git 收集结果
→ 读取项目 tsconfig,补充项目范围内的 .d.ts
→ 在原配置旁生成临时 tsconfig
→ 定位 vue-tsc 的 JS 入口
→ 使用当前 Node 调用 vue-tsc,强制 --noEmit
→ 处理输出与退出码
→ 退出时清理临时配置
运行时代码只有两个文件:
-
src/cli.ts:入口,串联流程、启动子进程、处理输出和退出码。 -
src/util.ts:参数解析、Git 文件收集、临时配置生成与清理、诊断归属判断。
setupArgs() 将参数分为三类:
- 文件参数:按扩展名识别
.vue/.ts/.tsx/.mts/.cts,大小写不敏感;相对路径按当前工作目录解析,也接受绝对路径。 - 工具参数:消费
-p/--project、Git 收集开关、错误过滤开关、帮助参数。支持--project=<path>和-p=<path>。 - 其他参数:原样转发给
vue-tsc,例如--pretty。
显式文件与 Git 收集模式可以混用,结果合并去重:
-
specifiedFiles:用户显式指定或 Git 收集的目标文件,用于错误归属。 -
files:目标列表的副本;生成配置时再拼接自动收集的.d.ts,作为临时配置的入口列表。
最终没有目标文件时:启用了任意 Git 收集开关,提示并退出 0;否则是用法错误,退出 1。--help 在文件收集和配置读取之前生效。
实现见 getChangedFiles()/getStagedFiles()/getUnstagedFiles()。
| 参数 | 数据来源 | 收集范围 |
|---|---|---|
--changed |
git status --porcelain=v1 -z -uall -- . |
暂存、未暂存、未跟踪等变更 |
--staged |
git diff --cached --name-only -z --diff-filter=ACMRT -- . |
暂存区变更 |
--unstaged |
git diff --name-only -z --diff-filter=ACMRT -- . |
已跟踪文件的未暂存变更,不含未跟踪文件 |
使用 NUL 分隔处理含空格路径;git status 重命名记录保留新路径、跳过旧路径。收集结果转为 cwd 相对路径,并过滤不支持的扩展名、node_modules 和已经不存在的文件。命令带 -- .,在仓库子目录执行时只收集该子目录范围的变更。
Git 子进程设有 30 秒超时和 64 MB 输出缓冲区。
--staged 按 index 选文件,但检查磁盘上的当前内容,不读取暂存快照。
入口见 createAndSetupTsConfig(),构造见 createTmpTsConfig()。
- 未传
-p时使用 cwd 的tsconfig.json,不向上搜索;传目录时读取目录内的tsconfig.json。 - 使用 TypeScript 的
readConfigFile()读取配置,支持注释和尾逗号。 - 使用
getParsedCommandLineOfConfigFile()解析extends链及原项目files/include/exclude范围,从文件列表中补充.d.ts。 - 展开保留原配置的其他字段,包括
extends、exclude、references和编译选项;替换入口files,并设置include: []。 -
files写绝对路径,避免 cwd 与-p配置目录不同导致路径错位。 -
skipLibCheck默认true,但根配置或extends链显式设置过时尊重用户值。
临时配置放在原 tsconfig 旁边,保证相对 extends、baseUrl、paths、typeRoots 等按原目录解析。
显式列入 files 的源码不受原 include/exclude 过滤。缩小入口不等于隔离依赖:目标文件通过 import 引入的其他文件仍可能进入类型检查。
检测到 references 时会提示;工具不跟随引用执行多项目检查,不能将 solution tsconfig 的调用视为完整项目检查。
createResolverRequires() 提供 cwd 和工具自身两个解析锚点。TypeScript 优先从当前项目加载,找不到再回退到工具位置。
resolveVueTscEntry() 首先按 cwd、工具位置的顺序解析 vue-tsc/package.json,拼出 bin/vue-tsc.js;若均失败,再按这两个锚点直接解析 bin 子路径。
这样通常优先使用项目版本,并兼容 pnpm 的符号链接布局。最终调用:
当前 Node + vue-tsc JS入口 + -p 临时配置 + 转发参数 + --noEmit
实现见 src/cli.ts:59–114。
普通模式使用 stdio: "inherit" 直接透传输出,退出码使用 status ?? 1,启动失败不会静默通过。
--errors-in-changed-only(别名 --changed-only)模式捕获输出,缓冲区为 64 MB;正常获得结果时完整打印 stdout/stderr,再判断是否阻断:
| 情况 | 结果 |
|---|---|
子进程启动或运行返回 error
|
退出 1
|
vue-tsc 成功 |
退出 0
|
| 非零状态,指定文件自身有错误 | 保留非零退出码 |
| 非零状态,有无文件位置的全局诊断 | 保留非零退出码 |
| 非零状态,输出无可识别的 TS 错误,例如崩溃 | 保留非零退出码 |
| 非零状态,错误全部属于非指定文件 | 展示错误和提示,但退出 0
|
filterErrorsInFiles() 去除 ANSI 色码,兼容普通与 --pretty 诊断格式,将文件路径规范化后与 specifiedFiles 比较。无位置的 error TSxxxx: 诊断单独归为全局错误。
过滤依据是文件归属,不比较 Git 基线或修改行。 指定文件中的旧错误仍阻断,非指定文件中的新错误也可能被豁免。自动补充的 .d.ts 不参与指定文件归属,除非它也被显式传入或由 Git 收集。
捕获模式设置 process.exitCode 而非立即 process.exit(),让输出自然排空,避免截断管道尾部。
registerCleanupHandler() 用集合记录临时路径,监听器只注册一次;退出或收到 SIGHUP/SIGINT/SIGTERM 时同步删除临时配置,信号退出码分别是 129/130/143。
rolldown.config.mjs 将 src/cli.ts 打包为根目录的 vue-tsc-files,使用 ESM、不压缩,TypeScript 保持外部依赖。根目录文件是生成的发布产物,不应直接编辑。
-
pnpm build:生成 CLI bundle。 -
pnpm check:oxlint、oxfmt 检查与 TypeScript 检查。 -
pnpm test:pretest 先构建,再执行 Node 测试。
test/util.test.ts 覆盖参数解析、Git 输出解析、诊断过滤和配置生成;test/cli.test.ts 覆盖真实 CLI 的退出码、依赖错误过滤、Git 收集、配置路径、依赖定位和临时文件清理。