diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index d1c8a2b7c..4532baa0c 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -81,6 +81,7 @@ mod eslint { pub mod no_import_assign; pub mod no_inner_declarations; pub mod no_irregular_whitespace; + pub mod no_iterator; pub mod no_loss_of_precision; pub mod no_mixed_operators; pub mod no_new_symbol; @@ -409,6 +410,7 @@ oxc_macros::declare_all_lint_rules! { eslint::no_import_assign, eslint::no_inner_declarations, eslint::no_irregular_whitespace, + eslint::no_iterator, eslint::no_loss_of_precision, eslint::no_mixed_operators, eslint::no_new_symbol, diff --git a/crates/oxc_linter/src/rules/eslint/no_iterator.rs b/crates/oxc_linter/src/rules/eslint/no_iterator.rs new file mode 100644 index 000000000..91a67b920 --- /dev/null +++ b/crates/oxc_linter/src/rules/eslint/no_iterator.rs @@ -0,0 +1,71 @@ +use oxc_ast::AstKind; +use oxc_diagnostics::{ + miette::{self, Diagnostic}, + thiserror::Error, +}; +use oxc_macros::declare_oxc_lint; +use oxc_span::{GetSpan, Span}; + +use crate::{context::LintContext, rule::Rule, AstNode}; + +#[derive(Debug, Error, Diagnostic)] +#[error("eslint(no-iterator): Reserved name '__iterator__'")] +#[diagnostic(severity(warning), help("Disallow the use of the `__iterator__` property."))] +struct NoIteratorDiagnostic(#[label] pub Span); + +#[derive(Debug, Default, Clone)] +pub struct NoIterator; + +declare_oxc_lint!( + /// ### What it does + /// Disallow the use of the __iterator__ property + /// + /// ### Why is this bad? + /// The __iterator__ property was a SpiderMonkey extension to JavaScript that could be used to create custom iterators that are compatible with JavaScript’s for in and for each constructs. However, this property is now obsolete, so it should not be used. Here’s an example of how this used to work: + /// + /// ### Example + /// ```javascript + /// Foo.prototype.__iterator__ = function() { + /// return new FooIterator(this); + /// } + /// ``` + NoIterator, + restriction +); + +impl Rule for NoIterator { + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { + let AstKind::MemberExpression(member_expression) = node.kind() else { return }; + if let Some(static_property_name) = member_expression.static_property_name() { + if static_property_name == "__iterator__" { + ctx.diagnostic(NoIteratorDiagnostic(Span::new( + member_expression.span().start, + member_expression.span().end, + ))); + } + } + } +} + +#[test] +fn test() { + use crate::tester::Tester; + + let pass = vec![ + "var a = test[__iterator__];", + "var __iterator__ = null;", + "foo[`__iterator`] = null;", + "foo[`__iterator__ + `] = null;", + ]; + + let fail = vec![ + "var a = test.__iterator__;", + "Foo.prototype.__iterator__ = function() {};", + "var a = test['__iterator__'];", + "var a = test[`__iterator__`];", + "test[`__iterator__`] = function () {};", + ]; + + Tester::new(NoIterator::NAME, pass, fail).test_and_snapshot(); +} diff --git a/crates/oxc_linter/src/snapshots/no_iterator.snap b/crates/oxc_linter/src/snapshots/no_iterator.snap new file mode 100644 index 000000000..a08340eda --- /dev/null +++ b/crates/oxc_linter/src/snapshots/no_iterator.snap @@ -0,0 +1,38 @@ +--- +source: crates/oxc_linter/src/tester.rs +expression: no_iterator +--- + ⚠ eslint(no-iterator): Reserved name '__iterator__' + ╭─[no_iterator.tsx:1:9] + 1 │ var a = test.__iterator__; + · ───────────────── + ╰──── + help: Disallow the use of the `__iterator__` property. + + ⚠ eslint(no-iterator): Reserved name '__iterator__' + ╭─[no_iterator.tsx:1:1] + 1 │ Foo.prototype.__iterator__ = function() {}; + · ────────────────────────── + ╰──── + help: Disallow the use of the `__iterator__` property. + + ⚠ eslint(no-iterator): Reserved name '__iterator__' + ╭─[no_iterator.tsx:1:9] + 1 │ var a = test['__iterator__']; + · ──────────────────── + ╰──── + help: Disallow the use of the `__iterator__` property. + + ⚠ eslint(no-iterator): Reserved name '__iterator__' + ╭─[no_iterator.tsx:1:9] + 1 │ var a = test[`__iterator__`]; + · ──────────────────── + ╰──── + help: Disallow the use of the `__iterator__` property. + + ⚠ eslint(no-iterator): Reserved name '__iterator__' + ╭─[no_iterator.tsx:1:1] + 1 │ test[`__iterator__`] = function () {}; + · ──────────────────── + ╰──── + help: Disallow the use of the `__iterator__` property.