diff options
author | Leo Kettmeir <crowlkats@toaxl.com> | 2022-01-27 15:09:47 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-27 15:09:47 +0100 |
commit | 382a978859a7a7a4351542be818bb2e59523429c (patch) | |
tree | be7039c3d6b1fe4c694cc95523d9c0895b8fb3c3 | |
parent | 884143218fad0e18f7553aaf079d52de703f7601 (diff) |
refactor: factor out CDP message types (#13501)
-rw-r--r-- | cli/cdp.rs | 474 | ||||
-rw-r--r-- | cli/main.rs | 1 | ||||
-rw-r--r-- | cli/tools/coverage/mod.rs | 29 | ||||
-rw-r--r-- | cli/tools/repl/channel.rs | 9 | ||||
-rw-r--r-- | cli/tools/repl/editor.rs | 81 | ||||
-rw-r--r-- | cli/tools/repl/mod.rs | 5 | ||||
-rw-r--r-- | cli/tools/repl/session.rs | 148 | ||||
-rw-r--r-- | core/inspector.rs | 4 |
8 files changed, 642 insertions, 109 deletions
diff --git a/cli/cdp.rs b/cli/cdp.rs new file mode 100644 index 000000000..24fb76e10 --- /dev/null +++ b/cli/cdp.rs @@ -0,0 +1,474 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. + +/// https://chromedevtools.github.io/devtools-protocol/tot/ +use deno_core::serde_json; +use deno_core::serde_json::Value; +use serde::Deserialize; +use serde::Serialize; + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-awaitPromise +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AwaitPromiseArgs { + pub promise_object_id: RemoteObjectId, + #[serde(skip_serializing_if = "Option::is_none")] + pub return_by_value: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub generate_preview: Option<bool>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-awaitPromise +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AwaitPromiseResponse { + pub result: RemoteObject, + pub exception_details: Option<ExceptionDetails>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-callFunctionOn +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CallFunctionOnArgs { + pub function_declaration: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub object_id: Option<RemoteObjectId>, + #[serde(skip_serializing_if = "Option::is_none")] + pub arguments: Option<Vec<CallArgument>>, + #[serde(skip_serializing_if = "Option::is_none")] + pub silent: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub return_by_value: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub generate_preview: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub user_gesture: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub await_promise: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub execution_context_id: Option<ExecutionContextId>, + #[serde(skip_serializing_if = "Option::is_none")] + pub object_group: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] + pub throw_on_side_effect: Option<bool>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-callFunctionOn +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CallFunctionOnResponse { + pub result: RemoteObject, + pub exception_details: Option<ExceptionDetails>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-compileScript +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompileScriptArgs { + pub expression: String, + #[serde(rename = "sourceURL")] + pub source_url: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub execution_context_id: Option<ExecutionContextId>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-compileScript +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CompileScriptResponse { + pub script_id: Option<ScriptId>, + pub exception_details: Option<ExceptionDetails>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-evaluate +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct EvaluateArgs { + pub expression: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub object_group: Option<String>, + #[serde( + rename = "includeCommandLineAPI", + skip_serializing_if = "Option::is_none" + )] + pub include_command_line_api: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub silent: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub context_id: Option<ExecutionContextId>, + #[serde(skip_serializing_if = "Option::is_none")] + pub return_by_value: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub generate_preview: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub user_gesture: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub await_promise: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub throw_on_side_effect: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub timeout: Option<TimeDelta>, + #[serde(skip_serializing_if = "Option::is_none")] + pub disable_breaks: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub repl_mode: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "allowUnsafeEvalBlockedByCSP")] + pub allow_unsafe_eval_blocked_by_csp: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub unique_context_id: Option<String>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-evaluate +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct EvaluateResponse { + pub result: RemoteObject, + pub exception_details: Option<ExceptionDetails>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-getProperties +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GetPropertiesArgs { + pub object_id: RemoteObjectId, + #[serde(skip_serializing_if = "Option::is_none")] + pub own_properties: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub accessor_properties_only: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub generate_preview: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub non_indexed_properties_only: Option<bool>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-getProperties +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GetPropertiesResponse { + pub result: Vec<PropertyDescriptor>, + pub internal_properties: Vec<InternalPropertyDescriptor>, + pub private_properties: Vec<PrivatePropertyDescriptor>, + pub exception_details: Option<ExceptionDetails>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-globalLexicalScopeNames +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GlobalLexicalScopeNamesArgs { + #[serde(skip_serializing_if = "Option::is_none")] + pub execution_context_id: Option<ExecutionContextId>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-globalLexicalScopeNames +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GlobalLexicalScopeNamesResponse { + pub names: Vec<String>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-queryObjects +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct QueryObjectsArgs { + pub prototype_object_id: RemoteObjectId, + #[serde(skip_serializing_if = "Option::is_none")] + pub object_group: Option<String>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-queryObjects +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct QueryObjectsResponse { + pub objects: RemoteObject, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-releaseObject +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ReleaseObjectArgs { + pub object_id: RemoteObjectId, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-releaseObjectGroup +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ReleaseObjectGroupArgs { + pub object_group: String, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-runScript +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RunScriptArgs { + pub script_id: ScriptId, + #[serde(skip_serializing_if = "Option::is_none")] + pub execution_context_id: Option<ExecutionContextId>, + #[serde(skip_serializing_if = "Option::is_none")] + pub object_group: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] + pub silent: Option<bool>, + #[serde( + rename = "includeCommandLineAPI", + skip_serializing_if = "Option::is_none" + )] + pub include_command_line_api: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub return_by_value: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub generate_preview: Option<bool>, + #[serde(skip_serializing_if = "Option::is_none")] + pub await_promise: Option<bool>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-runScript +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RunScriptResponse { + pub result: RemoteObject, + pub exception_details: Option<ExceptionDetails>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-setAsyncCallStackDepth +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SetAsyncCallStackDepthArgs { + pub max_depth: u64, +} + +// types + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-RemoteObject +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum RemoteObjectType { + Object, + Function, + Undefined, + String, + Number, + Boolean, + Symbol, + Bigint, +} + +impl std::fmt::Display for RemoteObjectType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&format!("{:?}", self).to_lowercase()) + } +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-RemoteObject +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum RemoteObjectSubType { + Array, + Null, + Node, + Regexp, + Date, + Map, + Set, + Weakmap, + Weakset, + Iterator, + Generator, + Error, + Proxy, + Promise, + Typedarray, + Arraybuffer, + Dataview, + Webassemblymemory, + Wasmvalue, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-RemoteObject +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RemoteObject { + #[serde(rename = "type")] + pub kind: RemoteObjectType, + pub subtype: Option<RemoteObjectSubType>, + pub class_name: Option<String>, + pub value: Option<Value>, + pub unserializable_value: Option<UnserializableValue>, + pub description: Option<String>, + pub object_id: Option<RemoteObjectId>, + pub preview: Option<ObjectPreview>, + pub custom_preview: Option<CustomPreview>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-ObjectPreview +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ObjectPreview { + #[serde(rename = "type")] + pub kind: RemoteObjectType, + pub subtype: Option<RemoteObjectSubType>, + pub description: Option<String>, + pub overflow: bool, + pub properties: Vec<PropertyPreview>, + pub entries: Option<Vec<EntryPreview>>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-PropertyPreview +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PropertyPreview { + pub name: String, + #[serde(rename = "type")] + pub kind: PropertyPreviewType, + pub value: Option<String>, + pub value_preview: Option<ObjectPreview>, + pub subtype: Option<RemoteObjectSubType>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-PropertyPreview +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum PropertyPreviewType { + Object, + Function, + Undefined, + String, + Number, + Boolean, + Symbol, + Accessor, + Bigint, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-EntryPreview +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct EntryPreview { + pub key: Option<ObjectPreview>, + pub value: ObjectPreview, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-CustomPreview +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CustomPreview { + pub header: String, + pub body_getter_id: RemoteObjectId, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-ExceptionDetails +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ExceptionDetails { + pub exception_id: u64, + pub text: String, + pub line_number: u64, + pub column_number: u64, + pub script_id: Option<ScriptId>, + pub url: Option<String>, + pub stack_trace: Option<StackTrace>, + pub exception: Option<RemoteObject>, + pub execution_context_id: Option<ExecutionContextId>, + pub exception_meta_data: Option<serde_json::Map<String, Value>>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-StackTrace +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct StackTrace { + pub description: Option<String>, + pub call_frames: Vec<CallFrame>, + pub parent: Option<Box<StackTrace>>, + pub parent_id: Option<StackTraceId>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-CallFrame +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CallFrame { + pub function_name: String, + pub script_id: ScriptId, + pub url: String, + pub line_number: u64, + pub column_number: u64, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-StackTraceId +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct StackTraceId { + pub id: String, + pub debugger_id: Option<UniqueDebuggerId>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-CallArgument +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CallArgument { + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option<Value>, + #[serde(skip_serializing_if = "Option::is_none")] + pub unserializable_value: Option<UnserializableValue>, + #[serde(skip_serializing_if = "Option::is_none")] + pub object_id: Option<RemoteObjectId>, +} + +impl From<&RemoteObject> for CallArgument { + fn from(obj: &RemoteObject) -> Self { + Self { + value: obj.value.clone(), + unserializable_value: obj.unserializable_value.clone(), + object_id: obj.object_id.clone(), + } + } +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-InternalPropertyDescriptor +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PropertyDescriptor { + pub name: String, + pub value: Option<RemoteObject>, + pub writable: Option<bool>, + pub get: Option<RemoteObject>, + pub set: Option<RemoteObject>, + pub configurable: bool, + pub enumerable: bool, + pub was_thrown: Option<bool>, + pub is_own: Option<bool>, + pub symbol: Option<RemoteObject>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-InternalPropertyDescriptor +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct InternalPropertyDescriptor { + pub name: String, + pub value: Option<RemoteObject>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-PrivatePropertyDescriptor +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PrivatePropertyDescriptor { + pub name: String, + pub value: Option<RemoteObject>, + pub get: Option<RemoteObject>, + pub set: Option<RemoteObject>, +} + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-RemoteObjectId +pub type RemoteObjectId = String; + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-ExecutionContextId +pub type ExecutionContextId = u64; + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-ScriptId +pub type ScriptId = String; + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-TimeDelta +pub type TimeDelta = u64; + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-UnserializableValue +pub type UnserializableValue = String; + +/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-UniqueDebuggerId +pub type UniqueDebuggerId = String; diff --git a/cli/main.rs b/cli/main.rs index c996425c7..f4871228e 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -2,6 +2,7 @@ mod auth_tokens; mod cache; +mod cdp; mod checksum; mod compat; mod config_file; diff --git a/cli/tools/coverage/mod.rs b/cli/tools/coverage/mod.rs index 1c14859ea..6177295a6 100644 --- a/cli/tools/coverage/mod.rs +++ b/cli/tools/coverage/mod.rs @@ -43,22 +43,34 @@ impl CoverageCollector { } async fn enable_debugger(&mut self) -> Result<(), AnyError> { - self.session.post_message("Debugger.enable", None).await?; + self + .session + .post_message::<()>("Debugger.enable", None) + .await?; Ok(()) } async fn enable_profiler(&mut self) -> Result<(), AnyError> { - self.session.post_message("Profiler.enable", None).await?; + self + .session + .post_message::<()>("Profiler.enable", None) + .await?; Ok(()) } async fn disable_debugger(&mut self) -> Result<(), AnyError> { - self.session.post_message("Debugger.disable", None).await?; + self + .session + .post_message::<()>("Debugger.disable", None) + .await?; Ok(()) } async fn disable_profiler(&mut self) -> Result<(), AnyError> { - self.session.post_message("Profiler.disable", None).await?; + self + .session + .post_message::<()>("Profiler.disable", None) + .await?; Ok(()) } @@ -66,10 +78,9 @@ impl CoverageCollector { &mut self, parameters: StartPreciseCoverageParameters, ) -> Result<StartPreciseCoverageReturnObject, AnyError> { - let parameters_value = serde_json::to_value(parameters)?; let return_value = self .session - .post_message("Profiler.startPreciseCoverage", Some(parameters_value)) + .post_message("Profiler.startPreciseCoverage", Some(parameters)) .await?; let return_object = serde_json::from_value(return_value)?; @@ -82,7 +93,7 @@ impl CoverageCollector { ) -> Result<TakePreciseCoverageReturnObject, AnyError> { let return_value = self .session - .post_message("Profiler.takePreciseCoverage", None) + .post_message::<()>("Profiler.takePreciseCoverage", None) .await?; let return_object = serde_json::from_value(return_value)?; @@ -592,8 +603,8 @@ pub async fn cover_files( })? }; let file = maybe_file.ok_or_else(|| { - anyhow!("Failed to fetch \"{}\" from cache. - Before generating coverage report, run `deno test --coverage` to ensure consistent state.", + anyhow!("Failed to fetch \"{}\" from cache. + Before generating coverage report, run `deno test --coverage` to ensure consistent state.", module_specifier ) })?; diff --git a/cli/tools/repl/channel.rs b/cli/tools/repl/channel.rs index 7cc802905..4f2086fb5 100644 --- a/cli/tools/repl/channel.rs +++ b/cli/tools/repl/channel.rs @@ -2,6 +2,7 @@ use deno_core::anyhow::anyhow; use deno_core::error::AnyError; +use deno_core::serde_json; use deno_core::serde_json::Value; use std::cell::RefCell; use tokio::sync::mpsc::channel; @@ -55,17 +56,19 @@ pub struct RustylineSyncMessageSender { } impl RustylineSyncMessageSender { - pub fn post_message( + pub fn post_message<T: serde::Serialize>( &self, method: &str, - params: Option<Value>, + params: Option<T>, ) -> Result<Value, AnyError> { if let Err(err) = self .message_tx .blocking_send(RustylineSyncMessage::PostMessage { method: method.to_string(), - params, + params: params + .map(|params| serde_json::to_value(params)) + .transpose()?, }) { Err(anyhow!("{}", err)) diff --git a/cli/tools/repl/editor.rs b/cli/tools/repl/editor.rs index 30b9fba87..8a327f624 100644 --- a/cli/tools/repl/editor.rs +++ b/cli/tools/repl/editor.rs @@ -1,13 +1,13 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +use crate::cdp; use crate::colors; use deno_ast::swc::parser::error::SyntaxError; use deno_ast::swc::parser::token::Token; use deno_ast::swc::parser::token::Word; use deno_core::error::AnyError; use deno_core::parking_lot::Mutex; -use deno_core::serde_json::json; -use deno_core::serde_json::Value; +use deno_core::serde_json; use rustyline::completion::Completer; use rustyline::error::ReadlineError; use rustyline::highlight::Highlighter; @@ -39,20 +39,14 @@ impl EditorHelper { .sync_sender .post_message( "Runtime.globalLexicalScopeNames", - Some(json!({ - "executionContextId": self.context_id, - })), + Some(cdp::GlobalLexicalScopeNamesArgs { + execution_context_id: Some(self.context_id), + }), ) .unwrap(); - - evaluate_response - .get("names") - .unwrap() - .as_array() - .unwrap() - .iter() - .map(|n| n.as_str().unwrap().to_string()) - .collect() + let evaluate_response: cdp::GlobalLexicalScopeNamesResponse = + serde_json::from_value(evaluate_response).unwrap(); + evaluate_response.names } pub fn get_expression_property_names(&self, expr: &str) -> Vec<String> { @@ -81,11 +75,8 @@ impl EditorHelper { fn get_expression_type(&self, expr: &str) -> Option<String> { self - .evaluate_expression(expr)? - .get("result")? - .get("type")? - .as_str() - .map(|s| s.to_string()) + .evaluate_expression(expr) + .map(|res| res.result.kind.to_string()) } fn get_object_expr_properties( @@ -93,44 +84,60 @@ impl EditorHelper { object_expr: &str, ) -> Option<Vec<String>> { let evaluate_result = self.evaluate_expression(object_expr)?; - let object_id = evaluate_result.get("result")?.get("objectId")?; + let object_id = evaluate_result.result.object_id?; let get_properties_response = self .sync_sender .post_message( "Runtime.getProperties", - Some(json!({ - "objectId": object_id, - })), + Some(cdp::GetPropertiesArgs { + object_id, + own_properties: None, + accessor_properties_only: None, + generate_preview: None, + non_indexed_properties_only: None, + }), ) .ok()?; - + let get_properties_response: cdp::GetPropertiesResponse = + serde_json::from_value(get_properties_response).ok()?; Some( get_properties_response - .get("result")? - .as_array() - .unwrap() - .iter() - .map(|r| r.get("name").unwrap().as_str().unwrap().to_string()) + .result + .into_iter() + .map(|prop| prop.name) .collect(), ) } - fn evaluate_expression(&self, expr: &str) -> Option<Value> { + fn evaluate_expression(&self, expr: &str) -> Option<cdp::EvaluateResponse> { let evaluate_response = self .sync_sender .post_message( "Runtime.evaluate", - Some(json!({ - "contextId": self.context_id, - "expression": expr, - "throwOnSideEffect": true, - "timeout": 200, - })), + Some(cdp::EvaluateArgs { + expression: expr.to_string(), + object_group: None, + include_command_line_api: None, + silent: None, + context_id: Some(self.context_id), + return_by_value: None, + generate_preview: None, + user_gesture: None, + await_promise: None, + throw_on_side_effect: Some(true), + timeout: Some(200), + disable_breaks: None, + repl_mode: None, + allow_unsafe_eval_blocked_by_csp: None, + unique_context_id: None, + }), ) .ok()?; + let evaluate_response: cdp::EvaluateResponse = + serde_json::from_value(evaluate_response).ok()?; - if evaluate_response.get("exceptionDetails").is_some() { + if evaluate_response.exception_details.is_some() { None } else { Some(evaluate_response) diff --git a/cli/tools/repl/mod.rs b/cli/tools/repl/mod.rs index 0c9fdbfb0..b49c641c4 100644 --- a/cli/tools/repl/mod.rs +++ b/cli/tools/repl/mod.rs @@ -33,10 +33,7 @@ async fn read_line_and_poll( } result = message_handler.recv() => { match result { - Some(RustylineSyncMessage::PostMessage { - method, - params - }) => { + Some(RustylineSyncMessage::PostMessage { method, params }) => { let result = repl_session .post_message_with_event_loop(&method, params) .await; diff --git a/cli/tools/repl/session.rs b/cli/tools/repl/session.rs index 5d458189f..57109eb1d 100644 --- a/cli/tools/repl/session.rs +++ b/cli/tools/repl/session.rs @@ -1,12 +1,13 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. +use crate::cdp; use crate::colors; use crate::lsp::ReplLanguageServer; use deno_ast::DiagnosticsError; use deno_ast::ImportsNotUsedAsValues; use deno_core::error::AnyError; use deno_core::futures::FutureExt; -use deno_core::serde_json::json; +use deno_core::serde_json; use deno_core::serde_json::Value; use deno_core::LocalInspectorSession; use deno_runtime::worker::MainWorker; @@ -58,7 +59,7 @@ impl std::fmt::Display for EvaluationOutput { struct TsEvaluateResponse { ts_code: String, - value: Value, + value: cdp::EvaluateResponse, } pub struct ReplSession { @@ -75,7 +76,9 @@ impl ReplSession { worker .with_event_loop( - session.post_message("Runtime.enable", None).boxed_local(), + session + .post_message::<()>("Runtime.enable", None) + .boxed_local(), ) .await?; @@ -115,9 +118,8 @@ impl ReplSession { let closed = self .evaluate_expression("(this.closed)") .await? - .get("result") - .unwrap() - .get("value") + .result + .value .unwrap() .as_bool() .unwrap(); @@ -125,10 +127,10 @@ impl ReplSession { Ok(closed) } - pub async fn post_message_with_event_loop( + pub async fn post_message_with_event_loop<T: serde::Serialize>( &mut self, method: &str, - params: Option<Value>, + params: Option<T>, ) -> Result<Value, AnyError> { self .worker @@ -156,23 +158,24 @@ impl ReplSession { match self.evaluate_line_with_object_wrapping(line).await { Ok(evaluate_response) => { - let evaluate_result = evaluate_response.value.get("result").unwrap(); - let evaluate_exception_details = - evaluate_response.value.get("exceptionDetails"); + let cdp::EvaluateResponse { + result, + exception_details, + } = evaluate_response.value; - if evaluate_exception_details.is_some() { - self.set_last_thrown_error(evaluate_result).await?; + if exception_details.is_some() { + self.set_last_thrown_error(&result).await?; } else { self .language_server .commit_text(&evaluate_response.ts_code) .await; - self.set_last_eval_result(evaluate_result).await?; + self.set_last_eval_result(&result).await?; } - let value = self.get_eval_value(evaluate_result).await?; - Ok(match evaluate_exception_details { + let value = self.get_eval_value(&result).await?; + Ok(match exception_details { Some(_) => EvaluationOutput::Error(format!("Uncaught {}", value)), None => EvaluationOutput::Value(value), }) @@ -224,7 +227,7 @@ impl ReplSession { .as_ref() .unwrap() .value - .get("exceptionDetails") + .exception_details .is_some()) { self.evaluate_ts_expression(line).await @@ -235,66 +238,90 @@ impl ReplSession { async fn set_last_thrown_error( &mut self, - error: &Value, + error: &cdp::RemoteObject, ) -> Result<(), AnyError> { self.post_message_with_event_loop( "Runtime.callFunctionOn", - Some(json!({ - "executionContextId": self.context_id, - "functionDeclaration": "function (object) { Deno[Deno.internal].lastThrownError = object; }", - "arguments": [ - error, - ], - })), + Some(cdp::CallFunctionOnArgs { + function_declaration: "function (object) { Deno[Deno.internal].lastThrownError = object; }".to_string(), + object_id: None, + arguments: Some(vec![error.into()]), + silent: None, + return_by_value: None, + generate_preview: None, + user_gesture: None, + await_promise: None, + execution_context_id: Some(self.context_id), + object_group: None, + throw_on_side_effect: None + }), ).await?; Ok(()) } async fn set_last_eval_result( &mut self, - evaluate_result: &Value, + evaluate_result: &cdp::RemoteObject, ) -> Result<(), AnyError> { - self.post_message_with_event_loop( - "Runtime.callFunctionOn", - Some(json!({ - "executionContextId": self.context_id, - "functionDeclaration": "function (object) { Deno[Deno.internal].lastEvalResult = object; }", - "arguments": [ - evaluate_result, - ], - })), - ).await?; + self + .post_message_with_event_loop( + "Runtime.callFunctionOn", + Some(cdp::CallFunctionOnArgs { + function_declaration: + "function (object) { Deno[Deno.internal].lastEvalResult = object; }" + .to_string(), + object_id: None, + arguments: Some(vec![evaluate_result.into()]), + silent: None, + return_by_value: None, + generate_preview: None, + user_gesture: None, + await_promise: None, + execution_context_id: Some(self.context_id), + object_group: None, + throw_on_side_effect: None, + }), + ) + .await?; Ok(()) } pub async fn get_eval_value( &mut self, - evaluate_result: &Value, + evaluate_result: &cdp::RemoteObject, ) -> Result<String, AnyError> { // TODO(caspervonb) we should investigate using previews here but to keep things // consistent with the previous implementation we just get the preview result from // Deno.inspectArgs. let inspect_response = self.post_message_with_event_loop( "Runtime.callFunctionOn", - Some(json!({ - "executionContextId": self.context_id, - "functionDeclaration": r#"function (object) { + Some(cdp::CallFunctionOnArgs { + function_declaration: r#"function (object) { try { return Deno[Deno.internal].inspectArgs(["%o", object], { colors: !Deno.noColor }); } catch (err) { return Deno[Deno.internal].inspectArgs(["%o", err]); } - }"#, - "arguments": [ - evaluate_result, - ], - })), + }"#.to_string(), + object_id: None, + arguments: Some(vec![evaluate_result.into()]), + silent: None, + return_by_value: None, + generate_preview: None, + user_gesture: None, + await_promise: None, + execution_context_id: Some(self.context_id), + object_group: None, + throw_on_side_effect: None + }), ).await?; - let inspect_result = inspect_response.get("result").unwrap(); - let value = inspect_result.get("value").unwrap().as_str().unwrap(); + let response: cdp::CallFunctionOnResponse = + serde_json::from_value(inspect_response)?; + let value = response.result.value.unwrap(); + let s = value.as_str().unwrap(); - Ok(value.to_string()) + Ok(s.to_string()) } async fn evaluate_ts_expression( @@ -344,16 +371,29 @@ impl ReplSession { async fn evaluate_expression( &mut self, expression: &str, - ) -> Result<Value, AnyError> { + ) -> Result<cdp::EvaluateResponse, AnyError> { self .post_message_with_event_loop( "Runtime.evaluate", - Some(json!({ - "expression": expression, - "contextId": self.context_id, - "replMode": true, - })), + Some(cdp::EvaluateArgs { + expression: expression.to_string(), + object_group: None, + include_command_line_api: None, + silent: None, + context_id: Some(self.context_id), + return_by_value: None, + generate_preview: None, + user_gesture: None, + await_promise: None, + throw_on_side_effect: None, + timeout: None, + disable_breaks: None, + repl_mode: Some(true), + allow_unsafe_eval_blocked_by_csp: None, + unique_context_id: None, + }), ) .await + .and_then(|res| serde_json::from_value(res).map_err(|e| e.into())) } } diff --git a/core/inspector.rs b/core/inspector.rs index 97a04407d..b6c86fb79 100644 --- a/core/inspector.rs +++ b/core/inspector.rs @@ -649,10 +649,10 @@ impl LocalInspectorSession { self.notification_queue.split_off(0) } - pub async fn post_message( + pub async fn post_message<T: serde::Serialize>( &mut self, method: &str, - params: Option<serde_json::Value>, + params: Option<T>, ) -> Result<serde_json::Value, Error> { let id = self.next_message_id; self.next_message_id += 1; |