summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/flags.rs76
-rw-r--r--cli/main.rs2
-rw-r--r--cli/tests/integration/repl_tests.rs52
-rw-r--r--cli/tools/repl/mod.rs35
4 files changed, 159 insertions, 6 deletions
diff --git a/cli/flags.rs b/cli/flags.rs
index cdd90fa33..b0e4b32ed 100644
--- a/cli/flags.rs
+++ b/cli/flags.rs
@@ -144,6 +144,7 @@ pub struct LintFlags {
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct ReplFlags {
+ pub eval_files: Option<Vec<String>>,
pub eval: Option<String>,
}
@@ -216,7 +217,10 @@ pub enum DenoSubcommand {
impl Default for DenoSubcommand {
fn default() -> DenoSubcommand {
- DenoSubcommand::Repl(ReplFlags { eval: None })
+ DenoSubcommand::Repl(ReplFlags {
+ eval_files: None,
+ eval: None,
+ })
}
}
@@ -556,7 +560,13 @@ where
Some(("uninstall", m)) => uninstall_parse(&mut flags, m),
Some(("upgrade", m)) => upgrade_parse(&mut flags, m),
Some(("vendor", m)) => vendor_parse(&mut flags, m),
- _ => handle_repl_flags(&mut flags, ReplFlags { eval: None }),
+ _ => handle_repl_flags(
+ &mut flags,
+ ReplFlags {
+ eval_files: None,
+ eval: None,
+ },
+ ),
}
Ok(flags)
@@ -1361,6 +1371,16 @@ fn repl_subcommand<'a>() -> Command<'a> {
runtime_args(Command::new("repl"), false, true)
.about("Read Eval Print Loop")
.arg(
+ Arg::new("eval-file")
+ .long("eval-file")
+ .min_values(1)
+ .takes_value(true)
+ .use_value_delimiter(true)
+ .require_equals(true)
+ .help("Evaluates the provided file(s) as scripts when the REPL starts. Accepts file paths and URLs.")
+ .value_hint(ValueHint::AnyPath),
+ )
+ .arg(
Arg::new("eval")
.long("eval")
.help("Evaluates the provided code when the REPL starts.")
@@ -2446,9 +2466,15 @@ fn repl_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
flags.type_check_mode = TypeCheckMode::None;
runtime_args_parse(flags, matches, false, true);
unsafely_ignore_certificate_errors_parse(flags, matches);
+
+ let eval_files: Option<Vec<String>> = matches
+ .values_of("eval-file")
+ .map(|values| values.map(String::from).collect());
+
handle_repl_flags(
flags,
ReplFlags {
+ eval_files,
eval: matches.value_of("eval").map(ToOwned::to_owned),
},
);
@@ -3884,7 +3910,10 @@ mod tests {
r.unwrap(),
Flags {
repl: true,
- subcommand: DenoSubcommand::Repl(ReplFlags { eval: None }),
+ subcommand: DenoSubcommand::Repl(ReplFlags {
+ eval_files: None,
+ eval: None
+ }),
allow_net: Some(vec![]),
unsafely_ignore_certificate_errors: None,
allow_env: Some(vec![]),
@@ -3906,7 +3935,10 @@ mod tests {
r.unwrap(),
Flags {
repl: true,
- subcommand: DenoSubcommand::Repl(ReplFlags { eval: None }),
+ subcommand: DenoSubcommand::Repl(ReplFlags {
+ eval_files: None,
+ eval: None
+ }),
import_map_path: Some("import_map.json".to_string()),
no_remote: true,
config_path: Some("tsconfig.json".to_string()),
@@ -3942,6 +3974,7 @@ mod tests {
Flags {
repl: true,
subcommand: DenoSubcommand::Repl(ReplFlags {
+ eval_files: None,
eval: Some("console.log('hello');".to_string()),
}),
allow_net: Some(vec![]),
@@ -3958,6 +3991,35 @@ mod tests {
}
#[test]
+ fn repl_with_eval_file_flag() {
+ #[rustfmt::skip]
+ let r = flags_from_vec(svec!["deno", "repl", "--eval-file=./a.js,./b.ts,https://examples.deno.land/hello-world.ts"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ repl: true,
+ subcommand: DenoSubcommand::Repl(ReplFlags {
+ eval_files: Some(vec![
+ "./a.js".to_string(),
+ "./b.ts".to_string(),
+ "https://examples.deno.land/hello-world.ts".to_string()
+ ]),
+ eval: None,
+ }),
+ allow_net: Some(vec![]),
+ allow_env: Some(vec![]),
+ allow_run: Some(vec![]),
+ allow_read: Some(vec![]),
+ allow_write: Some(vec![]),
+ allow_ffi: Some(vec![]),
+ allow_hrtime: true,
+ type_check_mode: TypeCheckMode::None,
+ ..Flags::default()
+ }
+ );
+ }
+
+ #[test]
fn allow_read_allowlist() {
use test_util::TempDir;
let temp_dir_guard = TempDir::new();
@@ -4590,6 +4652,7 @@ mod tests {
Flags {
repl: true,
subcommand: DenoSubcommand::Repl(ReplFlags {
+ eval_files: None,
eval: Some("console.log('hello');".to_string()),
}),
unsafely_ignore_certificate_errors: Some(vec![]),
@@ -4663,7 +4726,10 @@ mod tests {
r.unwrap(),
Flags {
repl: true,
- subcommand: DenoSubcommand::Repl(ReplFlags { eval: None }),
+ subcommand: DenoSubcommand::Repl(ReplFlags {
+ eval_files: None,
+ eval: None
+ }),
unsafely_ignore_certificate_errors: Some(svec![
"deno.land",
"localhost",
diff --git a/cli/main.rs b/cli/main.rs
index 7f86967aa..218bc70f5 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -930,7 +930,7 @@ async fn repl_command(
}
worker.run_event_loop(false).await?;
- tools::repl::run(&ps, worker, repl_flags.eval).await
+ tools::repl::run(&ps, worker, repl_flags.eval_files, repl_flags.eval).await
}
async fn run_from_stdin(flags: Flags) -> Result<i32, AnyError> {
diff --git a/cli/tests/integration/repl_tests.rs b/cli/tests/integration/repl_tests.rs
index 59acc7dfb..a63be3ece 100644
--- a/cli/tests/integration/repl_tests.rs
+++ b/cli/tests/integration/repl_tests.rs
@@ -709,3 +709,55 @@ fn eval_flag_runtime_error() {
assert!(out.contains("2500")); // should not prevent input
assert!(err.is_empty());
}
+
+#[test]
+fn eval_file_flag_valid_input() {
+ let (out, err) = util::run_and_collect_output_with_args(
+ true,
+ vec!["repl", "--eval-file=./001_hello.js"],
+ None,
+ None,
+ false,
+ );
+ assert!(out.contains("Hello World"));
+ assert!(err.is_empty());
+}
+
+#[test]
+fn eval_file_flag_call_defined_function() {
+ let (out, err) = util::run_and_collect_output_with_args(
+ true,
+ vec!["repl", "--eval-file=./tsc/d.ts"],
+ Some(vec!["v4()"]),
+ None,
+ false,
+ );
+ assert!(out.contains("hello"));
+ assert!(err.is_empty());
+}
+
+#[test]
+fn eval_file_flag_http_input() {
+ let (out, err) = util::run_and_collect_output_with_args(
+ true,
+ vec!["repl", "--eval-file=http://127.0.0.1:4545/tsc/d.ts"],
+ Some(vec!["v4()"]),
+ None,
+ true,
+ );
+ assert!(out.contains("hello"));
+ assert!(err.contains("Download"));
+}
+
+#[test]
+fn eval_file_flag_multiple_files() {
+ let (out, err) = util::run_and_collect_output_with_args(
+ true,
+ vec!["repl", "--eval-file=http://127.0.0.1:4545/import_type.ts,./tsc/d.ts,http://127.0.0.1:4545/type_definitions/foo.js"],
+ Some(vec!["b.method1=v4", "b.method1()+foo.toUpperCase()"]),
+ None,
+ true,
+ );
+ assert!(out.contains("helloFOO"));
+ assert!(err.contains("Download"));
+}
diff --git a/cli/tools/repl/mod.rs b/cli/tools/repl/mod.rs
index b49c641c4..f0964ec4d 100644
--- a/cli/tools/repl/mod.rs
+++ b/cli/tools/repl/mod.rs
@@ -2,6 +2,7 @@
use crate::proc_state::ProcState;
use deno_core::error::AnyError;
+use deno_runtime::permissions::Permissions;
use deno_runtime::worker::MainWorker;
use rustyline::error::ReadlineError;
@@ -58,9 +59,24 @@ async fn read_line_and_poll(
}
}
+async fn read_eval_file(
+ ps: &ProcState,
+ eval_file: &str,
+) -> Result<String, AnyError> {
+ let specifier = deno_core::resolve_url_or_path(eval_file)?;
+
+ let file = ps
+ .file_fetcher
+ .fetch(&specifier, &mut Permissions::allow_all())
+ .await?;
+
+ Ok((*file.source).clone())
+}
+
pub async fn run(
ps: &ProcState,
worker: MainWorker,
+ maybe_eval_files: Option<Vec<String>>,
maybe_eval: Option<String>,
) -> Result<i32, AnyError> {
let mut repl_session = ReplSession::initialize(worker).await?;
@@ -74,6 +90,25 @@ pub async fn run(
let history_file_path = ps.dir.root.join("deno_history.txt");
let editor = ReplEditor::new(helper, history_file_path);
+ if let Some(eval_files) = maybe_eval_files {
+ for eval_file in eval_files {
+ match read_eval_file(ps, &eval_file).await {
+ Ok(eval_source) => {
+ let output = repl_session
+ .evaluate_line_and_get_output(&eval_source)
+ .await?;
+ // only output errors
+ if let EvaluationOutput::Error(error_text) = output {
+ println!("error in --eval-file file {}. {}", eval_file, error_text);
+ }
+ }
+ Err(e) => {
+ println!("error in --eval-file file {}. {}", eval_file, e);
+ }
+ }
+ }
+ }
+
if let Some(eval) = maybe_eval {
let output = repl_session.evaluate_line_and_get_output(&eval).await?;
// only output errors