Skip to content

fix(parser): collapse a leading // in sanitizeUrl - #203

Merged
mgks merged 1 commit into
docmd-io:mainfrom
eeshsaxena:fix-sanitizeurl-protocol-relative
Aug 17, 2026
Merged

fix(parser): collapse a leading // in sanitizeUrl#203
mgks merged 1 commit into
docmd-io:mainfrom
eeshsaxena:fix-sanitizeurl-protocol-relative

Conversation

@eeshsaxena

Copy link
Copy Markdown
Contributor

sanitizeUrl collapses accidental double slashes, but it can't touch a leading //:

sanitizeUrl('//docs//guide/')  // -> '//docs/guide/'   (docstring says '/docs/guide/')

The regex /([^:])\/\/+/g only matches a slash-run that has a non-colon character in front of it, so a run at the very start of the string is never collapsed.

That leading // is not harmless. In a workspace build, buildAbsoluteUrl normalises an empty base to / and combines it with an absolute project path such as /search, producing //search/. A browser reads a leading // as a protocol-relative URL, i.e. //host/path, so the project-switcher link resolves against a different host:

new URL('//search/', 'https://example.com/docs/').href
// -> 'https://search/'   (not the intended 'https://example.com/search/')

There's actually a test in tests/cli-contracts/asset-base-url.test.js that already captured this //search/ output and rationalised it as "equivalent to /search/ in absolute terms" — but it isn't; //search/ points at the host search. Its assertion used /\/search\/$/, which passes for both forms, so the broken link slipped through.

The fix collapses every run of slashes and only preserves a genuine leading scheme:// separator (https://, ws://, ...). I also fixed the misleading comment in that test and tightened its assertion to require an exact /search/.

Verification:

  • packages/parser/test/sanitize-url.test.js — new unit test (leading //, interior/trailing runs, scheme:// preservation, and the new URL(...) cross-host resolution). It fails on main and passes with the change.
  • The resolveHref documented examples and a 300k-iteration fuzz of the href/nav helpers are unchanged (no new crashes, no altered outputs).

sanitizeUrl used /([^:])\/\/+/g, which can only collapse a run of
slashes that has a non-colon char in front of it. A leading // was
therefore left untouched, contradicting the function's own docstring
example (//docs//guide/ -> /docs/guide/).

This surfaces in workspace builds: buildAbsoluteUrl normalises an empty
base to '/' and combines it with an absolute project path like /search,
producing //search/. A browser treats a leading // as protocol-relative,
so the project-switcher link resolved to https://search/ (a different
host) instead of the intended same-site /search/.

Collapse every run of slashes, preserving only a genuine leading
scheme:// separator. Adds a sanitizeUrl unit test and tightens the
workspace switcher assertion to require an exact /search/.
@mgks
mgks merged commit e587773 into docmd-io:main Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants