Create ElementElement Error Detection

Create Element

Element Error Detection

Learn how to extend the function used to detect failures in the workflow.


Element Error Detection

To add the failure-detection logic for the new element, we'll update the file shown below:

// src/shared/kits/workflow/utilities/validate.ts

import type {
  Workflow,
  ElementFlow,
  ActionFlow,
  ConditionFlow,
  SwitchFlow,
  LoopFlow,
  ParallelFlow,
  Failure,
} from "../mvc/model/workflow";

export function validate(workflow: Workflow): Failure | null {
  if (workflow.flow.start.message === "") {
    return {
      type: "start",
      node: "start",
      message: "It can't be empty",
    };
  }
  if (workflow.flow.elements.length === 0) {
    return {
      type: "addTop",
      node: "addTop",
      message: "At least one element is required",
    };
  }
  for (const element of workflow.flow.elements) {
    const failure = validateElement(element);
    if (failure) return failure;
  }
  if (workflow.flow.end.message === "") {
    return {
      type: "end",
      node: "end",
      message: "It can't be empty",
    };
  }
  return null;
}

function validateElement(element: ElementFlow): Failure | null {
  switch (element.type) {
    case "action":
      return validateAction(element);
    case "condition":
      return validateCondition(element);
    case "switch":
      return validateSwitch(element);
    case "loop":
      return validateLoop(element);
    case "parallel":
      return validateParallel(element);
  }
}

function validateAction(element: ActionFlow): Failure | null {
  if (element.message === "") {
    return {
      type: "element",
      element: "action",
      id: element.id,
      node: `${element.id}/flow/block`,
      message: "It can't be empty",
    };
  }
  return null;
}

function validateCondition(element: ConditionFlow): Failure | null {
  if (element.if === "") {
    return {
      type: "element",
      element: "condition",
      id: element.id,
      node: `${element.id}/flow/block`,
      message: "It can't be empty",
    };
  }
  for (const thenElement of element.then) {
    const failure = validateElement(thenElement);
    if (failure) return failure;
  }
  for (const elseElement of element.else) {
    const failure = validateElement(elseElement);
    if (failure) return failure;
  }
  return null;
}

function validateSwitch(element: SwitchFlow): Failure | null {
  for (let i = 0; i < element.branches.length; i++) {
    const branch = element.branches[i];
    if (branch.case === "") {
      return {
        type: "element",
        element: "switch",
        id: element.id,
        branch: i,
        node: `${element.id}/flow/blockBranch/${i}`,
        message: "It can't be empty",
      };
    }
    for (const branchElement of branch.then) {
      const failure = validateElement(branchElement);
      if (failure) return failure;
    }
  }
  for (const defaultElement of element.default) {
    const failure = validateElement(defaultElement);
    if (failure) return failure;
  }
  return null;
}

function validateLoop(element: LoopFlow): Failure | null {
  if (element.while === "") {
    return {
      type: "element",
      element: "loop",
      id: element.id,
      node: `${element.id}/flow/block`,
      message: "It can't be empty",
    };
  }
  for (const intoElement of element.into) {
    const failure = validateElement(intoElement);
    if (failure) return failure;
  }
  return null;
}

function validateParallel(element: ParallelFlow): Failure | null {
  for (let i = 0; i < element.branches.length; i++) {
    const branch = element.branches[i];
    if (branch.label === "") {
      return {
        type: "element",
        element: "parallel",
        id: element.id,
        branch: i,
        node: `${element.id}/flow/blockBranch/${i}`,
        message: "It can't be empty",
      };
    }
    for (const branchElement of branch.then) {
      const failure = validateElement(branchElement);
      if (failure) return failure;
    }
  }
  return null;
}