Handle Windows absolute paths for schema inputs#2886
Open
schani wants to merge 1 commit into
Open
Conversation
Schema inputs given as Windows absolute paths (e.g. "C:\Users\me\top.schema.json") failed with "Could not fetch schema ..." or "Internal error: Defined value expected". Root cause: schema addresses are parsed with urijs, which treats the drive letter of a Windows absolute path as a URI *scheme* (lowercasing it and keeping the backslashes as an opaque path). The mangled address breaks schema-store lookups, and relative $refs resolve to bogus addresses like "c:///item.schema.json", which NodeIO then tries to fetch as HTTP URLs. The fix converts Windows absolute paths (drive-letter and UNC forms) to "file:" URIs before urijs ever sees them — in normalizeURI, Ref.root, and Ref.parse — and teaches NodeIO's readableFromFileOrURL to read "file:" URIs from disk. On POSIX, a drive-letter file URI is read as a path relative to the working directory, which is what allows the new regression check (test/check-windows-schema-paths.ts, run by test/test.ts before the fixtures) to exercise the whole pipeline on Linux CI, including relative $ref resolution between schema files. Fixes #2869 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
schani
commented
Jul 7, 2026
schani
left a comment
Member
Author
There was a problem hiding this comment.
We should probably first convert our more regular tests to vitest, then we can add these unit tests.
| // working directory), which is how the tests exercise this, and Node's fs | ||
| // accepts forward slashes on Windows anyway. The addresses were URI-decoded | ||
| // when they were normalized, so there's no percent-decoding to do here. | ||
| function filePathFromFileURI(fileURI: string): string { |
Member
Author
There was a problem hiding this comment.
Put that in a utility file and add comprehensive unit tests.
| // and treats the backslashes as an opaque path), so relative refs resolve to | ||
| // bogus addresses (issue #2869). Convert drive-letter and UNC paths to | ||
| // "file:" URIs, which NodeIO knows how to read. | ||
| function fixWindowsPath(pathOrURI: string): string { |
Member
Author
There was a problem hiding this comment.
Put that in a shared utility file and add comprehensive unit tests.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On Windows, giving quicktype a schema input as an absolute path fails:
Schemas without relative
$refs fail too, withInternal error: Defined value expected. Relative paths work.Root cause
Schema addresses are parsed with urijs, and a Windows absolute path is not a valid URI: urijs parses the drive letter of
C:\Users\me\top.schema.jsonas a URI scheme (lowercasing it, and keeping the backslashes as an opaque path). The mangled address breaks schema-store lookups, and relative$refs resolved against it viaabsoluteToyield bogus addresses likec:///item.schema.json, whichis-urlin NodeIO then classifies as HTTP URLs and tries to fetch.The fix
packages/quicktype-core/src/input/JSONSchemaInput.ts: a newfixWindowsPathhelper converts Windows absolute paths (drive-letterC:\.../C:/...and UNC\\server\share\...forms) tofile:URIs, applied at the three places where address strings are parsed into URIs (normalizeURI,Ref.root,Ref.parse). urijs handlesfile:URIs correctly, so normalization, schema-store keying, and relative-$refresolution all work unchanged (drive-letter casing is preserved because the letter is now in the URI path, not the scheme).packages/quicktype-core/src/input/io/NodeIO.ts:readableFromFileOrURLnow readsfile:URIs from disk instead of lettingis-urlclassify them as HTTP URLs. Deliberately noturl.fileURLToPath(its result is platform-dependent): a drive-letter URI maps toC:/dir/x.json, which is the correct absolute path on Windows (Node's fs accepts forward slashes there) and a cwd-relative path on POSIX, which is what makes the bug testable on Linux CI.Plain POSIX paths never hit either code path, and other input kinds (JSON, GraphQL) don't go through the schema-address machinery at all.
Tests (written first)
test/check-windows-schema-paths.ts, run bytest/test.tsbefore the fixtures in every CI job (same pattern as the #2850 check). It builds a literalC:/Users/quicktype/directory tree in a temp dir, chdirs into it, and runs the quicktype-core pipeline (JSONSchemaInput+FetchingJSONSchemaStore, exactly as the CLI wires it) with three schema-path spellings, where the top-level schema$refs a sibling file so relative-ref resolution is asserted too:The check was added and run before the fix, failing with the issue's exact symptom on both Windows cases (POSIX case passed):
After the fix it passes, and the issue's original command (simulated on Linux via a literal
C:/Users/Cat/tree, run asquicktype -s schema 'C:\Users\Cat\bookmark.schema.json' --lang typescript --just-types) now produces the same output as the relative-path invocation.Verification notes
FIXTURE=schema-golang script/teston all 63 local schema samples: green. (ref-remote.schemawas excluded — it fails identically on unmodified master in this environment because remote fetching viaglobal.fetchdoesn't work with the localgetStream; CI swaps in cross-fetch viaenv.sh. Unrelated to this change.)FIXTURE=golangon JSON priority samples: green (NodeIO's non-schema path unaffected).file:URI mappings follow the standard Windows file-URI convention, and the POSIX-side simulation exercises the full pipeline including$refresolution.Fixes #2869
🤖 Generated with Claude Code