mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(linter) eslint-plugin-next google-font-preconnect (#1932)
This commit is contained in:
parent
d24738d3fc
commit
3d00d31c1e
3 changed files with 134 additions and 0 deletions
|
|
@ -270,6 +270,7 @@ mod oxc {
|
|||
|
||||
mod nextjs {
|
||||
pub mod google_font_display;
|
||||
pub mod google_font_preconnect;
|
||||
}
|
||||
|
||||
oxc_macros::declare_all_lint_rules! {
|
||||
|
|
@ -509,4 +510,5 @@ oxc_macros::declare_all_lint_rules! {
|
|||
oxc::no_accumulating_spread,
|
||||
oxc::only_used_in_recursion,
|
||||
nextjs::google_font_display,
|
||||
nextjs::google_font_preconnect,
|
||||
}
|
||||
|
|
|
|||
109
crates/oxc_linter/src/rules/nextjs/google_font_preconnect.rs
Normal file
109
crates/oxc_linter/src/rules/nextjs/google_font_preconnect.rs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
use oxc_ast::{ast::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,
|
||||
utils::{get_string_literal_prop_value, has_jsx_prop_lowercase},
|
||||
AstNode,
|
||||
};
|
||||
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
#[error(r#"eslint-plugin-next(google-font-preconnect): `rel="preconnect"` is missing from Google Font."#)]
|
||||
#[diagnostic(
|
||||
severity(warning),
|
||||
help("See: https://nextjs.org/docs/messages/google-font-preconnect")
|
||||
)]
|
||||
struct GoogleFontPreconnectDiagnostic(#[label] pub Span);
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct GoogleFontPreconnect;
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
///
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
///
|
||||
/// ### Example
|
||||
/// ```javascript
|
||||
/// ```
|
||||
GoogleFontPreconnect,
|
||||
correctness
|
||||
);
|
||||
|
||||
impl Rule for GoogleFontPreconnect {
|
||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
let AstKind::JSXOpeningElement(jsx_opening_element) = node.kind() else { return };
|
||||
|
||||
let JSXElementName::Identifier(jsx_opening_element_name) = &jsx_opening_element.name else {
|
||||
return;
|
||||
};
|
||||
|
||||
if jsx_opening_element_name.name.as_str() != "link" {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(href_prop) = has_jsx_prop_lowercase(jsx_opening_element, "href") else {
|
||||
return;
|
||||
};
|
||||
let Some(href_prop_value) = get_string_literal_prop_value(href_prop) else { return };
|
||||
|
||||
let preconnect_missing =
|
||||
has_jsx_prop_lowercase(jsx_opening_element, "rel").map_or(true, |rel_prop| {
|
||||
let rel_prop_value = get_string_literal_prop_value(rel_prop);
|
||||
rel_prop_value != Some("preconnect")
|
||||
});
|
||||
|
||||
if href_prop_value.starts_with("https://fonts.gstatic.com") && preconnect_missing {
|
||||
ctx.diagnostic(GoogleFontPreconnectDiagnostic(jsx_opening_element_name.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
r#"export const Test = () => (
|
||||
<div>
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com"/>
|
||||
<link
|
||||
href={process.env.NEXT_PUBLIC_CANONICAL_URL}
|
||||
rel="canonical"
|
||||
/>
|
||||
<link
|
||||
href={new URL("../public/favicon.ico", import.meta.url).toString()}
|
||||
rel="icon"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
"#,
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
r#"
|
||||
export const Test = () => (
|
||||
<div>
|
||||
<link href="https://fonts.gstatic.com"/>
|
||||
</div>
|
||||
)
|
||||
"#,
|
||||
r#"
|
||||
export const Test = () => (
|
||||
<div>
|
||||
<link rel="preload" href="https://fonts.gstatic.com"/>
|
||||
</div>
|
||||
)
|
||||
"#,
|
||||
];
|
||||
|
||||
Tester::new_without_config(GoogleFontPreconnect::NAME, pass, fail).test_and_snapshot();
|
||||
}
|
||||
23
crates/oxc_linter/src/snapshots/google_font_preconnect.snap
Normal file
23
crates/oxc_linter/src/snapshots/google_font_preconnect.snap
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
expression: google_font_preconnect
|
||||
---
|
||||
⚠ eslint-plugin-next(google-font-preconnect): `rel="preconnect"` is missing from Google Font.
|
||||
╭─[google_font_preconnect.tsx:3:1]
|
||||
3 │ <div>
|
||||
4 │ <link href="https://fonts.gstatic.com"/>
|
||||
· ────
|
||||
5 │ </div>
|
||||
╰────
|
||||
help: See: https://nextjs.org/docs/messages/google-font-preconnect
|
||||
|
||||
⚠ eslint-plugin-next(google-font-preconnect): `rel="preconnect"` is missing from Google Font.
|
||||
╭─[google_font_preconnect.tsx:3:1]
|
||||
3 │ <div>
|
||||
4 │ <link rel="preload" href="https://fonts.gstatic.com"/>
|
||||
· ────
|
||||
5 │ </div>
|
||||
╰────
|
||||
help: See: https://nextjs.org/docs/messages/google-font-preconnect
|
||||
|
||||
|
||||
Loading…
Reference in a new issue