shuck-linter 0.0.43

Lint rule engine and checker for shell scripts
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
use crate::Severity;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Category {
    Correctness,
    Style,
    Performance,
    Portability,
    Security,
}

impl Category {
    pub const fn prefix(self) -> &'static str {
        match self {
            Self::Correctness => "C",
            Self::Style => "S",
            Self::Performance => "P",
            Self::Portability => "X",
            Self::Security => "K",
        }
    }

    pub fn from_prefix(prefix: &str) -> Option<Self> {
        match prefix {
            "C" => Some(Self::Correctness),
            "S" => Some(Self::Style),
            "P" => Some(Self::Performance),
            "X" => Some(Self::Portability),
            "K" => Some(Self::Security),
            _ => None,
        }
    }
}

macro_rules! declare_rules {
    (@sub $name:ident) => {
        ()
    };
    (@count $($name:ident),+ $(,)?) => {
        <[()]>::len(&[$(declare_rules!(@sub $name)),+])
    };
    ($(
        ($code:literal, $category:expr, $severity:expr, $name:ident),
    )+) => {
        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
        #[repr(u16)]
        pub enum Rule {
            $($name,)*
        }

        pub const ALL_RULES: [Rule; declare_rules!(@count $($name),+)] = [
            $(Rule::$name,)*
        ];

        impl Rule {
            pub const COUNT: usize = ALL_RULES.len();

            pub fn iter() -> impl ExactSizeIterator<Item = Self> + DoubleEndedIterator + Clone {
                ALL_RULES.into_iter()
            }

            pub const fn code(self) -> &'static str {
                match self {
                    $(Self::$name => $code,)*
                }
            }

            pub const fn category(self) -> Category {
                match self {
                    $(Self::$name => $category,)*
                }
            }

            pub const fn default_severity(self) -> Severity {
                match self {
                    $(Self::$name => $severity,)*
                }
            }
        }

        fn canonical_code_to_rule(code: &str) -> Option<Rule> {
            match code {
                $($code => Some(Rule::$name),)*
                _ => None,
            }
        }
    };
}

declare_rules! {
    ("C001", Category::Correctness, Severity::Warning, UnusedAssignment),
    ("C002", Category::Correctness, Severity::Warning, DynamicSourcePath),
    ("C003", Category::Correctness, Severity::Warning, UntrackedSourceFile),
    ("C004", Category::Correctness, Severity::Warning, UncheckedDirectoryChange),
    ("C005", Category::Correctness, Severity::Warning, SingleQuotedLiteral),
    ("C006", Category::Correctness, Severity::Error, UndefinedVariable),
    ("C007", Category::Correctness, Severity::Warning, FindOutputToXargs),
    ("C008", Category::Correctness, Severity::Warning, TrapStringExpansion),
    ("C009", Category::Correctness, Severity::Warning, QuotedBashRegex),
    ("C010", Category::Correctness, Severity::Warning, ChainedTestBranches),
    ("C011", Category::Correctness, Severity::Warning, LineOrientedInput),
    ("C012", Category::Correctness, Severity::Warning, LeadingGlobArgument),
    ("C013", Category::Correctness, Severity::Warning, FindOutputLoop),
    ("C014", Category::Correctness, Severity::Error, LocalTopLevel),
    ("C015", Category::Correctness, Severity::Warning, SudoRedirectionOrder),
    ("C016", Category::Correctness, Severity::Error, StrayClosingKeyword),
    ("C017", Category::Correctness, Severity::Warning, ConstantComparisonTest),
    ("C018", Category::Correctness, Severity::Error, LoopControlOutsideLoop),
    ("C019", Category::Correctness, Severity::Warning, LiteralUnaryStringTest),
    ("C020", Category::Correctness, Severity::Warning, TruthyLiteralTest),
    ("C021", Category::Correctness, Severity::Warning, ConstantCaseSubject),
    ("C022", Category::Correctness, Severity::Error, EmptyTest),
    ("C023", Category::Correctness, Severity::Error, LeadingZeroArithmetic),
    ("C024", Category::Correctness, Severity::Warning, AssignmentSpacing),
    ("C030", Category::Correctness, Severity::Error, MissingBracketSpace),
    ("C031", Category::Correctness, Severity::Error, MissingSpaceBeforeBracketClose),
    ("C032", Category::Correctness, Severity::Error, JammedTestBracket),
    ("C033", Category::Correctness, Severity::Error, IndentedHeredocClose),
    ("C025", Category::Correctness, Severity::Warning, PositionalTenBraces),
    ("C027", Category::Correctness, Severity::Warning, BareDoneWord),
    ("C034", Category::Correctness, Severity::Error, UnterminatedIf),
    ("C035", Category::Correctness, Severity::Error, MissingFi),
    ("C036", Category::Correctness, Severity::Error, BrokenTestEnd),
    ("C037", Category::Correctness, Severity::Error, BrokenTestParse),
    ("C038", Category::Correctness, Severity::Error, ElseIf),
    ("C039", Category::Correctness, Severity::Warning, OpenDoubleQuote),
    ("C040", Category::Correctness, Severity::Error, LinebreakInTest),
    ("C041", Category::Correctness, Severity::Error, CStyleComment),
    ("C042", Category::Correctness, Severity::Warning, CPrototypeFragment),
    ("C043", Category::Correctness, Severity::Warning, BadRedirectionFdOrder),
    ("C044", Category::Correctness, Severity::Warning, BareGlobCommandPath),
    ("C045", Category::Correctness, Severity::Warning, DiffMarkerLine),
    ("C046", Category::Correctness, Severity::Warning, PipeToKill),
    ("C047", Category::Correctness, Severity::Error, InvalidExitStatus),
    ("C048", Category::Correctness, Severity::Warning, CasePatternVar),
    ("C049", Category::Correctness, Severity::Warning, TautologyChain),
    ("C050", Category::Correctness, Severity::Warning, ArithmeticRedirectionTarget),
    ("C051", Category::Correctness, Severity::Error, DuplicateRedirect),
    ("C052", Category::Correctness, Severity::Error, AssignSpecialZero),
    ("C053", Category::Correctness, Severity::Warning, SpaceyAssign),
    ("C054", Category::Correctness, Severity::Warning, BareSlashMarker),
    ("C055", Category::Correctness, Severity::Warning, PatternWithVariable),
    ("C056", Category::Correctness, Severity::Warning, StatusCaptureAfterBranchTest),
    ("C057", Category::Correctness, Severity::Warning, SubstWithRedirect),
    ("C058", Category::Correctness, Severity::Warning, SubstWithRedirectErr),
    ("C059", Category::Correctness, Severity::Warning, RedirectToCommandName),
    ("C060", Category::Correctness, Severity::Warning, NonAbsoluteShebang),
    ("C061", Category::Correctness, Severity::Warning, TemplateBraceInCommand),
    ("C062", Category::Correctness, Severity::Warning, NestedParameterExpansion),
    ("C063", Category::Correctness, Severity::Warning, OverwrittenFunction),
    ("C064", Category::Correctness, Severity::Warning, IfMissingThen),
    ("C065", Category::Correctness, Severity::Warning, ElseWithoutThen),
    ("C066", Category::Correctness, Severity::Warning, MissingSemicolonBeforeBrace),
    ("C067", Category::Correctness, Severity::Warning, EmptyFunctionBody),
    ("C068", Category::Correctness, Severity::Warning, BareClosingBrace),
    ("C069", Category::Correctness, Severity::Warning, BackslashBeforeClosingBacktick),
    ("C070", Category::Correctness, Severity::Warning, PositionalParamAsOperator),
    ("C071", Category::Correctness, Severity::Warning, DoubleParenGrouping),
    ("C072", Category::Correctness, Severity::Warning, UnicodeQuoteInString),
    ("C073", Category::Correctness, Severity::Warning, IndentedShebang),
    ("C074", Category::Correctness, Severity::Warning, SpaceAfterHashBang),
    ("C075", Category::Correctness, Severity::Warning, ShebangNotOnFirstLine),
    (
        "C076",
        Category::Correctness,
        Severity::Warning,
        CommentedContinuationLine
    ),
    ("C077", Category::Correctness, Severity::Warning, SubshellInArithmetic),
    ("C078", Category::Correctness, Severity::Warning, UnquotedGlobsInFind),
    ("C080", Category::Correctness, Severity::Warning, GlobInGrepPattern),
    ("C081", Category::Correctness, Severity::Warning, GlobInStringComparison),
    ("C083", Category::Correctness, Severity::Warning, GlobInFindSubstitution),
    ("C084", Category::Correctness, Severity::Warning, UnquotedGrepRegex),
    (
        "C085",
        Category::Correctness,
        Severity::Warning,
        StderrBeforeStdoutRedirect
    ),
    (
        "C094",
        Category::Correctness,
        Severity::Warning,
        RedirectClobbersInput
    ),
    (
        "C082",
        Category::Correctness,
        Severity::Warning,
        EscapedNegationInTest
    ),
    (
        "C086",
        Category::Correctness,
        Severity::Warning,
        GreaterThanInTest
    ),
    (
        "C087",
        Category::Correctness,
        Severity::Warning,
        StringComparisonForVersion
    ),
    (
        "C088",
        Category::Correctness,
        Severity::Warning,
        MixedAndOrInCondition
    ),
    (
        "C089",
        Category::Correctness,
        Severity::Warning,
        QuotedCommandInTest
    ),
    (
        "C090",
        Category::Correctness,
        Severity::Warning,
        GlobInTestComparison
    ),
    (
        "C091",
        Category::Correctness,
        Severity::Warning,
        TildeInStringComparison
    ),
    ("C092", Category::Correctness, Severity::Warning, IfDollarCommand),
    (
        "C093",
        Category::Correctness,
        Severity::Warning,
        BacktickInCommandPosition
    ),
    (
        "C095",
        Category::Correctness,
        Severity::Warning,
        AssignmentLooksLikeComparison
    ),
    ("C096", Category::Correctness, Severity::Warning, SuspiciousBracketGlob),
    (
        "C097",
        Category::Correctness,
        Severity::Error,
        FunctionCalledWithoutArgs
    ),
    (
        "C098",
        Category::Correctness,
        Severity::Warning,
        SetFlagsWithoutDashes
    ),
    (
        "C099",
        Category::Correctness,
        Severity::Warning,
        QuotedArraySlice
    ),
    (
        "C100",
        Category::Correctness,
        Severity::Warning,
        QuotedBashSource
    ),
    (
        "C101",
        Category::Correctness,
        Severity::Warning,
        IfsSetToLiteralBackslashN
    ),
    (
        "C102",
        Category::Correctness,
        Severity::Warning,
        GlobInTestDirectory
    ),
    (
        "C103",
        Category::Correctness,
        Severity::Warning,
        FindOrWithoutGrouping
    ),
    (
        "C104",
        Category::Correctness,
        Severity::Warning,
        NonShellSyntaxInScript
    ),
    (
        "C105",
        Category::Correctness,
        Severity::Warning,
        ExportWithPositionalParams
    ),
    (
        "C106",
        Category::Correctness,
        Severity::Warning,
        AppendToArrayAsString
    ),
    (
        "C107",
        Category::Correctness,
        Severity::Warning,
        DollarQuestionAfterCommand
    ),
    (
        "C108",
        Category::Correctness,
        Severity::Warning,
        UnsetAssociativeArrayElement
    ),
    (
        "C109",
        Category::Correctness,
        Severity::Warning,
        MapfileProcessSubstitution
    ),
    (
        "C111",
        Category::Correctness,
        Severity::Warning,
        AtSignInStringCompare
    ),
    (
        "C112",
        Category::Correctness,
        Severity::Warning,
        ArraySliceInComparison
    ),
    (
        "C114",
        Category::Correctness,
        Severity::Warning,
        GlobWithExpansionInLoop
    ),
    (
        "C116",
        Category::Correctness,
        Severity::Warning,
        AssignmentToNumericVariable
    ),
    (
        "C117",
        Category::Correctness,
        Severity::Warning,
        PlusPrefixInAssignment
    ),
    (
        "C118",
        Category::Correctness,
        Severity::Warning,
        MalformedArithmeticInCondition
    ),
    (
        "C119",
        Category::Correctness,
        Severity::Warning,
        RedirectBeforePipe
    ),
    (
        "C120",
        Category::Correctness,
        Severity::Warning,
        ExprSubstrInTest
    ),
    (
        "C121",
        Category::Correctness,
        Severity::Warning,
        StringComparedWithEq
    ),
    (
        "C122",
        Category::Correctness,
        Severity::Warning,
        AFlagInDoubleBracket
    ),
    (
        "C123",
        Category::Correctness,
        Severity::Error,
        FunctionReferencesUnsetParam
    ),
    ("C124", Category::Correctness, Severity::Warning, UnreachableAfterExit),
    ("C127", Category::Correctness, Severity::Warning, UnusedHeredoc),
    (
        "C125",
        Category::Correctness,
        Severity::Warning,
        UncheckedDirectoryChangeInFunction
    ),
    (
        "C126",
        Category::Correctness,
        Severity::Error,
        ContinueOutsideLoopInFunction
    ),
    (
        "C128",
        Category::Correctness,
        Severity::Warning,
        CaseGlobReachability
    ),
    (
        "C129",
        Category::Correctness,
        Severity::Warning,
        CaseDefaultBeforeGlob
    ),
    (
        "C130",
        Category::Correctness,
        Severity::Warning,
        AppendWithEscapedQuotes
    ),
    (
        "C131",
        Category::Correctness,
        Severity::Warning,
        VariableAsCommandName
    ),
    (
        "C132",
        Category::Correctness,
        Severity::Warning,
        EnvPrefixExpansionOnly
    ),
    (
        "C133",
        Category::Correctness,
        Severity::Warning,
        ArrayToStringConversion
    ),
    (
        "C134",
        Category::Correctness,
        Severity::Warning,
        GetoptsOptionNotInCase
    ),
    (
        "C135",
        Category::Correctness,
        Severity::Warning,
        CaseArmNotInGetopts
    ),
    (
        "C136",
        Category::Correctness,
        Severity::Warning,
        LocalCrossReference
    ),
    (
        "C137",
        Category::Correctness,
        Severity::Warning,
        UnicodeSingleQuoteInSingleQuotes
    ),
    ("C138", Category::Correctness, Severity::Warning, HeredocMissingEnd),
    ("C139", Category::Correctness, Severity::Warning, SpacedAssignment),
    ("C140", Category::Correctness, Severity::Warning, BadVarName),
    ("C141", Category::Correctness, Severity::Error, LoopWithoutEnd),
    (
        "C142",
        Category::Correctness,
        Severity::Error,
        MissingDoneInForLoop
    ),
    ("C143", Category::Correctness, Severity::Error, DanglingElse),
    (
        "C144",
        Category::Correctness,
        Severity::Warning,
        HeredocCloserNotAlone
    ),
    ("C145", Category::Correctness, Severity::Warning, MisquotedHeredocClose),
    ("C146", Category::Correctness, Severity::Error, UntilMissingDo),
    ("C148", Category::Correctness, Severity::Warning, BrokenAssocKey),
    (
        "C150",
        Category::Correctness,
        Severity::Warning,
        SubshellLocalAssignment
    ),
    ("C151", Category::Correctness, Severity::Warning, CommaArrayElements),
    ("C155", Category::Correctness, Severity::Warning, SubshellSideEffect),
    (
        "C156",
        Category::Correctness,
        Severity::Warning,
        PossibleVariableMisspelling
    ),
    ("C157", Category::Correctness, Severity::Error, IfBracketGlued),
    (
        "C158",
        Category::Correctness,
        Severity::Warning,
        ImplicitGlobalInFunction
    ),
    ("C159", Category::Correctness, Severity::Warning, MutableGlobal),
    (
        "C160",
        Category::Correctness,
        Severity::Warning,
        UnanchoredSourcePath
    ),
    (
        "C161",
        Category::Correctness,
        Severity::Error,
        FunctionCalledBeforeDefined
    ),
    ("P001", Category::Performance, Severity::Warning, ExprArithmetic),
    ("P002", Category::Performance, Severity::Warning, GrepCountPipeline),
    ("P003", Category::Performance, Severity::Warning, SingleTestSubshell),
    ("P004", Category::Performance, Severity::Warning, SubshellTestGroup),
    ("X001", Category::Portability, Severity::Warning, DoubleBracketInSh),
    ("X002", Category::Portability, Severity::Warning, TestEqualityOperator),
    ("X003", Category::Portability, Severity::Warning, LocalVariableInSh),
    ("X004", Category::Portability, Severity::Warning, FunctionKeyword),
    ("X005", Category::Portability, Severity::Warning, BashCaseFallthrough),
    ("X006", Category::Portability, Severity::Warning, ProcessSubstitution),
    ("X007", Category::Portability, Severity::Warning, AnsiCQuoting),
    ("X010", Category::Portability, Severity::Warning, BraceExpansion),
    ("X011", Category::Portability, Severity::Warning, HereString),
    ("X008", Category::Portability, Severity::Warning, StandaloneArithmetic),
    ("X009", Category::Portability, Severity::Warning, SelectLoop),
    ("X014", Category::Portability, Severity::Warning, Coproc),
    ("X012", Category::Portability, Severity::Warning, AmpersandRedirection),
    ("X013", Category::Portability, Severity::Warning, ArrayAssignment),
    ("X015", Category::Portability, Severity::Warning, LetCommand),
    ("X016", Category::Portability, Severity::Warning, DeclareCommand),
    ("X017", Category::Portability, Severity::Warning, TrapErr),
    ("X018", Category::Portability, Severity::Warning, IndirectExpansion),
    ("X019", Category::Portability, Severity::Warning, ArrayReference),
    ("X020", Category::Portability, Severity::Warning, BraceFdRedirection),
    ("X021", Category::Portability, Severity::Warning, PipefailOption),
    ("X022", Category::Portability, Severity::Warning, WaitOption),
    ("X023", Category::Portability, Severity::Warning, SubstringExpansion),
    ("X024", Category::Portability, Severity::Warning, CaseModificationExpansion),
    ("X025", Category::Portability, Severity::Warning, ReplacementExpansion),
    ("X026", Category::Portability, Severity::Warning, BashFileSlurp),
    ("X027", Category::Portability, Severity::Warning, EchoFlags),
    ("X028", Category::Portability, Severity::Warning, TrLowerRange),
    ("X029", Category::Portability, Severity::Warning, TrUpperRange),
    ("X030", Category::Portability, Severity::Warning, EchoBackslashEscapes),
    ("X031", Category::Portability, Severity::Warning, SourceBuiltinInSh),
    ("X032", Category::Portability, Severity::Warning, PrintfQFormatInSh),
    ("X033", Category::Portability, Severity::Warning, IfElifBashTest),
    ("X035", Category::Portability, Severity::Warning, FunctionParamsInSh),
    ("X037", Category::Portability, Severity::Warning, ExtglobCase),
    ("X048", Category::Portability, Severity::Warning, ExtglobInCasePattern),
    ("X054", Category::Portability, Severity::Warning, ExtglobInSh),
    ("X065", Category::Portability, Severity::Warning, CaretNegationInBracket),
    ("X036", Category::Portability, Severity::Warning, ZshRedirPipe),
    ("X038", Category::Portability, Severity::Warning, ZshBraceIf),
    ("X039", Category::Portability, Severity::Warning, ZshAlwaysBlock),
    ("X040", Category::Portability, Severity::Warning, ArraySubscriptTest),
    ("X041", Category::Portability, Severity::Warning, ArraySubscriptCondition),
    ("X042", Category::Portability, Severity::Warning, SourcedWithArgs),
    ("X043", Category::Portability, Severity::Warning, ZshFlagExpansion),
    ("X044", Category::Portability, Severity::Warning, NestedZshSubstitution),
    ("X045", Category::Portability, Severity::Warning, PlusEqualsAppend),
    ("X051", Category::Portability, Severity::Warning, ZshNestedExpansion),
    ("X047", Category::Portability, Severity::Warning, MultiVarForLoop),
    ("X049", Category::Portability, Severity::Warning, ZshPromptBracket),
    ("X050", Category::Portability, Severity::Warning, CshSyntaxInSh),
    ("X053", Category::Portability, Severity::Warning, ZshAssignmentToZero),
    ("X056", Category::Portability, Severity::Warning, CStyleForInSh),
    ("X055", Category::Portability, Severity::Warning, DollarStringInSh),
    ("X057", Category::Portability, Severity::Warning, LegacyArithmeticInSh),
    ("X062", Category::Portability, Severity::Warning, CStyleForArithmeticInSh),
    ("X071", Category::Portability, Severity::Warning, ArrayKeysInSh),
    ("X081", Category::Portability, Severity::Warning, StarGlobRemovalInSh),
    ("X076", Category::Portability, Severity::Warning, ZshParameterFlag),
    ("X077", Category::Portability, Severity::Warning, NestedDefaultExpansion),
    ("X078", Category::Portability, Severity::Warning, ZshArraySubscriptInCase),
    ("X079", Category::Portability, Severity::Warning, ZshParameterIndexFlag),
    ("X046", Category::Portability, Severity::Warning, ExtglobInTest),
    ("X052", Category::Portability, Severity::Warning, FunctionKeywordInSh),
    ("X058", Category::Portability, Severity::Warning, LexicalComparisonInDoubleBracket),
    ("X059", Category::Portability, Severity::Warning, RegexMatchInSh),
    ("X060", Category::Portability, Severity::Warning, VTestInSh),
    ("X061", Category::Portability, Severity::Warning, ATestInSh),
    ("X063", Category::Portability, Severity::Warning, AmpersandRedirectInSh),
    ("X066", Category::Portability, Severity::Warning, PipeStderrInSh),
    ("X067", Category::Portability, Severity::Warning, HyphenatedFunctionName),
    ("X068", Category::Portability, Severity::Warning, ErrexitTrapInSh),
    ("X069", Category::Portability, Severity::Warning, SignalNameInTrap),
    ("X070", Category::Portability, Severity::Warning, BasePrefixInArithmetic),
    ("X072", Category::Portability, Severity::Warning, UnsetPatternInSh),
    ("X073", Category::Portability, Severity::Warning, OptionTestInSh),
    ("X074", Category::Portability, Severity::Warning, StickyBitTestInSh),
    ("X075", Category::Portability, Severity::Warning, OwnershipTestInSh),
    ("X080", Category::Portability, Severity::Warning, SourceInsideFunctionInSh),
    ("K001", Category::Security, Severity::Warning, RmGlobOnVariablePath),
    ("K002", Category::Security, Severity::Warning, SshLocalExpansion),
    ("K003", Category::Security, Severity::Warning, EvalOnArray),
    ("K004", Category::Security, Severity::Warning, FindExecDirWithShell),
    ("K006", Category::Security, Severity::Warning, RmRootishTarget),
    (
        "K007",
        Category::Security,
        Severity::Warning,
        ChmodWorldWritableSensitivePath
    ),
    ("K008", Category::Security, Severity::Warning, ForkBombPattern),
    ("S001", Category::Style, Severity::Warning, UnquotedExpansion),
    ("S002", Category::Style, Severity::Warning, ReadWithoutRaw),
    ("S003", Category::Style, Severity::Warning, LoopFromCommandOutput),
    ("S004", Category::Style, Severity::Warning, UnquotedCommandSubstitution),
    ("S005", Category::Style, Severity::Warning, LegacyBackticks),
    ("S006", Category::Style, Severity::Warning, LegacyArithmeticExpansion),
    ("S007", Category::Style, Severity::Warning, PrintfFormatVariable),
    ("S008", Category::Style, Severity::Warning, UnquotedArrayExpansion),
    ("S009", Category::Style, Severity::Warning, EchoedCommandSubstitution),
    ("S010", Category::Style, Severity::Warning, ExportCommandSubstitution),
    ("S011", Category::Style, Severity::Warning, CompoundTestOperator),
    ("S012", Category::Style, Severity::Warning, PsGrepPipeline),
    ("S013", Category::Style, Severity::Warning, LsGrepPipeline),
    ("S014", Category::Style, Severity::Warning, UnquotedDollarStar),
    ("S015", Category::Style, Severity::Warning, QuotedDollarStarLoop),
    ("S017", Category::Style, Severity::Warning, UnquotedArraySplit),
    ("S018", Category::Style, Severity::Warning, CommandOutputArraySplit),
    ("S021", Category::Style, Severity::Warning, PositionalArgsInString),
    ("S020", Category::Style, Severity::Warning, SingleIterationLoop),
    ("S032", Category::Style, Severity::Warning, BareCommandNameAssignment),
    ("S036", Category::Style, Severity::Warning, BareRead),
    ("S037", Category::Style, Severity::Warning, RedundantSpacesInEcho),
    ("S038", Category::Style, Severity::Warning, RedundantReturnStatus),
    ("S044", Category::Style, Severity::Warning, EchoToSedSubstitution),
    ("S050", Category::Style, Severity::Hint, UnquotedWordBetweenQuotes),
    ("S051", Category::Style, Severity::Warning, UnquotedTrClass),
    ("S052", Category::Style, Severity::Warning, UnquotedVariableInTest),
    ("S054", Category::Style, Severity::Warning, SuWithoutFlag),
    (
        "S055",
        Category::Style,
        Severity::Warning,
        GlobAssignedToVariable
    ),
    ("S056", Category::Style, Severity::Warning, CommandSubstitutionInAlias),
    ("S057", Category::Style, Severity::Warning, FunctionInAlias),
    ("S058", Category::Style, Severity::Warning, UnquotedPathInMkdir),
    ("S059", Category::Style, Severity::Warning, DeprecatedTempfileCommand),
    ("S060", Category::Style, Severity::Warning, EgrepDeprecated),
    ("S061", Category::Style, Severity::Warning, FgrepDeprecated),
    ("S062", Category::Style, Severity::Warning, DefaultValueInColonAssign),
    ("S064", Category::Style, Severity::Warning, XargsWithInlineReplace),
    ("S065", Category::Style, Severity::Warning, XPrefixInTest),
    ("S067", Category::Style, Severity::Warning, LeadingGlobInGrepPattern),
    ("S068", Category::Style, Severity::Warning, TrapSignalNumbers),
    ("S069", Category::Style, Severity::Hint, GetoptsInvalidFlagHandler),
    ("S070", Category::Style, Severity::Warning, DoubleQuoteNesting),
    ("S071", Category::Style, Severity::Warning, EnvPrefixCommandOnly),
    ("S076", Category::Style, Severity::Warning, MixedQuoteWord),
    (
        "S077",
        Category::Style,
        Severity::Warning,
        BraceVariableBeforeBracket
    ),
    ("S049", Category::Style, Severity::Warning, UnquotedTrRange),
    ("S046", Category::Style, Severity::Warning, LsPipedToXargs),
    ("S047", Category::Style, Severity::Warning, LsInSubstitution),
    (
        "S016",
        Category::Style,
        Severity::Warning,
        EchoInsideCommandSubstitution
    ),
    ("S019", Category::Style, Severity::Warning, GrepOutputInTest),
    ("S022", Category::Style, Severity::Hint, AvoidLetBuiltin),
    ("S033", Category::Style, Severity::Warning, EchoHereDoc),
    ("S034", Category::Style, Severity::Warning, ArrayIndexArithmetic),
    ("S035", Category::Style, Severity::Warning, ArithmeticScoreLine),
    ("S045", Category::Style, Severity::Warning, DollarInArithmetic),
    ("S023", Category::Style, Severity::Warning, EscapedUnderscore),
    ("S024", Category::Style, Severity::Warning, SingleQuoteBackslash),
    ("S025", Category::Style, Severity::Warning, LiteralBackslash),
    ("SH-173", Category::Style, Severity::Warning, BackslashBeforeCommand),
    ("S028", Category::Style, Severity::Warning, SuspectClosingQuote),
    ("S029", Category::Style, Severity::Warning, LiteralBraces),
    ("S030", Category::Style, Severity::Warning, HeredocEndSpace),
    ("S031", Category::Style, Severity::Warning, TrailingDirective),
    (
        "S039",
        Category::Style,
        Severity::Warning,
        LiteralBackslashInSingleQuotes
    ),
    ("S040", Category::Style, Severity::Warning, LiteralControlEscape),
    (
        "S041",
        Category::Style,
        Severity::Warning,
        FunctionBodyWithoutBraces
    ),
    (
        "S066",
        Category::Style,
        Severity::Warning,
        LocalDeclareCombined
    ),
    ("S042", Category::Style, Severity::Warning, IfsEqualsAmbiguity),
    ("S043", Category::Style, Severity::Warning, MissingShebangLine),
    ("S053", Category::Style, Severity::Warning, DuplicateShebangFlag),
    ("S072", Category::Style, Severity::Warning, LinebreakBeforeAnd),
    ("S073", Category::Style, Severity::Warning, SpacedTabstripClose),
    ("S074", Category::Style, Severity::Warning, AmpersandSemicolon),
    ("S075", Category::Style, Severity::Warning, CombineAppends),
    ("S078", Category::Style, Severity::Warning, ShebangShellPolicy),
    ("S079", Category::Style, Severity::Warning, ShebangFormPolicy),
    ("S080", Category::Style, Severity::Warning, ScriptSizeThreshold),
    ("S081", Category::Style, Severity::Warning, MissingFileDescription),
    ("S082", Category::Style, Severity::Warning, TodoFormat),
    ("S083", Category::Style, Severity::Warning, MissingFunctionDoc),
    ("S084", Category::Style, Severity::Warning, FunctionDocContent),
    ("S085", Category::Style, Severity::Warning, MissingMainEntrypoint),
}

pub fn code_to_rule(code: &str) -> Option<Rule> {
    canonical_code_to_rule(code).or(match code {
        "SH-001" => Some(Rule::UnquotedExpansion),
        "SH-002" => Some(Rule::ReadWithoutRaw),
        "SH-003" => Some(Rule::UnusedAssignment),
        "SH-004" => Some(Rule::LoopFromCommandOutput),
        "SH-005" => Some(Rule::UnquotedCommandSubstitution),
        "SH-008" => Some(Rule::LocalVariableInSh),
        "SH-009" => Some(Rule::FunctionKeyword),
        "SH-010" => Some(Rule::BashCaseFallthrough),
        "SH-011" => Some(Rule::ProcessSubstitution),
        "SH-012" => Some(Rule::AnsiCQuoting),
        "SH-015" => Some(Rule::BraceExpansion),
        "SH-016" => Some(Rule::HereString),
        "SH-018" => Some(Rule::ArrayAssignment),
        "SH-023" => Some(Rule::IndirectExpansion),
        "SH-024" => Some(Rule::ArrayReference),
        "SH-031" => Some(Rule::SubstringExpansion),
        "SH-032" => Some(Rule::CaseModificationExpansion),
        "SH-033" => Some(Rule::ReplacementExpansion),
        "SH-053" => Some(Rule::BashFileSlurp),
        "SH-013" => Some(Rule::StandaloneArithmetic),
        "SH-014" => Some(Rule::SelectLoop),
        "SH-019" => Some(Rule::Coproc),
        "SH-079" => Some(Rule::AvoidLetBuiltin),
        "SH-020" => Some(Rule::LetCommand),
        "SH-021" => Some(Rule::DeclareCommand),
        "SH-289" => Some(Rule::LocalDeclareCombined),
        "SH-029" => Some(Rule::PipefailOption),
        "SH-030" => Some(Rule::WaitOption),
        "SH-022" => Some(Rule::TrapErr),
        "SH-080" => Some(Rule::SourceBuiltinInSh),
        "SH-081" => Some(Rule::PrintfQFormatInSh),
        "SH-054" => Some(Rule::EchoFlags),
        "SH-058" => Some(Rule::TrLowerRange),
        "SH-059" => Some(Rule::TrUpperRange),
        "SH-061" => Some(Rule::EchoBackslashEscapes),
        "SH-226" => Some(Rule::FunctionKeywordInSh),
        "SH-274" => Some(Rule::HyphenatedFunctionName),
        "SH-234" => Some(Rule::IfsSetToLiteralBackslashN),
        "SH-236" => Some(Rule::GlobInTestDirectory),
        "SH-284" => Some(Rule::MalformedArithmeticInCondition),
        "SH-287" => Some(Rule::ExprSubstrInTest),
        "SH-288" => Some(Rule::StringComparedWithEq),
        "SH-290" => Some(Rule::AFlagInDoubleBracket),
        "SH-279" => Some(Rule::UnsetPatternInSh),
        "SH-291" => Some(Rule::NestedDefaultExpansion),
        "SH-304" => Some(Rule::SourceInsideFunctionInSh),
        "SH-275" => Some(Rule::ErrexitTrapInSh),
        "SH-276" => Some(Rule::SignalNameInTrap),
        "SH-297" => Some(Rule::TrapSignalNumbers),
        "SH-277" => Some(Rule::BasePrefixInArithmetic),
        "SH-034" => Some(Rule::LegacyBackticks),
        "SH-035" => Some(Rule::LegacyArithmeticExpansion),
        "SH-078" => Some(Rule::LeadingZeroArithmetic),
        "SH-157" => Some(Rule::ArrayIndexArithmetic),
        "SH-161" => Some(Rule::ArithmeticScoreLine),
        "SH-197" => Some(Rule::DollarInArithmetic),
        "SH-198" => Some(Rule::LsPipedToXargs),
        "SH-203" => Some(Rule::UnquotedTrRange),
        "SH-082" => Some(Rule::EscapedUnderscore),
        "SH-208" => Some(Rule::UnquotedTrClass),
        "SH-212" => Some(Rule::UnquotedVariableInTest),
        "SH-087" => Some(Rule::SingleQuoteBackslash),
        "SH-172" => Some(Rule::LiteralBackslashInSingleQuotes),
        "SH-185" => Some(Rule::IfsEqualsAmbiguity),
        "SH-088" => Some(Rule::LiteralBackslash),
        "SH-258" => Some(Rule::AssignmentToNumericVariable),
        "SH-259" => Some(Rule::PlusPrefixInAssignment),
        "SH-307" => Some(Rule::AppendWithEscapedQuotes),
        "SH-025" => Some(Rule::DynamicSourcePath),
        "SH-026" => Some(Rule::UntrackedSourceFile),
        "SH-027" => Some(Rule::UncheckedDirectoryChange),
        "SH-228" => Some(Rule::FunctionCalledWithoutArgs),
        "SH-292" => Some(Rule::FunctionReferencesUnsetParam),
        "SH-295" => Some(Rule::UncheckedDirectoryChangeInFunction),
        "SH-296" => Some(Rule::ContinueOutsideLoopInFunction),
        "SH-308" => Some(Rule::VariableAsCommandName),
        "SH-311" => Some(Rule::ArrayToStringConversion),
        "SH-337" => Some(Rule::BrokenAssocKey),
        "SH-347" => Some(Rule::SubshellSideEffect),
        "SH-340" => Some(Rule::CommaArrayElements),
        "SH-351" => Some(Rule::PossibleVariableMisspelling),
        "SH-036" => Some(Rule::SingleQuotedLiteral),
        "SH-037" => Some(Rule::PrintfFormatVariable),
        "SH-038" => Some(Rule::UnquotedArrayExpansion),
        "SH-039" => Some(Rule::UndefinedVariable),
        "SH-040" => Some(Rule::EchoedCommandSubstitution),
        "SH-051" => Some(Rule::CompoundTestOperator),
        "SH-170" => Some(Rule::RedundantReturnStatus),
        "SH-168" => Some(Rule::RedundantSpacesInEcho),
        "SH-196" => Some(Rule::EchoToSedSubstitution),
        "SH-205" => Some(Rule::UnquotedWordBetweenQuotes),
        "SH-066" => Some(Rule::EchoInsideCommandSubstitution),
        "SH-199" => Some(Rule::LsInSubstitution),
        "SH-163" => Some(Rule::BareRead),
        "SH-245" => Some(Rule::DeprecatedTempfileCommand),
        "SH-247" => Some(Rule::EgrepDeprecated),
        "SH-248" => Some(Rule::FgrepDeprecated),
        "SH-255" => Some(Rule::XargsWithInlineReplace),
        "SH-256" => Some(Rule::XPrefixInTest),
        "SH-306" => Some(Rule::DoubleQuoteNesting),
        "SH-309" => Some(Rule::EnvPrefixCommandOnly),
        "SH-350" => Some(Rule::MixedQuoteWord),
        "SH-354" => Some(Rule::BraceVariableBeforeBracket),
        "SH-071" => Some(Rule::GrepOutputInTest),
        "SH-076" => Some(Rule::SingleIterationLoop),
        "SH-128" => Some(Rule::BareCommandNameAssignment),
        "SH-041" => Some(Rule::FindOutputToXargs),
        "SH-042" => Some(Rule::TrapStringExpansion),
        "SH-043" => Some(Rule::QuotedBashRegex),
        "SH-044" => Some(Rule::RmGlobOnVariablePath),
        "SH-047" => Some(Rule::SshLocalExpansion),
        "SH-151" => Some(Rule::EvalOnArray),
        "SH-324" => Some(Rule::RmRootishTarget),
        "SH-325" => Some(Rule::ChmodWorldWritableSensitivePath),
        "SH-326" => Some(Rule::ForkBombPattern),
        "SH-045" => Some(Rule::ChainedTestBranches),
        "C079" => Some(Rule::ChainedTestBranches),
        "SH-201" => Some(Rule::ChainedTestBranches),
        "SH-046" => Some(Rule::LineOrientedInput),
        "SH-048" => Some(Rule::LeadingGlobArgument),
        "SH-049" => Some(Rule::FindOutputLoop),
        "SH-050" => Some(Rule::ExportCommandSubstitution),
        "SH-135" => Some(Rule::EchoHereDoc),
        "SH-052" => Some(Rule::LocalTopLevel),
        "SH-060" => Some(Rule::SudoRedirectionOrder),
        "SH-065" => Some(Rule::StrayClosingKeyword),
        "SH-146" => Some(Rule::AssignSpecialZero),
        "SH-147" => Some(Rule::SpaceyAssign),
        "SH-069" => Some(Rule::ConstantComparisonTest),
        "SH-070" => Some(Rule::LoopControlOutsideLoop),
        "SH-072" => Some(Rule::LiteralUnaryStringTest),
        "SH-073" => Some(Rule::TruthyLiteralTest),
        "SH-074" => Some(Rule::ConstantCaseSubject),
        "SH-075" => Some(Rule::EmptyTest),
        "SH-084" => Some(Rule::AssignmentSpacing),
        "SH-098" => Some(Rule::MissingBracketSpace),
        "SH-102" => Some(Rule::JammedTestBracket),
        "SH-104" => Some(Rule::IndentedHeredocClose),
        "SH-133" => Some(Rule::DiffMarkerLine),
        "SH-134" => Some(Rule::PipeToKill),
        "SH-086" => Some(Rule::PositionalTenBraces),
        "SH-091" => Some(Rule::BareDoneWord),
        "SH-100" => Some(Rule::MissingSpaceBeforeBracketClose),
        "SH-105" => Some(Rule::UnterminatedIf),
        "SH-106" => Some(Rule::MissingFi),
        "SH-107" => Some(Rule::FunctionParamsInSh),
        "SH-109" => Some(Rule::BrokenTestEnd),
        "SH-110" => Some(Rule::BrokenTestParse),
        "SH-111" => Some(Rule::ExtglobCase),
        "SH-182" => Some(Rule::ExtglobInCasePattern),
        "SH-261" => Some(Rule::ExtglobInSh),
        "SH-272" => Some(Rule::CaretNegationInBracket),
        "SH-207" => Some(Rule::EscapedNegationInTest),
        "SH-213" => Some(Rule::GreaterThanInTest),
        "SH-214" => Some(Rule::StringComparisonForVersion),
        "SH-215" => Some(Rule::MixedAndOrInCondition),
        "SH-216" => Some(Rule::QuotedCommandInTest),
        "SH-217" => Some(Rule::GlobInTestComparison),
        "SH-219" => Some(Rule::TildeInStringComparison),
        "SH-220" => Some(Rule::IfDollarCommand),
        "SH-221" => Some(Rule::BacktickInCommandPosition),
        "SH-112" => Some(Rule::ElseIf),
        "SH-113" => Some(Rule::OpenDoubleQuote),
        "SH-114" => Some(Rule::SuspectClosingQuote),
        "SH-115" => Some(Rule::LinebreakInTest),
        "SH-116" => Some(Rule::LiteralBraces),
        "SH-119" => Some(Rule::HeredocEndSpace),
        "SH-120" => Some(Rule::TrailingDirective),
        "SH-329" => Some(Rule::LinebreakBeforeAnd),
        "SH-330" => Some(Rule::SpacedTabstripClose),
        "SH-335" => Some(Rule::AmpersandSemicolon),
        "SH-349" => Some(Rule::CombineAppends),
        "SH-339" => Some(Rule::SubshellLocalAssignment),
        "SH-121" => Some(Rule::CStyleComment),
        "SH-123" => Some(Rule::CPrototypeFragment),
        "SH-129" => Some(Rule::BadRedirectionFdOrder),
        "SH-130" => Some(Rule::BareGlobCommandPath),
        "SH-141" => Some(Rule::InvalidExitStatus),
        "SH-142" => Some(Rule::CasePatternVar),
        "SH-143" => Some(Rule::TautologyChain),
        "SH-144" => Some(Rule::ArithmeticRedirectionTarget),
        "SH-145" => Some(Rule::DuplicateRedirect),
        "SH-148" => Some(Rule::BareSlashMarker),
        "SH-152" => Some(Rule::PatternWithVariable),
        "SH-155" => Some(Rule::StatusCaptureAfterBranchTest),
        "SH-017" => Some(Rule::AmpersandRedirection),
        "SH-028" => Some(Rule::BraceFdRedirection),
        "SH-270" => Some(Rule::AmpersandRedirectInSh),
        "SH-273" => Some(Rule::PipeStderrInSh),
        "SH-159" => Some(Rule::SubstWithRedirect),
        "SH-160" => Some(Rule::SubstWithRedirectErr),
        "SH-165" => Some(Rule::RedirectToCommandName),
        "SH-285" => Some(Rule::RedirectBeforePipe),
        "SH-166" => Some(Rule::NonAbsoluteShebang),
        "SH-167" => Some(Rule::TemplateBraceInCommand),
        "SH-169" => Some(Rule::NestedParameterExpansion),
        "SH-171" => Some(Rule::OverwrittenFunction),
        "SH-175" => Some(Rule::IfMissingThen),
        "SH-176" => Some(Rule::ElseWithoutThen),
        "SH-177" => Some(Rule::MissingSemicolonBeforeBrace),
        "SH-178" => Some(Rule::EmptyFunctionBody),
        "SH-179" => Some(Rule::BareClosingBrace),
        "SH-186" => Some(Rule::BackslashBeforeClosingBacktick),
        "SH-187" => Some(Rule::PositionalParamAsOperator),
        "SH-211" => Some(Rule::StderrBeforeStdoutRedirect),
        "SH-222" => Some(Rule::RedirectClobbersInput),
        "SH-188" => Some(Rule::DoubleParenGrouping),
        "SH-189" => Some(Rule::UnicodeQuoteInString),
        "SH-190" => Some(Rule::MissingShebangLine),
        "SH-191" => Some(Rule::IndentedShebang),
        "SH-192" => Some(Rule::SpaceAfterHashBang),
        "SH-193" => Some(Rule::ShebangNotOnFirstLine),
        "SH-223" => Some(Rule::DuplicateShebangFlag),
        "SH-224" => Some(Rule::AssignmentLooksLikeComparison),
        "SH-225" => Some(Rule::SuspiciousBracketGlob),
        "SH-227" => Some(Rule::SuWithoutFlag),
        "SH-231" => Some(Rule::GlobAssignedToVariable),
        "SH-194" => Some(Rule::CommentedContinuationLine),
        "SH-195" => Some(Rule::SubshellInArithmetic),
        "SH-200" => Some(Rule::UnquotedGlobsInFind),
        "SH-204" => Some(Rule::GlobInGrepPattern),
        "SH-206" => Some(Rule::GlobInStringComparison),
        "SH-209" => Some(Rule::GlobInFindSubstitution),
        "SH-210" => Some(Rule::UnquotedGrepRegex),
        "SH-229" => Some(Rule::SetFlagsWithoutDashes),
        "SH-230" => Some(Rule::QuotedArraySlice),
        "SH-232" => Some(Rule::QuotedBashSource),
        "SH-233" => Some(Rule::CommandSubstitutionInAlias),
        "SH-235" => Some(Rule::FunctionInAlias),
        "SH-237" => Some(Rule::FindOrWithoutGrouping),
        "SH-238" => Some(Rule::NonShellSyntaxInScript),
        "SH-239" => Some(Rule::ExportWithPositionalParams),
        "SH-240" => Some(Rule::UnquotedPathInMkdir),
        "SH-249" => Some(Rule::AtSignInStringCompare),
        "SH-250" => Some(Rule::ArraySliceInComparison),
        "SH-251" => Some(Rule::DefaultValueInColonAssign),
        "SH-241" => Some(Rule::AppendToArrayAsString),
        "SH-242" => Some(Rule::DollarQuestionAfterCommand),
        "SH-243" => Some(Rule::UnsetAssociativeArrayElement),
        "SH-244" => Some(Rule::MapfileProcessSubstitution),
        "SH-254" => Some(Rule::GlobWithExpansionInLoop),
        "SH-293" => Some(Rule::UnreachableAfterExit),
        "SH-298" => Some(Rule::UnusedHeredoc),
        "SH-300" => Some(Rule::GetoptsInvalidFlagHandler),
        "SH-301" => Some(Rule::CaseGlobReachability),
        "SH-302" => Some(Rule::CaseDefaultBeforeGlob),
        "SH-312" => Some(Rule::GetoptsOptionNotInCase),
        "SH-313" => Some(Rule::CaseArmNotInGetopts),
        "SH-318" => Some(Rule::HeredocMissingEnd),
        "SH-310" => Some(Rule::EnvPrefixExpansionOnly),
        "SH-055" => Some(Rule::ExprArithmetic),
        "SH-056" => Some(Rule::PsGrepPipeline),
        "SH-057" => Some(Rule::LsGrepPipeline),
        "SH-062" => Some(Rule::UnquotedDollarStar),
        "SH-063" => Some(Rule::QuotedDollarStarLoop),
        "SH-067" => Some(Rule::UnquotedArraySplit),
        "SH-068" => Some(Rule::CommandOutputArraySplit),
        "SH-294" => Some(Rule::LeadingGlobInGrepPattern),
        "SH-077" => Some(Rule::PositionalArgsInString),
        "SH-064" => Some(Rule::GrepCountPipeline),
        "SH-137" => Some(Rule::SingleTestSubshell),
        "SH-164" => Some(Rule::SubshellTestGroup),
        "SH-006" => Some(Rule::DoubleBracketInSh),
        "SH-007" => Some(Rule::TestEqualityOperator),
        "SH-093" => Some(Rule::IfElifBashTest),
        "SH-108" => Some(Rule::ZshRedirPipe),
        "SH-124" => Some(Rule::ZshBraceIf),
        "SH-125" => Some(Rule::ZshAlwaysBlock),
        "SH-140" => Some(Rule::SourcedWithArgs),
        "SH-153" => Some(Rule::ZshFlagExpansion),
        "SH-154" => Some(Rule::NestedZshSubstitution),
        "SH-158" => Some(Rule::PlusEqualsAppend),
        "SH-180" => Some(Rule::MultiVarForLoop),
        "SH-181" => Some(Rule::FunctionBodyWithoutBraces),
        "SH-183" => Some(Rule::ZshPromptBracket),
        "SH-184" => Some(Rule::CshSyntaxInSh),
        "SH-218" => Some(Rule::ZshNestedExpansion),
        "SH-260" => Some(Rule::ZshAssignmentToZero),
        "SH-262" => Some(Rule::DollarStringInSh),
        "SH-263" => Some(Rule::CStyleForInSh),
        "SH-264" => Some(Rule::LegacyArithmeticInSh),
        "SH-269" => Some(Rule::CStyleForArithmeticInSh),
        "SH-278" => Some(Rule::ArrayKeysInSh),
        "SH-305" => Some(Rule::StarGlobRemovalInSh),
        "SH-286" => Some(Rule::ZshParameterFlag),
        "SH-299" => Some(Rule::ZshArraySubscriptInCase),
        "SH-303" => Some(Rule::ZshParameterIndexFlag),
        "SH-126" => Some(Rule::ArraySubscriptTest),
        "SH-127" => Some(Rule::ArraySubscriptCondition),
        "SH-174" => Some(Rule::ExtglobInTest),
        "SH-265" => Some(Rule::LexicalComparisonInDoubleBracket),
        "SH-266" => Some(Rule::RegexMatchInSh),
        "SH-267" => Some(Rule::VTestInSh),
        "SH-268" => Some(Rule::ATestInSh),
        "SH-280" => Some(Rule::OptionTestInSh),
        "SH-281" => Some(Rule::StickyBitTestInSh),
        "SH-282" => Some(Rule::OwnershipTestInSh),
        "SH-283" => Some(Rule::FindExecDirWithShell),
        "SH-314" => Some(Rule::LocalCrossReference),
        "SH-315" => Some(Rule::UnicodeSingleQuoteInSingleQuotes),
        "SH-319" => Some(Rule::SpacedAssignment),
        "SH-320" => Some(Rule::BadVarName),
        "SH-321" => Some(Rule::LoopWithoutEnd),
        "SH-322" => Some(Rule::MissingDoneInForLoop),
        "SH-327" => Some(Rule::DanglingElse),
        "SH-332" => Some(Rule::HeredocCloserNotAlone),
        "SH-333" => Some(Rule::MisquotedHeredocClose),
        "SH-334" => Some(Rule::UntilMissingDo),
        "SH-353" => Some(Rule::IfBracketGlued),
        _ => None,
    })
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::BTreeSet;

    #[test]
    fn rule_codes_are_unique() {
        let codes = Rule::iter().map(Rule::code).collect::<BTreeSet<_>>();
        assert_eq!(codes.len(), Rule::COUNT);
    }

    #[test]
    fn resolves_legacy_shuck_aliases() {
        assert_eq!(code_to_rule("SH-001"), Some(Rule::UnquotedExpansion));
        assert_eq!(code_to_rule("SH-002"), Some(Rule::ReadWithoutRaw));
        assert_eq!(code_to_rule("SH-003"), Some(Rule::UnusedAssignment));
        assert_eq!(code_to_rule("SH-004"), Some(Rule::LoopFromCommandOutput));
        assert_eq!(
            code_to_rule("SH-005"),
            Some(Rule::UnquotedCommandSubstitution)
        );
        assert_eq!(code_to_rule("SH-010"), Some(Rule::BashCaseFallthrough));
        assert_eq!(code_to_rule("SH-013"), Some(Rule::StandaloneArithmetic));
        assert_eq!(code_to_rule("SH-014"), Some(Rule::SelectLoop));
        assert_eq!(code_to_rule("SH-019"), Some(Rule::Coproc));
        assert_eq!(code_to_rule("SH-034"), Some(Rule::LegacyBackticks));
        assert_eq!(
            code_to_rule("SH-035"),
            Some(Rule::LegacyArithmeticExpansion)
        );
        assert_eq!(code_to_rule("SH-055"), Some(Rule::ExprArithmetic));
        assert_eq!(code_to_rule("SH-056"), Some(Rule::PsGrepPipeline));
        assert_eq!(code_to_rule("SH-057"), Some(Rule::LsGrepPipeline));
        assert_eq!(code_to_rule("SH-107"), Some(Rule::FunctionParamsInSh));
        assert_eq!(code_to_rule("S014"), Some(Rule::UnquotedDollarStar));
        assert_eq!(code_to_rule("SH-062"), Some(Rule::UnquotedDollarStar));
        assert_eq!(code_to_rule("S015"), Some(Rule::QuotedDollarStarLoop));
        assert_eq!(code_to_rule("SH-063"), Some(Rule::QuotedDollarStarLoop));
        assert_eq!(code_to_rule("S017"), Some(Rule::UnquotedArraySplit));
        assert_eq!(code_to_rule("SH-067"), Some(Rule::UnquotedArraySplit));
        assert_eq!(code_to_rule("S018"), Some(Rule::CommandOutputArraySplit));
        assert_eq!(code_to_rule("SH-068"), Some(Rule::CommandOutputArraySplit));
        assert_eq!(code_to_rule("S067"), Some(Rule::LeadingGlobInGrepPattern));
        assert_eq!(code_to_rule("SH-294"), Some(Rule::LeadingGlobInGrepPattern));
        assert_eq!(code_to_rule("S068"), Some(Rule::TrapSignalNumbers));
        assert_eq!(code_to_rule("SH-297"), Some(Rule::TrapSignalNumbers));
        assert_eq!(code_to_rule("S069"), Some(Rule::GetoptsInvalidFlagHandler));
        assert_eq!(
            code_to_rule("SH-300"),
            Some(Rule::GetoptsInvalidFlagHandler)
        );
        assert_eq!(code_to_rule("S071"), Some(Rule::EnvPrefixCommandOnly));
        assert_eq!(code_to_rule("SH-309"), Some(Rule::EnvPrefixCommandOnly));
        assert_eq!(code_to_rule("S076"), Some(Rule::MixedQuoteWord));
        assert_eq!(code_to_rule("SH-350"), Some(Rule::MixedQuoteWord));
        assert_eq!(code_to_rule("S077"), Some(Rule::BraceVariableBeforeBracket));
        assert_eq!(
            code_to_rule("SH-354"),
            Some(Rule::BraceVariableBeforeBracket)
        );
        assert_eq!(code_to_rule("S021"), Some(Rule::PositionalArgsInString));
        assert_eq!(code_to_rule("SH-077"), Some(Rule::PositionalArgsInString));
        assert_eq!(code_to_rule("S020"), Some(Rule::SingleIterationLoop));
        assert_eq!(code_to_rule("SH-076"), Some(Rule::SingleIterationLoop));
        assert_eq!(code_to_rule("S032"), Some(Rule::BareCommandNameAssignment));
        assert_eq!(
            code_to_rule("SH-128"),
            Some(Rule::BareCommandNameAssignment)
        );
        assert_eq!(code_to_rule("SH-146"), Some(Rule::AssignSpecialZero));
        assert_eq!(code_to_rule("SH-147"), Some(Rule::SpaceyAssign));
        assert_eq!(code_to_rule("SH-064"), Some(Rule::GrepCountPipeline));
        assert_eq!(code_to_rule("SH-137"), Some(Rule::SingleTestSubshell));
        assert_eq!(code_to_rule("SH-164"), Some(Rule::SubshellTestGroup));
        assert_eq!(code_to_rule("S023"), Some(Rule::EscapedUnderscore));
        assert_eq!(code_to_rule("SH-082"), Some(Rule::EscapedUnderscore));
        assert_eq!(code_to_rule("S034"), Some(Rule::ArrayIndexArithmetic));
        assert_eq!(code_to_rule("SH-157"), Some(Rule::ArrayIndexArithmetic));
        assert_eq!(code_to_rule("S035"), Some(Rule::ArithmeticScoreLine));
        assert_eq!(code_to_rule("SH-161"), Some(Rule::ArithmeticScoreLine));
        assert_eq!(
            code_to_rule("SH-228"),
            Some(Rule::FunctionCalledWithoutArgs)
        );
        assert_eq!(
            code_to_rule("SH-292"),
            Some(Rule::FunctionReferencesUnsetParam)
        );
        assert_eq!(code_to_rule("S045"), Some(Rule::DollarInArithmetic));
        assert_eq!(code_to_rule("SH-197"), Some(Rule::DollarInArithmetic));
        assert_eq!(code_to_rule("S046"), Some(Rule::LsPipedToXargs));
        assert_eq!(code_to_rule("SH-198"), Some(Rule::LsPipedToXargs));
        assert_eq!(code_to_rule("S047"), Some(Rule::LsInSubstitution));
        assert_eq!(code_to_rule("SH-199"), Some(Rule::LsInSubstitution));
        assert_eq!(code_to_rule("S055"), Some(Rule::GlobAssignedToVariable));
        assert_eq!(code_to_rule("SH-231"), Some(Rule::GlobAssignedToVariable));
        assert_eq!(code_to_rule("SH-203"), Some(Rule::UnquotedTrRange));
        assert_eq!(code_to_rule("S024"), Some(Rule::SingleQuoteBackslash));
        assert_eq!(code_to_rule("SH-087"), Some(Rule::SingleQuoteBackslash));
        assert_eq!(code_to_rule("S052"), Some(Rule::UnquotedVariableInTest));
        assert_eq!(code_to_rule("SH-208"), Some(Rule::UnquotedTrClass));
        assert_eq!(code_to_rule("SH-212"), Some(Rule::UnquotedVariableInTest));
        assert_eq!(code_to_rule("S058"), Some(Rule::UnquotedPathInMkdir));
        assert_eq!(code_to_rule("S062"), Some(Rule::DefaultValueInColonAssign));
        assert_eq!(code_to_rule("S064"), Some(Rule::XargsWithInlineReplace));
        assert_eq!(code_to_rule("S011"), Some(Rule::CompoundTestOperator));
        assert_eq!(code_to_rule("S065"), Some(Rule::XPrefixInTest));
        assert_eq!(code_to_rule("SH-051"), Some(Rule::CompoundTestOperator));
        assert_eq!(
            code_to_rule("SH-251"),
            Some(Rule::DefaultValueInColonAssign)
        );
        assert_eq!(code_to_rule("SH-025"), Some(Rule::DynamicSourcePath));
        assert_eq!(code_to_rule("SH-256"), Some(Rule::XPrefixInTest));
        assert_eq!(
            code_to_rule("S039"),
            Some(Rule::LiteralBackslashInSingleQuotes)
        );
        assert_eq!(code_to_rule("S038"), Some(Rule::RedundantReturnStatus));
        assert_eq!(code_to_rule("SH-170"), Some(Rule::RedundantReturnStatus));
        assert_eq!(
            code_to_rule("SH-172"),
            Some(Rule::LiteralBackslashInSingleQuotes)
        );
        assert_eq!(code_to_rule("S026"), None);
        assert_eq!(code_to_rule("SH-092"), None);
        assert_eq!(code_to_rule("S040"), Some(Rule::LiteralControlEscape));
        assert_eq!(code_to_rule("SH-173"), Some(Rule::BackslashBeforeCommand));
        assert_eq!(code_to_rule("S041"), Some(Rule::FunctionBodyWithoutBraces));
        assert_eq!(
            code_to_rule("SH-181"),
            Some(Rule::FunctionBodyWithoutBraces)
        );
        assert_eq!(code_to_rule("S066"), Some(Rule::LocalDeclareCombined));
        assert_eq!(code_to_rule("SH-289"), Some(Rule::LocalDeclareCombined));
        assert_eq!(code_to_rule("SH-026"), Some(Rule::UntrackedSourceFile));
        assert_eq!(code_to_rule("SH-036"), Some(Rule::SingleQuotedLiteral));
        assert_eq!(code_to_rule("SH-037"), Some(Rule::PrintfFormatVariable));
        assert_eq!(code_to_rule("SH-038"), Some(Rule::UnquotedArrayExpansion));
        assert_eq!(code_to_rule("SH-039"), Some(Rule::UndefinedVariable));
        assert_eq!(
            code_to_rule("SH-040"),
            Some(Rule::EchoedCommandSubstitution)
        );
        assert_eq!(
            code_to_rule("SH-066"),
            Some(Rule::EchoInsideCommandSubstitution)
        );
        assert_eq!(code_to_rule("SH-168"), Some(Rule::RedundantSpacesInEcho));
        assert_eq!(code_to_rule("SH-196"), Some(Rule::EchoToSedSubstitution));
        assert_eq!(code_to_rule("SH-163"), Some(Rule::BareRead));
        assert_eq!(code_to_rule("SH-071"), Some(Rule::GrepOutputInTest));
        assert_eq!(code_to_rule("SH-041"), Some(Rule::FindOutputToXargs));
        assert_eq!(code_to_rule("SH-042"), Some(Rule::TrapStringExpansion));
        assert_eq!(code_to_rule("SH-043"), Some(Rule::QuotedBashRegex));
        assert_eq!(code_to_rule("SH-044"), Some(Rule::RmGlobOnVariablePath));
        assert_eq!(code_to_rule("SH-047"), Some(Rule::SshLocalExpansion));
        assert_eq!(code_to_rule("SH-324"), Some(Rule::RmRootishTarget));
        assert_eq!(
            code_to_rule("SH-325"),
            Some(Rule::ChmodWorldWritableSensitivePath)
        );
        assert_eq!(code_to_rule("SH-326"), Some(Rule::ForkBombPattern));
        assert_eq!(code_to_rule("SH-045"), Some(Rule::ChainedTestBranches));
        assert_eq!(code_to_rule("C079"), Some(Rule::ChainedTestBranches));
        assert_eq!(code_to_rule("SH-201"), Some(Rule::ChainedTestBranches));
        assert_eq!(code_to_rule("SH-046"), Some(Rule::LineOrientedInput));
        assert_eq!(code_to_rule("SH-049"), Some(Rule::FindOutputLoop));
        assert_eq!(
            code_to_rule("SH-050"),
            Some(Rule::ExportCommandSubstitution)
        );
        assert_eq!(code_to_rule("S033"), Some(Rule::EchoHereDoc));
        assert_eq!(code_to_rule("SH-135"), Some(Rule::EchoHereDoc));
        assert_eq!(code_to_rule("SH-052"), Some(Rule::LocalTopLevel));
        assert_eq!(code_to_rule("SH-060"), Some(Rule::SudoRedirectionOrder));
        assert_eq!(code_to_rule("SH-081"), Some(Rule::PrintfQFormatInSh));
        assert_eq!(code_to_rule("SH-275"), Some(Rule::ErrexitTrapInSh));
        assert_eq!(code_to_rule("SH-276"), Some(Rule::SignalNameInTrap));
        assert_eq!(code_to_rule("SH-277"), Some(Rule::BasePrefixInArithmetic));
        assert_eq!(code_to_rule("SH-069"), Some(Rule::ConstantComparisonTest));
        assert_eq!(code_to_rule("SH-070"), Some(Rule::LoopControlOutsideLoop));
        assert_eq!(code_to_rule("SH-072"), Some(Rule::LiteralUnaryStringTest));
        assert_eq!(code_to_rule("SH-073"), Some(Rule::TruthyLiteralTest));
        assert_eq!(code_to_rule("SH-074"), Some(Rule::ConstantCaseSubject));
        assert_eq!(code_to_rule("SH-075"), Some(Rule::EmptyTest));
        assert_eq!(code_to_rule("C023"), Some(Rule::LeadingZeroArithmetic));
        assert_eq!(code_to_rule("SH-078"), Some(Rule::LeadingZeroArithmetic));
        assert_eq!(code_to_rule("C024"), Some(Rule::AssignmentSpacing));
        assert_eq!(code_to_rule("SH-084"), Some(Rule::AssignmentSpacing));
        assert_eq!(code_to_rule("C030"), Some(Rule::MissingBracketSpace));
        assert_eq!(code_to_rule("SH-098"), Some(Rule::MissingBracketSpace));
        assert_eq!(
            code_to_rule("C031"),
            Some(Rule::MissingSpaceBeforeBracketClose)
        );
        assert_eq!(
            code_to_rule("SH-100"),
            Some(Rule::MissingSpaceBeforeBracketClose)
        );
        assert_eq!(code_to_rule("C032"), Some(Rule::JammedTestBracket));
        assert_eq!(code_to_rule("SH-102"), Some(Rule::JammedTestBracket));
        assert_eq!(code_to_rule("C033"), Some(Rule::IndentedHeredocClose));
        assert_eq!(code_to_rule("SH-104"), Some(Rule::IndentedHeredocClose));
        assert_eq!(code_to_rule("SH-134"), Some(Rule::PipeToKill));
        assert_eq!(code_to_rule("SH-086"), Some(Rule::PositionalTenBraces));
        assert_eq!(code_to_rule("C027"), Some(Rule::BareDoneWord));
        assert_eq!(code_to_rule("SH-091"), Some(Rule::BareDoneWord));
        assert_eq!(code_to_rule("C034"), Some(Rule::UnterminatedIf));
        assert_eq!(code_to_rule("SH-105"), Some(Rule::UnterminatedIf));
        assert_eq!(code_to_rule("C035"), Some(Rule::MissingFi));
        assert_eq!(code_to_rule("SH-106"), Some(Rule::MissingFi));
        assert_eq!(code_to_rule("C036"), Some(Rule::BrokenTestEnd));
        assert_eq!(code_to_rule("SH-109"), Some(Rule::BrokenTestEnd));
        assert_eq!(code_to_rule("C037"), Some(Rule::BrokenTestParse));
        assert_eq!(code_to_rule("SH-110"), Some(Rule::BrokenTestParse));
        assert_eq!(code_to_rule("SH-111"), Some(Rule::ExtglobCase));
        assert_eq!(code_to_rule("SH-182"), Some(Rule::ExtglobInCasePattern));
        assert_eq!(code_to_rule("SH-261"), Some(Rule::ExtglobInSh));
        assert_eq!(code_to_rule("SH-272"), Some(Rule::CaretNegationInBracket));
        assert_eq!(code_to_rule("C038"), Some(Rule::ElseIf));
        assert_eq!(code_to_rule("SH-112"), Some(Rule::ElseIf));
        assert_eq!(code_to_rule("C039"), Some(Rule::OpenDoubleQuote));
        assert_eq!(code_to_rule("SH-113"), Some(Rule::OpenDoubleQuote));
        assert_eq!(code_to_rule("S028"), Some(Rule::SuspectClosingQuote));
        assert_eq!(code_to_rule("SH-114"), Some(Rule::SuspectClosingQuote));
        assert_eq!(
            code_to_rule("SH-245"),
            Some(Rule::DeprecatedTempfileCommand)
        );
        assert_eq!(code_to_rule("SH-247"), Some(Rule::EgrepDeprecated));
        assert_eq!(code_to_rule("SH-248"), Some(Rule::FgrepDeprecated));
        assert_eq!(code_to_rule("SH-255"), Some(Rule::XargsWithInlineReplace));
        assert_eq!(code_to_rule("S029"), Some(Rule::LiteralBraces));
        assert_eq!(code_to_rule("SH-116"), Some(Rule::LiteralBraces));
        assert_eq!(code_to_rule("S030"), Some(Rule::HeredocEndSpace));
        assert_eq!(code_to_rule("SH-119"), Some(Rule::HeredocEndSpace));
        assert_eq!(code_to_rule("S031"), Some(Rule::TrailingDirective));
        assert_eq!(code_to_rule("SH-120"), Some(Rule::TrailingDirective));
        assert_eq!(code_to_rule("S072"), Some(Rule::LinebreakBeforeAnd));
        assert_eq!(code_to_rule("SH-329"), Some(Rule::LinebreakBeforeAnd));
        assert_eq!(code_to_rule("S073"), Some(Rule::SpacedTabstripClose));
        assert_eq!(code_to_rule("SH-330"), Some(Rule::SpacedTabstripClose));
        assert_eq!(code_to_rule("S074"), Some(Rule::AmpersandSemicolon));
        assert_eq!(code_to_rule("SH-335"), Some(Rule::AmpersandSemicolon));
        assert_eq!(code_to_rule("S075"), Some(Rule::CombineAppends));
        assert_eq!(code_to_rule("SH-349"), Some(Rule::CombineAppends));
        assert_eq!(code_to_rule("S085"), Some(Rule::MissingMainEntrypoint));
        assert_eq!(code_to_rule("C040"), Some(Rule::LinebreakInTest));
        assert_eq!(code_to_rule("SH-115"), Some(Rule::LinebreakInTest));
        assert_eq!(code_to_rule("C041"), Some(Rule::CStyleComment));
        assert_eq!(code_to_rule("SH-121"), Some(Rule::CStyleComment));
        assert_eq!(code_to_rule("C042"), Some(Rule::CPrototypeFragment));
        assert_eq!(code_to_rule("SH-123"), Some(Rule::CPrototypeFragment));
        assert_eq!(code_to_rule("C043"), Some(Rule::BadRedirectionFdOrder));
        assert_eq!(code_to_rule("SH-129"), Some(Rule::BadRedirectionFdOrder));
        assert_eq!(code_to_rule("C044"), Some(Rule::BareGlobCommandPath));
        assert_eq!(code_to_rule("SH-130"), Some(Rule::BareGlobCommandPath));
        assert_eq!(code_to_rule("C045"), Some(Rule::DiffMarkerLine));
        assert_eq!(code_to_rule("SH-133"), Some(Rule::DiffMarkerLine));
        assert_eq!(code_to_rule("C085"), Some(Rule::StderrBeforeStdoutRedirect));
        assert_eq!(code_to_rule("C094"), Some(Rule::RedirectClobbersInput));
        assert_eq!(
            code_to_rule("SH-211"),
            Some(Rule::StderrBeforeStdoutRedirect)
        );
        assert_eq!(code_to_rule("SH-222"), Some(Rule::RedirectClobbersInput));
        assert_eq!(code_to_rule("SH-141"), Some(Rule::InvalidExitStatus));
        assert_eq!(code_to_rule("SH-142"), Some(Rule::CasePatternVar));
        assert_eq!(code_to_rule("SH-143"), Some(Rule::TautologyChain));
        assert_eq!(
            code_to_rule("SH-144"),
            Some(Rule::ArithmeticRedirectionTarget)
        );
        assert_eq!(code_to_rule("SH-145"), Some(Rule::DuplicateRedirect));
        assert_eq!(code_to_rule("SH-148"), Some(Rule::BareSlashMarker));
        assert_eq!(code_to_rule("SH-151"), Some(Rule::EvalOnArray));
        assert_eq!(code_to_rule("SH-152"), Some(Rule::PatternWithVariable));
        assert_eq!(
            code_to_rule("SH-155"),
            Some(Rule::StatusCaptureAfterBranchTest)
        );
        assert_eq!(code_to_rule("SH-159"), Some(Rule::SubstWithRedirect));
        assert_eq!(code_to_rule("SH-160"), Some(Rule::SubstWithRedirectErr));
        assert_eq!(code_to_rule("SH-165"), Some(Rule::RedirectToCommandName));
        assert_eq!(code_to_rule("SH-166"), Some(Rule::NonAbsoluteShebang));
        assert_eq!(code_to_rule("SH-167"), Some(Rule::TemplateBraceInCommand));
        assert_eq!(code_to_rule("SH-169"), Some(Rule::NestedParameterExpansion));
        assert_eq!(code_to_rule("SH-171"), Some(Rule::OverwrittenFunction));
        assert_eq!(code_to_rule("SH-175"), Some(Rule::IfMissingThen));
        assert_eq!(code_to_rule("SH-176"), Some(Rule::ElseWithoutThen));
        assert_eq!(
            code_to_rule("SH-177"),
            Some(Rule::MissingSemicolonBeforeBrace)
        );
        assert_eq!(code_to_rule("SH-178"), Some(Rule::EmptyFunctionBody));
        assert_eq!(code_to_rule("SH-179"), Some(Rule::BareClosingBrace));
        assert_eq!(
            code_to_rule("SH-186"),
            Some(Rule::BackslashBeforeClosingBacktick)
        );
        assert_eq!(
            code_to_rule("SH-187"),
            Some(Rule::PositionalParamAsOperator)
        );
        assert_eq!(code_to_rule("SH-188"), Some(Rule::DoubleParenGrouping));
        assert_eq!(code_to_rule("SH-189"), Some(Rule::UnicodeQuoteInString));
        assert_eq!(code_to_rule("SH-190"), Some(Rule::MissingShebangLine));
        assert_eq!(code_to_rule("SH-191"), Some(Rule::IndentedShebang));
        assert_eq!(code_to_rule("SH-192"), Some(Rule::SpaceAfterHashBang));
        assert_eq!(code_to_rule("SH-193"), Some(Rule::ShebangNotOnFirstLine));
        assert_eq!(code_to_rule("SH-223"), Some(Rule::DuplicateShebangFlag));
        assert_eq!(code_to_rule("SH-079"), Some(Rule::AvoidLetBuiltin));
        assert_eq!(
            code_to_rule("SH-224"),
            Some(Rule::AssignmentLooksLikeComparison)
        );
        assert_eq!(code_to_rule("C096"), Some(Rule::SuspiciousBracketGlob));
        assert_eq!(code_to_rule("SH-225"), Some(Rule::SuspiciousBracketGlob));
        assert_eq!(code_to_rule("SH-227"), Some(Rule::SuWithoutFlag));
        assert_eq!(code_to_rule("SH-240"), Some(Rule::UnquotedPathInMkdir));
        assert_eq!(code_to_rule("SH-195"), Some(Rule::SubshellInArithmetic));
        assert_eq!(code_to_rule("C078"), Some(Rule::UnquotedGlobsInFind));
        assert_eq!(code_to_rule("SH-200"), Some(Rule::UnquotedGlobsInFind));
        assert_eq!(code_to_rule("C080"), Some(Rule::GlobInGrepPattern));
        assert_eq!(code_to_rule("SH-204"), Some(Rule::GlobInGrepPattern));
        assert_eq!(code_to_rule("C081"), Some(Rule::GlobInStringComparison));
        assert_eq!(code_to_rule("SH-206"), Some(Rule::GlobInStringComparison));
        assert_eq!(code_to_rule("C083"), Some(Rule::GlobInFindSubstitution));
        assert_eq!(code_to_rule("SH-209"), Some(Rule::GlobInFindSubstitution));
        assert_eq!(code_to_rule("C084"), Some(Rule::UnquotedGrepRegex));
        assert_eq!(code_to_rule("SH-210"), Some(Rule::UnquotedGrepRegex));
        assert_eq!(code_to_rule("C006"), Some(Rule::UndefinedVariable));
        assert_eq!(code_to_rule("SH-039"), Some(Rule::UndefinedVariable));
        assert_eq!(code_to_rule("C076"), Some(Rule::CommentedContinuationLine));
        assert_eq!(
            code_to_rule("SH-194"),
            Some(Rule::CommentedContinuationLine)
        );
        assert_eq!(code_to_rule("C098"), Some(Rule::SetFlagsWithoutDashes));
        assert_eq!(code_to_rule("SH-229"), Some(Rule::SetFlagsWithoutDashes));
        assert_eq!(code_to_rule("C099"), Some(Rule::QuotedArraySlice));
        assert_eq!(code_to_rule("SH-230"), Some(Rule::QuotedArraySlice));
        assert_eq!(code_to_rule("C100"), Some(Rule::QuotedBashSource));
        assert_eq!(code_to_rule("SH-232"), Some(Rule::QuotedBashSource));
        assert_eq!(
            code_to_rule("SH-233"),
            Some(Rule::CommandSubstitutionInAlias)
        );
        assert_eq!(code_to_rule("SH-235"), Some(Rule::FunctionInAlias));
        assert_eq!(code_to_rule("C103"), Some(Rule::FindOrWithoutGrouping));
        assert_eq!(code_to_rule("SH-237"), Some(Rule::FindOrWithoutGrouping));
        assert_eq!(code_to_rule("C104"), Some(Rule::NonShellSyntaxInScript));
        assert_eq!(code_to_rule("SH-238"), Some(Rule::NonShellSyntaxInScript));
        assert_eq!(code_to_rule("C105"), Some(Rule::ExportWithPositionalParams));
        assert_eq!(
            code_to_rule("SH-239"),
            Some(Rule::ExportWithPositionalParams)
        );
        assert_eq!(code_to_rule("C111"), Some(Rule::AtSignInStringCompare));
        assert_eq!(code_to_rule("SH-249"), Some(Rule::AtSignInStringCompare));
        assert_eq!(code_to_rule("C112"), Some(Rule::ArraySliceInComparison));
        assert_eq!(code_to_rule("SH-250"), Some(Rule::ArraySliceInComparison));
        assert_eq!(
            code_to_rule("C118"),
            Some(Rule::MalformedArithmeticInCondition)
        );
        assert_eq!(
            code_to_rule("SH-284"),
            Some(Rule::MalformedArithmeticInCondition)
        );
        assert_eq!(code_to_rule("C120"), Some(Rule::ExprSubstrInTest));
        assert_eq!(code_to_rule("SH-287"), Some(Rule::ExprSubstrInTest));
        assert_eq!(code_to_rule("C121"), Some(Rule::StringComparedWithEq));
        assert_eq!(code_to_rule("SH-288"), Some(Rule::StringComparedWithEq));
        assert_eq!(code_to_rule("C122"), Some(Rule::AFlagInDoubleBracket));
        assert_eq!(code_to_rule("SH-290"), Some(Rule::AFlagInDoubleBracket));
        assert_eq!(code_to_rule("C106"), Some(Rule::AppendToArrayAsString));
        assert_eq!(code_to_rule("SH-241"), Some(Rule::AppendToArrayAsString));
        assert_eq!(code_to_rule("C107"), Some(Rule::DollarQuestionAfterCommand));
        assert_eq!(
            code_to_rule("SH-242"),
            Some(Rule::DollarQuestionAfterCommand)
        );
        assert_eq!(
            code_to_rule("C108"),
            Some(Rule::UnsetAssociativeArrayElement)
        );
        assert_eq!(
            code_to_rule("SH-243"),
            Some(Rule::UnsetAssociativeArrayElement)
        );
        assert_eq!(code_to_rule("C109"), Some(Rule::MapfileProcessSubstitution));
        assert_eq!(
            code_to_rule("SH-244"),
            Some(Rule::MapfileProcessSubstitution)
        );
        assert_eq!(code_to_rule("C114"), Some(Rule::GlobWithExpansionInLoop));
        assert_eq!(code_to_rule("SH-254"), Some(Rule::GlobWithExpansionInLoop));
        assert_eq!(code_to_rule("C124"), Some(Rule::UnreachableAfterExit));
        assert_eq!(code_to_rule("SH-293"), Some(Rule::UnreachableAfterExit));
        assert_eq!(code_to_rule("C127"), Some(Rule::UnusedHeredoc));
        assert_eq!(code_to_rule("SH-298"), Some(Rule::UnusedHeredoc));
        assert_eq!(code_to_rule("C128"), Some(Rule::CaseGlobReachability));
        assert_eq!(code_to_rule("SH-301"), Some(Rule::CaseGlobReachability));
        assert_eq!(code_to_rule("C129"), Some(Rule::CaseDefaultBeforeGlob));
        assert_eq!(code_to_rule("SH-302"), Some(Rule::CaseDefaultBeforeGlob));
        assert_eq!(code_to_rule("C134"), Some(Rule::GetoptsOptionNotInCase));
        assert_eq!(code_to_rule("SH-312"), Some(Rule::GetoptsOptionNotInCase));
        assert_eq!(code_to_rule("C135"), Some(Rule::CaseArmNotInGetopts));
        assert_eq!(code_to_rule("SH-313"), Some(Rule::CaseArmNotInGetopts));
        assert_eq!(code_to_rule("C138"), Some(Rule::HeredocMissingEnd));
        assert_eq!(code_to_rule("SH-318"), Some(Rule::HeredocMissingEnd));
        assert_eq!(
            code_to_rule("C125"),
            Some(Rule::UncheckedDirectoryChangeInFunction)
        );
        assert_eq!(
            code_to_rule("SH-295"),
            Some(Rule::UncheckedDirectoryChangeInFunction)
        );
        assert_eq!(
            code_to_rule("C126"),
            Some(Rule::ContinueOutsideLoopInFunction)
        );
        assert_eq!(
            code_to_rule("SH-296"),
            Some(Rule::ContinueOutsideLoopInFunction)
        );
        assert_eq!(code_to_rule("C131"), Some(Rule::VariableAsCommandName));
        assert_eq!(code_to_rule("SH-308"), Some(Rule::VariableAsCommandName));
        assert_eq!(code_to_rule("C132"), Some(Rule::EnvPrefixExpansionOnly));
        assert_eq!(code_to_rule("SH-310"), Some(Rule::EnvPrefixExpansionOnly));
        assert_eq!(code_to_rule("C133"), Some(Rule::ArrayToStringConversion));
        assert_eq!(code_to_rule("SH-311"), Some(Rule::ArrayToStringConversion));
        assert_eq!(code_to_rule("C148"), Some(Rule::BrokenAssocKey));
        assert_eq!(code_to_rule("SH-337"), Some(Rule::BrokenAssocKey));
        assert_eq!(code_to_rule("SH-347"), Some(Rule::SubshellSideEffect));
        assert_eq!(code_to_rule("C150"), Some(Rule::SubshellLocalAssignment));
        assert_eq!(code_to_rule("SH-339"), Some(Rule::SubshellLocalAssignment));
        assert_eq!(code_to_rule("C151"), Some(Rule::CommaArrayElements));
        assert_eq!(code_to_rule("SH-340"), Some(Rule::CommaArrayElements));
        assert_eq!(
            code_to_rule("SH-351"),
            Some(Rule::PossibleVariableMisspelling)
        );
        assert_eq!(code_to_rule("SH-283"), Some(Rule::FindExecDirWithShell));
        assert_eq!(
            code_to_rule("C137"),
            Some(Rule::UnicodeSingleQuoteInSingleQuotes)
        );
        assert_eq!(
            code_to_rule("SH-315"),
            Some(Rule::UnicodeSingleQuoteInSingleQuotes)
        );
        assert_eq!(code_to_rule("C141"), Some(Rule::LoopWithoutEnd));
        assert_eq!(code_to_rule("SH-321"), Some(Rule::LoopWithoutEnd));
        assert_eq!(code_to_rule("C142"), Some(Rule::MissingDoneInForLoop));
        assert_eq!(code_to_rule("SH-322"), Some(Rule::MissingDoneInForLoop));
        assert_eq!(code_to_rule("C143"), Some(Rule::DanglingElse));
        assert_eq!(code_to_rule("SH-327"), Some(Rule::DanglingElse));
        assert_eq!(code_to_rule("C144"), Some(Rule::HeredocCloserNotAlone));
        assert_eq!(code_to_rule("SH-332"), Some(Rule::HeredocCloserNotAlone));
        assert_eq!(code_to_rule("C145"), Some(Rule::MisquotedHeredocClose));
        assert_eq!(code_to_rule("SH-333"), Some(Rule::MisquotedHeredocClose));
        assert_eq!(code_to_rule("C146"), Some(Rule::UntilMissingDo));
        assert_eq!(code_to_rule("SH-334"), Some(Rule::UntilMissingDo));
        assert_eq!(code_to_rule("C157"), Some(Rule::IfBracketGlued));
        assert_eq!(code_to_rule("SH-353"), Some(Rule::IfBracketGlued));
        assert_eq!(code_to_rule("X005"), Some(Rule::BashCaseFallthrough));
        assert_eq!(code_to_rule("X008"), Some(Rule::StandaloneArithmetic));
        assert_eq!(code_to_rule("X009"), Some(Rule::SelectLoop));
        assert_eq!(code_to_rule("X014"), Some(Rule::Coproc));
        assert_eq!(code_to_rule("X036"), Some(Rule::ZshRedirPipe));
        assert_eq!(code_to_rule("SH-108"), Some(Rule::ZshRedirPipe));
        assert_eq!(code_to_rule("X038"), Some(Rule::ZshBraceIf));
        assert_eq!(code_to_rule("SH-124"), Some(Rule::ZshBraceIf));
        assert_eq!(code_to_rule("X039"), Some(Rule::ZshAlwaysBlock));
        assert_eq!(code_to_rule("SH-125"), Some(Rule::ZshAlwaysBlock));
        assert_eq!(code_to_rule("X042"), Some(Rule::SourcedWithArgs));
        assert_eq!(code_to_rule("SH-140"), Some(Rule::SourcedWithArgs));
        assert_eq!(code_to_rule("X043"), Some(Rule::ZshFlagExpansion));
        assert_eq!(code_to_rule("SH-153"), Some(Rule::ZshFlagExpansion));
        assert_eq!(code_to_rule("X044"), Some(Rule::NestedZshSubstitution));
        assert_eq!(code_to_rule("SH-154"), Some(Rule::NestedZshSubstitution));
        assert_eq!(code_to_rule("X045"), Some(Rule::PlusEqualsAppend));
        assert_eq!(code_to_rule("SH-158"), Some(Rule::PlusEqualsAppend));
        assert_eq!(code_to_rule("X047"), Some(Rule::MultiVarForLoop));
        assert_eq!(code_to_rule("SH-180"), Some(Rule::MultiVarForLoop));
        assert_eq!(code_to_rule("X049"), Some(Rule::ZshPromptBracket));
        assert_eq!(code_to_rule("SH-183"), Some(Rule::ZshPromptBracket));
        assert_eq!(code_to_rule("X050"), Some(Rule::CshSyntaxInSh));
        assert_eq!(code_to_rule("SH-184"), Some(Rule::CshSyntaxInSh));
        assert_eq!(code_to_rule("X051"), Some(Rule::ZshNestedExpansion));
        assert_eq!(code_to_rule("SH-218"), Some(Rule::ZshNestedExpansion));
        assert_eq!(code_to_rule("X053"), Some(Rule::ZshAssignmentToZero));
        assert_eq!(code_to_rule("SH-260"), Some(Rule::ZshAssignmentToZero));
        assert_eq!(code_to_rule("X055"), Some(Rule::DollarStringInSh));
        assert_eq!(code_to_rule("SH-262"), Some(Rule::DollarStringInSh));
        assert_eq!(code_to_rule("X056"), Some(Rule::CStyleForInSh));
        assert_eq!(code_to_rule("SH-263"), Some(Rule::CStyleForInSh));
        assert_eq!(code_to_rule("X057"), Some(Rule::LegacyArithmeticInSh));
        assert_eq!(code_to_rule("SH-264"), Some(Rule::LegacyArithmeticInSh));
        assert_eq!(code_to_rule("X062"), Some(Rule::CStyleForArithmeticInSh));
        assert_eq!(code_to_rule("SH-269"), Some(Rule::CStyleForArithmeticInSh));
        assert_eq!(code_to_rule("X071"), Some(Rule::ArrayKeysInSh));
        assert_eq!(code_to_rule("SH-278"), Some(Rule::ArrayKeysInSh));
        assert_eq!(code_to_rule("X081"), Some(Rule::StarGlobRemovalInSh));
        assert_eq!(code_to_rule("SH-305"), Some(Rule::StarGlobRemovalInSh));
        assert_eq!(code_to_rule("X076"), Some(Rule::ZshParameterFlag));
        assert_eq!(code_to_rule("SH-286"), Some(Rule::ZshParameterFlag));
        assert_eq!(code_to_rule("X077"), Some(Rule::NestedDefaultExpansion));
        assert_eq!(code_to_rule("SH-291"), Some(Rule::NestedDefaultExpansion));
        assert_eq!(code_to_rule("X078"), Some(Rule::ZshArraySubscriptInCase));
        assert_eq!(code_to_rule("SH-299"), Some(Rule::ZshArraySubscriptInCase));
        assert_eq!(code_to_rule("X079"), Some(Rule::ZshParameterIndexFlag));
        assert_eq!(code_to_rule("SH-303"), Some(Rule::ZshParameterIndexFlag));
        assert_eq!(code_to_rule("X013"), Some(Rule::ArrayAssignment));
        assert_eq!(code_to_rule("SH-018"), Some(Rule::ArrayAssignment));
        assert_eq!(code_to_rule("X018"), Some(Rule::IndirectExpansion));
        assert_eq!(code_to_rule("SH-023"), Some(Rule::IndirectExpansion));
        assert_eq!(code_to_rule("X019"), Some(Rule::ArrayReference));
        assert_eq!(code_to_rule("SH-024"), Some(Rule::ArrayReference));
        assert_eq!(code_to_rule("X023"), Some(Rule::SubstringExpansion));
        assert_eq!(code_to_rule("SH-031"), Some(Rule::SubstringExpansion));
        assert_eq!(code_to_rule("X024"), Some(Rule::CaseModificationExpansion));
        assert_eq!(
            code_to_rule("SH-032"),
            Some(Rule::CaseModificationExpansion)
        );
        assert_eq!(code_to_rule("X025"), Some(Rule::ReplacementExpansion));
        assert_eq!(code_to_rule("SH-033"), Some(Rule::ReplacementExpansion));
        assert_eq!(code_to_rule("X026"), Some(Rule::BashFileSlurp));
        assert_eq!(code_to_rule("SH-053"), Some(Rule::BashFileSlurp));
        assert_eq!(code_to_rule("X027"), Some(Rule::EchoFlags));
        assert_eq!(code_to_rule("SH-054"), Some(Rule::EchoFlags));
        assert_eq!(code_to_rule("X028"), Some(Rule::TrLowerRange));
        assert_eq!(code_to_rule("SH-058"), Some(Rule::TrLowerRange));
        assert_eq!(code_to_rule("X029"), Some(Rule::TrUpperRange));
        assert_eq!(code_to_rule("SH-059"), Some(Rule::TrUpperRange));
        assert_eq!(code_to_rule("X030"), Some(Rule::EchoBackslashEscapes));
        assert_eq!(code_to_rule("SH-061"), Some(Rule::EchoBackslashEscapes));
    }
}