mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(linter): eslint-plugin-next/no-styled-jsx-in-document (#3184)
This commit is contained in:
parent
762677e17b
commit
5514936f51
3 changed files with 190 additions and 0 deletions
|
|
@ -355,6 +355,7 @@ mod nextjs {
|
|||
pub mod no_head_import_in_document;
|
||||
pub mod no_img_element;
|
||||
pub mod no_script_component_in_head;
|
||||
pub mod no_styled_jsx_in_document;
|
||||
pub mod no_sync_scripts;
|
||||
pub mod no_title_in_document_head;
|
||||
pub mod no_typos;
|
||||
|
|
@ -703,6 +704,7 @@ oxc_macros::declare_all_lint_rules! {
|
|||
nextjs::no_document_import_in_page,
|
||||
nextjs::no_unwanted_polyfillio,
|
||||
nextjs::no_before_interactive_script_outside_document,
|
||||
nextjs::no_styled_jsx_in_document,
|
||||
jsdoc::check_access,
|
||||
jsdoc::check_property_names,
|
||||
jsdoc::check_tag_names,
|
||||
|
|
|
|||
176
crates/oxc_linter/src/rules/nextjs/no_styled_jsx_in_document.rs
Normal file
176
crates/oxc_linter/src/rules/nextjs/no_styled_jsx_in_document.rs
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
use oxc_ast::{
|
||||
ast::{JSXAttributeItem, JSXElementName},
|
||||
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)]
|
||||
#[error("eslint-plugin-next(no-styled-jsx-in-document): `styled-jsx` should not be used in `pages/_document.js`")]
|
||||
#[diagnostic(severity(warning), help("Possible to fix it please see: https://nextjs.org/docs/messages/no-styled-jsx-in-document#possible-ways-to-fix-it"))]
|
||||
struct NoStyledJsxInDocumentDiagnostic(#[label] pub Span);
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NoStyledJsxInDocument;
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
///
|
||||
/// Prevent usage of styled-jsx in pages/_document.js.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// Custom CSS like styled-jsx is not allowed in a [Custom Document](https://nextjs.org/docs/pages/building-your-application/routing/custom-document).
|
||||
///
|
||||
/// ### Example
|
||||
/// ```javascript
|
||||
/// ```
|
||||
NoStyledJsxInDocument,
|
||||
correctness,
|
||||
);
|
||||
|
||||
impl Rule for NoStyledJsxInDocument {
|
||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
let AstKind::JSXOpeningElement(element) = node.kind() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if !matches!(&element.name, JSXElementName::Identifier(ident) if ident.name == "style") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check only pages/_document.* file
|
||||
let full_file_path = ctx.file_path();
|
||||
let Some(file_name) = full_file_path.file_name() else {
|
||||
return;
|
||||
};
|
||||
let Some(file_name) = file_name.to_str() else { return };
|
||||
if !file_name.starts_with("_document.") {
|
||||
return;
|
||||
}
|
||||
|
||||
let has_jsx_attribute = element.attributes.iter().any(|attribute| {
|
||||
matches!(attribute, JSXAttributeItem::Attribute(attribute) if attribute.is_identifier("jsx"))
|
||||
});
|
||||
|
||||
if has_jsx_attribute {
|
||||
ctx.diagnostic(NoStyledJsxInDocumentDiagnostic(element.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
use std::path::PathBuf;
|
||||
|
||||
let pass = vec![
|
||||
(
|
||||
"import Document, { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
export class MyDocument extends Document {
|
||||
static async getInitialProps(ctx) {
|
||||
const initialProps = await Document.getInitialProps(ctx)
|
||||
return { ...initialProps }
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
}",
|
||||
None,
|
||||
None,
|
||||
Some(PathBuf::from("pages/_document.tsx")),
|
||||
),
|
||||
(
|
||||
r#"import Document, { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
export class MyDocument extends Document {
|
||||
static async getInitialProps(ctx) {
|
||||
const initialProps = await Document.getInitialProps(ctx)
|
||||
return { ...initialProps }
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
<style>{" body{ color:red; } "}</style>
|
||||
<style {...{nonce: '123' }}></style>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
}"#,
|
||||
None,
|
||||
None,
|
||||
Some(PathBuf::from("pages/_document.tsx")),
|
||||
),
|
||||
(
|
||||
"
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<p>Hello world</p>
|
||||
<style jsx>{`
|
||||
p {
|
||||
color: orange;
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
)
|
||||
}
|
||||
",
|
||||
None,
|
||||
None,
|
||||
Some(PathBuf::from("pages/index.jsx")),
|
||||
),
|
||||
];
|
||||
|
||||
let fail = vec![(
|
||||
r#"
|
||||
import Document, { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
export class MyDocument extends Document {
|
||||
static async getInitialProps(ctx) {
|
||||
const initialProps = await Document.getInitialProps(ctx)
|
||||
return { ...initialProps }
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
<style jsx>{" body{ color:red; } "}</style>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
}"#,
|
||||
None,
|
||||
None,
|
||||
Some(PathBuf::from("pages/_document.jsx")),
|
||||
)];
|
||||
|
||||
Tester::new(NoStyledJsxInDocument::NAME, pass, fail).test_and_snapshot();
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
expression: no_styled_jsx_in_document
|
||||
---
|
||||
⚠ eslint-plugin-next(no-styled-jsx-in-document): `styled-jsx` should not be used in `pages/_document.js`
|
||||
╭─[no_styled_jsx_in_document.tsx:14:24]
|
||||
13 │ <Head />
|
||||
14 │ <style jsx>{" body{ color:red; } "}</style>
|
||||
· ───────────
|
||||
15 │ <body>
|
||||
╰────
|
||||
help: Possible to fix it please see: https://nextjs.org/docs/messages/no-styled-jsx-in-document#possible-ways-to-fix-it
|
||||
Loading…
Reference in a new issue