Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(linter): impl Serialize for OxlintConfig #5594

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/oxc_linter/src/config/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ use std::{borrow::Borrow, hash::Hash};

use rustc_hash::FxHashMap;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::{Deserialize, Serialize};

/// Predefine global variables.
///
/// Environments specify what global variables are predefined. See [ESLint's
/// list of
/// environments](https://eslint.org/docs/v8.x/use/configure/language-options#specifying-environments)
/// for what environments are available and what each one provides.
#[derive(Debug, Clone, Deserialize, JsonSchema)]
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct OxlintEnv(FxHashMap<String, bool>);

impl OxlintEnv {
Expand Down
6 changes: 3 additions & 3 deletions crates/oxc_linter/src/config/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{borrow, fmt, hash};

use rustc_hash::FxHashMap;
use schemars::JsonSchema;
use serde::{de::Visitor, Deserialize};
use serde::{de::Visitor, Deserialize, Serialize};

/// Add or remove global variables.
///
Expand All @@ -29,7 +29,7 @@ use serde::{de::Visitor, Deserialize};
/// You may also use `"readable"` or `false` to represent `"readonly"`, and
/// `"writeable"` or `true` to represent `"writable"`.
// <https://eslint.org/docs/v8.x/use/configure/language-options#using-configuration-files-1>
#[derive(Debug, Default, Deserialize, JsonSchema)]
#[derive(Debug, Default, Deserialize, Serialize, JsonSchema)]
pub struct OxlintGlobals(FxHashMap<String, GlobalValue>);
impl OxlintGlobals {
pub fn is_enabled<Q>(&self, name: &Q) -> bool
Expand All @@ -41,7 +41,7 @@ impl OxlintGlobals {
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, JsonSchema)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum GlobalValue {
Readonly,
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_linter/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::path::Path;
use oxc_diagnostics::OxcDiagnostic;
use rustc_hash::FxHashSet;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::{Deserialize, Serialize};

pub use self::{
env::OxlintEnv,
Expand Down Expand Up @@ -53,7 +53,7 @@ use crate::{
/// }
/// }
/// ```
#[derive(Debug, Default, Deserialize, JsonSchema)]
#[derive(Debug, Default, Deserialize, Serialize, JsonSchema)]
#[serde(default)]
pub struct OxlintConfig {
/// See [Oxlint Rules](https://oxc.rs/docs/guide/usage/linter/rules.html).
Expand Down
41 changes: 40 additions & 1 deletion crates/oxc_linter/src/config/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use rustc_hash::FxHashMap;
use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
use serde::{
de::{self, Deserializer, Visitor},
Deserialize,
ser::SerializeMap,
Deserialize, Serialize,
};

use crate::{
Expand Down Expand Up @@ -58,6 +59,32 @@ impl JsonSchema for OxlintRules {
}
}

impl Serialize for OxlintRules {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut rules = s.serialize_map(Some(self.len()))?;

for rule in &self.0 {
let key = rule.full_name();
match rule.config.as_ref() {
// e.g. unicorn/some-rule: ["warn", { foo: "bar" }]
Some(config) if !config.is_null() => {
let value = (rule.severity.as_str(), config);
rules.serialize_entry(&key, &value)?;
}
// e.g. unicorn/some-rule: "warn"
_ => {
rules.serialize_entry(&key, rule.severity.as_str())?;
}
}
}

rules.end()
}
}

// Manually implement Deserialize because the type is a bit complex...
// - Handle single value form and array form
// - SeverityConf into AllowWarnDeny
Expand Down Expand Up @@ -174,6 +201,18 @@ fn failed_to_parse_rule_value(value: &str, err: &str) -> OxcDiagnostic {
OxcDiagnostic::error(format!("Failed to rule value {value:?} with error {err:?}"))
}

impl ESLintRule {
/// Returns `<plugin_name>/<rule_name>` for non-eslint rules. For eslint rules, returns
/// `<rule_name>`. This is effectively the inverse operation for [`parse_rule_key`].
fn full_name(&self) -> Cow<'_, str> {
if self.plugin_name == "eslint" {
Cow::Borrowed(self.rule_name.as_str())
} else {
Cow::Owned(format!("{}/{}", self.plugin_name, self.rule_name))
}
}
}

#[cfg(test)]
mod test {
use serde::Deserialize;
Expand Down
6 changes: 3 additions & 3 deletions crates/oxc_linter/src/config/settings/jsdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ use std::borrow::Cow;

use rustc_hash::FxHashMap;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::{Deserialize, Serialize};

use crate::utils::default_true;

// <https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/settings.md>
#[derive(Debug, Deserialize, JsonSchema)]
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct JSDocPluginSettings {
/// For all rules but NOT apply to `check-access` and `empty-tags` rule
#[serde(default, rename = "ignorePrivate")]
Expand Down Expand Up @@ -180,7 +180,7 @@ impl JSDocPluginSettings {
}
}

#[derive(Clone, Debug, Deserialize, JsonSchema)]
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
#[serde(untagged)]
enum TagNamePreference {
TagNameOnly(String),
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_linter/src/config/settings/jsx_a11y.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use oxc_span::CompactStr;
use rustc_hash::FxHashMap;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::{Deserialize, Serialize};

// <https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#configurations>
#[derive(Debug, Deserialize, Default, JsonSchema)]
#[derive(Debug, Deserialize, Default, Serialize, JsonSchema)]
pub struct JSXA11yPluginSettings {
#[serde(rename = "polymorphicPropName")]
pub polymorphic_prop_name: Option<CompactStr>,
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_linter/src/config/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ mod next;
mod react;

use schemars::JsonSchema;
use serde::Deserialize;
use serde::{Deserialize, Serialize};

use self::{
jsdoc::JSDocPluginSettings, jsx_a11y::JSXA11yPluginSettings, next::NextPluginSettings,
react::ReactPluginSettings,
};

/// Shared settings for plugins
#[derive(Debug, Deserialize, Default, JsonSchema)]
#[derive(Debug, Deserialize, Serialize, Default, JsonSchema)]
pub struct OxlintSettings {
#[serde(default)]
#[serde(rename = "jsx-a11y")]
Expand Down
17 changes: 15 additions & 2 deletions crates/oxc_linter/src/config/settings/next.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::borrow::Cow;

use schemars::JsonSchema;
use serde::Deserialize;
use serde::{Deserialize, Serialize, Serializer};

#[derive(Debug, Deserialize, Default, JsonSchema)]
#[derive(Debug, Deserialize, Default, Serialize, JsonSchema)]
pub struct NextPluginSettings {
#[serde(default)]
#[serde(rename = "rootDir")]
Expand All @@ -27,8 +27,21 @@ enum OneOrMany<T> {
One(T),
Many(Vec<T>),
}

impl<T> Default for OneOrMany<T> {
fn default() -> Self {
OneOrMany::Many(Vec::new())
}
}

impl<T: Serialize> Serialize for OneOrMany<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Self::One(val) => val.serialize(serializer),
Self::Many(vec) => vec.serialize(serializer),
}
}
}
6 changes: 3 additions & 3 deletions crates/oxc_linter/src/config/settings/react.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ use std::borrow::Cow;

use oxc_span::CompactStr;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::{Deserialize, Serialize};

// <https://github.com/jsx-eslint/eslint-plugin-react#configuration-legacy-eslintrc->
#[derive(Debug, Deserialize, Default, JsonSchema)]
#[derive(Debug, Deserialize, Default, Serialize, JsonSchema)]
pub struct ReactPluginSettings {
#[serde(default)]
#[serde(rename = "formComponents")]
Expand All @@ -30,7 +30,7 @@ impl ReactPluginSettings {

// Deserialize helper types

#[derive(Clone, Debug, Deserialize, JsonSchema)]
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
#[serde(untagged)]
enum CustomComponent {
NameOnly(CompactStr),
Expand Down
8 changes: 8 additions & 0 deletions crates/oxc_linter/src/options/allow_warn_deny.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ impl AllowWarnDeny {
pub fn is_allow(self) -> bool {
self == Self::Allow
}

pub fn as_str(self) -> &'static str {
match self {
Self::Allow => "allow",
Self::Warn => "warn",
Self::Deny => "deny",
}
}
}

impl TryFrom<&str> for AllowWarnDeny {
Expand Down
Loading