synopkg 14.0.1

Consistent dependency versions in large JavaScript Monorepos
use {
  crate::{
    cli::Cli,
    rcfile::{
      error::RcfileError,
      javascript::{from_javascript_path, try_from_js_candidates},
      json::{from_json_path, try_from_json_candidates},
      package_json::try_from_package_json_config_property,
      yaml::{from_yaml_path, try_from_yaml_candidates},
      Rcfile,
    },
  },
  log::{debug, error},
  std::{path::PathBuf, process::exit, time::Instant},
};

impl Rcfile {
  pub fn from_disk(cli: &Cli) -> Rcfile {
    let start = Instant::now();
    let rcfile = Self::try_from_cli_option(cli)
      .or_else(|| try_from_json_candidates(cli))
      .or_else(|| try_from_yaml_candidates(cli))
      .or_else(|| try_from_package_json_config_property(cli))
      .or_else(|| try_from_js_candidates(cli))
      .map(|result| match result {
        Ok(rcfile) => rcfile,
        Err(err) => {
          error!("{err}");
          exit(1);
        }
      })
      .unwrap_or_else(|| {
        debug!("No config file found, using defaults");
        Rcfile::default()
      });
    debug!("Config discovery completed in {:?}", start.elapsed());
    rcfile.visit_unknown_rcfile_fields();
    rcfile
  }

  fn try_from_cli_option(cli: &Cli) -> Option<Result<Rcfile, RcfileError>> {
    cli.config_path.as_ref().map(|path| {
      let config_path = PathBuf::from(path);
      let absolute_path = if config_path.is_absolute() {
        config_path
      } else {
        cli.cwd.join(config_path)
      };

      debug!("Using config file from CLI option: {absolute_path:?}");

      if !absolute_path.exists() {
        return Err(RcfileError::FileReadFailed(std::io::Error::new(
          std::io::ErrorKind::NotFound,
          format!("Config file not found: {}", absolute_path.display()),
        )));
      }

      let extension = absolute_path.extension().and_then(|ext| ext.to_str());
      match extension {
        Some("json") => from_json_path(&absolute_path),
        Some("yaml") | Some("yml") => from_yaml_path(&absolute_path),
        Some("js") | Some("cjs") | Some("mjs") | Some("ts") | Some("cts") | Some("mts") => from_javascript_path(&absolute_path),
        _ => from_json_path(&absolute_path),
      }
    })
  }
}