Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

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

Đang mở
#5,892 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
52/100
Loại issue
Tái cấu trúc
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Ít trao đổi
Công nghệ
node.js, typescript
Lĩnh vực
performance, tooling

Hướng nghiên cứu

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.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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.
Ngôn ngữ chính
TypeScript
Star
6.5k
Fork
708
Merge trung bình
4 ngày 13 giờ
Pull request đã merge (30 ngày)
62

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của microsoft/rushstack

Tất cả issue của microsoft/rushstack

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.