From bc8b0fbff71a2d40f09d3a85d6047457370b8ea9 Mon Sep 17 00:00:00 2001 From: Tristan Manchester Date: Fri, 17 Apr 2026 09:43:42 +0200 Subject: [PATCH] Preserve else chains in TS log cleanup --- .../typescript/fixers/logs_cleanup.py | 7 ++ .../typescript/tests/test_ts_fixers.py | 72 ++++++++++++++++++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/desloppify/languages/typescript/fixers/logs_cleanup.py b/desloppify/languages/typescript/fixers/logs_cleanup.py index c12c46096..c204bafc3 100644 --- a/desloppify/languages/typescript/fixers/logs_cleanup.py +++ b/desloppify/languages/typescript/fixers/logs_cleanup.py @@ -200,6 +200,13 @@ def _try_remove_multiline_block( new_lines.append(f"{indent}}}\n") return j + 1 if re.match(r"\s*(?:if|else\s+if)\s*\(", stripped): + next_line_idx = j + 1 + while next_line_idx < len(lines) and lines[next_line_idx].strip() == "": + next_line_idx += 1 + if next_line_idx < len(lines): + next_stripped = lines[next_line_idx].strip() + if next_stripped.startswith("else"): + return None return j + 1 return None diff --git a/desloppify/languages/typescript/tests/test_ts_fixers.py b/desloppify/languages/typescript/tests/test_ts_fixers.py index c5145b804..de4b60b07 100644 --- a/desloppify/languages/typescript/tests/test_ts_fixers.py +++ b/desloppify/languages/typescript/tests/test_ts_fixers.py @@ -3,8 +3,12 @@ Covers: __init__, common, imports, vars, logs, params, if_chain, useeffect. """ +import subprocess +import tempfile import textwrap +from pathlib import Path +from desloppify.languages.typescript.detectors.logs import detect_logs from desloppify.languages.typescript.fixers import __all__ from desloppify.languages.typescript.fixers.fixer_io import apply_fixer from desloppify.languages.typescript.fixers.if_chain import ( @@ -632,6 +636,73 @@ def test_result_metadata(self, tmp_path): assert "lines_removed" in r assert "log_count" in r + def test_orphaned_else_after_debug_log_removal(self): + """Removing a debug log must not leave an orphaned else block behind.""" + test_code = textwrap.dedent( + """\ + function process(data) { + if (data.debug) { + console.log('[DEBUG] processing data', data); + } + else { + processData(data); + } + } + """ + ) + + with tempfile.TemporaryDirectory() as tmpdir: + test_file = Path(tmpdir) / "test.ts" + test_file.write_text(test_code) + + result = detect_logs(Path(tmpdir)) + fix_debug_logs(result.entries, dry_run=False) + + proc = subprocess.run( + ["node", "--check", str(test_file)], + capture_output=True, + text=True, + check=False, + ) + assert proc.returncode == 0, ( + f"Output has syntax error:\n{test_file.read_text()}\n{proc.stderr}" + ) + + def test_orphaned_else_in_if_elseif_chain(self): + """Removing logs from an if/else-if chain must preserve the final else.""" + test_code = textwrap.dedent( + """\ + function process(data) { + if (data.debug) { + console.log('[DEBUG] processing data', data); + } + else if (data.trace) { + console.log('[TRACE] data', data); + } + else { + processData(data); + } + } + """ + ) + + with tempfile.TemporaryDirectory() as tmpdir: + test_file = Path(tmpdir) / "test.ts" + test_file.write_text(test_code) + + result = detect_logs(Path(tmpdir)) + fix_debug_logs(result.entries, dry_run=False) + + proc = subprocess.run( + ["node", "--check", str(test_file)], + capture_output=True, + text=True, + check=False, + ) + assert proc.returncode == 0, ( + f"Output has syntax error:\n{test_file.read_text()}\n{proc.stderr}" + ) + # ===================================================================== # params.py — _is_param_context, fix_unused_params @@ -719,4 +790,3 @@ def test_dry_run(self, tmp_path): _ = fix_unused_params(entries, dry_run=True) assert ts_file.read_text() == original -