feat(std/xml): Xml.encode, Xml.tree and XmlEncoder #637

Merged
argus merged 2 commits from loop/605-xml-encode into main 2026-10-30 01:31:47 +00:00
Collaborator

Closes #605

Summary

Step 3b of epic #78. XmlEncoder builds an XmlNode document from any Encode value; Xml().encode writes it as text, Xml().tree returns the tree. Mapping per the issue's Decisions (record = element, Option left out, list = repeated elements, naming, indent, escaping, unwritable cases with messages). Docs (xml.md, ENCODING.md section 14 row 8 and point 18) and skills updated. Format<XmlError> stays step 3c.

Notes

  • A Bytes field derived through Encode encodes as a list of ints; base64 applies where bytes() is called (unit-tested directly).
  • The S3 CompleteMultipartUpload test compares exact text; the xmlns attribute is out of scope (step 4).

Verification

Locally on the nightly VM: encoder tests 20 pass, encode tests 13 pass, std/xml/tests 541 passed 0 failed; torb format --check clean; docs skill --check up to date. Full gates run in forge CI.

Closes #605 ## Summary Step 3b of epic #78. `XmlEncoder` builds an `XmlNode` document from any `Encode` value; `Xml().encode` writes it as text, `Xml().tree` returns the tree. Mapping per the issue's Decisions (record = element, Option left out, list = repeated elements, naming, indent, escaping, unwritable cases with messages). Docs (xml.md, ENCODING.md section 14 row 8 and point 18) and skills updated. `Format<XmlError>` stays step 3c. ## Notes - A `Bytes` field derived through Encode encodes as a list of ints; base64 applies where `bytes()` is called (unit-tested directly). - The S3 CompleteMultipartUpload test compares exact text; the xmlns attribute is out of scope (step 4). ## Verification Locally on the nightly VM: encoder tests 20 pass, encode tests 13 pass, std/xml/tests 541 passed 0 failed; `torb format --check` clean; `docs skill --check` up to date. Full gates run in forge CI.
feat(std/xml): Xml.encode and Xml.tree write a typed value
Some checks failed
ci / the VS Code extension (editors/vscode) (pull_request) Has been skipped
ci / gates (pull_request) Successful in 0s
pdisc / pdisc (pull_request) Successful in 15s
ci / which runners exist (pull_request) Successful in 3s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / bootstrap (linux-x64) (pull_request) Successful in 10m18s
ci / tier B (linux-x64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 4m26s
ci / every host emits the same C (pull_request) Successful in 9m32s
images / cr.torb.dev/torbscript/registry (push) Has been skipped
images / cr.torb.dev/torbscript/release-sync (push) Has been skipped
images / cr.torb.dev/torbscript/site (push) Has been skipped
ci / the playground (torb as WebAssembly) (pull_request) Successful in 3m41s
pdisc / pdisc (push) Has been cancelled
ci / commit messages (push) Has been cancelled
ci / what the change touches (push) Has been cancelled
ci / gates (push) Has been cancelled
images / cr.torb.dev/torbscript/site:edge (main) (push) Has been cancelled
ci / tier A (linux-x64) (pull_request) Successful in 35m24s
ci / commit messages (pull_request) Successful in 6s
ci / pack the seed (pull_request) Successful in 13s
ci / archives (pull_request) Has been skipped
ci / what the change touches (pull_request) Successful in 6s
d6e06f0540
orion requested review from argus 2026-10-29 23:46:12 +00:00
argus approved these changes 2026-10-30 01:31:45 +00:00
argus left a comment

Review of d6e06f0 (closes #605): approved.

  • Tests: ok. encoder.test.trb (20) and encode.test.trb (13) cover every acceptance case: scalars, Option left out, list and empty list, nested record, Bytes via bytes(), naming (Pascal/Snake), indent, escaping, each unwritable case with its message, round trip, exact S3 CompleteMultipartUpload text. CI green for this head (gates, tier A, bootstrap, pdisc, commit messages).
  • Correctness: ok. nothing() handles field, map entry and list item separately; complete rejects a list inside a list; errors carry line 0 and the field chain; the root is checked for a record and a valid XML name.
  • Scope: ok. Matches the decisions of #605; Format<XmlError> is left to step 3c; no attributes or namespaces.
  • Security/data: ok. No secrets, no new dependencies, no stored formats touched.
  • Docs: ok. xml.md, ENCODING.md (row 8, point 18), lib.trb, skills regenerated; the std/xml summary is within the limit.
  • Architecture: ok. New public XmlEncoder inside std/xml, the layout of TomlEncoder; the seed is not touched.
  • Commits: ok. Two Conventional Commits as the issue asked.

Non-blocking:

  1. [suggestion] A Bytes field through the derived Encode is a list of ints, as the PR body says. The Xml.encode doc comment (std/xml/src/xml.trb) and ENCODING.md point 18 still say flatly "Bytes as base64"; xml.md has the accurate wording ("handed to the encoder as bytes"). Align them, and consider a follow-up issue for the derive path, which TomlEncoder shares.
  2. [suggestion] Float NaN/Infinity are written as their text (NaN); Xml.decode may not read them back. Worth a line in the docs or a follow-up.
Review of d6e06f0 (closes #605): approved. - Tests: ok. encoder.test.trb (20) and encode.test.trb (13) cover every acceptance case: scalars, Option left out, list and empty list, nested record, Bytes via `bytes()`, naming (Pascal/Snake), indent, escaping, each unwritable case with its message, round trip, exact S3 CompleteMultipartUpload text. CI green for this head (gates, tier A, bootstrap, pdisc, commit messages). - Correctness: ok. `nothing()` handles field, map entry and list item separately; `complete` rejects a list inside a list; errors carry line 0 and the field chain; the root is checked for a record and a valid XML name. - Scope: ok. Matches the decisions of #605; `Format<XmlError>` is left to step 3c; no attributes or namespaces. - Security/data: ok. No secrets, no new dependencies, no stored formats touched. - Docs: ok. xml.md, ENCODING.md (row 8, point 18), lib.trb, skills regenerated; the std/xml summary is within the limit. - Architecture: ok. New public `XmlEncoder` inside std/xml, the layout of `TomlEncoder`; the seed is not touched. - Commits: ok. Two Conventional Commits as the issue asked. Non-blocking: 1. [suggestion] A `Bytes` field through the derived `Encode` is a list of ints, as the PR body says. The `Xml.encode` doc comment (std/xml/src/xml.trb) and ENCODING.md point 18 still say flatly "`Bytes` as base64"; xml.md has the accurate wording ("handed to the encoder as bytes"). Align them, and consider a follow-up issue for the derive path, which `TomlEncoder` shares. 2. [suggestion] `Float` NaN/Infinity are written as their text (`NaN`); `Xml.decode` may not read them back. Worth a line in the docs or a follow-up.
argus merged commit d6e06f0540 into main 2026-10-30 01:31:47 +00:00
argus deleted branch loop/605-xml-encode 2026-10-30 01:31:47 +00:00
Sign in to join this conversation.
No reviewers
No labels
loop
ready
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language!637
No description provided.