diff --git a/Cargo.lock b/Cargo.lock index 33d353626e..d51e476bf0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -412,6 +412,7 @@ dependencies = [ "serde_json", "sourcemap", "swc_common", + "swc_ecma_dep_graph", "swc_ecmascript", "sys-info", "tempfile", @@ -2260,6 +2261,18 @@ dependencies = [ "syn 1.0.36", ] +[[package]] +name = "swc_ecma_dep_graph" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb38c4567ac35d625c0da0a70d68449e38b23c1ae95df9ca6837811e2711136e" +dependencies = [ + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_visit", +] + [[package]] name = "swc_ecma_parser" version = "0.37.0" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 0d61cceed2..74694c1657 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -63,6 +63,7 @@ sys-info = "0.7.0" sourcemap = "6.0.1" swc_common = { version = "=0.10.2", features = ["sourcemap"] } swc_ecmascript = { version = "=0.7.0", features = ["codegen", "parser", "react", "transforms", "visit"] } +swc_ecma_dep_graph = "0.3.0" tempfile = "3.1.0" termcolor = "1.1.0" tokio = { version = "0.2.22", features = ["full"] } diff --git a/cli/tsc.rs b/cli/tsc.rs index 7996736949..eff9250629 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -55,10 +55,9 @@ use std::sync::atomic::Ordering; use std::sync::Arc; use std::sync::Mutex; use std::task::Poll; +use swc_common::comments::Comment; use swc_common::comments::CommentKind; -use swc_common::Span; -use swc_ecmascript::visit::Node; -use swc_ecmascript::visit::Visit; +use swc_ecma_dep_graph as dep_graph; use url::Url; pub const AVAILABLE_LIBS: &[&str] = &[ @@ -1437,121 +1436,6 @@ pub async fn runtime_transpile( Ok(v) } -#[derive(Clone, Debug, PartialEq)] -enum DependencyKind { - Import, - DynamicImport, - Export, -} - -#[derive(Clone, Debug, PartialEq)] -struct DependencyDescriptor { - span: Span, - specifier: String, - kind: DependencyKind, -} - -struct DependencyVisitor { - dependencies: Vec, -} - -impl Visit for DependencyVisitor { - fn visit_import_decl( - &mut self, - import_decl: &swc_ecmascript::ast::ImportDecl, - _parent: &dyn Node, - ) { - let src_str = import_decl.src.value.to_string(); - self.dependencies.push(DependencyDescriptor { - specifier: src_str, - kind: DependencyKind::Import, - span: import_decl.span, - }); - } - - fn visit_named_export( - &mut self, - named_export: &swc_ecmascript::ast::NamedExport, - _parent: &dyn Node, - ) { - if let Some(src) = &named_export.src { - let src_str = src.value.to_string(); - self.dependencies.push(DependencyDescriptor { - specifier: src_str, - kind: DependencyKind::Export, - span: named_export.span, - }); - } - } - - fn visit_export_all( - &mut self, - export_all: &swc_ecmascript::ast::ExportAll, - _parent: &dyn Node, - ) { - let src_str = export_all.src.value.to_string(); - self.dependencies.push(DependencyDescriptor { - specifier: src_str, - kind: DependencyKind::Export, - span: export_all.span, - }); - } - - fn visit_ts_import_type( - &mut self, - ts_import_type: &swc_ecmascript::ast::TsImportType, - _parent: &dyn Node, - ) { - // TODO(bartlomieju): possibly add separate DependencyKind - let src_str = ts_import_type.arg.value.to_string(); - self.dependencies.push(DependencyDescriptor { - specifier: src_str, - kind: DependencyKind::Import, - span: ts_import_type.arg.span, - }); - } - - fn visit_call_expr( - &mut self, - call_expr: &swc_ecmascript::ast::CallExpr, - parent: &dyn Node, - ) { - use swc_ecmascript::ast::Expr::*; - use swc_ecmascript::ast::ExprOrSuper::*; - - swc_ecmascript::visit::visit_call_expr(self, call_expr, parent); - let boxed_expr = match call_expr.callee.clone() { - Super(_) => return, - Expr(boxed) => boxed, - }; - - match &*boxed_expr { - Ident(ident) => { - if &ident.sym.to_string() != "import" { - return; - } - } - _ => return, - }; - - if let Some(arg) = call_expr.args.get(0) { - match &*arg.expr { - Lit(lit) => { - if let swc_ecmascript::ast::Lit::Str(str_) = lit { - let src_str = str_.value.to_string(); - self.dependencies.push(DependencyDescriptor { - specifier: src_str, - kind: DependencyKind::DynamicImport, - span: call_expr.span, - }); - } - } - _ => return, - } - } - } -} - #[derive(Clone, Debug, PartialEq)] pub struct ImportDesc { pub specifier: String, @@ -1587,39 +1471,39 @@ pub fn pre_process_file( let parser = AstParser::default(); let parse_result = parser.parse_module(file_name, media_type, source_code); let module = parse_result?; - let mut collector = DependencyVisitor { - dependencies: vec![], - }; - let module_span = module.span; - collector.visit_module(&module, &module); - let dependency_descriptors = collector.dependencies; + let dependency_descriptors = dep_graph::analyze_dependencies( + &module, + &parser.source_map, + &parser.comments, + ); // for each import check if there's relevant @deno-types directive let imports = dependency_descriptors .iter() + .filter(|desc| desc.kind != dep_graph::DependencyKind::Require) .filter(|desc| { if analyze_dynamic_imports { return true; } - - desc.kind != DependencyKind::DynamicImport + !desc.is_dynamic }) .map(|desc| { - let location = parser.get_span_location(desc.span); - let deno_types = get_deno_types(&parser, desc.span); + let deno_types = get_deno_types(&desc.leading_comments); ImportDesc { specifier: desc.specifier.to_string(), deno_types, - location: location.into(), + location: Location { + filename: file_name.to_string(), + col: desc.col, + line: desc.line, + }, } }) .collect(); // analyze comment from beginning of the file and find TS directives - let comments = parser - .comments - .with_leading(module_span.lo(), |cmts| cmts.to_vec()); + let comments = parser.get_span_comments(module.span); let mut references = vec![]; for comment in comments { @@ -1640,9 +1524,7 @@ pub fn pre_process_file( Ok((imports, references)) } -fn get_deno_types(parser: &AstParser, span: Span) -> Option { - let comments = parser.get_span_comments(span); - +fn get_deno_types(comments: &[Comment]) -> Option { if comments.is_empty() { return None; }