turbopack_dev_server/source/
issue_context.rs

1use anyhow::Result;
2use turbo_rcstr::RcStr;
3use turbo_tasks::{ResolvedVc, Value, Vc};
4use turbo_tasks_fs::FileSystemPath;
5use turbopack_core::{
6    introspect::{Introspectable, IntrospectableChildren},
7    issue::IssueDescriptionExt,
8};
9
10use super::{
11    ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataVary, ContentSources,
12    GetContentSourceContent,
13    route_tree::{MapGetContentSourceContent, RouteTree},
14};
15
16#[turbo_tasks::value]
17pub struct IssueFilePathContentSource {
18    file_path: Option<ResolvedVc<FileSystemPath>>,
19    description: RcStr,
20    source: ResolvedVc<Box<dyn ContentSource>>,
21}
22
23#[turbo_tasks::value_impl]
24impl IssueFilePathContentSource {
25    #[turbo_tasks::function]
26    pub fn new_file_path(
27        file_path: ResolvedVc<FileSystemPath>,
28        description: RcStr,
29        source: ResolvedVc<Box<dyn ContentSource>>,
30    ) -> Vc<Self> {
31        IssueFilePathContentSource {
32            file_path: Some(file_path),
33            description,
34            source,
35        }
36        .cell()
37    }
38
39    #[turbo_tasks::function]
40    pub fn new_description(
41        description: RcStr,
42        source: ResolvedVc<Box<dyn ContentSource>>,
43    ) -> Vc<Self> {
44        IssueFilePathContentSource {
45            file_path: None,
46            description,
47            source,
48        }
49        .cell()
50    }
51}
52
53#[turbo_tasks::value_impl]
54impl ContentSource for IssueFilePathContentSource {
55    #[turbo_tasks::function]
56    async fn get_routes(self: ResolvedVc<Self>) -> Result<Vc<RouteTree>> {
57        let this = self.await?;
58        let routes = content_source_get_routes_operation(this.source)
59            .issue_file_path(this.file_path.map(|v| *v), &*this.description)
60            .await?
61            .connect();
62        Ok(routes.map_routes(Vc::upcast(
63            IssueContextContentSourceMapper { source: self }.cell(),
64        )))
65    }
66
67    #[turbo_tasks::function]
68    fn get_children(&self) -> Vc<ContentSources> {
69        Vc::cell(vec![self.source])
70    }
71}
72
73#[turbo_tasks::function(operation)]
74fn content_source_get_routes_operation(
75    source: ResolvedVc<Box<dyn ContentSource>>,
76) -> Vc<RouteTree> {
77    source.get_routes()
78}
79
80#[turbo_tasks::value]
81struct IssueContextContentSourceMapper {
82    source: ResolvedVc<IssueFilePathContentSource>,
83}
84
85#[turbo_tasks::value_impl]
86impl MapGetContentSourceContent for IssueContextContentSourceMapper {
87    #[turbo_tasks::function]
88    fn map_get_content(
89        &self,
90        get_content: ResolvedVc<Box<dyn GetContentSourceContent>>,
91    ) -> Vc<Box<dyn GetContentSourceContent>> {
92        Vc::upcast(
93            IssueContextGetContentSourceContent {
94                get_content,
95                source: self.source,
96            }
97            .cell(),
98        )
99    }
100}
101
102#[turbo_tasks::value]
103struct IssueContextGetContentSourceContent {
104    get_content: ResolvedVc<Box<dyn GetContentSourceContent>>,
105    source: ResolvedVc<IssueFilePathContentSource>,
106}
107
108#[turbo_tasks::value_impl]
109impl GetContentSourceContent for IssueContextGetContentSourceContent {
110    #[turbo_tasks::function]
111    async fn vary(&self) -> Result<Vc<ContentSourceDataVary>> {
112        let source = self.source.await?;
113        Ok(get_content_source_vary_operation(self.get_content)
114            .issue_file_path(source.file_path.map(|v| *v), &*source.description)
115            .await?
116            .connect())
117    }
118
119    #[turbo_tasks::function]
120    async fn get(
121        &self,
122        path: RcStr,
123        data: Value<ContentSourceData>,
124    ) -> Result<Vc<ContentSourceContent>> {
125        let source = self.source.await?;
126        Ok(
127            get_content_source_get_operation(self.get_content, path, data)
128                .issue_file_path(source.file_path.map(|v| *v), &*source.description)
129                .await?
130                .connect(),
131        )
132    }
133}
134
135#[turbo_tasks::function(operation)]
136fn get_content_source_vary_operation(
137    get_content: ResolvedVc<Box<dyn GetContentSourceContent>>,
138) -> Vc<ContentSourceDataVary> {
139    get_content.vary()
140}
141
142#[turbo_tasks::function(operation)]
143fn get_content_source_get_operation(
144    get_content: ResolvedVc<Box<dyn GetContentSourceContent>>,
145    path: RcStr,
146    data: Value<ContentSourceData>,
147) -> Vc<ContentSourceContent> {
148    get_content.get(path, data)
149}
150
151#[turbo_tasks::value_impl]
152impl Introspectable for IssueFilePathContentSource {
153    #[turbo_tasks::function]
154    async fn ty(&self) -> Result<Vc<RcStr>> {
155        Ok(
156            if let Some(source) = ResolvedVc::try_sidecast::<Box<dyn Introspectable>>(self.source) {
157                source.ty()
158            } else {
159                Vc::cell("IssueContextContentSource".into())
160            },
161        )
162    }
163
164    #[turbo_tasks::function]
165    async fn title(&self) -> Result<Vc<RcStr>> {
166        Ok(
167            if let Some(source) = ResolvedVc::try_sidecast::<Box<dyn Introspectable>>(self.source) {
168                let title = source.title().await?;
169                Vc::cell(format!("{}: {}", self.description, title).into())
170            } else {
171                Vc::cell(self.description.clone())
172            },
173        )
174    }
175
176    #[turbo_tasks::function]
177    async fn details(&self) -> Result<Vc<RcStr>> {
178        Ok(
179            if let Some(source) = ResolvedVc::try_sidecast::<Box<dyn Introspectable>>(self.source) {
180                source.details()
181            } else {
182                Vc::cell(RcStr::default())
183            },
184        )
185    }
186
187    #[turbo_tasks::function]
188    async fn children(&self) -> Result<Vc<IntrospectableChildren>> {
189        Ok(
190            if let Some(source) = ResolvedVc::try_sidecast::<Box<dyn Introspectable>>(self.source) {
191                source.children()
192            } else {
193                Vc::cell(Default::default())
194            },
195        )
196    }
197}