mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
refactor(linter): improve the ergonomics around ESlintConfig (#3037)
This commit is contained in:
parent
d44301c871
commit
53c0ff5135
31 changed files with 168 additions and 186 deletions
|
|
@ -19,17 +19,18 @@ pub use self::{env::ESLintEnv, rules::ESLintRules, settings::ESLintSettings};
|
|||
|
||||
/// ESLint Config
|
||||
/// <https://eslint.org/docs/latest/use/configure/configuration-files-new#configuration-objects>
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct ESLintConfig {
|
||||
#[serde(default)]
|
||||
rules: ESLintRules,
|
||||
#[serde(default)]
|
||||
settings: ESLintSettings,
|
||||
#[serde(default)]
|
||||
env: ESLintEnv,
|
||||
pub(crate) rules: ESLintRules,
|
||||
pub(crate) settings: ESLintSettings,
|
||||
pub(crate) env: ESLintEnv,
|
||||
}
|
||||
|
||||
impl ESLintConfig {
|
||||
/// # Errors
|
||||
///
|
||||
/// * Parse Failure
|
||||
pub fn from_file(path: &Path) -> Result<Self, Report> {
|
||||
let mut string = std::fs::read_to_string(path).map_err(|e| {
|
||||
FailedToParseConfigError(vec![Error::new(FailedToOpenFileError(path.to_path_buf(), e))])
|
||||
|
|
@ -66,10 +67,6 @@ impl ESLintConfig {
|
|||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn properties(self) -> (ESLintSettings, ESLintEnv) {
|
||||
(self.settings, self.env)
|
||||
}
|
||||
|
||||
#[allow(clippy::option_if_let_else)]
|
||||
pub fn override_rules(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
disable_directives::{DisableDirectives, DisableDirectivesBuilder},
|
||||
fixer::{Fix, Message},
|
||||
javascript_globals::GLOBALS,
|
||||
ESLintEnv, ESLintSettings,
|
||||
ESLintConfig, ESLintEnv, ESLintSettings,
|
||||
};
|
||||
|
||||
pub struct LintContext<'a> {
|
||||
|
|
@ -26,9 +26,7 @@ pub struct LintContext<'a> {
|
|||
|
||||
file_path: Box<Path>,
|
||||
|
||||
settings: Arc<ESLintSettings>,
|
||||
|
||||
env: Arc<ESLintEnv>,
|
||||
pub eslint_config: Arc<ESLintConfig>,
|
||||
}
|
||||
|
||||
impl<'a> LintContext<'a> {
|
||||
|
|
@ -42,8 +40,7 @@ impl<'a> LintContext<'a> {
|
|||
fix: false,
|
||||
current_rule_name: "",
|
||||
file_path,
|
||||
settings: Arc::new(ESLintSettings::default()),
|
||||
env: Arc::new(ESLintEnv::default()),
|
||||
eslint_config: Arc::new(ESLintConfig::default()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,14 +51,8 @@ impl<'a> LintContext<'a> {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_settings(mut self, settings: &Arc<ESLintSettings>) -> Self {
|
||||
self.settings = Arc::clone(settings);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_env(mut self, env: &Arc<ESLintEnv>) -> Self {
|
||||
self.env = Arc::clone(env);
|
||||
pub fn with_eslint_config(mut self, eslint_config: &Arc<ESLintConfig>) -> Self {
|
||||
self.eslint_config = Arc::clone(eslint_config);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -73,10 +64,6 @@ impl<'a> LintContext<'a> {
|
|||
&self.disable_directives
|
||||
}
|
||||
|
||||
pub fn settings(&self) -> &ESLintSettings {
|
||||
&self.settings
|
||||
}
|
||||
|
||||
pub fn source_text(&self) -> &'a str {
|
||||
self.semantic().source_text()
|
||||
}
|
||||
|
|
@ -89,12 +76,16 @@ impl<'a> LintContext<'a> {
|
|||
&self.file_path
|
||||
}
|
||||
|
||||
pub fn envs(&self) -> &ESLintEnv {
|
||||
&self.env
|
||||
pub fn env(&self) -> &ESLintEnv {
|
||||
&self.eslint_config.env
|
||||
}
|
||||
|
||||
pub fn settings(&self) -> &ESLintSettings {
|
||||
&self.eslint_config.settings
|
||||
}
|
||||
|
||||
pub fn env_contains_var(&self, var: &str) -> bool {
|
||||
for env in self.env.iter() {
|
||||
for env in self.env().iter() {
|
||||
let env = GLOBALS.get(env).unwrap_or(&GLOBALS["builtin"]);
|
||||
if env.get(var).is_some() {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,12 @@ use std::{io::Write, rc::Rc, sync::Arc};
|
|||
|
||||
use oxc_diagnostics::Report;
|
||||
|
||||
pub use crate::{
|
||||
config::ESLintConfig,
|
||||
context::LintContext,
|
||||
options::{AllowWarnDeny, LintOptions},
|
||||
service::{LintService, LintServiceOptions},
|
||||
};
|
||||
use crate::{
|
||||
config::{ESLintEnv, ESLintSettings},
|
||||
fixer::Fix,
|
||||
|
|
@ -30,11 +36,6 @@ use crate::{
|
|||
rule::RuleCategory,
|
||||
rules::{RuleEnum, RULES},
|
||||
};
|
||||
pub use crate::{
|
||||
context::LintContext,
|
||||
options::{AllowWarnDeny, LintOptions},
|
||||
service::{LintService, LintServiceOptions},
|
||||
};
|
||||
use oxc_semantic::AstNode;
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
|
|
@ -52,8 +53,7 @@ fn size_asserts() {
|
|||
pub struct Linter {
|
||||
rules: Vec<(/* rule name */ &'static str, RuleEnum)>,
|
||||
options: LintOptions,
|
||||
settings: Arc<ESLintSettings>,
|
||||
env: Arc<ESLintEnv>,
|
||||
eslint_config: Arc<ESLintConfig>,
|
||||
}
|
||||
|
||||
impl Default for Linter {
|
||||
|
|
@ -67,9 +67,9 @@ impl Linter {
|
|||
///
|
||||
/// Returns `Err` if there are any errors parsing the configuration file.
|
||||
pub fn from_options(options: LintOptions) -> Result<Self, Report> {
|
||||
let (rules, settings, env) = options.derive_rules_and_settings_and_env()?;
|
||||
let (rules, eslint_config) = options.derive_rules_and_config()?;
|
||||
let rules = rules.into_iter().map(|rule| (rule.name(), rule)).collect();
|
||||
Ok(Self { rules, options, settings: Arc::new(settings), env: Arc::new(env) })
|
||||
Ok(Self { rules, options, eslint_config: Arc::new(eslint_config) })
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
|
@ -79,14 +79,14 @@ impl Linter {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_settings(mut self, settings: ESLintSettings) -> Self {
|
||||
self.settings = Arc::new(settings);
|
||||
pub fn with_eslint_config(mut self, eslint_config: ESLintConfig) -> Self {
|
||||
self.eslint_config = Arc::new(eslint_config);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_envs(mut self, env: ESLintEnv) -> Self {
|
||||
self.env = Arc::new(env);
|
||||
pub fn with_fix(mut self, yes: bool) -> Self {
|
||||
self.options.fix = yes;
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -98,16 +98,9 @@ impl Linter {
|
|||
self.rules.len()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_fix(mut self, yes: bool) -> Self {
|
||||
self.options.fix = yes;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn run<'a>(&self, ctx: LintContext<'a>) -> Vec<Message<'a>> {
|
||||
let semantic = Rc::clone(ctx.semantic());
|
||||
let mut ctx =
|
||||
ctx.with_fix(self.options.fix).with_settings(&self.settings).with_env(&self.env);
|
||||
let mut ctx = ctx.with_fix(self.options.fix).with_eslint_config(&self.eslint_config);
|
||||
|
||||
for (rule_name, rule) in &self.rules {
|
||||
ctx.with_rule_name(rule_name);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use rustc_hash::FxHashSet;
|
||||
use serde_json::{Number, Value};
|
||||
|
||||
use oxc_diagnostics::Error;
|
||||
|
||||
use crate::{
|
||||
config::{
|
||||
errors::{
|
||||
|
|
@ -9,11 +14,8 @@ use crate::{
|
|||
ESLintConfig,
|
||||
},
|
||||
rules::RULES,
|
||||
ESLintEnv, ESLintSettings, RuleCategory, RuleEnum,
|
||||
RuleCategory, RuleEnum,
|
||||
};
|
||||
use oxc_diagnostics::Error;
|
||||
use rustc_hash::FxHashSet;
|
||||
use serde_json::{Number, Value};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LintOptions {
|
||||
|
|
@ -29,7 +31,6 @@ pub struct LintOptions {
|
|||
pub jsx_a11y_plugin: bool,
|
||||
pub nextjs_plugin: bool,
|
||||
pub react_perf_plugin: bool,
|
||||
pub env: ESLintEnv,
|
||||
}
|
||||
|
||||
impl Default for LintOptions {
|
||||
|
|
@ -45,7 +46,6 @@ impl Default for LintOptions {
|
|||
jsx_a11y_plugin: false,
|
||||
nextjs_plugin: false,
|
||||
react_perf_plugin: false,
|
||||
env: ESLintEnv::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -112,12 +112,6 @@ impl LintOptions {
|
|||
self.react_perf_plugin = yes;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_env(mut self, env: Vec<String>) -> Self {
|
||||
self.env = ESLintEnv::from_vec(env);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
|
|
@ -186,9 +180,7 @@ impl LintOptions {
|
|||
/// # Errors
|
||||
///
|
||||
/// * Returns `Err` if there are any errors parsing the configuration file.
|
||||
pub fn derive_rules_and_settings_and_env(
|
||||
&self,
|
||||
) -> Result<(Vec<RuleEnum>, ESLintSettings, ESLintEnv), Error> {
|
||||
pub fn derive_rules_and_config(&self) -> Result<(Vec<RuleEnum>, ESLintConfig), Error> {
|
||||
let config =
|
||||
self.config_path.as_ref().map(|path| ESLintConfig::from_file(path)).transpose()?;
|
||||
|
||||
|
|
@ -238,12 +230,10 @@ impl LintOptions {
|
|||
|
||||
let mut rules = rules.into_iter().collect::<Vec<_>>();
|
||||
|
||||
let (settings, env) = config.map(ESLintConfig::properties).unwrap_or_default();
|
||||
|
||||
// for stable diagnostics output ordering
|
||||
rules.sort_unstable_by_key(RuleEnum::name);
|
||||
|
||||
Ok((rules, settings, env))
|
||||
Ok((rules, config.unwrap_or_default()))
|
||||
}
|
||||
|
||||
// get final filtered rules by reading `self.xxx_plugin`
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ fn test() {
|
|||
*
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
|
|
@ -123,7 +123,7 @@ fn test() {
|
|||
* @access public
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
|
|
@ -135,16 +135,16 @@ fn test() {
|
|||
* @accessLevel package
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"tagNamePreference": {
|
||||
"access": "accessLevel",
|
||||
},
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
(
|
||||
|
|
@ -165,7 +165,7 @@ fn test() {
|
|||
* @public
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
|
|
@ -177,14 +177,14 @@ fn test() {
|
|||
* @private
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"ignorePrivate": true,
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
(
|
||||
|
|
@ -205,7 +205,7 @@ fn test() {
|
|||
* @access foo
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
|
|
@ -217,14 +217,14 @@ fn test() {
|
|||
* @access foo
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"ignorePrivate": true,
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
(
|
||||
|
|
@ -238,11 +238,11 @@ fn test() {
|
|||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"tagNamePreference": {
|
||||
"access": "accessLevel",
|
||||
},
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
(
|
||||
|
|
@ -251,16 +251,16 @@ fn test() {
|
|||
* @access
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"tagNamePreference": {
|
||||
"access": false,
|
||||
},
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
(
|
||||
|
|
@ -282,7 +282,7 @@ fn test() {
|
|||
* @public
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
|
|
@ -295,7 +295,7 @@ fn test() {
|
|||
* @access private
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
|
|
@ -308,14 +308,14 @@ fn test() {
|
|||
* @access private
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"ignorePrivate": true,
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
(
|
||||
|
|
@ -325,7 +325,7 @@ fn test() {
|
|||
* @private
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
|
|
@ -338,14 +338,14 @@ fn test() {
|
|||
* @private
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"ignorePrivate": true,
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
(
|
||||
|
|
@ -355,7 +355,7 @@ fn test() {
|
|||
* @public
|
||||
*/
|
||||
function quux (foo) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ fn test() {
|
|||
* @property cfg.foo
|
||||
*/
|
||||
function quux ({foo, bar}) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
|
|
@ -335,7 +335,7 @@ fn test() {
|
|||
* @property cfg.foo
|
||||
*/
|
||||
quux ({foo, bar}) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
",
|
||||
|
|
@ -352,7 +352,7 @@ fn test() {
|
|||
* @property baz
|
||||
*/
|
||||
function quux ({foo, bar}, baz) {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
|
|
@ -368,7 +368,7 @@ fn test() {
|
|||
* @property baz
|
||||
*/
|
||||
function quux ({foo, bar}, baz) {
|
||||
|
||||
|
||||
}
|
||||
"#,
|
||||
None,
|
||||
|
|
@ -409,11 +409,11 @@ fn test() {
|
|||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"tagNamePreference": {
|
||||
"property": "prop",
|
||||
},
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -135,11 +135,11 @@ fn test() {
|
|||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"tagNamePreference": {
|
||||
"property": "prop",
|
||||
},
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
(
|
||||
|
|
@ -201,7 +201,7 @@ fn test() {
|
|||
* @property {anotherType} yetAnotherProp This with a type and desc.
|
||||
*/
|
||||
function quux () {
|
||||
|
||||
|
||||
}
|
||||
",
|
||||
None,
|
||||
|
|
@ -250,11 +250,11 @@ fn test() {
|
|||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"tagNamePreference": {
|
||||
"property": "prop",
|
||||
},
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
(
|
||||
|
|
|
|||
|
|
@ -130,11 +130,11 @@ fn test() {
|
|||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"tagNamePreference": {
|
||||
"property": "prop",
|
||||
},
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
];
|
||||
|
|
@ -179,11 +179,11 @@ fn test() {
|
|||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"tagNamePreference": {
|
||||
"property": "prop",
|
||||
},
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -140,11 +140,11 @@ fn test() {
|
|||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"tagNamePreference": {
|
||||
"property": "prop",
|
||||
},
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -116,11 +116,11 @@ fn test() {
|
|||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"tagNamePreference": {
|
||||
"property": "prop",
|
||||
},
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
];
|
||||
|
|
@ -165,11 +165,11 @@ fn test() {
|
|||
",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsdoc": {
|
||||
"settings": { "jsdoc": {
|
||||
"tagNamePreference": {
|
||||
"property": "prop",
|
||||
},
|
||||
},
|
||||
} },
|
||||
})),
|
||||
),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -465,7 +465,9 @@ fn test() {
|
|||
(
|
||||
r#"<SomeComponent as="img" aria-label="" />"#,
|
||||
None,
|
||||
Some(serde_json::json!({ "jsx-a11y": { "polymorphicPropName": "as" } })),
|
||||
Some(
|
||||
serde_json::json!({ "settings": { "jsx-a11y": { "polymorphicPropName": "as" } } }),
|
||||
),
|
||||
),
|
||||
(r"<object />", None, None),
|
||||
(r"<object><div aria-hidden /></object>", None, None),
|
||||
|
|
|
|||
|
|
@ -110,7 +110,9 @@ fn test() {
|
|||
(
|
||||
r"<Link>foo</Link>",
|
||||
None,
|
||||
Some(serde_json::json!({ "jsx-a11y": { "components": { "Link": "a" } } })),
|
||||
Some(
|
||||
serde_json::json!({ "settings": { "jsx-a11y": { "components": { "Link": "a" } } } }),
|
||||
),
|
||||
),
|
||||
(r"<a title={title} />", None, None),
|
||||
(r"<a aria-label={ariaLabel} />", None, None),
|
||||
|
|
@ -124,7 +126,9 @@ fn test() {
|
|||
(
|
||||
r"<Link />",
|
||||
None,
|
||||
Some(serde_json::json!({ "jsx-a11y": { "components": { "Link": "a" } } })),
|
||||
Some(
|
||||
serde_json::json!({ "settings": { "jsx-a11y": { "components": { "Link": "a" } } } }),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ fn test() {
|
|||
r"<Link href='#foo' />",
|
||||
Some(serde_json::json!({ "validHrefs": ["#foo"] })),
|
||||
Some(
|
||||
serde_json::json!({ "jsx-a11y": { "components": { "Anchor": "a", "Link": "a" } } }),
|
||||
serde_json::json!({ "settings": { "jsx-a11y": { "components": { "Anchor": "a", "Link": "a" } } } }),
|
||||
),
|
||||
),
|
||||
// (r#"<a {...props} />"#, Some(serde_json::json!(specialLink))),
|
||||
|
|
@ -578,7 +578,7 @@ fn test() {
|
|||
r"<Link href='#' onClick={() => void 0} />",
|
||||
None,
|
||||
Some(
|
||||
serde_json::json!({ "jsx-a11y": { "components": { "Anchor": "a", "Link": "a" } } }),
|
||||
serde_json::json!({ "settings": { "jsx-a11y": { "components": { "Anchor": "a", "Link": "a" } } } }),
|
||||
),
|
||||
),
|
||||
// (r#"<a hrefLeft={undefined} />"#, Some(serde_json::json!(specialLink))),
|
||||
|
|
|
|||
|
|
@ -108,11 +108,11 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"CustomComponent": "div",
|
||||
}
|
||||
}
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -182,12 +182,12 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"polymorphicPropName": "asChild",
|
||||
"components": {
|
||||
"Div": "div",
|
||||
}
|
||||
}
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -215,11 +215,11 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"Input": "input",
|
||||
}
|
||||
}
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -137,11 +137,11 @@ fn test() {
|
|||
r"<Footer onClick={doFoo} />",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"Footer": "footer",
|
||||
}
|
||||
}
|
||||
} }
|
||||
})),
|
||||
None,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -132,13 +132,13 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"CustomInput": "input",
|
||||
"Title": "h1",
|
||||
"Heading": "h2",
|
||||
},
|
||||
},
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -102,11 +102,11 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"HTMLTop": "html",
|
||||
}
|
||||
}
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -134,11 +134,11 @@ fn test() {
|
|||
r"<FooComponent title='Unique title' />",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"FooComponent": "iframe",
|
||||
},
|
||||
},
|
||||
}, }
|
||||
})),
|
||||
),
|
||||
];
|
||||
|
|
@ -159,11 +159,11 @@ fn test() {
|
|||
r"<FooComponent />",
|
||||
None,
|
||||
Some(serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"FooComponent": "iframe",
|
||||
},
|
||||
},
|
||||
}, }
|
||||
})),
|
||||
),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -195,11 +195,11 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"Image": "img",
|
||||
}
|
||||
}
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,12 +112,12 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"polymorphicPropName": "as",
|
||||
"components": {
|
||||
"Foo": "html",
|
||||
}
|
||||
}
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -188,14 +188,14 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"polymorphicPropName": "as",
|
||||
"components": {
|
||||
"Audio": "audio",
|
||||
"Video": "video",
|
||||
"Track": "track",
|
||||
},
|
||||
}
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,11 +123,11 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"Button": "button",
|
||||
}
|
||||
}
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,12 +78,12 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"Blink": "blink",
|
||||
"Marquee": "marquee"
|
||||
}
|
||||
}
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,11 +96,11 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"Button": "button",
|
||||
}
|
||||
}
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,11 +89,11 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"MyComponent": "div",
|
||||
}
|
||||
}
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1273,11 +1273,11 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"Link": "a"
|
||||
}
|
||||
},
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -85,12 +85,12 @@ fn test() {
|
|||
|
||||
fn settings() -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"jsx-a11y": {
|
||||
"settings": { "jsx-a11y": {
|
||||
"components": {
|
||||
"Foo": "div",
|
||||
"TableHeader": "th"
|
||||
}
|
||||
}
|
||||
} }
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -489,20 +489,20 @@ fn test() {
|
|||
(
|
||||
r#"<Link target="_blank" href={ dynamicLink }></Link>"#,
|
||||
Some(serde_json::json!([{ "enforceDynamicLinks": "never" }])),
|
||||
Some(serde_json::json!({ "react": { "linkComponents": ["Link"] } })),
|
||||
Some(serde_json::json!({ "settings": { "react": { "linkComponents": ["Link"] } } })),
|
||||
),
|
||||
(
|
||||
r#"<Link target="_blank" to={ dynamicLink }></Link>"#,
|
||||
Some(serde_json::json!([{ "enforceDynamicLinks": "never" }])),
|
||||
Some(
|
||||
serde_json::json!({"react": { "linkComponents": [{ "name": "Link", "linkAttribute": "to" }] }}),
|
||||
serde_json::json!({"settings": { "react": { "linkComponents": [{ "name": "Link", "linkAttribute": "to" }] } }}),
|
||||
),
|
||||
),
|
||||
(
|
||||
r#"<Link target="_blank" to={ dynamicLink }></Link>"#,
|
||||
Some(serde_json::json!([{ "enforceDynamicLinks": "never" }])),
|
||||
Some(
|
||||
serde_json::json!({ "react": { "linkComponents": [{ "name": "Link", "linkAttribute": ["to"] }] }}),
|
||||
serde_json::json!({ "settings": { "react": { "linkComponents": [{ "name": "Link", "linkAttribute": ["to"] }] } }}),
|
||||
),
|
||||
),
|
||||
(
|
||||
|
|
@ -683,13 +683,13 @@ fn test() {
|
|||
(
|
||||
r#"<Link target="_blank" href={ dynamicLink }></Link>"#,
|
||||
Some(serde_json::json!([{ "enforceDynamicLinks": "always"}])),
|
||||
Some(serde_json::json!({ "react": { "linkComponents": ["Link"] } })),
|
||||
Some(serde_json::json!({ "settings": { "react": { "linkComponents": ["Link"] } } })),
|
||||
),
|
||||
(
|
||||
r#"<Link target="_blank" to={ dynamicLink }></Link>"#,
|
||||
Some(serde_json::json!([{ "enforceDynamicLinks": "always" }])),
|
||||
Some(
|
||||
serde_json::json!({ "react": { "linkComponents": [{ "name": "Link", "linkAttribute": "to" }] } }),
|
||||
serde_json::json!({ "settings": { "react": { "linkComponents": [{ "name": "Link", "linkAttribute": "to" }] } } }),
|
||||
),
|
||||
),
|
||||
(
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use serde::Deserialize;
|
|||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
rules::RULES, ESLintSettings, Fixer, LintOptions, LintService, LintServiceOptions, Linter,
|
||||
rules::RULES, ESLintConfig, Fixer, LintOptions, LintService, LintServiceOptions, Linter,
|
||||
RuleEnum,
|
||||
};
|
||||
|
||||
|
|
@ -24,8 +24,8 @@ enum TestResult {
|
|||
#[derive(Debug, Clone, Default)]
|
||||
pub struct TestCase {
|
||||
source: String,
|
||||
config: Option<Value>,
|
||||
settings: Option<Value>,
|
||||
rule_config: Option<Value>,
|
||||
eslint_config: Option<Value>,
|
||||
path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
|
|
@ -42,22 +42,27 @@ impl From<String> for TestCase {
|
|||
}
|
||||
|
||||
impl From<(&str, Option<Value>)> for TestCase {
|
||||
fn from((source, config): (&str, Option<Value>)) -> Self {
|
||||
Self { source: source.to_string(), config, ..Self::default() }
|
||||
fn from((source, rule_config): (&str, Option<Value>)) -> Self {
|
||||
Self { source: source.to_string(), rule_config, ..Self::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(&str, Option<Value>, Option<Value>)> for TestCase {
|
||||
fn from((source, config, settings): (&str, Option<Value>, Option<Value>)) -> Self {
|
||||
Self { source: source.to_string(), config, settings, ..Self::default() }
|
||||
fn from((source, rule_config, eslint_config): (&str, Option<Value>, Option<Value>)) -> Self {
|
||||
Self { source: source.to_string(), rule_config, eslint_config, ..Self::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(&str, Option<Value>, Option<Value>, Option<PathBuf>)> for TestCase {
|
||||
fn from(
|
||||
(source, config, settings, path): (&str, Option<Value>, Option<Value>, Option<PathBuf>),
|
||||
(source, rule_config, eslint_config, path): (
|
||||
&str,
|
||||
Option<Value>,
|
||||
Option<Value>,
|
||||
Option<PathBuf>,
|
||||
),
|
||||
) -> Self {
|
||||
Self { source: source.to_string(), config, settings, path }
|
||||
Self { source: source.to_string(), rule_config, eslint_config, path }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -159,16 +164,16 @@ impl Tester {
|
|||
}
|
||||
|
||||
fn test_pass(&mut self) {
|
||||
for TestCase { source, config, settings, path } in self.expect_pass.clone() {
|
||||
let result = self.run(&source, config, false, &settings, &path);
|
||||
for TestCase { source, rule_config, eslint_config, path } in self.expect_pass.clone() {
|
||||
let result = self.run(&source, rule_config, &eslint_config, path, false);
|
||||
let passed = result == TestResult::Passed;
|
||||
assert!(passed, "expect test to pass: {source} {}", self.snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
fn test_fail(&mut self) {
|
||||
for TestCase { source, config, settings, path } in self.expect_fail.clone() {
|
||||
let result = self.run(&source, config, false, &settings, &path);
|
||||
for TestCase { source, rule_config, eslint_config, path } in self.expect_fail.clone() {
|
||||
let result = self.run(&source, rule_config, &eslint_config, path, false);
|
||||
let failed = result == TestResult::Failed;
|
||||
assert!(failed, "expect test to fail: {source}");
|
||||
}
|
||||
|
|
@ -176,7 +181,7 @@ impl Tester {
|
|||
|
||||
fn test_fix(&mut self) {
|
||||
for (test, expected, config) in self.expect_fix.clone() {
|
||||
let result = self.run(&test, config, true, &None, &None);
|
||||
let result = self.run(&test, config, &None, None, true);
|
||||
if let TestResult::Fixed(fixed_str) = result {
|
||||
assert_eq!(expected, fixed_str);
|
||||
} else {
|
||||
|
|
@ -188,16 +193,13 @@ impl Tester {
|
|||
fn run(
|
||||
&mut self,
|
||||
source_text: &str,
|
||||
config: Option<Value>,
|
||||
rule_config: Option<Value>,
|
||||
eslint_config: &Option<Value>,
|
||||
path: Option<PathBuf>,
|
||||
is_fix: bool,
|
||||
settings: &Option<Value>,
|
||||
path: &Option<PathBuf>,
|
||||
) -> TestResult {
|
||||
let allocator = Allocator::default();
|
||||
let rule = self.find_rule().read_json(config);
|
||||
let lint_settings: ESLintSettings = settings
|
||||
.as_ref()
|
||||
.map_or_else(ESLintSettings::default, |v| ESLintSettings::deserialize(v).unwrap());
|
||||
let rule = self.find_rule().read_json(rule_config);
|
||||
let options = LintOptions::default()
|
||||
.with_fix(is_fix)
|
||||
.with_import_plugin(self.import_plugin)
|
||||
|
|
@ -205,10 +207,13 @@ impl Tester {
|
|||
.with_jsx_a11y_plugin(self.jsx_a11y_plugin)
|
||||
.with_nextjs_plugin(self.nextjs_plugin)
|
||||
.with_react_perf_plugin(self.react_perf_plugin);
|
||||
let eslint_config = eslint_config
|
||||
.as_ref()
|
||||
.map_or_else(ESLintConfig::default, |v| ESLintConfig::deserialize(v).unwrap());
|
||||
let linter = Linter::from_options(options)
|
||||
.unwrap()
|
||||
.with_rules(vec![rule])
|
||||
.with_settings(lint_settings);
|
||||
.with_eslint_config(eslint_config);
|
||||
let path_to_lint = if self.import_plugin {
|
||||
assert!(path.is_none(), "import plugin does not support path");
|
||||
self.current_working_directory.join(&self.rule_path)
|
||||
|
|
|
|||
Loading…
Reference in a new issue