diff options
59 files changed, 886 insertions, 67 deletions
diff --git a/Cargo.lock b/Cargo.lock index 39ddd5cf3..283f785e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -213,6 +213,12 @@ dependencies = [ ] [[package]] +name = "build_const" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" + +[[package]] name = "bumpalo" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -316,6 +322,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" [[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +dependencies = [ + "build_const", +] + +[[package]] name = "crc32fast" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -430,6 +445,7 @@ dependencies = [ "semver-parser 0.9.0", "serde", "sourcemap", + "swc_bundler", "swc_common", "swc_ecmascript", "sys-info", @@ -662,6 +678,12 @@ dependencies = [ ] [[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + +[[package]] name = "flate2" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1476,6 +1498,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] +name = "petgraph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] name = "phf" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1639,6 +1671,12 @@ dependencies = [ ] [[package]] +name = "radix_fmt" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce082a9940a7ace2ad4a8b7d0b1eac6aa378895f18be598230c5f2284ac05426" + +[[package]] name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1829,6 +1867,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" [[package]] +name = "relative-path" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65aff7c83039e88c1c0b4bedf8dfa93d6ec84d5fc2945b37c1fa4186f46c5f94" + +[[package]] name = "remove_dir_all" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2226,6 +2270,32 @@ dependencies = [ ] [[package]] +name = "swc_bundler" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dabc79c5bf47498e16a01134846fbb677dd9c7233c591710587d76bd30cbe02" +dependencies = [ + "anyhow", + "crc", + "indexmap", + "is-macro", + "log", + "once_cell", + "petgraph", + "radix_fmt", + "relative-path", + "retain_mut", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_codegen", + "swc_ecma_parser", + "swc_ecma_transforms", + "swc_ecma_utils", + "swc_ecma_visit", +] + +[[package]] name = "swc_common" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 28ed44a8d..1cc568d5d 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -61,6 +61,7 @@ rustyline-derive = "0.3.1" serde = { version = "1.0.116", features = ["derive"] } sys-info = "0.7.0" sourcemap = "6.0.1" +swc_bundler = "=0.11.3" swc_common = { version = "=0.10.4", features = ["sourcemap"] } swc_ecmascript = { version = "=0.10.1", features = ["codegen", "dep_graph", "parser", "react", "transforms", "visit"] } tempfile = "3.1.0" diff --git a/cli/ast.rs b/cli/ast.rs index e3b45a6fd..95f243717 100644 --- a/cli/ast.rs +++ b/cli/ast.rs @@ -1,13 +1,14 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. use crate::media_type::MediaType; +use crate::tsc_config; use deno_core::error::AnyError; +use deno_core::serde_json; use deno_core::ModuleSpecifier; use std::error::Error; use std::fmt; use std::rc::Rc; -use std::result; use std::sync::Arc; use std::sync::RwLock; use swc_common::chain; @@ -21,6 +22,7 @@ use swc_common::errors::HandlerFlags; use swc_common::FileName; use swc_common::Globals; use swc_common::Loc; +use swc_common::SourceFile; use swc_common::SourceMap; use swc_common::Span; use swc_ecmascript::ast::Module; @@ -38,13 +40,11 @@ use swc_ecmascript::parser::TsConfig; use swc_ecmascript::transforms::fixer; use swc_ecmascript::transforms::helpers; use swc_ecmascript::transforms::pass::Optional; -use swc_ecmascript::transforms::proposals::decorators; +use swc_ecmascript::transforms::proposals; use swc_ecmascript::transforms::react; use swc_ecmascript::transforms::typescript; use swc_ecmascript::visit::FoldWith; -type Result<V> = result::Result<V, AnyError>; - static TARGET: JscTarget = JscTarget::Es2020; #[derive(Debug, Clone, Eq, PartialEq)] @@ -173,7 +173,10 @@ pub fn get_syntax(media_type: &MediaType) -> Syntax { /// Options which can be adjusted when transpiling a module. #[derive(Debug, Clone)] -pub struct TranspileOptions { +pub struct EmitOptions { + /// Indicate if JavaScript is being checked/transformed as well, or if it is + /// only TypeScript. + pub check_js: bool, /// When emitting a legacy decorator, also emit experimental decorator meta /// data. Defaults to `false`. pub emit_metadata: bool, @@ -190,9 +193,10 @@ pub struct TranspileOptions { pub transform_jsx: bool, } -impl Default for TranspileOptions { +impl Default for EmitOptions { fn default() -> Self { - TranspileOptions { + EmitOptions { + check_js: false, emit_metadata: false, inline_source_map: true, jsx_factory: "React.createElement".into(), @@ -202,6 +206,21 @@ impl Default for TranspileOptions { } } +impl From<tsc_config::TsConfig> for EmitOptions { + fn from(config: tsc_config::TsConfig) -> Self { + let options: tsc_config::EmitConfigOptions = + serde_json::from_value(config.0).unwrap(); + EmitOptions { + check_js: options.check_js, + emit_metadata: options.emit_decorator_metadata, + inline_source_map: true, + jsx_factory: options.jsx_factory, + jsx_fragment_factory: options.jsx_fragment_factory, + transform_jsx: options.jsx == "react", + } + } +} + /// A logical structure to hold the value of a parsed module for further /// processing. #[derive(Clone)] @@ -245,8 +264,8 @@ impl ParsedModule { /// The result is a tuple of the code and optional source map as strings. pub fn transpile( self, - options: &TranspileOptions, - ) -> Result<(String, Option<String>)> { + options: &EmitOptions, + ) -> Result<(String, Option<String>), AnyError> { let program = Program::Module(self.module); let jsx_pass = react::react( @@ -263,7 +282,7 @@ impl ParsedModule { ); let mut passes = chain!( Optional::new(jsx_pass, options.transform_jsx), - decorators::decorators(decorators::Config { + proposals::decorators::decorators(proposals::decorators::Config { legacy: true, emit_metadata: options.emit_metadata }), @@ -329,7 +348,7 @@ pub fn parse( specifier: &ModuleSpecifier, source: &str, media_type: &MediaType, -) -> Result<ParsedModule> { +) -> Result<ParsedModule, AnyError> { let source_map = SourceMap::default(); let source_file = source_map.new_source_file( FileName::Custom(specifier.to_string()), @@ -372,6 +391,95 @@ pub fn parse( }) } +/// A low level function which transpiles a source module into an swc +/// SourceFile. +pub fn transpile_module( + filename: &str, + src: &str, + media_type: &MediaType, + emit_options: &EmitOptions, + cm: Rc<SourceMap>, +) -> Result<(Rc<SourceFile>, Module), AnyError> { + // TODO(@kitsonk) DRY-up with ::parse() + let error_buffer = ErrorBuffer::new(); + let handler = Handler::with_emitter_and_flags( + Box::new(error_buffer.clone()), + HandlerFlags { + can_emit_warnings: true, + dont_buffer_diagnostics: true, + ..HandlerFlags::default() + }, + ); + let comments = SingleThreadedComments::default(); + let syntax = get_syntax(media_type); + let source_file = + cm.new_source_file(FileName::Custom(filename.to_string()), src.to_string()); + let lexer = Lexer::new( + syntax, + TARGET, + StringInput::from(&*source_file), + Some(&comments), + ); + let mut parser = swc_ecmascript::parser::Parser::new_from(lexer); + let sm = cm.clone(); + let module = parser.parse_module().map_err(move |err| { + let mut diagnostic = err.into_diagnostic(&handler); + diagnostic.emit(); + + DiagnosticBuffer::from_error_buffer(error_buffer, |span| { + sm.lookup_char_pos(span.lo) + }) + })?; + // TODO(@kitsonk) DRY-up with ::transpile() + let jsx_pass = react::react( + cm, + Some(&comments), + react::Options { + pragma: emit_options.jsx_factory.clone(), + pragma_frag: emit_options.jsx_fragment_factory.clone(), + // this will use `Object.assign()` instead of the `_extends` helper + // when spreading props. + use_builtins: true, + ..Default::default() + }, + ); + let mut passes = chain!( + Optional::new(jsx_pass, emit_options.transform_jsx), + proposals::decorators::decorators(proposals::decorators::Config { + legacy: true, + emit_metadata: emit_options.emit_metadata + }), + typescript::strip(), + fixer(Some(&comments)), + ); + let module = module.fold_with(&mut passes); + + Ok((source_file, module)) +} + +pub struct BundleHook; + +impl swc_bundler::Hook for BundleHook { + fn get_import_meta_url( + &self, + span: swc_common::Span, + file: &swc_common::FileName, + ) -> Result<Option<swc_ecmascript::ast::Expr>, AnyError> { + // we use custom file names, and swc "wraps" these in `<` and `>` so, we + // want to strip those back out. + let mut value = file.to_string(); + value.pop(); + value.remove(0); + Ok(Some(swc_ecmascript::ast::Expr::Lit( + swc_ecmascript::ast::Lit::Str(swc_ecmascript::ast::Str { + span, + value: value.into(), + has_escape: false, + }), + ))) + } +} + #[cfg(test)] mod tests { use super::*; @@ -436,7 +544,7 @@ mod tests { let module = parse(&specifier, source, &MediaType::TypeScript) .expect("could not parse module"); let (code, maybe_map) = module - .transpile(&TranspileOptions::default()) + .transpile(&EmitOptions::default()) .expect("could not strip types"); assert!(code.starts_with("var D;\n(function(D) {\n")); assert!( @@ -460,7 +568,7 @@ mod tests { let module = parse(&specifier, source, &MediaType::TSX) .expect("could not parse module"); let (code, _) = module - .transpile(&TranspileOptions::default()) + .transpile(&EmitOptions::default()) .expect("could not strip types"); assert!(code.contains("React.createElement(\"div\", null")); } @@ -491,7 +599,7 @@ mod tests { let module = parse(&specifier, source, &MediaType::TypeScript) .expect("could not parse module"); let (code, _) = module - .transpile(&TranspileOptions::default()) + .transpile(&EmitOptions::default()) .expect("could not strip types"); assert!(code.contains("_applyDecoratedDescriptor(")); } diff --git a/cli/flags.rs b/cli/flags.rs index 0f55b370f..63bad9f14 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -402,14 +402,7 @@ fn install_parse(flags: &mut Flags, matches: &clap::ArgMatches) { } fn bundle_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - // TODO(nayeemrmn): Replace the next couple lines with `compile_args_parse()` - // once `deno bundle --no-check` is supported. - importmap_arg_parse(flags, matches); - no_remote_arg_parse(flags, matches); - config_arg_parse(flags, matches); - reload_arg_parse(flags, matches); - lock_args_parse(flags, matches); - ca_file_arg_parse(flags, matches); + compile_args_parse(flags, matches); let source_file = matches.value_of("source_file").unwrap().to_string(); @@ -776,16 +769,7 @@ These must be added to the path manually if required.") } fn bundle_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("bundle") - // TODO(nayeemrmn): Replace the next couple lines with `compile_args()` once - // `deno bundle --no-check` is supported. - .arg(importmap_arg()) - .arg(no_remote_arg()) - .arg(config_arg()) - .arg(reload_arg()) - .arg(lock_arg()) - .arg(lock_write_arg()) - .arg(ca_file_arg()) + compile_args(SubCommand::with_name("bundle")) .arg( Arg::with_name("source_file") .takes_value(true) @@ -2354,6 +2338,24 @@ mod tests { } #[test] + fn bundle_nocheck() { + let r = + flags_from_vec_safe(svec!["deno", "bundle", "--no-check", "script.ts"]) + .unwrap(); + assert_eq!( + r, + Flags { + subcommand: DenoSubcommand::Bundle { + source_file: "script.ts".to_string(), + out_file: None, + }, + no_check: true, + ..Flags::default() + } + ); + } + + #[test] fn run_importmap() { let r = flags_from_vec_safe(svec![ "deno", diff --git a/cli/main.rs b/cli/main.rs index 48e76d9ab..1e174abd7 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -65,6 +65,7 @@ use crate::fs as deno_fs; use crate::media_type::MediaType; use crate::permissions::Permissions; use crate::program_state::ProgramState; +use crate::specifier_handler::FetchHandler; use crate::worker::MainWorker; use deno_core::error::AnyError; use deno_core::futures::future::FutureExt; @@ -304,7 +305,7 @@ async fn bundle_command( let module_specifier = ModuleSpecifier::resolve_url_or_path(&source_file)?; debug!(">>>>> bundle START"); - let program_state = ProgramState::new(flags)?; + let program_state = ProgramState::new(flags.clone())?; info!( "{} {}", @@ -312,10 +313,36 @@ async fn bundle_command( module_specifier.to_string() ); - let output = program_state - .ts_compiler - .bundle(&program_state, module_specifier) - .await?; + let output = if flags.no_check { + let handler = Rc::new(RefCell::new(FetchHandler::new( + &program_state, + Permissions::allow_all(), + )?)); + let mut builder = module_graph2::GraphBuilder2::new( + handler, + program_state.maybe_import_map.clone(), + ); + builder.insert(&module_specifier).await?; + let graph = builder.get_graph(&program_state.lockfile)?; + + let (s, stats, maybe_ignored_options) = + graph.bundle(module_graph2::BundleOptions { + debug: flags.log_level == Some(Level::Debug), + maybe_config_path: flags.config_path, + })?; + + if let Some(ignored_options) = maybe_ignored_options { + eprintln!("{}", ignored_options); + } + debug!("{}", stats); + + s + } else { + program_state + .ts_compiler + .bundle(&program_state, module_specifier) + .await? + }; debug!(">>>>> bundle END"); diff --git a/cli/module_graph2.rs b/cli/module_graph2.rs index 681cc3bb5..e2dcdfefc 100644 --- a/cli/module_graph2.rs +++ b/cli/module_graph2.rs @@ -1,7 +1,9 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use crate::ast; use crate::ast::parse; +use crate::ast::transpile_module; +use crate::ast::BundleHook; +use crate::ast::EmitOptions; use crate::ast::Location; use crate::ast::ParsedModule; use crate::import_map::ImportMap; @@ -21,6 +23,7 @@ use crate::tsc_config::TsConfig; use crate::version; use crate::AnyError; +use deno_core::error::Context; use deno_core::futures::stream::FuturesUnordered; use deno_core::futures::stream::StreamExt; use deno_core::serde_json::json; @@ -38,7 +41,6 @@ use std::rc::Rc; use std::result; use std::sync::Mutex; use std::time::Instant; -use swc_ecmascript::dep_graph::DependencyKind; lazy_static! { /// Matched the `@deno-types` pragma. @@ -108,6 +110,59 @@ impl fmt::Display for GraphError { impl Error for GraphError {} +/// A structure for handling bundle loading, which is implemented here, to +/// avoid a circular dependency with `ast`. +struct BundleLoader<'a> { + cm: Rc<swc_common::SourceMap>, + graph: &'a Graph2, + emit_options: &'a EmitOptions, +} + +impl<'a> BundleLoader<'a> { + pub fn new( + graph: &'a Graph2, + emit_options: &'a EmitOptions, + cm: Rc<swc_common::SourceMap>, + ) -> Self { + BundleLoader { + cm, + graph, + emit_options, + } + } +} + +impl swc_bundler::Load for BundleLoader<'_> { + fn load( + &self, + file: &swc_common::FileName, + ) -> Result<(Rc<swc_common::SourceFile>, swc_ecmascript::ast::Module), AnyError> + { + match file { + swc_common::FileName::Custom(filename) => { + let specifier = ModuleSpecifier::resolve_url_or_path(filename) + .context("Failed to convert swc FileName to ModuleSpecifier.")?; + if let Some(src) = self.graph.get_source(&specifier) { + let media_type = self + .graph + .get_media_type(&specifier) + .context("Looking up media type during bundling.")?; + transpile_module( + filename, + &src, + &media_type, + self.emit_options, + self.cm.clone(), + ) + } else { + Err(MissingDependency(specifier, "<bundle>".to_string()).into()) + } + } + _ => unreachable!("Received request for unsupported filename {:?}", file), + } + } +} + /// An enum which represents the parsed out values of references in source code. #[derive(Debug, Clone, Eq, PartialEq)] enum TypeScriptReference { @@ -273,10 +328,9 @@ impl Module { // Parse out all the syntactical dependencies for a module let dependencies = parsed_module.analyze_dependencies(); - for desc in dependencies - .iter() - .filter(|desc| desc.kind != DependencyKind::Require) - { + for desc in dependencies.iter().filter(|desc| { + desc.kind != swc_ecmascript::dep_graph::DependencyKind::Require + }) { let location = Location { filename: self.specifier.to_string(), col: desc.col, @@ -301,8 +355,8 @@ impl Module { .dependencies .entry(desc.specifier.to_string()) .or_default(); - if desc.kind == DependencyKind::ExportType - || desc.kind == DependencyKind::ImportType + if desc.kind == swc_ecmascript::dep_graph::DependencyKind::ExportType + || desc.kind == swc_ecmascript::dep_graph::DependencyKind::ImportType { dep.maybe_type = Some(specifier); } else { @@ -392,6 +446,12 @@ impl fmt::Display for Stats { } } +#[derive(Debug, Default)] +pub struct BundleOptions { + pub debug: bool, + pub maybe_config_path: Option<String>, +} + /// A structure which provides options when transpiling modules. #[derive(Debug, Default)] pub struct TranspileOptions { @@ -431,6 +491,76 @@ impl Graph2 { } } + /// Transform the module graph into a single JavaScript module which is + /// returned as a `String` in the result. + pub fn bundle( + &self, + options: BundleOptions, + ) -> Result<(String, Stats, Option<IgnoredCompilerOptions>), AnyError> { + if self.roots.is_empty() || self.roots.len() > 1 { + return Err(NotSupported(format!("Bundling is only supported when there is a single root module in the graph. Found: {}", self.roots.len())).into()); + } + + let start = Instant::now(); + let root_specifier = self.roots[0].clone(); + let mut ts_config = TsConfig::new(json!({ + "checkJs": false, + "emitDecoratorMetadata": false, + "jsx": "react", + "jsxFactory": "React.createElement", + "jsxFragmentFactory": "React.Fragment", + })); + let maybe_ignored_options = + ts_config.merge_user_config(options.maybe_config_path)?; + let emit_options: EmitOptions = ts_config.into(); + let cm = Rc::new(swc_common::SourceMap::new( + swc_common::FilePathMapping::empty(), + )); + let loader = BundleLoader::new(self, &emit_options, cm.clone()); + let hook = Box::new(BundleHook); + let globals = swc_common::Globals::new(); + let bundler = swc_bundler::Bundler::new( + &globals, + cm.clone(), + loader, + self, + swc_bundler::Config::default(), + hook, + ); + let mut entries = HashMap::new(); + entries.insert( + "bundle".to_string(), + swc_common::FileName::Custom(root_specifier.to_string()), + ); + let output = bundler + .bundle(entries) + .context("Unable to output bundle during Graph2::bundle().")?; + let mut buf = Vec::new(); + { + let mut emitter = swc_ecmascript::codegen::Emitter { + cfg: swc_ecmascript::codegen::Config { minify: false }, + cm: cm.clone(), + comments: None, + wr: Box::new(swc_ecmascript::codegen::text_writer::JsWriter::new( + cm, "\n", &mut buf, None, + )), + }; + + emitter + .emit_module(&output[0].module) + .context("Unable to emit bundle during Graph2::bundle().")?; + } + + let s = String::from_utf8(buf) + .context("Emitted bundle is an invalid utf-8 string.")?; + let stats = Stats(vec![ + ("Files".to_string(), self.modules.len() as u128), + ("Total time".to_string(), start.elapsed().as_millis()), + ]); + + Ok((s, stats, maybe_ignored_options)) + } + fn contains_module(&self, specifier: &ModuleSpecifier) -> bool { let s = self.resolve_specifier(specifier); self.modules.contains_key(s) @@ -725,16 +855,7 @@ impl Graph2 { let maybe_ignored_options = ts_config.merge_user_config(options.maybe_config_path)?; - let compiler_options = ts_config.as_transpile_config()?; - let check_js = compiler_options.check_js; - let transform_jsx = compiler_options.jsx == "react"; - let emit_options = ast::TranspileOptions { - emit_metadata: compiler_options.emit_decorator_metadata, - inline_source_map: true, - jsx_factory: compiler_options.jsx_factory, - jsx_fragment_factory: compiler_options.jsx_fragment_factory, - transform_jsx, - }; + let emit_options: EmitOptions = ts_config.clone().into(); let mut emit_count: u128 = 0; for (_, module) in self.modules.iter_mut() { @@ -748,7 +869,7 @@ impl Graph2 { } // if we don't have check_js enabled, we won't touch non TypeScript // modules - if !(check_js + if !(emit_options.check_js || module.media_type == MediaType::TSX || module.media_type == MediaType::TypeScript) { @@ -781,6 +902,27 @@ impl Graph2 { } } +impl swc_bundler::Resolve for Graph2 { + fn resolve( + &self, + referrer: &swc_common::FileName, + specifier: &str, + ) -> Result<swc_common::FileName, AnyError> { + let referrer = if let swc_common::FileName::Custom(referrer) = referrer { + ModuleSpecifier::resolve_url_or_path(referrer) + .context("Cannot resolve swc FileName to a module specifier")? + } else { + unreachable!( + "An unexpected referrer was passed when bundling: {:?}", + referrer + ) + }; + let specifier = self.resolve(specifier, &referrer)?; + + Ok(swc_common::FileName::Custom(specifier.to_string())) + } +} + /// A structure for building a dependency graph of modules. pub struct GraphBuilder2 { fetched: HashSet<ModuleSpecifier>, @@ -1095,6 +1237,50 @@ pub mod tests { } #[tokio::test] + async fn test_graph_bundle() { + let tests = vec![ + ("file:///tests/fixture01.ts", "fixture01.out"), + ("file:///tests/fixture02.ts", "fixture02.out"), + ("file:///tests/fixture03.ts", "fixture03.out"), + ("file:///tests/fixture04.ts", "fixture04.out"), + ("file:///tests/fixture05.ts", "fixture05.out"), + ("file:///tests/fixture06.ts", "fixture06.out"), + ("file:///tests/fixture07.ts", "fixture07.out"), + ("file:///tests/fixture08.ts", "fixture08.out"), + ("file:///tests/fixture09.ts", "fixture09.out"), + ("file:///tests/fixture10.ts", "fixture10.out"), + ("file:///tests/fixture11.ts", "fixture11.out"), + ("file:///tests/fixture12.ts", "fixture12.out"), + ("file:///tests/fixture13.ts", "fixture13.out"), + ("file:///tests/fixture14.ts", "fixture14.out"), + ]; + let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); + let fixtures = c.join("tests/bundle"); + + for (specifier, expected_str) in tests { + let specifier = ModuleSpecifier::resolve_url_or_path(specifier).unwrap(); + let handler = Rc::new(RefCell::new(MockSpecifierHandler { + fixtures: fixtures.clone(), + ..MockSpecifierHandler::default() + })); + let mut builder = GraphBuilder2::new(handler.clone(), None); + builder + .insert(&specifier) + .await + .expect("module not inserted"); + let graph = builder.get_graph(&None).expect("could not get graph"); + let (actual, stats, maybe_ignored_options) = graph + .bundle(BundleOptions::default()) + .expect("could not bundle"); + assert_eq!(stats.0.len(), 2); + assert_eq!(maybe_ignored_options, None); + let expected_path = fixtures.join(expected_str); + let expected = fs::read_to_string(expected_path).unwrap(); + assert_eq!(actual, expected, "fixture: {}", specifier); + } + } + + #[tokio::test] async fn test_graph_info() { let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); let fixtures = c.join("tests/module_graph"); diff --git a/cli/tests/bundle/file_tests-fixture01.ts b/cli/tests/bundle/file_tests-fixture01.ts new file mode 100644 index 000000000..3598d0298 --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture01.ts @@ -0,0 +1,3 @@ +import * as a from "./subdir/a.ts"; + +console.log(a); diff --git a/cli/tests/bundle/file_tests-fixture02.ts b/cli/tests/bundle/file_tests-fixture02.ts new file mode 100644 index 000000000..0cd291329 --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture02.ts @@ -0,0 +1,4 @@ +import * as b from "./subdir/b.ts"; + +console.log(b.b); // "b" +console.log(b.c); // { c: "c", default: class C } diff --git a/cli/tests/bundle/file_tests-fixture03.ts b/cli/tests/bundle/file_tests-fixture03.ts new file mode 100644 index 000000000..78365ce13 --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture03.ts @@ -0,0 +1,3 @@ +import { d } from "./subdir/d.ts"; + +console.log(d); diff --git a/cli/tests/bundle/file_tests-fixture04.ts b/cli/tests/bundle/file_tests-fixture04.ts new file mode 100644 index 000000000..590f4fef9 --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture04.ts @@ -0,0 +1,3 @@ +const a = await import("./subdir/a.ts"); + +console.log(a); diff --git a/cli/tests/bundle/file_tests-fixture05.ts b/cli/tests/bundle/file_tests-fixture05.ts new file mode 100644 index 000000000..19541ce59 --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture05.ts @@ -0,0 +1,3 @@ +import { a } from "./subdir/e.ts"; + +console.log(a); diff --git a/cli/tests/bundle/file_tests-fixture06.ts b/cli/tests/bundle/file_tests-fixture06.ts new file mode 100644 index 000000000..3d94332df --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture06.ts @@ -0,0 +1,4 @@ +import { isMain, modUrl } from "./subdir/f.ts"; + +console.log(isMain, modUrl); +console.log(import.meta.main, import.meta.url); diff --git a/cli/tests/bundle/file_tests-fixture07.ts b/cli/tests/bundle/file_tests-fixture07.ts new file mode 100644 index 000000000..0475a6c53 --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture07.ts @@ -0,0 +1,4 @@ +import { G } from "./subdir/g.ts"; +import { H } from "./subdir/h.ts"; + +console.log(new G(true), new H(true)); diff --git a/cli/tests/bundle/file_tests-fixture08.ts b/cli/tests/bundle/file_tests-fixture08.ts new file mode 100644 index 000000000..6af5d172e --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture08.ts @@ -0,0 +1 @@ +export * as a from "./subdir/a.ts"; diff --git a/cli/tests/bundle/file_tests-fixture09.ts b/cli/tests/bundle/file_tests-fixture09.ts new file mode 100644 index 000000000..30ba983ee --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture09.ts @@ -0,0 +1 @@ +export { a } from "./subdir/k.ts"; diff --git a/cli/tests/bundle/file_tests-fixture10.ts b/cli/tests/bundle/file_tests-fixture10.ts new file mode 100644 index 000000000..bec555da8 --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture10.ts @@ -0,0 +1,7 @@ +import { a as defaultA } from "./subdir/l.ts"; + +const o: { a?: string } = {}; + +const { a = defaultA } = o; + +console.log(a); diff --git a/cli/tests/bundle/file_tests-fixture11.ts b/cli/tests/bundle/file_tests-fixture11.ts new file mode 100644 index 000000000..d3f60d367 --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture11.ts @@ -0,0 +1,32 @@ +import { a as defaultA, O } from "./subdir/m.ts"; +export { O } from "./subdir/m.ts"; + +interface AOptions { + a?(): void; + c?: O; +} + +class A { + #a: () => void; + #c?: O; + constructor(o: AOptions = {}) { + const { + a = defaultA, + c, + } = o; + this.#a = a; + this.#c = c; + } + + a() { + this.#a(); + } + + c() { + console.log(this.#c); + } +} + +const a = new A(); +a.a(); +a.c(); diff --git a/cli/tests/bundle/file_tests-fixture12.ts b/cli/tests/bundle/file_tests-fixture12.ts new file mode 100644 index 000000000..32b9566bd --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture12.ts @@ -0,0 +1,7 @@ +import { a } from "./subdir/p.ts"; + +function b() { + a(); +} + +b(); diff --git a/cli/tests/bundle/file_tests-fixture13.ts b/cli/tests/bundle/file_tests-fixture13.ts new file mode 100644 index 000000000..7dc13534c --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture13.ts @@ -0,0 +1,11 @@ +import { D, d } from "./subdir/q.ts"; + +class A { + private s: D = d(); + + a() { + this.s.resolve(); + } +} + +new A(); diff --git a/cli/tests/bundle/file_tests-fixture14.ts b/cli/tests/bundle/file_tests-fixture14.ts new file mode 100644 index 000000000..aa8eef1b8 --- /dev/null +++ b/cli/tests/bundle/file_tests-fixture14.ts @@ -0,0 +1,4 @@ +// @deno-types="https://deno.land/x/lib/mod.d.ts" +import * as lib from "https://deno.land/x/lib/mod.js"; + +console.log(lib); diff --git a/cli/tests/bundle/file_tests-subdir-a.ts b/cli/tests/bundle/file_tests-subdir-a.ts new file mode 100644 index 000000000..9233cce2f --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-a.ts @@ -0,0 +1 @@ +export const a = "a"; diff --git a/cli/tests/bundle/file_tests-subdir-b.ts b/cli/tests/bundle/file_tests-subdir-b.ts new file mode 100644 index 000000000..1cf751c22 --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-b.ts @@ -0,0 +1,3 @@ +export * as c from "./c.ts"; + +export const b = "b"; diff --git a/cli/tests/bundle/file_tests-subdir-c.ts b/cli/tests/bundle/file_tests-subdir-c.ts new file mode 100644 index 000000000..7cc01f993 --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-c.ts @@ -0,0 +1,2 @@ +export const c = "c"; +export default class C {} diff --git a/cli/tests/bundle/file_tests-subdir-d.ts b/cli/tests/bundle/file_tests-subdir-d.ts new file mode 100644 index 000000000..9f1ba7f67 --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-d.ts @@ -0,0 +1,3 @@ +import { a } from "./a.ts"; + +export const d = { a }; diff --git a/cli/tests/bundle/file_tests-subdir-e.ts b/cli/tests/bundle/file_tests-subdir-e.ts new file mode 100644 index 000000000..55e8e0e18 --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-e.ts @@ -0,0 +1 @@ +export * from "./a.ts"; diff --git a/cli/tests/bundle/file_tests-subdir-f.ts b/cli/tests/bundle/file_tests-subdir-f.ts new file mode 100644 index 000000000..8bc8d9bf4 --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-f.ts @@ -0,0 +1,2 @@ +export const isMain = import.meta.main; +export const modUrl = import.meta.url; diff --git a/cli/tests/bundle/file_tests-subdir-g.ts b/cli/tests/bundle/file_tests-subdir-g.ts new file mode 100644 index 000000000..3eb4cd3cc --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-g.ts @@ -0,0 +1,12 @@ +const g: number[] = []; + +export class G { + #g!: number[]; + constructor(shared: boolean) { + if (shared) { + this.#g = g; + } else { + this.#g = []; + } + } +} diff --git a/cli/tests/bundle/file_tests-subdir-h.ts b/cli/tests/bundle/file_tests-subdir-h.ts new file mode 100644 index 000000000..9c86dd5c5 --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-h.ts @@ -0,0 +1,12 @@ +const g: number[] = []; + +export class H { + #g!: number[]; + constructor(shared: boolean) { + if (shared) { + this.#g = g; + } else { + this.#g = []; + } + } +} diff --git a/cli/tests/bundle/file_tests-subdir-i.ts b/cli/tests/bundle/file_tests-subdir-i.ts new file mode 100644 index 000000000..4ad9ce449 --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-i.ts @@ -0,0 +1,3 @@ +export function a(...d: string[]): string { + return d.join(" "); +} diff --git a/cli/tests/bundle/file_tests-subdir-j.ts b/cli/tests/bundle/file_tests-subdir-j.ts new file mode 100644 index 000000000..ac7bce0ea --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-j.ts @@ -0,0 +1,3 @@ +export function a(...d: string[]): string { + return d.join("/"); +} diff --git a/cli/tests/bundle/file_tests-subdir-k.ts b/cli/tests/bundle/file_tests-subdir-k.ts new file mode 100644 index 000000000..1b8a533f1 --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-k.ts @@ -0,0 +1,11 @@ +import * as _i from "./i.ts"; +import * as _j from "./j.ts"; + +const k = globalThis.value ? _i : _j; + +export const i = _i; +export const j = _j; + +export const { + a, +} = k; diff --git a/cli/tests/bundle/file_tests-subdir-l.ts b/cli/tests/bundle/file_tests-subdir-l.ts new file mode 100644 index 000000000..d767e6ad0 --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-l.ts @@ -0,0 +1 @@ +export { a } from "./a.ts"; diff --git a/cli/tests/bundle/file_tests-subdir-m.ts b/cli/tests/bundle/file_tests-subdir-m.ts new file mode 100644 index 000000000..21e86d07c --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-m.ts @@ -0,0 +1,2 @@ +export { a } from "./n.ts"; +export { O } from "./o.ts"; diff --git a/cli/tests/bundle/file_tests-subdir-n.ts b/cli/tests/bundle/file_tests-subdir-n.ts new file mode 100644 index 000000000..ac3c37005 --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-n.ts @@ -0,0 +1,3 @@ +export function a() { + console.log("a"); +} diff --git a/cli/tests/bundle/file_tests-subdir-o.ts b/cli/tests/bundle/file_tests-subdir-o.ts new file mode 100644 index 000000000..ab9753fea --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-o.ts @@ -0,0 +1,5 @@ +export enum O { + A, + B, + C, +} diff --git a/cli/tests/bundle/file_tests-subdir-p.ts b/cli/tests/bundle/file_tests-subdir-p.ts new file mode 100644 index 000000000..19b486f71 --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-p.ts @@ -0,0 +1 @@ +export * from "./i.ts"; diff --git a/cli/tests/bundle/file_tests-subdir-q.ts b/cli/tests/bundle/file_tests-subdir-q.ts new file mode 100644 index 000000000..9e5d4da37 --- /dev/null +++ b/cli/tests/bundle/file_tests-subdir-q.ts @@ -0,0 +1,13 @@ +/* eslint-disable */ +export interface D { + resolve: any; + reject: any; +} + +export function d(): D { + let methods; + const promise = new Promise((resolve, reject) => { + methods = { resolve, reject }; + }); + return Object.assign(promise, methods); +} diff --git a/cli/tests/bundle/fixture01.out b/cli/tests/bundle/fixture01.out new file mode 100644 index 000000000..e29d0d38a --- /dev/null +++ b/cli/tests/bundle/fixture01.out @@ -0,0 +1,7 @@ +const a = function() { + const a = "a"; + return { + a + }; +}(); +console.log(a); diff --git a/cli/tests/bundle/fixture02.out b/cli/tests/bundle/fixture02.out new file mode 100644 index 000000000..41880e73d --- /dev/null +++ b/cli/tests/bundle/fixture02.out @@ -0,0 +1,11 @@ +const c = function() { + const c1 = "c"; + class C { + } + return { + c: c1, + default: C + }; +}(); +console.log("b"); +console.log(c); diff --git a/cli/tests/bundle/fixture03.out b/cli/tests/bundle/fixture03.out new file mode 100644 index 000000000..d4c79e2ec --- /dev/null +++ b/cli/tests/bundle/fixture03.out @@ -0,0 +1,4 @@ +const d = { + a: "a" +}; +console.log(d); diff --git a/cli/tests/bundle/fixture04.out b/cli/tests/bundle/fixture04.out new file mode 100644 index 000000000..37869205b --- /dev/null +++ b/cli/tests/bundle/fixture04.out @@ -0,0 +1,2 @@ +const a = await import("./subdir/a.ts"); +console.log(a); diff --git a/cli/tests/bundle/fixture05.out b/cli/tests/bundle/fixture05.out new file mode 100644 index 000000000..7b2a34601 --- /dev/null +++ b/cli/tests/bundle/fixture05.out @@ -0,0 +1 @@ +console.log("a"); diff --git a/cli/tests/bundle/fixture06.out b/cli/tests/bundle/fixture06.out new file mode 100644 index 000000000..057c5b820 --- /dev/null +++ b/cli/tests/bundle/fixture06.out @@ -0,0 +1,2 @@ +console.log(false, "file:///tests/subdir/f.ts"); +console.log(import.meta.main, "file:///tests/fixture06.ts"); diff --git a/cli/tests/bundle/fixture07.out b/cli/tests/bundle/fixture07.out new file mode 100644 index 000000000..39e6a11e8 --- /dev/null +++ b/cli/tests/bundle/fixture07.out @@ -0,0 +1,23 @@ +const g = []; +class G { + #g; + constructor(shared){ + if (shared) { + this.#g = g; + } else { + this.#g = []; + } + } +} +const g1 = []; +class H { + #g; + constructor(shared1){ + if (shared1) { + this.#g = g1; + } else { + this.#g = []; + } + } +} +console.log(new G(true), new H(true)); diff --git a/cli/tests/bundle/fixture08.out b/cli/tests/bundle/fixture08.out new file mode 100644 index 000000000..f9435ab2a --- /dev/null +++ b/cli/tests/bundle/fixture08.out @@ -0,0 +1,7 @@ +const a = function() { + const a1 = "a"; + return { + a: a1 + }; +}(); +export { a }; diff --git a/cli/tests/bundle/fixture09.out b/cli/tests/bundle/fixture09.out new file mode 100644 index 000000000..7f9646946 --- /dev/null +++ b/cli/tests/bundle/fixture09.out @@ -0,0 +1,19 @@ +const _i = function() { + function a(...d) { + return d.join(" "); + } + return { + a + }; +}(); +const _j = function() { + function a(...d) { + return d.join("/"); + } + return { + a + }; +}(); +const k = globalThis.value ? _i : _j; +const { a , } = k; +export { a }; diff --git a/cli/tests/bundle/fixture10.out b/cli/tests/bundle/fixture10.out new file mode 100644 index 000000000..7436722b5 --- /dev/null +++ b/cli/tests/bundle/fixture10.out @@ -0,0 +1,4 @@ +const o = { +}; +const { a ="a" } = o; +console.log(a); diff --git a/cli/tests/bundle/fixture11.out b/cli/tests/bundle/fixture11.out new file mode 100644 index 000000000..2d1c966a1 --- /dev/null +++ b/cli/tests/bundle/fixture11.out @@ -0,0 +1,31 @@ +function a() { + console.log("a"); +} +var O; +(function(O1) { + O1[O1["A"] = 0] = "A"; + O1[O1["B"] = 1] = "B"; + O1[O1["C"] = 2] = "C"; +})((void 0) || (O = { +})); +const O1 = void 0; +export { O1 as O }; +class A { + #a; + #c; + constructor(o = { + }){ + const { a: a1 = a , c , } = o; + this.#a = a1; + this.#c = c; + } + a() { + this.#a(); + } + c() { + console.log(this.#c); + } +} +const a2 = new A(); +a2.a(); +a2.c(); diff --git a/cli/tests/bundle/fixture12.out b/cli/tests/bundle/fixture12.out new file mode 100644 index 000000000..64e2d6cdb --- /dev/null +++ b/cli/tests/bundle/fixture12.out @@ -0,0 +1,7 @@ +function a(...d) { + return d.join(" "); +} +function b() { + a(); +} +b(); diff --git a/cli/tests/bundle/fixture13.out b/cli/tests/bundle/fixture13.out new file mode 100644 index 000000000..1c7a8c991 --- /dev/null +++ b/cli/tests/bundle/fixture13.out @@ -0,0 +1,17 @@ +function d() { + let methods; + const promise = new Promise((resolve, reject)=>{ + methods = { + resolve, + reject + }; + }); + return Object.assign(promise, methods); +} +class A { + s = d(); + a() { + this.s.resolve(); + } +} +new A(); diff --git a/cli/tests/bundle/fixture14.out b/cli/tests/bundle/fixture14.out new file mode 100644 index 000000000..06e93a7cc --- /dev/null +++ b/cli/tests/bundle/fixture14.out @@ -0,0 +1,25 @@ +const lib = function() { + const a = function() { + const a1 = []; + return { + a: a1 + }; + }(); + const b = function() { + const b1 = []; + return { + b: b1 + }; + }(); + const c = function() { + const c1; + return { + c: c1 + }; + }(); + const mod; + return { + mod + }; +}(); +console.log(lib); diff --git a/cli/tests/bundle/https_deno.land-x-lib-a.ts b/cli/tests/bundle/https_deno.land-x-lib-a.ts new file mode 100644 index 000000000..a0a6f8e94 --- /dev/null +++ b/cli/tests/bundle/https_deno.land-x-lib-a.ts @@ -0,0 +1 @@ +export const a: string[] = []; diff --git a/cli/tests/bundle/https_deno.land-x-lib-b.js b/cli/tests/bundle/https_deno.land-x-lib-b.js new file mode 100644 index 000000000..13cacdd8b --- /dev/null +++ b/cli/tests/bundle/https_deno.land-x-lib-b.js @@ -0,0 +1 @@ +export const b = []; diff --git a/cli/tests/bundle/https_deno.land-x-lib-c.d.ts b/cli/tests/bundle/https_deno.land-x-lib-c.d.ts new file mode 100644 index 000000000..fac988e49 --- /dev/null +++ b/cli/tests/bundle/https_deno.land-x-lib-c.d.ts @@ -0,0 +1 @@ +export const c: string[]; diff --git a/cli/tests/bundle/https_deno.land-x-lib-c.js b/cli/tests/bundle/https_deno.land-x-lib-c.js new file mode 100644 index 000000000..620ca0b66 --- /dev/null +++ b/cli/tests/bundle/https_deno.land-x-lib-c.js @@ -0,0 +1,3 @@ +/// <reference types="./c.d.ts" /> + +export const c = []; diff --git a/cli/tests/bundle/https_deno.land-x-lib-mod.d.ts b/cli/tests/bundle/https_deno.land-x-lib-mod.d.ts new file mode 100644 index 000000000..76ed81df0 --- /dev/null +++ b/cli/tests/bundle/https_deno.land-x-lib-mod.d.ts @@ -0,0 +1,9 @@ +export * as a from "./a.ts"; +export * as b from "./b.js"; +export * as c from "./c.js"; + +export interface A { + a: string; +} + +export const mod: A[]; diff --git a/cli/tests/bundle/https_deno.land-x-lib-mod.js b/cli/tests/bundle/https_deno.land-x-lib-mod.js new file mode 100644 index 000000000..505162094 --- /dev/null +++ b/cli/tests/bundle/https_deno.land-x-lib-mod.js @@ -0,0 +1,5 @@ +export * as a from "./a.ts"; +export * as b from "./b.js"; +export * as c from "./c.js"; + +export const mod = []; diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs index 51eb922d9..d7786e966 100644 --- a/cli/tests/integration_tests.rs +++ b/cli/tests/integration_tests.rs @@ -839,6 +839,49 @@ fn bundle_exports() { } #[test] +fn bundle_exports_no_check() { + // First we have to generate a bundle of some module that has exports. + let mod1 = util::root_path().join("cli/tests/subdir/mod1.ts"); + assert!(mod1.is_file()); + let t = TempDir::new().expect("tempdir fail"); + let bundle = t.path().join("mod1.bundle.js"); + let mut deno = util::deno_cmd() + .current_dir(util::root_path()) + .arg("bundle") + .arg("--no-check") + .arg(mod1) + .arg(&bundle) + .spawn() + .expect("failed to spawn script"); + let status = deno.wait().expect("failed to wait for the child process"); + assert!(status.success()); + assert!(bundle.is_file()); + + // Now we try to use that bundle from another module. + let test = t.path().join("test.js"); + std::fs::write( + &test, + " + import { printHello3 } from \"./mod1.bundle.js\"; + printHello3(); ", + ) + .expect("error writing file"); + + let output = util::deno_cmd() + .current_dir(util::root_path()) + .arg("run") + .arg(&test) + .output() + .expect("failed to spawn script"); + // check the output of the test.ts program. + assert!(std::str::from_utf8(&output.stdout) + .unwrap() + .trim() + .ends_with("Hello")); + assert_eq!(output.stderr, b""); +} + +#[test] fn bundle_circular() { // First we have to generate a bundle of some module that has exports. let circular1 = util::root_path().join("cli/tests/subdir/circular1.ts"); @@ -1052,6 +1095,52 @@ fn bundle_import_map() { } #[test] +fn bundle_import_map_no_check() { + let import = util::root_path().join("cli/tests/bundle_im.ts"); + let import_map_path = util::root_path().join("cli/tests/bundle_im.json"); + assert!(import.is_file()); + let t = TempDir::new().expect("tempdir fail"); + let bundle = t.path().join("import_map.bundle.js"); + let mut deno = util::deno_cmd() + .current_dir(util::root_path()) + .arg("bundle") + .arg("--no-check") + .arg("--importmap") + .arg(import_map_path) + .arg("--unstable") + .arg(import) + .arg(&bundle) + .spawn() + .expect("failed to spawn script"); + let status = deno.wait().expect("failed to wait for the child process"); + assert!(status.success()); + assert!(bundle.is_file()); + + // Now we try to use that bundle from another module. + let test = t.path().join("test.js"); + std::fs::write( + &test, + " + import { printHello3 } from \"./import_map.bundle.js\"; + printHello3(); ", + ) + .expect("error writing file"); + + let output = util::deno_cmd() + .current_dir(util::root_path()) + .arg("run") + .arg(&test) + .output() + .expect("failed to spawn script"); + // check the output of the test.ts program. + assert!(std::str::from_utf8(&output.stdout) + .unwrap() + .trim() + .ends_with("Hello")); + assert_eq!(output.stderr, b""); +} + +#[test] fn info_with_compiled_source() { let _g = util::http_server(); let module_path = "http://127.0.0.1:4545/cli/tests/048_media_types_jsx.ts"; diff --git a/cli/tsc_config.rs b/cli/tsc_config.rs index 736fb3557..15a172a72 100644 --- a/cli/tsc_config.rs +++ b/cli/tsc_config.rs @@ -17,7 +17,7 @@ use std::str::FromStr; /// file, that we want to deserialize out of the final config for a transpile. #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct TranspileConfigOptions { +pub struct EmitConfigOptions { pub check_js: bool, pub emit_decorator_metadata: bool, pub jsx: String, @@ -202,7 +202,7 @@ pub fn parse_config( /// A structure for managing the configuration of TypeScript #[derive(Debug, Clone)] -pub struct TsConfig(Value); +pub struct TsConfig(pub Value); impl TsConfig { /// Create a new `TsConfig` with the base being the `value` supplied. @@ -247,15 +247,6 @@ impl TsConfig { Ok(None) } } - - /// Return the current configuration as a `TranspileConfigOptions` structure. - pub fn as_transpile_config( - &self, - ) -> Result<TranspileConfigOptions, AnyError> { - let options: TranspileConfigOptions = - serde_json::from_value(self.0.clone())?; - Ok(options) - } } impl Serialize for TsConfig { |