@wmfs/statelint 1.24.0 → 1.26.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.
Files changed (53) hide show
  1. package/.releaserc.json +1 -1
  2. package/CHANGELOG.md +9 -0
  3. package/README.md +1 -1
  4. package/lib/schema/StateMachine.j2119 +84 -14
  5. package/lib/statelint/state_node.js +113 -25
  6. package/package.json +8 -8
  7. package/test/fixtures/backoff-with-invalid-jitter-on-retry.json +17 -0
  8. package/test/fixtures/backoff-with-jitter-on-retry.json +17 -0
  9. package/test/fixtures/choice-rule-with-comment.json +19 -0
  10. package/test/fixtures/choice-with-context-object.json +22 -0
  11. package/test/fixtures/choice-with-resultselector.json +23 -0
  12. package/test/fixtures/fail-with-error-and-cause-path-using-intrinsic-functions.json +10 -0
  13. package/test/fixtures/fail-with-error-and-cause-path.json +10 -0
  14. package/test/fixtures/fail-with-resultselector.json +13 -0
  15. package/test/fixtures/fail-with-static-and-dynamic-cause.json +10 -0
  16. package/test/fixtures/fail-with-static-and-dynamic-error.json +10 -0
  17. package/test/fixtures/invalid-backoff-with-jitter-on-retry.json +17 -0
  18. package/test/fixtures/invalid-function-invocation.json +13 -0
  19. package/test/fixtures/map-with-itemprocessor-and-iterator.json +30 -0
  20. package/test/fixtures/map-with-itemprocessor.json +21 -0
  21. package/test/fixtures/map-with-itemspath-context-object.json +21 -0
  22. package/test/fixtures/map-with-null-itemspath.json +20 -0
  23. package/test/fixtures/map-with-parameters-and-itemselector.json +27 -0
  24. package/test/fixtures/map-with-parameters.json +19 -0
  25. package/test/fixtures/map-with-resultselector.json +24 -0
  26. package/test/fixtures/parallel-with-resultselector.json +25 -0
  27. package/test/fixtures/pass-with-intrinsic-function-inputpath.json +12 -0
  28. package/test/fixtures/pass-with-io-path-context-object.json +13 -0
  29. package/test/fixtures/pass-with-null-inputpath.json +12 -0
  30. package/test/fixtures/pass-with-null-outputpath.json +12 -0
  31. package/test/fixtures/pass-with-resultselector.json +15 -0
  32. package/test/fixtures/states-array-intrinsic-functions.json +19 -0
  33. package/test/fixtures/states-array-invocation-leftpad.json +13 -0
  34. package/test/fixtures/states-array-invocation.json +13 -0
  35. package/test/fixtures/states-encoding-decoding-intrinsic-functions.json +14 -0
  36. package/test/fixtures/states-format-invocation.json +13 -0
  37. package/test/fixtures/states-hash-intrinsic-functions.json +13 -0
  38. package/test/fixtures/states-json-intrinsic-functions.json +15 -0
  39. package/test/fixtures/states-jsontostring-invocation.json +14 -0
  40. package/test/fixtures/states-math-intrinsic-functions.json +14 -0
  41. package/test/fixtures/states-string-intrinsic-functions.json +13 -0
  42. package/test/fixtures/states-stringtojson-invocation.json +13 -0
  43. package/test/fixtures/states-uuid-intrinsic-functions.json +13 -0
  44. package/test/fixtures/succeed-with-comment-in-catcher.json +23 -0
  45. package/test/fixtures/succeed-with-resultselector.json +13 -0
  46. package/test/fixtures/task-with-credentials.json +13 -0
  47. package/test/fixtures/task-with-dynamic-timeouts.json +13 -0
  48. package/test/fixtures/task-with-invalid-credentials.json +11 -0
  49. package/test/fixtures/task-with-resultselector.json +15 -0
  50. package/test/fixtures/task-with-static-and-dynamic-heartbeat.json +13 -0
  51. package/test/fixtures/task-with-static-and-dynamic-timeout.json +13 -0
  52. package/test/fixtures/wait-with-resultselector.json +15 -0
  53. package/test/statelint_test.js +230 -157
@@ -7,43 +7,84 @@ const expect = chai.expect
7
7
  const stateLint = require('../lib')
8
8
 
9
9
  describe('StateMachineLint', () => {
10
- verify(
11
- 'Allow Fail states to omit optional Cause/Error fields',
12
- require('./fixtures/minimal-fail-state.json'),
13
- 0
14
- )
10
+ describe('Fail states', () => {
11
+ verify(
12
+ 'Allow Fail states to omit optional Cause/Error fields',
13
+ require('./fixtures/minimal-fail-state.json')
14
+ )
15
+
16
+ verify(
17
+ 'Allow Fail states to use ErrorPath and CausePath fields',
18
+ require('./fixtures/fail-with-error-and-cause-path.json')
19
+ )
20
+
21
+ verify(
22
+ 'Allow Fail states to use ErrorPath and CausePath fields with intrinsic functions',
23
+ require('./fixtures/fail-with-error-and-cause-path-using-intrinsic-functions.json')
24
+ )
25
+
26
+ verify(
27
+ 'Reject Fail state with both static and dynamic error',
28
+ require('./fixtures/fail-with-static-and-dynamic-error.json'),
29
+ 'may have only one of Error,ErrorPath'
30
+ )
31
+
32
+ verify(
33
+ 'Reject Fail state with both static and dynamic cause',
34
+ require('./fixtures/fail-with-static-and-dynamic-cause.json'),
35
+ 'may have only one of Cause,CausePath'
36
+ )
37
+ })
38
+
39
+ describe('Delay and Jitter', () => {
40
+ verify(
41
+ 'Allow Retry to with MaxDelaySeconds and JitterStrategy',
42
+ require('./fixtures/backoff-with-jitter-on-retry.json')
43
+ )
44
+
45
+ verify(
46
+ 'Reject invalid JitterStrategy',
47
+ require('./fixtures/backoff-with-invalid-jitter-on-retry.json'),
48
+ 'not one of the allowed values FULL,NONE'
49
+ )
50
+
51
+ verify(
52
+ 'Reject invalid MaxDelaySeconds',
53
+ require('./fixtures/invalid-backoff-with-jitter-on-retry.json'),
54
+ 'allowed floor is 0'
55
+ )
56
+ })
15
57
 
16
58
  describe('Empty ErrorEquals clauses', () => {
17
59
  verify(
18
- 'reject empty ErrorEquals on Catch',
60
+ 'Reject empty ErrorEquals on Catch',
19
61
  require('./fixtures/empty-error-equals-on-catch'),
20
- 1,
21
62
  'non-empty required'
22
63
  )
23
64
 
24
65
  verify(
25
- 'reject empty ErrorEquals on Retry',
66
+ 'Reject empty ErrorEquals on Retry',
26
67
  require('./fixtures/empty-error-equals-on-retry'),
27
- 1,
28
68
  'non-empty required'
29
69
  )
30
70
  })
31
71
 
32
- describe('Parameters only valid on Pass, Task, and Parallel', () => {
72
+ describe('Parameters only valid on Pass, Task, Parallel, and Map', () => {
73
+ verify(
74
+ 'Pass with Parameters',
75
+ require('./fixtures/pass-with-parameters')
76
+ )
33
77
  verify(
34
- 'Pass With Parameters',
35
- require('./fixtures/pass-with-parameters'),
36
- 0
78
+ 'Task with Parameters',
79
+ require('./fixtures/task-with-parameters')
37
80
  )
38
81
  verify(
39
- 'Task With Parameters',
40
- require('./fixtures/task-with-parameters'),
41
- 0
82
+ 'Parallel with Parameters',
83
+ require('./fixtures/parallel-with-parameters')
42
84
  )
43
85
  verify(
44
- 'Parallel With Parameters',
45
- require('./fixtures/parallel-with-parameters'),
46
- 0
86
+ 'Map with Parameters',
87
+ require('./fixtures/map-with-parameters')
47
88
  )
48
89
  })
49
90
 
@@ -51,25 +92,21 @@ describe('StateMachineLint', () => {
51
92
  verify(
52
93
  'Choice With Parameters',
53
94
  require('./fixtures/choice-with-parameters'),
54
- 1,
55
95
  '"Parameters'
56
96
  )
57
97
  verify(
58
98
  'Wait With Parameters',
59
99
  require('./fixtures/wait-with-parameters'),
60
- 1,
61
100
  '"Parameters'
62
101
  )
63
102
  verify(
64
103
  'Succeed With Parameters',
65
104
  require('./fixtures/succeed-with-parameters'),
66
- 1,
67
105
  '"Parameters'
68
106
  )
69
107
  verify(
70
108
  'Fail With Parameters',
71
109
  require('./fixtures/fail-with-parameters'),
72
- 1,
73
110
  '"Parameters'
74
111
  )
75
112
  })
@@ -78,7 +115,6 @@ describe('StateMachineLint', () => {
78
115
  verify(
79
116
  'reject non-Path constructs in Parameter fields ending in ".$"',
80
117
  require('./fixtures/parameter-path-problems'),
81
- 4,
82
118
  'bad1',
83
119
  'bad2',
84
120
  'bad3',
@@ -89,18 +125,15 @@ describe('StateMachineLint', () => {
89
125
  describe('ResultPath only valid on Pass, Task, Parallel', () => {
90
126
  verify(
91
127
  'Pass with ResultPath',
92
- require('./fixtures/pass-with-resultpath'),
93
- 0
128
+ require('./fixtures/pass-with-resultpath')
94
129
  )
95
130
  verify(
96
131
  'Task with ResultPath',
97
- require('./fixtures/task-with-resultpath'),
98
- 0
132
+ require('./fixtures/task-with-resultpath')
99
133
  )
100
134
  verify(
101
135
  'Parallel with ResultPath',
102
- require('./fixtures/parallel-with-resultpath'),
103
- 0
136
+ require('./fixtures/parallel-with-resultpath')
104
137
  )
105
138
  })
106
139
 
@@ -108,199 +141,239 @@ describe('StateMachineLint', () => {
108
141
  verify(
109
142
  'Choice with ResultPath',
110
143
  require('./fixtures/choice-with-resultpath'),
111
- 1,
112
144
  '"ResultPath"'
113
145
  )
114
146
  verify(
115
147
  'Wait with ResultPath',
116
148
  require('./fixtures/wait-with-resultpath'),
117
- 1,
118
149
  '"ResultPath"'
119
150
  )
120
151
  verify(
121
152
  'Succeed with ResultPath',
122
153
  require('./fixtures/succeed-with-resultpath'),
123
- 1,
124
154
  '"ResultPath"'
125
155
  )
126
156
  verify(
127
157
  'Fail with ResultPath',
128
158
  require('./fixtures/fail-with-resultpath'),
129
- 1,
130
159
  '"ResultPath"'
131
160
  )
132
161
  })
133
162
 
134
- describe('StateNode', () => {
135
- verify(
136
- 'should find missing StartAt targets',
137
- {
138
- StartAt: 'x',
139
- States: {
140
- y: {
141
- Type: 'Succeed'
142
- }
143
- }
144
- },
145
- 2
163
+ describe('Context object', () => {
164
+ verify(
165
+ 'Allow context object access in InputPath and OutputPath',
166
+ require('./fixtures/pass-with-io-path-context-object.json')
146
167
  )
147
-
148
168
  verify(
149
- 'should catch nested problems',
150
- {
151
- StartAt: 'x',
152
- States: {
153
- x: {
154
- StartAt: 'z',
155
- States: {
156
- w: 1
157
- }
158
- }
159
- }
160
- },
161
- 8
169
+ 'Allow context object access in Choice state Variable',
170
+ require('./fixtures/choice-with-context-object.json')
162
171
  )
163
-
164
172
  verify(
165
- 'should find States.ALL not in last position',
166
- {
167
- Retry: [
168
- { ErrorEquals: ['States.ALL'] },
169
- { ErrorEquals: ['YET ANOTHER'] }
170
- ]
171
- },
172
- 6
173
+ 'Allow context object access in Map state ItemsPath',
174
+ require('./fixtures/map-with-itemspath-context-object.json')
173
175
  )
176
+ })
174
177
 
178
+ describe('Timeouts', () => {
179
+ verify(
180
+ 'Allow dynamic timeout fields in Task state',
181
+ require('./fixtures/task-with-dynamic-timeouts.json')
182
+ )
175
183
  verify(
176
- 'should find States.ALL not by itself',
177
- {
178
- Retry: [
179
- { ErrorEquals: ['YET ANOTHER'] },
180
- { ErrorEquals: ['States.ALL', 'other'] }
181
- ]
182
- },
183
- 6
184
+ 'Reject task with static and dynamic timeouts',
185
+ require('./fixtures/task-with-static-and-dynamic-timeout.json'),
186
+ 'may have only one of TimeoutSeconds,TimeoutSecondsPath'
184
187
  )
188
+ verify(
189
+ 'Reject task with static and dynamic timeouts',
190
+ require('./fixtures/task-with-static-and-dynamic-heartbeat.json'),
191
+ 'may have only one of HeartbeatSeconds,HeartbeatSecondsPath'
192
+ )
193
+ })
185
194
 
195
+ describe('Null paths', () => {
186
196
  verify(
187
- 'should use Default field correctly',
188
- {
189
- StartAt: 'A',
190
- States: {
191
- A: {
192
- Type: 'Choice',
193
- Choices: [
194
- {
195
- Variable: '$.a',
196
- StringEquals: 'whoo',
197
- Next: 'B'
198
- }
199
- ],
200
- Default: 'C'
201
- },
202
- B: {
203
- Type: 'Succeed'
204
- },
205
- C: {
206
- Type: 'Succeed'
207
- }
208
- }
209
- },
210
- 0
197
+ 'Allow null values in InputPath',
198
+ require('./fixtures/pass-with-null-inputpath.json')
211
199
  )
200
+ verify(
201
+ 'Allow null values in OutputPath',
202
+ require('./fixtures/pass-with-null-outputpath.json')
203
+ )
204
+ verify(
205
+ 'Not allow null value in Map state ItemsPath',
206
+ require('./fixtures/map-with-null-itemspath.json'),
207
+ 'ItemsPath'
208
+ )
209
+ })
212
210
 
211
+ describe('ResultSelector', () => {
212
+ verify(
213
+ 'Allow ResultSelector on Task',
214
+ require('./fixtures/task-with-resultselector.json')
215
+ )
216
+ verify(
217
+ 'Allow ResultSelector on Parallel',
218
+ require('./fixtures/parallel-with-resultselector.json')
219
+ )
220
+ verify(
221
+ 'Allow ResultSelector on Map',
222
+ require('./fixtures/map-with-resultselector.json')
223
+ )
213
224
  verify(
214
- 'should find Next fields with targets that don\'t match state names',
215
- {
216
- StartAt: 'A',
217
- States: {
218
- A: {
219
- Type: 'Pass',
220
- Next: 'B'
221
- }
222
- }
223
- },
224
- 2
225
+ 'Reject ResultSelector on Pass',
226
+ require('./fixtures/pass-with-resultselector.json'),
227
+ '"ResultSelector"'
225
228
  )
229
+ verify(
230
+ 'Reject ResultSelector on Wait',
231
+ require('./fixtures/wait-with-resultselector.json'),
232
+ '"ResultSelector"'
233
+ )
234
+ verify(
235
+ 'Reject ResultSelector on Fail',
236
+ require('./fixtures/fail-with-resultselector.json'),
237
+ '"ResultSelector"'
238
+ )
239
+ verify(
240
+ 'Reject ResultSelector on Succeed',
241
+ require('./fixtures/succeed-with-resultselector.json'),
242
+ '"ResultSelector"'
243
+ )
244
+ verify(
245
+ 'Reject ResultSelector on Choice',
246
+ require('./fixtures/choice-with-resultselector.json'),
247
+ '"ResultSelector"'
248
+ )
249
+ })
226
250
 
251
+ describe('Intrinsic function invocation in payload builder fields', () => {
252
+ verify(
253
+ 'States Array invocation',
254
+ require('./fixtures/states-array-invocation.json')
255
+ )
256
+ verify(
257
+ 'States Format invocation',
258
+ require('./fixtures/states-format-invocation.json')
259
+ )
260
+ verify(
261
+ 'States StringToJson invocation',
262
+ require('./fixtures/states-stringtojson-invocation.json')
263
+ )
264
+ verify(
265
+ 'States JsonToString invocation',
266
+ require('./fixtures/states-jsontostring-invocation.json')
267
+ )
268
+ verify(
269
+ 'Reject invalid States Array invocation',
270
+ require('./fixtures/states-array-invocation-leftpad.json'),
271
+ 'not a JSONPath or intrinsic function expression'
272
+ )
273
+ verify(
274
+ 'Reject invalid Function invocation',
275
+ require('./fixtures/invalid-function-invocation.json'),
276
+ 'not a JSONPath or intrinsic function expression'
277
+ )
227
278
  verify(
228
- 'should find un-pointed-to states',
229
- {
230
- StartAt: 'A',
231
- States: {
232
- A: {
233
- Type: 'Succeed'
234
- },
235
- X: {
236
- Type: 'Succeed'
237
- }
238
- }
239
- },
240
- 1
279
+ 'Reject intrinsic function inputpath',
280
+ require('./fixtures/pass-with-intrinsic-function-inputpath.json'),
281
+ '"InputPath"'
241
282
  )
283
+ })
242
284
 
285
+ describe('Functions added in 2022', () => {
286
+ verify(
287
+ 'Array intrinsic function',
288
+ require('./fixtures/states-array-intrinsic-functions.json')
289
+ )
243
290
  verify(
244
- 'should find missing terminal state',
245
- {
246
- StartAt: 'A',
247
- States: {
248
- A: {
249
- Type: 'Pass',
250
- Next: 'B'
251
- },
252
- B: {
253
- Type: 'Pass',
254
- Next: 'A'
255
- }
256
- }
257
- },
258
- 1
291
+ 'Encoding/decoding intrinsic function',
292
+ require('./fixtures/states-encoding-decoding-intrinsic-functions.json')
259
293
  )
294
+ verify(
295
+ 'Hash intrinsic function',
296
+ require('./fixtures/states-hash-intrinsic-functions.json')
297
+ )
298
+ verify(
299
+ 'Json intrinsic function',
300
+ require('./fixtures/states-json-intrinsic-functions.json')
301
+ )
302
+ verify(
303
+ 'Math intrinsic function',
304
+ require('./fixtures/states-math-intrinsic-functions.json')
305
+ )
306
+ verify(
307
+ 'String intrinsic function',
308
+ require('./fixtures/states-string-intrinsic-functions.json')
309
+ )
310
+ verify(
311
+ 'UUID intrinsic function',
312
+ require('./fixtures/states-uuid-intrinsic-functions.json')
313
+ )
314
+ })
260
315
 
316
+ describe('Comment', () => {
261
317
  verify(
262
- 'should handle complex missing terminal',
263
- require('./fixtures/no-terminal.json'),
264
- 1
318
+ 'Allow Choice Rule to use Comment',
319
+ require('./fixtures/choice-rule-with-comment.json')
265
320
  )
321
+ verify(
322
+ 'Allow a Comment field in Catcher',
323
+ require('./fixtures/succeed-with-comment-in-catcher.json')
324
+ )
325
+ })
266
326
 
327
+ describe('Map state', () => {
328
+ verify(
329
+ 'Allow ItemProcessor in Map',
330
+ require('./fixtures/map-with-itemprocessor.json')
331
+ )
332
+ verify(
333
+ 'Reject Map state with both Iterator and ItemProcessor',
334
+ require('./fixtures/map-with-itemprocessor-and-iterator.json'),
335
+ 'may have only one of Iterator,ItemProcessor'
336
+ )
267
337
  verify(
268
- 'should catch linkage from one parallel branch to another',
269
- require('./fixtures/linked-parallel.json'),
270
- 4
338
+ 'Reject Map state with both Parameters and ItemSelector',
339
+ require('./fixtures/map-with-parameters-and-itemselector.json'),
340
+ 'may have only one of ItemSelector,Parameters'
271
341
  )
342
+ })
272
343
 
344
+ describe('Task state', () => {
345
+ verify(
346
+ 'Allow Credentials in Task',
347
+ require('./fixtures/task-with-credentials.json')
348
+ )
273
349
  verify(
274
- 'should catch duplicate state names, even in parallels',
275
- require('./fixtures/has-dupes.json'),
276
- 1
350
+ 'Reject invalid Credentials in Task',
351
+ require('./fixtures/task-with-invalid-credentials.json'),
352
+ 'should be an Object'
277
353
  )
278
354
  })
279
355
 
280
356
  describe('Validate Catch', () => {
281
357
  verify(
282
358
  'Catch States.ALL',
283
- require('./fixtures/hello-world-with-caught-failures'),
284
- 0)
359
+ require('./fixtures/hello-world-with-caught-failures')
360
+ )
285
361
  })
286
362
 
287
363
  describe('Real-life state machines', () => {
288
364
  verify(
289
365
  'BackoffRate maybe an integer',
290
- require('./fixtures/j2119_issues_37'),
291
- 0
366
+ require('./fixtures/j2119_issues_37')
292
367
  )
293
368
  })
294
369
  })
295
370
 
296
- function verify (label, json, count, ...msg) {
371
+ function verify (label, json, ...msg) {
297
372
  it(label, () => {
298
373
  const linter = stateLint()
299
374
  const problems = linter.validate(json)
300
375
 
301
- console.log(problems)
302
-
303
- expect(problems.length).to.eql(count)
376
+ expect(problems.length).to.eql(msg.length)
304
377
  for (let i = 0; i !== msg.length; ++i) {
305
378
  expect(problems[i]).to.include(msg[i])
306
379
  }