diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index f82db9fcc..cc9cfa619 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -170,6 +170,7 @@ mod unicorn { pub mod prefer_code_point; pub mod prefer_date_now; pub mod prefer_dom_node_append; + pub mod prefer_dom_node_dataset; pub mod prefer_logical_operator_over_ternary; pub mod prefer_optional_catch_binding; pub mod prefer_query_selector; @@ -321,6 +322,7 @@ oxc_macros::declare_all_lint_rules! { unicorn::prefer_code_point, unicorn::prefer_date_now, unicorn::prefer_dom_node_append, + unicorn::prefer_dom_node_dataset, unicorn::prefer_logical_operator_over_ternary, unicorn::prefer_optional_catch_binding, unicorn::prefer_query_selector, diff --git a/crates/oxc_linter/src/rules/unicorn/prefer_dom_node_dataset.rs b/crates/oxc_linter/src/rules/unicorn/prefer_dom_node_dataset.rs new file mode 100644 index 000000000..9cf0c8d7d --- /dev/null +++ b/crates/oxc_linter/src/rules/unicorn/prefer_dom_node_dataset.rs @@ -0,0 +1,263 @@ +use oxc_ast::{ + ast::{Argument, Expression}, + AstKind, +}; +use oxc_diagnostics::{ + miette::{self, Diagnostic}, + thiserror::Error, +}; +use oxc_macros::declare_oxc_lint; +use oxc_span::Span; + +use crate::{context::LintContext, rule::Rule, AstNode}; + +#[derive(Debug, Error, Diagnostic)] +enum PreferDomNodeDatasetDiagnostic { + #[error("eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`.")] + #[diagnostic( + severity(warning), + help("Access the `.dataset` object directly: `element.dataset.{1} = ...;`") + )] + Set(#[label] Span, String), + #[error("eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`.")] + #[diagnostic( + severity(warning), + help("Access the `.dataset` object directly: `element.dataset.{1}`") + )] + Get(#[label] Span, String), + #[error("eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`.")] + #[diagnostic( + severity(warning), + help("Check the `dataset` object directly: `Object.hasOwn(element.dataset, '{1}')") + )] + Has(#[label] Span, String), + #[error("eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`.")] + #[diagnostic( + severity(warning), + help("Access the `.dataset` object directly: `delete element.dataset.{1};") + )] + Remove(#[label] Span, String), +} + +#[derive(Debug, Default, Clone)] +pub struct PreferDomNodeDataset; + +declare_oxc_lint!( + /// ### What it does + /// + /// Use [`.dataset`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset) on DOM elements over `getAttribute(โ€ฆ)`, `.setAttribute(โ€ฆ)`, `.removeAttribute(โ€ฆ)` and `.hasAttribute(โ€ฆ)`. + /// + /// ### Why is this bad? + /// + /// The `dataset` property is a map of strings that contains all the `data-*` attributes from the element. It is a convenient way to access all of them at once. + /// + /// ### Example + /// ```javascript + /// // Bad + /// element.setAttribute('data-unicorn', '๐Ÿฆ„'); + /// + /// // Good + /// element.dataset.unicorn = '๐Ÿฆ„'; + /// ``` + PreferDomNodeDataset, + pedantic +); + +impl Rule for PreferDomNodeDataset { + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { + let AstKind::CallExpression(call_expr) = node.kind() else { + return; + }; + + let Some(member_expr) = call_expr.callee.get_member_expr() else { return }; + + if member_expr.is_computed() { + return; + } + + let Some((span, method_name)) = member_expr.static_property_info() else { return }; + + match method_name { + "setAttribute" => { + if call_expr.arguments.len() != 2 { + return; + } + } + "getAttribute" | "removeAttribute" | "hasAttribute" => { + if call_expr.arguments.len() != 1 { + return; + } + } + _ => return, + } + + let Argument::Expression(Expression::StringLiteral(string_lit)) = &call_expr.arguments[0] + else { + return; + }; + + let Some(dataset_property_name) = strip_data_prefix(&string_lit.value) else { + return; + }; + + match method_name { + "setAttribute" => { + ctx.diagnostic(PreferDomNodeDatasetDiagnostic::Set(span, dataset_property_name)); + } + "getAttribute" => { + ctx.diagnostic(PreferDomNodeDatasetDiagnostic::Get(span, dataset_property_name)); + } + + "removeAttribute" => ctx.diagnostic(PreferDomNodeDatasetDiagnostic::Remove( + string_lit.span, + dataset_property_name, + )), + + "hasAttribute" => { + ctx.diagnostic(PreferDomNodeDatasetDiagnostic::Has(span, dataset_property_name)); + } + + _ => unreachable!(), + } + } +} + +fn strip_data_prefix(s: &str) -> Option { + let prefix = "data-"; + if s.len() >= prefix.len() && s[..prefix.len()].eq_ignore_ascii_case(prefix) { + Some(s[prefix.len()..].to_string()) + } else { + None + } +} + +#[test] +fn test() { + use crate::tester::Tester; + + let pass = vec![ + r#"element.dataset.unicorn = '๐Ÿฆ„';"#, + r#"element.dataset['unicorn'] = '๐Ÿฆ„';"#, + r#"new element.setAttribute('data-unicorn', '๐Ÿฆ„');"#, + r#"setAttribute('data-unicorn', '๐Ÿฆ„');"#, + r#"element['setAttribute']('data-unicorn', '๐Ÿฆ„');"#, + r#"element[setAttribute]('data-unicorn', '๐Ÿฆ„');"#, + r#"element.foo('data-unicorn', '๐Ÿฆ„');"#, + r#"element.setAttribute('data-unicorn', '๐Ÿฆ„', 'extra');"#, + r#"element.setAttribute('data-unicorn');"#, + r#"element.setAttribute(...argumentsArray, ...argumentsArray2)"#, + r#"element.setAttribute(`data-unicorn`, '๐Ÿฆ„');"#, + r#"element.setAttribute(0, '๐Ÿฆ„');"#, + r#"element.setAttribute('foo-unicorn', '๐Ÿฆ„');"#, + r#"element.setAttribute('data', '๐Ÿฆ„');"#, + r#"delete element.dataset.unicorn;"#, + r#"delete element.dataset["unicorn"];"#, + r#"new element.removeAttribute("data-unicorn");"#, + r#"removeAttribute("data-unicorn");"#, + r#"element["removeAttribute"]("data-unicorn");"#, + r#"element[removeAttribute]("data-unicorn");"#, + r#"element.foo("data-unicorn");"#, + r#"element.removeAttribute("data-unicorn", "extra");"#, + r#"element.removeAttribute();"#, + r#"element.removeAttribute(...argumentsArray, ...argumentsArray2)"#, + r#"element.removeAttribute(`data-unicorn`);"#, + r#"element.removeAttribute(0);"#, + r#"element.removeAttribute("foo-unicorn");"#, + r#"element.removeAttribute("data");"#, + r#""unicorn" in element.dataset"#, + r#"element.dataset.hasOwnProperty("unicorn")"#, + r#"Object.prototype.hasOwnProperty.call(element.dataset, "unicorn")"#, + r#"Object.hasOwn(element.dataset, "unicorn")"#, + r#"Reflect.has(element.dataset, "unicorn")"#, + r#"new element.hasAttribute("data-unicorn");"#, + r#"hasAttribute("data-unicorn");"#, + r#"element["hasAttribute"]("data-unicorn");"#, + r#"element[hasAttribute]("data-unicorn");"#, + r#"element.foo("data-unicorn");"#, + r#"element.hasAttribute("data-unicorn", "extra");"#, + r#"element.hasAttribute();"#, + r#"element.hasAttribute(...argumentsArray, ...argumentsArray2)"#, + r#"element.hasAttribute(`data-unicorn`);"#, + r#"element.hasAttribute(0);"#, + r#"element.hasAttribute("foo-unicorn");"#, + r#"element.hasAttribute("data");"#, + r#"element.dataset.unicorn"#, + r#"new element.getAttribute("data-unicorn");"#, + r#"getAttribute("data-unicorn");"#, + r#"element["getAttribute"]("data-unicorn");"#, + r#"element[getAttribute]("data-unicorn");"#, + r#"element.foo("data-unicorn");"#, + r#"element.getAttribute("data-unicorn", "extra");"#, + r#"element.getAttribute();"#, + r#"element.getAttribute(...argumentsArray, ...argumentsArray2)"#, + r#"element.getAttribute(`data-unicorn`);"#, + r#"element.getAttribute(0);"#, + r#"element.getAttribute("foo-unicorn");"#, + r#"element.getAttribute("data");"#, + ]; + + let fail = vec![ + r#"element.setAttribute('data-unicorn', '๐Ÿฆ„');"#, + r#"element.setAttribute('data-๐Ÿฆ„', '๐Ÿฆ„');"#, + r#"element.setAttribute('data-ใ‚†', 'ใ‚†');"#, + r#"element.setAttribute('data-foo2', '๐Ÿฆ„');"#, + r#"element.setAttribute('data-foo:bar', 'zaz');"#, + r#"element.setAttribute("data-foo:bar", "zaz");"#, + r#"element.setAttribute('data-foo.bar', 'zaz');"#, + r#"element.setAttribute('data-foo-bar', 'zaz');"#, + r#"element.setAttribute('data-foo', /* comment */ 'bar');"#, + r#"element.querySelector('#selector').setAttribute('data-AllowAccess', true);"#, + r#"element.setAttribute("data-", "๐Ÿฆ„");"#, + r#"element.setAttribute("data--foo", "๐Ÿฆ„");"#, + r#"element.setAttribute("DATA--FOO", "๐Ÿฆ„");"#, + r#"element.setAttribute("DATA- ", "๐Ÿฆ„");"#, + r#"element.setAttribute("DATA-Foo-bar", "๐Ÿฆ„");"#, + r#"optional?.element.setAttribute("data-unicorn", "๐Ÿฆ„");"#, + r#"console.log(element.setAttribute("data-unicorn", "๐Ÿฆ„"))"#, + r#"element.removeAttribute('data-unicorn');"#, + r#"element.removeAttribute("data-unicorn");"#, + r#"element.removeAttribute("data-unicorn",);"#, + r#"element.removeAttribute("data-๐Ÿฆ„");"#, + r#"element.removeAttribute("data-ใ‚†");"#, + r#"element.removeAttribute("data-foo2");"#, + r#"element.removeAttribute("data-foo:bar");"#, + r#"element.removeAttribute("data-foo:bar");"#, + r#"element.removeAttribute("data-foo.bar");"#, + r#"element.removeAttribute("data-foo-bar");"#, + r#"element.removeAttribute("data-foo");"#, + r##"element.querySelector("#selector").removeAttribute("data-AllowAccess");"##, + r#"element.removeAttribute("data-");"#, + r#"optional?.element.removeAttribute("data-unicorn");"#, + r#"element.removeAttribute("data-unicorn")?.property"#, + r#"element.hasAttribute('data-unicorn');"#, + r#"element.hasAttribute("data-unicorn");"#, + r#"element.hasAttribute("data-unicorn",);"#, + r#"element.hasAttribute("data-๐Ÿฆ„");"#, + r#"element.hasAttribute("data-ใ‚†");"#, + r#"element.hasAttribute("data-foo2");"#, + r#"element.hasAttribute("data-foo:bar");"#, + r#"element.hasAttribute("data-foo:bar");"#, + r#"element.hasAttribute("data-foo.bar");"#, + r#"element.hasAttribute("data-foo-bar");"#, + r#"element.hasAttribute("data-foo");"#, + r##"element.querySelector("#selector").hasAttribute("data-AllowAccess");"##, + r#"optional?.element.hasAttribute("data-unicorn");"#, + r#"element.hasAttribute("data-unicorn").toString()"#, + r#"element.getAttribute('data-unicorn');"#, + r#"element.getAttribute("data-unicorn");"#, + r#"element.getAttribute("data-unicorn",);"#, + r#"element.getAttribute("data-๐Ÿฆ„");"#, + r#"element.getAttribute("data-ใ‚†");"#, + r#"element.getAttribute("data-foo2");"#, + r#"element.getAttribute("data-foo:bar");"#, + r#"element.getAttribute("data-foo:bar");"#, + r#"element.getAttribute("data-foo.bar");"#, + r#"element.getAttribute("data-foo-bar");"#, + r#"element.getAttribute("data-foo");"#, + r##"element.querySelector("#selector").getAttribute("data-AllowAccess");"##, + r#"optional?.element.getAttribute("data-unicorn");"#, + r#"element.getAttribute("data-unicorn").toString()"#, + ]; + + Tester::new_without_config(PreferDomNodeDataset::NAME, pass, fail).test_and_snapshot(); +} diff --git a/crates/oxc_linter/src/snapshots/prefer_dom_node_dataset.snap b/crates/oxc_linter/src/snapshots/prefer_dom_node_dataset.snap new file mode 100644 index 000000000..d0d43d90c --- /dev/null +++ b/crates/oxc_linter/src/snapshots/prefer_dom_node_dataset.snap @@ -0,0 +1,425 @@ +--- +source: crates/oxc_linter/src/tester.rs +expression: prefer_dom_node_dataset +--- + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute('data-unicorn', '๐Ÿฆ„'); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.unicorn = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute('data-๐Ÿฆ„', '๐Ÿฆ„'); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.๐Ÿฆ„ = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute('data-ใ‚†', 'ใ‚†'); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.ใ‚† = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute('data-foo2', '๐Ÿฆ„'); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.foo2 = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute('data-foo:bar', 'zaz'); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.foo:bar = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute("data-foo:bar", "zaz"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.foo:bar = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute('data-foo.bar', 'zaz'); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.foo.bar = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute('data-foo-bar', 'zaz'); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.foo-bar = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute('data-foo', /* comment */ 'bar'); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.foo = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.querySelector('#selector').setAttribute('data-AllowAccess', true); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.AllowAccess = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute("data-", "๐Ÿฆ„"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset. = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute("data--foo", "๐Ÿฆ„"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.-foo = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute("DATA--FOO", "๐Ÿฆ„"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.-FOO = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute("DATA- ", "๐Ÿฆ„"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset. = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.setAttribute("DATA-Foo-bar", "๐Ÿฆ„"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.Foo-bar = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ optional?.element.setAttribute("data-unicorn", "๐Ÿฆ„"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.unicorn = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `setAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ console.log(element.setAttribute("data-unicorn", "๐Ÿฆ„")) + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.unicorn = ...;` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.removeAttribute('data-unicorn'); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.unicorn; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.removeAttribute("data-unicorn"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.unicorn; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.removeAttribute("data-unicorn",); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.unicorn; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.removeAttribute("data-๐Ÿฆ„"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.๐Ÿฆ„; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.removeAttribute("data-ใ‚†"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.ใ‚†; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.removeAttribute("data-foo2"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.foo2; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.removeAttribute("data-foo:bar"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.foo:bar; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.removeAttribute("data-foo:bar"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.foo:bar; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.removeAttribute("data-foo.bar"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.foo.bar; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.removeAttribute("data-foo-bar"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.foo-bar; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.removeAttribute("data-foo"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.foo; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.querySelector("#selector").removeAttribute("data-AllowAccess"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.AllowAccess; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.removeAttribute("data-"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ optional?.element.removeAttribute("data-unicorn"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.unicorn; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `removeAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.removeAttribute("data-unicorn")?.property + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `delete element.dataset.unicorn; + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.hasAttribute('data-unicorn'); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, 'unicorn') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.hasAttribute("data-unicorn"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, 'unicorn') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.hasAttribute("data-unicorn",); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, 'unicorn') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.hasAttribute("data-๐Ÿฆ„"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, '๐Ÿฆ„') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.hasAttribute("data-ใ‚†"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, 'ใ‚†') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.hasAttribute("data-foo2"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, 'foo2') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.hasAttribute("data-foo:bar"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, 'foo:bar') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.hasAttribute("data-foo:bar"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, 'foo:bar') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.hasAttribute("data-foo.bar"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, 'foo.bar') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.hasAttribute("data-foo-bar"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, 'foo-bar') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.hasAttribute("data-foo"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, 'foo') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.querySelector("#selector").hasAttribute("data-AllowAccess"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, 'AllowAccess') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ optional?.element.hasAttribute("data-unicorn"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, 'unicorn') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `hasAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.hasAttribute("data-unicorn").toString() + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Check the `dataset` object directly: `Object.hasOwn(element.dataset, 'unicorn') + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.getAttribute('data-unicorn'); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.unicorn` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.getAttribute("data-unicorn"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.unicorn` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.getAttribute("data-unicorn",); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.unicorn` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.getAttribute("data-๐Ÿฆ„"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.๐Ÿฆ„` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.getAttribute("data-ใ‚†"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.ใ‚†` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.getAttribute("data-foo2"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.foo2` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.getAttribute("data-foo:bar"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.foo:bar` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.getAttribute("data-foo:bar"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.foo:bar` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.getAttribute("data-foo.bar"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.foo.bar` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.getAttribute("data-foo-bar"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.foo-bar` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.getAttribute("data-foo"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.foo` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.querySelector("#selector").getAttribute("data-AllowAccess"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.AllowAccess` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ optional?.element.getAttribute("data-unicorn"); + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.unicorn` + + โš  eslint-plugin-unicorn(prefer-dom-node-dataset): Prefer using `dataset` over `getAttribute`. + โ•ญโ”€[prefer_dom_node_dataset.tsx:1:1] + 1 โ”‚ element.getAttribute("data-unicorn").toString() + ยท โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + โ•ฐโ”€โ”€โ”€โ”€ + help: Access the `.dataset` object directly: `element.dataset.unicorn` + +