1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-24 08:09:08 -05:00

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.
This commit is contained in:
Bartek Iwańczuk 2022-12-16 17:11:10 +01:00 committed by GitHub
parent d7f4298015
commit ff71ef8175
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 84 additions and 49 deletions

View file

@ -940,7 +940,7 @@ mod repl {
true, true,
vec!["repl", "--quiet", "--allow-read", "--allow-env"], vec!["repl", "--quiet", "--allow-read", "--allow-env"],
Some(vec![r#"export {} from "npm:chalk";"#]), Some(vec![r#"export {} from "npm:chalk";"#]),
Some(env_vars), Some(env_vars.clone()),
true, true,
); );
@ -948,5 +948,21 @@ mod repl {
assert_contains!(out, "Chalk: [Function: Chalk],"); assert_contains!(out, "Chalk: [Function: Chalk],");
assert!(err.is_empty()); 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());
}
} }
} }

View file

@ -107,7 +107,7 @@ pub async fn run(flags: Flags, repl_flags: ReplFlags) -> Result<i32, AnyError> {
Ok(eval_source) => { Ok(eval_source) => {
let output = repl_session let output = repl_session
.evaluate_line_and_get_output(&eval_source) .evaluate_line_and_get_output(&eval_source)
.await?; .await;
// only output errors // only output errors
if let EvaluationOutput::Error(error_text) = output { if let EvaluationOutput::Error(error_text) = output {
println!( println!(
@ -124,7 +124,7 @@ pub async fn run(flags: Flags, repl_flags: ReplFlags) -> Result<i32, AnyError> {
} }
if let Some(eval) = repl_flags.eval { 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 // only output errors
if let EvaluationOutput::Error(error_text) = output { if let EvaluationOutput::Error(error_text) = output {
println!("Error in --eval flag: {}", error_text); 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) => { Ok(line) => {
should_exit_on_interrupt = false; should_exit_on_interrupt = false;
editor.update_history(line.clone()); 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 // 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(). // consistent behavior in when the user evaluates a call to close().

View file

@ -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 { struct TsEvaluateResponse {
ts_code: String, ts_code: String,
value: cdp::EvaluateResponse, value: cdp::EvaluateResponse,
@ -169,7 +180,7 @@ impl ReplSession {
pub async fn evaluate_line_and_get_output( pub async fn evaluate_line_and_get_output(
&mut self, &mut self,
line: &str, line: &str,
) -> Result<EvaluationOutput, AnyError> { ) -> EvaluationOutput {
fn format_diagnostic(diagnostic: &deno_ast::Diagnostic) -> String { fn format_diagnostic(diagnostic: &deno_ast::Diagnostic) -> String {
format!( format!(
"{}: {} at {}:{}", "{}: {} at {}:{}",
@ -180,7 +191,11 @@ impl ReplSession {
) )
} }
match self.evaluate_line_with_object_wrapping(line).await { async fn inner(
session: &mut ReplSession,
line: &str,
) -> Result<EvaluationOutput, AnyError> {
match session.evaluate_line_with_object_wrapping(line).await {
Ok(evaluate_response) => { Ok(evaluate_response) => {
let cdp::EvaluateResponse { let cdp::EvaluateResponse {
result, result,
@ -188,7 +203,7 @@ impl ReplSession {
} = evaluate_response.value; } = evaluate_response.value;
Ok(if let Some(exception_details) = exception_details { Ok(if let Some(exception_details) = exception_details {
self.set_last_thrown_error(&result).await?; session.set_last_thrown_error(&result).await?;
let description = match exception_details.exception { let description = match exception_details.exception {
Some(exception) => exception Some(exception) => exception
.description .description
@ -200,13 +215,13 @@ impl ReplSession {
exception_details.text, description exception_details.text, description
)) ))
} else { } else {
self session
.language_server .language_server
.commit_text(&evaluate_response.ts_code) .commit_text(&evaluate_response.ts_code)
.await; .await;
self.set_last_eval_result(&result).await?; session.set_last_eval_result(&result).await?;
let value = self.get_eval_value(&result).await?; let value = session.get_eval_value(&result).await?;
EvaluationOutput::Value(value) EvaluationOutput::Value(value)
}) })
} }
@ -232,6 +247,10 @@ impl ReplSession {
} }
} }
let result = inner(self, line).await;
result_to_evaluation_output(result)
}
async fn evaluate_line_with_object_wrapping( async fn evaluate_line_with_object_wrapping(
&mut self, &mut self,
line: &str, line: &str,