Skip to content

Commit

Permalink
feat(linter): implement Serialize for OxlintConfig
Browse files Browse the repository at this point in the history
  • Loading branch information
DonIsaac committed Aug 30, 2024
1 parent a512edc commit f38a5c1
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 27 deletions.
4 changes: 2 additions & 2 deletions crates/oxc_linter/src/config/env.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use rustc_hash::FxHashMap;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::{Serialize, Deserialize};
use std::{borrow::Borrow, hash::Hash};

/// Predefine global variables.
Expand All @@ -9,7 +9,7 @@ use std::{borrow::Borrow, hash::Hash};
/// 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, Serialize, Deserialize, 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
@@ -1,6 +1,6 @@
use rustc_hash::FxHashMap;
use schemars::JsonSchema;
use serde::{de::Visitor, Deserialize};
use serde::{de::Visitor, Serialize, Deserialize};
use std::{borrow, fmt, hash};

/// Add or remove global variables.
Expand Down Expand Up @@ -28,7 +28,7 @@ use std::{borrow, fmt, hash};
/// 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, Serialize, Deserialize, JsonSchema)]
pub struct OxlintGlobals(FxHashMap<String, GlobalValue>);
impl OxlintGlobals {
pub fn is_enabled<Q>(&self, name: &Q) -> bool
Expand All @@ -40,7 +40,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
57 changes: 48 additions & 9 deletions 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 All @@ -29,6 +30,14 @@ pub struct ESLintRule {
pub config: Option<serde_json::Value>,
}

impl Deref for OxlintRules {
type Target = Vec<ESLintRule>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl JsonSchema for OxlintRules {
fn schema_name() -> String {
"OxlintRules".to_owned()
Expand Down Expand Up @@ -58,6 +67,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 @@ -162,18 +197,22 @@ fn parse_rule_value(
}
}

impl Deref for OxlintRules {
type Target = Vec<ESLintRule>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

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 @@ -3,10 +3,10 @@ use std::borrow::Cow;
use crate::utils::default_true;
use rustc_hash::FxHashMap;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::{Serialize, Deserialize};

// <https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/settings.md>
#[derive(Debug, Deserialize, JsonSchema)]
#[derive(Debug, Serialize, Deserialize, 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 @@ -179,7 +179,7 @@ impl JSDocPluginSettings {
}
}

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

// <https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#configurations>
#[derive(Debug, Deserialize, Default, JsonSchema)]
#[derive(Debug, Default, Serialize, Deserialize, JsonSchema)]
#[serde(default)]
pub struct JSXA11yPluginSettings {
#[serde(rename = "polymorphicPropName")]
pub polymorphic_prop_name: Option<CompactStr>,
#[serde(default)]
pub components: FxHashMap<CompactStr, CompactStr>,
}
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::{Serialize, Deserialize};

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

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

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

#[derive(Debug, Deserialize, Default, JsonSchema)]
#[derive(Debug, Default, Serialize, Deserialize, JsonSchema)]
pub struct NextPluginSettings {
#[serde(default)]
#[serde(rename = "rootDir")]
Expand All @@ -27,8 +28,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::{Serialize, Deserialize};

// <https://github.com/jsx-eslint/eslint-plugin-react#configuration-legacy-eslintrc->
#[derive(Debug, Deserialize, Default, JsonSchema)]
#[derive(Debug, Default, Serialize, Deserialize, 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, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
enum CustomComponent {
NameOnly(CompactStr),
Expand Down

0 comments on commit f38a5c1

Please sign in to comment.