mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
refactor(linter): Add LinterBuilder (#5714)
This will replace `OxlintOptions` in an upstream PR. This also adds `plugins` to `Oxlintrc`. This field gets respected by the builder, but not by `OxlintOptions`.
This commit is contained in:
parent
8ade793dfe
commit
ba7b01fbdf
10 changed files with 397 additions and 49 deletions
294
crates/oxc_linter/src/builder.rs
Normal file
294
crates/oxc_linter/src/builder.rs
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
use std::{
|
||||
cell::{Ref, RefCell},
|
||||
fmt,
|
||||
};
|
||||
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::{
|
||||
options::LintPlugins, rules::RULES, AllowWarnDeny, FixKind, FrameworkFlags, LintConfig,
|
||||
LintFilter, LintFilterKind, LintOptions, Linter, Oxlintrc, RuleCategory, RuleEnum,
|
||||
RuleWithSeverity,
|
||||
};
|
||||
|
||||
#[must_use = "You dropped your builder without building a Linter! Did you mean to call .build()?"]
|
||||
pub struct LinterBuilder {
|
||||
rules: FxHashSet<RuleWithSeverity>,
|
||||
options: LintOptions,
|
||||
config: LintConfig,
|
||||
cache: RulesCache,
|
||||
}
|
||||
|
||||
impl Default for LinterBuilder {
|
||||
fn default() -> Self {
|
||||
Self { rules: Self::warn_correctness(LintPlugins::default()), ..Self::empty() }
|
||||
}
|
||||
}
|
||||
|
||||
impl LinterBuilder {
|
||||
/// Create a [`LinterBuilder`] with default plugins enabled and no
|
||||
/// configured rules.
|
||||
///
|
||||
/// You can think of this as `oxlint -A all`.
|
||||
pub fn empty() -> Self {
|
||||
let options = LintOptions::default();
|
||||
let cache = RulesCache::new(options.plugins);
|
||||
Self { rules: FxHashSet::default(), options, config: LintConfig::default(), cache }
|
||||
}
|
||||
|
||||
/// Warn on all rules in all plugins and categories, including those in `nursery`.
|
||||
/// This is the kitchen sink.
|
||||
///
|
||||
/// You can think of this as `oxlint -W all -W nursery`.
|
||||
pub fn all() -> Self {
|
||||
let options = LintOptions { plugins: LintPlugins::all(), ..LintOptions::default() };
|
||||
let cache = RulesCache::new(options.plugins);
|
||||
Self {
|
||||
rules: RULES
|
||||
.iter()
|
||||
.map(|rule| RuleWithSeverity { rule: rule.clone(), severity: AllowWarnDeny::Warn })
|
||||
.collect(),
|
||||
options,
|
||||
config: LintConfig::default(),
|
||||
cache,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a [`LinterBuilder`] from a loaded or manually built [`Oxlintrc`].
|
||||
/// `start_empty` will configure the builder to contain only the
|
||||
/// configuration settings from the config. When this is `false`, the config
|
||||
/// will be applied on top of a default [`Oxlintrc`].
|
||||
///
|
||||
/// # Example
|
||||
/// Here's how to create a [`Linter`] from a `.oxlintrc.json` file.
|
||||
/// ```
|
||||
/// use oxc_linter::{LinterBuilder, Oxlintrc};
|
||||
/// let oxlintrc = Oxlintrc::from_file("path/to/.oxlintrc.json").unwrap();
|
||||
/// let linter = LinterBuilder::from_oxlintrc(true, oxlintrc).build();
|
||||
/// // you can use `From` as a shorthand for `from_oxlintrc(false, oxlintrc)`
|
||||
/// let linter = LinterBuilder::from(oxlintrc).build();
|
||||
/// ```
|
||||
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 config = LintConfig { settings, env, globals };
|
||||
let options = LintOptions { plugins, ..Default::default() };
|
||||
let rules =
|
||||
if start_empty { FxHashSet::default() } else { Self::warn_correctness(plugins) };
|
||||
let cache = RulesCache::new(options.plugins);
|
||||
let mut builder = Self { rules, options, config, cache };
|
||||
|
||||
{
|
||||
let all_rules = builder.cache.borrow();
|
||||
oxlintrc_rules.override_rules(&mut builder.rules, all_rules.as_slice());
|
||||
}
|
||||
|
||||
builder
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_framework_hints(mut self, flags: FrameworkFlags) -> Self {
|
||||
self.options.framework_hints = flags;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn and_framework_hints(mut self, flags: FrameworkFlags) -> Self {
|
||||
self.options.framework_hints |= flags;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_fix(mut self, fix: FixKind) -> Self {
|
||||
self.options.fix = fix;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_plugins(mut self, plugins: LintPlugins) -> Self {
|
||||
self.options.plugins = plugins;
|
||||
self.cache.set_plugins(plugins);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn and_plugins(mut self, plugins: LintPlugins, enabled: bool) -> Self {
|
||||
self.options.plugins.set(plugins, enabled);
|
||||
self.cache.set_plugins(self.options.plugins);
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn with_rule(mut self, rule: RuleWithSeverity) -> Self {
|
||||
self.rules.insert(rule);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_filters<I: IntoIterator<Item = LintFilter>>(mut self, filters: I) -> Self {
|
||||
for filter in filters {
|
||||
self = self.with_filter(filter);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_filter(mut self, filter: LintFilter) -> Self {
|
||||
let (severity, filter) = filter.into();
|
||||
let all_rules = self.cache.borrow();
|
||||
|
||||
match severity {
|
||||
AllowWarnDeny::Deny | AllowWarnDeny::Warn => match filter {
|
||||
LintFilterKind::Category(category) => {
|
||||
self.rules.extend(
|
||||
all_rules
|
||||
.iter()
|
||||
.filter(|rule| rule.category() == category)
|
||||
.map(|rule| RuleWithSeverity::new(rule.clone(), severity)),
|
||||
);
|
||||
}
|
||||
LintFilterKind::Rule(_, name) => {
|
||||
self.rules.extend(
|
||||
all_rules
|
||||
.iter()
|
||||
.filter(|rule| rule.name() == name)
|
||||
.map(|rule| RuleWithSeverity::new(rule.clone(), severity)),
|
||||
);
|
||||
}
|
||||
LintFilterKind::Generic(name_or_category) => {
|
||||
if name_or_category == "all" {
|
||||
self.rules.extend(
|
||||
all_rules
|
||||
.iter()
|
||||
.filter(|rule| rule.category() != RuleCategory::Nursery)
|
||||
.map(|rule| RuleWithSeverity::new(rule.clone(), severity)),
|
||||
);
|
||||
} else {
|
||||
self.rules.extend(
|
||||
all_rules
|
||||
.iter()
|
||||
.filter(|rule| rule.name() == name_or_category)
|
||||
.map(|rule| RuleWithSeverity::new(rule.clone(), severity)),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
AllowWarnDeny::Allow => match filter {
|
||||
LintFilterKind::Category(category) => {
|
||||
self.rules.retain(|rule| rule.category() != category);
|
||||
}
|
||||
LintFilterKind::Rule(_, name) => {
|
||||
self.rules.retain(|rule| rule.name() != name);
|
||||
}
|
||||
LintFilterKind::Generic(name_or_category) => {
|
||||
if name_or_category == "all" {
|
||||
self.rules.clear();
|
||||
} else {
|
||||
self.rules.retain(|rule| rule.name() != name_or_category);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
drop(all_rules);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn build(self) -> Linter {
|
||||
let mut rules = self.rules.into_iter().collect::<Vec<_>>();
|
||||
rules.sort_unstable_by_key(|r| r.id());
|
||||
Linter::new(rules, self.options, self.config)
|
||||
}
|
||||
|
||||
/// Warn for all correctness rules in the given set of plugins.
|
||||
fn warn_correctness(plugins: LintPlugins) -> FxHashSet<RuleWithSeverity> {
|
||||
RULES
|
||||
.iter()
|
||||
.filter(|rule| {
|
||||
// NOTE: this logic means there's no way to disable ESLint
|
||||
// correctness rules. I think that's fine for now.
|
||||
rule.category() == RuleCategory::Correctness
|
||||
&& plugins.contains(LintPlugins::from(rule.plugin_name()))
|
||||
})
|
||||
.map(|rule| RuleWithSeverity { rule: rule.clone(), severity: AllowWarnDeny::Warn })
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Oxlintrc> for LinterBuilder {
|
||||
#[inline]
|
||||
fn from(oxlintrc: Oxlintrc) -> Self {
|
||||
Self::from_oxlintrc(false, oxlintrc)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for LinterBuilder {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("LinterBuilder")
|
||||
.field("rules", &self.rules)
|
||||
.field("options", &self.options)
|
||||
.field("config", &self.config)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
struct RulesCache(RefCell<Option<Vec<RuleEnum>>>, LintPlugins);
|
||||
impl RulesCache {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn new(plugins: LintPlugins) -> Self {
|
||||
Self(RefCell::new(None), plugins)
|
||||
}
|
||||
|
||||
pub fn set_plugins(&mut self, plugins: LintPlugins) {
|
||||
self.1 = plugins;
|
||||
self.clear();
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn borrow(&self) -> Ref<'_, Vec<RuleEnum>> {
|
||||
let cached = self.0.borrow();
|
||||
if cached.is_some() {
|
||||
Ref::map(cached, |cached| cached.as_ref().unwrap())
|
||||
} else {
|
||||
drop(cached);
|
||||
self.initialize();
|
||||
Ref::map(self.0.borrow(), |cached| cached.as_ref().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
/// If the cache cell is currently borrowed.
|
||||
fn clear(&self) {
|
||||
*self.0.borrow_mut() = None;
|
||||
}
|
||||
|
||||
/// Forcefully initialize this cache with all rules in all plugins currently
|
||||
/// enabled.
|
||||
///
|
||||
/// This will clobber whatever value is currently stored. It should only be
|
||||
/// called when the cache is not populated, either because it has not been
|
||||
/// initialized yet or it was cleared with [`Self::clear`].
|
||||
///
|
||||
/// # Panics
|
||||
/// If the cache cell is currently borrowed.
|
||||
fn initialize(&self) {
|
||||
debug_assert!(
|
||||
self.0.borrow().is_none(),
|
||||
"Cannot re-initialize a populated rules cache. It must be cleared first."
|
||||
);
|
||||
|
||||
let mut all_rules: Vec<_> = if self.1.is_all() {
|
||||
RULES.clone()
|
||||
} else {
|
||||
RULES
|
||||
.iter()
|
||||
.filter(|rule| self.1.contains(LintPlugins::from(rule.plugin_name())))
|
||||
.cloned()
|
||||
.collect()
|
||||
};
|
||||
all_rules.sort_unstable(); // TODO: do we need to sort? is is already sorted?
|
||||
|
||||
*self.0.borrow_mut() = Some(all_rules);
|
||||
}
|
||||
}
|
||||
|
|
@ -76,7 +76,7 @@ mod test {
|
|||
}));
|
||||
assert!(config.is_ok());
|
||||
|
||||
let Oxlintrc { rules, settings, env, globals } = config.unwrap();
|
||||
let Oxlintrc { rules, settings, env, globals, .. } = config.unwrap();
|
||||
assert!(!rules.is_empty());
|
||||
assert_eq!(
|
||||
settings.jsx_a11y.polymorphic_prop_name.as_ref().map(CompactStr::as_str),
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use super::{env::OxlintEnv, globals::OxlintGlobals, rules::OxlintRules, settings::OxlintSettings};
|
||||
|
||||
use crate::utils::read_to_string;
|
||||
use crate::{options::LintPlugins, utils::read_to_string};
|
||||
|
||||
/// Oxlint Configuration File
|
||||
///
|
||||
|
|
@ -42,7 +42,9 @@ use crate::utils::read_to_string;
|
|||
/// ```
|
||||
#[derive(Debug, Default, Deserialize, Serialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
#[non_exhaustive]
|
||||
pub struct Oxlintrc {
|
||||
pub plugins: LintPlugins,
|
||||
/// See [Oxlint Rules](https://oxc.rs/docs/guide/usage/linter/rules.html).
|
||||
pub rules: OxlintRules,
|
||||
pub settings: OxlintSettings,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
mod tester;
|
||||
|
||||
mod ast_util;
|
||||
mod builder;
|
||||
mod config;
|
||||
mod context;
|
||||
mod disable_directives;
|
||||
|
|
@ -29,11 +30,12 @@ use oxc_diagnostics::Error;
|
|||
use oxc_semantic::{AstNode, Semantic};
|
||||
|
||||
pub use crate::{
|
||||
builder::LinterBuilder,
|
||||
config::Oxlintrc,
|
||||
context::LintContext,
|
||||
fixer::FixKind,
|
||||
frameworks::FrameworkFlags,
|
||||
options::{AllowWarnDeny, InvalidFilterKind, LintFilter, OxlintOptions},
|
||||
options::{AllowWarnDeny, InvalidFilterKind, LintFilter, LintFilterKind, OxlintOptions},
|
||||
rule::{RuleCategory, RuleFixMeta, RuleMeta, RuleWithSeverity},
|
||||
service::{LintService, LintServiceOptions},
|
||||
};
|
||||
|
|
@ -67,6 +69,14 @@ impl Default for Linter {
|
|||
}
|
||||
|
||||
impl Linter {
|
||||
pub(crate) fn new(
|
||||
rules: Vec<RuleWithSeverity>,
|
||||
options: LintOptions,
|
||||
config: LintConfig,
|
||||
) -> Self {
|
||||
Self { rules, options, config: Arc::new(config) }
|
||||
}
|
||||
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `Err` if there are any errors parsing the configuration file.
|
||||
|
|
@ -82,14 +92,6 @@ impl Linter {
|
|||
self
|
||||
}
|
||||
|
||||
/// Used for testing
|
||||
#[cfg(test)]
|
||||
#[must_use]
|
||||
pub(crate) fn with_eslint_config(mut self, config: LintConfig) -> Self {
|
||||
self.config = Arc::new(config);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the kind of auto fixes to apply.
|
||||
///
|
||||
/// # Example
|
||||
|
|
|
|||
|
|
@ -4,12 +4,11 @@ mod plugins;
|
|||
|
||||
use std::{convert::From, path::PathBuf};
|
||||
|
||||
use filter::LintFilterKind;
|
||||
use oxc_diagnostics::Error;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
pub use allow_warn_deny::AllowWarnDeny;
|
||||
pub use filter::{InvalidFilterKind, LintFilter};
|
||||
pub use filter::{InvalidFilterKind, LintFilter, LintFilterKind};
|
||||
pub use plugins::{LintPluginOptions, LintPlugins};
|
||||
|
||||
use crate::{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ bitflags! {
|
|||
// NOTE: may be increased to a u32 if needed
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
|
||||
pub struct LintPlugins: u16 {
|
||||
/// Not really a plugin. Included for completeness.
|
||||
const ESLINT = 0;
|
||||
/// `eslint-plugin-react`, plus `eslint-plugin-react-hooks`
|
||||
const REACT = 1 << 0;
|
||||
/// `eslint-plugin-unicorn`
|
||||
|
|
@ -68,6 +70,12 @@ impl LintPlugins {
|
|||
self.contains(LintPlugins::VITEST)
|
||||
}
|
||||
|
||||
/// Returns `true` if the Jest plugin is enabled.
|
||||
#[inline]
|
||||
pub fn has_jest(self) -> bool {
|
||||
self.contains(LintPlugins::JEST)
|
||||
}
|
||||
|
||||
/// Returns `true` if Jest or Vitest plugins are enabled.
|
||||
#[inline]
|
||||
pub fn has_test(self) -> bool {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,19 @@ expression: json
|
|||
}
|
||||
]
|
||||
},
|
||||
"plugins": {
|
||||
"default": [
|
||||
"react",
|
||||
"unicorn",
|
||||
"typescript",
|
||||
"oxc"
|
||||
],
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/LintPlugins"
|
||||
}
|
||||
]
|
||||
},
|
||||
"rules": {
|
||||
"description": "See [Oxlint Rules](https://oxc.rs/docs/guide/usage/linter/rules.html).",
|
||||
"default": {},
|
||||
|
|
@ -222,6 +235,12 @@ expression: json
|
|||
}
|
||||
}
|
||||
},
|
||||
"LintPlugins": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"NextPluginSettings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ use serde::Deserialize;
|
|||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
fixer::FixKind, options::LintPluginOptions, rules::RULES, AllowWarnDeny, Fixer, LintService,
|
||||
LintServiceOptions, Linter, OxlintOptions, Oxlintrc, RuleEnum, RuleWithSeverity,
|
||||
fixer::FixKind, options::LintPlugins, rules::RULES, AllowWarnDeny, Fixer, LintService,
|
||||
LintServiceOptions, LinterBuilder, Oxlintrc, RuleEnum, RuleWithSeverity,
|
||||
};
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
|
|
@ -171,13 +171,7 @@ pub struct Tester {
|
|||
/// See: [insta::Settings::set_snapshot_suffix]
|
||||
snapshot_suffix: Option<&'static str>,
|
||||
current_working_directory: Box<Path>,
|
||||
// import_plugin: bool,
|
||||
// jest_plugin: bool,
|
||||
// vitest_plugin: bool,
|
||||
// jsx_a11y_plugin: bool,
|
||||
// nextjs_plugin: bool,
|
||||
// react_perf_plugin: bool,
|
||||
plugins: LintPluginOptions,
|
||||
plugins: LintPlugins,
|
||||
}
|
||||
|
||||
impl Tester {
|
||||
|
|
@ -201,7 +195,7 @@ impl Tester {
|
|||
snapshot: String::new(),
|
||||
snapshot_suffix: None,
|
||||
current_working_directory,
|
||||
plugins: LintPluginOptions::none(),
|
||||
plugins: LintPlugins::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -223,37 +217,37 @@ impl Tester {
|
|||
}
|
||||
|
||||
pub fn with_import_plugin(mut self, yes: bool) -> Self {
|
||||
self.plugins.import = yes;
|
||||
self.plugins.set(LintPlugins::IMPORT, yes);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_jest_plugin(mut self, yes: bool) -> Self {
|
||||
self.plugins.jest = yes;
|
||||
self.plugins.set(LintPlugins::JEST, yes);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_vitest_plugin(mut self, yes: bool) -> Self {
|
||||
self.plugins.vitest = yes;
|
||||
self.plugins.set(LintPlugins::VITEST, yes);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_jsx_a11y_plugin(mut self, yes: bool) -> Self {
|
||||
self.plugins.jsx_a11y = yes;
|
||||
self.plugins.set(LintPlugins::JSX_A11Y, yes);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_nextjs_plugin(mut self, yes: bool) -> Self {
|
||||
self.plugins.nextjs = yes;
|
||||
self.plugins.set(LintPlugins::NEXTJS, yes);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_react_perf_plugin(mut self, yes: bool) -> Self {
|
||||
self.plugins.react_perf = yes;
|
||||
self.plugins.set(LintPlugins::REACT_PERF, yes);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_node_plugin(mut self, yes: bool) -> Self {
|
||||
self.plugins.node = yes;
|
||||
self.plugins.set(LintPlugins::NODE, yes);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -351,28 +345,22 @@ impl Tester {
|
|||
) -> TestResult {
|
||||
let allocator = Allocator::default();
|
||||
let rule = self.find_rule().read_json(rule_config.unwrap_or_default());
|
||||
let options = OxlintOptions::default()
|
||||
.with_fix(fix.into())
|
||||
.with_import_plugin(self.plugins.import)
|
||||
.with_jest_plugin(self.plugins.jest)
|
||||
.with_vitest_plugin(self.plugins.vitest)
|
||||
.with_jsx_a11y_plugin(self.plugins.jsx_a11y)
|
||||
.with_nextjs_plugin(self.plugins.nextjs)
|
||||
.with_react_perf_plugin(self.plugins.react_perf)
|
||||
.with_node_plugin(self.plugins.node);
|
||||
let eslint_config = eslint_config
|
||||
let linter = eslint_config
|
||||
.as_ref()
|
||||
.map_or_else(Oxlintrc::default, |v| Oxlintrc::deserialize(v).unwrap());
|
||||
let linter = Linter::from_options(options)
|
||||
.unwrap()
|
||||
.with_rules(vec![RuleWithSeverity::new(rule, AllowWarnDeny::Warn)])
|
||||
.with_eslint_config(eslint_config.into());
|
||||
let path_to_lint = if self.plugins.import {
|
||||
.map_or_else(LinterBuilder::empty, |v| {
|
||||
LinterBuilder::from_oxlintrc(true, Oxlintrc::deserialize(v).unwrap())
|
||||
})
|
||||
.with_fix(fix.into())
|
||||
.with_plugins(self.plugins)
|
||||
.with_rule(RuleWithSeverity::new(rule, AllowWarnDeny::Warn))
|
||||
.build();
|
||||
|
||||
let path_to_lint = if self.plugins.has_import() {
|
||||
assert!(path.is_none(), "import plugin does not support path");
|
||||
self.current_working_directory.join(&self.rule_path)
|
||||
} else if let Some(path) = path {
|
||||
self.current_working_directory.join(path)
|
||||
} else if self.plugins.jest {
|
||||
} else if self.plugins.has_jest() {
|
||||
self.rule_path.with_extension("test.tsx")
|
||||
} else {
|
||||
self.rule_path.clone()
|
||||
|
|
@ -380,7 +368,8 @@ impl Tester {
|
|||
|
||||
let cwd = self.current_working_directory.clone();
|
||||
let paths = vec![path_to_lint.into_boxed_path()];
|
||||
let options = LintServiceOptions::new(cwd, paths).with_cross_module(self.plugins.import);
|
||||
let options =
|
||||
LintServiceOptions::new(cwd, paths).with_cross_module(self.plugins.has_import());
|
||||
let lint_service = LintService::from_linter(linter, options);
|
||||
let diagnostic_service = DiagnosticService::default();
|
||||
let tx_error = diagnostic_service.sender();
|
||||
|
|
@ -395,7 +384,7 @@ impl Tester {
|
|||
return TestResult::Fixed(fix_result.fixed_code.to_string());
|
||||
}
|
||||
|
||||
let diagnostic_path = if self.plugins.import {
|
||||
let diagnostic_path = if self.plugins.has_import() {
|
||||
self.rule_path.strip_prefix(&self.current_working_directory).unwrap()
|
||||
} else {
|
||||
&self.rule_path
|
||||
|
|
|
|||
|
|
@ -24,6 +24,19 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"plugins": {
|
||||
"default": [
|
||||
"react",
|
||||
"unicorn",
|
||||
"typescript",
|
||||
"oxc"
|
||||
],
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/LintPlugins"
|
||||
}
|
||||
]
|
||||
},
|
||||
"rules": {
|
||||
"description": "See [Oxlint Rules](https://oxc.rs/docs/guide/usage/linter/rules.html).",
|
||||
"default": {},
|
||||
|
|
@ -218,6 +231,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"LintPlugins": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"NextPluginSettings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
|||
|
|
@ -70,6 +70,22 @@ You may also use `"readable"` or `false` to represent `"readonly"`, and `"writea
|
|||
|
||||
|
||||
|
||||
## plugins
|
||||
|
||||
type: `array`
|
||||
|
||||
|
||||
|
||||
|
||||
### plugins[n]
|
||||
|
||||
type: `string`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## rules
|
||||
|
||||
type: `object`
|
||||
|
|
|
|||
Loading…
Reference in a new issue