task-script-support-cli 0.3.0 → 0.3.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 (85) hide show
  1. package/assets/yargs-template/task-runner/package-lock.json +128 -110
  2. package/assets/yargs-template/task-runner/src/commands/verify.ts +3 -2
  3. package/assets/yargs-template/task-runner/src/services/banner-service.ts +13 -9
  4. package/assets/yargs-template/task-runner/src/tasks/banner/print-banner.ts +38 -0
  5. package/assets/yargs-template/task-runner/src/tasks/banner/resolve-banner-font.ts +70 -0
  6. package/assets/yargs-template/task-runner/src/types/state.ts +4 -0
  7. package/{dist/assets/yargs-template/task-runner/src/wrappers → assets/yargs-template/task-runner/src/wrappers/electives}/concurrent-task-group.ts +4 -4
  8. package/assets/yargs-template/task-runner/src/wrappers/electives/resolver-task.ts +87 -0
  9. package/assets/yargs-template/task-runner/src/wrappers/{sequential-task-group.ts → electives/sequential-task-group.ts} +4 -4
  10. package/assets/yargs-template/task-runner/tests/commands/verify.test.ts +14 -21
  11. package/dist/assets/yargs-template/task-runner/package-lock.json +128 -110
  12. package/dist/assets/yargs-template/task-runner/src/commands/verify.ts +3 -2
  13. package/dist/assets/yargs-template/task-runner/src/services/banner-service.ts +13 -9
  14. package/dist/assets/yargs-template/task-runner/src/tasks/banner/print-banner.ts +38 -0
  15. package/dist/assets/yargs-template/task-runner/src/tasks/banner/resolve-banner-font.ts +70 -0
  16. package/dist/assets/yargs-template/task-runner/src/types/state.ts +4 -0
  17. package/{assets/yargs-template/task-runner/src/wrappers → dist/assets/yargs-template/task-runner/src/wrappers/electives}/concurrent-task-group.ts +4 -4
  18. package/dist/assets/yargs-template/task-runner/src/wrappers/electives/resolver-task.ts +87 -0
  19. package/dist/assets/yargs-template/task-runner/src/wrappers/{sequential-task-group.ts → electives/sequential-task-group.ts} +4 -4
  20. package/dist/assets/yargs-template/task-runner/tests/commands/verify.test.ts +14 -21
  21. package/dist/package.json +1 -1
  22. package/dist/src/commands/gen.d.ts +3 -1
  23. package/dist/src/commands/gen.d.ts.map +1 -1
  24. package/dist/src/commands/gen.js +2 -0
  25. package/dist/src/commands/gen.js.map +1 -1
  26. package/dist/src/services/project-service.d.ts +21 -0
  27. package/dist/src/services/project-service.d.ts.map +1 -1
  28. package/dist/src/services/project-service.js +41 -0
  29. package/dist/src/services/project-service.js.map +1 -1
  30. package/dist/src/services/templater-service.d.ts +1 -0
  31. package/dist/src/services/templater-service.d.ts.map +1 -1
  32. package/dist/src/services/templater-service.js +9 -3
  33. package/dist/src/services/templater-service.js.map +1 -1
  34. package/dist/src/tasks/generate/generate-command.d.ts +10 -3
  35. package/dist/src/tasks/generate/generate-command.d.ts.map +1 -1
  36. package/dist/src/tasks/generate/generate-command.js +27 -11
  37. package/dist/src/tasks/generate/generate-command.js.map +1 -1
  38. package/dist/src/tasks/generate/generate-service.d.ts +10 -3
  39. package/dist/src/tasks/generate/generate-service.d.ts.map +1 -1
  40. package/dist/src/tasks/generate/generate-service.js +26 -12
  41. package/dist/src/tasks/generate/generate-service.js.map +1 -1
  42. package/dist/src/tasks/generate/generate-task.d.ts +10 -3
  43. package/dist/src/tasks/generate/generate-task.d.ts.map +1 -1
  44. package/dist/src/tasks/generate/generate-task.js +27 -13
  45. package/dist/src/tasks/generate/generate-task.js.map +1 -1
  46. package/dist/src/tasks/generate/project-context-guard.d.ts +1 -1
  47. package/dist/src/tasks/generate/project-context-guard.js +1 -1
  48. package/dist/src/tasks/generate/resolve-injectables.d.ts +56 -0
  49. package/dist/src/tasks/generate/resolve-injectables.d.ts.map +1 -0
  50. package/dist/src/tasks/generate/resolve-injectables.js +134 -0
  51. package/dist/src/tasks/generate/resolve-injectables.js.map +1 -0
  52. package/dist/src/tasks/generate/select-gen-target-name.js +4 -4
  53. package/dist/src/tasks/generate/select-gen-target-name.js.map +1 -1
  54. package/dist/src/tasks/generate/select-gen-target.d.ts +1 -1
  55. package/dist/src/tasks/generate/select-gen-target.js +2 -2
  56. package/dist/src/tasks/generate/select-gen-target.js.map +1 -1
  57. package/dist/src/tasks/stdout/print-generated-results.js +2 -2
  58. package/dist/src/tasks/stdout/print-generated-results.js.map +1 -1
  59. package/dist/src/tasks/sync-configuration.d.ts +1 -1
  60. package/dist/src/tasks/sync-configuration.js +6 -6
  61. package/dist/src/tasks/sync-configuration.js.map +1 -1
  62. package/dist/src/types/state.d.ts +7 -3
  63. package/dist/src/types/state.d.ts.map +1 -1
  64. package/dist/src/types/state.js.map +1 -1
  65. package/package.json +1 -1
  66. package/src/commands/gen.ts +2 -0
  67. package/src/services/project-service.ts +54 -0
  68. package/src/services/templater-service.ts +15 -3
  69. package/src/tasks/generate/generate-command.ts +21 -11
  70. package/src/tasks/generate/generate-service.ts +20 -11
  71. package/src/tasks/generate/generate-task.ts +21 -12
  72. package/src/tasks/generate/project-context-guard.ts +1 -1
  73. package/src/tasks/generate/resolve-injectables.ts +154 -0
  74. package/src/tasks/generate/select-gen-target-name.ts +4 -4
  75. package/src/tasks/generate/select-gen-target.ts +2 -2
  76. package/src/tasks/stdout/print-generated-results.ts +2 -2
  77. package/src/tasks/sync-configuration.ts +6 -6
  78. package/src/types/state.ts +9 -3
  79. package/assets/yargs-template/task-runner/src/tasks/print-banner.ts +0 -73
  80. package/dist/assets/yargs-template/task-runner/src/tasks/print-banner.ts +0 -73
  81. package/dist/src/wrappers/gen-app-task.d.ts +0 -50
  82. package/dist/src/wrappers/gen-app-task.d.ts.map +0 -1
  83. package/dist/src/wrappers/gen-app-task.js +0 -124
  84. package/dist/src/wrappers/gen-app-task.js.map +0 -1
  85. package/src/wrappers/gen-app-task.ts +0 -150
@@ -1,17 +1,21 @@
1
1
  import { CLIArg } from "./process";
2
2
  import { AppState as State, TaskClass } from "task-script-support";
3
- import { ProjectConfig, ProjectData } from "./project";
3
+ import { ProjectConfig, ProjectData, ProjectImport } from "./project";
4
4
  export declare enum GenTargetType {
5
5
  Command = "command",
6
6
  Service = "service",
7
7
  Task = "task"
8
8
  }
9
+ export interface GenData {
10
+ readonly targetType?: GenTargetType;
11
+ readonly targetName?: string;
12
+ readonly imports?: ProjectImport[];
13
+ }
9
14
  export interface AppStateData {
10
15
  readonly banner?: {
11
16
  readonly font?: string;
12
17
  };
13
- readonly genTargetType?: GenTargetType;
14
- readonly genTargetName?: string;
18
+ readonly genData?: GenData;
15
19
  readonly environmentValidated?: boolean;
16
20
  readonly project?: ProjectConfig & ProjectData;
17
21
  readonly errorMessages?: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"./src/","sources":["src/types/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,QAAQ,IAAI,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAEvD,oBAAY,aAAa;IACvB,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,IAAI,SAAS;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE;QAChB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAEhC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,WAAW,CAAC;IAE/C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,eAAO,MAAM,qBAAqB;;;;;;;CAOjC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;AACrD,MAAM,MAAM,YAAY,GAAG,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"./src/","sources":["src/types/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,QAAQ,IAAI,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEtE,oBAAY,aAAa;IACvB,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,IAAI,SAAS;CACd;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE;QAChB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IAEF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAE3B,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,WAAW,CAAC;IAE/C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,eAAO,MAAM,qBAAqB;;;;;;;CAOjC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;AACrD,MAAM,MAAM,YAAY,GAAG,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","sourceRoot":"./src/","sources":["src/types/state.ts"],"names":[],"mappings":";;;AAIA,IAAY,aAIX;AAJD,WAAY,aAAa;IACvB,oCAAmB,CAAA;IACnB,oCAAmB,CAAA;IACnB,8BAAa,CAAA;AACf,CAAC,EAJW,aAAa,6BAAb,aAAa,QAIxB;AAgBY,QAAA,qBAAqB,GAAG;IACnC,iBAAiB,EAAE,mBAAmB;IACtC,cAAc,EAAE,gBAAgB;IAChC,QAAQ,EAAE,UAAU;IACpB,iBAAiB,EAAE,mBAAmB;IACtC,eAAe,EAAE,iBAAiB;IAClC,mBAAmB,EAAE,qBAAqB;CAC3C,CAAC"}
1
+ {"version":3,"file":"state.js","sourceRoot":"./src/","sources":["src/types/state.ts"],"names":[],"mappings":";;;AAIA,IAAY,aAIX;AAJD,WAAY,aAAa;IACvB,oCAAmB,CAAA;IACnB,oCAAmB,CAAA;IACnB,8BAAa,CAAA;AACf,CAAC,EAJW,aAAa,6BAAb,aAAa,QAIxB;AAsBY,QAAA,qBAAqB,GAAG;IACnC,iBAAiB,EAAE,mBAAmB;IACtC,cAAc,EAAE,gBAAgB;IAChC,QAAQ,EAAE,UAAU;IACpB,iBAAiB,EAAE,mBAAmB;IACtC,eAAe,EAAE,iBAAiB;IAClC,mBAAmB,EAAE,qBAAqB;CAC3C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "task-script-support-cli",
3
- "version": "0.3.0",
3
+ "version": "0.3.3",
4
4
  "main": "index.js",
5
5
  "type": "commonjs",
6
6
  "preferGlobal": true,
@@ -10,6 +10,7 @@ import PrintGeneratedResults from "../tasks/stdout/print-generated-results";
10
10
  import SyncConfiguration from "../tasks/sync-configuration";
11
11
  import SelectGenTargetName from "../tasks/generate/select-gen-target-name";
12
12
  import ProjectContextGuard from "../tasks/generate/project-context-guard";
13
+ import ResolveInjectables from "../tasks/generate/resolve-injectables";
13
14
 
14
15
  @singleton()
15
16
  export class GenCommand extends Command {
@@ -20,6 +21,7 @@ export class GenCommand extends Command {
20
21
  SelectGenTarget,
21
22
  SyncConfiguration,
22
23
  SelectGenTargetName,
24
+ ResolveInjectables,
23
25
  [GenerateCommand, GenerateService, GenerateTask],
24
26
  PrintGeneratedResults,
25
27
  ];
@@ -2,6 +2,8 @@ import { autoInjectable } from "tsyringe";
2
2
  import { FileService } from "./file-service";
3
3
  import { CaseType } from "../types/format";
4
4
  import { UtilService } from "./util-service";
5
+ import { GenData } from "../types/state";
6
+ import { ProjectImport } from "../types/project";
5
7
 
6
8
  @autoInjectable()
7
9
  export class ProjectService {
@@ -17,6 +19,42 @@ export class ProjectService {
17
19
  private utilService: UtilService,
18
20
  ) {}
19
21
 
22
+ /**
23
+ * Formalize the selected imports into a format that can be used in the source code being generated.
24
+ *
25
+ * 1. Generate a PascalCased import name from the filename
26
+ * 2. Convert to a relative path
27
+ * 3. Remove the file extension for TypeScript import
28
+ *
29
+ * @param selectedPaths the selected file paths to formalize
30
+ * @param relativeSource the path to the source file being generated to resolve relative paths
31
+ * @returns the formalized ProjectImport array ({ importClassName, importPath })
32
+ */
33
+ formalizeImports(
34
+ selectedPaths: string[],
35
+ relativeSource: string,
36
+ ): ProjectImport[] {
37
+ if (!selectedPaths?.length) {
38
+ return [];
39
+ }
40
+ const formalizedPaths: ProjectImport[] = [];
41
+ for (const fullPath of selectedPaths) {
42
+ const filename = this.fileService.getFilenameNoExt(fullPath);
43
+ const importClassName = this.utilService.titleizedToCase(
44
+ this.utilService.titleizeAll(filename),
45
+ CaseType.PASCAL_CASE,
46
+ );
47
+
48
+ formalizedPaths.push({
49
+ importClassName,
50
+ importPath: this.fileService
51
+ .toRelativePath(relativeSource, fullPath)
52
+ .replace(ProjectService.defaults.extention, ""),
53
+ });
54
+ }
55
+ return formalizedPaths;
56
+ }
57
+
20
58
  /**
21
59
  * Get all task files found in the project
22
60
  *
@@ -46,6 +84,22 @@ export class ProjectService {
46
84
  ];
47
85
  }
48
86
 
87
+ /**
88
+ * Returns a map of import class names to import paths.
89
+ *
90
+ * @param genData the GenData object containing the ProjectImport objects to map
91
+ * @returns a Map of import class names to relative import paths
92
+ */
93
+ getImportMap(genData: GenData) {
94
+ const imports = genData.imports || [];
95
+ return new Map<string, string>(
96
+ imports.map((imp: ProjectImport) => [
97
+ imp.importClassName,
98
+ imp.importPath,
99
+ ]),
100
+ );
101
+ }
102
+
49
103
  /**
50
104
  * Looks for a naming convention on the given filename array. Returns
51
105
  * the first found convention or the default one if it can't be detected.
@@ -4,6 +4,7 @@ import { autoInjectable } from "tsyringe";
4
4
  import { SpawnService } from "./spawn-service";
5
5
  import { LogService } from "./log-service";
6
6
  import { dockerIgnoreTemplate } from "../templates/docker-ignore";
7
+ import chalk from "chalk";
7
8
 
8
9
  const gitignoreContent = `node_modules
9
10
  dist
@@ -78,11 +79,19 @@ export class TemplateService {
78
79
  }
79
80
  }
80
81
 
82
+ toLogPath(pathString: string) {
83
+ return path.relative(
84
+ process.cwd(),
85
+ pathString.replaceAll("task-runner", this.outputName),
86
+ );
87
+ }
88
+
81
89
  private async copyDirectories() {
82
90
  for (const folder of this.dirListToCopy) {
83
91
  const src = path.join(this.sourceDir, folder);
84
92
  const dest = path.join(this.destination, folder);
85
- this.logger.debug(`Running Copy: cp -R ${src} ${dest}`);
93
+ // this.logger.debug(`Running Copy: cp -R ${src} ${dest}`);;
94
+ this.logger.debug(`Generating folder ${chalk.dim(this.toLogPath(dest))}`);
86
95
  fs.cpSync(src, dest, { recursive: true });
87
96
  }
88
97
  }
@@ -91,7 +100,8 @@ export class TemplateService {
91
100
  for (const filename of this.fileListToCopy) {
92
101
  const src = path.join(this.sourceDir, filename);
93
102
  const dest = path.join(this.destination, filename);
94
- this.logger.debug(`Running Copy: cp ${src} ${dest}`);
103
+ // this.logger.debug(`Running Copy: cp ${src} ${dest}`);
104
+ this.logger.debug(`Generating file ${chalk.dim(this.toLogPath(dest))}`);
95
105
  fs.copyFileSync(src, dest);
96
106
  }
97
107
  }
@@ -135,7 +145,9 @@ export class TemplateService {
135
145
  const rename = (ext = "") => {
136
146
  const src = path.join(this.destination, `task-runner${ext}`);
137
147
  const dest = path.join(this.destination, `${this.outputName}${ext}`);
138
- this.logger.debug(`Renaming task-runner to ${this.outputName}${ext}`);
148
+ this.logger.debug(
149
+ `Fixing references ${chalk.dim(`(${this.outputName}${ext})`)}`,
150
+ );
139
151
  fs.renameSync(src, dest);
140
152
  };
141
153
  rename();
@@ -5,15 +5,25 @@ import { CaseType } from "../../types/format";
5
5
  import path from "path";
6
6
  import { getCommandTemplate } from "../../templates/command";
7
7
  import { ProjectService } from "../../services/project-service";
8
- import GenerateAppTask from "../../wrappers/gen-app-task";
8
+ import { AppTask } from "../../wrappers/app-task";
9
+ import { FileService } from "../../services/file-service";
10
+ import { UtilService } from "../../services/util-service";
9
11
 
10
12
  /**
11
13
  * Generates a new command class
12
14
  */
13
15
  @autoInjectable()
14
- export default class GenerateCommand extends GenerateAppTask {
16
+ export default class GenerateCommand extends AppTask {
15
17
  loggerName = "Generate Command";
16
18
 
19
+ constructor(
20
+ private fileService: FileService,
21
+ private projectService: ProjectService,
22
+ private utilService: UtilService,
23
+ ) {
24
+ super();
25
+ }
26
+
17
27
  /**
18
28
  * Generates a new command class file.
19
29
  *
@@ -22,12 +32,12 @@ export default class GenerateCommand extends GenerateAppTask {
22
32
  async run(): Promise<void | Partial<AppState>> {
23
33
  const { utilService, fileService, projectService } = this;
24
34
 
25
- if (this.state.data.genTargetType !== GenTargetType.Command) {
35
+ if (this.state.data.genData!.targetType !== GenTargetType.Command) {
26
36
  return; // no-op
27
37
  }
28
38
 
29
39
  this.logger.info(chalk.blueBright("Generating Command"));
30
- const targetName = this.state.data.genTargetName!;
40
+ const targetName = this.state.data.genData!.targetName!;
31
41
  const targetDirectory = this.state.data.project!.commandDestination!;
32
42
 
33
43
  // detect case between commands and task files
@@ -40,10 +50,10 @@ export default class GenerateCommand extends GenerateAppTask {
40
50
  );
41
51
  const filename = `${utilService.titleizedToCase(targetName, convention)}${ProjectService.defaults.extention}`;
42
52
 
43
- const injectableMappings = new Map<string, string>();
44
- await this.addTasksToMap(injectableMappings);
45
-
46
- const rendered = getCommandTemplate(className, injectableMappings);
53
+ const injectablesMap = this.projectService.getImportMap(
54
+ this.state.data.genData!,
55
+ );
56
+ const rendered = getCommandTemplate(className, injectablesMap);
47
57
  const destination = path.join(targetDirectory, filename);
48
58
 
49
59
  // write contents
@@ -53,13 +63,13 @@ export default class GenerateCommand extends GenerateAppTask {
53
63
 
54
64
  /**
55
65
  * Checks state for required fields. Executes prior to run method.
56
- * Skips validation if genTargetType is not set to command.
66
+ * Skips validation if genData.targetType is not set to command.
57
67
  */
58
68
  async preRun() {
59
- if (this.state.data.genTargetType !== GenTargetType.Command) {
69
+ if (this.state.data.genData!.targetType !== GenTargetType.Command) {
60
70
  return; // no validation on no-op flow
61
71
  }
62
- if (!this.state.data.genTargetName) {
72
+ if (!this.state.data.genData!.targetName) {
63
73
  throw new Error("Unable to determine targetName");
64
74
  }
65
75
  if (!this.state.data.project) {
@@ -5,29 +5,39 @@ import { ProjectService } from "../../services/project-service";
5
5
  import { CaseType } from "../../types/format";
6
6
  import path from "path";
7
7
  import { getServiceTemplate } from "../../templates/service";
8
- import GenerateAppTask from "../../wrappers/gen-app-task";
8
+ import { AppTask } from "../../wrappers/app-task";
9
+ import { FileService } from "../../services/file-service";
10
+ import { UtilService } from "../../services/util-service";
9
11
 
10
12
  /**
11
13
  * Generates a new service class
12
14
  */
13
15
  @autoInjectable()
14
- export default class GenerateService extends GenerateAppTask {
16
+ export default class GenerateService extends AppTask {
15
17
  loggerName = "Generate Service";
16
18
 
19
+ constructor(
20
+ private fileService: FileService,
21
+ private projectService: ProjectService,
22
+ private utilService: UtilService,
23
+ ) {
24
+ super();
25
+ }
26
+
17
27
  /**
18
28
  * Generates a new service class file.
19
29
  *
20
30
  * @returns updated state with outputDestination set to a generated result path.
21
31
  */
22
32
  async run() {
23
- if (this.state.data.genTargetType !== GenTargetType.Service) {
33
+ if (this.state.data.genData!.targetType !== GenTargetType.Service) {
24
34
  return;
25
35
  }
26
36
 
27
37
  this.logger.info(chalk.blueBright("Generating Service"));
28
38
  const { utilService, projectService } = this;
29
39
 
30
- const targetName = this.state.data.genTargetName!;
40
+ const targetName = this.state.data.genData!.targetName!;
31
41
  const targetDirectory = this.state.data.project!.serviceDestination!;
32
42
 
33
43
  // detect case
@@ -38,10 +48,9 @@ export default class GenerateService extends GenerateAppTask {
38
48
  CaseType.PASCAL_CASE,
39
49
  );
40
50
 
41
- const injectableMappings = new Map<string, string>();
42
- if (this.argService.hasFlag("inject")) {
43
- await this.addServicesToMap(injectableMappings, targetDirectory);
44
- }
51
+ const injectableMappings = this.projectService.getImportMap(
52
+ this.state.data.genData!,
53
+ );
45
54
  const rendered = getServiceTemplate(className, injectableMappings);
46
55
  const filename = `${utilService.titleizedToCase(targetName, convention)}${ProjectService.defaults.extention}`;
47
56
  const destination = path.join(targetDirectory, filename);
@@ -53,13 +62,13 @@ export default class GenerateService extends GenerateAppTask {
53
62
 
54
63
  /**
55
64
  * Checks state for required fields. Executes prior to run method.
56
- * Skips validation if genTargetType is not set to service.
65
+ * Skips validation if genData.targetType is not set to service.
57
66
  */
58
67
  async preRun() {
59
- if (this.state.data.genTargetType !== GenTargetType.Service) {
68
+ if (this.state.data.genData!.targetType !== GenTargetType.Service) {
60
69
  return; // no validation on no-op flow
61
70
  }
62
- if (!this.state.data.genTargetName) {
71
+ if (!this.state.data.genData!.targetName) {
63
72
  throw new Error("Unable to determine targetName");
64
73
  }
65
74
  if (!this.state.data.project) {
@@ -5,22 +5,32 @@ import { getTaskTemplate } from "../../templates/task";
5
5
  import { CaseType } from "../../types/format";
6
6
  import { ProjectService } from "../../services/project-service";
7
7
  import path from "path";
8
- import GenAppTask from "../../wrappers/gen-app-task";
8
+ import { AppTask } from "../../wrappers/app-task";
9
+ import { FileService } from "../../services/file-service";
10
+ import { UtilService } from "../../services/util-service";
9
11
 
10
12
  /**
11
13
  * Generates a new task class
12
14
  */
13
15
  @autoInjectable()
14
- export default class GenerateTask extends GenAppTask {
16
+ export default class GenerateTask extends AppTask {
15
17
  loggerName = "Generate Task";
16
18
 
19
+ constructor(
20
+ private fileService: FileService,
21
+ private projectService: ProjectService,
22
+ private utilService: UtilService,
23
+ ) {
24
+ super();
25
+ }
26
+
17
27
  /**
18
28
  * Generates a new task class file.
19
29
  *
20
30
  * @returns updated state with outputDestination set to a generated result path.
21
31
  */
22
32
  async run() {
23
- if (this.state.data.genTargetType !== GenTargetType.Task) {
33
+ if (this.state.data.genData!.targetType !== GenTargetType.Task) {
24
34
  return;
25
35
  }
26
36
 
@@ -28,7 +38,7 @@ export default class GenerateTask extends GenAppTask {
28
38
 
29
39
  this.logger.info(chalk.blueBright("Generating Task"));
30
40
 
31
- const targetName = this.state.data.genTargetName!;
41
+ const targetName = this.state.data.genData!.targetName!;
32
42
  const targetDirectory = this.state.data.project!.taskDestination!;
33
43
 
34
44
  // detect case
@@ -39,11 +49,10 @@ export default class GenerateTask extends GenAppTask {
39
49
  CaseType.PASCAL_CASE,
40
50
  );
41
51
 
42
- const injectableMappings = new Map<string, string>();
43
- if (this.argService.hasFlag("inject")) {
44
- await this.addServicesToMap(injectableMappings, targetDirectory);
45
- }
46
- const rendered = getTaskTemplate(className, injectableMappings);
52
+ const injectablesMap = this.projectService.getImportMap(
53
+ this.state.data.genData!,
54
+ );
55
+ const rendered = getTaskTemplate(className, injectablesMap);
47
56
  const filename = `${utilService.titleizedToCase(targetName, convention)}${ProjectService.defaults.extention}`;
48
57
  const destination = path.join(targetDirectory, filename);
49
58
 
@@ -54,13 +63,13 @@ export default class GenerateTask extends GenAppTask {
54
63
 
55
64
  /**
56
65
  * Checks state for required fields. Executes prior to run method.
57
- * Skips validation if genTargetType is not set to task.
66
+ * Skips validation if genData.targetType is not set to task.
58
67
  */
59
68
  async preRun() {
60
- if (this.state.data.genTargetType !== GenTargetType.Task) {
69
+ if (this.state.data.genData!.targetType !== GenTargetType.Task) {
61
70
  return; // no validation on no-op flow
62
71
  }
63
- if (!this.state.data.genTargetName) {
72
+ if (!this.state.data.genData!.targetName) {
64
73
  throw new Error("Unable to determine targetName");
65
74
  }
66
75
  if (!this.state.data.project) {
@@ -4,7 +4,7 @@ import { AppTask } from "../../wrappers/app-task";
4
4
  import { autoInjectable } from "tsyringe";
5
5
 
6
6
  /**
7
- * Checks so see if we are in the context of a task-script-support
7
+ * Checks to see if we are in the context of a task-script-support
8
8
  * project or not and fails the process with a friendly error message.
9
9
  */
10
10
  @autoInjectable()
@@ -0,0 +1,154 @@
1
+ import { AppTask } from "../../wrappers/app-task";
2
+ import { autoInjectable } from "tsyringe";
3
+ import { FileService } from "../../services/file-service";
4
+ import { ProjectService } from "../../services/project-service";
5
+ import { PromptService } from "../../services/prompt-service";
6
+ import { UtilService } from "../../services/util-service";
7
+ import { ProjectImport } from "../../types/project";
8
+ import { CaseType } from "../../types/format";
9
+ import { AppState, GenTargetType } from "../../types/state";
10
+
11
+ /**
12
+ * ResolveInjectables
13
+ */
14
+ @autoInjectable()
15
+ export default class ResolveInjectables extends AppTask {
16
+ loggerName = "ResolveInjectables";
17
+
18
+ constructor(
19
+ private fileService: FileService,
20
+ private projectService: ProjectService,
21
+ private promptService: PromptService,
22
+ private utilService: UtilService,
23
+ ) {
24
+ super();
25
+ }
26
+
27
+ /**
28
+ * Prompts to select tasks or services to import into the file being generated.
29
+ *
30
+ * @param state the current state of the application. Expects genData to be
31
+ * populated with targetType. Expects the project to be populated with
32
+ * serviceDestination, taskDestination, and commandDestination.
33
+ * @returns updated state with genData imports field set.
34
+ */
35
+ async run(state: AppState): Promise<Partial<AppState>> {
36
+ if (this.shouldSkip()) return { data: { genData: { imports: [] } } };
37
+
38
+ const { genData, project } = state.data;
39
+
40
+ // determine the directory we would need to import into
41
+ const sourceDirectory =
42
+ genData!.targetType === GenTargetType.Service
43
+ ? project!.serviceDestination!
44
+ : project!.taskDestination!;
45
+
46
+ let injectableImports: ProjectImport[];
47
+ switch (genData!.targetType) {
48
+ case GenTargetType.Command:
49
+ injectableImports = await this.getTaskImports();
50
+ break;
51
+ case GenTargetType.Service:
52
+ case GenTargetType.Task:
53
+ injectableImports = await this.getServiceImports(sourceDirectory);
54
+ break;
55
+ default:
56
+ injectableImports = [];
57
+ }
58
+
59
+ return { data: { genData: { imports: injectableImports } } };
60
+ }
61
+
62
+ /**
63
+ * Prompt to select tasks to use in the command being generated.
64
+ *
65
+ * @returns the selected task imports
66
+ */
67
+ async getTaskImports(): Promise<ProjectImport[]> {
68
+ if (!this.state.data.project?.taskDestination) {
69
+ throw new Error("Unable to resolve task destination");
70
+ }
71
+
72
+ const taskFiles = this.fileService.getFilesInDir(
73
+ this.state.data.project.taskDestination,
74
+ );
75
+
76
+ this.logger.debug(`Found ${taskFiles.length} task files`);
77
+ const pickedTasks = await this.promptForImports("Include Tasks", taskFiles);
78
+
79
+ this.logger.debug(`Selected ${pickedTasks.length} tasks`);
80
+ // add them to the map
81
+ return !pickedTasks.length
82
+ ? []
83
+ : this.projectService.formalizeImports(
84
+ pickedTasks,
85
+ this.state.data.project!.commandDestination!,
86
+ );
87
+ }
88
+
89
+ /**
90
+ * Prompt to select services to use in the command being generated.
91
+ *
92
+ * @param sourcePath the path to the parent directory of the source file being
93
+ * generated to resolve relative paths for imports
94
+ * @returns the selected service imports
95
+ */
96
+ async getServiceImports(sourcePath: string): Promise<ProjectImport[]> {
97
+ if (!this.state.data.project?.serviceDestination) {
98
+ throw new Error("Unable to resolve service destination");
99
+ }
100
+
101
+ const serviceFiles = this.fileService.getFilesInDir(
102
+ this.state.data.project.serviceDestination,
103
+ );
104
+
105
+ this.logger.debug(`Found ${serviceFiles.length} service files`);
106
+ const pickedServices = await this.promptForImports(
107
+ "Include Services",
108
+ serviceFiles,
109
+ );
110
+
111
+ this.logger.debug(`Selected ${pickedServices.length} services`);
112
+
113
+ return !pickedServices.length
114
+ ? []
115
+ : this.projectService.formalizeImports(pickedServices, sourcePath);
116
+ }
117
+
118
+ /**
119
+ * Prompt to select imports to use in the class being generated.
120
+ *
121
+ * @param messagePrompt the prompt message to display
122
+ * @param filePaths the file paths to select from
123
+ * @returns the selected file paths
124
+ */
125
+ private async promptForImports(
126
+ messagePrompt: string,
127
+ filePaths: string[],
128
+ ): Promise<string[]> {
129
+ return await this.promptService.pickMultiple(
130
+ messagePrompt,
131
+ filePaths.map((filePath: string) => ({
132
+ name: this.utilService.titleizedToCase(
133
+ this.utilService.titleizeAll(
134
+ this.fileService.getFilenameNoExt(filePath),
135
+ ),
136
+ CaseType.PASCAL_CASE,
137
+ ),
138
+ value: filePath,
139
+ })),
140
+ );
141
+ }
142
+
143
+ /**
144
+ * Determines if the task should skip the prompt for injectables.
145
+ *
146
+ * @returns true if the task should be skipped.
147
+ */
148
+ private shouldSkip(): boolean {
149
+ return (
150
+ !this.argService.hasFlag("inject") &&
151
+ this.state.data.genData?.targetType !== GenTargetType.Command
152
+ );
153
+ }
154
+ }
@@ -25,7 +25,7 @@ export default class SelectGenTargetName extends AppTask {
25
25
  if (!targetName) {
26
26
  targetName =
27
27
  (await this.promptService.getInput(
28
- `Enter Name for ${chalk.blueBright(this.utilService.titleize(this.state.data.genTargetType!))}`,
28
+ `Enter Name for ${chalk.blueBright(this.utilService.titleize(this.state.data.genData!.targetType!))}`,
29
29
  )) || ProjectService.defaults.targetName;
30
30
  }
31
31
  if (!targetName) {
@@ -33,12 +33,12 @@ export default class SelectGenTargetName extends AppTask {
33
33
  }
34
34
  this.logger.debug(`Name selected: ${chalk.magentaBright(targetName)}`);
35
35
  targetName = this.utilService.titleizeAll(targetName);
36
- this.setData({ genTargetName: targetName });
36
+ this.setData({ genData: { targetName: targetName } });
37
37
  }
38
38
 
39
39
  async preRun() {
40
- if (!this.state.data.genTargetType) {
41
- throw new Error("Unable to determine genTargetType");
40
+ if (!this.state.data.genData?.targetType) {
41
+ throw new Error("Unable to determine genData.targetType");
42
42
  }
43
43
  }
44
44
  }
@@ -6,7 +6,7 @@ import { PromptService } from "../../services/prompt-service";
6
6
  import { CLIOptions } from "../../types/process";
7
7
 
8
8
  /**
9
- * Sets the genTargetType based on input
9
+ * Sets the genData.targetType based on input
10
10
  */
11
11
  @autoInjectable()
12
12
  export default class SelectGenTargetType extends AppTask {
@@ -31,7 +31,7 @@ export default class SelectGenTargetType extends AppTask {
31
31
  }
32
32
 
33
33
  this.logger.debug(`Target selected: ${chalk.magentaBright(target)}`);
34
- this.setData({ genTargetType: target });
34
+ this.setData({ genData: { targetType: target } });
35
35
  }
36
36
 
37
37
  async getGenTargetInput() {
@@ -24,8 +24,8 @@ export default class PrintGeneratedResults extends AppTask {
24
24
  }
25
25
 
26
26
  async run() {
27
- const genType: string = this.state.data.genTargetType
28
- ? this.utilService.titleize(this.state.data.genTargetType)
27
+ const genType: string = this.state.data.genData?.targetType
28
+ ? this.utilService.titleize(this.state.data.genData.targetType)
29
29
  : "Project";
30
30
 
31
31
  this.logger.info(`Generated Results for ${chalk.blueBright(genType)}`);