1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use std::sync::Arc;
use crate::ast::node::Node;
use crate::ast::r#enum::Enum;
use crate::ast::reference_space::ReferenceSpace;
use crate::ast::struct_declaration::StructDeclaration;
use crate::completion::find_completion_in_type_expr::TypeExprFilter;
use crate::traits::named_identifiable::NamedIdentifiable;

pub fn top_filter_for_reference_type(reference_type: ReferenceSpace) -> Arc<dyn Fn(&Node) -> bool> {
    match reference_type {
        ReferenceSpace::EnumDecorator |
        ReferenceSpace::EnumMemberDecorator |
        ReferenceSpace::ModelDecorator |
        ReferenceSpace::ModelFieldDecorator |
        ReferenceSpace::ModelRelationDecorator |
        ReferenceSpace::ModelPropertyDecorator |
        ReferenceSpace::InterfaceDecorator |
        ReferenceSpace::InterfaceFieldDecorator |
        ReferenceSpace::HandlerDecorator => Arc::new(move |top: &Node| {
            top.as_decorator_declaration().map_or(false, |d| d.decorator_class == reference_type)
        }),
        ReferenceSpace::PipelineItem => Arc::new(|top: &Node| {
            top.as_pipeline_item_declaration().is_some()
        }),
        ReferenceSpace::Middleware => Arc::new(|top: &Node| {
            top.as_middleware_declaration().is_some()
        }),
        ReferenceSpace::Default => Arc::new(|top: &Node| {
            top.is_enum() || top.is_model() || top.is_interface_declaration() || top.is_struct_declaration() || top.is_config() || top.is_constant_declaration() || top.is_namespace() || top.is_data_set()
        }),
    }
}

pub fn top_filter_for_any_model_field_decorators() -> Arc<dyn Fn(&Node) -> bool> {
    Arc::new(|top: &Node| {
        top.as_decorator_declaration().map_or(false, |d| match d.decorator_class {
            ReferenceSpace::ModelFieldDecorator => true,
            ReferenceSpace::ModelRelationDecorator => true,
            ReferenceSpace::ModelPropertyDecorator => true,
            _ => false,
        })
    })
}

pub fn top_filter_for_pipeline() -> Arc<dyn Fn(&Node) -> bool> {
    Arc::new(|top: &Node| {
        top.is_pipeline_item_declaration() || top.is_namespace()
    })
}

pub fn top_filter_for_middleware() -> Arc<dyn Fn(&Node) -> bool> {
    Arc::new(|top: &Node| {
        top.is_middleware_declaration() || top.is_namespace()
    })
}

pub fn top_filter_for_model() -> Arc<dyn Fn(&Node) -> bool> {
    Arc::new(|top: &Node| {
        top.is_model()
    })
}

pub fn top_filter_for_type_expr_filter(type_expr_filter: TypeExprFilter) -> Arc<dyn Fn(&Node) -> bool> {
    match type_expr_filter {
        TypeExprFilter::None => Arc::new(|top: &Node| {
            top.is_model() || top.is_interface_declaration() || top.is_enum() || (top.is_struct_declaration() && !struct_is_builtin(top.as_struct_declaration().unwrap()))
        }),
        TypeExprFilter::Model => Arc::new(|top: &Node| {
            (top.is_enum() && enum_is_normal(top.as_enum().unwrap())) || top.is_model()
        }),
        TypeExprFilter::ActionInput => Arc::new(|top: &Node| {
            top.is_interface_declaration()
        }),
    }
}

fn struct_is_builtin(struct_declaration: &StructDeclaration) -> bool {
    let str_path = struct_declaration.str_path();
    if str_path.len() != 2 {
        return false;
    }
    if str_path.first().unwrap() != &"std" {
        return false;
    }
    let last = *str_path.last().unwrap();
    vec!["String", "Bool", "Null", "Int", "Int64", "Float", "Float32", "Decimal", "ObjectId", "Date", "DateTime", "Array", "Dictionary"].contains(&last)
}

fn enum_is_normal(enum_declaration: &Enum) -> bool {
    !enum_declaration.interface && !enum_declaration.option
}