turbopack_core/
package_json.rs1use std::ops::Deref;
2
3use anyhow::Result;
4use async_trait::async_trait;
5use serde_json::Value as JsonValue;
6use turbo_rcstr::{RcStr, rcstr};
7use turbo_tasks::{NonLocalValue, ReadRef, ResolvedVc, Vc, debug::ValueDebugFormat};
8use turbo_tasks_fs::{FileJsonContent, FileSystemPath};
9
10use super::issue::Issue;
11use crate::{
12 asset::Asset,
13 issue::{IssueExt, IssueSource, IssueStage, StyledString},
14 source::Source,
15};
16
17#[derive(PartialEq, Eq, ValueDebugFormat, NonLocalValue)]
21pub struct PackageJson(ReadRef<FileJsonContent>);
22
23impl Deref for PackageJson {
24 type Target = JsonValue;
25 fn deref(&self) -> &Self::Target {
26 match &*self.0 {
27 FileJsonContent::Content(json) => json,
28 _ => unreachable!("PackageJson is guaranteed to hold Content"),
29 }
30 }
31}
32
33#[turbo_tasks::value(transparent, serialization = "skip")]
34pub struct OptionPackageJson(Option<PackageJson>);
35
36#[turbo_tasks::function]
39pub async fn read_package_json(path: ResolvedVc<Box<dyn Source>>) -> Result<Vc<OptionPackageJson>> {
40 let read = path.content().parse_json().await?;
41 match &*read {
42 FileJsonContent::Content(_) => Ok(OptionPackageJson(Some(PackageJson(read))).cell()),
43 FileJsonContent::NotFound => Ok(OptionPackageJson(None).cell()),
44 FileJsonContent::Unparsable(e) => {
45 let error_message = RcStr::from(format!(
46 "package.json is not parseable: invalid JSON: {}",
47 e.message
48 ));
49
50 let source = IssueSource::from_unparsable_json(path, e);
51 PackageJsonIssue {
52 error_message,
53 source,
54 }
55 .resolved_cell()
56 .emit();
57 Ok(OptionPackageJson(None).cell())
58 }
59 }
60}
61
62#[turbo_tasks::value(shared)]
64pub struct PackageJsonIssue {
65 pub error_message: RcStr,
66 pub source: IssueSource,
67}
68
69#[async_trait]
70#[turbo_tasks::value_impl]
71impl Issue for PackageJsonIssue {
72 async fn title(&self) -> Result<StyledString> {
73 Ok(StyledString::Text(rcstr!(
74 "Error parsing package.json file"
75 )))
76 }
77
78 fn stage(&self) -> IssueStage {
79 IssueStage::Parse
80 }
81
82 async fn file_path(&self) -> Result<FileSystemPath> {
83 self.source.file_path().await
84 }
85
86 async fn description(&self) -> Result<Option<StyledString>> {
87 Ok(Some(StyledString::Text(self.error_message.clone())))
88 }
89
90 fn source(&self) -> Option<IssueSource> {
91 Some(self.source)
92 }
93}