Skip to content

refactor(compiler-cli): drive WASM getMetadataForFile through the preprocessor pump loop - #71918

Draft
clydin wants to merge 3 commits into
angular:mainfrom
clydin:ngp-host-h4-1
Draft

clydin wants to merge 3 commits into
angular:mainfrom
clydin:ngp-host-h4-1

Conversation

@clydin

@clydin clydin commented Nov 10, 2026

Copy link
Copy Markdown
Member

Previously, WasmAnalyzer.getMetadataForFile delegated directly to
getMetadataForFileSync, which synchronously stepped the WASM query engine
to completion inside a single FFI call. When an asynchronous AnalysisHost
suspends module resolution or content loading across JavaScript round-trips,
blocking inside a single WASM export cannot yield back to the host.

Add ModuleRef and QueryEngine::get_metadata_for_file_id (tracking whether
ParseFile loaded a module on ParsedFileOwner::loaded so missing modules
return None under asynchronous hosts just as they do under DefaultFsHost).
Expose Analyzer::request_metadata_core and WasmAnalyzer::request_metadata,
emitting metadataResult events from WasmAnalyzer::pump as oneshot queries
settle.

Update the TypeScript WasmAnalyzer adapter so getMetadataForFile registers
a pending request via request_metadata and resolves through pumpLoop
alongside active analysis streams, while cleaning up in-flight requests when
close() is called.

@clydin clydin added the target: minor This PR is targeted for the next minor release label Nov 10, 2026
@angular-robot angular-robot Bot added the area: compiler Issues related to `ngc`, Angular's template compiler label Nov 10, 2026
@ngbot ngbot Bot added this to the Backlog milestone Nov 10, 2026
@clydin
clydin force-pushed the ngp-host-h4-1 branch 4 times, most recently from 917092d to 7217bb1 Compare November 11, 2026 18:33
… imports in preprocessor

Previously, `QueryEngine` invoked `AnalysisHost::resolve` directly on every
syntactic dependency scan, cross-file constant evaluation, export-map walk,
and NgModule scope traversal without an engine-level cache. For asynchronous
bundler hosts, repeating identical `(importer, specifier, kind, type_only,
attributes)` lookups across queries and rebuilds would generate redundant
cross-boundary round-trips. In addition, failed module resolutions only
recorded `UNRESOLVED_IMPORTS_FILE_ID` during the Stage-1 static dependency
scan of `.ts` sources. That scan does not resolve the specifiers of `.d.ts`
files, so a failed lookup made from one, such as a re-export to a missing
target, was untracked and not re-run when the target was later created.
Deleting a resolved file also left importers holding stale cached dependency
edges.

Introduce `ResolutionCache` on `QueryEngine` to memoize completed module
resolution outcomes per importer `FileId` and request key while maintaining
both a target-to-importer reverse index and an unresolved-importer index.
Route query-time module lookups through `QueryContext::resolve_request`,
`resolve_from_id`, and `resolve_from_path` so every resolution records the
importer dependency and every failed lookup—including negative cache hits—
records `UNRESOLVED_IMPORTS_FILE_ID`. Classify pure re-exports in
`analyze_file_syntax` with `ImportKind::ReExport` so syntactic dependency
discovery shares cached resolutions with cross-file evaluation and export-map
queries.

On `invalidate_file_id`, drop only the edited importer's cached resolutions
so edits to a leaf module preserve cached resolutions across its importers.
On `FileUpdateType::Deleted`, evict queries derived from importers that had
resolved to the deleted target while keeping their `ParseFile` results
cached. On `invalidate_module_resolution`, stop serving every cached
resolution and re-run importers with previously unresolved specifiers. The
superseded entries are kept as stale rather than dropped, so the reverse
index still covers importers whose queries stay cached and that therefore do
not resolve again, and a lookup that the host answers after the change is
not memoized.

When a host resolution changes a module's `IdKind`, also evict the importers
whose cached resolutions report the previous kind. The resolution that
changed the kind is not memoized, so the query re-run that follows asks the
host again.
…or and HybridCompiler

Bundler integrations and workspace reconfigurations can change how module
specifiers resolve without editing any individual source file—for example
when alias tables, export conditions, or package layouts change between
builds. While `invalidate_module_resolution` re-runs previously failed
resolutions after file creation or deletion, callers also need a way to
flush positive cached resolutions without discarding parsed ASTs.

Add `ResolutionCache::clear_all` and `QueryEngine::clear_resolution_cache`
to clear both host-internal and engine-level resolution caches and evict
queries derived from any importer's resolutions while preserving cached
`ParseFile` results. Expose `clear_resolution_cache` on `Analyzer`,
`TestAnalyzer`, `WasmAnalyzer`, and the sidecar JSON-RPC server, returning
the deduplicated list of stale module IDs while preserving virtual module
IDs verbatim instead of normalizing backslashes.

Surface `clearResolutionCache` on `IAnalyzer`, `WasmAnalyzer`,
`NapiAnalyzer`, `SidecarAnalyzer`, and `HybridCompiler`. In `HybridCompiler`,
sequence `clearResolutionCache` through the serialized update queue so
evicted analyses are dropped from the TypeScript file cache, recorded for
incremental emit, and refreshed on the following delta pass.
…processor pump loop

Previously, `WasmAnalyzer.getMetadataForFile` called the synchronous
`getMetadataForFile` WASM export directly, stepping the query engine to
completion inside a single FFI call. When an asynchronous `AnalysisHost`
suspends module resolution or content loading across JavaScript round-trips,
blocking inside a single WASM export cannot yield back to the host.

Add `ModuleRef` and `QueryEngine::get_metadata_for_file_id` (tracking whether
`ParseFile` loaded a module on `ParsedFileOwner::loaded` so missing modules
return `None` under asynchronous hosts just as they do under `DefaultFsHost`).
Expose `Analyzer::request_metadata_core` and `WasmAnalyzer::request_metadata`,
emitting `metadataResult` events from `WasmAnalyzer::pump` as oneshot queries
settle.

Update the TypeScript `WasmAnalyzer` adapter so `getMetadataForFile` registers
a pending request via `request_metadata` and resolves through `pumpLoop`
alongside active analysis streams, while cleaning up in-flight requests when
`close()` is called.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: compiler Issues related to `ngc`, Angular's template compiler state: blocked target: minor This PR is targeted for the next minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant