2929from __future__ import annotations
3030
3131import argparse
32- import html
3332import json
3433import os
3534import re
7776
7877GITHUB_HEADER = [
7978 "<table>" ,
80- "<tr><th>Test case</th><th>Δ</th><th>Location</th><th>Name</th><th>Message</th></tr>" ,
79+ "" ,
80+ "<tr>" ,
81+ "<th>Test case</th>" ,
82+ "<th>Diff</th>" ,
83+ "</tr>" ,
8184]
82- GITHUB_FOOTER = ["</table>" ]
85+ GITHUB_FOOTER = ["" , " </table>" ]
8386SUMMARY_NOTE = """
8487 Each test case represents one expected error annotation or a group of annotations
8588 sharing a tag. Counts are per test case, not per diagnostic — multiple diagnostics
@@ -167,11 +170,6 @@ def as_link(self) -> str:
167170 link = CONFORMANCE_URL .format (filename = file , line = self .positions .begin .line )
168171 return f"[{ file } :{ self .positions .begin .line } :{ self .positions .begin .column } ]({ link } )"
169172
170- def as_html_link (self ) -> str :
171- file = self .path .name
172- link = CONFORMANCE_URL .format (filename = file , line = self .positions .begin .line )
173- return f'<a href="{ link } ">{ self .positions .begin .line } :{ self .positions .begin .column } </a>'
174-
175173
176174@dataclass (kw_only = True , slots = True )
177175class TyDiagnostic :
@@ -334,71 +332,63 @@ def classify(self, source: Source) -> Classification:
334332 return Classification .TRUE_NEGATIVE
335333
336334
337- def tc_location_cell (tc : TestCase , * , rowspan : int , source : Source | None ) -> str :
338- """Build a <td> for the test-case-level location, spanning ``rowspan`` rows ."""
335+ def render_html_diff_row (tc : TestCase , * , source : Source | None ) -> list [ str ] :
336+ """Render a single HTML <tr> with a test-case link and a markdown diff block ."""
339337 all_diags = tc .old + tc .new if source is None else tc .diagnostics_by_source (source )
340338
341- if not all_diags :
342- return f'<td rowspan="{ rowspan } "></td>' if rowspan > 1 else "<td></td>"
343-
344- min_line = min (d .location .positions .begin .line for d in all_diags )
345- max_line = max (d .location .positions .begin .line for d in all_diags )
346- filename = all_diags [0 ].location .path .name
347-
348- if min_line == max_line :
349- url = CONFORMANCE_URL .format (filename = filename , line = min_line )
350- display = f"{ filename } :{ min_line } "
339+ if all_diags :
340+ min_line = min (d .location .positions .begin .line for d in all_diags )
341+ max_line = max (d .location .positions .begin .line for d in all_diags )
342+ filename = all_diags [0 ].location .path .name
343+ if min_line == max_line :
344+ url = CONFORMANCE_URL .format (filename = filename , line = min_line )
345+ display = f"{ filename } :{ min_line } "
346+ else :
347+ url = (
348+ f"{ CONFORMANCE_DIR_WITH_README } tests/{ filename } #L{ min_line } -L{ max_line } "
349+ )
350+ display = f"{ filename } :{ min_line } :{ max_line } "
351+ location = f"[{ display } ]({ url } )"
351352 else :
352- url = f"{ CONFORMANCE_DIR_WITH_README } tests/{ filename } #L{ min_line } -L{ max_line } "
353- display = f"{ filename } :{ min_line } :{ max_line } "
354-
355- rowspan_attr = f' rowspan="{ rowspan } "' if rowspan > 1 else ""
356- return f'<td{ rowspan_attr } ><a href="{ url } ">{ display } </a></td>'
357-
358-
359- def render_html_test_case_rows (tc : TestCase , * , source : Source | None ) -> list [str ]:
360- """Render one HTML <tr> per diagnostic for a test case.
361-
362- The test-case location cell spans all rows. The delta cell (-/+) spans
363- the diagnostics for its side. For changed entries, old rows come first,
364- then new rows, each group with its own spanning delta cell.
365- """
366-
367- def delta_cell (symbol : str , rowspan : int ) -> str :
368- rowspan_attr = f' rowspan="{ rowspan } "' if rowspan > 1 else ""
369- return f"<td{ rowspan_attr } >{ symbol } </td>"
370-
371- def diag_row (d : TyDiagnostic , prepend : str = "" ) -> str :
372- name = html .escape (d .check_name )
373- desc = html .escape (d .description .replace ("\\ |" , "|" ))
374- return (
375- f"<tr>{ prepend } "
376- f"<td>{ d .location .as_html_link ()} </td>"
377- f"<td>{ name } </td>"
378- f"<td>{ desc } </td>"
379- f"</tr>"
380- )
381-
382- def render_group (
383- diags : list [TyDiagnostic ], symbol : str , loc_prefix : str = ""
384- ) -> None :
385- for i , d in enumerate (diags ):
386- prepend = (loc_prefix + delta_cell (symbol , len (diags ))) if i == 0 else ""
387- rows .append (diag_row (d , prepend ))
388-
389- rows : list [str ] = []
353+ location = tc .key
390354
355+ diff_lines = []
391356 if source is None :
392- old_diags , new_diags = tc .old , tc .new
393- loc = tc_location_cell (tc , rowspan = len (old_diags ) + len (new_diags ), source = None )
394- render_group (old_diags , "-" , loc )
395- render_group (new_diags , "+" )
357+ for d in tc .old :
358+ diff_lines .append (
359+ f"-{ d .severity_for_display } [{ d .check_name } ] { d .description } "
360+ )
361+ for d in tc .new :
362+ diff_lines .append (
363+ f"+{ d .severity_for_display } [{ d .check_name } ] { d .description } "
364+ )
396365 else :
397- diags = tc .diagnostics_by_source (source )
398- loc = tc_location_cell (tc , rowspan = len (diags ), source = source )
399- render_group (diags , "-" if source == Source .OLD else "+" , loc )
366+ sign = "-" if source == Source .OLD else "+"
367+ for d in tc .diagnostics_by_source (source ):
368+ diff_lines .append (
369+ f"{ sign } { d .severity_for_display } [{ d .check_name } ] { d .description } "
370+ )
400371
401- return rows
372+ return [
373+ "" ,
374+ "<tr>" ,
375+ "" ,
376+ "<td>" ,
377+ "" ,
378+ location ,
379+ "" ,
380+ "</td>" ,
381+ "" ,
382+ "<td>" ,
383+ "" ,
384+ "```diff" ,
385+ * diff_lines ,
386+ "```" ,
387+ "" ,
388+ "</td>" ,
389+ "" ,
390+ "</tr>" ,
391+ ]
402392
403393
404394def render_diff_row (diagnostics : list [TyDiagnostic ], * , removed : bool = False ) -> str :
@@ -714,7 +704,7 @@ def render_test_cases(
714704 lines .append (render_diff_row (tc .old , removed = True ))
715705 lines .append (render_diff_row (tc .new , removed = False ))
716706 else :
717- lines .extend (render_html_test_case_rows (tc , source = None ))
707+ lines .extend (render_html_diff_row (tc , source = None ))
718708 else :
719709 if format == "diff" :
720710 lines .append (
@@ -724,7 +714,7 @@ def render_test_cases(
724714 )
725715 )
726716 else :
727- lines .extend (render_html_test_case_rows (tc , source = source ))
717+ lines .extend (render_html_diff_row (tc , source = source ))
728718
729719 if format == "diff" :
730720 lines .append ("```" )
0 commit comments