// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. use crate::ast; use crate::colors; use crate::media_type::MediaType; use crate::permissions::Permissions; use crate::tsc::runtime_bundle; use crate::tsc::runtime_compile; use crate::tsc_config; use deno_core::error::AnyError; use deno_core::futures::FutureExt; use deno_core::serde::Serialize; use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; use deno_core::BufVec; use deno_core::OpState; use serde::Deserialize; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; pub fn init(rt: &mut deno_core::JsRuntime) { super::reg_json_async(rt, "op_compile", op_compile); super::reg_json_async(rt, "op_transpile", op_transpile); } #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] struct CompileArgs { root_name: String, sources: Option>, bundle: bool, options: Option, } async fn op_compile( state: Rc>, args: Value, _data: BufVec, ) -> Result { super::check_unstable2(&state, "Deno.compile"); let args: CompileArgs = serde_json::from_value(args)?; let cli_state = super::global_state2(&state); let program_state = cli_state.clone(); let permissions = { let state = state.borrow(); state.borrow::().clone() }; let fut = if args.bundle { runtime_bundle( &program_state, permissions, &args.root_name, &args.sources, &args.options, ) .boxed_local() } else { runtime_compile( &program_state, permissions, &args.root_name, &args.sources, &args.options, ) .boxed_local() }; let result = fut.await?; Ok(result) } #[derive(Deserialize, Debug)] struct TranspileArgs { sources: HashMap, options: Option, } #[derive(Debug, Serialize)] struct RuntimeTranspileEmit { source: String, map: Option, } async fn op_transpile( state: Rc>, args: Value, _data: BufVec, ) -> Result { super::check_unstable2(&state, "Deno.transpileOnly"); let args: TranspileArgs = serde_json::from_value(args)?; let mut compiler_options = tsc_config::TsConfig::new(json!({ "checkJs": true, "emitDecoratorMetadata": false, "jsx": "react", "jsxFactory": "React.createElement", "jsxFragmentFactory": "React.Fragment", "inlineSourceMap": false, })); let user_options: HashMap = if let Some(options) = args.options { serde_json::from_str(&options)? } else { HashMap::new() }; let maybe_ignored_options = compiler_options.merge_user_config(&user_options)?; // TODO(@kitsonk) these really should just be passed back to the caller if let Some(ignored_options) = maybe_ignored_options { info!("{}: {}", colors::yellow("warning"), ignored_options); } let emit_options: ast::EmitOptions = compiler_options.into(); let mut emit_map = HashMap::new(); for (specifier, source) in args.sources { let media_type = MediaType::from(&specifier); let parsed_module = ast::parse(&specifier, &source, &media_type)?; let (source, maybe_source_map) = parsed_module.transpile(&emit_options)?; emit_map.insert( specifier.to_string(), RuntimeTranspileEmit { source, map: maybe_source_map, }, ); } let result = serde_json::to_value(emit_map)?; Ok(result) }