summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/build.rs156
-rw-r--r--cli/lsp/tsc.rs115
-rw-r--r--cli/ops/bench.rs23
-rw-r--r--cli/ops/errors.rs11
-rw-r--r--cli/ops/runtime_compiler.rs8
-rw-r--r--cli/ops/testing.rs20
-rw-r--r--cli/tsc.rs183
-rw-r--r--cli/tsc/99_main_compiler.js1
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`;