uri: lead with methods for form and percent coding (slice of #146) #179

Closed
opened 2026-10-08 07:03:42 +00:00 by orion · 5 comments
Collaborator

Goal

std/uri form and percent coding are used as methods: text.formDecoded(), pairs.formEncoded(), text.percentDecoded().

Part of #146 (methods are the preferred API style; owner direction 2026-10-06, first applied in #96 as Digest.equalsConstantTime with constantTimeEqual kept as a thin wrapper). This slice follows exactly that pattern.

Functions in scope

formDecoded (String), formEncoded (List<(String, String)>), percentDecoded (String) in std/uri. Keep as free functions: route (combines a template and a case, no single receiver) and the undocumented byte/character helpers in characters.trb (internal; see the open question on #146). Not marked ready yet: the ready buffer is full (4); label it when a slot frees.

Source (pinned record)

  • docs/standard-library/uri.md, URI.md; no design record fixes the API shape
  • Extension members are named where they are used (CONCEPT, "Extension Methods", pinned); callers use the method like any member. If an extend without a trait on a type of another package turns out not to work in std/, stop and re-plan instead of working around it.

Acceptance criteria

  • std/uri provides String.formDecoded(), List<(String, String)>.formEncoded() and String.percentDecoded() with the current result types
  • Tests (std/uri form and bridges test files): method result equals free function result on the existing vectors, including malformed escapes
  • Each free function stays and becomes a thin wrapper that only calls the method; its signature, behaviour and existing tests are unchanged. It is not marked deprecated here (the deprecation path is an open owner decision on #146).
  • The module's documentation page under docs/standard-library/ leads with the method in every example; the wrapper is listed as the older spelling. Examples are checked with trb check; skills/ is regenerated.
  • No caller outside the module changes (compiler/src and tools/ keep calling the wrapper).

Seed

No. Ordinary TorbScript in std/ only: no syntax change, no new native, no driver flag, no std name the compiler looks up by string. If that turns out wrong, stop and re-plan (two commits, seed refresh).

Size

One PR, one Conventional Commit (refactor(<module>): ... or feat(<module>): ...), tests and docs in the same commit.

Dependencies

Tracking epic: #146. No other dependency; independent of the other module slices.

## Goal `std/uri` form and percent coding are used as methods: `text.formDecoded()`, `pairs.formEncoded()`, `text.percentDecoded()`. Part of #146 (methods are the preferred API style; owner direction 2026-10-06, first applied in #96 as `Digest.equalsConstantTime` with `constantTimeEqual` kept as a thin wrapper). This slice follows exactly that pattern. ## Functions in scope `formDecoded` (`String`), `formEncoded` (`List<(String, String)>`), `percentDecoded` (`String`) in `std/uri`. Keep as free functions: `route` (combines a template and a case, no single receiver) and the undocumented byte/character helpers in `characters.trb` (internal; see the open question on #146). Not marked `ready` yet: the ready buffer is full (4); label it when a slot frees. ## Source (pinned record) - [docs/standard-library/uri.md](https://git.torb.dev/torbscript/language/src/commit/129f1574e8ad4c9c691306808eb39900e77d4fc2/docs/standard-library/uri.md), [URI.md](https://git.torb.dev/torbscript/language/src/commit/129f1574e8ad4c9c691306808eb39900e77d4fc2/docs/design/URI.md); no design record fixes the API shape - Extension members are named where they are used (CONCEPT, "Extension Methods", [pinned](https://git.torb.dev/torbscript/language/src/commit/129f1574e8ad4c9c691306808eb39900e77d4fc2/CONCEPT.md)); callers `use` the method like any member. If an `extend` without a trait on a type of another package turns out not to work in `std/`, stop and re-plan instead of working around it. ## Acceptance criteria - [ ] `std/uri` provides `String.formDecoded()`, `List<(String, String)>.formEncoded()` and `String.percentDecoded()` with the current result types - [ ] Tests (`std/uri` form and bridges test files): method result equals free function result on the existing vectors, including malformed escapes - [ ] Each free function stays and becomes a thin wrapper that only calls the method; its signature, behaviour and existing tests are unchanged. It is **not** marked `deprecated` here (the deprecation path is an open owner decision on #146). - [ ] The module's documentation page under `docs/standard-library/` leads with the method in every example; the wrapper is listed as the older spelling. Examples are checked with `trb check`; `skills/` is regenerated. - [ ] No caller outside the module changes (`compiler/src` and `tools/` keep calling the wrapper). ## Seed No. Ordinary TorbScript in `std/` only: no syntax change, no new native, no driver flag, no std name the compiler looks up by string. If that turns out wrong, stop and re-plan (two commits, seed refresh). ## Size One PR, one Conventional Commit (`refactor(<module>): ...` or `feat(<module>): ...`), tests and docs in the same commit. ## Dependencies Tracking epic: #146. No other dependency; independent of the other module slices.
Author
Collaborator

[loop:torbscript] scope update from the owner decision on #146 (torben, 2026-10-08): the free functions covered by this slice are removed in the same PR that adds the methods, not kept as wrappers and not marked deprecated. Migrate every caller in the repo (std, tests, examples, docs) to the method in the same PR. No lint migration rule needed.

[loop:torbscript] scope update from the owner decision on #146 (torben, 2026-10-08): the free functions covered by this slice are **removed** in the same PR that adds the methods, not kept as wrappers and not marked `deprecated`. Migrate every caller in the repo (std, tests, examples, docs) to the method in the same PR. No lint migration rule needed.
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261008 until 2026-10-08T11:36:00Z

[loop:torbscript] claim refine by session:loop-torbscript-20261008 until 2026-10-08T11:36:00Z
Author
Collaborator

[loop:torbscript] refine: ready. Checked at main 4a675e7 against ROADMAP, docs/design/URI.md, CONCEPT "Extension Methods" and the Open Questions (nothing blocks; deprecation path decided on #146).

Acceptance criteria (supersede the wrapper bullets in the body, per the scope-update comment)

  • String.formDecoded(): List<(String, String)>, List<(String, String)>.formEncoded(): String and String.percentDecoded(): Result<String, UriError> exist in std/uri with the current result types and behaviour.
  • The free functions formDecoded, formEncoded, percentDecoded are removed; no wrapper, no deprecated, no lint rule. Keep free: route, percentDecodedBytes and the other helpers of characters.trb.
  • Tests in std/uri/tests/bridges.test.trb are rewritten to the method spelling on the existing vectors (malformed escapes, invalid UTF-8, empty input, round trip) and still pass.
  • Docs lead with the methods and trb check passes on the examples: docs/standard-library/uri.md (frontmatter members list lines 24-25, import line 54, signatures at 312-314, prose at 120), the doc comments in form.trb/characters.trb, the docs/design/URI.md signature block and prose (lines ~330, 749-755, 796-799, 814, including segments().map(percentDecoded)); skills/torbscript-networking/references/standard-library/uri.md regenerated.

Free functions to remove: formDecoded (std/uri/src/form.trb:18), formEncoded (form.trb:71), percentDecoded (std/uri/src/characters.trb:249).

Callers to migrate (all inside std/uri; no caller in compiler/src, tools, examples, benchmarks or tests/conformance): uri.trb (lines ~14-15 imports, 742, 750, 769 formEncoded pairs, 928), template.trb (imports at 9-10, calls at 386-387, 865, 910), tests/bridges.test.trb, docs above. Not a caller: the local percentDecoded in std/yaml/src/scanner.trb:760 is a private function of its own with a different signature; leave it.

Where the methods are declared (lesson of #182, and #178): a method is found in the module a use names. Re-exported members only work through public use List.x from "./file" imported by the std/uri package path (as List.plainText from "std/markdown" does today); importing a re-export through a relative ../src/lib path fails (#182, open). Plan: declare extend String { formDecoded, percentDecoded } and extend List<(String, String)> { formEncoded } next to their bodies in form.trb and characters.trb, re-export in std/uri/src/lib.trb with public use String.formDecoded, List.formEncoded from "./form" and public use String.percentDecoded from "./characters" (replacing lines 27-28); internal callers and tests import from the declaring file (./form, ./characters, tests ../src/form, ../src/characters), docs and anything external from "std/uri". If an extend with a generic/tuple receiver in form.trb fails the seed's native back end (as List<MarkdownInline> did in lib.trb), move that one declaration as #178 did and say so in the PR; if the std/uri re-export import does not check, declare in lib.trb as compression and encoding do. Do not work around #182 in the compiler in this PR.

Pinned records: docs/standard-library/uri.md, docs/design/URI.md, CONCEPT.md "Extension Methods" at 129f1574e8. No design record fixes the API shape.

Seed: no (std only; no syntax change, no native, no driver flag; the names formDecoded/formEncoded/percentDecoded are not looked up by the compiler, wellknown.trb only names the types). Stop and re-plan if that proves wrong.
Size: one PR, one commit refactor(uri): make formDecoded, formEncoded and percentDecoded methods and remove the functions. Note: the ready buffer already holds #170-#172 and #177, so this is the fifth; implementation order stays oldest first.
Implementer model: sonnet/medium (std and docs only). Worker usage for this refine: about 60k tokens (sonnet).

next: implement

[loop:torbscript] refine: ready. Checked at main 4a675e7 against ROADMAP, docs/design/URI.md, CONCEPT "Extension Methods" and the Open Questions (nothing blocks; deprecation path decided on #146). **Acceptance criteria** (supersede the wrapper bullets in the body, per the scope-update comment) - `String.formDecoded(): List<(String, String)>`, `List<(String, String)>.formEncoded(): String` and `String.percentDecoded(): Result<String, UriError>` exist in `std/uri` with the current result types and behaviour. - The free functions `formDecoded`, `formEncoded`, `percentDecoded` are removed; no wrapper, no `deprecated`, no lint rule. Keep free: `route`, `percentDecodedBytes` and the other helpers of `characters.trb`. - Tests in `std/uri/tests/bridges.test.trb` are rewritten to the method spelling on the existing vectors (malformed escapes, invalid UTF-8, empty input, round trip) and still pass. - Docs lead with the methods and `trb check` passes on the examples: `docs/standard-library/uri.md` (frontmatter members list lines 24-25, import line 54, signatures at 312-314, prose at 120), the doc comments in `form.trb`/`characters.trb`, the `docs/design/URI.md` signature block and prose (lines ~330, 749-755, 796-799, 814, including `segments().map(percentDecoded)`); `skills/torbscript-networking/references/standard-library/uri.md` regenerated. **Free functions to remove:** `formDecoded` (std/uri/src/form.trb:18), `formEncoded` (form.trb:71), `percentDecoded` (std/uri/src/characters.trb:249). **Callers to migrate (all inside `std/uri`; no caller in compiler/src, tools, examples, benchmarks or tests/conformance):** `uri.trb` (lines ~14-15 imports, 742, 750, 769 `formEncoded pairs`, 928), `template.trb` (imports at 9-10, calls at 386-387, 865, 910), `tests/bridges.test.trb`, docs above. Not a caller: the local `percentDecoded` in `std/yaml/src/scanner.trb:760` is a private function of its own with a different signature; leave it. **Where the methods are declared (lesson of #182, and #178):** a method is found in the module a `use` names. Re-exported members only work through `public use List.x from "./file"` imported by the `std/uri` package path (as `List.plainText` from "std/markdown" does today); importing a re-export through a relative `../src/lib` path fails (#182, open). Plan: declare `extend String { formDecoded, percentDecoded }` and `extend List<(String, String)> { formEncoded }` next to their bodies in `form.trb` and `characters.trb`, re-export in `std/uri/src/lib.trb` with `public use String.formDecoded, List.formEncoded from "./form"` and `public use String.percentDecoded from "./characters"` (replacing lines 27-28); internal callers and tests import from the declaring file (`./form`, `./characters`, tests `../src/form`, `../src/characters`), docs and anything external from "std/uri". If an `extend` with a generic/tuple receiver in `form.trb` fails the seed's native back end (as `List<MarkdownInline>` did in lib.trb), move that one declaration as #178 did and say so in the PR; if the `std/uri` re-export import does not check, declare in `lib.trb` as compression and encoding do. Do not work around #182 in the compiler in this PR. **Pinned records:** docs/standard-library/uri.md, docs/design/URI.md, CONCEPT.md "Extension Methods" at 129f1574e8ad4c9c691306808eb39900e77d4fc2. No design record fixes the API shape. **Seed:** no (std only; no syntax change, no native, no driver flag; the names `formDecoded`/`formEncoded`/`percentDecoded` are not looked up by the compiler, wellknown.trb only names the types). Stop and re-plan if that proves wrong. **Size:** one PR, one commit `refactor(uri): make formDecoded, formEncoded and percentDecoded methods and remove the functions`. Note: the ready buffer already holds #170-#172 and #177, so this is the fifth; implementation order stays oldest first. **Implementer model:** sonnet/medium (std and docs only). Worker usage for this refine: about 60k tokens (sonnet). next: implement
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261008 until 2026-10-08T15:40:00Z

[loop:torbscript] claim implement by session:loop-torbscript-20261008 until 2026-10-08T15:40:00Z
Author
Collaborator

[loop:torbscript] implement: PR open at #187 (branch loop/179-uri-methods, one commit refactor(uri): make formDecoded, formEncoded and percentDecoded methods and remove the functions). String.formDecoded(), List<(String, String)>.formEncoded() and String.percentDecoded() are declared next to their bodies in form.trb/characters.trb and re-exported from std/uri via public use String.x, List.y; the three free functions are removed, callers in uri.trb, template.trb and bridges.test.trb migrated; docs/standard-library/uri.md, docs/design/URI.md and the skill reference lead with the methods. CI on 649f1f5a: bootstrap, tier A (docs check, doc --check, skill --check, format --check, std tests), commit messages and pdisc green; tier B skipped (not required); the aggregate gates job and seed/archive packaging were still finishing when I stopped waiting. One CI round was needed: a doc example (print [..].formEncoded()) parsed as indexing and failed doc --check; fixed and squashed. Worker usage: about 200k tokens (sonnet), estimated. next: review

Releasing the claim by session:loop-torbscript-20261008.

[loop:torbscript] implement: PR open at https://git.torb.dev/torbscript/language/pulls/187 (branch `loop/179-uri-methods`, one commit `refactor(uri): make formDecoded, formEncoded and percentDecoded methods and remove the functions`). `String.formDecoded()`, `List<(String, String)>.formEncoded()` and `String.percentDecoded()` are declared next to their bodies in `form.trb`/`characters.trb` and re-exported from `std/uri` via `public use String.x, List.y`; the three free functions are removed, callers in `uri.trb`, `template.trb` and `bridges.test.trb` migrated; `docs/standard-library/uri.md`, `docs/design/URI.md` and the skill reference lead with the methods. CI on 649f1f5a: bootstrap, tier A (docs check, doc --check, skill --check, format --check, std tests), commit messages and pdisc green; tier B skipped (not required); the aggregate `gates` job and seed/archive packaging were still finishing when I stopped waiting. One CI round was needed: a doc example (`print [..].formEncoded()`) parsed as indexing and failed `doc --check`; fixed and squashed. Worker usage: about 200k tokens (sonnet), estimated. next: review Releasing the claim by session:loop-torbscript-20261008.
argus closed this issue 2026-10-08 10:41:29 +00:00
Sign in to join this conversation.
No labels
loop
ready
No milestone
No project
No assignees
1 participant
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#179
No description provided.