mirror of
https://github.com/denoland/deno.git
synced 2025-02-13 01:06:00 -05:00
refactor: remove tsc snapshot (#28056)
This reverts commitacdc7dcdcf
and relands174e496847
. Closes https://github.com/denoland/deno/issues/28047 Closes https://github.com/denoland/deno/issues/28044
This commit is contained in:
parent
07410d19cf
commit
23540c2825
8 changed files with 599 additions and 580 deletions
485
cli/build.rs
485
cli/build.rs
|
@ -1,318 +1,183 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use deno_core::snapshot::*;
|
||||
use deno_runtime::*;
|
||||
|
||||
mod ts {
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use deno_core::op2;
|
||||
use deno_core::v8;
|
||||
use deno_core::OpState;
|
||||
use deno_error::JsErrorBox;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct LoadResponse {
|
||||
data: String,
|
||||
version: String,
|
||||
script_kind: i32,
|
||||
fn compress_decls(out_dir: &Path) {
|
||||
let decls = [
|
||||
"lib.deno_webgpu.d.ts",
|
||||
"lib.deno.ns.d.ts",
|
||||
"lib.deno.unstable.d.ts",
|
||||
"lib.deno.window.d.ts",
|
||||
"lib.deno.worker.d.ts",
|
||||
"lib.deno.shared_globals.d.ts",
|
||||
"lib.deno.ns.d.ts",
|
||||
"lib.deno.unstable.d.ts",
|
||||
"lib.decorators.d.ts",
|
||||
"lib.decorators.legacy.d.ts",
|
||||
"lib.dom.asynciterable.d.ts",
|
||||
"lib.dom.d.ts",
|
||||
"lib.dom.extras.d.ts",
|
||||
"lib.dom.iterable.d.ts",
|
||||
"lib.es2015.collection.d.ts",
|
||||
"lib.es2015.core.d.ts",
|
||||
"lib.es2015.d.ts",
|
||||
"lib.es2015.generator.d.ts",
|
||||
"lib.es2015.iterable.d.ts",
|
||||
"lib.es2015.promise.d.ts",
|
||||
"lib.es2015.proxy.d.ts",
|
||||
"lib.es2015.reflect.d.ts",
|
||||
"lib.es2015.symbol.d.ts",
|
||||
"lib.es2015.symbol.wellknown.d.ts",
|
||||
"lib.es2016.array.include.d.ts",
|
||||
"lib.es2016.d.ts",
|
||||
"lib.es2016.full.d.ts",
|
||||
"lib.es2016.intl.d.ts",
|
||||
"lib.es2017.arraybuffer.d.ts",
|
||||
"lib.es2017.d.ts",
|
||||
"lib.es2017.date.d.ts",
|
||||
"lib.es2017.full.d.ts",
|
||||
"lib.es2017.intl.d.ts",
|
||||
"lib.es2017.object.d.ts",
|
||||
"lib.es2017.sharedmemory.d.ts",
|
||||
"lib.es2017.string.d.ts",
|
||||
"lib.es2017.typedarrays.d.ts",
|
||||
"lib.es2018.asyncgenerator.d.ts",
|
||||
"lib.es2018.asynciterable.d.ts",
|
||||
"lib.es2018.d.ts",
|
||||
"lib.es2018.full.d.ts",
|
||||
"lib.es2018.intl.d.ts",
|
||||
"lib.es2018.promise.d.ts",
|
||||
"lib.es2018.regexp.d.ts",
|
||||
"lib.es2019.array.d.ts",
|
||||
"lib.es2019.d.ts",
|
||||
"lib.es2019.full.d.ts",
|
||||
"lib.es2019.intl.d.ts",
|
||||
"lib.es2019.object.d.ts",
|
||||
"lib.es2019.string.d.ts",
|
||||
"lib.es2019.symbol.d.ts",
|
||||
"lib.es2020.bigint.d.ts",
|
||||
"lib.es2020.d.ts",
|
||||
"lib.es2020.date.d.ts",
|
||||
"lib.es2020.full.d.ts",
|
||||
"lib.es2020.intl.d.ts",
|
||||
"lib.es2020.number.d.ts",
|
||||
"lib.es2020.promise.d.ts",
|
||||
"lib.es2020.sharedmemory.d.ts",
|
||||
"lib.es2020.string.d.ts",
|
||||
"lib.es2020.symbol.wellknown.d.ts",
|
||||
"lib.es2021.d.ts",
|
||||
"lib.es2021.full.d.ts",
|
||||
"lib.es2021.intl.d.ts",
|
||||
"lib.es2021.promise.d.ts",
|
||||
"lib.es2021.string.d.ts",
|
||||
"lib.es2021.weakref.d.ts",
|
||||
"lib.es2022.array.d.ts",
|
||||
"lib.es2022.d.ts",
|
||||
"lib.es2022.error.d.ts",
|
||||
"lib.es2022.full.d.ts",
|
||||
"lib.es2022.intl.d.ts",
|
||||
"lib.es2022.object.d.ts",
|
||||
"lib.es2022.regexp.d.ts",
|
||||
"lib.es2022.string.d.ts",
|
||||
"lib.es2023.array.d.ts",
|
||||
"lib.es2023.collection.d.ts",
|
||||
"lib.es2023.d.ts",
|
||||
"lib.es2023.full.d.ts",
|
||||
"lib.es2023.intl.d.ts",
|
||||
"lib.es2024.arraybuffer.d.ts",
|
||||
"lib.es2024.collection.d.ts",
|
||||
"lib.es2024.d.ts",
|
||||
"lib.es2024.full.d.ts",
|
||||
"lib.es2024.object.d.ts",
|
||||
"lib.es2024.promise.d.ts",
|
||||
"lib.es2024.regexp.d.ts",
|
||||
"lib.es2024.sharedmemory.d.ts",
|
||||
"lib.es2024.string.d.ts",
|
||||
"lib.es5.d.ts",
|
||||
"lib.es6.d.ts",
|
||||
"lib.esnext.array.d.ts",
|
||||
"lib.esnext.collection.d.ts",
|
||||
"lib.esnext.d.ts",
|
||||
"lib.esnext.decorators.d.ts",
|
||||
"lib.esnext.disposable.d.ts",
|
||||
"lib.esnext.full.d.ts",
|
||||
"lib.esnext.intl.d.ts",
|
||||
"lib.esnext.iterator.d.ts",
|
||||
"lib.scripthost.d.ts",
|
||||
"lib.webworker.asynciterable.d.ts",
|
||||
"lib.webworker.d.ts",
|
||||
"lib.webworker.importscripts.d.ts",
|
||||
"lib.webworker.iterable.d.ts",
|
||||
];
|
||||
for decl in decls {
|
||||
let file = format!("./tsc/dts/{decl}");
|
||||
compress_source(out_dir, &file);
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
// using the same op that is used in `tsc.rs` for loading modules and reading
|
||||
// files, but a slightly different implementation at build time.
|
||||
fn op_load(
|
||||
state: &mut OpState,
|
||||
#[string] load_specifier: &str,
|
||||
) -> Result<LoadResponse, JsErrorBox> {
|
||||
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");
|
||||
|
||||
// specifiers come across as `asset:///lib.{lib_name}.d.ts` and we need to
|
||||
// parse out just the name so we can lookup the asset.
|
||||
if let Some(caps) = re_asset.captures(load_specifier) {
|
||||
if let Some(lib) = caps.get(1).map(|m| m.as_str()) {
|
||||
// if it comes from an op crate, we were supplied with the path to the
|
||||
// file.
|
||||
let path = if let Some(op_crate_lib) = op_crate_libs.get(lib) {
|
||||
PathBuf::from(op_crate_lib)
|
||||
.canonicalize()
|
||||
.map_err(JsErrorBox::from_err)?
|
||||
// otherwise we will generate the path ourself
|
||||
} else {
|
||||
path_dts.join(format!("lib.{lib}.d.ts"))
|
||||
};
|
||||
let data =
|
||||
std::fs::read_to_string(path).map_err(JsErrorBox::from_err)?;
|
||||
return Ok(LoadResponse {
|
||||
data,
|
||||
version: "1".to_string(),
|
||||
// this corresponds to `ts.ScriptKind.TypeScript`
|
||||
script_kind: 3,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Err(JsErrorBox::new(
|
||||
"InvalidSpecifier",
|
||||
format!("An invalid specifier was requested: {}", load_specifier),
|
||||
))
|
||||
let ext_decls = [
|
||||
"console/lib.deno_console.d.ts",
|
||||
"url/lib.deno_url.d.ts",
|
||||
"web/lib.deno_web.d.ts",
|
||||
"fetch/lib.deno_fetch.d.ts",
|
||||
"websocket/lib.deno_websocket.d.ts",
|
||||
"webstorage/lib.deno_webstorage.d.ts",
|
||||
"canvas/lib.deno_canvas.d.ts",
|
||||
"crypto/lib.deno_crypto.d.ts",
|
||||
"cache/lib.deno_cache.d.ts",
|
||||
"net/lib.deno_net.d.ts",
|
||||
"broadcast_channel/lib.deno_broadcast_channel.d.ts",
|
||||
];
|
||||
for ext_decl in ext_decls {
|
||||
let file = format!("../ext/{ext_decl}");
|
||||
compress_source(out_dir, &file);
|
||||
}
|
||||
}
|
||||
|
||||
deno_core::extension!(deno_tsc,
|
||||
ops = [
|
||||
op_load,
|
||||
],
|
||||
esm_entry_point = "ext:deno_tsc/99_main_compiler.js",
|
||||
esm = [
|
||||
dir "tsc",
|
||||
"97_ts_host.js",
|
||||
"98_lsp.js",
|
||||
"99_main_compiler.js",
|
||||
],
|
||||
js = [
|
||||
dir "tsc",
|
||||
"00_typescript.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);
|
||||
},
|
||||
);
|
||||
fn compress_source(out_dir: &Path, file: &str) {
|
||||
let path = Path::new(file)
|
||||
.canonicalize()
|
||||
.unwrap_or_else(|_| panic!("expected file \"{file}\" to exist"));
|
||||
let contents = std::fs::read(&path).unwrap();
|
||||
|
||||
pub fn create_compiler_snapshot(snapshot_path: PathBuf, cwd: &Path) {
|
||||
// libs that are being provided by op crates.
|
||||
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.canvas", deno_canvas::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());
|
||||
println!("cargo:rerun-if-changed={}", path.display());
|
||||
|
||||
// ensure we invalidate the build properly.
|
||||
for (_, path) in op_crate_libs.iter() {
|
||||
println!("cargo:rerun-if-changed={}", path.display());
|
||||
}
|
||||
|
||||
// libs that should be loaded into the isolate before snapshotting.
|
||||
let libs = vec![
|
||||
// Deno custom type libraries
|
||||
"deno.window",
|
||||
"deno.worker",
|
||||
"deno.shared_globals",
|
||||
"deno.ns",
|
||||
"deno.unstable",
|
||||
// Deno built-in type libraries
|
||||
"decorators",
|
||||
"decorators.legacy",
|
||||
"dom.asynciterable",
|
||||
"dom",
|
||||
"dom.extras",
|
||||
"dom.iterable",
|
||||
"es2015.collection",
|
||||
"es2015.core",
|
||||
"es2015",
|
||||
"es2015.generator",
|
||||
"es2015.iterable",
|
||||
"es2015.promise",
|
||||
"es2015.proxy",
|
||||
"es2015.reflect",
|
||||
"es2015.symbol",
|
||||
"es2015.symbol.wellknown",
|
||||
"es2016.array.include",
|
||||
"es2016",
|
||||
"es2016.full",
|
||||
"es2016.intl",
|
||||
"es2017.arraybuffer",
|
||||
"es2017",
|
||||
"es2017.date",
|
||||
"es2017.full",
|
||||
"es2017.intl",
|
||||
"es2017.object",
|
||||
"es2017.sharedmemory",
|
||||
"es2017.string",
|
||||
"es2017.typedarrays",
|
||||
"es2018.asyncgenerator",
|
||||
"es2018.asynciterable",
|
||||
"es2018",
|
||||
"es2018.full",
|
||||
"es2018.intl",
|
||||
"es2018.promise",
|
||||
"es2018.regexp",
|
||||
"es2019.array",
|
||||
"es2019",
|
||||
"es2019.full",
|
||||
"es2019.intl",
|
||||
"es2019.object",
|
||||
"es2019.string",
|
||||
"es2019.symbol",
|
||||
"es2020.bigint",
|
||||
"es2020",
|
||||
"es2020.date",
|
||||
"es2020.full",
|
||||
"es2020.intl",
|
||||
"es2020.number",
|
||||
"es2020.promise",
|
||||
"es2020.sharedmemory",
|
||||
"es2020.string",
|
||||
"es2020.symbol.wellknown",
|
||||
"es2021",
|
||||
"es2021.full",
|
||||
"es2021.intl",
|
||||
"es2021.promise",
|
||||
"es2021.string",
|
||||
"es2021.weakref",
|
||||
"es2022.array",
|
||||
"es2022",
|
||||
"es2022.error",
|
||||
"es2022.full",
|
||||
"es2022.intl",
|
||||
"es2022.object",
|
||||
"es2022.regexp",
|
||||
"es2022.string",
|
||||
"es2023.array",
|
||||
"es2023.collection",
|
||||
"es2023",
|
||||
"es2023.full",
|
||||
"es2023.intl",
|
||||
"es2024.arraybuffer",
|
||||
"es2024.collection",
|
||||
"es2024",
|
||||
"es2024.full",
|
||||
"es2024.object",
|
||||
"es2024.promise",
|
||||
"es2024.regexp",
|
||||
"es2024.sharedmemory",
|
||||
"es2024.string",
|
||||
"es5",
|
||||
"es6",
|
||||
"esnext.array",
|
||||
"esnext.collection",
|
||||
"esnext",
|
||||
"esnext.decorators",
|
||||
"esnext.disposable",
|
||||
"esnext.full",
|
||||
"esnext.intl",
|
||||
"esnext.iterator",
|
||||
"scripthost",
|
||||
"webworker.asynciterable",
|
||||
"webworker",
|
||||
"webworker.importscripts",
|
||||
"webworker.iterable",
|
||||
];
|
||||
|
||||
let path_dts = cwd.join("tsc/dts");
|
||||
// ensure we invalidate the build properly.
|
||||
for name in libs.iter() {
|
||||
println!(
|
||||
"cargo:rerun-if-changed={}",
|
||||
path_dts.join(format!("lib.{name}.d.ts")).display()
|
||||
);
|
||||
}
|
||||
|
||||
// create a copy of the vector that includes any op crate libs to be passed
|
||||
// to the JavaScript compiler to build into the snapshot
|
||||
let mut build_libs = libs.clone();
|
||||
for (op_lib, _) in op_crate_libs.iter() {
|
||||
build_libs.push(op_lib.to_owned());
|
||||
}
|
||||
|
||||
// used in the tests to verify that after snapshotting it has the same number
|
||||
// of lib files loaded and hasn't included any ones lazily loaded from Rust
|
||||
std::fs::write(
|
||||
PathBuf::from(env::var_os("OUT_DIR").unwrap())
|
||||
.join("lib_file_names.json"),
|
||||
serde_json::to_string(&build_libs).unwrap(),
|
||||
)
|
||||
let compressed = zstd::bulk::compress(&contents, 19).unwrap();
|
||||
let mut out = out_dir.join(file.trim_start_matches("../"));
|
||||
let mut ext = out
|
||||
.extension()
|
||||
.map(|s| s.to_string_lossy())
|
||||
.unwrap_or_default()
|
||||
.into_owned();
|
||||
ext.push_str(".zstd");
|
||||
out.set_extension(ext);
|
||||
std::fs::create_dir_all(out.parent().unwrap()).unwrap();
|
||||
let mut file = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.write(true)
|
||||
.open(out)
|
||||
.unwrap();
|
||||
file
|
||||
.write_all(&(contents.len() as u32).to_le_bytes())
|
||||
.unwrap();
|
||||
|
||||
// Leak to satisfy type-checker. It's okay since it's only run once for a build script.
|
||||
let build_libs_ = Box::leak(Box::new(build_libs.clone()));
|
||||
let runtime_cb = Box::new(|rt: &mut deno_core::JsRuntimeForSnapshot| {
|
||||
let scope = &mut rt.handle_scope();
|
||||
file.write_all(&compressed).unwrap();
|
||||
}
|
||||
|
||||
let context = scope.get_current_context();
|
||||
let global = context.global(scope);
|
||||
fn compress_sources(out_dir: &Path) {
|
||||
compress_decls(out_dir);
|
||||
|
||||
let name = v8::String::new(scope, "snapshot").unwrap();
|
||||
let snapshot_fn_val = global.get(scope, name.into()).unwrap();
|
||||
let snapshot_fn: v8::Local<v8::Function> =
|
||||
snapshot_fn_val.try_into().unwrap();
|
||||
let undefined = v8::undefined(scope);
|
||||
let build_libs = build_libs_.clone();
|
||||
let build_libs_v8 =
|
||||
deno_core::serde_v8::to_v8(scope, build_libs).unwrap();
|
||||
|
||||
snapshot_fn
|
||||
.call(scope, undefined.into(), &[build_libs_v8])
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
let output = create_snapshot(
|
||||
CreateSnapshotOptions {
|
||||
cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"),
|
||||
startup_snapshot: None,
|
||||
extensions: vec![deno_tsc::init_ops_and_esm(
|
||||
op_crate_libs,
|
||||
build_libs,
|
||||
path_dts,
|
||||
)],
|
||||
extension_transpiler: None,
|
||||
with_runtime_cb: Some(runtime_cb),
|
||||
skip_op_registration: false,
|
||||
},
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// NOTE(bartlomieju): Compressing the TSC snapshot in debug build took
|
||||
// ~45s on M1 MacBook Pro; without compression it took ~1s.
|
||||
// Thus we're not using compressed snapshot, trading off
|
||||
// a lot of build time for some startup time in debug build.
|
||||
let mut file = std::fs::File::create(snapshot_path).unwrap();
|
||||
if cfg!(debug_assertions) {
|
||||
file.write_all(&output.output).unwrap();
|
||||
} else {
|
||||
let mut vec = Vec::with_capacity(output.output.len());
|
||||
vec.extend((output.output.len() as u32).to_le_bytes());
|
||||
vec.extend_from_slice(
|
||||
&zstd::bulk::compress(&output.output, 22)
|
||||
.expect("snapshot compression failed"),
|
||||
);
|
||||
file.write_all(&vec).unwrap();
|
||||
}
|
||||
|
||||
for path in output.files_loaded_during_snapshot {
|
||||
println!("cargo:rerun-if-changed={}", path.display());
|
||||
}
|
||||
let ext_sources = [
|
||||
"./tsc/99_main_compiler.js",
|
||||
"./tsc/97_ts_host.js",
|
||||
"./tsc/98_lsp.js",
|
||||
"./tsc/00_typescript.js",
|
||||
];
|
||||
for ext_source in ext_sources {
|
||||
compress_source(out_dir, ext_source);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,6 +202,12 @@ fn main() {
|
|||
// To debug snapshot issues uncomment:
|
||||
// op_fetch_asset::trace_serializer();
|
||||
|
||||
if !cfg!(debug_assertions) {
|
||||
let out_dir =
|
||||
std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
|
||||
compress_sources(&out_dir);
|
||||
}
|
||||
|
||||
if let Ok(c) = env::var("DENO_CANARY") {
|
||||
println!("cargo:rustc-env=DENO_CANARY={c}");
|
||||
}
|
||||
|
@ -345,12 +216,6 @@ fn main() {
|
|||
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);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let mut res = winres::WindowsResource::new();
|
||||
|
@ -362,11 +227,3 @@ fn main() {
|
|||
res.compile().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn deno_webgpu_get_declaration() -> PathBuf {
|
||||
let manifest_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||
manifest_dir
|
||||
.join("tsc")
|
||||
.join("dts")
|
||||
.join("lib.deno_webgpu.d.ts")
|
||||
}
|
||||
|
|
|
@ -606,7 +606,7 @@ impl Inner {
|
|||
ts_server.clone(),
|
||||
diagnostics_state.clone(),
|
||||
);
|
||||
let assets = Assets::new(ts_server.clone());
|
||||
let assets = Assets::new();
|
||||
let initial_cwd = std::env::current_dir().unwrap_or_else(|_| {
|
||||
panic!("Could not resolve current working directory")
|
||||
});
|
||||
|
@ -913,7 +913,6 @@ impl Inner {
|
|||
.await?;
|
||||
self.ts_fixable_diagnostics = fixable_diagnostics;
|
||||
}
|
||||
self.assets.initialize(self.snapshot()).await;
|
||||
|
||||
self.performance.measure(mark);
|
||||
Ok(InitializeResult {
|
||||
|
|
127
cli/lsp/tsc.rs
127
cli/lsp/tsc.rs
|
@ -1399,7 +1399,7 @@ fn new_assets_map() -> Arc<Mutex<AssetsMap>> {
|
|||
.map(|(k, v)| {
|
||||
let url_str = format!("asset:///{k}");
|
||||
let specifier = resolve_url(&url_str).unwrap();
|
||||
let asset = AssetDocument::new(specifier.clone(), v);
|
||||
let asset = AssetDocument::new(specifier.clone(), v.get());
|
||||
(specifier, asset)
|
||||
})
|
||||
.collect::<AssetsMap>();
|
||||
|
@ -1430,29 +1430,16 @@ impl AssetsSnapshot {
|
|||
/// multiple threads without needing to worry about race conditions.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Assets {
|
||||
ts_server: Arc<TsServer>,
|
||||
assets: Arc<Mutex<AssetsMap>>,
|
||||
}
|
||||
|
||||
impl Assets {
|
||||
pub fn new(ts_server: Arc<TsServer>) -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
ts_server,
|
||||
assets: new_assets_map(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes with the assets in the isolate.
|
||||
pub async fn initialize(&self, state_snapshot: Arc<StateSnapshot>) {
|
||||
let assets = get_isolate_assets(&self.ts_server, state_snapshot).await;
|
||||
let mut assets_map = self.assets.lock();
|
||||
for asset in assets {
|
||||
if !assets_map.contains_key(asset.specifier()) {
|
||||
assets_map.insert(asset.specifier().clone(), asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn snapshot(&self) -> AssetsSnapshot {
|
||||
// it's ok to not make a complete copy for snapshotting purposes
|
||||
// because assets are static
|
||||
|
@ -1477,39 +1464,6 @@ impl Assets {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get all the assets stored in the tsc isolate.
|
||||
async fn get_isolate_assets(
|
||||
ts_server: &TsServer,
|
||||
state_snapshot: Arc<StateSnapshot>,
|
||||
) -> Vec<AssetDocument> {
|
||||
let req = TscRequest::GetAssets;
|
||||
let res: Value = ts_server
|
||||
.request(state_snapshot, req, None, &Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
let response_assets = match res {
|
||||
Value::Array(value) => value,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let mut assets = Vec::with_capacity(response_assets.len());
|
||||
|
||||
for asset in response_assets {
|
||||
let mut obj = match asset {
|
||||
Value::Object(obj) => obj,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let specifier_str = obj.get("specifier").unwrap().as_str().unwrap();
|
||||
let specifier = ModuleSpecifier::parse(specifier_str).unwrap();
|
||||
let text = match obj.remove("text").unwrap() {
|
||||
Value::String(text) => text,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
assets.push(AssetDocument::new(specifier, text));
|
||||
}
|
||||
|
||||
assets
|
||||
}
|
||||
|
||||
fn get_tag_body_text(
|
||||
tag: &JsDocTagInfo,
|
||||
language_server: &language_server::Inner,
|
||||
|
@ -4547,6 +4501,21 @@ fn op_is_node_file(state: &mut OpState, #[string] path: String) -> bool {
|
|||
r
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
fn op_libs() -> Vec<String> {
|
||||
let mut out =
|
||||
Vec::with_capacity(crate::tsc::LAZILY_LOADED_STATIC_ASSETS.len());
|
||||
for key in crate::tsc::LAZILY_LOADED_STATIC_ASSETS.keys() {
|
||||
let lib = key
|
||||
.replace("lib.", "")
|
||||
.replace(".d.ts", "")
|
||||
.replace("deno_", "deno.");
|
||||
out.push(lib);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, deno_error::JsError)]
|
||||
enum LoadError {
|
||||
#[error("{0}")]
|
||||
|
@ -4947,13 +4916,13 @@ fn run_tsc_thread(
|
|||
// supplied snapshot is an isolate that contains the TypeScript language
|
||||
// server.
|
||||
let mut tsc_runtime = JsRuntime::new(RuntimeOptions {
|
||||
extensions: vec![deno_tsc::init_ops(
|
||||
extensions: vec![deno_tsc::init_ops_and_esm(
|
||||
performance,
|
||||
specifier_map,
|
||||
request_rx,
|
||||
)],
|
||||
create_params: create_isolate_create_params(),
|
||||
startup_snapshot: Some(tsc::compiler_snapshot()),
|
||||
startup_snapshot: None,
|
||||
inspector: has_inspector_server,
|
||||
..Default::default()
|
||||
});
|
||||
|
@ -5035,6 +5004,7 @@ deno_core::extension!(deno_tsc,
|
|||
op_script_version,
|
||||
op_project_version,
|
||||
op_poll_requests,
|
||||
op_libs,
|
||||
],
|
||||
options = {
|
||||
performance: Arc<Performance>,
|
||||
|
@ -5049,6 +5019,14 @@ deno_core::extension!(deno_tsc,
|
|||
options.request_rx,
|
||||
));
|
||||
},
|
||||
customizer = |ext: &mut deno_core::Extension| {
|
||||
use deno_core::ExtensionFileSource;
|
||||
ext.esm_files.to_mut().push(ExtensionFileSource::new_computed("ext:deno_tsc/99_main_compiler.js", crate::tsc::MAIN_COMPILER_SOURCE.get().into()));
|
||||
ext.esm_files.to_mut().push(ExtensionFileSource::new_computed("ext:deno_tsc/97_ts_host.js", crate::tsc::TS_HOST_SOURCE.get().into()));
|
||||
ext.esm_files.to_mut().push(ExtensionFileSource::new_computed("ext:deno_tsc/98_lsp.js", crate::tsc::LSP_SOURCE.get().into()));
|
||||
ext.js_files.to_mut().push(ExtensionFileSource::new_computed("ext:deno_cli_tsc/00_typescript.js", crate::tsc::TYPESCRIPT_SOURCE.get().into()));
|
||||
ext.esm_entry_point = Some("ext:deno_tsc/99_main_compiler.js");
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone, Deserialize_repr, Serialize_repr)]
|
||||
|
@ -5428,7 +5406,6 @@ pub struct JsNull;
|
|||
#[derive(Debug, Clone, Serialize)]
|
||||
pub enum TscRequest {
|
||||
GetDiagnostics((Vec<String>, usize)),
|
||||
GetAssets,
|
||||
|
||||
CleanupSemanticCache,
|
||||
// https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6230
|
||||
|
@ -5634,7 +5611,6 @@ impl TscRequest {
|
|||
("provideInlayHints", Some(serde_v8::to_v8(scope, args)?))
|
||||
}
|
||||
TscRequest::CleanupSemanticCache => ("cleanupSemanticCache", None),
|
||||
TscRequest::GetAssets => ("$getAssets", None),
|
||||
};
|
||||
|
||||
Ok(args)
|
||||
|
@ -5679,7 +5655,6 @@ impl TscRequest {
|
|||
TscRequest::GetSignatureHelpItems(_) => "getSignatureHelpItems",
|
||||
TscRequest::GetNavigateToItems(_) => "getNavigateToItems",
|
||||
TscRequest::ProvideInlayHints(_) => "provideInlayHints",
|
||||
TscRequest::GetAssets => "$getAssets",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6065,52 +6040,6 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_request_assets() {
|
||||
let (_, ts_server, snapshot, _) = setup(json!({}), &[]).await;
|
||||
let assets = get_isolate_assets(&ts_server, snapshot).await;
|
||||
let mut asset_names = assets
|
||||
.iter()
|
||||
.map(|a| {
|
||||
a.specifier()
|
||||
.to_string()
|
||||
.replace("asset:///lib.", "")
|
||||
.replace(".d.ts", "")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut expected_asset_names: Vec<String> = serde_json::from_str(
|
||||
include_str!(concat!(env!("OUT_DIR"), "/lib_file_names.json")),
|
||||
)
|
||||
.unwrap();
|
||||
asset_names.sort();
|
||||
|
||||
// if this test fails, update build.rs
|
||||
expected_asset_names.sort();
|
||||
assert_eq!(asset_names, expected_asset_names);
|
||||
|
||||
// get some notification when the size of the assets grows
|
||||
let mut total_size = 0;
|
||||
for asset in &assets {
|
||||
total_size += asset.text().len();
|
||||
}
|
||||
assert!(total_size > 0);
|
||||
#[allow(clippy::print_stderr)]
|
||||
// currently as of TS 5.7, it's 3MB
|
||||
if total_size > 3_500_000 {
|
||||
let mut sizes = Vec::new();
|
||||
for asset in &assets {
|
||||
sizes.push((asset.specifier(), asset.text().len()));
|
||||
}
|
||||
sizes.sort_by_cached_key(|(_, size)| *size);
|
||||
sizes.reverse();
|
||||
for (specifier, size) in &sizes {
|
||||
eprintln!("{}: {}", specifier, size);
|
||||
}
|
||||
eprintln!("Total size: {}", total_size);
|
||||
panic!("Assets were quite large.");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_modify_sources() {
|
||||
let (temp_dir, ts_server, snapshot, cache) = setup(
|
||||
|
|
|
@ -855,17 +855,3 @@ const setTypesNodeIgnorableNames = new Set([
|
|||
"WritableStreamDefaultWriter",
|
||||
]);
|
||||
ts.deno.setTypesNodeIgnorableNames(setTypesNodeIgnorableNames);
|
||||
|
||||
export function getAssets() {
|
||||
/** @type {{ specifier: string; text: string; }[]} */
|
||||
const assets = [];
|
||||
for (const sourceFile of SOURCE_FILE_CACHE.values()) {
|
||||
if (sourceFile.fileName.startsWith(ASSETS_URL_PREFIX)) {
|
||||
assets.push({
|
||||
specifier: sourceFile.fileName,
|
||||
text: sourceFile.text,
|
||||
});
|
||||
}
|
||||
}
|
||||
return assets;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import {
|
|||
error,
|
||||
filterMapDiagnostic,
|
||||
fromTypeScriptDiagnostics,
|
||||
getAssets,
|
||||
getCreateSourceFileOptions,
|
||||
host,
|
||||
IS_NODE_SOURCE_FILE_CACHE,
|
||||
|
@ -446,9 +445,6 @@ function serverRequest(id, method, args, scope, maybeChange) {
|
|||
ts.getSupportedCodeFixes(),
|
||||
);
|
||||
}
|
||||
case "$getAssets": {
|
||||
return respond(id, getAssets());
|
||||
}
|
||||
case "$getDiagnostics": {
|
||||
const projectVersion = args[1];
|
||||
// there's a possibility that we receive a change notification
|
||||
|
|
|
@ -13,13 +13,10 @@
|
|||
delete Object.prototype.__proto__;
|
||||
|
||||
import {
|
||||
assert,
|
||||
AssertionError,
|
||||
ASSETS_URL_PREFIX,
|
||||
debug,
|
||||
filterMapDiagnostic,
|
||||
fromTypeScriptDiagnostics,
|
||||
getAssets,
|
||||
host,
|
||||
setLogDebug,
|
||||
} from "./97_ts_host.js";
|
||||
|
@ -214,31 +211,20 @@ function exec({ config, debug: debugFlag, rootNames, localOnly }) {
|
|||
debug("<<< exec stop");
|
||||
}
|
||||
|
||||
globalThis.snapshot = function (libs) {
|
||||
for (const lib of libs) {
|
||||
const specifier = `lib.${lib}.d.ts`;
|
||||
// we are using internal APIs here to "inject" our custom libraries into
|
||||
// tsc, so things like `"lib": [ "deno.ns" ]` are supported.
|
||||
if (!ts.libs.includes(lib)) {
|
||||
ts.libs.push(lib);
|
||||
ts.libMap.set(lib, `lib.${lib}.d.ts`);
|
||||
}
|
||||
// we are caching in memory common type libraries that will be re-used by
|
||||
// tsc on when the snapshot is restored
|
||||
assert(
|
||||
!!host.getSourceFile(
|
||||
`${ASSETS_URL_PREFIX}${specifier}`,
|
||||
ts.ScriptTarget.ESNext,
|
||||
),
|
||||
`failed to load '${ASSETS_URL_PREFIX}${specifier}'`,
|
||||
);
|
||||
const libs = ops.op_libs();
|
||||
for (const lib of libs) {
|
||||
const specifier = `lib.${lib}.d.ts`;
|
||||
// we are using internal APIs here to "inject" our custom libraries into
|
||||
// tsc, so things like `"lib": [ "deno.ns" ]` are supported.
|
||||
if (!ts.libs.includes(lib)) {
|
||||
ts.libs.push(lib);
|
||||
ts.libMap.set(lib, specifier);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// exposes the functions that are called by `tsc::exec()` when type
|
||||
// checking TypeScript.
|
||||
globalThis.exec = exec;
|
||||
globalThis.getAssets = getAssets;
|
||||
|
||||
// exposes the functions that are called when the compiler is used as a
|
||||
// language service.
|
||||
|
|
512
cli/tsc/mod.rs
512
cli/tsc/mod.rs
|
@ -5,10 +5,10 @@ use std::collections::HashMap;
|
|||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use deno_ast::MediaType;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::ascii_str;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::located_script_name;
|
||||
use deno_core::op2;
|
||||
|
@ -18,7 +18,6 @@ use deno_core::serde::Deserializer;
|
|||
use deno_core::serde::Serialize;
|
||||
use deno_core::serde::Serializer;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_v8;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::JsRuntime;
|
||||
use deno_core::ModuleSpecifier;
|
||||
|
@ -59,33 +58,8 @@ pub use self::diagnostics::DiagnosticCategory;
|
|||
pub use self::diagnostics::Diagnostics;
|
||||
pub use self::diagnostics::Position;
|
||||
|
||||
pub static COMPILER_SNAPSHOT: Lazy<Box<[u8]>> = Lazy::new(
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
|| {
|
||||
static COMPRESSED_COMPILER_SNAPSHOT: &[u8] =
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/COMPILER_SNAPSHOT.bin"));
|
||||
|
||||
// NOTE(bartlomieju): Compressing the TSC snapshot in debug build took
|
||||
// ~45s on M1 MacBook Pro; without compression it took ~1s.
|
||||
// Thus we're not using compressed snapshot, trading off
|
||||
// a lot of build time for some startup time in debug build.
|
||||
#[cfg(debug_assertions)]
|
||||
return COMPRESSED_COMPILER_SNAPSHOT.to_vec().into_boxed_slice();
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
zstd::bulk::decompress(
|
||||
&COMPRESSED_COMPILER_SNAPSHOT[4..],
|
||||
u32::from_le_bytes(COMPRESSED_COMPILER_SNAPSHOT[0..4].try_into().unwrap())
|
||||
as usize,
|
||||
)
|
||||
.unwrap()
|
||||
.into_boxed_slice()
|
||||
},
|
||||
);
|
||||
|
||||
pub fn get_types_declaration_file_text() -> String {
|
||||
let mut assets = get_asset_texts_from_new_runtime()
|
||||
let mut assets = get_asset_texts()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|a| (a.specifier, a.text))
|
||||
|
@ -120,41 +94,146 @@ pub fn get_types_declaration_file_text() -> String {
|
|||
.join("\n")
|
||||
}
|
||||
|
||||
fn get_asset_texts_from_new_runtime() -> Result<Vec<AssetText>, AnyError> {
|
||||
deno_core::extension!(
|
||||
deno_cli_tsc,
|
||||
ops = [
|
||||
op_create_hash,
|
||||
op_emit,
|
||||
op_is_node_file,
|
||||
op_load,
|
||||
op_remap_specifier,
|
||||
op_resolve,
|
||||
op_respond,
|
||||
]
|
||||
);
|
||||
|
||||
// the assets are stored within the typescript isolate, so take them out of there
|
||||
let mut runtime = JsRuntime::new(RuntimeOptions {
|
||||
startup_snapshot: Some(compiler_snapshot()),
|
||||
extensions: vec![deno_cli_tsc::init_ops()],
|
||||
..Default::default()
|
||||
});
|
||||
let global = runtime
|
||||
.execute_script("get_assets.js", ascii_str!("globalThis.getAssets()"))?;
|
||||
let scope = &mut runtime.handle_scope();
|
||||
let local = deno_core::v8::Local::new(scope, global);
|
||||
Ok(serde_v8::from_v8::<Vec<AssetText>>(scope, local)?)
|
||||
fn get_asset_texts() -> Result<Vec<AssetText>, AnyError> {
|
||||
let mut out = Vec::with_capacity(LAZILY_LOADED_STATIC_ASSETS.len());
|
||||
for (name, text) in LAZILY_LOADED_STATIC_ASSETS.iter() {
|
||||
out.push(AssetText {
|
||||
specifier: format!("asset:///{name}"),
|
||||
text: text.to_string(),
|
||||
});
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
pub fn compiler_snapshot() -> &'static [u8] {
|
||||
&COMPILER_SNAPSHOT
|
||||
macro_rules! maybe_compressed_source {
|
||||
($file: expr) => {{
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
StaticAssetSource::Uncompressed(include_str!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/",
|
||||
$file
|
||||
)))
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
StaticAssetSource::Compressed(CompressedSource::new(include_bytes!(
|
||||
concat!(env!("OUT_DIR"), "/", $file, ".zstd")
|
||||
)))
|
||||
}
|
||||
}};
|
||||
(compressed = $comp: expr, uncompressed = $uncomp: expr) => {{
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
StaticAssetSource::Uncompressed(include_str!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/",
|
||||
$uncomp
|
||||
)))
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
StaticAssetSource::Compressed(CompressedSource::new(include_bytes!(
|
||||
concat!(env!("OUT_DIR"), "/", $comp, ".zstd")
|
||||
)))
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! inc {
|
||||
($e:expr) => {
|
||||
include_str!(concat!("./dts/", $e))
|
||||
macro_rules! maybe_compressed_lib {
|
||||
($name: expr, $file: expr) => {
|
||||
($name, maybe_compressed_source!(concat!("tsc/dts/", $file)))
|
||||
};
|
||||
($e: expr) => {
|
||||
maybe_compressed_lib!($e, $e)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! maybe_compressed_ext_lib {
|
||||
($name: expr, $file: expr) => {
|
||||
(
|
||||
$name,
|
||||
maybe_compressed_source!(
|
||||
compressed = concat!("ext/", $file),
|
||||
uncompressed = concat!("../ext/", $file)
|
||||
),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum StaticAssetSource {
|
||||
#[cfg_attr(debug_assertions, allow(dead_code))]
|
||||
Compressed(CompressedSource),
|
||||
Uncompressed(&'static str),
|
||||
}
|
||||
|
||||
/// Like a `Cow` but the owned form is an `Arc<str>` instead of `String`
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MaybeStaticSource {
|
||||
Computed(Arc<str>),
|
||||
Static(&'static str),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MaybeStaticSource {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
MaybeStaticSource::Computed(arc) => write!(f, "{}", arc),
|
||||
MaybeStaticSource::Static(s) => write!(f, "{}", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MaybeStaticSource> for Cow<'static, str> {
|
||||
fn from(value: MaybeStaticSource) -> Self {
|
||||
match value {
|
||||
MaybeStaticSource::Computed(arc) => Cow::Owned(arc.to_string()),
|
||||
MaybeStaticSource::Static(s) => Cow::Borrowed(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for MaybeStaticSource {
|
||||
fn as_ref(&self) -> &str {
|
||||
match self {
|
||||
MaybeStaticSource::Computed(arc) => arc.as_ref(),
|
||||
MaybeStaticSource::Static(s) => s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MaybeStaticSource> for String {
|
||||
fn from(value: MaybeStaticSource) -> Self {
|
||||
match value {
|
||||
MaybeStaticSource::Computed(arc) => arc.to_string(),
|
||||
MaybeStaticSource::Static(s) => s.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MaybeStaticSource> for Arc<str> {
|
||||
fn from(value: MaybeStaticSource) -> Self {
|
||||
match value {
|
||||
MaybeStaticSource::Computed(arc) => arc,
|
||||
MaybeStaticSource::Static(s) => Arc::from(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticAssetSource {
|
||||
pub fn get(&self) -> MaybeStaticSource {
|
||||
match self {
|
||||
StaticAssetSource::Compressed(compressed_source) => {
|
||||
MaybeStaticSource::Computed(compressed_source.get())
|
||||
}
|
||||
StaticAssetSource::Uncompressed(src) => MaybeStaticSource::Static(src),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::inherent_to_string)]
|
||||
pub fn to_string(&self) -> String {
|
||||
self.get().into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains static assets that are not preloaded in the compiler snapshot.
|
||||
|
@ -162,40 +241,154 @@ macro_rules! inc {
|
|||
/// We lazily load these because putting them in the compiler snapshot will
|
||||
/// increase memory usage when not used (last time checked by about 0.5MB).
|
||||
pub static LAZILY_LOADED_STATIC_ASSETS: Lazy<
|
||||
HashMap<&'static str, &'static str>,
|
||||
HashMap<&'static str, StaticAssetSource>,
|
||||
> = Lazy::new(|| {
|
||||
([
|
||||
(
|
||||
"lib.dom.asynciterable.d.ts",
|
||||
inc!("lib.dom.asynciterable.d.ts"),
|
||||
// compressed in build.rs
|
||||
maybe_compressed_ext_lib!(
|
||||
"lib.deno.console.d.ts",
|
||||
"console/lib.deno_console.d.ts"
|
||||
),
|
||||
("lib.dom.d.ts", inc!("lib.dom.d.ts")),
|
||||
("lib.dom.extras.d.ts", inc!("lib.dom.extras.d.ts")),
|
||||
("lib.dom.iterable.d.ts", inc!("lib.dom.iterable.d.ts")),
|
||||
("lib.es6.d.ts", inc!("lib.es6.d.ts")),
|
||||
("lib.es2016.full.d.ts", inc!("lib.es2016.full.d.ts")),
|
||||
("lib.es2017.full.d.ts", inc!("lib.es2017.full.d.ts")),
|
||||
("lib.es2018.full.d.ts", inc!("lib.es2018.full.d.ts")),
|
||||
("lib.es2019.full.d.ts", inc!("lib.es2019.full.d.ts")),
|
||||
("lib.es2020.full.d.ts", inc!("lib.es2020.full.d.ts")),
|
||||
("lib.es2021.full.d.ts", inc!("lib.es2021.full.d.ts")),
|
||||
("lib.es2022.full.d.ts", inc!("lib.es2022.full.d.ts")),
|
||||
("lib.esnext.full.d.ts", inc!("lib.esnext.full.d.ts")),
|
||||
("lib.scripthost.d.ts", inc!("lib.scripthost.d.ts")),
|
||||
("lib.webworker.d.ts", inc!("lib.webworker.d.ts")),
|
||||
(
|
||||
"lib.webworker.importscripts.d.ts",
|
||||
inc!("lib.webworker.importscripts.d.ts"),
|
||||
maybe_compressed_ext_lib!("lib.deno.url.d.ts", "url/lib.deno_url.d.ts"),
|
||||
maybe_compressed_ext_lib!("lib.deno.web.d.ts", "web/lib.deno_web.d.ts"),
|
||||
maybe_compressed_ext_lib!(
|
||||
"lib.deno.fetch.d.ts",
|
||||
"fetch/lib.deno_fetch.d.ts"
|
||||
),
|
||||
(
|
||||
"lib.webworker.iterable.d.ts",
|
||||
inc!("lib.webworker.iterable.d.ts"),
|
||||
maybe_compressed_ext_lib!(
|
||||
"lib.deno.websocket.d.ts",
|
||||
"websocket/lib.deno_websocket.d.ts"
|
||||
),
|
||||
maybe_compressed_ext_lib!(
|
||||
"lib.deno.webstorage.d.ts",
|
||||
"webstorage/lib.deno_webstorage.d.ts"
|
||||
),
|
||||
maybe_compressed_ext_lib!(
|
||||
"lib.deno.canvas.d.ts",
|
||||
"canvas/lib.deno_canvas.d.ts"
|
||||
),
|
||||
maybe_compressed_ext_lib!(
|
||||
"lib.deno.crypto.d.ts",
|
||||
"crypto/lib.deno_crypto.d.ts"
|
||||
),
|
||||
maybe_compressed_ext_lib!(
|
||||
"lib.deno.broadcast_channel.d.ts",
|
||||
"broadcast_channel/lib.deno_broadcast_channel.d.ts"
|
||||
),
|
||||
maybe_compressed_ext_lib!("lib.deno.net.d.ts", "net/lib.deno_net.d.ts"),
|
||||
maybe_compressed_ext_lib!(
|
||||
"lib.deno.cache.d.ts",
|
||||
"cache/lib.deno_cache.d.ts"
|
||||
),
|
||||
maybe_compressed_lib!("lib.deno.webgpu.d.ts", "lib.deno_webgpu.d.ts"),
|
||||
maybe_compressed_lib!("lib.deno.window.d.ts"),
|
||||
maybe_compressed_lib!("lib.deno.worker.d.ts"),
|
||||
maybe_compressed_lib!("lib.deno.shared_globals.d.ts"),
|
||||
maybe_compressed_lib!("lib.deno.ns.d.ts"),
|
||||
maybe_compressed_lib!("lib.deno.unstable.d.ts"),
|
||||
maybe_compressed_lib!("lib.decorators.d.ts"),
|
||||
maybe_compressed_lib!("lib.decorators.legacy.d.ts"),
|
||||
maybe_compressed_lib!("lib.dom.asynciterable.d.ts"),
|
||||
maybe_compressed_lib!("lib.dom.d.ts"),
|
||||
maybe_compressed_lib!("lib.dom.extras.d.ts"),
|
||||
maybe_compressed_lib!("lib.dom.iterable.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2015.collection.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2015.core.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2015.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2015.generator.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2015.iterable.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2015.promise.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2015.proxy.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2015.reflect.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2015.symbol.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2015.symbol.wellknown.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2016.array.include.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2016.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2016.full.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2016.intl.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2017.arraybuffer.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2017.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2017.date.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2017.full.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2017.intl.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2017.object.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2017.sharedmemory.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2017.string.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2017.typedarrays.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2018.asyncgenerator.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2018.asynciterable.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2018.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2018.full.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2018.intl.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2018.promise.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2018.regexp.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2019.array.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2019.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2019.full.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2019.intl.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2019.object.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2019.string.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2019.symbol.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2020.bigint.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2020.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2020.date.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2020.full.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2020.intl.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2020.number.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2020.promise.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2020.sharedmemory.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2020.string.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2020.symbol.wellknown.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2021.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2021.full.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2021.intl.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2021.promise.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2021.string.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2021.weakref.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2022.array.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2022.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2022.error.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2022.full.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2022.intl.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2022.object.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2022.regexp.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2022.string.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2023.array.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2023.collection.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2023.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2023.full.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2023.intl.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2024.arraybuffer.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2024.collection.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2024.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2024.full.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2024.object.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2024.promise.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2024.regexp.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2024.sharedmemory.d.ts"),
|
||||
maybe_compressed_lib!("lib.es2024.string.d.ts"),
|
||||
maybe_compressed_lib!("lib.es5.d.ts"),
|
||||
maybe_compressed_lib!("lib.es6.d.ts"),
|
||||
maybe_compressed_lib!("lib.esnext.array.d.ts"),
|
||||
maybe_compressed_lib!("lib.esnext.collection.d.ts"),
|
||||
maybe_compressed_lib!("lib.esnext.d.ts"),
|
||||
maybe_compressed_lib!("lib.esnext.decorators.d.ts"),
|
||||
maybe_compressed_lib!("lib.esnext.disposable.d.ts"),
|
||||
maybe_compressed_lib!("lib.esnext.full.d.ts"),
|
||||
maybe_compressed_lib!("lib.esnext.intl.d.ts"),
|
||||
maybe_compressed_lib!("lib.esnext.iterator.d.ts"),
|
||||
maybe_compressed_lib!("lib.scripthost.d.ts"),
|
||||
maybe_compressed_lib!("lib.webworker.asynciterable.d.ts"),
|
||||
maybe_compressed_lib!("lib.webworker.d.ts"),
|
||||
maybe_compressed_lib!("lib.webworker.importscripts.d.ts"),
|
||||
maybe_compressed_lib!("lib.webworker.iterable.d.ts"),
|
||||
(
|
||||
// Special file that can be used to inject the @types/node package.
|
||||
// This is used for `node:` specifiers.
|
||||
"node_types.d.ts",
|
||||
"/// <reference types=\"npm:@types/node\" />\n",
|
||||
StaticAssetSource::Uncompressed(
|
||||
"/// <reference types=\"npm:@types/node\" />\n",
|
||||
),
|
||||
),
|
||||
])
|
||||
.iter()
|
||||
|
@ -245,8 +438,8 @@ pub struct AssetText {
|
|||
}
|
||||
|
||||
/// Retrieve a static asset that are included in the binary.
|
||||
fn get_lazily_loaded_asset(asset: &str) -> Option<&'static str> {
|
||||
LAZILY_LOADED_STATIC_ASSETS.get(asset).map(|s| s.to_owned())
|
||||
fn get_lazily_loaded_asset(asset: &str) -> Option<MaybeStaticSource> {
|
||||
LAZILY_LOADED_STATIC_ASSETS.get(asset).map(|s| s.get())
|
||||
}
|
||||
|
||||
fn get_maybe_hash(
|
||||
|
@ -603,10 +796,10 @@ fn op_load_inner(
|
|||
} else if load_specifier == MISSING_DEPENDENCY_SPECIFIER {
|
||||
None
|
||||
} else if let Some(name) = load_specifier.strip_prefix("asset:///") {
|
||||
let maybe_source = get_lazily_loaded_asset(name);
|
||||
hash = get_maybe_hash(maybe_source, state.hash_data);
|
||||
let maybe_source = get_lazily_loaded_asset(name).map(Cow::from);
|
||||
hash = get_maybe_hash(maybe_source.as_deref(), state.hash_data);
|
||||
media_type = MediaType::from_str(load_specifier);
|
||||
maybe_source.map(Cow::Borrowed)
|
||||
maybe_source
|
||||
} else {
|
||||
let specifier = if let Some(remapped_specifier) =
|
||||
state.maybe_remapped_specifier(load_specifier)
|
||||
|
@ -748,6 +941,20 @@ fn op_remap_specifier(
|
|||
.map(|url| url.to_string())
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
fn op_libs() -> Vec<String> {
|
||||
let mut out = Vec::with_capacity(LAZILY_LOADED_STATIC_ASSETS.len());
|
||||
for key in LAZILY_LOADED_STATIC_ASSETS.keys() {
|
||||
let lib = key
|
||||
.replace("lib.", "")
|
||||
.replace(".d.ts", "")
|
||||
.replace("deno_", "deno.");
|
||||
out.push(lib);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[serde]
|
||||
fn op_resolve(
|
||||
|
@ -1087,6 +1294,84 @@ pub enum ExecError {
|
|||
Core(deno_core::error::CoreError),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct CompressedSource {
|
||||
bytes: &'static [u8],
|
||||
uncompressed: OnceLock<Arc<str>>,
|
||||
}
|
||||
|
||||
impl CompressedSource {
|
||||
#[cfg_attr(debug_assertions, allow(dead_code))]
|
||||
pub(crate) const fn new(bytes: &'static [u8]) -> Self {
|
||||
Self {
|
||||
bytes,
|
||||
uncompressed: OnceLock::new(),
|
||||
}
|
||||
}
|
||||
pub(crate) fn get(&self) -> Arc<str> {
|
||||
self
|
||||
.uncompressed
|
||||
.get_or_init(|| decompress_source(self.bytes))
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) static MAIN_COMPILER_SOURCE: StaticAssetSource =
|
||||
maybe_compressed_source!("tsc/99_main_compiler.js");
|
||||
pub(crate) static LSP_SOURCE: StaticAssetSource =
|
||||
maybe_compressed_source!("tsc/98_lsp.js");
|
||||
pub(crate) static TS_HOST_SOURCE: StaticAssetSource =
|
||||
maybe_compressed_source!("tsc/97_ts_host.js");
|
||||
pub(crate) static TYPESCRIPT_SOURCE: StaticAssetSource =
|
||||
maybe_compressed_source!("tsc/00_typescript.js");
|
||||
|
||||
pub(crate) fn decompress_source(contents: &[u8]) -> Arc<str> {
|
||||
let len_bytes = contents[0..4].try_into().unwrap();
|
||||
let len = u32::from_le_bytes(len_bytes);
|
||||
let uncompressed =
|
||||
zstd::bulk::decompress(&contents[4..], len as usize).unwrap();
|
||||
String::from_utf8(uncompressed).unwrap().into()
|
||||
}
|
||||
|
||||
deno_core::extension!(deno_cli_tsc,
|
||||
ops = [
|
||||
op_create_hash,
|
||||
op_emit,
|
||||
op_is_node_file,
|
||||
op_load,
|
||||
op_remap_specifier,
|
||||
op_resolve,
|
||||
op_respond,
|
||||
op_libs,
|
||||
],
|
||||
options = {
|
||||
request: Request,
|
||||
root_map: HashMap<String, Url>,
|
||||
remapped_specifiers: HashMap<String, Url>,
|
||||
},
|
||||
state = |state, options| {
|
||||
state.put(State::new(
|
||||
options.request.graph,
|
||||
options.request.hash_data,
|
||||
options.request.maybe_npm,
|
||||
options.request.maybe_tsbuildinfo,
|
||||
options.root_map,
|
||||
options.remapped_specifiers,
|
||||
std::env::current_dir()
|
||||
.context("Unable to get CWD")
|
||||
.unwrap(),
|
||||
));
|
||||
},
|
||||
customizer = |ext: &mut deno_core::Extension| {
|
||||
use deno_core::ExtensionFileSource;
|
||||
ext.esm_files.to_mut().push(ExtensionFileSource::new_computed("ext:deno_cli_tsc/99_main_compiler.js", crate::tsc::MAIN_COMPILER_SOURCE.get().into()));
|
||||
ext.esm_files.to_mut().push(ExtensionFileSource::new_computed("ext:deno_cli_tsc/97_ts_host.js", crate::tsc::TS_HOST_SOURCE.get().into()));
|
||||
ext.esm_files.to_mut().push(ExtensionFileSource::new_computed("ext:deno_cli_tsc/98_lsp.js", crate::tsc::LSP_SOURCE.get().into()));
|
||||
ext.js_files.to_mut().push(ExtensionFileSource::new_computed("ext:deno_cli_tsc/00_typescript.js", crate::tsc::TYPESCRIPT_SOURCE.get().into()));
|
||||
ext.esm_entry_point = Some("ext:deno_cli_tsc/99_main_compiler.js");
|
||||
}
|
||||
);
|
||||
|
||||
/// Execute a request on the supplied snapshot, returning a response which
|
||||
/// contains information, like any emitted files, diagnostics, statistics and
|
||||
/// optionally an updated TypeScript build info.
|
||||
|
@ -1117,36 +1402,6 @@ pub fn exec(request: Request) -> Result<Response, ExecError> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
deno_core::extension!(deno_cli_tsc,
|
||||
ops = [
|
||||
op_create_hash,
|
||||
op_emit,
|
||||
op_is_node_file,
|
||||
op_load,
|
||||
op_remap_specifier,
|
||||
op_resolve,
|
||||
op_respond,
|
||||
],
|
||||
options = {
|
||||
request: Request,
|
||||
root_map: HashMap<String, Url>,
|
||||
remapped_specifiers: HashMap<String, Url>,
|
||||
},
|
||||
state = |state, options| {
|
||||
state.put(State::new(
|
||||
options.request.graph,
|
||||
options.request.hash_data,
|
||||
options.request.maybe_npm,
|
||||
options.request.maybe_tsbuildinfo,
|
||||
options.root_map,
|
||||
options.remapped_specifiers,
|
||||
std::env::current_dir()
|
||||
.context("Unable to get CWD")
|
||||
.unwrap(),
|
||||
));
|
||||
},
|
||||
);
|
||||
|
||||
let request_value = json!({
|
||||
"config": request.config,
|
||||
"debug": request.debug,
|
||||
|
@ -1156,8 +1411,7 @@ pub fn exec(request: Request) -> Result<Response, ExecError> {
|
|||
let exec_source = format!("globalThis.exec({request_value})");
|
||||
|
||||
let mut runtime = JsRuntime::new(RuntimeOptions {
|
||||
startup_snapshot: Some(compiler_snapshot()),
|
||||
extensions: vec![deno_cli_tsc::init_ops(
|
||||
extensions: vec![deno_cli_tsc::init_ops_and_esm(
|
||||
request,
|
||||
root_map,
|
||||
remapped_specifiers,
|
||||
|
@ -1319,7 +1573,21 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn test_compiler_snapshot() {
|
||||
let mut js_runtime = JsRuntime::new(RuntimeOptions {
|
||||
startup_snapshot: Some(compiler_snapshot()),
|
||||
startup_snapshot: None,
|
||||
extensions: vec![super::deno_cli_tsc::init_ops_and_esm(
|
||||
Request {
|
||||
check_mode: TypeCheckMode::All,
|
||||
config: Arc::new(TsConfig(json!({}))),
|
||||
debug: false,
|
||||
graph: Arc::new(ModuleGraph::new(GraphKind::TypesOnly)),
|
||||
hash_data: 0,
|
||||
maybe_npm: None,
|
||||
maybe_tsbuildinfo: None,
|
||||
root_names: vec![],
|
||||
},
|
||||
HashMap::new(),
|
||||
HashMap::new(),
|
||||
)],
|
||||
..Default::default()
|
||||
});
|
||||
js_runtime
|
||||
|
@ -1402,7 +1670,7 @@ mod tests {
|
|||
.expect("should have invoked op")
|
||||
.expect("load should have succeeded");
|
||||
let expected = get_lazily_loaded_asset("lib.dom.d.ts").unwrap();
|
||||
assert_eq!(actual.data, expected);
|
||||
assert_eq!(actual.data, expected.to_string());
|
||||
assert!(actual.version.is_some());
|
||||
assert_eq!(actual.script_kind, 3);
|
||||
}
|
||||
|
|
|
@ -11612,14 +11612,12 @@ fn lsp_performance() {
|
|||
"lsp.update_diagnostics_lint",
|
||||
"lsp.update_diagnostics_ts",
|
||||
"lsp.update_global_cache",
|
||||
"tsc.host.$getAssets",
|
||||
"tsc.host.$getDiagnostics",
|
||||
"tsc.host.$getSupportedCodeFixes",
|
||||
"tsc.host.getQuickInfoAtPosition",
|
||||
"tsc.op.op_is_node_file",
|
||||
"tsc.op.op_load",
|
||||
"tsc.op.op_script_names",
|
||||
"tsc.request.$getAssets",
|
||||
"tsc.request.$getDiagnostics",
|
||||
"tsc.request.$getSupportedCodeFixes",
|
||||
"tsc.request.getQuickInfoAtPosition",
|
||||
|
|
Loading…
Add table
Reference in a new issue