task-script-support-cli 0.3.0 → 0.3.2

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 (83) hide show
  1. package/assets/yargs-template/task-runner/src/commands/verify.ts +3 -2
  2. package/assets/yargs-template/task-runner/src/services/banner-service.ts +13 -9
  3. package/assets/yargs-template/task-runner/src/tasks/banner/print-banner.ts +38 -0
  4. package/assets/yargs-template/task-runner/src/tasks/banner/resolve-banner-font.ts +70 -0
  5. package/assets/yargs-template/task-runner/src/types/state.ts +4 -0
  6. package/{dist/assets/yargs-template/task-runner/src/wrappers → assets/yargs-template/task-runner/src/wrappers/electives}/concurrent-task-group.ts +4 -4
  7. package/assets/yargs-template/task-runner/src/wrappers/electives/resolver-task.ts +87 -0
  8. package/assets/yargs-template/task-runner/src/wrappers/{sequential-task-group.ts → electives/sequential-task-group.ts} +4 -4
  9. package/assets/yargs-template/task-runner/tests/commands/verify.test.ts +14 -21
  10. package/dist/assets/yargs-template/task-runner/src/commands/verify.ts +3 -2
  11. package/dist/assets/yargs-template/task-runner/src/services/banner-service.ts +13 -9
  12. package/dist/assets/yargs-template/task-runner/src/tasks/banner/print-banner.ts +38 -0
  13. package/dist/assets/yargs-template/task-runner/src/tasks/banner/resolve-banner-font.ts +70 -0
  14. package/dist/assets/yargs-template/task-runner/src/types/state.ts +4 -0
  15. package/{assets/yargs-template/task-runner/src/wrappers → dist/assets/yargs-template/task-runner/src/wrappers/electives}/concurrent-task-group.ts +4 -4
  16. package/dist/assets/yargs-template/task-runner/src/wrappers/electives/resolver-task.ts +87 -0
  17. package/dist/assets/yargs-template/task-runner/src/wrappers/{sequential-task-group.ts → electives/sequential-task-group.ts} +4 -4
  18. package/dist/assets/yargs-template/task-runner/tests/commands/verify.test.ts +14 -21
  19. package/dist/package.json +1 -1
  20. package/dist/src/commands/gen.d.ts +3 -1
  21. package/dist/src/commands/gen.d.ts.map +1 -1
  22. package/dist/src/commands/gen.js +2 -0
  23. package/dist/src/commands/gen.js.map +1 -1
  24. package/dist/src/services/project-service.d.ts +21 -0
  25. package/dist/src/services/project-service.d.ts.map +1 -1
  26. package/dist/src/services/project-service.js +41 -0
  27. package/dist/src/services/project-service.js.map +1 -1
  28. package/dist/src/services/templater-service.d.ts +1 -0
  29. package/dist/src/services/templater-service.d.ts.map +1 -1
  30. package/dist/src/services/templater-service.js +9 -3
  31. package/dist/src/services/templater-service.js.map +1 -1
  32. package/dist/src/tasks/generate/generate-command.d.ts +10 -3
  33. package/dist/src/tasks/generate/generate-command.d.ts.map +1 -1
  34. package/dist/src/tasks/generate/generate-command.js +27 -11
  35. package/dist/src/tasks/generate/generate-command.js.map +1 -1
  36. package/dist/src/tasks/generate/generate-service.d.ts +10 -3
  37. package/dist/src/tasks/generate/generate-service.d.ts.map +1 -1
  38. package/dist/src/tasks/generate/generate-service.js +26 -12
  39. package/dist/src/tasks/generate/generate-service.js.map +1 -1
  40. package/dist/src/tasks/generate/generate-task.d.ts +10 -3
  41. package/dist/src/tasks/generate/generate-task.d.ts.map +1 -1
  42. package/dist/src/tasks/generate/generate-task.js +27 -13
  43. package/dist/src/tasks/generate/generate-task.js.map +1 -1
  44. package/dist/src/tasks/generate/project-context-guard.d.ts +1 -1
  45. package/dist/src/tasks/generate/project-context-guard.js +1 -1
  46. package/dist/src/tasks/generate/resolve-injectables.d.ts +56 -0
  47. package/dist/src/tasks/generate/resolve-injectables.d.ts.map +1 -0
  48. package/dist/src/tasks/generate/resolve-injectables.js +134 -0
  49. package/dist/src/tasks/generate/resolve-injectables.js.map +1 -0
  50. package/dist/src/tasks/generate/select-gen-target-name.js +4 -4
  51. package/dist/src/tasks/generate/select-gen-target-name.js.map +1 -1
  52. package/dist/src/tasks/generate/select-gen-target.d.ts +1 -1
  53. package/dist/src/tasks/generate/select-gen-target.js +2 -2
  54. package/dist/src/tasks/generate/select-gen-target.js.map +1 -1
  55. package/dist/src/tasks/stdout/print-generated-results.js +2 -2
  56. package/dist/src/tasks/stdout/print-generated-results.js.map +1 -1
  57. package/dist/src/tasks/sync-configuration.d.ts +1 -1
  58. package/dist/src/tasks/sync-configuration.js +6 -6
  59. package/dist/src/tasks/sync-configuration.js.map +1 -1
  60. package/dist/src/types/state.d.ts +7 -3
  61. package/dist/src/types/state.d.ts.map +1 -1
  62. package/dist/src/types/state.js.map +1 -1
  63. package/package.json +1 -1
  64. package/src/commands/gen.ts +2 -0
  65. package/src/services/project-service.ts +54 -0
  66. package/src/services/templater-service.ts +15 -3
  67. package/src/tasks/generate/generate-command.ts +21 -11
  68. package/src/tasks/generate/generate-service.ts +20 -11
  69. package/src/tasks/generate/generate-task.ts +21 -12
  70. package/src/tasks/generate/project-context-guard.ts +1 -1
  71. package/src/tasks/generate/resolve-injectables.ts +154 -0
  72. package/src/tasks/generate/select-gen-target-name.ts +4 -4
  73. package/src/tasks/generate/select-gen-target.ts +2 -2
  74. package/src/tasks/stdout/print-generated-results.ts +2 -2
  75. package/src/tasks/sync-configuration.ts +6 -6
  76. package/src/types/state.ts +9 -3
  77. package/assets/yargs-template/task-runner/src/tasks/print-banner.ts +0 -73
  78. package/dist/assets/yargs-template/task-runner/src/tasks/print-banner.ts +0 -73
  79. package/dist/src/wrappers/gen-app-task.d.ts +0 -50
  80. package/dist/src/wrappers/gen-app-task.d.ts.map +0 -1
  81. package/dist/src/wrappers/gen-app-task.js +0 -124
  82. package/dist/src/wrappers/gen-app-task.js.map +0 -1
  83. package/src/wrappers/gen-app-task.ts +0 -150
@@ -1,10 +1,11 @@
1
1
  import { singleton } from "tsyringe";
2
2
  import { Command } from "../wrappers/command";
3
3
  import CheckEnv from "../tasks/check-env";
4
- import PrintBanner from "../tasks/print-banner";
4
+ import PrintBanner from "../tasks/banner/print-banner";
5
5
  import LogState from "../tasks/log-state";
6
+ import ResolveBannerFont from "../tasks/banner/resolve-banner-font";
6
7
 
7
8
  @singleton()
8
9
  export class VerifyCommand extends Command {
9
- tasks = [PrintBanner, CheckEnv, LogState];
10
+ tasks = [ResolveBannerFont, PrintBanner, CheckEnv, LogState];
10
11
  }
@@ -1,17 +1,21 @@
1
1
  import { singleton } from "tsyringe";
2
2
  import figlet from "figlet";
3
3
 
4
+ /**
5
+ * BannerService
6
+ *
7
+ * Handles the generation of banner text using figlet.
8
+ *
9
+ * Some figlet fonts to try:
10
+ * ["ANSI Compact", "AMC Slash", "ANSI Shadow",
11
+ * "Basic", "Big", "Bell", "Calvin S", "Coinstak",
12
+ * "DOS Rebel", "Elite", "Emboss", "Future Smooth",
13
+ * "Kban", "Larry 3D 2", "Mono 9", "Shadow",
14
+ * "Small Poison", "Star Wars"]
15
+ */
4
16
  @singleton()
5
17
  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";
18
+ defaultFontFamily: string = "Standard";
15
19
 
16
20
  async toBanner(text: string, font?: string): Promise<string> {
17
21
  return await figlet.text(text, {
@@ -0,0 +1,38 @@
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 bannerService: BannerService,
17
+ private utilService: UtilService,
18
+ ) {
19
+ super();
20
+ }
21
+
22
+ async run({ data: { banner } }: AppState): Promise<Partial<AppState> | void> {
23
+ try {
24
+ console.log(
25
+ chalk.blueBright(
26
+ await this.bannerService.toBanner(
27
+ this.utilService.getAppName(),
28
+ banner?.font,
29
+ ),
30
+ ),
31
+ );
32
+
33
+ this.setData({ banner: { status: "success" } });
34
+ } catch (err) {
35
+ this.setData({ banner: { status: "failed" }, errorMessages: [`${err}`] });
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,70 @@
1
+ import { autoInjectable } from "tsyringe";
2
+ import { BannerService } from "../../services/banner-service";
3
+ import ResolverTask from "../../wrappers/electives/resolver-task";
4
+ import { CLIArgs } from "../../types/state";
5
+
6
+ /**
7
+ * ResolveBannerFont (Optional ResolverTask Pattern)
8
+ *
9
+ * ResolverTask that updates the AppStateData banner field. Resolves the banner
10
+ * font field via user input (bannerFont arg) or a randomly selected font value
11
+ * (randomFont arg). Uses BannerService's default otherwise. Doesn't define an
12
+ * envVar so doesn't support env overrides.
13
+ */
14
+ @autoInjectable()
15
+ export default class ResolveBannerFont extends ResolverTask {
16
+ loggerName = "ResolveBannerFont";
17
+
18
+ resolveTo = "banner" as const;
19
+ argVar = "bannerFont" as const;
20
+
21
+ constructor(private bannerService: BannerService) {
22
+ super();
23
+ }
24
+
25
+ /**
26
+ * Get the default banner font value.
27
+ */
28
+ //@override
29
+ async getDefaultValue<T>(): Promise<T | undefined> {
30
+ return { font: this.bannerService.defaultFontFamily } as T;
31
+ }
32
+
33
+ /**
34
+ * Attempt to resolve the font from the CLI args.
35
+ *
36
+ * @param args the CLIArgs to resolve from.
37
+ * @returns the resolved font, or undefined if no font args provided
38
+ */
39
+ //@override
40
+ async getArg<T>(args: CLIArgs) {
41
+ const bannerFont = args.bannerFont;
42
+ if (bannerFont) {
43
+ await this.validateFont(bannerFont);
44
+ return { font: bannerFont } as T;
45
+ }
46
+
47
+ // also allow --random-font arg as an override
48
+ if (args.randomFont) {
49
+ const randomFont = await this.bannerService.getRandomFont();
50
+ this.logger.debug(`Using random font ${randomFont}`);
51
+ return { font: randomFont } as T;
52
+ }
53
+
54
+ return undefined;
55
+ }
56
+
57
+ /**
58
+ * Validate a provided font is supported.
59
+ *
60
+ * @param font the font to validate.
61
+ * @throws Error if the font is not supported.
62
+ */
63
+ async validateFont(font: string): Promise<void> {
64
+ const availableFonts = await this.bannerService.getSupportedFonts();
65
+
66
+ if (!availableFonts.includes(font)) {
67
+ throw new Error(`Unsupported font provided: ${font}`);
68
+ }
69
+ }
70
+ }
@@ -31,6 +31,10 @@ export const EnvironmentConfigKeys = {
31
31
  PINO_LOG_TARGET: "PINO_LOG_TARGET",
32
32
  };
33
33
 
34
+ export const DefaultValues = {
35
+ debugMode: false,
36
+ };
37
+
34
38
  export type AppTaskClass = TaskClass<AppStateData, CLIArgs>;
35
39
 
36
40
  export type Yargs = typeof yargs;
@@ -1,13 +1,13 @@
1
- import { AppTask } from "./app-task";
1
+ import { AppTask } from "../app-task";
2
2
  import { autoInjectable } from "tsyringe";
3
- import { AppTaskClass } from "../types/state";
3
+ import { AppTaskClass } from "../../types/state";
4
4
 
5
5
  /**
6
6
  * Wrapper for Running a Group of Concurrent Tasks
7
7
  *
8
- * Extend this class and override the tasks array to run tasks
8
+ * Extend this class and override the tasks field to run tasks
9
9
  * concurrently within a Task itself. The fallback run method
10
- * handles state and execution of the tasks.
10
+ * handles the state and execution of the tasks.
11
11
  */
12
12
  @autoInjectable()
13
13
  export default class ConcurrentTaskGroup extends AppTask {
@@ -0,0 +1,87 @@
1
+ import {
2
+ AppState,
3
+ AppStateData,
4
+ CLIArgs,
5
+ DefaultValues,
6
+ EnvironmentConfigKeys,
7
+ } from "../../types/state";
8
+ import { AppTask } from "../app-task";
9
+ import { autoInjectable } from "tsyringe";
10
+
11
+ /**
12
+ * ResolverTask
13
+ *
14
+ * Wrapper Task that resolves a value in the AppStateData.
15
+ *
16
+ * Allows enforcing the following order of precedence for resolving a value:
17
+ * - CLI arg (if provided)
18
+ * - Environment variable (if set)
19
+ * - Default / Fallback value
20
+ */
21
+ @autoInjectable()
22
+ export default class ResolverTask extends AppTask {
23
+ loggerName = "Resolver";
24
+
25
+ /*
26
+ Extend the class and override the following fields to customize the resolver.
27
+ */
28
+
29
+ // the target field to resolve on AppStateData
30
+ declare resolveTo: keyof AppStateData;
31
+
32
+ // arg override has highest precedence
33
+ declare argVar?: keyof CLIArgs;
34
+
35
+ // then env override
36
+ declare envVar?: keyof typeof EnvironmentConfigKeys;
37
+
38
+ // finally, a default fallback value can be provided
39
+ declare defaultKey?: keyof typeof DefaultValues;
40
+
41
+ /*
42
+ Optionally, override these methods to customize additional behavior of the resolver.
43
+ */
44
+ async getDefaultValue<T>(): Promise<T | undefined> {
45
+ return this.defaultKey ? (DefaultValues[this.defaultKey] as T) : undefined;
46
+ }
47
+ async getArg<T>(args: CLIArgs): Promise<T | undefined> {
48
+ if (this.argVar && args[this.argVar]) {
49
+ return args[this.argVar] as T;
50
+ }
51
+ }
52
+ async getEnv<T>(): Promise<T | undefined> {
53
+ if (this.envVar && process.env[this.envVar]) {
54
+ return process.env[this.envVar] as T;
55
+ }
56
+ }
57
+
58
+ /*
59
+ The ResolverTask run method keeps the resolution order consistent across all
60
+ resolver tasks. It should not be overridden subclasses.
61
+ */
62
+ async run(): Promise<Partial<AppState> | void> {
63
+ const argResult = await this.getArg(this.state.args);
64
+ if (argResult) {
65
+ return {
66
+ data: {
67
+ [this.resolveTo]: argResult,
68
+ },
69
+ };
70
+ }
71
+
72
+ const envResult = await this.getEnv();
73
+ if (envResult) {
74
+ return {
75
+ data: {
76
+ [this.resolveTo]: envResult,
77
+ },
78
+ };
79
+ }
80
+
81
+ return {
82
+ data: {
83
+ [this.resolveTo]: await this.getDefaultValue(),
84
+ },
85
+ };
86
+ }
87
+ }
@@ -1,12 +1,12 @@
1
- import { AppTask } from "./app-task";
1
+ import { AppTask } from "../app-task";
2
2
  import { autoInjectable } from "tsyringe";
3
- import { AppTaskClass } from "../types/state";
3
+ import { AppTaskClass } from "../../types/state";
4
4
 
5
5
  /**
6
6
  * Wrapper for Running a Group of Sequential Tasks
7
7
  *
8
- * Extend this class and override the tasks array to run a sequence
9
- * of tasks in order as a Task. The fallback run method handles state
8
+ * Extend this class and override the tasks field to run a sequence
9
+ * of tasks in order as a Task. The fallback run method handles the state
10
10
  * and execution of the tasks.
11
11
  */
12
12
  @autoInjectable()
@@ -1,41 +1,34 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import { describe, it, expect, vi } from "vitest";
3
- import PrintBanner from "../../src/tasks/print-banner";
3
+ import PrintBanner from "../../src/tasks/banner/print-banner";
4
4
  import CheckEnv from "../../src/tasks/check-env";
5
5
  import { container } from "tsyringe";
6
- import { CommandService } from "task-script-support";
7
- import { AppStateData, CLIArgs } from "../../src/types/state";
6
+ import ResolveBannerFont from "../../src/tasks/banner/resolve-banner-font";
7
+ import { VerifyCommand } from "../../src/commands/verify";
8
+ import { CLIArgs } from "../../src/types/state";
8
9
 
9
- // Mock the tasks and their run methods
10
- vi.mock("../../src/tasks/print-banner", () => {
11
- const PrintBannerMock = vi.fn();
12
- PrintBannerMock.prototype.run = vi.fn();
13
- return { default: PrintBannerMock };
14
- });
15
-
16
- vi.mock("../../src/tasks/check-env", () => {
17
- const CheckEnvMock = vi.fn();
18
- CheckEnvMock.prototype.run = vi.fn();
19
- return { default: CheckEnvMock };
20
- });
10
+ vi.mock("../../src/tasks/banner/resolve-banner-font");
11
+ vi.mock("../../src/tasks/banner/print-banner");
12
+ vi.mock("../../src/tasks/check-env");
13
+ vi.mock("../../src/tasks/log-state");
21
14
 
22
15
  describe("verify command", () => {
23
16
  it("should run PrintBanner and then CheckEnv", async () => {
24
- const tasks = [PrintBanner, CheckEnv];
25
- container.register("Args", { useValue: [] });
17
+ const args: CLIArgs[] = [];
26
18
 
19
+ container.register("Args", { useValue: args });
27
20
  // when
28
- await new CommandService<AppStateData, CLIArgs>().runTasks(
29
- tasks,
30
- {} as CLIArgs,
31
- );
21
+ await container.resolve(VerifyCommand).handler(args);
32
22
 
33
23
  expect(PrintBanner).toHaveBeenCalled();
34
24
  expect(CheckEnv).toHaveBeenCalled();
35
25
 
36
26
  const printBannerInstance = (PrintBanner as any).mock.instances[0];
37
27
  const checkEnvInstance = (CheckEnv as any).mock.instances[0];
28
+ const resolveBannerFontInstance = (ResolveBannerFont as any).mock
29
+ .instances[0];
38
30
 
31
+ expect(resolveBannerFontInstance.run).toHaveBeenCalled();
39
32
  expect(printBannerInstance.run).toHaveBeenCalled();
40
33
  expect(checkEnvInstance.run).toHaveBeenCalled();
41
34
  });
@@ -1,10 +1,11 @@
1
1
  import { singleton } from "tsyringe";
2
2
  import { Command } from "../wrappers/command";
3
3
  import CheckEnv from "../tasks/check-env";
4
- import PrintBanner from "../tasks/print-banner";
4
+ import PrintBanner from "../tasks/banner/print-banner";
5
5
  import LogState from "../tasks/log-state";
6
+ import ResolveBannerFont from "../tasks/banner/resolve-banner-font";
6
7
 
7
8
  @singleton()
8
9
  export class VerifyCommand extends Command {
9
- tasks = [PrintBanner, CheckEnv, LogState];
10
+ tasks = [ResolveBannerFont, PrintBanner, CheckEnv, LogState];
10
11
  }
@@ -1,17 +1,21 @@
1
1
  import { singleton } from "tsyringe";
2
2
  import figlet from "figlet";
3
3
 
4
+ /**
5
+ * BannerService
6
+ *
7
+ * Handles the generation of banner text using figlet.
8
+ *
9
+ * Some figlet fonts to try:
10
+ * ["ANSI Compact", "AMC Slash", "ANSI Shadow",
11
+ * "Basic", "Big", "Bell", "Calvin S", "Coinstak",
12
+ * "DOS Rebel", "Elite", "Emboss", "Future Smooth",
13
+ * "Kban", "Larry 3D 2", "Mono 9", "Shadow",
14
+ * "Small Poison", "Star Wars"]
15
+ */
4
16
  @singleton()
5
17
  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";
18
+ defaultFontFamily: string = "Standard";
15
19
 
16
20
  async toBanner(text: string, font?: string): Promise<string> {
17
21
  return await figlet.text(text, {
@@ -0,0 +1,38 @@
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 bannerService: BannerService,
17
+ private utilService: UtilService,
18
+ ) {
19
+ super();
20
+ }
21
+
22
+ async run({ data: { banner } }: AppState): Promise<Partial<AppState> | void> {
23
+ try {
24
+ console.log(
25
+ chalk.blueBright(
26
+ await this.bannerService.toBanner(
27
+ this.utilService.getAppName(),
28
+ banner?.font,
29
+ ),
30
+ ),
31
+ );
32
+
33
+ this.setData({ banner: { status: "success" } });
34
+ } catch (err) {
35
+ this.setData({ banner: { status: "failed" }, errorMessages: [`${err}`] });
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,70 @@
1
+ import { autoInjectable } from "tsyringe";
2
+ import { BannerService } from "../../services/banner-service";
3
+ import ResolverTask from "../../wrappers/electives/resolver-task";
4
+ import { CLIArgs } from "../../types/state";
5
+
6
+ /**
7
+ * ResolveBannerFont (Optional ResolverTask Pattern)
8
+ *
9
+ * ResolverTask that updates the AppStateData banner field. Resolves the banner
10
+ * font field via user input (bannerFont arg) or a randomly selected font value
11
+ * (randomFont arg). Uses BannerService's default otherwise. Doesn't define an
12
+ * envVar so doesn't support env overrides.
13
+ */
14
+ @autoInjectable()
15
+ export default class ResolveBannerFont extends ResolverTask {
16
+ loggerName = "ResolveBannerFont";
17
+
18
+ resolveTo = "banner" as const;
19
+ argVar = "bannerFont" as const;
20
+
21
+ constructor(private bannerService: BannerService) {
22
+ super();
23
+ }
24
+
25
+ /**
26
+ * Get the default banner font value.
27
+ */
28
+ //@override
29
+ async getDefaultValue<T>(): Promise<T | undefined> {
30
+ return { font: this.bannerService.defaultFontFamily } as T;
31
+ }
32
+
33
+ /**
34
+ * Attempt to resolve the font from the CLI args.
35
+ *
36
+ * @param args the CLIArgs to resolve from.
37
+ * @returns the resolved font, or undefined if no font args provided
38
+ */
39
+ //@override
40
+ async getArg<T>(args: CLIArgs) {
41
+ const bannerFont = args.bannerFont;
42
+ if (bannerFont) {
43
+ await this.validateFont(bannerFont);
44
+ return { font: bannerFont } as T;
45
+ }
46
+
47
+ // also allow --random-font arg as an override
48
+ if (args.randomFont) {
49
+ const randomFont = await this.bannerService.getRandomFont();
50
+ this.logger.debug(`Using random font ${randomFont}`);
51
+ return { font: randomFont } as T;
52
+ }
53
+
54
+ return undefined;
55
+ }
56
+
57
+ /**
58
+ * Validate a provided font is supported.
59
+ *
60
+ * @param font the font to validate.
61
+ * @throws Error if the font is not supported.
62
+ */
63
+ async validateFont(font: string): Promise<void> {
64
+ const availableFonts = await this.bannerService.getSupportedFonts();
65
+
66
+ if (!availableFonts.includes(font)) {
67
+ throw new Error(`Unsupported font provided: ${font}`);
68
+ }
69
+ }
70
+ }
@@ -31,6 +31,10 @@ export const EnvironmentConfigKeys = {
31
31
  PINO_LOG_TARGET: "PINO_LOG_TARGET",
32
32
  };
33
33
 
34
+ export const DefaultValues = {
35
+ debugMode: false,
36
+ };
37
+
34
38
  export type AppTaskClass = TaskClass<AppStateData, CLIArgs>;
35
39
 
36
40
  export type Yargs = typeof yargs;
@@ -1,13 +1,13 @@
1
- import { AppTask } from "./app-task";
1
+ import { AppTask } from "../app-task";
2
2
  import { autoInjectable } from "tsyringe";
3
- import { AppTaskClass } from "../types/state";
3
+ import { AppTaskClass } from "../../types/state";
4
4
 
5
5
  /**
6
6
  * Wrapper for Running a Group of Concurrent Tasks
7
7
  *
8
- * Extend this class and override the tasks array to run tasks
8
+ * Extend this class and override the tasks field to run tasks
9
9
  * concurrently within a Task itself. The fallback run method
10
- * handles state and execution of the tasks.
10
+ * handles the state and execution of the tasks.
11
11
  */
12
12
  @autoInjectable()
13
13
  export default class ConcurrentTaskGroup extends AppTask {
@@ -0,0 +1,87 @@
1
+ import {
2
+ AppState,
3
+ AppStateData,
4
+ CLIArgs,
5
+ DefaultValues,
6
+ EnvironmentConfigKeys,
7
+ } from "../../types/state";
8
+ import { AppTask } from "../app-task";
9
+ import { autoInjectable } from "tsyringe";
10
+
11
+ /**
12
+ * ResolverTask
13
+ *
14
+ * Wrapper Task that resolves a value in the AppStateData.
15
+ *
16
+ * Allows enforcing the following order of precedence for resolving a value:
17
+ * - CLI arg (if provided)
18
+ * - Environment variable (if set)
19
+ * - Default / Fallback value
20
+ */
21
+ @autoInjectable()
22
+ export default class ResolverTask extends AppTask {
23
+ loggerName = "Resolver";
24
+
25
+ /*
26
+ Extend the class and override the following fields to customize the resolver.
27
+ */
28
+
29
+ // the target field to resolve on AppStateData
30
+ declare resolveTo: keyof AppStateData;
31
+
32
+ // arg override has highest precedence
33
+ declare argVar?: keyof CLIArgs;
34
+
35
+ // then env override
36
+ declare envVar?: keyof typeof EnvironmentConfigKeys;
37
+
38
+ // finally, a default fallback value can be provided
39
+ declare defaultKey?: keyof typeof DefaultValues;
40
+
41
+ /*
42
+ Optionally, override these methods to customize additional behavior of the resolver.
43
+ */
44
+ async getDefaultValue<T>(): Promise<T | undefined> {
45
+ return this.defaultKey ? (DefaultValues[this.defaultKey] as T) : undefined;
46
+ }
47
+ async getArg<T>(args: CLIArgs): Promise<T | undefined> {
48
+ if (this.argVar && args[this.argVar]) {
49
+ return args[this.argVar] as T;
50
+ }
51
+ }
52
+ async getEnv<T>(): Promise<T | undefined> {
53
+ if (this.envVar && process.env[this.envVar]) {
54
+ return process.env[this.envVar] as T;
55
+ }
56
+ }
57
+
58
+ /*
59
+ The ResolverTask run method keeps the resolution order consistent across all
60
+ resolver tasks. It should not be overridden subclasses.
61
+ */
62
+ async run(): Promise<Partial<AppState> | void> {
63
+ const argResult = await this.getArg(this.state.args);
64
+ if (argResult) {
65
+ return {
66
+ data: {
67
+ [this.resolveTo]: argResult,
68
+ },
69
+ };
70
+ }
71
+
72
+ const envResult = await this.getEnv();
73
+ if (envResult) {
74
+ return {
75
+ data: {
76
+ [this.resolveTo]: envResult,
77
+ },
78
+ };
79
+ }
80
+
81
+ return {
82
+ data: {
83
+ [this.resolveTo]: await this.getDefaultValue(),
84
+ },
85
+ };
86
+ }
87
+ }
@@ -1,12 +1,12 @@
1
- import { AppTask } from "./app-task";
1
+ import { AppTask } from "../app-task";
2
2
  import { autoInjectable } from "tsyringe";
3
- import { AppTaskClass } from "../types/state";
3
+ import { AppTaskClass } from "../../types/state";
4
4
 
5
5
  /**
6
6
  * Wrapper for Running a Group of Sequential Tasks
7
7
  *
8
- * Extend this class and override the tasks array to run a sequence
9
- * of tasks in order as a Task. The fallback run method handles state
8
+ * Extend this class and override the tasks field to run a sequence
9
+ * of tasks in order as a Task. The fallback run method handles the state
10
10
  * and execution of the tasks.
11
11
  */
12
12
  @autoInjectable()