From d658225bbe8b9b5ff861bcb4e5e584371c992d7f Mon Sep 17 00:00:00 2001 From: Justinas Delinda <8914032+minht11@users.noreply.github.com> Date: Tue, 10 Sep 2024 13:21:51 +0300 Subject: [PATCH] feat(linter): make noRestrictedTypes common options simpler (#3819) --- .../src/lint/nursery/no_restricted_types.rs | 74 ++++++++++++++++--- .../invalidCustom.options.json | 4 +- .../@biomejs/biome/configuration_schema.json | 6 ++ 3 files changed, 71 insertions(+), 13 deletions(-) diff --git a/crates/biome_js_analyze/src/lint/nursery/no_restricted_types.rs b/crates/biome_js_analyze/src/lint/nursery/no_restricted_types.rs index dbe0e325b35c..9e126d6b946c 100644 --- a/crates/biome_js_analyze/src/lint/nursery/no_restricted_types.rs +++ b/crates/biome_js_analyze/src/lint/nursery/no_restricted_types.rs @@ -5,7 +5,9 @@ use biome_analyze::{ declare_lint_rule, ActionCategory, Ast, FixKind, Rule, RuleDiagnostic, RuleSource, }; use biome_console::markup; -use biome_deserialize_macros::Deserializable; +use biome_deserialize::{ + Deserializable, DeserializableType, DeserializableValue, DeserializationDiagnostic, +}; use biome_js_factory::make; use biome_js_syntax::TsReferenceType; use biome_rowan::AstNode; @@ -37,15 +39,13 @@ declare_lint_rule! { /// "message": "Only bar is allowed", /// "use": "bar" /// }, - /// "OldAPI": { - /// "message": "Use NewAPI instead" - /// } + /// "OldAPI": "Use NewAPI instead" /// } /// } /// } /// ``` /// - /// In the example above, the rule will emit a diagnostics if tried to use `Foo` or `OldAPI` are used. + /// In the example above, the rule will emit a diagnostics if `Foo` or `OldAPI` are used. /// pub NoRestrictedTypes { version: "next", @@ -61,7 +61,7 @@ declare_lint_rule! { impl Rule for NoRestrictedTypes { type Query = Ast; - type State = CustomRestrictedType; + type State = CustomRestrictedTypeOptions; type Signals = Option; type Options = NoRestrictedTypesOptions; @@ -76,7 +76,7 @@ impl Rule for NoRestrictedTypes { let restricted_type = options.types.get(token_name)?.clone(); - Some(restricted_type) + Some(restricted_type.into()) } fn diagnostic(ctx: &RuleContext, state: &Self::State) -> Option { @@ -113,18 +113,72 @@ impl Rule for NoRestrictedTypes { } } -#[derive(Clone, Debug, Default, Deserializable, Deserialize, Serialize, Eq, PartialEq)] +#[derive( + Clone, + Debug, + Default, + biome_deserialize_macros::Deserializable, + Deserialize, + Serialize, + Eq, + PartialEq, +)] #[cfg_attr(feature = "schemars", derive(JsonSchema))] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct NoRestrictedTypesOptions { types: FxHashMap, } -#[derive(Debug, Clone, Default, Deserializable, Deserialize, Serialize, Eq, PartialEq)] +#[derive( + Debug, + Clone, + Default, + biome_deserialize_macros::Deserializable, + Deserialize, + Serialize, + Eq, + PartialEq, +)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct CustomRestrictedType { +pub struct CustomRestrictedTypeOptions { message: String, #[serde(rename = "use")] use_instead: Option, } + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[serde(untagged)] +pub enum CustomRestrictedType { + Plain(String), + WithOptions(CustomRestrictedTypeOptions), +} + +impl From for CustomRestrictedTypeOptions { + fn from(options: CustomRestrictedType) -> Self { + match options { + CustomRestrictedType::Plain(message) => CustomRestrictedTypeOptions { + message, + use_instead: None, + }, + CustomRestrictedType::WithOptions(options) => options, + } + } +} + +impl Deserializable for CustomRestrictedType { + fn deserialize( + value: &impl DeserializableValue, + name: &str, + diagnostics: &mut Vec, + ) -> Option { + if value.visitable_type()? == DeserializableType::Str { + biome_deserialize::Deserializable::deserialize(value, name, diagnostics) + .map(Self::Plain) + } else { + biome_deserialize::Deserializable::deserialize(value, name, diagnostics) + .map(Self::WithOptions) + } + } +} diff --git a/crates/biome_js_analyze/tests/specs/nursery/noRestrictedTypes/invalidCustom.options.json b/crates/biome_js_analyze/tests/specs/nursery/noRestrictedTypes/invalidCustom.options.json index a5aefa4941dd..68b3cc5b905f 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/noRestrictedTypes/invalidCustom.options.json +++ b/crates/biome_js_analyze/tests/specs/nursery/noRestrictedTypes/invalidCustom.options.json @@ -12,9 +12,7 @@ "message": "Only CustomType2 is allowed", "use": "CustomType2" }, - "Bar": { - "message": "Replace Bar with Foo" - }, + "Bar": "Replace Bar with Foo", "InvalidUse": { "message": "Do not use this type", "use": "@" diff --git a/packages/@biomejs/biome/configuration_schema.json b/packages/@biomejs/biome/configuration_schema.json index 6293a65a63c2..3f8871f0a11a 100644 --- a/packages/@biomejs/biome/configuration_schema.json +++ b/packages/@biomejs/biome/configuration_schema.json @@ -1062,6 +1062,12 @@ "additionalProperties": false }, "CustomRestrictedType": { + "anyOf": [ + { "type": "string" }, + { "$ref": "#/definitions/CustomRestrictedTypeOptions" } + ] + }, + "CustomRestrictedTypeOptions": { "type": "object", "required": ["message"], "properties": {