diff --git a/lib/rubocop/socketry/layout/consistent_blank_line_indentation.rb b/lib/rubocop/socketry/layout/consistent_blank_line_indentation.rb index 3ac40e8..318de58 100644 --- a/lib/rubocop/socketry/layout/consistent_blank_line_indentation.rb +++ b/lib/rubocop/socketry/layout/consistent_blank_line_indentation.rb @@ -49,6 +49,7 @@ def indentation(width) def on_new_investigation indentation_deltas = build_indentation_deltas current_level = 0 + semantic_level = 0 processed_source.lines.each_with_index do |line, index| line_number = index + 1 @@ -75,7 +76,16 @@ def on_new_investigation end end - current_level += delta + if delta > 0 + current_level += 1 + semantic_level += delta + elsif delta < 0 + semantic_level += delta + current_level = [current_level, semantic_level].min + end + + current_level = [current_level, 0].max + semantic_level = [semantic_level, 0].max end end @@ -87,10 +97,6 @@ def on_new_investigation def build_indentation_deltas Hash.new(0).tap do |deltas| walk_ast_for_indentation(processed_source.ast, deltas) - - # Cap deltas to a maximum of +1 or -1 per line to handle cases where - # multiple structures open/close on the same line (e.g., `[..., {`) - deltas.transform_values!{|delta| delta.nil? ? nil : delta.clamp(-1, 1)} end end diff --git a/releases.md b/releases.md index 87812b5..fa06af7 100644 --- a/releases.md +++ b/releases.md @@ -1,5 +1,9 @@ # Releases +## Unreleased + + - Fixed `Layout/ConsistentBlankLineIndentation` to preserve semantic indentation depth for same-line nested structures, avoiding negative indentation levels when later closing lines are processed. + ## v0.10.0 - Fixed `Layout/BlockDelimiterSpacing` to correctly treat a block as a statement (requiring space before `{`) when it is the sole body of a multi-line outer block or method/class/module definition. Previously, the absence of a `:begin` wrapper in the AST caused such blocks (e.g. `Async {foo}` or `let(:bar) {baz}` inside a `describe`/`context` block) to be misclassified as expression-context and have their space incorrectly removed. diff --git a/test/rubocop/socketry/layout/consistent_blank_line_indentation.rb b/test/rubocop/socketry/layout/consistent_blank_line_indentation.rb index 02c50cf..581dd93 100644 --- a/test/rubocop/socketry/layout/consistent_blank_line_indentation.rb +++ b/test/rubocop/socketry/layout/consistent_blank_line_indentation.rb @@ -830,4 +830,16 @@ def foo expect(offenses.first.message).to be(:include?, message) end end + + with "a top-level blank line after nested array and hash" do + let(:source) {"CONFIG = [[Foo, {\n\tbar: true\n}]\n]\n\nputs CONFIG\n"} + + it "does not crash when clamped deltas would otherwise make indentation negative" do + processed_source = RuboCop::ProcessedSource.new(source, RUBY_VERSION.to_f) + investigator = RuboCop::Cop::Commissioner.new([cop], [], raise_error: true) + report = investigator.investigate(processed_source) + offenses = report.offenses + expect(offenses).to be(:empty?) + end + end end