1use crate::{
2 are_nodes_over_length, declarations::ClassDeclaration, derive_ASTNode,
3 errors::parse_lexing_error, functions, number::NumberRepresentation, parse_bracketed,
4 throw_unexpected_token_with_token, to_string_bracketed,
5 type_annotations::generic_arguments_from_reader_sub_open_angle, ExpressionPosition,
6 FunctionHeader, ListItem, Marker, ParseErrors, ParseResult, Quoted, TSXKeyword,
7};
8
9use self::{
10 assignments::{LHSOfAssignment, VariableOrPropertyAccess},
11 object_literal::ObjectLiteral,
12 operators::{
13 IncrementOrDecrement, Operator, ARROW_FUNCTION_PRECEDENCE, COMMA_PRECEDENCE,
14 CONDITIONAL_TERNARY_PRECEDENCE, CONSTRUCTOR_PRECEDENCE,
15 CONSTRUCTOR_WITHOUT_PARENTHESIS_PRECEDENCE, INDEX_PRECEDENCE, MEMBER_ACCESS_PRECEDENCE,
16 PARENTHESIZED_EXPRESSION_AND_LITERAL_PRECEDENCE,
17 },
18};
19
20use super::{
21 tokens::token_as_identifier, ASTNode, Block, FunctionBase, JSXRoot, ParseError, ParseOptions,
22 Span, TSXToken, Token, TokenReader, TypeAnnotation,
23};
24
25#[cfg(feature = "extras")]
26use crate::extensions::is_expression::{is_expression_from_reader_sub_is_keyword, IsExpression};
27
28use derive_partial_eq_extras::PartialEqExtras;
29use get_field_by_type::GetFieldByType;
30use source_map::{Nullable, ToString};
31use tokenizer_lib::sized_tokens::{SizedToken, TokenEnd, TokenReaderWithTokenEnds, TokenStart};
32use visitable_derive::Visitable;
33
34pub mod arrow_function;
35pub mod assignments;
36pub mod object_literal;
37pub mod operators;
38pub mod template_literal;
39pub use arrow_function::{ArrowFunction, ExpressionOrBlock};
40
41pub use template_literal::TemplateLiteral;
42
43use operators::{
44 AssociativityDirection, BinaryAssignmentOperator, BinaryOperator, UnaryOperator,
45 UnaryPostfixAssignmentOperator, UnaryPrefixAssignmentOperator, ASSIGNMENT_PRECEDENCE,
46 FUNCTION_CALL_PRECEDENCE, RELATION_PRECEDENCE,
47};
48
49pub type ExpressionFunctionBase = functions::GeneralFunctionBase<ExpressionPosition>;
50pub type ExpressionFunction = FunctionBase<ExpressionFunctionBase>;
51
52use std::convert::{TryFrom, TryInto};
53
54#[apply(derive_ASTNode)]
58#[derive(PartialEqExtras, Debug, Clone, Visitable, GetFieldByType)]
59#[get_field_by_type_target(Span)]
60#[partial_eq_ignore_types(Span)]
61#[visit_self]
62pub enum Expression {
63 NumberLiteral(NumberRepresentation, Span),
65 StringLiteral(String, #[partial_eq_ignore] Quoted, Span),
66 BooleanLiteral(bool, Span),
67 RegexLiteral {
68 pattern: String,
69 flags: Option<String>,
70 position: Span,
71 },
72 ArrayLiteral(Vec<ArrayElement>, Span),
73 ObjectLiteral(ObjectLiteral),
74 TemplateLiteral(TemplateLiteral),
75 ParenthesizedExpression(Box<MultipleExpression>, Span),
76 BinaryOperation {
78 lhs: Box<Expression>,
79 operator: BinaryOperator,
80 rhs: Box<Expression>,
81 position: Span,
82 },
83 SpecialOperators(SpecialOperators, Span),
84 UnaryOperation {
85 operator: UnaryOperator,
86 operand: Box<Expression>,
87 position: Span,
88 },
89 Assignment {
91 lhs: LHSOfAssignment,
92 rhs: Box<Expression>,
93 position: Span,
94 },
95 BinaryAssignmentOperation {
97 lhs: VariableOrPropertyAccess,
98 operator: BinaryAssignmentOperator,
99 rhs: Box<Expression>,
100 position: Span,
101 },
102 UnaryPrefixAssignmentOperation {
103 operator: UnaryPrefixAssignmentOperator,
104 operand: VariableOrPropertyAccess,
105 position: Span,
106 },
107 UnaryPostfixAssignmentOperation {
108 operand: VariableOrPropertyAccess,
109 operator: UnaryPostfixAssignmentOperator,
110 position: Span,
111 },
112 VariableReference(String, Span),
114 ThisReference(Span),
115 SuperExpression(SuperReference, Span),
116 NewTarget(Span),
118 ImportMeta(Span),
119 DynamicImport {
120 path: Box<Expression>,
121 options: Option<Box<Expression>>,
122 position: Span,
123 },
124 PropertyAccess {
125 parent: Box<Expression>,
126 property: PropertyReference,
127 is_optional: bool,
128 position: Span,
129 },
130 Index {
132 indexee: Box<Expression>,
133 indexer: Box<MultipleExpression>,
134 is_optional: bool,
135 position: Span,
136 },
137 FunctionCall {
139 function: Box<Expression>,
140 type_arguments: Option<Vec<TypeAnnotation>>,
141 arguments: Vec<FunctionArgument>,
142 is_optional: bool,
143 position: Span,
144 },
145 ConstructorCall {
146 constructor: Box<Expression>,
147 type_arguments: Option<Vec<TypeAnnotation>>,
148 arguments: Option<Vec<FunctionArgument>>,
149 position: Span,
150 },
151 ConditionalTernary {
153 condition: Box<Expression>,
154 truthy_result: Box<Expression>,
155 falsy_result: Box<Expression>,
156 position: Span,
157 },
158 ArrowFunction(ArrowFunction),
160 ExpressionFunction(ExpressionFunction),
161 ClassExpression(ClassDeclaration<ExpressionPosition>),
163 Null(Span),
164 Comment {
165 content: String,
166 on: Box<Expression>,
167 position: Span,
168 is_multiline: bool,
169 prefix: bool,
170 },
171 JSXRoot(JSXRoot),
173 #[cfg(feature = "extras")]
175 IsExpression(IsExpression),
176 #[cfg_attr(feature = "self-rust-tokenize", self_tokenize_field(marker_id))]
177 Marker {
178 #[visit_skip_field]
179 marker_id: Marker<Expression>,
180 position: Span,
181 },
182}
183
184impl Eq for Expression {}
185
186#[derive(PartialEq, Debug, Clone)]
187#[apply(derive_ASTNode)]
188pub enum PropertyReference {
189 Standard {
190 property: String,
191 is_private: bool,
192 },
193 #[cfg_attr(feature = "self-rust-tokenize", self_tokenize_field(0))]
194 Marker(Marker<PropertyReference>),
195}
196
197impl ASTNode for Expression {
198 fn from_reader(
199 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
200 state: &mut crate::ParsingState,
201 options: &ParseOptions,
202 ) -> ParseResult<Expression> {
203 Self::from_reader_with_precedence(reader, state, options, COMMA_PRECEDENCE, None)
204 }
205
206 fn to_string_from_buffer<T: source_map::ToString>(
207 &self,
208 buf: &mut T,
209 options: &crate::ToStringOptions,
210 local: crate::LocalToStringInformation,
211 ) {
212 self.to_string_using_precedence(
213 buf,
214 options,
215 local,
216 ExpressionToStringArgument { on_left: false, parent_precedence: u8::MAX },
217 );
218 }
219
220 fn get_position(&self) -> Span {
221 *GetFieldByType::get(self)
222 }
223}
224
225impl Expression {
226 #[allow(clippy::similar_names)]
227 pub fn from_reader_with_precedence(
228 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
229 state: &mut crate::ParsingState,
230 options: &ParseOptions,
231 return_precedence: u8,
232 start: Option<TokenStart>,
234 ) -> ParseResult<Self> {
235 if let (true, Some(Token(peek, at))) = (options.partial_syntax, reader.peek()) {
236 let next_is_not_expression_like = peek.is_expression_delimiter()
237 || start.map_or(false, |start| {
238 peek.is_statement_or_declaration_start()
239 && state
240 .line_starts
241 .byte_indexes_on_different_lines(start.0 as usize, at.0 as usize)
242 });
243
244 if next_is_not_expression_like {
245 let point = start.unwrap_or(*at);
246 let position = point.union(source_map::End(at.0));
248 return Ok(Expression::Marker {
249 marker_id: state.new_partial_point_marker(point),
250 position,
251 });
252 }
253 }
254
255 let first_expression = match reader.next().ok_or_else(parse_lexing_error)? {
256 Token(TSXToken::StringLiteral(content, quoted), start) => {
257 let position = start.with_length(content.len() + 2);
258 Expression::StringLiteral(content, quoted, position)
259 }
260 Token(TSXToken::NumberLiteral(value), start) => {
261 let position = start.with_length(value.len());
262 match value.parse::<NumberRepresentation>() {
263 Ok(number) => Expression::NumberLiteral(number, position),
264 Err(_) => {
265 return Err(ParseError::new(ParseErrors::InvalidNumberLiteral, position));
267 }
268 }
269 }
270 Token(TSXToken::RegexLiteral(pattern), start) => {
271 let mut position = start.with_length(pattern.len());
272 let flag_token =
273 reader.conditional_next(|t| matches!(t, TSXToken::RegexFlagLiteral(..)));
274 let flags = if let Some(Token(TSXToken::RegexFlagLiteral(flags), start)) =
275 flag_token
276 {
277 if flags.contains(|chr| !matches!(chr, 'd' | 'g' | 'i' | 'm' | 's' | 'u' | 'y'))
278 {
279 return Err(ParseError::new(
280 ParseErrors::InvalidRegexFlag,
281 start.with_length(flags.len()),
282 ));
283 }
284 position = position.union(start.get_end_after(flags.len()));
285 Some(flags)
286 } else {
287 None
288 };
289 Expression::RegexLiteral { pattern, flags, position }
290 }
291 t @ Token(TSXToken::Keyword(TSXKeyword::True), _) => {
292 Expression::BooleanLiteral(true, t.get_span())
293 }
294 t @ Token(TSXToken::Keyword(TSXKeyword::False), _) => {
295 Expression::BooleanLiteral(false, t.get_span())
296 }
297 t @ Token(TSXToken::Keyword(TSXKeyword::This), _) => {
298 Expression::ThisReference(t.get_span())
299 }
300 t @ Token(TSXToken::Keyword(TSXKeyword::Import), start) => {
301 let token = reader.next();
302 if let Some(Token(TSXToken::Dot, _)) = token {
303 let meta_start = reader.expect_next(TSXToken::Identifier("meta".into()))?;
304 Expression::ImportMeta(start.union(meta_start.get_end_after("meta".len())))
305 } else if let Some(Token(TSXToken::OpenParentheses, _)) = token {
306 let path = Expression::from_reader(reader, state, options)?;
307 if let Expression::StringLiteral(path, ..) = &path {
308 state.constant_imports.push(path.clone());
309 }
310
311 let options =
312 if reader.conditional_next(|t| matches!(t, TSXToken::Comma)).is_some() {
313 Some(Box::new(Expression::from_reader(reader, state, options)?))
314 } else {
315 None
316 };
317 let end = reader.expect_next(TSXToken::CloseParentheses)?;
318 Expression::DynamicImport {
319 path: Box::new(path),
320 options,
321 position: start.union(end.get_end_after(1)),
322 }
323 } else if let Some(token) = token {
324 return throw_unexpected_token_with_token(
325 token,
326 &[TSXToken::Dot, TSXToken::OpenParentheses],
327 );
328 } else {
329 return Err(ParseError::new(ParseErrors::LexingFailed, t.get_span()));
330 }
331 }
332 t @ Token(TSXToken::Keyword(TSXKeyword::Super), _) => {
333 let _super_position = t.get_span();
334 let token = reader.next().unwrap();
335 let position = token.get_span();
336
337 let (reference, end) = match token {
338 Token(TSXToken::Dot, _) => {
339 let (property, property_pos) =
340 token_as_identifier(reader.next().unwrap(), "super property")?;
341 (
342 SuperReference::PropertyAccess { property },
343 TokenEnd::new(property_pos.end),
344 )
345 }
346 Token(TSXToken::OpenParentheses, _) => {
347 let (arguments, _, end_pos) = parse_bracketed(
348 reader,
349 state,
350 options,
351 None,
352 TSXToken::CloseParentheses,
353 )?;
354 (SuperReference::Call { arguments }, end_pos)
355 }
356 Token(TSXToken::OpenBracket, _) => {
357 let indexer = Expression::from_reader(reader, state, options)?;
358 let end = reader.expect_next(TSXToken::CloseBracket)?;
359 (
360 SuperReference::Index { indexer: Box::new(indexer) },
361 TokenEnd::new(end.0 + 1),
362 )
363 }
364 token => {
365 return throw_unexpected_token_with_token(
366 token,
367 &[TSXToken::Dot, TSXToken::OpenParentheses, TSXToken::OpenBracket],
368 );
369 }
370 };
371 Expression::SuperExpression(reference, position.union(end))
372 }
373 t @ Token(TSXToken::Keyword(TSXKeyword::Null), _) => Expression::Null(t.get_span()),
374 Token(TSXToken::Keyword(kw @ TSXKeyword::Class), start) => {
375 state.append_keyword_at_pos(start.0, kw);
376 ClassDeclaration::from_reader_sub_class_keyword(reader, state, options, start)
377 .map(Expression::ClassExpression)?
378 }
379 Token(TSXToken::Keyword(TSXKeyword::Yield), s) => {
380 let is_delegated =
382 reader.conditional_next(|t| matches!(t, TSXToken::Multiply)).is_some();
383
384 let operator =
385 if is_delegated { UnaryOperator::DelegatedYield } else { UnaryOperator::Yield };
386
387 let operand = Expression::from_reader_with_precedence(
388 reader,
389 state,
390 options,
391 operator.precedence(),
392 Some(s),
393 )?;
394 let position = s.union(operand.get_position());
395 Expression::UnaryOperation { operator, operand: Box::new(operand), position }
396 }
397 Token(TSXToken::OpenBracket, start) => {
398 let (items, _, end) = parse_bracketed::<ArrayElement>(
399 reader,
400 state,
401 options,
402 None,
403 TSXToken::CloseBracket,
404 )?;
405
406 Expression::ArrayLiteral(items, start.union(end))
407 }
408 Token(TSXToken::OpenBrace, start) => {
409 ObjectLiteral::from_reader_sub_open_curly(reader, state, options, start)
410 .map(Expression::ObjectLiteral)?
411 }
412 t @ Token(TSXToken::OpenParentheses, start) => {
413 let mut parentheses_depth = 1;
414 let is_arrow_function = if let Some(Token(
415 TSXToken::Keyword(..)
416 | TSXToken::Identifier(..)
417 | TSXToken::OpenBrace
418 | TSXToken::OpenBracket
419 | TSXToken::CloseParentheses
420 | TSXToken::Spread,
421 _,
422 )) = reader.peek()
423 {
424 let next = reader.scan(|token, _| match token {
425 TSXToken::OpenParentheses => {
426 parentheses_depth += 1;
427 false
428 }
429 TSXToken::CloseParentheses => {
430 parentheses_depth -= 1;
431 parentheses_depth == 0
432 }
433 _ => false,
434 });
435
436 if let Some(Token(token_type, _)) = next {
437 matches!(token_type, TSXToken::Arrow)
438 } else {
439 return Err(ParseError::new(
440 crate::ParseErrors::UnmatchedBrackets,
441 t.get_span(),
442 ));
443 }
444 } else {
445 false
446 };
447
448 if is_arrow_function {
449 let arrow_function = ArrowFunction::from_reader_sub_open_paren(
450 reader, state, options, false, start,
451 )?;
452 Expression::ArrowFunction(arrow_function)
453 } else {
454 let parenthesize_expression =
455 MultipleExpression::from_reader(reader, state, options)?;
456 let end = reader.expect_next_get_end(TSXToken::CloseParentheses)?;
457 Expression::ParenthesizedExpression(
458 Box::new(parenthesize_expression),
459 start.union(end),
460 )
461 }
462 }
463 t @ Token(TSXToken::Keyword(TSXKeyword::New), start) => {
464 if let Some(Token(TSXToken::Dot, _)) = reader.peek() {
465 reader.expect_next(TSXToken::Dot)?;
467 reader.expect_next(TSXToken::Identifier("target".into()))?;
468 Expression::NewTarget(t.get_span())
469 } else {
470 let constructor_expression = Self::from_reader_with_precedence(
472 reader,
473 state,
474 options,
475 FUNCTION_CALL_PRECEDENCE,
476 Some(start),
477 )?;
478 let position = start.union(constructor_expression.get_position());
479
480 let (type_arguments, end) = if reader
481 .conditional_next(|token| *token == TSXToken::OpenChevron)
482 .is_some()
483 {
484 let (generic_arguments, _, end_pos) =
485 parse_bracketed(reader, state, options, None, TSXToken::CloseChevron)?;
486 (Some(generic_arguments), end_pos)
487 } else {
488 (None, TokenEnd::new(position.end))
489 };
490
491 let (arguments, end) = if reader
492 .conditional_next(|token| *token == TSXToken::OpenParentheses)
493 .is_some()
494 {
495 parse_bracketed(reader, state, options, None, TSXToken::CloseParentheses)
496 .map(|(args, _, end)| (Some(args), end))?
497 } else {
498 (None, end)
500 };
501
502 Expression::ConstructorCall {
503 constructor: constructor_expression.into(),
504 type_arguments,
505 arguments,
506 position: start.union(end),
507 }
508 }
509 }
510 t @ Token(TSXToken::MultiLineComment(_) | TSXToken::Comment(_), _) => {
518 let (content, is_multiline, position) = TSXToken::try_into_comment(t).unwrap();
520
521 let expression = Self::from_reader_with_precedence(
522 reader,
523 state,
524 options,
525 return_precedence,
526 start,
527 )?;
528 let position = position.union(expression.get_position());
529 Expression::Comment {
530 is_multiline,
531 content,
532 position,
533 on: Box::new(expression),
534 prefix: true,
535 }
536 }
537 Token(TSXToken::DocTypeHTML, _) => {
539 JSXRoot::from_reader(reader, state, options).map(Expression::JSXRoot)?
540 }
541 Token(tok @ (TSXToken::JSXOpeningTagStart | TSXToken::JSXFragmentStart), span) => {
542 let var_name = matches!(tok, TSXToken::JSXFragmentStart);
543 JSXRoot::from_reader_sub_start(reader, state, options, var_name, span)
544 .map(Expression::JSXRoot)?
545 }
546 Token(TSXToken::TemplateLiteralStart, start) => {
547 TemplateLiteral::from_reader_sub_start_with_tag(reader, state, options, None, start)
548 .map(Expression::TemplateLiteral)?
549 }
550 Token(TSXToken::Keyword(kw), start) if function_header_ish(kw, reader) => {
551 let token = Token(TSXToken::Keyword(kw), start);
553 let (is_async, start, token) =
554 if let Token(TSXToken::Keyword(TSXKeyword::Async), start) = token {
555 (true, start, reader.next().unwrap())
556 } else {
557 (false, start, token)
558 };
559
560 if is_async
561 && !matches!(token, Token(TSXToken::Keyword(ref kw), _) if kw.is_in_function_header())
562 {
563 if let Token(TSXToken::OpenParentheses, start) = token {
564 let function = ArrowFunction::from_reader_sub_open_paren(
565 reader, state, options, is_async, start,
566 )?;
567 return Ok(Expression::ArrowFunction(function));
568 }
569
570 let (name, position) = token_as_identifier(token, "function parameter")?;
571 ArrowFunction::from_reader_with_first_parameter(
572 reader,
573 state,
574 options,
575 (name, position),
576 is_async,
577 )
578 .map(Expression::ArrowFunction)?
579 } else {
580 #[cfg(feature = "extras")]
581 {
582 use crate::functions::FunctionLocationModifier;
583 let (generator_keyword, token) =
584 if let Token(TSXToken::Keyword(TSXKeyword::Generator), _) = token {
585 (Some(token.get_span()), reader.next().unwrap())
586 } else {
587 (None, token)
588 };
589
590 let (location, token) = match token {
591 Token(TSXToken::Keyword(TSXKeyword::Server), _) => {
592 (Some(FunctionLocationModifier::Server), reader.next().unwrap())
593 }
594 Token(TSXToken::Keyword(TSXKeyword::Worker), _) => {
595 (Some(FunctionLocationModifier::Worker), reader.next().unwrap())
596 }
597 token => (None, token),
598 };
599
600 let Token(TSXToken::Keyword(TSXKeyword::Function), function_start) = token
602 else {
603 return throw_unexpected_token_with_token(
604 token,
605 &[TSXToken::Keyword(TSXKeyword::Function)],
606 );
607 };
608
609 let function_end =
610 function_start.get_end_after(TSXKeyword::Function.length() as usize);
611
612 if generator_keyword.is_some() {
613 let position = start.union(function_end);
614
615 let header = FunctionHeader::ChadFunctionHeader {
616 is_async,
617 is_generator: true,
618 location,
619 position,
620 };
621
622 let name = if let Some(Token(TSXToken::OpenParentheses, _)) =
623 reader.peek()
624 {
625 None
626 } else {
627 let (token, span) =
628 token_as_identifier(reader.next().unwrap(), "function name")?;
629 Some(crate::VariableIdentifier::Standard(token, span))
630 };
631
632 FunctionBase::from_reader_with_header_and_name(
633 reader,
634 state,
635 options,
636 (Some(header.get_position().get_start()), header),
637 ExpressionPosition(name),
638 )
639 .map(Expression::ExpressionFunction)?
640 } else {
641 let generator_star_token_position = reader
642 .conditional_next(|tok| matches!(tok, TSXToken::Multiply))
643 .map(|token| token.get_span());
644
645 let end = generator_star_token_position
646 .as_ref()
647 .map_or(function_end, Span::get_end);
648
649 let header = FunctionHeader::VirginFunctionHeader {
650 position: start.union(end),
651 is_async,
652 location,
653 generator_star_token_position,
654 };
655
656 let name = if let Some(Token(TSXToken::OpenParentheses, _)) =
657 reader.peek()
658 {
659 None
660 } else {
661 let (token, span) =
662 token_as_identifier(reader.next().unwrap(), "function name")?;
663 Some(crate::VariableIdentifier::Standard(token, span))
664 };
665
666 FunctionBase::from_reader_with_header_and_name(
667 reader,
668 state,
669 options,
670 (Some(header.get_position().get_start()), header),
671 ExpressionPosition(name),
672 )
673 .map(Expression::ExpressionFunction)?
674 }
675 }
676
677 #[cfg(not(feature = "extras"))]
678 {
679 let Token(TSXToken::Keyword(TSXKeyword::Function), _) = token else {
680 return throw_unexpected_token_with_token(
681 token,
682 &[TSXToken::Keyword(TSXKeyword::Function)],
683 );
684 };
685
686 let generator_star_token_position = reader
687 .conditional_next(|tok| matches!(tok, TSXToken::Multiply))
688 .map(|token| token.get_span());
689
690 let position =
691 start.union(generator_star_token_position.as_ref().unwrap_or(
692 &start.with_length(TSXKeyword::Function.length() as usize),
693 ));
694
695 let header = FunctionHeader::VirginFunctionHeader {
696 position,
697 is_async,
698 generator_star_token_position,
699 };
700
701 let name = if let Some(Token(TSXToken::OpenParentheses, _)) = reader.peek()
702 {
703 None
704 } else {
705 let (token, span) =
706 token_as_identifier(reader.next().unwrap(), "function name")?;
707
708 Some(crate::VariableIdentifier::Standard(token, span))
709 };
710 FunctionBase::from_reader_with_header_and_name(
711 reader,
712 state,
713 options,
714 (Some(start), header),
715 ExpressionPosition(name),
716 )
717 .map(Expression::ExpressionFunction)?
718 }
719 }
720 }
721 #[cfg(feature = "extras")]
722 t @ Token(TSXToken::Keyword(TSXKeyword::Is), start) if options.is_expressions => {
723 let mut parentheses_depth = 0;
725 let next = reader.scan(|token, _| match token {
726 TSXToken::OpenParentheses => {
727 parentheses_depth += 1;
728 false
729 }
730 TSXToken::CloseParentheses => {
731 parentheses_depth -= 1;
732 parentheses_depth == 0
733 }
734 _ => false,
735 });
736 if let Some(Token(token_type, _)) = next {
737 if let TSXToken::OpenBrace = token_type {
738 let is_expression_from_reader_sub_is_keyword =
739 is_expression_from_reader_sub_is_keyword(reader, state, options, start);
740
741 is_expression_from_reader_sub_is_keyword.map(Expression::IsExpression)?
742 } else {
743 Expression::VariableReference("is".to_owned(), start.with_length(2))
744 }
745 } else {
746 return Err(ParseError::new(
747 crate::ParseErrors::UnmatchedBrackets,
748 t.get_span(),
749 ));
750 }
751 }
752 Token(TSXToken::HashTag, start) => {
753 let (property_name, _) = token_as_identifier(
754 reader.next().ok_or_else(parse_lexing_error)?,
755 "private in expression",
756 )?;
757 let in_pos = state.expect_keyword(reader, TSXKeyword::In)?;
758 let rhs = Expression::from_reader_with_precedence(
759 reader,
760 state,
761 options,
762 RELATION_PRECEDENCE,
763 Some(in_pos),
764 )?;
765 let position = start.union(rhs.get_position());
766 Self::SpecialOperators(
767 SpecialOperators::In {
768 lhs: InExpressionLHS::PrivateProperty(property_name),
769 rhs: Box::new(rhs),
770 },
771 position,
772 )
773 }
774 token => {
775 if let Ok(unary_operator) = UnaryOperator::try_from(&token.0) {
776 let precedence = unary_operator.precedence();
777 let operand = Self::from_reader_with_precedence(
778 reader,
779 state,
780 options,
781 precedence,
782 Some(token.1),
783 )?;
784 let position = token.get_span().union(operand.get_position());
785 Expression::UnaryOperation {
786 operand: Box::new(operand),
787 operator: unary_operator,
788 position,
789 }
790 } else if let Ok(unary_prefix_operator) =
791 UnaryPrefixAssignmentOperator::try_from(&token.0)
792 {
793 let op_precedence = unary_prefix_operator.precedence();
795 let operand = VariableOrPropertyAccess::from_reader_with_precedence(
796 reader,
797 state,
798 options,
799 op_precedence,
800 )?;
801 let position = token.get_span().union(operand.get_position());
802 Expression::UnaryPrefixAssignmentOperation {
803 operand,
804 operator: unary_prefix_operator,
805 position,
806 }
807 } else {
808 if let TSXToken::Keyword(ref keyword) = token.0 {
809 if keyword.is_invalid_identifier() {
810 return Err(ParseError::new(
811 ParseErrors::ReservedIdentifier,
812 token.get_span(),
813 ));
814 }
815 }
816
817 let (name, position) = token_as_identifier(token, "variable reference")?;
818
819 if options.interpolation_points && name == crate::marker::MARKER {
820 let marker_id = state.new_partial_point_marker(position.get_start());
821 Expression::Marker { marker_id, position }
822 } else if let Some(Token(TSXToken::Arrow, _)) = reader.peek() {
823 let function = ArrowFunction::from_reader_with_first_parameter(
824 reader,
825 state,
826 options,
827 (name, position),
828 false,
829 )?;
830 Expression::ArrowFunction(function)
831 } else {
832 Expression::VariableReference(name, position)
833 }
834 }
835 }
836 };
837
838 if let Expression::ArrowFunction(..) = first_expression {
840 return Ok(first_expression);
841 }
842
843 Self::from_reader_sub_first_expression(
844 reader,
845 state,
846 options,
847 return_precedence,
848 first_expression,
849 )
850 }
851
852 pub(crate) fn from_reader_sub_first_expression(
853 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
854 state: &mut crate::ParsingState,
855 options: &ParseOptions,
856 parent_precedence: u8,
857 first_expression: Expression,
858 ) -> ParseResult<Self> {
859 let mut top = first_expression;
860 while top.get_precedence() != 2 {
861 let Token(peeked_token, _peeked_pos) = &reader.peek().ok_or_else(parse_lexing_error)?;
862
863 match peeked_token {
864 TSXToken::Comma => {
865 return Ok(top);
866 }
867 TSXToken::QuestionMark => {
868 if AssociativityDirection::RightToLeft
869 .should_return(parent_precedence, CONDITIONAL_TERNARY_PRECEDENCE)
870 {
871 return Ok(top);
872 }
873 reader.next();
874 let condition_position = top.get_position();
875 let condition = Box::new(top);
876 let lhs = Box::new(Self::from_reader(reader, state, options)?);
877 reader.expect_next(TSXToken::Colon)?;
878 let rhs = Self::from_reader(reader, state, options)?;
879 let position = condition_position.union(rhs.get_position());
880 top = Expression::ConditionalTernary {
881 position,
882 condition,
883 truthy_result: lhs,
884 falsy_result: Box::new(rhs),
885 };
886 }
887 TSXToken::OpenParentheses | TSXToken::OptionalCall => {
888 if AssociativityDirection::LeftToRight
889 .should_return(parent_precedence, FUNCTION_CALL_PRECEDENCE)
890 {
891 return Ok(top);
892 }
893 let next = reader.next().unwrap();
894 let is_optional = matches!(next.0, TSXToken::OptionalCall);
895 let (arguments, _, end) =
896 parse_bracketed(reader, state, options, None, TSXToken::CloseParentheses)?;
897 let position = top.get_position().union(end);
898 top = Expression::FunctionCall {
899 function: Box::new(top),
900 type_arguments: None,
901 arguments,
902 position,
903 is_optional,
904 };
905 }
906 TSXToken::OpenBracket | TSXToken::OptionalIndex => {
907 if AssociativityDirection::LeftToRight
908 .should_return(parent_precedence, INDEX_PRECEDENCE)
909 {
910 return Ok(top);
911 }
912 let next = reader.next().unwrap();
913 let is_optional = matches!(next.0, TSXToken::OptionalIndex);
914
915 let indexer = MultipleExpression::from_reader(reader, state, options)?;
916 let end = reader.expect_next_get_end(TSXToken::CloseBracket)?;
917 let position = top.get_position().union(end);
918 top = Expression::Index {
919 position,
920 indexee: Box::new(top),
921 indexer: Box::new(indexer),
922 is_optional,
923 };
924 }
925 TSXToken::TemplateLiteralStart => {
926 if AssociativityDirection::LeftToRight
928 .should_return(parent_precedence, FUNCTION_CALL_PRECEDENCE)
929 {
930 return Ok(top);
931 }
932 reader.next();
933 let start = TokenStart::new(top.get_position().start);
935 let tag = Some(Box::new(top));
936 let template_literal = TemplateLiteral::from_reader_sub_start_with_tag(
937 reader, state, options, tag, start,
938 );
939 top = template_literal.map(Expression::TemplateLiteral)?;
940 }
941 TSXToken::Dot | TSXToken::OptionalChain => {
942 if AssociativityDirection::LeftToRight
943 .should_return(parent_precedence, MEMBER_ACCESS_PRECEDENCE)
944 {
945 return Ok(top);
946 }
947
948 let Token(accessor, accessor_position) = reader.next().unwrap();
949 if matches!(top, Self::ObjectLiteral(..)) {
951 return Err(ParseError::new(
952 ParseErrors::CannotAccessObjectLiteralDirectly,
953 accessor_position.with_length(1),
954 ));
955 }
956
957 let is_optional = matches!(accessor, TSXToken::OptionalChain);
958
959 let Token(peek, at) = reader.peek().ok_or_else(parse_lexing_error)?;
960 let is_next_not_identifier = peek.is_expression_delimiter()
961 || (peek.is_statement_or_declaration_start()
962 && state.line_starts.byte_indexes_on_different_lines(
963 accessor_position.0 as usize,
964 at.0 as usize,
965 ));
966
967 let (property, position) = if options.partial_syntax && is_next_not_identifier {
968 let marker = state.new_partial_point_marker(accessor_position);
969 let position = accessor_position.union(source_map::End(at.0));
970 (PropertyReference::Marker(marker), position)
971 } else {
972 let is_private =
973 reader.conditional_next(|t| matches!(t, TSXToken::HashTag)).is_some();
974 let (property, position) = token_as_identifier(
975 reader.next().ok_or_else(parse_lexing_error)?,
976 "variable reference",
977 )?;
978 (PropertyReference::Standard { property, is_private }, position)
979 };
980 let position = top.get_position().union(position);
981 top = Expression::PropertyAccess {
982 parent: Box::new(top),
983 property,
984 position,
985 is_optional,
986 };
987 }
988 TSXToken::Assign => {
989 if AssociativityDirection::RightToLeft
990 .should_return(parent_precedence, ASSIGNMENT_PRECEDENCE)
991 {
992 return Ok(top);
993 }
994
995 let position = top.get_position();
996 let lhs: LHSOfAssignment = top.try_into()?;
997
998 let Token(_assignment, assignment_pos) = reader.next().unwrap();
999 let new_rhs = Self::from_reader_with_precedence(
1000 reader,
1001 state,
1002 options,
1003 parent_precedence,
1004 Some(assignment_pos),
1005 )?;
1006
1007 let position = position.union(new_rhs.get_position());
1008
1009 top = Expression::Assignment { position, lhs, rhs: Box::new(new_rhs) };
1010 }
1011 TSXToken::Comment(_) => {
1012 if reader.peek_n(1).is_some_and(|t| t.0.is_expression_postfix()) {
1014 let (content, is_multiline, position) =
1015 TSXToken::try_into_comment(reader.next().unwrap()).unwrap();
1016 top = Expression::Comment {
1017 content,
1018 on: Box::new(top),
1019 position,
1020 is_multiline,
1021 prefix: false,
1022 };
1023 } else {
1024 return Ok(top);
1025 }
1026 }
1027 TSXToken::MultiLineComment(_) => {
1028 let (content, is_multiline, position) =
1029 TSXToken::try_into_comment(reader.next().unwrap()).unwrap();
1030 top = Expression::Comment {
1031 content,
1032 on: Box::new(top),
1033 position,
1034 is_multiline,
1035 prefix: false,
1036 };
1037 }
1038 TSXToken::Keyword(TSXKeyword::As | TSXKeyword::Satisfies | TSXKeyword::Is)
1039 if options.type_annotations =>
1040 {
1041 if AssociativityDirection::LeftToRight
1042 .should_return(parent_precedence, RELATION_PRECEDENCE)
1043 {
1044 return Ok(top);
1045 }
1046
1047 if (cfg!(not(feature = "extras"))
1048 && matches!(peeked_token, TSXToken::Keyword(TSXKeyword::Is)))
1049 || (cfg!(not(feature = "full-typescript"))
1050 && matches!(peeked_token, TSXToken::Keyword(TSXKeyword::As)))
1051 {
1052 return Ok(top);
1053 }
1054
1055 let token = reader.next().unwrap();
1056 let reference = TypeAnnotation::from_reader(reader, state, options)?;
1057 let position = top.get_position().union(reference.get_position());
1058
1059 let special_operators = match token.0 {
1060 #[cfg(feature = "full-typescript")]
1061 TSXToken::Keyword(TSXKeyword::As) => SpecialOperators::AsCast {
1062 value: top.into(),
1063 rhs: match reference {
1064 TypeAnnotation::Name(
1066 crate::type_annotations::TypeName::Name(name),
1067 span,
1068 ) if name == "const" => TypeOrConst::Const(span),
1069 reference => TypeOrConst::Type(Box::new(reference)),
1070 },
1071 },
1072 TSXToken::Keyword(TSXKeyword::Satisfies) => SpecialOperators::Satisfies {
1073 value: top.into(),
1074 type_annotation: Box::new(reference),
1075 },
1076 #[cfg(feature = "extras")]
1077 TSXToken::Keyword(TSXKeyword::Is) if options.is_expressions => SpecialOperators::Is {
1078 value: top.into(),
1079 type_annotation: Box::new(reference),
1080 },
1081 _ => unreachable!(),
1082 };
1083 top = Self::SpecialOperators(special_operators, position);
1084 }
1085 #[cfg(feature = "full-typescript")]
1086 TSXToken::LogicalNot if options.type_annotations => {
1087 let Token(_token, not_pos) = reader.next().unwrap();
1088 let position = top.get_position().union(not_pos.get_end_after(1));
1089 top = Self::SpecialOperators(
1090 SpecialOperators::NonNullAssertion(Box::new(top)),
1091 position,
1092 );
1093 }
1094 TSXToken::Keyword(TSXKeyword::In) => {
1095 if AssociativityDirection::LeftToRight
1096 .should_return(parent_precedence, RELATION_PRECEDENCE)
1097 {
1098 return Ok(top);
1099 }
1100
1101 let Token(_token, in_pos) = reader.next().unwrap();
1102 let rhs = Expression::from_reader_with_precedence(
1103 reader,
1104 state,
1105 options,
1106 RELATION_PRECEDENCE,
1107 Some(in_pos),
1108 )?;
1109 let position = top.get_position().union(rhs.get_position());
1110 top = Self::SpecialOperators(
1111 SpecialOperators::In {
1112 lhs: InExpressionLHS::Expression(Box::new(top)),
1113 rhs: Box::new(rhs),
1114 },
1115 position,
1116 );
1117 }
1118 TSXToken::Keyword(TSXKeyword::InstanceOf) => {
1119 if AssociativityDirection::LeftToRight
1120 .should_return(parent_precedence, RELATION_PRECEDENCE)
1121 {
1122 return Ok(top);
1123 }
1124
1125 let Token(_, instance_of_pos) = reader.next().unwrap();
1126 let rhs = Expression::from_reader_with_precedence(
1127 reader,
1128 state,
1129 options,
1130 RELATION_PRECEDENCE,
1131 Some(instance_of_pos),
1132 )?;
1133 let position = top.get_position().union(rhs.get_position());
1134 top = Self::SpecialOperators(
1135 SpecialOperators::InstanceOf { lhs: Box::new(top), rhs: Box::new(rhs) },
1136 position,
1137 );
1138 }
1139 token => {
1140 let token = if let TSXToken::OpenChevron = token {
1143 if is_generic_arguments(reader) {
1144 if AssociativityDirection::LeftToRight
1145 .should_return(parent_precedence, FUNCTION_CALL_PRECEDENCE)
1146 {
1147 return Ok(top);
1148 }
1149 let _ = reader.next();
1150 let (type_arguments, _) = generic_arguments_from_reader_sub_open_angle(
1151 reader, state, options, None,
1152 )?;
1153 let (arguments, _, end) = parse_bracketed(
1154 reader,
1155 state,
1156 options,
1157 Some(TSXToken::OpenParentheses),
1158 TSXToken::CloseParentheses,
1159 )?;
1160 top = Expression::FunctionCall {
1161 position: top.get_position().union(end),
1162 function: Box::new(top),
1163 type_arguments: Some(type_arguments),
1164 arguments,
1165 is_optional: false,
1166 };
1167 continue;
1168 }
1169 &TSXToken::OpenChevron
1170 } else {
1171 token
1172 };
1173
1174 if let Ok(operator) = UnaryPostfixAssignmentOperator::try_from(token) {
1175 if operator
1176 .associativity_direction()
1177 .should_return(parent_precedence, operator.precedence())
1178 {
1179 return Ok(top);
1180 }
1181 let token = reader.next().unwrap();
1182
1183 let position = top.get_position().union(token.get_end());
1185 top = Expression::UnaryPostfixAssignmentOperation {
1186 operand: top.try_into()?,
1187 operator,
1188 position,
1189 };
1190 } else if let Ok(operator) = BinaryOperator::try_from(token) {
1191 if operator
1192 .associativity_direction()
1193 .should_return(parent_precedence, operator.precedence())
1194 {
1195 return Ok(top);
1196 }
1197
1198 let Token(token, op_pos) = reader.next().unwrap();
1199
1200 if !options.extra_operators && operator.is_non_standard() {
1201 return Err(ParseError::new(
1202 ParseErrors::NonStandardSyntaxUsedWithoutEnabled,
1203 op_pos.with_length(token.length() as usize),
1204 ));
1205 }
1206
1207 let rhs = Self::from_reader_with_precedence(
1209 reader,
1210 state,
1211 options,
1212 operator.precedence(),
1213 Some(op_pos),
1214 )?;
1215
1216 top = Expression::BinaryOperation {
1217 position: top.get_position().union(rhs.get_position()),
1218 lhs: Box::new(top),
1219 operator,
1220 rhs: Box::new(rhs),
1221 };
1222 } else if let Ok(operator) = BinaryAssignmentOperator::try_from(token) {
1223 if operator
1224 .associativity_direction()
1225 .should_return(parent_precedence, operator.precedence())
1226 {
1227 return Ok(top);
1228 }
1229 let Token(_, op_pos) = reader.next().unwrap();
1230 let new_rhs = Self::from_reader_with_precedence(
1231 reader,
1232 state,
1233 options,
1234 operator.precedence(),
1235 Some(op_pos),
1236 )?;
1237 top = Expression::BinaryAssignmentOperation {
1238 position: top.get_position().union(new_rhs.get_position()),
1239 lhs: top.try_into()?,
1240 operator,
1241 rhs: Box::new(new_rhs),
1242 };
1243 } else {
1244 return Ok(top);
1245 }
1246 }
1247 }
1248 }
1249
1250 Ok(top)
1251 }
1252
1253 #[must_use]
1254 pub fn get_precedence(&self) -> u8 {
1255 match self {
1257 Self::NumberLiteral(..)
1258 | Self::BooleanLiteral(..)
1259 | Self::StringLiteral(..)
1260 | Self::RegexLiteral { .. }
1261 | Self::ArrayLiteral(..)
1262 | Self::TemplateLiteral(..)
1263 | Self::ParenthesizedExpression(..)
1264 | Self::JSXRoot(..)
1265 | Self::ExpressionFunction(..)
1266 | Self::Null(..)
1267 | Self::ObjectLiteral(..)
1268 | Self::VariableReference(..)
1269 | Self::ThisReference(..)
1270 | Self::SuperExpression(..)
1271 | Self::NewTarget(..)
1272 | Self::ClassExpression(..)
1273 | Self::ImportMeta(..)
1274 | Self::DynamicImport { .. }
1275 | Self::Marker { .. } => PARENTHESIZED_EXPRESSION_AND_LITERAL_PRECEDENCE,
1276 Self::BinaryOperation { operator, .. } => operator.precedence(),
1277 Self::UnaryOperation { operator, .. } => operator.precedence(),
1278 Self::Assignment { .. } => ASSIGNMENT_PRECEDENCE,
1279 Self::BinaryAssignmentOperation { operator, .. } => operator.precedence(),
1280 Self::UnaryPrefixAssignmentOperation { operator, .. } => operator.precedence(),
1281 Self::UnaryPostfixAssignmentOperation { operator, .. } => operator.precedence(),
1282 Self::PropertyAccess { .. } => MEMBER_ACCESS_PRECEDENCE,
1283 Self::FunctionCall { .. } => FUNCTION_CALL_PRECEDENCE,
1284 Self::ConstructorCall { arguments: Some(_), .. } => CONSTRUCTOR_PRECEDENCE,
1285 Self::ConstructorCall { arguments: None, .. } => {
1286 CONSTRUCTOR_WITHOUT_PARENTHESIS_PRECEDENCE
1287 }
1288 Self::ArrowFunction(..) => ARROW_FUNCTION_PRECEDENCE,
1289 Self::Index { .. } => INDEX_PRECEDENCE,
1290 Self::ConditionalTernary { .. } => CONDITIONAL_TERNARY_PRECEDENCE,
1291 Self::Comment { ref on, .. } => on.get_precedence(),
1292 #[cfg(feature = "full-typescript")]
1293 Self::SpecialOperators(SpecialOperators::NonNullAssertion(..), _) => {
1294 PARENTHESIZED_EXPRESSION_AND_LITERAL_PRECEDENCE
1295 }
1296 Self::SpecialOperators(..) => RELATION_PRECEDENCE,
1298 #[cfg(feature = "extras")]
1300 Self::IsExpression(..) => PARENTHESIZED_EXPRESSION_AND_LITERAL_PRECEDENCE,
1301 }
1302 }
1303
1304 pub(crate) fn to_string_using_precedence<T: source_map::ToString>(
1305 &self,
1306 buf: &mut T,
1307 options: &crate::ToStringOptions,
1308 local: crate::LocalToStringInformation,
1309 local2: ExpressionToStringArgument,
1310 ) {
1311 let self_precedence = self.get_precedence();
1312 match self {
1317 Self::Marker { .. } => {
1318 assert!(options.expect_markers, "marker found");
1319 }
1320 Self::NumberLiteral(num, _) => buf.push_str(&num.to_string()),
1321 Self::StringLiteral(string, quoted, _) => {
1322 buf.push(quoted.as_char());
1323 buf.push_str(string);
1324 buf.push(quoted.as_char());
1325 }
1326 Self::BooleanLiteral(expression, _) => {
1327 buf.push_str(if *expression { "true" } else { "false" });
1328 }
1329 Self::RegexLiteral { pattern, flags, .. } => {
1330 buf.push('/');
1331 buf.push_str(pattern);
1332 buf.push('/');
1333 if let Some(flags) = flags {
1334 buf.push_str(flags);
1335 }
1336 }
1337 Self::BinaryOperation { lhs, operator, rhs, .. } => {
1338 lhs.to_string_using_precedence(
1339 buf,
1340 options,
1341 local,
1342 local2.with_precedence(self_precedence),
1343 );
1344 if options.pretty
1346 || matches!(
1347 (operator, &**lhs),
1348 (
1349 BinaryOperator::Subtract,
1350 Expression::UnaryPostfixAssignmentOperation {
1351 operator: UnaryPostfixAssignmentOperator(
1352 IncrementOrDecrement::Decrement
1353 ),
1354 ..
1355 },
1356 ) | (
1357 BinaryOperator::Add,
1358 Expression::UnaryPostfixAssignmentOperation {
1359 operator: UnaryPostfixAssignmentOperator(
1360 IncrementOrDecrement::Increment
1361 ),
1362 ..
1363 },
1364 )
1365 ) {
1366 buf.push(' ');
1367 }
1368 buf.push_str(operator.to_str());
1369 if options.pretty
1371 || matches!(
1372 (operator, &**rhs),
1373 (
1374 BinaryOperator::Subtract,
1375 Expression::UnaryPrefixAssignmentOperation {
1376 operator: UnaryPrefixAssignmentOperator::IncrementOrDecrement(
1377 IncrementOrDecrement::Decrement
1378 ),
1379 ..
1380 } | Expression::UnaryOperation {
1381 operator: UnaryOperator::Negation,
1382 ..
1383 },
1384 ) | (
1385 BinaryOperator::Add,
1386 Expression::UnaryPrefixAssignmentOperation {
1387 operator: UnaryPrefixAssignmentOperator::IncrementOrDecrement(
1388 IncrementOrDecrement::Increment
1389 ),
1390 ..
1391 } | Expression::UnaryOperation { operator: UnaryOperator::Plus, .. },
1392 )
1393 ) {
1394 buf.push(' ');
1395 }
1396 rhs.to_string_using_precedence(
1397 buf,
1398 options,
1399 local,
1400 local2.with_precedence(self_precedence),
1401 );
1402 }
1403 Self::SpecialOperators(special, _) => match special {
1404 #[cfg(feature = "full-typescript")]
1405 SpecialOperators::AsCast { value, rhs, .. } => {
1406 value.to_string_from_buffer(buf, options, local);
1407 if options.include_type_annotations {
1408 buf.push_str(" as ");
1409 match rhs {
1410 TypeOrConst::Type(type_annotation) => {
1411 type_annotation.to_string_from_buffer(buf, options, local);
1412 }
1413 TypeOrConst::Const(_) => {
1414 buf.push_str("const");
1415 }
1416 }
1417 }
1418 }
1419 SpecialOperators::Satisfies { value, type_annotation, .. } => {
1420 value.to_string_from_buffer(buf, options, local);
1421 if options.include_type_annotations {
1422 buf.push_str(" satisfies ");
1423 type_annotation.to_string_from_buffer(buf, options, local);
1424 }
1425 }
1426 SpecialOperators::In { lhs, rhs } => {
1427 match lhs {
1428 InExpressionLHS::PrivateProperty(property) => {
1429 buf.push('#');
1430 buf.push_str(property);
1431 }
1432 InExpressionLHS::Expression(lhs) => {
1433 lhs.to_string_using_precedence(
1434 buf,
1435 options,
1436 local,
1437 local2.with_precedence(self_precedence),
1438 );
1439 }
1440 }
1441 buf.push_str(" in ");
1443 rhs.to_string_using_precedence(
1444 buf,
1445 options,
1446 local,
1447 local2.with_precedence(self_precedence),
1448 );
1449 }
1450 SpecialOperators::InstanceOf { lhs, rhs } => {
1451 lhs.to_string_using_precedence(
1452 buf,
1453 options,
1454 local,
1455 local2.with_precedence(self_precedence),
1456 );
1457 buf.push_str(" instanceof ");
1459 rhs.to_string_using_precedence(
1460 buf,
1461 options,
1462 local,
1463 local2.with_precedence(self_precedence),
1464 );
1465 }
1466 #[cfg(feature = "full-typescript")]
1467 SpecialOperators::NonNullAssertion(on) => {
1468 on.to_string_using_precedence(
1469 buf,
1470 options,
1471 local,
1472 local2.with_precedence(self_precedence),
1473 );
1474 if options.include_type_annotations {
1475 buf.push('!');
1476 }
1477 }
1478 #[cfg(feature = "extras")]
1479 SpecialOperators::Is { value, type_annotation, .. } => {
1480 value.to_string_from_buffer(buf, options, local);
1481 buf.push_str(" is ");
1482 type_annotation.to_string_from_buffer(buf, options, local);
1483 }
1484 },
1485 Self::UnaryOperation { operand, operator, .. } => {
1486 buf.push_str(operator.to_str());
1487 if let (
1489 UnaryOperator::Negation,
1490 Expression::UnaryPrefixAssignmentOperation {
1491 operator:
1492 UnaryPrefixAssignmentOperator::IncrementOrDecrement(
1493 IncrementOrDecrement::Decrement,
1494 ),
1495 ..
1496 }
1497 | Expression::UnaryOperation { operator: UnaryOperator::Negation, .. },
1498 )
1499 | (
1500 UnaryOperator::Plus,
1501 Expression::UnaryPrefixAssignmentOperation {
1502 operator:
1503 UnaryPrefixAssignmentOperator::IncrementOrDecrement(
1504 IncrementOrDecrement::Increment,
1505 ),
1506 ..
1507 }
1508 | Expression::UnaryOperation { operator: UnaryOperator::Plus, .. },
1509 ) = (operator, &**operand)
1510 {
1511 buf.push(' ');
1512 }
1513 let right_argument = local2.with_precedence(self_precedence).on_right();
1514 operand.to_string_using_precedence(buf, options, local, right_argument);
1515 }
1516 Self::Assignment { lhs, rhs, .. } => {
1517 let require_parenthesis =
1518 matches!(lhs, LHSOfAssignment::ObjectDestructuring { .. }) && local2.on_left;
1519
1520 if require_parenthesis {
1521 buf.push('(');
1522 }
1523 lhs.to_string_from_buffer(buf, options, local);
1524 buf.push_str(if options.pretty { " = " } else { "=" });
1525 let right_argument = local2.with_precedence(self_precedence).on_right();
1526 rhs.to_string_using_precedence(buf, options, local, right_argument);
1527 if require_parenthesis {
1528 buf.push(')');
1529 }
1530 }
1531 Self::BinaryAssignmentOperation { lhs, operator, rhs, .. } => {
1532 lhs.to_string_from_buffer(buf, options, local);
1533 options.push_gap_optionally(buf);
1534 buf.push_str(operator.to_str());
1535 options.push_gap_optionally(buf);
1536 let right_argument = local2.with_precedence(self_precedence).on_right();
1537 rhs.to_string_using_precedence(buf, options, local, right_argument);
1538 }
1539 Self::UnaryPrefixAssignmentOperation { operand, operator, .. } => {
1540 buf.push_str(operator.to_str());
1541 operand.to_string_from_buffer(buf, options, local);
1542 }
1543 Self::UnaryPostfixAssignmentOperation { operand, operator, .. } => {
1544 operand.to_string_from_buffer(buf, options, local);
1545 buf.push_str(operator.to_str());
1546 }
1547 Self::VariableReference(name, position) => {
1548 buf.add_mapping(&position.with_source(local.under));
1549 buf.push_str(name);
1550 }
1551 Self::ThisReference(..) => {
1552 buf.push_str("this");
1553 }
1554 Self::NewTarget(..) => {
1555 buf.push_str("new.target");
1556 }
1557 Self::ImportMeta(..) => {
1558 buf.push_str("import.meta");
1559 }
1560 Self::DynamicImport { path, .. } => {
1561 buf.push_str("import(");
1562 path.to_string_from_buffer(buf, options, local);
1563 buf.push(')');
1564 }
1565 Self::PropertyAccess { parent, property, is_optional, position, .. } => {
1566 if options.enforce_limit_length_limit() && local.should_try_pretty_print {
1567 chain_to_string_from_buffer(self, buf, options, local);
1568 return;
1569 }
1570
1571 buf.add_mapping(&position.with_source(local.under));
1572
1573 if let Self::NumberLiteral(..) | Self::ObjectLiteral(..) | Self::ArrowFunction(..) =
1575 parent.get_non_parenthesized()
1576 {
1577 buf.push('(');
1578 parent.to_string_from_buffer(buf, options, local);
1579 buf.push(')');
1580 } else {
1581 parent.to_string_from_buffer(buf, options, local);
1582 }
1583
1584 if *is_optional {
1585 buf.push_str("?.");
1586 } else {
1587 buf.push('.');
1588 }
1589
1590 match property {
1591 PropertyReference::Standard { property, is_private } => {
1592 if *is_private {
1593 buf.push('#');
1594 }
1595 buf.push_str(property);
1596 }
1597 PropertyReference::Marker(..) => {
1598 assert!(options.expect_markers, "found marker");
1599 }
1600 }
1601 }
1602 Self::ParenthesizedExpression(expr, _) => {
1603 if matches!(&**expr, MultipleExpression::Single(inner) if inner.get_precedence() == PARENTHESIZED_EXPRESSION_AND_LITERAL_PRECEDENCE)
1605 {
1606 expr.to_string_on_left(buf, options, local);
1607 } else {
1608 buf.push('(');
1609 expr.to_string_from_buffer(buf, options, local);
1610 buf.push(')');
1611 }
1612 }
1613 Self::Index { indexee: expression, indexer, is_optional, .. } => {
1614 expression.to_string_using_precedence(buf, options, local, local2);
1615 if *is_optional {
1616 buf.push_str("?.");
1617 }
1618 buf.push('[');
1619 indexer.to_string_from_buffer(buf, options, local);
1620 buf.push(']');
1621 }
1622 Self::FunctionCall { function, type_arguments, arguments, is_optional, .. } => {
1623 if let Some(ExpressionOrBlock::Expression(expression)) = self.is_iife() {
1625 expression.to_string_from_buffer(buf, options, local);
1626 return;
1627 }
1628
1629 function.to_string_using_precedence(buf, options, local, local2);
1630
1631 if *is_optional {
1632 buf.push_str("?.");
1633 }
1634 if let (true, Some(type_arguments)) =
1635 (options.include_type_annotations, type_arguments)
1636 {
1637 to_string_bracketed(type_arguments, ('<', '>'), buf, options, local);
1638 }
1639 arguments_to_string(arguments, buf, options, local);
1640 }
1641 Self::ConstructorCall { constructor, type_arguments, arguments, .. } => {
1642 buf.push_str("new ");
1643 constructor.to_string_from_buffer(buf, options, local);
1644 if let (true, Some(type_arguments)) =
1645 (options.include_type_annotations, type_arguments)
1646 {
1647 to_string_bracketed(type_arguments, ('<', '>'), buf, options, local);
1648 }
1649 if let Some(arguments) = arguments {
1650 if !arguments.is_empty() || options.pretty {
1652 arguments_to_string(arguments, buf, options, local);
1653 }
1654 }
1655 }
1656 Self::JSXRoot(root) => root.to_string_from_buffer(buf, options, local),
1657 Self::ArrowFunction(arrow_function) => {
1658 if local2.on_left && arrow_function.header {
1660 buf.push('(');
1661 }
1662 arrow_function.to_string_from_buffer(buf, options, local);
1663 if local2.on_left && arrow_function.header {
1664 buf.push(')');
1665 }
1666 }
1667 Self::ExpressionFunction(function) => {
1668 if local2.on_left {
1669 buf.push('(');
1670 }
1671 function.to_string_from_buffer(buf, options, local);
1672 if local2.on_left {
1673 buf.push(')');
1674 }
1675 }
1676 Self::ArrayLiteral(values, _) => {
1677 if options.pretty && options.enforce_limit_length_limit() {
1679 const MAX_INLINE_OBJECT_LITERAL: u32 = 40;
1680
1681 let values_are_all_booleans_or_numbers =
1682 values.first().and_then(ArrayElement::inner_ref).is_some_and(|e| {
1683 matches!(
1684 e,
1685 Expression::BooleanLiteral(..) | Expression::NumberLiteral(..)
1686 )
1687 }) && values.iter().all(|e| {
1688 e.inner_ref().is_some_and(|e| {
1689 matches!(
1690 e,
1691 Expression::BooleanLiteral(..) | Expression::NumberLiteral(..)
1692 )
1693 })
1694 }) && are_nodes_over_length(
1695 values.iter(),
1696 options,
1697 local,
1698 Some(MAX_INLINE_OBJECT_LITERAL),
1699 true,
1700 );
1701
1702 if values_are_all_booleans_or_numbers {
1703 buf.push('[');
1704 let inner_local = local.next_level();
1705 buf.push_new_line();
1706 options.add_indent(inner_local.depth, buf);
1707 for (at_end, node) in
1708 iterator_endiate::EndiateIteratorExt::endiate(values.iter())
1709 {
1710 if buf.characters_on_current_line() > MAX_INLINE_OBJECT_LITERAL {
1711 buf.push_new_line();
1712 options.add_indent(inner_local.depth, buf);
1713 }
1714 node.to_string_from_buffer(buf, options, inner_local);
1715 if !at_end {
1716 buf.push(',');
1717 options.push_gap_optionally(buf);
1718 }
1719 }
1720 buf.push_new_line();
1721 options.add_indent(local.depth, buf);
1722 buf.push(']');
1723 return;
1724 };
1725 }
1726 to_string_bracketed(values, ('[', ']'), buf, options, local);
1727 }
1728 Self::ObjectLiteral(object_literal) => {
1729 if local2.on_left {
1730 buf.push('(');
1731 }
1732 to_string_bracketed(&object_literal.members, ('{', '}'), buf, options, local);
1733 if local2.on_left {
1734 buf.push(')');
1735 }
1736 }
1737 Self::ClassExpression(class) => {
1738 if local2.on_left {
1739 buf.push('(');
1740 }
1741 class.to_string_from_buffer(buf, options, local);
1742 if local2.on_left {
1743 buf.push(')');
1744 }
1745 }
1746 Self::Comment { content, on, is_multiline, prefix, position: _ } => {
1747 if *prefix && options.should_add_comment(content) {
1748 if *is_multiline {
1749 buf.push_str("/*");
1750 buf.push_str_contains_new_line(content);
1751 buf.push_str("*/ ");
1752 } else {
1753 buf.push_str("//");
1754 buf.push_str(content);
1755 buf.push_new_line();
1756 }
1757 }
1758 on.to_string_using_precedence(buf, options, local, local2);
1759 if !prefix && options.should_add_comment(content) {
1760 if *is_multiline {
1761 buf.push_str("/*");
1762 buf.push_str_contains_new_line(content);
1763 buf.push_str("*/ ");
1764 } else {
1765 buf.push_str("//");
1766 buf.push_str(content);
1767 buf.push_new_line();
1768 }
1769 }
1770 }
1771 Self::TemplateLiteral(template_literal) => {
1772 if let Some(tag) = &template_literal.tag {
1774 tag.to_string_using_precedence(buf, options, local, local2);
1775 }
1776 buf.push('`');
1777 for (static_part, dynamic_part) in &template_literal.parts {
1778 buf.push_str_contains_new_line(static_part.as_str());
1779
1780 buf.push_str("${");
1781 dynamic_part.to_string_from_buffer(buf, options, local);
1782 buf.push('}');
1783 }
1784 buf.push_str_contains_new_line(template_literal.last.as_str());
1785 buf.push('`');
1786 }
1787 Self::ConditionalTernary { condition, truthy_result, falsy_result, .. } => {
1788 let available_space = u32::from(options.max_line_length)
1789 .saturating_sub(buf.characters_on_current_line());
1790
1791 let split_lines = crate::are_nodes_over_length(
1792 [condition, truthy_result, falsy_result].iter().map(AsRef::as_ref),
1793 options,
1794 local,
1795 Some(available_space),
1796 true,
1797 );
1798 condition.to_string_using_precedence(
1799 buf,
1800 options,
1801 local,
1802 local2.with_precedence(CONDITIONAL_TERNARY_PRECEDENCE),
1803 );
1804 if split_lines {
1805 buf.push_new_line();
1806 options.add_indent(local.depth + 1, buf);
1807 buf.push_str("? ");
1808 } else {
1809 buf.push_str(if options.pretty { " ? " } else { "?" });
1810 }
1811 truthy_result.to_string_using_precedence(
1812 buf,
1813 options,
1814 local,
1815 local2.with_precedence(CONDITIONAL_TERNARY_PRECEDENCE).on_right(),
1816 );
1817 if split_lines {
1818 buf.push_new_line();
1819 options.add_indent(local.depth + 1, buf);
1820 buf.push_str(": ");
1821 } else {
1822 buf.push_str(if options.pretty { " : " } else { ":" });
1823 }
1824 falsy_result.to_string_using_precedence(
1825 buf,
1826 options,
1827 local,
1828 local2.with_precedence(CONDITIONAL_TERNARY_PRECEDENCE).on_right(),
1829 );
1830 }
1831 Self::Null(..) => buf.push_str("null"),
1832 #[cfg(feature = "extras")]
1833 Self::IsExpression(is_expr) => is_expr.to_string_from_buffer(buf, options, local),
1834 Self::SuperExpression(super_expr, _) => {
1835 buf.push_str("super");
1836 match super_expr {
1837 SuperReference::Call { arguments } => {
1838 arguments_to_string(arguments, buf, options, local);
1839 }
1840 SuperReference::PropertyAccess { property } => {
1841 buf.push('.');
1842 buf.push_str(property);
1843 }
1844 SuperReference::Index { indexer: index } => {
1845 buf.push('[');
1846 index.to_string_from_buffer(buf, options, local);
1847 buf.push(']');
1848 }
1849 }
1850 }
1851 }
1852 }
1856}
1857
1858fn function_header_ish(
1859 kw: TSXKeyword,
1860 reader: &mut impl TokenReader<TSXToken, TokenStart>,
1861) -> bool {
1862 kw.is_in_function_header()
1863 || (kw.is_special_function_header()
1864 && reader.peek().map_or(
1865 false,
1866 |Token(t, _)| matches!(t, TSXToken::Keyword(kw) if kw.is_in_function_header()),
1867 ))
1868}
1869
1870#[derive(Clone, Copy)]
1871pub(crate) struct ExpressionToStringArgument {
1872 pub on_left: bool,
1874 pub parent_precedence: u8,
1875}
1876
1877impl ExpressionToStringArgument {
1878 pub fn on_right(self) -> Self {
1879 Self { on_left: false, parent_precedence: self.parent_precedence }
1880 }
1881
1882 pub fn with_precedence(self, precedence: u8) -> Self {
1883 Self { on_left: self.on_left, parent_precedence: precedence }
1884 }
1885}
1886
1887#[apply(derive_ASTNode)]
1889#[derive(Debug, Clone, PartialEq, Visitable, get_field_by_type::GetFieldByType)]
1890#[get_field_by_type_target(Span)]
1891pub enum MultipleExpression {
1892 Multiple { lhs: Box<MultipleExpression>, rhs: Expression, position: Span },
1893 Single(Expression),
1894}
1895
1896impl MultipleExpression {
1897 #[must_use]
1898 pub fn is_iife(&self) -> Option<&ExpressionOrBlock> {
1899 if let MultipleExpression::Single(inner) = self {
1900 inner.is_iife()
1901 } else {
1902 None
1903 }
1904 }
1905
1906 #[must_use]
1907 pub fn get_rhs(&self) -> &Expression {
1908 match self {
1909 MultipleExpression::Multiple { rhs, .. } | MultipleExpression::Single(rhs) => rhs,
1910 }
1911 }
1912
1913 pub(crate) fn to_string_on_left<T: source_map::ToString>(
1914 &self,
1915 buf: &mut T,
1916 options: &crate::ToStringOptions,
1917 local: crate::LocalToStringInformation,
1918 ) {
1919 match self {
1920 MultipleExpression::Multiple { lhs, rhs, position: _ } => {
1921 lhs.to_string_on_left(buf, options, local);
1922 buf.push(',');
1923 rhs.to_string_from_buffer(buf, options, local);
1924 }
1925 MultipleExpression::Single(single) => {
1926 let local2 =
1927 ExpressionToStringArgument { on_left: true, parent_precedence: u8::MAX };
1928 single.to_string_using_precedence(buf, options, local, local2);
1929 }
1930 }
1931 }
1932}
1933
1934impl ASTNode for MultipleExpression {
1935 fn from_reader(
1936 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
1937 state: &mut crate::ParsingState,
1938 options: &ParseOptions,
1939 ) -> ParseResult<Self> {
1940 let first = Expression::from_reader(reader, state, options)?;
1941 if let Some(Token(TSXToken::Comma, _)) = reader.peek() {
1942 let mut top: MultipleExpression = first.into();
1943 while let Some(Token(TSXToken::Comma, _)) = reader.peek() {
1944 reader.next();
1945 let rhs = Expression::from_reader(reader, state, options)?;
1946 let position = top.get_position().union(rhs.get_position());
1947 top = MultipleExpression::Multiple { lhs: Box::new(top), rhs, position };
1948 }
1949 Ok(top)
1950 } else {
1951 Ok(MultipleExpression::Single(first))
1952 }
1953 }
1954
1955 fn to_string_from_buffer<T: source_map::ToString>(
1956 &self,
1957 buf: &mut T,
1958 options: &crate::ToStringOptions,
1959 local: crate::LocalToStringInformation,
1960 ) {
1961 match self {
1962 MultipleExpression::Multiple { lhs, rhs, position: _ } => {
1963 lhs.to_string_from_buffer(buf, options, local);
1964 buf.push(',');
1965 rhs.to_string_from_buffer(buf, options, local);
1966 }
1967 MultipleExpression::Single(rhs) => {
1968 rhs.to_string_from_buffer(buf, options, local);
1969 }
1970 }
1971 }
1972
1973 fn get_position(&self) -> Span {
1974 match self {
1975 MultipleExpression::Multiple { position, .. } => *position,
1976 MultipleExpression::Single(expr) => expr.get_position(),
1977 }
1978 }
1979}
1980
1981impl From<Expression> for MultipleExpression {
1982 fn from(expr: Expression) -> Self {
1983 MultipleExpression::Single(expr)
1984 }
1985}
1986
1987fn is_generic_arguments(reader: &mut impl TokenReader<TSXToken, crate::TokenStart>) -> bool {
1989 if !matches!(reader.peek(), Some(Token(TSXToken::OpenChevron, _))) {
1990 return false;
1991 }
1992
1993 let (mut generic_depth, mut bracket_depth) = (0, 0);
1995 let mut final_generic_position = None::<TokenEnd>;
1996
1997 let next_token = reader.scan(|token, position| {
1998 if matches!(
2000 token,
2001 TSXToken::StrictEqual
2002 | TSXToken::StrictNotEqual
2003 | TSXToken::LogicalAnd
2004 | TSXToken::LogicalOr
2005 | TSXToken::SemiColon
2006 ) {
2007 true
2008 } else {
2009 match token {
2010 TSXToken::OpenChevron => generic_depth += 1,
2011 TSXToken::CloseChevron => generic_depth -= 1,
2012 TSXToken::BitwiseShiftRight => generic_depth -= 2,
2013 TSXToken::BitwiseShiftRightUnsigned => generic_depth -= 3,
2014 TSXToken::OpenParentheses => bracket_depth += 1,
2015 TSXToken::CloseParentheses => bracket_depth -= 1,
2016 _ => {}
2017 }
2018 if generic_depth == 0 {
2019 final_generic_position = Some(TokenEnd::new(
2020 position.0 + tokenizer_lib::sized_tokens::SizedToken::length(token),
2021 ));
2022 true
2023 } else {
2024 bracket_depth < 0
2025 }
2026 }
2027 });
2028 if let (Some(last_position), Some(Token(TSXToken::OpenParentheses, open_paren_start))) =
2029 (final_generic_position, next_token)
2030 {
2031 last_position.is_adjacent_to(*open_paren_start)
2032 } else {
2033 false
2034 }
2035}
2036
2037pub(crate) fn arguments_to_string<T: source_map::ToString>(
2038 nodes: &[FunctionArgument],
2039 buf: &mut T,
2040 options: &crate::ToStringOptions,
2041 local: crate::LocalToStringInformation,
2042) {
2043 buf.push('(');
2044 if nodes.is_empty() {
2045 buf.push(')');
2046 return;
2047 }
2048
2049 let add_new_lines = are_nodes_over_length(
2050 nodes.iter(),
2051 options,
2052 local,
2053 Some(u32::from(options.max_line_length).saturating_sub(buf.characters_on_current_line())),
2054 true,
2055 );
2056
2057 if add_new_lines {
2058 buf.push_new_line();
2059 options.add_indent(local.depth + 1, buf);
2060 }
2061 let mut added_last = false;
2062 for node in nodes {
2063 if let FunctionArgument::Spread(Expression::ArrayLiteral(items, _), _) = node {
2065 if items.is_empty() {
2066 added_last = false;
2067 continue;
2068 }
2069 if added_last {
2070 buf.push(',');
2071 if add_new_lines {
2072 buf.push_new_line();
2073 options.add_indent(local.depth + 1, buf);
2074 } else {
2075 options.push_gap_optionally(buf);
2076 }
2077 }
2078 for (inner_at_end, item) in iterator_endiate::EndiateIteratorExt::endiate(items.iter())
2079 {
2080 if item.0.is_none() {
2081 buf.push_str("undefined");
2082 } else {
2083 item.to_string_from_buffer(buf, options, local);
2084 }
2085 if !inner_at_end {
2086 buf.push(',');
2087 options.push_gap_optionally(buf);
2088 }
2089 }
2090 added_last = true;
2091 } else {
2092 if added_last {
2093 buf.push(',');
2094 if add_new_lines {
2095 buf.push_new_line();
2096 options.add_indent(local.depth + 1, buf);
2097 } else {
2098 options.push_gap_optionally(buf);
2099 }
2100 }
2101 node.to_string_from_buffer(buf, options, local);
2102 added_last = true;
2103 }
2104 }
2105 if add_new_lines {
2106 buf.push_new_line();
2107 options.add_indent(local.depth, buf);
2108 }
2109 buf.push(')');
2110}
2111
2112#[apply(derive_ASTNode)]
2114#[derive(PartialEqExtras, Debug, Clone, Visitable)]
2115#[partial_eq_ignore_types(Span)]
2116pub enum SpecialOperators {
2117 Satisfies {
2119 value: Box<Expression>,
2120 type_annotation: Box<TypeAnnotation>,
2121 },
2122 In {
2123 lhs: InExpressionLHS,
2124 rhs: Box<Expression>,
2125 },
2126 InstanceOf {
2127 lhs: Box<Expression>,
2128 rhs: Box<Expression>,
2129 },
2130 #[cfg(feature = "extras")]
2131 Is {
2132 value: Box<Expression>,
2133 type_annotation: Box<TypeAnnotation>,
2134 },
2135 #[cfg(feature = "full-typescript")]
2136 NonNullAssertion(Box<Expression>),
2137 #[cfg(feature = "full-typescript")]
2138 AsCast {
2139 value: Box<Expression>,
2140 rhs: TypeOrConst,
2141 },
2142}
2143
2144#[cfg(feature = "full-typescript")]
2145#[apply(derive_ASTNode)]
2146#[derive(Debug, Clone, PartialEq, Visitable)]
2147pub enum TypeOrConst {
2148 Type(Box<TypeAnnotation>),
2149 Const(Span),
2150}
2151
2152#[apply(derive_ASTNode)]
2153#[derive(PartialEqExtras, Debug, Clone, Visitable)]
2154#[partial_eq_ignore_types(Span)]
2155pub enum InExpressionLHS {
2156 PrivateProperty(String),
2157 Expression(Box<Expression>),
2158}
2159
2160#[apply(derive_ASTNode)]
2161#[derive(Debug, Clone, PartialEq, Visitable)]
2162pub enum FunctionArgument {
2163 Spread(Expression, Span),
2164 Standard(Expression),
2165 Comment { content: String, is_multiline: bool, position: Span },
2166}
2167
2168impl ListItem for FunctionArgument {
2169 type LAST = ();
2170}
2171
2172impl ASTNode for FunctionArgument {
2173 fn from_reader(
2174 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
2175 state: &mut crate::ParsingState,
2176 options: &ParseOptions,
2177 ) -> ParseResult<Self> {
2178 let peek = &reader.peek().ok_or_else(parse_lexing_error)?.0;
2179 match peek {
2180 TSXToken::Spread => {
2181 let start_pos = reader.next().unwrap().1;
2182 let expression = Expression::from_reader(reader, state, options)?;
2183 let position = start_pos.union(expression.get_position());
2184 Ok(Self::Spread(expression, position))
2185 }
2186 t if t.is_comment() => {
2187 let (content, is_multiline, position) =
2188 TSXToken::try_into_comment(reader.next().unwrap()).unwrap();
2189
2190 if let Some(Token(
2192 TSXToken::CloseParentheses
2193 | TSXToken::JSXExpressionEnd
2194 | TSXToken::CloseBracket
2195 | TSXToken::Comma,
2196 _,
2197 )) = reader.peek()
2198 {
2199 return Ok(Self::Comment { content, is_multiline, position });
2200 }
2201
2202 let expr = Self::from_reader(reader, state, options)?;
2203 let position = position.union(expr.get_position());
2204
2205 Ok(match expr {
2206 FunctionArgument::Spread(expr, _end) => FunctionArgument::Spread(
2207 Expression::Comment {
2208 content,
2209 on: Box::new(expr),
2210 position,
2211 is_multiline,
2212 prefix: true,
2213 },
2214 position,
2215 ),
2216 FunctionArgument::Standard(expr) => {
2217 FunctionArgument::Standard(Expression::Comment {
2218 content,
2219 on: Box::new(expr),
2220 position,
2221 is_multiline,
2222 prefix: true,
2223 })
2224 }
2225 c @ FunctionArgument::Comment { .. } => c,
2227 })
2228 }
2229 _ => Ok(Self::Standard(Expression::from_reader(reader, state, options)?)),
2230 }
2231 }
2232
2233 fn to_string_from_buffer<T: source_map::ToString>(
2234 &self,
2235 buf: &mut T,
2236 options: &crate::ToStringOptions,
2237 local: crate::LocalToStringInformation,
2238 ) {
2239 match self {
2240 FunctionArgument::Spread(expression, _) => {
2241 buf.push_str("...");
2242 expression.to_string_from_buffer(buf, options, local);
2243 }
2244 FunctionArgument::Standard(expression) => {
2245 expression.to_string_from_buffer(buf, options, local);
2246 }
2247 FunctionArgument::Comment { content, is_multiline: _is_multiline, position: _ } => {
2248 if options.should_add_comment(content) {
2249 buf.push_str("/*");
2250 buf.push_str(content);
2251 buf.push_str("*/");
2252 }
2253 }
2254 }
2255 }
2256
2257 fn get_position(&self) -> Span {
2258 match self {
2259 FunctionArgument::Comment { position, .. } | FunctionArgument::Spread(_, position) => {
2260 *position
2261 }
2262 FunctionArgument::Standard(expr) => expr.get_position(),
2263 }
2264 }
2265}
2266
2267impl From<Expression> for FunctionArgument {
2268 fn from(value: Expression) -> Self {
2269 FunctionArgument::Standard(value)
2270 }
2271}
2272
2273#[derive(Debug, Clone, PartialEq, Visitable)]
2274#[apply(derive_ASTNode)]
2275pub struct ArrayElement(pub Option<FunctionArgument>);
2276
2277impl ASTNode for ArrayElement {
2278 fn get_position(&self) -> Span {
2279 self.0.as_ref().map_or(Span::NULL, ASTNode::get_position)
2280 }
2281
2282 fn from_reader(
2283 reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
2284 state: &mut crate::ParsingState,
2285 options: &ParseOptions,
2286 ) -> ParseResult<Self> {
2287 Ok(Self(Some(FunctionArgument::from_reader(reader, state, options)?)))
2288 }
2289
2290 fn to_string_from_buffer<T: source_map::ToString>(
2291 &self,
2292 buf: &mut T,
2293 options: &crate::ToStringOptions,
2294 local: crate::LocalToStringInformation,
2295 ) {
2296 if let Some(ref s) = self.0 {
2297 s.to_string_from_buffer(buf, options, local);
2298 }
2299 }
2300}
2301
2302impl ArrayElement {
2303 #[must_use]
2305 pub fn inner_ref(&self) -> Option<&Expression> {
2306 if let Some(ref inner) = self.0 {
2307 match inner {
2308 FunctionArgument::Spread(expr, _) | FunctionArgument::Standard(expr) => Some(expr),
2309 FunctionArgument::Comment { .. } => None,
2310 }
2311 } else {
2312 None
2313 }
2314 }
2315}
2316
2317impl ListItem for ArrayElement {
2318 const EMPTY: Option<Self> = Some(Self(None));
2319
2320 type LAST = ();
2321}
2322
2323impl Expression {
2325 #[must_use]
2327 pub fn build_iife(block: Block) -> Self {
2328 let position = block.get_position();
2329 Expression::FunctionCall {
2330 function: Expression::ParenthesizedExpression(
2331 Box::new(
2332 Expression::ArrowFunction(ArrowFunction {
2333 header: false,
2335 name: (),
2336 parameters: crate::functions::FunctionParameters {
2337 parameters: Default::default(),
2338 rest_parameter: Default::default(),
2339 position,
2340 leading: (),
2341 },
2342 return_type: None,
2343 type_parameters: None,
2344 position,
2345 body: ExpressionOrBlock::Block(block),
2346 })
2347 .into(),
2348 ),
2349 position,
2350 )
2351 .into(),
2352 type_arguments: None,
2353 arguments: Vec::new(),
2354 is_optional: false,
2355 position,
2356 }
2357 }
2358
2359 #[must_use]
2360 pub fn is_iife(&self) -> Option<&ExpressionOrBlock> {
2361 if let Expression::FunctionCall { arguments, function, .. } = self {
2362 if let (true, Expression::ParenthesizedExpression(expression, _)) =
2363 (arguments.is_empty(), &**function)
2364 {
2365 if let MultipleExpression::Single(Expression::ArrowFunction(function)) =
2366 &**expression
2367 {
2368 return Some(&function.body);
2369 }
2370 }
2371 }
2372 None
2373 }
2374
2375 #[must_use]
2377 pub fn get_non_parenthesized(&self) -> &Self {
2378 if let Expression::ParenthesizedExpression(inner_multiple_expr, _) = self {
2379 if let MultipleExpression::Single(expr) = &**inner_multiple_expr {
2380 expr.get_non_parenthesized()
2381 } else {
2382 self
2384 }
2385 } else if let Expression::Comment { on, .. } = self {
2386 on.get_non_parenthesized()
2387 } else {
2388 self
2389 }
2390 }
2391}
2392
2393#[apply(derive_ASTNode)]
2395#[derive(PartialEqExtras, Debug, Clone, Visitable)]
2396#[partial_eq_ignore_types(Span)]
2397pub enum SuperReference {
2398 Call { arguments: Vec<FunctionArgument> },
2399 PropertyAccess { property: String },
2400 Index { indexer: Box<Expression> },
2401}
2402
2403pub(crate) fn chain_to_string_from_buffer<T: source_map::ToString>(
2404 original: &Expression,
2405 buf: &mut T,
2406 options: &crate::ToStringOptions,
2407 local: crate::LocalToStringInformation,
2408) {
2409 let mut chain = Vec::new();
2410
2411 let split_between_lines = if options.enforce_limit_length_limit() {
2412 let room =
2413 u32::from(options.max_line_length).saturating_sub(buf.characters_on_current_line());
2414
2415 let mut buf = source_map::StringWithOptionalSourceMap {
2416 source: String::new(),
2417 source_map: None,
2418 quit_after: Some(room as usize),
2419 since_new_line: 0,
2420 };
2421 let mut over = false;
2422 let mut cur = Some(original);
2423 while let Some(node) = cur {
2424 chain.push(node);
2425 cur = match node {
2427 Expression::PropertyAccess { parent, property, .. } => {
2428 match property {
2429 PropertyReference::Standard { property, .. } => buf.push_str(property),
2430 PropertyReference::Marker(_) => {}
2431 }
2432 Some(parent)
2433 }
2434 Expression::Index { indexer, indexee, .. } => {
2435 indexer.to_string_from_buffer(&mut buf, options, local);
2436 Some(indexee)
2437 }
2438 Expression::FunctionCall { function, type_arguments, arguments, .. } => {
2439 if let (true, Some(type_arguments)) =
2440 (options.include_type_annotations, type_arguments)
2441 {
2442 to_string_bracketed(type_arguments, ('<', '>'), &mut buf, options, local);
2443 }
2444 arguments_to_string(arguments, &mut buf, options, local);
2445 Some(function)
2446 }
2447 expression => {
2448 expression.to_string_from_buffer(&mut buf, options, local);
2449 None
2450 }
2451 };
2452
2453 if buf.should_halt() {
2454 over = true;
2455 }
2457 }
2458 over
2459 } else {
2460 false
2461 };
2462
2463 if split_between_lines && !chain.is_empty() {
2464 let mut items = chain.into_iter().rev();
2465 items.next().unwrap().to_string_from_buffer(buf, options, local);
2466
2467 for item in items {
2468 match item {
2470 Expression::PropertyAccess { property, is_optional, .. } => {
2471 buf.push_new_line();
2472 options.add_indent(local.depth + 1, buf);
2473 if *is_optional {
2474 buf.push_str("?.");
2475 } else {
2476 buf.push('.');
2477 }
2478 match property {
2479 PropertyReference::Standard { property, is_private } => {
2480 if *is_private {
2481 buf.push('#');
2482 }
2483 buf.push_str(property);
2484 }
2485 PropertyReference::Marker(..) => {
2486 assert!(options.expect_markers, "found marker");
2487 }
2488 }
2489 }
2490 Expression::Index { indexer, is_optional, .. } => {
2491 buf.push_new_line();
2492 options.add_indent(local.depth + 1, buf);
2493 if *is_optional {
2494 buf.push_str("?.");
2495 }
2496 buf.push('[');
2497 indexer.to_string_from_buffer(buf, options, local);
2498 buf.push(']');
2499 }
2500 Expression::FunctionCall { type_arguments, arguments, is_optional, .. } => {
2501 if *is_optional {
2502 buf.push_str("?.");
2503 }
2504 if let (true, Some(type_arguments)) =
2505 (options.include_type_annotations, type_arguments)
2506 {
2507 to_string_bracketed(type_arguments, ('<', '>'), buf, options, local);
2508 }
2509 arguments_to_string(arguments, buf, options, local);
2510 }
2511 _ => unreachable!(),
2512 }
2513 }
2514 } else {
2515 original.to_string_from_buffer(buf, options, local.do_not_pretty_print());
2516 }
2517}
2518
2519#[cfg(test)]
2520mod tests {
2521 use super::{ASTNode, BinaryOperator, Expression, Expression::*, MultipleExpression};
2522 use crate::{
2523 assert_matches_ast, ast::FunctionArgument, number::NumberRepresentation, span, Quoted,
2524 };
2525
2526 #[test]
2527 fn literal() {
2528 assert_matches_ast!(
2529 "'string'",
2530 StringLiteral(Deref @ "string", Quoted::Single, span!(0, 8))
2531 );
2532 assert_matches_ast!(
2533 "\"string\"",
2534 StringLiteral(Deref @ "string", Quoted::Double, span!(0, 8))
2535 );
2536 assert_matches_ast!("true", BooleanLiteral(true, span!(0, 4)));
2540 }
2541
2542 #[test]
2543 fn parenthesized_expression() {
2544 assert_matches_ast!(
2546 "(45)",
2547 ParenthesizedExpression(
2548 Deref @ MultipleExpression::Single(NumberLiteral(
2549 NumberRepresentation::Number { .. },
2550 span!(1, 3),
2551 )),
2552 span!(0, 4),
2553 )
2554 );
2555 }
2556
2557 #[test]
2558 fn is_iife() {
2559 let expr = Expression::from_string("(() => 2)()".to_owned(), Default::default()).unwrap();
2560 assert!(expr.is_iife().is_some());
2561 }
2562
2563 #[test]
2564 fn multiple_expression() {
2565 assert_matches_ast!(
2566 "(45,2)",
2567 ParenthesizedExpression(
2568 Deref @ MultipleExpression::Multiple {
2569 lhs:
2570 Deref @ MultipleExpression::Single(NumberLiteral(
2571 NumberRepresentation::Number { .. },
2572 span!(1, 3),
2573 )),
2574 rhs: NumberLiteral(NumberRepresentation::Number { .. }, span!(4, 5)),
2575 position: _,
2576 },
2577 span!(0, 6),
2578 )
2579 );
2580 }
2581
2582 #[test]
2583 fn spread_function_argument() {
2584 assert_matches_ast!(
2585 "console.table(...a)",
2586 FunctionCall { arguments: Deref @ [FunctionArgument::Spread(VariableReference(..), span!(14, 18))], .. }
2587 );
2588 }
2589
2590 #[test]
2591 fn binary_expressions() {
2592 assert_matches_ast!("2 + 3", BinaryOperation {
2593 lhs: Deref @ NumberLiteral(NumberRepresentation::Number { .. }, span!(0, 1)),
2594 operator: BinaryOperator::Add,
2595 rhs: Deref @ NumberLiteral(NumberRepresentation::Number { .. }, span!(4, 5)),
2596 position: _
2597 });
2598 assert_matches_ast!("xt === 3", BinaryOperation {
2599 lhs: Deref @ VariableReference(..),
2600 operator: BinaryOperator::StrictEqual,
2601 rhs: Deref @ NumberLiteral(NumberRepresentation::Number { .. }, span!(7, 8)),
2602 position: _
2603 });
2604 assert_matches_ast!("x << 3", BinaryOperation {
2605 lhs: Deref @ VariableReference(..),
2606 operator: BinaryOperator::BitwiseShiftLeft,
2607 rhs: Deref @ NumberLiteral(NumberRepresentation::Number { .. }, span!(5, 6)),
2608 position: _
2609 });
2610 assert_matches_ast!("x >> 3", BinaryOperation {
2611 lhs: Deref @ VariableReference(..),
2612 operator: BinaryOperator::BitwiseShiftRight,
2613 rhs: Deref @ NumberLiteral(NumberRepresentation::Number { .. }, span!(5, 6)),
2614 position: _
2615 });
2616 assert_matches_ast!("x >>> 3", BinaryOperation {
2617 lhs: Deref @ VariableReference(..),
2618 operator: BinaryOperator::BitwiseShiftRightUnsigned,
2619 rhs: Deref @ NumberLiteral(NumberRepresentation::Number { .. }, span!(6, 7)),
2620 position: _
2621 });
2622 }
2623}