task-script-support-cli 0.1.1 → 0.2.3

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 (192) 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 +8 -3
  62. package/dist/src/commands/gen.d.ts +3 -1
  63. package/dist/src/commands/gen.d.ts.map +1 -1
  64. package/dist/src/commands/gen.js +4 -0
  65. package/dist/src/commands/gen.js.map +1 -1
  66. package/dist/src/commands/new.d.ts +8 -0
  67. package/dist/src/commands/new.d.ts.map +1 -0
  68. package/dist/src/commands/new.js +25 -0
  69. package/dist/src/commands/new.js.map +1 -0
  70. package/dist/src/index.js +6 -0
  71. package/dist/src/index.js.map +1 -1
  72. package/dist/src/services/cache-service.d.ts +11 -0
  73. package/dist/src/services/cache-service.d.ts.map +1 -0
  74. package/dist/src/services/cache-service.js +64 -0
  75. package/dist/src/services/cache-service.js.map +1 -0
  76. package/dist/src/services/file-service.d.ts +5 -1
  77. package/dist/src/services/file-service.d.ts.map +1 -1
  78. package/dist/src/services/file-service.js +16 -2
  79. package/dist/src/services/file-service.js.map +1 -1
  80. package/dist/src/services/log-service.d.ts.map +1 -1
  81. package/dist/src/services/log-service.js +7 -1
  82. package/dist/src/services/log-service.js.map +1 -1
  83. package/dist/src/services/project-service.d.ts +2 -2
  84. package/dist/src/services/project-service.d.ts.map +1 -1
  85. package/dist/src/services/project-service.js +5 -7
  86. package/dist/src/services/project-service.js.map +1 -1
  87. package/dist/src/services/prompt-service.d.ts +27 -0
  88. package/dist/src/services/prompt-service.d.ts.map +1 -0
  89. package/dist/src/services/prompt-service.js +67 -0
  90. package/dist/src/services/prompt-service.js.map +1 -0
  91. package/dist/src/services/spawn-service.d.ts +2 -1
  92. package/dist/src/services/spawn-service.d.ts.map +1 -1
  93. package/dist/src/services/spawn-service.js +16 -1
  94. package/dist/src/services/spawn-service.js.map +1 -1
  95. package/dist/src/services/util-service.d.ts +2 -0
  96. package/dist/src/services/util-service.d.ts.map +1 -1
  97. package/dist/src/services/util-service.js +4 -0
  98. package/dist/src/services/util-service.js.map +1 -1
  99. package/dist/src/tasks/check-env.d.ts +3 -2
  100. package/dist/src/tasks/check-env.d.ts.map +1 -1
  101. package/dist/src/tasks/check-env.js +11 -3
  102. package/dist/src/tasks/check-env.js.map +1 -1
  103. package/dist/src/tasks/create-new-project.d.ts +26 -0
  104. package/dist/src/tasks/create-new-project.d.ts.map +1 -0
  105. package/dist/src/tasks/create-new-project.js +76 -0
  106. package/dist/src/tasks/create-new-project.js.map +1 -0
  107. package/dist/src/tasks/generate-command.d.ts +18 -6
  108. package/dist/src/tasks/generate-command.d.ts.map +1 -1
  109. package/dist/src/tasks/generate-command.js +66 -29
  110. package/dist/src/tasks/generate-command.js.map +1 -1
  111. package/dist/src/tasks/generate-service.d.ts +10 -6
  112. package/dist/src/tasks/generate-service.d.ts.map +1 -1
  113. package/dist/src/tasks/generate-service.js +27 -26
  114. package/dist/src/tasks/generate-service.js.map +1 -1
  115. package/dist/src/tasks/generate-task.d.ts +10 -6
  116. package/dist/src/tasks/generate-task.d.ts.map +1 -1
  117. package/dist/src/tasks/generate-task.js +27 -26
  118. package/dist/src/tasks/generate-task.js.map +1 -1
  119. package/dist/src/tasks/print-banner.d.ts +3 -3
  120. package/dist/src/tasks/print-banner.d.ts.map +1 -1
  121. package/dist/src/tasks/print-banner.js +12 -8
  122. package/dist/src/tasks/print-banner.js.map +1 -1
  123. package/dist/src/tasks/print-generated-results.d.ts.map +1 -1
  124. package/dist/src/tasks/print-generated-results.js +13 -10
  125. package/dist/src/tasks/print-generated-results.js.map +1 -1
  126. package/dist/src/tasks/select-gen-target-name.d.ts +15 -0
  127. package/dist/src/tasks/select-gen-target-name.d.ts.map +1 -0
  128. package/dist/src/tasks/select-gen-target-name.js +58 -0
  129. package/dist/src/tasks/select-gen-target-name.js.map +1 -0
  130. package/dist/src/tasks/select-gen-target.d.ts +5 -0
  131. package/dist/src/tasks/select-gen-target.d.ts.map +1 -1
  132. package/dist/src/tasks/select-gen-target.js +16 -2
  133. package/dist/src/tasks/select-gen-target.js.map +1 -1
  134. package/dist/src/tasks/sync-configuration.d.ts +34 -0
  135. package/dist/src/tasks/sync-configuration.d.ts.map +1 -0
  136. package/dist/src/tasks/sync-configuration.js +116 -0
  137. package/dist/src/tasks/sync-configuration.js.map +1 -0
  138. package/dist/src/tasks/test-task.d.ts +10 -0
  139. package/dist/src/tasks/test-task.d.ts.map +1 -0
  140. package/dist/src/tasks/test-task.js +36 -0
  141. package/dist/src/tasks/test-task.js.map +1 -0
  142. package/dist/src/templates/command.js +2 -2
  143. package/dist/src/templates/command.js.map +1 -1
  144. package/dist/src/templates/service.js +1 -1
  145. package/dist/src/templates/service.js.map +1 -1
  146. package/dist/src/types/process.d.ts +2 -1
  147. package/dist/src/types/process.d.ts.map +1 -1
  148. package/dist/src/types/process.js +1 -0
  149. package/dist/src/types/process.js.map +1 -1
  150. package/dist/src/types/project.d.ts +12 -0
  151. package/dist/src/types/project.d.ts.map +1 -0
  152. package/dist/src/types/project.js +3 -0
  153. package/dist/src/types/project.js.map +1 -0
  154. package/dist/src/types/state.d.ts +5 -1
  155. package/dist/src/types/state.d.ts.map +1 -1
  156. package/dist/src/types/state.js +1 -0
  157. package/dist/src/types/state.js.map +1 -1
  158. package/dist/vitest.config.d.ts +3 -0
  159. package/dist/vitest.config.d.ts.map +1 -0
  160. package/dist/vitest.config.js +16 -0
  161. package/dist/vitest.config.js.map +1 -0
  162. package/package.json +8 -3
  163. package/src/commands/gen.ts +4 -0
  164. package/src/commands/new.ts +10 -0
  165. package/src/index.ts +7 -0
  166. package/src/services/cache-service.ts +50 -0
  167. package/src/services/file-service.ts +18 -1
  168. package/src/services/log-service.ts +6 -1
  169. package/src/services/project-service.ts +2 -2
  170. package/src/services/prompt-service.ts +60 -0
  171. package/src/services/spawn-service.ts +15 -1
  172. package/src/services/util-service.ts +5 -0
  173. package/src/tasks/check-env.ts +10 -2
  174. package/src/tasks/create-new-project.ts +66 -0
  175. package/src/tasks/generate-command.ts +84 -31
  176. package/src/tasks/generate-service.ts +24 -28
  177. package/src/tasks/generate-task.ts +24 -28
  178. package/src/tasks/print-banner.ts +10 -6
  179. package/src/tasks/print-generated-results.ts +15 -15
  180. package/src/tasks/select-gen-target-name.ts +44 -0
  181. package/src/tasks/select-gen-target.ts +16 -1
  182. package/src/tasks/sync-configuration.ts +121 -0
  183. package/src/tasks/test-task.ts +20 -0
  184. package/src/templates/command.ts +2 -2
  185. package/src/templates/service.ts +1 -1
  186. package/src/types/process.ts +1 -0
  187. package/src/types/project.ts +12 -0
  188. package/src/types/state.ts +7 -1
  189. package/tests/index.spec.ts +8 -0
  190. package/tests/setup.ts +1 -0
  191. package/tsconfig.json +1 -1
  192. package/vitest.config.ts +14 -0
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "task-runner",
3
+ "version": "0.1.0",
4
+ "main": "index.js",
5
+ "type": "commonjs",
6
+ "scripts": {
7
+ "start": "jiti src/index.ts",
8
+ "dev": "npm run build && node dist/src/index.js",
9
+ "clean": "rm -rf ./dist",
10
+ "lint": "eslint --config eslint.config.ts",
11
+ "watch": "onchange './*{.json,.sh,.ts}' 'src/*.ts' -- npm run build",
12
+ "format": "prettier --write ./",
13
+ "format-check": "prettier --check .",
14
+ "hooks-one-time-setup": "npx simple-git-hooks",
15
+ "prettier-watch": "onchange \"**/*\" -- prettier --write --ignore-unknown {{changed}}",
16
+ "build": "rm -rf ./dist && npx tsc && node dist/src/index.js -v",
17
+ "test": "vitest run",
18
+ "test-watch": "vitest"
19
+ },
20
+ "keywords": [],
21
+ "author": "",
22
+ "license": "ISC",
23
+ "description": "",
24
+ "simple-git-hooks": {
25
+ "pre-commit": "npx pretty-quick --staged && npm run lint"
26
+ },
27
+ "dependencies": {
28
+ "chalk": "^4.1.2",
29
+ "dotenv": "^17.2.3",
30
+ "figlet": "^1.9.4",
31
+ "immutable": "^5.1.4",
32
+ "reflect-metadata": "^0.2.2",
33
+ "task-script-support": "^2.3.0",
34
+ "tsyringe": "^4.10.0",
35
+ "yargs": "^18.0.0"
36
+ },
37
+ "devDependencies": {
38
+ "@eslint/js": "^9.39.3",
39
+ "@types/node": "^24.10.1",
40
+ "@types/yargs": "^17.0.35",
41
+ "eslint": "^10.0.3",
42
+ "jiti": "^2.6.1",
43
+ "onchange": "^7.1.0",
44
+ "prettier": "^3.7.1",
45
+ "pretty-quick": "^4.2.2",
46
+ "simple-git-hooks": "^2.13.1",
47
+ "typescript": "^5.9.3",
48
+ "typescript-eslint": "^8.48.0",
49
+ "vitest": "^4.0.15"
50
+ }
51
+ }
@@ -0,0 +1,10 @@
1
+ import { singleton } from "tsyringe";
2
+ import { Command } from "../wrappers/command";
3
+ import CheckEnv from "../tasks/check-env";
4
+ import PrintBanner from "../tasks/print-banner";
5
+ import LogState from "../tasks/log-state";
6
+
7
+ @singleton()
8
+ export class VerifyCommand extends Command {
9
+ tasks = [PrintBanner, CheckEnv, LogState];
10
+ }
@@ -0,0 +1,46 @@
1
+ import "reflect-metadata";
2
+
3
+ import dotenv from "dotenv";
4
+ import { container } from "tsyringe";
5
+
6
+ dotenv.config({ quiet: true });
7
+ import yargs from "yargs";
8
+ import { hideBin } from "yargs/helpers";
9
+
10
+ import { initializeInjectables } from "./wrappers/dependencies";
11
+ initializeInjectables();
12
+
13
+ import { UtilService } from "./services/util-service";
14
+ import { VerifyCommand } from "./commands/verify";
15
+
16
+ const name = UtilService.getAppName();
17
+
18
+ yargs(hideBin(process.argv))
19
+ .usage(`${UtilService.titleizeAll(name)} CLI Client`)
20
+ .command(
21
+ "verify",
22
+ "check the app is working",
23
+ (yargs) => {
24
+ yargs
25
+ .option("bf", {
26
+ alias: "banner-font",
27
+ type: "string",
28
+ describe: "provide a font for the app banner",
29
+ })
30
+ .option("rf", {
31
+ alias: "random-font",
32
+ type: "boolean",
33
+ describe: "use a random font for app banner",
34
+ default: false,
35
+ });
36
+ },
37
+ container.resolve(VerifyCommand).handler,
38
+ )
39
+ .option("d", {
40
+ alias: "debug",
41
+ type: "boolean",
42
+ describe: "enable extra logging",
43
+ default: false,
44
+ })
45
+ .help()
46
+ .parse();
@@ -0,0 +1,38 @@
1
+ import { singleton } from "tsyringe";
2
+ import figlet from "figlet";
3
+
4
+ @singleton()
5
+ export class BannerService {
6
+ _selectFonts = [
7
+ "AMC Slash",
8
+ "Calvin S",
9
+ "Bell",
10
+ "Pagga",
11
+ "Shadow",
12
+ "Small Block",
13
+ ];
14
+ defaultFontFamily: string = "Cybermedium";
15
+
16
+ async toBanner(text: string, font?: string): Promise<string> {
17
+ return await figlet.text(text, {
18
+ font: font || this.defaultFontFamily,
19
+ });
20
+ }
21
+
22
+ async getSupportedFonts(): Promise<string[]> {
23
+ return await new Promise((res, rej) => {
24
+ figlet.fonts((err, fonts) =>
25
+ err ? rej(err) : res(fonts || ([] as string[])),
26
+ );
27
+ });
28
+ }
29
+
30
+ async getRandomFont(): Promise<string> {
31
+ const randomIndexBetween = (start = 0, end = 0) =>
32
+ Math.floor(Math.random() * (end - start + 1)) + start;
33
+
34
+ const bannerFonts: string[] = await this.getSupportedFonts();
35
+ const randomFontIndex = randomIndexBetween(0, bannerFonts.length - 1);
36
+ return bannerFonts[randomFontIndex] || this.defaultFontFamily;
37
+ }
38
+ }
@@ -0,0 +1,48 @@
1
+ import { inject, injectable } from "tsyringe";
2
+ import { PinoLogger } from "task-script-support";
3
+ import pino from "pino";
4
+
5
+ @injectable()
6
+ export class LogService {
7
+ logger: pino.Logger;
8
+
9
+ static ParentInstance?: pino.Logger;
10
+
11
+ constructor(@inject("PinoLogger") private pinoLogger: PinoLogger) {
12
+ if (!LogService.ParentInstance) {
13
+ this.logger = pinoLogger.getLogger();
14
+ LogService.ParentInstance = this.logger;
15
+ } else {
16
+ this.logger = LogService.ParentInstance.child({});
17
+ }
18
+ }
19
+
20
+ setPrefix(prefix: string) {
21
+ if (!LogService.ParentInstance) {
22
+ this.logger = this.pinoLogger.getLogger(prefix);
23
+ LogService.ParentInstance = this.logger;
24
+ } else {
25
+ this.logger = LogService.ParentInstance.child({}, { msgPrefix: prefix });
26
+ }
27
+ }
28
+
29
+ public info(msg: string, obj?: unknown): void {
30
+ this.logger.info(obj, msg);
31
+ }
32
+
33
+ public error(err: Error | string, msg?: string, obj?: unknown): void {
34
+ if (err instanceof Error) {
35
+ this.logger.error({ err, ...(obj ? obj : {}) }, msg || "Error occurred");
36
+ } else {
37
+ this.logger.error(obj, `${msg}: ${err}`);
38
+ }
39
+ }
40
+
41
+ public warn(msg: string, obj?: unknown): void {
42
+ this.logger.warn(obj, msg);
43
+ }
44
+
45
+ public debug(msg: string, obj?: unknown): void {
46
+ this.logger.debug(obj, msg);
47
+ }
48
+ }
@@ -0,0 +1,87 @@
1
+ import childProcess, { ChildProcess, spawn } from "node:child_process";
2
+ import type { ProcessOutput, ProcessStatus } from "../types/process";
3
+ import { singleton } from "tsyringe";
4
+
5
+ @singleton()
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
+
16
+ execSync(command: string) {
17
+ try {
18
+ return childProcess.execSync(command).toString();
19
+ } catch (error) {
20
+ console.error(`Error executing command: ${command}`);
21
+ throw error;
22
+ }
23
+ }
24
+
25
+ exec(command: string): Promise<ProcessOutput> {
26
+ try {
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
+ });
33
+ } catch (error) {
34
+ console.error(`Error executing command: ${command}`, error);
35
+ throw error;
36
+ }
37
+ }
38
+
39
+ backgroundExec(command: string, args: string[] = []): ChildProcess {
40
+ const child = spawn(command, args, {
41
+ detached: true,
42
+ stdio: "ignore",
43
+ });
44
+
45
+ child.unref();
46
+ return child;
47
+ }
48
+
49
+ isProcessCompleted(pid: number): boolean {
50
+ try {
51
+ // sending signal 0 checks if the process exists
52
+ process.kill(pid, 0);
53
+ return false;
54
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
55
+ } catch (error) {
56
+ return true;
57
+ }
58
+ }
59
+
60
+ kill(pid: number) {
61
+ try {
62
+ process.kill(pid);
63
+ } catch (error) {
64
+ throw new Error(
65
+ `Failed to kill process with PID ${pid}: ${(error as Error).message}`,
66
+ );
67
+ }
68
+ }
69
+
70
+ forceKill(pid: number) {
71
+ try {
72
+ process.kill(pid, "SIGKILL");
73
+ } catch (error) {
74
+ throw new Error(
75
+ `Failed to forcefully kill process with PID ${pid}: ${(error as Error).message}`,
76
+ );
77
+ }
78
+ }
79
+
80
+ async getProcessStatus(pid: number): Promise<ProcessStatus> {
81
+ const completed = this.isProcessCompleted(pid);
82
+ return {
83
+ pid,
84
+ status: completed ? "completed" : "running",
85
+ };
86
+ }
87
+ }
@@ -0,0 +1,28 @@
1
+ import { singleton } from "tsyringe";
2
+ import pkgJson from "../../package.json";
3
+
4
+ @singleton()
5
+ export class UtilService {
6
+ static TITLEIZE_TEXT_BREAKPONT: RegExp = /[. _-]/g;
7
+
8
+ static titleize = (s: string) =>
9
+ s ? `${s[0]?.toUpperCase()}${s.slice(1, s.length)}` : s;
10
+ titleize = (s: string) => UtilService.titleize(s);
11
+
12
+ titleizeAll = (s: string) => UtilService.titleizeAll(s);
13
+ static titleizeAll = (str: string) =>
14
+ str
15
+ .trim()
16
+ .split(UtilService.TITLEIZE_TEXT_BREAKPONT)
17
+ .map(UtilService.titleize)
18
+ .join(" ");
19
+
20
+ static getAppName = () => pkgJson.name;
21
+ getAppName = () => pkgJson.name;
22
+
23
+ static getAppVersion = () => pkgJson.version;
24
+ getAppVersion = () => pkgJson.version;
25
+
26
+ static getAppDescription = () => pkgJson.description;
27
+ getAppDescription = () => pkgJson.description;
28
+ }
@@ -0,0 +1,49 @@
1
+ import chalk from "chalk";
2
+ import { AppTask } from "../wrappers/app-task";
3
+ import { autoInjectable } from "tsyringe";
4
+ import { EnvironmentConfigKeys } from "../types/state";
5
+
6
+ /**
7
+ * Checks the environment configuration
8
+ */
9
+ @autoInjectable()
10
+ export default class CheckEnv extends AppTask {
11
+ loggerName = "Check Environment";
12
+
13
+ async run() {
14
+ this.logger.info(chalk.blueBright("Running Check Environment"));
15
+
16
+ const errorMessages: string[] = [];
17
+ const requiredEnv: string[] = [];
18
+ const optionalEnv = [
19
+ EnvironmentConfigKeys.NODE_ENV,
20
+ EnvironmentConfigKeys.PINO_LOG_TARGET,
21
+ EnvironmentConfigKeys.PINO_LOG_DIR_PATH,
22
+ EnvironmentConfigKeys.PINO_LOG_FILENAME,
23
+ EnvironmentConfigKeys.PINO_LOG_LEVEL,
24
+ ];
25
+
26
+ [...optionalEnv, ...requiredEnv]
27
+ .filter((e) => !!process.env[e])
28
+ .forEach((e) => {
29
+ this.logger.info(`Read value for ${e}: ${process.env[e]}`);
30
+ });
31
+
32
+ requiredEnv
33
+ .filter((e) => !process.env[e])
34
+ .forEach((e) =>
35
+ errorMessages.push(`Missing required environment variable ${e}`),
36
+ );
37
+
38
+ // fail the process on bad environment
39
+ if (errorMessages.length) {
40
+ this.logger.error(
41
+ new Error("Misconfigured Environment"),
42
+ chalk.red(errorMessages.join("\n")),
43
+ );
44
+ process.exit(1);
45
+ }
46
+
47
+ this.state = this.setData({ environmentValidated: true });
48
+ }
49
+ }
@@ -0,0 +1,22 @@
1
+ import chalk from "chalk";
2
+ import { AppTask } from "../wrappers/app-task";
3
+ import { autoInjectable } from "tsyringe";
4
+
5
+ /**
6
+ * Logs the app state
7
+ */
8
+ @autoInjectable()
9
+ export default class LogState extends AppTask {
10
+ loggerName = "Log State";
11
+ async run() {
12
+ if (!this.state.args.debug) {
13
+ this.logger.debug(
14
+ chalk.dim("Skipping logging state, use debug flag to see state"),
15
+ );
16
+ return;
17
+ }
18
+
19
+ this.logger.info(chalk.blueBright("Running Log State"));
20
+ this.logger.debug("state", this.state);
21
+ }
22
+ }
@@ -0,0 +1,73 @@
1
+ import { autoInjectable } from "tsyringe";
2
+ import { AppState } from "../types/state";
3
+ import { AppTask } from "../wrappers/app-task";
4
+ import { BannerService } from "../services/banner-service";
5
+ import { UtilService } from "../services/util-service";
6
+ import chalk from "chalk";
7
+
8
+ /**
9
+ * Prints an app banner to the console
10
+ */
11
+ @autoInjectable()
12
+ export default class PrintBanner extends AppTask {
13
+ loggerName = "Print Banner";
14
+
15
+ constructor(
16
+ private bannnerSvc: BannerService,
17
+ private utilService: UtilService,
18
+ ) {
19
+ super();
20
+ }
21
+
22
+ async preRun() {
23
+ await this.validateFont();
24
+ }
25
+
26
+ async run({ args }: AppState): Promise<Partial<AppState> | void> {
27
+ let font = "";
28
+
29
+ try {
30
+ if (args.randomFont) {
31
+ font = await this.bannnerSvc.getRandomFont();
32
+ console.log(`Using random font ${font}`);
33
+ }
34
+
35
+ // allow banner-font as user input
36
+ if (args.bannerFont) {
37
+ font = args.bannerFont;
38
+ }
39
+
40
+ console.log(
41
+ chalk.blueBright(
42
+ await this.bannnerSvc.toBanner(this.utilService.getAppName(), font),
43
+ ),
44
+ );
45
+
46
+ // mutate state
47
+ this.setData({
48
+ banner: { font: font || this.bannnerSvc.defaultFontFamily },
49
+ });
50
+
51
+ // return updated state instead of calling setData
52
+ return { data: { banner: { status: "success" } } } as const;
53
+ } catch (err) {
54
+ this.setData({ banner: { status: "failed" }, errorMessages: [`${err}`] });
55
+ }
56
+ }
57
+
58
+ /*
59
+ Helper for ensuring font is supported if provided as input
60
+ */
61
+ async validateFont() {
62
+ const { args } = this.state;
63
+ if (!args.bannerFont) {
64
+ return;
65
+ }
66
+
67
+ const fontName = args.bannerFont;
68
+ const availableFonts = await this.bannnerSvc.getSupportedFonts();
69
+ if (!availableFonts.includes(fontName)) {
70
+ throw new Error(`Unsupported font provided: ${chalk.red(fontName)}`);
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,9 @@
1
+ export interface ProcessStatus {
2
+ readonly pid: number;
3
+ readonly status: "running" | "completed" | "unknown";
4
+ }
5
+
6
+ export interface ProcessOutput {
7
+ stdout?: string;
8
+ stderr?: string;
9
+ }
@@ -0,0 +1,31 @@
1
+ import { AppState as State } from "task-script-support";
2
+
3
+ // Add app data here as needed. Use readonly for immutable fields.
4
+ //
5
+ // Note: this object gets passed to deepMerge upon updating app state
6
+ // which also merges array fields. This might be fine or you might want
7
+ // to make your arrays <type>[] | undefined to allow clobbering.
8
+ export interface AppStateData {
9
+ readonly errorMessages?: string[];
10
+ readonly banner?: {
11
+ readonly status?: "success" | "failed";
12
+ readonly font?: string;
13
+ };
14
+ readonly environmentValidated?: boolean;
15
+ }
16
+
17
+ export type CLIArgs = {
18
+ readonly debug: boolean;
19
+ readonly randomFont: boolean;
20
+ readonly bannerFont?: string;
21
+ };
22
+
23
+ export type AppState = State<AppStateData, CLIArgs>;
24
+
25
+ export const EnvironmentConfigKeys = {
26
+ PINO_LOG_DIR_PATH: "PINO_LOG_DIR_PATH",
27
+ PINO_LOG_LEVEL: "PINO_LOG_LEVEL",
28
+ NODE_ENV: "NODE_ENV",
29
+ PINO_LOG_FILENAME: "PINO_LOG_FILENAME",
30
+ PINO_LOG_TARGET: "PINO_LOG_TARGET",
31
+ };
@@ -0,0 +1,42 @@
1
+ import { autoInjectable } from "tsyringe";
2
+ import { CommandService, Task } from "task-script-support";
3
+ import { LogService } from "../services/log-service";
4
+ import type { AppState, AppStateData, CLIArgs } from "../types/state";
5
+
6
+ @autoInjectable()
7
+ export class AppTask extends Task<AppStateData, CLIArgs> {
8
+ state: AppState = {
9
+ id: "uninitialized",
10
+ args: {} as CLIArgs,
11
+ data: {},
12
+ };
13
+ loggerName: string = "";
14
+
15
+ get logger(): LogService {
16
+ return this._logService!;
17
+ }
18
+
19
+ constructor(
20
+ public _logService?: LogService,
21
+ public _commandService?: CommandService<AppStateData, CLIArgs>,
22
+ ) {
23
+ super();
24
+ }
25
+
26
+ //@override
27
+ async initialize() {
28
+ if (this.loggerName) {
29
+ this.logger!.setPrefix(`${this.loggerName} :: `);
30
+ }
31
+ }
32
+
33
+ //@override
34
+ async run(state: AppState): Promise<Partial<AppState> | void> {
35
+ throw new Error(`run not implemented (${state.id})`);
36
+ }
37
+
38
+ setData(data: Partial<AppStateData>) {
39
+ this.state = this._commandService!.setData(this.state, data);
40
+ return this.state;
41
+ }
42
+ }
@@ -0,0 +1,20 @@
1
+ import { CommandService, TaskClass } from "task-script-support";
2
+ import { inject } from "tsyringe";
3
+ import { AppStateData, CLIArgs } from "../types/state";
4
+
5
+ export class Command {
6
+ tasks: TaskClass<AppStateData, CLIArgs>[] = [];
7
+
8
+ constructor(
9
+ @inject(CommandService<AppStateData, CLIArgs>)
10
+ private commandService: CommandService<AppStateData, CLIArgs>,
11
+ ) {}
12
+
13
+ get handler(): (...cliArgs: unknown[]) => Promise<void> {
14
+ return this.commandService.fromTasks(this.getTasks());
15
+ }
16
+
17
+ getTasks(): TaskClass<AppStateData, CLIArgs>[] {
18
+ return this.tasks;
19
+ }
20
+ }
@@ -0,0 +1,24 @@
1
+ import { CommandService, PinoLogger } from "task-script-support";
2
+ import { container } from "tsyringe";
3
+ import { AppStateData, CLIArgs } from "../types/state";
4
+
5
+ /**
6
+ * Register external dependencies as injectables
7
+ */
8
+ export const initializeInjectables = () => {
9
+ // register command service
10
+ container.registerSingleton(CommandService<AppStateData, CLIArgs>);
11
+
12
+ // configure args provider
13
+ const command = container.resolve(CommandService<AppStateData, CLIArgs>);
14
+ command.argsProvider = (...yargsArgs: unknown[]) => {
15
+ const args = command.argsProvider_Yargs(...yargsArgs);
16
+
17
+ // and register args
18
+ container.registerInstance("Args", args);
19
+ return args;
20
+ };
21
+
22
+ // register pino
23
+ container.registerInstance("PinoLogger", new PinoLogger());
24
+ };
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ npm start -- "$@"
@@ -0,0 +1,57 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ if [[ -z "$1" ]]; then
5
+ echo "Missing required parameter. Usage: ./templater.sh <output-name>"
6
+ exit 1;
7
+ fi
8
+
9
+ DIR_LIST_TO_COPY=('.vscode' 'src' 'tests')
10
+ FILE_LIST_TO_COPY=('.gitignore' '.prettierignore' '.prettierrc' 'task-runner' 'install-link.sh' 'eslint.config.ts' 'vitest.config.ts' 'package-lock.json' 'package.json' 'tsconfig.json')
11
+ NAME_REF_LIST=('package.json' 'package-lock.json' 'install-link.sh')
12
+ CWD=$(pwd)
13
+ SCRIPT_DIR=$(dirname "$0")
14
+ DESTINATION="$CWD/$1"
15
+
16
+ # ensure dest exists
17
+ if [ -f "$DESTINATION" ]; then
18
+ echo "Using destination: $DESTINATION"
19
+ else
20
+ echo "Creating destination directory: $DESTINATION"
21
+ mkdir -p "$DESTINATION"
22
+ fi
23
+
24
+ # copy directories
25
+ for folder in "${DIR_LIST_TO_COPY[@]}"; do
26
+ echo "Running Copy/: cp -R $SCRIPT_DIR/$folder $DESTINATION/$folder"
27
+ cp -R "$SCRIPT_DIR/$folder" "$DESTINATION/$folder"
28
+ done
29
+
30
+ # copy files
31
+ for filename in "${FILE_LIST_TO_COPY[@]}"; do
32
+ echo "Running Copy: cp $SCRIPT_DIR/$filename $DESTINATION/$filename"
33
+ cp "$SCRIPT_DIR/$filename" "$DESTINATION/$filename"
34
+ done
35
+
36
+ # fix naming
37
+ for fileToEdit in "${NAME_REF_LIST[@]}"; do
38
+ dest="$DESTINATION/$fileToEdit"
39
+ replace_pattern="s/task-runner/$1/g"
40
+ echo "Running Patch: cat \"$dest\" | sed -i \"$replace_pattern\" "
41
+ output=$(cat "$dest" | sed "$replace_pattern")
42
+ echo "$output" > "$dest"
43
+
44
+ # echo "Running patch: sed -i \"s/task-runner/$1/g\" \"$DESTINATION/$fileToEdit\""
45
+ # sed -i "s/task-runner/$1/g" "$DESTINATION/$fileToEdit"
46
+ done
47
+ mv "$DESTINATION/task-runner" "$DESTINATION/$1"
48
+
49
+
50
+ # cd into destination and run git init
51
+ echo "initializing with git"
52
+ INITIALIZED=$(cd "$DESTINATION" && git init -b main)
53
+
54
+ echo;
55
+ echo " Try:"
56
+ echo " cd $DESTINATION && npm i && npm run dev"
57
+ echo;