Repository navigation
fix(uri-template): support the ';' operator and RFC 6570 empty-list expansion - #3183
shhhhhhjokerist wants to merge 3 commits into
Conversation
🦋 Changeset detectedLatest commit: 155ae81 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@modelcontextprotocol/client
@modelcontextprotocol/codemod
@modelcontextprotocol/core
@modelcontextprotocol/server
@modelcontextprotocol/server-legacy
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
|
Thanks, the parse-side reading matches what I hit from the source, and sharing one Four rows from the Section 3.2.7 table are not covered by the committed tests yet, and one of them exposes a match-direction gap:
The two
One detail that deserves a code comment: If it keeps #3183 focused, I am glad to send a follow-up PR with the extra table rows and the exploded-list match test rather than pushing onto your branch. |
|
Thanks for the review — all three points are addressed in
Gates on
I don't see anything else left in this PR, but if you'd still rather take the keys / prefix-modifier rows as your own follow-up, that's a clean split — happy to either way. |
|
Read
No objection from me on the change. |
|
Recorded the single-member asymmetry as a known limitation in the changeset ( |
Fixes #3182
Per
CONTRIBUTING.md("Before starting work, comment on the issue so we can assign it to you"), I asked for assignment in #3182 (comment); the issue is still unassigned, so I'm opening this small, test-covered fix now and will hand it over if a maintainer prefers to assign it to someone else.Root cause
packages/core-internal/src/shared/uriTemplate.tsonly knew the reserved/label/path/query operators (+ # . / ? &):getOperator(line 91) did not list;, so{;x,y}was parsed as a simple expression whose variable names were literally;xand;y. Every variable lookup then missed and the whole expression collapsed to the remaining literal text (''or a bare number), so path-style parameters could not be produced.expandPartnorpartToRegExphad a;branch, so;name=valuesegments could not be matched back into variables either.{/tags},{?tags},{.tags}and{#tags}expanded to/,?tags=,.and#respectively — separators with nothing behind them.RFC 6570 §2.3 says a list value with zero members is considered undefined, and §3.2.7 says a path-style parameter appends
=only when its value is not empty:Fix
;to the operator list (getOperator).;as;name=valuefor each defined variable,;namewhen the value is the empty string, values pct-encoded against the unreserved set (so;,=and/stay literal separators), and;name=valueper member for exploded lists.isUndefinedValue), so it contributes nothing under every operator instead of leaving a dangling separator or an emptyname=pair. A defined empty string is unaffected:{;empty}→;empty,{?empty}→?empty=(§3.2.8).matchto parse;name=valueand;namesegments back into variables; a variable that was omitted or empty matches as''.Diff is confined to
uriTemplate.tsplus tests and a patch changeset for@modelcontextprotocol/core-internaland@modelcontextprotocol/server.Tests
Run against
packages/core-internal/test/shared/uriTemplate.test.ts. Added cases cover{;x,y}, the §3.2.7 examples (;who=fred,;half=50%25,;empty,;v=6;empty;who=fred,{;v,bar,who},{;x,y,empty},{;x,y,undef},{;list},{;list*}), a literal-prefix template (X{;color,year}→X;color=red;year=2012), pct-encoding (;v=a%20b,;v=a%3Bb%3Dc), matching (;x=1,;x=1;y=2,X;color=red;year=2012,;empty), negative matches (?x=1,;y=1), and empty-list expansion across all eight operators.RED on untouched
main:GREEN after the fix:
Checks run locally
pnpm -r typecheck— passpnpm -r lint— pass (ESLint + Prettier across every package)pnpm sync:snippets --checkandpnpm check:skills— pass@modelcontextprotocol/core-internalsuite —1863 passed (1863)(includes the schema-twin conformance tests)Risk
Contained to
UriTemplate.{;...}templates previously expanded to junk (the operator was swallowed into variable names), so no caller can be relying on the old output for;; empty lists previously produced a bare separator, which callers do not depend on either.matchkeeps the existing lenient behaviour for literal prefixes and now also understands;. Exploded;lists are supported in expansion; matching covers the non-exploded;name=value/;nameforms the issue reports.Known limitation
An exploded
;list with exactly one member expands to;list=redand matches back as the string'red'rather than['red']; a zero-member list expands to nothing and therefore does not match. Both follow from the existingstring | string[]Variablestype and the+in the repeated pattern, and are recorded in the changeset so nobody discovers them from a runtime error.