Repository navigation
Accept file URL paths in readFileSync #1616
Description
readFileSync rejects a statically typed file: URL before code generation. A string from fileURLToPath works, and the compiler already has that URL conversion. This requests support for the direct Node overload, with the same path checks and argument evaluation order.
The original investigation reproduced this with scriptc 0.4.0 and an unmodified source build of main at 94aa7065f17fdeeb31094ffcb71885b0d671b5ba. Platform: Linux x86_64, Debian glibc 2.41, Node 24.19.0.
Reproduction
In an empty directory, create these files.
package.json:
{
"private": true,
"type": "module",
"devDependencies": {
"scriptc": "0.4.0",
"@types/node": "26.1.1"
}
}tsconfig.json:
{
"compilerOptions": {
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler"
}
}repro.ts:
import { readFileSync } from 'node:fs'
console.log(readFileSync(new URL('./fixture.txt', import.meta.url), 'utf8'))Run:
printf hello > fixture.txt
npm install
node repro.ts
./node_modules/.bin/scriptc --version
./node_modules/.bin/scriptc build repro.ts --emit ir -o repro.ir.jsonNode prints hello and exits 0. scriptc reports 0.4.0, then exits 1 with:
SC1090: 'URL' values where 'string' is expected is not supported yet
No socket or application package is involved. The expected behavior is to accept the documented Node URL path, and preserve errors for invalid schemes, hosts and encoded separators. The one-argument Buffer form also rejects the direct URL.
After pnpm install --frozen-lockfile --ignore-scripts and pnpm -r build in the main checkout, this command gives the same SC1090 from the clean reproduction directory:
node /path/to/scriptc/packages/cli/dist/main.js build repro.ts --emit ir -o main.ir.jsonCause and proposed implementation
lowerFsEncodedRead chooses STRING for every non-descriptor source. The one-argument branch in module-calls.ts also lowers its path as STRING. A native URL therefore reaches the URL-to-string refusal, even though url.fileURLToPathUrl is already available.
A local frontend prototype selects that existing conversion for a typed URL, then feeds the resulting path to the existing encoded or Buffer read. For an encoding-bearing call, it first stages the URL and encoding operands in hidden locals, in source order, and only then converts the URL. Converting it while evaluating the first operand would throw too early when the encoding expression has side effects.
In the original investigation, the regression fails on unpatched main and passes with the prototype. It checks both encoded and Buffer reads and validates the generated IR. The compiler build, lint and formatting checks pass. These are frontend results, not a native parity claim: the available 0.4.0 runtime pack has ABI 22, while main requires ABI 23, and they were not linked together. Native tests still need to cover Unicode and space-containing paths, invalid schemes/hosts/escapes, operand side effects, and encoded and Buffer results.
The publication recheck covered open and closed issues and PRs for readFileSync, URL paths and file URLs. #645 added URL conversion APIs, and #577 and #34 describe older, broader lowering gaps. No equivalent report or pending fix was found for this direct readFileSync overload. Application context: oxidezap/baileyrs#176. The reproduction does not depend on that project.
Verification on 2026-10-21
The isolated publication recheck used Linux x86_64 WSL (Arch Linux, glibc 2.44), Node v26.12.0, scriptc@0.4.0 (tag commit 4bc8a4711c358ca09edaa758f5efd296bc6d2730) and @types/node@26.1.1. An unmodified source build of main at 4dd62802c85f77739f7b69dc491758c4cda6f3e5 confirmed the same filesystem diagnostic. It was installed with pnpm 11.28.6 using pnpm install --frozen-lockfile --ignore-scripts and built with pnpm -r build; it still reports version 0.4.0, so the SHA identifies it.
Earlier results at 94aa7065f come from the pinned investigation. The prototype results described above are from that investigation; the patch was not reapplied during publication. Its lowering checks do not establish native parity, and no patched native runtime was executed.
Activity
Accept file URL paths in synchronous fs functions
Accept file URL paths in existsSync, fs.promises and order-checked fs…