-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcli.ts
131 lines (116 loc) · 3.78 KB
/
cli.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import inquirer from "inquirer";
import fs from "node:fs";
import path from "node:path";
import chalk from "chalk";
import ora from "ora";
import figlet from "figlet";
import gradient from "gradient-string";
import boxen from "boxen";
import { z } from "zod";
// Typesafe input validation using Zod
const YearSchema = z.string().regex(/^\d{4}$/, "Please enter a valid year.");
const DaySchema = z.string().regex(/^(0?[1-9]|1[0-9]|2[0-5])$/, "Please enter a valid day between 1 and 25.");
const printBanner = (): void => {
console.log(gradient.vice(figlet.textSync("AOC CLI!", { horizontalLayout: "default" })));
console.log(
boxen(chalk.green("Welcome to the Advent of Code Challenge CLI!"), {
padding: 1,
margin: 1,
borderStyle: "round",
borderColor: "green",
})
);
};
const promptYearAndDay = async (): Promise<{ year: string; day: string }> => {
const yearPrompt = await inquirer.prompt([
{
type: "input",
name: "year",
message: "Enter the challenge year:",
default: new Date().getFullYear().toString(),
validate: (input: string) => {
const result = YearSchema.safeParse(input);
return result.success ? true : chalk.red(result.error.issues[0].message);
},
},
]);
const dayPrompt = await inquirer.prompt([
{
type: "input",
name: "day",
message: "Enter the challenge day (1-25):",
default: "1",
validate: (input: string) => {
const result = DaySchema.safeParse(input);
return result.success ? true : chalk.red(result.error.issues[0].message);
},
},
]);
return { year: yearPrompt.year, day: dayPrompt.day };
};
const confirmCreation = async (year: string, day: string): Promise<boolean> => {
const confirmPrompt = await inquirer.prompt([
{
type: "confirm",
name: "confirm",
message: `Create a new solution file for ${chalk.bold(year)}/day${chalk.bold(day)}?`,
},
]);
return confirmPrompt.confirm;
};
const createDirectories = (yearPath: string, dayPath: string): void => {
if (!fs.existsSync(yearPath)) {
fs.mkdirSync(yearPath);
}
if (!fs.existsSync(dayPath)) {
fs.mkdirSync(dayPath);
}
};
const copyTemplate = (templatePath: string, dayPath: string): void => {
const spinner = ora("Copying template files...").start();
try {
const copyDirWithSubDirs = (src: string, dest: string): void => {
fs.mkdirSync(dest, { recursive: true });
const entries = fs.readdirSync(src, { withFileTypes: true });
for (const entry of entries) {
const srcPath = path.join(src, entry.name);
const destPath = path.join(dest, entry.name);
if (entry.isDirectory()) {
copyDirWithSubDirs(srcPath, destPath);
} else {
fs.copyFileSync(srcPath, destPath);
}
}
};
copyDirWithSubDirs(templatePath, dayPath);
spinner.succeed("Template files copied successfully!");
} catch (error) {
spinner.fail("Failed to copy template files.");
console.error(chalk.red("Error:", error));
process.exit(1);
}
};
const main = async (): Promise<void> => {
printBanner();
const { year, day } = await promptYearAndDay();
const confirm = await confirmCreation(year, day);
if (!confirm) {
console.log(chalk.yellow("Operation cancelled."));
process.exit(0);
}
const templatePath = path.join(__dirname, "template");
const yearPath = path.join(__dirname, year);
const dayPath = path.join(yearPath, `day ${day}`);
createDirectories(yearPath, dayPath);
copyTemplate(templatePath, dayPath);
console.log(
boxen(chalk.green(`New solution file created at ${chalk.bold(`${yearPath}/day ${day}`)}\nHappy coding!`), {
padding: 1,
margin: 1,
borderStyle: "round",
borderColor: "green",
})
);
process.exit(0);
};
main();