Skip to content

Commit 4fb8d3f

Browse files
committed
Fix SpaceAfterComma to not infinite loop on multline map literals
Fixes #642
1 parent a3c28b1 commit 4fb8d3f

File tree

4 files changed

+30
-9
lines changed

4 files changed

+30
-9
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
* Add `placeholder`, `-moz-*`, `-ms-*`, and `-webkit-*` to `PseudoElement`
66
linter
7+
* Fix `SpaceAfterComma` to not infinite loop on map literals as arguments
8+
spanning multiple lines
79

810
## 0.43.0
911

lib/scss_lint/linter.rb

+2
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ def character_at(source_position, offset = 0)
181181
actual_line = source_position.line - 1
182182
actual_offset = source_position.offset + offset - 1
183183

184+
return nil if actual_offset < 0
185+
184186
engine.lines.size > actual_line && engine.lines[actual_line][actual_offset]
185187
end
186188

lib/scss_lint/linter/space_after_comma.rb

+14-9
Original file line numberDiff line numberDiff line change
@@ -78,19 +78,18 @@ def check_commas_after_args(args, arg_type)
7878
# Sometimes the line we're looking at doesn't even contain a comma!
7979
next unless engine.lines[arg.line - 1].include?(',')
8080

81-
offset = find_comma_offset(arg)
81+
comma_position = find_comma_position(arg)
8282

8383
# Check for space or newline after comma (we allow arguments to be split
8484
# up over multiple lines).
8585
spaces = 0
86-
while (char = character_at(arg.source_range.end_pos, offset + 1)) == ' '
86+
while (char = character_at(comma_position, spaces + 1)) == ' '
8787
spaces += 1
88-
offset += 1
8988
end
9089
next if char == "\n" || # Ignore trailing spaces
9190
valid_spaces_after_comma?(spaces)
9291

93-
add_lint arg, "Commas in #{arg_type} should be followed by a single space"
92+
add_lint comma_position, "Commas in #{arg_type} should be followed by a single space"
9493
end
9594
end
9695

@@ -100,20 +99,26 @@ def check_commas_after_args(args, arg_type)
10099
# source range. Thus we need to start at the indicated range, and check
101100
# left and right of that range, gradually moving further outward until
102101
# we find the comma.
103-
def find_comma_offset(arg)
102+
def find_comma_position(arg) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
104103
offset = 0
104+
pos = arg.source_range.end_pos
105105

106-
if character_at(arg.source_range.end_pos, offset) != ','
106+
if character_at(pos, offset) != ','
107107
loop do
108108
offset += 1
109-
break if character_at(arg.source_range.end_pos, offset) == ','
109+
break if (right_char = character_at(pos, offset)) == ','
110110
offset = -offset
111-
break if character_at(arg.source_range.end_pos, offset) == ','
111+
break if (left_char = character_at(pos, offset)) == ','
112112
offset = -offset
113+
114+
next unless right_char.nil? && left_char.nil?
115+
offset = 0
116+
pos = Sass::Source::Position.new(pos.line + 1, 1)
117+
break if character_at(pos, offset) == ','
113118
end
114119
end
115120

116-
offset
121+
Sass::Source::Position.new(pos.line, pos.offset + offset)
117122
end
118123
end
119124
end

spec/scss_lint/linter/space_after_comma_spec.rb

+12
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,18 @@
334334
it { should_not report_lint }
335335
end
336336
end
337+
338+
context 'when map literal spans multiple lines' do
339+
let(:scss) { <<-SCSS }
340+
@include mixin('arg1', (
341+
key1: 'arg2-key1-value',
342+
key2: 'arg2-key2-value'
343+
),$arg3: 'arg3-value', $arg4: 'arg4-value'
344+
);
345+
SCSS
346+
347+
it { should report_lint line: 4 }
348+
end
337349
end
338350

339351
context 'when more than one space is preferred' do

0 commit comments

Comments
 (0)