feat(rome_js_analyzer): add `noWith` rule
Closes
MODIFY
crates/rome_diagnostics_categories/src/categories.rs
crates/rome_diagnostics_categories/src/categories.rs
@@ -44,6 +44,7 @@ define_dategories! {
// nursery
"lint/nursery/noAccessKey": "https://docs.rome.tools/lint/rules/noAccessKey",
"lint/nursery/noAssignInExpressions": "https://docs.rome.tools/lint/rules/noAssignInExpressions",
+ "lint/nursery/noWith": "https://docs.rome.tools/lint/rules/noWith",
"lint/nursery/noBannedTypes":"https://docs.rome.tools/lint/rules/noBannedTypes",
"lint/nursery/noConstEnum": "https://docs.rome.tools/lint/rules/noConstEnum",
"lint/nursery/noConstructorReturn": "https://docs.rome.tools/lint/rules/noConstructorReturn",

MODIFY
crates/rome_js_analyze/src/analyzers/nursery.rs
crates/rome_js_analyze/src/analyzers/nursery.rs
@@ -21,9 +21,10 @@ mod no_string_case_mismatch;
mod no_unsafe_finally;
mod no_useless_switch_case;
mod no_void_type_return;
+mod no_with;
mod use_default_parameter_last;
mod use_default_switch_clause_last;
mod use_enum_initializers;
mod use_exponentiation_operator;
mod use_numeric_literals;
-declare_group! { pub (crate) Nursery { name : "nursery" , rules : [self :: no_access_key :: NoAccessKey , self :: no_assign_in_expressions :: NoAssignInExpressions , self :: no_banned_types :: NoBannedTypes , self :: no_const_enum :: NoConstEnum , self :: no_constructor_return :: NoConstructorReturn , self :: no_distracting_elements :: NoDistractingElements , self :: no_duplicate_object_keys :: NoDuplicateObjectKeys , self :: no_empty_interface :: NoEmptyInterface , self :: no_extra_non_null_assertion :: NoExtraNonNullAssertion , self :: no_header_scope :: NoHeaderScope , self :: no_invalid_constructor_super :: NoInvalidConstructorSuper , self :: no_non_null_assertion :: NoNonNullAssertion , self :: no_precision_loss :: NoPrecisionLoss , self :: no_redundant_alt :: NoRedundantAlt , self :: no_redundant_use_strict :: NoRedundantUseStrict , self :: no_setter_return :: NoSetterReturn , self :: no_string_case_mismatch :: NoStringCaseMismatch , self :: no_unsafe_finally :: NoUnsafeFinally , self :: no_useless_switch_case :: NoUselessSwitchCase , self :: no_void_type_return :: NoVoidTypeReturn , self :: use_default_parameter_last :: UseDefaultParameterLast , self :: use_default_switch_clause_last :: UseDefaultSwitchClauseLast , self :: use_enum_initializers :: UseEnumInitializers , self :: use_exponentiation_operator :: UseExponentiationOperator , self :: use_numeric_literals :: UseNumericLiterals ,] } }
+declare_group! { pub (crate) Nursery { name : "nursery" , rules : [self :: no_access_key :: NoAccessKey , self :: no_assign_in_expressions :: NoAssignInExpressions , self :: no_banned_types :: NoBannedTypes , self :: no_const_enum :: NoConstEnum , self :: no_constructor_return :: NoConstructorReturn , self :: no_distracting_elements :: NoDistractingElements , self :: no_duplicate_object_keys :: NoDuplicateObjectKeys , self :: no_empty_interface :: NoEmptyInterface , self :: no_extra_non_null_assertion :: NoExtraNonNullAssertion , self :: no_header_scope :: NoHeaderScope , self :: no_invalid_constructor_super :: NoInvalidConstructorSuper , self :: no_non_null_assertion :: NoNonNullAssertion , self :: no_precision_loss :: NoPrecisionLoss , self :: no_redundant_alt :: NoRedundantAlt , self :: no_redundant_use_strict :: NoRedundantUseStrict , self :: no_setter_return :: NoSetterReturn , self :: no_string_case_mismatch :: NoStringCaseMismatch , self :: no_unsafe_finally :: NoUnsafeFinally , self :: no_useless_switch_case :: NoUselessSwitchCase , self :: no_void_type_return :: NoVoidTypeReturn , self :: no_with :: NoWith , self :: use_default_parameter_last :: UseDefaultParameterLast , self :: use_default_switch_clause_last :: UseDefaultSwitchClauseLast , self :: use_enum_initializers :: UseEnumInitializers , self :: use_exponentiation_operator :: UseExponentiationOperator , self :: use_numeric_literals :: UseNumericLiterals ,] } }

ADD
crates/rome_js_analyze/src/analyzers/nursery/no_with.rs
+use rome_analyze::context::RuleContext;
+use rome_analyze::{declare_rule, Ast, Rule, RuleDiagnostic};
+use rome_console::markup;
+use rome_js_syntax::JsWithStatement;
+
+use rome_rowan::AstNode;
+
+declare_rule! {
+ /// Disallow `with` statements in non-strict contexts.
+ ///
+ /// The `with` statement is potentially problematic because it adds members of an object to the current
+ /// scope, making it impossible to tell what a variable inside the block actually refers to.
+ ///
+ /// ## Examples
+ ///
+ /// ### Invalid
+ ///
+ /// ```cjs,expect_diagnostic
+ /// function f() {
+ /// with (point) {
+ /// r = Math.sqrt(x * x + y * y); // is r a member of point?
+ /// }
+ /// }
+ /// ```
+ pub(crate) NoWith {
+ version: "12.0.0",
+ name: "noWith",
+ recommended: true,
+ }
+}
+
+impl Rule for NoWith {
+ type Query = Ast<JsWithStatement>;
+ type State = ();
+ type Signals = Option<Self::State>;
+ type Options = ();
+
+ fn run(_ctx: &RuleContext<Self>) -> Option<Self::State> {
+ Some(())
+ }
+
+ fn diagnostic(ctx: &RuleContext<Self>, _: &Self::State) -> Option<RuleDiagnostic> {
+ let node = ctx.query();
+ Some(RuleDiagnostic::new(
+ rule_category!(),
+ node.range(),
+ markup! {
+ "Unexpected use of "<Emphasis>"with"</Emphasis>" statement."
+ },
+ ).note(
+ "The with statement is potentially problematic because it adds members of an object to the current\nscope, making it impossible to tell what a variable inside the block actually refers to."
+ ))
+ }
+}

ADD
crates/rome_js_analyze/tests/specs/nursery/noWith/invalid.cjs
+function f() {
+ with (point) {
+ r = Math.sqrt(x * x + y * y); // is r a member of point?
+ }
+}
\ No newline at end of file

ADD
crates/rome_js_analyze/tests/specs/nursery/noWith/invalid.js.snap
+---
+source: crates/rome_js_analyze/tests/spec_tests.rs
+expression: invalid.js
+---
+# Input
+```js
+with (point) {
+ r = Math.sqrt(x * x + y * y); // is r a member of point?
+}
+```
+
+

ADD
crates/rome_js_analyze/tests/specs/nursery/noWith/valid.js.snap
+---
+source: crates/rome_js_analyze/tests/spec_tests.rs
+expression: valid.js
+---
+# Input
+```js
+const r = ({x, y}) => Math.sqrt(x * x + y * y);
+```
+
+

MODIFY
crates/rome_service/src/configuration/linter/rules.rs
crates/rome_service/src/configuration/linter/rules.rs
@@ -767,6 +767,8 @@ struct NurserySchema {
no_var: Option<RuleConfiguration>,
#[doc = "Disallow returning a value from a function with the return type 'void'"]
no_void_type_return: Option<RuleConfiguration>,
+ #[doc = "Disallow with statements in non-strict contexts."]
+ no_with: Option<RuleConfiguration>,
#[doc = "Enforce that ARIA state and property values are valid."]
use_aria_prop_types: Option<RuleConfiguration>,
#[doc = "Enforce that elements with ARIA roles must have all required ARIA attributes for that role."]
@@ -792,7 +794,7 @@ struct NurserySchema {
}
impl Nursery {
const CATEGORY_NAME: &'static str = "nursery";
- pub(crate) const CATEGORY_RULES: [&'static str; 33] = [
+ pub(crate) const CATEGORY_RULES: [&'static str; 34] = [
"noAccessKey",
"noAssignInExpressions",
"noBannedTypes",
@@ -815,6 +817,7 @@ impl Nursery {
"noUselessSwitchCase",
"noVar",
"noVoidTypeReturn",
+ "noWith",
"useAriaPropTypes",
"useAriaPropsForRole",
"useCamelCase",
@@ -827,7 +830,7 @@ impl Nursery {
"useHookAtTopLevel",
"useNumericLiterals",
];
- const RECOMMENDED_RULES: [&'static str; 24] = [
+ const RECOMMENDED_RULES: [&'static str; 25] = [
"noAssignInExpressions",
"noBannedTypes",
"noConstEnum",
@@ -845,6 +848,7 @@ impl Nursery {
"noUselessSwitchCase",
"noVar",
"noVoidTypeReturn",
+ "noWith",
"useAriaPropsForRole",
"useConst",
"useDefaultParameterLast",
@@ -853,7 +857,7 @@ impl Nursery {
"useExhaustiveDependencies",
"useNumericLiterals",
];
- const RECOMMENDED_RULES_AS_FILTERS: [RuleFilter<'static>; 24] = [
+ const RECOMMENDED_RULES_AS_FILTERS: [RuleFilter<'static>; 25] = [
RuleFilter::Rule("nursery", Self::CATEGORY_RULES[1]),
RuleFilter::Rule("nursery", Self::CATEGORY_RULES[2]),
RuleFilter::Rule("nursery", Self::CATEGORY_RULES[3]),
@@ -871,13 +875,14 @@ impl Nursery {
RuleFilter::Rule("nursery", Self::CATEGORY_RULES[19]),
RuleFilter::Rule("nursery", Self::CATEGORY_RULES[20]),
RuleFilter::Rule("nursery", Self::CATEGORY_RULES[21]),
- RuleFilter::Rule("nursery", Self::CATEGORY_RULES[23]),
- RuleFilter::Rule("nursery", Self::CATEGORY_RULES[25]),
+ RuleFilter::Rule("nursery", Self::CATEGORY_RULES[22]),
+ RuleFilter::Rule("nursery", Self::CATEGORY_RULES[24]),
RuleFilter::Rule("nursery", Self::CATEGORY_RULES[26]),
RuleFilter::Rule("nursery", Self::CATEGORY_RULES[27]),
RuleFilter::Rule("nursery", Self::CATEGORY_RULES[28]),
RuleFilter::Rule("nursery", Self::CATEGORY_RULES[29]),
- RuleFilter::Rule("nursery", Self::CATEGORY_RULES[32]),
+ RuleFilter::Rule("nursery", Self::CATEGORY_RULES[30]),
+ RuleFilter::Rule("nursery", Self::CATEGORY_RULES[33]),
];
pub(crate) fn is_recommended(&self) -> bool { !matches!(self.recommended, Some(false)) }
pub(crate) fn get_enabled_rules(&self) -> IndexSet<RuleFilter> {
@@ -904,7 +909,7 @@ impl Nursery {
pub(crate) fn is_recommended_rule(rule_name: &str) -> bool {
Self::RECOMMENDED_RULES.contains(&rule_name)
}
- pub(crate) fn recommended_rules_as_filters() -> [RuleFilter<'static>; 24] {
+ pub(crate) fn recommended_rules_as_filters() -> [RuleFilter<'static>; 25] {
Self::RECOMMENDED_RULES_AS_FILTERS
}
}

MODIFY
editors/vscode/configuration_schema.json
editors/vscode/configuration_schema.json
}
]
},
+ "noWith": {
+ "description": "Disallow with statements in non-strict contexts.",
+ "anyOf": [
+ {
+ "$ref": "#/definitions/RuleConfiguration"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
"recommended": {
"description": "It enables the recommended rules for this group",
"type": [

MODIFY
justfile
justfile
@@ -6,7 +6,6 @@ codegen:
cargo codegen-configuration
cargo codegen-schema
cargo codegen-bindings
- cargo codegen-aria
documentation:
cargo lintdoc

MODIFY
npm/backend-jsonrpc/src/workspace.ts
npm/backend-jsonrpc/src/workspace.ts
@@ -373,6 +373,10 @@ export interface Nursery {
* Disallow returning a value from a function with the return type 'void'
*/
noVoidTypeReturn?: RuleConfiguration;
+ /**
+ * Disallow with statements in non-strict contexts.
+ */
+ noWith?: RuleConfiguration;
/**
* It enables the recommended rules for this group
*/
@@ -692,6 +696,7 @@ export type Category =
| "lint/correctness/useValidForDirection"
| "lint/nursery/noAccessKey"
| "lint/nursery/noAssignInExpressions"
+ | "lint/nursery/noWith"
| "lint/nursery/noBannedTypes"
| "lint/nursery/noConstEnum"
| "lint/nursery/noConstructorReturn"

MODIFY
npm/rome/configuration_schema.json
npm/rome/configuration_schema.json
}
]
},
+ "noWith": {
+ "description": "Disallow with statements in non-strict contexts.",
+ "anyOf": [
+ {
+ "$ref": "#/definitions/RuleConfiguration"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
"recommended": {
"description": "It enables the recommended rules for this group",
"type": [

MODIFY
website/src/pages/lint/rules/index.mdx
website/src/pages/lint/rules/index.mdx
@@ -608,6 +608,12 @@ Disallow the use of <code>var</code>
Disallow returning a value from a function with the return type 'void'
</section>
<section class="rule">
+<h3 data-toc-exclude id="noWith">
+ <a href="/lint/rules/noWith">noWith</a>
+</h3>
+Disallow <code>with</code> statements in non-strict contexts.
+</section>
+<section class="rule">
<h3 data-toc-exclude id="useAriaPropTypes">
<a href="/lint/rules/useAriaPropTypes">useAriaPropTypes</a>
</h3>

feat(rome_js_analyzer): add `noWith` rule (#4025)

Closes https://github.com/rome/tools/issues/3993