Repository: vercel/next.js
Pull request: Turbopack: Update `jsonc-parser`, dedupe with SWC

I noticed we had two copies of this library.

There are a few minor API changes (some things that were properties are now methods, "message" is now "kind"), and I switched our error type over to use `RcStr` since it implements `Clone`.

Closes PACK-5181

Changed files:
filename: Cargo.lock
patch: @@ -3475,18 +3475,9 @@ dependencies = [
 
 [[package]]
 name = "jsonc-parser"
-version = "0.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a1853e40333206f9a685358046d13ab200169e3ee573019bddf0ede0dc29307"
-dependencies = [
- "serde_json",
-]
-
-[[package]]
-name = "jsonc-parser"
-version = "0.26.2"
+version = "0.26.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b558af6b49fd918e970471374e7a798b2c9bbcda624a210ffa3901ee5614bc8e"
+checksum = "1d6d80e6d70e7911a29f3cf3f44f452df85d06f73572b494ca99a2cad3fcf8f4"
 dependencies = [
  "serde_json",
 ]
@@ -6978,7 +6969,7 @@ dependencies = [
  "dashmap 5.5.3",
  "either",
  "indexmap 2.9.0",
- "jsonc-parser 0.26.2",
+ "jsonc-parser",
  "napi",
  "napi-derive",
  "once_cell",
@@ -9347,7 +9338,7 @@ dependencies = [
  "futures",
  "include_dir",
  "indexmap 2.9.0",
- "jsonc-parser 0.21.0",
+ "jsonc-parser",
  "mime",
  "notify",
  "parking_lot",

filename: turbopack/crates/turbo-tasks-fs/Cargo.toml
patch: @@ -33,7 +33,7 @@ dunce = { workspace = true }
 futures = { workspace = true }
 include_dir = { version = "0.7.2", features = ["nightly"] }
 indexmap = { workspace = true }
-jsonc-parser = { version = "0.21.0", features = ["serde"] }
+jsonc-parser = { version = "0.26.3", features = ["serde"] }
 mime = { workspace = true }
 notify = { workspace = true }
 parking_lot = { workspace = true }

filename: turbopack/crates/turbo-tasks-fs/src/json.rs
patch: @@ -1,18 +1,16 @@
-use std::{
-    borrow::Cow,
-    fmt::{Display, Formatter, Write},
-};
+use std::fmt::{Display, Formatter, Write};
 
 use anyhow::Result;
 use serde::{Deserialize, Serialize};
+use turbo_rcstr::RcStr;
 use turbo_tasks::{NonLocalValue, trace::TraceRawVcs};
 
 use crate::{rope::Rope, source_context::get_source_context};
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, TraceRawVcs, NonLocalValue)]
 pub struct UnparsableJson {
-    pub message: Cow<'static, str>,
-    pub path: Option<String>,
+    pub message: RcStr,
+    pub path: Option<RcStr>,
     /// The start line and column of the error.
     /// Line and column is 0-based.
     pub start_location: Option<(u32, u32)>,
@@ -34,18 +32,18 @@ fn byte_to_location(pos: usize, text: &str) -> (u32, u32) {
 impl UnparsableJson {
     pub fn from_jsonc_error(e: jsonc_parser::errors::ParseError, text: &str) -> Self {
         Self {
-            message: e.message.clone().into(),
+            message: RcStr::from(e.kind().to_string()),
             path: None,
-            start_location: Some(byte_to_location(e.range.start, text)),
-            end_location: Some(byte_to_location(e.range.end, text)),
+            start_location: Some(byte_to_location(e.range().start, text)),
+            end_location: Some(byte_to_location(e.range().end, text)),
         }
     }
 
     pub fn from_serde_path_to_error(e: serde_path_to_error::Error<serde_json::Error>) -> Self {
         let inner = e.inner();
         Self {
-            message: inner.to_string().into(),
-            path: Some(e.path().to_string()),
+            message: RcStr::from(inner.to_string()),
+            path: Some(RcStr::from(e.path().to_string())),
             start_location: Some((
                 inner.line().saturating_sub(1) as u32,
                 inner.column().saturating_sub(1) as u32,

filename: turbopack/crates/turbo-tasks-fs/src/lib.rs
patch: @@ -1942,15 +1942,15 @@ impl FileContent {
                 ) {
                     Ok(data) => match data {
                         Some(value) => FileJsonContent::Content(value),
-                        None => FileJsonContent::unparsable(
-                            "text content doesn't contain any json data",
-                        ),
+                        None => FileJsonContent::unparsable(rcstr!(
+                            "text content doesn't contain any json data"
+                        )),
                     },
                     Err(e) => FileJsonContent::Unparsable(Box::new(
                         UnparsableJson::from_jsonc_error(e, string.as_ref()),
                     )),
                 },
-                Err(_) => FileJsonContent::unparsable("binary is not valid utf-8 text"),
+                Err(_) => FileJsonContent::unparsable(rcstr!("binary is not valid utf-8 text")),
             },
             FileContent::NotFound => FileJsonContent::NotFound,
         }
@@ -1969,15 +1969,15 @@ impl FileContent {
                 ) {
                     Ok(data) => match data {
                         Some(value) => FileJsonContent::Content(value),
-                        None => FileJsonContent::unparsable(
-                            "text content doesn't contain any json data",
-                        ),
+                        None => FileJsonContent::unparsable(rcstr!(
+                            "text content doesn't contain any json data"
+                        )),
                     },
                     Err(e) => FileJsonContent::Unparsable(Box::new(
                         UnparsableJson::from_jsonc_error(e, string.as_ref()),
                     )),
                 },
-                Err(_) => FileJsonContent::unparsable("binary is not valid utf-8 text"),
+                Err(_) => FileJsonContent::unparsable(rcstr!("binary is not valid utf-8 text")),
             },
             FileContent::NotFound => FileJsonContent::NotFound,
         }
@@ -2084,16 +2084,16 @@ impl FileJsonContent {
     }
 }
 impl FileJsonContent {
-    pub fn unparsable(message: &'static str) -> Self {
+    pub fn unparsable(message: RcStr) -> Self {
         FileJsonContent::Unparsable(Box::new(UnparsableJson {
-            message: Cow::Borrowed(message),
+            message,
             path: None,
             start_location: None,
             end_location: None,
         }))
     }
 
-    pub fn unparsable_with_message(message: Cow<'static, str>) -> Self {
+    pub fn unparsable_with_message(message: RcStr) -> Self {
         FileJsonContent::Unparsable(Box::new(UnparsableJson {
             message,
             path: None,

filename: turbopack/crates/turbopack-core/src/asset.rs
patch: @@ -1,5 +1,5 @@
 use anyhow::Result;
-use turbo_rcstr::RcStr;
+use turbo_rcstr::{RcStr, rcstr};
 use turbo_tasks::{ResolvedVc, Vc};
 use turbo_tasks_fs::{
     FileContent, FileJsonContent, FileLinesContent, FileSystemPath, LinkContent, LinkType,
@@ -43,9 +43,10 @@ impl AssetContent {
         let this = self.await?;
         match &*this {
             AssetContent::File(content) => Ok(content.parse_json()),
-            AssetContent::Redirect { .. } => {
-                Ok(FileJsonContent::unparsable("a redirect can't be parsed as json").cell())
-            }
+            AssetContent::Redirect { .. } => Ok(FileJsonContent::unparsable(rcstr!(
+                "a redirect can't be parsed as json"
+            ))
+            .cell()),
         }
     }
 
@@ -81,9 +82,10 @@ impl AssetContent {
         let this = self.await?;
         match &*this {
             AssetContent::File(content) => Ok(content.parse_json_with_comments()),
-            AssetContent::Redirect { .. } => {
-                Ok(FileJsonContent::unparsable("a redirect can't be parsed as json").cell())
-            }
+            AssetContent::Redirect { .. } => Ok(FileJsonContent::unparsable(rcstr!(
+                "a redirect can't be parsed as json"
+            ))
+            .cell()),
         }
     }