From 56ea75817e57a908a3894abc7f1b85327d8a2efb Mon Sep 17 00:00:00 2001 From: Andreu Botella Date: Mon, 31 Jan 2022 13:43:32 +0100 Subject: [PATCH] example(core): Add example for TypeScript transpiling via deno_ast (#13545) --- Cargo.lock | 1 + core/Cargo.toml | 1 + core/examples/ts_module_loader.rs | 122 ++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 core/examples/ts_module_loader.rs diff --git a/Cargo.lock b/Cargo.lock index 28c8eb83b8..0d89411c7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -835,6 +835,7 @@ name = "deno_core" version = "0.117.0" dependencies = [ "anyhow", + "deno_ast", "futures", "indexmap", "libc", diff --git a/core/Cargo.toml b/core/Cargo.toml index 9729750854..4bf6b9aebe 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -33,4 +33,5 @@ path = "examples/http_bench_json_ops.rs" # These dependencies are only used for the 'http_bench_*_ops' examples. [dev-dependencies] +deno_ast = { version = "0.9.0", features = ["transpiling"] } tokio = { version = "1.10.1", features = ["full"] } diff --git a/core/examples/ts_module_loader.rs b/core/examples/ts_module_loader.rs new file mode 100644 index 0000000000..963533ffc6 --- /dev/null +++ b/core/examples/ts_module_loader.rs @@ -0,0 +1,122 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +//! This example shows how to use swc to transpile TypeScript and JSX/TSX +//! modules. +//! +//! It will only transpile, not typecheck (like Deno's `--no-check` flag). + +use std::pin::Pin; +use std::rc::Rc; + +use anyhow::anyhow; +use anyhow::bail; +use anyhow::Error; +use deno_ast::MediaType; +use deno_ast::ParseParams; +use deno_ast::SourceTextInfo; +use deno_core::resolve_import; +use deno_core::resolve_path; +use deno_core::JsRuntime; +use deno_core::ModuleLoader; +use deno_core::ModuleSource; +use deno_core::ModuleSourceFuture; +use deno_core::ModuleSpecifier; +use deno_core::ModuleType; +use deno_core::RuntimeOptions; +use futures::FutureExt; + +struct TypescriptModuleLoader; + +impl ModuleLoader for TypescriptModuleLoader { + fn resolve( + &self, + specifier: &str, + referrer: &str, + _is_main: bool, + ) -> Result { + Ok(resolve_import(specifier, referrer)?) + } + + fn load( + &self, + module_specifier: &ModuleSpecifier, + _maybe_referrer: Option, + _is_dyn_import: bool, + ) -> Pin> { + let module_specifier = module_specifier.clone(); + async move { + let path = module_specifier + .to_file_path() + .map_err(|_| anyhow!("Only file: URLs are supported."))?; + + let media_type = MediaType::from(&path); + let (module_type, should_transpile) = match MediaType::from(&path) { + MediaType::JavaScript | MediaType::Mjs | MediaType::Cjs => { + (ModuleType::JavaScript, false) + } + MediaType::Jsx => (ModuleType::JavaScript, true), + MediaType::TypeScript + | MediaType::Mts + | MediaType::Cts + | MediaType::Dts + | MediaType::Dmts + | MediaType::Dcts + | MediaType::Tsx => (ModuleType::JavaScript, true), + MediaType::Json => (ModuleType::Json, false), + _ => bail!("Unknown extension {:?}", path.extension()), + }; + + let code = std::fs::read_to_string(&path)?; + let code = if should_transpile { + let parsed = deno_ast::parse_module(ParseParams { + specifier: module_specifier.to_string(), + source: SourceTextInfo::from_string(code), + media_type, + capture_tokens: false, + scope_analysis: false, + maybe_syntax: None, + })?; + parsed.transpile(&Default::default())?.text + } else { + code + }; + let module = ModuleSource { + code, + module_type, + module_url_specified: module_specifier.to_string(), + module_url_found: module_specifier.to_string(), + }; + Ok(module) + } + .boxed_local() + } +} + +fn main() -> Result<(), Error> { + let args: Vec = std::env::args().collect(); + if args.len() < 2 { + println!("Usage: target/examples/debug/ts_module_loader "); + std::process::exit(1); + } + let main_url = args[1].clone(); + println!("Run {}", main_url); + + let mut js_runtime = JsRuntime::new(RuntimeOptions { + module_loader: Some(Rc::new(TypescriptModuleLoader)), + ..Default::default() + }); + + let main_module = resolve_path(&main_url)?; + + let future = async move { + let mod_id = js_runtime.load_main_module(&main_module, None).await?; + let _ = js_runtime.mod_evaluate(mod_id); + js_runtime.run_event_loop(false).await?; + Ok(()) + }; + + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(future) +}