asl-validator
Version:
Amazon States Language validator
88 lines (87 loc) • 4.11 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.stateTransitionsErrors = void 0;
var jsonpath_plus_1 = require("jsonpath-plus");
var types_1 = require("../types");
var stateTransitionsErrors = function (definition) {
var errorMessages = [];
// given a nested state machine, this function will examine
// each state and record its `Next` or `Default` values
// to see what states are reachable.
// Avoids traversing into Map or Parallel states since the
// states defined within those containers are not valid
// targets for states outside the containers.
var nextAndDefaultTargets = function (nestedStateMachine) {
var states = [];
Object.keys(nestedStateMachine.States).forEach(function (stateName) {
var nestedState = nestedStateMachine.States[stateName];
var isContainer = ["Map", "Parallel"].indexOf(nestedState.Type) >= 0;
if (isContainer) {
states.push.apply(states, (0, jsonpath_plus_1.JSONPath)({
json: nestedState,
path: "$.Next",
}));
states.push.apply(states, (0, jsonpath_plus_1.JSONPath)({
json: nestedState,
path: "$.Default",
}));
}
else {
states.push.apply(states, (0, jsonpath_plus_1.JSONPath)({
json: nestedState,
path: "$..[Next,Default]",
}));
}
});
return states;
};
// reports an error for each state that is found to be an invalid
// transition
var validateNestedStateMachine = function (nestedStateMachine) {
var availStateNames = [];
// don't traverse into any nested states. We only want to record the States
// that are immediately under the Branch.
// These are the only valid states to link to from within the branch
(0, jsonpath_plus_1.JSONPath)({
json: nestedStateMachine,
path: "$.States",
}).forEach(function (branchStates) {
availStateNames = availStateNames.concat(Object.keys(branchStates));
});
// check that there are no transitions outside this branch
var targetedStates = nextAndDefaultTargets(nestedStateMachine);
return targetedStates.filter(function (state) { return availStateNames.indexOf(state) === -1; });
};
// we know the step function is schema valid
// we know that every `Parallel` state has its expected `Branches` field
// we need to visit each Branch within a Parallel to ensure that it doesn't
// link outside its branch.
(0, jsonpath_plus_1.JSONPath)({
json: definition,
path: "$..Branches",
}).forEach(function (parallelBranches) {
parallelBranches.forEach(function (nestedStateMachine) {
var errs = validateNestedStateMachine(nestedStateMachine).map(function (state) { return ({
"Error code": types_1.StateMachineErrorCode.BranchOutboundTransitionTarget,
Message: "Parallel branch state cannot transition to target: ".concat(state),
}); });
errorMessages.push.apply(errorMessages, errs);
});
});
// we know the step function is schema valid
// we know that every `Map` state has its expected `Iterator` field
// we need to visit the Iterator within a Map to ensure that it doesn't
// link outside its container.
(0, jsonpath_plus_1.JSONPath)({
json: definition,
path: "$..Iterator",
}).forEach(function (nestedStateMachine) {
var errs = validateNestedStateMachine(nestedStateMachine).map(function (state) { return ({
"Error code": types_1.StateMachineErrorCode.MapOutboundTransitionTarget,
Message: "Map branch state cannot transition to target: ".concat(state),
}); });
errorMessages.push.apply(errorMessages, errs);
});
return errorMessages;
};
exports.stateTransitionsErrors = stateTransitionsErrors;