Skip to content

Commit

Permalink
feat: add import assertion to dep analyzer (#1387)
Browse files Browse the repository at this point in the history
Co-authored-by: 강동윤 <kdy1997.dev@gmail.com>
  • Loading branch information
bartlomieju and kdy1 committed Feb 10, 2021
1 parent bf445a7 commit 8ef78a9
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 5 deletions.
4 changes: 2 additions & 2 deletions ecmascript/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecmascript"
repository = "https://github.com/swc-project/swc.git"
version = "0.19.0"
version = "0.20.0"

[features]
codegen = ["swc_ecma_codegen"]
Expand All @@ -26,7 +26,7 @@ typescript = ["swc_ecma_transforms/typescript"]
[dependencies]
swc_ecma_ast = {version = "0.38.0", path = "./ast"}
swc_ecma_codegen = {version = "0.44.0", path = "./codegen", optional = true}
swc_ecma_dep_graph = {version = "0.13.0", path = "./dep-graph", optional = true}
swc_ecma_dep_graph = {version = "0.14.0", path = "./dep-graph", optional = true}
swc_ecma_parser = {version = "0.46.0", path = "./parser", optional = true}
swc_ecma_transforms = {version = "0.34.0", path = "./transforms", optional = true}
swc_ecma_utils = {version = "0.28.0", path = "./utils", optional = true}
Expand Down
2 changes: 1 addition & 1 deletion ecmascript/dep-graph/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_dep_graph"
repository = "https://github.com/swc-project/swc.git"
version = "0.13.0"
version = "0.14.0"

[dependencies]
swc_atoms = {version = "0.2", path = "../../atoms"}
Expand Down
96 changes: 94 additions & 2 deletions ecmascript/dep-graph/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use swc_atoms::JsWord;
use swc_common::{
comments::{Comment, SingleThreadedComments},
Expand Down Expand Up @@ -46,6 +47,9 @@ pub struct DependencyDescriptor {
/// The location of the specifier.
pub specifier_line: usize,
pub specifier_col: usize,
/// Import assertions for this dependency.
/// NOTE: it's filled only for static imports and exports.
pub import_assertions: HashMap<String, String>,
}

struct DependencyCollector<'a> {
Expand Down Expand Up @@ -80,6 +84,7 @@ impl<'a> Visit for DependencyCollector<'a> {
} else {
DependencyKind::Import
};
let import_assertions = parse_import_assertions(node.asserts.as_ref());
self.items.push(DependencyDescriptor {
kind,
is_dynamic: false,
Expand All @@ -89,6 +94,7 @@ impl<'a> Visit for DependencyCollector<'a> {
specifier,
specifier_col: specifier_location.col_display,
specifier_line: specifier_location.line,
import_assertions,
});
}

Expand All @@ -104,6 +110,7 @@ impl<'a> Visit for DependencyCollector<'a> {
} else {
DependencyKind::Export
};
let import_assertions = parse_import_assertions(node.asserts.as_ref());
self.items.push(DependencyDescriptor {
kind,
is_dynamic: false,
Expand All @@ -113,6 +120,7 @@ impl<'a> Visit for DependencyCollector<'a> {
specifier,
specifier_col: specifier_location.col_display,
specifier_line: specifier_location.line,
import_assertions,
});
}
}
Expand All @@ -123,6 +131,7 @@ impl<'a> Visit for DependencyCollector<'a> {
let location = self.get_location(span);
let leading_comments = self.get_leading_comments(span);
let specifier_location = self.get_location(node.src.span);
let import_assertions = parse_import_assertions(node.asserts.as_ref());
self.items.push(DependencyDescriptor {
kind: DependencyKind::Export,
is_dynamic: false,
Expand All @@ -132,6 +141,7 @@ impl<'a> Visit for DependencyCollector<'a> {
specifier,
specifier_col: specifier_location.col_display,
specifier_line: specifier_location.line,
import_assertions,
});
}

Expand All @@ -150,6 +160,7 @@ impl<'a> Visit for DependencyCollector<'a> {
specifier,
specifier_col: specifier_location.col_display,
specifier_line: specifier_location.line,
import_assertions: HashMap::default(),
});
}

Expand Down Expand Up @@ -201,13 +212,33 @@ impl<'a> Visit for DependencyCollector<'a> {
specifier,
specifier_col: specifier_location.col_display,
specifier_line: specifier_location.line,
import_assertions: HashMap::default(),
});
}
}
}
}
}

/// Parses import assertions into a hashmap. According to proposal the values
/// can only be strings (https://github.com/tc39/proposal-import-assertions#should-more-than-just-strings-be-supported-as-attribute-values)
/// and thus non-string values are skipped.
fn parse_import_assertions(asserts: Option<&ast::ObjectLit>) -> HashMap<String, String> {
let mut import_assertions = HashMap::new();
if let Some(asserts) = asserts {
for prop in &asserts.props {
let prop = prop.clone().expect_prop();
let key_value = prop.expect_key_value();
let key = key_value.key.expect_str().value.to_string();
let value_lit = key_value.value.expect_lit();
if let ast::Lit::Str(str_) = value_lit {
import_assertions.insert(key, str_.value.to_string());
}
}
}
import_assertions
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -222,7 +253,7 @@ mod tests {
file_name: &str,
source: &str,
) -> Result<(ast::Module, Lrc<SourceMap>, SingleThreadedComments), testing::StdErr> {
let output = ::testing::run_test(true, |cm, handler| {
let output = ::testing::run_test(false, |cm, handler| {
let fm =
cm.new_source_file(FileName::Custom(file_name.to_string()), source.to_string());

Expand All @@ -234,6 +265,7 @@ mod tests {
dynamic_import: true,
decorators: true,
no_early_errors: true,
import_assertions: true,
..Default::default()
}),
JscTarget::Es2015,
Expand Down Expand Up @@ -291,7 +323,6 @@ try {
}
"#;
let (module, source_map, comments) = helper("test.ts", &source).unwrap();
// eprintln!("module {:#?}", module);
let dependencies = analyze_dependencies(&module, &source_map, &comments);
assert_eq!(dependencies.len(), 8);
assert_eq!(
Expand All @@ -306,6 +337,7 @@ try {
specifier: JsWord::from("./test.ts"),
specifier_col: 21,
specifier_line: 1,
import_assertions: HashMap::default(),
},
DependencyDescriptor {
kind: DependencyKind::ImportType,
Expand All @@ -320,6 +352,7 @@ try {
specifier: JsWord::from("./foo.d.ts"),
specifier_col: 25,
specifier_line: 3,
import_assertions: HashMap::default(),
},
DependencyDescriptor {
kind: DependencyKind::Export,
Expand All @@ -334,6 +367,7 @@ try {
specifier: JsWord::from("./buzz.ts"),
specifier_col: 22,
specifier_line: 5,
import_assertions: HashMap::default(),
},
DependencyDescriptor {
kind: DependencyKind::ExportType,
Expand All @@ -355,6 +389,7 @@ try {
specifier: JsWord::from("./fizz.d.ts"),
specifier_col: 26,
specifier_line: 10,
import_assertions: HashMap::default(),
},
DependencyDescriptor {
kind: DependencyKind::Require,
Expand All @@ -365,6 +400,7 @@ try {
specifier: JsWord::from("path"),
specifier_col: 25,
specifier_line: 11,
import_assertions: HashMap::default(),
},
DependencyDescriptor {
kind: DependencyKind::Import,
Expand All @@ -375,6 +411,7 @@ try {
specifier: JsWord::from("./foo1.ts"),
specifier_col: 13,
specifier_line: 14,
import_assertions: HashMap::default(),
},
DependencyDescriptor {
kind: DependencyKind::Import,
Expand All @@ -385,6 +422,7 @@ try {
specifier: JsWord::from("./foo.ts"),
specifier_col: 29,
specifier_line: 17,
import_assertions: HashMap::default(),
},
DependencyDescriptor {
kind: DependencyKind::Require,
Expand All @@ -395,8 +433,62 @@ try {
specifier: JsWord::from("some_package"),
specifier_col: 24,
specifier_line: 23,
import_assertions: HashMap::default(),
}
]
);
}

#[test]
fn test_import_assertions() {
let source = r#"import * as bar from "./test.ts" assert { "type": "typescript" };
export * from "./test.ts" assert { "type": "typescript" };
export { bar } from "./test.json" assert { "type": "json" };
"#;
let (module, source_map, comments) = helper("test.ts", &source).unwrap();
let mut expected_assertions1 = HashMap::new();
expected_assertions1.insert("type".to_string(), "typescript".to_string());
let mut expected_assertions2 = HashMap::new();
expected_assertions2.insert("type".to_string(), "json".to_string());
let dependencies = analyze_dependencies(&module, &source_map, &comments);
assert_eq!(dependencies.len(), 3);
assert_eq!(
dependencies,
vec![
DependencyDescriptor {
kind: DependencyKind::Import,
is_dynamic: false,
leading_comments: Vec::new(),
col: 0,
line: 1,
specifier: JsWord::from("./test.ts"),
specifier_col: 21,
specifier_line: 1,
import_assertions: expected_assertions1.clone(),
},
DependencyDescriptor {
kind: DependencyKind::Export,
is_dynamic: false,
leading_comments: Vec::new(),
col: 0,
line: 2,
specifier: JsWord::from("./test.ts"),
specifier_col: 14,
specifier_line: 2,
import_assertions: expected_assertions1,
},
DependencyDescriptor {
kind: DependencyKind::Export,
is_dynamic: false,
leading_comments: Vec::new(),
col: 0,
line: 3,
specifier: JsWord::from("./test.json"),
specifier_col: 20,
specifier_line: 3,
import_assertions: expected_assertions2,
},
]
);
}
}

0 comments on commit 8ef78a9

Please sign in to comment.