summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/args/flags.rs46
-rw-r--r--cli/main.rs12
-rw-r--r--cli/tests/integration/init_tests.rs110
-rw-r--r--cli/tests/integration/mod.rs2
-rw-r--r--cli/tools/init/mod.rs49
-rw-r--r--cli/tools/init/templates/main.ts8
-rw-r--r--cli/tools/init/templates/main_test.ts6
-rw-r--r--cli/tools/mod.rs1
8 files changed, 234 insertions, 0 deletions
diff --git a/cli/args/flags.rs b/cli/args/flags.rs
index 08b48d1d5..a70b2c675 100644
--- a/cli/args/flags.rs
+++ b/cli/args/flags.rs
@@ -120,6 +120,11 @@ pub struct FmtFlags {
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
+pub struct InitFlags {
+ pub dir: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct InfoFlags {
pub json: bool,
pub file: Option<String>,
@@ -217,6 +222,7 @@ pub enum DenoSubcommand {
Doc(DocFlags),
Eval(EvalFlags),
Fmt(FmtFlags),
+ Init(InitFlags),
Info(InfoFlags),
Install(InstallFlags),
Uninstall(UninstallFlags),
@@ -554,6 +560,7 @@ pub fn flags_from_vec(args: Vec<String>) -> clap::Result<Flags> {
Some(("doc", m)) => doc_parse(&mut flags, m),
Some(("eval", m)) => eval_parse(&mut flags, m),
Some(("fmt", m)) => fmt_parse(&mut flags, m),
+ Some(("init", m)) => init_parse(&mut flags, m),
Some(("info", m)) => info_parse(&mut flags, m),
Some(("install", m)) => install_parse(&mut flags, m),
Some(("lint", m)) => lint_parse(&mut flags, m),
@@ -629,6 +636,7 @@ fn clap_root(version: &str) -> Command {
.subcommand(doc_subcommand())
.subcommand(eval_subcommand())
.subcommand(fmt_subcommand())
+ .subcommand(init_subcommand())
.subcommand(info_subcommand())
.subcommand(install_subcommand())
.subcommand(uninstall_subcommand())
@@ -1140,6 +1148,15 @@ Ignore formatting a file by adding an ignore comment at the top of the file:
)
}
+fn init_subcommand<'a>() -> Command<'a> {
+ Command::new("init").about("Initialize a new project").arg(
+ Arg::new("dir")
+ .takes_value(true)
+ .required(false)
+ .value_hint(ValueHint::DirPath),
+ )
+}
+
fn info_subcommand<'a>() -> Command<'a> {
Command::new("info")
.about("Show info about cache or info related to source file")
@@ -2436,6 +2453,12 @@ fn fmt_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
});
}
+fn init_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
+ flags.subcommand = DenoSubcommand::Init(InitFlags {
+ dir: matches.value_of("dir").map(|f| f.to_string()),
+ });
+}
+
fn info_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
reload_arg_parse(flags, matches);
config_args_parse(flags, matches);
@@ -5951,4 +5974,27 @@ mod tests {
]);
assert!(r.is_err());
}
+
+ #[test]
+ fn init() {
+ let r = flags_from_vec(svec!["deno", "init"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Init(InitFlags { dir: None }),
+ ..Flags::default()
+ }
+ );
+
+ let r = flags_from_vec(svec!["deno", "init", "foo"]);
+ assert_eq!(
+ r.unwrap(),
+ Flags {
+ subcommand: DenoSubcommand::Init(InitFlags {
+ dir: Some(String::from("foo")),
+ }),
+ ..Flags::default()
+ }
+ );
+ }
}
diff --git a/cli/main.rs b/cli/main.rs
index b157b3582..db625e404 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -51,6 +51,7 @@ use crate::args::EvalFlags;
use crate::args::Flags;
use crate::args::FmtFlags;
use crate::args::InfoFlags;
+use crate::args::InitFlags;
use crate::args::InstallFlags;
use crate::args::LintFlags;
use crate::args::ReplFlags;
@@ -273,6 +274,14 @@ async fn compile_command(
Ok(0)
}
+async fn init_command(
+ _flags: Flags,
+ init_flags: InitFlags,
+) -> Result<i32, AnyError> {
+ tools::init::init_project(init_flags).await?;
+ Ok(0)
+}
+
async fn info_command(
flags: Flags,
info_flags: InfoFlags,
@@ -941,6 +950,9 @@ fn get_subcommand(
DenoSubcommand::Fmt(fmt_flags) => {
format_command(flags, fmt_flags).boxed_local()
}
+ DenoSubcommand::Init(init_flags) => {
+ init_command(flags, init_flags).boxed_local()
+ }
DenoSubcommand::Info(info_flags) => {
info_command(flags, info_flags).boxed_local()
}
diff --git a/cli/tests/integration/init_tests.rs b/cli/tests/integration/init_tests.rs
new file mode 100644
index 000000000..a7a54f06b
--- /dev/null
+++ b/cli/tests/integration/init_tests.rs
@@ -0,0 +1,110 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use std::process::Stdio;
+use test_util as util;
+use test_util::TempDir;
+use util::assert_contains;
+
+#[test]
+fn init_subcommand_without_dir() {
+ let temp_dir = TempDir::new();
+ let cwd = temp_dir.path();
+ let deno_dir = util::new_deno_dir();
+
+ let mut deno_cmd = util::deno_cmd_with_deno_dir(&deno_dir);
+ let output = deno_cmd
+ .current_dir(cwd)
+ .arg("init")
+ .stdout(Stdio::piped())
+ .spawn()
+ .unwrap()
+ .wait_with_output()
+ .unwrap();
+ assert!(output.status.success());
+ let stdout = String::from_utf8(output.stdout).unwrap();
+ assert_contains!(stdout, "Project initialized");
+ assert!(!stdout.contains("cd"));
+ assert_contains!(stdout, "deno run main.ts");
+ assert_contains!(stdout, "deno test");
+
+ let mut deno_cmd = util::deno_cmd_with_deno_dir(&deno_dir);
+ let output = deno_cmd
+ .current_dir(cwd)
+ .env("NO_COLOR", "1")
+ .arg("run")
+ .arg("main.ts")
+ .stdout(Stdio::piped())
+ .spawn()
+ .unwrap()
+ .wait_with_output()
+ .unwrap();
+ assert!(output.status.success());
+ assert_eq!(output.stdout, b"Add 2 + 3 = 5\n");
+
+ let mut deno_cmd = util::deno_cmd_with_deno_dir(&deno_dir);
+ let output = deno_cmd
+ .current_dir(cwd)
+ .env("NO_COLOR", "1")
+ .arg("test")
+ .stdout(Stdio::piped())
+ .spawn()
+ .unwrap()
+ .wait_with_output()
+ .unwrap();
+ assert!(output.status.success());
+ let stdout = String::from_utf8(output.stdout).unwrap();
+ assert_contains!(stdout, "1 passed");
+}
+
+#[test]
+fn init_subcommand_with_dir_arg() {
+ let temp_dir = TempDir::new();
+ let cwd = temp_dir.path();
+ let deno_dir = util::new_deno_dir();
+
+ let mut deno_cmd = util::deno_cmd_with_deno_dir(&deno_dir);
+ let output = deno_cmd
+ .current_dir(cwd)
+ .arg("init")
+ .arg("my_dir")
+ .stdout(Stdio::piped())
+ .spawn()
+ .unwrap()
+ .wait_with_output()
+ .unwrap();
+ assert!(output.status.success());
+ let stdout = String::from_utf8(output.stdout).unwrap();
+ assert_contains!(stdout, "Project initialized");
+ assert_contains!(stdout, "cd my_dir");
+ assert_contains!(stdout, "deno run main.ts");
+ assert_contains!(stdout, "deno test");
+
+ let mut deno_cmd = util::deno_cmd_with_deno_dir(&deno_dir);
+ let output = deno_cmd
+ .current_dir(cwd)
+ .env("NO_COLOR", "1")
+ .arg("run")
+ .arg("my_dir/main.ts")
+ .stdout(Stdio::piped())
+ .spawn()
+ .unwrap()
+ .wait_with_output()
+ .unwrap();
+ assert!(output.status.success());
+ assert_eq!(output.stdout, b"Add 2 + 3 = 5\n");
+
+ let mut deno_cmd = util::deno_cmd_with_deno_dir(&deno_dir);
+ let output = deno_cmd
+ .current_dir(cwd)
+ .env("NO_COLOR", "1")
+ .arg("test")
+ .arg("my_dir/main_test.ts")
+ .stdout(Stdio::piped())
+ .spawn()
+ .unwrap()
+ .wait_with_output()
+ .unwrap();
+ assert!(output.status.success());
+ let stdout = String::from_utf8(output.stdout).unwrap();
+ assert_contains!(stdout, "1 passed");
+}
diff --git a/cli/tests/integration/mod.rs b/cli/tests/integration/mod.rs
index 3101d8dc7..53c83c009 100644
--- a/cli/tests/integration/mod.rs
+++ b/cli/tests/integration/mod.rs
@@ -74,6 +74,8 @@ mod eval;
mod fmt;
#[path = "info_tests.rs"]
mod info;
+#[path = "init_tests.rs"]
+mod init;
#[path = "inspector_tests.rs"]
mod inspector;
#[path = "install_tests.rs"]
diff --git a/cli/tools/init/mod.rs b/cli/tools/init/mod.rs
new file mode 100644
index 000000000..e47b88702
--- /dev/null
+++ b/cli/tools/init/mod.rs
@@ -0,0 +1,49 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use crate::args::InitFlags;
+use crate::compat;
+use deno_core::{anyhow::Context, error::AnyError};
+use std::io::Write;
+use std::path::Path;
+
+fn create_file(
+ dir: &Path,
+ filename: &str,
+ content: &str,
+) -> Result<(), AnyError> {
+ let mut file = std::fs::OpenOptions::new()
+ .write(true)
+ .create_new(true)
+ .open(dir.join(filename))
+ .with_context(|| format!("Failed to create {} file", filename))?;
+ file.write_all(content.as_bytes())?;
+ Ok(())
+}
+
+pub async fn init_project(init_flags: InitFlags) -> Result<(), AnyError> {
+ let cwd =
+ std::env::current_dir().context("Can't read current working directory.")?;
+ let dir = if let Some(dir) = &init_flags.dir {
+ let dir = cwd.join(dir);
+ std::fs::create_dir_all(&dir)?;
+ dir
+ } else {
+ cwd
+ };
+
+ let main_ts = include_str!("./templates/main.ts");
+ create_file(&dir, "main.ts", main_ts)?;
+
+ let main_test_ts = include_str!("./templates/main_test.ts")
+ .replace("{CURRENT_STD_URL}", compat::STD_URL_STR);
+ create_file(&dir, "main_test.ts", &main_test_ts)?;
+
+ println!("✅ Project initialized");
+ println!("Run these commands to get started");
+ if let Some(dir) = init_flags.dir {
+ println!(" cd {}", dir);
+ }
+ println!(" deno run main.ts");
+ println!(" deno test");
+ Ok(())
+}
diff --git a/cli/tools/init/templates/main.ts b/cli/tools/init/templates/main.ts
new file mode 100644
index 000000000..be043e97c
--- /dev/null
+++ b/cli/tools/init/templates/main.ts
@@ -0,0 +1,8 @@
+export function add(a: number, b: number): number {
+ return a + b;
+}
+
+// Learn more at https://deno.land/manual/examples/module_metadata#concepts
+if (import.meta.main) {
+ console.log("Add 2 + 3 =", add(2, 3));
+}
diff --git a/cli/tools/init/templates/main_test.ts b/cli/tools/init/templates/main_test.ts
new file mode 100644
index 000000000..5f60b571c
--- /dev/null
+++ b/cli/tools/init/templates/main_test.ts
@@ -0,0 +1,6 @@
+import { assertEquals } from "{CURRENT_STD_URL}testing/asserts.ts";
+import { add } from "./main.ts";
+
+Deno.test(function addTest() {
+ assertEquals(add(2, 3), 5);
+});
diff --git a/cli/tools/mod.rs b/cli/tools/mod.rs
index 7c5d79744..11c904776 100644
--- a/cli/tools/mod.rs
+++ b/cli/tools/mod.rs
@@ -4,6 +4,7 @@ pub mod bench;
pub mod coverage;
pub mod doc;
pub mod fmt;
+pub mod init;
pub mod installer;
pub mod lint;
pub mod repl;