Repository navigation
[7.1 API] Equivalent of BuilderProgram.getAllDependencies / batched module resolutionΒ #64920
Description
π Search Terms
getAllDependencies, dependency graph, getResolvedModule, batched, 7.1 API, typescript/sync, typescript/async
β Viability Checklist
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
β Suggestion
In TypeScript β€ 6, BuilderProgram.getAllDependencies(sourceFile) returned the transitive set of files a given source file depends on (module imports, /// <reference path>, type reference directives, and project-reference redirects).
With the 7.1 beta, builder/watch/solution-builder APIs are explicitly out of scope for stable (#64709), so there is no equivalent. The building blocks are mostly present (program.getSourceFileNames(), program.getSourceFile(), and the new program.getResolvedModule() / getResolvedTypeReferenceDirective() from #64247), but reconstructing the dependency graph requires one IPC round-trip per import per file, which gets expensive quickly on larger projects.
I'd like to request one (or both) of the following:
- A dependency-graph method on
Programβ e.g.program.getAllDependencies(sourceFile)orprogram.getDependencies(sourceFile)returning the direct/transitive dependency file names, computed server-side. - A batched resolution method β e.g.
program.getResolvedModules(sourceFile)returning all resolutions for a file in a single call, similar in spirit to the batched methods added in Add batched version for the several APIΒ #63904. This would let consumers build the graph themselves with one call per file instead of one call per import.
Option 1 is the ergonomic fit for the old API; option 2 is a smaller primitive and can be used independently.
π Motivating Example
I use getAllDependencies in StrykerJS to identify inrelated files and use that to implement mutant grouping (a roughly 50% performance improvement over single mutant validation). Migrating to 7.1 currently means re-implementing the traversal client-side.
Current client-side reconstruction (7.1 beta) (using AI)
import { API } from "typescript/sync";
function getAllDependencies(program: Program, rootFileName: string) {
const seen = new Set<string>();
const queue = [rootFileName];
while (queue.length) {
const fileName = queue.pop()!;
if (seen.has(fileName)) continue;
seen.add(fileName);
const sf = program.getSourceFile(fileName);
if (!sf) continue;
// One round-trip per import
for (const imp of sf.imports) {
const r = program.getResolvedModule(sf, imp.text /*, mode */);
if (r?.resolvedModule) queue.push(r.resolvedModule.resolvedFileName);
}
// One round-trip per type reference directive
for (const ref of sf.typeReferenceDirectives) {
const r = program.getResolvedTypeReferenceDirective(sf, ref.fileName);
if (r?.resolvedTypeReferenceDirective?.resolvedFileName) {
queue.push(r.resolvedTypeReferenceDirective.resolvedFileName);
}
}
for (const ref of sf.referencedFiles) {
queue.push(resolve(dirname(fileName), ref.fileName));
}
}
seen.delete(rootFileName);
return [...seen];
}Issues with this approach:
- Round-trip count scales with total import count, not file count.
- Project-reference output redirects (handled by the old builder method) have to be reimplemented manually.
- Resolution mode (
ESNextvsCommonJS) must be derived client-side per import.
π» Use Cases
- What do you want to use this for?
Generate a list of unrelated files so we can validate multiple mutants in a single type-check run.
- What shortcomings exist with current approaches?
Per-import IPC calls make the client-side traversal slow on large graphs, and project-reference redirects are easy to get subtly wrong.
- What workarounds are you using in the meantime?
The reconstruction above.
Activity