summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKitson Kelly <me@kitsonkelly.com>2020-10-20 14:10:42 +1100
committerGitHub <noreply@github.com>2020-10-20 14:10:42 +1100
commit57e95032c898cfdfe795e6924d402fdbe2ae59a8 (patch)
treee548b283d0129b5a1c00828f5a456cc094276bd1
parent034ab48086557af00216ffe311c71ad4eb0ec4d5 (diff)
feat(cli): add support for bundle --no-check (#8023)
Fixes #6686
-rw-r--r--Cargo.lock70
-rw-r--r--cli/Cargo.toml1
-rw-r--r--cli/ast.rs136
-rw-r--r--cli/flags.rs38
-rw-r--r--cli/main.rs37
-rw-r--r--cli/module_graph2.rs224
-rw-r--r--cli/tests/bundle/file_tests-fixture01.ts3
-rw-r--r--cli/tests/bundle/file_tests-fixture02.ts4
-rw-r--r--cli/tests/bundle/file_tests-fixture03.ts3
-rw-r--r--cli/tests/bundle/file_tests-fixture04.ts3
-rw-r--r--cli/tests/bundle/file_tests-fixture05.ts3
-rw-r--r--cli/tests/bundle/file_tests-fixture06.ts4
-rw-r--r--cli/tests/bundle/file_tests-fixture07.ts4
-rw-r--r--cli/tests/bundle/file_tests-fixture08.ts1
-rw-r--r--cli/tests/bundle/file_tests-fixture09.ts1
-rw-r--r--cli/tests/bundle/file_tests-fixture10.ts7
-rw-r--r--cli/tests/bundle/file_tests-fixture11.ts32
-rw-r--r--cli/tests/bundle/file_tests-fixture12.ts7
-rw-r--r--cli/tests/bundle/file_tests-fixture13.ts11
-rw-r--r--cli/tests/bundle/file_tests-fixture14.ts4
-rw-r--r--cli/tests/bundle/file_tests-subdir-a.ts1
-rw-r--r--cli/tests/bundle/file_tests-subdir-b.ts3
-rw-r--r--cli/tests/bundle/file_tests-subdir-c.ts2
-rw-r--r--cli/tests/bundle/file_tests-subdir-d.ts3
-rw-r--r--cli/tests/bundle/file_tests-subdir-e.ts1
-rw-r--r--cli/tests/bundle/file_tests-subdir-f.ts2
-rw-r--r--cli/tests/bundle/file_tests-subdir-g.ts12
-rw-r--r--cli/tests/bundle/file_tests-subdir-h.ts12
-rw-r--r--cli/tests/bundle/file_tests-subdir-i.ts3
-rw-r--r--cli/tests/bundle/file_tests-subdir-j.ts3
-rw-r--r--cli/tests/bundle/file_tests-subdir-k.ts11
-rw-r--r--cli/tests/bundle/file_tests-subdir-l.ts1
-rw-r--r--cli/tests/bundle/file_tests-subdir-m.ts2
-rw-r--r--cli/tests/bundle/file_tests-subdir-n.ts3
-rw-r--r--cli/tests/bundle/file_tests-subdir-o.ts5
-rw-r--r--cli/tests/bundle/file_tests-subdir-p.ts1
-rw-r--r--cli/tests/bundle/file_tests-subdir-q.ts13
-rw-r--r--cli/tests/bundle/fixture01.out7
-rw-r--r--cli/tests/bundle/fixture02.out11
-rw-r--r--cli/tests/bundle/fixture03.out4
-rw-r--r--cli/tests/bundle/fixture04.out2
-rw-r--r--cli/tests/bundle/fixture05.out1
-rw-r--r--cli/tests/bundle/fixture06.out2
-rw-r--r--cli/tests/bundle/fixture07.out23
-rw-r--r--cli/tests/bundle/fixture08.out7
-rw-r--r--cli/tests/bundle/fixture09.out19
-rw-r--r--cli/tests/bundle/fixture10.out4
-rw-r--r--cli/tests/bundle/fixture11.out31
-rw-r--r--cli/tests/bundle/fixture12.out7
-rw-r--r--cli/tests/bundle/fixture13.out17
-rw-r--r--cli/tests/bundle/fixture14.out25
-rw-r--r--cli/tests/bundle/https_deno.land-x-lib-a.ts1
-rw-r--r--cli/tests/bundle/https_deno.land-x-lib-b.js1
-rw-r--r--cli/tests/bundle/https_deno.land-x-lib-c.d.ts1
-rw-r--r--cli/tests/bundle/https_deno.land-x-lib-c.js3
-rw-r--r--cli/tests/bundle/https_deno.land-x-lib-mod.d.ts9
-rw-r--r--cli/tests/bundle/https_deno.land-x-lib-mod.js5
-rw-r--r--cli/tests/integration_tests.rs89
-rw-r--r--cli/tsc_config.rs13
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 {