Skip to main content

turbopack_core/
changed.rs

1use anyhow::Result;
2use turbo_tasks::{
3    Completion, Completions, ResolvedVc, TryJoinIterExt, Vc,
4    graph::{AdjacencyMap, GraphTraversal},
5};
6
7use crate::{asset::Asset, module::Module, reference::referenced_modules_and_affecting_sources};
8
9async fn get_referenced_modules_and_affecting_sources(
10    parent: ResolvedVc<Box<dyn Module>>,
11) -> Result<impl Iterator<Item = ResolvedVc<Box<dyn Module>>> + Send> {
12    // This graph is only used for change detection. Traverse resolved modules and affecting
13    // sources without emitting module-type issues for unrelated files matched by dynamic requests.
14    let modules = referenced_modules_and_affecting_sources(*parent, false)
15        .await?
16        .iter()
17        .flat_map(|(_, resolved)| resolved.modules.iter().copied())
18        .collect::<Vec<_>>();
19    Ok(modules.into_iter())
20}
21
22/// Returns a completion that changes when any content of any asset in the whole
23/// asset graph changes.
24/// Also changes when the resolution of any referenced module changes (= affecting sources).
25#[turbo_tasks::function]
26pub async fn any_source_content_changed_of_module(
27    root: ResolvedVc<Box<dyn Module>>,
28) -> Result<Vc<Completion>> {
29    let completions = AdjacencyMap::new()
30        .visit([root], get_referenced_modules_and_affecting_sources)
31        .await
32        .completed()?
33        .into_postorder_topological()
34        .map(|m| source_changed(*m))
35        .map(|v| v.to_resolved())
36        .try_join()
37        .await?;
38
39    Ok(Vc::<Completions>::cell(completions).completed())
40}
41
42/// Returns a completion that changes when the content of the given asset
43/// changes.
44#[turbo_tasks::function]
45pub async fn content_changed(asset: Vc<Box<dyn Asset>>) -> Result<Vc<Completion>> {
46    // Reading the file content is enough to add as dependency
47    asset.content().file_content().await?;
48    Ok(Completion::new())
49}
50
51/// Returns a completion that changes when the content of the given asset
52/// changes.
53#[turbo_tasks::function]
54pub async fn source_changed(asset: Vc<Box<dyn Module>>) -> Result<Vc<Completion>> {
55    if let Some(source) = *asset.source().await? {
56        // Reading the file content is enough to add as dependency
57        source.content().file_content().await?;
58    }
59    Ok(Completion::new())
60}