refactor: use dependency analyzer from SWC (#7334)

This commit is contained in:
Bartek Iwańczuk 2020-09-03 17:11:30 +02:00 committed by GitHub
parent 5b100cb874
commit dbd941148c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 135 deletions

13
Cargo.lock generated
View file

@ -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"

View file

@ -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"] }

View file

@ -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<DependencyDescriptor>,
}
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<String> {
let comments = parser.get_span_comments(span);
fn get_deno_types(comments: &[Comment]) -> Option<String> {
if comments.is_empty() {
return None;
}