Skip to content

Commit 2fd3c20

Browse files
committed
Use @clack/prompts for nicer prompts
1 parent b70fe74 commit 2fd3c20

File tree

3 files changed

+145
-105
lines changed

3 files changed

+145
-105
lines changed

index.mjs

Lines changed: 73 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,121 @@
11
#!/usr/bin/env node
22

3-
import c from "ansi-colors";
4-
import enquirer from "enquirer";
3+
import * as p from "@clack/prompts";
54
import path from "path";
65
import fs from "fs";
76
import { fileURLToPath } from "url";
8-
import { execSync } from "child_process";
7+
import { exec } from "child_process";
8+
import { promisify } from "util";
9+
import c from "picocolors";
910

1011
// Get __dirname in an ES6 module
1112
const __filename = fileURLToPath(import.meta.url);
1213
const __dirname = path.dirname(__filename);
1314

1415
const templates = [
1516
{
16-
name: "rescript-template-vite",
17-
message: "Vite",
17+
value: "rescript-template-vite",
18+
label: "Vite",
1819
hint: "Opinionated boilerplate for Vite, Tailwind and ReScript",
1920
},
2021
{
21-
name: "rescript-template-nextjs",
22-
message: "Next.js",
22+
value: "rescript-template-nextjs",
23+
label: "Next.js",
2324
hint: "Opinionated boilerplate for Next.js, Tailwind and ReScript",
2425
},
2526
{
26-
name: "rescript-template-basic",
27-
message: "Basic",
27+
value: "rescript-template-basic",
28+
label: "Basic",
2829
hint: "Command line hello world app",
2930
},
3031
];
3132

33+
function checkCancel(value) {
34+
if (p.isCancel(value)) {
35+
p.cancel("Project creation cancelled.");
36+
process.exit(0);
37+
}
38+
}
39+
3240
function validateProjectName(projectName) {
3341
const packageNameRegExp = /^[a-z0-9-]+$/;
3442

35-
if (packageNameRegExp.test(projectName)) {
36-
return true;
37-
} else {
43+
if (projectName.trim().length === 0) {
44+
return "Project name must not be empty.";
45+
}
46+
47+
if (!packageNameRegExp.test(projectName)) {
3848
return "Project name may only contain lower case letters, numbers and hyphens.";
3949
}
40-
}
4150

42-
async function getParams() {
43-
return await enquirer.prompt([
44-
{
45-
type: "input",
46-
name: "projectName",
47-
message: "What is the name of your new project?",
48-
initial: process.argv[2] || "my-rescript-app",
49-
validate: validateProjectName,
50-
},
51-
{
52-
type: "select",
53-
name: "templateName",
54-
message: "Select a template",
55-
choices: templates,
56-
},
57-
]);
51+
const projectPath = path.join(process.cwd(), projectName);
52+
if (fs.existsSync(projectPath)) {
53+
return `The folder ${projectName} already exist in the current directory.`;
54+
}
5855
}
5956

60-
function replaceLineInFile(filename, search, replace) {
61-
const contents = fs.readFileSync(filename, "utf8");
57+
async function replaceLineInFile(filename, search, replace) {
58+
const contents = await fs.promises.readFile(filename, "utf8");
6259
const replaced = contents.replace(search, replace);
63-
fs.writeFileSync(filename, replaced, "utf8");
64-
}
65-
66-
function setProjectName(templateName, projectName) {
67-
replaceLineInFile("package.json", `"name": "${templateName}"`, `"name": "${projectName}"`);
68-
replaceLineInFile("bsconfig.json", `"name": "${templateName}"`, `"name": "${projectName}"`);
69-
}
70-
71-
function installPackages() {
72-
console.log("Installing packages. This might take a couple of seconds...");
73-
74-
execSync("npm install");
75-
console.log(`Packages installed.`);
76-
}
77-
78-
function initGitRepo() {
79-
execSync("git init");
80-
console.log(`Initialized a git repository.`);
60+
await fs.promises.writeFile(filename, replaced, "utf8");
8161
}
8262

83-
function logSuccess(projectName, projectPath) {
84-
console.log(`\n${c.green("✔ Success!")} Created ${projectName} at ${c.green(projectPath)}.`);
85-
86-
console.log("\nNext steps:");
87-
console.log(`• ${c.bold("cd " + projectName)}`);
88-
console.log(`• ${c.bold("npm run res:dev")} to start the ReScript compiler in watch mode.`);
89-
console.log(`• See ${c.bold("README.md")} for more information.`);
90-
console.log(`\n${c.bold("Happy hacking!")}`);
63+
async function setProjectName(templateName, projectName) {
64+
await replaceLineInFile("package.json", `"name": "${templateName}"`, `"name": "${projectName}"`);
65+
await replaceLineInFile("bsconfig.json", `"name": "${templateName}"`, `"name": "${projectName}"`);
9166
}
9267

9368
async function main() {
94-
console.log(c.cyan(`Welcome to ${c.red("create-rescript-app")}!`));
95-
console.log("This tool will help you set up your new ReScript project quickly.\n");
96-
97-
const { projectName, templateName } = await getParams();
98-
99-
console.log(); // newline
69+
console.clear();
70+
71+
p.intro(`${c.bgCyan(c.black(" create-rescript-app "))}`);
72+
73+
const projectName = await p.text({
74+
message: "What is the name of your new ReScript project?",
75+
placeholder: process.argv[2] || "my-rescript-app",
76+
validate: validateProjectName,
77+
});
78+
checkCancel(projectName);
79+
80+
const templateName = await p.select({
81+
message: "Select a template",
82+
options: templates,
83+
});
84+
checkCancel(templateName);
85+
86+
const shouldContinue = await p.confirm({
87+
message: `Your new ReScript project ${c.cyan(projectName)} will now be created. Continue?`,
88+
});
89+
checkCancel(shouldContinue);
90+
91+
if (!shouldContinue) {
92+
p.outro("No project created.");
93+
process.exit(0);
94+
}
10095

10196
const templatePath = path.join(__dirname, "templates", templateName);
10297
const projectPath = path.join(process.cwd(), projectName);
10398

104-
if (fs.existsSync(projectPath)) {
105-
console.log(`The folder ${c.red(projectName)} already exist in the current directory.`);
106-
console.log("Please try again with another name.");
107-
process.exit(1);
108-
}
109-
110-
console.log(
111-
"Creating a new ReScript project",
112-
`in ${c.green(projectPath)} with template ${c.cyan(templateName)}.`
113-
);
99+
const s = p.spinner();
100+
s.start("Creating project...");
114101

115102
try {
116-
fs.cpSync(templatePath, projectPath, { recursive: true });
103+
await fs.promises.cp(templatePath, projectPath, { recursive: true });
117104
process.chdir(projectPath);
118105

119-
setProjectName(templateName, projectName);
120-
installPackages();
121-
initGitRepo();
122-
logSuccess(projectName, projectPath);
106+
await setProjectName(templateName, projectName);
107+
await promisify(exec)("npm install");
108+
await promisify(exec)("git init");
109+
s.stop("Project created.");
110+
111+
p.note(`cd ${projectName}\nnpm run res:dev`, "Next steps");
112+
p.outro(`Happy hacking! See ${c.cyan("README.md")} for more information.`);
123113
} catch (error) {
124-
console.log(error);
114+
s.stop("Installation error.");
115+
116+
p.outro(`Project creation failed.`);
117+
118+
p.log.error(error);
125119
}
126120
}
127121

package-lock.json

Lines changed: 71 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
"templates"
1818
],
1919
"dependencies": {
20-
"ansi-colors": "^4.1.3",
21-
"enquirer": "^2.3.6"
20+
"@clack/prompts": "^0.6.0"
2221
},
2322
"repository": {
2423
"type": "git",

0 commit comments

Comments
 (0)