Coverage for / home / runner / work / bijux-cli / bijux-cli / src / bijux_cli / cli / commands / help.py: 100%
54 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-01-26 17:59 +0000
« prev ^ index » next coverage.py v7.13.2, created at 2026-01-26 17:59 +0000
1# SPDX-License-Identifier: Apache-2.0
2# Copyright © 2025 Bijan Mousavi
4"""Pure help command logic (intent + payload builders).
6This module contains no IO, exit behavior, or policy resolution. It exposes
7pure helpers used by the help command runtime.
8"""
10from __future__ import annotations
12from dataclasses import dataclass
13import platform as _platform
14import sys
15import time
17import click
18import typer
20from bijux_cli.cli.core.command import ascii_safe, normalize_format
21from bijux_cli.core.enums import LogLevel, OutputFormat
22from bijux_cli.core.precedence import EffectiveConfig, OutputConfig
24_HUMAN = "human"
25_VALID_FORMATS = ("human", "json", "yaml")
28@dataclass(frozen=True)
29class HelpIntent:
30 """Resolved intent for the help command."""
32 tokens: list[str]
33 fmt_lower: str
34 format_value: OutputFormat | None
35 error_fmt: OutputFormat
36 include_runtime: bool
37 pretty: bool
38 quiet: bool
39 log_level: LogLevel
42def _build_help_intent(
43 tokens: list[str],
44 fmt: str,
45 effective: EffectiveConfig,
46 output: OutputConfig,
47) -> HelpIntent:
48 """Build a normalized help intent from raw CLI inputs."""
49 fmt_lower = fmt.strip().lower()
50 format_value = normalize_format(fmt)
51 error_fmt = format_value or OutputFormat.JSON
52 return HelpIntent(
53 tokens=tokens,
54 fmt_lower=fmt_lower,
55 format_value=format_value,
56 error_fmt=error_fmt,
57 include_runtime=output.include_runtime,
58 pretty=output.pretty,
59 quiet=effective.flags.quiet,
60 log_level=output.log_level,
61 )
64def _find_target_command(
65 ctx: typer.Context, path: list[str]
66) -> tuple[click.Command, click.Context] | None:
67 """Locate the Click command and context for a given command path."""
68 root_cmd: click.Command | None = ctx.parent.command if ctx.parent else None
69 if not root_cmd:
70 return None
72 current_cmd: click.Command | None = root_cmd
73 current_ctx = click.Context(root_cmd, info_name="bijux")
75 for token in path:
76 if not isinstance(current_cmd, click.Group):
77 return None
78 next_cmd = current_cmd.get_command(current_ctx, token)
79 if not next_cmd:
80 return None
81 current_ctx = click.Context(next_cmd, info_name=token, parent=current_ctx)
82 current_cmd = next_cmd
84 assert current_cmd is not None # noqa: S101 # nosec: B101
85 return current_cmd, current_ctx
88def _get_formatted_help(cmd: click.Command, ctx: click.Context) -> str:
89 """Return formatted help text for a command."""
90 help_text = cmd.get_help(ctx)
91 if (
92 hasattr(cmd, "context_settings")
93 and cmd.context_settings
94 and "-h" in cmd.context_settings.get("help_option_names", [])
95 and "-h, --help" not in help_text
96 ):
97 help_text = help_text.replace("--help", "-h, --help")
98 return help_text
101def _build_help_payload(
102 help_text: str, include_runtime: bool, started_at: float
103) -> dict[str, object]:
104 """Build a structured help payload for JSON/YAML output."""
105 payload: dict[str, object] = {"help": help_text}
106 if include_runtime:
107 return {
108 "help": payload["help"],
109 "python": ascii_safe(sys.version.split()[0], "python_version"),
110 "platform": ascii_safe(_platform.platform(), "platform"),
111 "runtime_ms": int((time.perf_counter() - started_at) * 1_000),
112 }
113 return payload
116__all__ = [
117 "HelpIntent",
118 "_HUMAN",
119 "_VALID_FORMATS",
120 "_build_help_payload",
121 "_build_help_intent",
122 "_find_target_command",
123 "_get_formatted_help",
124]