diff options
author | David Sherret <dsherret@users.noreply.github.com> | 2022-01-13 11:58:00 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-13 11:58:00 -0500 |
commit | f12164646ba8327e9e6275b0ab97602f85e9854f (patch) | |
tree | 1668ac008ac455d38d9eacd70dec4ed7f1d542c2 | |
parent | 5e2d7737f5542c02572aa6585c8a6a78c84ae5ab (diff) |
refactor: move transpiling to deno_ast (#13332)
-rw-r--r-- | Cargo.lock | 148 | ||||
-rw-r--r-- | cli/Cargo.toml | 10 | ||||
-rw-r--r-- | cli/ast/bundle_hook.rs | 51 | ||||
-rw-r--r-- | cli/ast/mod.rs | 919 | ||||
-rw-r--r-- | cli/ast/transforms.rs | 524 | ||||
-rw-r--r-- | cli/cache.rs | 8 | ||||
-rw-r--r-- | cli/emit.rs | 180 | ||||
-rw-r--r-- | cli/lsp/cache.rs | 1 | ||||
-rw-r--r-- | cli/lsp/code_lens.rs | 28 | ||||
-rw-r--r-- | cli/main.rs | 4 | ||||
-rw-r--r-- | cli/ops/runtime_compiler.rs | 1 | ||||
-rw-r--r-- | cli/proc_state.rs | 8 | ||||
-rw-r--r-- | cli/tools/doc.rs | 14 | ||||
-rw-r--r-- | cli/tools/repl/session.rs | 19 | ||||
-rw-r--r-- | cli/tools/test.rs | 25 | ||||
-rw-r--r-- | cli/tsc.rs | 4 |
16 files changed, 302 insertions, 1642 deletions
diff --git a/Cargo.lock b/Cargo.lock index 6a4a971df..27541d0be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -352,9 +352,9 @@ checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" [[package]] name = "bumpalo" -version = "3.8.0" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "byteorder" @@ -543,9 +543,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -553,9 +553,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" dependencies = [ "cfg-if 1.0.0", "lazy_static", @@ -763,10 +763,12 @@ dependencies = [ [[package]] name = "deno_ast" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a3eb87c6fddf68e02f7438728a611ff6ca84a644fc00d3b9ad5a006e212484" +checksum = "e81ceec755f9e4e270e8d7ef4ade1921eddc1717dea092c726b088f9c074721b" dependencies = [ + "anyhow", + "base64 0.13.0", "data-url", "dprint-swc-ecma-ast-view", "serde", @@ -855,9 +857,9 @@ dependencies = [ [[package]] name = "deno_doc" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3fd524cf36cae45b06de577f8f18b6ef786b56a3840fb721923ccddeeb09833" +checksum = "73ff82ae22a4012a843799f5baadda95ddc67cc3bed21fe5ebcda2c5cff768a1" dependencies = [ "cfg-if 1.0.0", "deno_ast", @@ -901,9 +903,9 @@ dependencies = [ [[package]] name = "deno_graph" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5eda28d50fc84d2b1774829316dcecdce1d41f0923b3a174f88cd599cafd529" +checksum = "5b2a21feedd2fde8846a8b94855498ff7e1c59bdf972a06a6faf228999c1f7fd" dependencies = [ "anyhow", "cfg-if 1.0.0", @@ -937,9 +939,9 @@ dependencies = [ [[package]] name = "deno_lint" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90b4b3dfb590568c6cb9ff24d4fb36645b47e480059517420fcb5d19758f75c9" +checksum = "6cf1715d924e6fdf45847868b31742ed305fb6270747c6046dc3c19f67c0d2f5" dependencies = [ "anyhow", "deno_ast", @@ -1212,9 +1214,9 @@ dependencies = [ [[package]] name = "dprint-plugin-typescript" -version = "0.61.0" +version = "0.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2cf0922de1556135f425df4de9968fd0b8e424eebc7fdb4001058c678bde475" +checksum = "b3e9b87d22638bc08075c827ae568e02b07fbf262142db90895383bac3f5a67e" dependencies = [ "anyhow", "deno_ast", @@ -1226,9 +1228,9 @@ dependencies = [ [[package]] name = "dprint-swc-ecma-ast-view" -version = "0.47.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbf1d058db8ad7c9790db7dbe852d0cbddd2a314e592387232fa3db02fe0771" +checksum = "3d189ada8940380247d23993d0ecf13e8b3b5b3a948dffa6fb7291fbd75cf961" dependencies = [ "bumpalo", "num-bigint", @@ -1498,9 +1500,9 @@ dependencies = [ [[package]] name = "fsevent-sys" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0e564d24da983c053beff1bb7178e237501206840a3e6bf4e267b9e8ae734a" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" dependencies = [ "libc", ] @@ -1729,9 +1731,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd" +checksum = "0c9de88456263e249e241fcd211d3954e2c9b0ef7ccfc235a444eb367cae3689" dependencies = [ "bytes", "fnv", @@ -1918,9 +1920,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg 1.0.1", "hashbrown", @@ -1985,9 +1987,9 @@ checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" [[package]] name = "is-macro" -version = "0.1.9" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a322dd16d960e322c3d92f541b4c1a4f0a2e81e1fdeee430d8cecc8b72e8015f" +checksum = "94b2c46692aee0d1b3aad44e781ac0f0e7db42ef27adaa0a877b627040019813" dependencies = [ "Inflector", "pmutil", @@ -2361,9 +2363,9 @@ dependencies = [ [[package]] name = "netif" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9e642845c332c335e3125759b10145a972c1f413cb48cd6d7b96e81821f281" +checksum = "c4c80b95aa77797835fccdc22f4c27458c0b04928cf9ab486e826e1dccf36745" dependencies = [ "libc", "winapi 0.3.9", @@ -2528,9 +2530,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl-probe" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "os_pipe" @@ -3088,9 +3090,9 @@ checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157" [[package]] name = "reqwest" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c4e0a76dc12a116108933f6301b95e83634e0c47b0afbed6abbaa0601e99258" +checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525" dependencies = [ "async-compression", "base64 0.13.0", @@ -3098,6 +3100,7 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", + "h2", "http", "http-body", "hyper", @@ -3482,9 +3485,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer", "cfg-if 1.0.0", @@ -3694,9 +3697,9 @@ dependencies = [ [[package]] name = "swc_bundler" -version = "0.96.0" +version = "0.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4df8e45a1d523403a5f256fca9ab216bcccbd5883b7aba6f8b5a5c1e69bcd31" +checksum = "7e4ba80b219e651c3eeb830abc7caa391e55c9ff1fd4370e5723a2cbd752ea93" dependencies = [ "ahash", "anyhow", @@ -3726,9 +3729,9 @@ dependencies = [ [[package]] name = "swc_common" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "757c84b893b4b16bbbe983acc8262f52fe5efd9b87b362f4196549e4f798c0a0" +checksum = "015b0c14152981b1590d05c6073ac602008e5fc414b7cc4b2bbae60220d27ff2" dependencies = [ "ahash", "ast_node", @@ -3753,9 +3756,9 @@ dependencies = [ [[package]] name = "swc_ecma_ast" -version = "0.62.0" +version = "0.65.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d00427977875928f37e92e260f226a91783812aaf3713562526a920befd6aa39" +checksum = "accaa4affdc0e2f3693c9d3b325ad97e9d9534e01abe5564b9b85c5d1cacdcbb" dependencies = [ "is-macro", "num-bigint", @@ -3768,9 +3771,9 @@ dependencies = [ [[package]] name = "swc_ecma_codegen" -version = "0.86.0" +version = "0.89.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "025d9bb2d836fac57bf5579f7049ff96e702632c0affb362234b26d587f996d1" +checksum = "667e9174226b2228b5ddc850f59db0b2689652efa0b5d5d3c072d1caba256cb7" dependencies = [ "bitflags", "memchr", @@ -3800,9 +3803,9 @@ dependencies = [ [[package]] name = "swc_ecma_dep_graph" -version = "0.55.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3368bafec3d3dd3f19e2108551b9d6dd1362c515cd138a652aff9f911409316" +checksum = "bf46c8d3c4b34072e2e958b259781d9a94a00f23806c402eba40b8e9865f9dda" dependencies = [ "swc_atoms", "swc_common", @@ -3812,9 +3815,9 @@ dependencies = [ [[package]] name = "swc_ecma_loader" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e4a236d9fc809d88e8d346381e72936dc8a4e4a2418d1f66ea8acb6ed298be" +checksum = "764c8e31524d35722aacdbee51e132424798365ddfd75deb81634f342c5fdce3" dependencies = [ "ahash", "anyhow", @@ -3825,9 +3828,9 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "0.84.0" +version = "0.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55406a1e109a7c4ad281ee4fe295249553b7fcbfa43b27f7b53d6112b2924af4" +checksum = "3c454cbd95ab84fd9ffc5059cffad80b7711bd4b8732257a7c83f4b2c809dfa1" dependencies = [ "either", "enum_kind", @@ -3845,9 +3848,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms" -version = "0.106.1" +version = "0.111.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4069c5474cfb5f786fa20dd013ab8b8b73f35522f82372e71c2307a2b904e38" +checksum = "ae472031803e9fddb9f9141edc3ec0c3bff5904cd08e0509f2ad88689678ce7c" dependencies = [ "swc_atoms", "swc_common", @@ -3864,13 +3867,14 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_base" -version = "0.52.1" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec358dadefdc2a834a623192bc972df7a74443a80b73a538495ebbf652bfc97d" +checksum = "74824b2df0931ed3d84201e50138b68d1dc78a802aef9dbdec4ea0ffcea8a28b" dependencies = [ "once_cell", "phf", "scoped-tls", + "serde", "smallvec", "swc_atoms", "swc_common", @@ -3883,9 +3887,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_classes" -version = "0.39.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ad7eb4fb019fc608ccff8a2ceffb7548ec94018cc2f523367b137b90b1d6a6" +checksum = "8a972a157b9104b7979a34556841f93e98d18d70b83c9e625b35dd390b57e59f" dependencies = [ "swc_atoms", "swc_common", @@ -3910,9 +3914,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_optimization" -version = "0.76.0" +version = "0.81.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb91bd9aea0f0dd57688340306203ec776ed2fd1e2b75871b7135566c5a4e82a" +checksum = "3af299ad73dc689a0516950613a9262203feff76adc3f2f14307a12bdd5835c9" dependencies = [ "ahash", "dashmap", @@ -3932,9 +3936,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_proposal" -version = "0.68.0" +version = "0.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6520f06130f57292dfd986c0484034f37f6a129699a139010a818e4cd164975" +checksum = "fe1cf222cfe757700ffea622589990b1b0ef0a18c85ffe6e8442ba515257aa98" dependencies = [ "either", "serde", @@ -3952,9 +3956,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_react" -version = "0.70.0" +version = "0.75.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef966c28b0f13412c546ebd777e61b197b2ef8c9214bee8393f25d0027adfef" +checksum = "cee01d3f5c0f424a199a4d13fc6fbe14cfd88ccff0b778558311075477e25310" dependencies = [ "ahash", "base64 0.13.0", @@ -3977,9 +3981,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_typescript" -version = "0.72.0" +version = "0.77.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca12da83a3ce8fa61defa77256f11bf63048830d45b2e3a67fb7208d5dfa8b5" +checksum = "50560b92ecbd43ee4dea19ae763d0bde8d753c8401d76115c714cfb51f838e76" dependencies = [ "serde", "swc_atoms", @@ -3994,9 +3998,9 @@ dependencies = [ [[package]] name = "swc_ecma_utils" -version = "0.59.0" +version = "0.63.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4684e029d1c06cd3ee86e83a3cffb7a90acb421b58204ed72c8e3719bc88eca5" +checksum = "a05826c1edd7d58ec97af8be523c9c15e24e6dc4c1762435bb12573d716dd7ba" dependencies = [ "once_cell", "swc_atoms", @@ -4008,9 +4012,9 @@ dependencies = [ [[package]] name = "swc_ecma_visit" -version = "0.48.1" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "decbd767e2630eb650cd97d49c74e4ce32beb9daeccd9602f52c48f32436006c" +checksum = "95cf6f39cd1c3682885125955e881bec872e0c1743eb1a31735da69b894f065e" dependencies = [ "num-bigint", "swc_atoms", @@ -4022,9 +4026,9 @@ dependencies = [ [[package]] name = "swc_ecmascript" -version = "0.103.2" +version = "0.108.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c47c72500ac5300ab11d5ede08c9bab878ac065c8a9169d34f2f7f28b1ec19f2" +checksum = "36c59346416fc6010a59c0fa10f19b8ba9a45bed7199005b7c452b68400fc345" dependencies = [ "swc_ecma_ast", "swc_ecma_codegen", @@ -4049,9 +4053,9 @@ dependencies = [ [[package]] name = "swc_fast_graph" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4857942a9c79e9836f51dca4ca0df89f354acfedc573708006c4365bad07083c" +checksum = "1d53bbcbb4b055c547f283af1f84211f425b95ac59e02d8b70c94b8a63a4704f" dependencies = [ "ahash", "indexmap", @@ -4061,9 +4065,9 @@ dependencies = [ [[package]] name = "swc_graph_analyzer" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5f079d9350dee80a59ac2f8be9867ed0a8ac9fb0023461b173e9e42168ff30" +checksum = "83b42a8b13068dd90dec954ec44576d5922914687bc34277f3b0f8d0bbeb4e83" dependencies = [ "ahash", "auto_impl", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 66fa281ee..10db61bf7 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -40,11 +40,11 @@ winapi = "=0.3.9" winres = "=0.1.11" [dependencies] -deno_ast = { version = "0.8.0", features = ["bundler", "codegen", "dep_graph", "module_specifier", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] } +deno_ast = { version = "0.9.0", features = ["bundler", "codegen", "dep_graph", "module_specifier", "proposal", "react", "sourcemap", "transforms", "transpiling", "typescript", "view", "visit"] } deno_core = { version = "0.113.0", path = "../core" } -deno_doc = "0.25.0" -deno_graph = "0.17.0" -deno_lint = { version = "0.21.0", features = ["docs"] } +deno_doc = "0.26.0" +deno_graph = "0.18.0" +deno_lint = { version = "0.22.0", features = ["docs"] } deno_runtime = { version = "0.39.0", path = "../runtime" } atty = "=0.2.14" @@ -56,7 +56,7 @@ data-url = "=0.1.1" dissimilar = "=1.0.2" dprint-plugin-json = "=0.14.0" dprint-plugin-markdown = "=0.12.0" -dprint-plugin-typescript = "=0.61.0" +dprint-plugin-typescript = "=0.62.0" encoding_rs = "=0.8.29" env_logger = "=0.8.4" fancy-regex = "=0.7.1" diff --git a/cli/ast/bundle_hook.rs b/cli/ast/bundle_hook.rs deleted file mode 100644 index a2dd658e3..000000000 --- a/cli/ast/bundle_hook.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -use deno_ast::swc::bundler::Hook; -use deno_ast::swc::bundler::ModuleRecord; -use deno_ast::swc::common::Span; -use deno_core::error::AnyError; - -/// This contains the logic for Deno to rewrite the `import.meta` when bundling. -pub struct BundleHook; - -impl Hook for BundleHook { - fn get_import_meta_props( - &self, - span: Span, - module_record: &ModuleRecord, - ) -> Result<Vec<deno_ast::swc::ast::KeyValueProp>, AnyError> { - use deno_ast::swc::ast; - - Ok(vec![ - ast::KeyValueProp { - key: ast::PropName::Ident(ast::Ident::new("url".into(), span)), - value: Box::new(ast::Expr::Lit(ast::Lit::Str(ast::Str { - span, - value: module_record.file_name.to_string().into(), - kind: ast::StrKind::Synthesized, - has_escape: false, - }))), - }, - ast::KeyValueProp { - key: ast::PropName::Ident(ast::Ident::new("main".into(), span)), - value: Box::new(if module_record.is_entry { - ast::Expr::Member(ast::MemberExpr { - span, - obj: ast::ExprOrSuper::Expr(Box::new(ast::Expr::MetaProp( - ast::MetaPropExpr { - meta: ast::Ident::new("import".into(), span), - prop: ast::Ident::new("meta".into(), span), - }, - ))), - prop: Box::new(ast::Expr::Ident(ast::Ident::new( - "main".into(), - span, - ))), - computed: false, - }) - } else { - ast::Expr::Lit(ast::Lit::Bool(ast::Bool { span, value: false })) - }), - }, - ]) - } -} diff --git a/cli/ast/mod.rs b/cli/ast/mod.rs deleted file mode 100644 index 419471daa..000000000 --- a/cli/ast/mod.rs +++ /dev/null @@ -1,919 +0,0 @@ -// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. - -use crate::config_file; -use crate::text_encoding::strip_bom; - -use deno_ast::get_syntax; -use deno_ast::swc::ast::Module; -use deno_ast::swc::ast::Program; -use deno_ast::swc::codegen::text_writer::JsWriter; -use deno_ast::swc::codegen::Node; -use deno_ast::swc::common::chain; -use deno_ast::swc::common::comments::SingleThreadedComments; -use deno_ast::swc::common::errors::Diagnostic as SwcDiagnostic; -use deno_ast::swc::common::BytePos; -use deno_ast::swc::common::FileName; -use deno_ast::swc::common::Globals; -use deno_ast::swc::common::Mark; -use deno_ast::swc::common::SourceMap; -use deno_ast::swc::common::Spanned; -use deno_ast::swc::parser::error::Error as SwcError; -use deno_ast::swc::parser::error::SyntaxError; -use deno_ast::swc::parser::lexer::Lexer; -use deno_ast::swc::parser::StringInput; -use deno_ast::swc::transforms::fixer; -use deno_ast::swc::transforms::helpers; -use deno_ast::swc::transforms::hygiene; -use deno_ast::swc::transforms::pass::Optional; -use deno_ast::swc::transforms::proposals; -use deno_ast::swc::transforms::react; -use deno_ast::swc::transforms::resolver_with_mark; -use deno_ast::swc::transforms::typescript; -use deno_ast::swc::visit::FoldWith; -use deno_ast::Diagnostic; -use deno_ast::LineAndColumnDisplay; -use deno_ast::MediaType; -use deno_ast::ParsedSource; -use deno_core::anyhow::anyhow; -use deno_core::error::AnyError; -use deno_core::resolve_url_or_path; -use deno_core::serde_json; -use deno_core::ModuleSpecifier; -use std::cell::RefCell; -use std::fmt; -use std::rc::Rc; - -mod bundle_hook; -mod transforms; - -pub use bundle_hook::BundleHook; - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Location { - pub specifier: String, - pub line: usize, - pub col: usize, -} - -impl Location { - pub fn from_pos(parsed_source: &ParsedSource, pos: BytePos) -> Self { - Location::from_line_and_column( - parsed_source.specifier().to_string(), - parsed_source.source().line_and_column_index(pos), - ) - } - - pub fn from_line_and_column( - specifier: String, - line_and_column: deno_ast::LineAndColumnIndex, - ) -> Self { - Location { - specifier, - line: line_and_column.line_index + 1, - col: line_and_column.column_index, - } - } -} - -impl From<deno_ast::swc::common::Loc> for Location { - fn from(swc_loc: deno_ast::swc::common::Loc) -> Self { - use deno_ast::swc::common::FileName::*; - - let filename = match &swc_loc.file.name { - Real(path_buf) => path_buf.to_string_lossy().to_string(), - Custom(str_) => str_.to_string(), - Url(url) => url.to_string(), - _ => panic!("invalid filename"), - }; - - Location { - specifier: filename, - line: swc_loc.line, - col: swc_loc.col.0, - } - } -} - -impl From<Location> for ModuleSpecifier { - fn from(loc: Location) -> Self { - resolve_url_or_path(&loc.specifier).unwrap() - } -} - -impl std::fmt::Display for Location { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}:{}:{}", self.specifier, self.line, self.col) - } -} - -#[derive(Debug)] -pub struct Diagnostics(pub Vec<Diagnostic>); - -impl std::error::Error for Diagnostics {} - -impl fmt::Display for Diagnostics { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for (i, diagnostic) in self.0.iter().enumerate() { - if i > 0 { - write!(f, "\n\n")?; - } - - write!(f, "{}", diagnostic)? - } - - Ok(()) - } -} - -#[derive(Debug, Clone)] -pub enum ImportsNotUsedAsValues { - Remove, - Preserve, - Error, -} - -/// Options which can be adjusted when transpiling a module. -#[derive(Debug, Clone)] -pub struct EmitOptions { - /// When emitting a legacy decorator, also emit experimental decorator meta - /// data. Defaults to `false`. - pub emit_metadata: bool, - /// What to do with import statements that only import types i.e. whether to - /// remove them (`Remove`), keep them as side-effect imports (`Preserve`) - /// or error (`Error`). Defaults to `Remove`. - pub imports_not_used_as_values: ImportsNotUsedAsValues, - /// Should the source map be inlined in the emitted code file, or provided - /// as a separate file. Defaults to `true`. - pub inline_source_map: bool, - /// Should the sources be inlined in the source map. Defaults to `true`. - pub inline_sources: bool, - /// Should a corresponding .map file be created for the output. This should be - /// false if inline_source_map is true. Defaults to `false`. - pub source_map: bool, - /// `true` if the program should use an implicit JSX import source/the "new" - /// JSX transforms. - pub jsx_automatic: bool, - /// If JSX is automatic, if it is in development mode, meaning that it should - /// import `jsx-dev-runtime` and transform JSX using `jsxDEV` import from the - /// JSX import source as well as provide additional debug information to the - /// JSX factory. - pub jsx_development: bool, - /// When transforming JSX, what value should be used for the JSX factory. - /// Defaults to `React.createElement`. - pub jsx_factory: String, - /// When transforming JSX, what value should be used for the JSX fragment - /// factory. Defaults to `React.Fragment`. - pub jsx_fragment_factory: String, - /// The string module specifier to implicitly import JSX factories from when - /// transpiling JSX. - pub jsx_import_source: Option<String>, - /// Should JSX be transformed or preserved. Defaults to `true`. - pub transform_jsx: bool, - /// Should import declarations be transformed to variable declarations. - /// This should only be set to true for the REPL. Defaults to `false`. - pub repl_imports: bool, -} - -impl Default for EmitOptions { - fn default() -> Self { - EmitOptions { - emit_metadata: false, - imports_not_used_as_values: ImportsNotUsedAsValues::Remove, - inline_source_map: true, - inline_sources: true, - source_map: false, - jsx_automatic: false, - jsx_development: false, - jsx_factory: "React.createElement".into(), - jsx_fragment_factory: "React.Fragment".into(), - jsx_import_source: None, - transform_jsx: true, - repl_imports: false, - } - } -} - -impl From<config_file::TsConfig> for EmitOptions { - fn from(config: config_file::TsConfig) -> Self { - let options: config_file::EmitConfigOptions = - serde_json::from_value(config.0).unwrap(); - let imports_not_used_as_values = - match options.imports_not_used_as_values.as_str() { - "preserve" => ImportsNotUsedAsValues::Preserve, - "error" => ImportsNotUsedAsValues::Error, - _ => ImportsNotUsedAsValues::Remove, - }; - let (transform_jsx, jsx_automatic, jsx_development) = - match options.jsx.as_str() { - "react" => (true, false, false), - "react-jsx" => (true, true, false), - "react-jsxdev" => (true, true, true), - _ => (false, false, false), - }; - EmitOptions { - emit_metadata: options.emit_decorator_metadata, - imports_not_used_as_values, - inline_source_map: options.inline_source_map, - inline_sources: options.inline_sources, - source_map: options.source_map, - jsx_automatic, - jsx_development, - jsx_factory: options.jsx_factory, - jsx_fragment_factory: options.jsx_fragment_factory, - jsx_import_source: options.jsx_import_source, - transform_jsx, - repl_imports: false, - } - } -} - -fn strip_config_from_emit_options( - options: &EmitOptions, -) -> typescript::strip::Config { - typescript::strip::Config { - pragma: Some(options.jsx_factory.clone()), - pragma_frag: Some(options.jsx_fragment_factory.clone()), - import_not_used_as_values: match options.imports_not_used_as_values { - ImportsNotUsedAsValues::Remove => { - typescript::strip::ImportsNotUsedAsValues::Remove - } - ImportsNotUsedAsValues::Preserve => { - typescript::strip::ImportsNotUsedAsValues::Preserve - } - // `Error` only affects the type-checking stage. Fall back to `Remove` here. - ImportsNotUsedAsValues::Error => { - typescript::strip::ImportsNotUsedAsValues::Remove - } - }, - use_define_for_class_fields: true, - // TODO(bartlomieju): this could be changed to `false` to provide `export {}` - // in Typescript files without manual changes - no_empty_export: true, - } -} - -/// Implements a configuration trait for source maps that reflects the logic -/// to embed sources in the source map or not. -#[derive(Debug)] -pub(crate) struct SourceMapConfig { - pub inline_sources: bool, -} - -impl deno_ast::swc::common::source_map::SourceMapGenConfig for SourceMapConfig { - fn file_name_to_source(&self, f: &FileName) -> String { - f.to_string() - } - - fn inline_sources_content(&self, f: &FileName) -> bool { - match f { - FileName::Real(..) | FileName::Custom(..) => false, - FileName::Url(..) => self.inline_sources, - _ => true, - } - } -} - -/// Transform a TypeScript file into a JavaScript file, based on the supplied -/// options. -/// -/// The result is a tuple of the code and optional source map as strings. -pub fn transpile( - parsed_source: &ParsedSource, - options: &EmitOptions, -) -> Result<(String, Option<String>), AnyError> { - ensure_no_fatal_diagnostics(parsed_source.diagnostics().iter())?; - let program: Program = (*parsed_source.program()).clone(); - let source_map = Rc::new(SourceMap::default()); - let source_map_config = SourceMapConfig { - inline_sources: options.inline_sources, - }; - let specifier = resolve_url_or_path(parsed_source.specifier())?; - let file_name = FileName::Url(specifier); - source_map - .new_source_file(file_name, parsed_source.source().text().to_string()); - let comments = parsed_source.comments().as_single_threaded(); // needs to be mutable - let globals = Globals::new(); - deno_ast::swc::common::GLOBALS.set(&globals, || { - let top_level_mark = Mark::fresh(Mark::root()); - let module = fold_program( - program, - options, - source_map.clone(), - &comments, - top_level_mark, - )?; - - let mut src_map_buf = vec![]; - let mut buf = vec![]; - { - let writer = Box::new(JsWriter::new( - source_map.clone(), - "\n", - &mut buf, - Some(&mut src_map_buf), - )); - let config = deno_ast::swc::codegen::Config { minify: false }; - let mut emitter = deno_ast::swc::codegen::Emitter { - cfg: config, - comments: Some(&comments), - cm: source_map.clone(), - wr: writer, - }; - module.emit_with(&mut emitter)?; - } - let mut src = String::from_utf8(buf)?; - let mut map: Option<String> = None; - { - let mut buf = Vec::new(); - source_map - .build_source_map_with_config(&mut src_map_buf, None, source_map_config) - .to_writer(&mut buf)?; - - if options.inline_source_map { - src.push_str("//# sourceMappingURL=data:application/json;base64,"); - let encoded_map = base64::encode(buf); - src.push_str(&encoded_map); - } else { - map = Some(String::from_utf8(buf)?); - } - } - Ok((src, map)) - }) -} - -/// A low level function which transpiles a source module into an swc -/// SourceFile. -pub fn transpile_module( - specifier: &ModuleSpecifier, - source: &str, - media_type: MediaType, - options: &EmitOptions, - cm: Rc<SourceMap>, -) -> Result<(Rc<deno_ast::swc::common::SourceFile>, Module), AnyError> { - let source = strip_bom(source); - let source = if media_type == MediaType::Json { - format!( - "export default JSON.parse(`{}`);", - source.replace("${", "\\${").replace('`', "\\`") - ) - } else { - source.to_string() - }; - let source_file = - cm.new_source_file(FileName::Url(specifier.clone()), source); - let input = StringInput::from(&*source_file); - let comments = SingleThreadedComments::default(); - let syntax = if media_type == MediaType::Json { - get_syntax(MediaType::JavaScript) - } else { - get_syntax(media_type) - }; - let lexer = Lexer::new(syntax, deno_ast::ES_VERSION, input, Some(&comments)); - let mut parser = deno_ast::swc::parser::Parser::new_from(lexer); - let module = parser - .parse_module() - .map_err(|e| swc_err_to_diagnostic(&cm, specifier, e))?; - let diagnostics = parser - .take_errors() - .into_iter() - .map(|e| swc_err_to_diagnostic(&cm, specifier, e)) - .collect::<Vec<_>>(); - - ensure_no_fatal_diagnostics(diagnostics.iter())?; - - let top_level_mark = Mark::fresh(Mark::root()); - let program = fold_program( - Program::Module(module), - options, - cm, - &comments, - top_level_mark, - )?; - let module = match program { - Program::Module(module) => module, - _ => unreachable!(), - }; - - Ok((source_file, module)) -} - -#[derive(Default, Clone)] -struct DiagnosticCollector { - diagnostics_cell: Rc<RefCell<Vec<SwcDiagnostic>>>, -} - -impl DiagnosticCollector { - pub fn into_handler(self) -> deno_ast::swc::common::errors::Handler { - deno_ast::swc::common::errors::Handler::with_emitter( - true, - false, - Box::new(self), - ) - } -} - -impl deno_ast::swc::common::errors::Emitter for DiagnosticCollector { - fn emit( - &mut self, - db: &deno_ast::swc::common::errors::DiagnosticBuilder<'_>, - ) { - use std::ops::Deref; - self.diagnostics_cell.borrow_mut().push(db.deref().clone()); - } -} - -fn fold_program( - program: Program, - options: &EmitOptions, - source_map: Rc<SourceMap>, - comments: &SingleThreadedComments, - top_level_mark: Mark, -) -> Result<Program, AnyError> { - let jsx_pass = react::react( - source_map.clone(), - Some(comments), - react::Options { - pragma: options.jsx_factory.clone(), - pragma_frag: options.jsx_fragment_factory.clone(), - // this will use `Object.assign()` instead of the `_extends` helper - // when spreading props. - use_builtins: true, - runtime: if options.jsx_automatic { - Some(react::Runtime::Automatic) - } else { - None - }, - development: options.jsx_development, - import_source: options.jsx_import_source.clone().unwrap_or_default(), - ..Default::default() - }, - top_level_mark, - ); - let mut passes = chain!( - Optional::new(transforms::DownlevelImportsFolder, options.repl_imports), - Optional::new(transforms::StripExportsFolder, options.repl_imports), - proposals::decorators::decorators(proposals::decorators::Config { - legacy: true, - emit_metadata: options.emit_metadata - }), - helpers::inject_helpers(), - resolver_with_mark(top_level_mark), - Optional::new( - typescript::strip::strip_with_config( - strip_config_from_emit_options(options), - top_level_mark - ), - !options.transform_jsx - ), - Optional::new( - typescript::strip::strip_with_jsx( - source_map.clone(), - strip_config_from_emit_options(options), - comments, - top_level_mark - ), - options.transform_jsx - ), - Optional::new(jsx_pass, options.transform_jsx), - fixer(Some(comments)), - hygiene(), - ); - - let emitter = DiagnosticCollector::default(); - let diagnostics_cell = emitter.diagnostics_cell.clone(); - let handler = emitter.into_handler(); - let result = deno_ast::swc::utils::HANDLER.set(&handler, || { - helpers::HELPERS.set(&helpers::Helpers::new(false), || { - program.fold_with(&mut passes) - }) - }); - - let diagnostics = diagnostics_cell.borrow(); - ensure_no_fatal_swc_diagnostics(&source_map, diagnostics.iter())?; - Ok(result) -} - -fn ensure_no_fatal_swc_diagnostics<'a>( - source_map: &SourceMap, - diagnostics: impl Iterator<Item = &'a SwcDiagnostic>, -) -> Result<(), AnyError> { - let fatal_diagnostics = diagnostics - .filter(|d| is_fatal_swc_diagnostic(d)) - .collect::<Vec<_>>(); - if !fatal_diagnostics.is_empty() { - Err(anyhow!( - "{}", - fatal_diagnostics - .iter() - .map(|d| format_swc_diagnostic(source_map, d)) - .collect::<Vec<_>>() - .join("\n\n") - )) - } else { - Ok(()) - } -} - -fn is_fatal_swc_diagnostic(diagnostic: &SwcDiagnostic) -> bool { - use deno_ast::swc::common::errors::Level; - match diagnostic.level { - Level::Bug - | Level::Cancelled - | Level::FailureNote - | Level::Fatal - | Level::PhaseFatal - | Level::Error => true, - Level::Help | Level::Note | Level::Warning => false, - } -} - -fn format_swc_diagnostic( - source_map: &SourceMap, - diagnostic: &SwcDiagnostic, -) -> String { - if let Some(span) = &diagnostic.span.primary_span() { - let file_name = source_map.span_to_filename(*span); - let loc = source_map.lookup_char_pos(span.lo); - format!( - "{} at {}:{}:{}", - diagnostic.message(), - file_name.to_string(), - loc.line, - loc.col_display + 1, - ) - } else { - diagnostic.message() - } -} - -fn swc_err_to_diagnostic( - source_map: &SourceMap, - specifier: &ModuleSpecifier, - err: SwcError, -) -> Diagnostic { - let location = source_map.lookup_char_pos(err.span().lo); - Diagnostic { - specifier: specifier.to_string(), - span: err.span(), - display_position: LineAndColumnDisplay { - line_number: location.line, - column_number: location.col_display + 1, - }, - kind: err.into_kind(), - } -} - -fn ensure_no_fatal_diagnostics<'a>( - diagnostics: impl Iterator<Item = &'a Diagnostic>, -) -> Result<(), Diagnostics> { - let fatal_diagnostics = diagnostics - .filter(|d| is_fatal_syntax_error(&d.kind)) - .map(ToOwned::to_owned) - .collect::<Vec<_>>(); - if !fatal_diagnostics.is_empty() { - Err(Diagnostics(fatal_diagnostics)) - } else { - Ok(()) - } -} - -fn is_fatal_syntax_error(error_kind: &SyntaxError) -> bool { - matches!( - error_kind, - // expected identifier - SyntaxError::TS1003 | - // expected semi-colon - SyntaxError::TS1005 | - // expected expression - SyntaxError::TS1109 | - // unterminated string literal - SyntaxError::UnterminatedStrLit - ) -} - -#[cfg(test)] -mod tests { - use super::*; - use deno_ast::parse_module; - use deno_ast::ParseParams; - use deno_ast::SourceTextInfo; - - use pretty_assertions::assert_eq; - - #[test] - fn test_transpile() { - let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap(); - let source = r#" -enum D { - A, - B, -} - -namespace N { - export enum D { - A = "value" - } - export const Value = 5; -} - -export class A { - private b: string; - protected c: number = 1; - e: "foo"; - constructor (public d = D.A) { - const e = "foo" as const; - this.e = e; - console.log(N.Value); - } -} - "#; - let module = deno_ast::parse_module(ParseParams { - specifier: specifier.as_str().to_string(), - source: SourceTextInfo::from_string(source.to_string()), - media_type: deno_ast::MediaType::TypeScript, - capture_tokens: false, - maybe_syntax: None, - scope_analysis: false, - }) - .unwrap(); - let (code, maybe_map) = - transpile(&module, &EmitOptions::default()).unwrap(); - let expected_text = r#"var D; -(function(D) { - D[D["A"] = 0] = "A"; - D[D["B"] = 1] = "B"; -})(D || (D = {})); -var N; -(function(N1) { - let D; - (function(D) { - D["A"] = "value"; - })(D = N1.D || (N1.D = {})); - var Value = N1.Value = 5; -})(N || (N = {})); -export class A { - d; - b; - c = 1; - e; - constructor(d = D.A){ - this.d = d; - const e = "foo"; - this.e = e; - console.log(N.Value); - } -} -"#; - assert_eq!(&code[..expected_text.len()], expected_text); - assert!( - code.contains("\n//# sourceMappingURL=data:application/json;base64,") - ); - assert!(maybe_map.is_none()); - } - - #[test] - fn test_transpile_tsx() { - let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap(); - let source = r#" - export class A { - render() { - return <div><span></span></div> - } - } - "#; - let module = parse_module(ParseParams { - specifier: specifier.as_str().to_string(), - source: SourceTextInfo::from_string(source.to_string()), - media_type: deno_ast::MediaType::Tsx, - capture_tokens: false, - maybe_syntax: None, - scope_analysis: true, // ensure scope analysis doesn't conflict with a second resolver pass - }) - .unwrap(); - let (code, _) = transpile(&module, &EmitOptions::default()).unwrap(); - assert!(code.contains("React.createElement(\"div\", null")); - } - - #[test] - fn test_transpile_jsx_pragma() { - let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap(); - let source = r#" -/** @jsx h */ -/** @jsxFrag Fragment */ -import { h, Fragment } from "https://deno.land/x/mod.ts"; - -function App() { - return ( - <div><></></div> - ); -}"#; - let module = parse_module(ParseParams { - specifier: specifier.as_str().to_string(), - source: SourceTextInfo::from_string(source.to_string()), - media_type: deno_ast::MediaType::Jsx, - capture_tokens: false, - maybe_syntax: None, - scope_analysis: true, - }) - .unwrap(); - let (code, _) = transpile(&module, &EmitOptions::default()).unwrap(); - let expected = r#"/** @jsx h */ /** @jsxFrag Fragment */ import { h, Fragment } from "https://deno.land/x/mod.ts"; -function App() { - return(/*#__PURE__*/ h("div", null, /*#__PURE__*/ h(Fragment, null))); -}"#; - assert_eq!(&code[..expected.len()], expected); - } - - #[test] - fn test_transpile_jsx_import_source_pragma() { - let specifier = resolve_url_or_path("https://deno.land/x/mod.tsx").unwrap(); - let source = r#" -/** @jsxImportSource jsx_lib */ - -function App() { - return ( - <div><></></div> - ); -}"#; - let module = parse_module(ParseParams { - specifier: specifier.as_str().to_string(), - source: SourceTextInfo::from_string(source.to_string()), - media_type: deno_ast::MediaType::Jsx, - capture_tokens: false, - maybe_syntax: None, - scope_analysis: true, - }) - .unwrap(); - let (code, _) = transpile(&module, &EmitOptions::default()).unwrap(); - let expected = r#"import { jsx as _jsx, Fragment as _Fragment } from "jsx_lib/jsx-runtime"; -/** @jsxImportSource jsx_lib */ function App() { - return(/*#__PURE__*/ _jsx("div", { - children: /*#__PURE__*/ _jsx(_Fragment, {}) - })); -"#; - assert_eq!(&code[..expected.len()], expected); - } - - #[test] - fn test_transpile_jsx_import_source_no_pragma() { - let specifier = resolve_url_or_path("https://deno.land/x/mod.tsx").unwrap(); - let source = r#" -function App() { - return ( - <div><></></div> - ); -}"#; - let module = parse_module(ParseParams { - specifier: specifier.as_str().to_string(), - source: SourceTextInfo::from_string(source.to_string()), - media_type: deno_ast::MediaType::Jsx, - capture_tokens: false, - maybe_syntax: None, - scope_analysis: true, - }) - .unwrap(); - let emit_options = EmitOptions { - jsx_automatic: true, - jsx_import_source: Some("jsx_lib".to_string()), - ..Default::default() - }; - let (code, _) = transpile(&module, &emit_options).unwrap(); - let expected = r#"import { jsx as _jsx, Fragment as _Fragment } from "jsx_lib/jsx-runtime"; -function App() { - return(/*#__PURE__*/ _jsx("div", { - children: /*#__PURE__*/ _jsx(_Fragment, {}) - })); -} -"#; - assert_eq!(&code[..expected.len()], expected); - } - - // TODO(@kitsonk) https://github.com/swc-project/swc/issues/2656 - // #[test] - // fn test_transpile_jsx_import_source_no_pragma_dev() { - // let specifier = resolve_url_or_path("https://deno.land/x/mod.tsx").unwrap(); - // let source = r#" - // function App() { - // return ( - // <div><></></div> - // ); - // }"#; - // let module = parse_module(ParseParams { - // specifier: specifier.as_str().to_string(), - // source: SourceTextInfo::from_string(source.to_string()), - // media_type: deno_ast::MediaType::Jsx, - // capture_tokens: false, - // maybe_syntax: None, - // scope_analysis: true, - // }) - // .unwrap(); - // let emit_options = EmitOptions { - // jsx_automatic: true, - // jsx_import_source: Some("jsx_lib".to_string()), - // jsx_development: true, - // ..Default::default() - // }; - // let (code, _) = transpile(&module, &emit_options).unwrap(); - // let expected = r#"import { jsx as _jsx, Fragment as _Fragment } from "jsx_lib/jsx-dev-runtime"; - // function App() { - // return(/*#__PURE__*/ _jsx("div", { - // children: /*#__PURE__*/ _jsx(_Fragment, { - // }) - // })); - // } - // "#; - // assert_eq!(&code[..expected.len()], expected); - // } - - #[test] - fn test_transpile_decorators() { - let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap(); - let source = r#" - function enumerable(value: boolean) { - return function ( - _target: any, - _propertyKey: string, - descriptor: PropertyDescriptor, - ) { - descriptor.enumerable = value; - }; - } - - export class A { - @enumerable(false) - a() { - Test.value; - } - } - "#; - let module = parse_module(ParseParams { - specifier: specifier.as_str().to_string(), - source: SourceTextInfo::from_string(source.to_string()), - media_type: deno_ast::MediaType::TypeScript, - capture_tokens: false, - maybe_syntax: None, - scope_analysis: false, - }) - .unwrap(); - let (code, _) = transpile(&module, &EmitOptions::default()).unwrap(); - assert!(code.contains("_applyDecoratedDescriptor(")); - } - - #[test] - fn transpile_handle_code_nested_in_ts_nodes_with_jsx_pass() { - // from issue 12409 - let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap(); - let source = r#" -export function g() { - let algorithm: any - algorithm = {} - - return <Promise>( - test(algorithm, false, keyUsages) - ) -} - "#; - let module = parse_module(ParseParams { - specifier: specifier.as_str().to_string(), - source: SourceTextInfo::from_string(source.to_string()), - media_type: deno_ast::MediaType::TypeScript, - capture_tokens: false, - maybe_syntax: None, - scope_analysis: false, - }) - .unwrap(); - let emit_options = EmitOptions { - transform_jsx: true, - ..Default::default() - }; - let (code, _) = transpile(&module, &emit_options).unwrap(); - let expected = r#"export function g() { - let algorithm; - algorithm = {}; - return test(algorithm, false, keyUsages); -}"#; - assert_eq!(&code[..expected.len()], expected); - } - - #[test] - fn diagnostic_jsx_spread_instead_of_panic() { - let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap(); - let source = r#"const A = () => { - return <div>{...[]}</div>; -};"#; - let parsed_source = parse_module(ParseParams { - specifier: specifier.as_str().to_string(), - source: SourceTextInfo::from_string(source.to_string()), - media_type: deno_ast::MediaType::Tsx, - capture_tokens: false, - maybe_syntax: None, - scope_analysis: false, - }) - .unwrap(); - let err = transpile(&parsed_source, &Default::default()) - .err() - .unwrap(); - - assert_eq!(err.to_string(), "Spread children are not supported in React. at https://deno.land/x/mod.ts:2:15"); - } -} diff --git a/cli/ast/transforms.rs b/cli/ast/transforms.rs deleted file mode 100644 index a89edc01d..000000000 --- a/cli/ast/transforms.rs +++ /dev/null @@ -1,524 +0,0 @@ -use deno_ast::swc::ast as swc_ast; -use deno_ast::swc::common::DUMMY_SP; -use deno_ast::swc::visit::noop_fold_type; -use deno_ast::swc::visit::Fold; - -/// Transforms import declarations to variable declarations -/// with a dynamic import. This is used to provide import -/// declaration support in the REPL. -pub struct DownlevelImportsFolder; - -impl Fold for DownlevelImportsFolder { - noop_fold_type!(); // skip typescript specific nodes - - fn fold_module_item( - &mut self, - module_item: swc_ast::ModuleItem, - ) -> swc_ast::ModuleItem { - use deno_ast::swc::ast::*; - - match module_item { - ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl)) => { - // Handle type only imports - if import_decl.type_only { - // should have no side effects - return create_empty_stmt(); - } - - // The initializer (ex. `await import('./mod.ts')`) - let initializer = - create_await_import_expr(&import_decl.src.value, import_decl.asserts); - - // Handle imports for the side effects - // ex. `import "module.ts"` -> `await import("module.ts");` - if import_decl.specifiers.is_empty() { - return ModuleItem::Stmt(Stmt::Expr(ExprStmt { - span: DUMMY_SP, - expr: initializer, - })); - } - - // Collect the specifiers and create the variable statement - let named_import_props = import_decl - .specifiers - .iter() - .filter_map(|specifier| match specifier { - ImportSpecifier::Default(specifier) => Some(create_key_value( - "default".to_string(), - specifier.local.sym.to_string(), - )), - ImportSpecifier::Named(specifier) => { - Some(match specifier.imported.as_ref() { - Some(name) => create_key_value( - match name { - ModuleExportName::Ident(ident) => ident.sym.to_string(), - ModuleExportName::Str(str) => str.value.to_string(), - }, - specifier.local.sym.to_string(), - ), - None => create_assignment(specifier.local.sym.to_string()), - }) - } - ImportSpecifier::Namespace(_) => None, - }) - .collect::<Vec<_>>(); - let namespace_import_name = - import_decl - .specifiers - .iter() - .find_map(|specifier| match specifier { - ImportSpecifier::Namespace(specifier) => { - Some(create_binding_ident(specifier.local.sym.to_string())) - } - _ => None, - }); - - ModuleItem::Stmt(Stmt::Decl(Decl::Var(VarDecl { - span: DUMMY_SP, - kind: VarDeclKind::Const, - declare: false, - decls: { - let mut decls = Vec::new(); - - if !named_import_props.is_empty() { - decls.push(VarDeclarator { - span: DUMMY_SP, - name: Pat::Object(ObjectPat { - span: DUMMY_SP, - optional: false, - props: named_import_props, - type_ann: None, - }), - definite: false, - init: Some(initializer.clone()), - }); - } - if let Some(namespace_import) = namespace_import_name { - decls.push(VarDeclarator { - span: DUMMY_SP, - name: Pat::Ident(namespace_import), - definite: false, - init: Some(initializer), - }); - } - - decls - }, - }))) - } - _ => module_item, - } - } -} - -/// Strips export declarations and exports on named exports for the REPL. -pub struct StripExportsFolder; - -impl Fold for StripExportsFolder { - noop_fold_type!(); // skip typescript specific nodes - - fn fold_module_item( - &mut self, - module_item: swc_ast::ModuleItem, - ) -> swc_ast::ModuleItem { - use deno_ast::swc::ast::*; - - match module_item { - ModuleItem::ModuleDecl(ModuleDecl::ExportAll(export_all)) => { - ModuleItem::Stmt(Stmt::Expr(ExprStmt { - span: DUMMY_SP, - expr: create_await_import_expr( - &export_all.src.value, - export_all.asserts, - ), - })) - } - ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(export_named)) => { - if let Some(src) = export_named.src { - ModuleItem::Stmt(Stmt::Expr(ExprStmt { - span: DUMMY_SP, - expr: create_await_import_expr(&src.value, export_named.asserts), - })) - } else { - create_empty_stmt() - } - } - ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr(default_expr)) => { - // transform a default export expression to its expression - ModuleItem::Stmt(Stmt::Expr(ExprStmt { - span: DUMMY_SP, - expr: default_expr.expr, - })) - } - ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(export_decl)) => { - // strip the export keyword on an exported declaration - ModuleItem::Stmt(Stmt::Decl(export_decl.decl)) - } - ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(default_decl)) => { - // only keep named default exports - match default_decl.decl { - DefaultDecl::Fn(FnExpr { - ident: Some(ident), - function, - }) => ModuleItem::Stmt(Stmt::Decl(Decl::Fn(FnDecl { - declare: false, - ident, - function, - }))), - DefaultDecl::Class(ClassExpr { - ident: Some(ident), - class, - }) => ModuleItem::Stmt(Stmt::Decl(Decl::Class(ClassDecl { - declare: false, - ident, - class, - }))), - _ => create_empty_stmt(), - } - } - _ => module_item, - } - } -} - -fn create_empty_stmt() -> swc_ast::ModuleItem { - use swc_ast::*; - ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })) -} - -fn create_binding_ident(name: String) -> swc_ast::BindingIdent { - swc_ast::BindingIdent { - id: create_ident(name), - type_ann: None, - } -} - -fn create_ident(name: String) -> swc_ast::Ident { - swc_ast::Ident { - span: DUMMY_SP, - sym: name.into(), - optional: false, - } -} - -fn create_key_value(key: String, value: String) -> swc_ast::ObjectPatProp { - swc_ast::ObjectPatProp::KeyValue(swc_ast::KeyValuePatProp { - // use a string literal because it will work in more scenarios than an identifier - key: swc_ast::PropName::Str(swc_ast::Str { - span: DUMMY_SP, - value: key.into(), - has_escape: false, - kind: swc_ast::StrKind::Synthesized, - }), - value: Box::new(swc_ast::Pat::Ident(swc_ast::BindingIdent { - id: swc_ast::Ident { - span: DUMMY_SP, - sym: value.into(), - optional: false, - }, - type_ann: None, - })), - }) -} - -fn create_await_import_expr( - module_specifier: &str, - maybe_asserts: Option<swc_ast::ObjectLit>, -) -> Box<swc_ast::Expr> { - use swc_ast::*; - let mut args = vec![ExprOrSpread { - spread: None, - expr: Box::new(Expr::Lit(Lit::Str(Str { - span: DUMMY_SP, - has_escape: false, - kind: StrKind::Normal { - contains_quote: false, - }, - value: module_specifier.into(), - }))), - }]; - - // add assert object if it exists - if let Some(asserts) = maybe_asserts { - args.push(ExprOrSpread { - spread: None, - expr: Box::new(Expr::Object(ObjectLit { - span: DUMMY_SP, - props: vec![PropOrSpread::Prop(Box::new(Prop::KeyValue( - KeyValueProp { - key: PropName::Ident(create_ident("assert".to_string())), - value: Box::new(Expr::Object(asserts)), - }, - )))], - })), - }) - } - - Box::new(Expr::Await(AwaitExpr { - span: DUMMY_SP, - arg: Box::new(Expr::Call(CallExpr { - span: DUMMY_SP, - callee: ExprOrSuper::Expr(Box::new(Expr::Ident(Ident { - span: DUMMY_SP, - sym: "import".into(), - optional: false, - }))), - args, - type_args: None, - })), - })) -} - -fn create_assignment(key: String) -> swc_ast::ObjectPatProp { - swc_ast::ObjectPatProp::Assign(swc_ast::AssignPatProp { - span: DUMMY_SP, - key: create_ident(key), - value: None, - }) -} - -#[cfg(test)] -mod test { - use deno_ast::swc::ast::Module; - use deno_ast::swc::codegen::text_writer::JsWriter; - use deno_ast::swc::codegen::Node; - use deno_ast::swc::common::FileName; - use deno_ast::swc::common::SourceMap; - use deno_ast::swc::parser::Parser; - use deno_ast::swc::parser::StringInput; - use deno_ast::swc::parser::Syntax; - use deno_ast::swc::parser::TsConfig; - use deno_ast::swc::visit::Fold; - use deno_ast::swc::visit::FoldWith; - use deno_ast::ModuleSpecifier; - use pretty_assertions::assert_eq; - use std::rc::Rc; - - use super::*; - - #[test] - fn test_downlevel_imports_type_only() { - test_transform( - DownlevelImportsFolder, - r#"import type { test } from "./mod.ts";"#, - ";", - ); - } - - #[test] - fn test_downlevel_imports_specifier_only() { - test_transform( - DownlevelImportsFolder, - r#"import "./mod.ts";"#, - r#"await import("./mod.ts");"#, - ); - - test_transform( - DownlevelImportsFolder, - r#"import {} from "./mod.ts";"#, - r#"await import("./mod.ts");"#, - ); - } - - #[test] - fn test_downlevel_imports_default() { - test_transform( - DownlevelImportsFolder, - r#"import mod from "./mod.ts";"#, - r#"const { "default": mod } = await import("./mod.ts");"#, - ); - } - - #[test] - fn test_downlevel_imports_named() { - test_transform( - DownlevelImportsFolder, - r#"import { A } from "./mod.ts";"#, - r#"const { A } = await import("./mod.ts");"#, - ); - - test_transform( - DownlevelImportsFolder, - r#"import { A, B, C } from "./mod.ts";"#, - r#"const { A , B , C } = await import("./mod.ts");"#, - ); - - test_transform( - DownlevelImportsFolder, - r#"import { A as LocalA, B, C as LocalC } from "./mod.ts";"#, - r#"const { "A": LocalA , B , "C": LocalC } = await import("./mod.ts");"#, - ); - } - - #[test] - fn test_downlevel_imports_namespace() { - test_transform( - DownlevelImportsFolder, - r#"import * as mod from "./mod.ts";"#, - r#"const mod = await import("./mod.ts");"#, - ); - } - - #[test] - fn test_downlevel_imports_mixed() { - test_transform( - DownlevelImportsFolder, - r#"import myDefault, { A, B as LocalB } from "./mod.ts";"#, - r#"const { "default": myDefault , A , "B": LocalB } = await import("./mod.ts");"#, - ); - - test_transform( - DownlevelImportsFolder, - r#"import myDefault, * as mod from "./mod.ts";"#, - r#"const { "default": myDefault } = await import("./mod.ts"), mod = await import("./mod.ts");"#, - ); - } - - #[test] - fn test_downlevel_imports_assertions() { - test_transform( - DownlevelImportsFolder, - r#"import data from "./mod.json" assert { type: "json" };"#, - "const { \"default\": data } = await import(\"./mod.json\", {\n assert: {\n type: \"json\"\n }\n});", - ); - } - - #[test] - fn test_strip_exports_export_all() { - test_transform( - StripExportsFolder, - r#"export * from "./test.ts";"#, - r#"await import("./test.ts");"#, - ); - } - - #[test] - fn test_strip_exports_export_named() { - test_transform( - StripExportsFolder, - r#"export { test } from "./test.ts";"#, - r#"await import("./test.ts");"#, - ); - - test_transform(StripExportsFolder, r#"export { test };"#, ";"); - } - - #[test] - fn test_strip_exports_assertions() { - test_transform( - StripExportsFolder, - r#"export { default as data } from "./mod.json" assert { type: "json" };"#, - "await import(\"./mod.json\", {\n assert: {\n type: \"json\"\n }\n});", - ); - } - - #[test] - fn test_strip_exports_export_all_assertions() { - // even though this doesn't really make sense for someone to do - test_transform( - StripExportsFolder, - r#"export * from "./mod.json" assert { type: "json" };"#, - "await import(\"./mod.json\", {\n assert: {\n type: \"json\"\n }\n});", - ); - } - - #[test] - fn test_strip_exports_export_default_expr() { - test_transform(StripExportsFolder, "export default 5;", "5;"); - } - - #[test] - fn test_strip_exports_export_default_decl_name() { - test_transform( - StripExportsFolder, - "export default class Test {}", - "class Test {\n}", - ); - - test_transform( - StripExportsFolder, - "export default function test() {}", - "function test() {}", - ); - } - - #[test] - fn test_strip_exports_export_default_decl_no_name() { - test_transform(StripExportsFolder, "export default class {}", ";"); - - test_transform(StripExportsFolder, "export default function() {}", ";"); - } - - #[test] - fn test_strip_exports_export_named_decls() { - test_transform( - StripExportsFolder, - "export class Test {}", - "class Test {\n}", - ); - - test_transform( - StripExportsFolder, - "export function test() {}", - "function test() {}", - ); - - test_transform(StripExportsFolder, "export enum Test {}", "enum Test {\n}"); - - test_transform( - StripExportsFolder, - "export namespace Test {}", - "module Test {\n}", - ); - } - - #[test] - fn test_strip_exports_not_in_namespace() { - test_transform( - StripExportsFolder, - "namespace Test { export class Test {} }", - "module Test {\n export class Test {\n }\n}", - ); - } - - fn test_transform( - mut transform: impl Fold, - src: &str, - expected_output: &str, - ) { - let (source_map, module) = parse(src); - let output = print(source_map, module.fold_with(&mut transform)); - assert_eq!(output, format!("{}\n", expected_output)); - } - - fn parse(src: &str) -> (Rc<SourceMap>, Module) { - let source_map = Rc::new(SourceMap::default()); - let source_file = source_map.new_source_file( - FileName::Url(ModuleSpecifier::parse("file:///test.ts").unwrap()), - src.to_string(), - ); - let input = StringInput::from(&*source_file); - let syntax = Syntax::Typescript(TsConfig { - ..Default::default() - }); - let mut parser = Parser::new(syntax, input, None); - (source_map, parser.parse_module().unwrap()) - } - - fn print(source_map: Rc<SourceMap>, module: Module) -> String { - let mut buf = vec![]; - { - let writer = - Box::new(JsWriter::new(source_map.clone(), "\n", &mut buf, None)); - let config = deno_ast::swc::codegen::Config { minify: false }; - let mut emitter = deno_ast::swc::codegen::Emitter { - cfg: config, - comments: None, - cm: source_map, - wr: writer, - }; - module.emit_with(&mut emitter).unwrap(); - } - String::from_utf8(buf).unwrap() - } -} diff --git a/cli/cache.rs b/cli/cache.rs index 218c699a1..1075230d1 100644 --- a/cli/cache.rs +++ b/cli/cache.rs @@ -149,7 +149,7 @@ impl Loader for FetchCacher { let file_fetcher = self.file_fetcher.clone(); async move { - let load_result = file_fetcher + file_fetcher .fetch(&specifier, &mut permissions) .await .map_or_else( @@ -170,9 +170,7 @@ impl Loader for FetchCacher { content: file.source, })) }, - ); - - (specifier, load_result) + ) } .boxed() } @@ -295,7 +293,7 @@ impl Loader for MemoryCacher { maybe_headers: None, content: c.to_owned(), }); - Box::pin(future::ready((specifier.clone(), Ok(response)))) + Box::pin(future::ready(Ok(response))) } } diff --git a/cli/emit.rs b/cli/emit.rs index 35d6f1110..e21013b61 100644 --- a/cli/emit.rs +++ b/cli/emit.rs @@ -4,10 +4,10 @@ //! populate a cache, emit files, and transform a graph into the structures for //! loading into an isolate. -use crate::ast; use crate::cache::CacheType; use crate::cache::Cacher; use crate::colors; +use crate::config_file; use crate::config_file::ConfigFile; use crate::config_file::IgnoredCompilerOptions; use crate::config_file::TsConfig; @@ -15,10 +15,25 @@ use crate::diagnostics::Diagnostics; use crate::flags; use crate::graph_util::GraphData; use crate::graph_util::ModuleEntry; +use crate::text_encoding::strip_bom; use crate::tsc; use crate::version; +use deno_ast::get_syntax; use deno_ast::swc; +use deno_ast::swc::bundler::Hook; +use deno_ast::swc::bundler::ModuleRecord; +use deno_ast::swc::common::comments::SingleThreadedComments; +use deno_ast::swc::common::FileName; +use deno_ast::swc::common::Mark; +use deno_ast::swc::common::SourceMap; +use deno_ast::swc::common::Span; +use deno_ast::swc::common::Spanned; +use deno_ast::swc::parser::error::Error as SwcError; +use deno_ast::swc::parser::lexer::Lexer; +use deno_ast::swc::parser::StringInput; +use deno_ast::Diagnostic; +use deno_ast::LineAndColumnDisplay; use deno_core::anyhow::anyhow; use deno_core::anyhow::Context; use deno_core::error::AnyError; @@ -27,6 +42,7 @@ use deno_core::serde::Deserialize; use deno_core::serde::Deserializer; use deno_core::serde::Serialize; use deno_core::serde::Serializer; +use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; use deno_core::ModuleSpecifier; @@ -517,7 +533,7 @@ pub(crate) struct BundleOptions { /// of modules from the graph. struct BundleLoader<'a> { cm: Rc<swc::common::SourceMap>, - emit_options: &'a ast::EmitOptions, + emit_options: &'a deno_ast::EmitOptions, graph: &'a ModuleGraph, } @@ -529,7 +545,7 @@ impl swc::bundler::Load for BundleLoader<'_> { match file_name { swc::common::FileName::Url(specifier) => { if let Some(m) = self.graph.get(specifier) { - let (fm, module) = ast::transpile_module( + let (fm, module) = transpile_module( specifier, m.maybe_source().unwrap_or(""), *m.media_type(), @@ -556,6 +572,77 @@ impl swc::bundler::Load for BundleLoader<'_> { } } +/// Transpiles a source module into an swc SourceFile. +fn transpile_module( + specifier: &ModuleSpecifier, + source: &str, + media_type: MediaType, + options: &deno_ast::EmitOptions, + cm: Rc<swc::common::SourceMap>, +) -> Result<(Rc<swc::common::SourceFile>, swc::ast::Module), AnyError> { + let source = strip_bom(source); + let source = if media_type == MediaType::Json { + format!( + "export default JSON.parse(`{}`);", + source.replace("${", "\\${").replace('`', "\\`") + ) + } else { + source.to_string() + }; + let source_file = + cm.new_source_file(FileName::Url(specifier.clone()), source); + let input = StringInput::from(&*source_file); + let comments = SingleThreadedComments::default(); + let syntax = if media_type == MediaType::Json { + get_syntax(MediaType::JavaScript) + } else { + get_syntax(media_type) + }; + let lexer = Lexer::new(syntax, deno_ast::ES_VERSION, input, Some(&comments)); + let mut parser = swc::parser::Parser::new_from(lexer); + let module = parser + .parse_module() + .map_err(|e| swc_err_to_diagnostic(&cm, specifier, e))?; + let diagnostics = parser + .take_errors() + .into_iter() + .map(|e| swc_err_to_diagnostic(&cm, specifier, e)) + .collect::<Vec<_>>(); + + let top_level_mark = Mark::fresh(Mark::root()); + let program = deno_ast::fold_program( + swc::ast::Program::Module(module), + options, + cm, + &comments, + top_level_mark, + &diagnostics, + )?; + let module = match program { + swc::ast::Program::Module(module) => module, + _ => unreachable!(), + }; + + Ok((source_file, module)) +} + +fn swc_err_to_diagnostic( + source_map: &SourceMap, + specifier: &ModuleSpecifier, + err: SwcError, +) -> Diagnostic { + let location = source_map.lookup_char_pos(err.span().lo); + Diagnostic { + specifier: specifier.to_string(), + span: err.span(), + display_position: LineAndColumnDisplay { + line_number: location.line, + column_number: location.col_display + 1, + }, + kind: err.into_kind(), + } +} + /// A resolver implementation for swc that resolves specifiers from the graph. struct BundleResolver<'a>(&'a ModuleGraph); @@ -597,8 +684,8 @@ pub(crate) fn bundle( ) -> Result<(String, Option<String>), AnyError> { let globals = swc::common::Globals::new(); deno_ast::swc::common::GLOBALS.set(&globals, || { - let emit_options: ast::EmitOptions = options.ts_config.into(); - let source_map_config = ast::SourceMapConfig { + let emit_options: deno_ast::EmitOptions = options.ts_config.into(); + let source_map_config = deno_ast::SourceMapConfig { inline_sources: emit_options.inline_sources, }; @@ -617,7 +704,7 @@ pub(crate) fn bundle( }; // This hook will rewrite the `import.meta` when bundling to give a consistent // behavior between bundled and unbundled code. - let hook = Box::new(ast::BundleHook); + let hook = Box::new(BundleHook); let mut bundler = swc::bundler::Bundler::new( &globals, cm.clone(), @@ -722,11 +809,10 @@ pub(crate) fn emit( if is_valid && !needs_reload { continue; } - let (emit, maybe_map) = - ast::transpile(&module.parsed_source, &emit_options)?; + let transpiled_source = module.parsed_source.transpile(&emit_options)?; emit_count += 1; - cache.set(CacheType::Emit, &module.specifier, emit)?; - if let Some(map) = maybe_map { + cache.set(CacheType::Emit, &module.specifier, transpiled_source.text)?; + if let Some(map) = transpiled_source.source_map { cache.set(CacheType::SourceMap, &module.specifier, map)?; } if !is_valid { @@ -861,6 +947,80 @@ pub(crate) fn to_file_map( files } +/// This contains the logic for Deno to rewrite the `import.meta` when bundling. +pub struct BundleHook; + +impl Hook for BundleHook { + fn get_import_meta_props( + &self, + span: Span, + module_record: &ModuleRecord, + ) -> Result<Vec<deno_ast::swc::ast::KeyValueProp>, AnyError> { + use deno_ast::swc::ast; + + Ok(vec![ + ast::KeyValueProp { + key: ast::PropName::Ident(ast::Ident::new("url".into(), span)), + value: Box::new(ast::Expr::Lit(ast::Lit::Str(ast::Str { + span, + value: module_record.file_name.to_string().into(), + kind: ast::StrKind::Synthesized, + has_escape: false, + }))), + }, + ast::KeyValueProp { + key: ast::PropName::Ident(ast::Ident::new("main".into(), span)), + value: Box::new(if module_record.is_entry { + ast::Expr::Member(ast::MemberExpr { + span, + obj: Box::new(ast::Expr::MetaProp(ast::MetaPropExpr { + span, + kind: ast::MetaPropKind::ImportMeta, + })), + prop: ast::MemberProp::Ident(ast::Ident::new("main".into(), span)), + }) + } else { + ast::Expr::Lit(ast::Lit::Bool(ast::Bool { span, value: false })) + }), + }, + ]) + } +} + +impl From<config_file::TsConfig> for deno_ast::EmitOptions { + fn from(config: config_file::TsConfig) -> Self { + let options: config_file::EmitConfigOptions = + serde_json::from_value(config.0).unwrap(); + let imports_not_used_as_values = + match options.imports_not_used_as_values.as_str() { + "preserve" => deno_ast::ImportsNotUsedAsValues::Preserve, + "error" => deno_ast::ImportsNotUsedAsValues::Error, + _ => deno_ast::ImportsNotUsedAsValues::Remove, + }; + let (transform_jsx, jsx_automatic, jsx_development) = + match options.jsx.as_str() { + "react" => (true, false, false), + "react-jsx" => (true, true, false), + "react-jsxdev" => (true, true, true), + _ => (false, false, false), + }; + deno_ast::EmitOptions { + emit_metadata: options.emit_decorator_metadata, + imports_not_used_as_values, + inline_source_map: options.inline_source_map, + inline_sources: options.inline_sources, + source_map: options.source_map, + jsx_automatic, + jsx_development, + jsx_factory: options.jsx_factory, + jsx_fragment_factory: options.jsx_fragment_factory, + jsx_import_source: options.jsx_import_source, + transform_jsx, + var_decl_imports: false, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/cli/lsp/cache.rs b/cli/lsp/cache.rs index 16ad76451..562ad78b0 100644 --- a/cli/lsp/cache.rs +++ b/cli/lsp/cache.rs @@ -80,6 +80,7 @@ impl CacheServer { maybe_resolver, None, None, + None, ) .await; diff --git a/cli/lsp/code_lens.rs b/cli/lsp/code_lens.rs index d0034069d..853a16f1f 100644 --- a/cli/lsp/code_lens.rs +++ b/cli/lsp/code_lens.rs @@ -157,7 +157,7 @@ impl DenoTestCollector { impl Visit for DenoTestCollector { fn visit_call_expr(&mut self, node: &ast::CallExpr) { - if let ast::ExprOrSuper::Expr(callee_expr) = &node.callee { + if let ast::Callee::Expr(callee_expr) = &node.callee { match callee_expr.as_ref() { ast::Expr::Ident(ident) => { if self.test_vars.contains(&ident.sym.to_string()) { @@ -165,13 +165,11 @@ impl Visit for DenoTestCollector { } } ast::Expr::Member(member_expr) => { - if let ast::Expr::Ident(ns_prop_ident) = member_expr.prop.as_ref() { + if let ast::MemberProp::Ident(ns_prop_ident) = &member_expr.prop { if ns_prop_ident.sym.to_string() == "test" { - if let ast::ExprOrSuper::Expr(obj_expr) = &member_expr.obj { - if let ast::Expr::Ident(ident) = obj_expr.as_ref() { - if ident.sym.to_string() == "Deno" { - self.check_call_expr(node, &ns_prop_ident.span); - } + if let ast::Expr::Ident(ident) = member_expr.obj.as_ref() { + if ident.sym.to_string() == "Deno" { + self.check_call_expr(node, &ns_prop_ident.span); } } } @@ -219,16 +217,12 @@ impl Visit for DenoTestCollector { } // Identify variable assignments where the init is `Deno.test` ast::Expr::Member(member_expr) => { - if let ast::ExprOrSuper::Expr(expr) = &member_expr.obj { - if let ast::Expr::Ident(obj_ident) = expr.as_ref() { - if obj_ident.sym.to_string() == "Deno" { - if let ast::Expr::Ident(prop_ident) = - &member_expr.prop.as_ref() - { - if prop_ident.sym.to_string() == "test" { - if let ast::Pat::Ident(binding_ident) = &decl.name { - self.test_vars.insert(binding_ident.id.sym.to_string()); - } + if let ast::Expr::Ident(obj_ident) = member_expr.obj.as_ref() { + if obj_ident.sym.to_string() == "Deno" { + if let ast::MemberProp::Ident(prop_ident) = &member_expr.prop { + if prop_ident.sym.to_string() == "test" { + if let ast::Pat::Ident(binding_ident) = &decl.name { + self.test_vars.insert(binding_ident.id.sym.to_string()); } } } diff --git a/cli/main.rs b/cli/main.rs index d1fda4727..b845a4f49 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -1,6 +1,5 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -mod ast; mod auth_tokens; mod cache; mod checksum; @@ -475,6 +474,7 @@ async fn info_command( maybe_resolver, maybe_locker, None, + None, ) .await; @@ -654,6 +654,7 @@ async fn create_graph_and_maybe_check( maybe_resolver, maybe_locker, None, + None, ) .await, ); @@ -999,6 +1000,7 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<i32, AnyError> { maybe_resolver, maybe_locker, None, + None, ) .await; let check_js = ps diff --git a/cli/ops/runtime_compiler.rs b/cli/ops/runtime_compiler.rs index 50268b7eb..3d079e2fb 100644 --- a/cli/ops/runtime_compiler.rs +++ b/cli/ops/runtime_compiler.rs @@ -217,6 +217,7 @@ async fn op_emit( maybe_resolver, None, None, + None, ) .await, ); diff --git a/cli/proc_state.rs b/cli/proc_state.rs index ceff64c54..253878872 100644 --- a/cli/proc_state.rs +++ b/cli/proc_state.rs @@ -382,10 +382,9 @@ impl ProcState { let graph_data = self.graph_data.read(); let found_specifier = graph_data.follow_redirect(specifier); match graph_data.get(&found_specifier) { - Some(_) if !self.reload => Box::pin(futures::future::ready(( - specifier.clone(), - Err(anyhow!("")), - ))), + Some(_) if !self.reload => { + Box::pin(futures::future::ready(Err(anyhow!("")))) + } _ => self.inner.load(specifier, is_dynamic), } } @@ -403,6 +402,7 @@ impl ProcState { maybe_resolver, maybe_locker, None, + None, ) .await; // If there was a locker, validate the integrity of all the modules in the diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index 5b258a540..1ef2e29eb 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -30,10 +30,10 @@ struct StubDocLoader; impl Loader for StubDocLoader { fn load( &mut self, - specifier: &ModuleSpecifier, + _specifier: &ModuleSpecifier, _is_dynamic: bool, ) -> LoadFuture { - Box::pin(future::ready((specifier.clone(), Ok(None)))) + Box::pin(future::ready(Ok(None))) } } @@ -74,18 +74,16 @@ impl Loader for DocLoader { let specifier = specifier.clone(); let ps = self.ps.clone(); async move { - let result = ps - .file_fetcher + ps.file_fetcher .fetch(&specifier, &mut Permissions::allow_all()) .await .map(|file| { Some(LoadResponse { - specifier: specifier.clone(), + specifier, content: file.source.clone(), maybe_headers: file.maybe_headers, }) - }); - (specifier.clone(), result) + }) } .boxed_local() } @@ -113,6 +111,7 @@ pub async fn print_docs( None, None, None, + None, ) .await; let doc_parser = @@ -152,6 +151,7 @@ pub async fn print_docs( Some(&resolver), None, None, + None, ) .await; let doc_parser = diff --git a/cli/tools/repl/session.rs b/cli/tools/repl/session.rs index d8276396a..5d458189f 100644 --- a/cli/tools/repl/session.rs +++ b/cli/tools/repl/session.rs @@ -1,10 +1,9 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -use crate::ast::transpile; -use crate::ast::Diagnostics; -use crate::ast::ImportsNotUsedAsValues; use crate::colors; use crate::lsp::ReplLanguageServer; +use deno_ast::DiagnosticsError; +use deno_ast::ImportsNotUsedAsValues; use deno_core::error::AnyError; use deno_core::futures::FutureExt; use deno_core::serde_json::json; @@ -184,7 +183,7 @@ impl ReplSession { Some(diagnostic) => { Ok(EvaluationOutput::Error(format_diagnostic(diagnostic))) } - None => match err.downcast_ref::<Diagnostics>() { + None => match err.downcast_ref::<DiagnosticsError>() { Some(diagnostics) => Ok(EvaluationOutput::Error( diagnostics .0 @@ -311,9 +310,8 @@ impl ReplSession { scope_analysis: false, })?; - let transpiled_src = transpile( - &parsed_module, - &crate::ast::EmitOptions { + let transpiled_src = parsed_module + .transpile(&deno_ast::EmitOptions { emit_metadata: false, source_map: false, inline_source_map: false, @@ -326,10 +324,9 @@ impl ReplSession { jsx_factory: "React.createElement".into(), jsx_fragment_factory: "React.Fragment".into(), jsx_import_source: None, - repl_imports: true, - }, - )? - .0; + var_decl_imports: true, + })? + .text; let value = self .evaluate_expression(&format!( diff --git a/cli/tools/test.rs b/cli/tools/test.rs index e5f03a19c..d991ef1ec 100644 --- a/cli/tools/test.rs +++ b/cli/tools/test.rs @@ -1,6 +1,5 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -use crate::ast::Location; use crate::cache; use crate::cache::CacherLoader; use crate::colors; @@ -535,9 +534,10 @@ async fn test_specifier( } fn extract_files_from_regex_blocks( - location: &Location, + specifier: &ModuleSpecifier, source: &str, media_type: MediaType, + file_line_index: usize, blocks_regex: &Regex, lines_regex: &Regex, ) -> Result<Vec<File>, AnyError> { @@ -594,9 +594,9 @@ fn extract_files_from_regex_blocks( let file_specifier = deno_core::resolve_url_or_path(&format!( "{}${}-{}{}", - location.specifier, - location.line + line_offset, - location.line + line_offset + line_count, + specifier, + file_line_index + line_offset + 1, + file_line_index + line_offset + line_count + 1, file_media_type.as_ts_extension(), )) .unwrap(); @@ -642,12 +642,11 @@ fn extract_files_from_source_comments( true }) .flat_map(|comment| { - let location = Location::from_pos(&parsed_source, comment.span.lo); - extract_files_from_regex_blocks( - &location, + specifier, &comment.text, media_type, + parsed_source.source().line_index(comment.span.lo), &blocks_regex, &lines_regex, ) @@ -663,19 +662,14 @@ fn extract_files_from_fenced_blocks( source: &str, media_type: MediaType, ) -> Result<Vec<File>, AnyError> { - let location = Location { - specifier: specifier.to_string(), - line: 1, - col: 0, - }; - let blocks_regex = Regex::new(r"```([^\r\n]*)\r?\n([\S\s]*?)```")?; let lines_regex = Regex::new(r"(?:\# ?)?(.*)")?; extract_files_from_regex_blocks( - &location, + specifier, source, media_type, + /* file line index */ 0, &blocks_regex, &lines_regex, ) @@ -1150,6 +1144,7 @@ pub async fn run_tests_with_watch( maybe_resolver, maybe_locker, None, + None, ) .await; graph_valid(&graph, !no_check, check_js)?; diff --git a/cli/tsc.rs b/cli/tsc.rs index a2265e36f..001cfaf5d 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -689,7 +689,7 @@ mod tests { }) }) .map_err(|err| err.into()); - Box::pin(future::ready((specifier.clone(), response))) + Box::pin(future::ready(response)) } } @@ -711,6 +711,7 @@ mod tests { None, None, None, + None, ) .await; State::new( @@ -737,6 +738,7 @@ mod tests { None, None, None, + None, ) .await; let config = TsConfig::new(json!({ |