Skip to content

Commit d6054ef

Browse files
committed
feat: deprecation warnings for 'bs-' prefixes
1 parent f2c1201 commit d6054ef

File tree

8 files changed

+222
-85
lines changed

8 files changed

+222
-85
lines changed

rewatch/src/build/compile.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,15 +507,19 @@ fn get_dependency_paths(
507507
build_dev_deps: bool,
508508
) -> Vec<Vec<String>> {
509509
let normal_deps = config
510+
.dependency_info
510511
.dependencies
512+
.value
511513
.clone()
512514
.unwrap_or_default()
513515
.into_iter()
514516
.map(DependentPackage::Normal)
515517
.collect();
516518
let dev_deps = if build_dev_deps {
517519
config
520+
.dependency_info
518521
.dev_dependencies
522+
.value
519523
.clone()
520524
.unwrap_or_default()
521525
.into_iter()

rewatch/src/build/deps.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,22 @@ fn get_dep_modules(
3737
// Get the list of allowed dependency packages for this package
3838
let allowed_dependencies: AHashSet<String> = package
3939
.config
40+
.dependency_info
4041
.dependencies
42+
.value
4143
.as_ref()
4244
.unwrap_or(&vec![])
4345
.iter()
44-
.chain(package.config.dev_dependencies.as_ref().unwrap_or(&vec![]).iter())
46+
.chain(
47+
package
48+
.config
49+
.dependency_info
50+
.dev_dependencies
51+
.value
52+
.as_ref()
53+
.unwrap_or(&vec![])
54+
.iter(),
55+
)
4556
.cloned()
4657
.collect();
4758

rewatch/src/build/packages.rs

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use super::packages;
44
use crate::config;
55
use crate::helpers;
66
use crate::helpers::StrippedVerbatimPath;
7+
use crate::helpers::deprecation_registry;
78
use crate::helpers::emojis::*;
89
use ahash::{AHashMap, AHashSet};
910
use anyhow::{Result, anyhow};
@@ -231,11 +232,24 @@ pub fn read_config(package_dir: &Path) -> Result<config::Config> {
231232
let rescript_json_path = package_dir.join("rescript.json");
232233
let bsconfig_json_path = package_dir.join("bsconfig.json");
233234

234-
if Path::new(&rescript_json_path).exists() {
235-
config::read(&rescript_json_path)
235+
let (config, config_path) = if Path::new(&rescript_json_path).exists() {
236+
(config::Config::new(&rescript_json_path), rescript_json_path)
236237
} else {
237-
config::read(&bsconfig_json_path)
238-
}
238+
(config::Config::new(&bsconfig_json_path), bsconfig_json_path)
239+
};
240+
241+
config.inspect(|config| {
242+
if config.dependency_info.dependencies.deprecation_warning {
243+
deprecation_registry::log_deprecated_field("bs-dependencies", "dependencies", &config_path);
244+
}
245+
if config.dependency_info.dev_dependencies.deprecation_warning {
246+
deprecation_registry::log_deprecated_field(
247+
"bs-dev-dependencies",
248+
"devDependencies",
249+
&config_path,
250+
);
251+
}
252+
})
239253
}
240254

241255
pub fn read_dependency(
@@ -298,9 +312,8 @@ fn read_dependencies(
298312
workspace_root: &Option<PathBuf>,
299313
show_progress: bool,
300314
) -> Vec<Dependency> {
301-
return parent_config
302-
.dependencies
303-
.to_owned()
315+
return parent_config.dependency_info.dependencies
316+
.to_owned().value
304317
.unwrap_or_default()
305318
.iter()
306319
.filter_map(|package_name| {
@@ -888,9 +901,21 @@ pub fn validate_packages_dependencies(packages: &AHashMap<String, Package>) -> b
888901
let mut detected_unallowed_dependencies: AHashMap<String, UnallowedDependency> = AHashMap::new();
889902

890903
for (package_name, package) in packages {
891-
let bs_dependencies = &package.config.dependencies.to_owned().unwrap_or(vec![]);
904+
let bs_dependencies = &package
905+
.config
906+
.dependency_info
907+
.dependencies
908+
.to_owned()
909+
.value
910+
.unwrap_or(vec![]);
892911
let pinned_dependencies = &package.config.pinned_dependencies.to_owned().unwrap_or(vec![]);
893-
let dev_dependencies = &package.config.dev_dependencies.to_owned().unwrap_or(vec![]);
912+
let dev_dependencies = &package
913+
.config
914+
.dependency_info
915+
.dev_dependencies
916+
.to_owned()
917+
.value
918+
.unwrap_or(vec![]);
894919

895920
[
896921
("bs-dependencies", bs_dependencies),
@@ -957,7 +982,7 @@ pub fn validate_packages_dependencies(packages: &AHashMap<String, Package>) -> b
957982
#[cfg(test)]
958983
mod test {
959984
use super::{Namespace, Package};
960-
use crate::config::Source;
985+
use crate::config::{Dependencies, DependencyInfo, Source};
961986
use ahash::{AHashMap, AHashSet};
962987
use std::path::PathBuf;
963988

@@ -979,8 +1004,16 @@ mod test {
9791004
warnings: None,
9801005
suffix: None,
9811006
pinned_dependencies: Some(pinned_deps),
982-
dependencies: Some(bs_deps),
983-
dev_dependencies: Some(build_dev_deps),
1007+
dependency_info: DependencyInfo {
1008+
dependencies: Dependencies {
1009+
deprecation_warning: false,
1010+
value: Some(bs_deps),
1011+
},
1012+
dev_dependencies: Dependencies {
1013+
deprecation_warning: false,
1014+
value: Some(build_dev_deps),
1015+
},
1016+
},
9841017
ppx_flags: None,
9851018
bsc_flags: None,
9861019
namespace: None,

rewatch/src/config.rs

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,34 @@ pub struct JsxSpecs {
180180
/// We do not care about the internal structure because the gentype config is loaded by bsc.
181181
pub type GenTypeConfig = serde_json::Value;
182182

183+
/// Wrapper around dependencies to emit a warning when the bs- prefix is used
184+
#[derive(Deserialize, Debug, Clone)]
185+
pub struct Dependencies {
186+
pub deprecation_warning: bool,
187+
pub value: Option<Vec<String>>,
188+
}
189+
190+
impl Default for Dependencies {
191+
fn default() -> Self {
192+
Self {
193+
deprecation_warning: false,
194+
value: None,
195+
}
196+
}
197+
}
198+
199+
impl From<Dependencies> for Option<Vec<String>> {
200+
fn from(dependencies: Dependencies) -> Self {
201+
dependencies.value
202+
}
203+
}
204+
205+
#[derive(Deserialize, Debug, Clone)]
206+
pub struct DependencyInfo {
207+
pub dependencies: Dependencies,
208+
pub dev_dependencies: Dependencies,
209+
}
210+
183211
/// # bsconfig.json representation
184212
/// This is tricky, there is a lot of ambiguity. This is probably incomplete.
185213
#[derive(Deserialize, Debug, Clone)]
@@ -195,19 +223,8 @@ pub struct Config {
195223
#[serde(rename = "pinned-dependencies")]
196224
pub pinned_dependencies: Option<Vec<String>>,
197225

198-
#[serde(
199-
default,
200-
alias = "bs-dependencies",
201-
deserialize_with = "deserialize_dependencies"
202-
)]
203-
pub dependencies: Option<Vec<String>>,
204-
#[serde(
205-
default,
206-
rename = "dev-dependencies",
207-
alias = "bs-dev-dependencies",
208-
deserialize_with = "deserialize_dev_dependencies"
209-
)]
210-
pub dev_dependencies: Option<Vec<String>>,
226+
#[serde(flatten, deserialize_with = "deserialize_dependencies")]
227+
pub dependency_info: DependencyInfo,
211228

212229
#[serde(rename = "ppx-flags")]
213230
pub ppx_flags: Option<Vec<OneOrMore<String>>>,
@@ -243,8 +260,8 @@ pub fn flatten_flags(flags: &Option<Vec<OneOrMore<String>>>) -> Vec<String> {
243260
}
244261
}
245262

246-
/// Since ppx-flags could be one or more, and could be nested potentiall, this function takes the
247-
/// flags and flattens them outright.
263+
/// Since ppx-flags could be one or more, and could potentially be nested, this function takes the
264+
/// flags and flattens them.
248265
pub fn flatten_ppx_flags(
249266
node_modules_dir: &Path,
250267
flags: &Option<Vec<OneOrMore<String>>>,
@@ -299,14 +316,6 @@ pub fn flatten_ppx_flags(
299316
}
300317
}
301318

302-
/// Try to convert a bsconfig from a certain path to a bsconfig struct
303-
pub fn read(path: &Path) -> Result<Config> {
304-
let read = fs::read_to_string(path)?;
305-
let parse = serde_json::from_str::<Config>(&read)?;
306-
307-
Ok(parse)
308-
}
309-
310319
fn namespace_from_package_name(package_name: &str) -> String {
311320
let len = package_name.len();
312321
let mut buf = String::with_capacity(len);
@@ -337,6 +346,14 @@ fn namespace_from_package_name(package_name: &str) -> String {
337346
}
338347

339348
impl Config {
349+
/// Try to convert a bsconfig from a certain path to a bsconfig struct
350+
pub fn new(path: &Path) -> Result<Self> {
351+
let read = fs::read_to_string(path)?;
352+
let parse = serde_json::from_str::<Config>(&read)?;
353+
354+
Ok(parse)
355+
}
356+
340357
pub fn get_namespace(&self) -> packages::Namespace {
341358
let namespace_from_package = namespace_from_package_name(&self.name);
342359
match (self.namespace.as_ref(), self.namespace_entry.as_ref()) {
@@ -682,7 +699,7 @@ mod tests {
682699
}
683700

684701
#[test]
685-
fn test_dependencies() {
702+
fn test_dependencies_deprecation() {
686703
let json = r#"
687704
{
688705
"name": "testrepo",
@@ -702,11 +719,15 @@ mod tests {
702719
"#;
703720

704721
let config = serde_json::from_str::<Config>(json).unwrap();
705-
assert_eq!(config.dependencies, Some(vec!["@testrepo/main".to_string()]));
722+
assert_eq!(
723+
config.dependency_info.dependencies.value,
724+
Some(vec!["@testrepo/main".to_string()])
725+
);
726+
assert_eq!(config.dependency_info.dependencies.deprecation_warning, true)
706727
}
707728

708729
#[test]
709-
fn test_dependencies_alias() {
730+
fn test_dependencies() {
710731
let json = r#"
711732
{
712733
"name": "testrepo",
@@ -726,11 +747,15 @@ mod tests {
726747
"#;
727748

728749
let config = serde_json::from_str::<Config>(json).unwrap();
729-
assert_eq!(config.dependencies, Some(vec!["@testrepo/main".to_string()]));
750+
assert_eq!(
751+
config.dependency_info.dependencies.value,
752+
Some(vec!["@testrepo/main".to_string()])
753+
);
754+
assert_eq!(config.dependency_info.dependencies.deprecation_warning, false);
730755
}
731756

732757
#[test]
733-
fn test_dev_dependencies() {
758+
fn test_dev_dependencies_deprecation() {
734759
let json = r#"
735760
{
736761
"name": "testrepo",
@@ -750,11 +775,15 @@ mod tests {
750775
"#;
751776

752777
let config = serde_json::from_str::<Config>(json).unwrap();
753-
assert_eq!(config.dev_dependencies, Some(vec!["@testrepo/main".to_string()]));
778+
assert_eq!(
779+
config.dependency_info.dev_dependencies.value,
780+
Some(vec!["@testrepo/main".to_string()])
781+
);
782+
assert_eq!(config.dependency_info.dev_dependencies.deprecation_warning, true);
754783
}
755784

756785
#[test]
757-
fn test_dev_dependencies_alias() {
786+
fn test_dev_dependencies() {
758787
let json = r#"
759788
{
760789
"name": "testrepo",
@@ -774,6 +803,10 @@ mod tests {
774803
"#;
775804

776805
let config = serde_json::from_str::<Config>(json).unwrap();
777-
assert_eq!(config.dev_dependencies, Some(vec!["@testrepo/main".to_string()]));
806+
assert_eq!(
807+
config.dependency_info.dev_dependencies.value,
808+
Some(vec!["@testrepo/main".to_string()])
809+
);
810+
assert_eq!(config.dependency_info.dev_dependencies.deprecation_warning, false);
778811
}
779812
}

rewatch/src/helpers.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
99

1010
pub type StdErr = String;
1111

12+
pub mod deprecation_registry;
1213
pub mod deserialize;
1314

1415
pub mod emojis {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use std::{
2+
path::PathBuf,
3+
sync::{Mutex, OnceLock},
4+
};
5+
6+
use ahash::AHashSet;
7+
8+
use super::StrippedVerbatimPath;
9+
10+
type DeprecationKey = (String, PathBuf);
11+
12+
static DEPRECATION_REGISTRY: OnceLock<Mutex<AHashSet<DeprecationKey>>> = OnceLock::new();
13+
14+
fn get_registry() -> &'static Mutex<AHashSet<DeprecationKey>> {
15+
DEPRECATION_REGISTRY.get_or_init(|| Mutex::new(AHashSet::new()))
16+
}
17+
18+
pub fn log_deprecated_field(field_name: &str, replacement_field_name: &str, file_path: &PathBuf) {
19+
let mut registry = match get_registry().lock() {
20+
Ok(lock) => lock,
21+
Err(e) => {
22+
log::error!(
23+
"Thread panicked while holding deprecation registry. This should never happen. Please report this as a bug."
24+
);
25+
e.into_inner()
26+
}
27+
};
28+
29+
let abs_path = file_path
30+
.canonicalize()
31+
.map(StrippedVerbatimPath::to_stripped_verbatim_path)
32+
.unwrap_or_else(|_| file_path.to_path_buf())
33+
.to_path_buf();
34+
35+
let key = (field_name.to_string(), abs_path);
36+
37+
if registry.insert(key) {
38+
log::warn!(
39+
"Deprecated use of field '{field_name}' found in {}.\n\
40+
Use '{replacement_field_name}' instead. This field will be removed in a future version.",
41+
file_path.display()
42+
);
43+
}
44+
}

0 commit comments

Comments
 (0)