asl-validator
Version:
Amazon States Language validator
197 lines (196 loc) • 8.89 kB
JavaScript
;
var json_schema_errors_1 = require("./checks/json-schema-errors");
var missing_transition_target_errors_1 = require("./checks/missing-transition-target-errors");
var state_transitions_errors_1 = require("./checks/state-transitions-errors");
var duplicate_state_names_errors_1 = require("./checks/duplicate-state-names-errors");
var missing_terminal_state_errors_1 = require("./checks/missing-terminal-state-errors");
var types_1 = require("./types");
var duplicate_payload_template_fields_1 = require("./checks/duplicate-payload-template-fields");
var state_checks_1 = require("./checks/state-checks");
var DefaultOptions = {
checkPaths: true,
checkArn: true,
};
module.exports = function validator(definition, opts) {
var _a;
// A state machine's query language defaults to JSONPath.
// The interpreter MUST support JSONPath and JSONata, and
// MAY support others.
var defaultQueryLanguage = (_a = definition.QueryLanguage) !== null && _a !== void 0 ? _a : "JSONPath";
var IsJsonPath = function (_a) {
var _b;
var state = _a.state;
var queryLanguage = (_b = state.QueryLanguage) !== null && _b !== void 0 ? _b : defaultQueryLanguage;
return queryLanguage === "JSONPath";
};
var IsJsonNata = function (_a) {
var _b;
var state = _a.state;
var queryLanguage = (_b = state.QueryLanguage) !== null && _b !== void 0 ? _b : defaultQueryLanguage;
return queryLanguage === "JSONata";
};
var options = opts !== null && opts !== void 0 ? opts : DefaultOptions;
var errors = (0, json_schema_errors_1.jsonSchemaErrors)(definition, options);
if (errors.length === 0) {
errors.push.apply(errors, (0, missing_transition_target_errors_1.missingTransitionTargetErrors)(definition, options));
errors.push.apply(errors, (0, state_transitions_errors_1.stateTransitionsErrors)(definition, options));
errors.push.apply(errors, (0, duplicate_state_names_errors_1.duplicateStateNames)(definition, options));
errors.push.apply(errors, (0, missing_terminal_state_errors_1.missingTerminalStateErrors)(definition, options));
errors.push.apply(errors, (0, duplicate_payload_template_fields_1.mustNotHaveDuplicateFieldNamesAfterEvaluation)(definition, options));
errors.push.apply(errors, (0, state_checks_1.stateChecks)(definition, options, [
{
filter: state_checks_1.IsTask,
checker: (0, state_checks_1.AtMostOne)({
props: ["TimeoutSeconds", "TimeoutSecondsPath"],
errorCode: types_1.StateMachineErrorCode.TaskTimeoutError,
}),
},
{
filter: state_checks_1.IsTask,
checker: (0, state_checks_1.AtMostOne)({
props: ["HeartbeatSeconds", "HeartbeatSecondsPath"],
errorCode: types_1.StateMachineErrorCode.TaskHeartbeatError,
}),
},
{
filter: state_checks_1.IsMap,
checker: (0, state_checks_1.ExactlyOne)({
props: ["ItemProcessor", "Iterator"],
errorCode: types_1.StateMachineErrorCode.MapItemProcessorError,
}),
},
{
filter: state_checks_1.IsMap,
checker: (0, state_checks_1.AtMostOne)({
props: ["ItemSelector", "Parameters"],
errorCode: types_1.StateMachineErrorCode.MapItemSelectorError,
}),
},
{
filter: state_checks_1.IsWait,
checker: (0, state_checks_1.ExactlyOne)({
props: ["Seconds", "SecondsPath", "Timestamp", "TimestampPath"],
errorCode: types_1.StateMachineErrorCode.WaitDurationError,
}),
},
{
// performs the check that non-Terminal states do not contain a `Next` field.
// This replaces the following schema snippet:
// "oneOf": [{
// "required": ["Next"]
// }, {
// "required": ["End"]
// }],
filter: function (entry) {
return !((0, state_checks_1.IsSucceed)(entry) || (0, state_checks_1.IsFail)(entry) || (0, state_checks_1.IsChoice)(entry));
},
checker: (0, state_checks_1.ExactlyOne)({
props: ["End", "Next"],
errorCode: types_1.StateMachineErrorCode.TerminalStateWithNextError,
}),
},
{
filter: state_checks_1.IsMap,
checker: (0, state_checks_1.AtMostOne)({
props: ["ToleratedFailureCount", "ToleratedFailureCountPath"],
errorCode: types_1.StateMachineErrorCode.MapToleratedFailureError,
}),
},
{
filter: state_checks_1.IsMap,
checker: (0, state_checks_1.AtMostOne)({
props: [
"ToleratedFailurePercentage",
"ToleratedFailurePercentagePath",
],
errorCode: types_1.StateMachineErrorCode.MapToleratedFailureError,
}),
},
{
filter: state_checks_1.IsMap,
checker: (0, state_checks_1.AtMostOne)({
props: ["MaxConcurrency", "MaxConcurrencyPath"],
errorCode: types_1.StateMachineErrorCode.MapMaxConcurrencyError,
}),
},
{
filter: state_checks_1.IsMap,
checker: (0, state_checks_1.AtMostOne)({
props: ["MaxItems", "MaxItemsPath"],
path: "$.ItemReader.ReaderConfig",
errorCode: types_1.StateMachineErrorCode.MapItemReaderMaxItemsError,
}),
},
{
filter: state_checks_1.IsMap,
checker: (0, state_checks_1.AtMostOne)({
props: ["MaxItemsPerBatch", "MaxItemsPerBatchPath"],
path: "$.ItemBatcher",
errorCode: types_1.StateMachineErrorCode.MapItemBatcherError,
}),
},
{
filter: state_checks_1.IsMap,
checker: (0, state_checks_1.AtMostOne)({
props: ["MaxInputBytesPerBatch", "MaxInputBytesPerBatchPath"],
path: "$.ItemBatcher",
errorCode: types_1.StateMachineErrorCode.MapItemBatcherError,
}),
},
{
filter: state_checks_1.IsFail,
checker: (0, state_checks_1.AtMostOne)({
props: ["Cause", "CausePath"],
errorCode: types_1.StateMachineErrorCode.FailCauseProperty,
}),
},
{
filter: state_checks_1.IsFail,
checker: (0, state_checks_1.AtMostOne)({
props: ["Error", "ErrorPath"],
errorCode: types_1.StateMachineErrorCode.FailErrorProperty,
}),
},
{
filter: IsJsonNata,
checker: (0, state_checks_1.None)({
props: [
"InputPath",
"OutputPath",
"ResultPath",
"Parameters",
"ResultSelector",
],
errorCode: types_1.StateMachineErrorCode.QueryLanguageFieldError,
}),
},
{
filter: IsJsonPath,
checker: (0, state_checks_1.None)({
props: ["Arguments", "Output"],
errorCode: types_1.StateMachineErrorCode.QueryLanguageFieldError,
}),
},
{
filter: function (entry) {
return (0, state_checks_1.IsMap)(entry) && IsJsonPath(entry);
},
checker: (0, state_checks_1.None)({
props: ["Arguments"],
path: "$.ItemReader",
errorCode: types_1.StateMachineErrorCode.QueryLanguageFieldError,
}),
},
]));
}
return {
isValid: errors.length === 0,
errors: errors,
errorsText: function (separator) {
if (separator === void 0) { separator = "\n"; }
return errors
.map(function (error) { return "".concat(error["Error code"], ": ").concat(error.Message); })
.join(separator);
},
};
};