From 03cdd0c9ba02b8d5fb3df9608ef8620af3111017 Mon Sep 17 00:00:00 2001 From: Lars van Vianen Date: Sun, 22 Dec 2024 09:12:43 +0100 Subject: [PATCH] Refactor --- src/ts/core/Action.ts | 10 +++--- src/ts/core/ActionRegistry.ts | 28 ++++++++-------- src/ts/core/ConfigLoader.ts | 59 ++++++++++++++++++++++------------ src/ts/core/FileWatcher.ts | 20 ++++++------ src/ts/core/Pipeline.ts | 14 ++++---- src/ts/core/PipelineManager.ts | 30 ++++++++--------- src/ts/core/Stage.ts | 6 ++-- src/ts/core/Step.ts | 8 ++--- src/ts/core/index.ts | 20 ++++++------ 9 files changed, 107 insertions(+), 88 deletions(-) diff --git a/src/ts/core/Action.ts b/src/ts/core/Action.ts index ae11b86..7434669 100644 --- a/src/ts/core/Action.ts +++ b/src/ts/core/Action.ts @@ -5,8 +5,8 @@ // Import // ============================================================================ -import { ActionInterface } from '../interface/ActionInterface'; -import { ActionOptionsType } from '../types/ActionOptionsType'; +import { ActionInterface } from "../interface/ActionInterface"; +import { ActionOptionsType } from "../types/ActionOptionsType"; // ============================================================================ @@ -27,7 +27,7 @@ export abstract class Action implements ActionInterface { * validation logic. * * @param options - The options to validate, ensuring they meet the - * action's specific requirements. + * action"s specific requirements. * @returns A boolean indicating whether the options are valid. Default * implementation always returns true. */ @@ -39,7 +39,7 @@ export abstract class Action implements ActionInterface { /** * Abstract method that must be implemented by derived classes to perform - * the action's main logic. + * the action"s main logic. * This method is invoked during the step execution process. * * @param options - A structured set of options specific to the action's @@ -57,7 +57,7 @@ export abstract class Action implements ActionInterface { * @returns A string description of the action. */ describe(): string { - return 'Base action for executing steps in the pipeline.'; + return "Base action for executing steps in the pipeline."; } /** diff --git a/src/ts/core/ActionRegistry.ts b/src/ts/core/ActionRegistry.ts index 4553b2a..8e34288 100644 --- a/src/ts/core/ActionRegistry.ts +++ b/src/ts/core/ActionRegistry.ts @@ -5,13 +5,13 @@ // Import // ============================================================================ -import { DirectoryCleanAction } from '../actions/DirectoryCleanAction/DirectoryCleanAction'; -import { DirectoryCopyAction } from '../actions/DirectoryCopyAction/DirectoryCopyAction'; -import { FileCopyAction } from '../actions/FileCopyAction/FileCopyAction'; -import { PackageManagerAction } from '../actions/PackageManagerAction/PackageManagerAction'; -import { StyleProcessingAction } from '../actions/StyleProcessingAction/StyleProcessingAction'; -import { VersionWriteAction } from '../actions/VersionWriterAction/VersionWriterAction'; -import { ActionInterface } from '../interface/ActionInterface'; +import { DirectoryCleanAction } from "../actions/DirectoryCleanAction/DirectoryCleanAction"; +import { DirectoryCopyAction } from "../actions/DirectoryCopyAction/DirectoryCopyAction"; +import { FileCopyAction } from "../actions/FileCopyAction/FileCopyAction"; +import { PackageManagerAction } from "../actions/PackageManagerAction/PackageManagerAction"; +import { StyleProcessingAction } from "../actions/StyleProcessingAction/StyleProcessingAction"; +import { VersionWriteAction } from "../actions/VersionWriterAction/VersionWriterAction"; +import { ActionInterface } from "../interface/ActionInterface"; // ============================================================================ @@ -33,7 +33,7 @@ const actionRegistry: Map ActionInterface> = new Map(); * @param name - The unique name of the action. This name is used to reference * the action in pipeline configurations. * @param actionClass - The class that implements the ActionInterface - * interface. This class defines the action's behavior. + * interface. This class defines the action"s behavior. * @throws Error if the action name is already registered, ensuring uniqueness * of action names. */ @@ -74,9 +74,9 @@ export function listRegisteredActions(): string[] { } // Pre-register core actions -registerAction('DirectoryCleanAction', DirectoryCleanAction); -registerAction('DirectoryCopyAction', DirectoryCopyAction); -registerAction('FileCopyAction', FileCopyAction); -registerAction('PackageManagerAction', PackageManagerAction); -registerAction('StyleProcessingAction', StyleProcessingAction); -registerAction('VersionWriteAction', VersionWriteAction); +registerAction("DirectoryCleanAction", DirectoryCleanAction); +registerAction("DirectoryCopyAction", DirectoryCopyAction); +registerAction("FileCopyAction", FileCopyAction); +registerAction("PackageManagerAction", PackageManagerAction); +registerAction("StyleProcessingAction", StyleProcessingAction); +registerAction("VersionWriteAction", VersionWriteAction); diff --git a/src/ts/core/ConfigLoader.ts b/src/ts/core/ConfigLoader.ts index af5c3f6..0b55682 100644 --- a/src/ts/core/ConfigLoader.ts +++ b/src/ts/core/ConfigLoader.ts @@ -4,10 +4,10 @@ * and converts it into a usable format for the pipeline. */ -import path from 'path'; -import fs from 'fs'; -import yaml from 'js-yaml'; -import { ConfigInterface } from '../interface/ConfigInterface'; +import path from "path"; +import fs from "fs"; +import yaml from "js-yaml"; +import { ConfigInterface } from "../interface/ConfigInterface"; export class ConfigLoader { private configPath: string; @@ -16,19 +16,21 @@ export class ConfigLoader { * Constructs a ConfigLoader instance, setting up the path to the * configuration file. */ - constructor(configFileName: string = 'pack.yaml') { + constructor(configFileName: string = "pack.yaml") { this.configPath = path.resolve(process.cwd(), configFileName); } /** * Loads the configuration from the YAML file. - * @returns ConfigInterface - The parsed configuration object containing the pipeline stages, steps, and global options. - * @throws Error if the configuration file cannot be read, parsed, or validated. + * @returns ConfigInterface - The parsed configuration object containing + * the pipeline stages, steps, and global options. + * @throws Error if the configuration file cannot be read, parsed, + * or validated. */ public loadConfig(): ConfigInterface { try { // Read and parse the YAML configuration file - const fileContents = fs.readFileSync(this.configPath, 'utf8'); + const fileContents = fs.readFileSync(this.configPath, "utf8"); const config = yaml.load(fileContents) as ConfigInterface; // Validate the configuration structure @@ -36,19 +38,24 @@ export class ConfigLoader { return config; } catch (error) { - throw new Error(`Failed to load config from ${this.configPath}: ${(error as Error).message}`); + throw new Error( + `Failed to load config from ${this.configPath}: ${(error as Error).message}` + ); } } /** * Validates the structure and content of the configuration object. - * Ensures that stages have unique names, valid dependencies, and that the configuration adheres to expected formats. + * Ensures that stages have unique names, valid dependencies, and that + * the configuration adheres to expected formats. * @param config - The configuration object to validate. * @throws Error if the configuration is invalid. */ private validateConfig(config: ConfigInterface): void { if (!config || !Array.isArray(config.stages)) { - throw new Error('Invalid configuration format: "stages" must be an array.'); + throw new Error( + "Invalid configuration format: 'stages' must be an array." + ); } const stageNames = new Set(); @@ -64,7 +71,9 @@ export class ConfigLoader { if (stage.dependsOn) { for (const dependency of stage.dependsOn) { if (!stageNames.has(dependency)) { - throw new Error(`Stage "${stage.name}" has an undefined dependency: "${dependency}".`); + throw new Error( + `Stage "${stage.name}" has an undefined dependency: "${dependency}".` + ); } } } @@ -75,31 +84,41 @@ export class ConfigLoader { } /** - * Validates the steps within a stage, ensuring each step has the necessary properties. + * Validates the steps within a stage, ensuring each step has the + * necessary properties. * @param steps - The steps array to validate. * @param stageName - The name of the stage containing the steps. * @throws Error if any step is invalid. */ private validateSteps(steps: any[], stageName: string): void { if (!Array.isArray(steps) || steps.length === 0) { - throw new Error(`Stage "${stageName}" must contain at least one step.`); + throw new Error( + `Stage "${stageName}" must contain at least one step.` + ); } const stepNames = new Set(); for (const step of steps) { - if (!step.name || typeof step.name !== 'string') { - throw new Error(`Each step in stage "${stageName}" must have a valid "name" property.`); + if (!step.name || typeof step.name !== "string") { + throw new Error( + `Each step in stage "${stageName}" must have a valid "name" property.` + ); } if (stepNames.has(step.name)) { - throw new Error(`Duplicate step name found in stage "${stageName}": "${step.name}".`); + throw new Error( + `Duplicate step name found in stage "${stageName}": "${step.name}".` + ); } stepNames.add(step.name); - // Further validation for step actions and options could be added here as needed - if (!step.action || typeof step.action !== 'string') { - throw new Error(`Step "${step.name}" in stage "${stageName}" must have a valid "action" property.`); + // Further validation for step actions and options could be added + // here as needed + if (!step.action || typeof step.action !== "string") { + throw new Error( + `Step "${step.name}" in stage "${stageName}" must have a valid "action" property.` + ); } } } diff --git a/src/ts/core/FileWatcher.ts b/src/ts/core/FileWatcher.ts index 069e817..5daba38 100644 --- a/src/ts/core/FileWatcher.ts +++ b/src/ts/core/FileWatcher.ts @@ -5,7 +5,7 @@ // Import // ============================================================================ -import chokidar, { FSWatcher } from 'chokidar'; +import chokidar, { FSWatcher } from "chokidar"; // ============================================================================ @@ -30,7 +30,7 @@ export class FileWatcher { this.watcher = chokidar.watch(this.pathsToWatch, { ignored: this.ignoredPaths, persistent: true, - ignoreInitial: true, // Prevents initial 'add' events on startup + ignoreInitial: true, // Prevents initial "add" events on startup awaitWriteFinish: { stabilityThreshold: 100, // Waits for file to finish writing pollInterval: 100, // Polling interval to check for file stability @@ -46,10 +46,10 @@ export class FileWatcher { */ private setupWatchers() { this.watcher - .on('ready', () => { - console.log('File watching is active. Waiting for changes...'); + .on("ready", () => { + console.log("File watching is active. Waiting for changes..."); }) - .on('change', (filePath) => { + .on("change", (filePath) => { console.log(`File changed: ${filePath}`); try { this.onChange(filePath); @@ -57,8 +57,8 @@ export class FileWatcher { console.error(`Error handling file change for ${filePath}:`, error); } }) - .on('error', (error) => { - console.error('Watcher encountered an error:', error); + .on("error", (error) => { + console.error("Watcher encountered an error:", error); }); } @@ -73,7 +73,7 @@ export class FileWatcher { ignoreInitial: true, }); this.setupWatchers(); - console.log('File watching started.'); + console.log("File watching started."); } } @@ -83,9 +83,9 @@ export class FileWatcher { public stopWatching(): void { if (this.watcher) { this.watcher.close().then(() => { - console.log('File watching stopped.'); + console.log("File watching stopped."); }).catch(error => { - console.error('Error stopping file watcher:', error); + console.error("Error stopping file watcher:", error); }); } } diff --git a/src/ts/core/Pipeline.ts b/src/ts/core/Pipeline.ts index ac03bbe..c355640 100644 --- a/src/ts/core/Pipeline.ts +++ b/src/ts/core/Pipeline.ts @@ -5,8 +5,8 @@ // Import // ============================================================================ -import { ConfigInterface } from '../interface/ConfigInterface'; -import { Stage } from './Stage'; +import { ConfigInterface } from "../interface/ConfigInterface"; +import { Stage } from "./Stage"; // ============================================================================ @@ -27,7 +27,7 @@ export class Pipeline { /** * Global options that apply across the entire pipeline. */ - private globalOptions?: ConfigInterface['globalOptions']; + private globalOptions?: ConfigInterface["globalOptions"]; /** * Constructs a new Pipeline instance with the given configuration. @@ -47,7 +47,7 @@ export class Pipeline { * handling, and execution control. */ async run(): Promise { - console.log('Starting pipeline execution...'); + console.log("Starting pipeline execution..."); // Track stages that have been completed const completedStages = new Set(); @@ -59,16 +59,16 @@ export class Pipeline { ); await this.runWithConcurrencyControl(stagePromises); } catch (error) { - console.error('Pipeline execution failed:', error); + console.error("Pipeline execution failed:", error); if (this.globalOptions?.haltOnFailure !== false) { - console.error('Halting pipeline due to failure.'); + console.error("Halting pipeline due to failure."); // Optionally halt the process if the pipeline is set to // halt on failure process.exit(1); } } - console.log('Pipeline execution completed successfully.'); + console.log("Pipeline execution completed successfully."); } /** diff --git a/src/ts/core/PipelineManager.ts b/src/ts/core/PipelineManager.ts index d16c68f..ce52495 100644 --- a/src/ts/core/PipelineManager.ts +++ b/src/ts/core/PipelineManager.ts @@ -5,8 +5,8 @@ // Import // ============================================================================ -import { spawn, ChildProcess } from 'child_process'; -import { LiveReloadServer } from '../core/LiveReloadServer'; +import { spawn, ChildProcess } from "child_process"; +import { LiveReloadServer } from "../core/LiveReloadServer"; // ============================================================================ @@ -24,24 +24,24 @@ export class PipelineManager { constructor(private reloadServer: LiveReloadServer) {} /** - * Restarts the pipeline process, killing the existing process if it's + * Restarts the pipeline process, killing the existing process if it"s * running. Notifies connected clients via the LiveReloadServer after * restarting. */ public restartPipeline(): void { if (this.pipelineProcess) { - console.log('Stopping current pipeline process...'); + console.log("Stopping current pipeline process..."); this.stopPipeline(); } - console.log('Starting pipeline...'); + console.log("Starting pipeline..."); this.pipelineProcess = spawn( - 'npm', - ['run', 'start'], - { stdio: 'inherit' } + "npm", + ["run", "start"], + { stdio: "inherit" } ); - this.pipelineProcess.on('close', (code) => { + this.pipelineProcess.on("close", (code) => { if (code !== 0) { console.error( `Pipeline process exited with code ${code}` @@ -51,13 +51,13 @@ export class PipelineManager { this.reloadServer.reloadClients(); }); - this.pipelineProcess.on('error', (error) => { + this.pipelineProcess.on("error", (error) => { console.error( - 'Error starting pipeline process:', error + "Error starting pipeline process:", error ); }); - this.pipelineProcess.on('exit', (code, signal) => { + this.pipelineProcess.on("exit", (code, signal) => { if (signal) { console.log( `Pipeline process was killed with signal: ${signal}` @@ -76,14 +76,14 @@ export class PipelineManager { */ public stopPipeline(): void { if (this.pipelineProcess) { - this.pipelineProcess.kill('SIGTERM'); + this.pipelineProcess.kill("SIGTERM"); this.pipelineProcess = null; console.log( - 'Pipeline process stopped.' + "Pipeline process stopped." ); } else { console.log( - 'No pipeline process is currently running.' + "No pipeline process is currently running." ); } } diff --git a/src/ts/core/Stage.ts b/src/ts/core/Stage.ts index 90bb6f2..036cb4c 100644 --- a/src/ts/core/Stage.ts +++ b/src/ts/core/Stage.ts @@ -5,8 +5,8 @@ // Import // ============================================================================ -import { StageInterface } from '../interface/StageInterface'; -import { Step } from './Step'; +import { StageInterface } from "../interface/StageInterface"; +import { Step } from "./Step"; // ============================================================================ @@ -76,7 +76,7 @@ export class Stage { if (!this.dependsOn) return; console.log( - `Stage ${this.name} is waiting for dependencies: ${this.dependsOn.join(', ')}` + `Stage ${this.name} is waiting for dependencies: ${this.dependsOn.join(", ")}` ); await Promise.all( this.dependsOn.map( diff --git a/src/ts/core/Step.ts b/src/ts/core/Step.ts index d21345f..7d2e772 100644 --- a/src/ts/core/Step.ts +++ b/src/ts/core/Step.ts @@ -5,9 +5,9 @@ // Import // ============================================================================ -import { ActionInterface } from '../interface/ActionInterface'; -import { StepInterface } from '../interface/StepInterface'; -import { getAction } from './ActionRegistry'; +import { ActionInterface } from "../interface/ActionInterface"; +import { StepInterface } from "../interface/StepInterface"; +import { getAction } from "./ActionRegistry"; // ============================================================================ @@ -53,7 +53,7 @@ export class Step { console.log(`Running step: ${this.name}`); try { // Validate options if the action provides a validation method - if (typeof this.action.validateOptions === 'function') { + if (typeof this.action.validateOptions === "function") { const isValid = this.action.validateOptions( this.options || {} ); diff --git a/src/ts/core/index.ts b/src/ts/core/index.ts index 4bede0b..d848ad6 100644 --- a/src/ts/core/index.ts +++ b/src/ts/core/index.ts @@ -3,19 +3,19 @@ // Export core classes and functions from the core directory -export { Pipeline } from './Pipeline'; -export { Stage } from './Stage'; -export { Step } from './Step'; -export { Action } from './Action'; -export { LiveReloadServer } from './LiveReloadServer'; -export { FileWatcher } from './FileWatcher'; -export { PipelineManager } from './PipelineManager'; +export { Pipeline } from "./Pipeline"; +export { Stage } from "./Stage"; +export { Step } from "./Step"; +export { Action } from "./Action"; +export { LiveReloadServer } from "./LiveReloadServer"; +export { FileWatcher } from "./FileWatcher"; +export { PipelineManager } from "./PipelineManager"; -// export { StyleProcessingAction } from './StyleProcessingAction'; // Example of exporting a specific action, add others as needed +// export { StyleProcessingAction } from "./StyleProcessingAction"; // Example of exporting a specific action, add others as needed // Export utility functions or other core modules if applicable // For example: -// export { someUtilityFunction } from './utils'; +// export { someUtilityFunction } from "./utils"; // Export registry for actions -// export { registerAction, getAction, listRegisteredActions } from '../actions/ActionRegistry'; \ No newline at end of file +// export { registerAction, getAction, listRegisteredActions } from "../actions/ActionRegistry"; \ No newline at end of file