@@ -10,51 +10,167 @@ defmodule ExCoveralls.Ignore do
1010 Enum . map ( info , & do_filter / 1 )
1111 end
1212
13+ defmodule State do
14+ defstruct ignore_mode: :no_ignore ,
15+ coverage: [ ] ,
16+ coverage_buffer: [ ] ,
17+ warnings: [ ] ,
18+ last_marker_index: nil
19+ end
20+
1321 defp do_filter ( % { name: name , source: source , coverage: coverage } ) do
14- lines = String . split ( source , "\n " )
15- list = Enum . zip ( lines , coverage )
16- |> Enum . map_reduce ( :no_ignore , & check_and_swap / 2 )
17- |> elem ( 0 )
18- |> List . zip
19- |> Enum . map ( & Tuple . to_list ( & 1 ) )
22+ source_lines = String . split ( source , "\n " )
2023
21- [ source , coverage ] = parse_filter_list ( list )
22- % { name: name , source: source , coverage: coverage }
23- end
24+ processing_result =
25+ Enum . zip ( source_lines , coverage )
26+ |> Enum . with_index ( )
27+ |> Enum . reduce ( % State { } , & process_line / 2 )
28+ |> process_end_of_file ( )
2429
25- defp check_and_swap ( { line , coverage } , ignore ) do
26- {
27- coverage_for_line ( { line , coverage } , ignore ) ,
28- ignore_next? ( line , ignore )
29- }
30+ updated_coverage = processing_result . coverage |> List . flatten ( ) |> Enum . reverse ( )
31+ warnings = Enum . sort_by ( processing_result . warnings , & elem ( & 1 , 0 ) )
32+ % { name: name , source: source , coverage: updated_coverage , warnings: warnings }
3033 end
3134
32- defp parse_filter_list ( [ ] ) , do: [ "" , [ ] ]
33- defp parse_filter_list ( [ lines , coverage ] ) , do: [ Enum . join ( lines , "\n " ) , coverage ]
34-
35- defp coverage_for_line ( { line , coverage } , ignore ) do
36- if ignore == :no_ignore do
37- { line , coverage }
38- else
39- { line , nil }
35+ defp process_line ( { { source_line , coverage_line } , index } , state ) do
36+ case detect_ignore_marker ( source_line ) do
37+ :none -> process_regular_line ( coverage_line , index , state )
38+ :start -> process_start_marker ( coverage_line , index , state )
39+ :stop -> process_stop_marker ( coverage_line , index , state )
40+ :next_line -> process_next_line_marker ( coverage_line , index , state )
4041 end
4142 end
4243
43- defp ignore_next? ( line , ignore ) do
44+ defp detect_ignore_marker ( line ) do
4445 case Regex . run ( ~r/ coveralls-ignore-(start|stop|next-line)/ , line , capture: :all_but_first ) do
45- [ "start" ] -> :ignore_block
46- [ "stop" ] -> :no_ignore
47- [ "next-line" ] ->
48- case ignore do
49- :ignore_block -> ignore
50- _sth -> :ignore_line
51- end
52- _sth ->
53- case ignore do
54- :ignore_line -> :no_ignore
55- _sth -> ignore
56- end
46+ [ "start" ] -> :start
47+ [ "stop" ] -> :stop
48+ [ "next-line" ] -> :next_line
49+ _sth -> :none
5750 end
5851 end
5952
53+ defp process_regular_line (
54+ coverage_line ,
55+ _index ,
56+ state = % { ignore_mode: :no_ignore , coverage_buffer: [ ] }
57+ ) do
58+ % { state | coverage: [ coverage_line | state . coverage ] }
59+ end
60+
61+ defp process_regular_line ( _coverage_line , _index , state = % { ignore_mode: :ignore_line } ) do
62+ % { state | ignore_mode: :no_ignore , coverage: [ nil | state . coverage ] }
63+ end
64+
65+ defp process_regular_line ( _coverage_line , _index , state = % { ignore_mode: :ignore_block } ) do
66+ % { state | coverage: [ nil | state . coverage ] }
67+ end
68+
69+ defp process_start_marker (
70+ _coverage_line ,
71+ index ,
72+ state = % { ignore_mode: :no_ignore }
73+ ) do
74+ % {
75+ state
76+ | ignore_mode: :ignore_block ,
77+ coverage: [ nil | state . coverage ] ,
78+ last_marker_index: index
79+ }
80+ end
81+
82+ defp process_start_marker ( _coverage_line , index , state = % { ignore_mode: :ignore_block } ) do
83+ warning = { index , "unexpected ignore-start or missing previous ignore-stop" }
84+
85+ % {
86+ state
87+ | coverage: [ nil | state . coverage ] ,
88+ warnings: [ warning | state . warnings ] ,
89+ last_marker_index: index
90+ }
91+ end
92+
93+ defp process_start_marker ( _coverage_line , index , state = % { ignore_mode: :ignore_line } ) do
94+ warning = { state . last_marker_index , "redundant ignore-next-line right before an ignore-start" }
95+
96+ % {
97+ state
98+ | ignore_mode: :ignore_block ,
99+ coverage: [ nil | state . coverage ] ,
100+ warnings: [ warning | state . warnings ] ,
101+ last_marker_index: index
102+ }
103+ end
104+
105+ defp process_stop_marker ( _coverage_line , index , state = % { ignore_mode: :ignore_block } ) do
106+ % {
107+ state
108+ | ignore_mode: :no_ignore ,
109+ coverage: [ nil | state . coverage ] ,
110+ last_marker_index: index
111+ }
112+ end
113+
114+ defp process_stop_marker ( _coverage_line , index , state ) do
115+ warning = { index , "unexpected ignore-stop or missing previous ignore-start" }
116+
117+ % {
118+ state
119+ | ignore_mode: :no_ignore ,
120+ coverage: [ nil | state . coverage ] ,
121+ warnings: [ warning | state . warnings ] ,
122+ last_marker_index: index
123+ }
124+ end
125+
126+ defp process_next_line_marker (
127+ _coverage_line ,
128+ index ,
129+ state = % { ignore_mode: :no_ignore }
130+ ) do
131+ % {
132+ state
133+ | ignore_mode: :ignore_line ,
134+ coverage: [ nil | state . coverage ] ,
135+ last_marker_index: index
136+ }
137+ end
138+
139+ defp process_next_line_marker (
140+ _coverage_line ,
141+ index ,
142+ state = % { ignore_mode: :ignore_block }
143+ ) do
144+ warning = { index , "redundant ignore-next-line inside ignore block" }
145+
146+ % {
147+ state
148+ | coverage: [ nil | state . coverage ] ,
149+ warnings: [ warning | state . warnings ]
150+ }
151+ end
152+
153+ defp process_next_line_marker (
154+ _coverage_line ,
155+ index ,
156+ state = % { ignore_mode: :ignore_line }
157+ ) do
158+ warning = { index , "duplicated ignore-next-line" }
159+
160+ % {
161+ state
162+ | coverage: [ nil | state . coverage ] ,
163+ warnings: [ warning | state . warnings ] ,
164+ last_marker_index: index
165+ }
166+ end
167+
168+ defp process_end_of_file ( state = % { ignore_mode: :ignore_block } ) do
169+ warning =
170+ { state . last_marker_index , "ignore-start without a corresponding ignore-stop" }
171+
172+ % { state | warnings: [ warning | state . warnings ] }
173+ end
174+
175+ defp process_end_of_file ( state ) , do: state
60176end
0 commit comments