1use derive_finite_automaton::FiniteAutomataConstructor;
6use derive_partial_eq_extras::PartialEqExtras;
7use enum_variants_strings::EnumVariantsStrings;
8use source_map::Span;
9use tokenizer_lib::{sized_tokens::TokenStart, Token};
10
11use crate::{ParseError, Quoted};
12
13#[derive(Debug, FiniteAutomataConstructor, PartialEqExtras)]
15#[automaton_mappings(
16 "{" => TSXToken::OpenBrace,
17 "}" => TSXToken::CloseBrace,
18 "[" => TSXToken::OpenBracket,
19 "]" => TSXToken::CloseBracket,
20 "(" => TSXToken::OpenParentheses,
21 ")" => TSXToken::CloseParentheses,
22 ":" => TSXToken::Colon,
23 "@" => TSXToken::At,
24 "," => TSXToken::Comma,
25 ";" => TSXToken::SemiColon,
26 "#" => TSXToken::HashTag,
27 "+" => TSXToken::Add,
28 "+=" => TSXToken::AddAssign,
29 "++" => TSXToken::Increment,
30 "-" => TSXToken::Subtract,
31 "-=" => TSXToken::SubtractAssign,
32 "--" => TSXToken::Decrement,
33 "*" => TSXToken::Multiply,
34 "*=" => TSXToken::MultiplyAssign,
35 "**" => TSXToken::Exponent,
36 "**=" => TSXToken::ExponentAssign,
37 "/" => TSXToken::Divide,
38 "//" => TSXToken::Comment(String::new()),
39 "/=" => TSXToken::DivideAssign,
40 "/*" => TSXToken::MultiLineComment(String::new()),
41 "%" => TSXToken::Modulo,
42 "%=" => TSXToken::ModuloAssign,
43 "=" => TSXToken::Assign,
44 "==" => TSXToken::Equal,
45 "===" => TSXToken::StrictEqual,
46 "=>" => TSXToken::Arrow,
47 "!" => TSXToken::LogicalNot,
48 "!=" => TSXToken::NotEqual,
49 "!==" => TSXToken::StrictNotEqual,
50 "&" => TSXToken::BitwiseAnd,
51 "&=" => TSXToken::BitwiseAndAssign,
52 "&&" => TSXToken::LogicalAnd,
53 "&&=" => TSXToken::LogicalAndAssign,
54 "|" => TSXToken::BitwiseOr,
55 "|=" => TSXToken::BitwiseOrAssign,
56 "||" => TSXToken::LogicalOr,
57 "||=" => TSXToken::LogicalOrAssign,
58 "~" => TSXToken::BitwiseNot,
59 "^" => TSXToken::BitwiseXOr,
60 "^=" => TSXToken::BitwiseXorAssign,
61 "?" => TSXToken::QuestionMark,
62 "?:" => TSXToken::OptionalMember,
63 "?." => TSXToken::OptionalChain,
64 "?.(" => TSXToken::OptionalCall,
65 "?.[" => TSXToken::OptionalIndex,
66 "-?:" => TSXToken::NonOptionalMember,
67 "??" => TSXToken::NullishCoalescing,
68 "??=" => TSXToken::NullishCoalescingAssign,
69 "!=" => TSXToken::NotEqual,
70 "!==" => TSXToken::StrictNotEqual,
71 "<" => TSXToken::OpenChevron,
72 ">" => TSXToken::CloseChevron,
73 "<=" => TSXToken::LessThanEqual,
74 ">=" => TSXToken::GreaterThanEqual,
75 "<<" => TSXToken::BitwiseShiftLeft,
76 "<<=" => TSXToken::BitwiseShiftLeftAssign,
77 ">>" => TSXToken::BitwiseShiftRight,
78 ">>=" => TSXToken::BitwiseShiftRightAssign,
79 ">>>" => TSXToken::BitwiseShiftRightUnsigned,
80 ">>>=" => TSXToken::BitwiseShiftRightUnsignedAssign,
81 "." => TSXToken::Dot,
82 "..." => TSXToken::Spread,
83)]
84#[cfg_attr(feature = "extras", automaton_mappings(
85 ">!" => TSXToken::InvertAssign,
86 "<@>" => TSXToken::ComposeOperator,
87 "|>" => TSXToken::PipeOperator,
88))]
89#[rustfmt::skip]
90pub enum TSXToken {
91 Identifier(String),
92 Keyword(TSXKeyword),
93 NumberLiteral(String),
94 StringLiteral(String, Quoted),
95 MultiLineComment(String), Comment(String),
96 HashBangComment(String),
98 RegexLiteral(String), RegexFlagLiteral(String),
99 TemplateLiteralStart, TemplateLiteralChunk(String), TemplateLiteralEnd,
100 TemplateLiteralExpressionStart, TemplateLiteralExpressionEnd,
101 Comma, SemiColon, Colon, Dot,
102 At,
104 Spread, Assign,
105 Arrow,
107 OpenParentheses,
109 CloseParentheses,
111 OpenBrace,
113 CloseBrace,
115 OpenBracket,
117 CloseBracket,
119 OpenChevron,
121 CloseChevron,
123 Add, Subtract, Multiply, Divide,
124 QuestionMark, Exponent, Modulo,
125 AddAssign, SubtractAssign, MultiplyAssign, DivideAssign, ExponentAssign, ModuloAssign,
126 Increment, Decrement,
127 BitwiseShiftLeft, BitwiseShiftRight, BitwiseShiftRightUnsigned,
128 BitwiseShiftLeftAssign, BitwiseShiftRightAssign, BitwiseShiftRightUnsignedAssign,
129 BitwiseOr, BitwiseXOr, BitwiseAnd, BitwiseNot,
130 BitwiseOrAssign, BitwiseAndAssign, BitwiseXorAssign,
131 LogicalOr, LogicalAnd, LogicalNot,
132 LogicalOrAssign, LogicalAndAssign,
133 Equal, NotEqual, StrictEqual, StrictNotEqual,
134 GreaterThanEqual, LessThanEqual,
135 OptionalChain, OptionalCall, OptionalIndex, NullishCoalescing, NullishCoalescingAssign,
136 OptionalMember,
138 NonOptionalMember,
140 HashTag,
142 JSXOpeningTagStart, JSXTagName(String), JSXOpeningTagEnd,
144 JSXClosingTagStart,
145 JSXClosingTagName(String),
147 JSXSelfClosingTag,
149 JSXAttributeKey(String), JSXAttributeAssign, JSXAttributeValue(String),
150 JSXContent(String), JSXContentLineBreak,
151 JSXExpressionStart, JSXExpressionEnd,
153 JSXFragmentStart, JSXFragmentEnd,
155 JSXComment(String),
157 DocTypeHTML,
159
160 #[cfg(feature = "extras")]
162 InvertAssign,
163 #[cfg(feature = "extras")]
164 ComposeOperator,
165 #[cfg(feature = "extras")]
166 PipeOperator,
167
168 EOS
169}
170
171impl tokenizer_lib::TokenTrait for TSXToken {
172 fn is_skippable(&self) -> bool {
173 self.is_comment()
175 }
176}
177
178impl tokenizer_lib::sized_tokens::SizedToken for TSXToken {
179 #[allow(clippy::cast_possible_truncation)]
180 fn length(&self) -> u32 {
181 match self {
182 TSXToken::Keyword(kw) => kw.length(),
183
184 TSXToken::JSXClosingTagName(lit)
185 | TSXToken::TemplateLiteralChunk(lit)
186 | TSXToken::JSXAttributeKey(lit)
187 | TSXToken::JSXContent(lit)
188 | TSXToken::JSXTagName(lit)
189 | TSXToken::Identifier(lit)
190 | TSXToken::NumberLiteral(lit)
191 | TSXToken::RegexFlagLiteral(lit) => lit.len() as u32,
192
193 TSXToken::JSXComment(comment) => comment.len() as u32 + 7,
194 TSXToken::MultiLineComment(comment) => comment.len() as u32 + 4,
195 TSXToken::StringLiteral(comment, _)
196 | TSXToken::Comment(comment)
197 | TSXToken::HashBangComment(comment) => comment.len() as u32 + 2,
198 TSXToken::JSXAttributeValue(value) | TSXToken::RegexLiteral(value) => {
199 value.len() as u32 + 2
200 }
201
202 TSXToken::DocTypeHTML => 15,
203
204 TSXToken::Comma
205 | TSXToken::SemiColon
206 | TSXToken::Colon
207 | TSXToken::At
208 | TSXToken::Assign
209 | TSXToken::OpenParentheses
210 | TSXToken::CloseParentheses
211 | TSXToken::OpenBrace
212 | TSXToken::CloseBrace
213 | TSXToken::OpenBracket
214 | TSXToken::CloseBracket
215 | TSXToken::OpenChevron
216 | TSXToken::CloseChevron
217 | TSXToken::Add
218 | TSXToken::Subtract
219 | TSXToken::Multiply
220 | TSXToken::Divide
221 | TSXToken::Modulo
222 | TSXToken::QuestionMark
223 | TSXToken::BitwiseOr
224 | TSXToken::BitwiseXOr
225 | TSXToken::BitwiseAnd
226 | TSXToken::BitwiseNot
227 | TSXToken::HashTag
228 | TSXToken::Dot
229 | TSXToken::TemplateLiteralStart
230 | TSXToken::TemplateLiteralEnd
231 | TSXToken::TemplateLiteralExpressionEnd
232 | TSXToken::JSXOpeningTagStart
233 | TSXToken::JSXOpeningTagEnd
234 | TSXToken::JSXExpressionStart
235 | TSXToken::JSXExpressionEnd
236 | TSXToken::JSXAttributeAssign
237 | TSXToken::JSXClosingTagStart
238 | TSXToken::JSXContentLineBreak => 1,
239
240 TSXToken::AddAssign
241 | TSXToken::SubtractAssign
242 | TSXToken::MultiplyAssign
243 | TSXToken::DivideAssign
244 | TSXToken::ModuloAssign
245 | TSXToken::Exponent
246 | TSXToken::ExponentAssign
247 | TSXToken::Increment
248 | TSXToken::Decrement
249 | TSXToken::Equal
250 | TSXToken::GreaterThanEqual
251 | TSXToken::LessThanEqual
252 | TSXToken::OptionalChain
253 | TSXToken::NullishCoalescing
254 | TSXToken::OptionalMember
255 | TSXToken::NonOptionalMember
256 | TSXToken::BitwiseOrAssign
257 | TSXToken::BitwiseAndAssign
258 | TSXToken::BitwiseXorAssign
259 | TSXToken::LogicalOr
260 | TSXToken::LogicalAnd
261 | TSXToken::LogicalNot
262 | TSXToken::Arrow
263 | TSXToken::BitwiseShiftLeft
264 | TSXToken::BitwiseShiftRight
265 | TSXToken::TemplateLiteralExpressionStart
266 | TSXToken::JSXFragmentStart
267 | TSXToken::JSXSelfClosingTag => 2,
268
269 TSXToken::Spread
270 | TSXToken::StrictEqual
271 | TSXToken::OptionalCall
272 | TSXToken::OptionalIndex
273 | TSXToken::NullishCoalescingAssign
274 | TSXToken::LogicalOrAssign
275 | TSXToken::LogicalAndAssign
276 | TSXToken::NotEqual
277 | TSXToken::BitwiseShiftLeftAssign
278 | TSXToken::BitwiseShiftRightAssign
279 | TSXToken::StrictNotEqual
280 | TSXToken::BitwiseShiftRightUnsigned
281 | TSXToken::JSXFragmentEnd => 3,
282
283 TSXToken::BitwiseShiftRightUnsignedAssign => 4,
284
285 TSXToken::EOS => 0,
287
288 #[cfg(feature = "extras")]
289 TSXToken::InvertAssign | TSXToken::PipeOperator => 2,
290 #[cfg(feature = "extras")]
291 TSXToken::ComposeOperator => 3,
292 }
293 }
294}
295
296impl Eq for TSXToken {}
297
298#[derive(Debug, PartialEq, EnumVariantsStrings, Clone, Copy)]
299#[enum_variants_strings_transform(transform = "lower_case")]
300#[rustfmt::skip]
301pub enum TSXKeyword {
302 Const, Var, Let,
303 If, Else, For, While, Do, Switch,
304 Class, Function, Constructor,
305 New, This, Super,
306 Case, Yield, Return, Continue, Break,
307 Import, Export, Default, From, With,
308 In, Of,
309 TypeOf, InstanceOf, Void, Delete,
310 Assert,
312 Asserts,
314 Debugger,
315 Try, Catch, Finally, Throw,
316 Async, Await,
317 Static,
318 Get, Set,
319 Extends,
320 Null,
321 True, False,
322 Abstract, Implements,
324 Enum, Interface, Type,
326 Private, Public, Protected,
328 As, Readonly, Satisfies, Declare, Namespace,
330 Is,
332 Infer, KeyOf, Unique, Symbol,
333 #[cfg(feature = "extras")] Module,
335 #[cfg(feature = "extras")] Server, #[cfg(feature = "extras")] Worker,
337 #[cfg(feature = "extras")] Nominal, #[cfg(feature = "extras")] Performs,
339
340 #[cfg(feature = "extras")]
341 Generator,
343
344 #[cfg(feature = "extras")]
345 Deferred
346}
347
348impl TSXKeyword {
349 #[cfg(feature = "extras")]
350 pub(crate) fn is_special_function_header(self) -> bool {
351 matches!(self, TSXKeyword::Worker | TSXKeyword::Server | TSXKeyword::Generator)
352 }
353
354 #[cfg(not(feature = "extras"))]
355 pub(crate) fn is_special_function_header(&self) -> bool {
356 false
357 }
358
359 pub(crate) fn is_in_function_header(self) -> bool {
360 matches!(self, TSXKeyword::Function | TSXKeyword::Async)
361 }
362
363 #[cfg(feature = "extras")]
364 pub(crate) fn is_in_method_header(self) -> bool {
365 matches!(
366 self,
367 TSXKeyword::Generator | TSXKeyword::Get | TSXKeyword::Set | TSXKeyword::Async
368 )
369 }
370
371 #[cfg(not(feature = "extras"))]
372 pub(crate) fn is_in_method_header(self) -> bool {
373 matches!(self, TSXKeyword::Get | TSXKeyword::Set | TSXKeyword::Async)
374 }
375
376 #[allow(clippy::cast_possible_truncation)]
377 pub(crate) fn length(self) -> u32 {
378 self.to_str().len() as u32
379 }
380
381 #[rustfmt::skip]
382 pub(crate) fn is_invalid_identifier(self) -> bool {
383 matches!(
384 self,
385 TSXKeyword::Const | TSXKeyword::Var | TSXKeyword::If | TSXKeyword::Else | TSXKeyword::For
386 | TSXKeyword::While | TSXKeyword::Do | TSXKeyword::Switch | TSXKeyword::Class | TSXKeyword::Function
387 | TSXKeyword::New | TSXKeyword::Super | TSXKeyword::Case | TSXKeyword::Return | TSXKeyword::Continue
388 | TSXKeyword::Break | TSXKeyword::Import | TSXKeyword::Export | TSXKeyword::Default | TSXKeyword::In
389 | TSXKeyword::TypeOf | TSXKeyword::InstanceOf | TSXKeyword::Void | TSXKeyword::Delete
390 | TSXKeyword::Debugger | TSXKeyword::Try | TSXKeyword::Catch | TSXKeyword::Finally | TSXKeyword::Throw
391 | TSXKeyword::Extends | TSXKeyword::Enum
392 )
393 }
394}
395
396impl TSXToken {
397 #[must_use]
398 pub fn is_identifier_or_ident(&self) -> bool {
399 matches!(self, TSXToken::Identifier(_) | TSXToken::Keyword(_))
400 }
401
402 #[must_use]
403 pub fn is_comment(&self) -> bool {
404 matches!(self, TSXToken::Comment(_) | TSXToken::MultiLineComment(_))
405 }
406
407 pub fn try_into_comment(
409 token: Token<TSXToken, TokenStart>,
410 ) -> Result<(String, bool, Span), Token<TSXToken, TokenStart>> {
411 if let Token(TSXToken::MultiLineComment(c), d) = token {
412 let len = c.len();
413 Ok((c, true, d.with_length(len + 4)))
414 } else if let Token(TSXToken::Comment(c), d) = token {
415 let len = c.len();
416 Ok((c, false, d.with_length(len + 2)))
417 } else {
418 Err(token)
419 }
420 }
421
422 #[must_use]
424 pub fn is_expression_prefix(&self) -> bool {
425 matches!(
426 self,
427 TSXToken::Keyword(TSXKeyword::Return | TSXKeyword::Case | TSXKeyword::Yield | TSXKeyword::Throw | TSXKeyword::TypeOf | TSXKeyword::In | TSXKeyword::Of | TSXKeyword::Await | TSXKeyword::Do | TSXKeyword::Extends | TSXKeyword::Void)
428 | TSXToken::Arrow
429 | TSXToken::SemiColon
431 | TSXToken::OpenParentheses
432 | TSXToken::OpenBrace
433 | TSXToken::OpenBracket
434 | TSXToken::JSXExpressionStart
435 | TSXToken::QuestionMark
436 | TSXToken::Colon
437 | TSXToken::LogicalNot
438 | TSXToken::LogicalAnd
439 | TSXToken::LogicalOr
440 | TSXToken::BitwiseNot
441 | TSXToken::BitwiseAnd
442 | TSXToken::BitwiseOr
443 | TSXToken::Multiply
444 | TSXToken::Add
445 | TSXToken::Subtract
446 | TSXToken::Divide
447 ) || self.is_assignment()
448 }
449
450 #[must_use]
452 pub fn is_expression_postfix(&self) -> bool {
453 matches!(
454 self,
455 TSXToken::MultiLineComment(..)
456 | TSXToken::LogicalAnd
457 | TSXToken::LogicalOr
458 | TSXToken::Multiply
459 | TSXToken::Add
460 | TSXToken::Subtract
461 | TSXToken::Divide
462 ) || self.is_assignment()
463 }
464
465 #[must_use]
467 pub fn from_slice(slice: &str) -> Self {
468 match TSXKeyword::from_str(slice) {
469 Ok(keyword_token) => TSXToken::Keyword(keyword_token),
470 Err(_) => TSXToken::Identifier(slice.to_owned()),
471 }
472 }
473
474 pub(crate) fn is_symbol(&self) -> bool {
475 !matches!(self, TSXToken::Keyword(_) | TSXToken::Identifier(..))
476 }
477
478 pub(crate) fn is_statement_or_declaration_start(&self) -> bool {
479 matches!(
480 self,
481 TSXToken::Keyword(
482 TSXKeyword::Function
483 | TSXKeyword::If
484 | TSXKeyword::For
485 | TSXKeyword::While
486 | TSXKeyword::Const
487 | TSXKeyword::Let
488 | TSXKeyword::Break
489 | TSXKeyword::Import
490 | TSXKeyword::Export
491 )
492 )
493 }
494
495 pub(crate) fn is_expression_delimiter(&self) -> bool {
496 matches!(
497 self,
498 TSXToken::Comma
499 | TSXToken::SemiColon
500 | TSXToken::Colon
501 | TSXToken::LogicalOr
502 | TSXToken::LogicalAnd
503 | TSXToken::CloseBrace
504 | TSXToken::CloseParentheses
505 | TSXToken::CloseBracket
506 ) || self.is_assignment()
507 }
508
509 pub(crate) fn is_assignment(&self) -> bool {
510 matches!(
511 self,
512 TSXToken::Assign
513 | TSXToken::MultiplyAssign
514 | TSXToken::AddAssign
515 | TSXToken::SubtractAssign
516 | TSXToken::DivideAssign
517 | TSXToken::ModuloAssign
518 | TSXToken::BitwiseOrAssign
519 | TSXToken::BitwiseAndAssign
520 | TSXToken::LogicalOrAssign
521 | TSXToken::LogicalAndAssign
522 )
523 }
524}
525
526pub(crate) fn token_as_identifier(
530 token: Token<TSXToken, TokenStart>,
531 at_location: &str,
532) -> crate::ParseResult<(String, Span)> {
533 let position = token.get_span();
534 let name = match token.0 {
535 TSXToken::Identifier(value) => value,
536 TSXToken::Keyword(keyword) => EnumVariantsStrings::to_str(&keyword).to_owned(),
537 token_type => {
538 return Err(ParseError::new(
539 crate::ParseErrors::ExpectedIdent { found: token_type, at_location },
540 position,
541 ));
542 }
543 };
544 Ok((name, position))
545}