mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 16:19:12 -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:
parent
d7f4298015
commit
ff71ef8175
3 changed files with 84 additions and 49 deletions
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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().
|
||||||
|
|
|
@ -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,56 +191,64 @@ impl ReplSession {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.evaluate_line_with_object_wrapping(line).await {
|
async fn inner(
|
||||||
Ok(evaluate_response) => {
|
session: &mut ReplSession,
|
||||||
let cdp::EvaluateResponse {
|
line: &str,
|
||||||
result,
|
) -> Result<EvaluationOutput, AnyError> {
|
||||||
exception_details,
|
match session.evaluate_line_with_object_wrapping(line).await {
|
||||||
} = evaluate_response.value;
|
Ok(evaluate_response) => {
|
||||||
|
let cdp::EvaluateResponse {
|
||||||
|
result,
|
||||||
|
exception_details,
|
||||||
|
} = 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
|
||||||
.unwrap_or_else(|| "Unknown exception".to_string()),
|
.unwrap_or_else(|| "Unknown exception".to_string()),
|
||||||
None => "Unknown exception".to_string(),
|
None => "Unknown exception".to_string(),
|
||||||
};
|
};
|
||||||
EvaluationOutput::Error(format!(
|
EvaluationOutput::Error(format!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// handle a parsing diagnostic
|
// handle a parsing diagnostic
|
||||||
match err.downcast_ref::<deno_ast::Diagnostic>() {
|
match err.downcast_ref::<deno_ast::Diagnostic>() {
|
||||||
Some(diagnostic) => {
|
Some(diagnostic) => {
|
||||||
Ok(EvaluationOutput::Error(format_diagnostic(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(
|
async fn evaluate_line_with_object_wrapping(
|
||||||
|
|
Loading…
Reference in a new issue