use std::env;use std::path::PathBuf;use std::sync::Arc;
use deno_core::snapshot_util::*;use deno_core::Extension;use deno_core::ExtensionFileSource;use deno_core::ExtensionFileSourceCode;use deno_runtime::deno_cache::SqliteBackedCache;use deno_runtime::deno_http::DefaultHttpPropertyExtractor;use deno_runtime::deno_kv::sqlite::SqliteDbHandler;use deno_runtime::permissions::PermissionsContainer;use deno_runtime::*;
mod ts { use super::*; use deno_core::error::custom_error; use deno_core::error::AnyError; use deno_core::op; use deno_core::OpState; use deno_runtime::deno_node::SUPPORTED_BUILTIN_NODE_MODULES; use serde::Deserialize; use serde_json::json; use serde_json::Value; use std::collections::HashMap; use std::path::Path; use std::path::PathBuf;
#[derive(Debug, Deserialize)] struct LoadArgs { specifier: String, }
#[op] fn op_build_info(state: &mut OpState) -> Value { let build_specifier = "asset:///bootstrap.ts";
let node_built_in_module_names = SUPPORTED_BUILTIN_NODE_MODULES.to_vec(); let build_libs = state.borrow::<Vec<&str>>(); json!({ "buildSpecifier": build_specifier, "libs": build_libs, "nodeBuiltInModuleNames": node_built_in_module_names, }) }
#[op] fn op_is_node_file() -> bool { false }
#[op] fn op_script_version( _state: &mut OpState, _args: Value, ) -> Result<Option<String>, AnyError> { Ok(Some("1".to_string())) }
#[op] fn op_load(state: &mut OpState, args: LoadArgs) -> Result<Value, AnyError> { let op_crate_libs = state.borrow::<HashMap<&str, PathBuf>>(); let path_dts = state.borrow::<PathBuf>(); let re_asset = lazy_regex::regex!(r"asset:/{3}lib\.(\S+)\.d\.ts"); let build_specifier = "asset:///bootstrap.ts";
if args.specifier == build_specifier { Ok(json!({ "data": r#"Deno.writeTextFile("hello.txt", "hello deno!");"#, "version": "1", "scriptKind": 3 })) } else if let Some(caps) = re_asset.captures(&args.specifier) { if let Some(lib) = caps.get(1).map(|m| m.as_str()) { let path = if let Some(op_crate_lib) = op_crate_libs.get(lib) { PathBuf::from(op_crate_lib).canonicalize()? } else { path_dts.join(format!("lib.{lib}.d.ts")) }; let data = std::fs::read_to_string(path)?; Ok(json!({ "data": data, "version": "1", "scriptKind": 3 })) } else { Err(custom_error( "InvalidSpecifier", format!("An invalid specifier was requested: {}", args.specifier), )) } } else { Err(custom_error( "InvalidSpecifier", format!("An invalid specifier was requested: {}", args.specifier), )) } }
deno_core::extension!(deno_tsc, ops = [op_build_info, op_is_node_file, op_load, op_script_version], js = [ dir "tsc", "00_typescript.js", "99_main_compiler.js", ], options = { op_crate_libs: HashMap<&'static str, PathBuf>, build_libs: Vec<&'static str>, path_dts: PathBuf, }, state = |state, options| { state.put(options.op_crate_libs); state.put(options.build_libs); state.put(options.path_dts); }, );
pub fn create_compiler_snapshot(snapshot_path: PathBuf, cwd: &Path) { let mut op_crate_libs = HashMap::new(); op_crate_libs.insert("deno.cache", deno_cache::get_declaration()); op_crate_libs.insert("deno.console", deno_console::get_declaration()); op_crate_libs.insert("deno.url", deno_url::get_declaration()); op_crate_libs.insert("deno.web", deno_web::get_declaration()); op_crate_libs.insert("deno.fetch", deno_fetch::get_declaration()); op_crate_libs.insert("deno.websocket", deno_websocket::get_declaration()); op_crate_libs.insert("deno.webstorage", deno_webstorage::get_declaration()); op_crate_libs.insert("deno.crypto", deno_crypto::get_declaration()); op_crate_libs.insert( "deno.broadcast_channel", deno_broadcast_channel::get_declaration(), ); op_crate_libs.insert("deno.net", deno_net::get_declaration());
for (_, path) in op_crate_libs.iter() { println!("cargo:rerun-if-changed={}", path.display()); }
let libs = vec![ "deno.window", "deno.worker", "deno.shared_globals", "deno.ns", "deno.unstable", "decorators", "decorators.legacy", "es5", "es2015.collection", "es2015.core", "es2015", "es2015.generator", "es2015.iterable", "es2015.promise", "es2015.proxy", "es2015.reflect", "es2015.symbol", "es2015.symbol.wellknown", "es2016.array.include", "es2016", "es2017", "es2017.intl", "es2017.object", "es2017.sharedmemory", "es2017.string", "es2017.typedarrays", "es2018.asyncgenerator", "es2018.asynciterable", "es2018", "es2018.intl", "es2018.promise", "es2018.regexp", "es2019.array", "es2019", "es2019.intl", "es2019.object", "es2019.string", "es2019.symbol", "es2020.bigint", "es2020", "es2020.date", "es2020.intl", "es2020.number", "es2020.promise", "es2020.sharedmemory", "es2020.string", "es2020.symbol.wellknown", "es2021", "es2021.intl", "es2021.promise", "es2021.string", "es2021.weakref", "es2022", "es2022.array", "es2022.error", "es2022.intl", "es2022.object", "es2022.regexp", "es2022.sharedmemory", "es2022.string", "es2023", "es2023.array", "esnext", "esnext.array", "esnext.intl", ];
let path_dts = cwd.join("tsc/dts"); for name in libs.iter() { println!( "cargo:rerun-if-changed={}", path_dts.join(format!("lib.{name}.d.ts")).display() ); } println!( "cargo:rerun-if-changed={}", cwd.join("tsc").join("00_typescript.js").display() ); println!( "cargo:rerun-if-changed={}", cwd.join("tsc").join("99_main_compiler.js").display() ); println!( "cargo:rerun-if-changed={}", cwd.join("js").join("40_testing.js").display() );
let mut build_libs = libs.clone(); for (op_lib, _) in op_crate_libs.iter() { build_libs.push(op_lib.to_owned()); }
std::fs::write( PathBuf::from(env::var_os("OUT_DIR").unwrap()) .join("lib_file_names.json"), serde_json::to_string(&build_libs).unwrap(), ) .unwrap();
let output = create_snapshot(CreateSnapshotOptions { cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"), snapshot_path, startup_snapshot: None, extensions: vec![deno_tsc::init_ops_and_esm( op_crate_libs, build_libs, path_dts, )],
#[cfg(debug_assertions)] compression_cb: None,
#[cfg(not(debug_assertions))] compression_cb: Some(Box::new(|vec, snapshot_slice| { eprintln!("Compressing TSC snapshot..."); vec.extend_from_slice( &zstd::bulk::compress(snapshot_slice, 22) .expect("snapshot compression failed"), ); })), snapshot_module_load_cb: None, with_runtime_cb: None, }); for path in output.files_loaded_during_snapshot { println!("cargo:rerun-if-changed={}", path.display()); } }
pub(crate) fn version() -> String { let file_text = std::fs::read_to_string("tsc/00_typescript.js").unwrap(); let version_text = " version = \""; for line in file_text.lines() { if let Some(index) = line.find(version_text) { let remaining_line = &line[index + version_text.len()..]; return remaining_line[..remaining_line.find('"').unwrap()].to_string(); } } panic!("Could not find ts version.") }}
deno_core::extension!( cli, esm_entry_point = "ext:cli/99_main.js", esm = [ dir "js", "40_testing.js", "99_main.js" ], customizer = |ext: &mut deno_core::Extension| { ext.esm_files.to_mut().push(ExtensionFileSource { specifier: "ext:cli/runtime/js/99_main.js", code: ExtensionFileSourceCode::LoadedFromFsDuringSnapshot( deno_runtime::js::PATH_FOR_99_MAIN_JS, ), }); });
#[must_use = "The files listed by create_cli_snapshot should be printed as 'cargo:rerun-if-changed' lines"]fn create_cli_snapshot(snapshot_path: PathBuf) -> CreateSnapshotOutput { let fs = Arc::new(deno_fs::RealFs); let extensions: Vec<Extension> = vec![ deno_webidl::deno_webidl::init_ops(), deno_console::deno_console::init_ops(), deno_url::deno_url::init_ops(), deno_web::deno_web::init_ops::<PermissionsContainer>( Default::default(), Default::default(), ), deno_fetch::deno_fetch::init_ops::<PermissionsContainer>(Default::default()), deno_cache::deno_cache::init_ops::<SqliteBackedCache>(None), deno_websocket::deno_websocket::init_ops::<PermissionsContainer>( "".to_owned(), None, None, ), deno_webstorage::deno_webstorage::init_ops(None), deno_crypto::deno_crypto::init_ops(None), deno_broadcast_channel::deno_broadcast_channel::init_ops( deno_broadcast_channel::InMemoryBroadcastChannel::default(), false, ), deno_ffi::deno_ffi::init_ops::<PermissionsContainer>(false), deno_net::deno_net::init_ops::<PermissionsContainer>( None, false, None, ), deno_tls::deno_tls::init_ops(), deno_kv::deno_kv::init_ops( SqliteDbHandler::<PermissionsContainer>::new(None), false, ), deno_napi::deno_napi::init_ops::<PermissionsContainer>(), deno_http::deno_http::init_ops::<DefaultHttpPropertyExtractor>(), deno_io::deno_io::init_ops(Default::default()), deno_fs::deno_fs::init_ops::<PermissionsContainer>(false, fs.clone()), deno_node::deno_node::init_ops::<PermissionsContainer>(None, fs), cli::init_ops_and_esm(), ];
create_snapshot(CreateSnapshotOptions { cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"), snapshot_path, startup_snapshot: Some(deno_runtime::js::deno_isolate_init()), extensions, compression_cb: None, snapshot_module_load_cb: None, with_runtime_cb: None, })}
fn git_commit_hash() -> String { if let Ok(output) = std::process::Command::new("git") .arg("rev-list") .arg("-1") .arg("HEAD") .output() { if output.status.success() { std::str::from_utf8(&output.stdout[..40]) .unwrap() .to_string() } else { "UNKNOWN".to_string() } } else { "UNKNOWN".to_string() }}
fn main() { if env::var_os("DOCS_RS").is_some() { return; }
let target = env::var("TARGET").unwrap(); let host = env::var("HOST").unwrap(); if target != host { panic!("Cross compiling with snapshot is not supported."); }
let symbols_path = std::path::Path::new("napi").join( format!("generated_symbol_exports_list_{}.def", env::consts::OS).as_str(), ) .canonicalize() .expect( "Missing symbols list! Generate using tools/napi/generate_symbols_lists.js", );
#[cfg(target_os = "windows")] println!( "cargo:rustc-link-arg-bin=deno=/DEF:{}", symbols_path.display() );
#[cfg(target_os = "macos")] println!( "cargo:rustc-link-arg-bin=deno=-Wl,-exported_symbols_list,{}", symbols_path.display() );
#[cfg(target_os = "linux")] { if env::var("CC").is_err() && glibc_version::get_version() .map(|ver| ver.major <= 2 && ver.minor < 35) .unwrap_or(false) { println!("cargo:warning=Compiling with all symbols exported, this will result in a larger binary. Please use glibc 2.35 or later for an optimised build."); println!("cargo:rustc-link-arg-bin=deno=-rdynamic"); } else { println!( "cargo:rustc-link-arg-bin=deno=-Wl,--export-dynamic-symbol-list={}", symbols_path.display() ); } }
if let Ok(c) = env::var("DENO_CANARY") { println!("cargo:rustc-env=DENO_CANARY={c}"); } println!("cargo:rerun-if-env-changed=DENO_CANARY");
println!("cargo:rustc-env=GIT_COMMIT_HASH={}", git_commit_hash()); println!("cargo:rerun-if-env-changed=GIT_COMMIT_HASH"); println!( "cargo:rustc-env=GIT_COMMIT_HASH_SHORT={}", &git_commit_hash()[..7] );
let ts_version = ts::version(); debug_assert_eq!(ts_version, "5.1.6"); println!("cargo:rustc-env=TS_VERSION={}", ts_version); println!("cargo:rerun-if-env-changed=TS_VERSION");
println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap()); println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
let c = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); let o = PathBuf::from(env::var_os("OUT_DIR").unwrap());
let compiler_snapshot_path = o.join("COMPILER_SNAPSHOT.bin"); ts::create_compiler_snapshot(compiler_snapshot_path, &c);
let cli_snapshot_path = o.join("CLI_SNAPSHOT.bin"); let output = create_cli_snapshot(cli_snapshot_path); for path in output.files_loaded_during_snapshot { println!("cargo:rerun-if-changed={}", path.display()) }
#[cfg(target_os = "windows")] { let mut res = winres::WindowsResource::new(); res.set_icon("deno.ico"); res.set_language(winapi::um::winnt::MAKELANGID( winapi::um::winnt::LANG_ENGLISH, winapi::um::winnt::SUBLANG_ENGLISH_US, )); res.compile().unwrap(); }}