From 85b539db23e1c494627040b2019ed04c7741b93a Mon Sep 17 00:00:00 2001 From: ematipico Date: Tue, 17 Jan 2023 13:21:08 +0000 Subject: [PATCH 1/5] chore: finally ready --- Cargo.lock | 39 +- crates/rome_analyze/Cargo.toml | 3 +- crates/rome_analyze/src/diagnostics.rs | 8 + crates/rome_analyze/src/lib.rs | 3 +- crates/rome_analyze/src/options.rs | 75 +- crates/rome_analyze/src/registry.rs | 49 +- crates/rome_analyze/src/rule.rs | 23 +- crates/rome_analyze/src/signals.rs | 6 +- crates/rome_cli/Cargo.toml | 1 + crates/rome_cli/src/commands/rage.rs | 31 +- crates/rome_cli/src/configuration.rs | 18 +- ...ration_over_config_file_issue_3175_v2.snap | 14 + .../with_configuration.snap | 2 +- .../with_malformed_configuration.snap | 6 +- .../main_configuration/incorrect_globals.snap | 29 +- .../incorrect_rule_name.snap | 59 +- .../main_configuration/line_width_error.snap | 31 +- crates/rome_deserialize/Cargo.toml | 20 + crates/rome_deserialize/src/diagnostics.rs | 134 + crates/rome_deserialize/src/json.rs | 525 ++++ crates/rome_deserialize/src/lib.rs | 46 + crates/rome_deserialize/src/visitor.rs | 62 + crates/rome_js_analyze/Cargo.toml | 3 + crates/rome_js_analyze/src/lib.rs | 26 +- .../nursery/use_exhaustive_dependencies.rs | 133 +- .../nursery/use_hook_at_top_level.rs | 5 +- crates/rome_js_analyze/tests/spec_tests.rs | 28 +- .../malformedOptions.js.snap | 15 +- .../useHookAtTopLevel/customHook.options.json | 4 +- crates/rome_json_syntax/src/lib.rs | 1 + crates/rome_json_syntax/src/string_ext.rs | 22 + crates/rome_lsp/src/session.rs | 2 +- crates/rome_service/Cargo.toml | 1 + .../src/configuration/diagnostics.rs | 241 +- .../src/configuration/generated.rs | 115 + .../src/configuration/javascript.rs | 2 +- .../src/configuration/linter/mod.rs | 14 +- .../src/configuration/linter/rules.rs | 2312 ++++++++++++----- crates/rome_service/src/configuration/mod.rs | 70 +- .../src/configuration/parse/json.rs | 368 +-- .../configuration/parse/json/configuration.rs | 48 +- .../src/configuration/parse/json/formatter.rs | 70 +- .../configuration/parse/json/javascript.rs | 86 +- .../src/configuration/parse/json/linter.rs | 122 +- .../src/configuration/parse/json/rules.rs | 1000 +++++++ .../src/configuration/parse/mod.rs | 1 - .../snapshots/deserialization_error.snap | 9 +- .../snapshots/incorrect_pattern.snap | 2 +- .../rome_service/src/configuration/visitor.rs | 32 - .../src/file_handlers/javascript.rs | 10 +- crates/rome_service/src/lib.rs | 4 +- crates/rome_service/tests/spec_tests.rs | 42 +- xtask/codegen/src/generate_configuration.rs | 544 ++-- xtask/lintdoc/src/main.rs | 6 +- 54 files changed, 4737 insertions(+), 1785 deletions(-) create mode 100644 crates/rome_deserialize/Cargo.toml create mode 100644 crates/rome_deserialize/src/diagnostics.rs create mode 100644 crates/rome_deserialize/src/json.rs create mode 100644 crates/rome_deserialize/src/lib.rs create mode 100644 crates/rome_deserialize/src/visitor.rs create mode 100644 crates/rome_json_syntax/src/string_ext.rs create mode 100644 crates/rome_service/src/configuration/generated.rs create mode 100644 crates/rome_service/src/configuration/parse/json/rules.rs delete mode 100644 crates/rome_service/src/configuration/visitor.rs diff --git a/Cargo.lock b/Cargo.lock index 9d3425506a0..7522d9ce6ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1587,12 +1587,13 @@ version = "0.0.0" dependencies = [ "bitflags", "rome_console", + "rome_deserialize", "rome_diagnostics", + "rome_json_parser", "rome_rowan", "rustc-hash", "schemars", "serde", - "serde_json", "tracing", ] @@ -1627,6 +1628,7 @@ dependencies = [ "pico-args", "rayon", "rome_console", + "rome_deserialize", "rome_diagnostics", "rome_flags", "rome_formatter", @@ -1681,6 +1683,21 @@ dependencies = [ "rome_rowan", ] +[[package]] +name = "rome_deserialize" +version = "0.0.0" +dependencies = [ + "indexmap", + "rome_console", + "rome_diagnostics", + "rome_json_parser", + "rome_json_syntax", + "rome_rowan", + "serde", + "serde_json", + "tracing", +] + [[package]] name = "rome_diagnostics" version = "0.0.0" @@ -1792,11 +1809,14 @@ dependencies = [ "rome_aria", "rome_console", "rome_control_flow", + "rome_deserialize", "rome_diagnostics", "rome_js_factory", "rome_js_parser", "rome_js_semantic", "rome_js_syntax", + "rome_json_factory", + "rome_json_syntax", "rome_rowan", "rome_text_edit", "rustc-hash", @@ -2021,6 +2041,7 @@ dependencies = [ "insta", "rome_analyze", "rome_console", + "rome_deserialize", "rome_diagnostics", "rome_flags", "rome_formatter", @@ -2185,18 +2206,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.143" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553" +checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.143" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391" +checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e" dependencies = [ "proc-macro2", "quote", @@ -2216,9 +2237,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" dependencies = [ "itoa", "ryu", @@ -2344,9 +2365,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" -version = "1.0.99" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" dependencies = [ "proc-macro2", "quote", diff --git a/crates/rome_analyze/Cargo.toml b/crates/rome_analyze/Cargo.toml index ccec199501e..e7d73197600 100644 --- a/crates/rome_analyze/Cargo.toml +++ b/crates/rome_analyze/Cargo.toml @@ -12,10 +12,11 @@ license = "MIT" rome_rowan = { path = "../rome_rowan" } rome_console = { path = "../rome_console" } rome_diagnostics = { path = "../rome_diagnostics" } +rome_json_parser = { path = "../rome_json_parser" } +rome_deserialize = { path = "../rome_deserialize"} bitflags = "1.3.2" rustc-hash = { workspace = true } serde = { version = "1.0.136", features = ["derive"] } -serde_json = { version = "1.0.85", features = ["raw_value"]} schemars = { version = "0.8.10", optional = true } tracing = { workspace = true } diff --git a/crates/rome_analyze/src/diagnostics.rs b/crates/rome_analyze/src/diagnostics.rs index fbf787a8421..9b385476012 100644 --- a/crates/rome_analyze/src/diagnostics.rs +++ b/crates/rome_analyze/src/diagnostics.rs @@ -132,6 +132,14 @@ impl AnalyzerDiagnostic { self.code_suggestion_list.push(suggestion); self } + + pub const fn is_rule_diagnostic(&self) -> bool { + matches!(self.kind, DiagnosticKind::Rule(_)) + } + + pub const fn is_raw(&self) -> bool { + matches!(self.kind, DiagnosticKind::Raw(_)) + } } #[derive(Debug, Diagnostic)] diff --git a/crates/rome_analyze/src/lib.rs b/crates/rome_analyze/src/lib.rs index 5d456e21c3c..1e0b893908e 100644 --- a/crates/rome_analyze/src/lib.rs +++ b/crates/rome_analyze/src/lib.rs @@ -38,8 +38,7 @@ pub use crate::rule::{ RuleMeta, RuleMetadata, SuppressAction, }; pub use crate::services::{FromServices, MissingServicesDiagnostic, ServiceBag}; -use crate::signals::DiagnosticSignal; -pub use crate::signals::{AnalyzerAction, AnalyzerSignal}; +pub use crate::signals::{AnalyzerAction, AnalyzerSignal, DiagnosticSignal}; pub use crate::syntax::{Ast, SyntaxVisitor}; pub use crate::visitor::{NodeVisitor, Visitor, VisitorContext, VisitorFinishContext}; pub use rule::DeserializableRuleOptions; diff --git a/crates/rome_analyze/src/options.rs b/crates/rome_analyze/src/options.rs index ed10355d5e4..31035754ebb 100644 --- a/crates/rome_analyze/src/options.rs +++ b/crates/rome_analyze/src/options.rs @@ -1,25 +1,19 @@ -use crate::signals::AnalyzerActionIter; -use crate::AnalyzerSignal; -use crate::{RuleKey, TextRange, TextSize}; -use rome_diagnostics::{Diagnostic, LineIndexBuf, Resource, SourceCode}; -use rome_rowan::Language; +use crate::RuleKey; use serde::Deserialize; -use serde_json::Error; -use serde_json::Value; use std::collections::HashMap; /// A convenient new type data structure to store the options that belong to a rule #[derive(Debug, Clone, Deserialize)] -pub struct RuleOptions(Value); +pub struct RuleOptions(String); impl RuleOptions { /// It returns the deserialized rule option - pub fn value(&self) -> &Value { + pub fn value(&self) -> &String { &self.0 } /// Creates a new [RuleOptions] - pub fn new(options: Value) -> Self { + pub fn new(options: String) -> Self { Self(options) } } @@ -30,7 +24,7 @@ pub struct AnalyzerRules(HashMap); impl AnalyzerRules { /// It tracks the options of a specific rule - pub fn push_rule(&mut self, rule_key: RuleKey, options: Value) { + pub fn push_rule(&mut self, rule_key: RuleKey, options: String) { self.0.insert(rule_key, RuleOptions::new(options)); } @@ -58,62 +52,3 @@ pub struct AnalyzerOptions { /// A data structured derived from the [`rome.json`] file pub configuration: AnalyzerConfiguration, } - -#[derive(Debug, Clone, Diagnostic)] -#[diagnostic(category = "lint/configuration")] -pub struct OptionsDeserializationDiagnostic { - #[message] - message: String, - #[description] - description: String, - #[location(resource)] - path: Resource<&'static str>, - #[location(span)] - span: Option, - #[location(source_code)] - source_code: Option>, -} - -impl OptionsDeserializationDiagnostic { - pub fn new(rule_name: &str, input: String, error: Error) -> Self { - let line_starts = LineIndexBuf::from_source_text(&input); - - let line_index = error.line().checked_sub(1); - let span = line_index.and_then(|line_index| { - let line_start = line_starts.get(line_index)?; - - let column_index = error.column().checked_sub(1)?; - let column_offset = TextSize::try_from(column_index).ok()?; - - let span_start = line_start + column_offset; - Some(TextRange::at(span_start, TextSize::from(0))) - }); - - let message = format!( - "Errors while reading options for rule {rule_name}: \n {}", - error - ); - - Self { - message: message.clone(), - description: message, - path: Resource::Memory, - span, - source_code: Some(SourceCode { - text: input, - line_starts: Some(line_starts), - }), - } - } -} - -impl AnalyzerSignal for OptionsDeserializationDiagnostic { - fn diagnostic(&self) -> Option { - let error = rome_diagnostics::Error::from(self.clone()); - Some(crate::AnalyzerDiagnostic::from_error(error)) - } - - fn actions(&self) -> AnalyzerActionIter { - AnalyzerActionIter::default() - } -} diff --git a/crates/rome_analyze/src/registry.rs b/crates/rome_analyze/src/registry.rs index 663d1022c7e..77ff1fad459 100644 --- a/crates/rome_analyze/src/registry.rs +++ b/crates/rome_analyze/src/registry.rs @@ -1,21 +1,20 @@ -use std::{ - any::TypeId, - borrow, - collections::{BTreeMap, BTreeSet}, -}; - use crate::{ context::{RuleContext, ServiceBagRuleOptionsWrapper}, matcher::{GroupKey, MatchQueryParams}, - options::OptionsDeserializationDiagnostic, query::{QueryKey, Queryable}, signals::RuleSignal, AddVisitor, AnalysisFilter, AnalyzerOptions, DeserializableRuleOptions, GroupCategory, QueryMatcher, Rule, RuleGroup, RuleKey, RuleMetadata, ServiceBag, SignalEntry, Visitor, }; +use rome_deserialize::Deserialized; use rome_diagnostics::Error; use rome_rowan::{AstNode, Language, RawSyntaxKind, SyntaxKind, SyntaxNode}; use rustc_hash::{FxHashMap, FxHashSet}; +use std::{ + any::TypeId, + borrow, + collections::{BTreeMap, BTreeSet}, +}; /// Defines all the phases that the [RuleRegistry] supports. #[repr(usize)] @@ -151,7 +150,7 @@ pub struct RuleRegistryBuilder<'a, L: Language> { visitors: BTreeMap<(Phases, TypeId), Box>>, // Service Bag services: ServiceBag, - diagnostics: Vec, + diagnostics: Vec, } impl RegistryVisitor for RuleRegistryBuilder<'_, L> { @@ -224,25 +223,23 @@ impl RegistryVisitor for RuleRegistryBuilder phase.rule_states.push(RuleState::default()); let rule_key = RuleKey::rule::(); - let options = if let Some(options) = self.options.configuration.rules.get_rule(&rule_key) { - let value = options.value(); - match ::try_from(value.clone()) { - Ok(result) => Ok(result), - Err(error) => Err(OptionsDeserializationDiagnostic::new( - rule_key.rule_name(), - value.to_string(), - error, - )), + let deserialized = + if let Some(options) = self.options.configuration.rules.get_rule(&rule_key) { + let value = options.value(); + ::from(value.to_string()) + } else { + Deserialized::new(::default(), vec![]) + }; + + if deserialized.has_errors() { + for error in deserialized.into_diagnostics() { + self.diagnostics.push(error) } } else { - Ok(::default()) - }; - - match options { - Ok(options) => self - .services - .insert_service(ServiceBagRuleOptionsWrapper::(options)), - Err(err) => self.diagnostics.push(err), + self.services + .insert_service(ServiceBagRuleOptionsWrapper::( + deserialized.into_parsed(), + )) } ::build_visitor(&mut self.visitors, self.root); @@ -263,7 +260,7 @@ impl AddVisitor for BTreeMap<(Phases, TypeId), Box = ( RuleRegistry, ServiceBag, - Vec, + Vec, BTreeMap<(Phases, TypeId), Box>>, ); diff --git a/crates/rome_analyze/src/rule.rs b/crates/rome_analyze/src/rule.rs index 513a6134075..dd2366e53bf 100644 --- a/crates/rome_analyze/src/rule.rs +++ b/crates/rome_analyze/src/rule.rs @@ -6,6 +6,8 @@ use crate::{ }; use rome_console::fmt::Display; use rome_console::{markup, MarkupBuf}; +use rome_deserialize::json::{deserialize_from_json, JsonDeserialize, VisitConfigurationAsJson}; +use rome_deserialize::Deserialized; use rome_diagnostics::advice::CodeSuggestionAdvice; use rome_diagnostics::location::AsSpan; use rome_diagnostics::Applicability; @@ -14,7 +16,6 @@ use rome_diagnostics::{ Visit, }; use rome_rowan::{AstNode, BatchMutation, BatchMutationExt, Language, TextRange}; -use serde::de::DeserializeOwned; /// Static metadata containing information about a rule pub struct RuleMetadata { @@ -234,13 +235,25 @@ impl_group_language!( T57, T58, T59 ); -pub trait DeserializableRuleOptions: Default + DeserializeOwned + Sized { - fn try_from(value: serde_json::Value) -> Result { - serde_json::from_value(value) +// pub trait DeserializableRuleOptions: Default + DeserializeOwned + Sized { +// fn try_from(value: String) -> Result { +// // parse_json(); +// } +// } + +pub trait DeserializableRuleOptions: + Default + Sized + JsonDeserialize + VisitConfigurationAsJson +{ + fn from(value: String) -> Deserialized { + deserialize_from_json(&value) } } -impl DeserializableRuleOptions for () {} +impl DeserializableRuleOptions for () { + fn from(_value: String) -> Deserialized { + Deserialized::new((), vec![]) + } +} /// Trait implemented by all analysis rules: declares interest to a certain AstNode type, /// and a callback function to be executed on all nodes matching the query to possibly diff --git a/crates/rome_analyze/src/signals.rs b/crates/rome_analyze/src/signals.rs index ea10b9133c7..28b524e5b60 100644 --- a/crates/rome_analyze/src/signals.rs +++ b/crates/rome_analyze/src/signals.rs @@ -25,7 +25,7 @@ pub trait AnalyzerSignal { /// from a provided factory function. Optionally, this signal can be configured /// to also emit a code action, by calling `.with_action` with a secondary /// factory function for said action. -pub(crate) struct DiagnosticSignal { +pub struct DiagnosticSignal { diagnostic: D, action: A, _diag: PhantomData<(L, T)>, @@ -36,7 +36,7 @@ where D: Fn() -> T, Error: From, { - pub(crate) fn new(factory: D) -> Self { + pub fn new(factory: D) -> Self { Self { diagnostic: factory, action: || None, @@ -46,7 +46,7 @@ where } impl DiagnosticSignal { - pub(crate) fn with_action(self, factory: B) -> DiagnosticSignal + pub fn with_action(self, factory: B) -> DiagnosticSignal where B: Fn() -> Option>, { diff --git a/crates/rome_cli/Cargo.toml b/crates/rome_cli/Cargo.toml index d28cf266756..5866b2e1802 100644 --- a/crates/rome_cli/Cargo.toml +++ b/crates/rome_cli/Cargo.toml @@ -20,6 +20,7 @@ rome_fs = { path = "../rome_fs" } rome_console = { path = "../rome_console" } rome_text_edit = { path = "../rome_text_edit" } rome_lsp = { path = "../rome_lsp" } +rome_deserialize = { path = "../rome_deserialize" } pico-args = { version ="0.5.0", features=["eq-separator"] } tracing = { workspace = true } tracing-tree = "0.2.0" diff --git a/crates/rome_cli/src/commands/rage.rs b/crates/rome_cli/src/commands/rage.rs index 57bbf870881..572ed8109c2 100644 --- a/crates/rome_cli/src/commands/rage.rs +++ b/crates/rome_cli/src/commands/rage.rs @@ -1,7 +1,7 @@ use rome_console::fmt::{Display, Formatter}; use rome_console::{fmt, markup, ConsoleExt, HorizontalLine, Markup}; -use rome_diagnostics::termcolor; use rome_diagnostics::termcolor::{ColorChoice, WriteColor}; +use rome_diagnostics::{termcolor, PrintDescription}; use rome_fs::FileSystem; use rome_service::workspace::{client, RageEntry, RageParams}; use rome_service::{load_config, DynRef, Workspace}; @@ -165,19 +165,32 @@ impl Display for RageConfiguration<'_, '_> { match load_config(self.0, None) { Ok(None) => KeyValuePair("Status", markup!("unset")).fmt(fmt)?, - Ok(Some(configuration)) => { + Ok(Some((configuration, diagnostics))) => { + let status = if !diagnostics.is_empty() { + for diagnostic in diagnostics { + (markup! { + {KeyValuePair("Error", markup!{ + {format!{"{}", PrintDescription(&diagnostic)}} + })} + }) + .fmt(fmt)?; + } + markup!("Loaded with errors") + } else { + markup!("Loaded successfully") + }; + markup! ( - {KeyValuePair("Status", markup!("loaded"))} + {KeyValuePair("Status", status)} {KeyValuePair("Formatter disabled", markup!({DebugDisplay(configuration.is_formatter_disabled())}))} {KeyValuePair("Linter disabled", markup!({DebugDisplay(configuration.is_linter_disabled())}))} ).fmt(fmt)? } - Err(err) => { - markup! ( - {KeyValuePair("Status", markup!("Failed to load"))} - {KeyValuePair("Error", markup!({format!("{err}")}))} - ).fmt(fmt)? - } + Err(err) => markup! ( + {KeyValuePair("Status", markup!("Failed to load"))} + {KeyValuePair("Error", markup!({format!("{err}")}))} + ) + .fmt(fmt)?, } Ok(()) diff --git a/crates/rome_cli/src/configuration.rs b/crates/rome_cli/src/configuration.rs index 3c9c6c06578..32591a8d22f 100644 --- a/crates/rome_cli/src/configuration.rs +++ b/crates/rome_cli/src/configuration.rs @@ -1,11 +1,23 @@ -use rome_service::{load_config, Configuration}; - use crate::{CliDiagnostic, CliSession}; +use rome_console::{markup, ConsoleExt}; +use rome_diagnostics::PrintDiagnostic; +use rome_service::{load_config, Configuration}; /// Load the configuration for this session of the CLI, merging the content of /// the `rome.json` file if it exists on disk with common command line options pub(crate) fn load_configuration(session: &mut CliSession) -> Result { - let mut configuration = load_config(&session.app.fs, None)?.unwrap_or_default(); + let console = &mut session.app.console; + let (mut configuration, diagnostics) = load_config(&session.app.fs, None)?.unwrap_or_default(); + if !diagnostics.is_empty() { + console.log(markup! { + "The configuration has errors, Rome will use its defaults for the sections that were invalid." + }); + for diagnostic in diagnostics { + console.error(markup! { + {PrintDiagnostic::verbose(&diagnostic)} + }) + } + } let files_max_size = session .args diff --git a/crates/rome_cli/tests/snapshots/main_commands_format/applies_custom_configuration_over_config_file_issue_3175_v2.snap b/crates/rome_cli/tests/snapshots/main_commands_format/applies_custom_configuration_over_config_file_issue_3175_v2.snap index 3ca18266f47..9465d674d5a 100644 --- a/crates/rome_cli/tests/snapshots/main_commands_format/applies_custom_configuration_over_config_file_issue_3175_v2.snap +++ b/crates/rome_cli/tests/snapshots/main_commands_format/applies_custom_configuration_over_config_file_issue_3175_v2.snap @@ -25,6 +25,20 @@ function f() { # Emitted Messages +```block +file.js format ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + i Formatter would have printed the following content: + + 1 1 │ function f() { + 2 │ - ··return·'hey'; + 2 │ + ··return·"hey"; + 3 3 │ } + 4 4 │ + + +``` + ```block Compared 1 file(s) in