@flowlab/all
Version:
A cool library focusing on handling various flows
86 lines (71 loc) • 3 kB
text/typescript
import { StepConfig, WorkflowDefinitionData, ConditionFunction, TaskStepConfig, ConditionStepConfig, ParallelStepConfig, SubWorkflowStepConfig, StepType } from '../types/config';
import { ConfigurationError } from '../errors';
export class WorkflowDefinition {
private data: WorkflowDefinitionData;
constructor(id: string, name?: string, description?: string) {
if (!id) throw new ConfigurationError('Workflow definition ID is required.');
this.data = {
id,
name,
description,
steps: {},
};
}
// --- Chainable Methods for Building ---
addStep(config: Omit<TaskStepConfig, 'type'>): this {
this._addStepInternal({ ...config, type: StepType.TASK });
return this;
}
addCondition(config: Omit<ConditionStepConfig, 'type'>): this {
this._addStepInternal({ ...config, type: StepType.CONDITION });
return this;
}
addParallel(config: Omit<ParallelStepConfig, 'type'>): this {
// TODO: Add validation for parallel steps structure
this._addStepInternal({ ...config, type: StepType.PARALLEL });
return this;
}
addSubWorkflow(config: Omit<SubWorkflowStepConfig, 'type'>): this {
this._addStepInternal({ ...config, type: StepType.SUB_WORKFLOW });
return this;
}
// TODO: Add methods for EventTrigger, EventListener etc.
setStartStep(stepId: string): this {
if (!this.data.steps[stepId]) {
throw new ConfigurationError(`Cannot set start step: Step with ID '${stepId}' does not exist in definition '${this.data.id}'.`);
}
this.data.startStepId = stepId;
return this;
}
// --- Internal Logic ---
private _addStepInternal(config: StepConfig): void {
if (!config.id) throw new ConfigurationError('Step ID is required.');
if (this.data.steps[config.id]) throw new ConfigurationError(`Step with ID '${config.id}' already exists in definition '${this.data.id}'.`);
// TODO: Add more validation based on step type (e.g., nextStepId presence/absence)
this.data.steps[config.id] = config;
}
// --- Accessors ---
get id(): string { return this.data.id; }
get name(): string | undefined { return this.data.name; }
get description(): string | undefined { return this.data.description; }
get startStepId(): string | undefined { return this.data.startStepId; }
getStep(stepId: string): StepConfig | undefined {
return this.data.steps[stepId];
}
getSteps(): Readonly<Record<string, StepConfig>> {
return this.data.steps;
}
// Get the raw data for persistence or inspection
getData(): Readonly<WorkflowDefinitionData> {
return this.data;
}
// TODO: Add a validate() method similar to Root
validate(): boolean {
if (!this.data.startStepId) {
console.error(`[Validation Error] Workflow '${this.id}': Start step not set.`);
return false;
}
// TODO: Check for unreachable steps, cycles (if not allowed), valid nextStepId refs etc.
return true;
}
}