fromFileSystemPath/toFileSystemPath in lib/util/url.ts are meant to be inverses for local filesystem paths (that's the whole point of the manual encode/decode tables — encodeURI/decodeURI leave URL-reserved characters like # and ? alone, so this module encodes them going in and decodes them coming back out).
The encode table (urlEncodePatterns) handles both:
const urlEncodePatterns = [
[/\?/g, "%3F"],
[/#/g, "%23"],
] as [RegExp, string][];
but the decode table (urlDecodePatterns) only reverses #, $, &, ,, @ — %3F → ? is missing:
const urlDecodePatterns = [/%23/g, "#", /%24/g, "$", /%26/g, "&", /%2C/g, ",", /%40/g, "@"];
The comment right above toFileSystemPath's decode step even names the character:
// Step 2: Manually decode characters that are not decoded by `decodeURI`.
// This includes characters such as "#" and "?", which have special meaning in URLs,
// but are just normal characters in a filesystem path.
Reproduction
? is a legal character in POSIX filenames. Any $RefParser.parse()/.dereference()/.bundle() call on a local path containing ? fails, because lib/index.ts runs user-supplied paths through fromFileSystemPath (which encodes ? → %3F) but resolution never decodes it back:
import $RefParser from "@apidevtools/json-schema-ref-parser";
// file exists at ./defs?1.json
await $RefParser.parse("./defs?1.json");
// ResolverError: Error opening file .../defs%3F1.json: ENOENT: no such file or directory
The literal ? in the path gets treated as if it were still URL query-string syntax and never makes it back to a real filesystem path.
Fix
Add the missing pair to urlDecodePatterns:
const urlDecodePatterns = [/%23/g, "#", /%24/g, "$", /%26/g, "&", /%2C/g, ",", /%3F/g, "?", /%40/g, "@"];
I have this fixed with a regression test and will open a PR referencing this issue.
fromFileSystemPath/toFileSystemPathinlib/util/url.tsare meant to be inverses for local filesystem paths (that's the whole point of the manual encode/decode tables —encodeURI/decodeURIleave URL-reserved characters like#and?alone, so this module encodes them going in and decodes them coming back out).The encode table (
urlEncodePatterns) handles both:but the decode table (
urlDecodePatterns) only reverses#,$,&,,,@—%3F→?is missing:The comment right above
toFileSystemPath's decode step even names the character:Reproduction
?is a legal character in POSIX filenames. Any$RefParser.parse()/.dereference()/.bundle()call on a local path containing?fails, becauselib/index.tsruns user-supplied paths throughfromFileSystemPath(which encodes?→%3F) but resolution never decodes it back:The literal
?in the path gets treated as if it were still URL query-string syntax and never makes it back to a real filesystem path.Fix
Add the missing pair to
urlDecodePatterns:I have this fixed with a regression test and will open a PR referencing this issue.