vouchington-tooling 0.13.4 → 0.15.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 (29) hide show
  1. package/README.md +3 -0
  2. package/ast-grep/rules/backend-no-test-file-imports.yml +1 -1
  3. package/ast-grep/rules/no-dynamic-import-in-vitest-config.yml +1 -1
  4. package/ast-grep/rules/no-dynamic-server-components.yml +41 -5
  5. package/ast-grep/rules/no-enable-indexscan-off.yml +17 -4
  6. package/ast-grep/rules/no-exports-in-tests-folder.yml +27 -4
  7. package/ast-grep/rules/no-object-assign-new-error.yml +1 -1
  8. package/ast-grep/rules/no-runner-temp-nullish.yml +1 -1
  9. package/ast-grep/rules/no-self-comparison-assertion.yml +21 -1
  10. package/ast-grep/rules/no-sql-offset.yml +1 -1
  11. package/ast-grep/rules/no-sync-throw-assert-on-async-enqueue.yml +1 -1
  12. package/ast-grep/rules/no-tautological-literal-assertion.yml +15 -1
  13. package/ast-grep/rules/no-test-max-lines-disable.yml +26 -4
  14. package/ast-grep/rules/no-three-sequential-awaits.yml +220 -12
  15. package/ast-grep/rules/nullable-options.yml +1 -1
  16. package/ast-grep/rules/pagination-no-exact-limit-has-next.yml +1 -1
  17. package/ast-grep/rules/playwright-no-bare-meta-press.yml +1 -1
  18. package/ast-grep/rules/storybook-no-webpack-final.yml +1 -1
  19. package/ast-grep/sgconfig.yml +1 -2
  20. package/package.json +1 -1
  21. package/skills/agent-workflow/SKILL.md +4 -1
  22. package/skills/agent-workflow/references/review-response.md +32 -0
  23. package/ast-grep/rules/no-dynamic-server-components-tsx.yml +0 -71
  24. package/ast-grep/rules/no-enable-indexscan-off-tsx.yml +0 -33
  25. package/ast-grep/rules/no-exports-in-tests-folder-tsx.yml +0 -42
  26. package/ast-grep/rules/no-self-comparison-assertion-tsx.yml +0 -43
  27. package/ast-grep/rules/no-tautological-literal-assertion-tsx.yml +0 -31
  28. package/ast-grep/rules/no-test-max-lines-disable-tsx.yml +0 -41
  29. package/ast-grep/rules/no-three-sequential-awaits-tsx.yml +0 -466
@@ -1,31 +0,0 @@
1
- id: no-tautological-literal-assertion-tsx
2
- language: Tsx
3
- severity: error
4
- message: 'This asserts a literal against an identical literal (e.g. expect(true).toBe(true)), which can never fail and provides zero real coverage of the code under test. Assert on the actual value the code under test produced instead -- for example expect(await run()).not.toBeNull(), or a specific value or shape derived from calling the function being tested.'
5
- files:
6
- - '**/*.test.tsx'
7
- - '**/*.spec.tsx'
8
- rule:
9
- pattern: 'expect($LIT).toBe($LIT)'
10
- constraints:
11
- LIT:
12
- any:
13
- - kind: 'true'
14
- - kind: 'false'
15
- - kind: 'number'
16
- - kind: 'string'
17
- - kind: 'null'
18
- - kind: 'undefined'
19
- examples:
20
- - code: 'expect(true).toBe(true)'
21
- isValid: false
22
- file: 'web/components/example/__tests__/add-to-list-menu-item.mock.test.tsx'
23
- - code: "expect('placeholder').toBe('placeholder')"
24
- isValid: false
25
- file: 'web/components/example/__tests__/source-list-item.interactions.mock.test.tsx'
26
- - code: 'expect(screen.getByRole("button")).toBeInTheDocument()'
27
- isValid: true
28
- file: 'web/components/example/__tests__/add-to-list-menu-item.mock.test.tsx'
29
- - code: 'expect(true).toBe(true)'
30
- isValid: true
31
- file: 'web/components/example/add-to-list-menu-item.tsx'
@@ -1,41 +0,0 @@
1
- # NOTE: This rule flags eslint/oxlint disable directives that suppress max-lines
2
- # (or all rules) inside test files. Test files must stay within their line limit;
3
- # split the test or extract reusable helpers instead.
4
- # NOTE: ast-grep maps `.tsx` to language `Tsx`, not `TypeScript`. This rule
5
- # only scans `.tsx` files; see no-test-max-lines-disable.yml for the
6
- # companion rule that covers `.ts/.mts/.cts` files.
7
- id: no-test-max-lines-disable-tsx
8
- language: Tsx
9
- severity: error
10
- message: 'Test files must not disable max-lines or all lint rules; split the test or extract reusable helpers instead.'
11
- files:
12
- - '**/*.test.tsx'
13
- - '**/*.spec.tsx'
14
- - '**/__tests__/**/*.tsx'
15
- rule:
16
- kind: comment
17
- any:
18
- - regex: '^(?://|/\*)\s*(?:eslint|oxlint)-disable(?:-next-line|-line)?\s*(?:\*/\s*$|--|\s*$)'
19
- - regex: '^(?://|/\*)\s*(?:eslint|oxlint)-disable(?:-next-line|-line)?(?:[^\n-]|-[^\n-])*(?:\s|,)(?:max-lines(?:[^-a-zA-Z0-9_]|$)|eslint/max-lines(?:[^-a-zA-Z0-9_]|$))'
20
- examples:
21
- - code: '// oxlint-disable max-lines'
22
- isValid: false
23
- file: 'web/components/__tests__/foo.test.tsx'
24
- - code: '// eslint-disable'
25
- isValid: false
26
- file: 'web/components/__tests__/foo.test.tsx'
27
- - code: '// oxlint-disable vitest/expect-expect'
28
- isValid: true
29
- file: 'web/components/__tests__/foo.test.tsx'
30
- - code: '// oxlint-disable no-console'
31
- isValid: true
32
- file: 'web/components/__tests__/foo.spec.tsx'
33
- - code: '// eslint-disable max-lines-per-function'
34
- isValid: true
35
- file: 'web/components/__tests__/foo.test.tsx'
36
- - code: '// eslint-disable eslint/max-lines-per-function'
37
- isValid: true
38
- file: 'web/components/__tests__/foo.test.tsx'
39
- - code: '// oxlint-disable no-console -- split because of max-lines'
40
- isValid: true
41
- file: 'web/components/__tests__/foo.test.tsx'
@@ -1,466 +0,0 @@
1
- id: no-three-sequential-awaits-tsx
2
- language: Tsx
3
- severity: error
4
- message: 'Avoid 3 sequential await statements; abstract dependent work or parallelize independent work with Promise.all().'
5
- files:
6
- - '**/*.tsx'
7
- ignores:
8
- - '**/*.test.tsx'
9
- - '**/*.spec.tsx'
10
- - '**/*.mock.test.tsx'
11
- - '**/*.stories.tsx'
12
- - 'web/test-helpers/**'
13
- rule:
14
- all:
15
- - not:
16
- any:
17
- - matches: async-disposable-acquisition
18
- - matches: async-disposable-commit
19
- - not:
20
- follows:
21
- stopBy: neighbor
22
- any:
23
- - all:
24
- - pattern:
25
- context: await $P
26
- selector: expression_statement
27
- - not:
28
- pattern: await params
29
- - not:
30
- pattern: await searchParams
31
- - not:
32
- has:
33
- pattern: Promise.all($$)
34
- - not:
35
- has:
36
- pattern: Promise.allSettled($$)
37
- - all:
38
- - pattern: const $W = await $P
39
- - not:
40
- pattern: const $W = await params
41
- - not:
42
- pattern: const $W = await searchParams
43
- - not:
44
- pattern: const $W = await Promise.all($$$)
45
- - not:
46
- pattern: const $W = await Promise.allSettled($$$)
47
- - all:
48
- - pattern: let $W = await $P
49
- - not:
50
- pattern: let $W = await params
51
- - not:
52
- pattern: let $W = await searchParams
53
- - not:
54
- pattern: let $W = await Promise.all($$$)
55
- - not:
56
- pattern: let $W = await Promise.allSettled($$$)
57
- - all:
58
- - pattern: var $W = await $P
59
- - not:
60
- pattern: var $W = await params
61
- - not:
62
- pattern: var $W = await searchParams
63
- - not:
64
- pattern: var $W = await Promise.all($$$)
65
- - not:
66
- pattern: var $W = await Promise.allSettled($$$)
67
- - all:
68
- - pattern:
69
- context: $W = await $P
70
- selector: expression_statement
71
- - not:
72
- pattern: $W = await params
73
- - not:
74
- pattern: $W = await searchParams
75
- - not:
76
- pattern: $W = await Promise.all($$$)
77
- - not:
78
- pattern: $W = await Promise.allSettled($$$)
79
- not:
80
- any:
81
- - matches: async-disposable-acquisition
82
- - matches: async-disposable-commit
83
- - any:
84
- - all:
85
- - pattern:
86
- context: await $A
87
- selector: expression_statement
88
- - not:
89
- pattern: await params
90
- - not:
91
- pattern: await searchParams
92
- - not:
93
- has:
94
- pattern: Promise.all($$)
95
- - not:
96
- has:
97
- pattern: Promise.allSettled($$)
98
- - all:
99
- - pattern: const $X = await $A
100
- - not:
101
- pattern: const $X = await params
102
- - not:
103
- pattern: const $X = await searchParams
104
- - not:
105
- pattern: const $X = await Promise.all($$$)
106
- - not:
107
- pattern: const $X = await Promise.allSettled($$$)
108
- - all:
109
- - pattern: let $X = await $A
110
- - not:
111
- pattern: let $X = await params
112
- - not:
113
- pattern: let $X = await searchParams
114
- - not:
115
- pattern: let $X = await Promise.all($$$)
116
- - not:
117
- pattern: let $X = await Promise.allSettled($$$)
118
- - all:
119
- - pattern: var $X = await $A
120
- - not:
121
- pattern: var $X = await params
122
- - not:
123
- pattern: var $X = await searchParams
124
- - not:
125
- pattern: var $X = await Promise.all($$$)
126
- - not:
127
- pattern: var $X = await Promise.allSettled($$$)
128
- - all:
129
- - pattern:
130
- context: $X = await $A
131
- selector: expression_statement
132
- - not:
133
- pattern: $X = await params
134
- - not:
135
- pattern: $X = await searchParams
136
- - not:
137
- pattern: $X = await Promise.all($$$)
138
- - not:
139
- pattern: $X = await Promise.allSettled($$$)
140
- - precedes:
141
- stopBy: neighbor
142
- all:
143
- - any:
144
- - all:
145
- - pattern:
146
- context: await $B
147
- selector: expression_statement
148
- - not:
149
- pattern: await params
150
- - not:
151
- pattern: await searchParams
152
- - not:
153
- has:
154
- pattern: Promise.all($$)
155
- - not:
156
- has:
157
- pattern: Promise.allSettled($$)
158
- - all:
159
- - pattern: const $Y = await $B
160
- - not:
161
- pattern: const $Y = await params
162
- - not:
163
- pattern: const $Y = await searchParams
164
- - not:
165
- pattern: const $Y = await Promise.all($$$)
166
- - not:
167
- pattern: const $Y = await Promise.allSettled($$$)
168
- - all:
169
- - pattern: let $Y = await $B
170
- - not:
171
- pattern: let $Y = await params
172
- - not:
173
- pattern: let $Y = await searchParams
174
- - not:
175
- pattern: let $Y = await Promise.all($$$)
176
- - not:
177
- pattern: let $Y = await Promise.allSettled($$$)
178
- - all:
179
- - pattern: var $Y = await $B
180
- - not:
181
- pattern: var $Y = await params
182
- - not:
183
- pattern: var $Y = await searchParams
184
- - not:
185
- pattern: var $Y = await Promise.all($$$)
186
- - not:
187
- pattern: var $Y = await Promise.allSettled($$$)
188
- - all:
189
- - pattern:
190
- context: $Y = await $B
191
- selector: expression_statement
192
- - not:
193
- pattern: $Y = await params
194
- - not:
195
- pattern: $Y = await searchParams
196
- - not:
197
- pattern: $Y = await Promise.all($$$)
198
- - not:
199
- pattern: $Y = await Promise.allSettled($$$)
200
- - not:
201
- any:
202
- - matches: async-disposable-acquisition
203
- - matches: async-disposable-commit
204
- - precedes:
205
- stopBy: neighbor
206
- not:
207
- any:
208
- - matches: async-disposable-acquisition
209
- - matches: async-disposable-commit
210
- any:
211
- - all:
212
- - pattern:
213
- context: await $C
214
- selector: expression_statement
215
- - not:
216
- pattern: await params
217
- - not:
218
- pattern: await searchParams
219
- - not:
220
- has:
221
- pattern: Promise.all($$)
222
- - not:
223
- has:
224
- pattern: Promise.allSettled($$)
225
- - all:
226
- - pattern: const $Z = await $C
227
- - not:
228
- pattern: const $Z = await params
229
- - not:
230
- pattern: const $Z = await searchParams
231
- - not:
232
- pattern: const $Z = await Promise.all($$$)
233
- - not:
234
- pattern: const $Z = await Promise.allSettled($$$)
235
- - all:
236
- - pattern: let $Z = await $C
237
- - not:
238
- pattern: let $Z = await params
239
- - not:
240
- pattern: let $Z = await searchParams
241
- - not:
242
- pattern: let $Z = await Promise.all($$$)
243
- - not:
244
- pattern: let $Z = await Promise.allSettled($$$)
245
- - all:
246
- - pattern: var $Z = await $C
247
- - not:
248
- pattern: var $Z = await params
249
- - not:
250
- pattern: var $Z = await searchParams
251
- - not:
252
- pattern: var $Z = await Promise.all($$$)
253
- - not:
254
- pattern: var $Z = await Promise.allSettled($$$)
255
- - all:
256
- - pattern:
257
- context: $Z = await $C
258
- selector: expression_statement
259
- - not:
260
- pattern: $Z = await params
261
- - not:
262
- pattern: $Z = await searchParams
263
- - not:
264
- pattern: $Z = await Promise.all($$$)
265
- - not:
266
- pattern: $Z = await Promise.allSettled($$$)
267
- constraints:
268
- A:
269
- not:
270
- regex: '^Promise\.all(Settled)?\b'
271
- B:
272
- not:
273
- regex: '^Promise\.all(Settled)?\b'
274
- C:
275
- not:
276
- regex: '^Promise\.all(Settled)?\b'
277
- P:
278
- not:
279
- regex: '^Promise\.all(Settled)?\b'
280
- utils:
281
- async-disposable-acquisition:
282
- all:
283
- - pattern:
284
- context: |
285
- async function run() {
286
- await using $RESOURCE = await $ACQUIRE
287
- }
288
- selector: expression_statement
289
- - precedes:
290
- # Pair only with the nearest lifecycle endpoint to the right.
291
- # Overlapping-resource policy belongs to a separate lifecycle rule.
292
- stopBy:
293
- any:
294
- - pattern:
295
- context: |
296
- async function run() {
297
- await using $_ = await $_
298
- }
299
- selector: expression_statement
300
- - pattern:
301
- context: |
302
- async function run() {
303
- await $_.commit($$$)
304
- }
305
- selector: expression_statement
306
- pattern:
307
- context: |
308
- async function run() {
309
- await $RESOURCE.commit($$$)
310
- }
311
- selector: expression_statement
312
- async-disposable-commit:
313
- all:
314
- - pattern:
315
- context: |
316
- async function run() {
317
- await $RESOURCE.commit($$$)
318
- }
319
- selector: expression_statement
320
- - follows:
321
- # Pair only with the nearest lifecycle endpoint to the left.
322
- # Overlapping-resource policy belongs to a separate lifecycle rule.
323
- stopBy:
324
- any:
325
- - pattern:
326
- context: |
327
- async function run() {
328
- await using $_ = await $_
329
- }
330
- selector: expression_statement
331
- - pattern:
332
- context: |
333
- async function run() {
334
- await $_.commit($$$)
335
- }
336
- selector: expression_statement
337
- pattern:
338
- context: |
339
- async function run() {
340
- await using $RESOURCE = await $ACQUIRE
341
- }
342
- selector: expression_statement
343
- examples:
344
- - code: |
345
- async function run() {
346
- await one()
347
- await two()
348
- await three()
349
- }
350
- isValid: false
351
- file: 'web/app/example.tsx'
352
- - code: |
353
- async function run() {
354
- const { id } = await params
355
- const topic = await getTopic(id)
356
- const aliases = await getAliases(id)
357
- return <div>{topic.name}{aliases.length}</div>
358
- }
359
- isValid: true
360
- file: 'web/app/example.tsx'
361
- - code: |
362
- async function run() {
363
- await Promise.all([one(), two(), three()])
364
- return <div />
365
- }
366
- isValid: true
367
- file: 'web/app/example.tsx'
368
- - code: |
369
- async function run() {
370
- await using transaction = await beginTransaction()
371
- await applyChange(transaction)
372
- await transaction.commit()
373
- return <div />
374
- }
375
- isValid: true
376
- file: 'web/app/example.tsx'
377
- - code: |
378
- async function run() {
379
- await using transaction = await beginBoundedTransaction({ timeoutMs: 1000 })
380
- await applyFirstChange(transaction)
381
- await applySecondChange(transaction)
382
- await transaction.commit()
383
- return <div />
384
- }
385
- isValid: true
386
- file: 'web/app/example.tsx'
387
- - code: |
388
- async function run() {
389
- await using transaction = await beginTransaction()
390
- await applyFirstChange(transaction)
391
- await applySecondChange(transaction)
392
- await applyThirdChange(transaction)
393
- await transaction.commit()
394
- return <div />
395
- }
396
- isValid: false
397
- file: 'web/app/example.tsx'
398
- - code: |
399
- async function run() {
400
- await unrelatedFirst()
401
- await unrelatedSecond()
402
- await unrelatedThird()
403
- await using transaction = await beginTransaction()
404
- await applyChange(transaction)
405
- await transaction.commit()
406
- return <div />
407
- }
408
- isValid: false
409
- file: 'web/app/example.tsx'
410
- - code: |
411
- async function run() {
412
- await using transaction = await beginTransaction()
413
- await applyFirstChange(transaction)
414
- await applySecondChange(transaction)
415
- await other.commit()
416
- return <div />
417
- }
418
- isValid: false
419
- file: 'web/app/example.tsx'
420
- - code: |
421
- async function run() {
422
- await using transaction = await beginTransaction()
423
- await applyChange(transaction)
424
- await transaction.commit()
425
- await afterFirst()
426
- await afterSecond()
427
- await afterThird()
428
- return <div />
429
- }
430
- isValid: false
431
- file: 'web/app/example.tsx'
432
- - code: |
433
- async function run() {
434
- await using outer = await acquire()
435
- {
436
- await using inner = await acquire()
437
- await innerFirst(inner)
438
- await innerSecond(inner)
439
- await innerThird(inner)
440
- await inner.commit()
441
- }
442
- await outer.commit()
443
- return <div />
444
- }
445
- isValid: false
446
- file: 'web/app/example.tsx'
447
- - code: |
448
- async function run() {
449
- await using transaction = await beginTransaction()
450
- await applyFirstChange(transaction)
451
- await applySecondChange(transaction)
452
- await transaction.rollback()
453
- return <div />
454
- }
455
- isValid: false
456
- file: 'web/app/example.tsx'
457
- - code: |
458
- async function run() {
459
- await using resource = await acquire()
460
- await useFirst(resource)
461
- await useSecond(resource)
462
- await resource.dispose()
463
- return <div />
464
- }
465
- isValid: false
466
- file: 'web/app/example.tsx'