summaryrefslogtreecommitdiff
path: root/cli/tsc
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tsc')
-rw-r--r--cli/tsc/99_main_compiler.js43
-rw-r--r--cli/tsc/mod.rs200
2 files changed, 139 insertions, 104 deletions
diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js
index a3cdad742..a0219fe13 100644
--- a/cli/tsc/99_main_compiler.js
+++ b/cli/tsc/99_main_compiler.js
@@ -385,7 +385,7 @@ delete Object.prototype.__proto__;
// paths must be either relative or absolute. Since
// analysis in Rust operates on fully resolved URLs,
// it makes sense to use the same scheme here.
- const ASSETS = "asset:///";
+ const ASSETS_URL_PREFIX = "asset:///";
/** Diagnostics that are intentionally ignored when compiling TypeScript in
* Deno, as they provide misleading or incorrect information. */
@@ -431,6 +431,7 @@ delete Object.prototype.__proto__;
noEmit: true,
strict: true,
target: ts.ScriptTarget.ESNext,
+ lib: ["lib.deno.window.d.ts"],
};
// todo(dsherret): can we remove this and just use ts.OperationCanceledException?
@@ -546,10 +547,10 @@ delete Object.prototype.__proto__;
return sourceFile;
},
getDefaultLibFileName() {
- return `${ASSETS}/lib.esnext.d.ts`;
+ return `${ASSETS_URL_PREFIX}lib.esnext.d.ts`;
},
getDefaultLibLocation() {
- return ASSETS;
+ return ASSETS_URL_PREFIX;
},
writeFile(fileName, data, _writeByteOrderMark, _onError, _sourceFiles) {
if (logDebug) {
@@ -887,6 +888,20 @@ delete Object.prototype.__proto__;
debug("<<< exec stop");
}
+ function getAssets() {
+ /** @type {{ specifier: string; text: string; }[]} */
+ const assets = [];
+ for (const sourceFile of sourceFileCache.values()) {
+ if (sourceFile.fileName.startsWith(ASSETS_URL_PREFIX)) {
+ assets.push({
+ specifier: sourceFile.fileName,
+ text: sourceFile.text,
+ });
+ }
+ }
+ return assets;
+ }
+
/**
* @param {number} id
* @param {any} data
@@ -935,16 +950,7 @@ delete Object.prototype.__proto__;
);
}
case "getAssets": {
- const assets = [];
- for (const sourceFile of sourceFileCache.values()) {
- if (sourceFile.fileName.startsWith(ASSETS)) {
- assets.push({
- specifier: sourceFile.fileName,
- text: sourceFile.text,
- });
- }
- }
- return respond(id, assets);
+ return respond(id, getAssets());
}
case "getApplicableRefactors": {
return respond(
@@ -1281,7 +1287,10 @@ delete Object.prototype.__proto__;
// 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}${specifier}`, ts.ScriptTarget.ESNext),
+ host.getSourceFile(
+ `${ASSETS_URL_PREFIX}${specifier}`,
+ ts.ScriptTarget.ESNext,
+ ),
);
}
// this helps ensure as much as possible is in memory that is re-usable
@@ -1292,12 +1301,16 @@ delete Object.prototype.__proto__;
options: SNAPSHOT_COMPILE_OPTIONS,
host,
});
- ts.getPreEmitDiagnostics(TS_SNAPSHOT_PROGRAM);
+ assert(ts.getPreEmitDiagnostics(TS_SNAPSHOT_PROGRAM).length === 0);
+
+ // remove this now that we don't need it anymore for warming up tsc
+ sourceFileCache.delete(buildSpecifier);
// exposes the two functions that are called by `tsc::exec()` when type
// checking TypeScript.
globalThis.startup = startup;
globalThis.exec = exec;
+ globalThis.getAssets = getAssets;
// exposes the functions that are called when the compiler is used as a
// language service.
diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs
index 6ea037522..d540e5b33 100644
--- a/cli/tsc/mod.rs
+++ b/cli/tsc/mod.rs
@@ -25,6 +25,7 @@ use deno_core::serde::Serializer;
use deno_core::serde_json;
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
+use deno_core::serde_v8;
use deno_core::Extension;
use deno_core::JsRuntime;
use deno_core::ModuleSpecifier;
@@ -49,28 +50,6 @@ pub use self::diagnostics::DiagnosticMessageChain;
pub use self::diagnostics::Diagnostics;
pub use self::diagnostics::Position;
-// Declaration files
-
-pub static DENO_NS_LIB: &str = include_str!("dts/lib.deno.ns.d.ts");
-pub static DENO_CONSOLE_LIB: &str = include_str!(env!("DENO_CONSOLE_LIB_PATH"));
-pub static DENO_URL_LIB: &str = include_str!(env!("DENO_URL_LIB_PATH"));
-pub static DENO_WEB_LIB: &str = include_str!(env!("DENO_WEB_LIB_PATH"));
-pub static DENO_FETCH_LIB: &str = include_str!(env!("DENO_FETCH_LIB_PATH"));
-pub static DENO_WEBGPU_LIB: &str = include_str!(env!("DENO_WEBGPU_LIB_PATH"));
-pub static DENO_WEBSOCKET_LIB: &str =
- include_str!(env!("DENO_WEBSOCKET_LIB_PATH"));
-pub static DENO_WEBSTORAGE_LIB: &str =
- include_str!(env!("DENO_WEBSTORAGE_LIB_PATH"));
-pub static DENO_CACHE_LIB: &str = include_str!(env!("DENO_CACHE_LIB_PATH"));
-pub static DENO_CRYPTO_LIB: &str = include_str!(env!("DENO_CRYPTO_LIB_PATH"));
-pub static DENO_BROADCAST_CHANNEL_LIB: &str =
- include_str!(env!("DENO_BROADCAST_CHANNEL_LIB_PATH"));
-pub static DENO_NET_LIB: &str = include_str!(env!("DENO_NET_LIB_PATH"));
-pub static SHARED_GLOBALS_LIB: &str =
- include_str!("dts/lib.deno.shared_globals.d.ts");
-pub static WINDOW_LIB: &str = include_str!("dts/lib.deno.window.d.ts");
-pub static UNSTABLE_NS_LIB: &str = include_str!("dts/lib.deno.unstable.d.ts");
-
pub static COMPILER_SNAPSHOT: Lazy<Box<[u8]>> = Lazy::new(
#[cold]
#[inline(never)]
@@ -89,28 +68,57 @@ pub static COMPILER_SNAPSHOT: Lazy<Box<[u8]>> = Lazy::new(
);
pub fn get_types_declaration_file_text(unstable: bool) -> String {
- let mut types = vec![
- DENO_NS_LIB,
- DENO_CONSOLE_LIB,
- DENO_URL_LIB,
- DENO_WEB_LIB,
- DENO_FETCH_LIB,
- DENO_WEBGPU_LIB,
- DENO_WEBSOCKET_LIB,
- DENO_WEBSTORAGE_LIB,
- DENO_CRYPTO_LIB,
- DENO_BROADCAST_CHANNEL_LIB,
- DENO_NET_LIB,
- SHARED_GLOBALS_LIB,
- DENO_CACHE_LIB,
- WINDOW_LIB,
+ let mut assets = get_asset_texts_from_new_runtime()
+ .unwrap()
+ .into_iter()
+ .map(|a| (a.specifier, a.text))
+ .collect::<HashMap<_, _>>();
+
+ let mut lib_names = vec![
+ "deno.ns",
+ "deno.console",
+ "deno.url",
+ "deno.web",
+ "deno.fetch",
+ "deno.webgpu",
+ "deno.websocket",
+ "deno.webstorage",
+ "deno.crypto",
+ "deno.broadcast_channel",
+ "deno.net",
+ "deno.shared_globals",
+ "deno.cache",
+ "deno.window",
];
if unstable {
- types.push(UNSTABLE_NS_LIB);
+ lib_names.push("deno.unstable");
}
- types.join("\n")
+ lib_names
+ .into_iter()
+ .map(|name| {
+ let asset_url = format!("asset:///lib.{}.d.ts", name);
+ assets.remove(&asset_url).unwrap()
+ })
+ .collect::<Vec<_>>()
+ .join("\n")
+}
+
+fn get_asset_texts_from_new_runtime() -> Result<Vec<AssetText>, AnyError> {
+ // 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![Extension::builder("deno_cli_tsc")
+ .ops(get_tsc_ops())
+ .build()],
+ ..Default::default()
+ });
+ let global =
+ runtime.execute_script("get_assets.js", "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)?)
}
pub fn compiler_snapshot() -> Snapshot {
@@ -124,40 +132,44 @@ macro_rules! inc {
}
/// Contains static assets that are not preloaded in the compiler snapshot.
-pub static STATIC_ASSETS: Lazy<HashMap<&'static str, &'static str>> =
- Lazy::new(|| {
- ([
- (
- "lib.dom.asynciterable.d.ts",
- inc!("lib.dom.asynciterable.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"),
- ),
- (
- "lib.webworker.iterable.d.ts",
- inc!("lib.webworker.iterable.d.ts"),
- ),
- ])
- .iter()
- .cloned()
- .collect()
- });
+///
+/// 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>,
+> = Lazy::new(|| {
+ ([
+ (
+ "lib.dom.asynciterable.d.ts",
+ inc!("lib.dom.asynciterable.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"),
+ ),
+ (
+ "lib.webworker.iterable.d.ts",
+ inc!("lib.webworker.iterable.d.ts"),
+ ),
+ ])
+ .iter()
+ .cloned()
+ .collect()
+});
/// A structure representing stats from a type check operation for a graph.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
@@ -193,9 +205,16 @@ impl fmt::Display for Stats {
}
}
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct AssetText {
+ pub specifier: String,
+ pub text: String,
+}
+
/// Retrieve a static asset that are included in the binary.
-pub fn get_asset(asset: &str) -> Option<&'static str> {
- STATIC_ASSETS.get(asset).map(|s| s.to_owned())
+fn get_lazily_loaded_asset(asset: &str) -> Option<&'static str> {
+ LAZILY_LOADED_STATIC_ASSETS.get(asset).map(|s| s.to_owned())
}
fn get_maybe_hash(
@@ -501,9 +520,8 @@ fn op_load(state: &mut OpState, args: Value) -> Result<Value, AnyError> {
hash = Some("1".to_string());
media_type = MediaType::Dts;
Some(Cow::Borrowed("declare const __: any;\nexport = __;\n"))
- } else if v.specifier.starts_with("asset:///") {
- let name = v.specifier.replace("asset:///", "");
- let maybe_source = get_asset(&name);
+ } else if let Some(name) = v.specifier.strip_prefix("asset:///") {
+ let maybe_source = get_lazily_loaded_asset(name);
hash = get_maybe_hash(maybe_source, &state.hash_data);
media_type = MediaType::from(&v.specifier);
maybe_source.map(Cow::Borrowed)
@@ -774,16 +792,7 @@ pub fn exec(request: Request) -> Result<Response, AnyError> {
let mut runtime = JsRuntime::new(RuntimeOptions {
startup_snapshot: Some(compiler_snapshot()),
extensions: vec![Extension::builder("deno_cli_tsc")
- .ops(vec![
- op_cwd::decl(),
- op_create_hash::decl(),
- op_emit::decl(),
- op_exists::decl(),
- op_is_node_file::decl(),
- op_load::decl(),
- op_resolve::decl(),
- op_respond::decl(),
- ])
+ .ops(get_tsc_ops())
.state(move |state| {
state.put(State::new(
request.graph_data.clone(),
@@ -833,6 +842,19 @@ pub fn exec(request: Request) -> Result<Response, AnyError> {
}
}
+fn get_tsc_ops() -> Vec<deno_core::OpDecl> {
+ vec![
+ op_cwd::decl(),
+ op_create_hash::decl(),
+ op_emit::decl(),
+ op_exists::decl(),
+ op_is_node_file::decl(),
+ op_load::decl(),
+ op_resolve::decl(),
+ op_respond::decl(),
+ ]
+}
+
#[cfg(test)]
mod tests {
use super::Diagnostic;
@@ -1089,7 +1111,7 @@ mod tests {
.expect("should have invoked op");
let actual: LoadResponse =
serde_json::from_value(value).expect("failed to deserialize");
- let expected = get_asset("lib.dom.d.ts").unwrap();
+ let expected = get_lazily_loaded_asset("lib.dom.d.ts").unwrap();
assert_eq!(actual.data, expected);
assert!(actual.version.is_some());
assert_eq!(actual.script_kind, 3);