mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(linter): start adding json schema for configuration file (#3375)
This commit is contained in:
parent
1e84644220
commit
fe208ddef6
12 changed files with 146 additions and 63 deletions
45
Cargo.lock
generated
45
Cargo.lock
generated
|
|
@ -435,6 +435,12 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.11.0"
|
||||
|
|
@ -1437,6 +1443,7 @@ dependencies = [
|
|||
"regex",
|
||||
"rust-lapper",
|
||||
"rustc-hash",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"static_assertions",
|
||||
|
|
@ -2171,6 +2178,31 @@ dependencies = [
|
|||
"hashlink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0218ceea14babe24a4a5836f86ade86c1effbc198164e619194cb5069187e29"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"indexmap",
|
||||
"schemars_derive",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed5a1ccce8ff962e31a165d41f6e2a2dd1245099dc4d594f5574a86cd90f4d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals 0.29.1",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
|
|
@ -2231,6 +2263,17 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.117"
|
||||
|
|
@ -2699,7 +2742,7 @@ checksum = "7a94b0f0954b3e59bfc2c246b4c8574390d94a4ad4ad246aaf2fb07d7dfd3b47"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"serde_derive_internals 0.28.0",
|
||||
"syn",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ unicode-width = "0.1.12"
|
|||
saphyr = "0.0.1"
|
||||
base64-simd = "0.8"
|
||||
cfg-if = "1.0.0"
|
||||
schemars = "0.8.20"
|
||||
|
||||
[workspace.metadata.cargo-shear]
|
||||
ignored = ["napi", "oxc_traverse"]
|
||||
|
|
|
|||
|
|
@ -30,26 +30,25 @@ oxc_syntax = { workspace = true }
|
|||
oxc_codegen = { workspace = true }
|
||||
oxc_resolver = { workspace = true }
|
||||
|
||||
rayon = { workspace = true }
|
||||
lazy_static = { workspace = true } # used in oxc_macros
|
||||
serde_json = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
regex = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
phf = { workspace = true, features = ["macros"] }
|
||||
itertools = { workspace = true }
|
||||
dashmap = { workspace = true }
|
||||
convert_case = { workspace = true }
|
||||
language-tags = { workspace = true }
|
||||
mime_guess = { workspace = true }
|
||||
url = { workspace = true }
|
||||
|
||||
rayon = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
regex = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
phf = { workspace = true, features = ["macros"] }
|
||||
itertools = { workspace = true }
|
||||
dashmap = { workspace = true }
|
||||
convert_case = { workspace = true }
|
||||
language-tags = { workspace = true }
|
||||
mime_guess = { workspace = true }
|
||||
url = { workspace = true }
|
||||
rust-lapper = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
memchr = { workspace = true }
|
||||
json-strip-comments = { workspace = true }
|
||||
|
||||
static_assertions = { workspace = true }
|
||||
schemars = { workspace = true, features = ["indexmap2"] }
|
||||
static_assertions = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
use rustc_hash::FxHashMap;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Environment
|
||||
/// <https://eslint.org/docs/latest/use/configure/language-options#using-configuration-files>
|
||||
///
|
||||
/// TS type is `Record<string, boolean>`
|
||||
/// <https://github.com/eslint/eslint/blob/ce838adc3b673e52a151f36da0eedf5876977514/lib/shared/types.js#L40>
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
// TODO: list the keys we support
|
||||
#[derive(Debug, Clone, Deserialize, JsonSchema)]
|
||||
pub struct ESLintEnv(FxHashMap<String, bool>);
|
||||
|
||||
impl ESLintEnv {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
/// <https://eslint.org/docs/v8.x/use/configure/language-options#using-configuration-files-1>
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
#[derive(Debug, Default, Deserialize, JsonSchema)]
|
||||
pub struct ESLintGlobals(FxHashMap<String, GlobalValue>);
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Deserialize)]
|
||||
// TODO: support deprecated `false`
|
||||
#[derive(Debug, Eq, PartialEq, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum GlobalValue {
|
||||
Readonly,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use std::path::Path;
|
|||
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use rustc_hash::FxHashSet;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{rules::RuleEnum, AllowWarnDeny, RuleWithSeverity};
|
||||
|
|
@ -17,8 +18,8 @@ pub use self::{
|
|||
};
|
||||
|
||||
/// ESLint Config
|
||||
/// <https://eslint.org/docs/v8.x/use/configure/configuration-files>
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
// <https://eslint.org/docs/v8.x/use/configure/configuration-files>
|
||||
#[derive(Debug, Default, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
pub struct ESLintConfig {
|
||||
pub(crate) rules: ESLintRules,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
use crate::AllowWarnDeny;
|
||||
use oxc_diagnostics::{Error, OxcDiagnostic};
|
||||
use serde::de::{self, Deserializer, Visitor};
|
||||
use serde::Deserialize;
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use std::{borrow::Cow, fmt, ops::Deref};
|
||||
|
||||
/// The `rules` field from ESLint config
|
||||
///
|
||||
/// TS type is `Record<string, RuleConf>`
|
||||
/// - type SeverityConf = 0 | 1 | 2 | "off" | "warn" | "error";
|
||||
/// - type RuleConf = SeverityConf | [SeverityConf, ...any[]];
|
||||
/// <https://github.com/eslint/eslint/blob/ce838adc3b673e52a151f36da0eedf5876977514/lib/shared/types.js#L12>
|
||||
use oxc_diagnostics::{Error, OxcDiagnostic};
|
||||
use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
|
||||
use serde::{
|
||||
de::{self, Deserializer, Visitor},
|
||||
Deserialize,
|
||||
};
|
||||
|
||||
use crate::AllowWarnDeny;
|
||||
|
||||
// The `rules` field from ESLint config
|
||||
//
|
||||
// TS type is `Record<string, RuleConf>`
|
||||
// - type SeverityConf = 0 | 1 | 2 | "off" | "warn" | "error";
|
||||
// - type RuleConf = SeverityConf | [SeverityConf, ...any[]];
|
||||
// <https://github.com/eslint/eslint/blob/ce838adc3b673e52a151f36da0eedf5876977514/lib/shared/types.js#L12>
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ESLintRules(Vec<ESLintRule>);
|
||||
|
||||
|
|
@ -22,6 +26,29 @@ pub struct ESLintRule {
|
|||
pub config: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
impl JsonSchema for ESLintRules {
|
||||
fn schema_name() -> String {
|
||||
"ESLintRules".to_owned()
|
||||
}
|
||||
|
||||
fn schema_id() -> Cow<'static, str> {
|
||||
Cow::Borrowed("ESLintRules")
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Clone, JsonSchema)]
|
||||
#[serde(untagged)]
|
||||
enum DummyRule {
|
||||
#[schemars(range(min = 0, max = 2.0))]
|
||||
Number(usize),
|
||||
String(String),
|
||||
Array(Vec<serde_json::Value>),
|
||||
}
|
||||
DummyRule::json_schema(gen)
|
||||
}
|
||||
}
|
||||
|
||||
// Manually implement Deserialize because the type is a bit complex...
|
||||
// - Handle single value form and array form
|
||||
// - SeverityConf into AllowWarnDeny
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
use rustc_hash::FxHashMap;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
/// <https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/settings.md>
|
||||
#[derive(Debug, Deserialize)]
|
||||
// <https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/settings.md>
|
||||
#[derive(Debug, Deserialize, JsonSchema)]
|
||||
pub struct JSDocPluginSettings {
|
||||
/// For all rules but NOT apply to `check-access` and `empty-tags` rule
|
||||
#[serde(default, rename = "ignorePrivate")]
|
||||
pub ignore_private: bool,
|
||||
|
||||
/// For all rules but NOT apply to `empty-tags` rule
|
||||
#[serde(default, rename = "ignoreInternal")]
|
||||
pub ignore_internal: bool,
|
||||
|
|
@ -14,12 +16,15 @@ pub struct JSDocPluginSettings {
|
|||
/// Only for `require-(yields|returns|description|example|param|throws)` rule
|
||||
#[serde(default = "default_true", rename = "ignoreReplacesDocs")]
|
||||
pub ignore_replaces_docs: bool,
|
||||
|
||||
/// Only for `require-(yields|returns|description|example|param|throws)` rule
|
||||
#[serde(default = "default_true", rename = "overrideReplacesDocs")]
|
||||
pub override_replaces_docs: bool,
|
||||
|
||||
/// Only for `require-(yields|returns|description|example|param|throws)` rule
|
||||
#[serde(default, rename = "augmentsExtendsReplacesDocs")]
|
||||
pub augments_extends_replaces_docs: bool,
|
||||
|
||||
/// Only for `require-(yields|returns|description|example|param|throws)` rule
|
||||
#[serde(default, rename = "implementsReplacesDocs")]
|
||||
pub implements_replaces_docs: bool,
|
||||
|
|
@ -173,7 +178,7 @@ fn default_true() -> bool {
|
|||
true
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[derive(Clone, Debug, Deserialize, JsonSchema)]
|
||||
#[serde(untagged)]
|
||||
enum TagNamePreference {
|
||||
TagNameOnly(String),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use rustc_hash::FxHashMap;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
/// <https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#configurations>
|
||||
#[derive(Debug, Deserialize, Default)]
|
||||
// <https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#configurations>
|
||||
#[derive(Debug, Deserialize, Default, JsonSchema)]
|
||||
pub struct JSXA11yPluginSettings {
|
||||
#[serde(rename = "polymorphicPropName")]
|
||||
pub polymorphic_prop_name: Option<String>,
|
||||
|
|
|
|||
|
|
@ -1,29 +1,34 @@
|
|||
use self::{
|
||||
jsdoc::JSDocPluginSettings, jsx_a11y::JSXA11yPluginSettings, next::NextPluginSettings,
|
||||
react::ReactPluginSettings,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
pub mod jsdoc;
|
||||
mod jsx_a11y;
|
||||
mod next;
|
||||
mod react;
|
||||
|
||||
/// The `settings` field from ESLint config
|
||||
/// An object containing name-value pairs of information that should be available to all rules
|
||||
///
|
||||
/// TS type is `Object`
|
||||
/// <https://github.com/eslint/eslint/blob/ce838adc3b673e52a151f36da0eedf5876977514/lib/shared/types.js#L53>
|
||||
/// But each plugin extends this with their own properties.
|
||||
#[derive(Debug, Deserialize, Default)]
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use self::{
|
||||
jsdoc::JSDocPluginSettings, jsx_a11y::JSXA11yPluginSettings, next::NextPluginSettings,
|
||||
react::ReactPluginSettings,
|
||||
};
|
||||
|
||||
// The `settings` field from ESLint config
|
||||
// An object containing name-value pairs of information that should be available to all rules
|
||||
//
|
||||
// TS type is `Object`
|
||||
// <https://github.com/eslint/eslint/blob/ce838adc3b673e52a151f36da0eedf5876977514/lib/shared/types.js#L53>
|
||||
// But each plugin extends this with their own properties.
|
||||
#[derive(Debug, Deserialize, Default, JsonSchema)]
|
||||
pub struct ESLintSettings {
|
||||
#[serde(default)]
|
||||
#[serde(rename = "jsx-a11y")]
|
||||
pub jsx_a11y: JSXA11yPluginSettings,
|
||||
|
||||
#[serde(default)]
|
||||
pub next: NextPluginSettings,
|
||||
|
||||
#[serde(default)]
|
||||
pub react: ReactPluginSettings,
|
||||
|
||||
#[serde(default)]
|
||||
pub jsdoc: JSDocPluginSettings,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
/// <https://nextjs.org/docs/pages/building-your-application/configuring/eslint#eslint-plugin>
|
||||
#[derive(Debug, Deserialize, Default)]
|
||||
#[derive(Debug, Deserialize, Default, JsonSchema)]
|
||||
pub struct NextPluginSettings {
|
||||
#[serde(default)]
|
||||
#[serde(rename = "rootDir")]
|
||||
|
|
@ -19,7 +19,7 @@ impl NextPluginSettings {
|
|||
|
||||
// Deserialize helper types
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, JsonSchema)]
|
||||
#[serde(untagged)]
|
||||
enum OneOrMany<T> {
|
||||
One(T),
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
/// <https://github.com/jsx-eslint/eslint-plugin-react#configuration-legacy-eslintrc->
|
||||
#[derive(Debug, Deserialize, Default)]
|
||||
// <https://github.com/jsx-eslint/eslint-plugin-react#configuration-legacy-eslintrc->
|
||||
#[derive(Debug, Deserialize, Default, JsonSchema)]
|
||||
pub struct ReactPluginSettings {
|
||||
#[serde(default)]
|
||||
#[serde(rename = "formComponents")]
|
||||
form_components: Vec<CustomComponent>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(rename = "linkComponents")]
|
||||
link_components: Vec<CustomComponent>,
|
||||
|
|
@ -24,7 +26,7 @@ impl ReactPluginSettings {
|
|||
|
||||
// Deserialize helper types
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[derive(Clone, Debug, Deserialize, JsonSchema)]
|
||||
#[serde(untagged)]
|
||||
enum CustomComponent {
|
||||
NameOnly(String),
|
||||
|
|
|
|||
Loading…
Reference in a new issue