task-script-support-cli 0.1.1 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/assets/yargs-template/task-runner/.prettierignore +3 -0
  2. package/assets/yargs-template/task-runner/.prettierrc +1 -0
  3. package/assets/yargs-template/task-runner/.vscode/launch.json +34 -0
  4. package/assets/yargs-template/task-runner/eslint.config.ts +11 -0
  5. package/assets/yargs-template/task-runner/install-link.sh +21 -0
  6. package/assets/yargs-template/task-runner/package-lock.json +3387 -0
  7. package/assets/yargs-template/task-runner/package.json +51 -0
  8. package/assets/yargs-template/task-runner/src/commands/verify.ts +10 -0
  9. package/assets/yargs-template/task-runner/src/index.ts +46 -0
  10. package/assets/yargs-template/task-runner/src/services/banner-service.ts +38 -0
  11. package/assets/yargs-template/task-runner/src/services/log-service.ts +48 -0
  12. package/assets/yargs-template/task-runner/src/services/spawn-service.ts +87 -0
  13. package/assets/yargs-template/task-runner/src/services/util-service.ts +28 -0
  14. package/assets/yargs-template/task-runner/src/tasks/check-env.ts +49 -0
  15. package/assets/yargs-template/task-runner/src/tasks/log-state.ts +22 -0
  16. package/assets/yargs-template/task-runner/src/tasks/print-banner.ts +73 -0
  17. package/assets/yargs-template/task-runner/src/types/process.ts +9 -0
  18. package/assets/yargs-template/task-runner/src/types/state.ts +31 -0
  19. package/assets/yargs-template/task-runner/src/wrappers/app-task.ts +42 -0
  20. package/assets/yargs-template/task-runner/src/wrappers/command.ts +20 -0
  21. package/assets/yargs-template/task-runner/src/wrappers/dependencies.ts +24 -0
  22. package/assets/yargs-template/task-runner/task-runner +3 -0
  23. package/assets/yargs-template/task-runner/templater.sh +57 -0
  24. package/assets/yargs-template/task-runner/tests/commands/verify.test.ts +42 -0
  25. package/assets/yargs-template/task-runner/tests/services/spawn-service.test.ts +132 -0
  26. package/assets/yargs-template/task-runner/tests/services/util-service.test.ts +36 -0
  27. package/assets/yargs-template/task-runner/tests/setup.ts +1 -0
  28. package/assets/yargs-template/task-runner/tests/tasks/check-env.test.ts +30 -0
  29. package/assets/yargs-template/task-runner/tsconfig.json +27 -0
  30. package/assets/yargs-template/task-runner/vitest.config.ts +14 -0
  31. package/dist/assets/yargs-template/task-runner/.prettierignore +3 -0
  32. package/dist/assets/yargs-template/task-runner/.prettierrc +1 -0
  33. package/dist/assets/yargs-template/task-runner/.vscode/launch.json +34 -0
  34. package/dist/assets/yargs-template/task-runner/eslint.config.ts +11 -0
  35. package/dist/assets/yargs-template/task-runner/install-link.sh +21 -0
  36. package/dist/assets/yargs-template/task-runner/package-lock.json +3387 -0
  37. package/dist/assets/yargs-template/task-runner/package.json +51 -0
  38. package/dist/assets/yargs-template/task-runner/src/commands/verify.ts +10 -0
  39. package/dist/assets/yargs-template/task-runner/src/index.ts +46 -0
  40. package/dist/assets/yargs-template/task-runner/src/services/banner-service.ts +38 -0
  41. package/dist/assets/yargs-template/task-runner/src/services/log-service.ts +48 -0
  42. package/dist/assets/yargs-template/task-runner/src/services/spawn-service.ts +87 -0
  43. package/dist/assets/yargs-template/task-runner/src/services/util-service.ts +28 -0
  44. package/dist/assets/yargs-template/task-runner/src/tasks/check-env.ts +49 -0
  45. package/dist/assets/yargs-template/task-runner/src/tasks/log-state.ts +22 -0
  46. package/dist/assets/yargs-template/task-runner/src/tasks/print-banner.ts +73 -0
  47. package/dist/assets/yargs-template/task-runner/src/types/process.ts +9 -0
  48. package/dist/assets/yargs-template/task-runner/src/types/state.ts +31 -0
  49. package/dist/assets/yargs-template/task-runner/src/wrappers/app-task.ts +42 -0
  50. package/dist/assets/yargs-template/task-runner/src/wrappers/command.ts +20 -0
  51. package/dist/assets/yargs-template/task-runner/src/wrappers/dependencies.ts +24 -0
  52. package/dist/assets/yargs-template/task-runner/task-runner +3 -0
  53. package/dist/assets/yargs-template/task-runner/templater.sh +57 -0
  54. package/dist/assets/yargs-template/task-runner/tests/commands/verify.test.ts +42 -0
  55. package/dist/assets/yargs-template/task-runner/tests/services/spawn-service.test.ts +132 -0
  56. package/dist/assets/yargs-template/task-runner/tests/services/util-service.test.ts +36 -0
  57. package/dist/assets/yargs-template/task-runner/tests/setup.ts +1 -0
  58. package/dist/assets/yargs-template/task-runner/tests/tasks/check-env.test.ts +30 -0
  59. package/dist/assets/yargs-template/task-runner/tsconfig.json +27 -0
  60. package/dist/assets/yargs-template/task-runner/vitest.config.ts +14 -0
  61. package/dist/package.json +9 -3
  62. package/dist/src/commands/about.d.ts +2 -2
  63. package/dist/src/commands/about.d.ts.map +1 -1
  64. package/dist/src/commands/about.js +2 -2
  65. package/dist/src/commands/about.js.map +1 -1
  66. package/dist/src/commands/configure.d.ts +8 -0
  67. package/dist/src/commands/configure.d.ts.map +1 -0
  68. package/dist/src/commands/configure.js +25 -0
  69. package/dist/src/commands/configure.js.map +1 -0
  70. package/dist/src/commands/gen.d.ts +9 -7
  71. package/dist/src/commands/gen.d.ts.map +1 -1
  72. package/dist/src/commands/gen.js +10 -6
  73. package/dist/src/commands/gen.js.map +1 -1
  74. package/dist/src/commands/new.d.ts +8 -0
  75. package/dist/src/commands/new.d.ts.map +1 -0
  76. package/dist/src/commands/new.js +25 -0
  77. package/dist/src/commands/new.js.map +1 -0
  78. package/dist/src/index.js +10 -0
  79. package/dist/src/index.js.map +1 -1
  80. package/dist/src/services/cache-service.d.ts +11 -0
  81. package/dist/src/services/cache-service.d.ts.map +1 -0
  82. package/dist/src/services/cache-service.js +64 -0
  83. package/dist/src/services/cache-service.js.map +1 -0
  84. package/dist/src/services/file-service.d.ts +8 -2
  85. package/dist/src/services/file-service.d.ts.map +1 -1
  86. package/dist/src/services/file-service.js +38 -6
  87. package/dist/src/services/file-service.js.map +1 -1
  88. package/dist/src/services/log-service.d.ts +1 -0
  89. package/dist/src/services/log-service.d.ts.map +1 -1
  90. package/dist/src/services/log-service.js +14 -1
  91. package/dist/src/services/log-service.js.map +1 -1
  92. package/dist/src/services/project-service.d.ts +3 -3
  93. package/dist/src/services/project-service.d.ts.map +1 -1
  94. package/dist/src/services/project-service.js +10 -10
  95. package/dist/src/services/project-service.js.map +1 -1
  96. package/dist/src/services/prompt-service.d.ts +34 -0
  97. package/dist/src/services/prompt-service.d.ts.map +1 -0
  98. package/dist/src/services/prompt-service.js +80 -0
  99. package/dist/src/services/prompt-service.js.map +1 -0
  100. package/dist/src/services/spawn-service.d.ts +2 -1
  101. package/dist/src/services/spawn-service.d.ts.map +1 -1
  102. package/dist/src/services/spawn-service.js +16 -1
  103. package/dist/src/services/spawn-service.js.map +1 -1
  104. package/dist/src/services/util-service.d.ts +2 -0
  105. package/dist/src/services/util-service.d.ts.map +1 -1
  106. package/dist/src/services/util-service.js +4 -0
  107. package/dist/src/services/util-service.js.map +1 -1
  108. package/dist/src/tasks/check-env.d.ts +3 -2
  109. package/dist/src/tasks/check-env.d.ts.map +1 -1
  110. package/dist/src/tasks/check-env.js +11 -3
  111. package/dist/src/tasks/check-env.js.map +1 -1
  112. package/dist/src/tasks/configure.d.ts +44 -0
  113. package/dist/src/tasks/configure.d.ts.map +1 -0
  114. package/dist/src/tasks/configure.js +102 -0
  115. package/dist/src/tasks/configure.js.map +1 -0
  116. package/dist/src/tasks/create-new-project.d.ts +26 -0
  117. package/dist/src/tasks/create-new-project.d.ts.map +1 -0
  118. package/dist/src/tasks/create-new-project.js +76 -0
  119. package/dist/src/tasks/create-new-project.js.map +1 -0
  120. package/dist/src/tasks/generate/generate-command.d.ts +35 -0
  121. package/dist/src/tasks/generate/generate-command.d.ts.map +1 -0
  122. package/dist/src/tasks/generate/generate-command.js +128 -0
  123. package/dist/src/tasks/generate/generate-command.js.map +1 -0
  124. package/dist/src/tasks/generate/generate-service.d.ts +30 -0
  125. package/dist/src/tasks/generate/generate-service.d.ts.map +1 -0
  126. package/dist/src/tasks/{generate-service.js → generate/generate-service.js} +32 -31
  127. package/dist/src/tasks/generate/generate-service.js.map +1 -0
  128. package/dist/src/tasks/generate/generate-task.d.ts +30 -0
  129. package/dist/src/tasks/generate/generate-task.d.ts.map +1 -0
  130. package/dist/src/tasks/{generate-task.js → generate/generate-task.js} +32 -31
  131. package/dist/src/tasks/generate/generate-task.js.map +1 -0
  132. package/dist/src/tasks/generate/select-gen-target-name.d.ts +15 -0
  133. package/dist/src/tasks/generate/select-gen-target-name.d.ts.map +1 -0
  134. package/dist/src/tasks/generate/select-gen-target-name.js +59 -0
  135. package/dist/src/tasks/generate/select-gen-target-name.js.map +1 -0
  136. package/dist/src/tasks/generate/select-gen-target.d.ts +14 -0
  137. package/dist/src/tasks/generate/select-gen-target.d.ts.map +1 -0
  138. package/dist/src/tasks/generate/select-gen-target.js +60 -0
  139. package/dist/src/tasks/generate/select-gen-target.js.map +1 -0
  140. package/dist/src/tasks/{print-about-information.d.ts → stdout/print-about-information.d.ts} +1 -1
  141. package/dist/src/tasks/stdout/print-about-information.d.ts.map +1 -0
  142. package/dist/src/tasks/{print-about-information.js → stdout/print-about-information.js} +2 -2
  143. package/dist/src/tasks/stdout/print-about-information.js.map +1 -0
  144. package/dist/src/tasks/stdout/print-banner.d.ts +12 -0
  145. package/dist/src/tasks/stdout/print-banner.d.ts.map +1 -0
  146. package/dist/src/tasks/{print-banner.js → stdout/print-banner.js} +15 -11
  147. package/dist/src/tasks/stdout/print-banner.js.map +1 -0
  148. package/dist/src/tasks/{print-generated-results.d.ts → stdout/print-generated-results.d.ts} +2 -2
  149. package/dist/src/tasks/stdout/print-generated-results.d.ts.map +1 -0
  150. package/dist/src/tasks/{print-generated-results.js → stdout/print-generated-results.js} +16 -12
  151. package/dist/src/tasks/stdout/print-generated-results.js.map +1 -0
  152. package/dist/src/tasks/sync-configuration.d.ts +38 -0
  153. package/dist/src/tasks/sync-configuration.d.ts.map +1 -0
  154. package/dist/src/tasks/sync-configuration.js +121 -0
  155. package/dist/src/tasks/sync-configuration.js.map +1 -0
  156. package/dist/src/tasks/test-task.d.ts +10 -0
  157. package/dist/src/tasks/test-task.d.ts.map +1 -0
  158. package/dist/src/tasks/test-task.js +36 -0
  159. package/dist/src/tasks/test-task.js.map +1 -0
  160. package/dist/src/templates/command.js +2 -2
  161. package/dist/src/templates/command.js.map +1 -1
  162. package/dist/src/templates/service.js +1 -1
  163. package/dist/src/templates/service.js.map +1 -1
  164. package/dist/src/types/process.d.ts +2 -1
  165. package/dist/src/types/process.d.ts.map +1 -1
  166. package/dist/src/types/process.js +1 -0
  167. package/dist/src/types/process.js.map +1 -1
  168. package/dist/src/types/project.d.ts +12 -0
  169. package/dist/src/types/project.d.ts.map +1 -0
  170. package/dist/src/types/project.js +3 -0
  171. package/dist/src/types/project.js.map +1 -0
  172. package/dist/src/types/state.d.ts +5 -1
  173. package/dist/src/types/state.d.ts.map +1 -1
  174. package/dist/src/types/state.js +1 -0
  175. package/dist/src/types/state.js.map +1 -1
  176. package/dist/src/wrappers/app-task.d.ts +1 -0
  177. package/dist/src/wrappers/app-task.d.ts.map +1 -1
  178. package/dist/src/wrappers/app-task.js +4 -0
  179. package/dist/src/wrappers/app-task.js.map +1 -1
  180. package/dist/vitest.config.d.ts +3 -0
  181. package/dist/vitest.config.d.ts.map +1 -0
  182. package/dist/vitest.config.js +16 -0
  183. package/dist/vitest.config.js.map +1 -0
  184. package/package.json +9 -3
  185. package/src/commands/about.ts +2 -2
  186. package/src/commands/configure.ts +10 -0
  187. package/src/commands/gen.ts +10 -6
  188. package/src/commands/new.ts +10 -0
  189. package/src/index.ts +12 -0
  190. package/src/services/cache-service.ts +50 -0
  191. package/src/services/file-service.ts +46 -5
  192. package/src/services/log-service.ts +14 -1
  193. package/src/services/project-service.ts +8 -5
  194. package/src/services/prompt-service.ts +71 -0
  195. package/src/services/spawn-service.ts +15 -1
  196. package/src/services/util-service.ts +5 -0
  197. package/src/tasks/check-env.ts +10 -2
  198. package/src/tasks/configure.ts +105 -0
  199. package/src/tasks/create-new-project.ts +66 -0
  200. package/src/tasks/generate/generate-command.ts +136 -0
  201. package/src/tasks/generate/generate-service.ts +78 -0
  202. package/src/tasks/generate/generate-task.ts +79 -0
  203. package/src/tasks/generate/select-gen-target-name.ts +44 -0
  204. package/src/tasks/generate/select-gen-target.ts +46 -0
  205. package/src/tasks/{print-about-information.ts → stdout/print-about-information.ts} +2 -2
  206. package/src/tasks/stdout/print-banner.ts +41 -0
  207. package/src/tasks/stdout/print-generated-results.ts +37 -0
  208. package/src/tasks/sync-configuration.ts +129 -0
  209. package/src/tasks/test-task.ts +20 -0
  210. package/src/templates/command.ts +2 -2
  211. package/src/templates/service.ts +1 -1
  212. package/src/types/process.ts +1 -0
  213. package/src/types/project.ts +12 -0
  214. package/src/types/state.ts +7 -1
  215. package/src/wrappers/app-task.ts +5 -0
  216. package/tests/index.spec.ts +8 -0
  217. package/tests/setup.ts +1 -0
  218. package/tsconfig.json +1 -1
  219. package/vitest.config.ts +14 -0
  220. package/dist/src/tasks/generate-command.d.ts +0 -23
  221. package/dist/src/tasks/generate-command.d.ts.map +0 -1
  222. package/dist/src/tasks/generate-command.js +0 -91
  223. package/dist/src/tasks/generate-command.js.map +0 -1
  224. package/dist/src/tasks/generate-service.d.ts +0 -26
  225. package/dist/src/tasks/generate-service.d.ts.map +0 -1
  226. package/dist/src/tasks/generate-service.js.map +0 -1
  227. package/dist/src/tasks/generate-task.d.ts +0 -26
  228. package/dist/src/tasks/generate-task.d.ts.map +0 -1
  229. package/dist/src/tasks/generate-task.js.map +0 -1
  230. package/dist/src/tasks/print-about-information.d.ts.map +0 -1
  231. package/dist/src/tasks/print-about-information.js.map +0 -1
  232. package/dist/src/tasks/print-banner.d.ts +0 -12
  233. package/dist/src/tasks/print-banner.d.ts.map +0 -1
  234. package/dist/src/tasks/print-banner.js.map +0 -1
  235. package/dist/src/tasks/print-generated-results.d.ts.map +0 -1
  236. package/dist/src/tasks/print-generated-results.js.map +0 -1
  237. package/dist/src/tasks/select-gen-target.d.ts +0 -9
  238. package/dist/src/tasks/select-gen-target.d.ts.map +0 -1
  239. package/dist/src/tasks/select-gen-target.js +0 -44
  240. package/dist/src/tasks/select-gen-target.js.map +0 -1
  241. package/src/tasks/generate-command.ts +0 -87
  242. package/src/tasks/generate-service.ts +0 -82
  243. package/src/tasks/generate-task.ts +0 -83
  244. package/src/tasks/print-banner.ts +0 -37
  245. package/src/tasks/print-generated-results.ts +0 -36
  246. package/src/tasks/select-gen-target.ts +0 -29
@@ -0,0 +1,71 @@
1
+ import { autoInjectable } from "tsyringe";
2
+ import { UtilService } from "./util-service";
3
+
4
+ import sortableCheckbox from "inquirer-sortable-checkbox";
5
+
6
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
7
+ const { search, input } = require("@inquirer/prompts");
8
+
9
+ @autoInjectable()
10
+ export class PromptService {
11
+ constructor(private utilService: UtilService) {}
12
+
13
+ /**
14
+ * Select an option from a list of choices. Allows search filtering.
15
+ * See: https://github.com/SBoudrias/Inquirer.js/tree/main/packages/search
16
+ *
17
+ * @param message the message to prompt (question to ask).
18
+ * @param options the selectable choices to search / choose from.
19
+ * @returns the selected choice value
20
+ */
21
+ async select(message: string, options: string[]) {
22
+ // wait for logging to catch up before prompting
23
+ await this.utilService.sleep(800);
24
+
25
+ const choices = options.map((opt) => ({ value: opt }));
26
+
27
+ const answer = await search({
28
+ message,
29
+ source: async (input: string | void) => {
30
+ if (!input) {
31
+ return choices;
32
+ }
33
+ return choices.filter((c) =>
34
+ c.value.toLowerCase().includes(input.toLowerCase()),
35
+ );
36
+ },
37
+ });
38
+
39
+ return answer;
40
+ }
41
+
42
+ /**
43
+ * Get a simple input string from the user.
44
+ *
45
+ * @param message the message to prompt the user with
46
+ * @param required whether or not to throw an error on empty input.
47
+ * @returns the read input string or undefined if not required
48
+ */
49
+ async getInput(message: string, required: boolean = true) {
50
+ await this.utilService.sleep(800);
51
+ return await input({ message, required });
52
+ }
53
+
54
+ /**
55
+ * Prompt with multi-select options returning the array of selections.
56
+ *
57
+ * @param message the message string to prompt with.
58
+ * @param options the options to choose from.
59
+ * @returns the selected optoins array
60
+ */
61
+ async pickMultiple<T>(
62
+ message: string,
63
+ options: { name: string; value: T }[],
64
+ ): Promise<T[]> {
65
+ await this.utilService.sleep(800);
66
+ return await sortableCheckbox({
67
+ message,
68
+ choices: options,
69
+ });
70
+ }
71
+ }
@@ -4,6 +4,15 @@ import { singleton } from "tsyringe";
4
4
 
5
5
  @singleton()
6
6
  export class SpawnService {
7
+ execSyncFromDir(command: string, dir: string) {
8
+ try {
9
+ return childProcess.execSync(command, { cwd: dir }).toString();
10
+ } catch (error) {
11
+ console.error(`Error executing command: ${command}`);
12
+ throw error;
13
+ }
14
+ }
15
+
7
16
  execSync(command: string) {
8
17
  try {
9
18
  return childProcess.execSync(command).toString();
@@ -15,7 +24,12 @@ export class SpawnService {
15
24
 
16
25
  exec(command: string) {
17
26
  try {
18
- return childProcess.exec(command).toString();
27
+ return new Promise((res, rej) => {
28
+ return childProcess.exec(command, (err, stdout, stderr) => {
29
+ if (err) return rej(err);
30
+ return res({ stdout, stderr });
31
+ });
32
+ });
19
33
  } catch (error) {
20
34
  console.error(`Error executing command: ${command}`, error);
21
35
  throw error;
@@ -84,4 +84,9 @@ export class UtilService {
84
84
 
85
85
  return null;
86
86
  }
87
+
88
+ sleep = (ms: number) => UtilService.sleep(ms);
89
+ static async sleep(ms: number) {
90
+ await new Promise((res) => setTimeout(res, ms));
91
+ }
87
92
  }
@@ -2,7 +2,7 @@ import chalk from "chalk";
2
2
  import { AppTask } from "../wrappers/app-task";
3
3
  import { autoInjectable } from "tsyringe";
4
4
  import { EnvironmentConfigKeys } from "../types/state";
5
- import FileService from "../services/file-service";
5
+ import { FileService } from "../services/file-service";
6
6
  import path from "path";
7
7
 
8
8
  /**
@@ -20,6 +20,7 @@ export default class CheckEnvironment extends AppTask {
20
20
  EnvironmentConfigKeys.PINO_LOG_DIR_PATH,
21
21
  EnvironmentConfigKeys.PINO_LOG_FILENAME,
22
22
  EnvironmentConfigKeys.PINO_LOG_LEVEL,
23
+ EnvironmentConfigKeys.TSSC_SILENCE_BANNER,
23
24
  ];
24
25
 
25
26
  constructor(private fileService: FileService) {
@@ -48,7 +49,8 @@ export default class CheckEnvironment extends AppTask {
48
49
 
49
50
  /**
50
51
  * Check for the folders we need to generate files in. Add errors
51
- * when no target directories can be found.
52
+ * when no target directories can be found. Saves project data to
53
+ * state so we don't have to refetch it later.
52
54
  *
53
55
  * @param projectDir the target project root directory path
54
56
  * @param errors string array error messages are added to
@@ -65,6 +67,12 @@ export default class CheckEnvironment extends AppTask {
65
67
  errors.push(`Unable to find any ${k} in project`);
66
68
  }
67
69
  });
70
+ this.setData({
71
+ project: {
72
+ rootDir: projectDir,
73
+ ...directories,
74
+ },
75
+ });
68
76
  }
69
77
 
70
78
  /**
@@ -0,0 +1,105 @@
1
+ import chalk from "chalk";
2
+ import { AppTask } from "../wrappers/app-task";
3
+ import { autoInjectable } from "tsyringe";
4
+ import { GenTargetType } from "../types/state";
5
+ import { ProjectConfig, ProjectData } from "../types/project";
6
+ import { PromptService } from "../services/prompt-service";
7
+ import { CacheService } from "../services/cache-service";
8
+ import { UtilService } from "../services/util-service";
9
+
10
+ /**
11
+ * Configures the Project Settings Cache in a Proactive way.
12
+ * Prompts for each resource type destination if not
13
+ * yet configured and multiple directories are found.
14
+ */
15
+ @autoInjectable()
16
+ export default class ConfigureCache extends AppTask {
17
+ loggerName = "Configure";
18
+
19
+ constructor(
20
+ private promptService: PromptService,
21
+ private cacheService: CacheService,
22
+ private utilService: UtilService,
23
+ ) {
24
+ super();
25
+ }
26
+
27
+ /**
28
+ * Configure each resource type's output destination directory. Allows
29
+ * the user to reset these values if their project has changed since
30
+ * last cached.
31
+ */
32
+ async run() {
33
+ this.logger.info(chalk.blueBright("Checking Configuration"));
34
+ const project: ProjectConfig & ProjectData = this.state.data.project!;
35
+
36
+ project.commandDestination = await this.getDestination(
37
+ GenTargetType.Command,
38
+ );
39
+ project.serviceDestination = await this.getDestination(
40
+ GenTargetType.Service,
41
+ );
42
+ project.taskDestination = await this.getDestination(GenTargetType.Task);
43
+
44
+ this.logger.debug(chalk.blackBright(`Saving configuration`));
45
+ await this.cacheService.writeProject(project);
46
+ this.setData({ project });
47
+ }
48
+
49
+ /**
50
+ * Prints the target destination path string
51
+ *
52
+ * @param dest the destination path to log
53
+ * @returns
54
+ */
55
+ logDestination = (dest: string = "") =>
56
+ this.logger.debug(`Destination: ${chalk.magentaBright(dest)}`);
57
+
58
+ /**
59
+ * Gets the destination path for generating resources by resource type.
60
+ * If only one resource destination folder was found it is returned
61
+ * otherwise the user is prompted to select one from the found folders.
62
+ *
63
+ * @param keyType the type of destination to resolve
64
+ * @returns the path of the resolved destination
65
+ */
66
+ async getDestination(keyType: "command" | "task" | "service") {
67
+ const foldersKey: keyof typeof this.state.data.project =
68
+ `${keyType}Folders` as keyof typeof this.state.data.project;
69
+
70
+ const nonTestFolders: string[] = (
71
+ this.state.data.project![foldersKey] as string[]
72
+ ).filter((folder: string) => !(folder || "").includes("/tests/"));
73
+
74
+ // if we only have one folder found, use this as the destination
75
+ const titleizedKey = chalk.blueBright(this.utilService.titleize(keyType));
76
+ if (nonTestFolders.length === 1) {
77
+ this.logger.debug(`Configuring single found ${titleizedKey} folder`);
78
+ return nonTestFolders[0] || "";
79
+ }
80
+
81
+ // otherwise prompt to pick one
82
+ await this.logger.flush();
83
+ const userSelection: string = await this.promptService.select(
84
+ `Multiple folders found. Select correct ${titleizedKey} folder`,
85
+ nonTestFolders,
86
+ );
87
+ return userSelection;
88
+ }
89
+
90
+ //@override
91
+ async preRun() {
92
+ this.verifyState();
93
+ }
94
+
95
+ /**
96
+ * Check we have all the required state set
97
+ */
98
+ verifyState() {
99
+ if (!this.state.data.project || !this.state.data.project.rootDir) {
100
+ throw new Error(
101
+ `Missing project rootDir! ${this.constructor.name} requires the CheckEnvironment task to be ran first.`,
102
+ );
103
+ }
104
+ }
105
+ }
@@ -0,0 +1,66 @@
1
+ import { SpawnService } from "../services/spawn-service";
2
+ import { FileService } from "../services/file-service";
3
+ import { PromptService } from "../services/prompt-service";
4
+ import { CLIOptions } from "../types/process";
5
+ import { AppTask } from "../wrappers/app-task";
6
+ import { autoInjectable } from "tsyringe";
7
+
8
+ /**
9
+ * Creates a New Task Script Support Project
10
+ */
11
+ @autoInjectable()
12
+ export default class CreateNewProject extends AppTask {
13
+ loggerName = "Create New Project";
14
+
15
+ constructor(
16
+ private fileService: FileService,
17
+ private spawnService: SpawnService,
18
+ private promptService: PromptService,
19
+ ) {
20
+ super();
21
+ }
22
+
23
+ /**
24
+ * Generates a new project. Updates state with outputDestination of the
25
+ * newly generated project path.
26
+ */
27
+ async run() {
28
+ // get path of the templater
29
+ const templaterFullPath = this.fileService.join(
30
+ __dirname,
31
+ "../../assets/yargs-template/task-runner/templater.sh",
32
+ );
33
+
34
+ // get execution directory
35
+ const runnerDir = this.fileService.getRunnerDir();
36
+
37
+ // get project name user input
38
+ const projectName: string = await this.getProjectName();
39
+
40
+ // execute the templater from the runner directory and provide given name
41
+ const shCmd = `bash ${templaterFullPath} ${projectName}`;
42
+ this.spawnService.execSyncFromDir(shCmd, runnerDir);
43
+
44
+ this.setData({
45
+ outputDestination: this.fileService.join(runnerDir, projectName),
46
+ });
47
+ }
48
+
49
+ /**
50
+ * Resolves the project name input from args or prompt.
51
+ *
52
+ * @returns the project name string
53
+ */
54
+ async getProjectName(): Promise<string> {
55
+ let projectName: string;
56
+ if (this.argService.hasFlag(CLIOptions.name)) {
57
+ projectName = this.argService.getOption<string>(CLIOptions.name);
58
+ } else {
59
+ projectName = await this.promptService.getInput("Enter Project Name");
60
+ }
61
+ if (!projectName) {
62
+ throw new Error("Unable to resolve projectName");
63
+ }
64
+ return projectName;
65
+ }
66
+ }
@@ -0,0 +1,136 @@
1
+ import chalk from "chalk";
2
+ import { AppTask } from "../../wrappers/app-task";
3
+ import { autoInjectable } from "tsyringe";
4
+ import { AppState, GenTargetType } from "../../types/state";
5
+ import { FileService } from "../../services/file-service";
6
+ import { UtilService } from "../../services/util-service";
7
+ import { CaseType } from "../../types/format";
8
+ import path from "path";
9
+ import { getCommandTemplate } from "../../templates/command";
10
+ import { ProjectService } from "../../services/project-service";
11
+ import { PromptService } from "../../services/prompt-service";
12
+
13
+ /**
14
+ * Generates a new command class
15
+ */
16
+ @autoInjectable()
17
+ export default class GenerateCommand extends AppTask {
18
+ loggerName = "Generate Command";
19
+
20
+ constructor(
21
+ private fileService: FileService,
22
+ private utilService: UtilService,
23
+ private projectService: ProjectService,
24
+ private promptService: PromptService,
25
+ ) {
26
+ super();
27
+ }
28
+
29
+ /**
30
+ * Generates a new command class file.
31
+ *
32
+ * @returns updated state with outputDestination set to generated result path.
33
+ */
34
+ async run(): Promise<void | Partial<AppState>> {
35
+ const { utilService, fileService, projectService } = this;
36
+
37
+ if (this.state.data.genTargetType !== GenTargetType.Command) {
38
+ return; // no-op
39
+ }
40
+
41
+ this.logger.info(chalk.blueBright("Generating Command"));
42
+ const targetName = this.state.data.genTargetName!;
43
+ const targetDirectory = this.state.data.project!.commandDestination!;
44
+
45
+ // detect case between commands and task files
46
+ const convention = projectService.getConvention();
47
+ this.logger.debug(`Using convention: ${chalk.magentaBright(convention)}`);
48
+
49
+ const className = utilService.titleizedToCase(
50
+ targetName,
51
+ CaseType.PASCAL_CASE,
52
+ );
53
+ const filename = `${utilService.titleizedToCase(targetName, convention)}${ProjectService.defaults.extention}`;
54
+
55
+ const taskMappings = new Map();
56
+ await this.addTasksToMap(taskMappings);
57
+ const rendered = getCommandTemplate(className, taskMappings);
58
+ const destination = path.join(targetDirectory, filename);
59
+
60
+ // write contents
61
+ fileService.writeFile(destination, rendered);
62
+ return { data: { outputDestination: destination } };
63
+ }
64
+
65
+ /**
66
+ * Checks state for required fields. Executes prior to run method.
67
+ * Skips validation if genTargetType is not set to command.
68
+ */
69
+ async preRun() {
70
+ if (this.state.data.genTargetType !== GenTargetType.Command) {
71
+ return; // no validation on no-op flow
72
+ }
73
+ if (!this.state.data.genTargetName) {
74
+ throw new Error("Unable to determine targetName");
75
+ }
76
+ if (!this.state.data.project) {
77
+ throw new Error("Unable to determine project");
78
+ }
79
+ if (!this.state.data.project.commandDestination) {
80
+ throw new Error("Unable to determine targetDirectory");
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Prompt to select tasks to use in the command being generated.
86
+ *
87
+ * @param taskMappings the map to add picked tasks to import for the command
88
+ */
89
+ async addTasksToMap(taskMappings: Map<string, string>) {
90
+ if (!this.state.data.project?.taskDestination) {
91
+ return;
92
+ }
93
+
94
+ const taskFiles = this.fileService.getFilesInDir(
95
+ this.state.data.project.taskDestination,
96
+ );
97
+
98
+ this.logger.debug(`Found ${taskFiles.length} task files`);
99
+ await this.logger.flush();
100
+
101
+ // prompt for tasks to use in the new command
102
+ const pickedTasks = await this.promptService.pickMultiple(
103
+ "Include Tasks",
104
+ taskFiles.map((tf) => ({
105
+ name: this.utilService.titleizedToCase(
106
+ this.utilService.titleizeAll(this.fileService.getFilenameNoExt(tf)),
107
+ CaseType.PASCAL_CASE,
108
+ ),
109
+ value: tf,
110
+ })),
111
+ );
112
+
113
+ this.logger.debug(`Selected ${pickedTasks.length} tasks`);
114
+ if (!pickedTasks.length) {
115
+ return;
116
+ }
117
+
118
+ // add them to the map
119
+ for (const picked of pickedTasks) {
120
+ const filename = this.fileService.getFilenameNoExt(picked);
121
+ const taskClassName = this.utilService.titleizedToCase(
122
+ this.utilService.titleizeAll(filename),
123
+ CaseType.PASCAL_CASE,
124
+ );
125
+ const relativeSource = this.state.data.project!.commandDestination!;
126
+ const relativeDest = picked;
127
+ taskMappings.set(
128
+ taskClassName,
129
+ this.fileService
130
+ .toRelativePath(relativeSource, relativeDest)
131
+ // remove extension for typescript import
132
+ .replace(ProjectService.defaults.extention, ""),
133
+ );
134
+ }
135
+ }
136
+ }
@@ -0,0 +1,78 @@
1
+ import chalk from "chalk";
2
+ import { AppTask } from "../../wrappers/app-task";
3
+ import { autoInjectable } from "tsyringe";
4
+ import { GenTargetType } from "../../types/state";
5
+ import { ProjectService } from "../../services/project-service";
6
+ import { UtilService } from "../../services/util-service";
7
+ import { FileService } from "../../services/file-service";
8
+ import { CaseType } from "../../types/format";
9
+ import path from "path";
10
+ import { getServiceTemplate } from "../../templates/service";
11
+
12
+ /**
13
+ * Generates a new service class
14
+ */
15
+ @autoInjectable()
16
+ export default class GenerateService extends AppTask {
17
+ loggerName = "Generate Service";
18
+
19
+ constructor(
20
+ private projectService: ProjectService,
21
+ private utilService: UtilService,
22
+ private fileService: FileService,
23
+ ) {
24
+ super();
25
+ }
26
+
27
+ /**
28
+ * Generates a new service class file.
29
+ *
30
+ * @returns updated state with outputDestination set to generated result path.
31
+ */
32
+ async run() {
33
+ if (this.state.data.genTargetType !== GenTargetType.Service) {
34
+ return;
35
+ }
36
+
37
+ this.logger.info(chalk.blueBright("Generating Service"));
38
+ const { utilService, projectService } = this;
39
+
40
+ const targetName = this.state.data.genTargetName!;
41
+ const targetDirectory = this.state.data.project!.serviceDestination!;
42
+
43
+ // detect case
44
+ const convention = projectService.getConvention();
45
+ this.logger.debug(`Using convention: ${chalk.magentaBright(convention)}`);
46
+ const className = utilService.titleizedToCase(
47
+ targetName,
48
+ CaseType.PASCAL_CASE,
49
+ );
50
+
51
+ const rendered = getServiceTemplate(className);
52
+ const filename = `${utilService.titleizedToCase(targetName, convention)}${ProjectService.defaults.extention}`;
53
+ const destination = path.join(targetDirectory, filename);
54
+
55
+ // write contents
56
+ this.fileService.writeFile(destination, rendered);
57
+ return { data: { outputDestination: destination } };
58
+ }
59
+
60
+ /**
61
+ * Checks state for required fields. Executes prior to run method.
62
+ * Skips validation if genTargetType is not set to service.
63
+ */
64
+ async preRun() {
65
+ if (this.state.data.genTargetType !== GenTargetType.Service) {
66
+ return; // no validation on no-op flow
67
+ }
68
+ if (!this.state.data.genTargetName) {
69
+ throw new Error("Unable to determine targetName");
70
+ }
71
+ if (!this.state.data.project) {
72
+ throw new Error("Unable to determine project");
73
+ }
74
+ if (!this.state.data.project.serviceDestination) {
75
+ throw new Error("Unable to determine targetDirectory");
76
+ }
77
+ }
78
+ }
@@ -0,0 +1,79 @@
1
+ import chalk from "chalk";
2
+ import { AppTask } from "../../wrappers/app-task";
3
+ import { autoInjectable } from "tsyringe";
4
+ import { GenTargetType } from "../../types/state";
5
+ import { getTaskTemplate } from "../../templates/task";
6
+ import { CaseType } from "../../types/format";
7
+ import { UtilService } from "../../services/util-service";
8
+ import { FileService } from "../../services/file-service";
9
+ import { ProjectService } from "../../services/project-service";
10
+ import path from "path";
11
+
12
+ /**
13
+ * Generates a new task class
14
+ */
15
+ @autoInjectable()
16
+ export default class GenerateTask extends AppTask {
17
+ loggerName = "Generate Task";
18
+
19
+ constructor(
20
+ private utilService: UtilService,
21
+ private fileService: FileService,
22
+ private projectService: ProjectService,
23
+ ) {
24
+ super();
25
+ }
26
+
27
+ /**
28
+ * Generates a new task class file.
29
+ *
30
+ * @returns updated state with outputDestination set to generated result path.
31
+ */
32
+ async run() {
33
+ if (this.state.data.genTargetType !== GenTargetType.Task) {
34
+ return;
35
+ }
36
+
37
+ const { utilService } = this;
38
+
39
+ this.logger.info(chalk.blueBright("Generating Task"));
40
+
41
+ const targetName = this.state.data.genTargetName!;
42
+ const targetDirectory = this.state.data.project!.taskDestination!;
43
+
44
+ // detect case
45
+ const convention = this.projectService.getConvention();
46
+ this.logger.debug(`Using convention: ${chalk.magentaBright(convention)}`);
47
+ const className = utilService.titleizedToCase(
48
+ targetName,
49
+ CaseType.PASCAL_CASE,
50
+ );
51
+
52
+ const rendered = getTaskTemplate(className);
53
+ const filename = `${utilService.titleizedToCase(targetName, convention)}${ProjectService.defaults.extention}`;
54
+ const destination = path.join(targetDirectory, filename);
55
+
56
+ // write contents
57
+ this.fileService.writeFile(destination, rendered);
58
+ return { data: { outputDestination: destination } };
59
+ }
60
+
61
+ /**
62
+ * Checks state for required fields. Executes prior to run method.
63
+ * Skips validation if genTargetType is not set to task.
64
+ */
65
+ async preRun() {
66
+ if (this.state.data.genTargetType !== GenTargetType.Task) {
67
+ return; // no validation on no-op flow
68
+ }
69
+ if (!this.state.data.genTargetName) {
70
+ throw new Error("Unable to determine targetName");
71
+ }
72
+ if (!this.state.data.project) {
73
+ throw new Error("Unable to determine project");
74
+ }
75
+ if (!this.state.data.project.taskDestination) {
76
+ throw new Error("Unable to determine targetDirectory");
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,44 @@
1
+ import chalk from "chalk";
2
+ import { AppTask } from "../../wrappers/app-task";
3
+ import { autoInjectable } from "tsyringe";
4
+ import { PromptService } from "../../services/prompt-service";
5
+ import { ProjectService } from "../../services/project-service";
6
+ import { UtilService } from "../../services/util-service";
7
+
8
+ /**
9
+ * SelectGenTargetName
10
+ */
11
+ @autoInjectable()
12
+ export default class SelectGenTargetName extends AppTask {
13
+ loggerName = "SelectGenTargetName";
14
+ constructor(
15
+ private promptService: PromptService,
16
+ private utilService: UtilService,
17
+ ) {
18
+ super();
19
+ }
20
+
21
+ async run() {
22
+ this.logger.info(chalk.blueBright("Checking Target Name"));
23
+
24
+ let targetName = this.argService.getTargetName();
25
+ if (!targetName) {
26
+ targetName =
27
+ (await this.promptService.getInput(
28
+ `Enter Name for ${chalk.blueBright(this.utilService.titleize(this.state.data.genTargetType!))}`,
29
+ )) || ProjectService.defaults.targetName;
30
+ }
31
+ if (!targetName) {
32
+ throw new Error("Unable to resolve targetName");
33
+ }
34
+ this.logger.debug(`Name selected: ${chalk.magentaBright(targetName)}`);
35
+ targetName = this.utilService.titleizeAll(targetName);
36
+ this.setData({ genTargetName: targetName });
37
+ }
38
+
39
+ async preRun() {
40
+ if (!this.state.data.genTargetType) {
41
+ throw new Error("Unable to determine genTargetType");
42
+ }
43
+ }
44
+ }