Skip to content

Commit 7fa8d23

Browse files
committed
Fix rewatch panic when package.json has no "name" field (#8291)
* Fix rewatch panic when package.json has no "name" field * CHANGELOG
1 parent f138d0c commit 7fa8d23

2 files changed

Lines changed: 63 additions & 31 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#### :bug: Bug fix
2525

2626
- Fix `null` and array values incorrectly matching the `Object` branch when pattern matching on `JSON.t` (or other untagged variants with an `Object` case) in statement position. https://github.com/rescript-lang/rescript/pull/8279
27+
- Fix rewatch panic when `package.json` has no `name` field. https://github.com/rescript-lang/rescript/pull/8291
2728

2829
#### :memo: Documentation
2930

rewatch/src/build/packages.rs

Lines changed: 62 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -425,35 +425,40 @@ fn flatten_dependencies(dependencies: Vec<Dependency>) -> Vec<Dependency> {
425425
}
426426

427427
pub fn read_package_name(package_dir: &Path) -> Result<String> {
428-
let mut file_name = "package.json";
429-
let package_json_path = package_dir.join(file_name);
430-
431-
let package_json_contents = if Path::exists(&package_json_path) {
432-
fs::read_to_string(&package_json_path).map_err(|e| anyhow!("Could not read package.json: {}", e))?
433-
} else {
434-
let rescript_json_path = package_dir.join("rescript.json");
435-
if Path::exists(&rescript_json_path) {
436-
file_name = "rescript.json";
437-
fs::read_to_string(&rescript_json_path)
438-
.map_err(|e| anyhow!("Could not read rescript.json: {}", e))?
439-
} else {
440-
return Err(anyhow!(
441-
"There is no package.json or rescript.json file in {}",
442-
package_dir.to_string_lossy()
443-
));
428+
let read_name = |file_name: &str| -> Result<Option<String>> {
429+
let path = package_dir.join(file_name);
430+
if !Path::exists(&path) {
431+
return Ok(None);
444432
}
433+
434+
let contents =
435+
fs::read_to_string(&path).map_err(|e| anyhow!("Could not read {}: {}", file_name, e))?;
436+
let json: serde_json::Value =
437+
serde_json::from_str(&contents).map_err(|e| anyhow!("Could not parse {}: {}", file_name, e))?;
438+
439+
Ok(json["name"].as_str().map(|name| name.to_string()))
445440
};
446441

447-
let package_json: serde_json::Value = serde_json::from_str(&package_json_contents)
448-
.map_err(|e| anyhow!("Could not parse {}: {}", file_name, e))?;
442+
if let Some(name) = read_name("package.json")? {
443+
return Ok(name);
444+
}
449445

450-
package_json["name"]
451-
.as_str()
452-
.map(|s| s.to_string())
453-
.ok_or_else(|| anyhow!("No name field found in package.json"))
446+
if let Some(name) = read_name("rescript.json")? {
447+
return Ok(name);
448+
}
449+
450+
Err(anyhow!(
451+
"No name field found in package.json or rescript.json in {}",
452+
package_dir.to_string_lossy()
453+
))
454454
}
455455

456-
fn make_package(config: config::Config, package_path: &Path, is_root: bool, is_local_dep: bool) -> Package {
456+
fn make_package(
457+
config: config::Config,
458+
package_path: &Path,
459+
is_root: bool,
460+
is_local_dep: bool,
461+
) -> Result<Package> {
457462
let source_folders = match config.sources.to_owned() {
458463
Some(config::OneOrMore::Single(source)) => get_source_dirs(source, None),
459464
Some(config::OneOrMore::Multiple(sources)) => {
@@ -480,7 +485,7 @@ fn make_package(config: config::Config, package_path: &Path, is_root: bool, is_l
480485
}
481486
};
482487

483-
let package_name = read_package_name(package_path).expect("Could not read package name");
488+
let package_name = read_package_name(package_path)?;
484489
if package_name != config.name {
485490
log::warn!(
486491
"\nPackage name mismatch for {}:\n\
@@ -492,7 +497,7 @@ This inconsistency will cause issues with package resolution.\n",
492497
);
493498
}
494499

495-
Package {
500+
Ok(Package {
496501
name: package_name,
497502
config: config.to_owned(),
498503
source_folders,
@@ -507,7 +512,7 @@ This inconsistency will cause issues with package resolution.\n",
507512
dirs: None,
508513
is_local_dep,
509514
is_root,
510-
}
515+
})
511516
}
512517

513518
fn read_packages(project_context: &ProjectContext, show_progress: bool) -> Result<AHashMap<String, Package>> {
@@ -520,7 +525,7 @@ fn read_packages(project_context: &ProjectContext, show_progress: bool) -> Resul
520525
.path
521526
.parent()
522527
.ok_or_else(|| anyhow!("Could not the read parent folder or a rescript.json file"))?;
523-
make_package(config.to_owned(), folder, true, true)
528+
make_package(config.to_owned(), folder, true, true)?
524529
};
525530

526531
map.insert(current_package.name.to_string(), current_package);
@@ -534,12 +539,12 @@ fn read_packages(project_context: &ProjectContext, show_progress: bool) -> Resul
534539
/* is local dep */ true,
535540
));
536541

537-
dependencies.iter().for_each(|d| {
542+
for d in dependencies.iter() {
538543
if !map.contains_key(&d.name) {
539-
let package = make_package(d.config.to_owned(), &d.path, false, d.is_local_dep);
544+
let package = make_package(d.config.to_owned(), &d.path, false, d.is_local_dep)?;
540545
map.insert(d.name.to_string(), package);
541546
}
542-
});
547+
}
543548

544549
Ok(map)
545550
}
@@ -1031,9 +1036,11 @@ pub fn validate_packages_dependencies(packages: &AHashMap<String, Package>) -> b
10311036
mod test {
10321037
use crate::config;
10331038

1034-
use super::{Namespace, Package};
1039+
use super::{Namespace, Package, read_package_name};
10351040
use ahash::{AHashMap, AHashSet};
1041+
use std::fs;
10361042
use std::path::PathBuf;
1043+
use tempfile::TempDir;
10371044

10381045
pub struct CreatePackageArgs {
10391046
name: String,
@@ -1139,4 +1146,28 @@ mod test {
11391146
let is_valid = super::validate_packages_dependencies(&packages);
11401147
assert!(is_valid)
11411148
}
1149+
1150+
#[test]
1151+
fn should_report_missing_name_when_package_and_rescript_json_lack_it() {
1152+
let temp_dir = TempDir::new().expect("temp dir should be created");
1153+
let package_dir = temp_dir.path();
1154+
1155+
fs::write(package_dir.join("package.json"), "{\n \"private\": true\n}\n")
1156+
.expect("package.json should be written");
1157+
fs::write(
1158+
package_dir.join("rescript.json"),
1159+
"{\n \"suffix\": \".mjs\"\n}\n",
1160+
)
1161+
.expect("rescript.json should be written");
1162+
1163+
let error = read_package_name(package_dir).expect_err("missing names should fail");
1164+
1165+
assert_eq!(
1166+
error.to_string(),
1167+
format!(
1168+
"No name field found in package.json or rescript.json in {}",
1169+
package_dir.to_string_lossy()
1170+
)
1171+
);
1172+
}
11421173
}

0 commit comments

Comments
 (0)