|
1 | 1 | const { mkdir } = require("fs/promises"); |
2 | 2 | const { join } = require("path"); |
3 | 3 | const { camelCase } = require("case-anything"); |
4 | | -const { createExerciseDirectoryName } = require("./generators/helpers"); |
| 4 | +const { |
| 5 | + createExerciseDirectoryName, |
| 6 | + getDirsWithExercises, |
| 7 | +} = require("./generators/helpers"); |
5 | 8 | const { writeReadme } = require("./generators/writeReadme"); |
6 | 9 | const { writeExercise } = require("./generators/writeExercise"); |
7 | 10 | const { writeExerciseSpec } = require("./generators/writeExerciseSpec"); |
8 | 11 |
|
| 12 | +/** |
| 13 | + * @typedef {import('plop').NodePlopAPI} Plop |
| 14 | + * @param {Plop} plop |
| 15 | + */ |
9 | 16 | module.exports = function (plop) { |
10 | | - plop.setActionType("createExercise", async function (answers) { |
11 | | - const { exerciseName } = answers; |
12 | | - if (!exerciseName) { |
13 | | - throw new Error( |
14 | | - `Invalid exerciseName. Expected: valid string. Actual: "${exerciseName}"` |
| 17 | + const NEW_DIR_OPTION = "<Make new directory>"; |
| 18 | + |
| 19 | + plop.setActionType( |
| 20 | + "createExercise", |
| 21 | + async function ({ pathForExercise, exerciseName }) { |
| 22 | + if (!exerciseName) { |
| 23 | + throw new Error( |
| 24 | + `Invalid exerciseName. Expected: valid string. Actual: "${exerciseName}"`, |
| 25 | + ); |
| 26 | + } else if (!pathForExercise.length) { |
| 27 | + throw new Error( |
| 28 | + "The new exercise cannot be placed in the project root", |
| 29 | + ); |
| 30 | + } |
| 31 | + |
| 32 | + const camelExerciseName = camelCase(exerciseName); |
| 33 | + const exerciseDirectoryName = await createExerciseDirectoryName( |
| 34 | + camelExerciseName, |
| 35 | + join(...pathForExercise), |
15 | 36 | ); |
16 | | - } |
17 | | - |
18 | | - const camelExerciseName = camelCase(exerciseName); |
19 | | - const exerciseDirectoryName = await createExerciseDirectoryName( |
20 | | - camelExerciseName |
21 | | - ); |
22 | | - const basePath = join("./", exerciseDirectoryName); |
23 | | - const solutionPath = join(basePath, "solution"); |
24 | | - |
25 | | - await mkdir(basePath); |
26 | | - await mkdir(solutionPath); |
27 | | - |
28 | | - await writeReadme(basePath); |
29 | | - await writeExercise(basePath); |
30 | | - await writeExercise(solutionPath); |
31 | | - await writeExerciseSpec(basePath); |
32 | | - await writeExerciseSpec(solutionPath); |
33 | | - }); |
| 37 | + const basePath = join( |
| 38 | + process.cwd(), |
| 39 | + ...pathForExercise, |
| 40 | + exerciseDirectoryName, |
| 41 | + ); |
| 42 | + const solutionPath = join(basePath, "solution"); |
| 43 | + |
| 44 | + await mkdir(basePath, { recursive: true }); |
| 45 | + await mkdir(solutionPath); |
| 46 | + |
| 47 | + await writeReadme(basePath); |
| 48 | + await writeExercise(basePath); |
| 49 | + await writeExercise(solutionPath); |
| 50 | + await writeExerciseSpec(basePath); |
| 51 | + await writeExerciseSpec(solutionPath); |
| 52 | + }, |
| 53 | + ); |
34 | 54 |
|
35 | 55 | plop.setGenerator("Basic", { |
36 | 56 | description: "Create a basic JavaScript exercise.", |
37 | | - prompts: [ |
38 | | - { |
| 57 | + prompts: async function (inquirer) { |
| 58 | + async function getPathForExercise(dirPath = []) { |
| 59 | + const exerciseDirs = await getDirsWithExercises(dirPath.join("/")); |
| 60 | + |
| 61 | + // Will only be empty when entering a new dir on a recursive call |
| 62 | + // Recursive call only happens when new dir required which can bypass this question |
| 63 | + const { dir } = exerciseDirs.length |
| 64 | + ? await inquirer.prompt({ |
| 65 | + type: "list", |
| 66 | + name: "dir", |
| 67 | + message: "Which directory should this exercise go in?", |
| 68 | + choices: [NEW_DIR_OPTION, ...exerciseDirs], |
| 69 | + }) |
| 70 | + : { dir: NEW_DIR_OPTION }; |
| 71 | + |
| 72 | + if (dir === NEW_DIR_OPTION) { |
| 73 | + const { newDirName } = await inquirer.prompt({ |
| 74 | + type: "input", |
| 75 | + name: "newDirName", |
| 76 | + message: "What is the name of the new directory?", |
| 77 | + }); |
| 78 | + dirPath.push(newDirName); |
| 79 | + } else { |
| 80 | + dirPath.push(dir); |
| 81 | + } |
| 82 | + |
| 83 | + const { needMoreDirs } = await inquirer.prompt({ |
| 84 | + type: "confirm", |
| 85 | + name: "needMoreDirs", |
| 86 | + message: "Does this exercise need to be nested in a subdirectory?", |
| 87 | + }); |
| 88 | + |
| 89 | + return needMoreDirs ? await getPathForExercise(dirPath) : dirPath; |
| 90 | + } |
| 91 | + |
| 92 | + const pathForExercise = await getPathForExercise(); |
| 93 | + const { exerciseName } = await inquirer.prompt({ |
39 | 94 | type: "input", |
40 | 95 | name: "exerciseName", |
41 | | - message: "What is the name of the exercise? (camelCase)", |
42 | | - }, |
43 | | - ], |
| 96 | + message: "What is the name of the new exercise (in camelCase)?", |
| 97 | + }); |
| 98 | + |
| 99 | + return { pathForExercise, exerciseName }; |
| 100 | + }, |
44 | 101 | actions: [{ type: "createExercise" }], |
45 | 102 | }); |
46 | 103 | }; |
0 commit comments