mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-27 06:30:20 +00:00
fix(check): allow hook calls inside closure hooks
This commit is contained in:
parent
420bc39ecc
commit
0e841f8411
1 changed files with 75 additions and 2 deletions
|
@ -1,6 +1,6 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use syn::{spanned::Spanned, visit::Visit};
|
||||
use syn::{spanned::Spanned, visit::Visit, Pat};
|
||||
|
||||
use crate::{
|
||||
issues::{Issue, IssueReport},
|
||||
|
@ -74,6 +74,20 @@ fn is_component_fn(item_fn: &syn::ItemFn) -> bool {
|
|||
returns_element(&item_fn.sig.output)
|
||||
}
|
||||
|
||||
fn get_closure_hook_body(local: &syn::Local) -> Option<&syn::Expr> {
|
||||
if let Pat::Ident(ident) = &local.pat {
|
||||
if is_hook_ident(&ident.ident) {
|
||||
if let Some((_, expr)) = &local.init {
|
||||
if let syn::Expr::Closure(closure) = &**expr {
|
||||
return Some(&closure.body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn fn_name_and_name_span(item_fn: &syn::ItemFn) -> (String, Span) {
|
||||
let name = item_fn.sig.ident.to_string();
|
||||
let name_span = item_fn.sig.ident.span().into();
|
||||
|
@ -173,6 +187,17 @@ impl<'ast> syn::visit::Visit<'ast> for VisitHooks {
|
|||
self.context.pop();
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, i: &'ast syn::Local) {
|
||||
if let Some(body) = get_closure_hook_body(i) {
|
||||
// if the closure is a hook, we only visit the body of the closure.
|
||||
// this prevents adding a ClosureInfo node to the context
|
||||
syn::visit::visit_expr(self, body);
|
||||
} else {
|
||||
// otherwise visit the whole local
|
||||
syn::visit::visit_local(self, i);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_expr_if(&mut self, i: &'ast syn::ExprIf) {
|
||||
self.context.push(Node::If(IfInfo::new(
|
||||
i.span().into(),
|
||||
|
@ -252,7 +277,7 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_no_issues() {
|
||||
fn test_no_hooks() {
|
||||
let contents = indoc! {r#"
|
||||
fn App(cx: Scope) -> Element {
|
||||
rsx! {
|
||||
|
@ -266,6 +291,54 @@ mod tests {
|
|||
assert_eq!(report.issues, vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hook_correctly_used_inside_component() {
|
||||
let contents = indoc! {r#"
|
||||
fn App(cx: Scope) -> Element {
|
||||
let count = use_state(cx, || 0);
|
||||
rsx! {
|
||||
p { "Hello World: {count}" }
|
||||
}
|
||||
}
|
||||
"#};
|
||||
|
||||
let report = check_file("app.rs".into(), contents);
|
||||
|
||||
assert_eq!(report.issues, vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hook_correctly_used_inside_hook_fn() {
|
||||
let contents = indoc! {r#"
|
||||
fn use_thing(cx: Scope) -> UseState<i32> {
|
||||
use_state(cx, || 0)
|
||||
}
|
||||
"#};
|
||||
|
||||
let report = check_file("use_thing.rs".into(), contents);
|
||||
|
||||
assert_eq!(report.issues, vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hook_correctly_used_inside_hook_closure() {
|
||||
let contents = indoc! {r#"
|
||||
fn App(cx: Scope) -> Element {
|
||||
let use_thing = || {
|
||||
use_state(cx, || 0)
|
||||
};
|
||||
let count = use_thing();
|
||||
rsx! {
|
||||
p { "Hello World: {count}" }
|
||||
}
|
||||
}
|
||||
"#};
|
||||
|
||||
let report = check_file("app.rs".into(), contents);
|
||||
|
||||
assert_eq!(report.issues, vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conditional_hook_if() {
|
||||
let contents = indoc! {r#"
|
||||
|
|
Loading…
Reference in a new issue