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