Stirling-PDF/shared-operations/src/workflow/validateOperations.ts

74 lines
3.3 KiB
TypeScript
Raw Normal View History

import { Operator } from "../functions";
2023-11-20 22:12:03 +01:00
import { Action } from "../../declarations/Action";
import { getOperatorByName } from "./getOperatorByName";
2023-11-20 22:12:03 +01:00
/** This function validates the "workflow-json" from the API */
2023-11-20 22:12:03 +01:00
export function validateOperations(actions: Action[]): { valid: boolean, reason?: string} {
2023-12-21 15:57:51 +01:00
const done: Action[] = [];
for (const action of actions) {
2023-12-21 15:57:51 +01:00
if (action.type === "done") {
if(done[action.values.id] !== undefined) {
return { valid: false, reason: "There is a duplicate id in the done actions." };
}
2023-12-21 15:57:51 +01:00
done[action.values.id] = action;
continue;
}
const operator = getOperatorByName(action.type);
if(!operator) {
return { valid: false, reason: `action.type ${action.type} does not exist` }
}
const validationResult = operator.schema.validate({values: action.values});
// TODO: convert everything to joiresult format
if(validationResult.error) {
return { valid: false, reason: validationResult.error.message};
}
if (action.actions) {
2023-12-21 15:57:51 +01:00
// Check io compatibility of the operators
for (const childAction of action.actions) {
if (childAction.type === "wait") {
if(done[childAction.values.id] === undefined) {
return { valid: false, reason: "There is a wait action that does not have an associated done action." };
}
for (const afterDoneChild of done[childAction.values.id]?.actions || []) {
const receivingOperator = getOperatorByName(afterDoneChild.type);
if (!receivingOperator) {
return { valid: false, reason: `The receiving operator ${afterDoneChild.type} does not exist.` };
} else if (!ioCompatible(operator, receivingOperator)) {
2023-12-21 15:57:51 +01:00
return { valid: false, reason: `Ouput of action ${action.type} is not compatible with input of action ${afterDoneChild.type}` };
}
}
}
else if (action.type === "done") {
return { valid: false, reason: `There shouldn't be a done action here.` };
}
else {
const receivingOperator = getOperatorByName(childAction.type);
if (!receivingOperator) {
return { valid: false, reason: `The receiving operator ${childAction.type} does not exist.` };
} else if (!ioCompatible(operator, receivingOperator)) {
2023-12-21 15:57:51 +01:00
return { valid: false, reason: `Ouput of action ${action.type} is not compatible with input of action ${childAction.type}` };
}
}
}
const validationResult = validateOperations(action.actions);
if(!validationResult.valid) {
return validationResult;
}
2023-11-20 22:12:03 +01:00
}
}
return { valid: true };
2023-12-21 15:57:51 +01:00
}
function ioCompatible(outputingOperator: typeof Operator, receivingOperator: typeof Operator): boolean {
2023-12-21 15:57:51 +01:00
const outputType = outputingOperator.schema.describe().keys.output.label;
const inputType = receivingOperator.schema.describe().keys.input.label;
2023-12-21 15:57:51 +01:00
return outputType == inputType;
}