Skip to content

fix: recognize percent-encoded octets in bare file-path links - #945

Open
csmcneill wants to merge 1 commit into
craft-ai-agents:mainfrom
csmcneill:fix/bare-file-path-percent-encoding
Open

fix: recognize percent-encoded octets in bare file-path links#945
csmcneill wants to merge 1 commit into
craft-ai-agents:mainfrom
csmcneill:fix/bare-file-path-percent-encoding

Conversation

@csmcneill

Copy link
Copy Markdown

Summary

Fixes #944. Bare (non-file://) markdown links to local files fail whenever the path contains a space, because percent-encoding (%20) is the only CommonMark-valid way to represent a space in an unbracketed link destination, and FILE_PATH_TARGET_REGEX's character class didn't include %. The link falls through to being classified as a generic URL, where new URL() throws on a schemeless absolute path — producing Failed to open URL: URL blocked. URL is malformed and cannot be parsed. instead of opening the file.

  • Adds a shared PATH_CHAR fragment in linkify.ts that accepts either a normal path character or a percent-encoded octet (%XX), used in both FILE_PATH_TARGET_REGEX and the sibling FILE_PATH_REGEX (the auto-linkify pass for bare paths in plain text — same gap existed there).
  • Decodes the matched path in resolveMarkdownLinkTarget (link-target.ts) before handing it to the file-open handler, mirroring the decode step resolveFileUrlPath already performs for file:// targets.
  • % alone (not followed by two hex digits) is still rejected — the fix matches valid percent-encoding grammar rather than loosening the character class to accept any %.

Explicit file:///... links are unaffected by this bug (already correct before this change) and continue to work the same way.

Test plan

  • Added regression tests: percent-encoded space, multiple octets in one path, decode-and-classify round trip via resolveMarkdownLinkTarget/classifyMarkdownLinkTarget, and a negative case confirming a bare unescaped % is still rejected.
  • bun test src/components/markdown/__tests__/ in packages/ui — 158 pass, 0 fail (full markdown suite, no regressions).
  • bun run tsc --noEmit in packages/ui — clean.

Bare (non-file://) markdown links to local files fail whenever the path
contains a space, because percent-encoding (%20) is the only CommonMark-valid
way to represent a space in an unbracketed link destination, and
FILE_PATH_TARGET_REGEX's character class didn't include `%`. The link falls
through to being treated as a generic URL, where `new URL()` throws on a
schemeless absolute path, producing a generic "malformed URL" error instead of
opening the file.

- Add a shared PATH_CHAR fragment (in linkify.ts) that accepts either a normal
  path character or a percent-encoded octet (%XX), and use it in both
  FILE_PATH_TARGET_REGEX and the sibling FILE_PATH_REGEX used for auto-linkifying
  bare paths in plain text.
- Decode the matched path in resolveMarkdownLinkTarget (link-target.ts) before
  handing it to the file-open handler, mirroring the decode step
  resolveFileUrlPath already performs for file:// targets.
- Add regression tests covering percent-encoded spaces, multiple octets in one
  path, and a negative case (bare unescaped % is still rejected).

Fixes craft-ai-agents#944
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.

File-path links with spaces fail as malformed URL instead of opening

1 participant