diff options
Diffstat (limited to 'cli')
-rw-r--r-- | cli/build.rs | 156 | ||||
-rw-r--r-- | cli/lsp/tsc.rs | 115 | ||||
-rw-r--r-- | cli/ops/bench.rs | 23 | ||||
-rw-r--r-- | cli/ops/errors.rs | 11 | ||||
-rw-r--r-- | cli/ops/runtime_compiler.rs | 8 | ||||
-rw-r--r-- | cli/ops/testing.rs | 20 | ||||
-rw-r--r-- | cli/tsc.rs | 183 | ||||
-rw-r--r-- | cli/tsc/99_main_compiler.js | 1 |
8 files changed, 317 insertions, 200 deletions
diff --git a/cli/build.rs b/cli/build.rs index 26b27a955..f1eb1829c 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -1,11 +1,14 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::error::custom_error; -use deno_core::op_sync; +use deno_core::error::AnyError; +use deno_core::op; use deno_core::serde::Deserialize; use deno_core::serde_json::json; use deno_core::serde_json::Value; +use deno_core::Extension; use deno_core::JsRuntime; +use deno_core::OpState; use deno_core::RuntimeOptions; use regex::Regex; use std::collections::HashMap; @@ -185,79 +188,112 @@ fn create_compiler_snapshot( build_libs.push(op_lib.to_owned()); } - let re_asset = Regex::new(r"asset:/{3}lib\.(\S+)\.d\.ts").expect("bad regex"); - let build_specifier = "asset:///bootstrap.ts"; + #[op] + fn op_build_info( + state: &mut OpState, + _args: Value, + _: (), + ) -> Result<Value, AnyError> { + let build_specifier = "asset:///bootstrap.ts"; + let build_libs = state.borrow::<Vec<&str>>(); + Ok(json!({ + "buildSpecifier": build_specifier, + "libs": build_libs, + })) + } - let mut js_runtime = JsRuntime::new(RuntimeOptions { - will_snapshot: true, - ..Default::default() - }); - js_runtime.register_op( - "op_build_info", - op_sync(move |_state, _args: Value, _: ()| { - Ok(json!({ - "buildSpecifier": build_specifier, - "libs": build_libs, - })) - }), - ); - js_runtime.register_op( - "op_cwd", - op_sync(move |_state, _args: Value, _: ()| Ok(json!("cache:///"))), - ); - // As of TypeScript 4.5, it tries to detect the existence of substitute lib - // files, which we currently don't use, so we just return false. - js_runtime.register_op( - "op_exists", - op_sync(move |_state, _args: LoadArgs, _: ()| Ok(json!(false))), - ); + #[op] + fn op_cwd( + _state: &mut OpState, + _args: Value, + _: (), + ) -> Result<Value, AnyError> { + Ok(json!("cache:///")) + } + + #[op] + fn op_exists( + _state: &mut OpState, + _args: Value, + _: (), + ) -> Result<Value, AnyError> { + Ok(json!(false)) + } + + #[op] // using the same op that is used in `tsc.rs` for loading modules and reading // files, but a slightly different implementation at build time. - js_runtime.register_op( - "op_load", - op_sync(move |_state, args: LoadArgs, _: ()| { - // we need a basic file to send to tsc to warm it up. - if args.specifier == build_specifier { + fn op_load( + state: &mut OpState, + args: LoadArgs, + _: (), + ) -> Result<Value, AnyError> { + let op_crate_libs = state.borrow::<HashMap<&str, &str>>(); + 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"; + + // we need a basic file to send to tsc to warm it up. + if args.specifier == build_specifier { + Ok(json!({ + "data": r#"console.log("hello deno!");"#, + "hash": "1", + // this corresponds to `ts.ScriptKind.TypeScript` + "scriptKind": 3 + })) + // 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. + } else if let Some(caps) = re_asset.captures(&args.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().unwrap() + // otherwise we are will generate the path ourself + } else { + path_dts.join(format!("lib.{}.d.ts", lib)) + }; + let data = std::fs::read_to_string(path)?; Ok(json!({ - "data": r#"console.log("hello deno!");"#, + "data": data, "hash": "1", // this corresponds to `ts.ScriptKind.TypeScript` "scriptKind": 3 })) - // 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. - } else if let Some(caps) = re_asset.captures(&args.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().unwrap() - // otherwise we are will generate the path ourself - } else { - path_dts.join(format!("lib.{}.d.ts", lib)) - }; - let data = std::fs::read_to_string(path)?; - Ok(json!({ - "data": data, - "hash": "1", - // this corresponds to `ts.ScriptKind.TypeScript` - "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), )) } - }), - ); - js_runtime.sync_ops_cache(); + } else { + Err(custom_error( + "InvalidSpecifier", + format!("An invalid specifier was requested: {}", args.specifier), + )) + } + } + let js_runtime = JsRuntime::new(RuntimeOptions { + will_snapshot: true, + extensions: vec![Extension::builder() + .ops(vec![ + op_build_info::decl(), + op_cwd::decl(), + op_exists::decl(), + op_load::decl(), + ]) + .state(move |state| { + state.put(op_crate_libs.clone()); + state.put(build_libs.clone()); + state.put(path_dts.clone()); + + Ok(()) + }) + .build()], + ..Default::default() + }); + create_snapshot(js_runtime, snapshot_path, files); } diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index b849f44e9..648045f4e 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -27,7 +27,7 @@ use deno_core::anyhow::anyhow; use deno_core::error::custom_error; use deno_core::error::AnyError; use deno_core::located_script_name; -use deno_core::op_sync; +use deno_core::op; use deno_core::parking_lot::Mutex; use deno_core::resolve_url; use deno_core::serde::de; @@ -40,7 +40,7 @@ use deno_core::url::Url; use deno_core::Extension; use deno_core::JsRuntime; use deno_core::ModuleSpecifier; -use deno_core::OpFn; +use deno_core::OpState; use deno_core::RuntimeOptions; use deno_runtime::tokio_util::create_basic_runtime; use log::error; @@ -2502,19 +2502,6 @@ fn normalize_specifier<S: AsRef<str>>( .map_err(|err| err.into()) } -// buffer-less json_sync ops -fn op_lsp<F, V, R>(op_fn: F) -> Box<OpFn> -where - F: Fn(&mut State, V) -> Result<R, AnyError> + 'static, - V: de::DeserializeOwned, - R: Serialize + 'static, -{ - op_sync(move |s, args, _: ()| { - let state = s.borrow_mut::<State>(); - op_fn(state, args) - }) -} - #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] struct SourceSnapshotArgs { @@ -2524,10 +2511,13 @@ struct SourceSnapshotArgs { /// The language service is dropping a reference to a source file snapshot, and /// we can drop our version of that document. +#[op] fn op_dispose( - state: &mut State, + state: &mut OpState, args: SourceSnapshotArgs, + _: (), ) -> Result<bool, AnyError> { + let state = state.borrow_mut::<State>(); let mark = state.performance.mark("op_dispose", Some(&args)); let specifier = state.normalize_specifier(&args.specifier)?; state.snapshots.remove(&(specifier, args.version.into())); @@ -2541,7 +2531,13 @@ struct SpecifierArgs { specifier: String, } -fn op_exists(state: &mut State, args: SpecifierArgs) -> Result<bool, AnyError> { +#[op] +fn op_exists( + state: &mut OpState, + args: SpecifierArgs, + _: (), +) -> Result<bool, AnyError> { + let state = state.borrow_mut::<State>(); // we don't measure the performance of op_exists anymore because as of TS 4.5 // it is noisy with all the checking for custom libs, that we can't see the // forrest for the trees as well as it compounds any lsp performance @@ -2569,10 +2565,13 @@ struct GetChangeRangeArgs { /// The language service wants to compare an old snapshot with a new snapshot to /// determine what source has changed. +#[op] fn op_get_change_range( - state: &mut State, + state: &mut OpState, args: GetChangeRangeArgs, + _: (), ) -> Result<Value, AnyError> { + let state = state.borrow_mut::<State>(); let mark = state.performance.mark("op_get_change_range", Some(&args)); let specifier = state.normalize_specifier(&args.specifier)?; cache_snapshot(state, &specifier, args.version.clone())?; @@ -2613,10 +2612,13 @@ fn op_get_change_range( r } +#[op] fn op_get_length( - state: &mut State, + state: &mut OpState, args: SourceSnapshotArgs, + _: (), ) -> Result<usize, AnyError> { + let state = state.borrow_mut::<State>(); let mark = state.performance.mark("op_get_length", Some(&args)); let specifier = state.normalize_specifier(args.specifier)?; let r = if let Some(Some(asset)) = @@ -2644,10 +2646,13 @@ struct GetTextArgs { end: usize, } +#[op] fn op_get_text( - state: &mut State, + state: &mut OpState, args: GetTextArgs, + _: (), ) -> Result<String, AnyError> { + let state = state.borrow_mut::<State>(); let mark = state.performance.mark("op_get_text", Some(&args)); let specifier = state.normalize_specifier(args.specifier)?; let maybe_asset = state.state_snapshot.assets.get_cached(&specifier); @@ -2664,14 +2669,23 @@ fn op_get_text( Ok(text::slice(content, args.start..args.end).to_string()) } -fn op_is_cancelled(state: &mut State, _: ()) -> Result<bool, AnyError> { +#[op] +fn op_is_cancelled( + state: &mut OpState, + _: (), + _: (), +) -> Result<bool, AnyError> { + let state = state.borrow_mut::<State>(); Ok(state.token.is_cancelled()) } +#[op] fn op_load( - state: &mut State, + state: &mut OpState, args: SpecifierArgs, + _: (), ) -> Result<Option<String>, AnyError> { + let state = state.borrow_mut::<State>(); let mark = state.performance.mark("op_load", Some(&args)); let specifier = state.normalize_specifier(args.specifier)?; let document = state.state_snapshot.documents.get(&specifier); @@ -2679,10 +2693,13 @@ fn op_load( Ok(document.map(|d| d.content().to_string())) } +#[op] fn op_resolve( - state: &mut State, + state: &mut OpState, args: ResolveArgs, + _: (), ) -> Result<Vec<Option<(String, String)>>, AnyError> { + let state = state.borrow_mut::<State>(); let mark = state.performance.mark("op_resolve", Some(&args)); let referrer = state.normalize_specifier(&args.base)?; @@ -2713,15 +2730,24 @@ fn op_resolve( result } -fn op_respond(state: &mut State, args: Response) -> Result<bool, AnyError> { +#[op] +fn op_respond( + state: &mut OpState, + args: Response, + _: (), +) -> Result<bool, AnyError> { + let state = state.borrow_mut::<State>(); state.response = Some(args); Ok(true) } +#[op] fn op_script_names( - state: &mut State, + state: &mut OpState, _args: Value, + _: (), ) -> Result<Vec<ModuleSpecifier>, AnyError> { + let state = state.borrow_mut::<State>(); Ok( state .state_snapshot @@ -2739,10 +2765,13 @@ struct ScriptVersionArgs { specifier: String, } +#[op] fn op_script_version( - state: &mut State, + state: &mut OpState, args: ScriptVersionArgs, + _: (), ) -> Result<Option<String>, AnyError> { + let state = state.borrow_mut::<State>(); // this op is very "noisy" and measuring its performance is not useful, so we // don't measure it uniquely anymore. let specifier = state.normalize_specifier(args.specifier)?; @@ -2776,17 +2805,17 @@ fn js_runtime(performance: Arc<Performance>) -> JsRuntime { fn init_extension(performance: Arc<Performance>) -> Extension { Extension::builder() .ops(vec![ - ("op_dispose", op_lsp(op_dispose)), - ("op_exists", op_lsp(op_exists)), - ("op_get_change_range", op_lsp(op_get_change_range)), - ("op_get_length", op_lsp(op_get_length)), - ("op_get_text", op_lsp(op_get_text)), - ("op_is_cancelled", op_lsp(op_is_cancelled)), - ("op_load", op_lsp(op_load)), - ("op_resolve", op_lsp(op_resolve)), - ("op_respond", op_lsp(op_respond)), - ("op_script_names", op_lsp(op_script_names)), - ("op_script_version", op_lsp(op_script_version)), + op_dispose::decl(), + op_exists::decl(), + op_get_change_range::decl(), + op_get_length::decl(), + op_get_text::decl(), + op_is_cancelled::decl(), + op_load::decl(), + op_resolve::decl(), + op_respond::decl(), + op_script_names::decl(), + op_script_version::decl(), ]) .state(move |state| { state.put(State::new( @@ -3832,7 +3861,7 @@ mod tests { #[test] fn test_op_exists() { - let (_, state_snapshot, _) = setup( + let (mut rt, state_snapshot, _) = setup( false, json!({ "target": "esnext", @@ -3843,12 +3872,16 @@ mod tests { &[], ); let performance = Arc::new(Performance::default()); - let mut state = State::new(state_snapshot, performance); - let actual = op_exists( - &mut state, + let state = State::new(state_snapshot, performance); + let op_state = rt.op_state(); + let mut op_state = op_state.borrow_mut(); + op_state.put(state); + let actual = op_exists::call( + &mut op_state, SpecifierArgs { specifier: "/error/unknown:something/index.d.ts".to_string(), }, + (), ); assert!(actual.is_ok()); let actual = actual.unwrap(); diff --git a/cli/ops/bench.rs b/cli/ops/bench.rs index b535e1236..ab15a2b4b 100644 --- a/cli/ops/bench.rs +++ b/cli/ops/bench.rs @@ -1,7 +1,7 @@ use crate::tools::bench::BenchEvent; use deno_core::error::generic_error; use deno_core::error::AnyError; -use deno_core::op_sync; +use deno_core::op; use deno_core::Extension; use deno_core::ModuleSpecifier; use deno_core::OpState; @@ -15,17 +15,11 @@ use uuid::Uuid; pub fn init(sender: UnboundedSender<BenchEvent>) -> Extension { Extension::builder() .ops(vec![ - ( - "op_pledge_test_permissions", - op_sync(op_pledge_test_permissions), - ), - ( - "op_restore_test_permissions", - op_sync(op_restore_test_permissions), - ), - ("op_get_bench_origin", op_sync(op_get_bench_origin)), - ("op_dispatch_bench_event", op_sync(op_dispatch_bench_event)), - ("op_bench_now", op_sync(op_bench_now)), + op_pledge_test_permissions::decl(), + op_restore_test_permissions::decl(), + op_get_bench_origin::decl(), + op_dispatch_bench_event::decl(), + op_bench_now::decl(), ]) .state(move |state| { state.put(sender.clone()); @@ -37,6 +31,7 @@ pub fn init(sender: UnboundedSender<BenchEvent>) -> Extension { #[derive(Clone)] struct PermissionsHolder(Uuid, Permissions); +#[op] pub fn op_pledge_test_permissions( state: &mut OpState, args: ChildPermissionsArg, @@ -55,6 +50,7 @@ pub fn op_pledge_test_permissions( Ok(token) } +#[op] pub fn op_restore_test_permissions( state: &mut OpState, token: Uuid, @@ -73,6 +69,7 @@ pub fn op_restore_test_permissions( } } +#[op] fn op_get_bench_origin( state: &mut OpState, _: (), @@ -81,6 +78,7 @@ fn op_get_bench_origin( Ok(state.borrow::<ModuleSpecifier>().to_string()) } +#[op] fn op_dispatch_bench_event( state: &mut OpState, event: BenchEvent, @@ -92,6 +90,7 @@ fn op_dispatch_bench_event( Ok(()) } +#[op] fn op_bench_now(state: &mut OpState, _: (), _: ()) -> Result<u64, AnyError> { let ns = state.borrow::<time::Instant>().elapsed().as_nanos(); let ns_u64 = u64::try_from(ns)?; diff --git a/cli/ops/errors.rs b/cli/ops/errors.rs index a9193b0cd..c215ade41 100644 --- a/cli/ops/errors.rs +++ b/cli/ops/errors.rs @@ -6,7 +6,7 @@ use crate::proc_state::ProcState; use crate::source_maps::get_orig_position; use crate::source_maps::CachedMaps; use deno_core::error::AnyError; -use deno_core::op_sync; +use deno_core::op; use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; @@ -19,9 +19,9 @@ use std::collections::HashMap; pub fn init() -> Extension { Extension::builder() .ops(vec![ - ("op_apply_source_map", op_sync(op_apply_source_map)), - ("op_format_diagnostic", op_sync(op_format_diagnostic)), - ("op_format_file_name", op_sync(op_format_file_name)), + op_apply_source_map::decl(), + op_format_diagnostic::decl(), + op_format_file_name::decl(), ]) .build() } @@ -42,6 +42,7 @@ struct AppliedSourceMap { column_number: u32, } +#[op] fn op_apply_source_map( state: &mut OpState, args: ApplySourceMap, @@ -66,6 +67,7 @@ fn op_apply_source_map( }) } +#[op] fn op_format_diagnostic( _state: &mut OpState, args: Value, @@ -75,6 +77,7 @@ fn op_format_diagnostic( Ok(json!(diagnostic.to_string())) } +#[op] fn op_format_file_name( _state: &mut OpState, file_name: String, diff --git a/cli/ops/runtime_compiler.rs b/cli/ops/runtime_compiler.rs index 3df93862d..6fb8d688c 100644 --- a/cli/ops/runtime_compiler.rs +++ b/cli/ops/runtime_compiler.rs @@ -16,7 +16,8 @@ use deno_core::anyhow::Context; use deno_core::error::custom_error; use deno_core::error::generic_error; use deno_core::error::AnyError; -use deno_core::op_async; + +use deno_core::op; use deno_core::parking_lot::RwLock; use deno_core::resolve_url_or_path; use deno_core::serde_json; @@ -35,9 +36,7 @@ use std::rc::Rc; use std::sync::Arc; pub fn init() -> Extension { - Extension::builder() - .ops(vec![("op_emit", op_async(op_emit))]) - .build() + Extension::builder().ops(vec![op_emit::decl()]).build() } #[derive(Debug, Deserialize)] @@ -141,6 +140,7 @@ fn to_maybe_jsx_import_source_module( } } +#[op] async fn op_emit( state: Rc<RefCell<OpState>>, args: EmitArgs, diff --git a/cli/ops/testing.rs b/cli/ops/testing.rs index b8995db83..ebaa819e1 100644 --- a/cli/ops/testing.rs +++ b/cli/ops/testing.rs @@ -1,7 +1,7 @@ use crate::tools::test::TestEvent; use deno_core::error::generic_error; use deno_core::error::AnyError; -use deno_core::op_sync; +use deno_core::op; use deno_core::Extension; use deno_core::ModuleSpecifier; use deno_core::OpState; @@ -14,16 +14,10 @@ use uuid::Uuid; pub fn init(sender: UnboundedSender<TestEvent>) -> Extension { Extension::builder() .ops(vec![ - ( - "op_pledge_test_permissions", - op_sync(op_pledge_test_permissions), - ), - ( - "op_restore_test_permissions", - op_sync(op_restore_test_permissions), - ), - ("op_get_test_origin", op_sync(op_get_test_origin)), - ("op_dispatch_test_event", op_sync(op_dispatch_test_event)), + op_pledge_test_permissions::decl(), + op_restore_test_permissions::decl(), + op_get_test_origin::decl(), + op_dispatch_test_event::decl(), ]) .state(move |state| { state.put(sender.clone()); @@ -35,6 +29,7 @@ pub fn init(sender: UnboundedSender<TestEvent>) -> Extension { #[derive(Clone)] struct PermissionsHolder(Uuid, Permissions); +#[op] pub fn op_pledge_test_permissions( state: &mut OpState, args: ChildPermissionsArg, @@ -53,6 +48,7 @@ pub fn op_pledge_test_permissions( Ok(token) } +#[op] pub fn op_restore_test_permissions( state: &mut OpState, token: Uuid, @@ -71,6 +67,7 @@ pub fn op_restore_test_permissions( } } +#[op] fn op_get_test_origin( state: &mut OpState, _: (), @@ -79,6 +76,7 @@ fn op_get_test_origin( Ok(state.borrow::<ModuleSpecifier>().to_string()) } +#[op] fn op_dispatch_test_event( state: &mut OpState, event: TestEvent, diff --git a/cli/tsc.rs b/cli/tsc.rs index 421d95dc5..ddb8a442e 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -11,18 +11,18 @@ use deno_core::anyhow::anyhow; use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::located_script_name; -use deno_core::op_sync; +use deno_core::op; use deno_core::parking_lot::RwLock; use deno_core::resolve_url_or_path; -use deno_core::serde::de; use deno_core::serde::Deserialize; 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::Extension; use deno_core::JsRuntime; use deno_core::ModuleSpecifier; -use deno_core::OpFn; +use deno_core::OpState; use deno_core::RuntimeOptions; use deno_core::Snapshot; use deno_graph::Resolved; @@ -298,18 +298,6 @@ fn normalize_specifier(specifier: &str) -> Result<ModuleSpecifier, AnyError> { .map_err(|err| err.into()) } -fn op<F, V, R>(op_fn: F) -> Box<OpFn> -where - F: Fn(&mut State, V) -> Result<R, AnyError> + 'static, - V: de::DeserializeOwned, - R: Serialize + 'static, -{ - op_sync(move |s, args, _: ()| { - let state = s.borrow_mut::<State>(); - op_fn(state, args) - }) -} - #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] struct CreateHashArgs { @@ -318,7 +306,13 @@ struct CreateHashArgs { data: String, } -fn op_create_hash(state: &mut State, args: Value) -> Result<Value, AnyError> { +#[op] +fn op_create_hash( + s: &mut OpState, + args: Value, + _: (), +) -> Result<Value, AnyError> { + let state = s.borrow_mut::<State>(); let v: CreateHashArgs = serde_json::from_value(args) .context("Invalid request from JavaScript for \"op_create_hash\".")?; let mut data = vec![v.data.as_bytes().to_owned()]; @@ -327,7 +321,9 @@ fn op_create_hash(state: &mut State, args: Value) -> Result<Value, AnyError> { Ok(json!({ "hash": hash })) } -fn op_cwd(state: &mut State, _args: Value) -> Result<String, AnyError> { +#[op] +fn op_cwd(s: &mut OpState, _args: Value, _: ()) -> Result<String, AnyError> { + let state = s.borrow_mut::<State>(); if let Some(config_specifier) = &state.maybe_config_specifier { let cwd = config_specifier.join("./")?; Ok(cwd.to_string()) @@ -350,7 +346,13 @@ struct EmitArgs { maybe_specifiers: Option<Vec<String>>, } -fn op_emit(state: &mut State, args: EmitArgs) -> Result<Value, AnyError> { +#[op] +fn op_emit( + state: &mut OpState, + args: EmitArgs, + _: (), +) -> Result<Value, AnyError> { + let state = state.borrow_mut::<State>(); match args.file_name.as_ref() { "deno:///.tsbuildinfo" => state.maybe_tsbuildinfo = Some(args.data), _ => { @@ -403,7 +405,13 @@ struct ExistsArgs { specifier: String, } -fn op_exists(state: &mut State, args: ExistsArgs) -> Result<bool, AnyError> { +#[op] +fn op_exists( + state: &mut OpState, + args: ExistsArgs, + _: (), +) -> Result<bool, AnyError> { + let state = state.borrow_mut::<State>(); let graph_data = state.graph_data.read(); if let Ok(specifier) = normalize_specifier(&args.specifier) { if specifier.scheme() == "asset" || specifier.scheme() == "data" { @@ -443,7 +451,9 @@ fn as_ts_script_kind(media_type: &MediaType) -> i32 { } } -fn op_load(state: &mut State, args: Value) -> Result<Value, AnyError> { +#[op] +fn op_load(state: &mut OpState, args: Value, _: ()) -> Result<Value, AnyError> { + let state = state.borrow_mut::<State>(); let v: LoadArgs = serde_json::from_value(args) .context("Invalid request from JavaScript for \"op_load\".")?; let specifier = normalize_specifier(&v.specifier) @@ -507,7 +517,13 @@ pub struct ResolveArgs { pub specifiers: Vec<String>, } -fn op_resolve(state: &mut State, args: ResolveArgs) -> Result<Value, AnyError> { +#[op] +fn op_resolve( + state: &mut OpState, + args: ResolveArgs, + _: (), +) -> Result<Value, AnyError> { + let state = state.borrow_mut::<State>(); let mut resolved: Vec<(String, String)> = Vec::new(); let referrer = if let Some(remapped_specifier) = state.remapped_specifiers.get(&args.base) @@ -612,7 +628,13 @@ struct RespondArgs { pub stats: emit::Stats, } -fn op_respond(state: &mut State, args: Value) -> Result<Value, AnyError> { +#[op] +fn op_respond( + state: &mut OpState, + args: Value, + _: (), +) -> Result<Value, AnyError> { + let state = state.borrow_mut::<State>(); let v: RespondArgs = serde_json::from_value(args) .context("Error converting the result for \"op_respond\".")?; state.maybe_response = Some(v); @@ -623,10 +645,6 @@ fn op_respond(state: &mut State, args: Value) -> Result<Value, AnyError> { /// contains information, like any emitted files, diagnostics, statistics and /// optionally an updated TypeScript build info. pub(crate) fn exec(request: Request) -> Result<Response, AnyError> { - let mut runtime = JsRuntime::new(RuntimeOptions { - startup_snapshot: Some(compiler_snapshot()), - ..Default::default() - }); // tsc cannot handle root specifiers that don't have one of the "acceptable" // extensions. Therefore, we have to check the root modules against their // extensions and remap any that are unacceptable to tsc and add them to the @@ -654,28 +672,32 @@ pub(crate) fn exec(request: Request) -> Result<Response, AnyError> { } }) .collect(); - - { - let op_state = runtime.op_state(); - let mut op_state = op_state.borrow_mut(); - op_state.put(State::new( - request.graph_data, - request.hash_data.clone(), - request.maybe_config_specifier.clone(), - request.maybe_tsbuildinfo.clone(), - root_map, - remapped_specifiers, - )); - } - - runtime.register_op("op_cwd", op(op_cwd)); - runtime.register_op("op_create_hash", op(op_create_hash)); - runtime.register_op("op_emit", op(op_emit)); - runtime.register_op("op_exists", op(op_exists)); - runtime.register_op("op_load", op(op_load)); - runtime.register_op("op_resolve", op(op_resolve)); - runtime.register_op("op_respond", op(op_respond)); - runtime.sync_ops_cache(); + let mut runtime = JsRuntime::new(RuntimeOptions { + startup_snapshot: Some(compiler_snapshot()), + extensions: vec![Extension::builder() + .ops(vec![ + op_cwd::decl(), + op_create_hash::decl(), + op_emit::decl(), + op_exists::decl(), + op_load::decl(), + op_resolve::decl(), + op_respond::decl(), + ]) + .state(move |state| { + state.put(State::new( + request.graph_data.clone(), + request.hash_data.clone(), + request.maybe_config_specifier.clone(), + request.maybe_tsbuildinfo.clone(), + root_map.clone(), + remapped_specifiers.clone(), + )); + Ok(()) + }) + .build()], + ..Default::default() + }); let startup_source = "globalThis.startup({ legacyFlag: false })"; let request_value = json!({ @@ -720,6 +742,7 @@ mod tests { use crate::diagnostics::DiagnosticCategory; use crate::emit::Stats; use deno_core::futures::future; + use deno_core::OpState; use deno_graph::ModuleKind; use std::fs; @@ -757,7 +780,7 @@ mod tests { maybe_specifier: Option<ModuleSpecifier>, maybe_hash_data: Option<Vec<Vec<u8>>>, maybe_tsbuildinfo: Option<String>, - ) -> State { + ) -> OpState { let specifier = maybe_specifier .unwrap_or_else(|| resolve_url_or_path("file:///main.ts").unwrap()); let hash_data = maybe_hash_data.unwrap_or_else(|| vec![b"".to_vec()]); @@ -774,14 +797,17 @@ mod tests { None, ) .await; - State::new( + let state = State::new( Arc::new(RwLock::new((&graph).into())), hash_data, None, maybe_tsbuildinfo, HashMap::new(), HashMap::new(), - ) + ); + let mut op_state = OpState::new(1); + op_state.put(state); + op_state } async fn test_exec( @@ -852,9 +878,12 @@ mod tests { #[tokio::test] async fn test_create_hash() { let mut state = setup(None, Some(vec![b"something".to_vec()]), None).await; - let actual = - op_create_hash(&mut state, json!({ "data": "some sort of content" })) - .expect("could not invoke op"); + let actual = op_create_hash::call( + &mut state, + json!({ "data": "some sort of content" }), + (), + ) + .expect("could not invoke op"); assert_eq!( actual, json!({"hash": "ae92df8f104748768838916857a1623b6a3c593110131b0a00f81ad9dac16511"}) @@ -898,16 +927,18 @@ mod tests { #[tokio::test] async fn test_emit() { let mut state = setup(None, None, None).await; - let actual = op_emit( + let actual = op_emit::call( &mut state, EmitArgs { data: "some file content".to_string(), file_name: "cache:///some/file.js".to_string(), maybe_specifiers: Some(vec!["file:///some/file.ts".to_string()]), }, + (), ) .expect("should have invoked op"); assert_eq!(actual, json!(true)); + let state = state.borrow::<State>(); assert_eq!(state.emitted_files.len(), 1); assert!(state.maybe_tsbuildinfo.is_none()); assert_eq!( @@ -926,7 +957,7 @@ mod tests { #[tokio::test] async fn test_emit_strange_specifier() { let mut state = setup(None, None, None).await; - let actual = op_emit( + let actual = op_emit::call( &mut state, EmitArgs { data: "some file content".to_string(), @@ -935,9 +966,11 @@ mod tests { vec!["file:///some/file.ts?q=.json".to_string()], ), }, + (), ) .expect("should have invoked op"); assert_eq!(actual, json!(true)); + let state = state.borrow::<State>(); assert_eq!(state.emitted_files.len(), 1); assert!(state.maybe_tsbuildinfo.is_none()); assert_eq!( @@ -956,16 +989,18 @@ mod tests { #[tokio::test] async fn test_emit_tsbuildinfo() { let mut state = setup(None, None, None).await; - let actual = op_emit( + let actual = op_emit::call( &mut state, EmitArgs { data: "some file content".to_string(), file_name: "deno:///.tsbuildinfo".to_string(), maybe_specifiers: None, }, + (), ) .expect("should have invoked op"); assert_eq!(actual, json!(true)); + let state = state.borrow::<State>(); assert_eq!(state.emitted_files.len(), 0); assert_eq!( state.maybe_tsbuildinfo, @@ -981,9 +1016,10 @@ mod tests { Some("some content".to_string()), ) .await; - let actual = op_load( + let actual = op_load::call( &mut state, json!({ "specifier": "https://deno.land/x/mod.ts"}), + (), ) .expect("should have invoked op"); assert_eq!( @@ -1012,9 +1048,12 @@ mod tests { Some("some content".to_string()), ) .await; - let value = - op_load(&mut state, json!({ "specifier": "asset:///lib.dom.d.ts" })) - .expect("should have invoked op"); + let value = op_load::call( + &mut state, + json!({ "specifier": "asset:///lib.dom.d.ts" }), + (), + ) + .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(); @@ -1031,9 +1070,12 @@ mod tests { Some("some content".to_string()), ) .await; - let actual = - op_load(&mut state, json!({ "specifier": "deno:///.tsbuildinfo"})) - .expect("should have invoked op"); + let actual = op_load::call( + &mut state, + json!({ "specifier": "deno:///.tsbuildinfo"}), + (), + ) + .expect("should have invoked op"); assert_eq!( actual, json!({ @@ -1047,9 +1089,10 @@ mod tests { #[tokio::test] async fn test_load_missing_specifier() { let mut state = setup(None, None, None).await; - let actual = op_load( + let actual = op_load::call( &mut state, json!({ "specifier": "https://deno.land/x/mod.ts"}), + (), ) .expect("should have invoked op"); assert_eq!( @@ -1070,12 +1113,13 @@ mod tests { None, ) .await; - let actual = op_resolve( + let actual = op_resolve::call( &mut state, ResolveArgs { base: "https://deno.land/x/a.ts".to_string(), specifiers: vec!["./b.ts".to_string()], }, + (), ) .expect("should have invoked op"); assert_eq!(actual, json!([["https://deno.land/x/b.ts", ".ts"]])); @@ -1089,12 +1133,13 @@ mod tests { None, ) .await; - let actual = op_resolve( + let actual = op_resolve::call( &mut state, ResolveArgs { base: "https://deno.land/x/a.ts".to_string(), specifiers: vec!["./bad.ts".to_string()], }, + (), ) .expect("should have not errored"); assert_eq!( @@ -1106,7 +1151,7 @@ mod tests { #[tokio::test] async fn test_respond() { let mut state = setup(None, None, None).await; - let actual = op_respond( + let actual = op_respond::call( &mut state, json!({ "diagnostics": [ @@ -1118,9 +1163,11 @@ mod tests { ], "stats": [["a", 12]] }), + (), ) .expect("should have invoked op"); assert_eq!(actual, json!(true)); + let state = state.borrow::<State>(); assert_eq!( state.maybe_response, Some(RespondArgs { diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js index 7215360a0..c124703a8 100644 --- a/cli/tsc/99_main_compiler.js +++ b/cli/tsc/99_main_compiler.js @@ -921,6 +921,7 @@ delete Object.prototype.__proto__; // A build time only op that provides some setup information that is used to // ensure the snapshot is setup properly. /** @type {{ buildSpecifier: string; libs: string[] }} */ + const { buildSpecifier, libs } = core.opSync("op_build_info", {}); for (const lib of libs) { const specifier = `lib.${lib}.d.ts`; |