mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(linter) eslint plugin unicorn: no this assignment (#1250)
This commit is contained in:
parent
8496156bb7
commit
11b43fa528
3 changed files with 182 additions and 0 deletions
|
|
@ -156,6 +156,7 @@ mod unicorn {
|
|||
pub mod no_object_as_default_parameter;
|
||||
pub mod no_static_only_class;
|
||||
pub mod no_thenable;
|
||||
pub mod no_this_assignment;
|
||||
pub mod no_unnecessary_await;
|
||||
pub mod no_useless_fallback_in_spread;
|
||||
pub mod prefer_add_event_listener;
|
||||
|
|
@ -298,6 +299,7 @@ oxc_macros::declare_all_lint_rules! {
|
|||
unicorn::no_object_as_default_parameter,
|
||||
unicorn::no_static_only_class,
|
||||
unicorn::no_thenable,
|
||||
unicorn::no_this_assignment,
|
||||
unicorn::no_unnecessary_await,
|
||||
unicorn::no_useless_fallback_in_spread,
|
||||
unicorn::prefer_add_event_listener,
|
||||
|
|
|
|||
147
crates/oxc_linter/src/rules/unicorn/no_this_assignment.rs
Normal file
147
crates/oxc_linter/src/rules/unicorn/no_this_assignment.rs
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
use oxc_ast::{
|
||||
ast::{AssignmentTarget, BindingPatternKind, Expression, SimpleAssignmentTarget},
|
||||
AstKind,
|
||||
};
|
||||
use oxc_diagnostics::{
|
||||
miette::{self, Diagnostic},
|
||||
thiserror::{self, Error},
|
||||
};
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{Atom, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
#[error("eslint-plugin-unicorn(no-this-assignment): Do not assign `this` to `{1}`")]
|
||||
#[diagnostic(
|
||||
severity(warning),
|
||||
help("Reference `this` directly instead of assigning it to a variable.")
|
||||
)]
|
||||
struct NoThisAssignmentDiagnostic(#[label] pub Span, Atom);
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NoThisAssignment;
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
///
|
||||
/// Disallow assigning `this` to a variable.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// Assigning `this` to a variable is unnecessary and confusing.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```javascript
|
||||
/// // fail
|
||||
/// const foo = this;
|
||||
/// class Bar {
|
||||
/// method() {
|
||||
/// foo.baz();
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// new Bar().method();
|
||||
///
|
||||
/// // pass
|
||||
/// class Bar {
|
||||
/// constructor(fooInstance) {
|
||||
/// this.fooInstance = fooInstance;
|
||||
/// }
|
||||
/// method() {
|
||||
/// this.fooInstance.baz();
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// new Bar(this).method();
|
||||
/// ```
|
||||
NoThisAssignment,
|
||||
pedantic
|
||||
);
|
||||
|
||||
impl Rule for NoThisAssignment {
|
||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
match node.kind() {
|
||||
AstKind::VariableDeclarator(variable_decl) => {
|
||||
let Some(init) = &variable_decl.init else {
|
||||
return;
|
||||
};
|
||||
|
||||
if !matches!(init.without_parenthesized(), Expression::ThisExpression(_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let BindingPatternKind::BindingIdentifier(binding_ident) = &variable_decl.id.kind
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
ctx.diagnostic(NoThisAssignmentDiagnostic(
|
||||
variable_decl.span,
|
||||
binding_ident.name.clone(),
|
||||
));
|
||||
}
|
||||
AstKind::AssignmentExpression(assignment_expr) => {
|
||||
if !matches!(
|
||||
assignment_expr.right.without_parenthesized(),
|
||||
Expression::ThisExpression(_)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
let AssignmentTarget::SimpleAssignmentTarget(simple_assignment_target) =
|
||||
&assignment_expr.left
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let SimpleAssignmentTarget::AssignmentTargetIdentifier(ident) =
|
||||
simple_assignment_target
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
ctx.diagnostic(NoThisAssignmentDiagnostic(
|
||||
assignment_expr.span,
|
||||
ident.name.clone(),
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
r#"const {property} = this;"#,
|
||||
r#"const property = this.property;"#,
|
||||
r#"const [element] = this;"#,
|
||||
r#"const element = this[0];"#,
|
||||
r#"([element] = this);"#,
|
||||
r#"element = this[0];"#,
|
||||
r#"property = this.property;"#,
|
||||
r#"const [element] = [this];"#,
|
||||
r#"([element] = [this]);"#,
|
||||
r#"const {property} = {property: this};"#,
|
||||
r#"({property} = {property: this});"#,
|
||||
r#"const self = true && this;"#,
|
||||
r#"const self = false || this;"#,
|
||||
r#"const self = false ?? this;"#,
|
||||
r#"foo.bar = this;"#,
|
||||
r#"function foo(a = this) {}"#,
|
||||
r#"function foo({a = this}) {}"#,
|
||||
r#"function foo([a = this]) {}"#,
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
r#"const foo = this;"#,
|
||||
r#"let foo;foo = this;"#,
|
||||
r#"var foo = bar, baz = this;"#,
|
||||
r#"var foo = (bar), baz = (this);"#,
|
||||
];
|
||||
|
||||
Tester::new_without_config(NoThisAssignment::NAME, pass, fail).test_and_snapshot();
|
||||
}
|
||||
33
crates/oxc_linter/src/snapshots/no_this_assignment.snap
Normal file
33
crates/oxc_linter/src/snapshots/no_this_assignment.snap
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
expression: no_this_assignment
|
||||
---
|
||||
⚠ eslint-plugin-unicorn(no-this-assignment): Do not assign `this` to `foo`
|
||||
╭─[no_this_assignment.tsx:1:1]
|
||||
1 │ const foo = this;
|
||||
· ──────────
|
||||
╰────
|
||||
help: Reference `this` directly instead of assigning it to a variable.
|
||||
|
||||
⚠ eslint-plugin-unicorn(no-this-assignment): Do not assign `this` to `foo`
|
||||
╭─[no_this_assignment.tsx:1:1]
|
||||
1 │ let foo;foo = this;
|
||||
· ──────────
|
||||
╰────
|
||||
help: Reference `this` directly instead of assigning it to a variable.
|
||||
|
||||
⚠ eslint-plugin-unicorn(no-this-assignment): Do not assign `this` to `baz`
|
||||
╭─[no_this_assignment.tsx:1:1]
|
||||
1 │ var foo = bar, baz = this;
|
||||
· ──────────
|
||||
╰────
|
||||
help: Reference `this` directly instead of assigning it to a variable.
|
||||
|
||||
⚠ eslint-plugin-unicorn(no-this-assignment): Do not assign `this` to `baz`
|
||||
╭─[no_this_assignment.tsx:1:1]
|
||||
1 │ var foo = (bar), baz = (this);
|
||||
· ────────────
|
||||
╰────
|
||||
help: Reference `this` directly instead of assigning it to a variable.
|
||||
|
||||
|
||||
Loading…
Reference in a new issue