summaryrefslogtreecommitdiff
path: root/cli/tools/repl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tools/repl.rs')
-rw-r--r--cli/tools/repl.rs107
1 files changed, 79 insertions, 28 deletions
diff --git a/cli/tools/repl.rs b/cli/tools/repl.rs
index 67e68c0cd..069d3e417 100644
--- a/cli/tools/repl.rs
+++ b/cli/tools/repl.rs
@@ -1,6 +1,8 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use crate::ast;
+use crate::ast::Diagnostic;
+use crate::ast::ImportsNotUsedAsValues;
use crate::ast::TokenOrComment;
use crate::colors;
use crate::media_type::MediaType;
@@ -187,7 +189,7 @@ impl Validator for EditorHelper {
let mut stack: Vec<Token> = Vec::new();
let mut in_template = false;
- for item in ast::lex("", ctx.input(), &MediaType::JavaScript) {
+ for item in ast::lex("", ctx.input(), &MediaType::TypeScript) {
if let TokenOrComment::Token(token) = item.inner {
match token {
Token::BackQuote => in_template = !in_template,
@@ -247,7 +249,7 @@ impl Highlighter for EditorHelper {
fn highlight<'l>(&self, line: &'l str, _: usize) -> Cow<'l, str> {
let mut out_line = String::from(line);
- for item in ast::lex("", line, &MediaType::JavaScript) {
+ for item in ast::lex("", line, &MediaType::TypeScript) {
// Adding color adds more bytes to the string,
// so an offset is needed to stop spans falling out of sync.
let offset = out_line.len() - line.len();
@@ -439,7 +441,48 @@ impl ReplSession {
self.worker.run_event_loop(false).await
}
- pub async fn evaluate_line(&mut self, line: &str) -> Result<Value, AnyError> {
+ pub async fn evaluate_line_and_get_output(
+ &mut self,
+ line: &str,
+ ) -> Result<String, AnyError> {
+ match self.evaluate_line_with_object_wrapping(line).await {
+ Ok(evaluate_response) => {
+ let evaluate_result = evaluate_response.get("result").unwrap();
+ let evaluate_exception_details =
+ evaluate_response.get("exceptionDetails");
+
+ if evaluate_exception_details.is_some() {
+ self.set_last_thrown_error(evaluate_result).await?;
+ } else {
+ self.set_last_eval_result(evaluate_result).await?;
+ }
+
+ let value = self.get_eval_value(evaluate_result).await?;
+ Ok(match evaluate_exception_details {
+ Some(_) => format!("Uncaught {}", value),
+ None => value,
+ })
+ }
+ Err(err) => {
+ // handle a parsing diagnostic
+ match err.downcast_ref::<Diagnostic>() {
+ Some(diagnostic) => Ok(format!(
+ "{}: {} at {}:{}",
+ colors::red("parse error"),
+ diagnostic.message,
+ diagnostic.location.line,
+ diagnostic.location.col
+ )),
+ None => Err(err),
+ }
+ }
+ }
+ }
+
+ async fn evaluate_line_with_object_wrapping(
+ &mut self,
+ line: &str,
+ ) -> Result<Value, AnyError> {
// It is a bit unexpected that { "foo": "bar" } is interpreted as a block
// statement rather than an object literal so we interpret it as an expression statement
// to match the behavior found in a typical prompt including browser developer tools.
@@ -451,9 +494,7 @@ impl ReplSession {
line.to_string()
};
- let evaluate_response = self
- .evaluate_expression(&format!("'use strict'; void 0;\n{}", &wrapped_line))
- .await?;
+ let evaluate_response = self.evaluate_ts_expression(&wrapped_line).await?;
// If that fails, we retry it without wrapping in parens letting the error bubble up to the
// user if it is still an error.
@@ -461,9 +502,7 @@ impl ReplSession {
if evaluate_response.get("exceptionDetails").is_some()
&& wrapped_line != line
{
- self
- .evaluate_expression(&format!("'use strict'; void 0;\n{}", &line))
- .await?
+ self.evaluate_ts_expression(&line).await?
} else {
evaluate_response
};
@@ -471,7 +510,7 @@ impl ReplSession {
Ok(evaluate_response)
}
- pub async fn set_last_thrown_error(
+ async fn set_last_thrown_error(
&mut self,
error: &Value,
) -> Result<(), AnyError> {
@@ -488,7 +527,7 @@ impl ReplSession {
Ok(())
}
- pub async fn set_last_eval_result(
+ async fn set_last_eval_result(
&mut self,
evaluate_result: &Value,
) -> Result<(), AnyError> {
@@ -529,6 +568,34 @@ impl ReplSession {
Ok(value.to_string())
}
+ async fn evaluate_ts_expression(
+ &mut self,
+ expression: &str,
+ ) -> Result<Value, AnyError> {
+ let parsed_module =
+ crate::ast::parse("repl.ts", &expression, &crate::MediaType::TypeScript)?;
+
+ let transpiled_src = parsed_module
+ .transpile(&crate::ast::EmitOptions {
+ emit_metadata: false,
+ source_map: false,
+ inline_source_map: false,
+ imports_not_used_as_values: ImportsNotUsedAsValues::Preserve,
+ // JSX is not supported in the REPL
+ transform_jsx: false,
+ jsx_factory: "React.createElement".into(),
+ jsx_fragment_factory: "React.Fragment".into(),
+ })?
+ .0;
+
+ self
+ .evaluate_expression(&format!(
+ "'use strict'; void 0;\n{}",
+ transpiled_src
+ ))
+ .await
+ }
+
async fn evaluate_expression(
&mut self,
expression: &str,
@@ -615,7 +682,7 @@ pub async fn run(
.await;
match line {
Ok(line) => {
- let evaluate_response = repl_session.evaluate_line(&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().
@@ -623,22 +690,6 @@ pub async fn run(
break;
}
- let evaluate_result = evaluate_response.get("result").unwrap();
- let evaluate_exception_details =
- evaluate_response.get("exceptionDetails");
-
- if evaluate_exception_details.is_some() {
- repl_session.set_last_thrown_error(evaluate_result).await?;
- } else {
- repl_session.set_last_eval_result(evaluate_result).await?;
- }
-
- let value = repl_session.get_eval_value(evaluate_result).await?;
- let output = match evaluate_exception_details {
- Some(_) => format!("Uncaught {}", value),
- None => value,
- };
-
println!("{}", output);
editor.add_history_entry(line);