Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

[api-extractor] Reuse TypeScript's module-resolution results to avoid realpath/lstat storm when resolving external package names

未关闭
#5,892 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
52/100
Issue 类型
重构
描述清晰度
基本清楚
活跃度
冷清

调研方向

Start at DeclarationReferenceGenerator._getPackageName, then inspect Collector, AstSymbolTable, and TypeScriptInternals.ts for program-resolution access. Include module and type-reference resolutions, verify packageId and resolvedFileName matching, and run the acceptance-test projects to confirm byte-identical API reports while preserving the filesystem fallback.

由索引模型根据 Issue 内容生成。

描述

Summary

During analysis, DeclarationReferenceGenerator._getPackageName(sourceFile) calls PackageJsonLookup.tryLoadNodePackageJsonFor(sourceFile.fileName) once per external source file. That path (PackageJsonLookup._tryLoadNodePackageJsonInner) calls FileSystem.getRealPath() (Node fs.realpathSync → an lstat per path segment, following symlinks) before the content cache can help, and the upward folder walk in _tryGetPackageFolderFor does it at each directory level. In pnpm workspaces (a node_modules symlink farm) this produces a large lstat storm and shows up as a significant chunk of api-extractor CPU time in profiles.

This was noticed while profiling the type-check optimization in https://github.com/microsoft/rushstack/pull/5891 — after removing the whole-program semantic check, realpathSync→lstat inside FileSystem.getRealPath → tryLoadNodePackageJsonFor was the next-largest chunk.

Insight

TypeScript already resolved every one of these modules during program construction and recorded the answer. Each ResolvedModuleFull carries:

  • resolvedFileName — the already-realpath'd target (TS paid the lstat cost once, cached), and
  • packageId.name — the bare package name, which is exactly what _getPackageName reconstructs via the filesystem walk (packageId.subModuleName holds the sub-path separately).
Proof of concept

Probing the @rushstack/mcp-server program via the (internal) program.forEachResolvedModule(cb):

resolutions: total=1111, withPackageId=1103, uniqueFiles=258
  @modelcontextprotocol/sdk  <=  @modelcontextprotocol/sdk/dist/esm/server/mcp.d.ts
  zod                        <=  zod/index.d.cts
  ...

99.3% of resolutions carry packageId, and packageId.name came back as the bare package name even for non-index files.

Proposed design
  1. Build a Map<resolvedFileName, packageId.name> once (e.g. off Collector/AstSymbolTable) via the internal program.forEachResolvedModule(...). Type-reference-directive resolutions (forEachResolvedTypeReferenceDirective) also carry packageId and should be included.
  2. In _getPackageName, consult the map first (keyed by sourceFile.fileName) — zero filesystem access for the common case.
  3. Fall back to tryLoadNodePackageJsonFor on a miss (the ~0.7% without packageId, or files reached via other means), preserving today's exact behavior.

forEachResolvedModule / getResolvedModule are TypeScript internals (not in the public .d.ts), but api-extractor already accesses TS internals via TypeScriptInternals.ts, so this is consistent with existing patterns.

Caveats to validate
  • packageId.name semantics — the TS doc comment hints it may include a subpath in some cases; the PoC showed bare names, but this needs verification against @types packages and deep imports vs. the existing packageJson.name behavior.
  • Key matching — resolvedFileName must equal the program's sourceFile.fileName (generally true; preserveSymlinks is the edge case).
  • Correctness — must produce byte-identical API reports across all acceptance-test projects. The fast-path-with-fallback design keeps this low-risk.
Related
  • Follow-up to #5891 (type-check pass optimization).
  • Also worth checking SourceMapper.getRealPath usage for the same treatment.
主要语言
TypeScript
星标
6.5k
派生
708
平均合并
2 天 1 小时
30 天内合并 PR
46

环境准备

我们还没有检查这个项目的环境配置文件。先看它的 README,通用步骤见我们的新手贡献指南。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

microsoft/rushstack 的其他 Issue

查看 microsoft/rushstack 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。