You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
vibed/nbd/.beans/nbd-mkkm--add-xml-output-fo...

108 lines
3.2 KiB
Markdown

---
# nbd-mkkm
title: Add --xml output format that wraps each ticket section in XML tags
status: todo
type: feature
priority: low
created_at: 2026-03-10T23:30:30Z
updated_at: 2026-03-10T23:30:30Z
---
## Background
From `nbd/TODO.md`:
> Add a `--xml` output format that prints tickets with XML around each section to make it easier to parse metadata.
Unlike `--json` (which is a complete, structured parse), the XML format adds lightweight tags around each metadata field in the human-readable output. This makes it trivial for scripts to extract specific fields using simple text tools (e.g., `grep`, `sed`, XPath) without pulling in a full JSON parser.
## Intended XML format
For a single ticket (`nbd read <id> --xml`):
```xml
<ticket>
<id>a3f9c2</id>
<title>Fix login bug</title>
<priority>8</priority>
<status>in_progress</status>
<type>bug</type>
<dependencies>
<dep>b7d41e</dep>
<dep>c9e823</dep>
</dependencies>
<body>Users cannot log in with email addresses containing +</body>
</ticket>
```
For a list (`nbd list --xml`):
```xml
<tickets>
<ticket>...</ticket>
<ticket>...</ticket>
</tickets>
```
## Implementation
### `src/main.rs`
Add a global `--xml` flag to the `Cli` struct, parallel to `--json`:
```rust
/// Output XML instead of a human-readable table.
#[arg(long, global = true)]
xml: bool,
```
Precedence: if both `--json` and `--xml` are supplied, `--json` wins (or return an error — TBD, but JSON-first is simpler).
Pass `cli.xml` through `dispatch` to every command handler, alongside `cli.json`.
Each command handler signature gains an `xml: bool` parameter. When `xml` is true and `json` is false, call the new `display::print_ticket_xml` / `display::print_list_xml` functions.
### `src/display.rs`
Add:
- `format_ticket_xml(ticket: &Ticket) -> String` — serialises a single ticket as XML
- `print_ticket_xml(ticket: &Ticket)` — wraps `format_ticket_xml` + `println!`
- `format_list_xml(tickets: &[Ticket]) -> String` — wraps list in `<tickets>`
- `print_list_xml(tickets: &[Ticket])`
XML escaping: at minimum, escape `&`, `<`, `>`, `"`, `'` in field values. Use a small helper `xml_escape(s: &str) -> String` rather than pulling in an XML crate.
For `dependencies`: render each as a `<dep>` child element.
### `src/tests.rs`
Add unit tests:
- `format_ticket_xml` with a ticket that has special characters in the title and body (`&`, `<`, `>`)
- `format_ticket_xml` with empty dependencies
- `format_ticket_xml` with multiple dependencies
- `format_list_xml` with zero and multiple tickets
### `tests/integration.rs`
Add integration tests:
- `nbd read <id> --xml` returns valid XML containing the ticket's fields
- `nbd list --xml` returns valid XML wrapping multiple tickets
- `nbd create ... --xml` returns the created ticket as XML
- `nbd update ... --xml` returns the updated ticket as XML
## Scope
All commands that support `--json` should also support `--xml`:
- `nbd create`
- `nbd read`
- `nbd list`
- `nbd update`
- `nbd ready`
- `nbd next`
- `nbd archive`
- `nbd migrate`
- `nbd graph` (the JSON graph format has a defined structure; XML should mirror it)
- `nbd claude-md` (wrap snippet in `<snippet>` tag)
- `nbd init` (wrap root path in `<init>`)