class Object

Public Instance Methods

check() click to toggle source
# File lib/puppet-lint/plugins/check_array_formatting.rb, line 95
def check
  # Create an instance-scope enumerator to walk through the Puppet manifest
  @manifest = tokens.each
  loop do
    token = @manifest.next
    next unless [:LBRACK].include?(token.type)

    # Found an array!  Send if off for processing unless it's actually a Classref.
    # We can disregard the return, becuase this is a top level array, and has no 'parent' to affect
    process_array unless %i[CLASSREF TYPE].include?(token.prev_code_token.type)
  end
end
fix(problem) click to toggle source
# File lib/puppet-lint/plugins/check_array_formatting.rb, line 108
def fix(problem)
  token_index = tokens.find_index(problem[:token])
  case problem[:message]
  when 'parsing error'
    # Truth table says we should never get here
    raise PuppetLint::NoFix
  when 'unexpected newline'
    # If we delete the INDENT first, we change the index of the offending token,
    # so we need to do the token first, then the INDENT
    tokens.delete_at(token_index)
    # If the previous token is an Indent, we'll want to delete that too
    tokens.delete_at(token_index - 1) if [:INDENT].include?(problem[:token].prev_token.type)
  when 'expected newline before element', 'expected newline before close'
    # If the preceeding token is a whitespace, replace it with a newline instead
    # so that we don't end up with trailing whitespaces
    if %i[WHITESPACE INDENT].include?(problem[:token].prev_token.type)
      problem[:token].prev_token.type = :NEWLINE
    else
      # Create a new Puppet Token object and insert it into the Puppet manifest in the correct location.
      # The location specified in Token.new() apparently doesn't matter since we're manually inserting it
      # into the Tokens array at the proper position using token_index.
      tokens.insert(token_index, PuppetLint::Lexer::Token.new(:NEWLINE, '\n', 0, 0))
    end
  end
end
process_array() click to toggle source
# File lib/puppet-lint/plugins/check_array_formatting.rb, line 2
def process_array
  # When we arrive here, the @manifest enumerator is "pointing" to
  # the opening LBRACK.  Start by iterating that to point to the
  # first element of the array:
  token = @manifest.next
  manifest_array = []
  len_of_nested_array = 0

  # Scan through the manifest until we encounter a RBRACK to close this array
  until [:RBRACK].include?(token.type) || token.nil?
    # If we encounter an LBRACK, we need to get our recursion on
    if [:LBRACK].include?(token.type)
      # Push the opening of the array as a placeholder unless the last token was a classref.
      # If it was, it was already pushed, so skip pushing.
      # We want to treat a classref and an array opening as a single token.
      manifest_array.push token unless %i[CLASSREF TYPE].include?(token.prev_code_token.type)
      # Recursively process this nested array.
      # Store return so we know if the child array was processed or not.
      len_of_nested_array = process_array
    # If we encounter something _other_ than COMMA, WHITESPACE, or INDENT, push it.
    # These don't include NEWLINE(s), which is what we need to keep track of.
    elsif !%i[COMMA WHITESPACE INDENT].include?(token.type)
      manifest_array.push token
    end
    # Advance.  (We're still looking for that RBRACK)
    token = @manifest.next
  end

  # We've found the RBRACK, and built a copy of the array in the Puppet manifest in the
  # local variable manifest_array.  Before we start validating, let's try to return early.
  #
  # Check the number of objects (tokens + newlines) we found, including child arrays.
  # If it's one or less, we can leave and return that we're *not* formatting
  return manifest_array.length if (manifest_array.length < 2) && (len_of_nested_array < 2)

  # Array is 2 or more elements. Time to validate it.
  #
  # First element of the array should be a NEWLINE.
  prev_token_was_newline = false

  # Start iterating our rebuilt array
  manifest_array.each_index do |x|
    if !prev_token_was_newline && [:NEWLINE].include?(manifest_array[x].type)
      # We were expecting a newline, so yay
      prev_token_was_newline = true
    elsif prev_token_was_newline && ![:NEWLINE].include?(manifest_array[x].type)
      # We were expecting something other than a newline, so yay
      prev_token_was_newline = false
    elsif !prev_token_was_newline && ![:NEWLINE].include?(manifest_array[x].type)
      # We were expecting a newline. :-(
      notify :warning,
             message: 'expected newline before element',
             line: manifest_array[x].line,
             column: manifest_array[x].column,
             token: manifest_array[x]
      # prev_token_was_newline is already false, so this isn't required
      # prev_token_was_newline = false
    elsif prev_token_was_newline && [:NEWLINE].include?(manifest_array[x].type)
      # We got an extra newline. Let's fix that up while we're at it.
      notify :warning,
             message: 'unexpected newline',
             line: manifest_array[x].line,
             column: manifest_array[x].column,
             token: manifest_array[x]
      # prev_token_was_newline is already true, so this isn't required
      # prev_token_was_newline = true
    else
      # Something has gone horribly wrong.  The truth table says we should never be here.
      notify :error,
             message: 'parsing error',
             line: manifest_array[x].line,
             column: manifest_array[x].column
    end
    # Next manifest_array item
  end

  # All elements of the array are done.
  # If the last token (not including the RBRACK) wasn't a newline, throw a warning.
  # Since we previously used token to scan forward to the ],
  # token is already pointing to the offending ].
  if !prev_token_was_newline # rubocop:disable NegatedIf "I find this clearer than `unless prev_token_was_newline`"
    notify :warning,
           message: 'expected newline before close',
           line: token.line,
           column: token.column,
           token: token
  end

  # Return the length of the array so we can make assumptions about
  # whether we're formatting or not
  manifest_array.length
end