use std::env;use std::path::Path;use std::path::PathBuf;
use deno_core::snapshot_util::*;use deno_core::Extension;use deno_runtime::deno_cache::SqliteBackedCache;use deno_runtime::permissions::PermissionsContainer;use deno_runtime::*;
mod ts { use super::*; use crate::deno_webgpu_get_declaration; use deno_core::error::custom_error; use deno_core::error::AnyError; use deno_core::op; use deno_core::OpState; use regex::Regex; 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, }
pub fn create_compiler_snapshot( snapshot_path: PathBuf, files: Vec<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.webgpu", deno_webgpu_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", "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.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.string", "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.{}.d.ts", name)).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()); }
#[op] fn op_build_info(state: &mut OpState) -> Value { let build_specifier = "asset:///bootstrap.ts"; let build_libs = state.borrow::<Vec<&str>>(); json!({ "buildSpecifier": build_specifier, "libs": build_libs, }) }
#[op] fn op_cwd() -> String { "cache:///".into() }
#[op] fn op_exists() -> bool { false }
#[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 = Regex::new(r"asset:/{3}lib\.(\S+)\.d\.ts").expect("bad regex"); let build_specifier = "asset:///bootstrap.ts";
if args.specifier == build_specifier { Ok(json!({ "data": r#"console.log("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().unwrap() } else { path_dts.join(format!("lib.{}.d.ts", lib)) }; 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), )) } }
create_snapshot(CreateSnapshotOptions { cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"), snapshot_path, startup_snapshot: None, extensions: vec![Extension::builder("deno_tsc") .ops(vec![ op_build_info::decl(), op_cwd::decl(), op_exists::decl(), op_is_node_file::decl(), op_load::decl(), op_script_version::decl(), ]) .state(move |state| { state.put(op_crate_libs.clone()); state.put(build_libs.clone()); state.put(path_dts.clone());
Ok(()) }) .build()], extensions_with_js: vec![], additional_files: files, compression_cb: Some(Box::new(|vec, snapshot_slice| { vec.extend_from_slice( &zstd::bulk::compress(snapshot_slice, 22) .expect("snapshot compression failed"), ); })), }); }
pub(crate) fn version() -> String { let file_text = std::fs::read_to_string("tsc/00_typescript.js").unwrap(); let mut version = String::new(); for line in file_text.lines() { let major_minor_text = "ts.versionMajorMinor = \""; let version_text = "ts.version = \"\".concat(ts.versionMajorMinor, \""; if version.is_empty() { if let Some(index) = line.find(major_minor_text) { let remaining_line = &line[index + major_minor_text.len()..]; version .push_str(&remaining_line[..remaining_line.find('"').unwrap()]); } } else if let Some(index) = line.find(version_text) { let remaining_line = &line[index + version_text.len()..]; version.push_str(&remaining_line[..remaining_line.find('"').unwrap()]); return version; } } panic!("Could not find ts version.") }}
fn create_cli_snapshot(snapshot_path: PathBuf, files: Vec<PathBuf>) { let extensions: Vec<Extension> = vec![ deno_webidl::init(), deno_console::init(), deno_url::init(), deno_tls::init(), deno_web::init::<PermissionsContainer>( deno_web::BlobStore::default(), Default::default(), ), deno_fetch::init::<PermissionsContainer>(Default::default()), deno_cache::init::<SqliteBackedCache>(None), deno_websocket::init::<PermissionsContainer>("".to_owned(), None, None), deno_webstorage::init(None), deno_crypto::init(None), deno_webgpu::init(false), deno_broadcast_channel::init( deno_broadcast_channel::InMemoryBroadcastChannel::default(), false, ), deno_node::init::<PermissionsContainer>(None), deno_ffi::init::<PermissionsContainer>(false), deno_net::init::<PermissionsContainer>( None, false, None, ), deno_napi::init::<PermissionsContainer>(false), deno_http::init(), deno_flash::init::<PermissionsContainer>(false), ];
create_snapshot(CreateSnapshotOptions { cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"), snapshot_path, startup_snapshot: Some(deno_runtime::js::deno_isolate_init()), extensions, extensions_with_js: vec![], additional_files: files, compression_cb: Some(Box::new(|vec, snapshot_slice| { lzzzz::lz4_hc::compress_to_vec( snapshot_slice, vec, lzzzz::lz4_hc::CLEVEL_MAX, ) .expect("snapshot compression failed"); })), })}
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")] { let ver = glibc_version::get_version().unwrap();
if env::var("CC").is_err() && ver.major <= 2 && ver.minor < 35 { 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=TS_VERSION={}", ts::version()); println!("cargo:rerun-if-env-changed=TS_VERSION");
println!( "cargo:rustc-env=DENO_CONSOLE_LIB_PATH={}", deno_console::get_declaration().display() ); println!( "cargo:rustc-env=DENO_URL_LIB_PATH={}", deno_url::get_declaration().display() ); println!( "cargo:rustc-env=DENO_WEB_LIB_PATH={}", deno_web::get_declaration().display() ); println!( "cargo:rustc-env=DENO_FETCH_LIB_PATH={}", deno_fetch::get_declaration().display() ); println!( "cargo:rustc-env=DENO_WEBGPU_LIB_PATH={}", deno_webgpu_get_declaration().display() ); println!( "cargo:rustc-env=DENO_WEBSOCKET_LIB_PATH={}", deno_websocket::get_declaration().display() ); println!( "cargo:rustc-env=DENO_WEBSTORAGE_LIB_PATH={}", deno_webstorage::get_declaration().display() ); println!( "cargo:rustc-env=DENO_CACHE_LIB_PATH={}", deno_cache::get_declaration().display() ); println!( "cargo:rustc-env=DENO_CRYPTO_LIB_PATH={}", deno_crypto::get_declaration().display() ); println!( "cargo:rustc-env=DENO_BROADCAST_CHANNEL_LIB_PATH={}", deno_broadcast_channel::get_declaration().display() ); println!( "cargo:rustc-env=DENO_NET_LIB_PATH={}", deno_net::get_declaration().display() );
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"); let js_files = get_js_files(env!("CARGO_MANIFEST_DIR"), "tsc"); ts::create_compiler_snapshot(compiler_snapshot_path, js_files, &c);
let cli_snapshot_path = o.join("CLI_SNAPSHOT.bin"); let mut js_files = get_js_files(env!("CARGO_MANIFEST_DIR"), "js"); js_files.push(deno_runtime::js::get_99_main()); create_cli_snapshot(cli_snapshot_path, js_files);
#[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(); }}
fn deno_webgpu_get_declaration() -> PathBuf { let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); manifest_dir .join("tsc") .join("dts") .join("lib.deno_webgpu.d.ts")}