@rudderstack/workflow-engine
Version:
A generic workflow execution engine
96 lines • 4.52 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WorkflowOutputsValidator = void 0;
const common_1 = require("../common");
const errors_1 = require("../errors");
// Matches: $.outputs.stepName,
// Result: [$.outputs.stepName, stepName, stepName];
// Matches: $.outputs.workflow.step,
// Result: [$.outputs.workflow.step, workflow.step, workflow, .step, step];
const regexOutputReference = /\$\.?outputs\.((\w+)(\.(\w+))?)/g;
class WorkflowOutputsValidator {
constructor(workflow) {
this.workflow = workflow;
this.seenSteps = new Set();
this.stepTypeMap = new Map();
}
validateWorkflowOutputReference(match, stepName, parentName) {
const workflowName = match[2]; // The name of the workflow step
// Access to the child step outputs is restricted to within the same parent workflow step;
if (parentName !== workflowName) {
throw new errors_1.WorkflowCreationError(`Invalid output reference: ${match[0]}, step is not a child of ${parentName}`, this.workflow.name, parentName, stepName);
}
}
validateExistanceOfOutputReference(match, stepName, parentName) {
const fullOutputName = match[1]; // For workflow step
const outputStepName = match[2]; // For simple step
// Check the referenced step output is already executed.
if (!this.seenSteps.has(fullOutputName) && !this.seenSteps.has(outputStepName)) {
throw new errors_1.WorkflowCreationError(`Invalid output reference: ${match[0]}, step is not executed yet.`, this.workflow.name, parentName ?? stepName, parentName ? stepName : undefined);
}
}
validateOutputReferences(stepName, template, parentName) {
if (!template) {
return;
}
const outputMatches = [...template.matchAll(regexOutputReference)];
// Multiple outputs may exist within the template so we need a loop.
// In this case, we are looking for workflow step output references.
// Format: $.outputs.workflowStepName.ChildStepName
for (const match of outputMatches) {
const primaryStepName = match[2]; // The name of the step
const childStepName = match[4]; // The name of the child step
if (this.stepTypeMap.get(primaryStepName) === common_1.StepType.Workflow && childStepName) {
this.validateWorkflowOutputReference(match, stepName, parentName);
}
this.validateExistanceOfOutputReference(match, stepName, parentName);
}
}
validateCommonStepParams(step, parentName) {
this.validateOutputReferences(step.name, step.condition, parentName);
this.validateOutputReferences(step.name, step.inputTemplate, parentName);
this.validateOutputReferences(step.name, step.loopCondition, parentName);
if (step.else) {
this.validateSteps([step.else], parentName);
}
}
validateBatchStep(step, parentName) {
if (step.batches) {
for (const batch of step.batches) {
this.validateOutputReferences(step.name, batch.filter, parentName);
this.validateOutputReferences(step.name, batch.map, parentName);
}
}
}
validateSteps(steps, parentName) {
for (const step of steps) {
const stepName = step.name;
const stepType = step.type;
this.stepTypeMap.set(stepName, stepType);
let outputName = stepName;
this.validateCommonStepParams(step, parentName);
if (step.type === common_1.StepType.Workflow) {
const workflowStep = step;
if (workflowStep.steps) {
this.validateSteps(workflowStep.steps, stepName);
}
}
else if (step.type === common_1.StepType.Simple) {
this.validateOutputReferences(stepName, step.template, parentName);
}
else if (step.type === common_1.StepType.Batch) {
this.validateBatchStep(step, parentName);
}
if (parentName) {
outputName = `${parentName}.${stepName}`;
}
this.seenSteps.add(outputName);
}
}
validateOutputs() {
const { steps: workflowSteps } = this.workflow;
this.validateSteps(workflowSteps);
}
}
exports.WorkflowOutputsValidator = WorkflowOutputsValidator;
//# sourceMappingURL=output_validator.js.map