summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2022-12-16 17:11:10 +0100
committerGitHub <noreply@github.com>2022-12-16 17:11:10 +0100
commitff71ef81751da1babdc4f9d1df5c279e7c64f305 (patch)
tree246cb7e45de792f1d87b2cb6071ae0d44d5f15fc
parentd7f4298015bd98ba5806ec48ee35e4be61a4143e (diff)
fix(repl): errors shouldn't terminate repl (#17082)
This commit changes REPL to never surface errors coming from code execution, but instead print them as errors to the REPL itself.
-rw-r--r--cli/tests/repl_tests.rs18
-rw-r--r--cli/tools/repl/mod.rs6
-rw-r--r--cli/tools/repl/session.rs113
3 files changed, 86 insertions, 51 deletions
diff --git a/cli/tests/repl_tests.rs b/cli/tests/repl_tests.rs
index a5c64f3b6..d64871bb0 100644
--- a/cli/tests/repl_tests.rs
+++ b/cli/tests/repl_tests.rs
@@ -940,7 +940,7 @@ mod repl {
true,
vec!["repl", "--quiet", "--allow-read", "--allow-env"],
Some(vec![r#"export {} from "npm:chalk";"#]),
- Some(env_vars),
+ Some(env_vars.clone()),
true,
);
@@ -948,5 +948,21 @@ mod repl {
assert_contains!(out, "Chalk: [Function: Chalk],");
assert!(err.is_empty());
}
+
+ {
+ let (out, err) = util::run_and_collect_output_with_args(
+ true,
+ vec!["repl", "--quiet", "--allow-read", "--allow-env"],
+ Some(vec![r#"import foo from "npm:asdfawe52345asdf""#]),
+ Some(env_vars),
+ true,
+ );
+
+ assert_contains!(
+ out,
+ "error: npm package 'asdfawe52345asdf' does not exist"
+ );
+ assert!(err.is_empty());
+ }
}
}
diff --git a/cli/tools/repl/mod.rs b/cli/tools/repl/mod.rs
index ff438aeb2..8fcae505e 100644
--- a/cli/tools/repl/mod.rs
+++ b/cli/tools/repl/mod.rs
@@ -107,7 +107,7 @@ pub async fn run(flags: Flags, repl_flags: ReplFlags) -> Result<i32, AnyError> {
Ok(eval_source) => {
let output = repl_session
.evaluate_line_and_get_output(&eval_source)
- .await?;
+ .await;
// only output errors
if let EvaluationOutput::Error(error_text) = output {
println!(
@@ -124,7 +124,7 @@ pub async fn run(flags: Flags, repl_flags: ReplFlags) -> Result<i32, AnyError> {
}
if let Some(eval) = repl_flags.eval {
- let output = repl_session.evaluate_line_and_get_output(&eval).await?;
+ let output = repl_session.evaluate_line_and_get_output(&eval).await;
// only output errors
if let EvaluationOutput::Error(error_text) = output {
println!("Error in --eval flag: {}", error_text);
@@ -156,7 +156,7 @@ pub async fn run(flags: Flags, repl_flags: ReplFlags) -> Result<i32, AnyError> {
Ok(line) => {
should_exit_on_interrupt = false;
editor.update_history(line.clone());
- let output = repl_session.evaluate_line_and_get_output(&line).await?;
+ let output = repl_session.evaluate_line_and_get_output(&line).await;
// We check for close and break here instead of making it a loop condition to get
// consistent behavior in when the user evaluates a call to close().
diff --git a/cli/tools/repl/session.rs b/cli/tools/repl/session.rs
index 3b30a140d..b636a4949 100644
--- a/cli/tools/repl/session.rs
+++ b/cli/tools/repl/session.rs
@@ -68,6 +68,17 @@ impl std::fmt::Display for EvaluationOutput {
}
}
+pub fn result_to_evaluation_output(
+ r: Result<EvaluationOutput, AnyError>,
+) -> EvaluationOutput {
+ match r {
+ Ok(value) => value,
+ Err(err) => {
+ EvaluationOutput::Error(format!("{} {}", colors::red("error:"), err))
+ }
+ }
+}
+
struct TsEvaluateResponse {
ts_code: String,
value: cdp::EvaluateResponse,
@@ -169,7 +180,7 @@ impl ReplSession {
pub async fn evaluate_line_and_get_output(
&mut self,
line: &str,
- ) -> Result<EvaluationOutput, AnyError> {
+ ) -> EvaluationOutput {
fn format_diagnostic(diagnostic: &deno_ast::Diagnostic) -> String {
format!(
"{}: {} at {}:{}",
@@ -180,56 +191,64 @@ impl ReplSession {
)
}
- match self.evaluate_line_with_object_wrapping(line).await {
- Ok(evaluate_response) => {
- let cdp::EvaluateResponse {
- result,
- exception_details,
- } = evaluate_response.value;
-
- Ok(if let Some(exception_details) = exception_details {
- self.set_last_thrown_error(&result).await?;
- let description = match exception_details.exception {
- Some(exception) => exception
- .description
- .unwrap_or_else(|| "Unknown exception".to_string()),
- None => "Unknown exception".to_string(),
- };
- EvaluationOutput::Error(format!(
- "{} {}",
- exception_details.text, description
- ))
- } else {
- self
- .language_server
- .commit_text(&evaluate_response.ts_code)
- .await;
-
- self.set_last_eval_result(&result).await?;
- let value = self.get_eval_value(&result).await?;
- EvaluationOutput::Value(value)
- })
- }
- Err(err) => {
- // handle a parsing diagnostic
- match err.downcast_ref::<deno_ast::Diagnostic>() {
- Some(diagnostic) => {
- Ok(EvaluationOutput::Error(format_diagnostic(diagnostic)))
+ async fn inner(
+ session: &mut ReplSession,
+ line: &str,
+ ) -> Result<EvaluationOutput, AnyError> {
+ match session.evaluate_line_with_object_wrapping(line).await {
+ Ok(evaluate_response) => {
+ let cdp::EvaluateResponse {
+ result,
+ exception_details,
+ } = evaluate_response.value;
+
+ Ok(if let Some(exception_details) = exception_details {
+ session.set_last_thrown_error(&result).await?;
+ let description = match exception_details.exception {
+ Some(exception) => exception
+ .description
+ .unwrap_or_else(|| "Unknown exception".to_string()),
+ None => "Unknown exception".to_string(),
+ };
+ EvaluationOutput::Error(format!(
+ "{} {}",
+ exception_details.text, description
+ ))
+ } else {
+ session
+ .language_server
+ .commit_text(&evaluate_response.ts_code)
+ .await;
+
+ session.set_last_eval_result(&result).await?;
+ let value = session.get_eval_value(&result).await?;
+ EvaluationOutput::Value(value)
+ })
+ }
+ Err(err) => {
+ // handle a parsing diagnostic
+ match err.downcast_ref::<deno_ast::Diagnostic>() {
+ Some(diagnostic) => {
+ Ok(EvaluationOutput::Error(format_diagnostic(diagnostic)))
+ }
+ None => match err.downcast_ref::<DiagnosticsError>() {
+ Some(diagnostics) => Ok(EvaluationOutput::Error(
+ diagnostics
+ .0
+ .iter()
+ .map(format_diagnostic)
+ .collect::<Vec<_>>()
+ .join("\n\n"),
+ )),
+ None => Err(err),
+ },
}
- None => match err.downcast_ref::<DiagnosticsError>() {
- Some(diagnostics) => Ok(EvaluationOutput::Error(
- diagnostics
- .0
- .iter()
- .map(format_diagnostic)
- .collect::<Vec<_>>()
- .join("\n\n"),
- )),
- None => Err(err),
- },
}
}
}
+
+ let result = inner(self, line).await;
+ result_to_evaluation_output(result)
}
async fn evaluate_line_with_object_wrapping(