Class: SasLinter::Rules::ChooseOneTemplate

Inherits:
SasLinter::Rule show all
Defined in:
lib/sas_linter/rules/choose_one_template.rb

Overview

Flag SAS sources that ship with the “CHOOSE ONE OF THE BELOW STATEMENTS” banner. The banner introduces a block of mutually-exclusive validity guards (typically ‘[USE FOR HC OR CHA WITH FS]`, `[USE FOR LTCF]`, `[USE FOR CHA WITHOUT FS]`, etc.), all commented out, and asks the downstream consumer to pick one before the source will work.

Why it’s an antipattern:

- The source is broken-by-default — every consumer must mutate it
  before use.
- SAS won't error on the dangling `end;` of the (also-commented)
  block, but the algorithm runs unguarded if no variant is picked.
- The deployment-context decision should belong to a config file or
  a separate per-context source variant, not to a comment-toggle
  buried in the middle of the algorithm.

Companion rule: ‘commented_out_guard` flags the individual disabled guards. This rule flags the banner that introduces them, so we can find every file that ships in the multi-template state regardless of whether any variant has already been activated.

Constant Summary collapse

TT =
SasLexer::Lexer::TokenType
TC =
SasLexer::Lexer::TokenChannel
/CHOOSE\s+ONE\s+OF\s+THE\s+BELOW\s+STATEMENTS/i

Instance Attribute Summary

Attributes inherited from SasLinter::Rule

#autofix

Instance Method Summary collapse

Methods inherited from SasLinter::Rule

all, #autofix?, description, fetch, from_config, inherited, #initialize, register, registry, rule_id, severity, supports_autofix?

Constructor Details

This class inherits a constructor from SasLinter::Rule

Instance Method Details

#check(_tokens, path:, all_tokens: nil, source: nil) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/sas_linter/rules/choose_one_template.rb', line 39

def check(_tokens, path:, all_tokens: nil, source: nil) # rubocop:disable Lint/UnusedMethodArgument
  return [] unless all_tokens

  all_tokens.filter_map do |tok|
    next unless tok[:channel] == TC::COMMENT
    next unless tok[:type] == TT::COMMENT_STAT
    next unless tok[:text] =~ BANNER

    finding(
      line: tok[:start_line],
      column: tok[:start_column] + 1,
      message: "'CHOOSE ONE OF THE BELOW STATEMENTS' banner — source is " \
               "broken-by-default; the alternative validity guards below " \
               "are all commented out so every consumer must edit this " \
               "file. Pick one variant, delete the others, and remove " \
               "this banner.",
      path: path
    )
  end
end