diff --git a/crates/biome_analyze/CONTRIBUTING.md b/crates/biome_analyze/CONTRIBUTING.md index 093c4df19a75..1f195217f91f 100644 --- a/crates/biome_analyze/CONTRIBUTING.md +++ b/crates/biome_analyze/CONTRIBUTING.md @@ -299,17 +299,44 @@ just ready ### Rule configuration -Some rules may allow customization using configuration. -Biome tries to introduce a minimum of the rule configuration. -Before adding an option discuss that. +Some rules may allow customization using options. +We try to keep rule options to a minimum and only when needed. +Before adding an option, it's worth a discussion. +Options should follow our [technical philosophy](https://biomejs.dev/internals/philosophy/#technical). -The first step is to create the data representation of the rule's configuration. +Let's assume that the rule we implement support the following options: + +- `behavior`: a string among `"A"`, `"B"`, and `"C"`; +- `threshold`: an integer between 0 and 255; +- `behaviorExceptions`: an array of strings. + +We would like to set the options in the `biome.json` configuration file: + +```json +{ + "linter": { + "rules": { + "recommended": true, + "nursery": { + "my-rule": { + "behavior": "A", + "threshold": 30, + "behaviorExceptions": ["f"], + } + } + } + } +} +``` + +The first step is to create the Rust data representation of the rule's options. ```rust,ignore #[derive(Debug, Default, Clone)] -pub struct GreatRuleOptions { - main_behavior: Behavior, - extra_behaviors: Vec, +pub struct MyRuleOptions { + behavior: Behavior, + threshold: u8, + behavior_exceptions: Vec } #[derive(Debug, Default, Clone)] @@ -321,24 +348,18 @@ pub enum Behavior { } ``` -You also need to picture the equivalent data representation in _JSON_: - -```json -{ - "mainBehavior": "A", - "extraBehaviors": ["C"] -} -``` +To allow deserializing instances of the types `MyRuleOptions` and `Behavior`, +they have to implement the `Deserializable` trait from the `biome_deserialize` crate. -So, you have to implement the `Deserializable` trait for these two types. -An implementation can reuse an existing type that implements `Deserializable`. -For example, we could deserialize `Behavior` by first deserializing a string, -and then checking that the string is either `A`, `B`, or `C`. -This is what we do in the following code snippet. -Note that, instead of using `String`, we use `TokenText`. -This avoids a string allocation. +In the following code, we implement `Deserializable` for `Behavior`. +We first deserialize the input into a `TokenText`. +Then we validate the retrieved text by checking that it is one of the allowed string variants. +If it is an unknown variant, we emit a diagnostic and return `None` to signal that the deserialization failed. +Otherwise, we return the corresponding variant. ```rust,ignore +use biome_deserialize::{Deserializable, DeserializableValue, DeserializationVisitor}; + impl Deserializable for Behavior { fn deserialize( value: impl DeserializableValue, @@ -348,9 +369,9 @@ impl Deserializable for Behavior { let range = value.range(); let value = TokenText::deserialize(value, diagnostics)?; match value.text() { - "A" => Some(Behavior.A), - "B" => Some(Behavior.B), - "C" => Some(Behavior.C), + "A" => Some(Behavior::A), + "B" => Some(Behavior::B), + "C" => Some(Behavior::C), _ => { diagnostics.push(DeserializationDiagnostic::new_unknown_value( value.text(), @@ -364,34 +385,30 @@ impl Deserializable for Behavior { } ``` -Implementing `Deserializable` for `GreatRuleOptions` requires more work, -because we cannot rely on an existing deserializable type. -We have to use a _deserialization visitor_. -We create a visitor by creating a zero-sized `struct` that implements `DeserializationVisitor`. -A visitor must specify the type that it produces in its associated type `Output`. -Here the visitor produces a `GreatRuleOptions`. -It must also specify which type is expected with the associated constant `EXPECTED_TYPE`. -Here we deserialize an object (a _map_ of string-value pairs). -Thus, it expects a `ExpectedType::MAP`. -So we implement `visit_map` that traverses the key-value pairs, -deserializes every key as a string (a token text to avoid allocating a string), -and deserializes the value based on the key. +To implement `Deserializable` for `MyRuleOptions`, +we cannot reuse an existing deserializer because a `struct` has custom fields. +Instead, we delegate the deserialization to a visitor. +We implement a visitor by implementing the `DeserializationVisitor` trait from the `biome_deserialize` crate. +The visitor traverses every field (key-value pair) of our object and deserialize them. +If an unknown field is found, we emit a diagnostic. ```rust,ignore -impl Deserializable for GreatRuleOptions { +use biome_deserialize::{DeserializationDiagnostic, Deserializable, DeserializableValue, DeserializationVisitor, VisitableType}; + +impl Deserializable for MyRuleOptions { fn deserialize( value: impl DeserializableValue, diagnostics: &mut Vec, ) -> Option { - value.deserialize(GreatRuleOptionsVisitor, diagnostics) + value.deserialize(MyRuleOptionsVisitor, diagnostics) } } -struct GreatRuleOptionsVisitor; -impl DeserializationVisitor for GreatRuleOptionsVisitor { - type Output = GreatRuleOptions; +struct MyRuleOptionsVisitor; +impl DeserializationVisitor for MyRuleOptionsVisitor { + type Output = MyRuleOptions; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, @@ -399,7 +416,7 @@ impl DeserializationVisitor for GreatRuleOptionsVisitor { _range: TextRange, diagnostics: &mut Vec, ) -> Option { - const ALLOWED_KEYS: &[&str] = &["mainBehavior", "extraBehavior"]; + const ALLOWED_KEYS: &[&str] = &["behavior", "threshold", "behaviorExceptions"]; let mut result = Self::Output::default(); for (key, value) in members { let key_range = key.range(); @@ -407,14 +424,19 @@ impl DeserializationVisitor for GreatRuleOptionsVisitor { continue; }; match key.text() { - "mainBehavior" => { - if let Some(strict_case) = Deserialize::deserialize(value, diagnostics) { - result.main_behavior = value; + "behavior" => { + if let Some(behavior) = Deserialize::deserialize(value, diagnostics) { + result.behavior = behavior; + } + } + "threshold" => { + if let Some(threshold) = Deserialize::deserialize(value, diagnostics) { + result.behavior = threshold; } } - "extraBehavior" => { - if let Some(enum_member_case) = Deserialize::deserialize(value, diagnostics) { - result.extra_behavior = enum_member_case; + "behaviorExceptions" => { + if let Some(exceptions) = Deserialize::deserialize(value, diagnostics) { + result.behavior_exceptions = exceptions; } } _ => diagnostics.push(DeserializationDiagnostic::new_unknown_key( @@ -431,45 +453,24 @@ impl DeserializationVisitor for GreatRuleOptionsVisitor { Once done, you can set the associated type `Options` of the rule: - ```rust,ignore -impl Rule for GreatRule { +impl Rule for MyRule { type Query = Semantic; type State = Fix; type Signals = Vec; - type Options = GreatRuleOptions; + type Options = MyRuleOptions; ... } ``` -This allows the rule to be configured inside `biome.json` file like: - -```json -{ - "linter": { - "rules": { - "recommended": true, - "nursery": { - "greatRule": { - "level": "error", - "options": { - "mainBehavior": "A" - } - } - } - } - } -} -``` - A rule can retrieve its option with: ```rust,ignore let options = ctx.options(); ``` -The compiler should warn you that `GreatRuleOptions` does not implement some required types. +The compiler should warn you that `MyRuleOptions` does not implement some required types. We currently require implementing _serde_'s traits `Deserialize`/`Serialize` and _Bpaf_'s parser trait. You can simply use a derive macros: @@ -477,7 +478,7 @@ You can simply use a derive macros: #[derive(Debug, Default, Clone, Serialize, Deserialize, Bpaf)] #[cfg_attr(feature = "schemars", derive(JsonSchema))] #[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct GreatRuleOptions { +pub struct MyRuleOptions { #[bpaf(hide)] #[serde(default, skip_serializing_if = "is_default")] main_behavior: Behavior, diff --git a/crates/biome_cli/tests/snapshots/main_configuration/incorrect_globals.snap b/crates/biome_cli/tests/snapshots/main_configuration/incorrect_globals.snap index 60ffcbc790f9..9d4613cb1f8c 100644 --- a/crates/biome_cli/tests/snapshots/main_configuration/incorrect_globals.snap +++ b/crates/biome_cli/tests/snapshots/main_configuration/incorrect_globals.snap @@ -31,7 +31,7 @@ configuration ━━━━━━━━━━━━━━━━━━━━━━ ```block biome.json:6:17 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected a string. + × Incorrect type, expected a string, but received a boolean. 4 │ }, 5 │ "javascript": { diff --git a/crates/biome_deserialize/README.md b/crates/biome_deserialize/README.md new file mode 100644 index 000000000000..21d71e9c7ba6 --- /dev/null +++ b/crates/biome_deserialize/README.md @@ -0,0 +1,89 @@ +# `biome_deserialize` + +`biome_deserialize` is a framework for deserializing Rust data structures generically. + +The crate consists of data structures that know how to deserialize themselves along with data formats that know how to deserialize data. +It provides the layer by which these two groups interact with each other, +allowing any supported data structure to be deserialized using any supported data format. + +`biome_deserialize` is designed for textual data formats. +It assumes that every supported data formats supports the following types: + +- null-like values; +- boolean; +- number -- integers and floats; +- string; +- array; +- maps of key-value pairs (covers objects). + +This crate is inspired by [serde](https://serde.rs/). +The only supported data format is JSON. + +## Design overview + +The crate provides three traits: + +- `Deserializable`; +- `DeserializableValue`; +- `DeserializationVisitor`. + +A data structure that knows how to deserialize itself is one that implements the `Deserializable` trait. + +`DeserializableValue` is implemented by data formats such as _JSON_. + +Simple implementations of `Deserializable` can reuse other deserializable data structures. +For instance, an enumeration that corresponds to a string among A, B, and C, can first deserialize a string and then check that the string is one of its values. + +Data structures that cannot directly use another deserializable data structures, use a visitor. +A visitor is generally a zero-sized data structure that implements the `DeserializationVisitor` trait. +A [visitor](https://en.wikipedia.org/wiki/Visitor_pattern) is a well-known design pattern. +It allows selecting an implementation based on the deserialized type without bothering of data format details. + +## Usage examples + +### Deserializing common types + +`biome_deserialize` implements `Deserializable` for common Rust data structure. + +In the following example, we deserialize a boolean, an array of integers, and an unordered map of string-integer pairs. + +```rust +use biome_deserialize::json::deserialize_from_json_str; +use biome_deserialize::Deserialized; +use biome_json_parser::JsonParserOptions; + +let json = "false"; +let Deserialized { + deserialized, + diagnostics, +} = deserialize_from_json_str::(&source, JsonParserOptions::default()); +assert_eq!(deserialized, Some(false)); + +let json = "[0, 1]"; +let Deserialized { + deserialized, + diagnostics, +} = deserialize_from_json_str::>(&source, JsonParserOptions::default()); +assert_eq!(deserialized, Some(vec![0, 1])); + +use std::collections::HashMap; +let json = r#"{ "a": 0, "b": 1 }"#; +let Deserialized { + deserialized, + diagnostics, +} = deserialize_from_json_str::>(&source, JsonParserOptions::default()); +assert_eq!(deserialized, Some(HashMap::from([("a".to_string(), 0), ("b".to_string(), 1)]))); +``` + +### Custom integer range + +...WIP... + +Sometimes you want to deserialize an integer and ensure that it is between two given integers. + +For instance, let's assume we want to deserialize a percentage represented by an integer between 0 and 100. +We can use the new-type pattern in Rust: + +```rust +pub struct Percentage(u8); +``` diff --git a/crates/biome_deserialize/src/diagnostics.rs b/crates/biome_deserialize/src/diagnostics.rs index c62680cf037e..3f3f25bb5963 100644 --- a/crates/biome_deserialize/src/diagnostics.rs +++ b/crates/biome_deserialize/src/diagnostics.rs @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize}; bitflags! { #[derive(Debug, Copy, Clone, Eq, PartialEq)] - pub struct ExpectedType: u8 { + pub struct VisitableType: u8 { const NULL = 1 << 0; const BOOL = 1 << 1; const NUMBER = 1 << 2; @@ -20,27 +20,25 @@ bitflags! { } } -impl Display for ExpectedType { - fn fmt(&self, fmt: &mut biome_console::fmt::Formatter) -> std::io::Result<()> { +impl std::fmt::Display for VisitableType { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { if self.is_empty() { return write!(fmt, "no value"); } - let mut is_not_first = false; - for expected_type in self.iter() { - if is_not_first { - write!(fmt, " or ")?; + for (i, expected_type) in self.iter().enumerate() { + if i != 0 { + write!(fmt, ", or ")?; } let expected_type = match expected_type { - ExpectedType::NULL => "null", - ExpectedType::BOOL => "a boolean", - ExpectedType::NUMBER => "a number", - ExpectedType::STR => "a string", - ExpectedType::ARRAY => "an array", - ExpectedType::MAP => "an object", + VisitableType::NULL => "null", + VisitableType::BOOL => "a boolean", + VisitableType::NUMBER => "a number", + VisitableType::STR => "a string", + VisitableType::ARRAY => "an array", + VisitableType::MAP => "an object", _ => unreachable!("Unhandled deserialization type."), }; write!(fmt, "{}", expected_type)?; - is_not_first = true; } Ok(()) } @@ -75,9 +73,13 @@ impl DeserializationDiagnostic { } /// Emitted when a generic node has an incorrect type - pub fn new_incorrect_type(expected_type: ExpectedType, range: impl AsSpan) -> Self { + pub fn new_incorrect_type( + actual_type: VisitableType, + expected_type: VisitableType, + range: impl AsSpan, + ) -> Self { Self::new(markup! { - "Incorrect type, expected "{expected_type}"." + "Incorrect type, expected "{format_args!("{}", expected_type)}", but received "{format_args!("{}", actual_type)}"." }) .with_range(range) } @@ -198,3 +200,22 @@ impl Advices for DeserializationAdvice { Ok(()) } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_visitable_type_fmt() { + assert_eq!(VisitableType::empty().to_string(), "no value"); + assert_eq!(VisitableType::NULL.to_string(), "null"); + assert_eq!( + VisitableType::NULL.union(VisitableType::BOOL).to_string(), + "null, or a boolean" + ); + assert_eq!( + VisitableType::all().to_string(), + "null, or a boolean, or a number, or a string, or an array, or an object" + ); + } +} diff --git a/crates/biome_deserialize/src/impls.rs b/crates/biome_deserialize/src/impls.rs index 87cc2c455aaf..05c260878592 100644 --- a/crates/biome_deserialize/src/impls.rs +++ b/crates/biome_deserialize/src/impls.rs @@ -1,9 +1,12 @@ +//! Implementations of [Deserializable] for common data structures. +//! +//! Tests of these implementations are available in [biome_deserialize::json::tests] module. use crate::{ - diagnostics::ExpectedType, Deserializable, DeserializableValue, DeserializationDiagnostic, + diagnostics::VisitableType, Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, }; use biome_rowan::{TextRange, TokenText}; -use indexmap::IndexSet; +use indexmap::{IndexMap, IndexSet}; use std::{ collections::{BTreeMap, HashMap, HashSet}, hash::{BuildHasher, Hash}, @@ -12,8 +15,6 @@ use std::{ path::PathBuf, }; -/// Implementation of [Deserializable] for common data structures. - /// A String representation of a number (integer, float). /// The format should be parsable by Rust numeric types. #[derive(Eq, PartialEq, Clone)] @@ -31,7 +32,7 @@ impl Deserializable for TokenNumber { struct Visitor; impl DeserializationVisitor for Visitor { type Output = TokenNumber; - const EXPECTED_TYPE: ExpectedType = ExpectedType::NUMBER; + const EXPECTED_TYPE: VisitableType = VisitableType::NUMBER; fn visit_number( self, value: TokenNumber, @@ -50,11 +51,12 @@ impl Deserializable for () { value: impl DeserializableValue, diagnostics: &mut Vec, ) -> Option { - diagnostics.push(DeserializationDiagnostic::new_incorrect_type( - ExpectedType::empty(), - value.range(), - )); - None + struct Visitor; + impl DeserializationVisitor for Visitor { + type Output = (); + const EXPECTED_TYPE: VisitableType = VisitableType::empty(); + } + value.deserialize(Visitor, diagnostics) } } @@ -66,7 +68,7 @@ impl Deserializable for bool { struct Visitor; impl DeserializationVisitor for Visitor { type Output = bool; - const EXPECTED_TYPE: ExpectedType = ExpectedType::BOOL; + const EXPECTED_TYPE: VisitableType = VisitableType::BOOL; fn visit_bool( self, value: bool, @@ -394,7 +396,7 @@ impl Deserializable for TokenText { struct Visitor; impl DeserializationVisitor for Visitor { type Output = TokenText; - const EXPECTED_TYPE: ExpectedType = ExpectedType::STR; + const EXPECTED_TYPE: VisitableType = VisitableType::STR; fn visit_str( self, value: TokenText, @@ -434,7 +436,7 @@ impl Deserializable for Vec { struct Visitor(PhantomData); impl DeserializationVisitor for Visitor { type Output = Vec; - const EXPECTED_TYPE: ExpectedType = ExpectedType::ARRAY; + const EXPECTED_TYPE: VisitableType = VisitableType::ARRAY; fn visit_array( self, values: impl Iterator, @@ -462,7 +464,7 @@ impl Deserializable for for Visitor { type Output = HashSet; - const EXPECTED_TYPE: ExpectedType = ExpectedType::ARRAY; + const EXPECTED_TYPE: VisitableType = VisitableType::ARRAY; fn visit_array( self, values: impl Iterator, @@ -488,7 +490,7 @@ impl Deserializable for IndexSet { struct Visitor(PhantomData); impl DeserializationVisitor for Visitor { type Output = IndexSet; - const EXPECTED_TYPE: ExpectedType = ExpectedType::ARRAY; + const EXPECTED_TYPE: VisitableType = VisitableType::ARRAY; fn visit_array( self, values: impl Iterator, @@ -518,7 +520,7 @@ impl DeserializationVisitor for Visitor { type Output = HashMap; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, members: impl Iterator, @@ -548,7 +550,41 @@ impl Deserializable for BTreeMap(PhantomData<(K, V)>); impl DeserializationVisitor for Visitor { type Output = BTreeMap; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; + fn visit_map( + self, + members: impl Iterator, + _range: TextRange, + diagnostics: &mut Vec, + ) -> Option { + let mut result = Self::Output::default(); + for (key, value) in members { + let key = Deserializable::deserialize(key, diagnostics); + let value = Deserializable::deserialize(value, diagnostics); + if let (Some(key), Some(value)) = (key, value) { + result.insert(key, value); + } + } + Some(result) + } + } + value.deserialize(Visitor(PhantomData), diagnostics) + } +} + +impl Deserializable + for IndexMap +{ + fn deserialize( + value: impl DeserializableValue, + diagnostics: &mut Vec, + ) -> Option { + struct Visitor(PhantomData<(K, V, S)>); + impl + DeserializationVisitor for Visitor + { + type Output = IndexMap; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, members: impl Iterator, diff --git a/crates/biome_deserialize/src/json.rs b/crates/biome_deserialize/src/json.rs index fcbfe8af1d6c..a09848319f4f 100644 --- a/crates/biome_deserialize/src/json.rs +++ b/crates/biome_deserialize/src/json.rs @@ -1,3 +1,4 @@ +//! Implementation of [DeserializableValue] for the JSON data format. use crate::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, Deserialized, TokenNumber, @@ -17,7 +18,7 @@ use biome_rowan::{AstNode, AstSeparatedList}; /// ## Examples /// /// ``` -/// use biome_deserialize::{DeserializationDiagnostic, Deserializable, DeserializableValue, DeserializationVisitor, ExpectedType}; +/// use biome_deserialize::{DeserializationDiagnostic, Deserializable, DeserializableValue, DeserializationVisitor, VisitableType}; /// use biome_deserialize::json::deserialize_from_json_str; /// use biome_rowan::{TextRange, TokenText}; /// @@ -39,7 +40,7 @@ use biome_rowan::{AstNode, AstSeparatedList}; /// impl DeserializationVisitor for Visitor { /// type Output = NewConfiguration; /// -/// const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; +/// const EXPECTED_TYPE: VisitableType = VisitableType::MAP; /// /// fn visit_map( /// self, @@ -71,7 +72,7 @@ use biome_rowan::{AstNode, AstSeparatedList}; /// } /// } /// -/// use biome_json_parser::JsonParserOptions; +/// use biome_json_parser::JsonParserOptions; /// let source = r#"{ "lorem": "ipsum" }"#; /// let deserialized = deserialize_from_json_str::(&source, JsonParserOptions::default()); /// assert!(!deserialized.has_errors()); @@ -148,11 +149,10 @@ impl DeserializableValue for AnyJsonValue { visitor.visit_number(TokenNumber(token_text), range, diagnostics) } AnyJsonValue::JsonObjectValue(object) => { - let members = object - .json_member_list() - .iter() - .filter_map(|x| x.ok()) - .filter_map(|x| Some((x.name().ok()?, x.value().ok()?))); + let members = object.json_member_list().iter().filter_map(|member| { + let member = member.ok()?; + Some((member.name().ok()?, member.value().ok()?)) + }); visitor.visit_map(members, range, diagnostics) } AnyJsonValue::JsonStringValue(value) => { @@ -178,3 +178,513 @@ impl DeserializableValue for JsonMemberName { visitor.visit_str(value, range, diagnostics) } } + +#[cfg(test)] +mod tests { + use std::{ + collections::{BTreeMap, HashMap, HashSet}, + num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}, + }; + + use super::*; + use biome_json_parser::JsonParserOptions; + use indexmap::{IndexMap, IndexSet}; + + #[test] + fn test_unit() { + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::<()>(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_bool() { + let source = "true"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert!(deserialized.unwrap()); + + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_f32() { + let source = "0.5"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, Some(0.5)); + } + + #[test] + fn test_f64() { + let source = "0.5"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, Some(0.5)); + } + + #[test] + fn test_i8() { + let source = "-1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, Some(-1)); + + let source = u8::MAX.to_string(); + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(&source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_i16() { + let source = "-1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, Some(-1)); + + let source = u16::MAX.to_string(); + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(&source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_i32() { + let source = "-1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, Some(-1)); + + let source = u32::MAX.to_string(); + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(&source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_i64() { + let source = "-1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, Some(-1)); + + let source = u64::MAX.to_string(); + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(&source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_isize() { + let source = "-1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, Some(-1)); + + let source = usize::MAX.to_string(); + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(&source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_u8() { + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, Some(0)); + + let source = "256"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_u16() { + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, Some(0)); + + let source = "-1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_u32() { + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, Some(0)); + + let source = "-1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_u64() { + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, Some(0)); + + let source = "-1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_usize() { + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, Some(0)); + + let source = "-1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_non_zero_u8() { + let source = "1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, NonZeroU8::new(1)); + + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_non_zero_u16() { + let source = "1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, NonZeroU16::new(1)); + + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_non_zero_u32() { + let source = "1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, NonZeroU32::new(1)); + + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_non_zero_u64() { + let source = "1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, NonZeroU64::new(1)); + + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_non_zero_usize() { + let source = "1"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized, NonZeroUsize::new(1)); + + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_number() { + let source = u128::MAX.to_string(); + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(&source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized.unwrap().text(), u128::MAX.to_string()); + + let source = "true"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_string() { + let source = r#""string""#; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized.unwrap(), "string"); + + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_vec() { + let source = r#"[0, 1]"#; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::>(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized.unwrap(), vec![0, 1]); + + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::>(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_hash_set() { + let source = r#"[0, 1]"#; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::>(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized.unwrap(), HashSet::from([0, 1])); + + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::>(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_index_set() { + let source = r#"[0, 1]"#; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::>(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!(deserialized.unwrap(), IndexSet::from([0, 1])); + + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::>(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_hash_map() { + let source = r#"{ "a": 0, "b": 1 }"#; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::>(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!( + deserialized.unwrap(), + HashMap::from([("a".to_string(), 0), ("b".to_string(), 1)]) + ); + + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::>(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_b_tree_map_map() { + let source = r#"{ "a": 0, "b": 1 }"#; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::>(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!( + deserialized.unwrap(), + BTreeMap::from([("a".to_string(), 0), ("b".to_string(), 1)]) + ); + + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::>(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } + + #[test] + fn test_index_map() { + let source = r#"{ "a": 0, "b": 1 }"#; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::>(source, JsonParserOptions::default()); + assert!(diagnostics.is_empty()); + assert_eq!( + deserialized.unwrap(), + IndexMap::from([("a".to_string(), 0), ("b".to_string(), 1)]) + ); + + let source = "0"; + let Deserialized { + deserialized, + diagnostics, + } = deserialize_from_json_str::>(source, JsonParserOptions::default()); + assert!(!diagnostics.is_empty()); + assert!(deserialized.is_none()); + } +} diff --git a/crates/biome_deserialize/src/lib.rs b/crates/biome_deserialize/src/lib.rs index 514d8a5d48c1..2969c1c460e1 100644 --- a/crates/biome_deserialize/src/lib.rs +++ b/crates/biome_deserialize/src/lib.rs @@ -1,6 +1,6 @@ //! `biome_deserialize` provides a framework to deserialize textual data format. //! -//! This is inspired by serde. +//! This is inspired by [serde](https://serde.rs/). //! 0ne of the main difference is the fault-tolerant behavior of `biome_deserialize`. //! Serde uses a fast-fail strategy, while `biome_deserialize` deserialize as much as possible //! and report several diagnostics (errors, warning, deprecation messages, ...). @@ -17,7 +17,7 @@ pub mod json; pub mod string_set; use biome_diagnostics::{Error, Severity}; use biome_rowan::{TextRange, TokenText}; -pub use diagnostics::{DeserializationAdvice, DeserializationDiagnostic, ExpectedType}; +pub use diagnostics::{DeserializationAdvice, DeserializationDiagnostic, VisitableType}; pub use impls::*; use std::fmt::Debug; pub use string_set::StringSet; @@ -31,10 +31,10 @@ pub use string_set::StringSet; /// When deserializing more complex types, such as `struct`, /// you have to use a type that implements [DeserializationVisitor]. /// -/// ### Example +/// ## Example /// /// ``` -/// use biome_deserialize::{DeserializationDiagnostic, Deserializable, DeserializableValue, DeserializationVisitor, ExpectedType}; +/// use biome_deserialize::{DeserializationDiagnostic, Deserializable, DeserializableValue}; /// use biome_deserialize::json::deserialize_from_json_str; /// use biome_rowan::{TextRange, TokenText}; /// @@ -48,7 +48,7 @@ pub use string_set::StringSet; /// value: impl DeserializableValue, /// diagnostics: &mut Vec, /// ) -> Option { -/// const ALLOWED_VARIANTS: &[&str] = &["A", "B", "C"]; +/// const ALLOWED_VARIANTS: &[&str] = &["A", "B"]; /// let range = value.range(); /// let value = TokenText::deserialize(value, diagnostics)?; /// match value.text() { @@ -95,12 +95,12 @@ pub trait DeserializableValue: Sized { /// This trait represents a visitor that walks through a [DeserializableValue]. /// /// We assume that a deserializable value has one of the following type: -/// - null / none -/// - boolean -/// - number (integer, floats) -/// - string -/// - array -/// - map (key-value pairs with value's type that can depend on its key) +/// - null / none; +/// - boolean; +/// - number -- an integer or a float +/// - string; +/// - array; +/// - map (key-value pairs with value's type that can depend on its key). /// /// Every type is associated to a `visit_` method. /// [DeserializableValue::deserialize] calls the `viist_` method that matches the type of the value. @@ -108,10 +108,10 @@ pub trait DeserializableValue: Sized { /// Most of the time you should implement [Deserializable] and rely on existing deserializable types. /// You should use a visitor only when you deserialize a map or a union of several types. /// -/// ### Examples +/// ## Examples /// /// ``` -/// use biome_deserialize::{DeserializationDiagnostic, Deserializable, DeserializableValue, DeserializationVisitor, ExpectedType}; +/// use biome_deserialize::{DeserializationDiagnostic, Deserializable, DeserializableValue, DeserializationVisitor, VisitableType}; /// use biome_deserialize::json::deserialize_from_json_str; /// use biome_rowan::{TextRange, TokenText}; /// @@ -131,7 +131,7 @@ pub trait DeserializableValue: Sized { /// struct PersonVisitor; /// impl DeserializationVisitor for PersonVisitor { /// type Output = Person; -/// const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; +/// const EXPECTED_TYPE: VisitableType = VisitableType::MAP; /// /// fn visit_map( /// self, @@ -143,10 +143,10 @@ pub trait DeserializableValue: Sized { /// let mut name = None; /// for (key, value) in members { /// let key_range = key.range(); -/// let Some(key) = TokenText::deserialize(key, diagnostics) else { +/// let Some(key) = String::deserialize(key, diagnostics) else { /// continue; /// }; -/// match key.text() { +/// match key { /// "name" => { /// name = Deserializable::deserialize(value, diagnostics); /// }, @@ -178,7 +178,7 @@ pub trait DeserializableValue: Sized { /// struct UnionVisitor; /// impl DeserializationVisitor for UnionVisitor { /// type Output = Union; -/// const EXPECTED_TYPE: ExpectedType = ExpectedType::BOOL.union(ExpectedType::STR); +/// const EXPECTED_TYPE: VisitableType = VisitableType::BOOL.union(VisitableType::STR); /// /// fn visit_bool( /// self, @@ -204,7 +204,7 @@ pub trait DeserializationVisitor: Sized { type Output; /// The expected type of the visited value. - const EXPECTED_TYPE: ExpectedType; + const EXPECTED_TYPE: VisitableType; /// The visited value is `null`. /// @@ -216,10 +216,11 @@ pub trait DeserializationVisitor: Sized { diagnostics: &mut Vec, ) -> Option { debug_assert!( - !Self::EXPECTED_TYPE.contains(ExpectedType::NULL), - "This method should be implemented because the type is expected." + !Self::EXPECTED_TYPE.contains(VisitableType::NULL), + "This method should be implemented because the expected type is null." ); diagnostics.push(DeserializationDiagnostic::new_incorrect_type( + VisitableType::NULL, Self::EXPECTED_TYPE, range, )); @@ -237,10 +238,11 @@ pub trait DeserializationVisitor: Sized { diagnostics: &mut Vec, ) -> Option { debug_assert!( - !Self::EXPECTED_TYPE.contains(ExpectedType::BOOL), - "This method should be implemented because the type is expected." + !Self::EXPECTED_TYPE.contains(VisitableType::BOOL), + "This method should be implemented because the expected type is bool." ); diagnostics.push(DeserializationDiagnostic::new_incorrect_type( + VisitableType::BOOL, Self::EXPECTED_TYPE, range, )); @@ -259,10 +261,11 @@ pub trait DeserializationVisitor: Sized { diagnostics: &mut Vec, ) -> Option { debug_assert!( - !Self::EXPECTED_TYPE.contains(ExpectedType::NUMBER), - "This method should be implemented because the type is expected." + !Self::EXPECTED_TYPE.contains(VisitableType::NUMBER), + "This method should be implemented because the expected type is number." ); diagnostics.push(DeserializationDiagnostic::new_incorrect_type( + VisitableType::NUMBER, Self::EXPECTED_TYPE, range, )); @@ -280,10 +283,11 @@ pub trait DeserializationVisitor: Sized { diagnostics: &mut Vec, ) -> Option { debug_assert!( - !Self::EXPECTED_TYPE.contains(ExpectedType::STR), - "This method should be implemented because the type is expected." + !Self::EXPECTED_TYPE.contains(VisitableType::STR), + "This method should be implemented because the expected type is str." ); diagnostics.push(DeserializationDiagnostic::new_incorrect_type( + VisitableType::STR, Self::EXPECTED_TYPE, range, )); @@ -301,10 +305,11 @@ pub trait DeserializationVisitor: Sized { diagnostics: &mut Vec, ) -> Option { debug_assert!( - !Self::EXPECTED_TYPE.contains(ExpectedType::ARRAY), - "This method should be implemented because the type is expected." + !Self::EXPECTED_TYPE.contains(VisitableType::ARRAY), + "This method should be implemented because the expected type is array." ); diagnostics.push(DeserializationDiagnostic::new_incorrect_type( + VisitableType::ARRAY, Self::EXPECTED_TYPE, range, )); @@ -322,10 +327,11 @@ pub trait DeserializationVisitor: Sized { diagnostics: &mut Vec, ) -> Option { debug_assert!( - !Self::EXPECTED_TYPE.contains(ExpectedType::MAP), - "This method should be implemented because the type is expected." + !Self::EXPECTED_TYPE.contains(VisitableType::MAP), + "This method should be implemented because the expected type is map." ); diagnostics.push(DeserializationDiagnostic::new_incorrect_type( + VisitableType::MAP, Self::EXPECTED_TYPE, range, )); diff --git a/crates/biome_js_analyze/src/analyzers/complexity/no_excessive_cognitive_complexity.rs b/crates/biome_js_analyze/src/analyzers/complexity/no_excessive_cognitive_complexity.rs index 72aa849e4301..80c8ee0515cf 100644 --- a/crates/biome_js_analyze/src/analyzers/complexity/no_excessive_cognitive_complexity.rs +++ b/crates/biome_js_analyze/src/analyzers/complexity/no_excessive_cognitive_complexity.rs @@ -5,7 +5,7 @@ use biome_analyze::{ use biome_console::markup; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_js_syntax::{ AnyFunctionLike, JsBreakStatement, JsContinueStatement, JsElseClause, JsLanguage, @@ -410,7 +410,7 @@ struct ComplexityOptionsVisitor; impl DeserializationVisitor for ComplexityOptionsVisitor { type Output = ComplexityOptions; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_js_analyze/src/semantic_analyzers/correctness/use_exhaustive_dependencies.rs b/crates/biome_js_analyze/src/semantic_analyzers/correctness/use_exhaustive_dependencies.rs index 90e6394ea74c..d522a0527be6 100644 --- a/crates/biome_js_analyze/src/semantic_analyzers/correctness/use_exhaustive_dependencies.rs +++ b/crates/biome_js_analyze/src/semantic_analyzers/correctness/use_exhaustive_dependencies.rs @@ -4,7 +4,7 @@ use biome_analyze::{context::RuleContext, declare_rule, Rule, RuleDiagnostic}; use biome_console::markup; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_js_semantic::{Capture, SemanticModel}; use biome_js_syntax::{ @@ -239,7 +239,7 @@ struct HooksOptionsVisitor; impl DeserializationVisitor for HooksOptionsVisitor { type Output = HooksOptions; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, @@ -315,7 +315,7 @@ struct HooksVisitor; impl DeserializationVisitor for HooksVisitor { type Output = Hooks; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_js_analyze/src/semantic_analyzers/style/no_restricted_globals.rs b/crates/biome_js_analyze/src/semantic_analyzers/style/no_restricted_globals.rs index 63f6041da0de..e10ed12bd45f 100644 --- a/crates/biome_js_analyze/src/semantic_analyzers/style/no_restricted_globals.rs +++ b/crates/biome_js_analyze/src/semantic_analyzers/style/no_restricted_globals.rs @@ -4,7 +4,7 @@ use biome_analyze::{declare_rule, Rule, RuleDiagnostic}; use biome_console::markup; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_js_semantic::{Binding, BindingExtensions}; use biome_js_syntax::{AnyJsIdentifierUsage, TextRange}; @@ -93,7 +93,7 @@ struct RestrictedGlobalsOptionsVisitor; impl DeserializationVisitor for RestrictedGlobalsOptionsVisitor { type Output = RestrictedGlobalsOptions; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_js_analyze/src/semantic_analyzers/style/use_naming_convention.rs b/crates/biome_js_analyze/src/semantic_analyzers/style/use_naming_convention.rs index e0a3acb12d3d..8ec2db295655 100644 --- a/crates/biome_js_analyze/src/semantic_analyzers/style/use_naming_convention.rs +++ b/crates/biome_js_analyze/src/semantic_analyzers/style/use_naming_convention.rs @@ -13,7 +13,7 @@ use biome_analyze::{ use biome_console::markup; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_diagnostics::Applicability; use biome_js_semantic::CanBeImportedExported; @@ -498,7 +498,7 @@ struct NamingConventionOptionsVisitor; impl DeserializationVisitor for NamingConventionOptionsVisitor { type Output = NamingConventionOptions; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_project/src/node_js_project/package_json.rs b/crates/biome_project/src/node_js_project/package_json.rs index 0ec6e4697614..720da218b8b1 100644 --- a/crates/biome_project/src/node_js_project/package_json.rs +++ b/crates/biome_project/src/node_js_project/package_json.rs @@ -2,7 +2,7 @@ use crate::{LanguageRoot, Manifest}; use biome_deserialize::json::deserialize_from_json_ast; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - Deserialized, ExpectedType, + Deserialized, VisitableType, }; use biome_json_syntax::JsonLanguage; use biome_rowan::TokenText; @@ -48,7 +48,7 @@ struct PackageJsonVisitor; impl DeserializationVisitor for PackageJsonVisitor { type Output = PackageJson; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_project/tests/invalid/lisence_not_string.json.snap b/crates/biome_project/tests/invalid/lisence_not_string.json.snap index ae86002fc2d8..beaee694869d 100644 --- a/crates/biome_project/tests/invalid/lisence_not_string.json.snap +++ b/crates/biome_project/tests/invalid/lisence_not_string.json.snap @@ -4,7 +4,7 @@ expression: lisence_not_string.json --- lisence_not_string.json:2:13 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected a string. + × Incorrect type, expected a string, but received a boolean. 1 │ { > 2 │ "license": false diff --git a/crates/biome_project/tests/invalid/name.json.snap b/crates/biome_project/tests/invalid/name.json.snap index 2aa400e1c886..3cd9e5f06248 100644 --- a/crates/biome_project/tests/invalid/name.json.snap +++ b/crates/biome_project/tests/invalid/name.json.snap @@ -4,7 +4,7 @@ expression: name.json --- name.json:2:10 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected a string. + × Incorrect type, expected a string, but received a boolean. 1 │ { > 2 │ "name": false diff --git a/crates/biome_service/src/configuration/parse/json/configuration.rs b/crates/biome_service/src/configuration/parse/json/configuration.rs index 7c1ac07918c2..6812b8f3b305 100644 --- a/crates/biome_service/src/configuration/parse/json/configuration.rs +++ b/crates/biome_service/src/configuration/parse/json/configuration.rs @@ -1,7 +1,7 @@ use crate::Configuration; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_rowan::TokenText; @@ -18,7 +18,7 @@ struct ConfigurationVisitor; impl DeserializationVisitor for ConfigurationVisitor { type Output = Configuration; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_service/src/configuration/parse/json/files.rs b/crates/biome_service/src/configuration/parse/json/files.rs index e25056344acb..7cdd95972e9d 100644 --- a/crates/biome_service/src/configuration/parse/json/files.rs +++ b/crates/biome_service/src/configuration/parse/json/files.rs @@ -1,7 +1,7 @@ use crate::configuration::FilesConfiguration; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_rowan::{TextRange, TokenText}; @@ -18,7 +18,7 @@ struct FilesConfigurationVisitor; impl DeserializationVisitor for FilesConfigurationVisitor { type Output = FilesConfiguration; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_service/src/configuration/parse/json/formatter.rs b/crates/biome_service/src/configuration/parse/json/formatter.rs index 6b4dc6d80881..c148a1baa320 100644 --- a/crates/biome_service/src/configuration/parse/json/formatter.rs +++ b/crates/biome_service/src/configuration/parse/json/formatter.rs @@ -1,7 +1,7 @@ use crate::configuration::{FormatterConfiguration, PlainIndentStyle}; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_rowan::{TextRange, TokenText}; @@ -18,7 +18,7 @@ struct FormatterConfigurationVisitor; impl DeserializationVisitor for FormatterConfigurationVisitor { type Output = FormatterConfiguration; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_service/src/configuration/parse/json/javascript/formatter.rs b/crates/biome_service/src/configuration/parse/json/javascript/formatter.rs index 2f04a64c79b5..e9fced1be84d 100644 --- a/crates/biome_service/src/configuration/parse/json/javascript/formatter.rs +++ b/crates/biome_service/src/configuration/parse/json/javascript/formatter.rs @@ -1,7 +1,7 @@ use crate::configuration::javascript::JavascriptFormatter; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_rowan::TokenText; @@ -18,7 +18,7 @@ struct JavascriptFormatterVisitor; impl DeserializationVisitor for JavascriptFormatterVisitor { type Output = JavascriptFormatter; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_service/src/configuration/parse/json/javascript/mod.rs b/crates/biome_service/src/configuration/parse/json/javascript/mod.rs index 837ec8e0bc0b..17c86ffff7b2 100644 --- a/crates/biome_service/src/configuration/parse/json/javascript/mod.rs +++ b/crates/biome_service/src/configuration/parse/json/javascript/mod.rs @@ -4,7 +4,7 @@ use crate::configuration::javascript::{JavascriptOrganizeImports, JavascriptPars use crate::configuration::JavascriptConfiguration; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_rowan::TokenText; @@ -21,7 +21,7 @@ struct JavascriptConfigurationVisitor; impl DeserializationVisitor for JavascriptConfigurationVisitor { type Output = JavascriptConfiguration; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, @@ -75,7 +75,7 @@ struct JavascriptOrganizeImportsVisitor; impl DeserializationVisitor for JavascriptOrganizeImportsVisitor { type Output = JavascriptOrganizeImports; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, @@ -100,7 +100,7 @@ struct JavascriptParserVisitor; impl DeserializationVisitor for JavascriptParserVisitor { type Output = JavascriptParser; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_service/src/configuration/parse/json/json_impl/mod.rs b/crates/biome_service/src/configuration/parse/json/json_impl/mod.rs index d4ce34df82d6..0e0399d079e7 100644 --- a/crates/biome_service/src/configuration/parse/json/json_impl/mod.rs +++ b/crates/biome_service/src/configuration/parse/json/json_impl/mod.rs @@ -1,7 +1,7 @@ use crate::configuration::json::{JsonConfiguration, JsonFormatter, JsonParser}; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_rowan::TokenText; @@ -18,7 +18,7 @@ struct JsonConfigurationVisitor; impl DeserializationVisitor for JsonConfigurationVisitor { type Output = JsonConfiguration; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, @@ -66,7 +66,7 @@ struct JsonParserVisitor; impl DeserializationVisitor for JsonParserVisitor { type Output = JsonParser; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, @@ -114,7 +114,7 @@ struct JsonFormatterVisitor; impl DeserializationVisitor for JsonFormatterVisitor { type Output = JsonFormatter; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_service/src/configuration/parse/json/linter.rs b/crates/biome_service/src/configuration/parse/json/linter.rs index 06617d4aa59b..fd8d719edbac 100644 --- a/crates/biome_service/src/configuration/parse/json/linter.rs +++ b/crates/biome_service/src/configuration/parse/json/linter.rs @@ -3,7 +3,7 @@ use crate::configuration::LinterConfiguration; use crate::RuleConfiguration; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_js_analyze::options::PossibleOptions; use biome_rowan::{TextRange, TokenText}; @@ -21,7 +21,7 @@ struct LinterConfigurationVisitor; impl DeserializationVisitor for LinterConfigurationVisitor { type Output = LinterConfiguration; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, @@ -77,7 +77,7 @@ struct RuleConfigurationVisitor<'a> { impl<'a> DeserializationVisitor for RuleConfigurationVisitor<'a> { type Output = RuleConfiguration; - const EXPECTED_TYPE: ExpectedType = ExpectedType::STR.union(ExpectedType::MAP); + const EXPECTED_TYPE: VisitableType = VisitableType::STR.union(VisitableType::MAP); fn visit_str( self, diff --git a/crates/biome_service/src/configuration/parse/json/organize_imports.rs b/crates/biome_service/src/configuration/parse/json/organize_imports.rs index 4a9ac10404f2..1306c1878ab4 100644 --- a/crates/biome_service/src/configuration/parse/json/organize_imports.rs +++ b/crates/biome_service/src/configuration/parse/json/organize_imports.rs @@ -1,7 +1,7 @@ use crate::configuration::organize_imports::OrganizeImports; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_rowan::{TextRange, TokenText}; @@ -18,7 +18,7 @@ struct OrganizeImportsVisitor; impl DeserializationVisitor for OrganizeImportsVisitor { type Output = OrganizeImports; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_service/src/configuration/parse/json/overrides.rs b/crates/biome_service/src/configuration/parse/json/overrides.rs index e8aee2005f1b..c2f5b2609129 100644 --- a/crates/biome_service/src/configuration/parse/json/overrides.rs +++ b/crates/biome_service/src/configuration/parse/json/overrides.rs @@ -4,7 +4,7 @@ use crate::configuration::overrides::{ }; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_rowan::TokenText; @@ -30,7 +30,7 @@ struct OverridePatternVisitor; impl DeserializationVisitor for OverridePatternVisitor { type Output = OverridePattern; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, @@ -99,7 +99,7 @@ struct OverrideFormatterConfigurationVisitor; impl DeserializationVisitor for OverrideFormatterConfigurationVisitor { type Output = OverrideFormatterConfiguration; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, @@ -169,7 +169,7 @@ struct OverrideLinterConfigurationVisitor; impl DeserializationVisitor for OverrideLinterConfigurationVisitor { type Output = OverrideLinterConfiguration; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, @@ -215,7 +215,7 @@ struct OverrideOrganizeImportsConfigurationVisitor; impl DeserializationVisitor for OverrideOrganizeImportsConfigurationVisitor { type Output = OverrideOrganizeImportsConfiguration; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_service/src/configuration/parse/json/rules.rs b/crates/biome_service/src/configuration/parse/json/rules.rs index 344bbe0c800c..4f83f0d8f100 100644 --- a/crates/biome_service/src/configuration/parse/json/rules.rs +++ b/crates/biome_service/src/configuration/parse/json/rules.rs @@ -5,7 +5,7 @@ use crate::Rules; use biome_console::markup; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_rowan::{TextRange, TokenText}; impl Deserializable for Rules { @@ -16,7 +16,7 @@ impl Deserializable for Rules { struct Visitor; impl DeserializationVisitor for Visitor { type Output = Rules; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, members: impl Iterator, @@ -103,7 +103,7 @@ impl Deserializable for A11y { struct Visitor; impl DeserializationVisitor for Visitor { type Output = A11y; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, members: impl Iterator, @@ -381,7 +381,7 @@ impl Deserializable for Complexity { struct Visitor; impl DeserializationVisitor for Visitor { type Output = Complexity; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, members: impl Iterator, @@ -626,7 +626,7 @@ impl Deserializable for Correctness { struct Visitor; impl DeserializationVisitor for Visitor { type Output = Correctness; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, members: impl Iterator, @@ -950,7 +950,7 @@ impl Deserializable for Nursery { struct Visitor; impl DeserializationVisitor for Visitor { type Output = Nursery; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, members: impl Iterator, @@ -1166,7 +1166,7 @@ impl Deserializable for Performance { struct Visitor; impl DeserializationVisitor for Visitor { type Output = Performance; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, members: impl Iterator, @@ -1233,7 +1233,7 @@ impl Deserializable for Security { struct Visitor; impl DeserializationVisitor for Visitor { type Output = Security; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, members: impl Iterator, @@ -1306,7 +1306,7 @@ impl Deserializable for Style { struct Visitor; impl DeserializationVisitor for Visitor { type Output = Style; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, members: impl Iterator, @@ -1615,7 +1615,7 @@ impl Deserializable for Suspicious { struct Visitor; impl DeserializationVisitor for Visitor { type Output = Suspicious; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, members: impl Iterator, diff --git a/crates/biome_service/src/configuration/parse/json/vcs.rs b/crates/biome_service/src/configuration/parse/json/vcs.rs index e26dd86f0854..06c09c0fd364 100644 --- a/crates/biome_service/src/configuration/parse/json/vcs.rs +++ b/crates/biome_service/src/configuration/parse/json/vcs.rs @@ -2,7 +2,7 @@ use crate::configuration::vcs::{VcsClientKind, VcsConfiguration}; use biome_console::markup; use biome_deserialize::{ Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, - ExpectedType, + VisitableType, }; use biome_rowan::TokenText; @@ -19,7 +19,7 @@ struct VcsConfigurationVisitor; impl DeserializationVisitor for VcsConfigurationVisitor { type Output = VcsConfiguration; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, diff --git a/crates/biome_service/tests/invalid/files_ignore_incorrect_type.json.snap b/crates/biome_service/tests/invalid/files_ignore_incorrect_type.json.snap index 59627854398b..7467ed7addcc 100644 --- a/crates/biome_service/tests/invalid/files_ignore_incorrect_type.json.snap +++ b/crates/biome_service/tests/invalid/files_ignore_incorrect_type.json.snap @@ -4,7 +4,7 @@ expression: files_ignore_incorrect_type.json --- files_ignore_incorrect_type.json:3:13 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected an array. + × Incorrect type, expected an array, but received a string. 1 │ { 2 │ "files": { diff --git a/crates/biome_service/tests/invalid/files_ignore_incorrect_value.json.snap b/crates/biome_service/tests/invalid/files_ignore_incorrect_value.json.snap index 7fc58134025b..be4f34ad2d38 100644 --- a/crates/biome_service/tests/invalid/files_ignore_incorrect_value.json.snap +++ b/crates/biome_service/tests/invalid/files_ignore_incorrect_value.json.snap @@ -4,7 +4,7 @@ expression: files_ignore_incorrect_value.json --- files_ignore_incorrect_value.json:3:25 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected a string. + × Incorrect type, expected a string, but received a boolean. 1 │ { 2 │ "files": { diff --git a/crates/biome_service/tests/invalid/files_include_incorrect_type.json.snap b/crates/biome_service/tests/invalid/files_include_incorrect_type.json.snap index f546623d7474..b9118631a18c 100644 --- a/crates/biome_service/tests/invalid/files_include_incorrect_type.json.snap +++ b/crates/biome_service/tests/invalid/files_include_incorrect_type.json.snap @@ -4,7 +4,7 @@ expression: files_include_incorrect_type.json --- files_include_incorrect_type.json:3:14 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected an array. + × Incorrect type, expected an array, but received a string. 1 │ { 2 │ "files": { diff --git a/crates/biome_service/tests/invalid/files_incorrect_type.json.snap b/crates/biome_service/tests/invalid/files_incorrect_type.json.snap index 4aa7a6b0ff7a..23790b8b05f7 100644 --- a/crates/biome_service/tests/invalid/files_incorrect_type.json.snap +++ b/crates/biome_service/tests/invalid/files_incorrect_type.json.snap @@ -4,7 +4,7 @@ expression: files_incorrect_type.json --- files_incorrect_type.json:2:11 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected an object. + × Incorrect type, expected an object, but received a string. 1 │ { > 2 │ "files": "wrong" diff --git a/crates/biome_service/tests/invalid/files_incorrect_type_for_value.json.snap b/crates/biome_service/tests/invalid/files_incorrect_type_for_value.json.snap index 26bf3b0b623f..2f1b42b3d00e 100644 --- a/crates/biome_service/tests/invalid/files_incorrect_type_for_value.json.snap +++ b/crates/biome_service/tests/invalid/files_incorrect_type_for_value.json.snap @@ -4,7 +4,7 @@ expression: files_incorrect_type_for_value.json --- files_incorrect_type_for_value.json:3:14 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected a number. + × Incorrect type, expected a number, but received a string. 1 │ { 2 │ "files": { diff --git a/crates/biome_service/tests/invalid/formatter_format_with_errors_incorrect_type.json.snap b/crates/biome_service/tests/invalid/formatter_format_with_errors_incorrect_type.json.snap index 90c5bb74b8af..3cfedeac40b2 100644 --- a/crates/biome_service/tests/invalid/formatter_format_with_errors_incorrect_type.json.snap +++ b/crates/biome_service/tests/invalid/formatter_format_with_errors_incorrect_type.json.snap @@ -4,7 +4,7 @@ expression: formatter_format_with_errors_incorrect_type.json --- formatter_format_with_errors_incorrect_type.json:3:23 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected a boolean. + × Incorrect type, expected a boolean, but received a string. 1 │ { 2 │ "formatter": { diff --git a/crates/biome_service/tests/invalid/formatter_incorrect_type.json.snap b/crates/biome_service/tests/invalid/formatter_incorrect_type.json.snap index 058ce0f82bf7..10224104cb08 100644 --- a/crates/biome_service/tests/invalid/formatter_incorrect_type.json.snap +++ b/crates/biome_service/tests/invalid/formatter_incorrect_type.json.snap @@ -4,7 +4,7 @@ expression: formatter_incorrect_type.json --- formatter_incorrect_type.json:2:15 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected an object. + × Incorrect type, expected an object, but received a string. 1 │ { > 2 │ "formatter": "string" diff --git a/crates/biome_service/tests/invalid/organize_imports.json.snap b/crates/biome_service/tests/invalid/organize_imports.json.snap index 4a7fe6760193..0eb905458522 100644 --- a/crates/biome_service/tests/invalid/organize_imports.json.snap +++ b/crates/biome_service/tests/invalid/organize_imports.json.snap @@ -4,7 +4,7 @@ expression: organize_imports.json --- organize_imports.json:3:14 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected a boolean. + × Incorrect type, expected a boolean, but received a string. 1 │ { 2 │ "organizeImports": { diff --git a/crates/biome_service/tests/invalid/overrides/incorrect_type.json.snap b/crates/biome_service/tests/invalid/overrides/incorrect_type.json.snap index a6dba44c0f8f..3c604a2fd981 100644 --- a/crates/biome_service/tests/invalid/overrides/incorrect_type.json.snap +++ b/crates/biome_service/tests/invalid/overrides/incorrect_type.json.snap @@ -4,7 +4,7 @@ expression: incorrect_type.json --- incorrect_type.json:2:15 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected an array. + × Incorrect type, expected an array, but received an object. 1 │ { > 2 │ "overrides": {} diff --git a/crates/biome_service/tests/invalid/overrides/incorrect_value_javascript.json.snap b/crates/biome_service/tests/invalid/overrides/incorrect_value_javascript.json.snap index 9410ab4e1417..003eec4d4a09 100644 --- a/crates/biome_service/tests/invalid/overrides/incorrect_value_javascript.json.snap +++ b/crates/biome_service/tests/invalid/overrides/incorrect_value_javascript.json.snap @@ -4,7 +4,7 @@ expression: incorrect_value_javascript.json --- incorrect_value_javascript.json:4:18 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected an object. + × Incorrect type, expected an object, but received an array. 2 │ "overrides": [ 3 │ { diff --git a/crates/biome_service/tests/invalid/schema.json.snap b/crates/biome_service/tests/invalid/schema.json.snap index c536fef43dae..ee7b92704443 100644 --- a/crates/biome_service/tests/invalid/schema.json.snap +++ b/crates/biome_service/tests/invalid/schema.json.snap @@ -4,7 +4,7 @@ expression: schema.json --- schema.json:2:13 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected a string. + × Incorrect type, expected a string, but received a boolean. 1 │ { > 2 │ "$schema": false diff --git a/crates/biome_service/tests/invalid/vcs_incorrect_type.json.snap b/crates/biome_service/tests/invalid/vcs_incorrect_type.json.snap index e6ebee8ad80a..e6993a903053 100644 --- a/crates/biome_service/tests/invalid/vcs_incorrect_type.json.snap +++ b/crates/biome_service/tests/invalid/vcs_incorrect_type.json.snap @@ -4,7 +4,7 @@ expression: vcs_incorrect_type.json --- vcs_incorrect_type.json:5:20 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected a boolean. + × Incorrect type, expected a boolean, but received a string. 3 │ "enabled": true, 4 │ "clientKind": "git", diff --git a/crates/biome_service/tests/invalid/vcs_missing_client.json.snap b/crates/biome_service/tests/invalid/vcs_missing_client.json.snap index 73b073ed02d7..43e7c77f655d 100644 --- a/crates/biome_service/tests/invalid/vcs_missing_client.json.snap +++ b/crates/biome_service/tests/invalid/vcs_missing_client.json.snap @@ -4,7 +4,7 @@ expression: vcs_missing_client.json --- vcs_missing_client.json:4:20 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected a boolean. + × Incorrect type, expected a boolean, but received a string. 2 │ "vcs": { 3 │ "enabled": true, diff --git a/crates/biome_service/tests/invalid/wrong_extends_incorrect_items.json.snap b/crates/biome_service/tests/invalid/wrong_extends_incorrect_items.json.snap index e918bde918f6..01913468b39b 100644 --- a/crates/biome_service/tests/invalid/wrong_extends_incorrect_items.json.snap +++ b/crates/biome_service/tests/invalid/wrong_extends_incorrect_items.json.snap @@ -4,7 +4,7 @@ expression: wrong_extends_incorrect_items.json --- wrong_extends_incorrect_items.json:2:32 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected a string. + × Incorrect type, expected a string, but received a number. 1 │ { > 2 │ "extends": ["something.json", 3, false, null] @@ -17,7 +17,7 @@ wrong_extends_incorrect_items.json:2:32 deserialize ━━━━━━━━━ wrong_extends_incorrect_items.json:2:35 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected a string. + × Incorrect type, expected a string, but received a boolean. 1 │ { > 2 │ "extends": ["something.json", 3, false, null] @@ -30,7 +30,7 @@ wrong_extends_incorrect_items.json:2:35 deserialize ━━━━━━━━━ wrong_extends_incorrect_items.json:2:42 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected a string. + × Incorrect type, expected a string, but received null. 1 │ { > 2 │ "extends": ["something.json", 3, false, null] diff --git a/crates/biome_service/tests/invalid/wrong_extends_type.json.snap b/crates/biome_service/tests/invalid/wrong_extends_type.json.snap index ba063620c941..c0adddf6c9aa 100644 --- a/crates/biome_service/tests/invalid/wrong_extends_type.json.snap +++ b/crates/biome_service/tests/invalid/wrong_extends_type.json.snap @@ -4,7 +4,7 @@ expression: wrong_extends_type.json --- wrong_extends_type.json:2:13 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Incorrect type, expected an array. + × Incorrect type, expected an array, but received a string. 1 │ { > 2 │ "extends": "something" diff --git a/xtask/codegen/src/generate_configuration.rs b/xtask/codegen/src/generate_configuration.rs index b21c1bb23a70..58cb9322b85e 100644 --- a/xtask/codegen/src/generate_configuration.rs +++ b/xtask/codegen/src/generate_configuration.rs @@ -305,7 +305,7 @@ pub(crate) fn generate_rules_configuration(mode: Mode) -> Result<()> { use crate::configuration::linter::*; use crate::Rules; use biome_console::markup; - use biome_deserialize::{Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, ExpectedType}; + use biome_deserialize::{Deserializable, DeserializableValue, DeserializationDiagnostic, DeserializationVisitor, VisitableType}; use biome_rowan::{TextRange, TokenText}; impl Deserializable for Rules { @@ -316,7 +316,7 @@ pub(crate) fn generate_rules_configuration(mode: Mode) -> Result<()> { struct Visitor; impl DeserializationVisitor for Visitor { type Output =Rules; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, members: impl Iterator, @@ -691,7 +691,7 @@ fn generate_visitor(group: &str, rules: &BTreeMap<&'static str, RuleMetadata>) - struct Visitor; impl DeserializationVisitor for Visitor { type Output =#group_struct_name; - const EXPECTED_TYPE: ExpectedType = ExpectedType::MAP; + const EXPECTED_TYPE: VisitableType = VisitableType::MAP; fn visit_map( self, members: impl Iterator,