1use crate::{derive_ASTNode, functions::HeadingAndPosition, VariableIdentifier};
2use tokenizer_lib::sized_tokens::TokenStart;
3use visitable_derive::Visitable;
4
5use crate::{
6 errors::parse_lexing_error,
7 functions::{FunctionBased, FunctionParameters, Parameter},
8 tokens::token_as_identifier,
9 ASTNode, Block, Expression, FunctionBase, ParseOptions, ParseResult, Span, TSXToken, Token,
10 TokenReader, TypeAnnotation, VariableField,
11};
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14pub struct ArrowFunctionBase;
15
16pub type ArrowFunction = FunctionBase<ArrowFunctionBase>;
17#[cfg_attr(target_family = "wasm", tsify::declare)]
18pub type IsAsync = bool;
19
20#[cfg_attr(target_family = "wasm", wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section))]
21#[allow(dead_code)]
22const TYPES: &str = r"
23 export interface ArrowFunction extends FunctionBase {
24 header: IsAsync,
25 body: ExpressionOrBlock
26 }
27";
28
29impl FunctionBased for ArrowFunctionBase {
30 type Name = ();
31 type Header = IsAsync;
32 type Body = ExpressionOrBlock;
33 type LeadingParameter = ();
34 type ParameterVisibility = ();
35
36 fn header_and_name_from_reader(
41 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
42 state: &mut crate::ParsingState,
43 _options: &ParseOptions,
44 ) -> ParseResult<(HeadingAndPosition<Self>, Self::Name)> {
45 let async_pos = state.optionally_expect_keyword(reader, crate::TSXKeyword::Async);
46 Ok(((async_pos.map(|s| s.get_start()), async_pos.is_some()), ()))
47 }
48
49 fn header_and_name_to_string_from_buffer<T: source_map::ToString>(
50 buf: &mut T,
51 is_async: &Self::Header,
52 _name: &Self::Name,
53 _options: &crate::ToStringOptions,
54 _local: crate::LocalToStringInformation,
55 ) {
56 if *is_async {
57 buf.push_str("async ");
58 }
59 }
60
61 fn parameters_from_reader<T: source_map::ToString>(
62 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
63 state: &mut crate::ParsingState,
64 options: &ParseOptions,
65 ) -> ParseResult<FunctionParameters<(), ()>> {
66 match reader.next().ok_or_else(parse_lexing_error)? {
67 Token(TSXToken::OpenParentheses, open_paren) => {
68 FunctionParameters::from_reader_sub_open_parenthesis(
69 reader, state, options, open_paren,
70 )
71 }
72 token => {
74 let (name, position) = token_as_identifier(token, "arrow function parameter")?;
75 let parameters = vec![Parameter {
76 visibility: (),
77 name: VariableField::Name(VariableIdentifier::Standard(name, position)).into(),
78 type_annotation: None,
79 additionally: None,
80 position,
81 }];
82 Ok(FunctionParameters { leading: (), parameters, rest_parameter: None, position })
83 }
84 }
85 }
86
87 fn parameters_to_string_from_buffer<T: source_map::ToString>(
88 buf: &mut T,
89 parameters: &FunctionParameters<(), ()>,
90 options: &crate::ToStringOptions,
91 local: crate::LocalToStringInformation,
92 ) {
93 if let ([Parameter { name, type_annotation, .. }], None) =
95 (parameters.parameters.as_slice(), ¶meters.rest_parameter)
96 {
97 let is_printing_type_annotation =
98 options.include_type_annotations && type_annotation.is_some();
99 if !is_printing_type_annotation {
100 if let VariableField::Name(name, ..) = name.get_ast_ref() {
101 name.to_string_from_buffer(buf, options, local);
102 return;
103 }
104 }
105 }
106 parameters.to_string_from_buffer(buf, options, local);
107 }
108
109 fn parameter_body_boundary_token_to_string_from_buffer<T: source_map::ToString>(
110 buf: &mut T,
111 options: &crate::ToStringOptions,
112 ) {
113 buf.push_str(if options.pretty { " => " } else { "=>" });
114 }
115
116 fn visit_name<TData>(
117 (): &Self::Name,
118 _: &mut (impl crate::VisitorReceiver<TData> + ?Sized),
119 _: &mut TData,
120 _: &crate::visiting::VisitOptions,
121 _: &mut temporary_annex::Annex<crate::Chain>,
122 ) {
123 }
124
125 fn visit_name_mut<TData>(
126 (): &mut Self::Name,
127 _: &mut (impl crate::VisitorMutReceiver<TData> + ?Sized),
128 _: &mut TData,
129 _: &crate::visiting::VisitOptions,
130 _: &mut temporary_annex::Annex<crate::Chain>,
131 ) {
132 }
133
134 fn get_name((): &Self::Name) -> Option<&str> {
135 None
136 }
137}
138
139impl ArrowFunction {
140 pub(crate) fn from_reader_with_first_parameter(
141 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
142 state: &mut crate::ParsingState,
143 options: &ParseOptions,
144 first_parameter: (String, Span),
145 is_async: IsAsync,
146 ) -> ParseResult<Self> {
147 let (first_parameter_name, first_parameter_position) = first_parameter;
148 let name = VariableField::Name(VariableIdentifier::Standard(
149 first_parameter_name,
150 first_parameter_position,
151 ));
152 let parameters = vec![Parameter {
153 visibility: (),
154 name: name.into(),
155 type_annotation: None,
156 additionally: None,
157 position: first_parameter.1,
158 }];
159 reader.expect_next(TSXToken::Arrow)?;
160 let body = ExpressionOrBlock::from_reader(reader, state, options)?;
161 let arrow_function = FunctionBase {
162 header: is_async,
163 position: first_parameter.1.union(body.get_position()),
164 name: (),
165 parameters: FunctionParameters {
166 parameters,
167 rest_parameter: None,
168 position: first_parameter.1,
169 leading: (),
170 },
171 return_type: None,
172 type_parameters: None,
173 body,
174 };
175 Ok(arrow_function)
176 }
177
178 pub(crate) fn from_reader_sub_open_paren(
179 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
180 state: &mut crate::ParsingState,
181 options: &ParseOptions,
182 is_async: IsAsync,
183 start: TokenStart,
184 ) -> ParseResult<Self> {
185 let parameters =
186 FunctionParameters::from_reader_sub_open_parenthesis(reader, state, options, start)?;
187
188 let return_type = if reader
189 .conditional_next(|token| options.type_annotations && matches!(token, TSXToken::Colon))
190 .is_some()
191 {
192 Some(TypeAnnotation::from_reader(reader, state, options)?)
193 } else {
194 None
195 };
196 reader.expect_next(TSXToken::Arrow)?;
197 let body = ExpressionOrBlock::from_reader(reader, state, options)?;
198 Ok(FunctionBase {
199 header: is_async,
200 name: (),
201 parameters,
202 return_type,
203 type_parameters: None,
204 position: start.union(body.get_position()),
205 body,
206 })
207 }
208}
209
210#[derive(Debug, Clone, PartialEq, Visitable)]
212#[apply(derive_ASTNode)]
213pub enum ExpressionOrBlock {
214 Expression(Box<Expression>),
215 Block(Block),
216}
217
218impl ASTNode for ExpressionOrBlock {
219 fn get_position(&self) -> Span {
220 match self {
221 ExpressionOrBlock::Expression(expression) => expression.get_position(),
222 ExpressionOrBlock::Block(block) => block.get_position(),
223 }
224 }
225
226 fn from_reader(
227 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
228 state: &mut crate::ParsingState,
229 options: &ParseOptions,
230 ) -> ParseResult<Self> {
231 if let Some(Token(TSXToken::OpenBrace, _)) = reader.peek() {
232 Ok(Self::Block(Block::from_reader(reader, state, options)?))
233 } else {
234 let expression = Expression::from_reader(reader, state, options)?;
235 Ok(Self::Expression(Box::new(expression)))
236 }
237 }
238
239 fn to_string_from_buffer<T: source_map::ToString>(
240 &self,
241 buf: &mut T,
242 options: &crate::ToStringOptions,
243 local: crate::LocalToStringInformation,
244 ) {
245 match self {
246 ExpressionOrBlock::Expression(expr) => expr.to_string_from_buffer(buf, options, local),
247 ExpressionOrBlock::Block(block) => block.to_string_from_buffer(buf, options, local),
248 }
249 }
250}