1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
use std::{borrow::Cow, mem::take};
use swc_common::pass::CompilerPass;
use swc_ecma_ast::*;
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut};

pub fn import_hoister() -> impl Fold + VisitMut + CompilerPass {
    as_folder(Hoister)
}

struct Hoister;

impl CompilerPass for Hoister {
    fn name() -> Cow<'static, str> {
        Cow::Borrowed("import-hoister")
    }
}

impl VisitMut for Hoister {
    noop_visit_mut_type!();

    fn visit_mut_module(&mut self, module: &mut Module) {
        let mut found_other = false;
        let mut need_work = false;

        for stmt in &module.body {
            match stmt {
                ModuleItem::ModuleDecl(ModuleDecl::Import(..)) => {
                    if found_other {
                        need_work = true;
                        break;
                    }
                }
                _ => {
                    found_other = true;
                }
            }
        }

        if !need_work {
            return;
        }

        let mut imports = Vec::with_capacity(module.body.len());
        let mut extra = vec![];

        for body in take(&mut module.body) {
            match body {
                ModuleItem::ModuleDecl(ModuleDecl::Import(..)) => {
                    imports.push(body);
                }
                _ => {
                    extra.push(body);
                }
            }
        }

        imports.extend(extra);
        module.body = imports;
    }
}