mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
perf(linter): move shared context info to ContextHost (#5795)
> Related to #5770 ## What This PR Does Moves state that is constant over a linted file out of `LintContext` and into a shared `ContextHost` struct, turning `LintContext` into a [flyweight](https://en.wikipedia.org/wiki/Flyweight_pattern). This brings `LintContext` from 144 bytes down to 96. `Linter::run` iterates over `(rule, ctx)` pairs in a very tight loop, and each rule instance gets its own clone of `ctx`. A smaller `LintContext` means better cache locality and a smaller heap allocation for this vec. I'm hoping to eventually get it small enough to fit in a single cache line. I made a PR a while ago that did something similar to this one, but instead of using an `Rc`, each `LintContext` stored a read-only reference. This added an extra lifetime parameter, making it slightly unwieldy, but I saw up to 15%/25% perf improvements on local benchmarks. I'll dig around for it and add a link shortly. ### Architecture  ---- 
This commit is contained in:
parent
17cd9038b7
commit
e413cad0d7
67 changed files with 574 additions and 274 deletions
177
crates/oxc_linter/src/context/host.rs
Normal file
177
crates/oxc_linter/src/context/host.rs
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
use oxc_semantic::Semantic;
|
||||
use oxc_span::SourceType;
|
||||
use std::{cell::RefCell, path::Path, rc::Rc, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
config::LintConfig,
|
||||
disable_directives::{DisableDirectives, DisableDirectivesBuilder},
|
||||
fixer::FixKind,
|
||||
frameworks,
|
||||
options::{LintOptions, LintPlugins},
|
||||
utils, FrameworkFlags, RuleWithSeverity,
|
||||
};
|
||||
|
||||
use super::{plugin_name_to_prefix, LintContext};
|
||||
|
||||
/// Stores shared information about a file being linted.
|
||||
///
|
||||
/// When linting a file, there are a number of shared resources that are
|
||||
/// independent of the rule being linted. [`ContextHost`] stores this context
|
||||
/// subset. When a lint rule is run, a [`LintContext`] with rule-specific
|
||||
/// information is spawned using [`ContextHost::spawn`].
|
||||
///
|
||||
/// ## API Encapsulation
|
||||
///
|
||||
/// In most cases, lint rules should be interacting with a [`LintContext`]. The
|
||||
/// only current exception to this is
|
||||
/// [should_run](`crate::rule::Rule::should_run`). Just before a file is linted,
|
||||
/// rules are filtered out based on that method. Creating a [`LintContext`] for
|
||||
/// rules that would never get run is a waste of resources, so they must use
|
||||
/// [`ContextHost`].
|
||||
///
|
||||
/// ## References
|
||||
/// - [Flyweight Pattern](https://en.wikipedia.org/wiki/Flyweight_pattern)
|
||||
#[must_use]
|
||||
#[non_exhaustive]
|
||||
pub struct ContextHost<'a> {
|
||||
pub(super) semantic: Rc<Semantic<'a>>,
|
||||
pub(super) disable_directives: DisableDirectives<'a>,
|
||||
/// Whether or not to apply code fixes during linting. Defaults to
|
||||
/// [`FixKind::None`] (no fixing).
|
||||
///
|
||||
/// Set via the `--fix`, `--fix-suggestions`, and `--fix-dangerously` CLI
|
||||
/// flags.
|
||||
pub(super) fix: FixKind,
|
||||
pub(super) file_path: Box<Path>,
|
||||
pub(super) config: Arc<LintConfig>,
|
||||
pub(super) frameworks: FrameworkFlags,
|
||||
pub(super) plugins: LintPlugins,
|
||||
}
|
||||
|
||||
impl<'a> ContextHost<'a> {
|
||||
/// # Panics
|
||||
/// If `semantic.cfg()` is `None`.
|
||||
pub fn new<P: AsRef<Path>>(
|
||||
file_path: P,
|
||||
semantic: Rc<Semantic<'a>>,
|
||||
options: LintOptions,
|
||||
) -> Self {
|
||||
// We should always check for `semantic.cfg()` being `Some` since we depend on it and it is
|
||||
// unwrapped without any runtime checks after construction.
|
||||
assert!(
|
||||
semantic.cfg().is_some(),
|
||||
"`LintContext` depends on `Semantic::cfg`, Build your semantic with cfg enabled(`SemanticBuilder::with_cfg`)."
|
||||
);
|
||||
|
||||
let disable_directives =
|
||||
DisableDirectivesBuilder::new(semantic.source_text(), semantic.trivias().clone())
|
||||
.build();
|
||||
|
||||
let file_path = file_path.as_ref().to_path_buf().into_boxed_path();
|
||||
|
||||
Self {
|
||||
semantic,
|
||||
disable_directives,
|
||||
fix: options.fix,
|
||||
file_path,
|
||||
config: Arc::new(LintConfig::default()),
|
||||
frameworks: options.framework_hints,
|
||||
plugins: options.plugins,
|
||||
}
|
||||
.sniff_for_frameworks()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn with_config(mut self, config: &Arc<LintConfig>) -> Self {
|
||||
self.config = Arc::clone(config);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn semantic(&self) -> &Semantic<'a> {
|
||||
&self.semantic
|
||||
}
|
||||
|
||||
/// Path to the file being linted.
|
||||
///
|
||||
/// When created from a [`LintService`](`crate::service::LintService`), this
|
||||
/// will be an absolute path.
|
||||
#[inline]
|
||||
pub fn file_path(&self) -> &Path {
|
||||
&self.file_path
|
||||
}
|
||||
|
||||
/// The source type of the file being linted, e.g. JavaScript, TypeScript,
|
||||
/// CJS, ESM, etc.
|
||||
#[inline]
|
||||
pub fn source_type(&self) -> &SourceType {
|
||||
self.semantic.source_type()
|
||||
}
|
||||
|
||||
pub(crate) fn spawn(self: Rc<Self>, rule: &RuleWithSeverity) -> LintContext<'a> {
|
||||
const DIAGNOSTICS_INITIAL_CAPACITY: usize = 128;
|
||||
let rule_name = rule.name();
|
||||
let plugin_name = self.map_jest(rule.plugin_name(), rule_name);
|
||||
|
||||
LintContext {
|
||||
parent: self,
|
||||
diagnostics: RefCell::new(Vec::with_capacity(DIAGNOSTICS_INITIAL_CAPACITY)),
|
||||
current_rule_name: rule_name,
|
||||
current_plugin_name: plugin_name,
|
||||
current_plugin_prefix: plugin_name_to_prefix(plugin_name),
|
||||
#[cfg(debug_assertions)]
|
||||
current_rule_fix_capabilities: rule.rule.fix(),
|
||||
severity: rule.severity.into(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn spawn_for_test(self: Rc<Self>) -> LintContext<'a> {
|
||||
const DIAGNOSTICS_INITIAL_CAPACITY: usize = 128;
|
||||
|
||||
LintContext {
|
||||
parent: Rc::clone(&self),
|
||||
diagnostics: RefCell::new(Vec::with_capacity(DIAGNOSTICS_INITIAL_CAPACITY)),
|
||||
current_rule_name: "",
|
||||
current_plugin_name: "eslint",
|
||||
current_plugin_prefix: "eslint",
|
||||
#[cfg(debug_assertions)]
|
||||
current_rule_fix_capabilities: crate::rule::RuleFixMeta::None,
|
||||
severity: oxc_diagnostics::Severity::Warning,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_jest(&self, plugin_name: &'static str, rule_name: &str) -> &'static str {
|
||||
if self.plugins.has_vitest()
|
||||
&& plugin_name == "jest"
|
||||
&& utils::is_jest_rule_adapted_to_vitest(rule_name)
|
||||
{
|
||||
"vitest"
|
||||
} else {
|
||||
plugin_name
|
||||
}
|
||||
}
|
||||
|
||||
/// Inspect the target file for clues about what frameworks are being used.
|
||||
/// Should only be called once immediately after construction.
|
||||
///
|
||||
/// Before invocation, `self.frameworks` contains hints obtained at the
|
||||
/// project level. For example, Oxlint may (eventually) search for a
|
||||
/// `package.json`` and look for relevant dependencies. This method builds
|
||||
/// on top of those hints, providing a more granular understanding of the
|
||||
/// frameworks in use.
|
||||
fn sniff_for_frameworks(mut self) -> Self {
|
||||
if self.plugins.has_test() {
|
||||
// let mut test_flags = FrameworkFlags::empty();
|
||||
|
||||
let vitest_like = frameworks::has_vitest_imports(self.semantic.module_record());
|
||||
let jest_like = frameworks::is_jestlike_file(&self.file_path)
|
||||
|| frameworks::has_jest_imports(self.semantic.module_record());
|
||||
|
||||
self.frameworks.set(FrameworkFlags::Vitest, vitest_like);
|
||||
self.frameworks.set(FrameworkFlags::Jest, jest_like);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
#![allow(rustdoc::private_intra_doc_links)] // useful for intellisense
|
||||
use std::{cell::RefCell, path::Path, rc::Rc, sync::Arc};
|
||||
mod host;
|
||||
|
||||
use std::{cell::RefCell, path::Path, rc::Rc};
|
||||
|
||||
use oxc_cfg::ControlFlowGraph;
|
||||
use oxc_diagnostics::{OxcDiagnostic, Severity};
|
||||
|
|
@ -10,36 +12,25 @@ use oxc_syntax::module_record::ModuleRecord;
|
|||
#[cfg(debug_assertions)]
|
||||
use crate::rule::RuleFixMeta;
|
||||
use crate::{
|
||||
config::LintConfig,
|
||||
disable_directives::{DisableDirectives, DisableDirectivesBuilder},
|
||||
disable_directives::DisableDirectives,
|
||||
fixer::{FixKind, Message, RuleFix, RuleFixer},
|
||||
javascript_globals::GLOBALS,
|
||||
AllowWarnDeny, FrameworkFlags, OxlintEnv, OxlintGlobals, OxlintSettings,
|
||||
};
|
||||
|
||||
pub use host::ContextHost;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[must_use]
|
||||
pub struct LintContext<'a> {
|
||||
semantic: Rc<Semantic<'a>>,
|
||||
/// Shared context independent of the rule being linted.
|
||||
parent: Rc<ContextHost<'a>>,
|
||||
|
||||
/// Diagnostics reported by the linter.
|
||||
///
|
||||
/// Contains diagnostics for all rules across all files.
|
||||
diagnostics: RefCell<Vec<Message<'a>>>,
|
||||
|
||||
disable_directives: Rc<DisableDirectives<'a>>,
|
||||
|
||||
/// Whether or not to apply code fixes during linting. Defaults to
|
||||
/// [`FixKind::None`] (no fixing).
|
||||
///
|
||||
/// Set via the `--fix`, `--fix-suggestions`, and `--fix-dangerously` CLI
|
||||
/// flags.
|
||||
fix: FixKind,
|
||||
|
||||
file_path: Rc<Path>,
|
||||
|
||||
config: Arc<LintConfig>,
|
||||
|
||||
// states
|
||||
current_plugin_name: &'static str,
|
||||
current_plugin_prefix: &'static str,
|
||||
|
|
@ -57,54 +48,11 @@ pub struct LintContext<'a> {
|
|||
/// }
|
||||
/// ```
|
||||
severity: Severity,
|
||||
frameworks: FrameworkFlags,
|
||||
}
|
||||
|
||||
impl<'a> LintContext<'a> {
|
||||
const WEBSITE_BASE_URL: &'static str = "https://oxc.rs/docs/guide/usage/linter/rules";
|
||||
|
||||
/// # Panics
|
||||
/// If `semantic.cfg()` is `None`.
|
||||
pub fn new(file_path: Box<Path>, semantic: Rc<Semantic<'a>>) -> Self {
|
||||
const DIAGNOSTICS_INITIAL_CAPACITY: usize = 128;
|
||||
|
||||
// We should always check for `semantic.cfg()` being `Some` since we depend on it and it is
|
||||
// unwrapped without any runtime checks after construction.
|
||||
assert!(
|
||||
semantic.cfg().is_some(),
|
||||
"`LintContext` depends on `Semantic::cfg`, Build your semantic with cfg enabled(`SemanticBuilder::with_cfg`)."
|
||||
);
|
||||
let disable_directives =
|
||||
DisableDirectivesBuilder::new(semantic.source_text(), semantic.trivias().clone())
|
||||
.build();
|
||||
Self {
|
||||
semantic,
|
||||
diagnostics: RefCell::new(Vec::with_capacity(DIAGNOSTICS_INITIAL_CAPACITY)),
|
||||
disable_directives: Rc::new(disable_directives),
|
||||
fix: FixKind::None,
|
||||
file_path: file_path.into(),
|
||||
config: Arc::new(LintConfig::default()),
|
||||
current_plugin_name: "eslint",
|
||||
current_plugin_prefix: "eslint",
|
||||
current_rule_name: "",
|
||||
#[cfg(debug_assertions)]
|
||||
current_rule_fix_capabilities: RuleFixMeta::None,
|
||||
severity: Severity::Warning,
|
||||
frameworks: FrameworkFlags::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable/disable automatic code fixes.
|
||||
pub fn with_fix(mut self, fix: FixKind) -> Self {
|
||||
self.fix = fix;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn with_config(mut self, config: &Arc<LintConfig>) -> Self {
|
||||
self.config = Arc::clone(config);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_plugin_name(mut self, plugin: &'static str) -> Self {
|
||||
self.current_plugin_name = plugin;
|
||||
self.current_plugin_prefix = plugin_name_to_prefix(plugin);
|
||||
|
|
@ -122,38 +70,37 @@ impl<'a> LintContext<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Update the severity of diagnostics reported by the rule this context is
|
||||
/// associated with.
|
||||
#[inline]
|
||||
pub fn with_severity(mut self, severity: AllowWarnDeny) -> Self {
|
||||
self.severity = Severity::from(severity);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set [`FrameworkFlags`], overwriting any existing flags.
|
||||
pub fn with_frameworks(mut self, frameworks: FrameworkFlags) -> Self {
|
||||
self.frameworks = frameworks;
|
||||
self
|
||||
}
|
||||
|
||||
/// Add additional [`FrameworkFlags`]
|
||||
pub fn and_frameworks(mut self, frameworks: FrameworkFlags) -> Self {
|
||||
self.frameworks |= frameworks;
|
||||
self
|
||||
}
|
||||
|
||||
/// Get information such as the control flow graph, bound symbols, AST, etc.
|
||||
/// for the file being linted.
|
||||
///
|
||||
/// Refer to [`Semantic`]'s documentation for more information.
|
||||
#[inline]
|
||||
pub fn semantic(&self) -> &Rc<Semantic<'a>> {
|
||||
&self.semantic
|
||||
&self.parent.semantic
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cfg(&self) -> &ControlFlowGraph {
|
||||
// SAFETY: `LintContext::new` is the only way to construct a `LintContext` and we always
|
||||
// assert the existence of control flow so it should always be `Some`.
|
||||
unsafe { self.semantic().cfg().unwrap_unchecked() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn disable_directives(&self) -> &DisableDirectives<'a> {
|
||||
&self.disable_directives
|
||||
&self.parent.disable_directives
|
||||
}
|
||||
|
||||
/// Source code of the file being linted.
|
||||
#[inline]
|
||||
pub fn source_text(&self) -> &'a str {
|
||||
self.semantic().source_text()
|
||||
}
|
||||
|
|
@ -165,29 +112,34 @@ impl<'a> LintContext<'a> {
|
|||
}
|
||||
|
||||
/// [`SourceType`] of the file currently being linted.
|
||||
#[inline]
|
||||
pub fn source_type(&self) -> &SourceType {
|
||||
self.semantic().source_type()
|
||||
}
|
||||
|
||||
/// Path to the file currently being linted.
|
||||
#[inline]
|
||||
pub fn file_path(&self) -> &Path {
|
||||
&self.file_path
|
||||
&self.parent.file_path
|
||||
}
|
||||
|
||||
/// Plugin settings
|
||||
#[inline]
|
||||
pub fn settings(&self) -> &OxlintSettings {
|
||||
&self.config.settings
|
||||
&self.parent.config.settings
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn globals(&self) -> &OxlintGlobals {
|
||||
&self.config.globals
|
||||
&self.parent.config.globals
|
||||
}
|
||||
|
||||
/// Runtime environments turned on/off by the user.
|
||||
///
|
||||
/// Examples of environments are `builtin`, `browser`, `node`, etc.
|
||||
#[inline]
|
||||
pub fn env(&self) -> &OxlintEnv {
|
||||
&self.config.env
|
||||
&self.parent.config.env
|
||||
}
|
||||
|
||||
pub fn env_contains_var(&self, var: &str) -> bool {
|
||||
|
|
@ -211,7 +163,7 @@ impl<'a> LintContext<'a> {
|
|||
}
|
||||
|
||||
fn add_diagnostic(&self, mut message: Message<'a>) {
|
||||
if self.disable_directives.contains(self.current_rule_name, message.span()) {
|
||||
if self.parent.disable_directives.contains(self.current_rule_name, message.span()) {
|
||||
return;
|
||||
}
|
||||
message.error = message
|
||||
|
|
@ -334,7 +286,7 @@ impl<'a> LintContext<'a> {
|
|||
(Some(message), None) => diagnostic.with_help(message.to_owned()),
|
||||
_ => diagnostic,
|
||||
};
|
||||
if self.fix.can_apply(rule_fix.kind()) {
|
||||
if self.parent.fix.can_apply(rule_fix.kind()) {
|
||||
let fix = rule_fix.into_fix(self.source_text());
|
||||
self.add_diagnostic(Message::new(diagnostic, Some(fix)));
|
||||
} else {
|
||||
|
|
@ -343,7 +295,7 @@ impl<'a> LintContext<'a> {
|
|||
}
|
||||
|
||||
pub fn frameworks(&self) -> FrameworkFlags {
|
||||
self.frameworks
|
||||
self.parent.frameworks
|
||||
}
|
||||
|
||||
/// AST nodes
|
||||
|
|
@ -380,16 +332,6 @@ impl<'a> LintContext<'a> {
|
|||
pub fn jsdoc(&self) -> &JSDocFinder<'a> {
|
||||
self.semantic().jsdoc()
|
||||
}
|
||||
|
||||
// #[inline]
|
||||
// fn plugin_name_to_prefix(&self, plugin_name: &'static str) -> &'static str {
|
||||
// let plugin_name = if self. plugin_name == "jest" && self.frameworks.contains(FrameworkFlags::Vitest) {
|
||||
// "vitest"
|
||||
// } else {
|
||||
// plugin_name
|
||||
// };
|
||||
// PLUGIN_PREFIXES.get(plugin_name).copied().unwrap_or(plugin_name)
|
||||
// }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -23,6 +23,7 @@ pub mod table;
|
|||
use std::{io::Write, path::Path, rc::Rc, sync::Arc};
|
||||
|
||||
use config::LintConfig;
|
||||
use context::ContextHost;
|
||||
use options::LintOptions;
|
||||
use oxc_diagnostics::Error;
|
||||
use oxc_semantic::{AstNode, Semantic};
|
||||
|
|
@ -113,22 +114,22 @@ impl Linter {
|
|||
self.rules.len()
|
||||
}
|
||||
|
||||
// pub fn run<'a>(&self, ctx: LintContext<'a>) -> Vec<Message<'a>> {
|
||||
pub fn run<'a>(&self, path: &Path, semantic: Rc<Semantic<'a>>) -> Vec<Message<'a>> {
|
||||
let ctx = self.create_ctx(path, semantic);
|
||||
let semantic = Rc::clone(ctx.semantic());
|
||||
let ctx_host =
|
||||
Rc::new(ContextHost::new(path, semantic, self.options).with_config(&self.config));
|
||||
|
||||
let rules = self
|
||||
.rules
|
||||
.iter()
|
||||
.filter(|rule| rule.should_run(&ctx))
|
||||
.map(|rule| (rule, self.ctx_for_rule(&ctx, rule)))
|
||||
.filter(|rule| rule.should_run(&ctx_host))
|
||||
.map(|rule| (rule, Rc::clone(&ctx_host).spawn(rule)))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (rule, ctx) in &rules {
|
||||
rule.run_once(ctx);
|
||||
}
|
||||
|
||||
let semantic = ctx_host.semantic();
|
||||
for symbol in semantic.symbols().symbol_ids() {
|
||||
for (rule, ctx) in &rules {
|
||||
rule.run_on_symbol(symbol, ctx);
|
||||
|
|
@ -153,53 +154,6 @@ impl Linter {
|
|||
writeln!(writer, "Default: {}", table.turned_on_by_default_count).unwrap();
|
||||
writeln!(writer, "Total: {}", table.total).unwrap();
|
||||
}
|
||||
|
||||
fn create_ctx<'a>(&self, path: &Path, semantic: Rc<Semantic<'a>>) -> LintContext<'a> {
|
||||
let mut ctx = LintContext::new(path.to_path_buf().into_boxed_path(), semantic)
|
||||
.with_fix(self.options.fix)
|
||||
.with_config(&self.config)
|
||||
.with_frameworks(self.options.framework_hints);
|
||||
|
||||
// set file-specific jest/vitest flags
|
||||
if self.options.plugins.has_test() {
|
||||
let mut test_flags = FrameworkFlags::empty();
|
||||
|
||||
if frameworks::has_vitest_imports(ctx.module_record()) {
|
||||
test_flags.set(FrameworkFlags::Vitest, true);
|
||||
} else if frameworks::is_jestlike_file(path)
|
||||
|| frameworks::has_jest_imports(ctx.module_record())
|
||||
{
|
||||
test_flags.set(FrameworkFlags::Jest, true);
|
||||
}
|
||||
|
||||
ctx = ctx.and_frameworks(test_flags);
|
||||
}
|
||||
|
||||
ctx
|
||||
}
|
||||
|
||||
fn ctx_for_rule<'a>(&self, ctx: &LintContext<'a>, rule: &RuleWithSeverity) -> LintContext<'a> {
|
||||
let rule_name = rule.name();
|
||||
let plugin_name = self.map_jest(rule.plugin_name(), rule_name);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
let ctx = ctx.clone().with_rule_fix_capabilities(rule.rule.fix());
|
||||
#[cfg(not(debug_assertions))]
|
||||
let ctx = ctx.clone();
|
||||
|
||||
ctx.with_plugin_name(plugin_name).with_rule_name(rule_name).with_severity(rule.severity)
|
||||
}
|
||||
|
||||
fn map_jest(&self, plugin_name: &'static str, rule_name: &str) -> &'static str {
|
||||
if self.options.plugins.has_vitest()
|
||||
&& plugin_name == "jest"
|
||||
&& utils::is_jest_rule_adapted_to_vitest(rule_name)
|
||||
{
|
||||
"vitest"
|
||||
} else {
|
||||
plugin_name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -6,12 +6,11 @@ use std::{convert::From, path::PathBuf};
|
|||
|
||||
use filter::LintFilterKind;
|
||||
use oxc_diagnostics::Error;
|
||||
use plugins::LintPlugins;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
pub use allow_warn_deny::AllowWarnDeny;
|
||||
pub use filter::{InvalidFilterKind, LintFilter};
|
||||
pub use plugins::LintPluginOptions;
|
||||
pub use plugins::{LintPluginOptions, LintPlugins};
|
||||
|
||||
use crate::{
|
||||
config::{LintConfig, OxlintConfig},
|
||||
|
|
@ -26,7 +25,7 @@ use crate::{
|
|||
/// outside of this crate.
|
||||
///
|
||||
/// [`Linter`]: crate::Linter
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub(crate) struct LintOptions {
|
||||
pub fix: FixKind,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ use std::{
|
|||
|
||||
use oxc_semantic::SymbolId;
|
||||
|
||||
use crate::{context::LintContext, AllowWarnDeny, AstNode, FixKind, RuleEnum};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
AllowWarnDeny, AstNode, FixKind, RuleEnum,
|
||||
};
|
||||
|
||||
pub trait Rule: Sized + Default + fmt::Debug {
|
||||
/// Initialize from eslint json configuration
|
||||
|
|
@ -39,7 +42,7 @@ pub trait Rule: Sized + Default + fmt::Debug {
|
|||
/// [`linter`]: crate::Linter
|
||||
#[expect(unused_variables)]
|
||||
#[inline]
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,10 @@ use oxc_semantic::{AstNode, ScopeFlags, SymbolFlags, SymbolId};
|
|||
use oxc_span::GetSpan;
|
||||
use symbol::Symbol;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NoUnusedVars(Box<NoUnusedVarsOptions>);
|
||||
|
|
@ -210,7 +213,7 @@ impl Rule for NoUnusedVars {
|
|||
self.run_on_symbol_internal(&symbol, ctx);
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
// ignore .d.ts and vue files.
|
||||
// 1. declarations have side effects (they get merged together)
|
||||
// 2. vue scripts declare variables that get used in the template, which
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use oxc_diagnostics::{LabeledSpan, OxcDiagnostic};
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
// use oxc_span::{CompactStr, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule};
|
||||
use crate::{context::{LintContext, ContextHost}, rule::Rule};
|
||||
|
||||
// #[derive(Debug, Error, Diagnostic)]
|
||||
// #[error("")]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule};
|
||||
use crate::{context::{LintContext, ContextHost}, rule::Rule};
|
||||
|
||||
fn no_exports_found(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("No exports found")
|
||||
|
|
|
|||
|
|
@ -288,6 +288,32 @@ fn convert_pattern(pattern: &str) -> String {
|
|||
format!("(?ui)^{pattern}(\\.|$)")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn debug() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let mut pass: Vec<(&str, Option<serde_json::Value>)> = vec![];
|
||||
|
||||
let mut fail = vec![];
|
||||
|
||||
let pass_vitest = vec![(
|
||||
"
|
||||
import { test } from 'vitest';
|
||||
test.skip(\"skipped test\", () => {})
|
||||
",
|
||||
None,
|
||||
)];
|
||||
|
||||
let fail_vitest = vec![];
|
||||
|
||||
pass.extend(pass_vitest);
|
||||
fail.extend(fail_vitest);
|
||||
|
||||
Tester::new(ExpectExpect::NAME, pass, fail)
|
||||
.with_jest_plugin(true)
|
||||
.with_vitest_plugin(true)
|
||||
.test();
|
||||
}
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,11 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::Span;
|
||||
use phf::phf_set;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_typos_diagnostic(typo: &str, suggestion: &str, span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(format!("{typo} may be a typo. Did you mean {suggestion}?"))
|
||||
|
|
@ -47,7 +51,7 @@ const NEXTJS_DATA_FETCHING_FUNCTIONS: phf::Set<&'static str> = phf_set! {
|
|||
const THRESHOLD: i32 = 1;
|
||||
|
||||
impl Rule for NoTypos {
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
let Some(path) = ctx.file_path().to_str() else {
|
||||
return false;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{
|
||||
context::LintContext,
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
utils::{get_prop_value, has_jsx_prop_ignore_case, is_create_element_call},
|
||||
AstNode,
|
||||
|
|
@ -152,7 +152,7 @@ impl Rule for ButtonHasType {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,12 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, utils::get_prop_value, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
utils::get_prop_value,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn boolean_value_diagnostic(attr: &str, span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(format!("Value must be omitted for boolean attribute {attr:?}"))
|
||||
|
|
@ -149,7 +154,7 @@ impl Rule for JsxBooleanValue {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,11 @@ use oxc_semantic::NodeId;
|
|||
use oxc_span::{GetSpan as _, Span};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn jsx_curly_brace_presence_unnecessary_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Curly braces are unnecessary here.").with_label(span)
|
||||
|
|
@ -350,7 +354,7 @@ impl Rule for JsxCurlyBracePresence {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn missing_key_prop_for_element_in_array(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(r#"Missing "key" prop for element in array."#).with_label(span)
|
||||
|
|
@ -68,7 +72,7 @@ impl Rule for JsxKey {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,11 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::Span;
|
||||
use regex::Regex;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn jsx_no_comment_textnodes_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Comments inside children section of tag should be placed inside braces")
|
||||
|
|
@ -61,7 +65,7 @@ impl Rule for JsxNoCommentTextnodes {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,11 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::{Atom, Span};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn jsx_no_duplicate_props_diagnostic(x0: &str, span1: Span, span2: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(format!("No duplicate props allowed. The prop \"{x0}\" is duplicated."))
|
||||
|
|
@ -72,7 +76,7 @@ impl Rule for JsxNoDuplicateProps {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{CompactStr, GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn target_blank_without_noreferrer(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Using target=`_blank` without rel=`noreferrer` (which implies rel=`noopener`) is a security risk in older browsers: see https://mathiasbynens.github.io/rel-noopener/#recommendations")
|
||||
|
|
@ -241,7 +245,7 @@ impl Rule for JsxNoTargetBlank {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn jsx_no_undef_diagnostic(ident_name: &str, span1: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Disallow undeclared variables in JSX")
|
||||
|
|
@ -72,7 +76,7 @@ impl Rule for JsxNoUndef {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,11 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_semantic::NodeId;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn needs_more_children(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Fragments should contain more than one child.").with_label(span)
|
||||
|
|
@ -78,7 +82,7 @@ impl Rule for JsxNoUselessFragment {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use oxc_span::{Atom, Span};
|
|||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{
|
||||
context::LintContext,
|
||||
context::{ContextHost, LintContext},
|
||||
fixer::{Fix, RuleFix},
|
||||
rule::Rule,
|
||||
utils::is_same_member_expression,
|
||||
|
|
@ -122,7 +122,7 @@ impl Rule for JsxPropsNoSpreadMulti {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, utils::is_create_element_call, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
utils::is_create_element_call,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_children_prop_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Avoid passing children using a prop.")
|
||||
|
|
@ -86,7 +91,7 @@ impl Rule for NoChildrenProp {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{
|
||||
context::LintContext,
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
utils::{has_jsx_prop, is_create_element_call},
|
||||
AstNode,
|
||||
|
|
@ -91,7 +91,7 @@ impl Rule for NoDanger {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{
|
||||
context::LintContext,
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
utils::{is_es5_component, is_es6_component},
|
||||
AstNode,
|
||||
|
|
@ -118,7 +118,7 @@ impl Rule for NoDirectMutationState {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_find_dom_node_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Unexpected call to `findDOMNode`.")
|
||||
|
|
@ -67,7 +71,7 @@ impl Rule for NoFindDomNode {
|
|||
ctx.diagnostic(no_find_dom_node_diagnostic(span));
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_is_mounted_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Do not use isMounted")
|
||||
|
|
@ -67,7 +71,7 @@ impl Rule for NoIsMounted {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_render_return_value_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Do not depend on the return value from ReactDOM.render.")
|
||||
|
|
@ -82,7 +86,7 @@ impl Rule for NoRenderReturnValue {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,12 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, utils::get_parent_component, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
utils::get_parent_component,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_set_state_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Do not use setState").with_label(span)
|
||||
|
|
@ -66,7 +71,7 @@ impl Rule for NoSetState {
|
|||
ctx.diagnostic(no_set_state_diagnostic(call_expr.callee.span()));
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,12 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, utils::get_parent_component, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
utils::get_parent_component,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn this_refs_deprecated(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Using this.refs is deprecated.")
|
||||
|
|
@ -125,7 +130,7 @@ impl Rule for NoStringRefs {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::Span;
|
||||
use phf::{phf_map, Map};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_unescaped_entities_diagnostic(span: Span, unescaped: char, escaped: &str) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(format!("`{unescaped}` can be escaped with {escaped}")).with_label(span)
|
||||
|
|
@ -62,7 +66,7 @@ impl Rule for NoUnescapedEntities {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,12 @@ use regex::Regex;
|
|||
use rustc_hash::FxHashSet;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, utils::get_jsx_attribute_name, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
utils::get_jsx_attribute_name,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn invalid_prop_on_tag(span: Span, prop: &str, tag: &str) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Invalid property found")
|
||||
|
|
@ -540,7 +545,7 @@ impl Rule for NoUnknownProperty {
|
|||
});
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{
|
||||
context::LintContext,
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
utils::{is_es5_component, is_es6_component},
|
||||
AstNode,
|
||||
|
|
@ -75,7 +75,7 @@ impl Rule for PreferEs6Class {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn react_in_jsx_scope_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("'React' must be in scope when using JSX")
|
||||
|
|
@ -59,7 +63,7 @@ impl Rule for ReactInJsxScope {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{
|
||||
context::LintContext,
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
utils::{is_es5_component, is_es6_component},
|
||||
AstNode,
|
||||
|
|
@ -79,7 +79,7 @@ impl Rule for RequireRenderReturn {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, globals::HTML_TAG, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
globals::HTML_TAG,
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn self_closing_comp_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Unnecessary closing tag")
|
||||
|
|
@ -119,7 +124,7 @@ impl Rule for SelfClosingComp {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,12 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::Span;
|
||||
use phf::phf_set;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, utils::is_create_element_call, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
utils::is_create_element_call,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn void_dom_elements_no_children_diagnostic(tag: &str, span: Span) -> OxcDiagnostic {
|
||||
// TODO: use imperative phrasing
|
||||
|
|
@ -142,7 +147,7 @@ impl Rule for VoidDomElementsNoChildren {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{CompactStr, GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn adjacent_overload_signatures_diagnostic(
|
||||
fn_name: &str,
|
||||
|
|
@ -320,7 +324,7 @@ impl Rule for AdjacentOverloadSignatures {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_semantic::AstNode;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct ArrayType(Box<ArrayTypeConfig>);
|
||||
|
|
@ -136,7 +139,7 @@ impl Rule for ArrayType {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,10 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::Span;
|
||||
use regex::Regex;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
};
|
||||
|
||||
fn comment(ts_comment_name: &str, span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(format!(
|
||||
|
|
@ -213,7 +216,7 @@ impl Rule for BanTsComment {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn type_diagnostic(banned_type: &str, suggested_type: &str, span2: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(format!(
|
||||
|
|
@ -88,7 +92,7 @@ impl Rule for BanTypes {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn consistent_indexed_object_style_diagnostic(a: &str, b: &str, span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(format!("A {a} is preferred over an {b}."))
|
||||
|
|
@ -245,7 +249,7 @@ impl Rule for ConsistentIndexedObjectStyle {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn consistent_type_definitions_diagnostic(
|
||||
preferred_type_kind: &str,
|
||||
|
|
@ -220,7 +224,7 @@ impl Rule for ConsistentTypeDefinitions {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use oxc_semantic::{Reference, SymbolId};
|
|||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{
|
||||
context::LintContext,
|
||||
context::{ContextHost, LintContext},
|
||||
fixer::{RuleFix, RuleFixer},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
|
|
@ -268,7 +268,7 @@ impl Rule for ConsistentTypeImports {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use oxc_syntax::operator::UnaryOperator;
|
|||
|
||||
use crate::{
|
||||
ast_util::outermost_paren_parent,
|
||||
context::LintContext,
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
rules::eslint::array_callback_return::return_checker::{
|
||||
check_statement, StatementReturnStatus,
|
||||
|
|
@ -300,7 +300,7 @@ impl Rule for ExplicitFunctionReturnType {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,11 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::Span;
|
||||
use oxc_syntax::operator::{AssignmentOperator, BinaryOperator};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NoConfusingNonNullAssertion;
|
||||
|
|
@ -111,7 +115,7 @@ impl Rule for NoConfusingNonNullAssertion {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::Span;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_duplicate_enum_values_diagnostic(span: Span, span1: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Disallow duplicate enum member values")
|
||||
|
|
@ -67,7 +71,7 @@ impl Rule for NoDuplicateEnumValues {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::Span;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_empty_interface_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("an empty interface is equivalent to `{}`").with_label(span)
|
||||
|
|
@ -69,7 +73,7 @@ impl Rule for NoEmptyInterface {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::Span;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_explicit_any_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Unexpected any. Specify a different type.")
|
||||
|
|
@ -114,7 +118,7 @@ impl Rule for NoExplicitAny {
|
|||
Self { fix_to_unknown, ignore_rest_args }
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_extra_non_null_assertion_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("extra non-null assertion").with_label(span)
|
||||
|
|
@ -63,7 +67,7 @@ impl Rule for NoExtraNonNullAssertion {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, fixer::Fix, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
fixer::Fix,
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_import_type_side_effects_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("TypeScript will only remove the inline type specifiers which will leave behind a side effect import at runtime.")
|
||||
|
|
@ -117,7 +122,7 @@ impl Rule for NoImportTypeSideEffects {
|
|||
);
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_namespace_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("ES2015 module syntax is preferred over namespaces.")
|
||||
|
|
@ -99,7 +103,7 @@ impl Rule for NoNamespace {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_semantic::SymbolId;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NoNonNullAssertedNullishCoalescing;
|
||||
|
|
@ -48,7 +52,7 @@ impl Rule for NoNonNullAssertedNullishCoalescing {
|
|||
ctx.diagnostic(no_non_null_asserted_nullish_coalescing_diagnostic(ts_non_null_expr.span));
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_non_null_asserted_optional_chain_diagnostic(span: Span, span1: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("non-null assertions after an optional chain expression")
|
||||
|
|
@ -91,7 +95,7 @@ impl Rule for NoNonNullAssertedOptionalChain {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NoNonNullAssertion;
|
||||
|
|
@ -37,7 +41,7 @@ impl Rule for NoNonNullAssertion {
|
|||
ctx.diagnostic(no_non_null_assertion_diagnostic(expr.span));
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,11 @@ use oxc_span::{CompactStr, GetSpan, Span};
|
|||
use rustc_hash::FxHashSet;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_this_alias_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Unexpected aliasing of 'this' to local variable.")
|
||||
|
|
@ -153,7 +157,7 @@ impl Rule for NoThisAlias {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_unnecessary_type_constraint_diagnostic(
|
||||
generic_type: &str,
|
||||
|
|
@ -68,7 +72,7 @@ impl Rule for NoUnnecessaryTypeConstraint {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_semantic::SymbolId;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_unsafe_declaration_merging_diagnostic(span: Span, span1: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Unsafe declaration merging between classes and interfaces.")
|
||||
|
|
@ -61,7 +65,7 @@ impl Rule for NoUnsafeDeclarationMerging {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,12 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{ast_util::is_global_require_call, context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
ast_util::is_global_require_call,
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn no_var_requires_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Require statement not part of import statement.")
|
||||
|
|
@ -66,7 +71,7 @@ impl Rule for NoVarRequires {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn prefer_as_const_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Expected a `const` assertion instead of a literal type annotation.")
|
||||
|
|
@ -82,7 +86,7 @@ impl Rule for PreferAsConst {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn prefer_enum_initializers_diagnostic(
|
||||
member_name: &str,
|
||||
|
|
@ -59,7 +63,7 @@ impl Rule for PreferEnumInitializers {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, fixer::Fix, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
fixer::Fix,
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn prefer_function_type_diagnostic(suggestion: &str, span: Span) -> OxcDiagnostic {
|
||||
// FIXME: use imperative message phrasing
|
||||
|
|
@ -397,7 +402,7 @@ impl Rule for PreferFunctionType {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ use oxc_macros::declare_oxc_lint;
|
|||
use oxc_span::Span;
|
||||
use oxc_syntax::operator::{BinaryOperator, UnaryOperator};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn prefer_literal_enum_member_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(
|
||||
|
|
@ -109,7 +113,7 @@ impl Rule for PreferLiteralEnumMember {
|
|||
ctx.diagnostic(prefer_literal_enum_member_diagnostic(decl.span));
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,11 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
AstNode,
|
||||
};
|
||||
|
||||
fn prefer_namespace_keyword_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Use 'namespace' instead of 'module' to declare custom TypeScript modules.")
|
||||
|
|
@ -69,7 +73,7 @@ impl Rule for PreferNamespaceKeyword {
|
|||
});
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
};
|
||||
|
||||
fn prefer_ts_expect_error_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Enforce using `@ts-expect-error` over `@ts-ignore`")
|
||||
|
|
@ -74,7 +77,7 @@ impl Rule for PreferTsExpectError {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule};
|
||||
use crate::{
|
||||
context::{ContextHost, LintContext},
|
||||
rule::Rule,
|
||||
};
|
||||
|
||||
fn triple_slash_reference_diagnostic(ref_kind: &str, span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(format!("Do not use a triple slash reference for {ref_kind}, use `import` style instead."))
|
||||
|
|
@ -163,7 +166,7 @@ impl Rule for TripleSlashReference {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_typescript()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -302,14 +302,14 @@ pub fn is_equality_matcher(matcher: &KnownMemberExpressionProperty) -> bool {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::{path::Path, rc::Rc};
|
||||
use std::rc::Rc;
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_parser::Parser;
|
||||
use oxc_semantic::SemanticBuilder;
|
||||
use oxc_span::SourceType;
|
||||
|
||||
use crate::LintContext;
|
||||
use crate::{options::LintOptions, ContextHost};
|
||||
|
||||
#[test]
|
||||
fn test_is_jest_file() {
|
||||
|
|
@ -320,16 +320,18 @@ mod test {
|
|||
let semantic_ret = SemanticBuilder::new("").with_cfg(true).build(program).semantic;
|
||||
let semantic_ret = Rc::new(semantic_ret);
|
||||
|
||||
let path = Path::new("foo.js");
|
||||
let ctx = LintContext::new(Box::from(path), Rc::clone(&semantic_ret));
|
||||
let build_ctx = |path: &'static str| {
|
||||
Rc::new(ContextHost::new(path, Rc::clone(&semantic_ret), LintOptions::default()))
|
||||
.spawn_for_test()
|
||||
};
|
||||
|
||||
let ctx = build_ctx("foo.js");
|
||||
assert!(!super::is_jest_file(&ctx));
|
||||
|
||||
let path = Path::new("foo.test.js");
|
||||
let ctx = LintContext::new(Box::from(path), Rc::clone(&semantic_ret));
|
||||
let ctx = build_ctx("foo.test.js");
|
||||
assert!(super::is_jest_file(&ctx));
|
||||
|
||||
let path = Path::new("__tests__/foo/test.spec.js");
|
||||
let ctx = LintContext::new(Box::from(path), semantic_ret);
|
||||
let ctx = build_ctx("__tests__/foo/test.spec.js");
|
||||
assert!(super::is_jest_file(&ctx));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_semantic::SymbolId;
|
||||
use oxc_span::Span;
|
||||
|
||||
use crate::{rule::Rule, AstNode, LintContext};
|
||||
use crate::{context::ContextHost, rule::Rule, AstNode, LintContext};
|
||||
|
||||
fn react_perf_inline_diagnostic(message: &'static str, attr_span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn(message)
|
||||
|
|
@ -119,7 +119,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
ctx.source_type().is_jsx()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ pub fn declare_all_lint_rules(metadata: AllLintRulesMeta) -> TokenStream {
|
|||
let expanded = quote! {
|
||||
#(pub use self::#use_stmts::#struct_names;)*
|
||||
|
||||
use crate::{context::LintContext, rule::{Rule, RuleCategory, RuleFixMeta, RuleMeta}, AstNode};
|
||||
use crate::{context::{ContextHost, LintContext}, rule::{Rule, RuleCategory, RuleFixMeta, RuleMeta}, AstNode};
|
||||
use oxc_semantic::SymbolId;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -134,7 +134,7 @@ pub fn declare_all_lint_rules(metadata: AllLintRulesMeta) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn should_run(&self, ctx: &LintContext) -> bool {
|
||||
pub(super) fn should_run(&self, ctx: &ContextHost) -> bool {
|
||||
match self {
|
||||
#(Self::#struct_names(rule) => rule.should_run(ctx)),*
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue