diff options
-rw-r--r-- | cli/args/flags.rs | 54 | ||||
-rw-r--r-- | cli/tools/init/mod.rs | 176 | ||||
-rw-r--r-- | cli/tools/init/templates/deno.json | 5 | ||||
-rw-r--r-- | cli/tools/init/templates/main.ts | 8 | ||||
-rw-r--r-- | cli/tools/init/templates/main_test.ts | 6 | ||||
-rw-r--r-- | tests/specs/init/lib/__test__.jsonc | 16 | ||||
-rw-r--r-- | tests/specs/init/lib/dry_publish.out | 7 | ||||
-rw-r--r-- | tests/specs/init/lib/init.out | 14 | ||||
-rw-r--r-- | tests/specs/init/lib/test.out | 14 |
9 files changed, 232 insertions, 68 deletions
diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 89f53d593..d2321f32e 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -205,6 +205,7 @@ impl FmtFlags { #[derive(Clone, Debug, Eq, PartialEq)] pub struct InitFlags { pub dir: Option<String>, + pub lib: bool, } #[derive(Clone, Debug, Eq, PartialEq)] @@ -2052,11 +2053,18 @@ fn init_subcommand() -> Command { Command::new("init") .about("Initialize a new project") .defer(|cmd| { - cmd.arg( - Arg::new("dir") - .required(false) - .value_hint(ValueHint::DirPath), - ) + cmd + .arg( + Arg::new("dir") + .required(false) + .value_hint(ValueHint::DirPath), + ) + .arg( + Arg::new("lib") + .long("lib") + .required(false) + .action(ArgAction::SetTrue), + ) }) } @@ -4033,6 +4041,7 @@ fn fmt_parse(flags: &mut Flags, matches: &mut ArgMatches) { fn init_parse(flags: &mut Flags, matches: &mut ArgMatches) { flags.subcommand = DenoSubcommand::Init(InitFlags { dir: matches.remove_one::<String>("dir"), + lib: matches.get_flag("lib"), }); } @@ -9753,7 +9762,10 @@ mod tests { assert_eq!( r.unwrap(), Flags { - subcommand: DenoSubcommand::Init(InitFlags { dir: None }), + subcommand: DenoSubcommand::Init(InitFlags { + dir: None, + lib: false + }), ..Flags::default() } ); @@ -9764,6 +9776,7 @@ mod tests { Flags { subcommand: DenoSubcommand::Init(InitFlags { dir: Some(String::from("foo")), + lib: false }), ..Flags::default() } @@ -9773,11 +9786,38 @@ mod tests { assert_eq!( r.unwrap(), Flags { - subcommand: DenoSubcommand::Init(InitFlags { dir: None }), + subcommand: DenoSubcommand::Init(InitFlags { + dir: None, + lib: false + }), log_level: Some(Level::Error), ..Flags::default() } ); + + let r = flags_from_vec(svec!["deno", "init", "--lib"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Init(InitFlags { + dir: None, + lib: true + }), + ..Flags::default() + } + ); + + let r = flags_from_vec(svec!["deno", "init", "foo", "--lib"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Init(InitFlags { + dir: Some(String::from("foo")), + lib: true + }), + ..Flags::default() + } + ); } #[test] diff --git a/cli/tools/init/mod.rs b/cli/tools/init/mod.rs index fb2e6e7af..23b14e17c 100644 --- a/cli/tools/init/mod.rs +++ b/cli/tools/init/mod.rs @@ -4,33 +4,11 @@ use crate::args::InitFlags; use crate::colors; use deno_core::anyhow::Context; use deno_core::error::AnyError; +use deno_core::serde_json::json; use log::info; use std::io::Write; use std::path::Path; -fn create_file( - dir: &Path, - filename: &str, - content: &str, -) -> Result<(), AnyError> { - let path = dir.join(filename); - if path.exists() { - info!( - "ℹ️ {}", - colors::gray(format!("Skipped creating {filename} as it already exists")) - ); - Ok(()) - } else { - let mut file = std::fs::OpenOptions::new() - .write(true) - .create_new(true) - .open(path) - .with_context(|| format!("Failed to create {filename} file"))?; - file.write_all(content.as_bytes())?; - Ok(()) - } -} - pub fn init_project(init_flags: InitFlags) -> Result<(), AnyError> { let cwd = std::env::current_dir().context("Can't read current working directory.")?; @@ -42,15 +20,82 @@ pub fn init_project(init_flags: InitFlags) -> Result<(), AnyError> { cwd }; - let main_ts = include_str!("./templates/main.ts"); - create_file(&dir, "main.ts", main_ts)?; + if init_flags.lib { + // Extract the directory name to use as the project name + let project_name = dir + .file_name() + .unwrap_or_else(|| dir.as_os_str()) + .to_str() + .unwrap(); + + create_file( + &dir, + "mod.ts", + r#"export function add(a: number, b: number): number { + return a + b; +} +"#, + )?; + create_file( + &dir, + "mod_test.ts", + r#"import { assertEquals } from "jsr:@std/assert"; +import { add } from "./mod.ts"; + +Deno.test(function addTest() { + assertEquals(add(2, 3), 5); +}); +"#, + )?; + + create_json_file( + &dir, + "deno.json", + &json!({ + "name": project_name, + "version": "1.0.0", + "exports": "./mod.ts", + "tasks": { + "dev": "deno test --watch mod.ts" + } + }), + )?; + } else { + create_file( + &dir, + "main.ts", + r#"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)); +} +"#, + )?; + create_file( + &dir, + "main_test.ts", + r#"import { assertEquals } from "jsr:@std/assert"; +import { add } from "./main.ts"; - create_file( - &dir, - "main_test.ts", - include_str!("./templates/main_test.ts"), - )?; - create_file(&dir, "deno.json", include_str!("./templates/deno.json"))?; +Deno.test(function addTest() { + assertEquals(add(2, 3), 5); +}); +"#, + )?; + + create_json_file( + &dir, + "deno.json", + &json!({ + "tasks": { + "dev": "deno run --watch main.ts" + } + }), + )?; + } info!("✅ {}", colors::green("Project initialized")); info!(""); @@ -60,16 +105,63 @@ pub fn init_project(init_flags: InitFlags) -> Result<(), AnyError> { info!(" cd {}", dir); info!(""); } - info!(" {}", colors::gray("# Run the program")); - info!(" deno run main.ts"); - info!(""); - info!( - " {}", - colors::gray("# Run the program and watch for file changes") - ); - info!(" deno task dev"); - info!(""); - info!(" {}", colors::gray("# Run the tests")); - info!(" deno test"); + if init_flags.lib { + info!(" {}", colors::gray("# Run the tests")); + info!(" deno test"); + info!(""); + info!( + " {}", + colors::gray("# Run the tests and watch for file changes") + ); + info!(" deno task dev"); + info!(""); + info!(" {}", colors::gray("# Publish to JSR (dry run)")); + info!(" deno publish --dry-run"); + } else { + info!(" {}", colors::gray("# Run the program")); + info!(" deno run main.ts"); + info!(""); + info!( + " {}", + colors::gray("# Run the program and watch for file changes") + ); + info!(" deno task dev"); + info!(""); + info!(" {}", colors::gray("# Run the tests")); + info!(" deno test"); + } Ok(()) } + +fn create_json_file( + dir: &Path, + filename: &str, + value: &deno_core::serde_json::Value, +) -> Result<(), AnyError> { + let mut text = deno_core::serde_json::to_string_pretty(value)?; + text.push('\n'); + create_file(dir, filename, &text) +} + +fn create_file( + dir: &Path, + filename: &str, + content: &str, +) -> Result<(), AnyError> { + let path = dir.join(filename); + if path.exists() { + info!( + "ℹ️ {}", + colors::gray(format!("Skipped creating {filename} as it already exists")) + ); + Ok(()) + } else { + let mut file = std::fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(path) + .with_context(|| format!("Failed to create {filename} file"))?; + file.write_all(content.as_bytes())?; + Ok(()) + } +} diff --git a/cli/tools/init/templates/deno.json b/cli/tools/init/templates/deno.json deleted file mode 100644 index 3c5130f1d..000000000 --- a/cli/tools/init/templates/deno.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "tasks": { - "dev": "deno run --watch main.ts" - } -} diff --git a/cli/tools/init/templates/main.ts b/cli/tools/init/templates/main.ts deleted file mode 100644 index be043e97c..000000000 --- a/cli/tools/init/templates/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 26af2582b..000000000 --- a/cli/tools/init/templates/main_test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { assertEquals } from "jsr:@std/assert"; -import { add } from "./main.ts"; - -Deno.test(function addTest() { - assertEquals(add(2, 3), 5); -}); diff --git a/tests/specs/init/lib/__test__.jsonc b/tests/specs/init/lib/__test__.jsonc new file mode 100644 index 000000000..076930ae6 --- /dev/null +++ b/tests/specs/init/lib/__test__.jsonc @@ -0,0 +1,16 @@ +{ + "tempDir": true, + "steps": [{ + "args": "init --lib project", + "output": "init.out" + }, { + "cwd": "project", + "args": "test", + "output": "test.out" + }, { + "cwd": "project", + "args": "publish --dry-run", + "output": "dry_publish.out", + "exitCode": 1 + }] +} diff --git a/tests/specs/init/lib/dry_publish.out b/tests/specs/init/lib/dry_publish.out new file mode 100644 index 000000000..31f91c38d --- /dev/null +++ b/tests/specs/init/lib/dry_publish.out @@ -0,0 +1,7 @@ +Check file:///[WILDLINE]/mod.ts +Checking for slow types in the public API... +Check file:///[WILDLINE]/mod.ts +error: Failed preparing 'project'. + +Caused by: + Invalid package name, use '@<scope_name>/<package_name> format diff --git a/tests/specs/init/lib/init.out b/tests/specs/init/lib/init.out new file mode 100644 index 000000000..0f1a83f30 --- /dev/null +++ b/tests/specs/init/lib/init.out @@ -0,0 +1,14 @@ +✅ Project initialized + +Run these commands to get started + + cd project + + # Run the tests + deno test + + # Run the tests and watch for file changes + deno task dev + + # Publish to JSR (dry run) + deno publish --dry-run diff --git a/tests/specs/init/lib/test.out b/tests/specs/init/lib/test.out new file mode 100644 index 000000000..0b225a52b --- /dev/null +++ b/tests/specs/init/lib/test.out @@ -0,0 +1,14 @@ +Download http://127.0.0.1:4250/@std/assert/meta.json +Download http://127.0.0.1:4250/@std/assert/0.220.1_meta.json +[UNORDERED_START] +Download http://127.0.0.1:4250/@std/assert/0.220.1/mod.ts +Download http://127.0.0.1:4250/@std/assert/0.220.1/assert_equals.ts +Download http://127.0.0.1:4250/@std/assert/0.220.1/assert.ts +Download http://127.0.0.1:4250/@std/assert/0.220.1/fail.ts +[UNORDERED_END] +Check file:///[WILDLINE]/mod_test.ts +running 1 test from ./mod_test.ts +addTest ... ok ([WILDLINE]) + +ok | 1 passed | 0 failed ([WILDLINE]) + |