mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
refactor(linter): add schemars and serde traits to AllowWarnDeny and RuleCategories (#6119)
This commit is contained in:
parent
40bd919849
commit
82b8f217ab
2 changed files with 151 additions and 10 deletions
|
|
@ -1,10 +1,15 @@
|
|||
use std::{convert::From, fmt};
|
||||
use std::{
|
||||
convert::From,
|
||||
fmt::{self, Display},
|
||||
};
|
||||
|
||||
use oxc_diagnostics::{OxcDiagnostic, Severity};
|
||||
use schemars::{schema::SchemaObject, JsonSchema};
|
||||
use serde::{de, Deserialize, Serialize};
|
||||
use serde_json::{Number, Value};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AllowWarnDeny {
|
||||
Allow, // Off
|
||||
Warn, // Warn
|
||||
|
|
@ -65,18 +70,89 @@ impl TryFrom<&Value> for AllowWarnDeny {
|
|||
}
|
||||
}
|
||||
|
||||
fn invalid_int_severity<D: Display>(value: D) -> OxcDiagnostic {
|
||||
OxcDiagnostic::error(format!(
|
||||
r#"Failed to parse rule severity, expected one of `0`, `1` or `2`, but got {value}"#
|
||||
))
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for AllowWarnDeny {
|
||||
type Error = OxcDiagnostic;
|
||||
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(Self::Allow),
|
||||
1 => Ok(Self::Warn),
|
||||
2 => Ok(Self::Deny),
|
||||
x => Err(invalid_int_severity(x)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<i64> for AllowWarnDeny {
|
||||
type Error = OxcDiagnostic;
|
||||
|
||||
fn try_from(value: i64) -> Result<Self, Self::Error> {
|
||||
if value < 0 {
|
||||
return Err(invalid_int_severity("a negative number"));
|
||||
}
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
Self::try_from(value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Number> for AllowWarnDeny {
|
||||
type Error = OxcDiagnostic;
|
||||
|
||||
fn try_from(value: &Number) -> Result<Self, Self::Error> {
|
||||
match value.as_i64() {
|
||||
Some(0) => Ok(Self::Allow),
|
||||
Some(1) => Ok(Self::Warn),
|
||||
Some(2) => Ok(Self::Deny),
|
||||
_ => Err(OxcDiagnostic::error(format!(
|
||||
r#"Failed to parse rule severity, expected one of `0`, `1` or `2`, but got {value:?}"#
|
||||
))),
|
||||
let value = value.as_i64().ok_or_else(|| invalid_int_severity(value))?;
|
||||
Self::try_from(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for AllowWarnDeny {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
{
|
||||
struct AllowWarnDenyVisitor;
|
||||
|
||||
impl<'de> de::Visitor<'de> for AllowWarnDenyVisitor {
|
||||
type Value = AllowWarnDeny;
|
||||
|
||||
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
"an int between 0 and 2 or a string".fmt(f)
|
||||
}
|
||||
|
||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Self::Value::try_from(v).map_err(de::Error::custom)
|
||||
}
|
||||
|
||||
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Self::Value::try_from(v).map_err(de::Error::custom)
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Self::Value::try_from(v).map_err(de::Error::custom)
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Self::Value::try_from(v.as_str()).map_err(de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(AllowWarnDenyVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -128,3 +204,43 @@ impl From<AllowWarnDeny> for Severity {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialize() {
|
||||
let tests = [
|
||||
(AllowWarnDeny::Allow, r#""allow""#),
|
||||
(AllowWarnDeny::Warn, r#""warn""#),
|
||||
(AllowWarnDeny::Deny, r#""deny""#),
|
||||
];
|
||||
for (input, expected) in tests {
|
||||
assert_eq!(serde_json::to_string(&input).unwrap(), expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize() {
|
||||
let tests = [
|
||||
// allow
|
||||
(r#""allow""#, AllowWarnDeny::Allow),
|
||||
(r#""off""#, AllowWarnDeny::Allow),
|
||||
("0", AllowWarnDeny::Allow),
|
||||
// warn
|
||||
(r#""warn""#, AllowWarnDeny::Warn),
|
||||
("1", AllowWarnDeny::Warn),
|
||||
// deny
|
||||
(r#""error""#, AllowWarnDeny::Deny),
|
||||
(r#""deny""#, AllowWarnDeny::Deny),
|
||||
("2", AllowWarnDeny::Deny),
|
||||
];
|
||||
|
||||
for (input, expected) in tests {
|
||||
let msg = format!("input: {input}");
|
||||
let actual: AllowWarnDeny = serde_json::from_str(input).expect(&msg);
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use std::{
|
|||
};
|
||||
|
||||
use oxc_semantic::SymbolId;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
|
|
@ -61,7 +63,8 @@ pub trait RuleMeta {
|
|||
}
|
||||
|
||||
/// Rule categories defined by rust-clippy
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum RuleCategory {
|
||||
/// Code that is outright wrong or useless
|
||||
Correctness,
|
||||
|
|
@ -277,6 +280,7 @@ impl RuleWithSeverity {
|
|||
mod test {
|
||||
use markdown::{to_html_with_options, Options};
|
||||
|
||||
use super::RuleCategory;
|
||||
use crate::rules::RULES;
|
||||
|
||||
#[test]
|
||||
|
|
@ -295,4 +299,25 @@ mod test {
|
|||
assert!(!html.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_rule_category() {
|
||||
let tests = [
|
||||
("correctness", RuleCategory::Correctness),
|
||||
("suspicious", RuleCategory::Suspicious),
|
||||
("restriction", RuleCategory::Restriction),
|
||||
("perf", RuleCategory::Perf),
|
||||
("pedantic", RuleCategory::Pedantic),
|
||||
("style", RuleCategory::Style),
|
||||
("nursery", RuleCategory::Nursery),
|
||||
];
|
||||
|
||||
for (input, expected) in tests {
|
||||
let de: RuleCategory = serde_json::from_str(&format!("{input:?}")).unwrap();
|
||||
// deserializes to expected value
|
||||
assert_eq!(de, expected, "{input}");
|
||||
// try_from on a str produces the same value as deserializing
|
||||
assert_eq!(de, RuleCategory::try_from(input).unwrap(), "{input}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue