Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

Commit

Permalink
feat(rome_service): add extends functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
ematipico committed Jun 17, 2023
1 parent 36311b0 commit 1f7ec40
Show file tree
Hide file tree
Showing 51 changed files with 1,062 additions and 109 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ inherits = "release"
debug = true

[workspace.dependencies]
indexmap = "1.9.1"
indexmap = "1.9.3"
tracing = { version = "0.1.31", default-features = false, features = ["std"] }
dashmap = "5.4.0"
rustc-hash = "1.1.0"
Expand Down
19 changes: 11 additions & 8 deletions crates/rome_cli/src/commands/check.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::cli_options::CliOptions;
use crate::configuration::load_configuration;
use crate::configuration::{load_configuration, LoadedConfiguration};
use crate::vcs::store_path_to_ignore_from_vcs;
use crate::{execute_mode, CliDiagnostic, CliSession, Execution, TraversalMode};
use rome_console::{markup, ConsoleExt};
use rome_diagnostics::{DiagnosticExt, PrintDiagnostic, Severity};
use rome_diagnostics::{PrintDiagnostic, Severity};
use rome_service::configuration::organize_imports::OrganizeImports;
use rome_service::configuration::{FormatterConfiguration, LinterConfiguration};
use rome_service::workspace::{FixFileMode, UpdateSettingsParams};
Expand Down Expand Up @@ -53,17 +53,20 @@ pub(crate) fn check(
Some(FixFileMode::SafeAndUnsafeFixes)
};

let (mut fs_configuration, diagnostics, configuration_path) =
load_configuration(&mut session, &cli_options)?.consume();
let LoadedConfiguration {
configuration: mut fs_configuration,
diagnostics,
directory_path: configuration_path,
..
} = load_configuration(&mut session, &cli_options)?;
if !diagnostics.is_empty() {
let console = &mut session.app.console;
console.log(markup!{
<Warn>"Found errors in the configuration file, Rome will use its defaults for the sections that are incorrect."</Warn>
<Error>"Found errors in the configuration file, Rome will use its defaults for the sections that are incorrect."</Error>
});
for diagnostic in diagnostics {
let diagnostic = diagnostic.with_severity(Severity::Warning);
console.log(markup! {
{PrintDiagnostic::verbose(&diagnostic)}
console.error(markup! {
{if cli_options.verbose { PrintDiagnostic::verbose(&diagnostic) } else { PrintDiagnostic::simple(&diagnostic) }}
})
}
}
Expand Down
11 changes: 8 additions & 3 deletions crates/rome_cli/src/commands/ci.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::cli_options::CliOptions;
use crate::configuration::LoadedConfiguration;
use crate::vcs::store_path_to_ignore_from_vcs;
use crate::{
configuration::load_configuration, execute_mode, CliDiagnostic, CliSession, Execution,
Expand All @@ -23,14 +24,18 @@ pub(crate) struct CiCommandPayload {

/// Handler for the "ci" command of the Rome CLI
pub(crate) fn ci(mut session: CliSession, payload: CiCommandPayload) -> Result<(), CliDiagnostic> {
let (mut configuration, diagnostics, configuration_path) =
load_configuration(&mut session, &payload.cli_options)?.consume();
let LoadedConfiguration {
mut configuration,
diagnostics,
directory_path: configuration_path,
..
} = load_configuration(&mut session, &payload.cli_options)?;

if !diagnostics.is_empty() {
let console = &mut session.app.console;
for diagnostic in diagnostics {
console.error(markup! {
{PrintDiagnostic::verbose(&diagnostic)}
{if payload.cli_options.verbose { PrintDiagnostic::verbose(&diagnostic) } else { PrintDiagnostic::simple(&diagnostic) }}
})
}
return Err(CliDiagnostic::incompatible_end_configuration(
Expand Down
10 changes: 7 additions & 3 deletions crates/rome_cli/src/commands/format.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::cli_options::CliOptions;
use crate::configuration::load_configuration;
use crate::configuration::{load_configuration, LoadedConfiguration};
use crate::execute::ReportMode;
use crate::vcs::store_path_to_ignore_from_vcs;
use crate::{execute_mode, CliDiagnostic, CliSession, Execution, TraversalMode};
Expand Down Expand Up @@ -38,8 +38,12 @@ pub(crate) fn format(
files_configuration,
write,
} = payload;
let (mut configuration, diagnostics, configuration_path) =
load_configuration(&mut session, &cli_options)?.consume();
let LoadedConfiguration {
mut configuration,
diagnostics,
directory_path: configuration_path,
..
} = load_configuration(&mut session, &cli_options)?;
if !diagnostics.is_empty() {
let console = &mut session.app.console;
console.log(markup!{
Expand Down
9 changes: 7 additions & 2 deletions crates/rome_cli/src/commands/migrate.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::cli_options::CliOptions;
use crate::configuration::load_configuration;
use crate::configuration::{load_configuration, LoadedConfiguration};
use crate::diagnostics::MigrationDiagnostic;
use crate::execute::{execute_mode, Execution, TraversalMode};
use crate::{CliDiagnostic, CliSession};
Expand All @@ -10,7 +10,12 @@ pub(crate) fn migrate(
cli_options: CliOptions,
write: bool,
) -> Result<(), CliDiagnostic> {
let (_, _, path) = load_configuration(&mut session, &cli_options)?.consume();
let LoadedConfiguration {
configuration: _,
diagnostics: _,
directory_path: path,
..
} = load_configuration(&mut session, &cli_options)?;
let config_name = session.app.fs.config_name();
if let Some(path) = path {
execute_mode(
Expand Down
22 changes: 20 additions & 2 deletions crates/rome_cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,18 @@ pub enum RomeCommand {
#[bpaf(external, optional, hide_usage)]
files_configuration: Option<FilesConfiguration>,

/// A file name with its extension to pass when reading from standard in, e.g. echo 'let a;' | rome format --stdin-file-path=file.js"
/// A file name with its extension to pass when reading from standard in, e.g. echo 'let a;' | rome format --stdin-file-path=file.js".
#[bpaf(long("stdin-file-path"), argument("PATH"), hide_usage)]
stdin_file_path: Option<String>,

#[bpaf(external, hide_usage)]
cli_options: CliOptions,

/// Writes formatted files to file system.
#[bpaf(switch)]
write: bool,

/// Single file, single path or list of paths
/// Single file, single path or list of paths.
#[bpaf(positional("PATH"), many)]
paths: Vec<OsString>,
},
Expand Down Expand Up @@ -189,6 +190,23 @@ impl RomeCommand {
pub const fn has_metrics(&self) -> bool {
false
}

pub fn is_verbose(&self) -> bool {
match self {
RomeCommand::Version(_) => false,
RomeCommand::Rage(_) => false,
RomeCommand::Start => false,
RomeCommand::Stop => false,
RomeCommand::Check { cli_options, .. } => cli_options.verbose,
RomeCommand::Format { cli_options, .. } => cli_options.verbose,
RomeCommand::Ci { cli_options, .. } => cli_options.verbose,
RomeCommand::Init => false,
RomeCommand::LspProxy(cli_options) => cli_options.verbose,
RomeCommand::Migrate(cli_options, _) => cli_options.verbose,
RomeCommand::RunServer { .. } => false,
RomeCommand::PrintSocket => false,
}
}
}

pub fn parse_command() -> OptionParser<RomeCommand> {
Expand Down
5 changes: 2 additions & 3 deletions crates/rome_cli/src/commands/rage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,8 @@ impl Display for RageConfiguration<'_, '_> {

match load_config(self.0, ConfigurationBasePath::default()) {
Ok(None) => KeyValuePair("Status", markup!(<Dim>"unset"</Dim>)).fmt(fmt)?,
Ok(Some(deserialized)) => {
let (deserialized, _) = deserialized;
let (configuration, diagnostics) = deserialized.consume();
Ok(Some(result)) => {
let (configuration, diagnostics) = result.deserialized.consume();
let status = if !diagnostics.is_empty() {
for diagnostic in diagnostics {
(markup! {
Expand Down
102 changes: 86 additions & 16 deletions crates/rome_cli/src/configuration.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,97 @@
use std::path::PathBuf;

use crate::cli_options::CliOptions;
use crate::{CliDiagnostic, CliSession};
use rome_console::markup;
use rome_deserialize::json::deserialize_from_json_str;
use rome_deserialize::Deserialized;
use rome_service::{load_config, Configuration, ConfigurationBasePath};
use rome_diagnostics::Error;
use rome_fs::{FileSystem, OpenOptions};
use rome_service::configuration::diagnostics::CantLoadExtendFile;
use rome_service::configuration::ConfigurationPayload;
use rome_service::{
load_config, Configuration, ConfigurationBasePath, DynRef, MergeWith, WorkspaceError,
};
use std::path::PathBuf;

#[derive(Default)]
pub struct LoadedConfiguration {
deserialized: Deserialized<Configuration>,
path: Option<PathBuf>,
pub(crate) directory_path: Option<PathBuf>,
pub(crate) file_path: Option<PathBuf>,
pub(crate) configuration: Configuration,
pub(crate) diagnostics: Vec<Error>,
}

impl LoadedConfiguration {
pub fn consume(self) -> (Configuration, Vec<rome_diagnostics::Error>, Option<PathBuf>) {
let path = self.path;
let (configuration, diagnostics) = self.deserialized.consume();
(configuration, diagnostics, path)
/// It updates the loaded configuration by resolving the `extends` field.
///
/// If a configuration can't be resolved from the file system, the operation will fail.
pub fn apply_extends(&mut self, fs: &DynRef<dyn FileSystem>) -> Result<(), WorkspaceError> {
let deserialized = self.deserialize_extends(fs)?;
let (configurations, errors): (Vec<_>, Vec<_>) =
deserialized.into_iter().map(|d| d.consume()).unzip();
for c in configurations {
self.configuration.merge_with(c);
}
self.diagnostics
.extend(errors.into_iter().flatten().collect::<Vec<_>>());

Ok(())
}

fn deserialize_extends(
&mut self,
fs: &DynRef<dyn FileSystem>,
) -> Result<Vec<Deserialized<Configuration>>, WorkspaceError> {
let Some(extends) = &self.configuration.extends else {
return Ok(vec![]);
};

let directory_path = self
.directory_path
.as_ref()
.cloned()
.unwrap_or(fs.working_directory().unwrap_or(PathBuf::from("./")));
let mut deserialized_configurations = vec![];
for path in extends.index_set() {
let config_path = directory_path.join(path);
let mut file = fs
.open_with_options(config_path.as_path(), OpenOptions::default().read(true))
.map_err(|err| {
CantLoadExtendFile::new(config_path.display().to_string(), err.to_string()).with_verbose_advice(
markup!{
"Rome tried to load the configuration file "<Emphasis>{directory_path.display().to_string()}</Emphasis>" using "<Emphasis>{config_path.display().to_string()}</Emphasis>" as base path."
}
)
})?;
let mut content = String::new();
file.read_to_string(&mut content).map_err(|err| {
CantLoadExtendFile::new(config_path.display().to_string(), err.to_string()).with_verbose_advice(
markup!{
"It's possible that the file was created with a different user/group. Make sure you have the rights to read the file."
}
)

})?;
let deserialized = deserialize_from_json_str::<Configuration>(content.as_str());
deserialized_configurations.push(deserialized)
}
Ok(deserialized_configurations)
}
}

impl From<Option<(Deserialized<Configuration>, PathBuf)>> for LoadedConfiguration {
fn from(value: Option<(Deserialized<Configuration>, PathBuf)>) -> Self {
if let Some((deserialized, path)) = value {
LoadedConfiguration {
impl From<Option<ConfigurationPayload>> for LoadedConfiguration {
fn from(value: Option<ConfigurationPayload>) -> Self {
if let Some(value) = value {
let ConfigurationPayload {
configuration_directory_path,
configuration_file_path,
deserialized,
path: Some(path),
} = value;
let (configuration, diagnostics) = deserialized.consume();
LoadedConfiguration {
configuration,
diagnostics,
directory_path: Some(configuration_directory_path),
file_path: Some(configuration_file_path),
}
} else {
LoadedConfiguration::default()
Expand All @@ -43,7 +110,10 @@ pub(crate) fn load_configuration(
Some(path) => ConfigurationBasePath::FromUser(PathBuf::from(path)),
};

let config = load_config(&session.app.fs, base_path)?;
let fs = &session.app.fs;
let config = load_config(fs, base_path)?;
let mut loaded_configuration = LoadedConfiguration::from(config);

Ok(config.into())
loaded_configuration.apply_extends(fs)?;
Ok(loaded_configuration)
}
10 changes: 8 additions & 2 deletions crates/rome_cli/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,18 @@ pub struct CheckError {
action_kind: CheckActionKind,
}

#[derive(Debug, Clone, Copy)]
#[derive(Clone, Copy)]
pub enum CheckActionKind {
Check,
Apply,
}

impl Debug for CheckActionKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self, f)
}
}

impl Display for CheckActionKind {
fn fmt(&self, fmt: &mut Formatter) -> std::io::Result<()> {
match self {
Expand Down Expand Up @@ -688,7 +694,7 @@ mod test {
fn termination_diagnostic_size() {
assert_eq!(
std::mem::size_of::<CliDiagnostic>(),
88,
104,
"you successfully decreased the size of the diagnostic!"
)
}
Expand Down
13 changes: 12 additions & 1 deletion crates/rome_cli/src/execute/process_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,17 @@ pub(crate) fn process_file(ctx: &TraversalOptions, path: &Path) -> FileResult {
None
}
})
.and(
file_features
.support_kind_for(&FeatureName::Format)
.and_then(|support_kind| {
if support_kind.is_not_enabled() {
Some(support_kind)
} else {
None
}
}),
)
.and(
file_features
.support_kind_for(&FeatureName::OrganizeImports)
Expand Down Expand Up @@ -323,7 +334,7 @@ pub(crate) fn process_file(ctx: &TraversalOptions, path: &Path) -> FileResult {
if ctx.execution.as_fix_file_mode().is_some() {
true
} else {
return Ok(result);
false
}
}
TraversalMode::CI { .. } => false,
Expand Down
5 changes: 4 additions & 1 deletion crates/rome_cli/src/execute/traverse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,10 @@ impl<'ctx, 'app> TraversalContext for TraversalOptions<'ctx, 'app> {
};

match self.execution.traversal_mode() {
TraversalMode::Check { .. } => file_features.supports_for(&FeatureName::Lint),
TraversalMode::Check { .. } => {
file_features.supports_for(&FeatureName::Lint)
|| file_features.supports_for(&FeatureName::Format)
}
TraversalMode::CI { .. } => {
file_features.supports_for(&FeatureName::Lint)
|| file_features.supports_for(&FeatureName::Format)
Expand Down
7 changes: 5 additions & 2 deletions crates/rome_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ fn main() -> ExitCode {
Ok(command) => {
let color_mode = to_color_mode(command.get_color());
console.set_color(color_mode);
let is_verbose = command.is_verbose();
let result = run_workspace(&mut console, command);
match result {
Err(termination) => {
dbg!(&is_verbose);
console.error(markup! {
{PrintDiagnostic::verbose(&termination)}
});
{if is_verbose { PrintDiagnostic::verbose(&termination) } else { PrintDiagnostic::simple(&termination) }}
});

termination.report()
}
Ok(_) => ExitCode::SUCCESS,
Expand Down
Loading

0 comments on commit 1f7ec40

Please sign in to comment.