1use crate::{
2 derive_ASTNode, errors::parse_lexing_error, throw_unexpected_token,
3 type_annotations::TypeAnnotationFunctionParameters, types::enum_declaration::EnumDeclaration,
4 ASTNode, Expression, ParseError, ParseOptions, ParseResult, Span, StatementPosition,
5 TSXKeyword, TSXToken, Token, TypeAnnotation, VariableIdentifier,
6};
7
8use super::{
9 variable::VariableDeclaration, ClassDeclaration, ImportExportPart, ImportLocation,
10 InterfaceDeclaration, StatementFunction, TypeAlias,
11};
12
13use get_field_by_type::GetFieldByType;
14use tokenizer_lib::TokenReader;
15use visitable_derive::Visitable;
16
17#[apply(derive_ASTNode)]
19#[derive(Debug, PartialEq, Clone, Visitable, get_field_by_type::GetFieldByType)]
20#[get_field_by_type_target(Span)]
21pub enum ExportDeclaration {
22 Item {
23 exported: Exportable,
24 position: Span,
25 },
26 Default {
28 expression: Box<Expression>,
29 position: Span,
30 },
31 DefaultFunction {
32 is_async: bool,
34 identifier: Option<VariableIdentifier>,
35 #[visit_skip_field]
36 parameters: TypeAnnotationFunctionParameters,
37 return_type: Option<TypeAnnotation>,
38 position: Span,
39 },
40}
41
42#[apply(derive_ASTNode)]
43#[derive(Debug, PartialEq, Clone, Visitable)]
44pub enum Exportable {
45 Class(ClassDeclaration<StatementPosition>),
46 Function(StatementFunction),
47 Variable(VariableDeclaration),
48 Interface(InterfaceDeclaration),
49 TypeAlias(TypeAlias),
50 EnumDeclaration(EnumDeclaration),
51 Parts(Vec<ImportExportPart<ExportDeclaration>>),
52 ImportAll {
53 r#as: Option<VariableIdentifier>,
54 from: ImportLocation,
55 },
56 ImportParts {
57 parts: Vec<ImportExportPart<super::ImportDeclaration>>,
59 from: ImportLocation,
60 type_definitions_only: bool,
61 },
62}
63
64impl ASTNode for ExportDeclaration {
65 fn get_position(&self) -> Span {
66 *self.get()
67 }
68
69 fn from_reader(
70 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
71 state: &mut crate::ParsingState,
72 options: &ParseOptions,
73 ) -> ParseResult<Self> {
74 let start = state.expect_keyword(reader, TSXKeyword::Export)?;
75
76 match reader.peek().ok_or_else(parse_lexing_error)? {
77 Token(TSXToken::Keyword(TSXKeyword::Default), _) => {
78 reader.next();
79 if options.type_definition_module
80 && reader.peek().map_or(
81 false,
82 |t| matches!(t.0, TSXToken::Keyword(kw) if kw.is_in_function_header()),
83 ) {
84 let is_async = reader
85 .conditional_next(|t| matches!(t, TSXToken::Keyword(TSXKeyword::Async)))
86 .is_some();
87
88 #[allow(unused)]
89 let token = reader.next();
90 debug_assert!(matches!(
91 token.unwrap().0,
92 TSXToken::Keyword(TSXKeyword::Function)
93 ));
94
95 let identifier =
96 if let Some(Token(TSXToken::OpenParentheses, _)) = reader.peek() {
97 None
98 } else {
99 Some(VariableIdentifier::from_reader(reader, state, options)?)
100 };
101
102 let parameters =
103 TypeAnnotationFunctionParameters::from_reader(reader, state, options)?;
104
105 let return_type = reader
106 .conditional_next(|tok| matches!(tok, TSXToken::Colon))
107 .is_some()
108 .then(|| TypeAnnotation::from_reader(reader, state, options))
109 .transpose()?;
110
111 let position = start.union(
112 return_type.as_ref().map_or(parameters.position, ASTNode::get_position),
113 );
114
115 Ok(ExportDeclaration::DefaultFunction {
116 position,
117 is_async,
118 identifier,
119 parameters,
120 return_type,
121 })
122 } else {
123 let expression = Expression::from_reader(reader, state, options)?;
124 let position = start.union(expression.get_position());
125 Ok(ExportDeclaration::Default { expression: Box::new(expression), position })
126 }
127 }
128 Token(TSXToken::Multiply, _) => {
129 reader.next();
130 let r#as = if let Some(Token(TSXToken::Keyword(TSXKeyword::As), _)) = reader.peek()
131 {
132 state.append_keyword_at_pos(reader.next().unwrap().1 .0, TSXKeyword::As);
133 Some(VariableIdentifier::from_reader(reader, state, options)?)
134 } else {
135 None
136 };
137 let start = state.expect_keyword(reader, TSXKeyword::From)?;
138
139 let (from, end) = ImportLocation::from_reader(reader, state, options, Some(start))?;
140
141 Ok(ExportDeclaration::Item {
142 exported: Exportable::ImportAll { r#as, from },
143 position: start.union(end),
144 })
145 }
146 Token(TSXToken::Keyword(TSXKeyword::Class), _) => {
147 let Token(_, start) = reader.next().unwrap();
148 state.append_keyword_at_pos(start.0, TSXKeyword::Class);
149 let class_declaration =
150 ClassDeclaration::from_reader_sub_class_keyword(reader, state, options, start)?;
151 let position = start.union(class_declaration.get_position());
152 Ok(Self::Item { exported: Exportable::Class(class_declaration), position })
153 }
154 Token(TSXToken::Keyword(TSXKeyword::Enum), _) => {
155 let Token(_, start) = reader.next().unwrap();
156 let enum_declaration = EnumDeclaration::from_reader(reader, state, options)?;
157 let position = start.union(enum_declaration.get_position());
158 Ok(Self::Item { exported: Exportable::EnumDeclaration(enum_declaration), position })
159 }
160 Token(TSXToken::Keyword(TSXKeyword::Const | TSXKeyword::Let), _) => {
161 let variable_declaration =
162 VariableDeclaration::from_reader(reader, state, options)?;
163 let position = start.union(variable_declaration.get_position());
164 Ok(Self::Item { exported: Exportable::Variable(variable_declaration), position })
165 }
166 Token(TSXToken::Keyword(TSXKeyword::Interface), _) => {
167 let interface_declaration =
168 InterfaceDeclaration::from_reader(reader, state, options)?;
169 let position = start.union(interface_declaration.get_position());
170 Ok(Self::Item { exported: Exportable::Interface(interface_declaration), position })
171 }
172 Token(TSXToken::Keyword(TSXKeyword::Type), _) => {
173 if let Token(TSXToken::OpenBrace, _) =
174 reader.peek_n(1).ok_or_else(parse_lexing_error)?
175 {
176 state.append_keyword_at_pos(reader.next().unwrap().1 .0, TSXKeyword::Type);
177 let Token(_, start) = reader.next().unwrap(); let (parts, _, _end) = crate::parse_bracketed::<ImportExportPart<_>>(
180 reader,
181 state,
182 options,
183 None,
184 TSXToken::CloseBrace,
185 )?;
186
187 let from_pos = state.expect_keyword(reader, TSXKeyword::From)?;
188
189 let (from, end) =
190 ImportLocation::from_reader(reader, state, options, Some(from_pos))?;
191
192 Ok(Self::Item {
193 exported: Exportable::ImportParts {
194 parts,
195 from,
196 type_definitions_only: true,
197 },
198 position: start.union(end),
199 })
200 } else {
201 let type_alias = TypeAlias::from_reader(reader, state, options)?;
202 let position = start.union(type_alias.get_position());
203 Ok(Self::Item { exported: Exportable::TypeAlias(type_alias), position })
204 }
205 }
206 Token(TSXToken::OpenBrace, _) => {
207 let Token(_, start) = reader.next().unwrap();
208 let mut bracket_depth = 1;
209 let after_bracket = reader.scan(|token, _| match token {
210 TSXToken::OpenBrace => {
211 bracket_depth += 1;
212 false
213 }
214 TSXToken::CloseBrace => {
215 bracket_depth -= 1;
216 bracket_depth == 0
217 }
218 _ => false,
219 });
220 if let Some(Token(token_type, _)) = after_bracket {
221 if let TSXToken::Keyword(TSXKeyword::From) = token_type {
222 let (parts, _, _end) = crate::parse_bracketed::<ImportExportPart<_>>(
223 reader,
224 state,
225 options,
226 None,
227 TSXToken::CloseBrace,
228 )?;
229 let Token(_from_kw, start) = reader.next().unwrap();
230 state.append_keyword_at_pos(start.0, TSXKeyword::From);
231
232 let (from, end) =
233 ImportLocation::from_reader(reader, state, options, Some(start))?;
234 Ok(Self::Item {
235 exported: Exportable::ImportParts {
236 parts,
237 from,
238 type_definitions_only: false,
239 },
240 position: start.union(end),
241 })
242 } else {
243 let (parts, _, end) = crate::parse_bracketed::<ImportExportPart<_>>(
244 reader,
245 state,
246 options,
247 None,
248 TSXToken::CloseBrace,
249 )?;
250 Ok(Self::Item {
251 exported: Exportable::Parts(parts),
252 position: start.union(end),
253 })
254 }
255 } else {
256 Err(ParseError::new(
257 crate::ParseErrors::UnmatchedBrackets,
258 start.with_length(1),
259 ))
260 }
261 }
262 Token(TSXToken::Keyword(kw), _) if kw.is_in_function_header() => {
263 let function_declaration = StatementFunction::from_reader(reader, state, options)?;
264 let position = start.union(function_declaration.get_position());
265 Ok(Self::Item { exported: Exportable::Function(function_declaration), position })
266 }
267 _ => throw_unexpected_token(
268 reader,
269 &[
270 TSXToken::Keyword(TSXKeyword::Class),
271 TSXToken::Keyword(TSXKeyword::Function),
272 TSXToken::Keyword(TSXKeyword::Const),
273 TSXToken::Keyword(TSXKeyword::Let),
274 TSXToken::Keyword(TSXKeyword::Interface),
275 TSXToken::Keyword(TSXKeyword::Type),
276 TSXToken::OpenBrace,
277 ],
278 ),
279 }
280 }
281
282 fn to_string_from_buffer<T: source_map::ToString>(
283 &self,
284 buf: &mut T,
285 options: &crate::ToStringOptions,
286 local: crate::LocalToStringInformation,
287 ) {
288 match self {
289 ExportDeclaration::Item { exported, .. } => {
290 buf.push_str("export ");
291 match exported {
292 Exportable::Class(class_declaration) => {
293 class_declaration.to_string_from_buffer(buf, options, local);
294 }
295 Exportable::Function(function_declaration) => {
296 function_declaration.to_string_from_buffer(buf, options, local);
297 }
298 Exportable::Interface(interface_declaration) => {
299 interface_declaration.to_string_from_buffer(buf, options, local);
300 }
301 Exportable::Variable(variable_dec_stmt) => {
302 variable_dec_stmt.to_string_from_buffer(buf, options, local);
303 }
304 Exportable::TypeAlias(type_alias) => {
305 type_alias.to_string_from_buffer(buf, options, local);
306 }
307 Exportable::EnumDeclaration(enum_declaration) => {
308 enum_declaration.to_string_from_buffer(buf, options, local);
309 }
310 Exportable::Parts(parts) => {
311 super::import_export_parts_to_string_from_buffer(
312 parts, buf, options, local,
313 );
314 }
315 Exportable::ImportAll { r#as, from } => {
316 buf.push_str("* ");
317 if let Some(r#as) = r#as {
318 buf.push_str("as ");
319 r#as.to_string_from_buffer(buf, options, local);
320 buf.push(' ');
321 }
322 buf.push_str("from \"");
323 from.to_string_from_buffer(buf);
324 buf.push('"');
325 }
326 Exportable::ImportParts { parts, from, type_definitions_only } => {
327 if *type_definitions_only {
328 buf.push_str("type ");
329 }
330 super::import_export_parts_to_string_from_buffer(
331 parts, buf, options, local,
332 );
333 options.push_gap_optionally(buf);
334 buf.push_str("from \"");
335 from.to_string_from_buffer(buf);
336 buf.push('"');
337 }
338 }
339 }
340 ExportDeclaration::Default { expression, position: _ } => {
341 buf.push_str("export default ");
342 expression.to_string_from_buffer(buf, options, local);
343 }
344 ExportDeclaration::DefaultFunction {
345 is_async,
346 identifier,
347 parameters,
348 return_type,
349 position: _,
350 } => {
351 if options.include_type_annotations {
352 buf.push_str("export default ");
353 if *is_async {
354 buf.push_str("async ");
355 }
356 buf.push_str("function ");
357 if let Some(ref identifier) = identifier {
358 identifier.to_string_from_buffer(buf, options, local);
359 buf.push(' ');
360 }
361 parameters.to_string_from_buffer(buf, options, local);
362 if let Some(ref return_type) = return_type {
363 buf.push_str(": ");
364 return_type.to_string_from_buffer(buf, options, local);
365 }
366 }
367 }
368 }
369 }
370}