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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use rnode::RNode;
use stc_ts_ast_rnode::{
    RClassMember, RJSXAttrOrSpread, RJSXElementChild, RParam, RPat, RTsExprWithTypeArgs, RTsFnParam, RTsTupleElement, RTsType,
    RTsTypeElement, RTsTypeParam,
};

/// Visit with output
pub trait Validate<'context, T: ?Sized>
where
    T: RNode,
{
    type Output;
    type Context: 'context + Copy;

    fn validate(&mut self, node: &T, ctxt: Self::Context) -> Self::Output;
}

impl<'c, T, V> Validate<'c, Box<T>> for V
where
    Self: Validate<'c, T>,
    T: RNode,
{
    type Context = <Self as Validate<'c, T>>::Context;
    type Output = <Self as Validate<'c, T>>::Output;

    fn validate(&mut self, node: &Box<T>, ctxt: Self::Context) -> Self::Output {
        self.validate(&**node, ctxt)
    }
}

impl<'c, T, V> Validate<'c, Option<T>> for V
where
    Self: Validate<'c, T>,
    T: RNode,
{
    type Context = <Self as Validate<'c, T>>::Context;
    type Output = Option<<Self as Validate<'c, T>>::Output>;

    fn validate(&mut self, node: &Option<T>, ctxt: Self::Context) -> Self::Output {
        node.as_ref().map(|n| self.validate(n, ctxt))
    }
}

pub trait ValidateInDeclOrder: RNode {}

impl<T> ValidateInDeclOrder for Box<T> where T: ValidateInDeclOrder {}

impl<T> ValidateInDeclOrder for Option<T> where T: ValidateInDeclOrder {}

impl ValidateInDeclOrder for RParam {}

impl ValidateInDeclOrder for RPat {}

impl ValidateInDeclOrder for RTsType {}

impl ValidateInDeclOrder for RTsFnParam {}

impl ValidateInDeclOrder for RTsTypeParam {}

impl ValidateInDeclOrder for RTsExprWithTypeArgs {}

impl ValidateInDeclOrder for RTsTupleElement {}

impl ValidateInDeclOrder for RTsTypeElement {}

impl ValidateInDeclOrder for RJSXElementChild {}

impl ValidateInDeclOrder for RJSXAttrOrSpread {}

/// TODO(kdy1): Remove this
impl ValidateInDeclOrder for RClassMember {}

impl<'c, T, V, O, E> Validate<'c, Vec<T>> for V
where
    Self: Validate<'c, T, Output = Result<O, E>>,
    T: ValidateInDeclOrder,
    Vec<T>: RNode,
{
    type Context = <Self as Validate<'c, T>>::Context;
    type Output = Result<Vec<O>, E>;

    fn validate(&mut self, nodes: &Vec<T>, ctxt: Self::Context) -> Self::Output {
        nodes.iter().map(|node| self.validate(node, ctxt)).collect()
    }
}

pub trait ValidateWith<'c, V> {
    type Output;
    type Context: 'c + Copy;
    fn validate_with(&self, v: &mut V) -> Self::Output
    where
        Self::Context: Unit,
    {
        self.validate_with_args(v, Unit::make())
    }

    fn validate_with_default(&self, v: &mut V) -> Self::Output
    where
        Self::Context: Default,
    {
        self.validate_with_args(v, Default::default())
    }

    fn validate_with_args(&self, v: &mut V, ctxt: Self::Context) -> Self::Output;
}

pub trait Unit {
    fn make() -> Self;
}
impl Unit for () {
    fn make() -> Self {}
}

impl<'c, V, T> ValidateWith<'c, V> for T
where
    V: Validate<'c, T>,
    T: RNode,
{
    type Context = V::Context;
    type Output = V::Output;

    #[inline]
    fn validate_with_args(&self, v: &mut V, ctxt: Self::Context) -> Self::Output {
        v.validate(self, ctxt)
    }
}