Skip to content

Commit

Permalink
feat(cli): deno init --lib (denoland#22499)
Browse files Browse the repository at this point in the history
Closes denoland#22287

Co-authored-by: Asher Gomez <[email protected]>
Co-authored-by: David Sherret <[email protected]>
  • Loading branch information
3 people committed Jul 10, 2024
1 parent 9776a13 commit ff5163a
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 68 deletions.
54 changes: 47 additions & 7 deletions cli/args/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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),
)
})
}

Expand Down Expand Up @@ -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"),
});
}

Expand Down Expand Up @@ -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()
}
);
Expand All @@ -9764,6 +9776,7 @@ mod tests {
Flags {
subcommand: DenoSubcommand::Init(InitFlags {
dir: Some(String::from("foo")),
lib: false
}),
..Flags::default()
}
Expand All @@ -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]
Expand Down
176 changes: 134 additions & 42 deletions cli/tools/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.")?;
Expand All @@ -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!("");
Expand All @@ -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(())
}
}
5 changes: 0 additions & 5 deletions cli/tools/init/templates/deno.json

This file was deleted.

8 changes: 0 additions & 8 deletions cli/tools/init/templates/main.ts

This file was deleted.

6 changes: 0 additions & 6 deletions cli/tools/init/templates/main_test.ts

This file was deleted.

16 changes: 16 additions & 0 deletions tests/specs/init/lib/__test__.jsonc
Original file line number Diff line number Diff line change
@@ -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
}]
}
7 changes: 7 additions & 0 deletions tests/specs/init/lib/dry_publish.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Check file:https:///[WILDLINE]/mod.ts
Checking for slow types in the public API...
Check file:https:///[WILDLINE]/mod.ts
error: Failed preparing 'project'.

Caused by:
Invalid package name, use '@<scope_name>/<package_name> format
14 changes: 14 additions & 0 deletions tests/specs/init/lib/init.out
Original file line number Diff line number Diff line change
@@ -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
14 changes: 14 additions & 0 deletions tests/specs/init/lib/test.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Download https://127.0.0.1:4250/@std/assert/meta.json
Download https://127.0.0.1:4250/@std/assert/0.220.1_meta.json
[UNORDERED_START]
Download https://127.0.0.1:4250/@std/assert/0.220.1/mod.ts
Download https://127.0.0.1:4250/@std/assert/0.220.1/assert_equals.ts
Download https://127.0.0.1:4250/@std/assert/0.220.1/assert.ts
Download https://127.0.0.1:4250/@std/assert/0.220.1/fail.ts
[UNORDERED_END]
Check file:https:///[WILDLINE]/mod_test.ts
running 1 test from ./mod_test.ts
addTest ... ok ([WILDLINE])

ok | 1 passed | 0 failed ([WILDLINE])

0 comments on commit ff5163a

Please sign in to comment.