mirror of
https://github.com/denoland/deno.git
synced 2024-12-23 15:49:44 -05:00
refactor: strongly typed TSC ops (#20466)
Removes usage of `serde_json::Value` in several ops used in TSC, in favor of using strongly typed structs. This will unblock more changes in https://github.com/denoland/deno/pull/20462.
This commit is contained in:
parent
950e0e9cd6
commit
82c2864065
3 changed files with 83 additions and 57 deletions
78
cli/build.rs
78
cli/build.rs
|
@ -16,8 +16,7 @@ mod ts {
|
|||
use deno_core::OpState;
|
||||
use deno_runtime::deno_node::SUPPORTED_BUILTIN_NODE_MODULES;
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
use serde_json::Value;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
@ -28,17 +27,31 @@ mod ts {
|
|||
specifier: String,
|
||||
}
|
||||
|
||||
#[op]
|
||||
fn op_build_info(state: &mut OpState) -> Value {
|
||||
let build_specifier = "asset:///bootstrap.ts";
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct BuildInfoResponse {
|
||||
build_specifier: String,
|
||||
libs: Vec<String>,
|
||||
node_built_in_module_names: Vec<String>,
|
||||
}
|
||||
|
||||
let node_built_in_module_names = SUPPORTED_BUILTIN_NODE_MODULES.to_vec();
|
||||
let build_libs = state.borrow::<Vec<&str>>();
|
||||
json!({
|
||||
"buildSpecifier": build_specifier,
|
||||
"libs": build_libs,
|
||||
"nodeBuiltInModuleNames": node_built_in_module_names,
|
||||
})
|
||||
#[op]
|
||||
fn op_build_info<'s>(state: &mut OpState) -> BuildInfoResponse {
|
||||
let build_specifier = "asset:///bootstrap.ts".to_string();
|
||||
let build_libs = state
|
||||
.borrow::<Vec<&str>>()
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let node_built_in_module_names = SUPPORTED_BUILTIN_NODE_MODULES
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
BuildInfoResponse {
|
||||
build_specifier,
|
||||
libs: build_libs,
|
||||
node_built_in_module_names,
|
||||
}
|
||||
}
|
||||
|
||||
#[op]
|
||||
|
@ -46,18 +59,35 @@ mod ts {
|
|||
false
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ScriptVersionArgs {
|
||||
specifier: String,
|
||||
}
|
||||
|
||||
#[op]
|
||||
fn op_script_version(
|
||||
_state: &mut OpState,
|
||||
_args: Value,
|
||||
_args: ScriptVersionArgs,
|
||||
) -> Result<Option<String>, AnyError> {
|
||||
Ok(Some("1".to_string()))
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct LoadResponse {
|
||||
data: String,
|
||||
version: String,
|
||||
script_kind: i32,
|
||||
}
|
||||
|
||||
#[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.
|
||||
fn op_load(state: &mut OpState, args: LoadArgs) -> Result<Value, AnyError> {
|
||||
fn op_load(
|
||||
state: &mut OpState,
|
||||
args: LoadArgs,
|
||||
) -> Result<LoadResponse, AnyError> {
|
||||
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");
|
||||
|
@ -65,12 +95,12 @@ mod ts {
|
|||
|
||||
// we need a basic file to send to tsc to warm it up.
|
||||
if args.specifier == build_specifier {
|
||||
Ok(json!({
|
||||
"data": r#"Deno.writeTextFile("hello.txt", "hello deno!");"#,
|
||||
"version": "1",
|
||||
Ok(LoadResponse {
|
||||
data: r#"Deno.writeTextFile("hello.txt", "hello deno!");"#.to_string(),
|
||||
version: "1".to_string(),
|
||||
// this corresponds to `ts.ScriptKind.TypeScript`
|
||||
"scriptKind": 3
|
||||
}))
|
||||
script_kind: 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) {
|
||||
|
@ -84,12 +114,12 @@ mod ts {
|
|||
path_dts.join(format!("lib.{lib}.d.ts"))
|
||||
};
|
||||
let data = std::fs::read_to_string(path)?;
|
||||
Ok(json!({
|
||||
"data": data,
|
||||
"version": "1",
|
||||
Ok(LoadResponse {
|
||||
data,
|
||||
version: "1".to_string(),
|
||||
// this corresponds to `ts.ScriptKind.TypeScript`
|
||||
"scriptKind": 3
|
||||
}))
|
||||
script_kind: 3,
|
||||
})
|
||||
} else {
|
||||
Err(custom_error(
|
||||
"InvalidSpecifier",
|
||||
|
|
|
@ -3252,26 +3252,29 @@ fn op_is_node_file(state: &mut OpState, path: String) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct LoadResponse {
|
||||
data: Arc<str>,
|
||||
script_kind: i32,
|
||||
version: Option<String>,
|
||||
}
|
||||
|
||||
#[op]
|
||||
fn op_load(
|
||||
state: &mut OpState,
|
||||
args: SpecifierArgs,
|
||||
) -> Result<Value, AnyError> {
|
||||
) -> Result<Option<LoadResponse>, AnyError> {
|
||||
let state = state.borrow_mut::<State>();
|
||||
let mark = state.performance.mark("op_load", Some(&args));
|
||||
let specifier = state.normalize_specifier(args.specifier)?;
|
||||
let asset_or_document = state.get_asset_or_document(&specifier);
|
||||
state.performance.measure(mark);
|
||||
Ok(match asset_or_document {
|
||||
Some(doc) => {
|
||||
json!({
|
||||
"data": doc.text(),
|
||||
"scriptKind": crate::tsc::as_ts_script_kind(doc.media_type()),
|
||||
"version": state.script_version(&specifier),
|
||||
})
|
||||
}
|
||||
None => Value::Null,
|
||||
})
|
||||
Ok(asset_or_document.map(|doc| LoadResponse {
|
||||
data: doc.text(),
|
||||
script_kind: crate::tsc::as_ts_script_kind(doc.media_type()),
|
||||
version: state.script_version(&specifier),
|
||||
}))
|
||||
}
|
||||
|
||||
#[op]
|
||||
|
@ -3312,10 +3315,9 @@ fn op_resolve(
|
|||
}
|
||||
|
||||
#[op]
|
||||
fn op_respond(state: &mut OpState, args: Response) -> bool {
|
||||
fn op_respond(state: &mut OpState, args: Response) {
|
||||
let state = state.borrow_mut::<State>();
|
||||
state.response = Some(args);
|
||||
true
|
||||
}
|
||||
|
||||
#[op]
|
||||
|
|
|
@ -733,12 +733,9 @@ struct RespondArgs {
|
|||
}
|
||||
|
||||
#[op]
|
||||
fn op_respond(state: &mut OpState, args: Value) -> Result<Value, AnyError> {
|
||||
fn op_respond(state: &mut OpState, args: RespondArgs) {
|
||||
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);
|
||||
Ok(json!(true))
|
||||
state.maybe_response = Some(args);
|
||||
}
|
||||
|
||||
/// Execute a request on the supplied snapshot, returning a response which
|
||||
|
@ -1160,21 +1157,18 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn test_respond() {
|
||||
let mut state = setup(None, None, None).await;
|
||||
let actual = op_respond::call(
|
||||
&mut state,
|
||||
json!({
|
||||
"diagnostics": [
|
||||
{
|
||||
"messageText": "Unknown compiler option 'invalid'.",
|
||||
"category": 1,
|
||||
"code": 5023
|
||||
}
|
||||
],
|
||||
"stats": [["a", 12]]
|
||||
}),
|
||||
)
|
||||
.expect("should have invoked op");
|
||||
assert_eq!(actual, json!(true));
|
||||
let args = serde_json::from_value(json!({
|
||||
"diagnostics": [
|
||||
{
|
||||
"messageText": "Unknown compiler option 'invalid'.",
|
||||
"category": 1,
|
||||
"code": 5023
|
||||
}
|
||||
],
|
||||
"stats": [["a", 12]]
|
||||
}))
|
||||
.unwrap();
|
||||
op_respond::call(&mut state, args);
|
||||
let state = state.borrow::<State>();
|
||||
assert_eq!(
|
||||
state.maybe_response,
|
||||
|
|
Loading…
Reference in a new issue