kist 0.0.0 → 0.1.31

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 (237) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +298 -3
  3. package/js/actions/CoreActions.d.ts +6 -0
  4. package/js/actions/CoreActions.js +47 -0
  5. package/js/actions/DirectoryCleanAction/DirectoryCleanAction.d.ts +36 -0
  6. package/js/actions/DirectoryCleanAction/DirectoryCleanAction.js +123 -0
  7. package/js/actions/DirectoryCleanAction/index.d.ts +2 -0
  8. package/js/actions/DirectoryCleanAction/index.js +8 -0
  9. package/js/actions/DirectoryCopyAction/DirectoryCopyAction.d.ts +42 -0
  10. package/js/actions/DirectoryCopyAction/DirectoryCopyAction.js +118 -0
  11. package/js/actions/DirectoryCopyAction/index.d.ts +2 -0
  12. package/js/actions/DirectoryCopyAction/index.js +8 -0
  13. package/js/actions/DirectoryCreateAction/DirectoryCreateAction.d.ts +30 -0
  14. package/js/actions/DirectoryCreateAction/DirectoryCreateAction.js +85 -0
  15. package/js/actions/DirectoryCreateAction/index.d.ts +2 -0
  16. package/js/actions/DirectoryCreateAction/index.js +8 -0
  17. package/js/actions/DocumentationAction/DocumentationAction.d.ts +23 -0
  18. package/js/actions/DocumentationAction/DocumentationAction.js +88 -0
  19. package/js/actions/DocumentationAction/index.d.ts +2 -0
  20. package/js/actions/DocumentationAction/index.js +8 -0
  21. package/js/actions/FileCopyAction/FileCopyAction.d.ts +42 -0
  22. package/js/actions/FileCopyAction/FileCopyAction.js +127 -0
  23. package/js/actions/FileCopyAction/index.d.ts +2 -0
  24. package/js/actions/FileCopyAction/index.js +8 -0
  25. package/js/actions/FileRenameAction/FileRenameAction.d.ts +30 -0
  26. package/js/actions/FileRenameAction/FileRenameAction.js +84 -0
  27. package/js/actions/FileRenameAction/index.d.ts +2 -0
  28. package/js/actions/FileRenameAction/index.js +8 -0
  29. package/js/actions/JavaScriptMinifyAction/JavaScriptMinifyAction.d.ts +31 -0
  30. package/js/actions/JavaScriptMinifyAction/JavaScriptMinifyAction.js +98 -0
  31. package/js/actions/JavaScriptMinifyAction/index.d.ts +2 -0
  32. package/js/actions/JavaScriptMinifyAction/index.js +8 -0
  33. package/js/actions/JavaScriptMinifyAction/terser.config.d.ts +27 -0
  34. package/js/actions/JavaScriptMinifyAction/terser.config.js +119 -0
  35. package/js/actions/LintAction/LintAction.d.ts +17 -0
  36. package/js/actions/LintAction/LintAction.js +63 -0
  37. package/js/actions/LintAction/index.d.ts +2 -0
  38. package/js/actions/LintAction/index.js +8 -0
  39. package/js/actions/PackageManagerAction/PackageManagerAction.d.ts +57 -0
  40. package/js/actions/PackageManagerAction/PackageManagerAction.js +161 -0
  41. package/js/actions/PackageManagerAction/index.d.ts +2 -0
  42. package/js/actions/PackageManagerAction/index.js +8 -0
  43. package/js/actions/PackageManagerAction/package.config.d.ts +16 -0
  44. package/js/actions/PackageManagerAction/package.config.js +91 -0
  45. package/js/actions/StyleProcessingAction/StyleProcessingAction.d.ts +34 -0
  46. package/js/actions/StyleProcessingAction/StyleProcessingAction.js +164 -0
  47. package/js/actions/StyleProcessingAction/index.d.ts +2 -0
  48. package/js/actions/StyleProcessingAction/index.js +8 -0
  49. package/js/actions/StyleProcessingAction/postcss.config.compressed.d.ts +10 -0
  50. package/js/actions/StyleProcessingAction/postcss.config.compressed.js +31 -0
  51. package/js/actions/StyleProcessingAction/postcss.config.expanded.d.ts +16 -0
  52. package/js/actions/StyleProcessingAction/postcss.config.expanded.js +45 -0
  53. package/js/actions/SvgPackagerAction/SvgPackagerAction.d.ts +68 -0
  54. package/js/actions/SvgPackagerAction/SvgPackagerAction.js +186 -0
  55. package/js/actions/SvgPackagerAction/index.d.ts +2 -0
  56. package/js/actions/SvgPackagerAction/index.js +8 -0
  57. package/js/actions/SvgReaderAction/SvgReaderAction.d.ts +32 -0
  58. package/js/actions/SvgReaderAction/SvgReaderAction.js +87 -0
  59. package/js/actions/SvgReaderAction/index.d.ts +2 -0
  60. package/js/actions/SvgReaderAction/index.js +8 -0
  61. package/js/actions/SvgSpriteAction/SvgSpriteAction.d.ts +37 -0
  62. package/js/actions/SvgSpriteAction/SvgSpriteAction.js +114 -0
  63. package/js/actions/SvgSpriteAction/index.d.ts +2 -0
  64. package/js/actions/SvgSpriteAction/index.js +8 -0
  65. package/js/actions/SvgSpriteAction/svgsprite.config.d.ts +3 -0
  66. package/js/actions/SvgSpriteAction/svgsprite.config.js +117 -0
  67. package/js/actions/SvgToPngAction/SvgToPngAction.d.ts +28 -0
  68. package/js/actions/SvgToPngAction/SvgToPngAction.js +108 -0
  69. package/js/actions/SvgToPngAction/index.d.ts +2 -0
  70. package/js/actions/SvgToPngAction/index.js +8 -0
  71. package/js/actions/TypeScriptCompilerAction/TypeScriptCompilerAction.d.ts +28 -0
  72. package/js/actions/TypeScriptCompilerAction/TypeScriptCompilerAction.js +96 -0
  73. package/js/actions/TypeScriptCompilerAction/index.d.ts +2 -0
  74. package/js/actions/TypeScriptCompilerAction/index.js +8 -0
  75. package/js/actions/VersionWriteAction/VersionWriteAction.d.ts +45 -0
  76. package/js/actions/VersionWriteAction/VersionWriteAction.js +147 -0
  77. package/js/actions/VersionWriteAction/index.d.ts +2 -0
  78. package/js/actions/VersionWriteAction/index.js +8 -0
  79. package/js/cli/ArgumentParser.d.ts +62 -0
  80. package/js/cli/ArgumentParser.js +118 -0
  81. package/js/cli.d.ts +6 -0
  82. package/js/cli.js +58 -0
  83. package/js/core/abstract/AbstractProcess.d.ts +62 -0
  84. package/js/core/abstract/AbstractProcess.js +96 -0
  85. package/js/core/abstract/AbstractValidator.d.ts +72 -0
  86. package/js/core/abstract/AbstractValidator.js +128 -0
  87. package/js/core/config/ConfigLoader.d.ts +47 -0
  88. package/js/core/config/ConfigLoader.js +130 -0
  89. package/js/core/config/ConfigStore.d.ts +53 -0
  90. package/js/core/config/ConfigStore.js +136 -0
  91. package/js/core/config/defaultConfig.d.ts +5 -0
  92. package/js/core/config/defaultConfig.js +131 -0
  93. package/js/core/pipeline/Action.d.ts +60 -0
  94. package/js/core/pipeline/Action.js +77 -0
  95. package/js/core/pipeline/ActionRegistry.d.ts +80 -0
  96. package/js/core/pipeline/ActionRegistry.js +180 -0
  97. package/js/core/pipeline/Pipeline.d.ts +42 -0
  98. package/js/core/pipeline/Pipeline.js +107 -0
  99. package/js/core/pipeline/PipelineManager.d.ts +55 -0
  100. package/js/core/pipeline/PipelineManager.js +164 -0
  101. package/js/core/pipeline/Stage.d.ts +45 -0
  102. package/js/core/pipeline/Stage.js +110 -0
  103. package/js/core/pipeline/Step.d.ts +26 -0
  104. package/js/core/pipeline/Step.js +85 -0
  105. package/js/core/validation/OptionsValidator.d.ts +43 -0
  106. package/js/core/validation/OptionsValidator.js +123 -0
  107. package/js/index.d.ts +3 -0
  108. package/js/index.js +36 -0
  109. package/js/interface/ActionInterface.d.ts +57 -0
  110. package/js/interface/ActionInterface.js +5 -0
  111. package/js/interface/ActionPlugin.d.ts +4 -0
  112. package/js/interface/ActionPlugin.js +5 -0
  113. package/js/interface/ConfigInterface.d.ts +43 -0
  114. package/js/interface/ConfigInterface.js +5 -0
  115. package/js/interface/LiveOptionsInterface.d.ts +42 -0
  116. package/js/interface/LiveOptionsInterface.js +2 -0
  117. package/js/interface/MetadataInterface.d.ts +95 -0
  118. package/js/interface/MetadataInterface.js +2 -0
  119. package/js/interface/OptionsInterface.d.ts +45 -0
  120. package/js/interface/OptionsInterface.js +5 -0
  121. package/js/interface/PipelineOptionsInterface.d.ts +66 -0
  122. package/js/interface/PipelineOptionsInterface.js +5 -0
  123. package/js/interface/StageInterface.d.ts +79 -0
  124. package/js/interface/StageInterface.js +5 -0
  125. package/js/interface/StepInterface.d.ts +66 -0
  126. package/js/interface/StepInterface.js +5 -0
  127. package/js/interface/StepOptionsInterface.d.ts +38 -0
  128. package/js/interface/StepOptionsInterface.js +21 -0
  129. package/js/interface/index.d.ts +7 -0
  130. package/js/interface/index.js +3 -0
  131. package/js/kist.d.ts +58 -0
  132. package/js/kist.js +145 -0
  133. package/js/live/LiveServer.d.ts +95 -0
  134. package/js/live/LiveServer.js +233 -0
  135. package/js/live/LiveWatcher.d.ts +45 -0
  136. package/js/live/LiveWatcher.js +140 -0
  137. package/js/logger/Logger.d.ts +94 -0
  138. package/js/logger/Logger.js +151 -0
  139. package/js/logger/LoggerStyles.d.ts +23 -0
  140. package/js/logger/LoggerStyles.js +30 -0
  141. package/js/types/ActionOptionsType.d.ts +8 -0
  142. package/js/types/ActionOptionsType.js +2 -0
  143. package/js/types/index.d.ts +1 -0
  144. package/js/types/index.js +3 -0
  145. package/package.json +93 -7
  146. package/ts/actions/CoreActions.ts +64 -0
  147. package/ts/actions/DirectoryCleanAction/DirectoryCleanAction.ts +121 -0
  148. package/ts/actions/DirectoryCleanAction/index.ts +11 -0
  149. package/ts/actions/DirectoryCopyAction/DirectoryCopyAction.ts +118 -0
  150. package/ts/actions/DirectoryCopyAction/index.ts +11 -0
  151. package/ts/actions/DirectoryCreateAction/DirectoryCreateAction.ts +81 -0
  152. package/ts/actions/DirectoryCreateAction/index.ts +11 -0
  153. package/ts/actions/DocumentationAction/DocumentationAction.ts +100 -0
  154. package/ts/actions/DocumentationAction/index.ts +11 -0
  155. package/ts/actions/FileCopyAction/FileCopyAction.ts +125 -0
  156. package/ts/actions/FileCopyAction/index.ts +11 -0
  157. package/ts/actions/FileRenameAction/FileRenameAction.ts +82 -0
  158. package/ts/actions/FileRenameAction/index.ts +11 -0
  159. package/ts/actions/JavaScriptMinifyAction/JavaScriptMinifyAction.ts +109 -0
  160. package/ts/actions/JavaScriptMinifyAction/index.ts +11 -0
  161. package/ts/actions/JavaScriptMinifyAction/terser.config.ts +177 -0
  162. package/ts/actions/LintAction/LintAction.ts +67 -0
  163. package/ts/actions/LintAction/index.ts +11 -0
  164. package/ts/actions/PackageManagerAction/PackageManagerAction.ts +176 -0
  165. package/ts/actions/PackageManagerAction/index.ts +11 -0
  166. package/ts/actions/PackageManagerAction/package.config.ts +94 -0
  167. package/ts/actions/SassDocAction/SassDocAction.ts +66 -0
  168. package/ts/actions/SassDocAction/index.ts +11 -0
  169. package/ts/actions/StyleProcessingAction/StyleProcessingAction.ts +142 -0
  170. package/ts/actions/StyleProcessingAction/index.ts +11 -0
  171. package/ts/actions/StyleProcessingAction/postcss.config.compressed.ts +31 -0
  172. package/ts/actions/StyleProcessingAction/postcss.config.expanded.ts +47 -0
  173. package/ts/actions/SvgPackagerAction/SvgPackagerAction.ts +187 -0
  174. package/ts/actions/SvgPackagerAction/index.ts +11 -0
  175. package/ts/actions/SvgReaderAction/SvgReaderAction.ts +77 -0
  176. package/ts/actions/SvgReaderAction/index.ts +11 -0
  177. package/ts/actions/SvgSpriteAction/SvgSpriteAction.ts +127 -0
  178. package/ts/actions/SvgSpriteAction/index.ts +11 -0
  179. package/ts/actions/SvgSpriteAction/svgsprite.config.ts +123 -0
  180. package/ts/actions/SvgToPngAction/SvgToPngAction.ts +113 -0
  181. package/ts/actions/SvgToPngAction/index.ts +11 -0
  182. package/ts/actions/TypeScriptCompilerAction/TypeScriptCompilerAction.ts +117 -0
  183. package/ts/actions/TypeScriptCompilerAction/index.ts +11 -0
  184. package/ts/actions/VersionWriteAction/VersionWriteAction.ts +174 -0
  185. package/ts/actions/VersionWriteAction/index.ts +11 -0
  186. package/ts/actions/index.ts +0 -0
  187. package/ts/cli/ArgumentParser.ts +150 -0
  188. package/ts/cli/index.ts +1 -0
  189. package/ts/cli.ts +56 -0
  190. package/ts/core/abstract/AbstractProcess.ts +109 -0
  191. package/ts/core/abstract/AbstractSingleton.ts +46 -0
  192. package/ts/core/abstract/AbstractValidator.ts +167 -0
  193. package/ts/core/abstract/index.ts +0 -0
  194. package/ts/core/config/ConfigLoader.ts +141 -0
  195. package/ts/core/config/ConfigStore copy.ts +201 -0
  196. package/ts/core/config/ConfigStore.ts +157 -0
  197. package/ts/core/config/defaultConfig.ts +154 -0
  198. package/ts/core/config/index.ts +0 -0
  199. package/ts/core/index.ts +34 -0
  200. package/ts/core/pipeline/Action.ts +101 -0
  201. package/ts/core/pipeline/ActionRegistry.ts +216 -0
  202. package/ts/core/pipeline/Pipeline.ts +121 -0
  203. package/ts/core/pipeline/PipelineManager.ts +170 -0
  204. package/ts/core/pipeline/Stage.ts +131 -0
  205. package/ts/core/pipeline/Step.ts +96 -0
  206. package/ts/core/pipeline/index.ts +0 -0
  207. package/ts/core/validation/ActionValidator.ts +97 -0
  208. package/ts/core/validation/ConfigValidator.ts +103 -0
  209. package/ts/core/validation/OptionsValidator.ts +179 -0
  210. package/ts/core/validation/StageValidator.ts +175 -0
  211. package/ts/core/validation/StepValidator.ts +203 -0
  212. package/ts/core/validation/index.ts +0 -0
  213. package/ts/index.ts +26 -0
  214. package/ts/interface/ActionInterface.ts +70 -0
  215. package/ts/interface/ActionPlugin.ts +14 -0
  216. package/ts/interface/ConfigInterface.ts +55 -0
  217. package/ts/interface/File.ts +24 -0
  218. package/ts/interface/LiveOptionsInterface.ts +46 -0
  219. package/ts/interface/MetadataInterface.ts +105 -0
  220. package/ts/interface/OptionsInterface.ts +58 -0
  221. package/ts/interface/PackageJson.ts +171 -0
  222. package/ts/interface/PipelineOptionsInterface.ts +74 -0
  223. package/ts/interface/SVG.ts +84 -0
  224. package/ts/interface/StageInterface.ts +96 -0
  225. package/ts/interface/StepInterface.ts +83 -0
  226. package/ts/interface/StepOptionsInterface.ts +57 -0
  227. package/ts/interface/index.ts +9 -0
  228. package/ts/kist.ts +161 -0
  229. package/ts/live/LiveServer.ts +311 -0
  230. package/ts/live/LiveWatcher.ts +150 -0
  231. package/ts/live/index.ts +11 -0
  232. package/ts/logger/Logger.ts +187 -0
  233. package/ts/logger/LoggerStyles.ts +28 -0
  234. package/ts/logger/index.ts +0 -0
  235. package/ts/types/ActionOptionsType.ts +10 -0
  236. package/ts/types/index.ts +3 -0
  237. package/index.js +0 -3
@@ -0,0 +1,96 @@
1
+ // ============================================================================
2
+ // Import
3
+ // ============================================================================
4
+
5
+ import { ActionInterface } from "../../interface/ActionInterface";
6
+ import { StepInterface } from "../../interface/StepInterface";
7
+ import { AbstractProcess } from "../abstract/AbstractProcess";
8
+ import { ActionRegistry } from "./ActionRegistry";
9
+
10
+ // ============================================================================
11
+ // Class
12
+ // ============================================================================
13
+
14
+ /**
15
+ * Represents a single step in a stage, encapsulating its execution logic.
16
+ * This class manages the resolution and execution of actions associated
17
+ * with each step.
18
+ */
19
+ export class Step extends AbstractProcess {
20
+ // Parameters
21
+ // ========================================================================
22
+
23
+ private name: string;
24
+ private action: ActionInterface;
25
+ private options?: Record<string, any>;
26
+
27
+ // Constructor
28
+ // ========================================================================
29
+
30
+ /**
31
+ * Constructs a Step instance based on the provided step definition.
32
+ * Dynamically resolves the action class from the registry.
33
+ *
34
+ * @param step - The step definition containing the step name, action name,
35
+ * and options.
36
+ * @throws Error if the specified action is not registered in the action
37
+ * registry.
38
+ */
39
+ constructor(step: StepInterface) {
40
+ super();
41
+ this.name = step.name;
42
+
43
+ // Resolve the action class from the registry using the action name
44
+ const actionRegistry = ActionRegistry.getInstance();
45
+ // console.log(step.action)
46
+ // const ActionClass = actionRegistry.getAction(step.action.name);
47
+ const ActionClass = actionRegistry.getAction(String(step.action));
48
+ if (!ActionClass) {
49
+ let msg = `
50
+ Unknown action "${step.action}" for step "${this.name}".
51
+ Ensure the action is registered in the registry.
52
+ `;
53
+ this.logError(msg);
54
+ throw new Error(msg);
55
+ }
56
+
57
+ // Initialize the action with the specific class from the registry
58
+ this.action = new ActionClass();
59
+ this.options = step.options;
60
+
61
+ this.logInfo(
62
+ `Step "${this.name}" initialized with action "${step.action.constructor.name}".`,
63
+ );
64
+ }
65
+
66
+ // Methods
67
+ // ========================================================================
68
+
69
+ /**
70
+ * Executes the step by invoking its action's execute method.
71
+ */
72
+ async execute(): Promise<void> {
73
+ this.logInfo(`Executing step: ${this.name}`);
74
+
75
+ try {
76
+ // Validate options if the action provides a validation method
77
+ if (typeof this.action.validateOptions === "function") {
78
+ const isValid = this.action.validateOptions(
79
+ this.options || {},
80
+ );
81
+ if (!isValid) {
82
+ throw new Error(`Invalid options for step: ${this.name}`);
83
+ }
84
+ }
85
+
86
+ // Execute the action with the provided options
87
+ await this.action.execute(this.options || {});
88
+ this.logInfo(`Step "${this.name}" completed successfully.`);
89
+ } catch (error) {
90
+ this.logError(
91
+ `Error executing step "${this.name}": ${error}`,
92
+ error,
93
+ );
94
+ }
95
+ }
96
+ }
File without changes
@@ -0,0 +1,97 @@
1
+ // ============================================================================
2
+ // Import
3
+ // ============================================================================
4
+
5
+ import { AbstractValidator } from "../abstract/AbstractValidator";
6
+ import { ActionRegistry } from "../pipeline/ActionRegistry";
7
+
8
+ // ============================================================================
9
+ // Types
10
+ // ============================================================================
11
+
12
+ /**
13
+ * Type representing the structure of action properties for validation.
14
+ */
15
+ type ActionValidationKeys = "action";
16
+
17
+ // ============================================================================
18
+ // Class
19
+ // ============================================================================
20
+
21
+ /**
22
+ * Validates actions by ensuring they are registered in the `ActionRegistry`.
23
+ * Extends `AbstractValidator` for consistent validation and logging.
24
+ */
25
+ export class ActionValidator extends AbstractValidator<
26
+ Record<ActionValidationKeys, string>
27
+ > {
28
+ // Parameters
29
+ // ========================================================================
30
+
31
+ private actionRegistry: ActionRegistry;
32
+
33
+ // Constructor
34
+ // ========================================================================
35
+
36
+ constructor() {
37
+ super();
38
+ this.actionRegistry = ActionRegistry.getInstance();
39
+ this.logInfo("ActionValidator initialized.");
40
+ }
41
+
42
+ // Methods
43
+ // ========================================================================
44
+
45
+ /**
46
+ * Validates an action object with the structure { action: string }.
47
+ *
48
+ * @param target - The action object to validate.
49
+ * @throws Error if the action is invalid or not registered.
50
+ */
51
+ public validate(target: Record<ActionValidationKeys, string>): void {
52
+ const action = target.action;
53
+ this.logInfo(`Validating action: "${action}"`);
54
+
55
+ if (!action || typeof action !== "string") {
56
+ this.throwValidationError(
57
+ "action",
58
+ action,
59
+ "Action name must be a non-empty string.",
60
+ );
61
+ }
62
+
63
+ const registeredAction = this.actionRegistry.getAction(action);
64
+
65
+ if (!registeredAction) {
66
+ this.throwValidationError(
67
+ "action",
68
+ action,
69
+ `Action "${action}" is not registered in the ActionRegistry.`,
70
+ );
71
+ }
72
+
73
+ this.logValidationSuccess("action", action);
74
+ }
75
+
76
+ /**
77
+ * Validates a specific property of the action object.
78
+ * This is required to fulfill the `AbstractValidator` contract.
79
+ *
80
+ * @param key - The property key (e.g., "action").
81
+ * @param value - The value of the property to validate.
82
+ * @throws Error if the validation fails.
83
+ */
84
+ protected validateProperty<
85
+ K extends keyof Record<ActionValidationKeys, string>,
86
+ >(key: K, value: Record<ActionValidationKeys, string>[K]): void {
87
+ if (key === "action") {
88
+ this.validate({ action: value });
89
+ } else {
90
+ this.throwValidationError(
91
+ key,
92
+ value,
93
+ `Unknown property key: "${String(key)}".`,
94
+ );
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,103 @@
1
+ // ============================================================================
2
+ // Import
3
+ // ============================================================================
4
+
5
+ import { ConfigInterface } from "../../interface/ConfigInterface";
6
+ import { AbstractValidator } from "../abstract/AbstractValidator";
7
+ import { StageValidator } from "./StageValidator";
8
+
9
+ // ============================================================================
10
+ // Class
11
+ // ============================================================================
12
+
13
+ /**
14
+ * Validates the overall configuration, including stages and global options.
15
+ */
16
+ export class ConfigValidator extends AbstractValidator<ConfigInterface> {
17
+ // Parameters
18
+ // ========================================================================
19
+
20
+ private stageValidator: StageValidator;
21
+
22
+ // Constructor
23
+ // ========================================================================
24
+
25
+ constructor() {
26
+ super();
27
+ this.stageValidator = new StageValidator();
28
+ this.logInfo("ConfigValidator initialized.");
29
+ }
30
+
31
+ // Methods
32
+ // ========================================================================
33
+
34
+ /**
35
+ * Validates the entire configuration object.
36
+ * @param config - The configuration object to validate.
37
+ * @throws Error if validation fails.
38
+ */
39
+ public validate(config: ConfigInterface): void {
40
+ this.logInfo("Validating configuration.");
41
+
42
+ // Validate each property of the configuration
43
+ for (const key in config) {
44
+ if (Object.prototype.hasOwnProperty.call(config, key)) {
45
+ this.validateProperty(
46
+ key as keyof ConfigInterface,
47
+ config[key as keyof ConfigInterface],
48
+ );
49
+ }
50
+ }
51
+
52
+ this.logInfo("Configuration validated successfully.");
53
+ }
54
+
55
+ /**
56
+ * Validates a specific property of the configuration object.
57
+ *
58
+ * @param key - The key of the property to validate.
59
+ * @param value - The value of the property to validate.
60
+ * @throws Error if validation fails.
61
+ */
62
+ protected validateProperty<K extends keyof ConfigInterface>(
63
+ key: K,
64
+ value: ConfigInterface[K],
65
+ ): void {
66
+ switch (key) {
67
+ case "stages":
68
+ if (Array.isArray(value)) {
69
+ this.validateStages(value); // Validate only if it's an array
70
+ } else {
71
+ this.throwValidationError(
72
+ key,
73
+ value,
74
+ "'stages' must be an array.",
75
+ );
76
+ }
77
+ break;
78
+
79
+ default:
80
+ // Add validation for other properties if needed
81
+ this.throwValidationError(
82
+ key,
83
+ value,
84
+ `Unknown or unsupported configuration property: "${String(key)}".`,
85
+ );
86
+ }
87
+
88
+ this.logValidationSuccess(key, value);
89
+ }
90
+
91
+ /**
92
+ * Validates the stages in the configuration.
93
+ *
94
+ * @param stages - The stages to validate.
95
+ * @throws Error if validation fails.
96
+ */
97
+ private validateStages(stages: ConfigInterface["stages"]): void {
98
+ for (const stage of stages) {
99
+ // Validate each stage
100
+ this.stageValidator.validate(stage);
101
+ }
102
+ }
103
+ }
@@ -0,0 +1,179 @@
1
+ // ============================================================================
2
+ // Import
3
+ // ============================================================================
4
+
5
+ import { OptionsInterface } from "../../interface/OptionsInterface";
6
+ import { AbstractValidator } from "../abstract/AbstractValidator";
7
+
8
+ // ============================================================================
9
+ // Class
10
+ // ============================================================================
11
+
12
+ /**
13
+ * OptionsValidator provides centralized validation logic for pipeline options.
14
+ * Extends AbstractValidator for consistent validation and logging.
15
+ */
16
+ export class OptionsValidator extends AbstractValidator<OptionsInterface> {
17
+ // Parameters
18
+ // ========================================================================
19
+
20
+ /**
21
+ * A runtime mapping of enumerated options for validation.
22
+ */
23
+ private static allowedValues: Partial<
24
+ Record<keyof OptionsInterface, unknown[]>
25
+ > = {
26
+ logLevel: ["debug", "info", "warn", "error"],
27
+ };
28
+
29
+ // Constructor
30
+ // ========================================================================
31
+
32
+ constructor() {
33
+ super();
34
+ this.logDebug("OptionsValidator initialized.");
35
+ }
36
+
37
+ // Methods
38
+ // ========================================================================
39
+
40
+ /**
41
+ * Validates a specific property of the options object.
42
+ *
43
+ * @param key - The key of the option to validate.
44
+ * @param value - The value of the option to validate.
45
+ * @throws Error if validation fails.
46
+ */
47
+ protected validateProperty<K extends keyof OptionsInterface>(
48
+ key: K,
49
+ value: OptionsInterface[K],
50
+ ): void {
51
+ if (value === undefined) {
52
+ this.throwValidationError(
53
+ key,
54
+ value,
55
+ `Option "${String(key)}" cannot be undefined.`,
56
+ );
57
+ return;
58
+ }
59
+
60
+ const allowedValues = OptionsValidator.allowedValues[key];
61
+ if (allowedValues && !allowedValues.includes(value)) {
62
+ this.throwValidationError(
63
+ key,
64
+ value,
65
+ `Invalid value "${value}" for option "${String(key)}". Allowed values are: ${allowedValues.join(", ")}.`,
66
+ );
67
+ return;
68
+ }
69
+
70
+ this.validateByType(key, value);
71
+ this.logValidationSuccess(key, value);
72
+ }
73
+
74
+ /**
75
+ * Validates a property based on its type when it does not have predefined
76
+ * allowed values.
77
+ *
78
+ * @param key - The key to validate.
79
+ * @param value - The value to validate.
80
+ */
81
+ private validateByType<K extends keyof OptionsInterface>(
82
+ key: K,
83
+ value: OptionsInterface[K],
84
+ ): void {
85
+ switch (key) {
86
+ case "stepTimeout":
87
+ case "maxConcurrentStages":
88
+ if (typeof value === "number" && value >= 0) {
89
+ this.validateNumber(key, value);
90
+ } else {
91
+ this.throwValidationError(
92
+ key,
93
+ value,
94
+ "Must be a non-negative number.",
95
+ );
96
+ }
97
+ break;
98
+
99
+ case "haltOnFailure":
100
+ case "tags":
101
+ if (this.isValidObject(value)) {
102
+ this.validateObject(key, value);
103
+ } else {
104
+ this.throwValidationError(
105
+ key,
106
+ value,
107
+ "Must be a valid object.",
108
+ );
109
+ }
110
+ break;
111
+
112
+ case "live":
113
+ this.validateLiveOptions(value as OptionsInterface["live"]);
114
+ break;
115
+
116
+ default:
117
+ if (typeof value === "string" && value.trim() !== "") {
118
+ this.validateString(key, value);
119
+ } else {
120
+ this.throwValidationError(
121
+ key,
122
+ value,
123
+ "Must be a non-empty string.",
124
+ );
125
+ }
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Validates the `live` configuration, ensuring all nested properties
131
+ * conform to their expected types and ranges.
132
+ *
133
+ * @param value - The live reload configuration to validate.
134
+ */
135
+ private validateLiveOptions(value: OptionsInterface["live"]): void {
136
+ if (value?.port && (value.port < 1 || value.port > 65535)) {
137
+ this.throwValidationError(
138
+ "live.port",
139
+ value.port,
140
+ "Port must be a number between 1 and 65535.",
141
+ );
142
+ }
143
+ if (value?.root && typeof value.root !== "string") {
144
+ this.throwValidationError(
145
+ "live.root",
146
+ value.root,
147
+ "Root must be a valid string path.",
148
+ );
149
+ }
150
+ if (value?.watchPaths && !Array.isArray(value.watchPaths)) {
151
+ this.throwValidationError(
152
+ "live.watchPaths",
153
+ value.watchPaths,
154
+ "Must be an array of paths.",
155
+ );
156
+ }
157
+ if (value?.ignoredPaths && !Array.isArray(value.ignoredPaths)) {
158
+ this.throwValidationError(
159
+ "live.ignoredPaths",
160
+ value.ignoredPaths,
161
+ "Must be an array of paths.",
162
+ );
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Checks if the given value is a valid object.
168
+ *
169
+ * @param value - The value to check.
170
+ * @returns True if the value is an object and not null or an array.
171
+ */
172
+ private isValidObject(value: unknown): value is Record<string, unknown> {
173
+ return (
174
+ typeof value === "object" &&
175
+ value !== null &&
176
+ !Array.isArray(value)
177
+ );
178
+ }
179
+ }
@@ -0,0 +1,175 @@
1
+ // ============================================================================
2
+ // Import
3
+ // ============================================================================
4
+
5
+ import { StageInterface } from "../../interface/StageInterface";
6
+ import { AbstractValidator } from "../abstract/AbstractValidator";
7
+ import { StepValidator } from "./StepValidator";
8
+
9
+ // ============================================================================
10
+ // Class
11
+ // ============================================================================
12
+
13
+ /**
14
+ * StageValidator ensures that stages within the configuration meet the required criteria.
15
+ * It validates the stage properties, dependencies, and steps for correctness.
16
+ */
17
+ export class StageValidator extends AbstractValidator<StageInterface> {
18
+ // Parameters
19
+ // ========================================================================
20
+
21
+ private stageNames: Set<string>;
22
+ private stepValidator: StepValidator;
23
+
24
+ // Constructor
25
+ // ========================================================================
26
+
27
+ constructor() {
28
+ super();
29
+ this.stageNames = new Set();
30
+ this.stepValidator = new StepValidator();
31
+ this.logInfo("StageValidator initialized.");
32
+ }
33
+
34
+ // Methods
35
+ // ========================================================================
36
+
37
+ /**
38
+ * Validates an entire stage object.
39
+ *
40
+ * @param stage - The stage object to validate.
41
+ * @throws Error if the stage or any of its properties are invalid.
42
+ */
43
+ public validate(stage: StageInterface): void {
44
+ this.logInfo(`Validating stage: "${stage.name}"`);
45
+
46
+ try {
47
+ // Validate individual properties of the stage
48
+ this.validateProperty("name", stage.name);
49
+ this.validateProperty("dependsOn", stage.dependsOn);
50
+ this.validateProperty("steps", stage.steps);
51
+
52
+ this.logInfo(`Stage "${stage.name}" validated successfully.`);
53
+ } catch (error) {
54
+ this.logError(
55
+ `Validation failed for stage "${stage.name}": ${(error as Error).message}`,
56
+ );
57
+ throw error;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Validates individual properties of the stage.
63
+ *
64
+ * @param key - The property name to validate.
65
+ * @param value - The property value to validate.
66
+ * @throws Error if the property value is invalid.
67
+ */
68
+ public validateProperty<K extends keyof StageInterface>(
69
+ key: K,
70
+ value: StageInterface[K],
71
+ ): void {
72
+ switch (key) {
73
+ case "name":
74
+ this.validateName(value as string);
75
+ break;
76
+
77
+ case "dependsOn":
78
+ this.validateDependencies(value as string[]);
79
+ break;
80
+
81
+ case "steps":
82
+ this.validateSteps(value as StageInterface["steps"]);
83
+ break;
84
+
85
+ default:
86
+ this.throwValidationError(
87
+ key,
88
+ value,
89
+ "Unknown property provided for validation.",
90
+ );
91
+ }
92
+
93
+ // Log validation success with the property name and value
94
+ this.logValidationSuccess(key, value);
95
+ }
96
+
97
+ /**
98
+ * Validates the name of the stage.
99
+ *
100
+ * @param name - The name of the stage.
101
+ * @throws Error if the name is invalid.
102
+ */
103
+ private validateName(name: string): void {
104
+ if (!name || typeof name !== "string") {
105
+ this.throwValidationError(
106
+ "name",
107
+ name,
108
+ "Stage must have a valid 'name' property.",
109
+ );
110
+ }
111
+
112
+ if (this.stageNames.has(name)) {
113
+ this.throwValidationError(
114
+ "name",
115
+ name,
116
+ `Duplicate stage name found: "${name}".`,
117
+ );
118
+ }
119
+
120
+ this.stageNames.add(name);
121
+ }
122
+
123
+ /**
124
+ * Validates the stage dependencies.
125
+ *
126
+ * @param dependencies - The dependencies to validate.
127
+ * @throws Error if any dependency is invalid.
128
+ */
129
+ private validateDependencies(dependencies: string[] | undefined): void {
130
+ if (dependencies && !Array.isArray(dependencies)) {
131
+ throw new Error("Stage dependencies must be an array.");
132
+ }
133
+
134
+ dependencies?.forEach((dependency) => {
135
+ if (!this.stageNames.has(dependency)) {
136
+ this.throwValidationError(
137
+ "dependsOn",
138
+ [dependency], // Wrap dependency in an array to match the expected type
139
+ `Undefined dependency: "${dependency}". Ensure it references a valid stage.`,
140
+ );
141
+ }
142
+ });
143
+ }
144
+
145
+ /**
146
+ * Validates the steps within the stage.
147
+ *
148
+ * @param steps - The steps array to validate.
149
+ * @throws Error if any step is invalid.
150
+ */
151
+ private validateSteps(steps: StageInterface["steps"]): void {
152
+ if (!Array.isArray(steps) || steps.length === 0) {
153
+ this.throwValidationError(
154
+ "steps",
155
+ steps,
156
+ "Each stage must contain at least one step.",
157
+ );
158
+ }
159
+
160
+ const stepNames = new Set<string>();
161
+ steps.forEach((step) => {
162
+ if (stepNames.has(step.name)) {
163
+ this.throwValidationError(
164
+ "steps",
165
+ steps, // Pass the full steps array for context
166
+ `Duplicate step name found in stage: "${step.name}".`,
167
+ );
168
+ }
169
+ stepNames.add(step.name);
170
+
171
+ // Validate each step using StepValidator
172
+ this.stepValidator.validate(step);
173
+ });
174
+ }
175
+ }