Skip to content

Commit

Permalink
feat(linter): configure by category in config files
Browse files Browse the repository at this point in the history
> closes #5454

Adds a `categories` property to config files, where each key is a `RuleCategory` and each value is `"allow"/"off"`, `"warn"`, or `"deny"/"error"`.

Note that this change won't come into effect until after #6088 is merged.
  • Loading branch information
DonIsaac committed Sep 27, 2024
1 parent 5b9cb7e commit 055e407
Show file tree
Hide file tree
Showing 8 changed files with 251 additions and 2 deletions.
7 changes: 6 additions & 1 deletion crates/oxc_linter/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ impl LinterBuilder {
/// ```
pub fn from_oxlintrc(start_empty: bool, oxlintrc: Oxlintrc) -> Self {
// TODO: monorepo config merging, plugin-based extends, etc.
let Oxlintrc { plugins, settings, env, globals, rules: oxlintrc_rules } = oxlintrc;
let Oxlintrc { plugins, settings, env, globals, categories, rules: oxlintrc_rules } =
oxlintrc;

let config = LintConfig { settings, env, globals };
let options = LintOptions { plugins, ..Default::default() };
Expand All @@ -79,6 +80,10 @@ impl LinterBuilder {
let cache = RulesCache::new(options.plugins);
let mut builder = Self { rules, options, config, cache };

if !categories.is_empty() {
builder = builder.with_filters(categories.filters());
}

{
let all_rules = builder.cache.borrow();
oxlintrc_rules.override_rules(&mut builder.rules, all_rules.as_slice());
Expand Down
88 changes: 88 additions & 0 deletions crates/oxc_linter/src/config/categories.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use std::{borrow::Cow, ops::Deref};

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

use crate::{AllowWarnDeny, LintFilter, RuleCategory};

/// Configure an entire category of rules all at once.
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct OxlintCategories(FxHashMap<RuleCategory, AllowWarnDeny>);

impl Deref for OxlintCategories {
type Target = FxHashMap<RuleCategory, AllowWarnDeny>;

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

impl OxlintCategories {
#[must_use]
pub fn filters(&self) -> impl Iterator<Item = LintFilter> + '_ {
self.iter().map(|(category, severity)| LintFilter::new(*severity, *category).unwrap())
}
}

impl JsonSchema for OxlintCategories {
fn schema_id() -> Cow<'static, str> {
Cow::Borrowed("OxlintCategories")
}

fn schema_name() -> String {
"OxlintCategories".to_string()
}

fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
let severity = gen.subschema_for::<AllowWarnDeny>();
let mut schema =
gen.subschema_for::<FxHashMap<RuleCategory, AllowWarnDeny>>().into_object();

{
let obj = &mut schema.object();
let properties = &mut obj.properties;

obj.additional_properties = None;

properties.insert(RuleCategory::Correctness.as_str().to_string(), severity.clone());
properties.insert(RuleCategory::Suspicious.as_str().to_string(), severity.clone());
properties.insert(RuleCategory::Pedantic.as_str().to_string(), severity.clone());
properties.insert(RuleCategory::Perf.as_str().to_string(), severity.clone());
properties.insert(RuleCategory::Style.as_str().to_string(), severity.clone());
properties.insert(RuleCategory::Restriction.as_str().to_string(), severity.clone());
properties.insert(RuleCategory::Nursery.as_str().to_string(), severity.clone());
}

{
let metadata = &mut schema.metadata();
metadata.title = Some("Rule Categories".to_string());

metadata.description = Some(
r#"
Configure an entire category of rules all at once.
Rules enabled or disabled this way will be overwritten by individual rules in the `rules` field.
# Example
```json
{
"categories": {
"correctness": "warn"
},
"rules": {
"eslint/no-unused-vars": "error"
}
}
```
"#
.trim()
.to_string(),
);

metadata.examples = vec![serde_json::json!({ "correctness": "warn" })];
}

schema.into()
}
}
1 change: 1 addition & 0 deletions crates/oxc_linter/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod categories;
mod env;
mod globals;
mod oxlintrc;
Expand Down
6 changes: 5 additions & 1 deletion crates/oxc_linter/src/config/oxlintrc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use oxc_diagnostics::OxcDiagnostic;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use super::{env::OxlintEnv, globals::OxlintGlobals, rules::OxlintRules, settings::OxlintSettings};
use super::{
categories::OxlintCategories, env::OxlintEnv, globals::OxlintGlobals, rules::OxlintRules,
settings::OxlintSettings,
};

use crate::{options::LintPlugins, utils::read_to_string};

Expand Down Expand Up @@ -45,6 +48,7 @@ use crate::{options::LintPlugins, utils::read_to_string};
#[non_exhaustive]
pub struct Oxlintrc {
pub plugins: LintPlugins,
pub categories: OxlintCategories,
/// See [Oxlint Rules](https://oxc.rs/docs/guide/usage/linter/rules.html).
pub rules: OxlintRules,
pub settings: OxlintSettings,
Expand Down
12 changes: 12 additions & 0 deletions crates/oxc_linter/src/rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,18 @@ impl RuleCategory {
Self::Nursery => "New lints that are still under development.",
}
}

pub fn as_str(self) -> &'static str {
match self {
Self::Correctness => "correctness",
Self::Suspicious => "suspicious",
Self::Pedantic => "pedantic",
Self::Perf => "perf",
Self::Style => "style",
Self::Restriction => "restriction",
Self::Nursery => "nursery",
}
}
}

impl TryFrom<&str> for RuleCategory {
Expand Down
41 changes: 41 additions & 0 deletions crates/oxc_linter/src/snapshots/schema_json.snap
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ expression: json
"description": "Oxlint Configuration File\n\nThis configuration is aligned with ESLint v8's configuration schema (`eslintrc.json`).\n\nUsage: `oxlint -c oxlintrc.json --import-plugin`\n\n::: danger NOTE\n\nOnly the `.json` format is supported. You can use comments in configuration files.\n\n:::\n\nExample\n\n`.oxlintrc.json`\n\n```json { \"env\": { \"browser\": true }, \"globals\": { \"foo\": \"readonly\" }, \"settings\": { }, \"rules\": { \"eqeqeq\": \"warn\", \"import/no-cycle\": \"error\" } } ```",
"type": "object",
"properties": {
"categories": {
"default": {},
"allOf": [
{
"$ref": "#/definitions/OxlintCategories"
}
]
},
"env": {
"description": "Environments enable and disable collections of global variables.",
"default": {
Expand Down Expand Up @@ -267,6 +275,39 @@ expression: json
}
]
},
"OxlintCategories": {
"title": "Rule Categories",
"description": "Configure an entire category of rules all at once.\n\nRules enabled or disabled this way will be overwritten by individual rules in the `rules` field.\n\n# Example\n```json\n{\n \"categories\": {\n \"correctness\": \"warn\"\n },\n \"rules\": {\n \"eslint/no-unused-vars\": \"error\"\n }\n}\n```",
"examples": [
{
"correctness": "warn"
}
],
"type": "object",
"properties": {
"correctness": {
"$ref": "#/definitions/AllowWarnDeny"
},
"nursery": {
"$ref": "#/definitions/AllowWarnDeny"
},
"pedantic": {
"$ref": "#/definitions/AllowWarnDeny"
},
"perf": {
"$ref": "#/definitions/AllowWarnDeny"
},
"restriction": {
"$ref": "#/definitions/AllowWarnDeny"
},
"style": {
"$ref": "#/definitions/AllowWarnDeny"
},
"suspicious": {
"$ref": "#/definitions/AllowWarnDeny"
}
}
},
"OxlintEnv": {
"description": "Predefine global variables.\n\nEnvironments 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.",
"type": "object",
Expand Down
41 changes: 41 additions & 0 deletions npm/oxlint/configuration_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
"description": "Oxlint Configuration File\n\nThis configuration is aligned with ESLint v8's configuration schema (`eslintrc.json`).\n\nUsage: `oxlint -c oxlintrc.json --import-plugin`\n\n::: danger NOTE\n\nOnly the `.json` format is supported. You can use comments in configuration files.\n\n:::\n\nExample\n\n`.oxlintrc.json`\n\n```json { \"env\": { \"browser\": true }, \"globals\": { \"foo\": \"readonly\" }, \"settings\": { }, \"rules\": { \"eqeqeq\": \"warn\", \"import/no-cycle\": \"error\" } } ```",
"type": "object",
"properties": {
"categories": {
"default": {},
"allOf": [
{
"$ref": "#/definitions/OxlintCategories"
}
]
},
"env": {
"description": "Environments enable and disable collections of global variables.",
"default": {
Expand Down Expand Up @@ -263,6 +271,39 @@
}
]
},
"OxlintCategories": {
"title": "Rule Categories",
"description": "Configure an entire category of rules all at once.\n\nRules enabled or disabled this way will be overwritten by individual rules in the `rules` field.\n\n# Example\n```json\n{\n \"categories\": {\n \"correctness\": \"warn\"\n },\n \"rules\": {\n \"eslint/no-unused-vars\": \"error\"\n }\n}\n```",
"examples": [
{
"correctness": "warn"
}
],
"type": "object",
"properties": {
"correctness": {
"$ref": "#/definitions/AllowWarnDeny"
},
"nursery": {
"$ref": "#/definitions/AllowWarnDeny"
},
"pedantic": {
"$ref": "#/definitions/AllowWarnDeny"
},
"perf": {
"$ref": "#/definitions/AllowWarnDeny"
},
"restriction": {
"$ref": "#/definitions/AllowWarnDeny"
},
"style": {
"$ref": "#/definitions/AllowWarnDeny"
},
"suspicious": {
"$ref": "#/definitions/AllowWarnDeny"
}
}
},
"OxlintEnv": {
"description": "Predefine global variables.\n\nEnvironments 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.",
"type": "object",
Expand Down
57 changes: 57 additions & 0 deletions tasks/website/src/linter/snapshots/schema_markdown.snap
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,63 @@ Example
```


## categories

type: `object`




### categories.correctness






### categories.nursery






### categories.pedantic






### categories.perf






### categories.restriction






### categories.style






### categories.suspicious







## env

type: `object`
Expand Down

0 comments on commit 055e407

Please sign in to comment.