@flowlab/all
Version:
A cool library focusing on handling various flows
229 lines (207 loc) • 7.12 kB
text/typescript
import { IStepConfig, StepType, INodeContext, IWorkflowContext } from '../types/index.js';
/**
* MARK: - Step
* @class Step
* @description 代表工作流中的一个步骤实例
*/
export class Step {
public readonly config: IStepConfig;
constructor(config: IStepConfig) {
// 可以在这里添加对 config 的验证
if (!config.id) throw new Error("步骤配置必须包含 'id'");
if (!config.type) throw new Error(`步骤 "${config.id}" 必须包含 'type'`);
// 设置默认值
this.config = {
maxRetries: 0,
retryDelay: 0,
compensateOnFailure: false,
...config,
};
}
/**
* MARK: - Getters
* 获取步骤 ID
*/
get id(): string {
return this.config.id;
}
/**
* MARK: - Getters
* 获取步骤类型
*/
get type(): StepType {
return this.config.type;
}
/**
* MARK: nextStepId
* 获取下一个顺序步骤的 ID
*/
get nextStepId(): string | undefined {
return this.config.nextStepId;
}
/**
* 评估条件 (仅用于 CONDITION 类型)
* @param context - 工作流上下文
* @returns 条件评估结果 (布尔值或分支键名)
* @throws 如果步骤类型不是 CONDITION 或未提供条件/分支,则抛出错误
*/
evaluateCondition(context: IWorkflowContext): boolean | string {
if (this.type !== StepType.CONDITION) {
throw new Error(`步骤 "${this.id}" 不是条件类型,无法评估条件。`);
}
if (!this.config.condition) {
throw new Error(`条件步骤 "${this.id}" 未定义 'condition' 函数或表达式。`);
}
try {
const result = this.config.condition(context);
if (typeof result === 'boolean') {
// 如果是布尔值,通常用于决定是否执行 nextStepId
return result;
} else if (typeof result === 'string') {
// 如果是字符串,用作分支的 key
if (!this.config.branches || !this.config.branches[result]) {
console.warn(`[Step: ${this.id}] 条件评估结果 "${result}" 没有对应的分支目标。`);
// 可以选择抛出错误或返回一个默认行为(例如 false)
// throw new Error(`条件步骤 "${this.id}" 的分支中未找到键 "${result}"。`);
return false; // 或者返回一个特殊值表示无匹配分支
}
return result; // 返回分支的 key
} else {
throw new Error(`条件步骤 "${this.id}" 的 'condition' 函数返回了无效类型: ${typeof result}`);
}
} catch (error: any) {
console.error(`[Step: ${this.id}] 评估条件时出错:`, error);
throw new Error(`评估步骤 "${this.id}" 的条件时失败: ${error.message}`);
}
}
/**
* 获取条件分支的目标步骤 ID (仅用于 CONDITION 类型)
* @param branchKey - evaluateCondition 返回的分支键名
* @returns 目标步骤 ID
* @throws 如果步骤类型不是 CONDITION 或未提供分支,或找不到对应的分支键,则抛出错误
*/
getBranchTarget(branchKey: string): string {
if (this.type !== StepType.CONDITION) {
throw new Error(`步骤 "${this.id}" 不是条件类型,无法获取分支目标。`);
}
if (!this.config.branches) {
throw new Error(`条件步骤 "${this.id}" 未定义 'branches'。`);
}
const targetStepId = this.config.branches[branchKey];
if (!targetStepId) {
throw new Error(`条件步骤 "${this.id}" 的分支中未找到键 "${branchKey}"。`);
}
return targetStepId;
}
/**
* 获取并行步骤的配置 (仅用于 PARALLEL 类型)
* @returns 并行步骤配置数组
* @throws 如果步骤类型不是 PARALLEL 或未提供并行步骤,则抛出错误
*/
getParallelSteps(): IStepConfig[] {
if (this.type !== StepType.PARALLEL) {
throw new Error(`步骤 "${this.id}" 不是并行类型,无法获取并行步骤。`);
}
if (!this.config.parallelSteps || this.config.parallelSteps.length === 0) {
throw new Error(`并行步骤 "${this.id}" 未定义 'parallelSteps' 或为空。`);
}
return this.config.parallelSteps;
}
/**
* 获取子工作流 ID (仅用于 SUB_WORKFLOW 类型)
* @returns 子工作流定义 ID
* @throws 如果步骤类型不是 SUB_WORKFLOW 或未提供子工作流 ID,则抛出错误
*/
getSubWorkflowId(): string {
if (this.type !== StepType.SUB_WORKFLOW) {
throw new Error(`步骤 "${this.id}" 不是子工作流类型。`);
}
if (!this.config.subWorkflowId) {
throw new Error(`子工作流步骤 "${this.id}" 未定义 'subWorkflowId'。`);
}
return this.config.subWorkflowId;
}
/**
* 获取传递给子工作流的输入 (仅用于 SUB_WORKFLOW 类型)
*/
getSubWorkflowInput(): Record<string, any> | undefined {
if (this.type !== StepType.SUB_WORKFLOW) {
throw new Error(`步骤 "${this.id}" 不是子工作流类型。`);
}
return this.config.subWorkflowInput;
}
/**
* 获取关联的节点 ID (仅用于 TASK 类型)
*/
getNodeId(): string | undefined {
if (this.type !== StepType.TASK) {
// 对于非 TASK 类型,可能没有 nodeId
// console.warn(`步骤 "${this.id}" 不是 TASK 类型,但尝试获取 nodeId。`);
return undefined;
}
if (!this.config.nodeId) {
throw new Error(`任务步骤 "${this.id}" 未定义 'nodeId'。`);
}
return this.config.nodeId;
}
/**
* 获取事件名称 (仅用于 EVENT_* 类型)
*/
getEventName(): string {
if (this.type !== StepType.EVENT_TRIGGER && this.type !== StepType.EVENT_LISTENER) {
throw new Error(`步骤 "${this.id}" 不是事件类型。`);
}
if (!this.config.event) {
throw new Error(`事件步骤 "${this.id}" 未定义 'event' 名称。`);
}
return this.config.event;
}
/**
* 获取步骤的静态输入或输入映射
*/
getInputConfig(): Record<string, any> | undefined {
return this.config.input;
}
/**
* 获取步骤的输出映射
*/
getOutputMapping(): Record<string, string> | undefined {
return this.config.outputMapping;
}
/**
* 获取超时时间
*/
getTimeout(): number | undefined {
return this.config.timeout;
}
/**
* 获取最大重试次数
*/
getMaxRetries(): number {
return this.config.maxRetries ?? 0;
}
/**
* 获取重试延迟
*/
getRetryDelay(): number {
return this.config.retryDelay ?? 0;
}
/**
* 获取失败补偿设置
*/
getCompensateOnFailure(): boolean | string {
return this.config.compensateOnFailure ?? false;
}
/**
* 获取执行此步骤所需的角色
*/
getRequiredRoles(): string[] | undefined {
return this.config.requiredRoles;
}
/**
* 获取 SLA 配置
*/
getSla(): number | undefined {
return this.config.sla;
}
}