2024-01-01 14:58:21 -05:00
|
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2022-08-19 19:37:05 -04:00
|
|
|
|
|
|
|
|
|
use crate::args::InitFlags;
|
2022-12-08 00:34:28 -05:00
|
|
|
|
use crate::colors;
|
2022-08-29 14:19:54 -04:00
|
|
|
|
use deno_core::anyhow::Context;
|
|
|
|
|
use deno_core::error::AnyError;
|
2024-07-09 21:13:34 -04:00
|
|
|
|
use deno_core::serde_json::json;
|
2022-09-02 11:59:36 -04:00
|
|
|
|
use log::info;
|
2022-08-19 19:37:05 -04:00
|
|
|
|
use std::io::Write;
|
|
|
|
|
use std::path::Path;
|
|
|
|
|
|
2024-03-11 23:48:00 -04:00
|
|
|
|
pub fn init_project(init_flags: InitFlags) -> Result<(), AnyError> {
|
2022-08-19 19:37:05 -04:00
|
|
|
|
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
|
|
|
|
|
};
|
|
|
|
|
|
2024-08-08 12:54:39 -04:00
|
|
|
|
if init_flags.serve {
|
|
|
|
|
create_file(
|
|
|
|
|
&dir,
|
|
|
|
|
"main.ts",
|
|
|
|
|
r#"import { type Route, route, serveDir } from "@std/http";
|
|
|
|
|
|
|
|
|
|
const routes: Route[] = [
|
|
|
|
|
{
|
|
|
|
|
pattern: new URLPattern({ pathname: "/" }),
|
|
|
|
|
handler: () => new Response("Home page"),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
pattern: new URLPattern({ pathname: "/users/:id" }),
|
|
|
|
|
handler: (_req, _info, params) => new Response(params?.pathname.groups.id),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
pattern: new URLPattern({ pathname: "/static/*" }),
|
2024-09-02 19:01:36 -04:00
|
|
|
|
handler: (req) => serveDir(req),
|
2024-08-08 12:54:39 -04:00
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
function defaultHandler(_req: Request) {
|
|
|
|
|
return new Response("Not found", { status: 404 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handler = route(routes, defaultHandler);
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
fetch(req) {
|
|
|
|
|
return handler(req);
|
|
|
|
|
},
|
|
|
|
|
} satisfies Deno.ServeDefaultExport;
|
|
|
|
|
"#,
|
|
|
|
|
)?;
|
|
|
|
|
create_file(
|
|
|
|
|
&dir,
|
|
|
|
|
"main_test.ts",
|
|
|
|
|
r#"import { assertEquals } from "@std/assert";
|
|
|
|
|
import server from "./main.ts";
|
|
|
|
|
|
|
|
|
|
Deno.test(async function serverFetch() {
|
|
|
|
|
const req = new Request("https://deno.land");
|
|
|
|
|
const res = await server.fetch(req);
|
|
|
|
|
assertEquals(await res.text(), "Home page");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Deno.test(async function serverFetchNotFound() {
|
|
|
|
|
const req = new Request("https://deno.land/404");
|
|
|
|
|
const res = await server.fetch(req);
|
|
|
|
|
assertEquals(res.status, 404);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Deno.test(async function serverFetchUsers() {
|
|
|
|
|
const req = new Request("https://deno.land/users/123");
|
|
|
|
|
const res = await server.fetch(req);
|
|
|
|
|
assertEquals(await res.text(), "123");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Deno.test(async function serverFetchStatic() {
|
2024-09-02 19:01:36 -04:00
|
|
|
|
const req = new Request("https://deno.land/static/hello.js");
|
2024-08-08 12:54:39 -04:00
|
|
|
|
const res = await server.fetch(req);
|
2024-09-02 19:01:36 -04:00
|
|
|
|
assertEquals(await res.text(), 'console.log("Hello, world!");\n');
|
|
|
|
|
assertEquals(res.headers.get("content-type"), "text/javascript; charset=UTF-8");
|
2024-08-08 12:54:39 -04:00
|
|
|
|
});
|
|
|
|
|
"#,
|
|
|
|
|
)?;
|
|
|
|
|
|
2024-09-02 19:01:36 -04:00
|
|
|
|
let static_dir = dir.join("static");
|
|
|
|
|
std::fs::create_dir_all(&static_dir)?;
|
|
|
|
|
create_file(
|
|
|
|
|
&static_dir,
|
|
|
|
|
"hello.js",
|
|
|
|
|
r#"console.log("Hello, world!");
|
|
|
|
|
"#,
|
|
|
|
|
)?;
|
|
|
|
|
|
2024-08-08 12:54:39 -04:00
|
|
|
|
create_json_file(
|
|
|
|
|
&dir,
|
|
|
|
|
"deno.json",
|
|
|
|
|
&json!({
|
|
|
|
|
"tasks": {
|
|
|
|
|
"dev": "deno serve --watch -R main.ts",
|
|
|
|
|
},
|
|
|
|
|
"imports": {
|
|
|
|
|
"@std/assert": "jsr:@std/assert@1",
|
|
|
|
|
"@std/http": "jsr:@std/http@1",
|
|
|
|
|
}
|
|
|
|
|
}),
|
|
|
|
|
)?;
|
|
|
|
|
} else if init_flags.lib {
|
2024-07-09 21:13:34 -04:00
|
|
|
|
// 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",
|
2024-07-14 13:22:43 -04:00
|
|
|
|
r#"import { assertEquals } from "@std/assert";
|
2024-07-09 21:13:34 -04:00
|
|
|
|
import { add } from "./mod.ts";
|
|
|
|
|
|
|
|
|
|
Deno.test(function addTest() {
|
|
|
|
|
assertEquals(add(2, 3), 5);
|
|
|
|
|
});
|
|
|
|
|
"#,
|
|
|
|
|
)?;
|
|
|
|
|
|
|
|
|
|
create_json_file(
|
|
|
|
|
&dir,
|
|
|
|
|
"deno.json",
|
|
|
|
|
&json!({
|
|
|
|
|
"name": project_name,
|
2024-07-14 13:22:43 -04:00
|
|
|
|
"version": "0.1.0",
|
2024-08-08 10:28:18 -04:00
|
|
|
|
"exports": "./mod.ts",
|
2024-07-09 21:13:34 -04:00
|
|
|
|
"tasks": {
|
|
|
|
|
"dev": "deno test --watch mod.ts"
|
2024-07-14 13:22:43 -04:00
|
|
|
|
},
|
2024-08-16 09:12:52 -04:00
|
|
|
|
"license": "MIT",
|
2024-07-14 13:22:43 -04:00
|
|
|
|
"imports": {
|
|
|
|
|
"@std/assert": "jsr:@std/assert@1"
|
|
|
|
|
},
|
2024-07-09 21:13:34 -04:00
|
|
|
|
}),
|
|
|
|
|
)?;
|
|
|
|
|
} else {
|
|
|
|
|
create_file(
|
|
|
|
|
&dir,
|
|
|
|
|
"main.ts",
|
|
|
|
|
r#"export function add(a: number, b: number): number {
|
|
|
|
|
return a + b;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-12 15:04:27 -04:00
|
|
|
|
// Learn more at https://docs.deno.com/runtime/manual/examples/module_metadata#concepts
|
2024-07-09 21:13:34 -04:00
|
|
|
|
if (import.meta.main) {
|
|
|
|
|
console.log("Add 2 + 3 =", add(2, 3));
|
|
|
|
|
}
|
|
|
|
|
"#,
|
|
|
|
|
)?;
|
|
|
|
|
create_file(
|
|
|
|
|
&dir,
|
|
|
|
|
"main_test.ts",
|
2024-07-14 13:22:43 -04:00
|
|
|
|
r#"import { assertEquals } from "@std/assert";
|
2024-07-09 21:13:34 -04:00
|
|
|
|
import { add } from "./main.ts";
|
2022-08-19 19:37:05 -04:00
|
|
|
|
|
2024-07-09 21:13:34 -04:00
|
|
|
|
Deno.test(function addTest() {
|
|
|
|
|
assertEquals(add(2, 3), 5);
|
|
|
|
|
});
|
|
|
|
|
"#,
|
|
|
|
|
)?;
|
|
|
|
|
|
|
|
|
|
create_json_file(
|
|
|
|
|
&dir,
|
|
|
|
|
"deno.json",
|
|
|
|
|
&json!({
|
|
|
|
|
"tasks": {
|
|
|
|
|
"dev": "deno run --watch main.ts"
|
2024-07-14 13:22:43 -04:00
|
|
|
|
},
|
|
|
|
|
"imports": {
|
|
|
|
|
"@std/assert": "jsr:@std/assert@1"
|
2024-07-09 21:13:34 -04:00
|
|
|
|
}
|
|
|
|
|
}),
|
|
|
|
|
)?;
|
|
|
|
|
}
|
2022-12-08 00:34:28 -05:00
|
|
|
|
|
|
|
|
|
info!("✅ {}", colors::green("Project initialized"));
|
|
|
|
|
info!("");
|
|
|
|
|
info!("{}", colors::gray("Run these commands to get started"));
|
|
|
|
|
info!("");
|
2022-08-19 19:37:05 -04:00
|
|
|
|
if let Some(dir) = init_flags.dir {
|
2022-09-02 11:59:36 -04:00
|
|
|
|
info!(" cd {}", dir);
|
2022-12-08 00:34:28 -05:00
|
|
|
|
info!("");
|
2022-08-19 19:37:05 -04:00
|
|
|
|
}
|
2024-08-08 12:54:39 -04:00
|
|
|
|
if init_flags.serve {
|
|
|
|
|
info!(" {}", colors::gray("# Run the server"));
|
|
|
|
|
info!(" deno serve -R main.ts");
|
|
|
|
|
info!("");
|
|
|
|
|
info!(
|
|
|
|
|
" {}",
|
|
|
|
|
colors::gray("# Run the server and watch for file changes")
|
|
|
|
|
);
|
|
|
|
|
info!(" deno task dev");
|
|
|
|
|
info!("");
|
|
|
|
|
info!(" {}", colors::gray("# Run the tests"));
|
2024-09-02 19:01:36 -04:00
|
|
|
|
info!(" deno test -R");
|
2024-08-08 12:54:39 -04:00
|
|
|
|
} else if init_flags.lib {
|
2024-07-09 21:13:34 -04:00
|
|
|
|
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");
|
|
|
|
|
}
|
2022-08-19 19:37:05 -04:00
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2024-07-09 21:13:34 -04:00
|
|
|
|
|
|
|
|
|
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(())
|
|
|
|
|
}
|
|
|
|
|
}
|