summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/flags.rs44
-rw-r--r--cli/main.rs9
-rw-r--r--cli/tests/integration/repl_tests.rs44
-rw-r--r--cli/tools/repl.rs33
4 files changed, 116 insertions, 14 deletions
diff --git a/cli/flags.rs b/cli/flags.rs
index f42dd771c..2371445c3 100644
--- a/cli/flags.rs
+++ b/cli/flags.rs
@@ -91,7 +91,9 @@ pub enum DenoSubcommand {
rules: bool,
json: bool,
},
- Repl,
+ Repl {
+ eval: Option<String>,
+ },
Run {
script: String,
},
@@ -119,7 +121,7 @@ pub enum DenoSubcommand {
impl Default for DenoSubcommand {
fn default() -> DenoSubcommand {
- DenoSubcommand::Repl
+ DenoSubcommand::Repl { eval: None }
}
}
@@ -955,6 +957,13 @@ Ignore linting a file by adding an ignore comment at the top of the file:
fn repl_subcommand<'a, 'b>() -> App<'a, 'b> {
runtime_args(SubCommand::with_name("repl"), false, true)
.about("Read Eval Print Loop")
+ .arg(
+ Arg::with_name("eval")
+ .long("eval")
+ .help("Evaluates the provided code when the REPL starts.")
+ .takes_value(true)
+ .value_name("code"),
+ )
}
fn run_subcommand<'a, 'b>() -> App<'a, 'b> {
@@ -1701,7 +1710,9 @@ fn lint_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
fn repl_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
runtime_args_parse(flags, matches, false, true);
flags.repl = true;
- flags.subcommand = DenoSubcommand::Repl;
+ flags.subcommand = DenoSubcommand::Repl {
+ eval: matches.value_of("eval").map(ToOwned::to_owned),
+ };
flags.allow_net = Some(vec![]);
flags.allow_env = Some(vec![]);
flags.allow_run = Some(vec![]);
@@ -2706,7 +2717,7 @@ mod tests {
r.unwrap(),
Flags {
repl: true,
- subcommand: DenoSubcommand::Repl,
+ subcommand: DenoSubcommand::Repl { eval: None },
allow_net: Some(vec![]),
allow_env: Some(vec![]),
allow_run: Some(vec![]),
@@ -2727,7 +2738,7 @@ mod tests {
r.unwrap(),
Flags {
repl: true,
- subcommand: DenoSubcommand::Repl,
+ subcommand: DenoSubcommand::Repl { eval: None },
import_map_path: Some("import_map.json".to_string()),
no_remote: true,
config_path: Some("tsconfig.json".to_string()),
@@ -2754,6 +2765,29 @@ mod tests {
}
#[test]
+ fn repl_with_eval_flag() {
+ #[rustfmt::skip]
+ let r = flags_from_vec(svec!["deno", "repl", "--eval", "console.log('hello');"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ repl: true,
+ subcommand: DenoSubcommand::Repl {
+ eval: Some("console.log('hello');".to_string()),
+ },
+ allow_net: Some(vec![]),
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_plugin: true,
+ allow_hrtime: true,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
fn allow_read_allowlist() {
use tempfile::TempDir;
let temp_dir = TempDir::new().expect("tempdir fail").path().to_path_buf();
diff --git a/cli/main.rs b/cli/main.rs
index 77366ec12..7d375c0c4 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -774,7 +774,10 @@ async fn format_command(
Ok(())
}
-async fn run_repl(flags: Flags) -> Result<(), AnyError> {
+async fn run_repl(
+ flags: Flags,
+ maybe_eval: Option<String>,
+) -> Result<(), AnyError> {
let main_module = resolve_url_or_path("./$deno$repl.ts").unwrap();
let permissions = Permissions::from_options(&flags.clone().into());
let program_state = ProgramState::build(flags).await?;
@@ -782,7 +785,7 @@ async fn run_repl(flags: Flags) -> Result<(), AnyError> {
create_main_worker(&program_state, main_module.clone(), permissions, false);
worker.run_event_loop(false).await?;
- tools::repl::run(&program_state, worker).await
+ tools::repl::run(&program_state, worker, maybe_eval).await
}
async fn run_from_stdin(flags: Flags) -> Result<(), AnyError> {
@@ -1341,7 +1344,7 @@ fn get_subcommand(
ignore,
json,
} => lint_command(flags, files, rules, ignore, json).boxed_local(),
- DenoSubcommand::Repl => run_repl(flags).boxed_local(),
+ DenoSubcommand::Repl { eval } => run_repl(flags, eval).boxed_local(),
DenoSubcommand::Run { script } => run_command(flags, script).boxed_local(),
DenoSubcommand::Test {
no_run,
diff --git a/cli/tests/integration/repl_tests.rs b/cli/tests/integration/repl_tests.rs
index b96b398ae..7ce91d406 100644
--- a/cli/tests/integration/repl_tests.rs
+++ b/cli/tests/integration/repl_tests.rs
@@ -436,7 +436,7 @@ fn exports_stripped() {
}
#[test]
-fn eval_unterminated() {
+fn call_eval_unterminated() {
let (out, err) = util::run_and_collect_output(
true,
"repl",
@@ -644,3 +644,45 @@ fn custom_inspect() {
assert!(out.contains("Oops custom inspect error"));
assert!(err.is_empty());
}
+
+#[test]
+fn eval_flag_valid_input() {
+ let (out, err) = util::run_and_collect_output_with_args(
+ true,
+ vec!["repl", "--eval", "const t = 10;"],
+ Some(vec!["t * 500;"]),
+ None,
+ false,
+ );
+ assert!(out.contains("5000"));
+ assert!(err.is_empty());
+}
+
+#[test]
+fn eval_flag_parse_error() {
+ let (out, err) = util::run_and_collect_output_with_args(
+ true,
+ vec!["repl", "--eval", "const %"],
+ Some(vec!["250 * 10"]),
+ None,
+ false,
+ );
+ assert!(test_util::strip_ansi_codes(&out)
+ .contains("error in --eval flag. parse error: Unexpected token `%`."));
+ assert!(out.contains("2500")); // should not prevent input
+ assert!(err.is_empty());
+}
+
+#[test]
+fn eval_flag_runtime_error() {
+ let (out, err) = util::run_and_collect_output_with_args(
+ true,
+ vec!["repl", "--eval", "throw new Error('Testing')"],
+ Some(vec!["250 * 10"]),
+ None,
+ false,
+ );
+ assert!(out.contains("error in --eval flag. Uncaught Error: Testing"));
+ assert!(out.contains("2500")); // should not prevent input
+ assert!(err.is_empty());
+}
diff --git a/cli/tools/repl.rs b/cli/tools/repl.rs
index d527ea868..3de859698 100644
--- a/cli/tools/repl.rs
+++ b/cli/tools/repl.rs
@@ -418,6 +418,20 @@ Object.defineProperty(globalThis, "_error", {
});
"#;
+enum EvaluationOutput {
+ Value(String),
+ Error(String),
+}
+
+impl std::fmt::Display for EvaluationOutput {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ EvaluationOutput::Value(value) => f.write_str(value),
+ EvaluationOutput::Error(value) => f.write_str(value),
+ }
+ }
+}
+
struct ReplSession {
worker: MainWorker,
session: LocalInspectorSession,
@@ -497,7 +511,7 @@ impl ReplSession {
pub async fn evaluate_line_and_get_output(
&mut self,
line: &str,
- ) -> Result<String, AnyError> {
+ ) -> Result<EvaluationOutput, AnyError> {
match self.evaluate_line_with_object_wrapping(line).await {
Ok(evaluate_response) => {
let evaluate_result = evaluate_response.get("result").unwrap();
@@ -512,20 +526,20 @@ impl ReplSession {
let value = self.get_eval_value(evaluate_result).await?;
Ok(match evaluate_exception_details {
- Some(_) => format!("Uncaught {}", value),
- None => value,
+ Some(_) => EvaluationOutput::Error(format!("Uncaught {}", value)),
+ None => EvaluationOutput::Value(value),
})
}
Err(err) => {
// handle a parsing diagnostic
match err.downcast_ref::<Diagnostic>() {
- Some(diagnostic) => Ok(format!(
+ Some(diagnostic) => Ok(EvaluationOutput::Error(format!(
"{}: {} at {}:{}",
colors::red("parse error"),
diagnostic.message,
diagnostic.location.line,
diagnostic.location.col
- )),
+ ))),
None => Err(err),
}
}
@@ -707,6 +721,7 @@ async fn read_line_and_poll(
pub async fn run(
program_state: &ProgramState,
worker: MainWorker,
+ maybe_eval: Option<String>,
) -> Result<(), AnyError> {
let mut repl_session = ReplSession::initialize(worker).await?;
let (message_tx, mut message_rx) = channel(1);
@@ -721,6 +736,14 @@ pub async fn run(
let history_file_path = program_state.dir.root.join("deno_history.txt");
let editor = ReplEditor::new(helper, history_file_path);
+ if let Some(eval) = maybe_eval {
+ 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);
+ }
+ }
+
println!("Deno {}", crate::version::deno());
println!("exit using ctrl+d or close()");