Skip to main content

turbopack_dev_server/source/
combined.rs

1use anyhow::Result;
2use turbo_rcstr::{RcStr, rcstr};
3use turbo_tasks::{ResolvedVc, TryJoinIterExt, Vc};
4use turbopack_core::introspect::{Introspectable, IntrospectableChildren};
5
6use crate::source::{
7    ContentSource, ContentSources,
8    route_tree::{RouteTree, RouteTrees},
9};
10
11/// Combines multiple [`ContentSource`]s by [merging][RouteTrees::merge] [`RouteTree`]s.
12#[turbo_tasks::value(shared)]
13pub struct CombinedContentSource {
14    pub sources: Vec<ResolvedVc<Box<dyn ContentSource>>>,
15}
16
17impl CombinedContentSource {
18    pub fn new(sources: Vec<ResolvedVc<Box<dyn ContentSource>>>) -> Vc<Self> {
19        CombinedContentSource { sources }.cell()
20    }
21}
22
23#[turbo_tasks::value_impl]
24impl ContentSource for CombinedContentSource {
25    #[turbo_tasks::function]
26    async fn get_routes(&self) -> Result<Vc<RouteTree>> {
27        let all_routes = self
28            .sources
29            .iter()
30            .map(|s| async move { s.get_routes().to_resolved().await })
31            .try_join()
32            .await?;
33        Ok(Vc::<RouteTrees>::cell(all_routes).merge())
34    }
35
36    #[turbo_tasks::function]
37    fn get_children(&self) -> Vc<ContentSources> {
38        Vc::cell(self.sources.clone())
39    }
40}
41
42#[turbo_tasks::value_impl]
43impl Introspectable for CombinedContentSource {
44    #[turbo_tasks::function]
45    fn ty(&self) -> Vc<RcStr> {
46        Vc::cell(rcstr!("combined content source"))
47    }
48
49    #[turbo_tasks::function]
50    async fn title(&self) -> Result<Vc<RcStr>> {
51        let titles = self
52            .sources
53            .iter()
54            .map(|&source| async move {
55                Ok(
56                    if let Some(source) =
57                        ResolvedVc::try_sidecast::<Box<dyn Introspectable>>(source)
58                    {
59                        Some(source.title().await?)
60                    } else {
61                        None
62                    },
63                )
64            })
65            .try_join()
66            .await?;
67        let mut titles = titles.into_iter().flatten().collect::<Vec<_>>();
68        titles.sort();
69        const NUMBER_OF_TITLES_TO_DISPLAY: usize = 5;
70        let mut titles = titles
71            .iter()
72            .map(|t| t.as_str())
73            .filter(|t| !t.is_empty())
74            .take(NUMBER_OF_TITLES_TO_DISPLAY + 1)
75            .collect::<Vec<_>>();
76        if titles.len() > NUMBER_OF_TITLES_TO_DISPLAY {
77            titles[NUMBER_OF_TITLES_TO_DISPLAY] = "...";
78        }
79        Ok(Vc::cell(titles.join(", ").into()))
80    }
81
82    #[turbo_tasks::function]
83    async fn children(&self) -> Result<Vc<IntrospectableChildren>> {
84        Ok(Vc::cell(
85            self.sources
86                .iter()
87                .copied()
88                .map(|s| async move { Ok(ResolvedVc::try_sidecast::<Box<dyn Introspectable>>(s)) })
89                .try_join()
90                .await?
91                .into_iter()
92                .flatten()
93                .map(|i| (rcstr!("source"), i))
94                .collect(),
95        ))
96    }
97}