class Object

Public Instance Methods

check() click to toggle source
# File lib/puppet-lint/plugins/check_strict_indent.rb, line 37
def check
  chars_per_indent = PuppetLint.configuration.chars_per_indent || 2
  indent = 0
  colon_indent = nil

  matches = match(tokens)

  tokens.select do |token|
    token.type == :NEWLINE
  end.reject do |token|
    # ignore newline at end of code
    token.next_token.nil?
  end.each do |token|
    temp_indent = 0

    # indent for open groups in the previous line
    open_groups = 0
    prev_token = token.prev_token
    while !prev_token.nil? and prev_token.type != :NEWLINE
      temp_indent += 1 if prev_token.type == :HEREDOC_OPEN
      if %i[LBRACE LBRACK
            LPAREN].include?(prev_token.type) && (matches[prev_token].nil? or matches[prev_token].line > prev_token.line)
        # left braces not matched in the same line increase indent
        open_groups += 1
      end
      prev_token = prev_token.prev_token
    end
    indent += open_groups

    # reset prev_token to last non-whitespace token on previous line
    prev_token = token.prev_token
    while !prev_token.nil? and (prev_token.type == :WHITESPACE or prev_token.type == :COMMENT)
      prev_token = prev_token.prev_token
    end

    # get type if available
    prev_type = prev_token.nil? ? nil : prev_token.type

    # handle change in indent based on last token
    case prev_type
    when :COLON
      if open_groups == 0
        if colon_indent.nil?
          # only indent for a colon when you haven't indented yet
          colon_indent = prev_token.line
          indent += 1
        else
          # you probably missed a semicolon two lines ago
        end
      end
    when :SEMIC
      unless colon_indent.nil?
        # only unindent for a semicolon when we've indented for a colon
        colon_indent = nil
        indent -= 1
      end
    when :EQUALS, :FARROW
      temp_indent += 1
    end

    # unindent for closing brackets in the current line
    next_token = token.next_token
    while !next_token.nil? and next_token.type != :NEWLINE
      if %i[RBRACE RBRACK RPAREN].include?(next_token.type)
        if !matches[next_token].nil? and matches[next_token].line < next_token.line
          # right braces matched in a previous line decrease indent
          indent -= 1
        end
        if next_token.type == :RBRACE and !colon_indent.nil? && (!matches[next_token].nil? and matches[next_token].line < colon_indent)
          # unindent at the end of resources if needed
          indent -= 1
          colon_indent = nil
        end
      end
      next_token = next_token.next_token
    end

    # obviously we have a problem
    if indent < 0
      notify :error, {
        message: 'Error calculating indent. Please file an issue at https://github.com/relud/puppet-lint-indent-check/issues',
        line: token.next_token.line,
        column: token.next_token.column,
      }
      # stop parsing indent
      break
    end

    # get actual indent
    actual = 0
    actual = if token.next_token.type == :INDENT
               token.next_token.value.length
             elsif !token.prev_token.nil? and token.prev_token.type == :HEREDOC
               token.prev_token.value.split("\n").last.length
             elsif !token.prev_token.nil? and token.prev_token.type == :HEREDOC_OPEN
               next_token.prev_token.value.split("\n").last.length
             else
               0
             end

    # expected indent
    expected = (indent + temp_indent) * chars_per_indent

    # oh no! incorrect indent!
    next unless actual != expected

    # no one cares if blank lines and comments are indented correctly
    next if %i[COMMENT NEWLINE].include?(token.next_token.type)

    notify :warning, {
      message: "indent should be #{expected} chars and is #{actual}",
      line: token.next_token.line,
      column: token.next_token.column,
      token: token.next_token,
      indent: expected,
    }
  end
end
fix(problem) click to toggle source
# File lib/puppet-lint/plugins/check_strict_indent.rb, line 156
def fix(problem)
  char_for_indent = ' '
  if %i[INDENT WHITESPACE].include?(problem[:token].type)
    problem[:token].value = char_for_indent * problem[:indent]
  else
    tokens.insert(
      tokens.find_index(problem[:token]),
      PuppetLint::Lexer::Token.new(:INDENT, char_for_indent * problem[:indent], problem[:line], problem[:column]),
    )
  end
end
match(tokens) click to toggle source
# File lib/puppet-lint/plugins/check_strict_indent.rb, line 5
def match(tokens)
  opening_token = {
    RBRACE: :LBRACE,
    RBRACK: :LBRACK,
    RPAREN: :LPAREN,
    HEREDOC: :HEREDOC_OPEN,
    HEREDOC_POST: :HEREDOC_OPEN,
  }
  open = {
    LBRACE: [],
    LBRACK: [],
    LPAREN: [],
    HEREDOC_OPEN: [],
  }

  matches = {}

  tokens.each do |token|
    if %i[LBRACE LBRACK LPAREN HEREDOC_OPEN].include?(token.type)
      open[token.type] << token
    elsif %i[RBRACE RBRACK RPAREN HEREDOC HEREDOC_POST].include?(token.type)
      match = open[opening_token[token.type]].pop
      unless match.nil?
        matches[token] = match
        matches[match] = token
      end
    end
  end

  matches
end