Skip to content

Commit

Permalink
feat(lint/noGlobalAssign): add rule (#1377)
Browse files Browse the repository at this point in the history
Co-authored-by: Victorien Elvinger <victorien@elvinger.fr>
  • Loading branch information
chansuke and Conaclos authored Jan 6, 2024
1 parent ec403e8 commit a42f202
Show file tree
Hide file tree
Showing 17 changed files with 491 additions and 57 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ Biome now scores 97% compatibility with Prettier and features more than 180 lint
- Add [noGlobalEval](https://biomejs.dev/linter/rules/no-global-eval) that reports any use of the global `eval`.
Contributed by @you-5805
- Add [noGlobalAssign](https://biomejs.dev/linter/rules/no-global-assign) that reports assignment to global variables. Contributed by @chansuke
```js
Object = {}; // report assignment to `Object`.
```
#### Enhancements
- Address [#959](https://github.com/biomejs/biome/issues/959) and [#1157](https://github.com/biomejs/biome/issues/1157). [noEmptyInterface](https://biomejs.dev/linter/rules/no-empty-interface) no longer reports empty interfaces that extend a type. Contributed by @Conaclos
Expand Down
1 change: 1 addition & 0 deletions crates/biome_diagnostics_categories/src/categories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ define_categories! {
"lint/nursery/noDuplicateJsonKeys": "https://biomejs.dev/linter/rules/no-duplicate-json-keys",
"lint/nursery/noEmptyBlockStatements": "https://biomejs.dev/linter/rules/no-empty-block-statements",
"lint/nursery/noGlobalEval": "https://biomejs.dev/linter/rules/no-global-eval",
"lint/nursery/noGlobalAssign": "https://biomejs.dev/linter/rules/no-global-assign",
"lint/nursery/noImplicitAnyLet": "https://biomejs.dev/linter/rules/no-implicit-any-let",
"lint/nursery/noInvalidUseBeforeDeclaration": "https://biomejs.dev/linter/rules/no-invalid-use-before-declaration",
"lint/nursery/noMisleadingCharacterClass": "https://biomejs.dev/linter/rules/no-misleading-character-class",
Expand Down
2 changes: 2 additions & 0 deletions crates/biome_js_analyze/src/semantic_analyzers/nursery.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use crate::globals::browser::BROWSER;
use crate::globals::node::NODE;
use crate::globals::runtime::{BUILTIN, ES_2021};

use crate::semantic_services::SemanticServices;
use biome_analyze::{context::RuleContext, declare_rule, Rule, RuleDiagnostic};
use biome_console::markup;
use biome_js_syntax::{JsSyntaxKind, TextRange};

declare_rule! {
/// Disallow assignments to native objects and read-only global variables.
///
/// _JavaScript environments contain numerous built-in global variables, such as `window` in browsers and `process` in _Node.js.
/// Assigning values to these global variables can be problematic as it can override essential functionality.
///
/// Source: https://eslint.org/docs/latest/rules/no-global-assign
///
/// ## Examples
///
/// ### Invalid
///
/// ```js,expect_diagnostic
/// Object = null;
/// ```
///
/// ```js,expect_diagnostic
/// window = {};
/// ```
///
/// ```js,expect_diagnostic
/// undefined = true;
/// ```
///
/// ## Valid
///
/// ```js
/// a = 0;
/// ```
///
/// ```js
/// let window;
/// window = {};
/// ```
pub(crate) NoGlobalAssign {
version: "next",
name: "noGlobalAssign",
recommended: true,
}
}

impl Rule for NoGlobalAssign {
type Query = SemanticServices;
type State = TextRange;
type Signals = Vec<Self::State>;
type Options = ();

fn run(ctx: &RuleContext<Self>) -> Self::Signals {
let global_refs = ctx.query().all_unresolved_references();
let mut result = vec![];
for global_ref in global_refs {
let is_write = global_ref.syntax().kind() == JsSyntaxKind::JS_IDENTIFIER_ASSIGNMENT;
if is_write {
let identifier = global_ref.syntax().text_trimmed();
let text = identifier.to_string();
let is_global_var = NODE.binary_search(&text.as_str()).is_ok()
|| BROWSER.binary_search(&text.as_str()).is_ok()
|| BUILTIN.binary_search(&text.as_str()).is_ok()
|| ES_2021.binary_search(&text.as_str()).is_ok();
if is_global_var {
result.push(*global_ref.range());
}
}
}
result
}

fn diagnostic(_ctx: &RuleContext<Self>, range: &Self::State) -> Option<RuleDiagnostic> {
Some(
RuleDiagnostic::new(
rule_category!(),
range,
markup! {
"A global variable should not be reassigned."
},
)
.note(markup! {
"Assigning to a global variable can override essential functionality."
}),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
window = {};
Object = null;
undefined = 1;
length = 1;
top = 1;
String++;
({Object = 0, String = 0} = {});
require = 0;
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
---
source: crates/biome_js_analyze/tests/spec_tests.rs
expression: invalid.js
---
# Input
```js
window = {};
Object = null;
undefined = 1;
length = 1;
top = 1;
String++;
({Object = 0, String = 0} = {});
require = 0;
```

# Diagnostics
```
invalid.js:1:1 lint/nursery/noGlobalAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! A global variable should not be reassigned.
> 1 │ window = {};
│ ^^^^^^^
2 │ Object = null;
3 │ undefined = 1;
i Assigning to a global variable can override essential functionality.
```

```
invalid.js:1:13 lint/nursery/noGlobalAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! A global variable should not be reassigned.
> 1 │ window = {};
> 2 │ Object = null;
│ ^^^^^^^
3 │ undefined = 1;
4 │ length = 1;
i Assigning to a global variable can override essential functionality.
```

```
invalid.js:2:15 lint/nursery/noGlobalAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! A global variable should not be reassigned.
1 │ window = {};
> 2 │ Object = null;
> 3 │ undefined = 1;
│ ^^^^^^^^^^
4 │ length = 1;
5 │ top = 1;
i Assigning to a global variable can override essential functionality.
```

```
invalid.js:3:15 lint/nursery/noGlobalAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! A global variable should not be reassigned.
1 │ window = {};
2 │ Object = null;
> 3 │ undefined = 1;
> 4 │ length = 1;
│ ^^^^^^^
5 │ top = 1;
6 │ String++;
i Assigning to a global variable can override essential functionality.
```

```
invalid.js:4:12 lint/nursery/noGlobalAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! A global variable should not be reassigned.
2 │ Object = null;
3 │ undefined = 1;
> 4 │ length = 1;
> 5 │ top = 1;
│ ^^^^
6 │ String++;
7 │ ({Object = 0, String = 0} = {});
i Assigning to a global variable can override essential functionality.
```

```
invalid.js:5:9 lint/nursery/noGlobalAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! A global variable should not be reassigned.
3 │ undefined = 1;
4 │ length = 1;
> 5 │ top = 1;
> 6 │ String++;
│ ^^^^^^
7 │ ({Object = 0, String = 0} = {});
8 │ require = 0;
i Assigning to a global variable can override essential functionality.
```

```
invalid.js:7:3 lint/nursery/noGlobalAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! A global variable should not be reassigned.
5 │ top = 1;
6 │ String++;
> 7 │ ({Object = 0, String = 0} = {});
│ ^^^^^^^
8 │ require = 0;
i Assigning to a global variable can override essential functionality.
```

```
invalid.js:7:15 lint/nursery/noGlobalAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! A global variable should not be reassigned.
5 │ top = 1;
6 │ String++;
> 7 │ ({Object = 0, String = 0} = {});
│ ^^^^^^^
8 │ require = 0;
i Assigning to a global variable can override essential functionality.
```

```
invalid.js:7:33 lint/nursery/noGlobalAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! A global variable should not be reassigned.
5 │ top = 1;
6 │ String++;
> 7 │ ({Object = 0, String = 0} = {});
> 8 │ require = 0;
│ ^^^^^^^^
i Assigning to a global variable can override essential functionality.
```


Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
a = 1;

let window;
window = {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
source: crates/biome_js_analyze/tests/spec_tests.rs
expression: valid.js
---
# Input
```js
a = 1;

let window;
window = {};

```


Loading

0 comments on commit a42f202

Please sign in to comment.