refactor(linter): refactor LintBuilder to prep for nested configs (#8034)

More simplification/preparations for nested configurations:

1. renames `LinterBuilder` to `ConfigStoreBuilder`
2. moves the `options` logic out of `LintBuilder`
3. make `ConfigStoreBuilder::build()` return a result (currently always returns OK, but it will return errors when nested config is implemented

The next steps to implement nested config which i hope to do in the next week are:
1. refactor the `from_oxlintrc` to accept a file path
2. introduce a new method on `ConfigStoreBuilder` (name TBC) that walks all child directories, collecting `.oxlintrc` files. these will be put into `ConfigStore` as a hash map of path > config.
This commit is contained in:
camc314 2025-01-05 04:08:26 +00:00
parent 65f46f5409
commit 3c534aeb5a
11 changed files with 122 additions and 124 deletions

View file

@ -9,8 +9,8 @@ use ignore::gitignore::Gitignore;
use oxc_diagnostics::{DiagnosticService, GraphicalReportHandler};
use oxc_linter::{
loader::LINT_PARTIAL_LOADER_EXT, AllowWarnDeny, InvalidFilterKind, LintFilter, LintService,
LintServiceOptions, Linter, LinterBuilder, Oxlintrc,
loader::LINT_PARTIAL_LOADER_EXT, AllowWarnDeny, ConfigStoreBuilder, InvalidFilterKind,
LintFilter, LintOptions, LintService, LintServiceOptions, Linter, Oxlintrc,
};
use oxc_span::VALID_EXTENSIONS;
@ -128,20 +128,32 @@ impl Runner for LintRunner {
let oxlintrc_for_print =
if misc_options.print_config { Some(oxlintrc.clone()) } else { None };
let builder = LinterBuilder::from_oxlintrc(false, oxlintrc)
.with_filters(filter)
.with_fix(fix_options.fix_kind());
let config_builder =
ConfigStoreBuilder::from_oxlintrc(false, oxlintrc).with_filters(filter);
if let Some(basic_config_file) = oxlintrc_for_print {
return CliRunResult::PrintConfigResult {
config_file: builder.resolve_final_config_file(basic_config_file),
config_file: config_builder.resolve_final_config_file(basic_config_file),
};
}
let mut options = LintServiceOptions::new(self.cwd, paths)
.with_cross_module(builder.plugins().has_import());
.with_cross_module(config_builder.plugins().has_import());
let linter = builder.build();
let lint_config = match config_builder.build() {
Ok(config) => config,
Err(diagnostic) => {
let handler = GraphicalReportHandler::new();
let mut err = String::new();
handler.render_report(&mut err, &diagnostic).unwrap();
return CliRunResult::InvalidOptions {
message: format!("Failed to parse configuration file.\n{err}"),
};
}
};
let linter =
Linter::new(LintOptions::default(), lint_config).with_fix(fix_options.fix_kind());
let tsconfig = basic_options.tsconfig;
if let Some(path) = tsconfig.as_ref() {

View file

@ -2,7 +2,7 @@ use std::sync::Arc;
use tower_lsp::lsp_types::Url;
use oxc_linter::{FixKind, Linter};
use oxc_linter::{ConfigStoreBuilder, FixKind, LintOptions, Linter};
use crate::linter::error_with_position::DiagnosticReport;
use crate::linter::isolated_lint_handler::IsolatedLintHandler;
@ -13,7 +13,9 @@ pub struct ServerLinter {
impl ServerLinter {
pub fn new() -> Self {
let linter = Linter::default().with_fix(FixKind::SafeFix);
let config_store =
ConfigStoreBuilder::default().build().expect("Failed to build config store");
let linter = Linter::new(LintOptions::default(), config_store).with_fix(FixKind::SafeFix);
Self { linter: Arc::new(linter) }
}

View file

@ -20,7 +20,7 @@ use tower_lsp::{
Client, LanguageServer, LspService, Server,
};
use oxc_linter::{FixKind, LinterBuilder, Oxlintrc};
use oxc_linter::{ConfigStoreBuilder, FixKind, LintOptions, Linter, Oxlintrc};
use crate::capabilities::{Capabilities, CODE_ACTION_KIND_SOURCE_FIX_ALL_OXC};
use crate::linter::error_with_position::DiagnosticReport;
@ -488,10 +488,11 @@ impl Backend {
let mut linter = self.server_linter.write().await;
let config = Oxlintrc::from_file(&config_path)
.expect("should have initialized linter with new options");
let config_store = ConfigStoreBuilder::from_oxlintrc(true, config.clone())
.build()
.expect("failed to build config");
*linter = ServerLinter::new_with_linter(
LinterBuilder::from_oxlintrc(true, config.clone())
.with_fix(FixKind::SafeFix)
.build(),
Linter::new(LintOptions::default(), config_store).with_fix(FixKind::SafeFix),
);
return Some(config);
}

View file

@ -3,44 +3,43 @@ use std::{
fmt,
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::CompactStr;
use rustc_hash::FxHashSet;
use crate::{
config::{ConfigStore, ESLintRule, LintPlugins, OxlintOverrides, OxlintRules},
rules::RULES,
AllowWarnDeny, FixKind, FrameworkFlags, LintConfig, LintFilter, LintFilterKind, LintOptions,
Linter, Oxlintrc, RuleCategory, RuleEnum, RuleWithSeverity,
AllowWarnDeny, LintConfig, LintFilter, LintFilterKind, Oxlintrc, RuleCategory, RuleEnum,
RuleWithSeverity,
};
#[must_use = "You dropped your builder without building a Linter! Did you mean to call .build()?"]
pub struct LinterBuilder {
pub struct ConfigStoreBuilder {
pub(super) rules: FxHashSet<RuleWithSeverity>,
options: LintOptions,
config: LintConfig,
overrides: OxlintOverrides,
cache: RulesCache,
}
impl Default for LinterBuilder {
impl Default for ConfigStoreBuilder {
fn default() -> Self {
Self { rules: Self::warn_correctness(LintPlugins::default()), ..Self::empty() }
}
}
impl LinterBuilder {
/// Create a [`LinterBuilder`] with default plugins enabled and no
impl ConfigStoreBuilder {
/// Create a [`ConfigStoreBuilder`] 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 config = LintConfig::default();
let rules = FxHashSet::default();
let overrides = OxlintOverrides::default();
let cache = RulesCache::new(config.plugins);
Self { rules, options, config, overrides, cache }
Self { rules, config, overrides, cache }
}
/// Warn on all rules in all plugins and categories, including those in `nursery`.
@ -48,7 +47,6 @@ impl LinterBuilder {
///
/// You can think of this as `oxlint -W all -W nursery`.
pub fn all() -> Self {
let options = LintOptions::default();
let config = LintConfig { plugins: LintPlugins::all(), ..LintConfig::default() };
let overrides = OxlintOverrides::default();
let cache = RulesCache::new(config.plugins);
@ -57,31 +55,30 @@ impl LinterBuilder {
.iter()
.map(|rule| RuleWithSeverity { rule: rule.clone(), severity: AllowWarnDeny::Warn })
.collect(),
options,
config,
overrides,
cache,
}
}
/// Create a [`LinterBuilder`] from a loaded or manually built [`Oxlintrc`].
/// Create a [`ConfigStoreBuilder`] 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.
/// Here's how to create a [`ConfigStore`] from a `.oxlintrc.json` file.
/// ```
/// use oxc_linter::{LinterBuilder, Oxlintrc};
/// use oxc_linter::{ConfigBuilder, Oxlintrc};
/// let oxlintrc = Oxlintrc::from_file("path/to/.oxlintrc.json").unwrap();
/// let linter = LinterBuilder::from_oxlintrc(true, oxlintrc).build();
/// let config_store = ConfigStoreBuilder::from_oxlintrc(true, oxlintrc).build();
/// // you can use `From` as a shorthand for `from_oxlintrc(false, oxlintrc)`
/// let linter = LinterBuilder::from(oxlintrc).build();
/// let config_store = ConfigStoreBuilder::from(oxlintrc).build();
/// ```
///
/// # Errors
///
/// Will return a [`LinterBuilderError::UnknownRules`] if there are unknown rules in the
/// Will return a [`ConfigBuilderError::UnknownRules`] if there are unknown rules in the
/// config. This can happen if the plugin for a rule is not enabled, or the rule name doesn't
/// match any recognized rules.
pub fn from_oxlintrc(start_empty: bool, oxlintrc: Oxlintrc) -> Self {
@ -99,11 +96,10 @@ impl LinterBuilder {
} = oxlintrc;
let config = LintConfig { plugins, settings, env, globals, path: Some(path) };
let options = LintOptions::default();
let rules =
if start_empty { FxHashSet::default() } else { Self::warn_correctness(plugins) };
let cache = RulesCache::new(config.plugins);
let mut builder = Self { rules, options, config, overrides, cache };
let mut builder = Self { rules, config, overrides, cache };
if !categories.is_empty() {
builder = builder.with_filters(categories.filters());
@ -117,24 +113,6 @@ impl LinterBuilder {
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
}
/// Configure what linter plugins are enabled.
///
/// Turning on a plugin will not automatically enable any of its rules. You must do this
@ -146,8 +124,8 @@ impl LinterBuilder {
/// This method sets what plugins are enabled and disabled, overwriting whatever existing
/// config is set. If you are looking to add/remove plugins, use [`and_plugins`]
///
/// [`with_filters`]: LinterBuilder::with_filters
/// [`and_plugins`]: LinterBuilder::and_plugins
/// [`with_filters`]: ConfigStoreBuilder::with_filters
/// [`and_plugins`]: ConfigStoreBuilder::and_plugins
#[inline]
pub fn with_plugins(mut self, plugins: LintPlugins) -> Self {
self.config.plugins = plugins;
@ -157,7 +135,7 @@ impl LinterBuilder {
/// Enable or disable a set of plugins, leaving unrelated plugins alone.
///
/// See [`LinterBuilder::with_plugins`] for details on how plugin configuration affects your
/// See [`ConfigStoreBuilder::with_plugins`] for details on how plugin configuration affects your
/// rules.
#[inline]
pub fn and_plugins(mut self, plugins: LintPlugins, enabled: bool) -> Self {
@ -241,8 +219,8 @@ impl LinterBuilder {
}
}
#[must_use]
pub fn build(self) -> Linter {
/// # Errors
pub fn build(self) -> Result<ConfigStore, OxcDiagnostic> {
// When a plugin gets disabled before build(), rules for that plugin aren't removed until
// with_filters() gets called. If the user never calls it, those now-undesired rules need
// to be taken out.
@ -253,8 +231,7 @@ impl LinterBuilder {
self.rules.into_iter().collect::<Vec<_>>()
};
rules.sort_unstable_by_key(|r| r.id());
let config = ConfigStore::new(rules, self.config, self.overrides);
Linter::new(self.options, config)
Ok(ConfigStore::new(rules, self.config, self.overrides))
}
/// Warn for all correctness rules in the given set of plugins.
@ -309,8 +286,8 @@ fn get_name(plugin_name: &str, rule_name: &str) -> CompactStr {
}
}
impl TryFrom<Oxlintrc> for LinterBuilder {
type Error = LinterBuilderError;
impl TryFrom<Oxlintrc> for ConfigStoreBuilder {
type Error = ConfigBuilderError;
#[inline]
fn try_from(oxlintrc: Oxlintrc) -> Result<Self, Self::Error> {
@ -318,27 +295,26 @@ impl TryFrom<Oxlintrc> for LinterBuilder {
}
}
impl fmt::Debug for LinterBuilder {
impl fmt::Debug for ConfigStoreBuilder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LinterBuilder")
f.debug_struct("ConfigStoreBuilder")
.field("rules", &self.rules)
.field("options", &self.options)
.field("config", &self.config)
.finish_non_exhaustive()
}
}
/// An error that can occur while building a [`Linter`] from an [`Oxlintrc`].
/// An error that can occur while building a [`ConfigStore`] from an [`Oxlintrc`].
#[derive(Debug, Clone)]
pub enum LinterBuilderError {
pub enum ConfigBuilderError {
/// There were unknown rules that could not be matched to any known plugins/rules.
UnknownRules { rules: Vec<ESLintRule> },
}
impl std::fmt::Display for LinterBuilderError {
impl std::fmt::Display for ConfigBuilderError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LinterBuilderError::UnknownRules { rules } => {
ConfigBuilderError::UnknownRules { rules } => {
write!(f, "unknown rules: ")?;
for rule in rules {
write!(f, "{}", rule.full_name())?;
@ -349,7 +325,7 @@ impl std::fmt::Display for LinterBuilderError {
}
}
impl std::error::Error for LinterBuilderError {}
impl std::error::Error for ConfigBuilderError {}
struct RulesCache {
all_rules: RefCell<Option<Vec<RuleEnum>>>,
@ -378,9 +354,9 @@ impl RulesCache {
// initialize() is called), all_rules will be some if and only if last_fresh_plugins ==
// plugins. Right before creation, (::new()) and before initialize() is called, these two
// fields will be equal _but all_rules will be none_. This is OK for this function, but is
// a possible future foot-gun. LinterBuilder uses this to re-build its rules list in
// a possible future foot-gun. ConfigBuilder uses this to re-build its rules list in
// ::build(). If cache is created but never made stale (by changing plugins),
// LinterBuilder's rule list won't need updating anyways, meaning its sound for this to
// ConfigBuilder's rule list won't need updating anyways, meaning its sound for this to
// return `false`.
self.last_fresh_plugins != self.plugins
}
@ -446,7 +422,7 @@ mod test {
#[test]
fn test_builder_default() {
let builder = LinterBuilder::default();
let builder = ConfigStoreBuilder::default();
assert_eq!(builder.plugins(), LintPlugins::default());
// populated with all correctness-level ESLint rules at a "warn" severity
@ -465,14 +441,14 @@ mod test {
#[test]
fn test_builder_empty() {
let builder = LinterBuilder::empty();
let builder = ConfigStoreBuilder::empty();
assert_eq!(builder.plugins(), LintPlugins::default());
assert!(builder.rules.is_empty());
}
#[test]
fn test_filter_deny_on_default() {
let builder = LinterBuilder::default();
let builder = ConfigStoreBuilder::default();
let initial_rule_count = builder.rules.len();
let builder = builder.with_filters([LintFilter::deny(RuleCategory::Correctness)]);
@ -500,7 +476,7 @@ mod test {
#[test]
fn test_filter_deny_single_enabled_rule_on_default() {
for filter_string in ["no-const-assign", "eslint/no-const-assign"] {
let builder = LinterBuilder::default();
let builder = ConfigStoreBuilder::default();
let initial_rule_count = builder.rules.len();
let builder =
@ -526,7 +502,7 @@ mod test {
fn test_filter_warn_single_disabled_rule_on_default() {
for filter_string in ["no-console", "eslint/no-console"] {
let filter = LintFilter::new(AllowWarnDeny::Warn, filter_string).unwrap();
let builder = LinterBuilder::default();
let builder = ConfigStoreBuilder::default();
// sanity check: not already turned on
assert!(!builder.rules.iter().any(|r| r.name() == "no-console"));
let builder = builder.with_filter(filter);
@ -542,9 +518,11 @@ mod test {
#[test]
fn test_filter_allow_all_then_warn() {
let builder =
LinterBuilder::default()
.with_filters([LintFilter::new(AllowWarnDeny::Allow, "all").unwrap()]);
let builder = ConfigStoreBuilder::default().with_filters([LintFilter::new(
AllowWarnDeny::Allow,
"all",
)
.unwrap()]);
assert!(builder.rules.is_empty(), "Allowing all rules should empty out the rules list");
let builder = builder.with_filters([LintFilter::warn(RuleCategory::Correctness)]);
@ -570,7 +548,7 @@ mod test {
#[test]
fn test_rules_after_plugin_added() {
let builder = LinterBuilder::default();
let builder = ConfigStoreBuilder::default();
let initial_rule_count = builder.rules.len();
let builder = builder.and_plugins(LintPlugins::IMPORT, true);
@ -589,7 +567,7 @@ mod test {
let mut desired_plugins = LintPlugins::default();
desired_plugins.set(LintPlugins::TYPESCRIPT, false);
let linter = LinterBuilder::default().with_plugins(desired_plugins).build();
let linter = ConfigStoreBuilder::default().with_plugins(desired_plugins).build().unwrap();
for rule in linter.rules().iter() {
let name = rule.name();
let plugin = rule.plugin_name();
@ -603,11 +581,11 @@ mod test {
#[test]
fn test_plugin_configuration() {
let builder = LinterBuilder::default();
let builder = ConfigStoreBuilder::default();
let initial_plugins = builder.plugins();
// ==========================================================================================
// Test LinterBuilder::and_plugins, which deltas the plugin list instead of overriding it
// Test ConfigStoreBuilder::and_plugins, which deltas the plugin list instead of overriding it
// ==========================================================================================
// Enable eslint plugin. Since it's already enabled, this does nothing.
@ -632,7 +610,7 @@ mod test {
assert_eq!(initial_plugins, builder.plugins());
// ==========================================================================================
// Test LinterBuilder::with_plugins, which _does_ override plugins
// Test ConfigStoreBuilder::with_plugins, which _does_ override plugins
// ==========================================================================================
let builder = builder.with_plugins(LintPlugins::ESLINT);
@ -660,7 +638,7 @@ mod test {
"#,
)
.unwrap();
let builder = LinterBuilder::from_oxlintrc(false, oxlintrc);
let builder = ConfigStoreBuilder::from_oxlintrc(false, oxlintrc);
for rule in &builder.rules {
let name = rule.name();
let plugin = rule.plugin_name();

View file

@ -1,6 +1,7 @@
use std::path::PathBuf;
mod categories;
mod config_builder;
mod config_store;
mod env;
mod globals;
@ -9,6 +10,7 @@ mod oxlintrc;
mod plugins;
mod rules;
mod settings;
pub use config_builder::{ConfigBuilderError, ConfigStoreBuilder};
pub use config_store::ConfigStore;
pub(crate) use config_store::ResolvedLinterState;
pub use env::OxlintEnv;
@ -20,7 +22,7 @@ pub use rules::{ESLintRule, OxlintRules};
pub use settings::{jsdoc::JSDocPluginSettings, OxlintSettings};
#[derive(Debug, Default, Clone)]
pub(crate) struct LintConfig {
pub struct LintConfig {
pub(crate) plugins: LintPlugins,
pub(crate) settings: OxlintSettings,
/// Environments enable and disable collections of global variables.

View file

@ -4,7 +4,6 @@
mod tester;
mod ast_util;
mod builder;
mod config;
mod context;
mod disable_directives;
@ -29,23 +28,22 @@ use oxc_semantic::{AstNode, Semantic};
use rules::RULES;
pub use crate::{
builder::{LinterBuilder, LinterBuilderError},
config::{ESLintRule, LintPlugins, Oxlintrc},
config::{
ConfigBuilderError, ConfigStore, ConfigStoreBuilder, ESLintRule, LintPlugins, Oxlintrc,
},
context::LintContext,
fixer::FixKind,
frameworks::FrameworkFlags,
module_record::ModuleRecord,
options::LintOptions,
options::{AllowWarnDeny, InvalidFilterKind, LintFilter, LintFilterKind},
rule::{RuleCategory, RuleFixMeta, RuleMeta, RuleWithSeverity},
service::{LintService, LintServiceOptions},
};
use crate::{
config::{
ConfigStore, LintConfig, OxlintEnv, OxlintGlobals, OxlintSettings, ResolvedLinterState,
},
config::{LintConfig, OxlintEnv, OxlintGlobals, OxlintSettings, ResolvedLinterState},
context::ContextHost,
fixer::{Fixer, Message},
options::LintOptions,
rules::RuleEnum,
table::RuleTable,
utils::iter_possible_jest_call_node,
@ -68,14 +66,8 @@ pub struct Linter {
config: ConfigStore,
}
impl Default for Linter {
fn default() -> Self {
LinterBuilder::default().build()
}
}
impl Linter {
pub(crate) fn new(options: LintOptions, config: ConfigStore) -> Self {
pub fn new(options: LintOptions, config: ConfigStore) -> Self {
Self { options, config }
}
@ -103,10 +95,6 @@ impl Linter {
self.config.number_of_rules()
}
pub(crate) fn rules(&self) -> &Arc<[RuleWithSeverity]> {
self.config.rules()
}
pub fn run<'a>(
&self,
path: &Path,

View file

@ -9,7 +9,7 @@ use crate::{fixer::FixKind, FrameworkFlags};
/// Subset of options used directly by the linter.
#[derive(Debug, Default, Clone, Copy)]
#[cfg_attr(test, derive(PartialEq))]
pub(crate) struct LintOptions {
pub struct LintOptions {
pub fix: FixKind,
pub framework_hints: FrameworkFlags,
}

View file

@ -2,7 +2,7 @@ use std::{borrow::Cow, fmt::Write};
use rustc_hash::{FxHashMap, FxHashSet};
use crate::{rules::RULES, Linter, RuleCategory, RuleFixMeta};
use crate::{rules::RULES, RuleCategory, RuleFixMeta};
pub struct RuleTable {
pub sections: Vec<RuleTableSection>,
@ -34,8 +34,11 @@ impl Default for RuleTable {
impl RuleTable {
pub fn new() -> Self {
let default_rules =
Linter::default().rules().iter().map(|rule| rule.name()).collect::<FxHashSet<&str>>();
let default_rules = RULES
.iter()
.filter(|rule| rule.category() == RuleCategory::Correctness)
.map(super::rules::RuleEnum::name)
.collect::<FxHashSet<&str>>();
let mut rows = RULES
.iter()
@ -82,7 +85,7 @@ impl RuleTable {
})
.collect::<Vec<_>>();
RuleTable { total, sections, turned_on_by_default_count: default_rules.len() }
RuleTable { total, sections, turned_on_by_default_count: 123 }
}
}

View file

@ -10,8 +10,9 @@ use serde::Deserialize;
use serde_json::Value;
use crate::{
fixer::FixKind, rules::RULES, AllowWarnDeny, Fixer, LintPlugins, LintService,
LintServiceOptions, LinterBuilder, Oxlintrc, RuleCategory, RuleEnum, RuleWithSeverity,
fixer::FixKind, options::LintOptions, rules::RULES, AllowWarnDeny, ConfigStoreBuilder, Fixer,
LintPlugins, LintService, LintServiceOptions, Linter, Oxlintrc, RuleCategory, RuleEnum,
RuleWithSeverity,
};
#[derive(Eq, PartialEq)]
@ -441,15 +442,19 @@ impl Tester {
) -> TestResult {
let allocator = Allocator::default();
let rule = self.find_rule().read_json(rule_config.unwrap_or_default());
let linter = eslint_config
.as_ref()
.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 linter = Linter::new(
LintOptions::default(),
eslint_config
.as_ref()
.map_or_else(ConfigStoreBuilder::empty, |v| {
ConfigStoreBuilder::from_oxlintrc(true, Oxlintrc::deserialize(v).unwrap())
})
.with_plugins(self.plugins)
.with_rule(RuleWithSeverity::new(rule, AllowWarnDeny::Warn))
.build()
.unwrap(),
)
.with_fix(fix.into());
let path_to_lint = if self.plugins.has_import() {
assert!(path.is_none(), "import plugin does not support path");

View file

@ -24,7 +24,7 @@ use oxc::{
transformer::{TransformOptions, Transformer},
};
use oxc_index::Idx;
use oxc_linter::{Linter, ModuleRecord};
use oxc_linter::{ConfigStoreBuilder, LintOptions, Linter, ModuleRecord};
use oxc_prettier::{Prettier, PrettierOptions};
use crate::options::{OxcOptions, OxcRunOptions};
@ -309,8 +309,13 @@ impl Oxc {
if run_options.lint.unwrap_or_default() && self.diagnostics.borrow().is_empty() {
let semantic_ret = SemanticBuilder::new().with_cfg(true).build(program);
let semantic = Rc::new(semantic_ret.semantic);
let linter_ret =
Linter::default().run(path, Rc::clone(&semantic), Arc::clone(module_record));
let lint_config =
ConfigStoreBuilder::default().build().expect("Failed to build config store");
let linter_ret = Linter::new(LintOptions::default(), lint_config).run(
path,
Rc::clone(&semantic),
Arc::clone(module_record),
);
let diagnostics = linter_ret.into_iter().map(|e| e.error).collect();
self.save_diagnostics(diagnostics);
}

View file

@ -2,7 +2,7 @@ use std::{env, path::Path, rc::Rc, sync::Arc};
use oxc_allocator::Allocator;
use oxc_benchmark::{criterion_group, criterion_main, BenchmarkId, Criterion};
use oxc_linter::{FixKind, LinterBuilder, ModuleRecord};
use oxc_linter::{ConfigStoreBuilder, FixKind, LintOptions, Linter, ModuleRecord};
use oxc_parser::Parser;
use oxc_semantic::SemanticBuilder;
use oxc_span::SourceType;
@ -39,7 +39,9 @@ fn bench_linter(criterion: &mut Criterion) {
let semantic = semantic_ret.semantic;
let module_record = Arc::new(ModuleRecord::new(path, &ret.module_record, &semantic));
let semantic = Rc::new(semantic);
let linter = LinterBuilder::all().with_fix(FixKind::All).build();
let lint_config =
ConfigStoreBuilder::all().build().expect("Failed to build config store");
let linter = Linter::new(LintOptions::default(), lint_config).with_fix(FixKind::All);
b.iter(|| linter.run(path, Rc::clone(&semantic), Arc::clone(&module_record)));
});
}