Skip to main content

shuck_linter/
registry.rs

1use crate::Severity;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4pub enum Category {
5    Correctness,
6    Style,
7    Performance,
8    Portability,
9    Security,
10}
11
12impl Category {
13    pub const fn prefix(self) -> &'static str {
14        match self {
15            Self::Correctness => "C",
16            Self::Style => "S",
17            Self::Performance => "P",
18            Self::Portability => "X",
19            Self::Security => "K",
20        }
21    }
22
23    pub fn from_prefix(prefix: &str) -> Option<Self> {
24        match prefix {
25            "C" => Some(Self::Correctness),
26            "S" => Some(Self::Style),
27            "P" => Some(Self::Performance),
28            "X" => Some(Self::Portability),
29            "K" => Some(Self::Security),
30            _ => None,
31        }
32    }
33}
34
35macro_rules! declare_rules {
36    (@sub $name:ident) => {
37        ()
38    };
39    (@count $($name:ident),+ $(,)?) => {
40        <[()]>::len(&[$(declare_rules!(@sub $name)),+])
41    };
42    ($(
43        ($code:literal, $category:expr, $severity:expr, $name:ident),
44    )+) => {
45        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
46        #[repr(u16)]
47        pub enum Rule {
48            $($name,)*
49        }
50
51        pub const ALL_RULES: [Rule; declare_rules!(@count $($name),+)] = [
52            $(Rule::$name,)*
53        ];
54
55        impl Rule {
56            pub const COUNT: usize = ALL_RULES.len();
57
58            pub fn iter() -> impl ExactSizeIterator<Item = Self> + DoubleEndedIterator + Clone {
59                ALL_RULES.into_iter()
60            }
61
62            pub const fn code(self) -> &'static str {
63                match self {
64                    $(Self::$name => $code,)*
65                }
66            }
67
68            pub const fn category(self) -> Category {
69                match self {
70                    $(Self::$name => $category,)*
71                }
72            }
73
74            pub const fn default_severity(self) -> Severity {
75                match self {
76                    $(Self::$name => $severity,)*
77                }
78            }
79        }
80
81        fn canonical_code_to_rule(code: &str) -> Option<Rule> {
82            match code {
83                $($code => Some(Rule::$name),)*
84                _ => None,
85            }
86        }
87    };
88}
89
90declare_rules! {
91    ("C001", Category::Correctness, Severity::Warning, UnusedAssignment),
92    ("C002", Category::Correctness, Severity::Warning, DynamicSourcePath),
93    ("C003", Category::Correctness, Severity::Warning, UntrackedSourceFile),
94    ("C004", Category::Correctness, Severity::Warning, UncheckedDirectoryChange),
95    ("C005", Category::Correctness, Severity::Warning, SingleQuotedLiteral),
96    ("C006", Category::Correctness, Severity::Error, UndefinedVariable),
97    ("C007", Category::Correctness, Severity::Warning, FindOutputToXargs),
98    ("C008", Category::Correctness, Severity::Warning, TrapStringExpansion),
99    ("C009", Category::Correctness, Severity::Warning, QuotedBashRegex),
100    ("C010", Category::Correctness, Severity::Warning, ChainedTestBranches),
101    ("C011", Category::Correctness, Severity::Warning, LineOrientedInput),
102    ("C012", Category::Correctness, Severity::Warning, LeadingGlobArgument),
103    ("C013", Category::Correctness, Severity::Warning, FindOutputLoop),
104    ("C014", Category::Correctness, Severity::Error, LocalTopLevel),
105    ("C015", Category::Correctness, Severity::Warning, SudoRedirectionOrder),
106    ("C016", Category::Correctness, Severity::Error, StrayClosingKeyword),
107    ("C017", Category::Correctness, Severity::Warning, ConstantComparisonTest),
108    ("C018", Category::Correctness, Severity::Error, LoopControlOutsideLoop),
109    ("C019", Category::Correctness, Severity::Warning, LiteralUnaryStringTest),
110    ("C020", Category::Correctness, Severity::Warning, TruthyLiteralTest),
111    ("C021", Category::Correctness, Severity::Warning, ConstantCaseSubject),
112    ("C022", Category::Correctness, Severity::Error, EmptyTest),
113    ("C023", Category::Correctness, Severity::Error, LeadingZeroArithmetic),
114    ("C024", Category::Correctness, Severity::Warning, AssignmentSpacing),
115    ("C030", Category::Correctness, Severity::Error, MissingBracketSpace),
116    ("C031", Category::Correctness, Severity::Error, MissingSpaceBeforeBracketClose),
117    ("C032", Category::Correctness, Severity::Error, JammedTestBracket),
118    ("C033", Category::Correctness, Severity::Error, IndentedHeredocClose),
119    ("C025", Category::Correctness, Severity::Warning, PositionalTenBraces),
120    ("C027", Category::Correctness, Severity::Warning, BareDoneWord),
121    ("C034", Category::Correctness, Severity::Error, UnterminatedIf),
122    ("C035", Category::Correctness, Severity::Error, MissingFi),
123    ("C036", Category::Correctness, Severity::Error, BrokenTestEnd),
124    ("C037", Category::Correctness, Severity::Error, BrokenTestParse),
125    ("C038", Category::Correctness, Severity::Error, ElseIf),
126    ("C039", Category::Correctness, Severity::Warning, OpenDoubleQuote),
127    ("C040", Category::Correctness, Severity::Error, LinebreakInTest),
128    ("C041", Category::Correctness, Severity::Error, CStyleComment),
129    ("C042", Category::Correctness, Severity::Warning, CPrototypeFragment),
130    ("C043", Category::Correctness, Severity::Warning, BadRedirectionFdOrder),
131    ("C044", Category::Correctness, Severity::Warning, BareGlobCommandPath),
132    ("C045", Category::Correctness, Severity::Warning, DiffMarkerLine),
133    ("C046", Category::Correctness, Severity::Warning, PipeToKill),
134    ("C047", Category::Correctness, Severity::Error, InvalidExitStatus),
135    ("C048", Category::Correctness, Severity::Warning, CasePatternVar),
136    ("C049", Category::Correctness, Severity::Warning, TautologyChain),
137    ("C050", Category::Correctness, Severity::Warning, ArithmeticRedirectionTarget),
138    ("C051", Category::Correctness, Severity::Error, DuplicateRedirect),
139    ("C052", Category::Correctness, Severity::Error, AssignSpecialZero),
140    ("C053", Category::Correctness, Severity::Warning, SpaceyAssign),
141    ("C054", Category::Correctness, Severity::Warning, BareSlashMarker),
142    ("C055", Category::Correctness, Severity::Warning, PatternWithVariable),
143    ("C056", Category::Correctness, Severity::Warning, StatusCaptureAfterBranchTest),
144    ("C057", Category::Correctness, Severity::Warning, SubstWithRedirect),
145    ("C058", Category::Correctness, Severity::Warning, SubstWithRedirectErr),
146    ("C059", Category::Correctness, Severity::Warning, RedirectToCommandName),
147    ("C060", Category::Correctness, Severity::Warning, NonAbsoluteShebang),
148    ("C061", Category::Correctness, Severity::Warning, TemplateBraceInCommand),
149    ("C062", Category::Correctness, Severity::Warning, NestedParameterExpansion),
150    ("C063", Category::Correctness, Severity::Warning, OverwrittenFunction),
151    ("C064", Category::Correctness, Severity::Warning, IfMissingThen),
152    ("C065", Category::Correctness, Severity::Warning, ElseWithoutThen),
153    ("C066", Category::Correctness, Severity::Warning, MissingSemicolonBeforeBrace),
154    ("C067", Category::Correctness, Severity::Warning, EmptyFunctionBody),
155    ("C068", Category::Correctness, Severity::Warning, BareClosingBrace),
156    ("C069", Category::Correctness, Severity::Warning, BackslashBeforeClosingBacktick),
157    ("C070", Category::Correctness, Severity::Warning, PositionalParamAsOperator),
158    ("C071", Category::Correctness, Severity::Warning, DoubleParenGrouping),
159    ("C072", Category::Correctness, Severity::Warning, UnicodeQuoteInString),
160    ("C073", Category::Correctness, Severity::Warning, IndentedShebang),
161    ("C074", Category::Correctness, Severity::Warning, SpaceAfterHashBang),
162    ("C075", Category::Correctness, Severity::Warning, ShebangNotOnFirstLine),
163    (
164        "C076",
165        Category::Correctness,
166        Severity::Warning,
167        CommentedContinuationLine
168    ),
169    ("C077", Category::Correctness, Severity::Warning, SubshellInArithmetic),
170    ("C078", Category::Correctness, Severity::Warning, UnquotedGlobsInFind),
171    ("C080", Category::Correctness, Severity::Warning, GlobInGrepPattern),
172    ("C081", Category::Correctness, Severity::Warning, GlobInStringComparison),
173    ("C083", Category::Correctness, Severity::Warning, GlobInFindSubstitution),
174    ("C084", Category::Correctness, Severity::Warning, UnquotedGrepRegex),
175    (
176        "C085",
177        Category::Correctness,
178        Severity::Warning,
179        StderrBeforeStdoutRedirect
180    ),
181    (
182        "C094",
183        Category::Correctness,
184        Severity::Warning,
185        RedirectClobbersInput
186    ),
187    (
188        "C082",
189        Category::Correctness,
190        Severity::Warning,
191        EscapedNegationInTest
192    ),
193    (
194        "C086",
195        Category::Correctness,
196        Severity::Warning,
197        GreaterThanInTest
198    ),
199    (
200        "C087",
201        Category::Correctness,
202        Severity::Warning,
203        StringComparisonForVersion
204    ),
205    (
206        "C088",
207        Category::Correctness,
208        Severity::Warning,
209        MixedAndOrInCondition
210    ),
211    (
212        "C089",
213        Category::Correctness,
214        Severity::Warning,
215        QuotedCommandInTest
216    ),
217    (
218        "C090",
219        Category::Correctness,
220        Severity::Warning,
221        GlobInTestComparison
222    ),
223    (
224        "C091",
225        Category::Correctness,
226        Severity::Warning,
227        TildeInStringComparison
228    ),
229    ("C092", Category::Correctness, Severity::Warning, IfDollarCommand),
230    (
231        "C093",
232        Category::Correctness,
233        Severity::Warning,
234        BacktickInCommandPosition
235    ),
236    (
237        "C095",
238        Category::Correctness,
239        Severity::Warning,
240        AssignmentLooksLikeComparison
241    ),
242    ("C096", Category::Correctness, Severity::Warning, SuspiciousBracketGlob),
243    (
244        "C097",
245        Category::Correctness,
246        Severity::Error,
247        FunctionCalledWithoutArgs
248    ),
249    (
250        "C098",
251        Category::Correctness,
252        Severity::Warning,
253        SetFlagsWithoutDashes
254    ),
255    (
256        "C099",
257        Category::Correctness,
258        Severity::Warning,
259        QuotedArraySlice
260    ),
261    (
262        "C100",
263        Category::Correctness,
264        Severity::Warning,
265        QuotedBashSource
266    ),
267    (
268        "C101",
269        Category::Correctness,
270        Severity::Warning,
271        IfsSetToLiteralBackslashN
272    ),
273    (
274        "C102",
275        Category::Correctness,
276        Severity::Warning,
277        GlobInTestDirectory
278    ),
279    (
280        "C103",
281        Category::Correctness,
282        Severity::Warning,
283        FindOrWithoutGrouping
284    ),
285    (
286        "C104",
287        Category::Correctness,
288        Severity::Warning,
289        NonShellSyntaxInScript
290    ),
291    (
292        "C105",
293        Category::Correctness,
294        Severity::Warning,
295        ExportWithPositionalParams
296    ),
297    (
298        "C106",
299        Category::Correctness,
300        Severity::Warning,
301        AppendToArrayAsString
302    ),
303    (
304        "C107",
305        Category::Correctness,
306        Severity::Warning,
307        DollarQuestionAfterCommand
308    ),
309    (
310        "C108",
311        Category::Correctness,
312        Severity::Warning,
313        UnsetAssociativeArrayElement
314    ),
315    (
316        "C109",
317        Category::Correctness,
318        Severity::Warning,
319        MapfileProcessSubstitution
320    ),
321    (
322        "C111",
323        Category::Correctness,
324        Severity::Warning,
325        AtSignInStringCompare
326    ),
327    (
328        "C112",
329        Category::Correctness,
330        Severity::Warning,
331        ArraySliceInComparison
332    ),
333    (
334        "C114",
335        Category::Correctness,
336        Severity::Warning,
337        GlobWithExpansionInLoop
338    ),
339    (
340        "C116",
341        Category::Correctness,
342        Severity::Warning,
343        AssignmentToNumericVariable
344    ),
345    (
346        "C117",
347        Category::Correctness,
348        Severity::Warning,
349        PlusPrefixInAssignment
350    ),
351    (
352        "C118",
353        Category::Correctness,
354        Severity::Warning,
355        MalformedArithmeticInCondition
356    ),
357    (
358        "C119",
359        Category::Correctness,
360        Severity::Warning,
361        RedirectBeforePipe
362    ),
363    (
364        "C120",
365        Category::Correctness,
366        Severity::Warning,
367        ExprSubstrInTest
368    ),
369    (
370        "C121",
371        Category::Correctness,
372        Severity::Warning,
373        StringComparedWithEq
374    ),
375    (
376        "C122",
377        Category::Correctness,
378        Severity::Warning,
379        AFlagInDoubleBracket
380    ),
381    (
382        "C123",
383        Category::Correctness,
384        Severity::Error,
385        FunctionReferencesUnsetParam
386    ),
387    ("C124", Category::Correctness, Severity::Warning, UnreachableAfterExit),
388    ("C127", Category::Correctness, Severity::Warning, UnusedHeredoc),
389    (
390        "C125",
391        Category::Correctness,
392        Severity::Warning,
393        UncheckedDirectoryChangeInFunction
394    ),
395    (
396        "C126",
397        Category::Correctness,
398        Severity::Error,
399        ContinueOutsideLoopInFunction
400    ),
401    (
402        "C128",
403        Category::Correctness,
404        Severity::Warning,
405        CaseGlobReachability
406    ),
407    (
408        "C129",
409        Category::Correctness,
410        Severity::Warning,
411        CaseDefaultBeforeGlob
412    ),
413    (
414        "C130",
415        Category::Correctness,
416        Severity::Warning,
417        AppendWithEscapedQuotes
418    ),
419    (
420        "C131",
421        Category::Correctness,
422        Severity::Warning,
423        VariableAsCommandName
424    ),
425    (
426        "C132",
427        Category::Correctness,
428        Severity::Warning,
429        EnvPrefixExpansionOnly
430    ),
431    (
432        "C133",
433        Category::Correctness,
434        Severity::Warning,
435        ArrayToStringConversion
436    ),
437    (
438        "C134",
439        Category::Correctness,
440        Severity::Warning,
441        GetoptsOptionNotInCase
442    ),
443    (
444        "C135",
445        Category::Correctness,
446        Severity::Warning,
447        CaseArmNotInGetopts
448    ),
449    (
450        "C136",
451        Category::Correctness,
452        Severity::Warning,
453        LocalCrossReference
454    ),
455    (
456        "C137",
457        Category::Correctness,
458        Severity::Warning,
459        UnicodeSingleQuoteInSingleQuotes
460    ),
461    ("C138", Category::Correctness, Severity::Warning, HeredocMissingEnd),
462    ("C139", Category::Correctness, Severity::Warning, SpacedAssignment),
463    ("C140", Category::Correctness, Severity::Warning, BadVarName),
464    ("C141", Category::Correctness, Severity::Error, LoopWithoutEnd),
465    (
466        "C142",
467        Category::Correctness,
468        Severity::Error,
469        MissingDoneInForLoop
470    ),
471    ("C143", Category::Correctness, Severity::Error, DanglingElse),
472    (
473        "C144",
474        Category::Correctness,
475        Severity::Warning,
476        HeredocCloserNotAlone
477    ),
478    ("C145", Category::Correctness, Severity::Warning, MisquotedHeredocClose),
479    ("C146", Category::Correctness, Severity::Error, UntilMissingDo),
480    ("C148", Category::Correctness, Severity::Warning, BrokenAssocKey),
481    (
482        "C150",
483        Category::Correctness,
484        Severity::Warning,
485        SubshellLocalAssignment
486    ),
487    ("C151", Category::Correctness, Severity::Warning, CommaArrayElements),
488    ("C155", Category::Correctness, Severity::Warning, SubshellSideEffect),
489    (
490        "C156",
491        Category::Correctness,
492        Severity::Warning,
493        PossibleVariableMisspelling
494    ),
495    ("C157", Category::Correctness, Severity::Error, IfBracketGlued),
496    (
497        "C158",
498        Category::Correctness,
499        Severity::Warning,
500        ImplicitGlobalInFunction
501    ),
502    ("C159", Category::Correctness, Severity::Warning, MutableGlobal),
503    (
504        "C160",
505        Category::Correctness,
506        Severity::Warning,
507        UnanchoredSourcePath
508    ),
509    (
510        "C161",
511        Category::Correctness,
512        Severity::Error,
513        FunctionCalledBeforeDefined
514    ),
515    ("P001", Category::Performance, Severity::Warning, ExprArithmetic),
516    ("P002", Category::Performance, Severity::Warning, GrepCountPipeline),
517    ("P003", Category::Performance, Severity::Warning, SingleTestSubshell),
518    ("P004", Category::Performance, Severity::Warning, SubshellTestGroup),
519    ("X001", Category::Portability, Severity::Warning, DoubleBracketInSh),
520    ("X002", Category::Portability, Severity::Warning, TestEqualityOperator),
521    ("X003", Category::Portability, Severity::Warning, LocalVariableInSh),
522    ("X004", Category::Portability, Severity::Warning, FunctionKeyword),
523    ("X005", Category::Portability, Severity::Warning, BashCaseFallthrough),
524    ("X006", Category::Portability, Severity::Warning, ProcessSubstitution),
525    ("X007", Category::Portability, Severity::Warning, AnsiCQuoting),
526    ("X010", Category::Portability, Severity::Warning, BraceExpansion),
527    ("X011", Category::Portability, Severity::Warning, HereString),
528    ("X008", Category::Portability, Severity::Warning, StandaloneArithmetic),
529    ("X009", Category::Portability, Severity::Warning, SelectLoop),
530    ("X014", Category::Portability, Severity::Warning, Coproc),
531    ("X012", Category::Portability, Severity::Warning, AmpersandRedirection),
532    ("X013", Category::Portability, Severity::Warning, ArrayAssignment),
533    ("X015", Category::Portability, Severity::Warning, LetCommand),
534    ("X016", Category::Portability, Severity::Warning, DeclareCommand),
535    ("X017", Category::Portability, Severity::Warning, TrapErr),
536    ("X018", Category::Portability, Severity::Warning, IndirectExpansion),
537    ("X019", Category::Portability, Severity::Warning, ArrayReference),
538    ("X020", Category::Portability, Severity::Warning, BraceFdRedirection),
539    ("X021", Category::Portability, Severity::Warning, PipefailOption),
540    ("X022", Category::Portability, Severity::Warning, WaitOption),
541    ("X023", Category::Portability, Severity::Warning, SubstringExpansion),
542    ("X024", Category::Portability, Severity::Warning, CaseModificationExpansion),
543    ("X025", Category::Portability, Severity::Warning, ReplacementExpansion),
544    ("X026", Category::Portability, Severity::Warning, BashFileSlurp),
545    ("X027", Category::Portability, Severity::Warning, EchoFlags),
546    ("X028", Category::Portability, Severity::Warning, TrLowerRange),
547    ("X029", Category::Portability, Severity::Warning, TrUpperRange),
548    ("X030", Category::Portability, Severity::Warning, EchoBackslashEscapes),
549    ("X031", Category::Portability, Severity::Warning, SourceBuiltinInSh),
550    ("X032", Category::Portability, Severity::Warning, PrintfQFormatInSh),
551    ("X033", Category::Portability, Severity::Warning, IfElifBashTest),
552    ("X035", Category::Portability, Severity::Warning, FunctionParamsInSh),
553    ("X037", Category::Portability, Severity::Warning, ExtglobCase),
554    ("X048", Category::Portability, Severity::Warning, ExtglobInCasePattern),
555    ("X054", Category::Portability, Severity::Warning, ExtglobInSh),
556    ("X065", Category::Portability, Severity::Warning, CaretNegationInBracket),
557    ("X036", Category::Portability, Severity::Warning, ZshRedirPipe),
558    ("X038", Category::Portability, Severity::Warning, ZshBraceIf),
559    ("X039", Category::Portability, Severity::Warning, ZshAlwaysBlock),
560    ("X040", Category::Portability, Severity::Warning, ArraySubscriptTest),
561    ("X041", Category::Portability, Severity::Warning, ArraySubscriptCondition),
562    ("X042", Category::Portability, Severity::Warning, SourcedWithArgs),
563    ("X043", Category::Portability, Severity::Warning, ZshFlagExpansion),
564    ("X044", Category::Portability, Severity::Warning, NestedZshSubstitution),
565    ("X045", Category::Portability, Severity::Warning, PlusEqualsAppend),
566    ("X051", Category::Portability, Severity::Warning, ZshNestedExpansion),
567    ("X047", Category::Portability, Severity::Warning, MultiVarForLoop),
568    ("X049", Category::Portability, Severity::Warning, ZshPromptBracket),
569    ("X050", Category::Portability, Severity::Warning, CshSyntaxInSh),
570    ("X053", Category::Portability, Severity::Warning, ZshAssignmentToZero),
571    ("X056", Category::Portability, Severity::Warning, CStyleForInSh),
572    ("X055", Category::Portability, Severity::Warning, DollarStringInSh),
573    ("X057", Category::Portability, Severity::Warning, LegacyArithmeticInSh),
574    ("X062", Category::Portability, Severity::Warning, CStyleForArithmeticInSh),
575    ("X071", Category::Portability, Severity::Warning, ArrayKeysInSh),
576    ("X081", Category::Portability, Severity::Warning, StarGlobRemovalInSh),
577    ("X076", Category::Portability, Severity::Warning, ZshParameterFlag),
578    ("X077", Category::Portability, Severity::Warning, NestedDefaultExpansion),
579    ("X078", Category::Portability, Severity::Warning, ZshArraySubscriptInCase),
580    ("X079", Category::Portability, Severity::Warning, ZshParameterIndexFlag),
581    ("X046", Category::Portability, Severity::Warning, ExtglobInTest),
582    ("X052", Category::Portability, Severity::Warning, FunctionKeywordInSh),
583    ("X058", Category::Portability, Severity::Warning, LexicalComparisonInDoubleBracket),
584    ("X059", Category::Portability, Severity::Warning, RegexMatchInSh),
585    ("X060", Category::Portability, Severity::Warning, VTestInSh),
586    ("X061", Category::Portability, Severity::Warning, ATestInSh),
587    ("X063", Category::Portability, Severity::Warning, AmpersandRedirectInSh),
588    ("X066", Category::Portability, Severity::Warning, PipeStderrInSh),
589    ("X067", Category::Portability, Severity::Warning, HyphenatedFunctionName),
590    ("X068", Category::Portability, Severity::Warning, ErrexitTrapInSh),
591    ("X069", Category::Portability, Severity::Warning, SignalNameInTrap),
592    ("X070", Category::Portability, Severity::Warning, BasePrefixInArithmetic),
593    ("X072", Category::Portability, Severity::Warning, UnsetPatternInSh),
594    ("X073", Category::Portability, Severity::Warning, OptionTestInSh),
595    ("X074", Category::Portability, Severity::Warning, StickyBitTestInSh),
596    ("X075", Category::Portability, Severity::Warning, OwnershipTestInSh),
597    ("X080", Category::Portability, Severity::Warning, SourceInsideFunctionInSh),
598    ("K001", Category::Security, Severity::Warning, RmGlobOnVariablePath),
599    ("K002", Category::Security, Severity::Warning, SshLocalExpansion),
600    ("K003", Category::Security, Severity::Warning, EvalOnArray),
601    ("K004", Category::Security, Severity::Warning, FindExecDirWithShell),
602    ("K006", Category::Security, Severity::Warning, RmRootishTarget),
603    (
604        "K007",
605        Category::Security,
606        Severity::Warning,
607        ChmodWorldWritableSensitivePath
608    ),
609    ("K008", Category::Security, Severity::Warning, ForkBombPattern),
610    ("S001", Category::Style, Severity::Warning, UnquotedExpansion),
611    ("S002", Category::Style, Severity::Warning, ReadWithoutRaw),
612    ("S003", Category::Style, Severity::Warning, LoopFromCommandOutput),
613    ("S004", Category::Style, Severity::Warning, UnquotedCommandSubstitution),
614    ("S005", Category::Style, Severity::Warning, LegacyBackticks),
615    ("S006", Category::Style, Severity::Warning, LegacyArithmeticExpansion),
616    ("S007", Category::Style, Severity::Warning, PrintfFormatVariable),
617    ("S008", Category::Style, Severity::Warning, UnquotedArrayExpansion),
618    ("S009", Category::Style, Severity::Warning, EchoedCommandSubstitution),
619    ("S010", Category::Style, Severity::Warning, ExportCommandSubstitution),
620    ("S011", Category::Style, Severity::Warning, CompoundTestOperator),
621    ("S012", Category::Style, Severity::Warning, PsGrepPipeline),
622    ("S013", Category::Style, Severity::Warning, LsGrepPipeline),
623    ("S014", Category::Style, Severity::Warning, UnquotedDollarStar),
624    ("S015", Category::Style, Severity::Warning, QuotedDollarStarLoop),
625    ("S017", Category::Style, Severity::Warning, UnquotedArraySplit),
626    ("S018", Category::Style, Severity::Warning, CommandOutputArraySplit),
627    ("S021", Category::Style, Severity::Warning, PositionalArgsInString),
628    ("S020", Category::Style, Severity::Warning, SingleIterationLoop),
629    ("S032", Category::Style, Severity::Warning, BareCommandNameAssignment),
630    ("S036", Category::Style, Severity::Warning, BareRead),
631    ("S037", Category::Style, Severity::Warning, RedundantSpacesInEcho),
632    ("S038", Category::Style, Severity::Warning, RedundantReturnStatus),
633    ("S044", Category::Style, Severity::Warning, EchoToSedSubstitution),
634    ("S050", Category::Style, Severity::Hint, UnquotedWordBetweenQuotes),
635    ("S051", Category::Style, Severity::Warning, UnquotedTrClass),
636    ("S052", Category::Style, Severity::Warning, UnquotedVariableInTest),
637    ("S054", Category::Style, Severity::Warning, SuWithoutFlag),
638    (
639        "S055",
640        Category::Style,
641        Severity::Warning,
642        GlobAssignedToVariable
643    ),
644    ("S056", Category::Style, Severity::Warning, CommandSubstitutionInAlias),
645    ("S057", Category::Style, Severity::Warning, FunctionInAlias),
646    ("S058", Category::Style, Severity::Warning, UnquotedPathInMkdir),
647    ("S059", Category::Style, Severity::Warning, DeprecatedTempfileCommand),
648    ("S060", Category::Style, Severity::Warning, EgrepDeprecated),
649    ("S061", Category::Style, Severity::Warning, FgrepDeprecated),
650    ("S062", Category::Style, Severity::Warning, DefaultValueInColonAssign),
651    ("S064", Category::Style, Severity::Warning, XargsWithInlineReplace),
652    ("S065", Category::Style, Severity::Warning, XPrefixInTest),
653    ("S067", Category::Style, Severity::Warning, LeadingGlobInGrepPattern),
654    ("S068", Category::Style, Severity::Warning, TrapSignalNumbers),
655    ("S069", Category::Style, Severity::Hint, GetoptsInvalidFlagHandler),
656    ("S070", Category::Style, Severity::Warning, DoubleQuoteNesting),
657    ("S071", Category::Style, Severity::Warning, EnvPrefixCommandOnly),
658    ("S076", Category::Style, Severity::Warning, MixedQuoteWord),
659    (
660        "S077",
661        Category::Style,
662        Severity::Warning,
663        BraceVariableBeforeBracket
664    ),
665    ("S049", Category::Style, Severity::Warning, UnquotedTrRange),
666    ("S046", Category::Style, Severity::Warning, LsPipedToXargs),
667    ("S047", Category::Style, Severity::Warning, LsInSubstitution),
668    (
669        "S016",
670        Category::Style,
671        Severity::Warning,
672        EchoInsideCommandSubstitution
673    ),
674    ("S019", Category::Style, Severity::Warning, GrepOutputInTest),
675    ("S022", Category::Style, Severity::Hint, AvoidLetBuiltin),
676    ("S033", Category::Style, Severity::Warning, EchoHereDoc),
677    ("S034", Category::Style, Severity::Warning, ArrayIndexArithmetic),
678    ("S035", Category::Style, Severity::Warning, ArithmeticScoreLine),
679    ("S045", Category::Style, Severity::Warning, DollarInArithmetic),
680    ("S023", Category::Style, Severity::Warning, EscapedUnderscore),
681    ("S024", Category::Style, Severity::Warning, SingleQuoteBackslash),
682    ("S025", Category::Style, Severity::Warning, LiteralBackslash),
683    ("SH-173", Category::Style, Severity::Warning, BackslashBeforeCommand),
684    ("S028", Category::Style, Severity::Warning, SuspectClosingQuote),
685    ("S029", Category::Style, Severity::Warning, LiteralBraces),
686    ("S030", Category::Style, Severity::Warning, HeredocEndSpace),
687    ("S031", Category::Style, Severity::Warning, TrailingDirective),
688    (
689        "S039",
690        Category::Style,
691        Severity::Warning,
692        LiteralBackslashInSingleQuotes
693    ),
694    ("S040", Category::Style, Severity::Warning, LiteralControlEscape),
695    (
696        "S041",
697        Category::Style,
698        Severity::Warning,
699        FunctionBodyWithoutBraces
700    ),
701    (
702        "S066",
703        Category::Style,
704        Severity::Warning,
705        LocalDeclareCombined
706    ),
707    ("S042", Category::Style, Severity::Warning, IfsEqualsAmbiguity),
708    ("S043", Category::Style, Severity::Warning, MissingShebangLine),
709    ("S053", Category::Style, Severity::Warning, DuplicateShebangFlag),
710    ("S072", Category::Style, Severity::Warning, LinebreakBeforeAnd),
711    ("S073", Category::Style, Severity::Warning, SpacedTabstripClose),
712    ("S074", Category::Style, Severity::Warning, AmpersandSemicolon),
713    ("S075", Category::Style, Severity::Warning, CombineAppends),
714    ("S078", Category::Style, Severity::Warning, ShebangShellPolicy),
715    ("S079", Category::Style, Severity::Warning, ShebangFormPolicy),
716    ("S080", Category::Style, Severity::Warning, ScriptSizeThreshold),
717    ("S081", Category::Style, Severity::Warning, MissingFileDescription),
718    ("S082", Category::Style, Severity::Warning, TodoFormat),
719    ("S083", Category::Style, Severity::Warning, MissingFunctionDoc),
720    ("S084", Category::Style, Severity::Warning, FunctionDocContent),
721    ("S085", Category::Style, Severity::Warning, MissingMainEntrypoint),
722}
723
724pub fn code_to_rule(code: &str) -> Option<Rule> {
725    canonical_code_to_rule(code).or(match code {
726        "SH-001" => Some(Rule::UnquotedExpansion),
727        "SH-002" => Some(Rule::ReadWithoutRaw),
728        "SH-003" => Some(Rule::UnusedAssignment),
729        "SH-004" => Some(Rule::LoopFromCommandOutput),
730        "SH-005" => Some(Rule::UnquotedCommandSubstitution),
731        "SH-008" => Some(Rule::LocalVariableInSh),
732        "SH-009" => Some(Rule::FunctionKeyword),
733        "SH-010" => Some(Rule::BashCaseFallthrough),
734        "SH-011" => Some(Rule::ProcessSubstitution),
735        "SH-012" => Some(Rule::AnsiCQuoting),
736        "SH-015" => Some(Rule::BraceExpansion),
737        "SH-016" => Some(Rule::HereString),
738        "SH-018" => Some(Rule::ArrayAssignment),
739        "SH-023" => Some(Rule::IndirectExpansion),
740        "SH-024" => Some(Rule::ArrayReference),
741        "SH-031" => Some(Rule::SubstringExpansion),
742        "SH-032" => Some(Rule::CaseModificationExpansion),
743        "SH-033" => Some(Rule::ReplacementExpansion),
744        "SH-053" => Some(Rule::BashFileSlurp),
745        "SH-013" => Some(Rule::StandaloneArithmetic),
746        "SH-014" => Some(Rule::SelectLoop),
747        "SH-019" => Some(Rule::Coproc),
748        "SH-079" => Some(Rule::AvoidLetBuiltin),
749        "SH-020" => Some(Rule::LetCommand),
750        "SH-021" => Some(Rule::DeclareCommand),
751        "SH-289" => Some(Rule::LocalDeclareCombined),
752        "SH-029" => Some(Rule::PipefailOption),
753        "SH-030" => Some(Rule::WaitOption),
754        "SH-022" => Some(Rule::TrapErr),
755        "SH-080" => Some(Rule::SourceBuiltinInSh),
756        "SH-081" => Some(Rule::PrintfQFormatInSh),
757        "SH-054" => Some(Rule::EchoFlags),
758        "SH-058" => Some(Rule::TrLowerRange),
759        "SH-059" => Some(Rule::TrUpperRange),
760        "SH-061" => Some(Rule::EchoBackslashEscapes),
761        "SH-226" => Some(Rule::FunctionKeywordInSh),
762        "SH-274" => Some(Rule::HyphenatedFunctionName),
763        "SH-234" => Some(Rule::IfsSetToLiteralBackslashN),
764        "SH-236" => Some(Rule::GlobInTestDirectory),
765        "SH-284" => Some(Rule::MalformedArithmeticInCondition),
766        "SH-287" => Some(Rule::ExprSubstrInTest),
767        "SH-288" => Some(Rule::StringComparedWithEq),
768        "SH-290" => Some(Rule::AFlagInDoubleBracket),
769        "SH-279" => Some(Rule::UnsetPatternInSh),
770        "SH-291" => Some(Rule::NestedDefaultExpansion),
771        "SH-304" => Some(Rule::SourceInsideFunctionInSh),
772        "SH-275" => Some(Rule::ErrexitTrapInSh),
773        "SH-276" => Some(Rule::SignalNameInTrap),
774        "SH-297" => Some(Rule::TrapSignalNumbers),
775        "SH-277" => Some(Rule::BasePrefixInArithmetic),
776        "SH-034" => Some(Rule::LegacyBackticks),
777        "SH-035" => Some(Rule::LegacyArithmeticExpansion),
778        "SH-078" => Some(Rule::LeadingZeroArithmetic),
779        "SH-157" => Some(Rule::ArrayIndexArithmetic),
780        "SH-161" => Some(Rule::ArithmeticScoreLine),
781        "SH-197" => Some(Rule::DollarInArithmetic),
782        "SH-198" => Some(Rule::LsPipedToXargs),
783        "SH-203" => Some(Rule::UnquotedTrRange),
784        "SH-082" => Some(Rule::EscapedUnderscore),
785        "SH-208" => Some(Rule::UnquotedTrClass),
786        "SH-212" => Some(Rule::UnquotedVariableInTest),
787        "SH-087" => Some(Rule::SingleQuoteBackslash),
788        "SH-172" => Some(Rule::LiteralBackslashInSingleQuotes),
789        "SH-185" => Some(Rule::IfsEqualsAmbiguity),
790        "SH-088" => Some(Rule::LiteralBackslash),
791        "SH-258" => Some(Rule::AssignmentToNumericVariable),
792        "SH-259" => Some(Rule::PlusPrefixInAssignment),
793        "SH-307" => Some(Rule::AppendWithEscapedQuotes),
794        "SH-025" => Some(Rule::DynamicSourcePath),
795        "SH-026" => Some(Rule::UntrackedSourceFile),
796        "SH-027" => Some(Rule::UncheckedDirectoryChange),
797        "SH-228" => Some(Rule::FunctionCalledWithoutArgs),
798        "SH-292" => Some(Rule::FunctionReferencesUnsetParam),
799        "SH-295" => Some(Rule::UncheckedDirectoryChangeInFunction),
800        "SH-296" => Some(Rule::ContinueOutsideLoopInFunction),
801        "SH-308" => Some(Rule::VariableAsCommandName),
802        "SH-311" => Some(Rule::ArrayToStringConversion),
803        "SH-337" => Some(Rule::BrokenAssocKey),
804        "SH-347" => Some(Rule::SubshellSideEffect),
805        "SH-340" => Some(Rule::CommaArrayElements),
806        "SH-351" => Some(Rule::PossibleVariableMisspelling),
807        "SH-036" => Some(Rule::SingleQuotedLiteral),
808        "SH-037" => Some(Rule::PrintfFormatVariable),
809        "SH-038" => Some(Rule::UnquotedArrayExpansion),
810        "SH-039" => Some(Rule::UndefinedVariable),
811        "SH-040" => Some(Rule::EchoedCommandSubstitution),
812        "SH-051" => Some(Rule::CompoundTestOperator),
813        "SH-170" => Some(Rule::RedundantReturnStatus),
814        "SH-168" => Some(Rule::RedundantSpacesInEcho),
815        "SH-196" => Some(Rule::EchoToSedSubstitution),
816        "SH-205" => Some(Rule::UnquotedWordBetweenQuotes),
817        "SH-066" => Some(Rule::EchoInsideCommandSubstitution),
818        "SH-199" => Some(Rule::LsInSubstitution),
819        "SH-163" => Some(Rule::BareRead),
820        "SH-245" => Some(Rule::DeprecatedTempfileCommand),
821        "SH-247" => Some(Rule::EgrepDeprecated),
822        "SH-248" => Some(Rule::FgrepDeprecated),
823        "SH-255" => Some(Rule::XargsWithInlineReplace),
824        "SH-256" => Some(Rule::XPrefixInTest),
825        "SH-306" => Some(Rule::DoubleQuoteNesting),
826        "SH-309" => Some(Rule::EnvPrefixCommandOnly),
827        "SH-350" => Some(Rule::MixedQuoteWord),
828        "SH-354" => Some(Rule::BraceVariableBeforeBracket),
829        "SH-071" => Some(Rule::GrepOutputInTest),
830        "SH-076" => Some(Rule::SingleIterationLoop),
831        "SH-128" => Some(Rule::BareCommandNameAssignment),
832        "SH-041" => Some(Rule::FindOutputToXargs),
833        "SH-042" => Some(Rule::TrapStringExpansion),
834        "SH-043" => Some(Rule::QuotedBashRegex),
835        "SH-044" => Some(Rule::RmGlobOnVariablePath),
836        "SH-047" => Some(Rule::SshLocalExpansion),
837        "SH-151" => Some(Rule::EvalOnArray),
838        "SH-324" => Some(Rule::RmRootishTarget),
839        "SH-325" => Some(Rule::ChmodWorldWritableSensitivePath),
840        "SH-326" => Some(Rule::ForkBombPattern),
841        "SH-045" => Some(Rule::ChainedTestBranches),
842        "C079" => Some(Rule::ChainedTestBranches),
843        "SH-201" => Some(Rule::ChainedTestBranches),
844        "SH-046" => Some(Rule::LineOrientedInput),
845        "SH-048" => Some(Rule::LeadingGlobArgument),
846        "SH-049" => Some(Rule::FindOutputLoop),
847        "SH-050" => Some(Rule::ExportCommandSubstitution),
848        "SH-135" => Some(Rule::EchoHereDoc),
849        "SH-052" => Some(Rule::LocalTopLevel),
850        "SH-060" => Some(Rule::SudoRedirectionOrder),
851        "SH-065" => Some(Rule::StrayClosingKeyword),
852        "SH-146" => Some(Rule::AssignSpecialZero),
853        "SH-147" => Some(Rule::SpaceyAssign),
854        "SH-069" => Some(Rule::ConstantComparisonTest),
855        "SH-070" => Some(Rule::LoopControlOutsideLoop),
856        "SH-072" => Some(Rule::LiteralUnaryStringTest),
857        "SH-073" => Some(Rule::TruthyLiteralTest),
858        "SH-074" => Some(Rule::ConstantCaseSubject),
859        "SH-075" => Some(Rule::EmptyTest),
860        "SH-084" => Some(Rule::AssignmentSpacing),
861        "SH-098" => Some(Rule::MissingBracketSpace),
862        "SH-102" => Some(Rule::JammedTestBracket),
863        "SH-104" => Some(Rule::IndentedHeredocClose),
864        "SH-133" => Some(Rule::DiffMarkerLine),
865        "SH-134" => Some(Rule::PipeToKill),
866        "SH-086" => Some(Rule::PositionalTenBraces),
867        "SH-091" => Some(Rule::BareDoneWord),
868        "SH-100" => Some(Rule::MissingSpaceBeforeBracketClose),
869        "SH-105" => Some(Rule::UnterminatedIf),
870        "SH-106" => Some(Rule::MissingFi),
871        "SH-107" => Some(Rule::FunctionParamsInSh),
872        "SH-109" => Some(Rule::BrokenTestEnd),
873        "SH-110" => Some(Rule::BrokenTestParse),
874        "SH-111" => Some(Rule::ExtglobCase),
875        "SH-182" => Some(Rule::ExtglobInCasePattern),
876        "SH-261" => Some(Rule::ExtglobInSh),
877        "SH-272" => Some(Rule::CaretNegationInBracket),
878        "SH-207" => Some(Rule::EscapedNegationInTest),
879        "SH-213" => Some(Rule::GreaterThanInTest),
880        "SH-214" => Some(Rule::StringComparisonForVersion),
881        "SH-215" => Some(Rule::MixedAndOrInCondition),
882        "SH-216" => Some(Rule::QuotedCommandInTest),
883        "SH-217" => Some(Rule::GlobInTestComparison),
884        "SH-219" => Some(Rule::TildeInStringComparison),
885        "SH-220" => Some(Rule::IfDollarCommand),
886        "SH-221" => Some(Rule::BacktickInCommandPosition),
887        "SH-112" => Some(Rule::ElseIf),
888        "SH-113" => Some(Rule::OpenDoubleQuote),
889        "SH-114" => Some(Rule::SuspectClosingQuote),
890        "SH-115" => Some(Rule::LinebreakInTest),
891        "SH-116" => Some(Rule::LiteralBraces),
892        "SH-119" => Some(Rule::HeredocEndSpace),
893        "SH-120" => Some(Rule::TrailingDirective),
894        "SH-329" => Some(Rule::LinebreakBeforeAnd),
895        "SH-330" => Some(Rule::SpacedTabstripClose),
896        "SH-335" => Some(Rule::AmpersandSemicolon),
897        "SH-349" => Some(Rule::CombineAppends),
898        "SH-339" => Some(Rule::SubshellLocalAssignment),
899        "SH-121" => Some(Rule::CStyleComment),
900        "SH-123" => Some(Rule::CPrototypeFragment),
901        "SH-129" => Some(Rule::BadRedirectionFdOrder),
902        "SH-130" => Some(Rule::BareGlobCommandPath),
903        "SH-141" => Some(Rule::InvalidExitStatus),
904        "SH-142" => Some(Rule::CasePatternVar),
905        "SH-143" => Some(Rule::TautologyChain),
906        "SH-144" => Some(Rule::ArithmeticRedirectionTarget),
907        "SH-145" => Some(Rule::DuplicateRedirect),
908        "SH-148" => Some(Rule::BareSlashMarker),
909        "SH-152" => Some(Rule::PatternWithVariable),
910        "SH-155" => Some(Rule::StatusCaptureAfterBranchTest),
911        "SH-017" => Some(Rule::AmpersandRedirection),
912        "SH-028" => Some(Rule::BraceFdRedirection),
913        "SH-270" => Some(Rule::AmpersandRedirectInSh),
914        "SH-273" => Some(Rule::PipeStderrInSh),
915        "SH-159" => Some(Rule::SubstWithRedirect),
916        "SH-160" => Some(Rule::SubstWithRedirectErr),
917        "SH-165" => Some(Rule::RedirectToCommandName),
918        "SH-285" => Some(Rule::RedirectBeforePipe),
919        "SH-166" => Some(Rule::NonAbsoluteShebang),
920        "SH-167" => Some(Rule::TemplateBraceInCommand),
921        "SH-169" => Some(Rule::NestedParameterExpansion),
922        "SH-171" => Some(Rule::OverwrittenFunction),
923        "SH-175" => Some(Rule::IfMissingThen),
924        "SH-176" => Some(Rule::ElseWithoutThen),
925        "SH-177" => Some(Rule::MissingSemicolonBeforeBrace),
926        "SH-178" => Some(Rule::EmptyFunctionBody),
927        "SH-179" => Some(Rule::BareClosingBrace),
928        "SH-186" => Some(Rule::BackslashBeforeClosingBacktick),
929        "SH-187" => Some(Rule::PositionalParamAsOperator),
930        "SH-211" => Some(Rule::StderrBeforeStdoutRedirect),
931        "SH-222" => Some(Rule::RedirectClobbersInput),
932        "SH-188" => Some(Rule::DoubleParenGrouping),
933        "SH-189" => Some(Rule::UnicodeQuoteInString),
934        "SH-190" => Some(Rule::MissingShebangLine),
935        "SH-191" => Some(Rule::IndentedShebang),
936        "SH-192" => Some(Rule::SpaceAfterHashBang),
937        "SH-193" => Some(Rule::ShebangNotOnFirstLine),
938        "SH-223" => Some(Rule::DuplicateShebangFlag),
939        "SH-224" => Some(Rule::AssignmentLooksLikeComparison),
940        "SH-225" => Some(Rule::SuspiciousBracketGlob),
941        "SH-227" => Some(Rule::SuWithoutFlag),
942        "SH-231" => Some(Rule::GlobAssignedToVariable),
943        "SH-194" => Some(Rule::CommentedContinuationLine),
944        "SH-195" => Some(Rule::SubshellInArithmetic),
945        "SH-200" => Some(Rule::UnquotedGlobsInFind),
946        "SH-204" => Some(Rule::GlobInGrepPattern),
947        "SH-206" => Some(Rule::GlobInStringComparison),
948        "SH-209" => Some(Rule::GlobInFindSubstitution),
949        "SH-210" => Some(Rule::UnquotedGrepRegex),
950        "SH-229" => Some(Rule::SetFlagsWithoutDashes),
951        "SH-230" => Some(Rule::QuotedArraySlice),
952        "SH-232" => Some(Rule::QuotedBashSource),
953        "SH-233" => Some(Rule::CommandSubstitutionInAlias),
954        "SH-235" => Some(Rule::FunctionInAlias),
955        "SH-237" => Some(Rule::FindOrWithoutGrouping),
956        "SH-238" => Some(Rule::NonShellSyntaxInScript),
957        "SH-239" => Some(Rule::ExportWithPositionalParams),
958        "SH-240" => Some(Rule::UnquotedPathInMkdir),
959        "SH-249" => Some(Rule::AtSignInStringCompare),
960        "SH-250" => Some(Rule::ArraySliceInComparison),
961        "SH-251" => Some(Rule::DefaultValueInColonAssign),
962        "SH-241" => Some(Rule::AppendToArrayAsString),
963        "SH-242" => Some(Rule::DollarQuestionAfterCommand),
964        "SH-243" => Some(Rule::UnsetAssociativeArrayElement),
965        "SH-244" => Some(Rule::MapfileProcessSubstitution),
966        "SH-254" => Some(Rule::GlobWithExpansionInLoop),
967        "SH-293" => Some(Rule::UnreachableAfterExit),
968        "SH-298" => Some(Rule::UnusedHeredoc),
969        "SH-300" => Some(Rule::GetoptsInvalidFlagHandler),
970        "SH-301" => Some(Rule::CaseGlobReachability),
971        "SH-302" => Some(Rule::CaseDefaultBeforeGlob),
972        "SH-312" => Some(Rule::GetoptsOptionNotInCase),
973        "SH-313" => Some(Rule::CaseArmNotInGetopts),
974        "SH-318" => Some(Rule::HeredocMissingEnd),
975        "SH-310" => Some(Rule::EnvPrefixExpansionOnly),
976        "SH-055" => Some(Rule::ExprArithmetic),
977        "SH-056" => Some(Rule::PsGrepPipeline),
978        "SH-057" => Some(Rule::LsGrepPipeline),
979        "SH-062" => Some(Rule::UnquotedDollarStar),
980        "SH-063" => Some(Rule::QuotedDollarStarLoop),
981        "SH-067" => Some(Rule::UnquotedArraySplit),
982        "SH-068" => Some(Rule::CommandOutputArraySplit),
983        "SH-294" => Some(Rule::LeadingGlobInGrepPattern),
984        "SH-077" => Some(Rule::PositionalArgsInString),
985        "SH-064" => Some(Rule::GrepCountPipeline),
986        "SH-137" => Some(Rule::SingleTestSubshell),
987        "SH-164" => Some(Rule::SubshellTestGroup),
988        "SH-006" => Some(Rule::DoubleBracketInSh),
989        "SH-007" => Some(Rule::TestEqualityOperator),
990        "SH-093" => Some(Rule::IfElifBashTest),
991        "SH-108" => Some(Rule::ZshRedirPipe),
992        "SH-124" => Some(Rule::ZshBraceIf),
993        "SH-125" => Some(Rule::ZshAlwaysBlock),
994        "SH-140" => Some(Rule::SourcedWithArgs),
995        "SH-153" => Some(Rule::ZshFlagExpansion),
996        "SH-154" => Some(Rule::NestedZshSubstitution),
997        "SH-158" => Some(Rule::PlusEqualsAppend),
998        "SH-180" => Some(Rule::MultiVarForLoop),
999        "SH-181" => Some(Rule::FunctionBodyWithoutBraces),
1000        "SH-183" => Some(Rule::ZshPromptBracket),
1001        "SH-184" => Some(Rule::CshSyntaxInSh),
1002        "SH-218" => Some(Rule::ZshNestedExpansion),
1003        "SH-260" => Some(Rule::ZshAssignmentToZero),
1004        "SH-262" => Some(Rule::DollarStringInSh),
1005        "SH-263" => Some(Rule::CStyleForInSh),
1006        "SH-264" => Some(Rule::LegacyArithmeticInSh),
1007        "SH-269" => Some(Rule::CStyleForArithmeticInSh),
1008        "SH-278" => Some(Rule::ArrayKeysInSh),
1009        "SH-305" => Some(Rule::StarGlobRemovalInSh),
1010        "SH-286" => Some(Rule::ZshParameterFlag),
1011        "SH-299" => Some(Rule::ZshArraySubscriptInCase),
1012        "SH-303" => Some(Rule::ZshParameterIndexFlag),
1013        "SH-126" => Some(Rule::ArraySubscriptTest),
1014        "SH-127" => Some(Rule::ArraySubscriptCondition),
1015        "SH-174" => Some(Rule::ExtglobInTest),
1016        "SH-265" => Some(Rule::LexicalComparisonInDoubleBracket),
1017        "SH-266" => Some(Rule::RegexMatchInSh),
1018        "SH-267" => Some(Rule::VTestInSh),
1019        "SH-268" => Some(Rule::ATestInSh),
1020        "SH-280" => Some(Rule::OptionTestInSh),
1021        "SH-281" => Some(Rule::StickyBitTestInSh),
1022        "SH-282" => Some(Rule::OwnershipTestInSh),
1023        "SH-283" => Some(Rule::FindExecDirWithShell),
1024        "SH-314" => Some(Rule::LocalCrossReference),
1025        "SH-315" => Some(Rule::UnicodeSingleQuoteInSingleQuotes),
1026        "SH-319" => Some(Rule::SpacedAssignment),
1027        "SH-320" => Some(Rule::BadVarName),
1028        "SH-321" => Some(Rule::LoopWithoutEnd),
1029        "SH-322" => Some(Rule::MissingDoneInForLoop),
1030        "SH-327" => Some(Rule::DanglingElse),
1031        "SH-332" => Some(Rule::HeredocCloserNotAlone),
1032        "SH-333" => Some(Rule::MisquotedHeredocClose),
1033        "SH-334" => Some(Rule::UntilMissingDo),
1034        "SH-353" => Some(Rule::IfBracketGlued),
1035        _ => None,
1036    })
1037}
1038
1039#[cfg(test)]
1040mod tests {
1041    use super::*;
1042    use std::collections::BTreeSet;
1043
1044    #[test]
1045    fn rule_codes_are_unique() {
1046        let codes = Rule::iter().map(Rule::code).collect::<BTreeSet<_>>();
1047        assert_eq!(codes.len(), Rule::COUNT);
1048    }
1049
1050    #[test]
1051    fn resolves_legacy_shuck_aliases() {
1052        assert_eq!(code_to_rule("SH-001"), Some(Rule::UnquotedExpansion));
1053        assert_eq!(code_to_rule("SH-002"), Some(Rule::ReadWithoutRaw));
1054        assert_eq!(code_to_rule("SH-003"), Some(Rule::UnusedAssignment));
1055        assert_eq!(code_to_rule("SH-004"), Some(Rule::LoopFromCommandOutput));
1056        assert_eq!(
1057            code_to_rule("SH-005"),
1058            Some(Rule::UnquotedCommandSubstitution)
1059        );
1060        assert_eq!(code_to_rule("SH-010"), Some(Rule::BashCaseFallthrough));
1061        assert_eq!(code_to_rule("SH-013"), Some(Rule::StandaloneArithmetic));
1062        assert_eq!(code_to_rule("SH-014"), Some(Rule::SelectLoop));
1063        assert_eq!(code_to_rule("SH-019"), Some(Rule::Coproc));
1064        assert_eq!(code_to_rule("SH-034"), Some(Rule::LegacyBackticks));
1065        assert_eq!(
1066            code_to_rule("SH-035"),
1067            Some(Rule::LegacyArithmeticExpansion)
1068        );
1069        assert_eq!(code_to_rule("SH-055"), Some(Rule::ExprArithmetic));
1070        assert_eq!(code_to_rule("SH-056"), Some(Rule::PsGrepPipeline));
1071        assert_eq!(code_to_rule("SH-057"), Some(Rule::LsGrepPipeline));
1072        assert_eq!(code_to_rule("SH-107"), Some(Rule::FunctionParamsInSh));
1073        assert_eq!(code_to_rule("S014"), Some(Rule::UnquotedDollarStar));
1074        assert_eq!(code_to_rule("SH-062"), Some(Rule::UnquotedDollarStar));
1075        assert_eq!(code_to_rule("S015"), Some(Rule::QuotedDollarStarLoop));
1076        assert_eq!(code_to_rule("SH-063"), Some(Rule::QuotedDollarStarLoop));
1077        assert_eq!(code_to_rule("S017"), Some(Rule::UnquotedArraySplit));
1078        assert_eq!(code_to_rule("SH-067"), Some(Rule::UnquotedArraySplit));
1079        assert_eq!(code_to_rule("S018"), Some(Rule::CommandOutputArraySplit));
1080        assert_eq!(code_to_rule("SH-068"), Some(Rule::CommandOutputArraySplit));
1081        assert_eq!(code_to_rule("S067"), Some(Rule::LeadingGlobInGrepPattern));
1082        assert_eq!(code_to_rule("SH-294"), Some(Rule::LeadingGlobInGrepPattern));
1083        assert_eq!(code_to_rule("S068"), Some(Rule::TrapSignalNumbers));
1084        assert_eq!(code_to_rule("SH-297"), Some(Rule::TrapSignalNumbers));
1085        assert_eq!(code_to_rule("S069"), Some(Rule::GetoptsInvalidFlagHandler));
1086        assert_eq!(
1087            code_to_rule("SH-300"),
1088            Some(Rule::GetoptsInvalidFlagHandler)
1089        );
1090        assert_eq!(code_to_rule("S071"), Some(Rule::EnvPrefixCommandOnly));
1091        assert_eq!(code_to_rule("SH-309"), Some(Rule::EnvPrefixCommandOnly));
1092        assert_eq!(code_to_rule("S076"), Some(Rule::MixedQuoteWord));
1093        assert_eq!(code_to_rule("SH-350"), Some(Rule::MixedQuoteWord));
1094        assert_eq!(code_to_rule("S077"), Some(Rule::BraceVariableBeforeBracket));
1095        assert_eq!(
1096            code_to_rule("SH-354"),
1097            Some(Rule::BraceVariableBeforeBracket)
1098        );
1099        assert_eq!(code_to_rule("S021"), Some(Rule::PositionalArgsInString));
1100        assert_eq!(code_to_rule("SH-077"), Some(Rule::PositionalArgsInString));
1101        assert_eq!(code_to_rule("S020"), Some(Rule::SingleIterationLoop));
1102        assert_eq!(code_to_rule("SH-076"), Some(Rule::SingleIterationLoop));
1103        assert_eq!(code_to_rule("S032"), Some(Rule::BareCommandNameAssignment));
1104        assert_eq!(
1105            code_to_rule("SH-128"),
1106            Some(Rule::BareCommandNameAssignment)
1107        );
1108        assert_eq!(code_to_rule("SH-146"), Some(Rule::AssignSpecialZero));
1109        assert_eq!(code_to_rule("SH-147"), Some(Rule::SpaceyAssign));
1110        assert_eq!(code_to_rule("SH-064"), Some(Rule::GrepCountPipeline));
1111        assert_eq!(code_to_rule("SH-137"), Some(Rule::SingleTestSubshell));
1112        assert_eq!(code_to_rule("SH-164"), Some(Rule::SubshellTestGroup));
1113        assert_eq!(code_to_rule("S023"), Some(Rule::EscapedUnderscore));
1114        assert_eq!(code_to_rule("SH-082"), Some(Rule::EscapedUnderscore));
1115        assert_eq!(code_to_rule("S034"), Some(Rule::ArrayIndexArithmetic));
1116        assert_eq!(code_to_rule("SH-157"), Some(Rule::ArrayIndexArithmetic));
1117        assert_eq!(code_to_rule("S035"), Some(Rule::ArithmeticScoreLine));
1118        assert_eq!(code_to_rule("SH-161"), Some(Rule::ArithmeticScoreLine));
1119        assert_eq!(
1120            code_to_rule("SH-228"),
1121            Some(Rule::FunctionCalledWithoutArgs)
1122        );
1123        assert_eq!(
1124            code_to_rule("SH-292"),
1125            Some(Rule::FunctionReferencesUnsetParam)
1126        );
1127        assert_eq!(code_to_rule("S045"), Some(Rule::DollarInArithmetic));
1128        assert_eq!(code_to_rule("SH-197"), Some(Rule::DollarInArithmetic));
1129        assert_eq!(code_to_rule("S046"), Some(Rule::LsPipedToXargs));
1130        assert_eq!(code_to_rule("SH-198"), Some(Rule::LsPipedToXargs));
1131        assert_eq!(code_to_rule("S047"), Some(Rule::LsInSubstitution));
1132        assert_eq!(code_to_rule("SH-199"), Some(Rule::LsInSubstitution));
1133        assert_eq!(code_to_rule("S055"), Some(Rule::GlobAssignedToVariable));
1134        assert_eq!(code_to_rule("SH-231"), Some(Rule::GlobAssignedToVariable));
1135        assert_eq!(code_to_rule("SH-203"), Some(Rule::UnquotedTrRange));
1136        assert_eq!(code_to_rule("S024"), Some(Rule::SingleQuoteBackslash));
1137        assert_eq!(code_to_rule("SH-087"), Some(Rule::SingleQuoteBackslash));
1138        assert_eq!(code_to_rule("S052"), Some(Rule::UnquotedVariableInTest));
1139        assert_eq!(code_to_rule("SH-208"), Some(Rule::UnquotedTrClass));
1140        assert_eq!(code_to_rule("SH-212"), Some(Rule::UnquotedVariableInTest));
1141        assert_eq!(code_to_rule("S058"), Some(Rule::UnquotedPathInMkdir));
1142        assert_eq!(code_to_rule("S062"), Some(Rule::DefaultValueInColonAssign));
1143        assert_eq!(code_to_rule("S064"), Some(Rule::XargsWithInlineReplace));
1144        assert_eq!(code_to_rule("S011"), Some(Rule::CompoundTestOperator));
1145        assert_eq!(code_to_rule("S065"), Some(Rule::XPrefixInTest));
1146        assert_eq!(code_to_rule("SH-051"), Some(Rule::CompoundTestOperator));
1147        assert_eq!(
1148            code_to_rule("SH-251"),
1149            Some(Rule::DefaultValueInColonAssign)
1150        );
1151        assert_eq!(code_to_rule("SH-025"), Some(Rule::DynamicSourcePath));
1152        assert_eq!(code_to_rule("SH-256"), Some(Rule::XPrefixInTest));
1153        assert_eq!(
1154            code_to_rule("S039"),
1155            Some(Rule::LiteralBackslashInSingleQuotes)
1156        );
1157        assert_eq!(code_to_rule("S038"), Some(Rule::RedundantReturnStatus));
1158        assert_eq!(code_to_rule("SH-170"), Some(Rule::RedundantReturnStatus));
1159        assert_eq!(
1160            code_to_rule("SH-172"),
1161            Some(Rule::LiteralBackslashInSingleQuotes)
1162        );
1163        assert_eq!(code_to_rule("S026"), None);
1164        assert_eq!(code_to_rule("SH-092"), None);
1165        assert_eq!(code_to_rule("S040"), Some(Rule::LiteralControlEscape));
1166        assert_eq!(code_to_rule("SH-173"), Some(Rule::BackslashBeforeCommand));
1167        assert_eq!(code_to_rule("S041"), Some(Rule::FunctionBodyWithoutBraces));
1168        assert_eq!(
1169            code_to_rule("SH-181"),
1170            Some(Rule::FunctionBodyWithoutBraces)
1171        );
1172        assert_eq!(code_to_rule("S066"), Some(Rule::LocalDeclareCombined));
1173        assert_eq!(code_to_rule("SH-289"), Some(Rule::LocalDeclareCombined));
1174        assert_eq!(code_to_rule("SH-026"), Some(Rule::UntrackedSourceFile));
1175        assert_eq!(code_to_rule("SH-036"), Some(Rule::SingleQuotedLiteral));
1176        assert_eq!(code_to_rule("SH-037"), Some(Rule::PrintfFormatVariable));
1177        assert_eq!(code_to_rule("SH-038"), Some(Rule::UnquotedArrayExpansion));
1178        assert_eq!(code_to_rule("SH-039"), Some(Rule::UndefinedVariable));
1179        assert_eq!(
1180            code_to_rule("SH-040"),
1181            Some(Rule::EchoedCommandSubstitution)
1182        );
1183        assert_eq!(
1184            code_to_rule("SH-066"),
1185            Some(Rule::EchoInsideCommandSubstitution)
1186        );
1187        assert_eq!(code_to_rule("SH-168"), Some(Rule::RedundantSpacesInEcho));
1188        assert_eq!(code_to_rule("SH-196"), Some(Rule::EchoToSedSubstitution));
1189        assert_eq!(code_to_rule("SH-163"), Some(Rule::BareRead));
1190        assert_eq!(code_to_rule("SH-071"), Some(Rule::GrepOutputInTest));
1191        assert_eq!(code_to_rule("SH-041"), Some(Rule::FindOutputToXargs));
1192        assert_eq!(code_to_rule("SH-042"), Some(Rule::TrapStringExpansion));
1193        assert_eq!(code_to_rule("SH-043"), Some(Rule::QuotedBashRegex));
1194        assert_eq!(code_to_rule("SH-044"), Some(Rule::RmGlobOnVariablePath));
1195        assert_eq!(code_to_rule("SH-047"), Some(Rule::SshLocalExpansion));
1196        assert_eq!(code_to_rule("SH-324"), Some(Rule::RmRootishTarget));
1197        assert_eq!(
1198            code_to_rule("SH-325"),
1199            Some(Rule::ChmodWorldWritableSensitivePath)
1200        );
1201        assert_eq!(code_to_rule("SH-326"), Some(Rule::ForkBombPattern));
1202        assert_eq!(code_to_rule("SH-045"), Some(Rule::ChainedTestBranches));
1203        assert_eq!(code_to_rule("C079"), Some(Rule::ChainedTestBranches));
1204        assert_eq!(code_to_rule("SH-201"), Some(Rule::ChainedTestBranches));
1205        assert_eq!(code_to_rule("SH-046"), Some(Rule::LineOrientedInput));
1206        assert_eq!(code_to_rule("SH-049"), Some(Rule::FindOutputLoop));
1207        assert_eq!(
1208            code_to_rule("SH-050"),
1209            Some(Rule::ExportCommandSubstitution)
1210        );
1211        assert_eq!(code_to_rule("S033"), Some(Rule::EchoHereDoc));
1212        assert_eq!(code_to_rule("SH-135"), Some(Rule::EchoHereDoc));
1213        assert_eq!(code_to_rule("SH-052"), Some(Rule::LocalTopLevel));
1214        assert_eq!(code_to_rule("SH-060"), Some(Rule::SudoRedirectionOrder));
1215        assert_eq!(code_to_rule("SH-081"), Some(Rule::PrintfQFormatInSh));
1216        assert_eq!(code_to_rule("SH-275"), Some(Rule::ErrexitTrapInSh));
1217        assert_eq!(code_to_rule("SH-276"), Some(Rule::SignalNameInTrap));
1218        assert_eq!(code_to_rule("SH-277"), Some(Rule::BasePrefixInArithmetic));
1219        assert_eq!(code_to_rule("SH-069"), Some(Rule::ConstantComparisonTest));
1220        assert_eq!(code_to_rule("SH-070"), Some(Rule::LoopControlOutsideLoop));
1221        assert_eq!(code_to_rule("SH-072"), Some(Rule::LiteralUnaryStringTest));
1222        assert_eq!(code_to_rule("SH-073"), Some(Rule::TruthyLiteralTest));
1223        assert_eq!(code_to_rule("SH-074"), Some(Rule::ConstantCaseSubject));
1224        assert_eq!(code_to_rule("SH-075"), Some(Rule::EmptyTest));
1225        assert_eq!(code_to_rule("C023"), Some(Rule::LeadingZeroArithmetic));
1226        assert_eq!(code_to_rule("SH-078"), Some(Rule::LeadingZeroArithmetic));
1227        assert_eq!(code_to_rule("C024"), Some(Rule::AssignmentSpacing));
1228        assert_eq!(code_to_rule("SH-084"), Some(Rule::AssignmentSpacing));
1229        assert_eq!(code_to_rule("C030"), Some(Rule::MissingBracketSpace));
1230        assert_eq!(code_to_rule("SH-098"), Some(Rule::MissingBracketSpace));
1231        assert_eq!(
1232            code_to_rule("C031"),
1233            Some(Rule::MissingSpaceBeforeBracketClose)
1234        );
1235        assert_eq!(
1236            code_to_rule("SH-100"),
1237            Some(Rule::MissingSpaceBeforeBracketClose)
1238        );
1239        assert_eq!(code_to_rule("C032"), Some(Rule::JammedTestBracket));
1240        assert_eq!(code_to_rule("SH-102"), Some(Rule::JammedTestBracket));
1241        assert_eq!(code_to_rule("C033"), Some(Rule::IndentedHeredocClose));
1242        assert_eq!(code_to_rule("SH-104"), Some(Rule::IndentedHeredocClose));
1243        assert_eq!(code_to_rule("SH-134"), Some(Rule::PipeToKill));
1244        assert_eq!(code_to_rule("SH-086"), Some(Rule::PositionalTenBraces));
1245        assert_eq!(code_to_rule("C027"), Some(Rule::BareDoneWord));
1246        assert_eq!(code_to_rule("SH-091"), Some(Rule::BareDoneWord));
1247        assert_eq!(code_to_rule("C034"), Some(Rule::UnterminatedIf));
1248        assert_eq!(code_to_rule("SH-105"), Some(Rule::UnterminatedIf));
1249        assert_eq!(code_to_rule("C035"), Some(Rule::MissingFi));
1250        assert_eq!(code_to_rule("SH-106"), Some(Rule::MissingFi));
1251        assert_eq!(code_to_rule("C036"), Some(Rule::BrokenTestEnd));
1252        assert_eq!(code_to_rule("SH-109"), Some(Rule::BrokenTestEnd));
1253        assert_eq!(code_to_rule("C037"), Some(Rule::BrokenTestParse));
1254        assert_eq!(code_to_rule("SH-110"), Some(Rule::BrokenTestParse));
1255        assert_eq!(code_to_rule("SH-111"), Some(Rule::ExtglobCase));
1256        assert_eq!(code_to_rule("SH-182"), Some(Rule::ExtglobInCasePattern));
1257        assert_eq!(code_to_rule("SH-261"), Some(Rule::ExtglobInSh));
1258        assert_eq!(code_to_rule("SH-272"), Some(Rule::CaretNegationInBracket));
1259        assert_eq!(code_to_rule("C038"), Some(Rule::ElseIf));
1260        assert_eq!(code_to_rule("SH-112"), Some(Rule::ElseIf));
1261        assert_eq!(code_to_rule("C039"), Some(Rule::OpenDoubleQuote));
1262        assert_eq!(code_to_rule("SH-113"), Some(Rule::OpenDoubleQuote));
1263        assert_eq!(code_to_rule("S028"), Some(Rule::SuspectClosingQuote));
1264        assert_eq!(code_to_rule("SH-114"), Some(Rule::SuspectClosingQuote));
1265        assert_eq!(
1266            code_to_rule("SH-245"),
1267            Some(Rule::DeprecatedTempfileCommand)
1268        );
1269        assert_eq!(code_to_rule("SH-247"), Some(Rule::EgrepDeprecated));
1270        assert_eq!(code_to_rule("SH-248"), Some(Rule::FgrepDeprecated));
1271        assert_eq!(code_to_rule("SH-255"), Some(Rule::XargsWithInlineReplace));
1272        assert_eq!(code_to_rule("S029"), Some(Rule::LiteralBraces));
1273        assert_eq!(code_to_rule("SH-116"), Some(Rule::LiteralBraces));
1274        assert_eq!(code_to_rule("S030"), Some(Rule::HeredocEndSpace));
1275        assert_eq!(code_to_rule("SH-119"), Some(Rule::HeredocEndSpace));
1276        assert_eq!(code_to_rule("S031"), Some(Rule::TrailingDirective));
1277        assert_eq!(code_to_rule("SH-120"), Some(Rule::TrailingDirective));
1278        assert_eq!(code_to_rule("S072"), Some(Rule::LinebreakBeforeAnd));
1279        assert_eq!(code_to_rule("SH-329"), Some(Rule::LinebreakBeforeAnd));
1280        assert_eq!(code_to_rule("S073"), Some(Rule::SpacedTabstripClose));
1281        assert_eq!(code_to_rule("SH-330"), Some(Rule::SpacedTabstripClose));
1282        assert_eq!(code_to_rule("S074"), Some(Rule::AmpersandSemicolon));
1283        assert_eq!(code_to_rule("SH-335"), Some(Rule::AmpersandSemicolon));
1284        assert_eq!(code_to_rule("S075"), Some(Rule::CombineAppends));
1285        assert_eq!(code_to_rule("SH-349"), Some(Rule::CombineAppends));
1286        assert_eq!(code_to_rule("S085"), Some(Rule::MissingMainEntrypoint));
1287        assert_eq!(code_to_rule("C040"), Some(Rule::LinebreakInTest));
1288        assert_eq!(code_to_rule("SH-115"), Some(Rule::LinebreakInTest));
1289        assert_eq!(code_to_rule("C041"), Some(Rule::CStyleComment));
1290        assert_eq!(code_to_rule("SH-121"), Some(Rule::CStyleComment));
1291        assert_eq!(code_to_rule("C042"), Some(Rule::CPrototypeFragment));
1292        assert_eq!(code_to_rule("SH-123"), Some(Rule::CPrototypeFragment));
1293        assert_eq!(code_to_rule("C043"), Some(Rule::BadRedirectionFdOrder));
1294        assert_eq!(code_to_rule("SH-129"), Some(Rule::BadRedirectionFdOrder));
1295        assert_eq!(code_to_rule("C044"), Some(Rule::BareGlobCommandPath));
1296        assert_eq!(code_to_rule("SH-130"), Some(Rule::BareGlobCommandPath));
1297        assert_eq!(code_to_rule("C045"), Some(Rule::DiffMarkerLine));
1298        assert_eq!(code_to_rule("SH-133"), Some(Rule::DiffMarkerLine));
1299        assert_eq!(code_to_rule("C085"), Some(Rule::StderrBeforeStdoutRedirect));
1300        assert_eq!(code_to_rule("C094"), Some(Rule::RedirectClobbersInput));
1301        assert_eq!(
1302            code_to_rule("SH-211"),
1303            Some(Rule::StderrBeforeStdoutRedirect)
1304        );
1305        assert_eq!(code_to_rule("SH-222"), Some(Rule::RedirectClobbersInput));
1306        assert_eq!(code_to_rule("SH-141"), Some(Rule::InvalidExitStatus));
1307        assert_eq!(code_to_rule("SH-142"), Some(Rule::CasePatternVar));
1308        assert_eq!(code_to_rule("SH-143"), Some(Rule::TautologyChain));
1309        assert_eq!(
1310            code_to_rule("SH-144"),
1311            Some(Rule::ArithmeticRedirectionTarget)
1312        );
1313        assert_eq!(code_to_rule("SH-145"), Some(Rule::DuplicateRedirect));
1314        assert_eq!(code_to_rule("SH-148"), Some(Rule::BareSlashMarker));
1315        assert_eq!(code_to_rule("SH-151"), Some(Rule::EvalOnArray));
1316        assert_eq!(code_to_rule("SH-152"), Some(Rule::PatternWithVariable));
1317        assert_eq!(
1318            code_to_rule("SH-155"),
1319            Some(Rule::StatusCaptureAfterBranchTest)
1320        );
1321        assert_eq!(code_to_rule("SH-159"), Some(Rule::SubstWithRedirect));
1322        assert_eq!(code_to_rule("SH-160"), Some(Rule::SubstWithRedirectErr));
1323        assert_eq!(code_to_rule("SH-165"), Some(Rule::RedirectToCommandName));
1324        assert_eq!(code_to_rule("SH-166"), Some(Rule::NonAbsoluteShebang));
1325        assert_eq!(code_to_rule("SH-167"), Some(Rule::TemplateBraceInCommand));
1326        assert_eq!(code_to_rule("SH-169"), Some(Rule::NestedParameterExpansion));
1327        assert_eq!(code_to_rule("SH-171"), Some(Rule::OverwrittenFunction));
1328        assert_eq!(code_to_rule("SH-175"), Some(Rule::IfMissingThen));
1329        assert_eq!(code_to_rule("SH-176"), Some(Rule::ElseWithoutThen));
1330        assert_eq!(
1331            code_to_rule("SH-177"),
1332            Some(Rule::MissingSemicolonBeforeBrace)
1333        );
1334        assert_eq!(code_to_rule("SH-178"), Some(Rule::EmptyFunctionBody));
1335        assert_eq!(code_to_rule("SH-179"), Some(Rule::BareClosingBrace));
1336        assert_eq!(
1337            code_to_rule("SH-186"),
1338            Some(Rule::BackslashBeforeClosingBacktick)
1339        );
1340        assert_eq!(
1341            code_to_rule("SH-187"),
1342            Some(Rule::PositionalParamAsOperator)
1343        );
1344        assert_eq!(code_to_rule("SH-188"), Some(Rule::DoubleParenGrouping));
1345        assert_eq!(code_to_rule("SH-189"), Some(Rule::UnicodeQuoteInString));
1346        assert_eq!(code_to_rule("SH-190"), Some(Rule::MissingShebangLine));
1347        assert_eq!(code_to_rule("SH-191"), Some(Rule::IndentedShebang));
1348        assert_eq!(code_to_rule("SH-192"), Some(Rule::SpaceAfterHashBang));
1349        assert_eq!(code_to_rule("SH-193"), Some(Rule::ShebangNotOnFirstLine));
1350        assert_eq!(code_to_rule("SH-223"), Some(Rule::DuplicateShebangFlag));
1351        assert_eq!(code_to_rule("SH-079"), Some(Rule::AvoidLetBuiltin));
1352        assert_eq!(
1353            code_to_rule("SH-224"),
1354            Some(Rule::AssignmentLooksLikeComparison)
1355        );
1356        assert_eq!(code_to_rule("C096"), Some(Rule::SuspiciousBracketGlob));
1357        assert_eq!(code_to_rule("SH-225"), Some(Rule::SuspiciousBracketGlob));
1358        assert_eq!(code_to_rule("SH-227"), Some(Rule::SuWithoutFlag));
1359        assert_eq!(code_to_rule("SH-240"), Some(Rule::UnquotedPathInMkdir));
1360        assert_eq!(code_to_rule("SH-195"), Some(Rule::SubshellInArithmetic));
1361        assert_eq!(code_to_rule("C078"), Some(Rule::UnquotedGlobsInFind));
1362        assert_eq!(code_to_rule("SH-200"), Some(Rule::UnquotedGlobsInFind));
1363        assert_eq!(code_to_rule("C080"), Some(Rule::GlobInGrepPattern));
1364        assert_eq!(code_to_rule("SH-204"), Some(Rule::GlobInGrepPattern));
1365        assert_eq!(code_to_rule("C081"), Some(Rule::GlobInStringComparison));
1366        assert_eq!(code_to_rule("SH-206"), Some(Rule::GlobInStringComparison));
1367        assert_eq!(code_to_rule("C083"), Some(Rule::GlobInFindSubstitution));
1368        assert_eq!(code_to_rule("SH-209"), Some(Rule::GlobInFindSubstitution));
1369        assert_eq!(code_to_rule("C084"), Some(Rule::UnquotedGrepRegex));
1370        assert_eq!(code_to_rule("SH-210"), Some(Rule::UnquotedGrepRegex));
1371        assert_eq!(code_to_rule("C006"), Some(Rule::UndefinedVariable));
1372        assert_eq!(code_to_rule("SH-039"), Some(Rule::UndefinedVariable));
1373        assert_eq!(code_to_rule("C076"), Some(Rule::CommentedContinuationLine));
1374        assert_eq!(
1375            code_to_rule("SH-194"),
1376            Some(Rule::CommentedContinuationLine)
1377        );
1378        assert_eq!(code_to_rule("C098"), Some(Rule::SetFlagsWithoutDashes));
1379        assert_eq!(code_to_rule("SH-229"), Some(Rule::SetFlagsWithoutDashes));
1380        assert_eq!(code_to_rule("C099"), Some(Rule::QuotedArraySlice));
1381        assert_eq!(code_to_rule("SH-230"), Some(Rule::QuotedArraySlice));
1382        assert_eq!(code_to_rule("C100"), Some(Rule::QuotedBashSource));
1383        assert_eq!(code_to_rule("SH-232"), Some(Rule::QuotedBashSource));
1384        assert_eq!(
1385            code_to_rule("SH-233"),
1386            Some(Rule::CommandSubstitutionInAlias)
1387        );
1388        assert_eq!(code_to_rule("SH-235"), Some(Rule::FunctionInAlias));
1389        assert_eq!(code_to_rule("C103"), Some(Rule::FindOrWithoutGrouping));
1390        assert_eq!(code_to_rule("SH-237"), Some(Rule::FindOrWithoutGrouping));
1391        assert_eq!(code_to_rule("C104"), Some(Rule::NonShellSyntaxInScript));
1392        assert_eq!(code_to_rule("SH-238"), Some(Rule::NonShellSyntaxInScript));
1393        assert_eq!(code_to_rule("C105"), Some(Rule::ExportWithPositionalParams));
1394        assert_eq!(
1395            code_to_rule("SH-239"),
1396            Some(Rule::ExportWithPositionalParams)
1397        );
1398        assert_eq!(code_to_rule("C111"), Some(Rule::AtSignInStringCompare));
1399        assert_eq!(code_to_rule("SH-249"), Some(Rule::AtSignInStringCompare));
1400        assert_eq!(code_to_rule("C112"), Some(Rule::ArraySliceInComparison));
1401        assert_eq!(code_to_rule("SH-250"), Some(Rule::ArraySliceInComparison));
1402        assert_eq!(
1403            code_to_rule("C118"),
1404            Some(Rule::MalformedArithmeticInCondition)
1405        );
1406        assert_eq!(
1407            code_to_rule("SH-284"),
1408            Some(Rule::MalformedArithmeticInCondition)
1409        );
1410        assert_eq!(code_to_rule("C120"), Some(Rule::ExprSubstrInTest));
1411        assert_eq!(code_to_rule("SH-287"), Some(Rule::ExprSubstrInTest));
1412        assert_eq!(code_to_rule("C121"), Some(Rule::StringComparedWithEq));
1413        assert_eq!(code_to_rule("SH-288"), Some(Rule::StringComparedWithEq));
1414        assert_eq!(code_to_rule("C122"), Some(Rule::AFlagInDoubleBracket));
1415        assert_eq!(code_to_rule("SH-290"), Some(Rule::AFlagInDoubleBracket));
1416        assert_eq!(code_to_rule("C106"), Some(Rule::AppendToArrayAsString));
1417        assert_eq!(code_to_rule("SH-241"), Some(Rule::AppendToArrayAsString));
1418        assert_eq!(code_to_rule("C107"), Some(Rule::DollarQuestionAfterCommand));
1419        assert_eq!(
1420            code_to_rule("SH-242"),
1421            Some(Rule::DollarQuestionAfterCommand)
1422        );
1423        assert_eq!(
1424            code_to_rule("C108"),
1425            Some(Rule::UnsetAssociativeArrayElement)
1426        );
1427        assert_eq!(
1428            code_to_rule("SH-243"),
1429            Some(Rule::UnsetAssociativeArrayElement)
1430        );
1431        assert_eq!(code_to_rule("C109"), Some(Rule::MapfileProcessSubstitution));
1432        assert_eq!(
1433            code_to_rule("SH-244"),
1434            Some(Rule::MapfileProcessSubstitution)
1435        );
1436        assert_eq!(code_to_rule("C114"), Some(Rule::GlobWithExpansionInLoop));
1437        assert_eq!(code_to_rule("SH-254"), Some(Rule::GlobWithExpansionInLoop));
1438        assert_eq!(code_to_rule("C124"), Some(Rule::UnreachableAfterExit));
1439        assert_eq!(code_to_rule("SH-293"), Some(Rule::UnreachableAfterExit));
1440        assert_eq!(code_to_rule("C127"), Some(Rule::UnusedHeredoc));
1441        assert_eq!(code_to_rule("SH-298"), Some(Rule::UnusedHeredoc));
1442        assert_eq!(code_to_rule("C128"), Some(Rule::CaseGlobReachability));
1443        assert_eq!(code_to_rule("SH-301"), Some(Rule::CaseGlobReachability));
1444        assert_eq!(code_to_rule("C129"), Some(Rule::CaseDefaultBeforeGlob));
1445        assert_eq!(code_to_rule("SH-302"), Some(Rule::CaseDefaultBeforeGlob));
1446        assert_eq!(code_to_rule("C134"), Some(Rule::GetoptsOptionNotInCase));
1447        assert_eq!(code_to_rule("SH-312"), Some(Rule::GetoptsOptionNotInCase));
1448        assert_eq!(code_to_rule("C135"), Some(Rule::CaseArmNotInGetopts));
1449        assert_eq!(code_to_rule("SH-313"), Some(Rule::CaseArmNotInGetopts));
1450        assert_eq!(code_to_rule("C138"), Some(Rule::HeredocMissingEnd));
1451        assert_eq!(code_to_rule("SH-318"), Some(Rule::HeredocMissingEnd));
1452        assert_eq!(
1453            code_to_rule("C125"),
1454            Some(Rule::UncheckedDirectoryChangeInFunction)
1455        );
1456        assert_eq!(
1457            code_to_rule("SH-295"),
1458            Some(Rule::UncheckedDirectoryChangeInFunction)
1459        );
1460        assert_eq!(
1461            code_to_rule("C126"),
1462            Some(Rule::ContinueOutsideLoopInFunction)
1463        );
1464        assert_eq!(
1465            code_to_rule("SH-296"),
1466            Some(Rule::ContinueOutsideLoopInFunction)
1467        );
1468        assert_eq!(code_to_rule("C131"), Some(Rule::VariableAsCommandName));
1469        assert_eq!(code_to_rule("SH-308"), Some(Rule::VariableAsCommandName));
1470        assert_eq!(code_to_rule("C132"), Some(Rule::EnvPrefixExpansionOnly));
1471        assert_eq!(code_to_rule("SH-310"), Some(Rule::EnvPrefixExpansionOnly));
1472        assert_eq!(code_to_rule("C133"), Some(Rule::ArrayToStringConversion));
1473        assert_eq!(code_to_rule("SH-311"), Some(Rule::ArrayToStringConversion));
1474        assert_eq!(code_to_rule("C148"), Some(Rule::BrokenAssocKey));
1475        assert_eq!(code_to_rule("SH-337"), Some(Rule::BrokenAssocKey));
1476        assert_eq!(code_to_rule("SH-347"), Some(Rule::SubshellSideEffect));
1477        assert_eq!(code_to_rule("C150"), Some(Rule::SubshellLocalAssignment));
1478        assert_eq!(code_to_rule("SH-339"), Some(Rule::SubshellLocalAssignment));
1479        assert_eq!(code_to_rule("C151"), Some(Rule::CommaArrayElements));
1480        assert_eq!(code_to_rule("SH-340"), Some(Rule::CommaArrayElements));
1481        assert_eq!(
1482            code_to_rule("SH-351"),
1483            Some(Rule::PossibleVariableMisspelling)
1484        );
1485        assert_eq!(code_to_rule("SH-283"), Some(Rule::FindExecDirWithShell));
1486        assert_eq!(
1487            code_to_rule("C137"),
1488            Some(Rule::UnicodeSingleQuoteInSingleQuotes)
1489        );
1490        assert_eq!(
1491            code_to_rule("SH-315"),
1492            Some(Rule::UnicodeSingleQuoteInSingleQuotes)
1493        );
1494        assert_eq!(code_to_rule("C141"), Some(Rule::LoopWithoutEnd));
1495        assert_eq!(code_to_rule("SH-321"), Some(Rule::LoopWithoutEnd));
1496        assert_eq!(code_to_rule("C142"), Some(Rule::MissingDoneInForLoop));
1497        assert_eq!(code_to_rule("SH-322"), Some(Rule::MissingDoneInForLoop));
1498        assert_eq!(code_to_rule("C143"), Some(Rule::DanglingElse));
1499        assert_eq!(code_to_rule("SH-327"), Some(Rule::DanglingElse));
1500        assert_eq!(code_to_rule("C144"), Some(Rule::HeredocCloserNotAlone));
1501        assert_eq!(code_to_rule("SH-332"), Some(Rule::HeredocCloserNotAlone));
1502        assert_eq!(code_to_rule("C145"), Some(Rule::MisquotedHeredocClose));
1503        assert_eq!(code_to_rule("SH-333"), Some(Rule::MisquotedHeredocClose));
1504        assert_eq!(code_to_rule("C146"), Some(Rule::UntilMissingDo));
1505        assert_eq!(code_to_rule("SH-334"), Some(Rule::UntilMissingDo));
1506        assert_eq!(code_to_rule("C157"), Some(Rule::IfBracketGlued));
1507        assert_eq!(code_to_rule("SH-353"), Some(Rule::IfBracketGlued));
1508        assert_eq!(code_to_rule("X005"), Some(Rule::BashCaseFallthrough));
1509        assert_eq!(code_to_rule("X008"), Some(Rule::StandaloneArithmetic));
1510        assert_eq!(code_to_rule("X009"), Some(Rule::SelectLoop));
1511        assert_eq!(code_to_rule("X014"), Some(Rule::Coproc));
1512        assert_eq!(code_to_rule("X036"), Some(Rule::ZshRedirPipe));
1513        assert_eq!(code_to_rule("SH-108"), Some(Rule::ZshRedirPipe));
1514        assert_eq!(code_to_rule("X038"), Some(Rule::ZshBraceIf));
1515        assert_eq!(code_to_rule("SH-124"), Some(Rule::ZshBraceIf));
1516        assert_eq!(code_to_rule("X039"), Some(Rule::ZshAlwaysBlock));
1517        assert_eq!(code_to_rule("SH-125"), Some(Rule::ZshAlwaysBlock));
1518        assert_eq!(code_to_rule("X042"), Some(Rule::SourcedWithArgs));
1519        assert_eq!(code_to_rule("SH-140"), Some(Rule::SourcedWithArgs));
1520        assert_eq!(code_to_rule("X043"), Some(Rule::ZshFlagExpansion));
1521        assert_eq!(code_to_rule("SH-153"), Some(Rule::ZshFlagExpansion));
1522        assert_eq!(code_to_rule("X044"), Some(Rule::NestedZshSubstitution));
1523        assert_eq!(code_to_rule("SH-154"), Some(Rule::NestedZshSubstitution));
1524        assert_eq!(code_to_rule("X045"), Some(Rule::PlusEqualsAppend));
1525        assert_eq!(code_to_rule("SH-158"), Some(Rule::PlusEqualsAppend));
1526        assert_eq!(code_to_rule("X047"), Some(Rule::MultiVarForLoop));
1527        assert_eq!(code_to_rule("SH-180"), Some(Rule::MultiVarForLoop));
1528        assert_eq!(code_to_rule("X049"), Some(Rule::ZshPromptBracket));
1529        assert_eq!(code_to_rule("SH-183"), Some(Rule::ZshPromptBracket));
1530        assert_eq!(code_to_rule("X050"), Some(Rule::CshSyntaxInSh));
1531        assert_eq!(code_to_rule("SH-184"), Some(Rule::CshSyntaxInSh));
1532        assert_eq!(code_to_rule("X051"), Some(Rule::ZshNestedExpansion));
1533        assert_eq!(code_to_rule("SH-218"), Some(Rule::ZshNestedExpansion));
1534        assert_eq!(code_to_rule("X053"), Some(Rule::ZshAssignmentToZero));
1535        assert_eq!(code_to_rule("SH-260"), Some(Rule::ZshAssignmentToZero));
1536        assert_eq!(code_to_rule("X055"), Some(Rule::DollarStringInSh));
1537        assert_eq!(code_to_rule("SH-262"), Some(Rule::DollarStringInSh));
1538        assert_eq!(code_to_rule("X056"), Some(Rule::CStyleForInSh));
1539        assert_eq!(code_to_rule("SH-263"), Some(Rule::CStyleForInSh));
1540        assert_eq!(code_to_rule("X057"), Some(Rule::LegacyArithmeticInSh));
1541        assert_eq!(code_to_rule("SH-264"), Some(Rule::LegacyArithmeticInSh));
1542        assert_eq!(code_to_rule("X062"), Some(Rule::CStyleForArithmeticInSh));
1543        assert_eq!(code_to_rule("SH-269"), Some(Rule::CStyleForArithmeticInSh));
1544        assert_eq!(code_to_rule("X071"), Some(Rule::ArrayKeysInSh));
1545        assert_eq!(code_to_rule("SH-278"), Some(Rule::ArrayKeysInSh));
1546        assert_eq!(code_to_rule("X081"), Some(Rule::StarGlobRemovalInSh));
1547        assert_eq!(code_to_rule("SH-305"), Some(Rule::StarGlobRemovalInSh));
1548        assert_eq!(code_to_rule("X076"), Some(Rule::ZshParameterFlag));
1549        assert_eq!(code_to_rule("SH-286"), Some(Rule::ZshParameterFlag));
1550        assert_eq!(code_to_rule("X077"), Some(Rule::NestedDefaultExpansion));
1551        assert_eq!(code_to_rule("SH-291"), Some(Rule::NestedDefaultExpansion));
1552        assert_eq!(code_to_rule("X078"), Some(Rule::ZshArraySubscriptInCase));
1553        assert_eq!(code_to_rule("SH-299"), Some(Rule::ZshArraySubscriptInCase));
1554        assert_eq!(code_to_rule("X079"), Some(Rule::ZshParameterIndexFlag));
1555        assert_eq!(code_to_rule("SH-303"), Some(Rule::ZshParameterIndexFlag));
1556        assert_eq!(code_to_rule("X013"), Some(Rule::ArrayAssignment));
1557        assert_eq!(code_to_rule("SH-018"), Some(Rule::ArrayAssignment));
1558        assert_eq!(code_to_rule("X018"), Some(Rule::IndirectExpansion));
1559        assert_eq!(code_to_rule("SH-023"), Some(Rule::IndirectExpansion));
1560        assert_eq!(code_to_rule("X019"), Some(Rule::ArrayReference));
1561        assert_eq!(code_to_rule("SH-024"), Some(Rule::ArrayReference));
1562        assert_eq!(code_to_rule("X023"), Some(Rule::SubstringExpansion));
1563        assert_eq!(code_to_rule("SH-031"), Some(Rule::SubstringExpansion));
1564        assert_eq!(code_to_rule("X024"), Some(Rule::CaseModificationExpansion));
1565        assert_eq!(
1566            code_to_rule("SH-032"),
1567            Some(Rule::CaseModificationExpansion)
1568        );
1569        assert_eq!(code_to_rule("X025"), Some(Rule::ReplacementExpansion));
1570        assert_eq!(code_to_rule("SH-033"), Some(Rule::ReplacementExpansion));
1571        assert_eq!(code_to_rule("X026"), Some(Rule::BashFileSlurp));
1572        assert_eq!(code_to_rule("SH-053"), Some(Rule::BashFileSlurp));
1573        assert_eq!(code_to_rule("X027"), Some(Rule::EchoFlags));
1574        assert_eq!(code_to_rule("SH-054"), Some(Rule::EchoFlags));
1575        assert_eq!(code_to_rule("X028"), Some(Rule::TrLowerRange));
1576        assert_eq!(code_to_rule("SH-058"), Some(Rule::TrLowerRange));
1577        assert_eq!(code_to_rule("X029"), Some(Rule::TrUpperRange));
1578        assert_eq!(code_to_rule("SH-059"), Some(Rule::TrUpperRange));
1579        assert_eq!(code_to_rule("X030"), Some(Rule::EchoBackslashEscapes));
1580        assert_eq!(code_to_rule("SH-061"), Some(Rule::EchoBackslashEscapes));
1581    }
1582}