1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-21 15:04:11 -05:00

refactor: move transpiling to deno_ast (#13332)

This commit is contained in:
David Sherret 2022-01-13 11:58:00 -05:00 committed by GitHub
parent 5e2d7737f5
commit f12164646b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 302 additions and 1642 deletions

148
Cargo.lock generated
View file

@ -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",

View file

@ -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"

View file

@ -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 }))
}),
},
])
}
}

View file

@ -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");
}
}

View file

@ -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()
}
}

View file

@ -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)))
}
}

View file

@ -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::*;

View file

@ -80,6 +80,7 @@ impl CacheServer {
maybe_resolver,
None,
None,
None,
)
.await;

View file

@ -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());
}
}
}

View file

@ -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

View file

@ -217,6 +217,7 @@ async fn op_emit(
maybe_resolver,
None,
None,
None,
)
.await,
);

View file

@ -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

View file

@ -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 =

View file

@ -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!(

View file

@ -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)?;

View file

@ -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!({