Skip to content

Commit 023c160

Browse files
committed
feat(linter): impl Serialize for OxlintConfig (#5594)
Re-creation of #5331
1 parent 28aad28 commit 023c160

File tree

12 files changed

+246
-32
lines changed

12 files changed

+246
-32
lines changed

crates/oxc_linter/src/config/env.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ use std::{borrow::Borrow, hash::Hash};
22

33
use rustc_hash::FxHashMap;
44
use schemars::JsonSchema;
5-
use serde::Deserialize;
5+
use serde::{Deserialize, Serialize};
66

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

1616
impl OxlintEnv {

crates/oxc_linter/src/config/globals.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::{borrow, fmt, hash};
22

33
use rustc_hash::FxHashMap;
44
use schemars::JsonSchema;
5-
use serde::{de::Visitor, Deserialize};
5+
use serde::{de::Visitor, Deserialize, Serialize};
66

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

44-
#[derive(Debug, Clone, Copy, PartialEq, Eq, JsonSchema)]
44+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, JsonSchema)]
4545
#[serde(rename_all = "lowercase")]
4646
pub enum GlobalValue {
4747
Readonly,

crates/oxc_linter/src/config/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::path::Path;
88
use oxc_diagnostics::OxcDiagnostic;
99
use rustc_hash::FxHashSet;
1010
use schemars::JsonSchema;
11-
use serde::Deserialize;
11+
use serde::{Deserialize, Serialize};
1212

1313
pub use self::{
1414
env::OxlintEnv,
@@ -53,7 +53,7 @@ use crate::{
5353
/// }
5454
/// }
5555
/// ```
56-
#[derive(Debug, Default, Deserialize, JsonSchema)]
56+
#[derive(Debug, Default, Deserialize, Serialize, JsonSchema)]
5757
#[serde(default)]
5858
pub struct OxlintConfig {
5959
/// See [Oxlint Rules](https://oxc.rs/docs/guide/usage/linter/rules.html).

crates/oxc_linter/src/config/rules.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use rustc_hash::FxHashMap;
55
use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
66
use serde::{
77
de::{self, Deserializer, Visitor},
8-
Deserialize,
8+
ser::SerializeMap,
9+
Deserialize, Serialize,
910
};
1011

1112
use crate::{
@@ -58,6 +59,32 @@ impl JsonSchema for OxlintRules {
5859
}
5960
}
6061

62+
impl Serialize for OxlintRules {
63+
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
64+
where
65+
S: serde::Serializer,
66+
{
67+
let mut rules = s.serialize_map(Some(self.len()))?;
68+
69+
for rule in &self.0 {
70+
let key = rule.full_name();
71+
match rule.config.as_ref() {
72+
// e.g. unicorn/some-rule: ["warn", { foo: "bar" }]
73+
Some(config) if !config.is_null() => {
74+
let value = (rule.severity.as_str(), config);
75+
rules.serialize_entry(&key, &value)?;
76+
}
77+
// e.g. unicorn/some-rule: "warn"
78+
_ => {
79+
rules.serialize_entry(&key, rule.severity.as_str())?;
80+
}
81+
}
82+
}
83+
84+
rules.end()
85+
}
86+
}
87+
6188
// Manually implement Deserialize because the type is a bit complex...
6289
// - Handle single value form and array form
6390
// - SeverityConf into AllowWarnDeny
@@ -174,6 +201,18 @@ fn failed_to_parse_rule_value(value: &str, err: &str) -> OxcDiagnostic {
174201
OxcDiagnostic::error(format!("Failed to rule value {value:?} with error {err:?}"))
175202
}
176203

204+
impl ESLintRule {
205+
/// Returns `<plugin_name>/<rule_name>` for non-eslint rules. For eslint rules, returns
206+
/// `<rule_name>`. This is effectively the inverse operation for [`parse_rule_key`].
207+
fn full_name(&self) -> Cow<'_, str> {
208+
if self.plugin_name == "eslint" {
209+
Cow::Borrowed(self.rule_name.as_str())
210+
} else {
211+
Cow::Owned(format!("{}/{}", self.plugin_name, self.rule_name))
212+
}
213+
}
214+
}
215+
177216
#[cfg(test)]
178217
mod test {
179218
use serde::Deserialize;

crates/oxc_linter/src/config/settings/jsdoc.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ use std::borrow::Cow;
22

33
use rustc_hash::FxHashMap;
44
use schemars::JsonSchema;
5-
use serde::Deserialize;
5+
use serde::{Deserialize, Serialize};
66

77
use crate::utils::default_true;
88

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

183-
#[derive(Clone, Debug, Deserialize, JsonSchema)]
183+
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
184184
#[serde(untagged)]
185185
enum TagNamePreference {
186186
TagNameOnly(String),

crates/oxc_linter/src/config/settings/jsx_a11y.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use oxc_span::CompactStr;
22
use rustc_hash::FxHashMap;
33
use schemars::JsonSchema;
4-
use serde::Deserialize;
4+
use serde::{Deserialize, Serialize};
55

66
// <https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#configurations>
7-
#[derive(Debug, Deserialize, Default, JsonSchema)]
7+
#[derive(Debug, Deserialize, Default, Serialize, JsonSchema)]
88
pub struct JSXA11yPluginSettings {
99
#[serde(rename = "polymorphicPropName")]
1010
pub polymorphic_prop_name: Option<CompactStr>,

crates/oxc_linter/src/config/settings/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ mod next;
44
mod react;
55

66
use schemars::JsonSchema;
7-
use serde::Deserialize;
7+
use serde::{Deserialize, Serialize};
88

99
use self::{
1010
jsdoc::JSDocPluginSettings, jsx_a11y::JSXA11yPluginSettings, next::NextPluginSettings,
1111
react::ReactPluginSettings,
1212
};
1313

1414
/// Shared settings for plugins
15-
#[derive(Debug, Deserialize, Default, JsonSchema)]
15+
#[derive(Debug, Deserialize, Serialize, Default, JsonSchema)]
1616
pub struct OxlintSettings {
1717
#[serde(default)]
1818
#[serde(rename = "jsx-a11y")]

crates/oxc_linter/src/config/settings/next.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::borrow::Cow;
22

33
use schemars::JsonSchema;
4-
use serde::Deserialize;
4+
use serde::{Deserialize, Serialize, Serializer};
55

6-
#[derive(Debug, Deserialize, Default, JsonSchema)]
6+
#[derive(Debug, Deserialize, Default, Serialize, JsonSchema)]
77
pub struct NextPluginSettings {
88
#[serde(default)]
99
#[serde(rename = "rootDir")]
@@ -27,8 +27,21 @@ enum OneOrMany<T> {
2727
One(T),
2828
Many(Vec<T>),
2929
}
30+
3031
impl<T> Default for OneOrMany<T> {
3132
fn default() -> Self {
3233
OneOrMany::Many(Vec::new())
3334
}
3435
}
36+
37+
impl<T: Serialize> Serialize for OneOrMany<T> {
38+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
39+
where
40+
S: Serializer,
41+
{
42+
match self {
43+
Self::One(val) => val.serialize(serializer),
44+
Self::Many(vec) => vec.serialize(serializer),
45+
}
46+
}
47+
}

crates/oxc_linter/src/config/settings/react.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ use std::borrow::Cow;
22

33
use oxc_span::CompactStr;
44
use schemars::JsonSchema;
5-
use serde::Deserialize;
5+
use serde::{Deserialize, Serialize};
66

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

3131
// Deserialize helper types
3232

33-
#[derive(Clone, Debug, Deserialize, JsonSchema)]
33+
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
3434
#[serde(untagged)]
3535
enum CustomComponent {
3636
NameOnly(CompactStr),

crates/oxc_linter/src/options/allow_warn_deny.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ impl AllowWarnDeny {
1919
pub fn is_allow(self) -> bool {
2020
self == Self::Allow
2121
}
22+
23+
pub fn as_str(self) -> &'static str {
24+
match self {
25+
Self::Allow => "allow",
26+
Self::Warn => "warn",
27+
Self::Deny => "deny",
28+
}
29+
}
2230
}
2331

2432
impl TryFrom<&str> for AllowWarnDeny {

0 commit comments

Comments
 (0)