From 38c0a3a6929f7da143ca73a456950856c1ae7c00 Mon Sep 17 00:00:00 2001 From: Esrom Date: Sat, 7 Nov 2026 16:13:17 -0800 Subject: [PATCH] fix: remove unused json_output parameter from AST commands --- src/interface/cli/ast_commands.py | 7 +--- src/interface/cli/main.py | 9 +++-- tests/unit/interface/cli/test_ast_commands.py | 34 +++++++++++++++++-- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/interface/cli/ast_commands.py b/src/interface/cli/ast_commands.py index ece5e9f2..d929cab1 100644 --- a/src/interface/cli/ast_commands.py +++ b/src/interface/cli/ast_commands.py @@ -315,9 +315,7 @@ def _read_file( return None, 2 -def ast_parse( - file_path: str, json_output: bool = True, root: str | None = None, quiet: bool = False -) -> int: +def ast_parse(file_path: str, root: str | None = None, quiet: bool = False) -> int: """Parse a markdown file and output the AST as JSON. Reads the file, parses it with JerryDocument, and prints a JSON object @@ -325,7 +323,6 @@ def ast_parse( Args: file_path: Path to the markdown file to parse. - json_output: Unused flag kept for API symmetry; output is always JSON. root: Optional ``--root`` containment override (BUG-010 Option C). See ``_read_file`` for semantics. quiet: Suppress stderr transparency notes and broad-root warnings @@ -497,7 +494,6 @@ def ast_validate( def ast_query( file_path: str, selector: str, - json_output: bool = True, root: str | None = None, quiet: bool = False, ) -> int: @@ -510,7 +506,6 @@ def ast_query( Args: file_path: Path to the markdown file to query. selector: The node type string to query (e.g., "heading", "blockquote"). - json_output: Unused flag kept for API symmetry; output is always JSON. root: Optional ``--root`` containment override (BUG-010 Option C). See ``_read_file`` for semantics. quiet: Suppress stderr transparency notes and broad-root warnings diff --git a/src/interface/cli/main.py b/src/interface/cli/main.py index b018043f..c03f6678 100644 --- a/src/interface/cli/main.py +++ b/src/interface/cli/main.py @@ -118,7 +118,7 @@ def main() -> int: elif args.namespace == "context": return _handle_context(args) elif args.namespace == "ast": - return _handle_ast(args, json_output) + return _handle_ast(args) elif args.namespace == "agents": return _handle_agents(args, json_output) elif args.namespace == "ci": @@ -390,7 +390,7 @@ def _handle_context(args: Any) -> int: return 1 -def _handle_ast(args: Any, json_output: bool) -> int: +def _handle_ast(args: Any) -> int: """Route ast namespace commands. Does not require the CLIAdapter; calls the domain layer directly via @@ -403,7 +403,6 @@ def _handle_ast(args: Any, json_output: bool) -> int: ``getattr(args, "root"/"quiet", None/False)`` and passed through to every command, matching the existing defensive pattern already used for ``schema``/``nav``. - json_output: Whether JSON output was requested (passed through to commands). Returns: Exit code: 0 (success), 1 (validation failure), 2 (parse error). @@ -432,7 +431,7 @@ def _handle_ast(args: Any, json_output: bool) -> int: quiet = getattr(args, "quiet", False) if args.command == "parse": - return ast_parse(args.file, json_output, root=root, quiet=quiet) + return ast_parse(args.file, root=root, quiet=quiet) elif args.command == "render": return ast_render(args.file, root=root, quiet=quiet) elif args.command == "validate": @@ -444,7 +443,7 @@ def _handle_ast(args: Any, json_output: bool) -> int: quiet=quiet, ) elif args.command == "query": - return ast_query(args.file, args.selector, json_output, root=root, quiet=quiet) + return ast_query(args.file, args.selector, root=root, quiet=quiet) elif args.command == "frontmatter": return ast_frontmatter(args.file, root=root, quiet=quiet) elif args.command == "modify": diff --git a/tests/unit/interface/cli/test_ast_commands.py b/tests/unit/interface/cli/test_ast_commands.py index 6594f6ae..f3c4152c 100644 --- a/tests/unit/interface/cli/test_ast_commands.py +++ b/tests/unit/interface/cli/test_ast_commands.py @@ -25,6 +25,7 @@ from __future__ import annotations +import inspect import json import sys import tempfile @@ -1175,7 +1176,7 @@ class FakeArgs: file = str(tmp_md_file) with patch("sys.stdout", new_callable=StringIO): - result = _handle_ast(FakeArgs(), json_output=False) + result = _handle_ast(FakeArgs()) assert result == 1 def test_handle_ast_unknown_command_prints_error_to_stderr_only( @@ -1191,7 +1192,7 @@ class FakeArgs: command = "nonexistent" file = str(tmp_md_file) - result = _handle_ast(FakeArgs(), json_output=False) + result = _handle_ast(FakeArgs()) captured = capsys.readouterr() assert result == 1 assert captured.out == "" @@ -2054,3 +2055,32 @@ def test_ast_commands_module_when_imported_then_get_repo_root_is_not_defined(sel not from this legacy single-root convenience accessor. Guard against silent reintroduction.""" assert not hasattr(ast_commands_module, "_get_repo_root") + + +# ============================================================================= +# GH #378: unused json_output parameter removed from the ast command path +# ============================================================================= +# +# ast_parse and ast_query always serialize their output as JSON; the +# json_output parameter they accepted was never read, and _handle_ast only +# existed to forward the global --json flag into them. These guards prevent +# silent reintroduction of the dead parameter. +# ============================================================================= + + +class TestJsonOutputParameterRemoved: + """GH #378: guard against reintroduction of the unused json_output parameter.""" + + def test_ast_parse_when_inspected_then_has_no_json_output_parameter(self) -> None: + """ast_parse must not expose json_output -- it always emits JSON.""" + assert "json_output" not in inspect.signature(ast_parse).parameters + + def test_ast_query_when_inspected_then_has_no_json_output_parameter(self) -> None: + """ast_query must not expose json_output -- it always emits JSON.""" + assert "json_output" not in inspect.signature(ast_query).parameters + + def test_handle_ast_when_inspected_then_has_no_json_output_parameter(self) -> None: + """_handle_ast must not accept json_output -- no ast command reads it.""" + from src.interface.cli.main import _handle_ast + + assert "json_output" not in inspect.signature(_handle_ast).parameters