Skip to content

Commit

Permalink
feat(lint): add noDocumentImportInPage rule (#4265)
Browse files Browse the repository at this point in the history
Co-authored-by: unvalley <38400669+unvalley@users.noreply.github.com>
  • Loading branch information
kaioduarte and unvalley authored Oct 13, 2024
1 parent 4d3e6cd commit 2342984
Show file tree
Hide file tree
Showing 17 changed files with 283 additions and 84 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b
#### New features

- Add [noDocumentCookie](https://biomejs.dev/linter/rules/no-document-cookie/). Contributed by @tunamaguro
- Add [noDocumentImportInPage](https://biomejs.dev/linter/rules/no-document-import-in-page/). Contributed by @kaioduarte
- Add [noHeadElement](https://biomejs.dev/linter/rules/no-head-element/). Contributed by @kaioduarte
- Add [noHeadImportInDocument](https://biomejs.dev/linter/rules/no-head-import-in-document/). Contributed by @kaioduarte
- Add [noImgElement](https://biomejs.dev/linter/rules/no-img-element/). Contributed by @kaioduarte
- Add [guardForIn](https://biomejs.dev/linter/rules/guard-for-in/). Contributed by @fireairforce

#### Bug Fixes
Expand Down
10 changes: 10 additions & 0 deletions crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs

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

188 changes: 104 additions & 84 deletions crates/biome_configuration/src/analyzer/linter/rules.rs

Large diffs are not rendered by default.

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 @@ -138,6 +138,7 @@ define_categories! {
"lint/nursery/noConsole": "https://biomejs.dev/linter/rules/no-console",
"lint/nursery/noDescendingSpecificity": "https://biomejs.dev/linter/rules/no-descending-specificity",
"lint/nursery/noDocumentCookie": "https://biomejs.dev/linter/rules/no-document-cookie",
"lint/nursery/noDocumentImportInPage": "https://biomejs.dev/linter/rules/no-document-import-in-page",
"lint/nursery/noDoneCallback": "https://biomejs.dev/linter/rules/no-done-callback",
"lint/nursery/noDuplicateAtImportRules": "https://biomejs.dev/linter/rules/no-duplicate-at-import-rules",
"lint/nursery/noDuplicateCustomProperties": "https://biomejs.dev/linter/rules/no-duplicate-custom-properties",
Expand Down
2 changes: 2 additions & 0 deletions crates/biome_js_analyze/src/lint/nursery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use biome_analyze::declare_lint_group;

pub mod no_common_js;
pub mod no_document_cookie;
pub mod no_document_import_in_page;
pub mod no_duplicate_else_if;
pub mod no_dynamic_namespace_import_access;
pub mod no_enum;
Expand Down Expand Up @@ -42,6 +43,7 @@ declare_lint_group! {
rules : [
self :: no_common_js :: NoCommonJs ,
self :: no_document_cookie :: NoDocumentCookie ,
self :: no_document_import_in_page :: NoDocumentImportInPage ,
self :: no_duplicate_else_if :: NoDuplicateElseIf ,
self :: no_dynamic_namespace_import_access :: NoDynamicNamespaceImportAccess ,
self :: no_enum :: NoEnum ,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use biome_analyze::{
context::RuleContext, declare_lint_rule, Ast, Rule, RuleDiagnostic, RuleSource, RuleSourceKind,
};
use biome_console::markup;
use biome_js_syntax::{JsFileSource, JsImport};
use biome_rowan::AstNode;

declare_lint_rule! {
/// Prevents importing `next/document` outside of `pages/_document.jsx` in Next.js projects.
///
/// The `next/document` module is intended for customizing the document structure globally in Next.js.
/// Importing it outside of `pages/_document.js` can cause unexpected behavior and break certain features of the framework.
///
/// ## Examples
///
/// ### Valid
///
/// ```jsx
/// import { Document, Html } from 'next/document'
///
/// export default class MyDocument extends Document {
/// render() {
/// return (
/// <Html lang="en">
/// {/* */}
/// </Html>
/// )
/// }
/// }
/// ```
///
pub NoDocumentImportInPage {
version: "next",
name: "noDocumentImportInPage",
language: "jsx",
sources: &[RuleSource::EslintNext("no-document-import-in-page")],
source_kind: RuleSourceKind::SameLogic,
recommended: false,
}
}

impl Rule for NoDocumentImportInPage {
type Query = Ast<JsImport>;
type State = ();
type Signals = Option<Self::State>;
type Options = ();

fn run(ctx: &RuleContext<Self>) -> Self::Signals {
if !ctx.source_type::<JsFileSource>().is_jsx() {
return None;
}

let import = ctx.query();
let import_source = import.import_clause().ok()?.source().ok()?;
let module_name = import_source.inner_string_text().ok()?;

if module_name != "next/document" {
return None;
}

let path = ctx.file_path();

if !path
.ancestors()
.filter_map(|a| a.file_name())
.any(|f| f == "pages")
{
return None;
}

let file_name = path.file_stem()?.to_str()?;
let parent_name = path.parent()?.file_stem()?.to_str()?;

if parent_name == "_document" || file_name == "_document" {
return None;
}

Some(())
}

fn diagnostic(ctx: &RuleContext<Self>, _: &Self::State) -> Option<RuleDiagnostic> {
return Some(
RuleDiagnostic::new(
rule_category!(),
ctx.query().range(),
markup! {
"Don't use "<Emphasis>"next/document"</Emphasis>" outside of pages/_document.jsx to avoid unexpected behaviors."
},
)
.note(markup! {
"Only import "<Emphasis>"next/document"</Emphasis>" within "<Emphasis>"pages/_document.jsx"</Emphasis>" to customize the global document structure."
})
);
}
}
1 change: 1 addition & 0 deletions crates/biome_js_analyze/src/options.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 @@
import Document from "next/document";
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
source: crates/biome_js_analyze/tests/spec_tests.rs
assertion_line: 86
expression: valid.jsx
---
# Input
```jsx
import Document from "next/document";
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import Document from "next/document";
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
source: crates/biome_js_analyze/tests/spec_tests.rs
assertion_line: 86
expression: _document.jsx
---
# Input
```jsx
import Document from "next/document";
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import Document from "next/document";
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
source: crates/biome_js_analyze/tests/spec_tests.rs
assertion_line: 86
expression: invalid.jsx
---
# Input
```jsx
import Document from "next/document";
```

# Diagnostics
```
invalid.jsx:1:1 lint/nursery/noDocumentImportInPage ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! Don't use next/document outside of pages/_document.jsx to avoid unexpected behaviors.
> 1 │ import Document from "next/document";
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
i Only import next/document within pages/_document.jsx to customize the global document structure.
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import Document from "next/document";
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
source: crates/biome_js_analyze/tests/spec_tests.rs
assertion_line: 86
expression: valid.jsx
---
# Input
```jsx
import Document from "next/document";
```
5 changes: 5 additions & 0 deletions packages/@biomejs/backend-jsonrpc/src/workspace.ts

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

7 changes: 7 additions & 0 deletions packages/@biomejs/biome/configuration_schema.json

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

0 comments on commit 2342984

Please sign in to comment.