Skip to content

Commit

Permalink
refactor(linter-config): remove dead code and deduplicate code (#612)
Browse files Browse the repository at this point in the history
  • Loading branch information
Conaclos authored Oct 27, 2023
1 parent ed2a5ac commit 55a7aee
Show file tree
Hide file tree
Showing 9 changed files with 1,177 additions and 4,178 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ impl Default for ComplexityOptions {
}
}

// Required by [Bpaf].
impl FromStr for ComplexityOptions {
type Err = ();

Expand Down
142 changes: 35 additions & 107 deletions crates/biome_js_analyze/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,15 @@ use crate::semantic_analyzers::style::use_naming_convention::{
};
use biome_analyze::options::RuleOptions;
use biome_analyze::RuleKey;
use biome_deserialize::json::VisitJsonNode;
use biome_deserialize::{DeserializationDiagnostic, VisitNode};
use biome_json_syntax::{AnyJsonValue, JsonLanguage, JsonMemberName, JsonObjectValue};
use biome_rowan::AstNode;
use biome_json_syntax::JsonLanguage;
use bpaf::Bpaf;
#[cfg(feature = "schemars")]
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::str::FromStr;

#[derive(Default, Deserialize, Serialize, Debug, Eq, PartialEq, Clone, Bpaf)]
#[derive(Deserialize, Serialize, Debug, Eq, PartialEq, Clone, Bpaf)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields, untagged)]
pub enum PossibleOptions {
Expand All @@ -36,20 +34,36 @@ pub enum PossibleOptions {
NamingConvention(#[bpaf(external(naming_convention_options), hide)] NamingConventionOptions),
/// Options for `noRestrictedGlobals` rule
RestrictedGlobals(#[bpaf(external(restricted_globals_options), hide)] RestrictedGlobalsOptions),
/// No options available
#[default]
NoOptions,
}

// Required by [Bpaf].
impl FromStr for PossibleOptions {
type Err = ();

fn from_str(_s: &str) -> Result<Self, Self::Err> {
Ok(Self::NoOptions)
Ok(Self::Complexity(ComplexityOptions::default()))
}
}

impl PossibleOptions {
pub fn new_from_rule_name(rule_name: &str) -> Option<Self> {
match rule_name {
"noExcessiveCognitiveComplexity" => {
Some(Self::Complexity(ComplexityOptions::default()))
}
"noRestrictedGlobals" => {
Some(Self::RestrictedGlobals(RestrictedGlobalsOptions::default()))
}
"useExhaustiveDependencies" | "useHookAtTopLevel" => {
Some(Self::Hooks(HooksOptions::default()))
}
"useNamingConvention" => {
Some(Self::NamingConvention(NamingConventionOptions::default()))
}
_ => None,
}
}

pub fn extract_option(&self, rule_key: &RuleKey) -> RuleOptions {
match rule_key.rule_name() {
"noExcessiveCognitiveComplexity" => {
Expand Down Expand Up @@ -86,113 +100,27 @@ impl PossibleOptions {
}
}

impl PossibleOptions {
pub fn map_to_rule_options(
impl VisitNode<JsonLanguage> for PossibleOptions {
fn visit_map(
&mut self,
value: &AnyJsonValue,
name: &str,
rule_name: &str,
key: &biome_rowan::SyntaxNode<JsonLanguage>,
value: &biome_rowan::SyntaxNode<JsonLanguage>,
diagnostics: &mut Vec<DeserializationDiagnostic>,
) -> Option<()> {
let value = JsonObjectValue::cast_ref(value.syntax()).or_else(|| {
diagnostics.push(DeserializationDiagnostic::new_incorrect_type_for_value(
name,
"object",
value.range(),
));
None
})?;
for element in value.json_member_list() {
let element = element.ok()?;
let key = element.name().ok()?;
let value = element.value().ok()?;
let name = key.inner_string_text().ok()?;
self.validate_key(&key, rule_name, diagnostics)?;
match name.text() {
"hooks" => {
let mut options = HooksOptions::default();
self.map_to_array(&value, &name, &mut options, diagnostics)?;
*self = PossibleOptions::Hooks(options);
}
"maxAllowedComplexity" => {
let mut options = ComplexityOptions::default();
options.visit_map(key.syntax(), value.syntax(), diagnostics)?;
*self = PossibleOptions::Complexity(options);
}
"strictCase" | "enumMemberCase" => {
let mut options = match self {
PossibleOptions::NamingConvention(options) => options.clone(),
_ => NamingConventionOptions::default(),
};
options.visit_map(key.syntax(), value.syntax(), diagnostics)?;
*self = PossibleOptions::NamingConvention(options);
}

"deniedGlobals" => {
let mut options = match self {
PossibleOptions::RestrictedGlobals(options) => options.clone(),
_ => RestrictedGlobalsOptions::default(),
};
options.visit_map(key.syntax(), value.syntax(), diagnostics)?;
*self = PossibleOptions::RestrictedGlobals(options);
}
_ => (),
match self {
PossibleOptions::Complexity(options) => {
options.visit_map(key, value, diagnostics)?;
}
}

Some(())
}

pub fn validate_key(
&mut self,
node: &JsonMemberName,
rule_name: &str,
diagnostics: &mut Vec<DeserializationDiagnostic>,
) -> Option<()> {
let key_name = node.inner_string_text().ok()?;
let key_name = key_name.text();
match rule_name {
"useExhaustiveDependencies" | "useHookAtTopLevel" => {
if key_name != "hooks" {
diagnostics.push(DeserializationDiagnostic::new_unknown_key(
key_name,
node.range(),
&["hooks"],
));
}
PossibleOptions::Hooks(options) => {
options.visit_map(key, value, diagnostics)?;
}
"useNamingConvention" => {
if !matches!(key_name, "strictCase" | "enumMemberCase") {
diagnostics.push(DeserializationDiagnostic::new_unknown_key(
key_name,
node.range(),
&["strictCase", "enumMemberCase"],
));
}
PossibleOptions::NamingConvention(options) => {
options.visit_map(key, value, diagnostics)?;
}
"noExcessiveComplexity" => {
if !matches!(key_name, "maxAllowedComplexity") {
diagnostics.push(DeserializationDiagnostic::new_unknown_key(
key_name,
node.range(),
&["maxAllowedComplexity"],
));
}
PossibleOptions::RestrictedGlobals(options) => {
options.visit_map(key, value, diagnostics)?;
}
"noRestrictedGlobals" => {
if !matches!(key_name, "deniedGlobals") {
diagnostics.push(DeserializationDiagnostic::new_unknown_key(
key_name,
node.range(),
&["deniedGlobals"],
));
}
}
_ => {}
}

Some(())
}
}

impl VisitNode<JsonLanguage> for PossibleOptions {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use biome_js_syntax::{
binding_ext::AnyJsBindingDeclaration, JsCallExpression, JsStaticMemberExpression, JsSyntaxKind,
JsSyntaxNode, JsVariableDeclaration, TextRange,
};
use biome_json_syntax::{AnyJsonValue, JsonLanguage, JsonSyntaxNode};
use biome_rowan::{AstNode, AstSeparatedList, SyntaxNode, SyntaxNodeCast};
use biome_json_syntax::{JsonLanguage, JsonSyntaxNode};
use biome_rowan::{AstNode, AstSeparatedList, SyntaxNodeCast};
use bpaf::Bpaf;
use rustc_hash::{FxHashMap, FxHashSet};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -278,6 +278,14 @@ impl VisitNode<JsonLanguage> for Hooks {
match name_text {
"name" => {
self.name = self.map_to_string(&value, name_text, diagnostics)?;
if self.name.is_empty() {
diagnostics.push(
DeserializationDiagnostic::new(markup!(
"The field "<Emphasis>"name"</Emphasis>" is mandatory"
))
.with_range(value.range()),
)
}
}
"closureIndex" => {
self.closure_index = self.map_to_usize(&value, name_text, usize::MAX, diagnostics);
Expand Down Expand Up @@ -310,27 +318,6 @@ impl VisitNode<JsonLanguage> for HooksOptions {
has_only_known_keys(node, &["hooks"], diagnostics)
}

fn visit_array_member(
&mut self,
element: &SyntaxNode<JsonLanguage>,
diagnostics: &mut Vec<DeserializationDiagnostic>,
) -> Option<()> {
let mut hook = Hooks::default();
let element = AnyJsonValue::cast_ref(element)?;
self.map_to_object(&element, "hooks", &mut hook, diagnostics)?;
if hook.name.is_empty() {
diagnostics.push(
DeserializationDiagnostic::new(markup!(
"The field "<Emphasis>"name"</Emphasis>" is mandatory"
))
.with_range(element.range()),
)
} else {
self.hooks.push(hook);
}
Some(())
}

fn visit_map(
&mut self,
key: &JsonSyntaxNode,
Expand All @@ -341,58 +328,19 @@ impl VisitNode<JsonLanguage> for HooksOptions {
let name_text = name.text();
if name_text == "hooks" {
let array = value.as_json_array_value()?;
if array.elements().len() < 1 {
diagnostics.push(
DeserializationDiagnostic::new("At least one element is needed")
.with_range(array.range()),
);
return Some(());
}

for element in array.elements() {
let element = element.ok()?;
let hook_array = element.as_json_array_value()?;

let len = hook_array.elements().len();
if len < 1 {
diagnostics.push(
DeserializationDiagnostic::new("At least one element is needed")
.with_range(hook_array.range()),
);
return Some(());
}
if len > 3 {
diagnostics.push(
DeserializationDiagnostic::new(
"Too many elements, maximum three are expected",
)
.with_range(hook_array.range()),
);
return Some(());
}
let mut elements = hook_array.elements().iter();
let hook_name = elements.next()?.ok()?;
let hook_name = hook_name
.as_json_string_value()
.ok_or_else(|| {
DeserializationDiagnostic::new_incorrect_type("string", hook_name.range())
})
.ok()?
.inner_string_text()
.ok()?
.to_string();

let closure_index = if let Some(element) = elements.next() {
let element = element.ok()?;
Some(self.map_to_u8(&element, name_text, u8::MAX, diagnostics)? as usize)
} else {
None
};
let dependencies_index = if let Some(element) = elements.next() {
let element = element.ok()?;
Some(self.map_to_u8(&element, name_text, u8::MAX, diagnostics)? as usize)
} else {
None
};

self.hooks.push(Hooks {
name: hook_name,
closure_index,
dependencies_index,
});
let mut hooks = Hooks::default();
self.map_to_object(&element, "hooks", &mut hooks, diagnostics)?;
self.hooks.push(hooks);
}
}
Some(())
Expand Down
Loading

0 comments on commit 55a7aee

Please sign in to comment.