statelint 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/data/StateMachine.j2119 +57 -6
- data/lib/statelint/state_node.rb +61 -7
- data/statelint.gemspec +1 -1
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 0f7cf7b9cd3f0f19021f4bb2fb8657b1f282f5dd014914b0ecee706a1f89abdd
         | 
| 4 | 
            +
              data.tar.gz: 11cd1013ed9799022e84986f740d53cc04ebb64dd26555f7131922fb8c862f4d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: cae59e2cd4ac26483138e8f1ae50c74cb09f93f5bb76dab010db0748ae0bde3d86e19679e081ba8d3ae8a2193d9428f755b1882a928d45550ea66201e793978a
         | 
| 7 | 
            +
              data.tar.gz: b325d6cafdbc3ce69ebcfca460a2d8c8eaad5bef6f5fcaad36b90cf49ec79f5381e02d9280ccd4b982b3451c4bf9a639472abeb87c30127cc43a5d38f661e1fe
         | 
    
        data/data/StateMachine.j2119
    CHANGED
    
    | @@ -20,9 +20,10 @@ A State whose "End" field's value is true is a "Terminal State". | |
| 20 20 | 
             
            Each of a Succeed State and a Fail State is a "Terminal State".
         | 
| 21 21 | 
             
            A State which is not a Terminal State or a Choice State MUST have a string field named "Next".
         | 
| 22 22 | 
             
            A Terminal State MUST NOT have a field named "Next".
         | 
| 23 | 
            -
            A State MAY have a  | 
| 23 | 
            +
            A State MAY have a field named "InputPath".
         | 
| 24 24 | 
             
            Each of a Pass State, a Task State, a Parallel State, and a Map State MAY have a nullable-referencePath field named "ResultPath".
         | 
| 25 | 
            -
             | 
| 25 | 
            +
            Each of a Task State, a Parallel State, and a Map State MAY have a field named "ResultSelector".
         | 
| 26 | 
            +
            A State MAY have a field named "OutputPath".
         | 
| 26 27 | 
             
            A Pass State MAY have a field named "Result".
         | 
| 27 28 | 
             
            A Fail State MUST NOT have a field named "InputPath".
         | 
| 28 29 | 
             
            A Fail State MUST NOT have a field named "OutputPath".
         | 
| @@ -32,6 +33,10 @@ Each of a Task State, a Parallel State, and a Map State MAY have an object-array | |
| 32 33 | 
             
            A Task State MUST have a URI field named "Resource".
         | 
| 33 34 | 
             
            A Task State MAY have a positive-integer field named "TimeoutSeconds" whose value MUST be less than 99999999.
         | 
| 34 35 | 
             
            A Task State MAY have a positive-integer field named "HeartbeatSeconds" whose value MUST be less than 99999999.
         | 
| 36 | 
            +
            A Task State MAY have a referencePath field named "TimeoutSecondsPath".
         | 
| 37 | 
            +
            A Task State MAY have a referencePath field named "HeartbeatSecondsPath".
         | 
| 38 | 
            +
            A Task State MAY have only one of "TimeoutSeconds" and "TimeoutSecondsPath".
         | 
| 39 | 
            +
            A Task State MAY have only one of "HeartbeatSeconds" and "HeartbeatSecondsPath".
         | 
| 35 40 | 
             
            A Retrier MUST have a nonempty-string-array field named "ErrorEquals".
         | 
| 36 41 | 
             
            A Retrier MAY have an positive-integer field named "IntervalSeconds".
         | 
| 37 42 | 
             
            A Retrier MAY have a nonnegative-integer field named "MaxAttempts" whose value MUST be less than 99999999.
         | 
| @@ -51,9 +56,9 @@ A Choice Rule MUST have a string field named "Next". | |
| 51 56 | 
             
            A Choice Rule with an "And" field is a "Boolean".
         | 
| 52 57 | 
             
            A Choice Rule with an "Or" field is a "Boolean".
         | 
| 53 58 | 
             
            A Choice Rule with a "Not" field is a "Boolean".
         | 
| 54 | 
            -
            A Choice Rule MAY have a  | 
| 59 | 
            +
            A Choice Rule MAY have a field named "Variable".
         | 
| 55 60 | 
             
            A Choice Rule with a "Variable" field is a "Comparison".
         | 
| 56 | 
            -
            A Comparison MUST have a field named one of "StringEquals", "StringLessThan", "StringGreaterThan", "StringLessThanEquals", "StringGreaterThanEquals", "NumericEquals", "NumericLessThan", "NumericGreaterThan", "NumericLessThanEquals", "NumericGreaterThanEquals", "BooleanEquals", "TimestampEquals", "TimestampLessThan", "TimestampGreaterThan", "TimestampLessThanEquals", or " | 
| 61 | 
            +
            A Comparison MUST have a field named one of "StringEquals", "StringLessThan", "StringGreaterThan", "StringLessThanEquals", "StringGreaterThanEquals", "NumericEquals", "NumericLessThan", "NumericGreaterThan", "NumericLessThanEquals", "NumericGreaterThanEquals", "BooleanEquals", "TimestampEquals", "TimestampLessThan", "TimestampGreaterThan", "TimestampLessThanEquals", "TimestampGreaterThanEquals", "StringEqualsPath", "StringLessThanPath", "StringGreaterThanPath", "StringLessThanEqualsPath", "StringGreaterThanEqualsPath", "NumericEqualsPath", "NumericLessThanPath", "NumericGreaterThanPath", "NumericLessThanEqualsPath", "NumericGreaterThanEqualsPath", "BooleanEqualsPath", "TimestampEqualsPath", "TimestampLessThanPath", "TimestampGreaterThanPath", "TimestampLessThanEqualsPath", "TimestampGreaterThanEqualsPath", "IsNull", "IsPresent", "IsNumeric", "IsString", "IsBoolean", "IsTimestamp", or "StringMatches".
         | 
| 57 62 | 
             
            A Comparison MAY have a string field named "StringEquals".
         | 
| 58 63 | 
             
            A Comparison MAY have a string field named "StringLessThan".
         | 
| 59 64 | 
             
            A Comparison MAY have a string field named "StringGreaterThan".
         | 
| @@ -70,6 +75,29 @@ A Comparison MAY have a timestamp field named "TimestampLessThan". | |
| 70 75 | 
             
            A Comparison MAY have a timestamp field named "TimestampGreaterThan".
         | 
| 71 76 | 
             
            A Comparison MAY have a timestamp field named "TimestampLessThanEquals".
         | 
| 72 77 | 
             
            A Comparison MAY have a timestamp field named "TimestampGreaterThanEquals".
         | 
| 78 | 
            +
            A Comparison MAY have a boolean field named "IsNull".
         | 
| 79 | 
            +
            A Comparison MAY have a boolean field named "IsPresent".
         | 
| 80 | 
            +
            A Comparison MAY have a boolean field named "IsNumeric".
         | 
| 81 | 
            +
            A Comparison MAY have a boolean field named "IsString".
         | 
| 82 | 
            +
            A Comparison MAY have a boolean field named "IsBoolean".
         | 
| 83 | 
            +
            A Comparison MAY have a boolean field named "IsTimestamp".
         | 
| 84 | 
            +
            A Comparison MAY have a string field named "StringMatches".
         | 
| 85 | 
            +
            A Comparison MAY have a referencePath field named "StringEqualsPath".
         | 
| 86 | 
            +
            A Comparison MAY have a referencePath field named "StringLessThanPath".
         | 
| 87 | 
            +
            A Comparison MAY have a referencePath field named "StringGreaterThanPath".
         | 
| 88 | 
            +
            A Comparison MAY have a referencePath field named "StringLessThanEqualsPath".
         | 
| 89 | 
            +
            A Comparison MAY have a referencePath field named "StringGreaterThanEqualsPath".
         | 
| 90 | 
            +
            A Comparison MAY have a referencePath field named "NumericEqualsPath".
         | 
| 91 | 
            +
            A Comparison MAY have a referencePath field named "NumericLessThanPath".
         | 
| 92 | 
            +
            A Comparison MAY have a referencePath field named "NumericGreaterThanPath".
         | 
| 93 | 
            +
            A Comparison MAY have a referencePath field named "NumericLessThanEqualsPath".
         | 
| 94 | 
            +
            A Comparison MAY have a referencePath field named "NumericGreaterThanEqualsPath".
         | 
| 95 | 
            +
            A Comparison MAY have a referencePath field named "BooleanEqualsPath".
         | 
| 96 | 
            +
            A Comparison MAY have a referencePath field named "TimestampEqualsPath".
         | 
| 97 | 
            +
            A Comparison MAY have a referencePath field named "TimestampLessThanPath".
         | 
| 98 | 
            +
            A Comparison MAY have a referencePath field named "TimestampGreaterThanPath".
         | 
| 99 | 
            +
            A Comparison MAY have a referencePath field named "TimestampLessThanEqualsPath".
         | 
| 100 | 
            +
            A Comparison MAY have a referencePath field named "TimestampGreaterThanEqualsPath".
         | 
| 73 101 | 
             
            A Comparison MUST NOT have a field named "And".
         | 
| 74 102 | 
             
            A Comparison MUST NOT have a field named "Or".
         | 
| 75 103 | 
             
            A Comparison MUST NOT have a field named "Not".
         | 
| @@ -80,7 +108,7 @@ A Nested Rule with an "And" field is a "Nested Boolean". | |
| 80 108 | 
             
            A Nested Rule with an "Or" field is a "Nested Boolean".
         | 
| 81 109 | 
             
            A Nested Rule with a "Not" field is a "Nested Boolean".
         | 
| 82 110 | 
             
            A Nested Rule MUST NOT have a field named "Next".
         | 
| 83 | 
            -
            A Nested Rule MAY have a  | 
| 111 | 
            +
            A Nested Rule MAY have a field named "Variable".
         | 
| 84 112 | 
             
            A Nested Rule with a "Variable" field is a "Nested Comparison".
         | 
| 85 113 | 
             
            A Nested Comparison MAY have a string field named "StringEquals".
         | 
| 86 114 | 
             
            A Nested Comparison MAY have a string field named "StringLessThan".
         | 
| @@ -98,6 +126,29 @@ A Nested Comparison MAY have a timestamp field named "TimestampLessThan". | |
| 98 126 | 
             
            A Nested Comparison MAY have a timestamp field named "TimestampGreaterThan".
         | 
| 99 127 | 
             
            A Nested Comparison MAY have a timestamp field named "TimestampLessThanEquals".
         | 
| 100 128 | 
             
            A Nested Comparison MAY have a timestamp field named "TimestampGreaterThanEquals".
         | 
| 129 | 
            +
            A Nested Comparison MAY have a boolean field named "IsNull".
         | 
| 130 | 
            +
            A Nested Comparison MAY have a boolean field named "IsPresent".
         | 
| 131 | 
            +
            A Nested Comparison MAY have a boolean field named "IsNumeric".
         | 
| 132 | 
            +
            A Nested Comparison MAY have a boolean field named "IsString".
         | 
| 133 | 
            +
            A Nested Comparison MAY have a boolean field named "IsBoolean".
         | 
| 134 | 
            +
            A Nested Comparison MAY have a boolean field named "IsTimestamp".
         | 
| 135 | 
            +
            A Nested Comparison MAY have a string field named "StringMatches".
         | 
| 136 | 
            +
            A Nested Comparison MAY have a referencePath field named "StringEqualsPath".
         | 
| 137 | 
            +
            A Nested Comparison MAY have a referencePath field named "StringLessThanPath".
         | 
| 138 | 
            +
            A Nested Comparison MAY have a referencePath field named "StringGreaterThanPath".
         | 
| 139 | 
            +
            A Nested Comparison MAY have a referencePath field named "StringLessThanEqualsPath".
         | 
| 140 | 
            +
            A Nested Comparison MAY have a referencePath field named "StringGreaterThanEqualsPath".
         | 
| 141 | 
            +
            A Nested Comparison MAY have a referencePath field named "NumericEqualsPath".
         | 
| 142 | 
            +
            A Nested Comparison MAY have a referencePath field named "NumericLessThanPath".
         | 
| 143 | 
            +
            A Nested Comparison MAY have a referencePath field named "NumericGreaterThanPath".
         | 
| 144 | 
            +
            A Nested Comparison MAY have a referencePath field named "NumericLessThanEqualsPath".
         | 
| 145 | 
            +
            A Nested Comparison MAY have a referencePath field named "NumericGreaterThanEqualsPath".
         | 
| 146 | 
            +
            A Nested Comparison MAY have a referencePath field named "BooleanEqualsPath".
         | 
| 147 | 
            +
            A Nested Comparison MAY have a referencePath field named "TimestampEqualsPath".
         | 
| 148 | 
            +
            A Nested Comparison MAY have a referencePath field named "TimestampLessThanPath".
         | 
| 149 | 
            +
            A Nested Comparison MAY have a referencePath field named "TimestampGreaterThanPath".
         | 
| 150 | 
            +
            A Nested Comparison MAY have a referencePath field named "TimestampLessThanEqualsPath".
         | 
| 151 | 
            +
            A Nested Comparison MAY have a referencePath field named "TimestampGreaterThanEqualsPath".
         | 
| 101 152 | 
             
            A Nested Comparison MUST NOT have a field named "And".
         | 
| 102 153 | 
             
            A Nested Comparison MUST NOT have a field named "Or".
         | 
| 103 154 | 
             
            A Nested Comparison MUST NOT have a field named "Not".
         | 
| @@ -109,7 +160,7 @@ A Wait State MUST have only one of "Seconds", "SecondsPath", "Timestamp", and "T | |
| 109 160 | 
             
            A Wait State MUST have a field named one of "Seconds", "SecondsPath", "Timestamp", or "TimestampPath".
         | 
| 110 161 | 
             
            A Parallel State MUST have an object-array field named "Branches"; each element is a "Branch".
         | 
| 111 162 | 
             
            A Map State MUST have an object field named "Iterator"; its value is a "Branch".
         | 
| 112 | 
            -
            A Map State MAY have a  | 
| 163 | 
            +
            A Map State MAY have a field named "ItemsPath".
         | 
| 113 164 | 
             
            A Map State MAY have a numeric field named "MaxConcurrency".
         | 
| 114 165 | 
             
            A Branch MUST have an object field named "States"; each field is a "State".
         | 
| 115 166 | 
             
            A Branch MUST have a string field named "StartAt".
         | 
    
        data/lib/statelint/state_node.rb
    CHANGED
    
    | @@ -32,6 +32,10 @@ module StateMachineLint | |
| 32 32 | 
             
                  # We keep track of all the state names and complain about
         | 
| 33 33 | 
             
                  #  dupes
         | 
| 34 34 | 
             
                  @all_state_names = {}
         | 
| 35 | 
            +
                  @payload_builder_fields = ["Parameters", "ResultSelector"]
         | 
| 36 | 
            +
                  @context_object_access_fields = [{"field"=> "InputPath", "nullable"=> true}, {"field"=> "OutputPath", "nullable"=> true}, {"field"=>  "ItemsPath", "nullable"=> false}]
         | 
| 37 | 
            +
                  @choice_state_nested_operators = ["And", "Or", "Not"]
         | 
| 38 | 
            +
                  @intrinsic_invocation_regex = /^States\.(JsonToString|Format|StringToJson|Array)\(.+\)$/
         | 
| 35 39 | 
             
                end
         | 
| 36 40 |  | 
| 37 41 | 
             
                def check(node, path, problems)
         | 
| @@ -57,8 +61,17 @@ module StateMachineLint | |
| 57 61 | 
             
                    states = node['States']
         | 
| 58 62 | 
             
                    states.keys.each do |name|
         | 
| 59 63 | 
             
                      child = states[name]
         | 
| 60 | 
            -
                      if child.is_a?(Hash) | 
| 61 | 
            -
                         | 
| 64 | 
            +
                      if child.is_a?(Hash)
         | 
| 65 | 
            +
                        child_path = path + '.' + name
         | 
| 66 | 
            +
                        probe_context_object_access(child, child_path, problems)
         | 
| 67 | 
            +
                        @payload_builder_fields.each do |field_name|
         | 
| 68 | 
            +
                          if child.key?(field_name)
         | 
| 69 | 
            +
                            probe_payload_builder(child[field_name], child_path, problems, field_name)
         | 
| 70 | 
            +
                          end
         | 
| 71 | 
            +
                        end  
         | 
| 72 | 
            +
                        if child.key?("Type") && child["Type"] == "Choice" && child.key?("Choices")
         | 
| 73 | 
            +
                          probe_choice_state(child["Choices"], child_path + '.Choices' , problems)
         | 
| 74 | 
            +
                        end
         | 
| 62 75 | 
             
                      end
         | 
| 63 76 |  | 
| 64 77 | 
             
                      if @all_state_names[name]
         | 
| @@ -121,25 +134,66 @@ module StateMachineLint | |
| 121 134 | 
             
                  end
         | 
| 122 135 | 
             
                end
         | 
| 123 136 |  | 
| 137 | 
            +
                def probe_context_object_access(node, path, problems)
         | 
| 138 | 
            +
                  @context_object_access_fields.each do |field|
         | 
| 139 | 
            +
                    field_name = field["field"]
         | 
| 140 | 
            +
                    nullable = field["nullable"]
         | 
| 141 | 
            +
                    if node.key?(field_name)
         | 
| 142 | 
            +
                      if !nullable && node[field_name].nil?
         | 
| 143 | 
            +
                        problems << "Field \"#{field_name}\" defined at \"#{path}\" should be non-null"
         | 
| 144 | 
            +
                        return
         | 
| 145 | 
            +
                      end
         | 
| 146 | 
            +
                      if !node[field_name].nil? and !is_valid_parameters_path?(node[field_name])
         | 
| 147 | 
            +
                        problems << "Field \"#{field_name}\" defined at \"#{path}\" is not a JSONPath"
         | 
| 148 | 
            +
                      end
         | 
| 149 | 
            +
                    end
         | 
| 150 | 
            +
                  end
         | 
| 151 | 
            +
                end
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                def probe_choice_state(node, path, problems)
         | 
| 154 | 
            +
                  if node.is_a?(Hash)
         | 
| 155 | 
            +
                    if node.key?("Variable") && !is_valid_parameters_path?(node["Variable"])
         | 
| 156 | 
            +
                      problems << "Field \"Variable\" of Choice state at \"#{path}\" is not a JSONPath"
         | 
| 157 | 
            +
                    end
         | 
| 158 | 
            +
                    @choice_state_nested_operators.each do |operator|
         | 
| 159 | 
            +
                      if node.key?(operator)
         | 
| 160 | 
            +
                        probe_choice_state(node[operator], path + '.' + operator, problems)
         | 
| 161 | 
            +
                      end
         | 
| 162 | 
            +
                    end 
         | 
| 163 | 
            +
                  elsif node.is_a?(Array)
         | 
| 164 | 
            +
                    node.size.times {|i| probe_choice_state(node[i], "#{path}[#{i}]", problems) }
         | 
| 165 | 
            +
                  end
         | 
| 166 | 
            +
                end
         | 
| 167 | 
            +
             | 
| 124 168 | 
             
                # Search through Parameters for object nodes and check field semantics
         | 
| 125 | 
            -
                def  | 
| 169 | 
            +
                def probe_payload_builder(node, path, problems, field_name)
         | 
| 126 170 | 
             
                  if node.is_a?(Hash)
         | 
| 127 171 | 
             
                    node.each do |name, val|
         | 
| 128 172 | 
             
                      if name.end_with? '.$'
         | 
| 129 | 
            -
                        if  | 
| 130 | 
            -
                          problems << "Field \"#{name}\" of  | 
| 173 | 
            +
                        if !is_intrinsic_invocation?(val) && !is_valid_parameters_path?(val)
         | 
| 174 | 
            +
                          problems << "Field \"#{name}\" of #{field_name} at \"#{path}\" is not a JSONPath or intrinsic function expression"
         | 
| 131 175 | 
             
                        end
         | 
| 132 176 | 
             
                      else
         | 
| 133 | 
            -
                         | 
| 177 | 
            +
                        probe_payload_builder(val, "#{path}.#{name}", problems, field_name)
         | 
| 134 178 | 
             
                      end
         | 
| 135 179 | 
             
                    end
         | 
| 136 180 | 
             
                  elsif node.is_a?(Array)
         | 
| 137 | 
            -
                    node.size.times {|i|  | 
| 181 | 
            +
                    node.size.times {|i| probe_payload_builder(node[i], "#{path}[#{i}]", problems, field_name) }
         | 
| 138 182 | 
             
                  end
         | 
| 139 183 | 
             
                end
         | 
| 140 184 |  | 
| 185 | 
            +
                def is_intrinsic_invocation?(val)
         | 
| 186 | 
            +
                  if val.is_a?(String) && val.match?(@intrinsic_invocation_regex)
         | 
| 187 | 
            +
                    return true
         | 
| 188 | 
            +
                  end
         | 
| 189 | 
            +
                  return false
         | 
| 190 | 
            +
                end
         | 
| 191 | 
            +
             | 
| 141 192 | 
             
                # Check if a string that ends with ".$" is a valid path
         | 
| 142 193 | 
             
                def is_valid_parameters_path?(val)
         | 
| 194 | 
            +
                  if !val.is_a?(String)
         | 
| 195 | 
            +
                    return false
         | 
| 196 | 
            +
                  end
         | 
| 143 197 | 
             
                  # If the value begins with “$$”, the first dollar character is stripped off and the remainder MUST be a Path.
         | 
| 144 198 | 
             
                  if val.start_with?("$$")
         | 
| 145 199 | 
             
                    path_to_check = val.gsub(/^\$/, "")
         | 
    
        data/statelint.gemspec
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: statelint
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.5.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Tim Bray
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2020- | 
| 11 | 
            +
            date: 2020-08-13 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: j2119
         |