1use super::{Expr, Pat, Span};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub struct ImportName {
9 pub name: String,
11 #[serde(skip_serializing_if = "Option::is_none")]
13 pub alias: Option<String>,
14 pub is_namespace: bool,
16}
17
18impl ImportName {
19 pub fn named(name: impl Into<String>) -> Self {
21 Self {
22 name: name.into(),
23 alias: None,
24 is_namespace: false,
25 }
26 }
27
28 pub fn aliased(name: impl Into<String>, alias: impl Into<String>) -> Self {
30 Self {
31 name: name.into(),
32 alias: Some(alias.into()),
33 is_namespace: false,
34 }
35 }
36
37 pub fn default(name: impl Into<String>) -> Self {
39 Self {
40 name: name.into(),
41 alias: None,
42 is_namespace: false,
43 }
44 }
45
46 pub fn namespace(alias: impl Into<String>) -> Self {
48 Self {
49 name: "*".into(),
50 alias: Some(alias.into()),
51 is_namespace: true,
52 }
53 }
54}
55
56#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
58pub struct ExportName {
59 pub name: String,
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub alias: Option<String>,
64}
65
66impl ExportName {
67 pub fn named(name: impl Into<String>) -> Self {
69 Self {
70 name: name.into(),
71 alias: None,
72 }
73 }
74
75 pub fn aliased(name: impl Into<String>, alias: impl Into<String>) -> Self {
77 Self {
78 name: name.into(),
79 alias: Some(alias.into()),
80 }
81 }
82}
83
84#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
86pub struct Method {
87 pub name: String,
89 pub params: Vec<super::Param>,
91 pub body: Vec<Stmt>,
93 pub is_static: bool,
95 #[serde(skip_serializing_if = "Option::is_none")]
97 pub return_type: Option<String>,
98}
99
100impl Method {
101 pub fn new(name: impl Into<String>, params: Vec<super::Param>, body: Vec<Stmt>) -> Self {
102 Self {
103 name: name.into(),
104 params,
105 body,
106 is_static: false,
107 return_type: None,
108 }
109 }
110}
111
112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
114pub enum Stmt {
115 Expr(Expr),
117
118 Let {
120 name: String,
121 init: Option<Expr>,
122 mutable: bool,
123 #[serde(skip_serializing_if = "Option::is_none")]
125 type_annotation: Option<String>,
126 #[serde(skip_serializing_if = "Option::is_none")]
128 span: Option<Span>,
129 },
130
131 Block(Vec<Stmt>),
133
134 If {
136 test: Expr,
137 consequent: Box<Stmt>,
138 alternate: Option<Box<Stmt>>,
139 #[serde(skip_serializing_if = "Option::is_none")]
141 span: Option<Span>,
142 },
143
144 While {
146 test: Expr,
147 body: Box<Stmt>,
148 #[serde(skip_serializing_if = "Option::is_none")]
150 span: Option<Span>,
151 },
152
153 For {
155 init: Option<Box<Stmt>>,
156 test: Option<Expr>,
157 update: Option<Expr>,
158 body: Box<Stmt>,
159 #[serde(skip_serializing_if = "Option::is_none")]
161 span: Option<Span>,
162 },
163
164 ForIn {
166 variable: String,
167 iterable: Expr,
168 body: Box<Stmt>,
169 #[serde(skip_serializing_if = "Option::is_none")]
171 span: Option<Span>,
172 },
173
174 Return(Option<Expr>),
176
177 Break,
179
180 Continue,
182
183 TryCatch {
185 body: Box<Stmt>,
186 catch_param: Option<String>,
187 catch_body: Option<Box<Stmt>>,
188 finally_body: Option<Box<Stmt>>,
189 #[serde(skip_serializing_if = "Option::is_none")]
191 span: Option<Span>,
192 },
193
194 Function(crate::Function),
196
197 Import {
201 source: String,
203 names: Vec<ImportName>,
205 #[serde(skip_serializing_if = "Option::is_none")]
207 span: Option<Span>,
208 },
209
210 Export {
212 names: Vec<ExportName>,
214 #[serde(skip_serializing_if = "Option::is_none")]
216 source: Option<String>,
217 #[serde(skip_serializing_if = "Option::is_none")]
219 span: Option<Span>,
220 },
221
222 Class {
224 name: String,
226 #[serde(skip_serializing_if = "Option::is_none")]
228 extends: Option<String>,
229 methods: Vec<Method>,
231 #[serde(skip_serializing_if = "Option::is_none")]
233 span: Option<Span>,
234 },
235
236 Destructure {
242 pat: Pat,
244 value: Expr,
246 mutable: bool,
248 #[serde(skip_serializing_if = "Option::is_none")]
250 span: Option<Span>,
251 },
252
253 Comment {
262 text: String,
264 block: bool,
266 #[serde(skip_serializing_if = "Option::is_none")]
268 span: Option<Span>,
269 },
270}
271
272impl Stmt {
274 pub fn expr(e: Expr) -> Self {
275 Stmt::Expr(e)
276 }
277
278 pub fn let_decl(name: impl Into<String>, init: Option<Expr>) -> Self {
279 Stmt::Let {
280 name: name.into(),
281 init,
282 mutable: true,
283 type_annotation: None,
284 span: None,
285 }
286 }
287
288 pub fn const_decl(name: impl Into<String>, init: Expr) -> Self {
289 Stmt::Let {
290 name: name.into(),
291 init: Some(init),
292 mutable: false,
293 type_annotation: None,
294 span: None,
295 }
296 }
297
298 pub fn block(stmts: Vec<Stmt>) -> Self {
299 Stmt::Block(stmts)
300 }
301
302 pub fn if_stmt(test: Expr, consequent: Stmt, alternate: Option<Stmt>) -> Self {
303 Stmt::If {
304 test,
305 consequent: Box::new(consequent),
306 alternate: alternate.map(Box::new),
307 span: None,
308 }
309 }
310
311 pub fn while_loop(test: Expr, body: Stmt) -> Self {
312 Stmt::While {
313 test,
314 body: Box::new(body),
315 span: None,
316 }
317 }
318
319 pub fn for_loop(
320 init: Option<Stmt>,
321 test: Option<Expr>,
322 update: Option<Expr>,
323 body: Stmt,
324 ) -> Self {
325 Stmt::For {
326 init: init.map(Box::new),
327 test,
328 update,
329 body: Box::new(body),
330 span: None,
331 }
332 }
333
334 pub fn for_in(variable: impl Into<String>, iterable: Expr, body: Stmt) -> Self {
335 Stmt::ForIn {
336 variable: variable.into(),
337 iterable,
338 body: Box::new(body),
339 span: None,
340 }
341 }
342
343 pub fn return_stmt(expr: Option<Expr>) -> Self {
344 Stmt::Return(expr)
345 }
346
347 pub fn break_stmt() -> Self {
348 Stmt::Break
349 }
350
351 pub fn continue_stmt() -> Self {
352 Stmt::Continue
353 }
354
355 pub fn try_catch(
356 body: Stmt,
357 catch_param: Option<String>,
358 catch_body: Option<Stmt>,
359 finally_body: Option<Stmt>,
360 ) -> Self {
361 Stmt::TryCatch {
362 body: Box::new(body),
363 catch_param,
364 catch_body: catch_body.map(Box::new),
365 finally_body: finally_body.map(Box::new),
366 span: None,
367 }
368 }
369
370 pub fn function(f: crate::Function) -> Self {
371 Stmt::Function(f)
372 }
373
374 pub fn import(source: impl Into<String>, names: Vec<ImportName>) -> Self {
376 Stmt::Import {
377 source: source.into(),
378 names,
379 span: None,
380 }
381 }
382
383 pub fn export(names: Vec<ExportName>, source: Option<String>) -> Self {
385 Stmt::Export {
386 names,
387 source,
388 span: None,
389 }
390 }
391
392 pub fn class(name: impl Into<String>, extends: Option<String>, methods: Vec<Method>) -> Self {
394 Stmt::Class {
395 name: name.into(),
396 extends,
397 methods,
398 span: None,
399 }
400 }
401
402 pub fn destructure(pat: Pat, value: Expr, mutable: bool) -> Self {
404 Stmt::Destructure {
405 pat,
406 value,
407 mutable,
408 span: None,
409 }
410 }
411
412 pub fn comment_line(text: impl Into<String>) -> Self {
414 Stmt::Comment {
415 text: text.into(),
416 block: false,
417 span: None,
418 }
419 }
420
421 pub fn comment_block(text: impl Into<String>) -> Self {
423 Stmt::Comment {
424 text: text.into(),
425 block: true,
426 span: None,
427 }
428 }
429
430 pub fn with_span(self, span: Span) -> Self {
432 match self {
433 Stmt::Let {
434 name,
435 init,
436 mutable,
437 type_annotation,
438 ..
439 } => Stmt::Let {
440 name,
441 init,
442 mutable,
443 type_annotation,
444 span: Some(span),
445 },
446 Stmt::If {
447 test,
448 consequent,
449 alternate,
450 ..
451 } => Stmt::If {
452 test,
453 consequent,
454 alternate,
455 span: Some(span),
456 },
457 Stmt::While { test, body, .. } => Stmt::While {
458 test,
459 body,
460 span: Some(span),
461 },
462 Stmt::For {
463 init,
464 test,
465 update,
466 body,
467 ..
468 } => Stmt::For {
469 init,
470 test,
471 update,
472 body,
473 span: Some(span),
474 },
475 Stmt::ForIn {
476 variable,
477 iterable,
478 body,
479 ..
480 } => Stmt::ForIn {
481 variable,
482 iterable,
483 body,
484 span: Some(span),
485 },
486 Stmt::TryCatch {
487 body,
488 catch_param,
489 catch_body,
490 finally_body,
491 ..
492 } => Stmt::TryCatch {
493 body,
494 catch_param,
495 catch_body,
496 finally_body,
497 span: Some(span),
498 },
499 Stmt::Destructure {
500 pat,
501 value,
502 mutable,
503 ..
504 } => Stmt::Destructure {
505 pat,
506 value,
507 mutable,
508 span: Some(span),
509 },
510 Stmt::Comment { text, block, .. } => Stmt::Comment {
511 text,
512 block,
513 span: Some(span),
514 },
515 Stmt::Import { source, names, .. } => Stmt::Import {
516 source,
517 names,
518 span: Some(span),
519 },
520 Stmt::Export { names, source, .. } => Stmt::Export {
521 names,
522 source,
523 span: Some(span),
524 },
525 Stmt::Class {
526 name,
527 extends,
528 methods,
529 ..
530 } => Stmt::Class {
531 name,
532 extends,
533 methods,
534 span: Some(span),
535 },
536 other => other,
537 }
538 }
539}