diff --git a/crates/rome_js_analyze/src/analyzers/nursery/no_redundant_use_strict.rs b/crates/rome_js_analyze/src/analyzers/nursery/no_redundant_use_strict.rs index 6d2ec8dcf33..818c1e92153 100644 --- a/crates/rome_js_analyze/src/analyzers/nursery/no_redundant_use_strict.rs +++ b/crates/rome_js_analyze/src/analyzers/nursery/no_redundant_use_strict.rs @@ -2,7 +2,9 @@ use crate::JsRuleAction; use rome_analyze::{context::RuleContext, declare_rule, ActionCategory, Ast, Rule, RuleDiagnostic}; use rome_console::markup; use rome_diagnostics::Applicability; -use rome_js_syntax::{JsDirective, JsDirectiveList, JsFunctionBody, JsModule, JsScript}; +use rome_js_syntax::{ + AnyJsClass, JsDirective, JsDirectiveList, JsFunctionBody, JsModule, JsScript, +}; use rome_rowan::{declare_node_union, AstNode, BatchMutationExt}; @@ -12,13 +14,13 @@ declare_rule! { /// ## Examples /// /// ### Invalid - /// ```js,expect_diagnostic + /// ```cjs,expect_diagnostic /// "use strict"; /// function foo() { /// "use strict"; /// } /// ``` - /// ```js,expect_diagnostic + /// ```cjs,expect_diagnostic /// "use strict"; /// "use strict"; /// @@ -26,19 +28,34 @@ declare_rule! { /// /// } /// ``` - /// ```js,expect_diagnostic + /// ```cjs,expect_diagnostic /// function foo() { /// "use strict"; /// "use strict"; /// } /// ``` + /// ```cjs,expect_diagnostic + /// class C1 { + /// test() { + /// "use strict"; + /// } + /// } + /// ``` + /// ```cjs,expect_diagnostic + /// const C2 = class { + /// test() { + /// "use strict"; + /// } + /// }; + /// + /// ``` /// ### Valid - /// ```js + /// ```cjs /// function foo() { /// /// } ///``` - /// ```js + /// ```cjs /// function foo() { /// "use strict"; /// } @@ -55,44 +72,49 @@ declare_rule! { } } -declare_node_union! { AnyNodeWithDirectives = JsFunctionBody | JsModule | JsScript } +declare_node_union! { AnyNodeWithDirectives = JsFunctionBody | JsScript } impl AnyNodeWithDirectives { fn directives(&self) -> JsDirectiveList { match self { AnyNodeWithDirectives::JsFunctionBody(node) => node.directives(), AnyNodeWithDirectives::JsScript(script) => script.directives(), - AnyNodeWithDirectives::JsModule(module) => module.directives(), } } } +declare_node_union! { pub(crate) AnyJsStrictModeNode = AnyJsClass| JsModule | JsDirective } impl Rule for NoRedundantUseStrict { type Query = Ast; - type State = JsDirective; + type State = AnyJsStrictModeNode; type Signals = Option; type Options = (); fn run(ctx: &RuleContext) -> Self::Signals { let node = ctx.query(); - let mut outer_most: Option = None; - for parent in node - .syntax() - .ancestors() - .filter_map(AnyNodeWithDirectives::cast) - { - for directive in parent.directives() { - if directive.value_token().map_or(false, |t| { - matches!(t.text_trimmed(), "'use strict'" | "\"use strict\"") - }) { - outer_most = Some(directive); - break; // continue with next parent + let mut outer_most: Option = None; + let root = ctx.root(); + match root { + rome_js_syntax::AnyJsRoot::JsModule(js_module) => outer_most = Some(js_module.into()), + _ => { + for n in node.syntax().ancestors() { + if let Some(parent) = AnyNodeWithDirectives::cast_ref(&n) { + for directive in parent.directives() { + let directive_text = directive.inner_string_text().ok()?; + if directive_text == "use strict" { + outer_most = Some(directive.into()); + break; // continue with next parent + } + } + } else if let Some(module_or_class) = AnyJsClass::cast_ref(&n) { + outer_most = Some(module_or_class.into()); + } } } } if let Some(outer_most) = outer_most { // skip itself - if &outer_most == node { + if outer_most.syntax() == node.syntax() { return None; } return Some(outer_most); @@ -101,18 +123,28 @@ impl Rule for NoRedundantUseStrict { None } fn diagnostic(ctx: &RuleContext, state: &Self::State) -> Option { - let diag = RuleDiagnostic::new( + let mut diag = RuleDiagnostic::new( rule_category!(), ctx.query().range(), markup! { "Redundant "{"use strict"}" directive." }, - ) - .detail( - state.range(), - markup! {"This outer "{"use strict"}" directive already enables strict mode."}, ); + match state { + AnyJsStrictModeNode::AnyJsClass(js_class) => diag = diag.detail( + js_class.range(), + markup! {"All parts of a class's body are already in strict mode."}, + ) , + AnyJsStrictModeNode::JsModule(_js_module) => diag= diag.note( + markup! {"The entire contents of "{"JavaScript modules"}" are automatically in strict mode, with no statement needed to initiate it."}, + ), + AnyJsStrictModeNode::JsDirective(js_directive) => diag= diag.detail( + js_directive.range(), + markup! {"This outer "{"use strict"}" directive already enables strict mode."}, + ), + } + Some(diag) } diff --git a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.cjs b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.cjs new file mode 100644 index 00000000000..ef5b97349da --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.cjs @@ -0,0 +1,14 @@ +"use strict"; +"use strict"; + +function test() { + "use strict"; + function inner_a() { + "use strict"; // redundant directive + } + function inner_b() { + function inner_inner() { + "use strict"; // additional redundant directive + } + } +} diff --git a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.cjs.snap b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.cjs.snap new file mode 100644 index 00000000000..e1e824b0a0b --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.cjs.snap @@ -0,0 +1,149 @@ +--- +source: crates/rome_js_analyze/tests/spec_tests.rs +assertion_line: 86 +expression: invalid.cjs +--- +# Input +```js +"use strict"; +"use strict"; + +function test() { + "use strict"; + function inner_a() { + "use strict"; // redundant directive + } + function inner_b() { + function inner_inner() { + "use strict"; // additional redundant directive + } + } +} + +``` + +# Diagnostics +``` +invalid.cjs:2:1 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Redundant use strict directive. + + 1 │ "use strict"; + > 2 │ "use strict"; + │ ^^^^^^^^^^^^^ + 3 │ + 4 │ function test() { + + i This outer use strict directive already enables strict mode. + + > 1 │ "use strict"; + │ ^^^^^^^^^^^^^ + 2 │ "use strict"; + 3 │ + + i Safe fix: Remove the redundant "use strict" directive + + 1 1 │ "use strict"; + 2 │ - "use·strict"; + 3 2 │ + 4 3 │ function test() { + + +``` + +``` +invalid.cjs:5:2 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Redundant use strict directive. + + 4 │ function test() { + > 5 │ "use strict"; + │ ^^^^^^^^^^^^^ + 6 │ function inner_a() { + 7 │ "use strict"; // redundant directive + + i This outer use strict directive already enables strict mode. + + > 1 │ "use strict"; + │ ^^^^^^^^^^^^^ + 2 │ "use strict"; + 3 │ + + i Safe fix: Remove the redundant "use strict" directive + + 3 3 │ + 4 4 │ function test() { + 5 │ - → "use·strict"; + 6 │ - → function·inner_a()·{ + 5 │ + → function·inner_a()·{ + 7 6 │ "use strict"; // redundant directive + 8 7 │ } + + +``` + +``` +invalid.cjs:7:3 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Redundant use strict directive. + + 5 │ "use strict"; + 6 │ function inner_a() { + > 7 │ "use strict"; // redundant directive + │ ^^^^^^^^^^^^^ + 8 │ } + 9 │ function inner_b() { + + i This outer use strict directive already enables strict mode. + + > 1 │ "use strict"; + │ ^^^^^^^^^^^^^ + 2 │ "use strict"; + 3 │ + + i Safe fix: Remove the redundant "use strict" directive + + 5 5 │ "use strict"; + 6 6 │ function inner_a() { + 7 │ - → → "use·strict";·//·redundant·directive + 8 │ - → } + 7 │ + → } + 9 8 │ function inner_b() { + 10 9 │ function inner_inner() { + + +``` + +``` +invalid.cjs:11:4 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Redundant use strict directive. + + 9 │ function inner_b() { + 10 │ function inner_inner() { + > 11 │ "use strict"; // additional redundant directive + │ ^^^^^^^^^^^^^ + 12 │ } + 13 │ } + + i This outer use strict directive already enables strict mode. + + > 1 │ "use strict"; + │ ^^^^^^^^^^^^^ + 2 │ "use strict"; + 3 │ + + i Safe fix: Remove the redundant "use strict" directive + + 9 9 │ function inner_b() { + 10 10 │ function inner_inner() { + 11 │ - → → → "use·strict";·//·additional·redundant·directive + 12 │ - → → } + 11 │ + → → } + 13 12 │ } + 14 13 │ } + + +``` + + diff --git a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.js b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.js index ef5b97349da..e229dd065e2 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.js +++ b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.js @@ -1,14 +1,20 @@ -"use strict"; +// js module "use strict"; -function test() { +function foo() { "use strict"; - function inner_a() { - "use strict"; // redundant directive - } - function inner_b() { - function inner_inner() { - "use strict"; // additional redundant directive - } +} + +class C1 { + // All code here is evaluated in strict mode + test() { + "use strict"; } } + +const C2 = class { + // All code here is evaluated in strict mode + test() { + "use strict"; + } +}; diff --git a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.js.snap index 0b566cd0b0f..a6b7904e3ab 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.js.snap @@ -1,25 +1,31 @@ --- source: crates/rome_js_analyze/tests/spec_tests.rs -assertion_line: 83 +assertion_line: 86 expression: invalid.js --- # Input ```js -"use strict"; +// js module "use strict"; -function test() { +function foo() { "use strict"; - function inner_a() { - "use strict"; // redundant directive - } - function inner_b() { - function inner_inner() { - "use strict"; // additional redundant directive - } +} + +class C1 { + // All code here is evaluated in strict mode + test() { + "use strict"; } } +const C2 = class { + // All code here is evaluated in strict mode + test() { + "use strict"; + } +}; + ``` # Diagnostics @@ -28,25 +34,21 @@ invalid.js:2:1 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━ ! Redundant use strict directive. - 1 │ "use strict"; + 1 │ // js module > 2 │ "use strict"; │ ^^^^^^^^^^^^^ 3 │ - 4 │ function test() { - - i This outer use strict directive already enables strict mode. + 4 │ function foo() { - > 1 │ "use strict"; - │ ^^^^^^^^^^^^^ - 2 │ "use strict"; - 3 │ + i The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it. i Safe fix: Remove the redundant "use strict" directive - 1 1 │ "use strict"; + 1 │ - //·js·module 2 │ - "use·strict"; + 1 │ + 3 2 │ - 4 3 │ function test() { + 4 3 │ function foo() { ``` @@ -56,92 +58,75 @@ invalid.js:5:2 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━ ! Redundant use strict directive. - 4 │ function test() { + 4 │ function foo() { > 5 │ "use strict"; │ ^^^^^^^^^^^^^ - 6 │ function inner_a() { - 7 │ "use strict"; // redundant directive + 6 │ } + 7 │ - i This outer use strict directive already enables strict mode. - - > 1 │ "use strict"; - │ ^^^^^^^^^^^^^ - 2 │ "use strict"; - 3 │ + i The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it. i Safe fix: Remove the redundant "use strict" directive 3 3 │ - 4 4 │ function test() { + 4 4 │ function foo() { 5 │ - → "use·strict"; - 6 │ - → function·inner_a()·{ - 5 │ + → function·inner_a()·{ - 7 6 │ "use strict"; // redundant directive - 8 7 │ } + 6 5 │ } + 7 6 │ ``` ``` -invalid.js:7:3 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:11:3 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Redundant use strict directive. - 5 │ "use strict"; - 6 │ function inner_a() { - > 7 │ "use strict"; // redundant directive - │ ^^^^^^^^^^^^^ - 8 │ } - 9 │ function inner_b() { + 9 │ // All code here is evaluated in strict mode + 10 │ test() { + > 11 │ "use strict"; + │ ^^^^^^^^^^^^^ + 12 │ } + 13 │ } - i This outer use strict directive already enables strict mode. - - > 1 │ "use strict"; - │ ^^^^^^^^^^^^^ - 2 │ "use strict"; - 3 │ + i The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it. i Safe fix: Remove the redundant "use strict" directive - 5 5 │ "use strict"; - 6 6 │ function inner_a() { - 7 │ - → → "use·strict";·//·redundant·directive - 8 │ - → } - 7 │ + → } - 9 8 │ function inner_b() { - 10 9 │ function inner_inner() { + 9 9 │ // All code here is evaluated in strict mode + 10 10 │ test() { + 11 │ - → → "use·strict"; + 12 │ - → } + 11 │ + → } + 13 12 │ } + 14 13 │ ``` ``` -invalid.js:11:4 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:18:3 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Redundant use strict directive. - 9 │ function inner_b() { - 10 │ function inner_inner() { - > 11 │ "use strict"; // additional redundant directive - │ ^^^^^^^^^^^^^ - 12 │ } - 13 │ } - - i This outer use strict directive already enables strict mode. + 16 │ // All code here is evaluated in strict mode + 17 │ test() { + > 18 │ "use strict"; + │ ^^^^^^^^^^^^^ + 19 │ } + 20 │ }; - > 1 │ "use strict"; - │ ^^^^^^^^^^^^^ - 2 │ "use strict"; - 3 │ + i The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it. i Safe fix: Remove the redundant "use strict" directive - 9 9 │ function inner_b() { - 10 10 │ function inner_inner() { - 11 │ - → → → "use·strict";·//·additional·redundant·directive - 12 │ - → → } - 11 │ + → → } - 13 12 │ } - 14 13 │ } + 16 16 │ // All code here is evaluated in strict mode + 17 17 │ test() { + 18 │ - → → "use·strict"; + 19 │ - → } + 18 │ + → } + 20 19 │ }; + 21 20 │ ``` diff --git a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.ts b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.ts new file mode 100644 index 00000000000..375e05e0b24 --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.ts @@ -0,0 +1,3 @@ +function test(): void { + "use strict"; +} diff --git a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.ts.snap b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.ts.snap new file mode 100644 index 00000000000..5cb9f84a0b9 --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalid.ts.snap @@ -0,0 +1,38 @@ +--- +source: crates/rome_js_analyze/tests/spec_tests.rs +assertion_line: 86 +expression: invalid.ts +--- +# Input +```js +function test(): void { + "use strict"; +} + +``` + +# Diagnostics +``` +invalid.ts:2:2 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Redundant use strict directive. + + 1 │ function test(): void { + > 2 │ "use strict"; + │ ^^^^^^^^^^^^^ + 3 │ } + 4 │ + + i The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it. + + i Safe fix: Remove the redundant "use strict" directive + + 1 1 │ function test(): void { + 2 │ - → "use·strict"; + 3 2 │ } + 4 3 │ + + +``` + + diff --git a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidClass.cjs b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidClass.cjs new file mode 100644 index 00000000000..2522e90628b --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidClass.cjs @@ -0,0 +1,11 @@ +class C1 { + test() { + "use strict"; + } +} + +const C2 = class { + test() { + "use strict"; + } +}; diff --git a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidClass.cjs.snap b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidClass.cjs.snap new file mode 100644 index 00000000000..c9c6dc39319 --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidClass.cjs.snap @@ -0,0 +1,98 @@ +--- +source: crates/rome_js_analyze/tests/spec_tests.rs +assertion_line: 86 +expression: invalidClass.cjs +--- +# Input +```js +class C1 { + test() { + "use strict"; + } +} + +const C2 = class { + test() { + "use strict"; + } +}; + +``` + +# Diagnostics +``` +invalidClass.cjs:3:3 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Redundant use strict directive. + + 1 │ class C1 { + 2 │ test() { + > 3 │ "use strict"; + │ ^^^^^^^^^^^^^ + 4 │ } + 5 │ } + + i All parts of a class's body are already in strict mode. + + > 1 │ class C1 { + │ ^^^^^^^^^^ + > 2 │ test() { + > 3 │ "use strict"; + > 4 │ } + > 5 │ } + │ ^ + 6 │ + 7 │ const C2 = class { + + i Safe fix: Remove the redundant "use strict" directive + + 1 1 │ class C1 { + 2 2 │ test() { + 3 │ - → → "use·strict"; + 4 │ - → } + 3 │ + → } + 5 4 │ } + 6 5 │ + + +``` + +``` +invalidClass.cjs:9:3 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Redundant use strict directive. + + 7 │ const C2 = class { + 8 │ test() { + > 9 │ "use strict"; + │ ^^^^^^^^^^^^^ + 10 │ } + 11 │ }; + + i All parts of a class's body are already in strict mode. + + 5 │ } + 6 │ + > 7 │ const C2 = class { + │ ^^^^^^^ + > 8 │ test() { + > 9 │ "use strict"; + > 10 │ } + > 11 │ }; + │ ^ + 12 │ + + i Safe fix: Remove the redundant "use strict" directive + + 7 7 │ const C2 = class { + 8 8 │ test() { + 9 │ - → → "use·strict"; + 10 │ - → } + 9 │ + → } + 11 10 │ }; + 12 11 │ + + +``` + + diff --git a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidFunction.cjs b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidFunction.cjs new file mode 100644 index 00000000000..146815574af --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidFunction.cjs @@ -0,0 +1,4 @@ +function test() { + "use strict"; + "use strict"; +} diff --git a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidFunction.cjs.snap b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidFunction.cjs.snap new file mode 100644 index 00000000000..81c606631bb --- /dev/null +++ b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidFunction.cjs.snap @@ -0,0 +1,47 @@ +--- +source: crates/rome_js_analyze/tests/spec_tests.rs +assertion_line: 86 +expression: invalidFunction.cjs +--- +# Input +```js +function test() { + "use strict"; + "use strict"; +} + +``` + +# Diagnostics +``` +invalidFunction.cjs:3:2 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Redundant use strict directive. + + 1 │ function test() { + 2 │ "use strict"; + > 3 │ "use strict"; + │ ^^^^^^^^^^^^^ + 4 │ } + 5 │ + + i This outer use strict directive already enables strict mode. + + 1 │ function test() { + > 2 │ "use strict"; + │ ^^^^^^^^^^^^^ + 3 │ "use strict"; + 4 │ } + + i Safe fix: Remove the redundant "use strict" directive + + 1 1 │ function test() { + 2 2 │ "use strict"; + 3 │ - → "use·strict"; + 4 3 │ } + 5 4 │ + + +``` + + diff --git a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidFunction.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidFunction.js.snap index ffb5d655d2f..3a8929361d0 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidFunction.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/invalidFunction.js.snap @@ -1,6 +1,6 @@ --- source: crates/rome_js_analyze/tests/spec_tests.rs -assertion_line: 83 +assertion_line: 86 expression: invalidFunction.js --- # Input @@ -14,24 +14,42 @@ function test() { # Diagnostics ``` -invalidFunction.js:3:2 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalidFunction.js:2:2 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Redundant use strict directive. 1 │ function test() { - 2 │ "use strict"; - > 3 │ "use strict"; + > 2 │ "use strict"; │ ^^^^^^^^^^^^^ + 3 │ "use strict"; 4 │ } - 5 │ - i This outer use strict directive already enables strict mode. + i The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it. + + i Safe fix: Remove the redundant "use strict" directive + + 1 1 │ function test() { + 2 2 │ "use strict"; + 3 │ - → "use·strict"; + 4 3 │ } + 5 4 │ + + +``` + +``` +invalidFunction.js:3:2 lint/nursery/noRedundantUseStrict FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Redundant use strict directive. 1 │ function test() { - > 2 │ "use strict"; + 2 │ "use strict"; + > 3 │ "use strict"; │ ^^^^^^^^^^^^^ - 3 │ "use strict"; 4 │ } + 5 │ + + i The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it. i Safe fix: Remove the redundant "use strict" directive diff --git a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/valid.js b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/valid.cjs similarity index 100% rename from crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/valid.js rename to crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/valid.cjs diff --git a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/valid.js.snap b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/valid.cjs.snap similarity index 78% rename from crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/valid.js.snap rename to crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/valid.cjs.snap index aae9688cc56..07f27a4d2bd 100644 --- a/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/valid.js.snap +++ b/crates/rome_js_analyze/tests/specs/nursery/noRedundantUseStrict/valid.cjs.snap @@ -1,7 +1,7 @@ --- source: crates/rome_js_analyze/tests/spec_tests.rs -assertion_line: 83 -expression: valid.js +assertion_line: 86 +expression: valid.cjs --- # Input ```js diff --git a/crates/rome_js_syntax/src/directive_ext.rs b/crates/rome_js_syntax/src/directive_ext.rs new file mode 100644 index 00000000000..78e46c49224 --- /dev/null +++ b/crates/rome_js_syntax/src/directive_ext.rs @@ -0,0 +1,64 @@ +use rome_rowan::{SyntaxResult, SyntaxTokenText, TextSize}; + +use crate::JsDirective; + +impl JsDirective { + /// Get the inner text of a string not including the quotes + /// + /// ## Examples + /// + /// ``` + /// use rome_js_factory::syntax::{JsDirective, JsSyntaxKind::*}; + /// use rome_js_factory::JsSyntaxTreeBuilder; + /// use rome_rowan::AstNode; + /// let mut tree_builder = JsSyntaxTreeBuilder::new(); + /// tree_builder.start_node(JS_DIRECTIVE); + /// tree_builder.token(JS_STRING_LITERAL, "\"use strict\""); + /// tree_builder.finish_node(); + /// let node = tree_builder.finish(); + /// let js_directive = JsDirective::cast(node).unwrap(); + /// let text = js_directive.inner_string_text().unwrap(); + /// assert_eq!(text, "use strict") + /// ``` + pub fn inner_string_text(&self) -> SyntaxResult { + let value = self.value_token()?; + let mut text = value.token_text_trimmed(); + + static QUOTES: [char; 2] = ['"', '\'']; + + if text.starts_with(QUOTES) { + let range = text.range().add_start(TextSize::from(1)); + text = text.slice(range); + } + + if text.ends_with(QUOTES) { + let range = text.range().sub_end(TextSize::from(1)); + text = text.slice(range); + } + + Ok(text) + } +} + +#[cfg(test)] +mod tests { + use rome_js_factory::syntax::{JsDirective, JsSyntaxKind::*}; + use rome_js_factory::JsSyntaxTreeBuilder; + use rome_rowan::AstNode; + + #[test] + fn js_directive_inner_string_text() { + let tokens = vec!["\"use strict\"", "'use strict'"]; + for token in tokens { + let mut tree_builder = JsSyntaxTreeBuilder::new(); + tree_builder.start_node(JS_DIRECTIVE); + tree_builder.token(JS_STRING_LITERAL, token); + tree_builder.finish_node(); + + let node = tree_builder.finish(); + let js_directive = JsDirective::cast(node).unwrap(); + let text = js_directive.inner_string_text().unwrap(); + assert_eq!(text, "use strict") + } + } +} diff --git a/crates/rome_js_syntax/src/lib.rs b/crates/rome_js_syntax/src/lib.rs index 164eacf2864..0eaafd6b701 100644 --- a/crates/rome_js_syntax/src/lib.rs +++ b/crates/rome_js_syntax/src/lib.rs @@ -5,6 +5,7 @@ #[macro_use] mod generated; pub mod binding_ext; +pub mod directive_ext; pub mod expr_ext; pub mod identifier_ext; pub mod import_ext; diff --git a/website/src/pages/lint/rules/noRedundantUseStrict.md b/website/src/pages/lint/rules/noRedundantUseStrict.md index 7481ef9b141..6354eb77570 100644 --- a/website/src/pages/lint/rules/noRedundantUseStrict.md +++ b/website/src/pages/lint/rules/noRedundantUseStrict.md @@ -11,7 +11,7 @@ Prevents from having redundant `"use strict"`. ### Invalid -```jsx +```js "use strict"; function foo() { "use strict"; @@ -46,7 +46,7 @@ function foo() { -```jsx +```js "use strict"; "use strict"; @@ -81,7 +81,7 @@ function foo() { -```jsx +```js function foo() { "use strict"; "use strict"; @@ -117,15 +117,100 @@ function foo() { +```js +class C1 { + test() { + "use strict"; + } +} +``` + +
nursery/noRedundantUseStrict.js:3:3 lint/nursery/noRedundantUseStrict  FIXABLE  ━━━━━━━━━━━━━━━━━━━━
+
+   Redundant use strict directive.
+  
+    1 │ class C1 {
+    2 │ 	test() {
+  > 3 │ 		"use strict";
+   		^^^^^^^^^^^^^
+    4 │ 	}
+    5 │ }
+  
+   All parts of a class's body are already in strict mode.
+  
+  > 1 │ class C1 {
+   ^^^^^^^^^^
+  > 2 │ 	test() {
+  > 3 │ 		"use strict";
+  > 4 │ 	}
+  > 5 │ }
+   ^
+    6 │ 
+  
+   Safe fix: Remove the redundant "use strict" directive
+  
+    1 1  class C1 {
+    2 2  	test() {
+    3  - "use·strict";
+    4  - }
+      3+ }
+    5 4  }
+    6 5  
+  
+
+ +```js +const C2 = class { + test() { + "use strict"; + } +}; + +``` + +
nursery/noRedundantUseStrict.js:3:3 lint/nursery/noRedundantUseStrict  FIXABLE  ━━━━━━━━━━━━━━━━━━━━
+
+   Redundant use strict directive.
+  
+    1 │ const C2 = class {
+    2 │ 	test() {
+  > 3 │ 		"use strict";
+   		^^^^^^^^^^^^^
+    4 │ 	}
+    5 │ };
+  
+   All parts of a class's body are already in strict mode.
+  
+  > 1 │ const C2 = class {
+              ^^^^^^^
+  > 2 │ 	test() {
+  > 3 │ 		"use strict";
+  > 4 │ 	}
+  > 5 │ };
+   ^
+    6 │ 
+  
+   Safe fix: Remove the redundant "use strict" directive
+  
+    1 1  const C2 = class {
+    2 2  	test() {
+    3  - "use·strict";
+    4  - }
+      3+ }
+    5 4  };
+    6 5  
+  
+
+ ### Valid -```jsx +```js function foo() { } ``` -```jsx +```js function foo() { "use strict"; }