From c6917133942c791480cd2aec7297b2a2ee623059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 28 Jul 2020 22:33:23 +0200 Subject: [PATCH] refactor: Use SWC to strip types for "--no-check" flag (#6895) --- Cargo.lock | 115 +++++++++++++++++++++++++++++++++++++++----- cli/Cargo.toml | 4 +- cli/global_state.rs | 5 +- cli/swc_util.rs | 93 +++++++++++++++++++++++++++++------ cli/tsc.rs | 65 ++++++++----------------- 5 files changed, 206 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b51137a3b..ebb21f892e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,6 +70,12 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + [[package]] name = "ast_node" version = "0.7.0" @@ -400,6 +406,8 @@ dependencies = [ "serde_derive", "serde_json", "sourcemap", + "swc_ecma_codegen", + "swc_ecma_transforms", "sys-info", "tempfile", "termcolor", @@ -437,9 +445,9 @@ dependencies = [ [[package]] name = "deno_lint" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d13c7f86b00ec9d37d82feda3ae7903d239c86923b0e8157d76636587d494aa" +checksum = "fbdf386c931a0c09550f80ea3ac6c59e115d3e8c2cffb5e196d4cda1aeff690c" dependencies = [ "dprint-plugin-typescript", "lazy_static", @@ -515,9 +523,9 @@ dependencies = [ [[package]] name = "dprint-plugin-typescript" -version = "0.21.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71677ecb7ac1522167c60ba7132811b25b03bec76d7b4276a66770ea4063d58" +checksum = "afab3ed9d8240f14f68e05ccf200dd6034a8bb55fcf0e945f775030d0fca78fa" dependencies = [ "dprint-core", "serde", @@ -1353,6 +1361,15 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +[[package]] +name = "ordered-float" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3741934be594d77de1c8461ebcbbe866f585ea616a9753aa78f2bdc69f0e4579" +dependencies = [ + "num-traits", +] + [[package]] name = "os_pipe" version = "0.9.2" @@ -2195,9 +2212,9 @@ dependencies = [ [[package]] name = "swc_ecma_ast" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aacf20b5d1587fcbfdd5e09c9e9ee55fa862c93f3ddeea9ec847a124eff27a2" +checksum = "9dcdd53f72ccc81568bcf789f9aeaa065588705ab46113e9f6ba4014f8829f5d" dependencies = [ "enum_kind", "is-macro", @@ -2209,10 +2226,38 @@ dependencies = [ ] [[package]] -name = "swc_ecma_parser" -version = "0.28.0" +name = "swc_ecma_codegen" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77389b91b7ee1a59b8d424c86c835147da95eccec1ad289860e42ef1a109fd28" +checksum = "8d48467780147af9075def6d7c75198af57e1b74ad28e8508850974be785f8cd" +dependencies = [ + "bitflags", + "num-bigint", + "sourcemap", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_codegen_macros", +] + +[[package]] +name = "swc_ecma_codegen_macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04378143fd1296af71dd3aea2e096bef6fbf8aa3c25352d44d62d7f28aa9851b" +dependencies = [ + "pmutil", + "proc-macro2 1.0.18", + "quote 1.0.7", + "swc_macros_common", + "syn 1.0.33", +] + +[[package]] +name = "swc_ecma_parser" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9226cca2e6d482ffe48be00b83c9745b9e574d6d5833e1e3735837a502784af9" dependencies = [ "either", "enum_kind", @@ -2244,10 +2289,56 @@ dependencies = [ ] [[package]] -name = "swc_ecma_visit" -version = "0.9.0" +name = "swc_ecma_transforms" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb14e6a02ccd20b815f79b030b4372a12cb6a2b117a4794fb8d89c3fe1f78fc" +checksum = "f37a55159354623098b9a54893d26c655109833df807d846c54e34103a349a4f" +dependencies = [ + "Inflector", + "arrayvec", + "dashmap", + "either", + "fxhash", + "indexmap", + "is-macro", + "log 0.4.11", + "once_cell", + "ordered-float", + "regex", + "scoped-tls 1.0.0", + "serde", + "serde_json", + "smallvec 1.4.1", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_utils", + "swc_ecma_visit", + "unicode-xid 0.2.1", +] + +[[package]] +name = "swc_ecma_utils" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229c983a8e263edaf1b8ec5b79d92664d158303cc1fa4bff93690b6a2585e668" +dependencies = [ + "once_cell", + "scoped-tls 1.0.0", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_visit", + "unicode-xid 0.2.1", +] + +[[package]] +name = "swc_ecma_visit" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9516e5e423776d9ee88628b0caef0bcdab1aacf3e33469b7fc4fdfb9aa7e1617" dependencies = [ "num-bigint", "swc_atoms", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 3e1e1e75f0..076a4e6b01 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -23,7 +23,7 @@ winapi = "0.3.8" [dependencies] deno_core = { path = "../core", version = "0.50.0" } -deno_lint = "0.1.17" +deno_lint = "0.1.19" atty = "0.2.14" base64 = "0.12.2" @@ -50,6 +50,8 @@ serde_derive = "1.0.112" serde_json = { version = "1.0.55", features = [ "preserve_order" ] } sys-info = "0.7.0" sourcemap = "6.0.0" +swc_ecma_transforms = "=0.16.0" +swc_ecma_codegen = "=0.29.1" tempfile = "3.1.0" termcolor = "1.1.0" tokio = { version = "0.2.22", features = ["full"] } diff --git a/cli/global_state.rs b/cli/global_state.rs index 8e5808c903..a26fc453e0 100644 --- a/cli/global_state.rs +++ b/cli/global_state.rs @@ -174,10 +174,7 @@ impl GlobalState { if should_compile { if self.flags.no_check { - self - .ts_compiler - .transpile(self.clone(), permissions, module_graph) - .await?; + self.ts_compiler.transpile(module_graph).await?; } else { self .ts_compiler diff --git a/cli/swc_util.rs b/cli/swc_util.rs index 8203c4c3a3..d79f7cccbf 100644 --- a/cli/swc_util.rs +++ b/cli/swc_util.rs @@ -12,18 +12,29 @@ use crate::swc_common::Globals; use crate::swc_common::SourceMap; use crate::swc_common::Span; use crate::swc_ecma_ast; +use crate::swc_ecma_ast::Program; use crate::swc_ecma_parser::lexer::Lexer; use crate::swc_ecma_parser::EsConfig; use crate::swc_ecma_parser::JscTarget; use crate::swc_ecma_parser::Parser; -use crate::swc_ecma_parser::Session; use crate::swc_ecma_parser::SourceFileInput; use crate::swc_ecma_parser::Syntax; use crate::swc_ecma_parser::TsConfig; +use crate::swc_ecma_visit::FoldWith; +use deno_core::ErrBox; use std::error::Error; use std::fmt; use std::sync::Arc; use std::sync::RwLock; +use swc_common::chain; +use swc_ecma_codegen::text_writer::JsWriter; +use swc_ecma_codegen::Node; +use swc_ecma_transforms::fixer; +use swc_ecma_transforms::typescript; + +struct DummyHandler; + +impl swc_ecma_codegen::Handlers for DummyHandler {} fn get_default_es_config() -> EsConfig { let mut config = EsConfig::default(); @@ -179,34 +190,77 @@ impl AstParser { ); let buffered_err = self.buffered_error.clone(); - let session = Session { - handler: &self.handler, - }; - let syntax = get_syntax_for_media_type(media_type); let lexer = Lexer::new( - session, syntax, JscTarget::Es2019, SourceFileInput::from(&*swc_source_file), Some(&self.comments), ); - let mut parser = Parser::new_from(session, lexer); + let mut parser = Parser::new_from(lexer); - let parse_result = - parser - .parse_module() - .map_err(move |mut err: DiagnosticBuilder| { - err.emit(); - SwcDiagnosticBuffer::from_swc_error(buffered_err, self) - }); + let parse_result = parser.parse_module().map_err(move |err| { + let mut diagnostic = err.into_diagnostic(&self.handler); + diagnostic.emit(); + SwcDiagnosticBuffer::from_swc_error(buffered_err, self) + }); callback(parse_result) }) } + pub fn strip_types( + &self, + file_name: &str, + media_type: MediaType, + source_code: &str, + ) -> Result { + self.parse_module(file_name, media_type, source_code, |parse_result| { + let module = parse_result?; + let program = Program::Module(module); + let mut compiler_pass = chain!(typescript::strip(), fixer()); + let program = swc_ecma_transforms::util::COMMENTS + .set(&self.comments, || program.fold_with(&mut compiler_pass)); + + let mut src_map_buf = vec![]; + let mut buf = vec![]; + { + let handlers = Box::new(DummyHandler); + let writer = Box::new(JsWriter::new( + self.source_map.clone(), + "\n", + &mut buf, + Some(&mut src_map_buf), + )); + let config = swc_ecma_codegen::Config { minify: false }; + let mut emitter = swc_ecma_codegen::Emitter { + cfg: config, + comments: Some(&self.comments), + cm: self.source_map.clone(), + wr: writer, + handlers, + }; + program.emit_with(&mut emitter)?; + } + let mut src = String::from_utf8(buf).map_err(ErrBox::from)?; + { + let mut buf = vec![]; + self + .source_map + .build_source_map_from(&mut src_map_buf, None) + .to_writer(&mut buf)?; + let map = String::from_utf8(buf)?; + + src.push_str("//# sourceMappingURL=data:application/json;base64,"); + let encoded_map = base64::encode(map.as_bytes()); + src.push_str(&encoded_map); + } + Ok(src) + }) + } + pub fn get_span_location(&self, span: Span) -> swc_common::Loc { self.source_map.lookup_char_pos(span.lo()) } @@ -227,3 +281,14 @@ impl AstParser { } } } + +#[test] +fn test_strip_types() { + let ast_parser = AstParser::default(); + let result = ast_parser + .strip_types("test.ts", MediaType::TypeScript, "const a: number = 10;") + .unwrap(); + assert!(result.starts_with( + "const a = 10;\n//# sourceMappingURL=data:application/json;base64," + )); +} diff --git a/cli/tsc.rs b/cli/tsc.rs index b3d8aebd90..7bc70c786a 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -413,13 +413,6 @@ struct CompileResponse { build_info: Option, stats: Option>, } -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct TranspileResponse { - diagnostics: Diagnostic, - emit_map: HashMap, - stats: Option>, -} // TODO(bartlomieju): possible deduplicate once TS refactor is stabilized #[derive(Deserialize)] @@ -742,8 +735,6 @@ impl TsCompiler { pub async fn transpile( &self, - global_state: GlobalState, - permissions: Permissions, module_graph: ModuleGraph, ) -> Result<(), ErrBox> { let mut source_files: Vec = Vec::new(); @@ -762,44 +753,30 @@ impl TsCompiler { return Ok(()); } - let source_files_json = - serde_json::to_value(source_files).expect("Filed to serialize data"); - let compiler_config = self.config.clone(); - let cwd = std::env::current_dir().unwrap(); - let performance = - matches!(global_state.flags.log_level, Some(Level::Debug)); - let j = match (compiler_config.path, compiler_config.content) { - (Some(config_path), Some(config_data)) => json!({ - "config": str::from_utf8(&config_data).unwrap(), - "configPath": config_path, - "cwd": cwd, - "performance": performance, - "sourceFiles": source_files_json, - "type": msg::CompilerRequestType::Transpile, - }), - _ => json!({ - "performance": performance, - "sourceFiles": source_files_json, - "type": msg::CompilerRequestType::Transpile, - }), - }; + let mut emit_map = HashMap::new(); - let req_msg = j.to_string(); + for source_file in source_files { + let parser = AstParser::default(); + let stripped_source = parser.strip_types( + &source_file.file_name, + MediaType::TypeScript, + &source_file.source_code, + )?; - let json_str = - execute_in_same_thread(global_state.clone(), permissions, req_msg) - .await?; + // TODO(bartlomieju): this is superfluous, just to make caching function happy + let emitted_filename = PathBuf::from(&source_file.file_name) + .with_extension("js") + .to_string_lossy() + .to_string(); + let emitted_source = EmittedSource { + filename: source_file.file_name.to_string(), + contents: stripped_source, + }; - let transpile_response: TranspileResponse = - serde_json::from_str(&json_str)?; - - if !transpile_response.diagnostics.items.is_empty() { - return Err(ErrBox::from(transpile_response.diagnostics)); + emit_map.insert(emitted_filename, emitted_source); } - maybe_log_stats(transpile_response.stats); - - self.cache_emitted_files(transpile_response.emit_map)?; + self.cache_emitted_files(emit_map)?; Ok(()) } @@ -1710,9 +1687,7 @@ mod tests { ) .unwrap(); - let result = ts_compiler - .transpile(mock_state.clone(), Permissions::allow_all(), module_graph) - .await; + let result = ts_compiler.transpile(module_graph).await; assert!(result.is_ok()); let compiled_file = ts_compiler.get_compiled_module(&out.url).unwrap(); let source_code = compiled_file.code;