Skip to content

Commit 1b3f523

Browse files
authored
Rewatch: warnings for unsupported/unknown rescript.json fields (#8031)
* Rewatch: warnings for unsupported/unknown rescript.json fields * CHANGELOG * Format * rewatch tests * Fixed: gentypeconfig is a supported field
1 parent 3d9c244 commit 1b3f523

16 files changed

+179
-9
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
#### :bug: Bug fix
2222

23+
- Rewatch: warnings for unsupported/unknown rescript.json fields. https://github.com/rescript-lang/rescript/pull/8031
24+
2325
#### :memo: Documentation
2426

2527
#### :nail_care: Polish

rewatch/Cargo.lock

Lines changed: 25 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rewatch/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ num_cpus = "1.17.0"
2424
regex = "1.7.1"
2525
serde = { version = "1.0.152", features = ["derive"] }
2626
serde_json = { version = "1.0.93" }
27+
serde_ignored = "0.1.11"
2728
sysinfo = "0.29.10"
2829
tempfile = "3.10.1"
2930

rewatch/CompilerConfigurationSpec.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ This document contains a list of all bsconfig parameters with remarks, and wheth
1818
| generators | array of Rule-Generator | | [_] |
1919
| cut-generators | boolean | | [_] |
2020
| jsx | JSX | | [x] |
21-
| gentypeconfig | Gentype | | [_] |
21+
| gentypeconfig | Gentype | | [x] |
2222
| compiler-flags | array of string | | [x] |
2323
| warnings | Warnings | | [x] |
2424
| ppx-flags | array of string | | [x] |

rewatch/src/build.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ pub fn incremental_build(
370370
println!("{}", &compile_warnings);
371371
}
372372
if initial_build {
373-
log_deprecations(build_state);
373+
log_config_warnings(build_state);
374374
}
375375
if helpers::contains_ascii_characters(&compile_errors) {
376376
println!("{}", &compile_errors);
@@ -399,7 +399,7 @@ pub fn incremental_build(
399399
println!("{}", &compile_warnings);
400400
}
401401
if initial_build {
402-
log_deprecations(build_state);
402+
log_config_warnings(build_state);
403403
}
404404

405405
// Write per-package compiler metadata to `lib/bs/compiler-info.json` (idempotent)
@@ -409,7 +409,7 @@ pub fn incremental_build(
409409
}
410410
}
411411

412-
fn log_deprecations(build_state: &BuildCommandState) {
412+
fn log_config_warnings(build_state: &BuildCommandState) {
413413
build_state.packages.iter().for_each(|(_, package)| {
414414
// Only warn for local dependencies, not external packages
415415
if package.is_local_dep {
@@ -426,6 +426,18 @@ fn log_deprecations(build_state: &BuildCommandState) {
426426
}
427427
},
428428
);
429+
430+
package
431+
.config
432+
.get_unsupported_fields()
433+
.iter()
434+
.for_each(|field| log_unsupported_config_field(&package.name, field));
435+
436+
package
437+
.config
438+
.get_unknown_fields()
439+
.iter()
440+
.for_each(|field| log_unknown_config_field(&package.name, field));
429441
}
430442
});
431443
}
@@ -438,6 +450,20 @@ fn log_deprecated_config_field(package_name: &str, field_name: &str, new_field_n
438450
println!("\n{}", style(warning).yellow());
439451
}
440452

453+
fn log_unsupported_config_field(package_name: &str, field_name: &str) {
454+
let warning = format!(
455+
"The field '{field_name}' found in the package config of '{package_name}' is not supported by ReScript 12's new build system."
456+
);
457+
println!("\n{}", style(warning).yellow());
458+
}
459+
460+
fn log_unknown_config_field(package_name: &str, field_name: &str) {
461+
let warning = format!(
462+
"Unknown field '{field_name}' found in the package config of '{package_name}'. This option will be ignored."
463+
);
464+
println!("\n{}", style(warning).yellow());
465+
}
466+
441467
// write build.ninja files in the packages after a non-incremental build
442468
// this is necessary to bust the editor tooling cache. The editor tooling
443469
// is watching this file.

rewatch/src/config.rs

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@ pub struct Config {
308308
#[serde(skip)]
309309
deprecation_warnings: Vec<DeprecationWarning>,
310310

311+
// Holds unknown fields we encountered while parsing
312+
#[serde(skip, default)]
313+
unknown_fields: Vec<String>,
314+
311315
#[serde(default = "default_path")]
312316
pub path: PathBuf,
313317
}
@@ -435,9 +439,14 @@ impl Config {
435439

436440
/// Try to convert a bsconfig from a string to a bsconfig struct
437441
pub fn new_from_json_string(config_str: &str) -> Result<Self> {
438-
let mut config = serde_json::from_str::<Config>(config_str)?;
442+
let mut deserializer = serde_json::Deserializer::from_str(config_str);
443+
let mut unknown_fields = Vec::new();
444+
let mut config: Config = serde_ignored::deserialize(&mut deserializer, |path| {
445+
unknown_fields.push(path.to_string());
446+
})?;
439447

440448
config.handle_deprecations()?;
449+
config.unknown_fields = unknown_fields;
441450

442451
Ok(config)
443452
}
@@ -662,6 +671,42 @@ impl Config {
662671
&self.deprecation_warnings
663672
}
664673

674+
pub fn get_unknown_fields(&self) -> Vec<String> {
675+
self.unknown_fields
676+
.iter()
677+
.filter(|field| !self.is_unsupported_field(field))
678+
.cloned()
679+
.collect()
680+
}
681+
682+
pub fn get_unsupported_fields(&self) -> Vec<String> {
683+
self.unknown_fields
684+
.iter()
685+
.filter(|field| self.is_unsupported_field(field))
686+
.cloned()
687+
.collect::<Vec<_>>()
688+
}
689+
690+
fn is_unsupported_field(&self, field: &str) -> bool {
691+
const UNSUPPORTED_TOP_LEVEL_FIELDS: &[&str] = &[
692+
"version",
693+
"ignored-dirs",
694+
"generators",
695+
"cut-generators",
696+
"pp-flags",
697+
"js-post-build",
698+
"entries",
699+
"use-stdlib",
700+
"external-stdlib",
701+
"bs-external-includes",
702+
"reanalyze",
703+
];
704+
705+
let top_level = field.split(|c| ['.', '['].contains(&c)).next().unwrap_or(field);
706+
707+
UNSUPPORTED_TOP_LEVEL_FIELDS.contains(&top_level)
708+
}
709+
665710
fn handle_deprecations(&mut self) -> Result<()> {
666711
if self.dependencies.is_some() && self.bs_dependencies.is_some() {
667712
bail!("dependencies and bs-dependencies are mutually exclusive. Please use 'dependencies'.");
@@ -729,6 +774,7 @@ pub mod tests {
729774
deprecation_warnings: vec![],
730775
experimental_features: None,
731776
allowed_dependents: args.allowed_dependents,
777+
unknown_fields: vec![],
732778
path: args.path,
733779
}
734780
}
@@ -1023,6 +1069,42 @@ pub mod tests {
10231069
assert!(config.get_deprecations().is_empty());
10241070
}
10251071

1072+
#[test]
1073+
fn test_unknown_fields_are_collected() {
1074+
let json = r#"
1075+
{
1076+
"name": "testrepo",
1077+
"sources": {
1078+
"dir": "src",
1079+
"subdirs": true
1080+
},
1081+
"some-new-field": true
1082+
}
1083+
"#;
1084+
1085+
let config = Config::new_from_json_string(json).expect("a valid json string");
1086+
assert_eq!(config.get_unknown_fields(), vec!["some-new-field".to_string()]);
1087+
assert!(config.get_unsupported_fields().is_empty());
1088+
}
1089+
1090+
#[test]
1091+
fn test_unsupported_fields_are_collected() {
1092+
let json = r#"
1093+
{
1094+
"name": "testrepo",
1095+
"sources": {
1096+
"dir": "src",
1097+
"subdirs": true
1098+
},
1099+
"ignored-dirs": ["scripts"]
1100+
}
1101+
"#;
1102+
1103+
let config = Config::new_from_json_string(json).expect("a valid json string");
1104+
assert_eq!(config.get_unsupported_fields(), vec!["ignored-dirs".to_string()]);
1105+
assert!(config.get_unknown_fields().is_empty());
1106+
}
1107+
10261108
#[test]
10271109
fn test_compiler_flags() {
10281110
let json = r#"

rewatch/testrepo/packages/deprecated-config/rescript.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
"in-source": true
1111
},
1212
"suffix": ".mjs",
13+
"ignored-dirs": ["scripts"],
14+
"some-new-field": true,
1315
"bs-dependencies": [],
1416
"bs-dev-dependencies": [],
1517
"bsc-flags": []

rewatch/tests/snapshots/bs-dev-dependency-used-by-non-dev-source.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ Use 'dev-dependencies' instead.
1111
The field 'bsc-flags' found in the package config of '@testrepo/deprecated-config' is deprecated and will be removed in a future version.
1212
Use 'compiler-flags' instead.
1313

14+
The field 'ignored-dirs' found in the package config of '@testrepo/deprecated-config' is not supported by ReScript 12's new build system.
15+
16+
Unknown field 'some-new-field' found in the package config of '@testrepo/deprecated-config'. This option will be ignored.
17+
1418
We've found a bug for you!
1519
/packages/with-dev-deps/src/FileToTest.res:2:6-11
1620

rewatch/tests/snapshots/clean-rebuild.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ Use 'dev-dependencies' instead.
1010

1111
The field 'bsc-flags' found in the package config of '@testrepo/deprecated-config' is deprecated and will be removed in a future version.
1212
Use 'compiler-flags' instead.
13+
14+
The field 'ignored-dirs' found in the package config of '@testrepo/deprecated-config' is not supported by ReScript's new build system (rewatch).
15+
16+
Unknown field 'some-new-field' found in the package config of '@testrepo/deprecated-config'. This option will be ignored.

rewatch/tests/snapshots/dependency-cycle.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ Use 'dev-dependencies' instead.
1111
The field 'bsc-flags' found in the package config of '@testrepo/deprecated-config' is deprecated and will be removed in a future version.
1212
Use 'compiler-flags' instead.
1313

14+
The field 'ignored-dirs' found in the package config of '@testrepo/deprecated-config' is not supported by ReScript 12's new build system.
15+
16+
Unknown field 'some-new-field' found in the package config of '@testrepo/deprecated-config'. This option will be ignored.
17+
1418
Can't continue... Found a circular dependency in your code:
1519
Dep01 (packages/dep01/src/Dep01.res)
1620
→ Dep02 (packages/dep02/src/Dep02.res)

0 commit comments

Comments
 (0)