Skip to main content

flowjs_parser/
ast.rs

1//! Typed representation of the Flow parser AST.
2//!
3//! Coverage: primitives, literals, nullable, object, union, intersection,
4//! generic, tuple, array, typeof, opaque. Unrecognized nodes deserialize as
5//! `Other` via `#[serde(other)]`.
6//!
7//! Future: complete the AST to remove all `Other` fallbacks. Missing variants:
8//!   - TypeAnnotation: FunctionTypeAnnotation (params, return, rest, type params),
9//!     InterfaceTypeAnnotation, ExistsTypeAnnotation (*), IndexedAccessType,
10//!     OptionalIndexedAccessType, KeyofTypeAnnotation, ConditionalTypeAnnotation,
11//!     InferTypeAnnotation, TypeOperator, ComponentTypeAnnotation
12//!   - Declaration: InterfaceDeclaration, DeclareTypeAlias, DeclareClass,
13//!     DeclareFunction, DeclareVariable, DeclareModule
14//!   - Statement: ImportDeclaration, DeclareModuleExports, TypeCastExpression
15//!   - PropertyKey: NumberLiteral (numeric keys)
16//!   - ObjectMember: ObjectTypeInternalSlot, ObjectTypeCallProperty
17//!   - Positional info: loc (SourceLocation), range ([start, end]) on all nodes
18//!
19//! Reference: https://github.com/facebook/flow/blob/main/src/parser/estree_translator.ml
20
21use serde::Deserialize;
22
23// ── Program ─────────────────────────────────────────────────────────────
24
25/// Root AST node returned by the Flow parser.
26#[derive(Debug, Clone, Deserialize)]
27pub struct Program {
28    pub body: Vec<Statement>,
29    #[serde(default)]
30    pub errors: Vec<ParseError>,
31}
32
33/// A parse error reported by the Flow parser.
34#[derive(Debug, Clone, Deserialize)]
35pub struct ParseError {
36    pub message: String,
37    pub loc: Option<SourceLocation>,
38}
39
40/// Source location attached to a parse error.
41#[derive(Debug, Clone, Deserialize)]
42pub struct SourceLocation {
43    pub start: Position,
44    pub end: Position,
45}
46
47/// Line and column (both 1-based for line, 0-based for column, matching Flow convention).
48#[derive(Debug, Clone, Deserialize)]
49pub struct Position {
50    pub line: u32,
51    pub column: u32,
52}
53
54// ── Statements ──────────────────────────────────────────────────────────
55
56/// Top-level statement in a Flow program.
57#[derive(Debug, Clone, Deserialize)]
58#[serde(tag = "type")]
59pub enum Statement {
60    ExportNamedDeclaration {
61        declaration: Option<Declaration>,
62    },
63    DeclareExportDeclaration {
64        declaration: Option<Declaration>,
65    },
66    /// Catch-all for statement types we don't inspect.
67    #[serde(other)]
68    Other,
69}
70
71// ── Declarations ────────────────────────────────────────────────────────
72
73/// A type-level declaration inside an export statement.
74#[derive(Debug, Clone, Deserialize)]
75#[serde(tag = "type")]
76pub enum Declaration {
77    TypeAlias {
78        id: Identifier,
79        right: TypeAnnotation,
80    },
81    OpaqueType {
82        id: Identifier,
83        supertype: Option<TypeAnnotation>,
84    },
85    DeclareOpaqueType {
86        id: Identifier,
87        supertype: Option<TypeAnnotation>,
88    },
89    #[serde(other)]
90    Other,
91}
92
93// ── Type annotations ────────────────────────────────────────────────────
94
95/// A Flow type annotation node.
96#[derive(Debug, Clone, Deserialize)]
97#[serde(tag = "type")]
98pub enum TypeAnnotation {
99    // Primitives
100    StringTypeAnnotation,
101    NumberTypeAnnotation,
102    BooleanTypeAnnotation,
103    VoidTypeAnnotation,
104    MixedTypeAnnotation,
105    AnyTypeAnnotation,
106    EmptyTypeAnnotation,
107    NullLiteralTypeAnnotation,
108    BigIntTypeAnnotation,
109    SymbolTypeAnnotation,
110
111    // Literals
112    StringLiteralTypeAnnotation {
113        value: String,
114    },
115    NumberLiteralTypeAnnotation {
116        value: f64,
117    },
118    BooleanLiteralTypeAnnotation {
119        value: bool,
120    },
121
122    // Nullable (?T)
123    NullableTypeAnnotation {
124        #[serde(rename = "typeAnnotation")]
125        type_annotation: Box<TypeAnnotation>,
126    },
127
128    // Object ({| +key: T |})
129    ObjectTypeAnnotation {
130        #[serde(default)]
131        properties: Vec<ObjectMember>,
132        #[serde(default)]
133        indexers: Vec<ObjectTypeIndexer>,
134        #[serde(default)]
135        exact: bool,
136    },
137
138    // Union (A | B)
139    UnionTypeAnnotation {
140        types: Vec<TypeAnnotation>,
141    },
142
143    // Intersection (A & B)
144    IntersectionTypeAnnotation {
145        types: Vec<TypeAnnotation>,
146    },
147
148    // Named type reference (Foo, $ReadOnlyArray<T>)
149    GenericTypeAnnotation {
150        id: Identifier,
151        #[serde(rename = "typeParameters")]
152        type_parameters: Option<TypeParameterInstantiation>,
153    },
154
155    // Tuple ([A, B, C])
156    TupleTypeAnnotation {
157        #[serde(alias = "types", default)]
158        #[serde(rename = "elementTypes")]
159        element_types: Vec<TypeAnnotation>,
160    },
161
162    // Array (T[])
163    ArrayTypeAnnotation {
164        #[serde(rename = "elementType")]
165        element_type: Box<TypeAnnotation>,
166    },
167
168    // typeof T
169    TypeofTypeAnnotation {
170        argument: Box<TypeAnnotation>,
171    },
172
173    #[serde(other)]
174    Other,
175}
176
177impl TypeAnnotation {
178    /// Short type tag for assertions (e.g. `"StringTypeAnnotation"`).
179    pub fn type_name(&self) -> &'static str {
180        match self {
181            Self::StringTypeAnnotation => "StringTypeAnnotation",
182            Self::NumberTypeAnnotation => "NumberTypeAnnotation",
183            Self::BooleanTypeAnnotation => "BooleanTypeAnnotation",
184            Self::VoidTypeAnnotation => "VoidTypeAnnotation",
185            Self::MixedTypeAnnotation => "MixedTypeAnnotation",
186            Self::AnyTypeAnnotation => "AnyTypeAnnotation",
187            Self::EmptyTypeAnnotation => "EmptyTypeAnnotation",
188            Self::NullLiteralTypeAnnotation => "NullLiteralTypeAnnotation",
189            Self::BigIntTypeAnnotation => "BigIntTypeAnnotation",
190            Self::SymbolTypeAnnotation => "SymbolTypeAnnotation",
191            Self::StringLiteralTypeAnnotation { .. } => "StringLiteralTypeAnnotation",
192            Self::NumberLiteralTypeAnnotation { .. } => "NumberLiteralTypeAnnotation",
193            Self::BooleanLiteralTypeAnnotation { .. } => "BooleanLiteralTypeAnnotation",
194            Self::NullableTypeAnnotation { .. } => "NullableTypeAnnotation",
195            Self::ObjectTypeAnnotation { .. } => "ObjectTypeAnnotation",
196            Self::UnionTypeAnnotation { .. } => "UnionTypeAnnotation",
197            Self::IntersectionTypeAnnotation { .. } => "IntersectionTypeAnnotation",
198            Self::GenericTypeAnnotation { .. } => "GenericTypeAnnotation",
199            Self::TupleTypeAnnotation { .. } => "TupleTypeAnnotation",
200            Self::ArrayTypeAnnotation { .. } => "ArrayTypeAnnotation",
201            Self::TypeofTypeAnnotation { .. } => "TypeofTypeAnnotation",
202            Self::Other => "Other",
203        }
204    }
205}
206
207// ── Object type members ─────────────────────────────────────────────────
208
209/// A member of an object type annotation.
210#[derive(Debug, Clone, Deserialize)]
211#[serde(tag = "type")]
212pub enum ObjectMember {
213    ObjectTypeProperty {
214        key: PropertyKey,
215        value: TypeAnnotation,
216        variance: Option<Variance>,
217        #[serde(default)]
218        optional: bool,
219    },
220    ObjectTypeSpreadProperty {
221        argument: TypeAnnotation,
222    },
223    #[serde(other)]
224    Other,
225}
226
227/// An indexer on an object type (`[key: K]: V`).
228#[derive(Debug, Clone, Deserialize)]
229pub struct ObjectTypeIndexer {
230    pub key: TypeAnnotation,
231    pub value: TypeAnnotation,
232}
233
234// ── Shared nodes ────────────────────────────────────────────────────────
235
236/// An identifier node.
237#[derive(Debug, Clone, Deserialize)]
238pub struct Identifier {
239    pub name: String,
240}
241
242/// Property key — either an identifier or a string literal (for quoted keys).
243#[derive(Debug, Clone, Deserialize)]
244#[serde(tag = "type")]
245pub enum PropertyKey {
246    Identifier {
247        name: String,
248    },
249    /// Quoted key — Flow parser emits `Literal` (not `StringLiteral`) for property keys.
250    Literal {
251        value: serde_json::Value,
252    },
253    #[serde(other)]
254    Other,
255}
256
257impl PropertyKey {
258    /// The key's text regardless of representation.
259    pub fn name(&self) -> Option<&str> {
260        match self {
261            Self::Identifier { name } => Some(name),
262            Self::Literal { value } => value.as_str(),
263            Self::Other => None,
264        }
265    }
266
267    /// Whether this key is a quoted literal (non-identifier).
268    pub fn is_quoted(&self) -> bool {
269        matches!(self, Self::Literal { .. })
270    }
271}
272
273/// Variance annotation (`+` = plus, `-` = minus).
274#[derive(Debug, Clone, Deserialize)]
275pub struct Variance {
276    pub kind: VarianceKind,
277}
278
279/// Variance direction.
280#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)]
281#[serde(rename_all = "lowercase")]
282pub enum VarianceKind {
283    Plus,
284    Minus,
285}
286
287/// Type parameter instantiation (`<T, U>`).
288#[derive(Debug, Clone, Deserialize)]
289pub struct TypeParameterInstantiation {
290    pub params: Vec<TypeAnnotation>,
291}