diff --git a/Cargo.lock b/Cargo.lock index 168e32b..b782f92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1256,10 +1256,11 @@ dependencies = [ [[package]] name = "swc_common" -version = "8.0.1" +version = "8.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e4a932c152e7142de2d5dba1c393e5523c47cd8fe656e5b0d411954bbaf1810" +checksum = "7d96ac5d021c7c20acb3073940b4ee59b62989a705f855783c4a452e0737a2e6" dependencies = [ + "anyhow", "ast_node", "better_scoped_tls", "cfg-if", @@ -1310,14 +1311,16 @@ dependencies = [ [[package]] name = "swc_ecma_ast" -version = "8.1.0" +version = "8.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01f80679b1afc52ae0663eed0a2539cc3c108d48c287b5601712f9850d9fa9c2" +checksum = "4062a54522a9c02d2b68cc09282774b87121cd48693b0e67ae8c18b31b709866" dependencies = [ "bitflags", "is-macro", "num-bigint", + "once_cell", "phf", + "rustc-hash 2.1.1", "scoped-tls", "serde", "string_enum", @@ -1576,10 +1579,12 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "11.0.0" +version = "11.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e06ecaef86a547831f7f01f342434e4b0d0f363762f8e7a2b84da7a0a5f92e" +checksum = "aa942372098c7c0e7fd8c584a577378d2f659c934429b8252c4e26fae31d7ea7" dependencies = [ + "arrayvec", + "bitflags", "either", "new_debug_unreachable", "num-bigint", @@ -1599,9 +1604,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_base" -version = "12.0.0" +version = "12.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0b747f04a004d9b56b903305e4567e1d30c9cd226a8310a29cac06f7ac8173a" +checksum = "b46e3a36213d78fb4233e596b8a5c81c6cdafe02d03d780eed006c983aa0a724" dependencies = [ "better_scoped_tls", "bitflags", @@ -1710,9 +1715,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_proposal" -version = "12.0.0" +version = "12.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048ba8acaa043f9468bb3bd1f5aae6f2e6b06865119226f9c45a971a012cc2d8" +checksum = "5265158f5134b7b37dd2d53e7730921b8b5f567f6baddcc52129c2eb55927214" dependencies = [ "either", "rustc-hash 2.1.1", @@ -1730,9 +1735,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_react" -version = "13.0.0" +version = "13.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b66c31438de864f9694493d3f3a08744a5604b59df03774d09e0f541f29976c" +checksum = "d8e7635afe1e1e798d61ff3107b8d27e437e61f243dd226a47fb10724693be66" dependencies = [ "base64", "dashmap", diff --git a/Cargo.toml b/Cargo.toml index 54e32b3..db97976 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,21 +51,21 @@ unicode-width = "0.2.0" # # NOTE: You can automatically update these dependencies by running ./scripts/update_swc_deps.ts swc_atoms = "=5.0.0" -swc_common = "=8.0.1" +swc_common = "=8.1.0" swc_config = { version = "=2.0.0", optional = true } swc_config_macro = { version = "=1.0.0", optional = true } -swc_ecma_ast = { version = "=8.1.0", features = ["serde-impl"] } +swc_ecma_ast = { version = "=8.1.2", features = ["serde-impl"] } swc_ecma_codegen = { version = "=10.0.0", optional = true } swc_ecma_codegen_macros = { version = "=2.0.0", optional = true } swc_ecma_loader = { version = "=8.0.0", optional = true } -swc_ecma_parser = "=11.0.0" -swc_ecma_transforms_base = { version = "=12.0.0", optional = true } +swc_ecma_parser = "=11.1.2" +swc_ecma_transforms_base = { version = "=12.2.0", optional = true } swc_ecma_transforms_classes = { version = "=12.0.0", optional = true } swc_ecma_transforms_compat = { version = "=13.0.0", optional = true } swc_ecma_transforms_macros = { version = "=1.0.0", optional = true } swc_ecma_transforms_optimization = { version = "=12.0.0", optional = true } -swc_ecma_transforms_proposal = { version = "=12.0.0", optional = true } -swc_ecma_transforms_react = { version = "=13.0.0", optional = true } +swc_ecma_transforms_proposal = { version = "=12.0.1", optional = true } +swc_ecma_transforms_react = { version = "=13.0.1", optional = true } swc_ecma_transforms_typescript = { version = "=13.0.0", optional = true } swc_ecma_utils = { version = "=12.0.0", optional = true } swc_ecma_visit = { version = "=8.0.0", optional = true } diff --git a/src/transpiling/mod.rs b/src/transpiling/mod.rs index 47b3c66..976163f 100644 --- a/src/transpiling/mod.rs +++ b/src/transpiling/mod.rs @@ -633,10 +633,12 @@ impl DiagnosticCollector { } impl crate::swc::common::errors::Emitter for DiagnosticCollector { - fn emit(&mut self, db: &crate::swc::common::errors::DiagnosticBuilder<'_>) { - use std::ops::Deref; + fn emit( + &mut self, + db: &mut crate::swc::common::errors::DiagnosticBuilder<'_>, + ) { let mut diagnostics = self.diagnostics.lock(); - diagnostics.push(db.deref().clone()); + diagnostics.push(db.take()); } } @@ -678,6 +680,7 @@ pub fn fold_program<'a>( proposal::decorator_2022_03::decorator_2022_03(), options.use_decorators_proposal, ), + proposal::explicit_resource_management::explicit_resource_management(), helpers::inject_helpers(marks.top_level), // transform imports to var decls before doing the typescript pass // so that swc doesn't do any optimizations on the import declarations @@ -982,6 +985,113 @@ var N; assert!(transpiled_source.source_map.is_none()); } + #[test] + fn test_explicit_resource_management() { + let specifier = + ModuleSpecifier::parse("https://deno.land/x/mod.ts").unwrap(); + let source = "using data = create();\nconsole.log(data);"; + let program = parse_program(ParseParams { + specifier, + text: source.into(), + media_type: MediaType::TypeScript, + capture_tokens: false, + maybe_syntax: None, + scope_analysis: false, + }) + .unwrap(); + let transpiled_source = program + .transpile( + &TranspileOptions::default(), + &TranspileModuleOptions::default(), + &EmitOptions::default(), + ) + .unwrap() + .into_source(); + let expected_text = r#"function _ts_add_disposable_resource(env, value, async) { + if (value !== null && value !== void 0) { + if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); + var dispose, inner; + if (async) { + if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); + dispose = value[Symbol.asyncDispose]; + } + if (dispose === void 0) { + if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); + dispose = value[Symbol.dispose]; + if (async) inner = dispose; + } + if (typeof dispose !== "function") throw new TypeError("Object not disposable."); + if (inner) dispose = function() { + try { + inner.call(this); + } catch (e) { + return Promise.reject(e); + } + }; + env.stack.push({ + value: value, + dispose: dispose, + async: async + }); + } else if (async) { + env.stack.push({ + async: true + }); + } + return value; +} +function _ts_dispose_resources(env) { + var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; + }; + return (_ts_dispose_resources = function _ts_dispose_resources(env) { + function fail(e) { + env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; + env.hasError = true; + } + var r, s = 0; + function next() { + while(r = env.stack.pop()){ + try { + if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next); + if (r.dispose) { + var result = r.dispose.call(r.value); + if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { + fail(e); + return next(); + }); + } else s |= 1; + } catch (e) { + fail(e); + } + } + if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); + if (env.hasError) throw env.error; + } + return next(); + })(env); +} +const env = { + stack: [], + error: void 0, + hasError: false +}; +try { + var data = _ts_add_disposable_resource(env, create(), false); + console.log(data); +} catch (e) { + env.error = e; + env.hasError = true; +} finally{ + _ts_dispose_resources(env); +}"#; + assert_eq!( + &transpiled_source.text[..expected_text.len()], + expected_text + ); + } + #[test] fn test_transpile_tsx() { let specifier =