Repository: ChristopheBougere/asl-validator (ts)

Issue:
Validation error in Parameters for Task type Pass
**Describe the bug**
For State Type Pass it throws validation errror
```
 keyword: 'type',
    dataPath: ".States['EmptyState'].Parameters[0]",
    schemaPath: 'pass.json#/properties/Parameters/items/type',
    params: { type: 'object' },
    message: 'should be object'
```
**To Reproduce**
Please provide a complete state machine definition:
```json
{
  "StartAt": "EmptyState",
  "States": {
    "EmptyState": {
       "Type": "Pass",
      "Parameters": ["abc"],
      "ResultPath": "$.emptyState",
      "End": true
    }
  }
}
```

**Expected behavior**

Parameters can accept ARRAY, NUMBER, BOOLEAN, OBJECT, STRING

**Version:** [e.g. 1.9.4, can be found by running `asl-validator --version`]
2.2.1
**Additional context**
Add any other context about the problem here.


Pull request description:
fix(schemas): payload template definition was too restrictive
closes #101 

Patch:
diff --git a/bin/asl-validator.ts b/bin/asl-validator.ts
index a596c22..563ba9e 100755
--- a/bin/asl-validator.ts
+++ b/bin/asl-validator.ts
@@ -5,13 +5,15 @@ import fs from 'fs';
 import program from 'commander';
 
 import validator from '../src/validator';
-import { StateMachine } from '../src/types';
+import {StateMachine, ValidationOptions} from '../src/types';
 
 program
   .description('Amazon States Language validator')
   .option('--json-definition <jsonDefinition>', 'JSON definition')
   .option('--json-path <jsonPath>', 'JSON path')
   .option('--silent', 'silent mode')
+  .option('--no-path-check', 'skips checking path expressions')
+  .option('--no-arn-check', 'skips the arn check for Resource values')
   .parse(process.argv);
 
 let definition;
@@ -31,7 +33,11 @@ try {
   process.exit(2);
 }
 try {
-  const result = validator(definition);
+  const validationOpts: ValidationOptions = {
+    checkArn: !program.noArnCheck,
+    checkPaths: !program.noPathCheck
+  }
+  const result = validator(definition, validationOpts);
   if (result.isValid) {
     if (!program.silent) {
       console.log('✓ State machine definition is valid');
@@ -48,4 +54,4 @@ try {
     console.error('Validator exception:', e);
   }
   process.exit(2);
-}
+}
\ No newline at end of file
diff --git a/src/checks/duplicate-payload-template-fields.ts b/src/checks/duplicate-payload-template-fields.ts
index cf58d19..4397ffb 100644
--- a/src/checks/duplicate-payload-template-fields.ts
+++ b/src/checks/duplicate-payload-template-fields.ts
@@ -1,10 +1,10 @@
 import {JSONPath} from 'jsonpath-plus';
-import {StateMachine, StateMachineError, StateMachineErrorCode} from '../types';
+import {AslChecker, StateMachineError, StateMachineErrorCode} from '../types';
 
 // From the ASL spec:
 // > A JSON object MUST NOT have duplicate field names after fields
 // > ending with the characters ".$" are renamed to strip the ".$" suffix.
-export const mustNotHaveDuplicateFieldNamesAfterEvaluation = (definition: StateMachine): StateMachineError[] => {
+export const mustNotHaveDuplicateFieldNamesAfterEvaluation: AslChecker = (definition) => {
     // find each `Parameters` or `ResultSelector` field
     // for each one, examine each node's children for field names
     // that will be in conflict after evaluation.
@@ -38,4 +38,4 @@ export const mustNotHaveDuplicateFieldNamesAfterEvaluation = (definition: StateM
             });
         });
     return errorMessages;
-}
+}
\ No newline at end of file
diff --git a/src/checks/duplicate-state-names-errors.ts b/src/checks/duplicate-state-names-errors.ts
index 09e6408..0fdea14 100644
--- a/src/checks/duplicate-state-names-errors.ts
+++ b/src/checks/duplicate-state-names-errors.ts
@@ -1,24 +1,24 @@
-import { JSONPath } from 'jsonpath-plus';
-import { StateMachine, StateMachineError, StateMachineErrorCode, States } from '../types';
+import {JSONPath} from 'jsonpath-plus';
+import {AslChecker, StateMachineError, StateMachineErrorCode, States} from '../types';
 
-export default function duplicateStateNames(definition: StateMachine): StateMachineError[] {
-  const errorMessages: StateMachineError[] = [];
-  const names: Record<string, number> = {};
-  JSONPath<States[]>({ json: definition, path: '$..[\'States\']' })
-    .forEach((states) => {
-      Object.keys(states).forEach((stateName) => {
-        const current = names[stateName];
-        names[stateName] = current ? current + 1 : 1;
-      });
-    });
-  for (const [key, value] of Object.entries(names)) {
-    if (value > 1) {
-      errorMessages.push({
-        'Error code': StateMachineErrorCode.DuplicateStateNames,
-        Message: `A state with this name already exists: ${key}`,
-      });
+export const duplicateStateNames: AslChecker = (definition) => {
+    const errorMessages: StateMachineError[] = [];
+    const names: Record<string, number> = {};
+    JSONPath<States[]>({json: definition, path: '$..[\'States\']'})
+        .forEach((states) => {
+            Object.keys(states).forEach((stateName) => {
+                const current = names[stateName];
+                names[stateName] = current ? current + 1 : 1;
+            });
+        });
+    for (const [key, value] of Object.entries(names)) {
+        if (value > 1) {
+            errorMessages.push({
+                'Error code': StateMachineErrorCode.DuplicateStateNames,
+                Message: `A state with this name already exists: ${key}`,
+            });
+        }
     }
-  }
 
-  return errorMessages;
-}
+    return errorMessages;
+}
\ No newline at end of file
diff --git a/src/checks/json-schema-errors.ts b/src/checks/json-schema-errors.ts
index 3760fb4..333a03d 100644
--- a/src/checks/json-schema-errors.ts
+++ b/src/checks/json-schema-errors.ts
@@ -11,11 +11,11 @@ import task from '../schemas/task.json';
 import wait from '../schemas/wait.json';
 import map from '../schemas/map.json';
 import errors from '../schemas/errors.json';
-import {StateMachine, StateMachineError, StateMachineErrorCode} from '../types';
+import {AslChecker, StateMachineErrorCode} from '../types';
 import {registerAll} from "asl-path-validator";
 import {isArnFormatValid} from "./formats";
 
-export default function jsonSchemaErrors(definition: StateMachine): StateMachineError[] {
+export const jsonSchemaErrors: AslChecker = (definition, options) => {
     const ajv = new Ajv({
         schemas: [
             paths,
@@ -33,8 +33,18 @@ export default function jsonSchemaErrors(definition: StateMachine): StateMachine
         ],
         allowUnionTypes: true
     });
-    registerAll(ajv);
-    ajv.addFormat("asl_arn", isArnFormatValid)
+    if (options.checkPaths) {
+        registerAll(ajv);
+    } else {
+        ajv.addFormat("asl_path", () => true);
+        ajv.addFormat("asl_ref_path", () => true);
+        ajv.addFormat("asl_payload_template", () => true);
+    }
+    if (options.checkArn) {
+        ajv.addFormat("asl_arn", isArnFormatValid)
+    } else {
+        ajv.addFormat("asl_arn", () => true);
+    }
     ajv.validate('http://asl-validator.cloud/state-machine.json#', definition);
 
     // the use of oneOf can generate a lot of errors since it'll test
@@ -44,8 +54,8 @@ export default function jsonSchemaErrors(definition: StateMachine): StateMachine
     // these for us in their errors. The challenge is which to show when there
     // are multiple.
     //
-    // for example, given the simplest example with a one step definition with only
-    // a single Pass state. Introducing a typo for the OutputPath expression generates
+    // for example, given the simplest example with a one-step definition with only
+    // a Pass state. Introducing a typo for the OutputPath expression generates
     // 9 errors from AJV.
     //
     if (!ajv.errors) {
@@ -67,7 +77,7 @@ export default function jsonSchemaErrors(definition: StateMachine): StateMachine
         deepest = Math.max(deepest, depth);
     });
 
-    // if there is a oneOf keyword error, then remove all of the
+    // if there is a oneOf keyword error, then remove the
     // other non-format related errors before proceeding
     const instancePathsWithOneOfKeyword = new Set<string>();
     selectedErrors
@@ -86,4 +96,4 @@ export default function jsonSchemaErrors(definition: StateMachine): StateMachine
                 schemaPath: error.schemaPath
             }
         }));
-}
+}
\ No newline at end of file
diff --git a/src/checks/missing-terminal-state-errors.ts b/src/checks/missing-terminal-state-errors.ts
index 7568359..858ddf4 100644
--- a/src/checks/missing-terminal-state-errors.ts
+++ b/src/checks/missing-terminal-state-errors.ts
@@ -1,39 +1,39 @@
-import { JSONPath } from 'jsonpath-plus';
-import { StateMachine, StateMachineError, StateMachineErrorCode, States } from '../types';
+import {JSONPath} from 'jsonpath-plus';
+import {AslChecker, StateMachineError, StateMachineErrorCode, States} from '../types';
 
-export default function missingTerminalStateErrors(definition: StateMachine): StateMachineError[] {
-  const errorMessages: StateMachineError[] = [];
-  // find each enclosed state machine and verify that
-  // each state machine contains at least one of the following:
-  // - state with End: true
-  // - state with Type: Succeed
-  // - state with Type: Fail
-  const terminals: Record<string, number> = {};
-  let fsmId = 1;
-  JSONPath<States[]>({ json: definition, path: '$..[\'States\']' })
-    .forEach((states) => {
-      const fsmKey = `fsm${fsmId}`;
-      // initialize the nested fsm to have a terminal count of zero
-      terminals[fsmKey] = 0;
-      // check each of its states to see if the fsm terminates
-      Object.keys(states).forEach((stateName) => {
-        const state = states[stateName];
-        const count = terminals[fsmKey];
-        if (['Succeed', 'Fail'].indexOf(state.Type as string) !== -1 || state.End) {
-          terminals[fsmKey] = count ? count + 1 : 1;
+export const missingTerminalStateErrors: AslChecker = (definition) => {
+    const errorMessages: StateMachineError[] = [];
+    // find each enclosed state machine and verify that
+    // each state machine contains at least one of the following:
+    // - state with End: true
+    // - state with Type: Succeed
+    // - state with Type: Fail
+    const terminals: Record<string, number> = {};
+    let fsmId = 1;
+    JSONPath<States[]>({json: definition, path: '$..[\'States\']'})
+        .forEach((states) => {
+            const fsmKey = `fsm${fsmId}`;
+            // initialize the nested fsm to have a terminal count of zero
+            terminals[fsmKey] = 0;
+            // check each of its states to see if the fsm terminates
+            Object.keys(states).forEach((stateName) => {
+                const state = states[stateName];
+                const count = terminals[fsmKey];
+                if (['Succeed', 'Fail'].indexOf(state.Type as string) !== -1 || state.End) {
+                    terminals[fsmKey] = count ? count + 1 : 1;
+                }
+            });
+            fsmId += 1;
+        });
+    for (const [key, value] of Object.entries(terminals)) {
+        if (value === 0) {
+            errorMessages.push({
+                'Error code': StateMachineErrorCode.MissingTerminalState,
+                // better to have a line number here
+                Message: `State machine ${key} is missing a terminal state`,
+            });
         }
-      });
-      fsmId += 1;
-    });
-  for (const [key, value] of Object.entries(terminals)) {
-    if (value === 0) {
-      errorMessages.push({
-        'Error code': StateMachineErrorCode.MissingTerminalState,
-        // better to have a line number here
-        Message: `State machine ${key} is missing a terminal state`,
-      });
     }
-  }
 
-  return errorMessages;
-}
+    return errorMessages;
+}
\ No newline at end of file
diff --git a/src/checks/missing-transition-target-errors.ts b/src/checks/missing-transition-target-errors.ts
index 7b72a2b..8f2692d 100644
--- a/src/checks/missing-transition-target-errors.ts
+++ b/src/checks/missing-transition-target-errors.ts
@@ -1,31 +1,31 @@
-import { JSONPath } from 'jsonpath-plus';
-import { StateMachine, StateMachineError, StateMachineErrorCode, States } from '../types';
+import {JSONPath} from 'jsonpath-plus';
+import {AslChecker, StateMachineErrorCode, States} from '../types';
 
-export default function missingTransitionTargetErrors(definition: StateMachine): StateMachineError[] {
-  // retrieve all states
-  let machineStates: string[] = [];
-  JSONPath<States[]>({ json: definition, path: '$..States' })
-    .forEach((s) => {
-      machineStates = machineStates.concat(Object.keys(s));
-    });
+export const missingTransitionTargetErrors: AslChecker = (definition) => {
+    // retrieve all states
+    let machineStates: string[] = [];
+    JSONPath<States[]>({json: definition, path: '$..States'})
+        .forEach((s) => {
+            machineStates = machineStates.concat(Object.keys(s));
+        });
 
-  // retrieve all reachable states
-  const reachableStates = JSONPath<string[]>({ json: definition, path: '$..[StartAt,Next,Default]' })
-    .filter((path, pos, array) => array.indexOf(path) === pos);
+    // retrieve all reachable states
+    const reachableStates = JSONPath<string[]>({json: definition, path: '$..[StartAt,Next,Default]'})
+        .filter((path, pos, array) => array.indexOf(path) === pos);
 
-  // check if all states are reachable
-  const unreachable = machineStates.filter((state) => reachableStates.indexOf(state) === -1)
-    .map((state) => ({
-      'Error code': StateMachineErrorCode.MissingTransitionTarget,
-      Message: `State ${state} is not reachable`,
-    }));
+    // check if all states are reachable
+    const unreachable = machineStates.filter((state) => reachableStates.indexOf(state) === -1)
+        .map((state) => ({
+            'Error code': StateMachineErrorCode.MissingTransitionTarget,
+            Message: `State ${state} is not reachable`,
+        }));
 
-  // check if all 'Next', 'StartAt' and 'Default' states exist
-  const inexistant = reachableStates.filter((state) => machineStates.indexOf(state) === -1)
-    .map((state) => ({
-      'Error code': StateMachineErrorCode.MissingTransitionTarget,
-      Message: `Missing 'StartAt'|'Next'|'Default' target: ${state}`,
-    }));
+    // check if all 'Next', 'StartAt' and 'Default' states exist
+    const inexistant = reachableStates.filter((state) => machineStates.indexOf(state) === -1)
+        .map((state) => ({
+            'Error code': StateMachineErrorCode.MissingTransitionTarget,
+            Message: `Missing 'StartAt'|'Next'|'Default' target: ${state}`,
+        }));
 
-  return unreachable.concat(inexistant);
-}
+    return unreachable.concat(inexistant);
+}
\ No newline at end of file
diff --git a/src/checks/state-transitions-errors.ts b/src/checks/state-transitions-errors.ts
index f24a171..5ef47c4 100644
--- a/src/checks/state-transitions-errors.ts
+++ b/src/checks/state-transitions-errors.ts
@@ -1,7 +1,7 @@
 import { JSONPath } from 'jsonpath-plus';
-import { StateMachine, StateMachineError, StateMachineErrorCode, States } from '../types';
+import {AslChecker, StateMachine, StateMachineError, StateMachineErrorCode, States} from '../types';
 
-export default function stateTransitionsErrors(definition: StateMachine): StateMachineError[] {
+export const stateTransitionsErrors : AslChecker = (definition) => {
   const errorMessages: StateMachineError[] = [];
 
   // given a nested state machine, this function will examine
@@ -70,4 +70,4 @@ export default function stateTransitionsErrors(definition: StateMachine): StateM
     });
 
   return errorMessages;
-}
+}
\ No newline at end of file
diff --git a/src/schemas/paths.json b/src/schemas/paths.json
index 53922f5..04e276b 100644
--- a/src/schemas/paths.json
+++ b/src/schemas/paths.json
@@ -10,48 +10,67 @@
       "type": "string",
       "format": "asl_ref_path"
     },
+    "_payload_template_object": {
+      "type": "object",
+      "patternProperties": {
+        "^.+\\.\\$$": {
+          "$comment": "matches fields ending in .$",
+          "type": "string",
+          "nullable": true,
+          "format": "asl_payload_template"
+        },
+        "^.+(([^.][^$])|([^.][$]))$": {
+          "$comment": "matches fields NOT ending in .$",
+          "oneOf": [
+            {
+              "type": [
+                "number",
+                "boolean",
+                "string",
+                "null"
+              ]
+            },
+            {
+              "type": "array",
+              "items": {
+                "$ref": "#/definitions/asl_payload_template"
+              }
+            },
+            {
+              "$ref": "#/definitions/_asl_payload_template"
+            }
+          ]
+        }
+      }
+    },
     "asl_payload_template": {
       "oneOf": [
         {
-          "type": "object",
-          "patternProperties": {
-            "^.+\\.\\$$": {
-              "$comment": "matches fields ending in .$",
-              "type": "string",
-              "nullable": true,
-              "format": "asl_payload_template"
-            },
-            "^.+(([^.][^$])|([^.][$]))$": {
-              "$comment": "matches fields NOT ending in .$",
-              "oneOf": [
-                {
-                  "type": [
-                    "number",
-                    "boolean",
-                    "string",
-                    "null"
-                  ]
-                },
-                {
-                  "type": "array",
-                  "items": {
-                    "$ref": "#/definitions/asl_payload_template"
-                  }
-                },
-                {
-                  "$ref": "#/definitions/asl_payload_template"
-                }
-              ]
-            }
-          }
+          "$ref": "#/definitions/_payload_template_object"
         },
         {
           "type": "array",
           "items": {
             "$ref": "#/definitions/asl_payload_template"
           }
+        },
+        {
+          "type": ["string", "boolean", "number"]
+        }
+      ]
+    },
+    "_asl_payload_template": {
+      "oneOf": [
+        {
+          "$ref": "#/definitions/_payload_template_object"
+        },
+        {
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/_asl_payload_template"
+          }
         }
       ]
     }
   }
-}
\ No newline at end of file
+}
diff --git a/src/types.ts b/src/types.ts
index 3a3fccd..f2d61e8 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -21,3 +21,10 @@ export type StateMachineError = {
     schemaPath: string;
   }
 };
+
+export interface ValidationOptions {
+  readonly checkPaths: boolean;
+  readonly checkArn: boolean;
+}
+
+export type AslChecker = (definition: StateMachine, options: ValidationOptions) => StateMachineError[];
\ No newline at end of file
diff --git a/src/validator.ts b/src/validator.ts
index 267393e..b174284 100644
--- a/src/validator.ts
+++ b/src/validator.ts
@@ -1,33 +1,38 @@
 import {ErrorObject} from 'ajv';
 
-import jsonSchemaErrors from './checks/json-schema-errors';
-import missingTransitionTargetErrors from  './checks/missing-transition-target-errors';
-import stateTransitionsErrors from  './checks/state-transitions-errors';
-import duplicateStateNamesErrors from './checks/duplicate-state-names-errors';
-import missingTerminalStateErrors from './checks/missing-terminal-state-errors';
-import { StateMachine, StateMachineError } from './types';
+import {jsonSchemaErrors} from './checks/json-schema-errors';
+import {missingTransitionTargetErrors} from './checks/missing-transition-target-errors';
+import {stateTransitionsErrors} from './checks/state-transitions-errors';
+import {duplicateStateNames} from './checks/duplicate-state-names-errors';
+import {missingTerminalStateErrors} from './checks/missing-terminal-state-errors';
+import {StateMachine, StateMachineError, ValidationOptions} from './types';
 import {mustNotHaveDuplicateFieldNamesAfterEvaluation} from "./checks/duplicate-payload-template-fields";
 
-export default function validator(definition: StateMachine): {
-  isValid: boolean;
-  errors: (ErrorObject | StateMachineError)[];
-  errorsText: (separator?: string) => string;
-} {
+const DefaultOptions: ValidationOptions = {
+    checkPaths: true,
+    checkArn: true,
+}
 
-  const errors = jsonSchemaErrors(definition);
-  if (errors.length === 0) {
-    errors.push(...missingTransitionTargetErrors(definition));
-    errors.push(...stateTransitionsErrors(definition));
-    errors.push(...duplicateStateNamesErrors(definition));
-    errors.push(...missingTerminalStateErrors(definition));
-    errors.push(...mustNotHaveDuplicateFieldNamesAfterEvaluation(definition))
-  }
+export default function validator(definition: StateMachine, opts?: ValidationOptions): {
+    isValid: boolean;
+    errors: (ErrorObject | StateMachineError)[];
+    errorsText: (separator?: string) => string;
+} {
+    const options = opts ?? DefaultOptions;
+    const errors = jsonSchemaErrors(definition, options);
+    if (errors.length === 0) {
+        errors.push(...missingTransitionTargetErrors(definition, options));
+        errors.push(...stateTransitionsErrors(definition, options));
+        errors.push(...duplicateStateNames(definition, options));
+        errors.push(...missingTerminalStateErrors(definition, options));
+        errors.push(...mustNotHaveDuplicateFieldNamesAfterEvaluation(definition, options))
+    }
 
-  return {
-    isValid: errors.length === 0,
-    errors,
-    errorsText: (separator = '\n') => errors
-      .map(error => `${error['Error code']}: ${error.Message}`)
-      .join(separator),
-  };
-}
+    return {
+        isValid: errors.length === 0,
+        errors,
+        errorsText: (separator = '\n') => errors
+            .map(error => `${error['Error code']}: ${error.Message}`)
+            .join(separator),
+    };
+}
\ No newline at end of file


Test patch:
diff --git a/src/__tests__/definitions/valid-pass-array.json b/src/__tests__/definitions/valid-pass-array.json
new file mode 100644
index 0000000..2ff3a09
--- /dev/null
+++ b/src/__tests__/definitions/valid-pass-array.json
@@ -0,0 +1,11 @@
+{
+  "StartAt": "EmptyState",
+  "States": {
+    "EmptyState": {
+      "Type": "Pass",
+      "Parameters": ["abc"],
+      "ResultPath": "$.emptyState",
+      "End": true
+    }
+  }
+}
diff --git a/src/__tests__/error-reporting.test.ts b/src/__tests__/error-reporting.test.ts
index ae4f18c..76a6cb6 100644
--- a/src/__tests__/error-reporting.test.ts
+++ b/src/__tests__/error-reporting.test.ts
@@ -44,7 +44,7 @@ describe("tests with definitions containing errors to see what's reported", () =
                     schemaError: {
                         instancePath: "/States/Hello, World/Parameters/lorem.$",
                         // the regular expression in the path is escaped by AJV when it reports the location of the error
-                        schemaPath: "#/oneOf/0/patternProperties/%5E.%2B%5C.%5C%24%24/format"
+                        schemaPath: "#/patternProperties/%5E.%2B%5C.%5C%24%24/format"
                     }
                 }
             ]
@@ -61,4 +61,4 @@ describe("tests with definitions containing errors to see what's reported", () =
         expect(errors).toStrictEqual(input.expected_errors)
     });
 
-});
\ No newline at end of file
+});
diff --git a/src/__tests__/options.test.ts b/src/__tests__/options.test.ts
new file mode 100644
index 0000000..f7b5daa
--- /dev/null
+++ b/src/__tests__/options.test.ts
@@ -0,0 +1,59 @@
+import fs from "fs";
+import path from "path";
+import {StateMachine, ValidationOptions} from "../types";
+import validator from "../validator";
+
+describe("show how the options impact validation", () => {
+
+    const loadDef = (file: string): StateMachine => {
+        return JSON.parse(fs.readFileSync(path.join(__dirname, 'definitions', file), "utf-8")) as StateMachine;
+    }
+
+    const expectValid = (file: string, options: ValidationOptions): void => {
+        const definition = loadDef(file);
+        const {isValid, errors} = validator(definition, options);
+        expect(errors ?? []).toStrictEqual([]);
+        expect(isValid).toBe(true);
+    }
+
+    const expectInvalid = (file: string, options: ValidationOptions): void => {
+        const definition = loadDef(file);
+        const {isValid} = validator(definition, options);
+        expect(isValid).toBe(false);
+    }
+
+    describe("checkPaths", () => {
+        const options: ValidationOptions = {
+            checkPaths: false,
+            checkArn: true
+        }
+        it.each(
+            [
+                "invalid-json-path.json",
+                "invalid-payload-template.asl.json"
+            ]
+        )("%s should not report path error", (file) => {
+            expect.hasAssertions();
+            expectValid(file, options);
+        });
+        it("should still report other errors if path expressions are disabled", () => {
+            expect.hasAssertions();
+            expectInvalid("invalid-state-name-too-long.json", options);
+        });
+    });
+
+    describe("checkArn", () => {
+        const options: ValidationOptions = {
+            checkPaths: true,
+            checkArn: false
+        }
+        it("should ignore task arn errors", () => {
+            expect.hasAssertions();
+            expectValid("invalid-cfn-definition-substitutions.json", options);
+        });
+        it("should still report other errors if task arn checks are disabled", () => {
+            expect.hasAssertions();
+            expectInvalid("invalid-state-name-too-long.json", options);
+        });
+    })
+});
\ No newline at end of file