diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c5de2554d..cbfba5ccbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ #### :bug: Bug fix +- Rewatch: warnings for unsupported/unknown rescript.json fields. https://github.com/rescript-lang/rescript/pull/8031 + #### :memo: Documentation #### :nail_care: Polish diff --git a/rewatch/Cargo.lock b/rewatch/Cargo.lock index 5a3e8170c3..118a20d971 100644 --- a/rewatch/Cargo.lock +++ b/rewatch/Cargo.lock @@ -788,6 +788,7 @@ dependencies = [ "rayon", "regex", "serde", + "serde_ignored", "serde_json", "sysinfo", "tempfile", @@ -823,24 +824,44 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "serde_ignored" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115dffd5f3853e06e746965a20dcbae6ee747ae30b543d91b0e089668bb07798" +dependencies = [ + "serde", + "serde_core", +] + [[package]] name = "serde_json" version = "1.0.140" diff --git a/rewatch/Cargo.toml b/rewatch/Cargo.toml index 330f948f90..7006b5ab1e 100644 --- a/rewatch/Cargo.toml +++ b/rewatch/Cargo.toml @@ -24,6 +24,7 @@ num_cpus = "1.17.0" regex = "1.7.1" serde = { version = "1.0.152", features = ["derive"] } serde_json = { version = "1.0.93" } +serde_ignored = "0.1.11" sysinfo = "0.29.10" tempfile = "3.10.1" diff --git a/rewatch/src/build.rs b/rewatch/src/build.rs index f141280832..7736f6523e 100644 --- a/rewatch/src/build.rs +++ b/rewatch/src/build.rs @@ -370,7 +370,7 @@ pub fn incremental_build( println!("{}", &compile_warnings); } if initial_build { - log_deprecations(build_state); + log_config_warnings(build_state); } if helpers::contains_ascii_characters(&compile_errors) { println!("{}", &compile_errors); @@ -399,7 +399,7 @@ pub fn incremental_build( println!("{}", &compile_warnings); } if initial_build { - log_deprecations(build_state); + log_config_warnings(build_state); } // Write per-package compiler metadata to `lib/bs/compiler-info.json` (idempotent) @@ -409,7 +409,7 @@ pub fn incremental_build( } } -fn log_deprecations(build_state: &BuildCommandState) { +fn log_config_warnings(build_state: &BuildCommandState) { build_state.packages.iter().for_each(|(_, package)| { // Only warn for local dependencies, not external packages if package.is_local_dep { @@ -426,6 +426,18 @@ fn log_deprecations(build_state: &BuildCommandState) { } }, ); + + package + .config + .get_unsupported_fields() + .iter() + .for_each(|field| log_unsupported_config_field(&package.name, field)); + + package + .config + .get_unknown_fields() + .iter() + .for_each(|field| log_unknown_config_field(&package.name, field)); } }); } @@ -438,6 +450,20 @@ fn log_deprecated_config_field(package_name: &str, field_name: &str, new_field_n println!("\n{}", style(warning).yellow()); } +fn log_unsupported_config_field(package_name: &str, field_name: &str) { + let warning = format!( + "The field '{field_name}' found in the package config of '{package_name}' is not supported by ReScript 12's new build system." + ); + println!("\n{}", style(warning).yellow()); +} + +fn log_unknown_config_field(package_name: &str, field_name: &str) { + let warning = format!( + "Unknown field '{field_name}' found in the package config of '{package_name}'. This option will be ignored." + ); + println!("\n{}", style(warning).yellow()); +} + // write build.ninja files in the packages after a non-incremental build // this is necessary to bust the editor tooling cache. The editor tooling // is watching this file. diff --git a/rewatch/src/config.rs b/rewatch/src/config.rs index 6e12a9f209..6bb5104461 100644 --- a/rewatch/src/config.rs +++ b/rewatch/src/config.rs @@ -308,6 +308,10 @@ pub struct Config { #[serde(skip)] deprecation_warnings: Vec, + // Holds unknown fields we encountered while parsing + #[serde(skip, default)] + unknown_fields: Vec, + #[serde(default = "default_path")] pub path: PathBuf, } @@ -435,9 +439,14 @@ impl Config { /// Try to convert a bsconfig from a string to a bsconfig struct pub fn new_from_json_string(config_str: &str) -> Result { - let mut config = serde_json::from_str::(config_str)?; + let mut deserializer = serde_json::Deserializer::from_str(config_str); + let mut unknown_fields = Vec::new(); + let mut config: Config = serde_ignored::deserialize(&mut deserializer, |path| { + unknown_fields.push(path.to_string()); + })?; config.handle_deprecations()?; + config.unknown_fields = unknown_fields; Ok(config) } @@ -662,6 +671,49 @@ impl Config { &self.deprecation_warnings } + pub fn get_unknown_fields(&self) -> Vec { + self.unknown_fields + .iter() + .filter(|field| !self.is_unsupported_field(field)) + .cloned() + .collect() + } + + pub fn get_unsupported_fields(&self) -> Vec { + let mut fields = self + .unknown_fields + .iter() + .filter(|field| self.is_unsupported_field(field)) + .cloned() + .collect::>(); + + if self.gentype_config.is_some() { + fields.push("gentypeconfig".to_string()); + } + + fields + } + + fn is_unsupported_field(&self, field: &str) -> bool { + const UNSUPPORTED_TOP_LEVEL_FIELDS: &[&str] = &[ + "version", + "ignored-dirs", + "generators", + "cut-generators", + "pp-flags", + "js-post-build", + "entries", + "use-stdlib", + "external-stdlib", + "bs-external-includes", + "reanalyze", + ]; + + let top_level = field.split(|c| ['.', '['].contains(&c)).next().unwrap_or(field); + + UNSUPPORTED_TOP_LEVEL_FIELDS.contains(&top_level) + } + fn handle_deprecations(&mut self) -> Result<()> { if self.dependencies.is_some() && self.bs_dependencies.is_some() { bail!("dependencies and bs-dependencies are mutually exclusive. Please use 'dependencies'."); @@ -729,6 +781,7 @@ pub mod tests { deprecation_warnings: vec![], experimental_features: None, allowed_dependents: args.allowed_dependents, + unknown_fields: vec![], path: args.path, } } @@ -1023,6 +1076,42 @@ pub mod tests { assert!(config.get_deprecations().is_empty()); } + #[test] + fn test_unknown_fields_are_collected() { + let json = r#" + { + "name": "testrepo", + "sources": { + "dir": "src", + "subdirs": true + }, + "some-new-field": true + } + "#; + + let config = Config::new_from_json_string(json).expect("a valid json string"); + assert_eq!(config.get_unknown_fields(), vec!["some-new-field".to_string()]); + assert!(config.get_unsupported_fields().is_empty()); + } + + #[test] + fn test_unsupported_fields_are_collected() { + let json = r#" + { + "name": "testrepo", + "sources": { + "dir": "src", + "subdirs": true + }, + "ignored-dirs": ["scripts"] + } + "#; + + let config = Config::new_from_json_string(json).expect("a valid json string"); + assert_eq!(config.get_unsupported_fields(), vec!["ignored-dirs".to_string()]); + assert!(config.get_unknown_fields().is_empty()); + } + #[test] fn test_compiler_flags() { let json = r#" diff --git a/rewatch/testrepo/packages/deprecated-config/rescript.json b/rewatch/testrepo/packages/deprecated-config/rescript.json index 4fbfa98214..8a1d772c6c 100644 --- a/rewatch/testrepo/packages/deprecated-config/rescript.json +++ b/rewatch/testrepo/packages/deprecated-config/rescript.json @@ -10,6 +10,8 @@ "in-source": true }, "suffix": ".mjs", + "ignored-dirs": ["scripts"], + "some-new-field": true, "bs-dependencies": [], "bs-dev-dependencies": [], "bsc-flags": [] diff --git a/rewatch/tests/snapshots/bs-dev-dependency-used-by-non-dev-source.txt b/rewatch/tests/snapshots/bs-dev-dependency-used-by-non-dev-source.txt index 393f245c5b..d0e96bce1a 100644 --- a/rewatch/tests/snapshots/bs-dev-dependency-used-by-non-dev-source.txt +++ b/rewatch/tests/snapshots/bs-dev-dependency-used-by-non-dev-source.txt @@ -11,6 +11,10 @@ Use 'dev-dependencies' instead. The field 'bsc-flags' found in the package config of '@testrepo/deprecated-config' is deprecated and will be removed in a future version. Use 'compiler-flags' instead. +The field 'ignored-dirs' found in the package config of '@testrepo/deprecated-config' is not supported by ReScript 12's new build system. + +Unknown field 'some-new-field' found in the package config of '@testrepo/deprecated-config'. This option will be ignored. + We've found a bug for you! /packages/with-dev-deps/src/FileToTest.res:2:6-11 diff --git a/rewatch/tests/snapshots/clean-rebuild.txt b/rewatch/tests/snapshots/clean-rebuild.txt index 9fa176a312..eb27a15123 100644 --- a/rewatch/tests/snapshots/clean-rebuild.txt +++ b/rewatch/tests/snapshots/clean-rebuild.txt @@ -10,3 +10,7 @@ Use 'dev-dependencies' instead. The field 'bsc-flags' found in the package config of '@testrepo/deprecated-config' is deprecated and will be removed in a future version. Use 'compiler-flags' instead. + +The field 'ignored-dirs' found in the package config of '@testrepo/deprecated-config' is not supported by ReScript's new build system (rewatch). + +Unknown field 'some-new-field' found in the package config of '@testrepo/deprecated-config'. This option will be ignored. diff --git a/rewatch/tests/snapshots/dependency-cycle.txt b/rewatch/tests/snapshots/dependency-cycle.txt index b5bf195403..15df26e85c 100644 --- a/rewatch/tests/snapshots/dependency-cycle.txt +++ b/rewatch/tests/snapshots/dependency-cycle.txt @@ -11,6 +11,10 @@ Use 'dev-dependencies' instead. The field 'bsc-flags' found in the package config of '@testrepo/deprecated-config' is deprecated and will be removed in a future version. Use 'compiler-flags' instead. +The field 'ignored-dirs' found in the package config of '@testrepo/deprecated-config' is not supported by ReScript 12's new build system. + +Unknown field 'some-new-field' found in the package config of '@testrepo/deprecated-config'. This option will be ignored. + Can't continue... Found a circular dependency in your code: Dep01 (packages/dep01/src/Dep01.res) → Dep02 (packages/dep02/src/Dep02.res) diff --git a/rewatch/tests/snapshots/remove-file.txt b/rewatch/tests/snapshots/remove-file.txt index 9c9337be41..a0a9edd519 100644 --- a/rewatch/tests/snapshots/remove-file.txt +++ b/rewatch/tests/snapshots/remove-file.txt @@ -11,6 +11,10 @@ Use 'dev-dependencies' instead. The field 'bsc-flags' found in the package config of '@testrepo/deprecated-config' is deprecated and will be removed in a future version. Use 'compiler-flags' instead. +The field 'ignored-dirs' found in the package config of '@testrepo/deprecated-config' is not supported by ReScript 12's new build system. + +Unknown field 'some-new-field' found in the package config of '@testrepo/deprecated-config'. This option will be ignored. + We've found a bug for you! /packages/dep01/src/Dep01.res:3:9-17 diff --git a/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt b/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt index 26d085b182..2f0cc34a28 100644 --- a/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt +++ b/rewatch/tests/snapshots/rename-file-internal-dep-namespace.txt @@ -11,6 +11,10 @@ Use 'dev-dependencies' instead. The field 'bsc-flags' found in the package config of '@testrepo/deprecated-config' is deprecated and will be removed in a future version. Use 'compiler-flags' instead. +The field 'ignored-dirs' found in the package config of '@testrepo/deprecated-config' is not supported by ReScript 12's new build system. + +Unknown field 'some-new-field' found in the package config of '@testrepo/deprecated-config'. This option will be ignored. + We've found a bug for you! /packages/new-namespace/src/NS_alias.res:2:1-16 diff --git a/rewatch/tests/snapshots/rename-file-internal-dep.txt b/rewatch/tests/snapshots/rename-file-internal-dep.txt index fbb8c93803..3a8c6e1f4c 100644 --- a/rewatch/tests/snapshots/rename-file-internal-dep.txt +++ b/rewatch/tests/snapshots/rename-file-internal-dep.txt @@ -11,6 +11,10 @@ Use 'dev-dependencies' instead. The field 'bsc-flags' found in the package config of '@testrepo/deprecated-config' is deprecated and will be removed in a future version. Use 'compiler-flags' instead. +The field 'ignored-dirs' found in the package config of '@testrepo/deprecated-config' is not supported by ReScript 12's new build system. + +Unknown field 'some-new-field' found in the package config of '@testrepo/deprecated-config'. This option will be ignored. + We've found a bug for you! /packages/main/src/Main.res:4:13-29 diff --git a/rewatch/tests/snapshots/rename-file-with-interface.txt b/rewatch/tests/snapshots/rename-file-with-interface.txt index 942e802943..b0642c89af 100644 --- a/rewatch/tests/snapshots/rename-file-with-interface.txt +++ b/rewatch/tests/snapshots/rename-file-with-interface.txt @@ -11,3 +11,7 @@ Use 'dev-dependencies' instead. The field 'bsc-flags' found in the package config of '@testrepo/deprecated-config' is deprecated and will be removed in a future version. Use 'compiler-flags' instead. + +The field 'ignored-dirs' found in the package config of '@testrepo/deprecated-config' is not supported by ReScript 12's new build system. + +Unknown field 'some-new-field' found in the package config of '@testrepo/deprecated-config'. This option will be ignored. diff --git a/rewatch/tests/snapshots/rename-file.txt b/rewatch/tests/snapshots/rename-file.txt index b316e37ff4..78d52b3b0f 100644 --- a/rewatch/tests/snapshots/rename-file.txt +++ b/rewatch/tests/snapshots/rename-file.txt @@ -10,3 +10,7 @@ Use 'dev-dependencies' instead. The field 'bsc-flags' found in the package config of '@testrepo/deprecated-config' is deprecated and will be removed in a future version. Use 'compiler-flags' instead. + +The field 'ignored-dirs' found in the package config of '@testrepo/deprecated-config' is not supported by ReScript 12's new build system. + +Unknown field 'some-new-field' found in the package config of '@testrepo/deprecated-config'. This option will be ignored. diff --git a/rewatch/tests/snapshots/rename-interface-file.txt b/rewatch/tests/snapshots/rename-interface-file.txt index d5e13249dd..d08776798f 100644 --- a/rewatch/tests/snapshots/rename-interface-file.txt +++ b/rewatch/tests/snapshots/rename-interface-file.txt @@ -11,3 +11,7 @@ Use 'dev-dependencies' instead. The field 'bsc-flags' found in the package config of '@testrepo/deprecated-config' is deprecated and will be removed in a future version. Use 'compiler-flags' instead. + +The field 'ignored-dirs' found in the package config of '@testrepo/deprecated-config' is not supported by ReScript 12's new build system. + +Unknown field 'some-new-field' found in the package config of '@testrepo/deprecated-config'. This option will be ignored.