Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[[case]]
name = "command_install_invalid_package_json"
vp = "global"
steps = [
{ argv = ["vpt", "write-file", ".node-version", "22.18.0"], snapshot = false },
{ argv = ["vpt", "write-file", "package.json", "not-json"], snapshot = false },
{ argv = ["vp", "install"], comment = "should name the package.json that failed to parse", continue-on-failure = true },
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# command_install_invalid_package_json

## `vpt write-file .node-version 22.18.0`


## `vpt write-file package.json not-json`


## `vp install`

should name the package.json that failed to parse

**Exit code:** 1

```
VITE+ - The Unified Toolchain for the Web

error: Failed to download Node.js runtime: Failed to parse <workspace>/package.json: expected ident at line 1 column 2
```
5 changes: 5 additions & 0 deletions crates/vp_js_runtime/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use thiserror::Error;
use vt_path::AbsolutePath;
use vt_str::Str;

/// Errors that can occur during JavaScript runtime management
Expand Down Expand Up @@ -40,6 +41,10 @@ pub enum Error {
#[error("Failed to parse version index: {reason}")]
VersionIndexParseFailed { reason: Str },

/// Failed to parse package.json
#[error("Failed to parse {path}: {reason}")]
PackageJsonParseFailed { path: Box<AbsolutePath>, reason: Str },

/// No version matching the requirement found
#[error("No version matching '{version_req}' found")]
NoMatchingVersion { version_req: Str },
Expand Down
70 changes: 69 additions & 1 deletion crates/vp_js_runtime/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,11 @@ pub async fn read_package_json(
}

let content = tokio::fs::read_to_string(package_json_path).await?;
let pkg: PackageJson = serde_json::from_str(&content)?;
let pkg: PackageJson =
serde_json::from_str(&content).map_err(|e| Error::PackageJsonParseFailed {
path: package_json_path.as_absolute_path().into(),
reason: vt_str::format!("{e}"),
})?;
Ok(Some(pkg))
}

Expand Down Expand Up @@ -992,6 +996,70 @@ mod tests {
.await;
}

#[tokio::test]
async fn test_read_package_json_invalid_json_names_file() {
let temp_dir = TempDir::new().unwrap();
let temp_path = AbsolutePathBuf::new(temp_dir.path().to_path_buf()).unwrap();

// Write invalid package.json file
let package_json_path = temp_path.join("package.json");
tokio::fs::write(&package_json_path, "not-json").await.unwrap();

let error = read_package_json(&package_json_path).await.unwrap_err();

// Should be the dedicated package.json error variant
assert!(
matches!(error, Error::PackageJsonParseFailed { .. }),
"unexpected error: {error:?}"
);

// Should name the file, line & column that failed to parse
assert_eq!(
error.to_string(),
format!(
"Failed to parse {}: expected ident at line 1 column 2",
package_json_path.as_absolute_path()
)
);
}

#[tokio::test]
async fn test_download_runtime_for_project_invalid_package_json() {
let vp_home = TempDir::new().unwrap();
vp_shared::EnvConfig::with_vars_async(
[(env_vars::VP_HOME, vp_home.path().as_os_str())],
|_| async {
let temp_dir = TempDir::new().unwrap();
let temp_path = AbsolutePathBuf::new(temp_dir.path().to_path_buf()).unwrap();

// Write invalid package.json file
tokio::fs::write(temp_path.join("package.json"), "not-json").await.unwrap();

// Write sibling .node-version to trigger proceeding to package.json re-read
tokio::fs::write(temp_path.join(".node-version"), "22.18.0\n").await.unwrap();

let error = download_runtime_for_project(&temp_path).await.unwrap_err();

// Should fail on the package.json re-read
assert!(
matches!(error, Error::PackageJsonParseFailed { .. }),
"unexpected error: {error:?}"
);

// Should name the file, line & column that failed to parse
let package_json_path = temp_path.join("package.json");
assert_eq!(
error.to_string(),
format!(
"Failed to parse {}: expected ident at line 1 column 2",
package_json_path.as_absolute_path()
)
);
},
)
.await;
}

#[tokio::test]
async fn test_download_runtime_for_project_inherits_parent_node_version() {
let vp_home = shared_vp_home();
Expand Down
Loading